Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Merge pull request #3623 from nyalldawson/true_north_214
[composer] Backport fixes for true north handling to 2.14
  • Loading branch information
nyalldawson committed Oct 20, 2016
2 parents b2a2c18 + d78d62e commit 36d3fef
Show file tree
Hide file tree
Showing 18 changed files with 478 additions and 10 deletions.
39 changes: 39 additions & 0 deletions python/core/composer/qgscomposerpicture.sip
Expand Up @@ -30,6 +30,13 @@ class QgsComposerPicture: QgsComposerItem
Unknown
};

//! Method for syncing rotation to a map's North direction
enum NorthMode
{
GridNorth, /*!< Align to grid north */
TrueNorth, /*!< Align to true north */
};

QgsComposerPicture( QgsComposition *composition /TransferThis/);
~QgsComposerPicture();

Expand Down Expand Up @@ -132,6 +139,38 @@ class QgsComposerPicture: QgsComposerItem
*/
bool useRotationMap() const;

/**
* Returns the mode used to align the picture to a map's North.
* @see setNorthMode()
* @see northOffset()
* @note added in QGIS 2.18
*/
NorthMode northMode() const;

/**
* Sets the mode used to align the picture to a map's North.
* @see northMode()
* @see setNorthOffset()
* @note added in QGIS 2.18
*/
void setNorthMode( NorthMode mode );

/**
* Returns the offset added to the picture's rotation from a map's North.
* @see setNorthOffset()
* @see northMode()
* @note added in QGIS 2.18
*/
double northOffset() const;

/**
* Sets the offset added to the picture's rotation from a map's North.
* @see northOffset()
* @see setNorthMode()
* @note added in QGIS 2.18
*/
void setNorthOffset( double offset );

/** Returns the resize mode used for drawing the picture within the composer
* item's frame.
* @returns resize mode of picture
Expand Down
1 change: 1 addition & 0 deletions python/core/core.sip
Expand Up @@ -21,6 +21,7 @@
%Include qgsannotation.sip
%Include qgsapplication.sip
%Include qgsattributeaction.sip
%Include qgsbearingutils.sip
%Include qgsbrowsermodel.sip
%Include qgsclipper.sip
%Include qgscolorscheme.sip
Expand Down
21 changes: 21 additions & 0 deletions python/core/qgsbearingutils.sip
@@ -0,0 +1,21 @@
/**
* \class QgsBearingUtils
* \ingroup core
* Utilities for calculating bearings and directions.
* \note Added in version 2.18
*/
class QgsBearingUtils
{
%TypeHeaderCode
#include <qgsbearingutils.h>
%End
public:

/**
* Returns the direction to true north from a specified point and for a specified
* coordinate reference system. The returned value is in degrees clockwise from
* vertical. An exception will be thrown if the bearing could not be calculated.
*/
static double bearingTrueNorth( const QgsCoordinateReferenceSystem& crs,
const QgsPoint& point );
};
2 changes: 1 addition & 1 deletion python/core/qgspoint.sip
Expand Up @@ -148,7 +148,7 @@ class QgsPoint
double sqrDistToSegment( double x1, double y1, double x2, double y2, QgsPoint& minDistPoint /Out/, double epsilon = DEFAULT_SEGMENT_EPSILON ) const;

/** Calculates azimuth between this point and other one (clockwise in degree, starting from north) */
double azimuth( const QgsPoint& other );
double azimuth( const QgsPoint& other ) const;

