Skip to content
Permalink
Browse files

Add QgsCoordinateTransformContext arguments to QgsCoordinateTransform…

… constructor

And automatically retrieve correct datum transforms for the
transform, based on the information in the context.

Also add a convenience constructor which takes a QgsProject
instance instead of a QgsCoordinateTransformContext and which
automatically retrieves the project's transform context and uses
that. This is designed to make it easy to upgrade existing
Python code (by adding just QgsProject.instance() to the transform
constructors).
  • Loading branch information
nyalldawson committed Nov 5, 2017
1 parent 2edb2d8 commit 91e0afb613c5e5dcd9a053c569d6e7eda29c1526
@@ -45,14 +45,42 @@ class QgsCoordinateTransform
Default constructor, creates an invalid QgsCoordinateTransform.
%End

QgsCoordinateTransform( const QgsCoordinateReferenceSystem &source,
const QgsCoordinateReferenceSystem &destination );
explicit QgsCoordinateTransform( const QgsCoordinateReferenceSystem &source,
const QgsCoordinateReferenceSystem &destination );
%Docstring
Constructs a QgsCoordinateTransform using QgsCoordinateReferenceSystem objects.
\param source source CRS, typically of the layer's coordinate system
\param destination CRS, typically of the map canvas coordinate system
%End

explicit QgsCoordinateTransform( const QgsCoordinateReferenceSystem &source,
const QgsCoordinateReferenceSystem &destination,
const QgsCoordinateTransformContext &context );
%Docstring
Constructs a QgsCoordinateTransform to transform from the ``source``
to ``destination`` coordinate reference system.

The ``context`` argument specifies the context under which the transform
will be applied, and is used for calculating necessary datum transforms
to utilise.

.. versionadded:: 3.0
%End

explicit QgsCoordinateTransform( const QgsCoordinateReferenceSystem &source,
const QgsCoordinateReferenceSystem &destination,
const QgsProject *project );
%Docstring
Constructs a QgsCoordinateTransform to transform from the ``source``
to ``destination`` coordinate reference system, when used with the
given ``project``.

No reference to ``project`` is stored or utilised outside of the constructor,
and it is used to retrieve the project's transform context only.

.. versionadded:: 3.0
%End

QgsCoordinateTransform( const QgsCoordinateTransform &o );
%Docstring
Copy constructor
@@ -86,6 +114,13 @@ Default constructor, creates an invalid QgsCoordinateTransform.
\param crs CRS to transform coordinates to
.. seealso:: :py:func:`destinationCrs()`
.. seealso:: :py:func:`setSourceCrs()`
%End

void setContext( const QgsCoordinateTransformContext &context );
%Docstring
Sets the ``context`` in which the coordinate transform should be
calculated.
.. versionadded:: 3.0
%End

QgsCoordinateReferenceSystem sourceCrs() const;
@@ -213,14 +248,53 @@ Default constructor, creates an invalid QgsCoordinateTransform.

int sourceDatumTransform() const;
%Docstring
Returns the index of the datum transform to use when projecting from the source
CRS.

This is usually calculated automatically from the transform's QgsCoordinateTransformContext,
but can be manually overwritten by a call to setSourceDatumTransform().

.. seealso:: setSourceDatumTransform()
.. seealso:: destinationDatumTransform()
:rtype: int
%End
void setSourceDatumTransform( int dt );

void setSourceDatumTransform( int datum );
%Docstring
Sets the index of the ``datum`` transform to use when projecting from the source
CRS.

This is usually calculated automatically from the transform's QgsCoordinateTransformContext.
Calling this method will overwrite any automatically calculated datum transform.

.. seealso:: sourceDatumTransform()
.. seealso:: setDestinationDatumTransform()
%End

int destinationDatumTransform() const;
%Docstring
Returns the index of the datum transform to use when projecting to the destination
CRS.

This is usually calculated automatically from the transform's QgsCoordinateTransformContext,
but can be manually overwritten by a call to setDestinationDatumTransform().

.. seealso:: setDestinationDatumTransform()
.. seealso:: sourceDatumTransform()
:rtype: int
%End
void setDestinationDatumTransform( int dt );

