Skip to content

Commit 91e0afb

Browse files
committed
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).
1 parent 2edb2d8 commit 91e0afb

6 files changed

+296
-25
lines changed

python/core/qgscoordinatetransform.sip

+78-4
Original file line numberDiff line numberDiff line change
@@ -45,14 +45,42 @@ class QgsCoordinateTransform
4545
Default constructor, creates an invalid QgsCoordinateTransform.
4646
%End
4747

48-
QgsCoordinateTransform( const QgsCoordinateReferenceSystem &source,
49-
const QgsCoordinateReferenceSystem &destination );
48+
explicit QgsCoordinateTransform( const QgsCoordinateReferenceSystem &source,
49+
const QgsCoordinateReferenceSystem &destination );
5050
%Docstring
5151
Constructs a QgsCoordinateTransform using QgsCoordinateReferenceSystem objects.
5252
\param source source CRS, typically of the layer's coordinate system
5353
\param destination CRS, typically of the map canvas coordinate system
5454
%End
5555

56+
explicit QgsCoordinateTransform( const QgsCoordinateReferenceSystem &source,
57+
const QgsCoordinateReferenceSystem &destination,
58+
const QgsCoordinateTransformContext &context );
59+
%Docstring
60+
Constructs a QgsCoordinateTransform to transform from the ``source``
61+
to ``destination`` coordinate reference system.
62+
63+
The ``context`` argument specifies the context under which the transform
64+
will be applied, and is used for calculating necessary datum transforms
65+
to utilise.
66+
67+
.. versionadded:: 3.0
68+
%End
69+
70+
explicit QgsCoordinateTransform( const QgsCoordinateReferenceSystem &source,
71+
const QgsCoordinateReferenceSystem &destination,
72+
const QgsProject *project );
73+
%Docstring
74+
Constructs a QgsCoordinateTransform to transform from the ``source``
75+
to ``destination`` coordinate reference system, when used with the
76+
given ``project``.
77+
78+
No reference to ``project`` is stored or utilised outside of the constructor,
79+
and it is used to retrieve the project's transform context only.
80+
81+
.. versionadded:: 3.0
82+
%End
83+
5684
QgsCoordinateTransform( const QgsCoordinateTransform &o );
5785
%Docstring
5886
Copy constructor
@@ -86,6 +114,13 @@ Default constructor, creates an invalid QgsCoordinateTransform.
86114
\param crs CRS to transform coordinates to
87115
.. seealso:: :py:func:`destinationCrs()`
88116
.. seealso:: :py:func:`setSourceCrs()`
117+
%End
118+
119+
void setContext( const QgsCoordinateTransformContext &context );
120+
%Docstring
121+
Sets the ``context`` in which the coordinate transform should be
122+
calculated.
123+
.. versionadded:: 3.0
89124
%End
90125

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

214249
int sourceDatumTransform() const;
215250
%Docstring
251+
Returns the index of the datum transform to use when projecting from the source
252+
CRS.
253+
254+
This is usually calculated automatically from the transform's QgsCoordinateTransformContext,
255+
but can be manually overwritten by a call to setSourceDatumTransform().
256+
257+
.. seealso:: setSourceDatumTransform()
258+
.. seealso:: destinationDatumTransform()
216259
:rtype: int
217260
%End
218-
void setSourceDatumTransform( int dt );
261+
262+
void setSourceDatumTransform( int datum );
263+
%Docstring
264+
Sets the index of the ``datum`` transform to use when projecting from the source
265+
CRS.
266+
267+
This is usually calculated automatically from the transform's QgsCoordinateTransformContext.
268+
Calling this method will overwrite any automatically calculated datum transform.
269+
270+
.. seealso:: sourceDatumTransform()
271+
.. seealso:: setDestinationDatumTransform()
272+
%End
273+
219274
int destinationDatumTransform() const;
220275
%Docstring
276+
Returns the index of the datum transform to use when projecting to the destination
277+
CRS.
278+
279+
This is usually calculated automatically from the transform's QgsCoordinateTransformContext,
280+
but can be manually overwritten by a call to setDestinationDatumTransform().
281+
282+
.. seealso:: setDestinationDatumTransform()
283+
.. seealso:: sourceDatumTransform()
221284
:rtype: int
222285
%End
223-
void setDestinationDatumTransform( int dt );
286+
287+
void setDestinationDatumTransform( int datum );
288+
%Docstring
289+
Sets the index of the ``datum`` transform to use when projecting to the destination
290+
CRS.
291+
292+
This is usually calculated automatically from the transform's QgsCoordinateTransformContext.
293+
Calling this method will overwrite any automatically calculated datum transform.
294+
295+
.. seealso:: destinationDatumTransform()
296+
.. seealso:: setSourceDatumTransform()
297+
%End
224298

