Skip to content

Commit 315b28c

Browse files
author
Hugo Mercier
committed
Inverted polygon renderer: fix rendering when projection is enabled
1 parent 230c050 commit 315b28c

File tree

5 files changed

+52
-45
lines changed

5 files changed

+52
-45
lines changed

src/core/symbology-ng/qgsinvertedpolygonrenderer.cpp

+26-40
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,6 @@ void QgsInvertedPolygonRenderer::startRender( QgsRenderContext& context, const Q
6363
return;
6464
}
6565

66-
mSubRenderer->startRender( context, fields );
6766
mFeaturesCategoryMap.clear();
6867
mFeatureDecorations.clear();
6968
mFields = fields;
@@ -81,28 +80,36 @@ void QgsInvertedPolygonRenderer::startRender( QgsRenderContext& context, const Q
8180
// convert viewport to dest CRS
8281
QRect e( context.painter()->viewport() );
8382
// add some space to hide borders and tend to infinity
84-
e.adjust( -e.width()*10, -e.height()*10, e.width()*10, e.height()*10 );
83+
e.adjust( -e.width()*5, -e.height()*5, e.width()*5, e.height()*5 );
8584
QgsPolyline exteriorRing;
8685
exteriorRing << mtp.toMapCoordinates( e.topLeft() );
8786
exteriorRing << mtp.toMapCoordinates( e.topRight() );
8887
exteriorRing << mtp.toMapCoordinates( e.bottomRight() );
8988
exteriorRing << mtp.toMapCoordinates( e.bottomLeft() );
9089
exteriorRing << mtp.toMapCoordinates( e.topLeft() );
9190

92-
mTransform = context.coordinateTransform();
91+
// copy the rendering context
92+
mContext = context;
93+
9394
// If reprojection is enabled, we must reproject during renderFeature
9495
// and act as if there is no reprojection
9596
// If we don't do that, there is no need to have a simple rectangular extent
9697
// that covers the whole screen
9798
// (a rectangle in the destCRS cannot be expressed as valid coordinates in the sourceCRS in general)
98-
if (mTransform)
99+
if ( context.coordinateTransform() )
99100
{
100101
// disable projection
101-
context.setCoordinateTransform(0);
102+
mContext.setCoordinateTransform(0);
103+
// recompute extent so that polygon clipping is correct
104+
QRect v( context.painter()->viewport() );
105+
mContext.setExtent( QgsRectangle( mtp.toMapCoordinates( v.topLeft() ), mtp.toMapCoordinates( v.bottomRight() ) ) );
106+
// do we have to recompute the MapToPixel ?
102107
}
103108

104109
mExtentPolygon.clear();
105110
mExtentPolygon.append(exteriorRing);
111+
112+
mSubRenderer->startRender( mContext, fields );
106113
}
107114

108115
bool QgsInvertedPolygonRenderer::renderFeature( QgsFeature& feature, QgsRenderContext& context, int layer, bool selected, bool drawVertexMarker )
@@ -173,6 +180,13 @@ bool QgsInvertedPolygonRenderer::renderFeature( QgsFeature& feature, QgsRenderCo
173180
{
174181
return false;
175182
}
183+
184+
const QgsCoordinateTransform* xform = context.coordinateTransform();
185+
if ( xform )
186+
{
187+
geom->transform( *xform );
188+
}
189+
176190
if ( (geom->wkbType() == QGis::WKBPolygon) ||
177191
(geom->wkbType() == QGis::WKBPolygon25D) ) {
178192
multi.append(geom->asPolygon() );
@@ -215,34 +229,12 @@ bool QgsInvertedPolygonRenderer::renderFeature( QgsFeature& feature, QgsRenderCo
215229

216230
for ( int i = 0; i < multi.size(); i++ ) {
217231
// add the exterior ring as interior ring to the first polygon
218-
if ( mTransform ) {
219-
QgsPolyline new_ls;
220-
QgsPolyline& old_ls = multi[i][0];
221-
for ( int k = 0; k < old_ls.size(); k++ ) {
222-
new_ls.append( mTransform->transform( old_ls[k] ) );
223-
}
224-
cFeat.multiPolygon[0].append( new_ls );
225-
}
226-
else
227-
{
228-
cFeat.multiPolygon[0].append( multi[i][0] );
229-
}
232+
cFeat.multiPolygon[0].append( multi[i][0] );
233+
230234
// add interior rings as new polygons
231235
for ( int j = 1; j < multi[i].size(); j++ ) {
232236
QgsPolygon new_poly;
233-
if ( mTransform ) {
234-
QgsPolyline new_ls;
235-
QgsPolyline& old_ls = multi[i][j];
236-
for ( int k = 0; k < old_ls.size(); k++ ) {
237-
new_ls.append( mTransform->transform( old_ls[k] ) );
238-
}
239-
new_poly.append( new_ls );
240-
}
241-
else
242-
{
243-
new_poly.append( multi[i][j] );
244-
}
245-
237+
new_poly.append( multi[i][j] );
246238
cFeat.multiPolygon.append( new_poly );
247239
}
248240
}
@@ -281,7 +273,7 @@ void QgsInvertedPolygonRenderer::stopRender( QgsRenderContext& context )
281273
}
282274
}
283275
}
284-
mSubRenderer->renderFeature( feat, context );
276+
mSubRenderer->renderFeature( feat, mContext );
285277
}
286278

