Skip to content

Commit

Permalink
Nicer API for datum transforms
Browse files Browse the repository at this point in the history
Instead of using QPairs of ints, use more descriptive structs, also
rename a lot of datum related methods for clarity and add docs
  • Loading branch information
nyalldawson committed Dec 15, 2017
1 parent ed0c93f commit 69c3deb
Show file tree
Hide file tree
Showing 24 changed files with 512 additions and 224 deletions.
8 changes: 8 additions & 0 deletions doc/api_break.dox
Expand Up @@ -935,6 +935,14 @@ plugins calling these methods will need to be updated.
- 'theNode', 'theDoc' parameters in readXML and writeXML have been renamed to 'node' and 'document' respectively
- readXML() and writeXML() have been removed.
- initialize() was removed.
- datumTransformations() now returns a list of QgsCoordinateTransform.TransformPair instead of a list of lists.
- datumTransformString() was renamed to datumTransformToProj()
- datumTransformCrsInfo() was renamed to datumTransformInfo(), and now returns a QgsCoordinateTransform.TransformInfo object.
- sourceDatumTransform() was renamed to sourceDatumTransformId()
- setSourceDatumTransform() was renamed to setSourceDatumTransformId()
- destinationDatumTransform() was renamed to destinationDatumTransformId()
- setDestinationDatumTransform() was renamed to setDestinationDatumTransformId()


QgsCoordinateTransformCache {#qgis_api_break_3_0_QgsCoordinateTransformCache}
---------------------------
Expand Down
124 changes: 124 additions & 0 deletions python/core/conversions.sip
Expand Up @@ -1848,6 +1848,130 @@ template<int, TYPE2*>
%End
};

template <TYPE>
%MappedType QMap< QPair< QString, QString>, TYPE >
{
%TypeHeaderCode
#include <QPair>
#include <QMap>
%End

%ConvertFromTypeCode
//convert map to a python dictionary
PyObject *d;

if ( ( d = PyDict_New() ) == NULL )
return NULL;

for ( auto it = sipCpp->constBegin(); it != sipCpp->constEnd(); ++ it )
{
PyObject *keyobj;
if ( ( keyobj = PyTuple_New( 2 ) ) == NULL )
{
Py_DECREF( d );
return NULL;
}

TYPE *t = new TYPE(it.value());
PyObject *tobj = sipConvertFromNewType(t, sipType_TYPE, sipTransferObj);
if ( tobj == NULL )
{
Py_DECREF(d);
delete t;
return NULL;
}

// build key
PyObject *k1obj = sipConvertFromNewType( new QString( it.key().first ), sipType_QString, sipTransferObj );
PyTuple_SetItem( keyobj, 0, k1obj );
PyObject *k2obj = sipConvertFromNewType( new QString( it.key().second ), sipType_QString, sipTransferObj );
PyTuple_SetItem( keyobj, 1, k2obj );

if(keyobj == NULL || tobj == NULL || PyDict_SetItem(d, keyobj, tobj) < 0)
{
Py_DECREF(d);

if (keyobj)
{
Py_DECREF(keyobj);
}

if (tobj)
{
Py_DECREF(tobj);
}
return NULL;
}

Py_DECREF(keyobj);
Py_DECREF(tobj);
}

return d;
%End

%ConvertToTypeCode
Py_ssize_t i = 0;
PyObject *kobj, *tobj;

// Check the type if that is all that is required.
if (sipIsErr == NULL)
{
if (!PyDict_Check(sipPy))
return 0;

while (PyDict_Next(sipPy, &i, &kobj, &tobj))
if (!sipCanConvertToType(tobj, sipType_TYPE, SIP_NOT_NONE))
return 0;

return 1;
}

PyObject *t1obj, *t2obj;
QMap< QPair< QString, QString>, TYPE > *qm = new QMap< QPair< QString, QString>, TYPE >;

int state;
while (PyDict_Next(sipPy, &i, &t1obj, &t2obj))
{
PyObject *sipKeyFirst = PyTuple_GetItem( t1obj, 0 );
PyObject *sipKeySecond = PyTuple_GetItem( t1obj, 1 );
QString *k1 = reinterpret_cast<QString *>(sipConvertToType(sipKeyFirst, sipType_QString, sipTransferObj, SIP_NOT_NONE, &state, sipIsErr));
if (*sipIsErr)
{
sipReleaseType(k1, sipType_QString, state);
delete qm;
return 0;
}

QString *k2 = reinterpret_cast<QString *>(sipConvertToType(sipKeySecond, sipType_QString, sipTransferObj, SIP_NOT_NONE, &state, sipIsErr));
if (*sipIsErr)
{
sipReleaseType(k1, sipType_QString, state);
sipReleaseType(k2, sipType_QString, state);
delete qm;
return 0;
}

TYPE *t = reinterpret_cast<TYPE *>(sipConvertToType(t2obj, sipType_TYPE, sipTransferObj, SIP_NOT_NONE, &state, sipIsErr));
if (*sipIsErr)
{
sipReleaseType(t, sipType_TYPE, state);

delete qm;
return 0;
}

qm->insert( qMakePair( *k1,*k2 ), *t );
sipReleaseType(k1, sipType_QString, state);
sipReleaseType(k2, sipType_QString, state);
sipReleaseType(t, sipType_TYPE, state);
}

*sipCppPtr = qm;

return sipGetState( sipTransferObj );
%End
};

