Skip to content
Permalink
Browse files

[composer] Use intersection rather than clip for transformed grids

Previous behaviour was to clip transformed grid lines to the visible
map extent. This caused problems if a map item had no border (a
solid line would be shown along the map extent), and also meant
that reprojected lines which crossed out of the map extent and back
in again did not have annotations or grid frame markings shown.

Also implement an improved logic for detecting the map frame side
for annotations.
  • Loading branch information
nyalldawson committed Nov 6, 2014
1 parent abf0087 commit b2423241ff0135487371b218b52b157fca7a3bec
@@ -1615,11 +1615,15 @@ int QgsComposerMapGrid::xGridLinesCRSTransform( const QgsRectangle& bbox, const
}
crossed180 = false;

gridLine = trimLineToMap( gridLine, QgsRectangle( mComposerMap->rect() ) );
if ( gridLine.size() > 0 )
QList<QPolygonF> lineSegments = trimLinesToMap( gridLine, QgsRectangle( mComposerMap->rect() ) );
QList<QPolygonF>::const_iterator lineIt = lineSegments.constBegin();
for ( ; lineIt != lineSegments.constEnd(); lineIt ++ )
{
lines.append( qMakePair( currentLevel, gridLine ) );
gridLineCount++;
if (( *lineIt ).size() > 0 )
{
lines.append( qMakePair( currentLevel, *lineIt ) );
gridLineCount++;
}
}
currentLevel -= mGridIntervalY;
}
@@ -1677,11 +1681,15 @@ int QgsComposerMapGrid::yGridLinesCRSTransform( const QgsRectangle& bbox, const
currentY += step;
}
//clip grid line to map polygon
gridLine = trimLineToMap( gridLine, QgsRectangle( mComposerMap->rect() ) );
if ( gridLine.size() > 0 )
QList<QPolygonF> lineSegments = trimLinesToMap( gridLine, QgsRectangle( mComposerMap->rect() ) );
QList<QPolygonF>::const_iterator lineIt = lineSegments.constBegin();
for ( ; lineIt != lineSegments.constEnd(); lineIt ++ )
{
lines.append( qMakePair( currentLevel, gridLine ) );
gridLineCount++;
if (( *lineIt ).size() > 0 )
{
lines.append( qMakePair( currentLevel, *lineIt ) );
gridLineCount++;
}
}
currentLevel += mGridIntervalX;
if ( crosses180 && currentLevel > 180.0 )
@@ -1775,26 +1783,31 @@ bool QgsComposerMapGrid::shouldShowDivisionForDisplayMode( const QgsComposerMapG
|| ( mode == QgsComposerMapGrid::LongitudeOnly && coordinate == QgsComposerMapGrid::Longitude );
}

bool sortByDistance( const QPair<double, QgsComposerMapGrid::BorderSide>& a, const QPair<double, QgsComposerMapGrid::BorderSide>& b )
{
return a.first < b.first;
}

