@@ -69,6 +69,9 @@ void QgsInvertedPolygonRenderer::startRender( QgsRenderContext& context, const Q
69
69
return ;
70
70
}
71
71
72
+ // first call start render on the sub renderer
73
+ mSubRenderer ->startRender ( context, fields );
74
+
72
75
mFeaturesCategories .clear ();
73
76
mFeatureDecorations .clear ();
74
77
mFields = fields;
@@ -114,8 +117,6 @@ void QgsInvertedPolygonRenderer::startRender( QgsRenderContext& context, const Q
114
117
115
118
mExtentPolygon .clear ();
116
119
mExtentPolygon .append ( exteriorRing );
117
-
118
- mSubRenderer ->startRender ( mContext , fields );
119
120
}
120
121
121
122
bool QgsInvertedPolygonRenderer::renderFeature ( QgsFeature& feature, QgsRenderContext& context, int layer, bool selected, bool drawVertexMarker )
@@ -171,9 +172,7 @@ bool QgsInvertedPolygonRenderer::renderFeature( QgsFeature& feature, QgsRenderCo
171
172
172
173
if ( ! mSymbolCategories .contains ( catId ) )
173
174
{
174
- // the exterior ring must be a square in the destination CRS
175
175
CombinedFeature cFeat;
176
- cFeat.multiPolygon .append ( mExtentPolygon );
177
176
// store the first feature
178
177
cFeat.feature = feature;
179
178
mSymbolCategories .insert ( catId, mSymbolCategories .count () );
@@ -182,11 +181,11 @@ bool QgsInvertedPolygonRenderer::renderFeature( QgsFeature& feature, QgsRenderCo
182
181
183
182
// update the geometry
184
183
CombinedFeature& cFeat = mFeaturesCategories [ mSymbolCategories [catId] ];
185
- QgsGeometry* geom = feature.geometry ();
186
- if ( !geom )
184
+ if ( !feature.geometry () )
187
185
{
188
186
return false ;
189
187
}
188
+ QScopedPointer<QgsGeometry> geom ( new QgsGeometry ( *feature.geometry () ) );
190
189
191
190
const QgsCoordinateTransform* xform = context.coordinateTransform ();
192
191
if ( xform )
@@ -196,61 +195,15 @@ bool QgsInvertedPolygonRenderer::renderFeature( QgsFeature& feature, QgsRenderCo
196
195
197
196
if ( mPreprocessingEnabled )
198
197
{
199
- // preprocessing
200
- if ( ! cFeat. feature . geometry () )
198
+ // fix the polygon if it is not valid
199
+ if ( ! geom-> isGeosValid () )
201
200
{
202
- // first feature: add the current geometry
203
- cFeat.feature .setGeometry ( new QgsGeometry ( *geom ) );
204
- }
205
- else
206
- {
207
- // other features: combine them (union)
208
- QgsGeometry* combined = cFeat.feature .geometry ()->combine ( geom );
209
- if ( combined && combined->isGeosValid () )
210
- {
211
- cFeat.feature .setGeometry ( combined );
212
- }
201
+ geom.reset ( geom->buffer ( 0 , 0 ) );
213
202
}
214
203
}
215
- else
216
- {
217
- // No preprocessing involved.
218
- // We build here a "reversed" geometry of all the polygons
219
- //
220
- // The final geometry is a multipolygon F, with :
221
- // * the first polygon of F having the current extent as its exterior ring
222
- // * each polygon's exterior ring is added as interior ring of the first polygon of F
223
- // * each polygon's interior ring is added as new polygons in F
224
- //
225
- // No validity check is done, on purpose, it will be very slow and painting
226
- // operations do not need geometries to be valid
227
-
228
- QgsMultiPolygon multi;
229
- if (( geom->wkbType () == QGis::WKBPolygon ) ||
230
- ( geom->wkbType () == QGis::WKBPolygon25D ) )
231
- {
232
- multi.append ( geom->asPolygon () );
233
- }
234
- else if (( geom->wkbType () == QGis::WKBMultiPolygon ) ||
235
- ( geom->wkbType () == QGis::WKBMultiPolygon25D ) )
236
- {
237
- multi = geom->asMultiPolygon ();
238
- }
204
+ // add the geometry to the list of geometries for this feature
205
+ cFeat.geometries .append ( geom.take () );
239
206
240
- for ( int i = 0 ; i < multi.size (); i++ )
241
- {
242
- // add the exterior ring as interior ring to the first polygon
243
- cFeat.multiPolygon [0 ].append ( multi[i][0 ] );
244
-
245
- // add interior rings as new polygons
246
- for ( int j = 1 ; j < multi[i].size (); j++ )
247
- {
248
- QgsPolygon new_poly;
249
- new_poly.append ( multi[i][j] );
250
- cFeat.multiPolygon .append ( new_poly );
251
- }
252
- }
253
- }
254
207
return true ;
255
208
}
256
209
@@ -267,23 +220,61 @@ void QgsInvertedPolygonRenderer::stopRender( QgsRenderContext& context )
267
220
268
221
for ( FeatureCategoryVector::iterator cit = mFeaturesCategories .begin (); cit != mFeaturesCategories .end (); ++cit )
269
222
{
270
- QgsFeature feat ( cit->feature ) ;
271
- if ( ! mPreprocessingEnabled )
223
+ QgsFeature& feat = cit->feature ;
224
+ if ( mPreprocessingEnabled )
272
225
{
273
- // no preprocessing - the final polygon has already been prepared
274
- feat.setGeometry ( QgsGeometry::fromMultiPolygon ( cit->multiPolygon ) );
226
+ // compute the unary union on the polygons
227
+ QScopedPointer<QgsGeometry> unioned ( QgsGeometryAlgorithms::unaryUnion ( cit->geometries ) );
228
+ // compute the difference with the extent
229
+ QScopedPointer<QgsGeometry> rect ( QgsGeometry::fromPolygon ( mExtentPolygon ) );
230
+ QgsGeometry *final = rect->difference ( const_cast <QgsGeometry*>(unioned.data ()) );
231
+ if ( final )
232
+ {
233
+ feat.setGeometry ( final );
234
+ }
275
235
}
276
236
else
277
237
{
278
- // preprocessing mode - we still have to invert (using difference)
279
- if ( feat.geometry () )
238
+ // No preprocessing involved.
239
+ // We build here a "reversed" geometry of all the polygons
240
+ //
241
+ // The final geometry is a multipolygon F, with :
242
+ // * the first polygon of F having the current extent as its exterior ring
243
+ // * each polygon's exterior ring is added as interior ring of the first polygon of F
244
+ // * each polygon's interior ring is added as new polygons in F
245
+ //
246
+ // No validity check is done, on purpose, it will be very slow and painting
247
+ // operations do not need geometries to be valid
248
+ QgsMultiPolygon finalMulti;
249
+ finalMulti.append ( mExtentPolygon );
250
+ foreach ( QgsGeometry* geom, cit->geometries )
280
251
{
281
- QScopedPointer<QgsGeometry> rect ( QgsGeometry::fromPolygon ( mExtentPolygon ) );
282
- QgsGeometry *final = rect->difference ( feat.geometry () );
283
- if ( final )
252
+ QgsMultiPolygon multi;
253
+ if (( geom->wkbType () == QGis::WKBPolygon ) ||
254
+ ( geom->wkbType () == QGis::WKBPolygon25D ) )
255
+ {
256
+ multi.append ( geom->asPolygon () );
257
+ }
258
+ else if (( geom->wkbType () == QGis::WKBMultiPolygon ) ||
259
+ ( geom->wkbType () == QGis::WKBMultiPolygon25D ) )
260
+ {
261
+ multi = geom->asMultiPolygon ();
262
+ }
263
+
264
+ for ( int i = 0 ; i < multi.size (); i++ )
284
265
{
285
- feat.setGeometry ( final );
266
+ // add the exterior ring as interior ring to the first polygon
267
+ finalMulti[0 ].append ( multi[i][0 ] );
268
+
269
+ // add interior rings as new polygons
270
+ for ( int j = 1 ; j < multi[i].size (); j++ )
271
+ {
272
+ QgsPolygon new_poly;
273
+ new_poly.append ( multi[i][j] );
274
+ finalMulti.append ( new_poly );
275
+ }
286
276
}
277
+ feat.setGeometry ( QgsGeometry::fromMultiPolygon ( finalMulti ) );
287
278
}
288
279
}
289
280
mSubRenderer ->renderFeature ( feat, mContext );
0 commit comments