Skip to content

Commit

Permalink
Add support for serializing transform contexts
Browse files Browse the repository at this point in the history
  • Loading branch information
nyalldawson committed Dec 15, 2017
1 parent 3d1b8ae commit 1013c0b
Show file tree
Hide file tree
Showing 4 changed files with 169 additions and 1 deletion.
14 changes: 14 additions & 0 deletions python/core/qgscoordinatetransformcontext.sip
Expand Up @@ -11,6 +11,7 @@




class QgsCoordinateTransformContext
{
%Docstring
Expand Down Expand Up @@ -168,6 +169,19 @@ class QgsCoordinateTransformContext
:rtype: QPair< int, int >
%End

void readXml( const QDomElement &element, const QDomDocument &document, const QgsReadWriteContext &context );
%Docstring
Reads the context's state from a DOM ``element``.
.. seealso:: writeXml()
%End

void writeXml( QDomElement &element, QDomDocument &document, const QgsReadWriteContext &context ) const;
%Docstring
Writes the context's state to a DOM ``element``.
.. seealso:: readXml()
%End


};


Expand Down
105 changes: 105 additions & 0 deletions src/core/qgscoordinatetransformcontext.cpp
Expand Up @@ -147,3 +147,108 @@ QPair<int, int> QgsCoordinateTransformContext::calculateDatumTransforms( const Q
d->mLock.unlock();
return qMakePair( srcTransform, destTransform );
}

void QgsCoordinateTransformContext::readXml( const QDomElement &element, const QDomDocument &, const QgsReadWriteContext & )
{
d.detach();
d->mLock.lockForWrite();

d->mSourceDestDatumTransforms.clear();
d->mSourceDatumTransforms.clear();
d->mDestDatumTransforms.clear();

const QDomNodeList contextNodes = element.elementsByTagName( QStringLiteral( "transformContext" ) );
if ( contextNodes.count() < 1 )
{
d->mLock.unlock();
return;
}

const QDomElement contextElem = contextNodes.at( 0 ).toElement();

// src/dest transforms
const QDomNodeList srcDestNodes = contextElem.elementsByTagName( QStringLiteral( "srcDest" ) );
for ( int i = 0; i < srcDestNodes.size(); ++i )
{
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 ), qMakePair( value1, value2 ) );
}
}

// src transforms
const QDomNodeList srcNodes = contextElem.elementsByTagName( QStringLiteral( "source" ) );
for ( int i = 0; i < srcNodes .size(); ++i )
{
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 );
}
}

// dest transforms
const QDomNodeList destNodes = contextElem.elementsByTagName( QStringLiteral( "dest" ) );
for ( int i = 0; i < destNodes.size(); ++i )
{
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 );
}
}

d->mLock.unlock();
}

void QgsCoordinateTransformContext::writeXml( QDomElement &element, QDomDocument &document, const QgsReadWriteContext & ) const
{
d->mLock.lockForRead();

QDomElement contextElem = document.createElement( QStringLiteral( "transformContext" ) );

//src/dest transforms
for ( auto it = d->mSourceDestDatumTransforms.constBegin(); it != d->mSourceDestDatumTransforms.constEnd(); ++ it )
{
QDomElement transformElem = document.createElement( QStringLiteral( "srcDest" ) );
transformElem.setAttribute( QStringLiteral( "source" ), it.key().first );
transformElem.setAttribute( QStringLiteral( "dest" ), it.key().second );
transformElem.setAttribute( QStringLiteral( "sourceTransform" ), it.value().first );
transformElem.setAttribute( QStringLiteral( "destTransform" ), it.value().second );
contextElem.appendChild( transformElem );
}

// src transforms
for ( auto it = d->mSourceDatumTransforms.constBegin(); it != d->mSourceDatumTransforms.constEnd(); ++ it )
{
QDomElement transformElem = document.createElement( QStringLiteral( "source" ) );
transformElem.setAttribute( QStringLiteral( "crs" ), it.key() );
transformElem.setAttribute( QStringLiteral( "transform" ), it.value() );
contextElem.appendChild( transformElem );
}

// dest transforms
for ( auto it = d->mDestDatumTransforms.constBegin(); it != d->mDestDatumTransforms.constEnd(); ++ it )
{
QDomElement transformElem = document.createElement( QStringLiteral( "dest" ) );
transformElem.setAttribute( QStringLiteral( "crs" ), it.key() );
transformElem.setAttribute( QStringLiteral( "transform" ), it.value() );
contextElem.appendChild( transformElem );
}

element.appendChild( contextElem );
d->mLock.unlock();
}
15 changes: 15 additions & 0 deletions src/core/qgscoordinatetransformcontext.h
Expand Up @@ -22,6 +22,8 @@
#include "qgis.h"
#include "qgscoordinatetransformcontext_p.h"