QgsComposerMapGrid::BorderSide QgsComposerMapGrid::borderForLineCoord( const QPointF& p, const AnnotationCoordinate coordinateType ) const
{
if ( !mComposerMap )
{
return QgsComposerMapGrid::Left;
}

double framePenWidth = mComposerMap->hasFrame() ? mComposerMap->pen().widthF() : 0.000000001;
double tolerance = qMax( mComposerMap->hasFrame() ? mComposerMap->pen().widthF() : 0.0, 1.0 );

//check for corner coordinates
if (( p.y() <= framePenWidth && p.x() <= framePenWidth ) // top left
|| ( p.y() <= framePenWidth && p.x() >= ( mComposerMap->rect().width() - framePenWidth ) ) //top right
|| ( p.y() >= ( mComposerMap->rect().height() - framePenWidth ) && p.x() <= framePenWidth ) //bottom left
|| ( p.y() >= ( mComposerMap->rect().height() - framePenWidth ) && p.x() >= ( mComposerMap->rect().width() - framePenWidth ) ) //bottom right
if (( p.y() <= tolerance && p.x() <= tolerance ) // top left
|| ( p.y() <= tolerance && p.x() >= ( mComposerMap->rect().width() - tolerance ) ) //top right
|| ( p.y() >= ( mComposerMap->rect().height() - tolerance ) && p.x() <= tolerance ) //bottom left
|| ( p.y() >= ( mComposerMap->rect().height() - tolerance ) && p.x() >= ( mComposerMap->rect().width() - tolerance ) ) //bottom right
)
{
//coordinate is in corner - fall back to preferred side for coordinate type
if ( coordinateType == QgsComposerMapGrid::Latitude )
{
if ( p.x() <= framePenWidth )
if ( p.x() <= tolerance )
{
return QgsComposerMapGrid::Left;
}
@@ -1805,7 +1818,7 @@ QgsComposerMapGrid::BorderSide QgsComposerMapGrid::borderForLineCoord( const QPo
}
else
{
if ( p.y() <= framePenWidth )
if ( p.y() <= tolerance )
{
return QgsComposerMapGrid::Top;
}
@@ -1816,23 +1829,15 @@ QgsComposerMapGrid::BorderSide QgsComposerMapGrid::borderForLineCoord( const QPo
}
}

//otherwise, guess side based on point
if ( p.y() <= framePenWidth )
{
return QgsComposerMapGrid::Top;
}
else if ( p.x() <= framePenWidth )
{
return QgsComposerMapGrid::Left;
}
else if ( p.x() >= ( mComposerMap->rect().width() - framePenWidth ) )
{
return QgsComposerMapGrid::Right;
}
else
{
return QgsComposerMapGrid::Bottom;
}
//otherwise, guess side based on closest map side to point
QList< QPair<double, QgsComposerMapGrid::BorderSide > > distanceToSide;
distanceToSide << qMakePair( p.x(), QgsComposerMapGrid::Left );
distanceToSide << qMakePair( mComposerMap->rect().width() - p.x(), QgsComposerMapGrid::Right );
distanceToSide << qMakePair( p.y(), QgsComposerMapGrid::Top );
distanceToSide << qMakePair( mComposerMap->rect().height() - p.y(), QgsComposerMapGrid::Bottom );

qSort( distanceToSide.begin(), distanceToSide.end(), sortByDistance );
return distanceToSide.at( 0 ).second;
}

void QgsComposerMapGrid::setLineSymbol( QgsLineSymbolV2* symbol )
@@ -2268,21 +2273,25 @@ int QgsComposerMapGrid::crsGridParams( QgsRectangle& crsRect, QgsCoordinateTrans
return 0;
}

QPolygonF QgsComposerMapGrid::trimLineToMap( const QPolygonF& line, const QgsRectangle& rect )
QList<QPolygonF> QgsComposerMapGrid::trimLinesToMap( const QPolygonF& line, const QgsRectangle& rect )
{
QgsPolyline polyLine;
QPolygonF::const_iterator lineIt = line.constBegin();
for ( ; lineIt != line.constEnd(); ++lineIt )
QgsGeometry* lineGeom = QgsGeometry::fromQPolygonF( line );
QgsGeometry* rectGeom = QgsGeometry::fromRect( rect );

QgsGeometry* intersected = lineGeom->intersection( rectGeom );
QList<QgsGeometry*> intersectedParts = intersected->asGeometryCollection();

QList<QPolygonF> trimmedLines;
QList<QgsGeometry*>::const_iterator geomIt = intersectedParts.constBegin();
for ( ; geomIt != intersectedParts.constEnd(); geomIt++ )
{
polyLine.append( QgsPoint( lineIt->x(), lineIt->y() ) );
trimmedLines << ( *geomIt )->asQPolygonF();
}

QgsGeometry* geom = QgsGeometry::fromPolyline( polyLine );

QPolygonF clippedLine;
QgsClipper::clippedLineWKB( geom->asWkb(), rect, clippedLine );
delete geom;
return clippedLine;
qDeleteAll( intersectedParts );
intersectedParts.clear();
delete intersected;
delete lineGeom;
delete rectGeom;
return trimmedLines;
}


@@ -931,7 +931,7 @@ class CORE_EXPORT QgsComposerMapGrid : public QgsComposerMapItem
/**Get parameters for drawing grid in CRS different to map CRS*/
int crsGridParams( QgsRectangle& crsRect, QgsCoordinateTransform& inverseTransform ) const;

static QPolygonF trimLineToMap( const QPolygonF& line, const QgsRectangle& rect );
static QList<QPolygonF> trimLinesToMap( const QPolygonF &line, const QgsRectangle &rect );

QPolygonF scalePolygon( const QPolygonF &polygon, const double scale ) const;

@@ -35,6 +35,7 @@ class TestQgsComposerMapGrid: public QObject
void init();// will be called before each testfunction is executed.
void cleanup();// will be called after every testfunction.
void grid(); //test if grid and grid annotation works
void reprojected(); //test if reprojected grid works
void crossGrid(); //test if grid "cross" mode works
void markerGrid(); //test if grid "marker" mode works
void frameOnly(); //test if grid "frame/annotation" mode works
@@ -128,6 +129,31 @@ void TestQgsComposerMapGrid::grid()
QVERIFY( testResult );
}

void TestQgsComposerMapGrid::reprojected()
{
mComposerMap->setNewExtent( QgsRectangle( -243577.565, 2939084.773, 1215622.435, 3668684.773 ) );
QgsCoordinateReferenceSystem geographic = QgsCoordinateReferenceSystem( 4326 );
mComposerMap->grid()->setCrs( geographic );
mComposerMap->grid()->setEnabled( true );
mComposerMap->grid()->setIntervalX( 1 );
mComposerMap->grid()->setIntervalY( 1 );
mComposerMap->grid()->setAnnotationEnabled( false );
mComposerMap->grid()->setGridLineColor( QColor( 0, 0, 0 ) );
mComposerMap->grid()->setGridLineWidth( 0.5 );
mComposerMap->grid()->setBlendMode( QPainter::CompositionMode_SourceOver );
mComposerMap->grid()->setFrameStyle( QgsComposerMapGrid::ExteriorTicks );
mComposerMap->grid()->setFrameWidth( 10 );
mComposerMap->setFrameEnabled( false );
QgsCompositionChecker checker( "composermap_gridreprojected", mComposition );

bool testResult = checker.testComposition( mReport, 0, 0 );
mComposerMap->grid()->setEnabled( false );
mComposerMap->grid()->setCrs( mMapSettings.destinationCrs() );
mComposerMap->grid()->setFrameStyle( QgsComposerMapGrid::NoFrame );
mComposerMap->setFrameEnabled( true );
QVERIFY( testResult );
}

void TestQgsComposerMapGrid::crossGrid()
{
mComposerMap->setNewExtent( QgsRectangle( 781662.375, 3339523.125, 793062.375, 3345223.125 ) );
@@ -177,6 +203,7 @@ void TestQgsComposerMapGrid::frameOnly()
mComposerMap->grid()->setAnnotationEnabled( false );
//set a frame for testing
mComposerMap->grid()->setFrameStyle( QgsComposerMapGrid::Zebra );
mComposerMap->grid()->setFrameWidth( 2.0 );
mComposerMap->grid()->setFramePenSize( 0.5 );
mComposerMap->grid()->setBlendMode( QPainter::CompositionMode_SourceOver );
QgsCompositionChecker checker( "composermap_gridframeonly", mComposition );
Binary file not shown.

0 comments on commit b242324

Please sign in to comment.
You can’t perform that action at this time.