void setDestinationDatumTransform( int datum );
%Docstring
Sets the index of the ``datum`` transform to use when projecting to the destination
CRS.

This is usually calculated automatically from the transform's QgsCoordinateTransformContext.
Calling this method will overwrite any automatically calculated datum transform.

.. seealso:: destinationDatumTransform()
.. seealso:: setSourceDatumTransform()
%End

void initialize();
%Docstring
@@ -22,6 +22,7 @@
#include "qgspointxy.h"
#include "qgsrectangle.h"
#include "qgsexception.h"
#include "qgsproject.h"

//qt includes
#include <QDomNode>
@@ -47,7 +48,17 @@ QgsCoordinateTransform::QgsCoordinateTransform()

QgsCoordinateTransform::QgsCoordinateTransform( const QgsCoordinateReferenceSystem &source, const QgsCoordinateReferenceSystem &destination )
{
d = new QgsCoordinateTransformPrivate( source, destination );
d = new QgsCoordinateTransformPrivate( source, destination, QgsCoordinateTransformContext() );
}

QgsCoordinateTransform::QgsCoordinateTransform( const QgsCoordinateReferenceSystem &source, const QgsCoordinateReferenceSystem &destination, const QgsCoordinateTransformContext &context )
{
d = new QgsCoordinateTransformPrivate( source, destination, context );
}

QgsCoordinateTransform::QgsCoordinateTransform( const QgsCoordinateReferenceSystem &source, const QgsCoordinateReferenceSystem &destination, const QgsProject *project )
{
d = new QgsCoordinateTransformPrivate( source, destination, project ? project->transformContext() : QgsCoordinateTransformContext() );
}