225299
void initialize();
226300
%Docstring

src/core/qgscoordinatetransform.cpp

+22-1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "qgspointxy.h"
2323
#include "qgsrectangle.h"
2424
#include "qgsexception.h"
25+
#include "qgsproject.h"
2526

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

4849
QgsCoordinateTransform::QgsCoordinateTransform( const QgsCoordinateReferenceSystem &source, const QgsCoordinateReferenceSystem &destination )
4950
{
50-
d = new QgsCoordinateTransformPrivate( source, destination );
51+
d = new QgsCoordinateTransformPrivate( source, destination, QgsCoordinateTransformContext() );
52+
}
53+
54+
QgsCoordinateTransform::QgsCoordinateTransform( const QgsCoordinateReferenceSystem &source, const QgsCoordinateReferenceSystem &destination, const QgsCoordinateTransformContext &context )
55+
{
56+
d = new QgsCoordinateTransformPrivate( source, destination, context );
57+
}
58+
59+
QgsCoordinateTransform::QgsCoordinateTransform( const QgsCoordinateReferenceSystem &source, const QgsCoordinateReferenceSystem &destination, const QgsProject *project )
60+
{
61+
d = new QgsCoordinateTransformPrivate( source, destination, project ? project->transformContext() : QgsCoordinateTransformContext() );
5162
}
5263

