Skip to content
Permalink
Browse files

Nicer API for datum transforms

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 1, 2017
1 parent ed0c93f commit 69c3debfc031992315af6032cf633b0ca4036cf7
@@ -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}
---------------------------
@@ -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* >
@@ -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.
@@ -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 );
@@ -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" )
@@ -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() ) );
@@ -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
@@ -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();
}

@@ -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 );
@@ -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(); }
@@ -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
@@ -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 )
{
@@ -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() );
@@ -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();
@@ -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 );
@@ -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
@@ -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:
@@ -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:

0 comments on commit 69c3deb

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