Skip to content

Commit

Permalink
Add API to handle non-rectangular georeferenced regions in geopdf pages
Browse files Browse the repository at this point in the history
  • Loading branch information
nyalldawson committed Aug 20, 2019
1 parent 417f8d9 commit edf81aa
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 25 deletions.
51 changes: 27 additions & 24 deletions src/core/qgsabstractgeopdfexporter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -369,30 +369,33 @@ QString QgsAbstractGeoPdfExporter::createCompositionXml( const QList<ComponentLa
georeferencing.appendChild( srs );
}

/* Define the viewport where georeferenced coordinates are available.
If not specified, the extent of BoundingPolygon will be used instead.
If none of BoundingBox and BoundingPolygon are specified,
the whole PDF page will be assumed to be georeferenced.
*/
QDomElement boundingBox = doc.createElement( QStringLiteral( "BoundingBox" ) );
boundingBox.setAttribute( QStringLiteral( "x1" ), QString::number( section.pageBoundsMm.xMinimum() / 25.4 * 72 ) );
boundingBox.setAttribute( QStringLiteral( "y1" ), QString::number( section.pageBoundsMm.yMinimum() / 25.4 * 72 ) );
boundingBox.setAttribute( QStringLiteral( "x2" ), QString::number( section.pageBoundsMm.xMaximum() / 25.4 * 72 ) );
boundingBox.setAttribute( QStringLiteral( "y2" ), QString::number( section.pageBoundsMm.yMaximum() / 25.4 * 72 ) );
georeferencing.appendChild( boundingBox );

#if 0
/*
Define a polygon / neatline in PDF units into which the
Measure tool will display coordinates.
If not specified, BoundingBox will be used instead.
If none of BoundingBox and BoundingPolygon are specified,
the whole PDF page will be assumed to be georeferenced.
*/
QDomElement boundingPolygon = doc.createElement( QStringLiteral( "BoundingPolygon" ) );
boundingPolygon.appendChild( doc.createTextNode( QStringLiteral( "POLYGON((1 1,9 1,9 14,1 14,1 1))" ) ) );
georeferencing.appendChild( boundingPolygon );
#endif
if ( !section.pageBoundsPolygon.isEmpty() )
{
/*
Define a polygon / neatline in PDF units into which the
Measure tool will display coordinates.
If not specified, BoundingBox will be used instead.
If none of BoundingBox and BoundingPolygon are specified,
the whole PDF page will be assumed to be georeferenced.
*/
QDomElement boundingPolygon = doc.createElement( QStringLiteral( "BoundingPolygon" ) );
boundingPolygon.appendChild( doc.createTextNode( section.pageBoundsPolygon.asWkt() ) );
georeferencing.appendChild( boundingPolygon );
}
else
{
/* Define the viewport where georeferenced coordinates are available.
If not specified, the extent of BoundingPolygon will be used instead.
If none of BoundingBox and BoundingPolygon are specified,
the whole PDF page will be assumed to be georeferenced.
*/
QDomElement boundingBox = doc.createElement( QStringLiteral( "BoundingBox" ) );
boundingBox.setAttribute( QStringLiteral( "x1" ), QString::number( section.pageBoundsMm.xMinimum() / 25.4 * 72 ) );
boundingBox.setAttribute( QStringLiteral( "y1" ), QString::number( section.pageBoundsMm.yMinimum() / 25.4 * 72 ) );
boundingBox.setAttribute( QStringLiteral( "x2" ), QString::number( section.pageBoundsMm.xMaximum() / 25.4 * 72 ) );
boundingBox.setAttribute( QStringLiteral( "y2" ), QString::number( section.pageBoundsMm.yMaximum() / 25.4 * 72 ) );
georeferencing.appendChild( boundingBox );
}