5364
QgsCoordinateTransform::QgsCoordinateTransform( const QgsCoordinateTransform &o )
@@ -67,12 +78,22 @@ void QgsCoordinateTransform::setSourceCrs( const QgsCoordinateReferenceSystem &c
6778
{
6879
d.detach();
6980
d->mSourceCRS = crs;
81+
d->calculateTransforms();
7082
d->initialize();
7183
}
7284
void QgsCoordinateTransform::setDestinationCrs( const QgsCoordinateReferenceSystem &crs )
7385
{
7486
d.detach();
7587
d->mDestCRS = crs;
88+
d->calculateTransforms();
89+
d->initialize();
90+
}
91+
92+
void QgsCoordinateTransform::setContext( const QgsCoordinateTransformContext &context )
93+
{
94+
d.detach();
95+
d->mContext = context;
96+
d->calculateTransforms();
7697
d->initialize();
7798
}
7899

src/core/qgscoordinatetransform.h

+84-4
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ class QgsCoordinateTransformPrivate;
2727
class QgsPointXY;
2828
class QgsRectangle;
2929
class QPolygonF;
30+
class QgsCoordinateTransformContext;
31+
class QgsProject;
3032

3133
/**
3234
* \ingroup core
@@ -63,8 +65,36 @@ class CORE_EXPORT QgsCoordinateTransform
6365
* \param source source CRS, typically of the layer's coordinate system
6466
* \param destination CRS, typically of the map canvas coordinate system
6567
*/
66-
QgsCoordinateTransform( const QgsCoordinateReferenceSystem &source,
67-
const QgsCoordinateReferenceSystem &destination );
68+
explicit QgsCoordinateTransform( const QgsCoordinateReferenceSystem &source,
69+
const QgsCoordinateReferenceSystem &destination );
70+
71+
/**
72+
* Constructs a QgsCoordinateTransform to transform from the \a source
73+
* to \a destination coordinate reference system.
74+
*
75+
* The \a context argument specifies the context under which the transform
76+
* will be applied, and is used for calculating necessary datum transforms
77+
* to utilise.
78+
*
79+
* \since QGIS 3.0
80+
*/
81+
explicit QgsCoordinateTransform( const QgsCoordinateReferenceSystem &source,
82+
const QgsCoordinateReferenceSystem &destination,
83+
const QgsCoordinateTransformContext &context );
84+
85+
/**
86+
* Constructs a QgsCoordinateTransform to transform from the \a source
87+
* to \a destination coordinate reference system, when used with the
88+
* given \a project.
89+
*
90+
* No reference to \a project is stored or utilised outside of the constructor,
91+
* and it is used to retrieve the project's transform context only.
92+
*
93+
* \since QGIS 3.0
94+
*/
95+
explicit QgsCoordinateTransform( const QgsCoordinateReferenceSystem &source,
96+
const QgsCoordinateReferenceSystem &destination,
97+
const QgsProject *project );
6898

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

134+
/**
135+
* Sets the \a context in which the coordinate transform should be
136+
* calculated.
137+
* \since QGIS 3.0
138+
*/
139+
void setContext( const QgsCoordinateTransformContext &context );
140+
104141
/**
105142
* Returns the source coordinate reference system, which the transform will
106143
* transform coordinates from.
@@ -271,10 +308,53 @@ class CORE_EXPORT QgsCoordinateTransform
271308
\returns epsgNr epsg code of the transformation (or 0 if not in epsg db)*/
272309
static bool datumTransformCrsInfo( int datumTransform, int &epsgNr, QString &srcProjection, QString &dstProjection, QString &remarks, QString &scope, bool &preferred, bool &deprecated );
273310

311+
/**
312+
* Returns the index of the datum transform to use when projecting from the source
313+
* CRS.
314+
*
315+
* This is usually calculated automatically from the transform's QgsCoordinateTransformContext,
316+
* but can be manually overwritten by a call to setSourceDatumTransform().
317+
*
318+
* \see setSourceDatumTransform()
319+
* \see destinationDatumTransform()
320+
*/
274321
int sourceDatumTransform() const;
275-
void setSourceDatumTransform( int dt );
322+
323+
/**
324+
* Sets the index of the \a datum transform to use when projecting from the source
325+
* CRS.
326+
*
327+
* This is usually calculated automatically from the transform's QgsCoordinateTransformContext.
328+
* Calling this method will overwrite any automatically calculated datum transform.
329+
*
330+
* \see sourceDatumTransform()
331+
* \see setDestinationDatumTransform()
332+
*/
333+
void setSourceDatumTransform( int datum );
334+
335+
/**
336+
* Returns the index of the datum transform to use when projecting to the destination
337+
* CRS.
338+
*
339+
* This is usually calculated automatically from the transform's QgsCoordinateTransformContext,
340+
* but can be manually overwritten by a call to setDestinationDatumTransform().
341+
*
342+
* \see setDestinationDatumTransform()
343+
* \see sourceDatumTransform()
344+
*/
276345
int destinationDatumTransform() const;
277-
void setDestinationDatumTransform( int dt );
346+
347+
/**
348+
* Sets the index of the \a datum transform to use when projecting to the destination
349+
* CRS.
350+
*
351+
* This is usually calculated automatically from the transform's QgsCoordinateTransformContext.
352+
* Calling this method will overwrite any automatically calculated datum transform.
353+
*
354+
* \see destinationDatumTransform()
355+
* \see setSourceDatumTransform()
356+
*/
357+
void setDestinationDatumTransform( int datum );
278358

279359
//!initialize is used to actually create the Transformer instance
280360
void initialize();

src/core/qgscoordinatetransform_p.cpp

+28-12
Original file line numberDiff line numberDiff line change
@@ -50,11 +50,15 @@ QgsCoordinateTransformPrivate::QgsCoordinateTransformPrivate()
5050
setFinder();
5151
}
5252

53-
QgsCoordinateTransformPrivate::QgsCoordinateTransformPrivate( const QgsCoordinateReferenceSystem &source, const QgsCoordinateReferenceSystem &destination )
53+
QgsCoordinateTransformPrivate::QgsCoordinateTransformPrivate( const QgsCoordinateReferenceSystem &source,
54+
const QgsCoordinateReferenceSystem &destination,
55+
const QgsCoordinateTransformContext &context )
5456
: mSourceCRS( source )
5557
, mDestCRS( destination )
58+
, mContext( context )
5659
{
5760
setFinder();
61+
calculateTransforms();
5862
initialize();
5963
}
6064

