Skip to content

Commit

Permalink
Use proj strings to serialize datum transforms IDs
Browse files Browse the repository at this point in the history
Since datum transforms IDs are local only, and can even change
when underlying library versions are updated, we can't use them
to safely store and retrieve datum transforms.

Instead we use the proj strings and recover the local session
transform ID from that.
  • Loading branch information
nyalldawson committed Dec 15, 2017
1 parent 3187352 commit 6ff744a
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 44 deletions.
70 changes: 42 additions & 28 deletions src/core/qgscoordinatetransformcontext.cpp
Expand Up @@ -188,14 +188,18 @@ void QgsCoordinateTransformContext::readXml( const QDomElement &element, const Q
const QDomElement transformElem = srcDestNodes.at( i ).toElement();
QString key1 = transformElem.attribute( QStringLiteral( "source" ) );
QString key2 = transformElem.attribute( QStringLiteral( "dest" ) );
bool ok = false;
int value1 = transformElem.attribute( QStringLiteral( "sourceTransform" ) ).toInt( &ok );
bool ok2 = false;
int value2 = transformElem.attribute( QStringLiteral( "destTransform" ) ).toInt( &ok2 );
if ( ok && ok2 )
{
d->mSourceDestDatumTransforms.insert( qMakePair( key1, key2 ), QgsCoordinateTransform::TransformPair( value1, value2 ) );
}

QString value1 = transformElem.attribute( QStringLiteral( "sourceTransform" ) );
QString value2 = transformElem.attribute( QStringLiteral( "destTransform" ) );

int datumId1 = -1;
int datumId2 = -1;
if ( !value1.isEmpty() )
datumId1 = QgsCoordinateTransform::projStringToDatumTransformId( value1 );
if ( !value2.isEmpty() )
datumId2 = QgsCoordinateTransform::projStringToDatumTransformId( value2 );
//TODO - throw warning if value1 or value2 is non-empty, yet no matching transform was found
d->mSourceDestDatumTransforms.insert( qMakePair( key1, key2 ), QgsCoordinateTransform::TransformPair( datumId1, datumId2 ) );
}

