Skip to content
Permalink
Browse files

[FEATURE][composer] Allow choice of CRS for map items

This allows the CRS for map items to differ from the canvas/project
CRS. It also allows different map items to have different CRS,
eg an overview map can be set to a different CRS to the main map.

An unfortunate side effect of this change and the ongoing work
to separate compositions from canvas is that datum transforms
are no longer supported in composer. This cannot be fixed until
the datum transform store is rewritten to not depend on canvas
(ie, it's also broken for upcoming multi-canvas work)
  • Loading branch information
nyalldawson committed Jan 17, 2017
1 parent 305f9f0 commit 9a6d714061fcd40217ca52e68f307e0a4ea26a47
@@ -128,6 +128,7 @@ class QgsComposerMap : QgsComposerItem
// QgsRectangle* currentMapExtent();

QgsCoordinateReferenceSystem crs() const;
void setCrs( const QgsCoordinateReferenceSystem& crs );

PreviewMode previewMode() const;
void setPreviewMode( PreviewMode m );
@@ -37,6 +37,7 @@
#include "qgsmapthemecollection.h"
#include "qgsmapthemes.h"
#include "qgisgui.h"
#include "qgscsexception.h"

#include <QMessageBox>

@@ -99,6 +100,8 @@ QgsComposerMapWidget::QgsComposerMapWidget( QgsComposerMap* composerMap )
connect( mOverviewFrameMapComboBox, SIGNAL( itemChanged( QgsComposerItem* ) ), this, SLOT( overviewMapChanged( QgsComposerItem* ) ) );
}

connect( mCrsSelector, &QgsProjectionSelectionWidget::crsChanged, this, &QgsComposerMapWidget::mapCrsChanged );

updateGuiElements();
loadGridEntries();
loadOverviewEntries();
@@ -260,6 +263,42 @@ void QgsComposerMapWidget::cleanUpOverviewFrameStyleSelector( QgsPanelWidget* co
mComposerMap->endCommand();
}

void QgsComposerMapWidget::mapCrsChanged( const QgsCoordinateReferenceSystem& crs )
{
if ( !mComposerMap )
{
return;
}

if ( mComposerMap->crs() == crs )
return;

// try to reproject to maintain extent
QgsCoordinateReferenceSystem oldCrs = mComposerMap->crs();

bool updateExtent = false;
QgsRectangle newExtent;
try
{
QgsCoordinateTransform xForm( oldCrs, crs );
QgsRectangle prevExtent = *mComposerMap->currentMapExtent();
newExtent = xForm.transformBoundingBox( prevExtent );
updateExtent = true;
}
catch ( QgsCsException & )
{
//transform failed, don't update extent
}

mComposerMap->beginCommand( tr( "Map CRS changed" ) );
mComposerMap->setCrs( crs );
if ( updateExtent )
mComposerMap->zoomToExtent( newExtent );
mComposerMap->endCommand();
mComposerMap->cache();
mComposerMap->update();
}

