Skip to content

Commit

Permalink
Inverted polygon renderer: fix rendering when projection is enabled
Browse files Browse the repository at this point in the history
  • Loading branch information
Hugo Mercier committed May 26, 2014
1 parent 230c050 commit 315b28c
Show file tree
Hide file tree
Showing 5 changed files with 52 additions and 45 deletions.
66 changes: 26 additions & 40 deletions src/core/symbology-ng/qgsinvertedpolygonrenderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,6 @@ void QgsInvertedPolygonRenderer::startRender( QgsRenderContext& context, const Q
return;
}

mSubRenderer->startRender( context, fields );
mFeaturesCategoryMap.clear();
mFeatureDecorations.clear();
mFields = fields;
Expand All @@ -81,28 +80,36 @@ void QgsInvertedPolygonRenderer::startRender( QgsRenderContext& context, const Q
// convert viewport to dest CRS
QRect e( context.painter()->viewport() );
// add some space to hide borders and tend to infinity
e.adjust( -e.width()*10, -e.height()*10, e.width()*10, e.height()*10 );
e.adjust( -e.width()*5, -e.height()*5, e.width()*5, e.height()*5 );
QgsPolyline exteriorRing;
exteriorRing << mtp.toMapCoordinates( e.topLeft() );
exteriorRing << mtp.toMapCoordinates( e.topRight() );
exteriorRing << mtp.toMapCoordinates( e.bottomRight() );
exteriorRing << mtp.toMapCoordinates( e.bottomLeft() );
exteriorRing << mtp.toMapCoordinates( e.topLeft() );

mTransform = context.coordinateTransform();
// copy the rendering context
mContext = context;

// If reprojection is enabled, we must reproject during renderFeature
// and act as if there is no reprojection
// If we don't do that, there is no need to have a simple rectangular extent
// that covers the whole screen
// (a rectangle in the destCRS cannot be expressed as valid coordinates in the sourceCRS in general)
if (mTransform)
if ( context.coordinateTransform() )
{
// disable projection
context.setCoordinateTransform(0);
mContext.setCoordinateTransform(0);
// recompute extent so that polygon clipping is correct
QRect v( context.painter()->viewport() );
mContext.setExtent( QgsRectangle( mtp.toMapCoordinates( v.topLeft() ), mtp.toMapCoordinates( v.bottomRight() ) ) );
// do we have to recompute the MapToPixel ?
}

mExtentPolygon.clear();
mExtentPolygon.append(exteriorRing);

mSubRenderer->startRender( mContext, fields );
}

bool QgsInvertedPolygonRenderer::renderFeature( QgsFeature& feature, QgsRenderContext& context, int layer, bool selected, bool drawVertexMarker )
Expand Down Expand Up @@ -173,6 +180,13 @@ bool QgsInvertedPolygonRenderer::renderFeature( QgsFeature& feature, QgsRenderCo
{
return false;
}

const QgsCoordinateTransform* xform = context.coordinateTransform();
if ( xform )
{
geom->transform( *xform );
}

if ( (geom->wkbType() == QGis::WKBPolygon) ||
(geom->wkbType() == QGis::WKBPolygon25D) ) {
multi.append(geom->asPolygon() );
Expand Down Expand Up @@ -215,34 +229,12 @@ bool QgsInvertedPolygonRenderer::renderFeature( QgsFeature& feature, QgsRenderCo

for ( int i = 0; i < multi.size(); i++ ) {
// add the exterior ring as interior ring to the first polygon
if ( mTransform ) {
QgsPolyline new_ls;
QgsPolyline& old_ls = multi[i][0];
for ( int k = 0; k < old_ls.size(); k++ ) {
new_ls.append( mTransform->transform( old_ls[k] ) );
}
cFeat.multiPolygon[0].append( new_ls );
}
else
{
cFeat.multiPolygon[0].append( multi[i][0] );
}
cFeat.multiPolygon[0].append( multi[i][0] );

// add interior rings as new polygons
for ( int j = 1; j < multi[i].size(); j++ ) {
QgsPolygon new_poly;
if ( mTransform ) {
QgsPolyline new_ls;
QgsPolyline& old_ls = multi[i][j];
for ( int k = 0; k < old_ls.size(); k++ ) {
new_ls.append( mTransform->transform( old_ls[k] ) );
}
new_poly.append( new_ls );
}
else
{
new_poly.append( multi[i][j] );
}

new_poly.append( multi[i][j] );
cFeat.multiPolygon.append( new_poly );
}
}
Expand Down Expand Up @@ -281,7 +273,7 @@ void QgsInvertedPolygonRenderer::stopRender( QgsRenderContext& context )
}
}
}
mSubRenderer->renderFeature( feat, context );
mSubRenderer->renderFeature( feat, mContext );
}

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