#if 0
Expand All @@ -205,12 +209,13 @@ void QgsCoordinateTransformContext::readXml( const QDomElement &element, const Q
{
const QDomElement transformElem = srcNodes.at( i ).toElement();
QString key = transformElem.attribute( QStringLiteral( "crs" ) );
bool ok = false;
int value = transformElem.attribute( QStringLiteral( "transform" ) ).toInt( &ok );
if ( ok )
{
d->mSourceDatumTransforms.insert( key, value );
}
QString value = transformElem.attribute( QStringLiteral( "transform" ) );
if ( value.isEmpty() )
continue;

int datumId = QgsCoordinateTransform::projStringToDatumTransformId( value );
//TODO - throw warning if datumId is -1
d->mSourceDatumTransforms.insert( key, datumId );
}

// dest transforms
Expand All @@ -219,12 +224,13 @@ void QgsCoordinateTransformContext::readXml( const QDomElement &element, const Q
{
const QDomElement transformElem = destNodes.at( i ).toElement();
QString key = transformElem.attribute( QStringLiteral( "crs" ) );
bool ok = false;
int value = transformElem.attribute( QStringLiteral( "transform" ) ).toInt( &ok );
if ( ok )
{
d->mDestDatumTransforms.insert( key, value );
}
QString value = transformElem.attribute( QStringLiteral( "transform" ) );
if ( value.isEmpty() )
continue;

int datumId = QgsCoordinateTransform::projStringToDatumTransformId( value );
//TODO - throw warning if datumId is -1
d->mDestDatumTransforms.insert( key, datumId );
}
#endif

Expand All @@ -243,8 +249,8 @@ void QgsCoordinateTransformContext::writeXml( QDomElement &element, const QgsRea
QDomElement transformElem = element.ownerDocument().createElement( QStringLiteral( "srcDest" ) );
transformElem.setAttribute( QStringLiteral( "source" ), it.key().first );
transformElem.setAttribute( QStringLiteral( "dest" ), it.key().second );
transformElem.setAttribute( QStringLiteral( "sourceTransform" ), it.value().sourceTransformId );
transformElem.setAttribute( QStringLiteral( "destTransform" ), it.value().destinationTransformId );
transformElem.setAttribute( QStringLiteral( "sourceTransform" ), it.value().sourceTransformId < 0 ? QString() : QgsCoordinateTransform::datumTransformToProj( it.value().sourceTransformId ) );
transformElem.setAttribute( QStringLiteral( "destTransform" ), it.value().destinationTransformId < 0 ? QString() : QgsCoordinateTransform::datumTransformToProj( it.value().destinationTransformId ) );
contextElem.appendChild( transformElem );
}

Expand All @@ -254,7 +260,7 @@ void QgsCoordinateTransformContext::writeXml( QDomElement &element, const QgsRea
{
QDomElement transformElem = element.ownerDocument().createElement( QStringLiteral( "source" ) );
transformElem.setAttribute( QStringLiteral( "crs" ), it.key() );
transformElem.setAttribute( QStringLiteral( "transform" ), it.value() );
transformElem.setAttribute( QStringLiteral( "transform" ), it.value() < 0 ? QString() : it.value() );
contextElem.appendChild( transformElem );
}

Expand All @@ -263,7 +269,7 @@ void QgsCoordinateTransformContext::writeXml( QDomElement &element, const QgsRea
{
QDomElement transformElem = element.ownerDocument().createElement( QStringLiteral( "dest" ) );
transformElem.setAttribute( QStringLiteral( "crs" ), it.key() );
transformElem.setAttribute( QStringLiteral( "transform" ), it.value() );
transformElem.setAttribute( QStringLiteral( "transform" ), it.value() < 0 ? QString() : it.value() );
contextElem.appendChild( transformElem );
}
#endif
Expand Down Expand Up @@ -305,13 +311,15 @@ void QgsCoordinateTransformContext::readSettings()
destAuthId = split.at( 1 ).split( '_' ).at( 0 );
}

QString proj = settings.value( *pkeyIt ).toString();
int datumId = QgsCoordinateTransform::projStringToDatumTransformId( proj );
if ( pkeyIt->contains( QLatin1String( "srcTransform" ) ) )
{
transforms[ qMakePair( srcAuthId, destAuthId )].first = settings.value( *pkeyIt ).toInt();
transforms[ qMakePair( srcAuthId, destAuthId )].first = datumId;
}
else if ( pkeyIt->contains( QLatin1String( "destTransform" ) ) )
{
transforms[ qMakePair( srcAuthId, destAuthId )].second = settings.value( *pkeyIt ).toInt();
transforms[ qMakePair( srcAuthId, destAuthId )].second = datumId;
}
}
}
Expand Down Expand Up @@ -346,10 +354,16 @@ void QgsCoordinateTransformContext::writeSettings()
QString srcAuthId = transformIt.key().first;
QString destAuthId = transformIt.key().second;
int sourceDatumTransform = transformIt.value().sourceTransformId;
QString sourceDatumProj;
if ( sourceDatumTransform >= 0 )
sourceDatumProj = QgsCoordinateTransform::datumTransformToProj( sourceDatumTransform );
int destinationDatumTransform = transformIt.value().destinationTransformId;
QString destinationDatumProj;
if ( destinationDatumTransform >= 0 )
destinationDatumProj = QgsCoordinateTransform::datumTransformToProj( destinationDatumTransform );

settings.setValue( srcAuthId + "//" + destAuthId + "_srcTransform", sourceDatumTransform );
settings.setValue( srcAuthId + "//" + destAuthId + "_destTransform", destinationDatumTransform );
settings.setValue( srcAuthId + "//" + destAuthId + "_srcTransform", sourceDatumProj );
settings.setValue( srcAuthId + "//" + destAuthId + "_destTransform", destinationDatumProj );
}

settings.endGroup();
Expand Down
54 changes: 38 additions & 16 deletions tests/src/python/test_qgscoordinatetransformcontext.py
Expand Up @@ -300,13 +300,24 @@ def testWriteReadXmlSingleVariant(self):
def testWriteReadXml(self):
# setup a context
context = QgsCoordinateTransformContext()
self.assertTrue(context.addSourceDestinationDatumTransform(QgsCoordinateReferenceSystem('EPSG:3111'),
QgsCoordinateReferenceSystem('EPSG:4283'), 1, 2))
self.assertTrue(context.addSourceDestinationDatumTransform(QgsCoordinateReferenceSystem('EPSG:28356'),
QgsCoordinateReferenceSystem(4283), 3, 4))

self.assertEqual(context.sourceDestinationDatumTransforms(), {('EPSG:3111', 'EPSG:4283'): QgsCoordinateTransform.TransformPair(1, 2),
('EPSG:28356', 'EPSG:4283'): QgsCoordinateTransform.TransformPair(3, 4)})
source_id_1 = QgsCoordinateTransform.datumTransformations(QgsCoordinateReferenceSystem(4204),
QgsCoordinateReferenceSystem(4326))[0].sourceTransformId
dest_id_1 = QgsCoordinateTransform.datumTransformations(QgsCoordinateReferenceSystem(4204),
QgsCoordinateReferenceSystem(4326))[0].destinationTransformId

source_id_2 = QgsCoordinateTransform.datumTransformations(QgsCoordinateReferenceSystem(4205),
QgsCoordinateReferenceSystem(4326))[0].sourceTransformId
dest_id_2 = QgsCoordinateTransform.datumTransformations(QgsCoordinateReferenceSystem(4205),
QgsCoordinateReferenceSystem(4326))[0].destinationTransformId

