Skip to content

Commit acf2c45

Browse files
author
Hugo Mercier
committed
Mask renderer: do not store temporary features anymore
1 parent c1b4fe8 commit acf2c45

File tree

2 files changed

+65
-48
lines changed

2 files changed

+65
-48
lines changed

src/core/symbology-ng/qgsmaskrendererv2.cpp

+57-47
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,12 @@ bool QgsMaskRendererV2::renderFeature( QgsFeature& feature, QgsRenderContext& co
7373
{
7474
Q_UNUSED( context );
7575

76+
// store this feature as a feature to render with decoration if needed
77+
if ( selected || drawVertexMarker )
78+
{
79+
mFeatureDecorations.append( FeatureDecoration( feature, selected, drawVertexMarker, layer) );
80+
}
81+
7682
// Features are grouped by category of symbols (returned by symbol(s)ForFeature)
7783
// This way, users can have multiple inverted polygon fills for a layer,
7884
// for instance, with rule based renderer and different symbols
@@ -103,24 +109,10 @@ bool QgsMaskRendererV2::renderFeature( QgsFeature& feature, QgsRenderContext& co
103109
catId.append( reinterpret_cast<const char*>(&sym), sizeof(sym) );
104110
}
105111
}
106-
if ( !catId.isEmpty() )
107-
{
108-
mFeaturesCategoryMap[catId].append( feature );
109-
}
110112

111-
// store this feature as a feature to render with decoration if needed
112-
if ( selected || drawVertexMarker )
113+
if ( catId.isEmpty() )
113114
{
114-
mFeatureDecorations.append( FeatureDecoration( feature, selected, drawVertexMarker, layer) );
115-
}
116-
117-
return true;
118-
}
119-
120-
void QgsMaskRendererV2::stopRender( QgsRenderContext& context )
121-
{
122-
if ( !mSubRenderer ) {
123-
return;
115+
return false;
124116
}
125117

126118
// We build here a "reversed" geometry of all the polygons
@@ -132,12 +124,9 @@ void QgsMaskRendererV2::stopRender( QgsRenderContext& context )
132124
//
133125
// No validity check is done, on purpose, it will be very slow and painting
134126
// operations do not need geometries to be valid
135-
for ( FeatureCategoryMap::iterator cit = mFeaturesCategoryMap.begin(); cit != mFeaturesCategoryMap.end(); ++cit)
127+
if ( ! mFeaturesCategoryMap.contains(catId) )
136128
{
137-
QgsMultiPolygon geom;
138-
geom.push_back( QgsPolygon() );
139-
140-
// build a rectangle out of the current extent
129+
// add the exterior ring
141130
QgsRectangle e = context.extent();
142131
// add some space to hide borders
143132
e.scale(2.0);
@@ -147,34 +136,54 @@ void QgsMaskRendererV2::stopRender( QgsRenderContext& context )
147136
extent_ring.push_back( QgsPoint(e.xMaximum(), e.yMaximum()) );
148137
extent_ring.push_back( QgsPoint(e.xMinimum(), e.yMaximum()) );
149138
extent_ring.push_back( QgsPoint(e.xMinimum(), e.yMinimum()) );
150-
geom[0].push_back( extent_ring );
139+
CombinedFeature cFeat;
140+
QgsPolygon exterior_ring_poly;
141+
exterior_ring_poly.append(extent_ring);
142+
cFeat.multiPolygon.append(exterior_ring_poly);
143+
// store the first feature
144+
cFeat.feature = feature;
145+
mFeaturesCategoryMap.insert( catId, cFeat );
146+
}
151147

152-
for ( QList<QgsFeature>::iterator fit = cit.value().begin(); fit != cit.value().end(); ++fit )
153-
{
154-
if ( ! fit->geometry() ) {
155-
continue;
156-
}
157-
QgsMultiPolygon multi;
158-
if ( (fit->geometry()->wkbType() == QGis::WKBPolygon) || (fit->geometry()->wkbType() == QGis::WKBPolygon25D) ) {
159-
multi.push_back( fit->geometry()->asPolygon() );
160-
}
161-
else if ( (fit->geometry()->wkbType() == QGis::WKBMultiPolygon) || (fit->geometry()->wkbType() == QGis::WKBMultiPolygon25D) ) {
162-
multi = fit->geometry()->asMultiPolygon();
163-
}
164-
for ( int i = 0; i < multi.size(); i++ ) {
165-
// add the exterior ring as interior ring
166-
geom[0].push_back( multi[i][0] );
167-
// add interior rings as new exterior rings
168-
for ( int j = 1; j < multi[i].size(); j++ ) {
169-
QgsPolygon new_poly;
170-
new_poly.push_back( multi[i][j] );
171-
geom.push_back( new_poly );
172-
}
173-
}
148+
// update the gometry
149+
CombinedFeature& cFeat = mFeaturesCategoryMap[catId];
150+
QgsMultiPolygon multi;
151+
QgsGeometry* geom = feature.geometry();
152+
if ( !geom )
153+
{
154+
return false;
155+
}
156+
if ( (geom->wkbType() == QGis::WKBPolygon) ||
157+
(geom->wkbType() == QGis::WKBPolygon25D) ) {
158+
multi.append(geom->asPolygon() );
159+
}
160+
else if ( (geom->wkbType() == QGis::WKBMultiPolygon) ||
161+
(geom->wkbType() == QGis::WKBMultiPolygon25D) ) {
162+
multi = geom->asMultiPolygon();
163+
}
164+
for ( int i = 0; i < multi.size(); i++ ) {
165+
// add the exterior ring as interior ring to the first polygon
166+
cFeat.multiPolygon[0].append( multi[i][0] );
167+
// add interior rings as new polygons
168+
for ( int j = 1; j < multi[i].size(); j++ ) {
169+
QgsPolygon new_poly;
170+
new_poly.append( multi[i][j] );
171+
cFeat.multiPolygon.append( new_poly );
174172
}
173+
}
174+
return true;
175+
}
176+
177+
void QgsMaskRendererV2::stopRender( QgsRenderContext& context )
178+
{
179+
if ( !mSubRenderer ) {
180+
return;
181+
}
175182

176-
QgsFeature feat( cit.value()[0] );
177-
feat.setGeometry( QgsGeometry::fromMultiPolygon( geom ) );
183+
for ( FeatureCategoryMap::iterator cit = mFeaturesCategoryMap.begin(); cit != mFeaturesCategoryMap.end(); ++cit)
184+
{
185+
QgsFeature feat( cit.value().feature );
186+
feat.setGeometry( QgsGeometry::fromMultiPolygon( cit.value().multiPolygon ) );
178187
mSubRenderer->renderFeature( feat, context );
179188
}
180189

@@ -184,9 +193,10 @@ void QgsMaskRendererV2::stopRender( QgsRenderContext& context )
184193
QgsRectangle e = context.extent();
185194
// add some space to hide borders
186195
e.scale(2.0);
196+
// empty feature with default attributes
187197
QgsFeature feat( mFields );
188198
feat.setGeometry( QgsGeometry::fromRect(e) );
189-
mSubRenderer->renderFeature( feat, context );
199+
mSubRenderer->renderFeature( feat, context );
190200
}
191201

192202
// draw feature decorations

src/core/symbology-ng/qgsmaskrendererv2.h

+8-1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "qgssymbolv2.h"
2121
#include "qgsexpression.h"
2222
#include "qgsfeature.h"
23+
#include "qgsgeometry.h"
2324
#include <QScopedPointer>
2425

2526
/**
@@ -112,7 +113,13 @@ class CORE_EXPORT QgsMaskRendererV2 : public QgsFeatureRendererV2
112113
/** Embedded renderer */
113114
QScopedPointer<QgsFeatureRendererV2> mSubRenderer;
114115

115-
typedef QMap< QByteArray, QList<QgsFeature> > FeatureCategoryMap;
116+
/** Structure where the reversed geometry is built during renderFeature */
117+
struct CombinedFeature
118+
{
119+
QgsMultiPolygon multiPolygon; //< the final combined geometry
120+
QgsFeature feature; //< one feature (for attriute-based rendering)
121+
};
122+
typedef QMap< QByteArray, CombinedFeature > FeatureCategoryMap;
116123
/** where features are stored, based on their symbol category */
117124
FeatureCategoryMap mFeaturesCategoryMap;
118125

0 commit comments

Comments
 (0)