2828#include < QDomElement>
2929
3030QgsInvertedPolygonRenderer::QgsInvertedPolygonRenderer ( const QgsFeatureRendererV2* subRenderer )
31- : QgsFeatureRendererV2( " invertedPolygonRenderer" )
31+ : QgsFeatureRendererV2( " invertedPolygonRenderer" ), mPreprocessingEnabled( false )
3232{
3333 if ( subRenderer ) {
3434 setEmbeddedRenderer ( subRenderer );
@@ -154,15 +154,6 @@ bool QgsInvertedPolygonRenderer::renderFeature( QgsFeature& feature, QgsRenderCo
154154 return false ;
155155 }
156156
157- // We build here a "reversed" geometry of all the polygons
158- //
159- // The final geometry is a multipolygon F, with :
160- // * the first polygon of F having the current extent as its exterior ring
161- // * each polygon's exterior ring is added as interior ring of the first polygon of F
162- // * each polygon's interior ring is added as new polygons in F
163- //
164- // No validity check is done, on purpose, it will be very slow and painting
165- // operations do not need geometries to be valid
166157 if ( ! mFeaturesCategoryMap .contains (catId) )
167158 {
168159 // the exterior ring must be a square in the destination CRS
@@ -173,7 +164,7 @@ bool QgsInvertedPolygonRenderer::renderFeature( QgsFeature& feature, QgsRenderCo
173164 mFeaturesCategoryMap .insert ( catId, cFeat );
174165 }
175166
176- // update the gometry
167+ // update the geometry
177168 CombinedFeature& cFeat = mFeaturesCategoryMap [catId];
178169 QgsMultiPolygon multi;
179170 QgsGeometry* geom = feature.geometry ();
@@ -190,37 +181,69 @@ bool QgsInvertedPolygonRenderer::renderFeature( QgsFeature& feature, QgsRenderCo
190181 multi = geom->asMultiPolygon ();
191182 }
192183
193- for ( int i = 0 ; i < multi.size (); i++ ) {
194- // add the exterior ring as interior ring to the first polygon
195- if ( mTransform ) {
196- QgsPolyline new_ls;
197- QgsPolyline& old_ls = multi[i][0 ];
198- for ( int k = 0 ; k < old_ls.size (); k++ ) {
199- new_ls.append ( mTransform ->transform ( old_ls[k] ) );
200- }
201- cFeat.multiPolygon [0 ].append ( new_ls );
184+ if ( mPreprocessingEnabled )
185+ {
186+ // preprocessing
187+ if ( ! cFeat.feature .geometry () )
188+ {
189+ // first feature: add the current geometry
190+ cFeat.feature .setGeometry ( new QgsGeometry (*geom) );
202191 }
203192 else
204193 {
205- cFeat.multiPolygon [0 ].append ( multi[i][0 ] );
194+ // other features: combine them (union)
195+ QgsGeometry* combined = cFeat.feature .geometry ()->combine ( geom );
196+ if ( combined && combined->isGeosValid () )
197+ {
198+ cFeat.feature .setGeometry ( combined );
199+ }
206200 }
207- // add interior rings as new polygons
208- for ( int j = 1 ; j < multi[i].size (); j++ ) {
209- QgsPolygon new_poly;
201+ }
202+ else
203+ {
204+ // No preprocessing involved.
205+ // We build here a "reversed" geometry of all the polygons
206+ //
207+ // The final geometry is a multipolygon F, with :
208+ // * the first polygon of F having the current extent as its exterior ring
209+ // * each polygon's exterior ring is added as interior ring of the first polygon of F
210+ // * each polygon's interior ring is added as new polygons in F
211+ //
212+ // No validity check is done, on purpose, it will be very slow and painting
213+ // operations do not need geometries to be valid
214+
215+ for ( int i = 0 ; i < multi.size (); i++ ) {
216+ // add the exterior ring as interior ring to the first polygon
210217 if ( mTransform ) {
211218 QgsPolyline new_ls;
212- QgsPolyline& old_ls = multi[i][j ];
219+ QgsPolyline& old_ls = multi[i][0 ];
213220 for ( int k = 0 ; k < old_ls.size (); k++ ) {
214221 new_ls.append ( mTransform ->transform ( old_ls[k] ) );
215222 }
216- new_poly .append ( new_ls );
223+ cFeat. multiPolygon [ 0 ] .append ( new_ls );
217224 }
218225 else
219226 {
220- new_poly. append ( multi[i][j ] );
227+ cFeat. multiPolygon [ 0 ]. append ( multi[i][0 ] );
221228 }
229+ // add interior rings as new polygons
230+ for ( int j = 1 ; j < multi[i].size (); j++ ) {
231+ QgsPolygon new_poly;
232+ if ( mTransform ) {
233+ QgsPolyline new_ls;
234+ QgsPolyline& old_ls = multi[i][j];
235+ for ( int k = 0 ; k < old_ls.size (); k++ ) {
236+ new_ls.append ( mTransform ->transform ( old_ls[k] ) );
237+ }
238+ new_poly.append ( new_ls );
239+ }
240+ else
241+ {
242+ new_poly.append ( multi[i][j] );
243+ }
222244
223- cFeat.multiPolygon .append ( new_poly );
245+ cFeat.multiPolygon .append ( new_poly );
246+ }
224247 }
225248 }
226249 return true ;
@@ -239,7 +262,24 @@ void QgsInvertedPolygonRenderer::stopRender( QgsRenderContext& context )
239262 for ( FeatureCategoryMap::iterator cit = mFeaturesCategoryMap .begin (); cit != mFeaturesCategoryMap .end (); ++cit)
240263 {
241264 QgsFeature feat ( cit.value ().feature );
242- feat.setGeometry ( QgsGeometry::fromMultiPolygon ( cit.value ().multiPolygon ) );
265+ if ( !mPreprocessingEnabled )
266+ {
267+ // no preprocessing - the final polygon has already been prepared
268+ feat.setGeometry ( QgsGeometry::fromMultiPolygon ( cit.value ().multiPolygon ) );
269+ }
270+ else
271+ {
272+ // preprocessing mode - we still have to invert (using difference)
273+ if ( feat.geometry () )
274+ {
275+ QScopedPointer<QgsGeometry> rect ( QgsGeometry::fromPolygon ( mExtentPolygon ) );
276+ QgsGeometry *final = rect->difference ( feat.geometry () );
277+ if ( final )
278+ {
279+ feat.setGeometry ( final );
280+ }
281+ }
282+ }
243283 mSubRenderer ->renderFeature ( feat, context );
244284 }
245285
@@ -280,12 +320,17 @@ QString QgsInvertedPolygonRenderer::dump() const
280320
281321QgsFeatureRendererV2* QgsInvertedPolygonRenderer::clone ()
282322{
323+ QgsInvertedPolygonRenderer* newRenderer;
283324 if ( mSubRenderer .isNull () )
284325 {
285- return new QgsInvertedPolygonRenderer ( 0 );
326+ newRenderer = new QgsInvertedPolygonRenderer ( 0 );
327+ }
328+ else
329+ {
330+ newRenderer = new QgsInvertedPolygonRenderer ( mSubRenderer ->clone () );
286331 }
287- // else
288- return new QgsInvertedPolygonRenderer ( mSubRenderer -> clone () ) ;
332+ newRenderer-> setPreprocessingEnabled ( preprocessingEnabled () );
333+ return newRenderer ;
289334}
290335
291336QgsFeatureRendererV2* QgsInvertedPolygonRenderer::create ( QDomElement& element )
@@ -297,13 +342,15 @@ QgsFeatureRendererV2* QgsInvertedPolygonRenderer::create( QDomElement& element )
297342 {
298343 r->setEmbeddedRenderer ( QgsFeatureRendererV2::load ( embeddedRendererElem ) );
299344 }
345+ r->setPreprocessingEnabled ( element.attribute ( " preprocessing" , " 0" ).toInt () == 1 );
300346 return r;
301347}
302348
303349QDomElement QgsInvertedPolygonRenderer::save ( QDomDocument& doc )
304350{
305351 QDomElement rendererElem = doc.createElement ( RENDERER_TAG_NAME );
306352 rendererElem.setAttribute ( " type" , " invertedPolygonRenderer" );
353+ rendererElem.setAttribute ( " preprocessing" , preprocessingEnabled () ? " 1" : " 0" );
307354
308355 if ( mSubRenderer )
309356 {
0 commit comments