self.assertTrue(context.addSourceDestinationDatumTransform(QgsCoordinateReferenceSystem(4204),
QgsCoordinateReferenceSystem(4326), source_id_1, dest_id_1))
self.assertTrue(context.addSourceDestinationDatumTransform(QgsCoordinateReferenceSystem(4205),
QgsCoordinateReferenceSystem(4326), source_id_2, dest_id_2))

self.assertEqual(context.sourceDestinationDatumTransforms(), {('EPSG:4204', 'EPSG:4326'): QgsCoordinateTransform.TransformPair(source_id_1, dest_id_1),
('EPSG:4205', 'EPSG:4326'): QgsCoordinateTransform.TransformPair(source_id_2, dest_id_2)})

# save to xml
doc = QDomDocument("testdoc")
Expand All @@ -318,8 +329,8 @@ def testWriteReadXml(self):
context2.readXml(elem, QgsReadWriteContext())

# check result
self.assertEqual(context2.sourceDestinationDatumTransforms(), {('EPSG:3111', 'EPSG:4283'): QgsCoordinateTransform.TransformPair(1, 2),
('EPSG:28356', 'EPSG:4283'): QgsCoordinateTransform.TransformPair(3, 4)})
self.assertEqual(context2.sourceDestinationDatumTransforms(), {('EPSG:4204', 'EPSG:4326'): QgsCoordinateTransform.TransformPair(source_id_1, dest_id_1),
('EPSG:4205', 'EPSG:4326'): QgsCoordinateTransform.TransformPair(source_id_2, dest_id_2)})

def testProject(self):
"""
Expand All @@ -337,17 +348,28 @@ def testProject(self):
def testReadWriteSettings(self):
context = QgsCoordinateTransformContext()
context.readSettings()

source_id_1 = QgsCoordinateTransform.datumTransformations(QgsCoordinateReferenceSystem(4204),
QgsCoordinateReferenceSystem(4326))[0].sourceTransformId
dest_id_1 = QgsCoordinateTransform.datumTransformations(QgsCoordinateReferenceSystem(4204),
QgsCoordinateReferenceSystem(4326))[0].destinationTransformId

source_id_2 = QgsCoordinateTransform.datumTransformations(QgsCoordinateReferenceSystem(4205),
QgsCoordinateReferenceSystem(4326))[0].sourceTransformId
dest_id_2 = QgsCoordinateTransform.datumTransformations(QgsCoordinateReferenceSystem(4205),
QgsCoordinateReferenceSystem(4326))[0].destinationTransformId

# should be empty
self.assertEqual(context.sourceDestinationDatumTransforms(), {})

self.assertTrue(context.addSourceDestinationDatumTransform(QgsCoordinateReferenceSystem('EPSG:3111'),
QgsCoordinateReferenceSystem('EPSG:4283'), 1, 2))
self.assertTrue(context.addSourceDestinationDatumTransform(QgsCoordinateReferenceSystem('EPSG:28356'),
QgsCoordinateReferenceSystem(4283), 3, 4))
self.assertTrue(context.addSourceDestinationDatumTransform(QgsCoordinateReferenceSystem('EPSG:4204'),
QgsCoordinateReferenceSystem('EPSG:4326'), source_id_1, dest_id_1))
self.assertTrue(context.addSourceDestinationDatumTransform(QgsCoordinateReferenceSystem('EPSG:4205'),
QgsCoordinateReferenceSystem(4326), source_id_2, dest_id_2))

self.assertEqual(context.sourceDestinationDatumTransforms(),
{('EPSG:3111', 'EPSG:4283'): QgsCoordinateTransform.TransformPair(1, 2),
('EPSG:28356', 'EPSG:4283'): QgsCoordinateTransform.TransformPair(3, 4)})
{('EPSG:4204', 'EPSG:4326'): QgsCoordinateTransform.TransformPair(source_id_1, dest_id_1),
('EPSG:4205', 'EPSG:4326'): QgsCoordinateTransform.TransformPair(source_id_2, dest_id_2)})

# save to settings
context.writeSettings()
Expand All @@ -359,8 +381,8 @@ def testReadWriteSettings(self):

# check result
self.assertEqual(context2.sourceDestinationDatumTransforms(),
{('EPSG:3111', 'EPSG:4283'): QgsCoordinateTransform.TransformPair(1, 2),
('EPSG:28356', 'EPSG:4283'): QgsCoordinateTransform.TransformPair(3, 4)})
{('EPSG:4204', 'EPSG:4326'): QgsCoordinateTransform.TransformPair(source_id_1, dest_id_1),
('EPSG:4205', 'EPSG:4326'): QgsCoordinateTransform.TransformPair(source_id_2, dest_id_2)})


if __name__ == '__main__':
Expand Down

0 comments on commit 6ff744a

Please sign in to comment.