Skip to content

Commit

Permalink
[needs-docs] Composer maps default to a "use project CRS" setting
Browse files Browse the repository at this point in the history
And overriding projection is only done if user has manually
chosen a different CRS from the list.

This means that templates and compositions in server can still
adapt to follow the project CRS, but if desired specific map
items (eg an overview map) can use the CRS override to always
show in a particular CRS.
  • Loading branch information
nyalldawson committed Jan 18, 2017
1 parent 6a4d605 commit a3dd380
Show file tree
Hide file tree
Showing 7 changed files with 60 additions and 18 deletions.
1 change: 1 addition & 0 deletions python/core/composer/qgscomposermap.sip
Expand Up @@ -128,6 +128,7 @@ class QgsComposerMap : QgsComposerItem
// QgsRectangle* currentMapExtent();

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

PreviewMode previewMode() const;
Expand Down
9 changes: 6 additions & 3 deletions src/app/composer/qgscomposermapwidget.cpp
Expand Up @@ -64,6 +64,9 @@ QgsComposerMapWidget::QgsComposerMapWidget( QgsComposerMap* composerMap )
mPreviewModeComboBox->insertItem( 1, tr( "Render" ) );
mPreviewModeComboBox->insertItem( 2, tr( "Rectangle" ) );

mCrsSelector->setOptionVisible( QgsProjectionSelectionWidget::CrsNotSet, true );
mCrsSelector->setNotSetText( tr( "Use project CRS" ) );

// follow preset combo
mFollowVisibilityPresetCombo->setModel( new QStringListModel( mFollowVisibilityPresetCombo ) );
connect( mFollowVisibilityPresetCombo, SIGNAL( currentIndexChanged( int ) ), this, SLOT( followVisibilityPresetSelected( int ) ) );
Expand Down Expand Up @@ -270,7 +273,7 @@ void QgsComposerMapWidget::mapCrsChanged( const QgsCoordinateReferenceSystem& cr
return;
}

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

// try to reproject to maintain extent
Expand All @@ -280,7 +283,7 @@ void QgsComposerMapWidget::mapCrsChanged( const QgsCoordinateReferenceSystem& cr
QgsRectangle newExtent;
try
{
QgsCoordinateTransform xForm( oldCrs, crs );
QgsCoordinateTransform xForm( oldCrs, crs.isValid() ? crs : QgsProject::instance()->crs() );
QgsRectangle prevExtent = *mComposerMap->currentMapExtent();
newExtent = xForm.transformBoundingBox( prevExtent );
updateExtent = true;
Expand Down Expand Up @@ -605,7 +608,7 @@ void QgsComposerMapWidget::updateGuiElements()

blockAllSignals( true );

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

//width, height, scale
double scale = mComposerMap->scale();
Expand Down
29 changes: 19 additions & 10 deletions src/core/composer/qgscomposermap.cpp
Expand Up @@ -124,9 +124,6 @@ QgsComposerMap::QgsComposerMap( QgsComposition *composition )

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

mGridStack = new QgsComposerMapGridStack( this );
mOverviewStack = new QgsComposerMapOverviewStack( this );
connectUpdateSlot();
Expand Down Expand Up @@ -204,14 +201,15 @@ void QgsComposerMap::draw( QPainter *painter, const QgsRectangle& extent, QSizeF
QgsMapSettings QgsComposerMap::mapSettings( const QgsRectangle& extent, QSizeF size, int dpi ) const
{
QgsExpressionContext expressionContext = createExpressionContext();
QgsCoordinateReferenceSystem renderCrs = crs();

QgsMapSettings jobMapSettings;
jobMapSettings.setDestinationCrs( mCrs );
jobMapSettings.setDestinationCrs( renderCrs );
jobMapSettings.setCrsTransformEnabled( true );
jobMapSettings.setExtent( extent );
jobMapSettings.setOutputSize( size.toSize() );
jobMapSettings.setOutputDpi( dpi );
jobMapSettings.setMapUnits( mCrs.mapUnits() );
jobMapSettings.setMapUnits( renderCrs.mapUnits() );
jobMapSettings.setBackgroundColor( Qt::transparent );
jobMapSettings.setRotation( mEvaluatedMapRotation );

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

jobMapSettings.datumTransformStore().setDestinationCrs( mCrs );
jobMapSettings.datumTransformStore().setDestinationCrs( renderCrs );

return jobMapSettings;
}
Expand Down Expand Up @@ -873,7 +871,11 @@ QgsRectangle* QgsComposerMap::currentMapExtent()

QgsCoordinateReferenceSystem QgsComposerMap::crs() const
{
return mCrs;
if ( mCrs.isValid() )
return mCrs;
else if ( mComposition && mComposition->project() )
return mComposition->project()->crs();
return QgsCoordinateReferenceSystem();
}

void QgsComposerMap::setCrs( const QgsCoordinateReferenceSystem& crs )
Expand Down Expand Up @@ -1271,9 +1273,12 @@ 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 );
if ( mCrs.isValid() )
{
QDomElement crsElem = doc.createElement( QStringLiteral( "crs" ) );
mCrs.writeXml( crsElem, doc );
composerMapElem.appendChild( crsElem );
}

// follow map theme
composerMapElem.setAttribute( QStringLiteral( "followPreset" ), mFollowVisibilityPreset ? "true" : "false" );
Expand Down Expand Up @@ -1382,6 +1387,10 @@ bool QgsComposerMap::readXml( const QDomElement& itemElem, const QDomDocument& d
QDomElement crsElem = crsNodeList.at( 0 ).toElement();
mCrs.readXml( crsElem );
}
else
{
mCrs = QgsCoordinateReferenceSystem();
}

//map rotation
if ( !qgsDoubleNear( itemElem.attribute( QStringLiteral( "mapRotation" ), QStringLiteral( "0" ) ).toDouble(), 0.0 ) )
Expand Down
22 changes: 20 additions & 2 deletions src/core/composer/qgscomposermap.h
Expand Up @@ -168,15 +168,33 @@ class CORE_EXPORT QgsComposerMap : public QgsComposerItem
QgsRectangle* currentMapExtent();

/**
* Returns the map's coordinate reference system.
* Returns coordinate reference system used for rendering the map.
* This will match the presetCrs() if that is set, or if a preset
* CRS is not set then the map's CRS will follow the composition's
* project's CRS.
* @note added in QGIS 3.0
* @see presetCrs()
* @see setCrs()
*/
QgsCoordinateReferenceSystem crs() const;

/**
* Sets the map's coordinate reference system.
* Returns the map's preset coordinate reference system. If set, this
* CRS will be used to render the map regardless of any project CRS
* setting. If the returned CRS is not valid then the project CRS
* will be used to render the map.
* @note added in QGIS 3.0
* @see crs()
* @see setCrs()
*/
QgsCoordinateReferenceSystem presetCrs() const { return mCrs; }

/**
* Sets the map's preset coordinate reference system. If a valid CRS is
* set, this CRS will be used to render the map regardless of any project CRS
* setting. If the CRS is not valid then the project CRS will be used to render the map.
* @see crs()
* @see presetCrs()
* @note added in QGIS 3.0
*/
void setCrs( const QgsCoordinateReferenceSystem& crs );
Expand Down
1 change: 1 addition & 0 deletions src/gui/qgsprojectionselectionwidget.cpp
Expand Up @@ -223,6 +223,7 @@ void QgsProjectionSelectionWidget::comboIndexChanged( int idx )
}
case QgsProjectionSelectionWidget::CrsNotSet:
emit cleared();
emit crsChanged( QgsCoordinateReferenceSystem() );
return;
}
}
Expand Down
6 changes: 4 additions & 2 deletions src/server/qgswmsconfigparser.cpp
Expand Up @@ -79,8 +79,10 @@ QgsComposition* QgsWmsConfigParser::createPrintComposition( const QString& compo
continue;
}