QgsCoordinateTransform::QgsCoordinateTransform( const QgsCoordinateTransform &o )
@@ -67,12 +78,22 @@ void QgsCoordinateTransform::setSourceCrs( const QgsCoordinateReferenceSystem &c
{
d.detach();
d->mSourceCRS = crs;
d->calculateTransforms();
d->initialize();
}
void QgsCoordinateTransform::setDestinationCrs( const QgsCoordinateReferenceSystem &crs )
{
d.detach();
d->mDestCRS = crs;
d->calculateTransforms();
d->initialize();
}

void QgsCoordinateTransform::setContext( const QgsCoordinateTransformContext &context )
{
d.detach();
d->mContext = context;
d->calculateTransforms();
d->initialize();
}

@@ -27,6 +27,8 @@ class QgsCoordinateTransformPrivate;
class QgsPointXY;
class QgsRectangle;
class QPolygonF;
class QgsCoordinateTransformContext;
class QgsProject;

/**
* \ingroup core
@@ -63,8 +65,36 @@ class CORE_EXPORT QgsCoordinateTransform
* \param source source CRS, typically of the layer's coordinate system
* \param destination CRS, typically of the map canvas coordinate system
*/
QgsCoordinateTransform( const QgsCoordinateReferenceSystem &source,
const QgsCoordinateReferenceSystem &destination );
explicit QgsCoordinateTransform( const QgsCoordinateReferenceSystem &source,
const QgsCoordinateReferenceSystem &destination );

/**
* Constructs a QgsCoordinateTransform to transform from the \a source
* to \a destination coordinate reference system.
*
* The \a context argument specifies the context under which the transform
* will be applied, and is used for calculating necessary datum transforms
* to utilise.
*
* \since QGIS 3.0
*/
explicit QgsCoordinateTransform( const QgsCoordinateReferenceSystem &source,
const QgsCoordinateReferenceSystem &destination,
const QgsCoordinateTransformContext &context );

/**
* Constructs a QgsCoordinateTransform to transform from the \a source
* to \a destination coordinate reference system, when used with the
* given \a project.
*
* No reference to \a project is stored or utilised outside of the constructor,
* and it is used to retrieve the project's transform context only.
*
* \since QGIS 3.0
*/
explicit QgsCoordinateTransform( const QgsCoordinateReferenceSystem &source,
const QgsCoordinateReferenceSystem &destination,
const QgsProject *project );

/**
* Copy constructor
@@ -101,6 +131,13 @@ class CORE_EXPORT QgsCoordinateTransform
*/
void setDestinationCrs( const QgsCoordinateReferenceSystem &crs );

/**
* Sets the \a context in which the coordinate transform should be
* calculated.
* \since QGIS 3.0
*/
void setContext( const QgsCoordinateTransformContext &context );

/**
* Returns the source coordinate reference system, which the transform will
* transform coordinates from.
@@ -271,10 +308,53 @@ class CORE_EXPORT QgsCoordinateTransform
\returns epsgNr epsg code of the transformation (or 0 if not in epsg db)*/
static bool datumTransformCrsInfo( int datumTransform, int &epsgNr, QString &srcProjection, QString &dstProjection, QString &remarks, QString &scope, bool &preferred, bool &deprecated );

/**
* Returns the index of the datum transform to use when projecting from the source
* CRS.
*
* This is usually calculated automatically from the transform's QgsCoordinateTransformContext,
* but can be manually overwritten by a call to setSourceDatumTransform().
*
* \see setSourceDatumTransform()
* \see destinationDatumTransform()
*/
int sourceDatumTransform() const;
void setSourceDatumTransform( int dt );

/**
* Sets the index of the \a datum transform to use when projecting from the source
* CRS.
*
* This is usually calculated automatically from the transform's QgsCoordinateTransformContext.
* Calling this method will overwrite any automatically calculated datum transform.
*
* \see sourceDatumTransform()
* \see setDestinationDatumTransform()
*/
void setSourceDatumTransform( int datum );

/**
* Returns the index of the datum transform to use when projecting to the destination
* CRS.
*
* This is usually calculated automatically from the transform's QgsCoordinateTransformContext,
* but can be manually overwritten by a call to setDestinationDatumTransform().
*
* \see setDestinationDatumTransform()
* \see sourceDatumTransform()
*/
int destinationDatumTransform() const;
void setDestinationDatumTransform( int dt );

/**
* Sets the index of the \a datum transform to use when projecting to the destination
* CRS.
*
* This is usually calculated automatically from the transform's QgsCoordinateTransformContext.
* Calling this method will overwrite any automatically calculated datum transform.
*
* \see destinationDatumTransform()
* \see setSourceDatumTransform()
*/
void setDestinationDatumTransform( int datum );

//!initialize is used to actually create the Transformer instance
void initialize();
@@ -50,11 +50,15 @@ QgsCoordinateTransformPrivate::QgsCoordinateTransformPrivate()
setFinder();
}

QgsCoordinateTransformPrivate::QgsCoordinateTransformPrivate( const QgsCoordinateReferenceSystem &source, const QgsCoordinateReferenceSystem &destination )
QgsCoordinateTransformPrivate::QgsCoordinateTransformPrivate( const QgsCoordinateReferenceSystem &source,
const QgsCoordinateReferenceSystem &destination,
const QgsCoordinateTransformContext &context )
: mSourceCRS( source )
, mDestCRS( destination )
, mContext( context )
{
setFinder();
calculateTransforms();
initialize();
}