287279
// when no features are visible, we still have to draw the exterior rectangle
@@ -293,22 +285,16 @@ void QgsInvertedPolygonRenderer::stopRender( QgsRenderContext& context )
293285
// empty feature with default attributes
294286
QgsFeature feat( mFields );
295287
feat.setGeometry( QgsGeometry::fromPolygon( mExtentPolygon ) );
296-
mSubRenderer->renderFeature( feat, context );
288+
mSubRenderer->renderFeature( feat, mContext );
297289
}
298290

299291
// draw feature decorations
300292
foreach (FeatureDecoration deco, mFeatureDecorations )
301293
{
302-
mSubRenderer->renderFeature( deco.feature, context, deco.layer, deco.selected, deco.drawMarkers );
294+
mSubRenderer->renderFeature( deco.feature, mContext, deco.layer, deco.selected, deco.drawMarkers );
303295
}
304296

305-
mSubRenderer->stopRender( context );
306-
307-
if ( mTransform )
308-
{
309-
// restore the coordinate transform if needed
310-
context.setCoordinateTransform( mTransform );
311-
}
297+
mSubRenderer->stopRender( mContext );
312298
}
313299

314300
QString QgsInvertedPolygonRenderer::dump() const

src/core/symbology-ng/qgsinvertedpolygonrenderer.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -139,8 +139,8 @@ class CORE_EXPORT QgsInvertedPolygonRenderer : public QgsFeatureRendererV2
139139
/** the polygon used as exterior ring that covers the current extent */
140140
QgsPolygon mExtentPolygon;
141141

142-
/** the current coordinate transform (or null) */
143-
const QgsCoordinateTransform* mTransform;
142+
/** the context used for rendering */
143+
QgsRenderContext mContext;
144144

145145
/** fields of each feature*/
146146
QgsFields mFields;

tests/src/core/testqgsinvertedpolygonrenderer.cpp

+24-3
Original file line numberDiff line numberDiff line change
@@ -48,11 +48,12 @@ class TestQgsInvertedPolygon: public QObject
4848
void singleSubRenderer();
4949
void graduatedSubRenderer();
5050
void preprocess();
51+
void projectionTest();
5152

5253
private:
5354
bool mTestHasError;
5455
bool setQml( QString qmlFile );
55-
bool imageCheck( QString theType );
56+
bool imageCheck( QString theType, const QgsRectangle* = 0 );
5657
QgsMapSettings mMapSettings;
5758
QgsVectorLayer * mpPolysLayer;
5859
QString mTestDataDir;
@@ -124,6 +125,19 @@ void TestQgsInvertedPolygon::preprocess()
124125
QVERIFY( imageCheck( "inverted_polys_preprocess" ) );
125126
}
126127

128+
//-8639421,8382691 : -3969110,12570905
129+
void TestQgsInvertedPolygon::projectionTest()
130+
{
131+
// FIXME will have to find some overlapping polygons
132+
mReport += "<h2>Inverted polygon renderer, projection test</h2>\n";
133+
mMapSettings.setDestinationCrs( QgsCoordinateReferenceSystem("EPSG:2154") );
134+
mMapSettings.setCrsTransformEnabled( true );
135+
QgsRectangle extent( QgsPoint(-8639421,8382691), QgsPoint(-3969110,12570905) );
136+
QVERIFY( setQml( "inverted_polys_single.qml" ) );
137+
QVERIFY( imageCheck( "inverted_polys_projection", &extent ) );
138+
mMapSettings.setCrsTransformEnabled( false );
139+
}
140+
127141
//
128142
// Private helper functions not called directly by CTest
129143
//
@@ -144,11 +158,18 @@ bool TestQgsInvertedPolygon::setQml( QString qmlFile )
144158
return myStyleFlag;
145159
}
146160

147-
bool TestQgsInvertedPolygon::imageCheck( QString theTestType )
161+
bool TestQgsInvertedPolygon::imageCheck( QString theTestType, const QgsRectangle* extent )
148162
{
149163
//use the QgsRenderChecker test utility class to
150164
//ensure the rendered output matches our control image
151-
mMapSettings.setExtent( mpPolysLayer->extent() );
165+
if ( !extent )
166+
{
167+
mMapSettings.setExtent( mpPolysLayer->extent() );
168+
}
169+
else
170+
{
171+
mMapSettings.setExtent( *extent );
172+
}
152173
QgsRenderChecker myChecker;
153174
myChecker.setControlName( "expected_" + theTestType );
154175
myChecker.setMapSettings( mMapSettings );

0 commit comments

Comments
 (0)