class QgsReadWriteContext;

/***************************************************************************
* This class is considered CRITICAL and any change MUST be accompanied with
* full unit tests in testqgsfeature.cpp.
Expand Down Expand Up @@ -175,6 +177,19 @@ class CORE_EXPORT QgsCoordinateTransformContext
QPair< int, int > calculateDatumTransforms( const QgsCoordinateReferenceSystem &source,
const QgsCoordinateReferenceSystem &destination ) const;

/**
* Reads the context's state from a DOM \a element.
* \see writeXml()
*/
void readXml( const QDomElement &element, const QDomDocument &document, const QgsReadWriteContext &context );

/**
* Writes the context's state to a DOM \a element.
* \see readXml()
*/
void writeXml( QDomElement &element, QDomDocument &document, const QgsReadWriteContext &context ) const;


private:

QExplicitlySharedDataPointer<QgsCoordinateTransformContextPrivate> d;
Expand Down
36 changes: 35 additions & 1 deletion tests/src/python/test_qgscoordinatetransformcontext.py
Expand Up @@ -15,8 +15,10 @@
import qgis # NOQA

from qgis.core import (QgsCoordinateReferenceSystem,
QgsCoordinateTransformContext)
QgsCoordinateTransformContext,
QgsReadWriteContext)
from qgis.testing import start_app, unittest
from qgis.PyQt.QtXml import QDomDocument

app = start_app()

Expand Down Expand Up @@ -180,6 +182,38 @@ def testCalculate(self):
QgsCoordinateReferenceSystem('EPSG:3111')),
(1, -1))

def testWriteReadXml(self):
# setup a context
context = QgsCoordinateTransformContext()
self.assertTrue(context.addSourceDatumTransform(QgsCoordinateReferenceSystem('EPSG:3111'), 1))
self.assertTrue(context.addSourceDatumTransform(QgsCoordinateReferenceSystem('EPSG:28356'), 2))
self.assertTrue(context.addDestinationDatumTransform(QgsCoordinateReferenceSystem('EPSG:3113'), 11))
self.assertTrue(context.addDestinationDatumTransform(QgsCoordinateReferenceSystem('EPSG:28355'), 12))
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.sourceDatumTransforms(), {'EPSG:3111': 1, 'EPSG:28356': 2})
self.assertEqual(context.destinationDatumTransforms(), {'EPSG:3113': 11, 'EPSG:28355': 12})
self.assertEqual(context.sourceDestinationDatumTransforms(), {('EPSG:3111', 'EPSG:4283'): (1, 2),
('EPSG:28356', 'EPSG:4283'): (3, 4)})

# save to xml
doc = QDomDocument("testdoc")
elem = doc.createElement("test")
context.writeXml(elem, doc, QgsReadWriteContext())

# restore from xml
context2 = QgsCoordinateTransformContext()
context2.readXml(elem, doc, QgsReadWriteContext())

# check result
self.assertEqual(context2.sourceDatumTransforms(), {'EPSG:3111': 1, 'EPSG:28356': 2})
self.assertEqual(context2.destinationDatumTransforms(), {'EPSG:3113': 11, 'EPSG:28355': 12})
self.assertEqual(context2.sourceDestinationDatumTransforms(), {('EPSG:3111', 'EPSG:4283'): (1, 2),
('EPSG:28356', 'EPSG:4283'): (3, 4)})


if __name__ == '__main__':
unittest.main()

0 comments on commit 1013c0b

Please sign in to comment.