// draw feature decorations
foreach (FeatureDecoration deco, mFeatureDecorations )
{
mSubRenderer->renderFeature( deco.feature, context, deco.layer, deco.selected, deco.drawMarkers );
mSubRenderer->renderFeature( deco.feature, mContext, deco.layer, deco.selected, deco.drawMarkers );
}

mSubRenderer->stopRender( context );

if ( mTransform )
{
// restore the coordinate transform if needed
context.setCoordinateTransform( mTransform );
}
mSubRenderer->stopRender( mContext );
}

QString QgsInvertedPolygonRenderer::dump() const
Expand Down
4 changes: 2 additions & 2 deletions src/core/symbology-ng/qgsinvertedpolygonrenderer.h
Original file line number Diff line number Diff line change
Expand Up @@ -139,8 +139,8 @@ class CORE_EXPORT QgsInvertedPolygonRenderer : public QgsFeatureRendererV2
/** the polygon used as exterior ring that covers the current extent */
QgsPolygon mExtentPolygon;

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

/** fields of each feature*/
QgsFields mFields;
Expand Down
27 changes: 24 additions & 3 deletions tests/src/core/testqgsinvertedpolygonrenderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,12 @@ class TestQgsInvertedPolygon: public QObject
void singleSubRenderer();
void graduatedSubRenderer();
void preprocess();
void projectionTest();

private:
bool mTestHasError;
bool setQml( QString qmlFile );
bool imageCheck( QString theType );
bool imageCheck( QString theType, const QgsRectangle* = 0 );
QgsMapSettings mMapSettings;
QgsVectorLayer * mpPolysLayer;
QString mTestDataDir;
Expand Down Expand Up @@ -124,6 +125,19 @@ void TestQgsInvertedPolygon::preprocess()
QVERIFY( imageCheck( "inverted_polys_preprocess" ) );
}

//-8639421,8382691 : -3969110,12570905
void TestQgsInvertedPolygon::projectionTest()
{
// FIXME will have to find some overlapping polygons
mReport += "<h2>Inverted polygon renderer, projection test</h2>\n";
mMapSettings.setDestinationCrs( QgsCoordinateReferenceSystem("EPSG:2154") );
mMapSettings.setCrsTransformEnabled( true );
QgsRectangle extent( QgsPoint(-8639421,8382691), QgsPoint(-3969110,12570905) );
QVERIFY( setQml( "inverted_polys_single.qml" ) );
QVERIFY( imageCheck( "inverted_polys_projection", &extent ) );
mMapSettings.setCrsTransformEnabled( false );
}

//
// Private helper functions not called directly by CTest
//
Expand All @@ -144,11 +158,18 @@ bool TestQgsInvertedPolygon::setQml( QString qmlFile )
return myStyleFlag;
}

bool TestQgsInvertedPolygon::imageCheck( QString theTestType )
bool TestQgsInvertedPolygon::imageCheck( QString theTestType, const QgsRectangle* extent )
{
//use the QgsRenderChecker test utility class to
//ensure the rendered output matches our control image
mMapSettings.setExtent( mpPolysLayer->extent() );
if ( !extent )
{
mMapSettings.setExtent( mpPolysLayer->extent() );
}
else
{
mMapSettings.setExtent( *extent );
}
QgsRenderChecker myChecker;
myChecker.setControlName( "expected_" + theTestType );
myChecker.setMapSettings( mMapSettings );
Expand Down
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 315b28c

Please sign in to comment.