// Change CRS of map to match requested CRS
if ( mapSettings.destinationCrs().isValid() )
// Change CRS of map set to "project CRS" to match requested CRS
// (if map has a valid preset crs then we keep this crs and don't use the
// requested crs for this map item)
if ( mapSettings.destinationCrs().isValid() && !currentMap->presetCrs().isValid() )
currentMap->setCrs( mapSettings.destinationCrs() );

QStringList coordList = extent.split( QStringLiteral( "," ) );
Expand Down
10 changes: 9 additions & 1 deletion tests/src/python/test_qgscomposermap.py
Expand Up @@ -156,25 +156,33 @@ def testMapCrs(self):
composition.addComposerMap(map)

self.assertEqual(map.crs().authid(), 'EPSG:4326')
self.assertFalse(map.presetCrs().isValid())

# overwrite CRS
map.setCrs(QgsCoordinateReferenceSystem('EPSG:3857'))
self.assertEqual(map.crs().authid(), 'EPSG:3857')
self.assertEqual(map.presetCrs().authid(), 'EPSG:3857')
checker = QgsCompositionChecker('composermap_crs3857', composition)
checker.setControlPathPrefix("composer_map")
result, message = checker.testComposition()
self.assertTrue(result, message)

# overwrite CRS
map.setCrs(QgsCoordinateReferenceSystem('EPSG:4326'))
self.assertEqual(map.presetCrs().authid(), 'EPSG:4326')
self.assertEqual(map.crs().authid(), 'EPSG:4326')
rectangle = QgsRectangle(-124, 17, -78, 52)
map.zoomToExtent(rectangle)
self.assertEqual(map.crs().authid(), 'EPSG:4326')
checker = QgsCompositionChecker('composermap_crs4326', composition)
checker.setControlPathPrefix("composer_map")
result, message = checker.testComposition()
self.assertTrue(result, message)

# change back to project CRS
map.setCrs(QgsCoordinateReferenceSystem())
self.assertEqual(map.crs().authid(), 'EPSG:4326')
self.assertFalse(map.presetCrs().isValid())

# Fails because addItemsFromXml has been commented out in sip
@unittest.expectedFailure
def testuniqueId(self):
Expand Down

0 comments on commit a3dd380

Please sign in to comment.