for ( const ControlPoint &point : section.controlPoints )
{
Expand Down
15 changes: 14 additions & 1 deletion src/core/qgsabstractgeopdfexporter.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include <QDateTime>
#include "qgsfeature.h"
#include "qgsabstractmetadatabase.h"
#include "qgspolygon.h"

#define SIP_NO_FILE

Expand Down Expand Up @@ -153,9 +154,21 @@ class CORE_EXPORT QgsAbstractGeoPdfExporter

struct GeoReferencedSection
{
//! Bounds of the georeferenced section on the page, in millimeters

/**
* Bounds of the georeferenced section on the page, in millimeters.
*
* \note if pageBoundsPolygon is specified then this setting is ignored.
*/
QgsRectangle pageBoundsMm;

/**
* Bounds of the georeferenced section on the page, in millimeters, as a free-form polygon.
*
* If specified, this will be used instead of pageBoundsMm.
*/
QgsPolygon pageBoundsPolygon;

//! Coordinate reference system for georeferenced section
QgsCoordinateReferenceSystem crs;

Expand Down
46 changes: 46 additions & 0 deletions tests/src/core/testqgsgeopdfexport.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ class TestQgsGeoPdfExport : public QObject
void testComposition();
void testMetadata();
void testGeoref();
void testGeorefPolygon();
void testGroups();

private:
Expand Down Expand Up @@ -352,6 +353,51 @@ void TestQgsGeoPdfExport::testGeoref()
QCOMPARE( cp1.attribute( QStringLiteral( "y" ) ), QStringLiteral( "-2.83465" ) );
}

void TestQgsGeoPdfExport::testGeorefPolygon()
{
// test georeferencing a region using polygon bounds
TestGeoPdfExporter geoPdfExporter;

QList< QgsAbstractGeoPdfExporter::ComponentLayerDetail > renderedLayers;
QgsAbstractGeoPdfExporter::ExportDetails details;

// with points
QgsAbstractGeoPdfExporter::GeoReferencedSection section;
section.crs = QgsCoordinateReferenceSystem( QStringLiteral( "EPSG:4283" ) );
section.pageBoundsMm = QgsRectangle( 0, 0, 253.2, 222.25 );
QgsPolygon p;
p.fromWkt( QStringLiteral( "Polygon((30 5, 250 15, 240 200, 50 190, 30 5))" ) );
section.pageBoundsPolygon = p;
section.controlPoints.append( QgsAbstractGeoPdfExporter::ControlPoint( QgsPointXY( 0, 0 ), QgsPointXY( -122.4, 53.6 ) ) );
section.controlPoints.append( QgsAbstractGeoPdfExporter::ControlPoint( QgsPointXY( 253.2, 0 ), QgsPointXY( -78, 53.6 ) ) );
section.controlPoints.append( QgsAbstractGeoPdfExporter::ControlPoint( QgsPointXY( 253.2, 222.25 ), QgsPointXY( -78, 14.6 ) ) );
section.controlPoints.append( QgsAbstractGeoPdfExporter::ControlPoint( QgsPointXY( 0, 222.25 ), QgsPointXY( -122.4, 14.6 ) ) );
details.georeferencedSections << section;

QString composition = geoPdfExporter.createCompositionXml( renderedLayers, details );
QgsDebugMsg( composition );
QDomDocument doc;
doc.setContent( composition );
QCOMPARE( doc.elementsByTagName( QStringLiteral( "SRS" ) ).at( 0 ).toElement().text(), QStringLiteral( "EPSG:4283" ) );
QCOMPARE( doc.elementsByTagName( QStringLiteral( "BoundingPolygon" ) ).at( 0 ).toElement().text(), QStringLiteral( "Polygon ((30 5, 250 15, 240 200, 50 190, 30 5))" ) );

QDomNodeList cps = doc.elementsByTagName( QStringLiteral( "ControlPoint" ) );
QCOMPARE( cps.count(), 4 );
QDomElement cp1;
for ( int i = 0; i < 4; ++i )
{
if ( cps.at( i ).toElement().attribute( QStringLiteral( "GeoX" ) ) == QStringLiteral( "-122.4" )
&& cps.at( i ).toElement().attribute( QStringLiteral( "GeoY" ) ) == QStringLiteral( "53.6" ) )
{
cp1 = cps.at( i ).toElement();
break;
}
}
QVERIFY( !cp1.isNull() );
QCOMPARE( cp1.attribute( QStringLiteral( "x" ) ), QStringLiteral( "0" ) );
QCOMPARE( cp1.attribute( QStringLiteral( "y" ) ), QStringLiteral( "-2.83465" ) );
}

void TestQgsGeoPdfExport::testGroups()
{
TestGeoPdfExporter geoPdfExporter;
Expand Down

0 comments on commit edf81aa

Please sign in to comment.