void QgsComposerMapWidget::on_mAtlasCheckBox_toggled( bool checked )
{
if ( !mComposerMap )
@@ -471,6 +510,23 @@ void QgsComposerMapWidget::on_mSetToMapCanvasExtentButton_clicked()

QgsRectangle newExtent = QgisApp::instance()->mapCanvas()->mapSettings().visibleExtent();

//transform?
if ( QgisApp::instance()->mapCanvas()->mapSettings().destinationCrs()
!= mComposerMap->crs() )
{
try
{
QgsCoordinateTransform xForm( QgisApp::instance()->mapCanvas()->mapSettings().destinationCrs(),
mComposerMap->crs() );
newExtent = xForm.transformBoundingBox( newExtent );
}
catch ( QgsCsException & )
{
//transform failed, better not proceed
return;
}
}

mComposerMap->beginCommand( tr( "Map extent changed" ) );
mComposerMap->zoomToExtent( newExtent );
mComposerMap->endCommand();
@@ -487,6 +543,23 @@ void QgsComposerMapWidget::on_mViewExtentInCanvasButton_clicked()

if ( !currentMapExtent.isEmpty() )
{
//transform?
if ( QgisApp::instance()->mapCanvas()->mapSettings().destinationCrs()
!= mComposerMap->crs() )
{
try
{
QgsCoordinateTransform xForm( mComposerMap->crs(),
QgisApp::instance()->mapCanvas()->mapSettings().destinationCrs() );
currentMapExtent = xForm.transformBoundingBox( currentMapExtent );
}
catch ( QgsCsException & )
{
//transform failed, better not proceed
return;
}
}

QgisApp::instance()->mapCanvas()->setExtent( currentMapExtent );
QgisApp::instance()->mapCanvas()->refresh();
}
@@ -532,6 +605,8 @@ void QgsComposerMapWidget::updateGuiElements()

blockAllSignals( true );

whileBlocking( mCrsSelector )->setCrs( mComposerMap->crs() );

//width, height, scale
double scale = mComposerMap->scale();

@@ -121,6 +121,8 @@ class QgsComposerMapWidget: public QgsComposerItemBaseWidget, private Ui::QgsCom
void updateOverviewFrameStyleFromWidget();
void cleanUpOverviewFrameStyleSelector( QgsPanelWidget* container );

void mapCrsChanged( const QgsCoordinateReferenceSystem& crs );

private:
QgsComposerMap* mComposerMap;

@@ -124,6 +124,9 @@ QgsComposerMap::QgsComposerMap( QgsComposition *composition )

void QgsComposerMap::init()
{
if ( mComposition && mComposition->project() )
mCrs = mComposition->project()->crs();

mGridStack = new QgsComposerMapGridStack( this );
mOverviewStack = new QgsComposerMapOverviewStack( this );
connectUpdateSlot();
@@ -205,10 +208,12 @@ QgsMapSettings QgsComposerMap::mapSettings( const QgsRectangle& extent, QSizeF s
QgsExpressionContext expressionContext = createExpressionContext();

QgsMapSettings jobMapSettings;
jobMapSettings.setDestinationCrs( mCrs );
jobMapSettings.setCrsTransformEnabled( true );
jobMapSettings.setExtent( extent );
jobMapSettings.setOutputSize( size.toSize() );
jobMapSettings.setOutputDpi( dpi );
jobMapSettings.setMapUnits( crs().mapUnits() );
jobMapSettings.setMapUnits( mCrs.mapUnits() );
jobMapSettings.setBackgroundColor( Qt::transparent );
jobMapSettings.setOutputImageFormat( ms.outputImageFormat() );
jobMapSettings.setRotation( mEvaluatedMapRotation );
@@ -233,8 +238,6 @@ QgsMapSettings QgsComposerMap::mapSettings( const QgsRectangle& extent, QSizeF s
}
jobMapSettings.setLayers( layers );
jobMapSettings.setLayerStyleOverrides( layerStyleOverridesToRender( expressionContext ) );
jobMapSettings.setDestinationCrs( crs() );
jobMapSettings.setCrsTransformEnabled( ms.hasCrsTransformEnabled() );
jobMapSettings.setFlags( ms.flags() );
jobMapSettings.setFlag( QgsMapSettings::DrawSelection, false );

@@ -253,7 +256,7 @@ QgsMapSettings QgsComposerMap::mapSettings( const QgsRectangle& extent, QSizeF s
jobMapSettings.setFlag( QgsMapSettings::DrawEditingInfo, false );
jobMapSettings.setFlag( QgsMapSettings::UseAdvancedEffects, mComposition->useAdvancedEffects() ); // respect the composition's useAdvancedEffects flag

jobMapSettings.datumTransformStore() = ms.datumTransformStore();
jobMapSettings.datumTransformStore().setDestinationCrs( mCrs );

return jobMapSettings;
}
@@ -873,14 +876,12 @@ QgsRectangle* QgsComposerMap::currentMapExtent()

QgsCoordinateReferenceSystem QgsComposerMap::crs() const
{
if ( mComposition )
{
return mComposition->mapSettings().destinationCrs();
}
else
{
return QgsCoordinateReferenceSystem();
}
return mCrs;
}

void QgsComposerMap::setCrs( const QgsCoordinateReferenceSystem& crs )
{
mCrs = crs;
}

const QgsRectangle* QgsComposerMap::currentMapExtent() const
@@ -1273,6 +1274,10 @@ bool QgsComposerMap::writeXml( QDomElement& elem, QDomDocument & doc ) const
extentElem.setAttribute( QStringLiteral( "ymax" ), qgsDoubleToString( mExtent.yMaximum() ) );
composerMapElem.appendChild( extentElem );

QDomElement crsElem = doc.createElement( QStringLiteral( "crs" ) );
mCrs.writeXml( crsElem, doc );
composerMapElem.appendChild( crsElem );

// follow map theme
composerMapElem.setAttribute( QStringLiteral( "followPreset" ), mFollowVisibilityPreset ? "true" : "false" );
composerMapElem.setAttribute( QStringLiteral( "followPresetName" ), mFollowVisibilityPresetName );
@@ -1374,6 +1379,13 @@ bool QgsComposerMap::readXml( const QDomElement& itemElem, const QDomDocument& d
setNewExtent( QgsRectangle( xmin, ymin, xmax, ymax ) );
}

QDomNodeList crsNodeList = itemElem.elementsByTagName( QStringLiteral( "crs" ) );
if ( !crsNodeList.isEmpty() )
{
QDomElement crsElem = crsNodeList.at( 0 ).toElement();
mCrs.readXml( crsElem );
}

//map rotation
if ( !qgsDoubleNear( itemElem.attribute( QStringLiteral( "mapRotation" ), QStringLiteral( "0" ) ).toDouble(), 0.0 ) )
{
@@ -170,9 +170,17 @@ class CORE_EXPORT QgsComposerMap : public QgsComposerItem
/**
* Returns the map's coordinate reference system.
* @note added in QGIS 3.0
* @see setCrs()
*/
QgsCoordinateReferenceSystem crs() const;

/**
* Sets the map's coordinate reference system.
* @see crs()
* @note added in QGIS 3.0
*/
void setCrs( const QgsCoordinateReferenceSystem& crs );

PreviewMode previewMode() const {return mPreviewMode;}
void setPreviewMode( PreviewMode m );

@@ -454,6 +462,9 @@ class CORE_EXPORT QgsComposerMap : public QgsComposerItem
// so that full rectangle in paper is used.
QgsRectangle mExtent;

//! Map CRS
QgsCoordinateReferenceSystem mCrs;

// Current temporary map region in map units. This is overwritten when atlas feature changes. It's also
// used when the user changes the map extent and an atlas preview is enabled. This allows the user
// to manually tweak each atlas preview page without affecting the actual original map extent.
@@ -2832,6 +2832,12 @@ bool QgsComposition::exportAsPDF( const QString& file )
void QgsComposition::georeferenceOutput( const QString& file, QgsComposerMap* map,
const QRectF& exportRegion, double dpi ) const
{
if ( !map )
map = referenceMap();

if ( !map )
return; // no reference map

if ( dpi < 0 )
dpi = printResolution();

0 comments on commit 9a6d714

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