template <TYPE>
%MappedType QVector< TYPE* >
Expand Down
18 changes: 9 additions & 9 deletions python/core/qgscoordinatetransformcontext.sip
Expand Up @@ -64,31 +64,31 @@ class QgsCoordinateTransformContext



QMap< QPair< QString, QString>, QPair< int, int > > sourceDestinationDatumTransforms() const;
QMap< QPair< QString, QString>, QgsCoordinateTransform::TransformPair > sourceDestinationDatumTransforms() const;
%Docstring
Returns the stored mapping for source to destination CRS pairs to associated datum transforms to use.
The map keys will be QgsCoordinateReferenceSystems.authid()s.

If either the source transform or destination transform is -1, then no datum transform is
If either the source transform ID or destination transform ID is -1, then no datum transform is
required for transformations for that source or destination.

\warning This method should not be used to calculate the corresponding datum transforms
to use for a coordinate transform. Instead, always use calculateDatumTransforms()
to determine this.

.. seealso:: addSourceDestinationDatumTransform()
:rtype: QMap< QPair< str, QString>, QPair< int, int > >
:rtype: QMap< QPair< str, QString>, QgsCoordinateTransform.TransformPair >
%End

bool addSourceDestinationDatumTransform( const QgsCoordinateReferenceSystem &sourceCrs,
const QgsCoordinateReferenceSystem &destinationCrs,
int sourceTransform,
int destinationTransform );
int sourceTransformId,
int destinationTransformId );
%Docstring
Adds a new ``sourceTransform`` and ``destinationTransform`` to use when projecting coordinates
from the the specified ``sourceCrs`` to the specified ``destinationCrs``.

If either ``sourceTransform`` or ``destinationTransform`` is -1, then no datum transform is
If either ``sourceTransformId`` or ``destinationTransformId`` is -1, then no datum transform is
required for transformations for that source or destination.

Returns true if the new transform pair was added successfully.
Expand Down Expand Up @@ -122,19 +122,19 @@ class QgsCoordinateTransformContext
:rtype: bool
%End

