@@ -61,7 +61,7 @@ inline static QgsRectangle calculateBoundingBox( QGis::WkbType wkbType, unsigned
61
61
}
62
62
63
63
// ! Generalize the WKB-geometry using the BBOX of the original geometry
64
- inline static bool generalizeWkbGeometry (
64
+ static bool generalizeWkbGeometryByBoundingBox (
65
65
QGis::WkbType wkbType,
66
66
unsigned char * sourceWkb, size_t sourceWkbSize,
67
67
unsigned char * targetWkb, size_t & targetWkbSize,
@@ -169,7 +169,7 @@ bool QgsMapToPixelSimplifier::simplifyWkbGeometry(
169
169
if (( simplifyFlags & QgsMapToPixelSimplifier::SimplifyEnvelope ) &&
170
170
isGeneralizableByMapBoundingBox ( envelope, map2pixelTol ) )
171
171
{
172
- isGeneralizable = generalizeWkbGeometry ( wkbType, sourceWkb, sourceWkbSize, targetWkb, targetWkbSize, envelope, writeHeader );
172
+ isGeneralizable = generalizeWkbGeometryByBoundingBox ( wkbType, sourceWkb, sourceWkbSize, targetWkb, targetWkbSize, envelope, writeHeader );
173
173
if ( isGeneralizable )
174
174
return true ;
175
175
}
@@ -222,8 +222,8 @@ bool QgsMapToPixelSimplifier::simplifyWkbGeometry(
222
222
double * ptr = ( double * )targetWkb;
223
223
map2pixelTol *= map2pixelTol; // -> Use mappixelTol for 'LengthSquare' calculations.
224
224
225
- bool isaUngenerizableSegment ;
226
- bool hasUngenerizableSegments = false ; // -> To avoid replace the simplified geometry by its BBOX when there are 'long' segments.
225
+ bool isLongSegment ;
226
+ bool hasLongSegments = false ; // -> To avoid replace the simplified geometry by its BBOX when there are 'long' segments.
227
227
228
228
// Check whether the LinearRing is really closed.
229
229
if ( isaLinearRing )
@@ -249,44 +249,55 @@ bool QgsMapToPixelSimplifier::simplifyWkbGeometry(
249
249
memcpy ( &x, sourceWkb, sizeof ( double ) ); sourceWkb += sizeOfDoubleX;
250
250
memcpy ( &y, sourceWkb, sizeof ( double ) ); sourceWkb += sizeOfDoubleY;
251
251
252
- isaUngenerizableSegment = false ;
252
+ isLongSegment = false ;
253
253
254
254
if ( i == 0 ||
255
255
!isGeneralizable ||
256
- ( isaUngenerizableSegment = ( calculateLengthSquared2D ( x, y, lastX, lastY ) > map2pixelTol ) ) ||
256
+ ( isLongSegment = ( calculateLengthSquared2D ( x, y, lastX, lastY ) > map2pixelTol ) ) ||
257
257
( !isaLinearRing && ( i == 1 || i >= numPoints - 2 ) ) )
258
258
{
259
259
memcpy ( ptr, &x, sizeof ( double ) ); lastX = x; ptr++;
260
260
memcpy ( ptr, &y, sizeof ( double ) ); lastY = y; ptr++;
261
261
numTargetPoints++;
262
262
263
- if ( isaUngenerizableSegment && !hasUngenerizableSegments )
264
- {
265
- hasUngenerizableSegments = true ;
266
- }
263
+ hasLongSegments |= isLongSegment;
267
264
}
268
265
269
266
r.combineExtentWith ( x, y );
270
267
}
271
268
targetWkb = wkb2 + 4 ;
272
269
273
- // Fix the topology of the geometry
274
- if ( numTargetPoints <= ( isaLinearRing ? 2 : 1 ) && !hasUngenerizableSegments )
270
+ if ( numTargetPoints < ( isaLinearRing ? 4 : 2 ) )
275
271
{
276
- unsigned char * targetTempWkb = targetWkb;
277
- int targetWkbTempSize = targetWkbSize;
278
-
279
- sourceWkb = sourcePrevWkb;
280
- targetWkb = targetPrevWkb;
281
- targetWkbSize = targetWkbPrevSize;
282
- if ( generalizeWkbGeometry ( wkbType, sourceWkb, sourceWkbSize, targetWkb, targetWkbSize, r, writeHeader ) )
283
- return true ;
284
-
285
- targetWkb = targetTempWkb;
286
- targetWkbSize = targetWkbTempSize;
272
+ // we simplified the geometry too much!
273
+ if ( !hasLongSegments )
274
+ {
275
+ // approximate the geometry's shape by its bounding box
276
+ // (rect for linear ring / one segment for line string)
277
+ unsigned char * targetTempWkb = targetWkb;
278
+ int targetWkbTempSize = targetWkbSize;
279
+
280
+ sourceWkb = sourcePrevWkb;
281
+ targetWkb = targetPrevWkb;
282
+ targetWkbSize = targetWkbPrevSize;
283
+ if ( generalizeWkbGeometryByBoundingBox ( wkbType, sourceWkb, sourceWkbSize, targetWkb, targetWkbSize, r, writeHeader ) )
284
+ return true ;
285
+
286
+ targetWkb = targetTempWkb;
287
+ targetWkbSize = targetWkbTempSize;
288
+ }
289
+ else
290
+ {
291
+ // Bad luck! The simplified geometry is invalid and approximation by bounding box
292
+ // would create artifacts due to long segments. Worst of all, we may have overwritten
293
+ // the original coordinates by the simplified ones (source and target WKB ptr can be the same)
294
+ // so we cannot even undo the changes here. We will return invalid geometry and hope that
295
+ // other pieces of QGIS will survive that :-/
296
+ }
287
297
}
288
298
if ( isaLinearRing )
289
299
{
300
+ // make sure we keep the linear ring closed
290
301
memcpy ( &x, targetWkb + 0 , sizeof ( double ) );
291
302
memcpy ( &y, targetWkb + sizeof ( double ), sizeof ( double ) );
292
303
if ( lastX != x || lastY != y )
0 commit comments