@@ -64,6 +68,7 @@ QgsCoordinateTransformPrivate::QgsCoordinateTransformPrivate( const QgsCoordinat
6468
, mShortCircuit( other.mShortCircuit )
6569
, mSourceCRS( other.mSourceCRS )
6670
, mDestCRS( other.mDestCRS )
71+
, mContext( other.mContext )
6772
, mSourceDatumTransform( other.mSourceDatumTransform )
6873
, mDestinationDatumTransform( other.mDestinationDatumTransform )
6974
{
@@ -101,7 +106,9 @@ bool QgsCoordinateTransformPrivate::initialize()
101106

102107
mIsValid = true;
103108

104-
bool useDefaultDatumTransform = ( mSourceDatumTransform == - 1 && mDestinationDatumTransform == -1 );
109+
int sourceDatumTransform = mSourceDatumTransform;
110+
int destDatumTransform = mDestinationDatumTransform;
111+
bool useDefaultDatumTransform = ( sourceDatumTransform == - 1 && destDatumTransform == -1 );
105112

106113
// init the projections (destination and source)
107114
freeProj();
@@ -111,24 +118,24 @@ bool QgsCoordinateTransformPrivate::initialize()
111118
{
112119
mSourceProjString = stripDatumTransform( mSourceProjString );
113120
}
114-
if ( mSourceDatumTransform != -1 )
121+
if ( sourceDatumTransform != -1 )
115122
{
116-
mSourceProjString += ( ' ' + datumTransformString( mSourceDatumTransform ) );
123+
mSourceProjString += ( ' ' + datumTransformString( sourceDatumTransform ) );
117124
}
118125

119126
mDestProjString = mDestCRS.toProj4();
120127
if ( !useDefaultDatumTransform )
121128
{
122129
mDestProjString = stripDatumTransform( mDestProjString );
123130
}
124-
if ( mDestinationDatumTransform != -1 )
131+
if ( destDatumTransform != -1 )
125132
{
126-
mDestProjString += ( ' ' + datumTransformString( mDestinationDatumTransform ) );
133+
mDestProjString += ( ' ' + datumTransformString( destDatumTransform ) );
127134
}
128135

129136
if ( !useDefaultDatumTransform )
130137
{
131-
addNullGridShifts( mSourceProjString, mDestProjString );
138+
addNullGridShifts( mSourceProjString, mDestProjString, sourceDatumTransform, destDatumTransform );
132139
}
133140

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

195+
void QgsCoordinateTransformPrivate::calculateTransforms()
196+
{
197+
// recalculate datum transforms from context
198+
QPair< int, int > transforms = mContext.calculateDatumTransforms( mSourceCRS, mDestCRS );
199+
mSourceDatumTransform = transforms.first;
200+
mDestinationDatumTransform = transforms.second;
201+
}
202+
188203
QPair<projPJ, projPJ> QgsCoordinateTransformPrivate::threadLocalProjData()
189204
{
190205
mProjLock.lockForRead();
@@ -301,27 +316,28 @@ QString QgsCoordinateTransformPrivate::datumTransformString( int datumTransform
301316
return transformString;
302317
}
303318

304-
void QgsCoordinateTransformPrivate::addNullGridShifts( QString &srcProjString, QString &destProjString ) const
319+
void QgsCoordinateTransformPrivate::addNullGridShifts( QString &srcProjString, QString &destProjString,
320+
int sourceDatumTransform, int destinationDatumTransform ) const
305321
{
306322
//if one transformation uses ntv2, the other one needs to be null grid shift
307-
if ( mDestinationDatumTransform == -1 && srcProjString.contains( QLatin1String( "+nadgrids" ) ) ) //add null grid if source transformation is ntv2
323+
if ( destinationDatumTransform == -1 && srcProjString.contains( QLatin1String( "+nadgrids" ) ) ) //add null grid if source transformation is ntv2
308324
{
309325
destProjString += QLatin1String( " +nadgrids=@null" );
310326
return;
311327
}
312-
if ( mSourceDatumTransform == -1 && destProjString.contains( QLatin1String( "+nadgrids" ) ) )
328+
if ( sourceDatumTransform == -1 && destProjString.contains( QLatin1String( "+nadgrids" ) ) )
313329
{
314330
srcProjString += QLatin1String( " +nadgrids=@null" );
315331
return;
316332
}
317333

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

0 commit comments

Comments
 (0)