Skip to content
Permalink
Browse files
Inverted polygon renderer: fix rendering when projection is enabled
  • Loading branch information
Hugo Mercier committed May 26, 2014
1 parent 230c050 commit 315b28c21c4a591f418435de47d81469c8046ec7
@@ -63,7 +63,6 @@ void QgsInvertedPolygonRenderer::startRender( QgsRenderContext& context, const Q
return;
}

mSubRenderer->startRender( context, fields );
mFeaturesCategoryMap.clear();
mFeatureDecorations.clear();
mFields = fields;
@@ -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 )
@@ -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() );
@@ -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 );
}
}
@@ -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
@@ -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
@@ -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;
@@ -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;
@@ -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
//
@@ -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 );
Binary file not shown.
Binary file not shown.

0 comments on commit 315b28c

Please sign in to comment.