QPair< int, int > calculateDatumTransforms( const QgsCoordinateReferenceSystem &source,
QgsCoordinateTransform::TransformPair calculateDatumTransforms( const QgsCoordinateReferenceSystem &source,
const QgsCoordinateReferenceSystem &destination ) const;
%Docstring
Returns the pair of source and destination datum transforms to use
for a transform from the specified ``source`` CRS to ``destination`` CRS.

Returns -1 if a datum transform should not be used for the source or
Returns an ID of -1 if a datum transform should not be used for the source or
destination.

.. note::

source and destination are reversible.
:rtype: QPair< int, int >
:rtype: QgsCoordinateTransform.TransformPair
%End

void readXml( const QDomElement &element, const QDomDocument &document, const QgsReadWriteContext &context );
Expand Down
2 changes: 1 addition & 1 deletion src/3d/qgs3dmapsettings.cpp
Expand Up @@ -85,7 +85,7 @@ void Qgs3DMapSettings::readXml( const QDomElement &elem, const QgsReadWriteConte
if ( terrainGenType == "dem" )
{
QgsDemTerrainGenerator *demTerrainGenerator = new QgsDemTerrainGenerator;
demTerrainGenerator->setCrs( mCrs );
demTerrainGenerator->setCrs( mCrs, mTransformContext );
mTerrainGenerator.reset( demTerrainGenerator );
}
else if ( terrainGenType == "quantized-mesh" )
Expand Down
4 changes: 2 additions & 2 deletions src/3d/qgs3dutils.cpp
Expand Up @@ -294,14 +294,14 @@ QgsVector3D Qgs3DUtils::worldToMapCoordinates( const QgsVector3D &worldCoords, c
worldCoords.y() + origin.z() );
}

QgsVector3D Qgs3DUtils::transformWorldCoordinates( const QgsVector3D &worldPoint1, const QgsVector3D &origin1, const QgsCoordinateReferenceSystem &crs1, const QgsVector3D &origin2, const QgsCoordinateReferenceSystem &crs2 )
QgsVector3D Qgs3DUtils::transformWorldCoordinates( const QgsVector3D &worldPoint1, const QgsVector3D &origin1, const QgsCoordinateReferenceSystem &crs1, const QgsVector3D &origin2, const QgsCoordinateReferenceSystem &crs2, const QgsCoordinateTransformContext &context )
{
QgsVector3D mapPoint1 = worldToMapCoordinates( worldPoint1, origin1 );
QgsVector3D mapPoint2 = mapPoint1;
if ( crs1 != crs2 )
{
// reproject if necessary
QgsCoordinateTransform ct( crs1, crs2 );
QgsCoordinateTransform ct( crs1, crs2, context );
try
{
QgsPointXY pt = ct.transform( QgsPointXY( mapPoint1.x(), mapPoint1.y() ) );
Expand Down
3 changes: 2 additions & 1 deletion src/3d/qgs3dutils.h
Expand Up @@ -98,7 +98,8 @@ class _3D_EXPORT Qgs3DUtils
static QgsVector3D worldToMapCoordinates( const QgsVector3D &worldCoords, const QgsVector3D &origin );

//! Transforms a world point from (origin1, crs1) to (origin2, crs2)
static QgsVector3D transformWorldCoordinates( const QgsVector3D &worldPoint1, const QgsVector3D &origin1, const QgsCoordinateReferenceSystem &crs1, const QgsVector3D &origin2, const QgsCoordinateReferenceSystem &crs2 );
static QgsVector3D transformWorldCoordinates( const QgsVector3D &worldPoint1, const QgsVector3D &origin1, const QgsCoordinateReferenceSystem &crs1, const QgsVector3D &origin2, const QgsCoordinateReferenceSystem &crs2,
const QgsCoordinateTransformContext &context );
};

#endif // QGS3DUTILS_H
5 changes: 3 additions & 2 deletions src/3d/terrain/qgsdemterraingenerator.cpp
Expand Up @@ -35,9 +35,10 @@ QgsRasterLayer *QgsDemTerrainGenerator::layer() const
return qobject_cast<QgsRasterLayer *>( mLayer.layer.data() );
}

void QgsDemTerrainGenerator::setCrs( const QgsCoordinateReferenceSystem &crs )
void QgsDemTerrainGenerator::setCrs( const QgsCoordinateReferenceSystem &crs, const QgsCoordinateTransformContext &context )
{
mCrs = crs;
mTransformContext = context;
updateGenerator();
}

Expand Down Expand Up @@ -103,7 +104,7 @@ void QgsDemTerrainGenerator::updateGenerator()
if ( dem )
{
QgsRectangle te = dem->extent();
QgsCoordinateTransform terrainToMapTransform( dem->crs(), mCrs );
QgsCoordinateTransform terrainToMapTransform( dem->crs(), mCrs, mTransformContext );
te = terrainToMapTransform.transformBoundingBox( te );

mTerrainTilingScheme = QgsTilingScheme( te, mCrs );
Expand Down
5 changes: 4 additions & 1 deletion src/3d/terrain/qgsdemterraingenerator.h
Expand Up @@ -46,7 +46,7 @@ class _3D_EXPORT QgsDemTerrainGenerator : public QgsTerrainGenerator
QgsRasterLayer *layer() const;

//! Sets CRS of the terrain
void setCrs( const QgsCoordinateReferenceSystem &crs );
void setCrs( const QgsCoordinateReferenceSystem &crs, const QgsCoordinateTransformContext &context );

//! Sets resolution of the generator (how many elevation samples on one side of a terrain tile)
void setResolution( int resolution ) { mResolution = resolution; updateGenerator(); }
Expand Down Expand Up @@ -77,6 +77,9 @@ class _3D_EXPORT QgsDemTerrainGenerator : public QgsTerrainGenerator
QgsDemHeightMapGenerator *mHeightMapGenerator = nullptr;

QgsCoordinateReferenceSystem mCrs;

QgsCoordinateTransformContext mTransformContext;

//! source layer for heights
QgsMapLayerRef mLayer;
//! how many vertices to place on one side of the tile
Expand Down
2 changes: 1 addition & 1 deletion src/app/3d/qgs3dmapcanvasdockwidget.cpp
Expand Up @@ -119,7 +119,7 @@ void Qgs3DMapCanvasDockWidget::configure()
QgsVector3D p = Qgs3DUtils::transformWorldCoordinates(
oldLookingAt,
oldOrigin, oldCrs,
map->origin(), map->crs() );
map->origin(), map->crs(), QgsProject::instance()->transformContext() );

if ( p != oldLookingAt )
{
Expand Down
6 changes: 3 additions & 3 deletions src/app/3d/qgs3dmapconfigwidget.cpp
Expand Up @@ -90,7 +90,7 @@ void Qgs3DMapConfigWidget::apply()
if ( tGenNeedsUpdate )
{
QgsDemTerrainGenerator *demTerrainGen = new QgsDemTerrainGenerator;
demTerrainGen->setCrs( mMap->crs() );
demTerrainGen->setCrs( mMap->crs(), QgsProject::instance()->transformContext() );
demTerrainGen->setLayer( demLayer );
demTerrainGen->setResolution( spinTerrainResolution->value() );
demTerrainGen->setSkirtHeight( spinTerrainSkirtHeight->value() );
Expand All @@ -111,7 +111,7 @@ void Qgs3DMapConfigWidget::apply()
{
// reproject terrain's extent to map CRS
QgsRectangle te = mMap->terrainGenerator()->extent();
QgsCoordinateTransform terrainToMapTransform( mMap->terrainGenerator()->crs(), mMap->crs() );
QgsCoordinateTransform terrainToMapTransform( mMap->terrainGenerator()->crs(), mMap->crs(), QgsProject::instance() );
te = terrainToMapTransform.transformBoundingBox( te );

QgsPointXY center = te.center();
Expand Down Expand Up @@ -140,7 +140,7 @@ void Qgs3DMapConfigWidget::updateMaxZoomLevel()
if ( demLayer )
{
QgsDemTerrainGenerator *demTerrainGen = new QgsDemTerrainGenerator;
demTerrainGen->setCrs( mMap->crs() );
demTerrainGen->setCrs( mMap->crs(), QgsProject::instance()->transformContext() );
demTerrainGen->setLayer( demLayer );
demTerrainGen->setResolution( spinTerrainResolution->value() );
tGen.reset( demTerrainGen );
Expand Down
10 changes: 5 additions & 5 deletions src/app/qgsdatumtransformtablewidget.cpp
Expand Up @@ -85,9 +85,9 @@ QVariant QgsDatumTransformTableModel::data( const QModelIndex &index, int role )
QPair< QString, QString> crses = mTransformContext.sourceDestinationDatumTransforms().keys().at( index.row() );
sourceCrs = crses.first;
destinationCrs = crses.second;
QPair< int, int> transforms = mTransformContext.sourceDestinationDatumTransforms().value( crses );
sourceTransform = transforms.first;
destinationTransform = transforms.second;
const QgsCoordinateTransform::TransformPair transforms = mTransformContext.sourceDestinationDatumTransforms().value( crses );
sourceTransform = transforms.sourceTransformId;
destinationTransform = transforms.destinationTransformId;
#ifdef singlesourcedest
}
#endif
Expand All @@ -110,7 +110,7 @@ QVariant QgsDatumTransformTableModel::data( const QModelIndex &index, int role )
case SourceTransformColumn:
if ( sourceTransform != -1 )
{
return QgsCoordinateTransform::datumTransformString( sourceTransform );
return QgsCoordinateTransform::datumTransformToProj( sourceTransform );
}
break;
case DestinationCrsColumn:
Expand All @@ -119,7 +119,7 @@ QVariant QgsDatumTransformTableModel::data( const QModelIndex &index, int role )
case DestinationTransformColumn:
if ( destinationTransform != -1 )
{
return QgsCoordinateTransform::datumTransformString( destinationTransform );
return QgsCoordinateTransform::datumTransformToProj( destinationTransform );
}
break;
default:
Expand Down

0 comments on commit 69c3deb

Please sign in to comment.