/** Compares this point with another point with a fuzzy tolerance
* @param other point to compare with
Expand Down
37 changes: 37 additions & 0 deletions src/app/composer/qgscomposerpicturewidget.cpp
Expand Up @@ -44,6 +44,13 @@ QgsComposerPictureWidget::QgsComposerPictureWidget( QgsComposerPicture* picture
mOutlineColorButton->setColorDialogTitle( tr( "Select outline color" ) );
mOutlineColorButton->setContext( "composer" );

mNorthTypeComboBox->blockSignals( true );
mNorthTypeComboBox->addItem( tr( "Grid north" ), QgsComposerPicture::GridNorth );
mNorthTypeComboBox->addItem( tr( "True north" ), QgsComposerPicture::TrueNorth );
mNorthTypeComboBox->blockSignals( false );
mPictureRotationOffsetSpinBox->setClearValue( 0.0 );
mPictureRotationSpinBox->setClearValue( 0.0 );

//add widget for general composer item properties
QgsComposerItemWidget* itemPropertiesWidget = new QgsComposerItemWidget( this, picture );
mainLayout->addWidget( itemPropertiesWidget );
Expand Down Expand Up @@ -273,6 +280,8 @@ void QgsComposerPictureWidget::on_mRotationFromComposerMapCheckBox_stateChanged(
mPicture->setRotationMap( -1 );
mPictureRotationSpinBox->setEnabled( true );
mComposerMapComboBox->setEnabled( false );
mNorthTypeComboBox->setEnabled( false );
mPictureRotationOffsetSpinBox->setEnabled( false );
mPicture->setPictureRotation( mPictureRotationSpinBox->value() );
}
else
Expand All @@ -286,6 +295,8 @@ void QgsComposerPictureWidget::on_mRotationFromComposerMapCheckBox_stateChanged(

mPicture->setRotationMap( composerId );
mPictureRotationSpinBox->setEnabled( false );
mNorthTypeComboBox->setEnabled( true );
mPictureRotationOffsetSpinBox->setEnabled( true );
mComposerMapComboBox->setEnabled( true );
}
mPicture->endCommand();
Expand Down Expand Up @@ -388,6 +399,8 @@ void QgsComposerPictureWidget::setGuiElementValues()
mPictureLineEdit->blockSignals( true );
mComposerMapComboBox->blockSignals( true );
mRotationFromComposerMapCheckBox->blockSignals( true );
mNorthTypeComboBox->blockSignals( true );
mPictureRotationOffsetSpinBox->blockSignals( true );
mResizeModeComboBox->blockSignals( true );
mAnchorPointComboBox->blockSignals( true );
mFillColorButton->blockSignals( true );
Expand All @@ -410,13 +423,19 @@ void QgsComposerPictureWidget::setGuiElementValues()
{
mComposerMapComboBox->setCurrentIndex( itemId );
}
mNorthTypeComboBox->setEnabled( true );
mPictureRotationOffsetSpinBox->setEnabled( true );
}
else
{
mRotationFromComposerMapCheckBox->setCheckState( Qt::Unchecked );
mPictureRotationSpinBox->setEnabled( true );
mComposerMapComboBox->setEnabled( false );
mNorthTypeComboBox->setEnabled( false );
mPictureRotationOffsetSpinBox->setEnabled( false );
}
mNorthTypeComboBox->setCurrentIndex( mNorthTypeComboBox->findData( mPicture->northMode() ) );
mPictureRotationOffsetSpinBox->setValue( mPicture->northOffset() );

mResizeModeComboBox->setCurrentIndex(( int )mPicture->resizeMode() );
//disable picture rotation for non-zoom modes
Expand Down Expand Up @@ -444,6 +463,8 @@ void QgsComposerPictureWidget::setGuiElementValues()
mPictureRotationSpinBox->blockSignals( false );
mPictureLineEdit->blockSignals( false );
mComposerMapComboBox->blockSignals( false );
mNorthTypeComboBox->blockSignals( false );
mPictureRotationOffsetSpinBox->blockSignals( false );
mResizeModeComboBox->blockSignals( false );
mAnchorPointComboBox->blockSignals( false );
mFillColorButton->blockSignals( false );
Expand Down Expand Up @@ -726,6 +747,22 @@ void QgsComposerPictureWidget::showEvent( QShowEvent * event )
refreshMapComboBox();
}

void QgsComposerPictureWidget::on_mPictureRotationOffsetSpinBox_valueChanged( double d )
{
mPicture->beginCommand( tr( "Picture North offset changed" ), QgsComposerMergeCommand::ComposerPictureNorthOffset );
mPicture->setNorthOffset( d );
mPicture->endCommand();
mPicture->update();
}

void QgsComposerPictureWidget::on_mNorthTypeComboBox_currentIndexChanged( int index )
{
mPicture->beginCommand( tr( "Picture North mode changed" ) );
mPicture->setNorthMode( static_cast< QgsComposerPicture::NorthMode >( mNorthTypeComboBox->itemData( index ).toInt() ) );
mPicture->endCommand();
mPicture->update();
}

void QgsComposerPictureWidget::resizeEvent( QResizeEvent * event )
{
Q_UNUSED( event );
Expand Down
2 changes: 2 additions & 0 deletions src/app/composer/qgscomposerpicturewidget.h
Expand Up @@ -73,6 +73,8 @@ class QgsComposerPictureWidget: public QgsComposerItemBaseWidget, private Ui::Qg
void on_mFillColorButton_colorChanged( const QColor& color );
void on_mOutlineColorButton_colorChanged( const QColor& color );
void on_mOutlineWidthSpinBox_valueChanged( double d );
void on_mPictureRotationOffsetSpinBox_valueChanged( double d );
void on_mNorthTypeComboBox_currentIndexChanged( int index );

private:
QgsComposerPicture* mPicture;
Expand Down
2 changes: 2 additions & 0 deletions src/core/CMakeLists.txt
Expand Up @@ -76,6 +76,7 @@ SET(QGIS_CORE_SRCS
qgis.cpp
qgsapplication.cpp
qgsattributeaction.cpp
qgsbearingutils.cpp
qgsbrowsermodel.cpp
qgscachedfeatureiterator.cpp
qgscacheindex.cpp
Expand Down Expand Up @@ -583,6 +584,7 @@ SET(QGIS_CORE_HDRS
qgis.h
qgsannotation.h
qgsattributeaction.h
qgsbearingutils.h
qgscachedfeatureiterator.h
qgscacheindex.h
qgscacheindexfeatureid.h
Expand Down
1 change: 1 addition & 0 deletions src/core/composer/qgscomposeritemcommand.h
Expand Up @@ -105,6 +105,7 @@ class CORE_EXPORT QgsComposerMergeCommand: public QgsComposerItemCommand
LegendRasterBorderWidth,
//composer picture
ComposerPictureRotation,
ComposerPictureNorthOffset,
// composer scalebar
ScaleBarLineWidth,
ScaleBarHeight,
Expand Down
79 changes: 73 additions & 6 deletions src/core/composer/qgscomposerpicture.cpp
Expand Up @@ -28,6 +28,10 @@
#include "qgsnetworkcontentfetcher.h"
#include "qgssymbollayerv2utils.h"
#include "qgssvgcache.h"
#include "qgslogger.h"
#include "qgsbearingutils.h"
#include "qgsmapsettings.h"

#include <QDomDocument>
#include <QDomElement>
#include <QFileInfo>
Expand All @@ -44,6 +48,8 @@ QgsComposerPicture::QgsComposerPicture( QgsComposition *composition )
, mMode( Unknown )
, mPictureRotation( 0 )
, mRotationMap( nullptr )
, mNorthMode( GridNorth )
, mNorthOffset( 0.0 )
, mResizeMode( QgsComposerPicture::Zoom )
, mPictureAnchor( UpperLeft )
, mSvgFillColor( QColor( 255, 255, 255 ) )
Expand All @@ -61,6 +67,8 @@ QgsComposerPicture::QgsComposerPicture()
, mMode( Unknown )
, mPictureRotation( 0 )
, mRotationMap( nullptr )
, mNorthMode( GridNorth )
, mNorthOffset( 0.0 )
, mResizeMode( QgsComposerPicture::Zoom )
, mPictureAnchor( UpperLeft )
, mSvgFillColor( QColor( 255, 255, 255 ) )
Expand Down Expand Up @@ -419,6 +427,43 @@ void QgsComposerPicture::remotePictureLoaded()
mLoaded = true;
}

void QgsComposerPicture::updateMapRotation()
{
if ( !mRotationMap )
return;

// take map rotation
double rotation = mRotationMap->mapRotation();

// handle true north
switch ( mNorthMode )
{
case GridNorth:
break; // nothing to do

case TrueNorth:
{
QgsPoint center = mRotationMap->currentMapExtent()->center();
QgsCoordinateReferenceSystem crs = mComposition->mapSettings().destinationCrs();

try
{
double bearing = QgsBearingUtils::bearingTrueNorth( crs, center );
rotation += bearing;
}
catch ( QgsException& e )
{
Q_UNUSED( e );
QgsDebugMsg( QString( "Caught exception %1" ).arg( e.what() ) );
}
break;
}
}

rotation += mNorthOffset;
setPictureRotation( rotation );
}

void QgsComposerPicture::loadPicture( const QString &path )
{
if ( path.startsWith( "http" ) )
Expand Down Expand Up @@ -650,7 +695,8 @@ void QgsComposerPicture::setRotationMap( int composerMapId )

if ( composerMapId == -1 ) //disable rotation from map
{
QObject::disconnect( mRotationMap, SIGNAL( mapRotationChanged( double ) ), this, SLOT( setPictureRotation( double ) ) );
disconnect( mRotationMap, SIGNAL( mapRotationChanged( double ) ), this, SLOT( updateMapRotation() ) );
disconnect( mRotationMap, SIGNAL( extentChanged() ), this, SLOT( updateMapRotation() ) );
mRotationMap = nullptr;
}

Expand All @@ -661,12 +707,14 @@ void QgsComposerPicture::setRotationMap( int composerMapId )
}
if ( mRotationMap )
{
QObject::disconnect( mRotationMap, SIGNAL( mapRotationChanged( double ) ), this, SLOT( setPictureRotation( double ) ) );
disconnect( mRotationMap, SIGNAL( mapRotationChanged( double ) ), this, SLOT( updateMapRotation() ) );
disconnect( mRotationMap, SIGNAL( extentChanged() ), this, SLOT( updateMapRotation() ) );
}
mPictureRotation = map->mapRotation();
QObject::connect( map, SIGNAL( mapRotationChanged( double ) ), this, SLOT( setPictureRotation( double ) ) );
connect( map, SIGNAL( mapRotationChanged( double ) ), this, SLOT( updateMapRotation() ) );
connect( map, SIGNAL( extentChanged() ), this, SLOT( updateMapRotation() ) );
mRotationMap = map;
update();
updateMapRotation();
emit pictureRotationChanged( mPictureRotation );
}

Expand Down Expand Up @@ -761,6 +809,8 @@ bool QgsComposerPicture::writeXML( QDomElement& elem, QDomDocument & doc ) const
{
composerPictureElem.setAttribute( "mapId", mRotationMap->id() );
}
composerPictureElem.setAttribute( "northMode", mNorthMode );
composerPictureElem.setAttribute( "northOffset", mNorthOffset );

_writeXML( composerPictureElem, doc );
elem.appendChild( composerPictureElem );
Expand Down Expand Up @@ -827,6 +877,9 @@ bool QgsComposerPicture::readXML( const QDomElement& itemElem, const QDomDocumen
}

//rotation map
mNorthMode = static_cast< NorthMode >( itemElem.attribute( "northMode", "0" ).toInt() );
mNorthOffset = itemElem.attribute( "northOffset", "0" ).toDouble();

int rotationMapId = itemElem.attribute( "mapId", "-1" ).toInt();
if ( rotationMapId == -1 )
{
Expand All @@ -837,10 +890,12 @@ bool QgsComposerPicture::readXML( const QDomElement& itemElem, const QDomDocumen

if ( mRotationMap )
{
QObject::disconnect( mRotationMap, SIGNAL( mapRotationChanged( double ) ), this, SLOT( setRotation( double ) ) );
disconnect( mRotationMap, SIGNAL( mapRotationChanged( double ) ), this, SLOT( updateMapRotation() ) );
disconnect( mRotationMap, SIGNAL( extentChanged() ), this, SLOT( updateMapRotation() ) );
}
mRotationMap = mComposition->getComposerMapById( rotationMapId );
QObject::connect( mRotationMap, SIGNAL( mapRotationChanged( double ) ), this, SLOT( setRotation( double ) ) );
connect( mRotationMap, SIGNAL( mapRotationChanged( double ) ), this, SLOT( updateMapRotation() ) );
connect( mRotationMap, SIGNAL( extentChanged() ), this, SLOT( updateMapRotation() ) );
}

refreshPicture();
Expand All @@ -861,6 +916,18 @@ int QgsComposerPicture::rotationMap() const
}
}

void QgsComposerPicture::setNorthMode( QgsComposerPicture::NorthMode mode )
{
mNorthMode = mode;
updateMapRotation();
}

void QgsComposerPicture::setNorthOffset( double offset )
{
mNorthOffset = offset;
updateMapRotation();
}

void QgsComposerPicture::setPictureAnchor( QgsComposerItem::ItemPositionMode anchor )
{
mPictureAnchor = anchor;
Expand Down

0 comments on commit 36d3fef

Please sign in to comment.