@@ -64,6 +68,7 @@ QgsCoordinateTransformPrivate::QgsCoordinateTransformPrivate( const QgsCoordinat
, mShortCircuit( other.mShortCircuit )
, mSourceCRS( other.mSourceCRS )
, mDestCRS( other.mDestCRS )
, mContext( other.mContext )
, mSourceDatumTransform( other.mSourceDatumTransform )
, mDestinationDatumTransform( other.mDestinationDatumTransform )
{
@@ -101,7 +106,9 @@ bool QgsCoordinateTransformPrivate::initialize()

mIsValid = true;

bool useDefaultDatumTransform = ( mSourceDatumTransform == - 1 && mDestinationDatumTransform == -1 );
int sourceDatumTransform = mSourceDatumTransform;
int destDatumTransform = mDestinationDatumTransform;
bool useDefaultDatumTransform = ( sourceDatumTransform == - 1 && destDatumTransform == -1 );

// init the projections (destination and source)
freeProj();
@@ -111,24 +118,24 @@ bool QgsCoordinateTransformPrivate::initialize()
{
mSourceProjString = stripDatumTransform( mSourceProjString );
}
if ( mSourceDatumTransform != -1 )
if ( sourceDatumTransform != -1 )
{
mSourceProjString += ( ' ' + datumTransformString( mSourceDatumTransform ) );
mSourceProjString += ( ' ' + datumTransformString( sourceDatumTransform ) );
}

mDestProjString = mDestCRS.toProj4();
if ( !useDefaultDatumTransform )
{
mDestProjString = stripDatumTransform( mDestProjString );
}
if ( mDestinationDatumTransform != -1 )
if ( destDatumTransform != -1 )
{
mDestProjString += ( ' ' + datumTransformString( mDestinationDatumTransform ) );
mDestProjString += ( ' ' + datumTransformString( destDatumTransform ) );
}

if ( !useDefaultDatumTransform )
{
addNullGridShifts( mSourceProjString, mDestProjString );
addNullGridShifts( mSourceProjString, mDestProjString, sourceDatumTransform, destDatumTransform );
}

// create proj projections for current thread
@@ -185,6 +192,14 @@ bool QgsCoordinateTransformPrivate::initialize()
return mIsValid;
}

void QgsCoordinateTransformPrivate::calculateTransforms()
{
// recalculate datum transforms from context
QPair< int, int > transforms = mContext.calculateDatumTransforms( mSourceCRS, mDestCRS );
mSourceDatumTransform = transforms.first;
mDestinationDatumTransform = transforms.second;
}

QPair<projPJ, projPJ> QgsCoordinateTransformPrivate::threadLocalProjData()
{
mProjLock.lockForRead();
@@ -301,27 +316,28 @@ QString QgsCoordinateTransformPrivate::datumTransformString( int datumTransform
return transformString;
}

void QgsCoordinateTransformPrivate::addNullGridShifts( QString &srcProjString, QString &destProjString ) const
void QgsCoordinateTransformPrivate::addNullGridShifts( QString &srcProjString, QString &destProjString,
int sourceDatumTransform, int destinationDatumTransform ) const
{
//if one transformation uses ntv2, the other one needs to be null grid shift
if ( mDestinationDatumTransform == -1 && srcProjString.contains( QLatin1String( "+nadgrids" ) ) ) //add null grid if source transformation is ntv2
if ( destinationDatumTransform == -1 && srcProjString.contains( QLatin1String( "+nadgrids" ) ) ) //add null grid if source transformation is ntv2
{
destProjString += QLatin1String( " +nadgrids=@null" );
return;
}
if ( mSourceDatumTransform == -1 && destProjString.contains( QLatin1String( "+nadgrids" ) ) )
if ( sourceDatumTransform == -1 && destProjString.contains( QLatin1String( "+nadgrids" ) ) )
{
srcProjString += QLatin1String( " +nadgrids=@null" );
return;
}

//add null shift grid for google mercator
//(see e.g. http://trac.osgeo.org/proj/wiki/FAQ#ChangingEllipsoidWhycantIconvertfromWGS84toGoogleEarthVirtualGlobeMercator)
if ( mSourceCRS.authid().compare( QLatin1String( "EPSG:3857" ), Qt::CaseInsensitive ) == 0 && mSourceDatumTransform == -1 )
if ( mSourceCRS.authid().compare( QLatin1String( "EPSG:3857" ), Qt::CaseInsensitive ) == 0 && sourceDatumTransform == -1 )
{
srcProjString += QLatin1String( " +nadgrids=@null" );
}
if ( mDestCRS.authid().compare( QLatin1String( "EPSG:3857" ), Qt::CaseInsensitive ) == 0 && mDestinationDatumTransform == -1 )
if ( mDestCRS.authid().compare( QLatin1String( "EPSG:3857" ), Qt::CaseInsensitive ) == 0 && destinationDatumTransform == -1 )
{
destProjString += QLatin1String( " +nadgrids=@null" );
}

0 comments on commit 91e0afb

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