Move all datum transform related methods to QgsDatumTransform

This commit is contained in:
Nyall Dawson 2017-12-19 08:47:02 +10:00
parent e678bfa042
commit f216b188d6
18 changed files with 416 additions and 390 deletions

View File

@ -935,9 +935,9 @@ 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.
- datumTransformations() was moved to QgsDatumTransform, and now returns a list of QgsDatumTransform.TransformPair instead of a list of lists.
- datumTransformString() was moved to QgsDatumTransform and renamed to datumTransformToProj()
- datumTransformCrsInfo() was moved to QgsDatumTransform and renamed to datumTransformInfo(), and now returns a QgsDatumTransform.TransformInfo object.
- sourceDatumTransform() was renamed to sourceDatumTransformId()
- setSourceDatumTransform() was renamed to setSourceDatumTransformId()
- destinationDatumTransform() was renamed to destinationDatumTransformId()

View File

@ -28,6 +28,10 @@ transforms coordinates from the layer's coordinate system to the map canvas.
.. note::
Since QGIS 3.0 QgsCoordinateReferenceSystem objects are implicitly shared.
.. seealso:: :py:class:`QgsDatumTransform`
.. seealso:: :py:class:`QgsCoordinateTransformContext`
%End
%TypeHeaderCode
@ -252,47 +256,6 @@ otherwise points are transformed from destination to source CRS.
bool isShortCircuited() const;
%Docstring
Returns true if the transform short circuits because the source and destination are equivalent.
%End
static QList< QgsDatumTransform::TransformPair > datumTransformations( const QgsCoordinateReferenceSystem &source, const QgsCoordinateReferenceSystem &destination );
%Docstring
Returns a list of datum transformations which are available for the given ``source`` and ``destination`` CRS.
.. seealso:: :py:func:`datumTransformToProj()`
.. seealso:: :py:func:`datumTransformInfo()`
%End
static QString datumTransformToProj( int datumTransformId );
%Docstring
Returns a proj string representing the specified ``datumTransformId`` datum transform ID.
.. seealso:: :py:func:`datumTransformations()`
.. seealso:: :py:func:`datumTransformInfo()`
.. seealso:: :py:func:`projStringToDatumTransformId()`
%End
static int projStringToDatumTransformId( const QString &string );
%Docstring
Returns the datum transform ID corresponding to a specified proj ``string``.
Returns -1 if matching datum ID was not found.
.. seealso:: :py:func:`datumTransformToProj()`
.. versionadded:: 3.0
%End
static QgsDatumTransform::TransformInfo datumTransformInfo( int datumTransformId );
%Docstring
Returns detailed information about the specified ``datumTransformId``.
If ``datumTransformId`` was not a valid transform ID, a TransformInfo with TransformInfo.datumTransformId of
-1 will be returned.
.. seealso:: :py:func:`datumTransformations()`
.. seealso:: :py:func:`datumTransformToProj()`
%End
int sourceDatumTransformId() const;

View File

@ -37,6 +37,11 @@ applies for destination CRS transforms set using addDestinationDatumTransform().
QgsCoordinateTransformContext objects are implicitly shared.
.. seealso:: :py:class:`QgsDatumTransform`
.. seealso:: :py:class:`QgsCoordinateTransform`
.. versionadded:: 3.0
%End

View File

@ -8,11 +8,17 @@
class QgsDatumTransform
{
%Docstring
Contains methods and classes relating the datum transformations.
.. seealso:: :py:class:`QgsCoordinateTransformContext`
.. seealso:: :py:class:`QgsCoordinateTransform`
.. versionadded:: 3.0
%End
@ -103,6 +109,46 @@ True if transform is deprecated
%End
};
static QList< QgsDatumTransform::TransformPair > datumTransformations( const QgsCoordinateReferenceSystem &source, const QgsCoordinateReferenceSystem &destination );
%Docstring
Returns a list of datum transformations which are available for the given ``source`` and ``destination`` CRS.
.. seealso:: :py:func:`datumTransformToProj()`
.. seealso:: :py:func:`datumTransformInfo()`
%End
static QString datumTransformToProj( int datumTransformId );
%Docstring
Returns a proj string representing the specified ``datumTransformId`` datum transform ID.
.. seealso:: :py:func:`datumTransformations()`
.. seealso:: :py:func:`datumTransformInfo()`
.. seealso:: :py:func:`projStringToDatumTransformId()`
%End
static int projStringToDatumTransformId( const QString &string );
%Docstring
Returns the datum transform ID corresponding to a specified proj ``string``.
Returns -1 if matching datum ID was not found.
.. seealso:: :py:func:`datumTransformToProj()`
%End
static QgsDatumTransform::TransformInfo datumTransformInfo( int datumTransformId );
%Docstring
Returns detailed information about the specified ``datumTransformId``.
If ``datumTransformId`` was not a valid transform ID, a TransformInfo with TransformInfo.datumTransformId of
-1 will be returned.
.. seealso:: :py:func:`datumTransformations()`
.. seealso:: :py:func:`datumTransformToProj()`
%End
};
/************************************************************************

View File

@ -9151,7 +9151,7 @@ void QgisApp::projectCrsChanged()
if ( !transformsToAskFor.contains( it.value()->crs() ) &&
it.value()->crs() != QgsProject::instance()->crs() &&
!QgsProject::instance()->transformContext().hasTransform( it.value()->crs(), QgsProject::instance()->crs() ) &&
QgsCoordinateTransform::datumTransformations( it.value()->crs(), QgsProject::instance()->crs() ).count() > 1 )
QgsDatumTransform::datumTransformations( it.value()->crs(), QgsProject::instance()->crs() ).count() > 1 )
{
transformsToAskFor.append( it.value()->crs() );
}

View File

@ -110,7 +110,7 @@ QVariant QgsDatumTransformTableModel::data( const QModelIndex &index, int role )
case SourceTransformColumn:
if ( sourceTransform != -1 )
{
return QgsCoordinateTransform::datumTransformToProj( sourceTransform );
return QgsDatumTransform::datumTransformToProj( sourceTransform );
}
break;
case DestinationCrsColumn:
@ -119,7 +119,7 @@ QVariant QgsDatumTransformTableModel::data( const QModelIndex &index, int role )
case DestinationTransformColumn:
if ( destinationTransform != -1 )
{
return QgsCoordinateTransform::datumTransformToProj( destinationTransform );
return QgsDatumTransform::datumTransformToProj( destinationTransform );
}
break;
default:

View File

@ -161,6 +161,7 @@ SET(QGIS_CORE_SRCS
qgsdatasourceuri.cpp
qgsdataprovider.cpp
qgsdatetimestatisticalsummary.cpp
qgsdatumtransform.cpp
qgsdbfilterproxymodel.cpp
qgsdefaultvalue.cpp
qgsdiagramrenderer.cpp

View File

@ -700,97 +700,6 @@ const char *finder( const char *name )
return proj.toUtf8();
}
QList< QgsDatumTransform::TransformPair > QgsCoordinateTransform::datumTransformations( const QgsCoordinateReferenceSystem &srcCRS, const QgsCoordinateReferenceSystem &destCRS )
{
QList< QgsDatumTransform::TransformPair > transformations;
QString srcGeoId = srcCRS.geographicCrsAuthId();
QString destGeoId = destCRS.geographicCrsAuthId();
if ( srcGeoId.isEmpty() || destGeoId.isEmpty() )
{
return transformations;
}
QStringList srcSplit = srcGeoId.split( ':' );
QStringList destSplit = destGeoId.split( ':' );
if ( srcSplit.size() < 2 || destSplit.size() < 2 )
{
return transformations;
}
int srcAuthCode = srcSplit.at( 1 ).toInt();
int destAuthCode = destSplit.at( 1 ).toInt();
if ( srcAuthCode == destAuthCode )
{
return transformations; //crs have the same datum
}
QList<int> directTransforms;
searchDatumTransform( QStringLiteral( "SELECT coord_op_code FROM tbl_datum_transform WHERE source_crs_code=%1 AND target_crs_code=%2 ORDER BY deprecated ASC,preferred DESC" ).arg( srcAuthCode ).arg( destAuthCode ),
directTransforms );
QList<int> reverseDirectTransforms;
searchDatumTransform( QStringLiteral( "SELECT coord_op_code FROM tbl_datum_transform WHERE source_crs_code = %1 AND target_crs_code=%2 ORDER BY deprecated ASC,preferred DESC" ).arg( destAuthCode ).arg( srcAuthCode ),
reverseDirectTransforms );
QList<int> srcToWgs84;
searchDatumTransform( QStringLiteral( "SELECT coord_op_code FROM tbl_datum_transform WHERE (source_crs_code=%1 AND target_crs_code=%2) OR (source_crs_code=%2 AND target_crs_code=%1) ORDER BY deprecated ASC,preferred DESC" ).arg( srcAuthCode ).arg( 4326 ),
srcToWgs84 );
QList<int> destToWgs84;
searchDatumTransform( QStringLiteral( "SELECT coord_op_code FROM tbl_datum_transform WHERE (source_crs_code=%1 AND target_crs_code=%2) OR (source_crs_code=%2 AND target_crs_code=%1) ORDER BY deprecated ASC,preferred DESC" ).arg( destAuthCode ).arg( 4326 ),
destToWgs84 );
//add direct datum transformations
for ( int transform : qgis::as_const( directTransforms ) )
{
transformations.push_back( QgsDatumTransform::TransformPair( transform, -1 ) );
}
//add direct datum transformations
for ( int transform : qgis::as_const( directTransforms ) )
{
transformations.push_back( QgsDatumTransform::TransformPair( -1, transform ) );
}
for ( int srcTransform : qgis::as_const( srcToWgs84 ) )
{
for ( int destTransform : qgis::as_const( destToWgs84 ) )
{
transformations.push_back( QgsDatumTransform::TransformPair( srcTransform, destTransform ) );
}
}
return transformations;
}
void QgsCoordinateTransform::searchDatumTransform( const QString &sql, QList< int > &transforms )
{
sqlite3_database_unique_ptr database;
int openResult = database.open_v2( QgsApplication::srsDatabaseFilePath(), SQLITE_OPEN_READONLY, nullptr );
if ( openResult != SQLITE_OK )
{
return;
}
sqlite3_statement_unique_ptr statement;
int prepareRes;
statement = database.prepare( sql, prepareRes );
if ( prepareRes != SQLITE_OK )
{
return;
}
QString cOpCode;
while ( statement.step() == SQLITE_ROW )
{
cOpCode = statement.columnAsText( 0 );
transforms.push_back( cOpCode.toInt() );
}
}
bool QgsCoordinateTransform::setFromCache( const QgsCoordinateReferenceSystem &src, const QgsCoordinateReferenceSystem &dest, int srcDatumTransform, int destDatumTransform )
{
if ( !src.isValid() || !dest.isValid() )
@ -833,61 +742,6 @@ void QgsCoordinateTransform::addToCache()
sCacheLock.unlock();
}
QString QgsCoordinateTransform::datumTransformToProj( int datumTransform )
{
return QgsCoordinateTransformPrivate::datumTransformString( datumTransform );
}
int QgsCoordinateTransform::projStringToDatumTransformId( const QString &string )
{
return QgsCoordinateTransformPrivate::transformIdFromString( string );
}
QgsDatumTransform::TransformInfo QgsCoordinateTransform::datumTransformInfo( int datumTransform )
{
QgsDatumTransform::TransformInfo info;
sqlite3_database_unique_ptr database;
int openResult = database.open_v2( QgsApplication::srsDatabaseFilePath(), SQLITE_OPEN_READONLY, nullptr );
if ( openResult != SQLITE_OK )
{
return info;
}
sqlite3_statement_unique_ptr statement;
QString sql = QStringLiteral( "SELECT epsg_nr,source_crs_code,target_crs_code,remarks,scope,preferred,deprecated FROM tbl_datum_transform WHERE coord_op_code=%1" ).arg( datumTransform );
int prepareRes;
statement = database.prepare( sql, prepareRes );
if ( prepareRes != SQLITE_OK )
{
return info;
}
int srcCrsId, destCrsId;
if ( statement.step() != SQLITE_ROW )
{
return info;
}
info.datumTransformId = datumTransform;
info.epsgCode = statement.columnAsInt64( 0 );
srcCrsId = statement.columnAsInt64( 1 );
destCrsId = statement.columnAsInt64( 2 );
info.remarks = statement.columnAsText( 3 );
info.scope = statement.columnAsText( 4 );
info.preferred = statement.columnAsInt64( 5 ) != 0;
info.deprecated = statement.columnAsInt64( 6 ) != 0;
QgsCoordinateReferenceSystem srcCrs = QgsCoordinateReferenceSystem::fromOgcWmsCrs( QStringLiteral( "EPSG:%1" ).arg( srcCrsId ) );
info.sourceCrsDescription = srcCrs.description();
info.sourceCrsAuthId = srcCrs.authid();
QgsCoordinateReferenceSystem destCrs = QgsCoordinateReferenceSystem::fromOgcWmsCrs( QStringLiteral( "EPSG:%1" ).arg( destCrsId ) );
info.destinationCrsDescription = destCrs.description();
info.destinationCrsAuthId = destCrs.authid();
return info;
}
int QgsCoordinateTransform::sourceDatumTransformId() const
{
return d->mSourceDatumTransform;

View File

@ -44,6 +44,9 @@ class QgsProject;
* operations are from the perspective of the layer. For example, a forward transformation
* transforms coordinates from the layer's coordinate system to the map canvas.
* \note Since QGIS 3.0 QgsCoordinateReferenceSystem objects are implicitly shared.
*
* \see QgsDatumTransform
* \see QgsCoordinateTransformContext
*/
class CORE_EXPORT QgsCoordinateTransform
{
@ -312,38 +315,6 @@ class CORE_EXPORT QgsCoordinateTransform
*/
bool isShortCircuited() const;
/**
* Returns a list of datum transformations which are available for the given \a source and \a destination CRS.
* \see datumTransformToProj()
* \see datumTransformInfo()
*/
static QList< QgsDatumTransform::TransformPair > datumTransformations( const QgsCoordinateReferenceSystem &source, const QgsCoordinateReferenceSystem &destination );
/**
* Returns a proj string representing the specified \a datumTransformId datum transform ID.
* \see datumTransformations()
* \see datumTransformInfo()
* \see projStringToDatumTransformId()
*/
static QString datumTransformToProj( int datumTransformId );
/**
* Returns the datum transform ID corresponding to a specified proj \a string.
* Returns -1 if matching datum ID was not found.
* \see datumTransformToProj()
* \since QGIS 3.0
*/
static int projStringToDatumTransformId( const QString &string );
/**
* Returns detailed information about the specified \a datumTransformId.
* If \a datumTransformId was not a valid transform ID, a TransformInfo with TransformInfo::datumTransformId of
* -1 will be returned.
* \see datumTransformations()
* \see datumTransformToProj()
*/
static QgsDatumTransform::TransformInfo datumTransformInfo( int datumTransformId );
/**
* Returns the ID of the datum transform to use when projecting from the source
* CRS.
@ -406,8 +377,6 @@ class CORE_EXPORT QgsCoordinateTransform
private:
static void searchDatumTransform( const QString &sql, QList< int > &transforms );
mutable QExplicitlySharedDataPointer<QgsCoordinateTransformPrivate> d;
//! Transform context

View File

@ -140,7 +140,7 @@ bool QgsCoordinateTransformPrivate::initialize()
}
if ( sourceDatumTransform != -1 )
{
mSourceProjString += ( ' ' + datumTransformString( sourceDatumTransform ) );
mSourceProjString += ( ' ' + QgsDatumTransform::datumTransformToProj( sourceDatumTransform ) );
}
mDestProjString = mDestCRS.toProj4();
@ -150,7 +150,7 @@ bool QgsCoordinateTransformPrivate::initialize()
}
if ( destDatumTransform != -1 )
{
mDestProjString += ( ' ' + datumTransformString( destDatumTransform ) );
mDestProjString += ( ' ' + QgsDatumTransform::datumTransformToProj( destDatumTransform ) );
}
if ( !useDefaultDatumTransform )
@ -284,114 +284,6 @@ QString QgsCoordinateTransformPrivate::stripDatumTransform( const QString &proj4
return newProjString;
}
QString QgsCoordinateTransformPrivate::datumTransformString( int datumTransform )
{
QString transformString;
sqlite3_database_unique_ptr database;
int openResult = database.open_v2( QgsApplication::srsDatabaseFilePath(), SQLITE_OPEN_READONLY, nullptr );
if ( openResult != SQLITE_OK )
{
return transformString;
}
sqlite3_statement_unique_ptr statement;
QString sql = QStringLiteral( "SELECT coord_op_method_code,p1,p2,p3,p4,p5,p6,p7 FROM tbl_datum_transform WHERE coord_op_code=%1" ).arg( datumTransform );
int prepareRes;
statement = database.prepare( sql, prepareRes );
if ( prepareRes != SQLITE_OK )
{
return transformString;
}
if ( statement.step() == SQLITE_ROW )
{
//coord_op_methode_code
int methodCode = statement.columnAsInt64( 0 );
if ( methodCode == 9615 ) //ntv2
{
transformString = "+nadgrids=" + statement.columnAsText( 1 );
}
else if ( methodCode == 9603 || methodCode == 9606 || methodCode == 9607 )
{
transformString += QLatin1String( "+towgs84=" );
double p1 = statement.columnAsDouble( 1 );
double p2 = statement.columnAsDouble( 2 );
double p3 = statement.columnAsDouble( 3 );
double p4 = statement.columnAsDouble( 4 );
double p5 = statement.columnAsDouble( 5 );
double p6 = statement.columnAsDouble( 6 );
double p7 = statement.columnAsDouble( 7 );
if ( methodCode == 9603 ) //3 parameter transformation
{
transformString += QStringLiteral( "%1,%2,%3" ).arg( QString::number( p1 ), QString::number( p2 ), QString::number( p3 ) );
}
else //7 parameter transformation
{
transformString += QStringLiteral( "%1,%2,%3,%4,%5,%6,%7" ).arg( QString::number( p1 ), QString::number( p2 ), QString::number( p3 ), QString::number( p4 ), QString::number( p5 ), QString::number( p6 ), QString::number( p7 ) );
}
}
}
return transformString;
}
int QgsCoordinateTransformPrivate::transformIdFromString( const QString &string )
{
sqlite3_database_unique_ptr database;
int openResult = database.open_v2( QgsApplication::srsDatabaseFilePath(), SQLITE_OPEN_READONLY, nullptr );
if ( openResult != SQLITE_OK )
{
return -1;
}
sqlite3_statement_unique_ptr statement;
QString sql = QStringLiteral( "SELECT coord_op_method_code,p1,p2,p3,p4,p5,p6,p7,coord_op_code FROM tbl_datum_transform" );
int prepareRes;
statement = database.prepare( sql, prepareRes );
if ( prepareRes != SQLITE_OK )
{
return -1;
}
while ( statement.step() == SQLITE_ROW )
{
QString transformString;
//coord_op_methode_code
int methodCode = statement.columnAsInt64( 0 );
if ( methodCode == 9615 ) //ntv2
{
transformString = "+nadgrids=" + statement.columnAsText( 1 );
}
else if ( methodCode == 9603 || methodCode == 9606 || methodCode == 9607 )
{
transformString += QLatin1String( "+towgs84=" );
double p1 = statement.columnAsDouble( 1 );
double p2 = statement.columnAsDouble( 2 );
double p3 = statement.columnAsDouble( 3 );
double p4 = statement.columnAsDouble( 4 );
double p5 = statement.columnAsDouble( 5 );
double p6 = statement.columnAsDouble( 6 );
double p7 = statement.columnAsDouble( 7 );
if ( methodCode == 9603 ) //3 parameter transformation
{
transformString += QStringLiteral( "%1,%2,%3" ).arg( QString::number( p1 ), QString::number( p2 ), QString::number( p3 ) );
}
else //7 parameter transformation
{
transformString += QStringLiteral( "%1,%2,%3,%4,%5,%6,%7" ).arg( QString::number( p1 ), QString::number( p2 ), QString::number( p3 ), QString::number( p4 ), QString::number( p5 ), QString::number( p6 ), QString::number( p7 ) );
}
}
if ( transformString.compare( string, Qt::CaseInsensitive ) == 0 )
{
return statement.columnAsInt64( 8 );
}
}
return -1;
}
void QgsCoordinateTransformPrivate::addNullGridShifts( QString &srcProjString, QString &destProjString,
int sourceDatumTransform, int destinationDatumTransform ) const
{

View File

@ -128,21 +128,6 @@ class QgsCoordinateTransformPrivate : public QSharedData
QReadWriteLock mProjLock;
QMap < uintptr_t, QPair< projPJ, projPJ > > mProjProjections;
/**
* Returns the proj transform string corresponding to a
* datum transform ID.
* \see transformIdFromString()
*/
static QString datumTransformString( int transformId );
/**
* Attempts to match a proj datum transform string to a datum ID.
* Returns -1 if datum ID was not found.
* \see datumTransformString()
* \since QGIS 3.0
*/
static int transformIdFromString( const QString &string );
private:
//! Removes +nadgrids and +towgs84 from proj4 string

View File

@ -203,7 +203,7 @@ bool QgsCoordinateTransformContext::readXml( const QDomElement &element, const Q
//warn if value1 or value2 is non-empty, yet no matching transform was found
if ( !value1.isEmpty() )
{
datumId1 = QgsCoordinateTransform::projStringToDatumTransformId( value1 );
datumId1 = QgsDatumTransform::projStringToDatumTransformId( value1 );
if ( datumId1 < 0 )
{
result = false;
@ -212,7 +212,7 @@ bool QgsCoordinateTransformContext::readXml( const QDomElement &element, const Q
}
if ( !value2.isEmpty() )
{
datumId2 = QgsCoordinateTransform::projStringToDatumTransformId( value2 );
datumId2 = QgsDatumTransform::projStringToDatumTransformId( value2 );
if ( datumId2 < 0 )
{
result = false;
@ -271,8 +271,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 < 0 ? QString() : QgsCoordinateTransform::datumTransformToProj( it.value().sourceTransformId ) );
transformElem.setAttribute( QStringLiteral( "destTransform" ), it.value().destinationTransformId < 0 ? QString() : QgsCoordinateTransform::datumTransformToProj( it.value().destinationTransformId ) );
transformElem.setAttribute( QStringLiteral( "sourceTransform" ), it.value().sourceTransformId < 0 ? QString() : QgsDatumTransform::datumTransformToProj( it.value().sourceTransformId ) );
transformElem.setAttribute( QStringLiteral( "destTransform" ), it.value().destinationTransformId < 0 ? QString() : QgsDatumTransform::datumTransformToProj( it.value().destinationTransformId ) );
contextElem.appendChild( transformElem );
}
@ -334,7 +334,7 @@ void QgsCoordinateTransformContext::readSettings()
}
QString proj = settings.value( *pkeyIt ).toString();
int datumId = QgsCoordinateTransform::projStringToDatumTransformId( proj );
int datumId = QgsDatumTransform::projStringToDatumTransformId( proj );
if ( pkeyIt->contains( QLatin1String( "srcTransform" ) ) )
{
transforms[ qMakePair( srcAuthId, destAuthId )].first = datumId;
@ -378,11 +378,11 @@ void QgsCoordinateTransformContext::writeSettings()
int sourceDatumTransform = transformIt.value().sourceTransformId;
QString sourceDatumProj;
if ( sourceDatumTransform >= 0 )
sourceDatumProj = QgsCoordinateTransform::datumTransformToProj( sourceDatumTransform );
sourceDatumProj = QgsDatumTransform::datumTransformToProj( sourceDatumTransform );
int destinationDatumTransform = transformIt.value().destinationTransformId;
QString destinationDatumProj;
if ( destinationDatumTransform >= 0 )
destinationDatumProj = QgsCoordinateTransform::datumTransformToProj( destinationDatumTransform );
destinationDatumProj = QgsDatumTransform::datumTransformToProj( destinationDatumTransform );
settings.setValue( srcAuthId + "//" + destAuthId + "_srcTransform", sourceDatumProj );
settings.setValue( srcAuthId + "//" + destAuthId + "_destTransform", destinationDatumProj );

View File

@ -53,6 +53,9 @@ class QDomElement;
*
* \note QgsCoordinateTransformContext objects are implicitly shared.
*
* \see QgsDatumTransform
* \see QgsCoordinateTransform
*
* \since QGIS 3.0
*/

View File

@ -0,0 +1,263 @@
/***************************************************************************
qgsdatumtransform.cpp
------------------------
begin : Dec 2017
copyright : (C) 2017 Nyall Dawson
email : nyall dot dawson at gmail dot com
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#include "qgsdatumtransform.h"
#include "qgscoordinatereferencesystem.h"
#include "qgsapplication.h"
#include "qgssqliteutils.h"
#include <sqlite3.h>
QList< QgsDatumTransform::TransformPair > QgsDatumTransform::datumTransformations( const QgsCoordinateReferenceSystem &srcCRS, const QgsCoordinateReferenceSystem &destCRS )
{
QList< QgsDatumTransform::TransformPair > transformations;
QString srcGeoId = srcCRS.geographicCrsAuthId();
QString destGeoId = destCRS.geographicCrsAuthId();
if ( srcGeoId.isEmpty() || destGeoId.isEmpty() )
{
return transformations;
}
QStringList srcSplit = srcGeoId.split( ':' );
QStringList destSplit = destGeoId.split( ':' );
if ( srcSplit.size() < 2 || destSplit.size() < 2 )
{
return transformations;
}
int srcAuthCode = srcSplit.at( 1 ).toInt();
int destAuthCode = destSplit.at( 1 ).toInt();
if ( srcAuthCode == destAuthCode )
{
return transformations; //crs have the same datum
}
QList<int> directTransforms;
searchDatumTransform( QStringLiteral( "SELECT coord_op_code FROM tbl_datum_transform WHERE source_crs_code=%1 AND target_crs_code=%2 ORDER BY deprecated ASC,preferred DESC" ).arg( srcAuthCode ).arg( destAuthCode ),
directTransforms );
QList<int> reverseDirectTransforms;
searchDatumTransform( QStringLiteral( "SELECT coord_op_code FROM tbl_datum_transform WHERE source_crs_code = %1 AND target_crs_code=%2 ORDER BY deprecated ASC,preferred DESC" ).arg( destAuthCode ).arg( srcAuthCode ),
reverseDirectTransforms );
QList<int> srcToWgs84;
searchDatumTransform( QStringLiteral( "SELECT coord_op_code FROM tbl_datum_transform WHERE (source_crs_code=%1 AND target_crs_code=%2) OR (source_crs_code=%2 AND target_crs_code=%1) ORDER BY deprecated ASC,preferred DESC" ).arg( srcAuthCode ).arg( 4326 ),
srcToWgs84 );
QList<int> destToWgs84;
searchDatumTransform( QStringLiteral( "SELECT coord_op_code FROM tbl_datum_transform WHERE (source_crs_code=%1 AND target_crs_code=%2) OR (source_crs_code=%2 AND target_crs_code=%1) ORDER BY deprecated ASC,preferred DESC" ).arg( destAuthCode ).arg( 4326 ),
destToWgs84 );
//add direct datum transformations
for ( int transform : qgis::as_const( directTransforms ) )
{
transformations.push_back( QgsDatumTransform::TransformPair( transform, -1 ) );
}
//add direct datum transformations
for ( int transform : qgis::as_const( directTransforms ) )
{
transformations.push_back( QgsDatumTransform::TransformPair( -1, transform ) );
}
for ( int srcTransform : qgis::as_const( srcToWgs84 ) )
{
for ( int destTransform : qgis::as_const( destToWgs84 ) )
{
transformations.push_back( QgsDatumTransform::TransformPair( srcTransform, destTransform ) );
}
}
return transformations;
}
void QgsDatumTransform::searchDatumTransform( const QString &sql, QList< int > &transforms )
{
sqlite3_database_unique_ptr database;
int openResult = database.open_v2( QgsApplication::srsDatabaseFilePath(), SQLITE_OPEN_READONLY, nullptr );
if ( openResult != SQLITE_OK )
{
return;
}
sqlite3_statement_unique_ptr statement;
int prepareRes;
statement = database.prepare( sql, prepareRes );
if ( prepareRes != SQLITE_OK )
{
return;
}
QString cOpCode;
while ( statement.step() == SQLITE_ROW )
{
cOpCode = statement.columnAsText( 0 );
transforms.push_back( cOpCode.toInt() );
}
}
QString QgsDatumTransform::datumTransformToProj( int datumTransform )
{
QString transformString;
sqlite3_database_unique_ptr database;
int openResult = database.open_v2( QgsApplication::srsDatabaseFilePath(), SQLITE_OPEN_READONLY, nullptr );
if ( openResult != SQLITE_OK )
{
return transformString;
}
sqlite3_statement_unique_ptr statement;
QString sql = QStringLiteral( "SELECT coord_op_method_code,p1,p2,p3,p4,p5,p6,p7 FROM tbl_datum_transform WHERE coord_op_code=%1" ).arg( datumTransform );
int prepareRes;
statement = database.prepare( sql, prepareRes );
if ( prepareRes != SQLITE_OK )
{
return transformString;
}
if ( statement.step() == SQLITE_ROW )
{
//coord_op_methode_code
int methodCode = statement.columnAsInt64( 0 );
if ( methodCode == 9615 ) //ntv2
{
transformString = "+nadgrids=" + statement.columnAsText( 1 );
}
else if ( methodCode == 9603 || methodCode == 9606 || methodCode == 9607 )
{
transformString += QLatin1String( "+towgs84=" );
double p1 = statement.columnAsDouble( 1 );
double p2 = statement.columnAsDouble( 2 );
double p3 = statement.columnAsDouble( 3 );
double p4 = statement.columnAsDouble( 4 );
double p5 = statement.columnAsDouble( 5 );
double p6 = statement.columnAsDouble( 6 );
double p7 = statement.columnAsDouble( 7 );
if ( methodCode == 9603 ) //3 parameter transformation
{
transformString += QStringLiteral( "%1,%2,%3" ).arg( QString::number( p1 ), QString::number( p2 ), QString::number( p3 ) );
}
else //7 parameter transformation
{
transformString += QStringLiteral( "%1,%2,%3,%4,%5,%6,%7" ).arg( QString::number( p1 ), QString::number( p2 ), QString::number( p3 ), QString::number( p4 ), QString::number( p5 ), QString::number( p6 ), QString::number( p7 ) );
}
}
}
return transformString;
}
int QgsDatumTransform::projStringToDatumTransformId( const QString &string )
{
sqlite3_database_unique_ptr database;
int openResult = database.open_v2( QgsApplication::srsDatabaseFilePath(), SQLITE_OPEN_READONLY, nullptr );
if ( openResult != SQLITE_OK )
{
return -1;
}
sqlite3_statement_unique_ptr statement;
QString sql = QStringLiteral( "SELECT coord_op_method_code,p1,p2,p3,p4,p5,p6,p7,coord_op_code FROM tbl_datum_transform" );
int prepareRes;
statement = database.prepare( sql, prepareRes );
if ( prepareRes != SQLITE_OK )
{
return -1;
}
while ( statement.step() == SQLITE_ROW )
{
QString transformString;
//coord_op_methode_code
int methodCode = statement.columnAsInt64( 0 );
if ( methodCode == 9615 ) //ntv2
{
transformString = "+nadgrids=" + statement.columnAsText( 1 );
}
else if ( methodCode == 9603 || methodCode == 9606 || methodCode == 9607 )
{
transformString += QLatin1String( "+towgs84=" );
double p1 = statement.columnAsDouble( 1 );
double p2 = statement.columnAsDouble( 2 );
double p3 = statement.columnAsDouble( 3 );
double p4 = statement.columnAsDouble( 4 );
double p5 = statement.columnAsDouble( 5 );
double p6 = statement.columnAsDouble( 6 );
double p7 = statement.columnAsDouble( 7 );
if ( methodCode == 9603 ) //3 parameter transformation
{
transformString += QStringLiteral( "%1,%2,%3" ).arg( QString::number( p1 ), QString::number( p2 ), QString::number( p3 ) );
}
else //7 parameter transformation
{
transformString += QStringLiteral( "%1,%2,%3,%4,%5,%6,%7" ).arg( QString::number( p1 ), QString::number( p2 ), QString::number( p3 ), QString::number( p4 ), QString::number( p5 ), QString::number( p6 ), QString::number( p7 ) );
}
}
if ( transformString.compare( string, Qt::CaseInsensitive ) == 0 )
{
return statement.columnAsInt64( 8 );
}
}
return -1;
}
QgsDatumTransform::TransformInfo QgsDatumTransform::datumTransformInfo( int datumTransform )
{
QgsDatumTransform::TransformInfo info;
sqlite3_database_unique_ptr database;
int openResult = database.open_v2( QgsApplication::srsDatabaseFilePath(), SQLITE_OPEN_READONLY, nullptr );
if ( openResult != SQLITE_OK )
{
return info;
}
sqlite3_statement_unique_ptr statement;
QString sql = QStringLiteral( "SELECT epsg_nr,source_crs_code,target_crs_code,remarks,scope,preferred,deprecated FROM tbl_datum_transform WHERE coord_op_code=%1" ).arg( datumTransform );
int prepareRes;
statement = database.prepare( sql, prepareRes );
if ( prepareRes != SQLITE_OK )
{
return info;
}
int srcCrsId, destCrsId;
if ( statement.step() != SQLITE_ROW )
{
return info;
}
info.datumTransformId = datumTransform;
info.epsgCode = statement.columnAsInt64( 0 );
srcCrsId = statement.columnAsInt64( 1 );
destCrsId = statement.columnAsInt64( 2 );
info.remarks = statement.columnAsText( 3 );
info.scope = statement.columnAsText( 4 );
info.preferred = statement.columnAsInt64( 5 ) != 0;
info.deprecated = statement.columnAsInt64( 6 ) != 0;
QgsCoordinateReferenceSystem srcCrs = QgsCoordinateReferenceSystem::fromOgcWmsCrs( QStringLiteral( "EPSG:%1" ).arg( srcCrsId ) );
info.sourceCrsDescription = srcCrs.description();
info.sourceCrsAuthId = srcCrs.authid();
QgsCoordinateReferenceSystem destCrs = QgsCoordinateReferenceSystem::fromOgcWmsCrs( QStringLiteral( "EPSG:%1" ).arg( destCrsId ) );
info.destinationCrsDescription = destCrs.description();
info.destinationCrsAuthId = destCrs.authid();
return info;
}

View File

@ -20,9 +20,16 @@
#include "qgis_core.h"
#include <QString>
class QgsCoordinateReferenceSystem;
/**
* Contains methods and classes relating the datum transformations.
* \ingroup core
*
* \see QgsCoordinateTransformContext
* \see QgsCoordinateTransform
*
* \since QGIS 3.0
*/
class CORE_EXPORT QgsDatumTransform
@ -107,6 +114,43 @@ class CORE_EXPORT QgsDatumTransform
bool deprecated = false;
};
/**
* Returns a list of datum transformations which are available for the given \a source and \a destination CRS.
* \see datumTransformToProj()
* \see datumTransformInfo()
*/
static QList< QgsDatumTransform::TransformPair > datumTransformations( const QgsCoordinateReferenceSystem &source, const QgsCoordinateReferenceSystem &destination );
/**
* Returns a proj string representing the specified \a datumTransformId datum transform ID.
* \see datumTransformations()
* \see datumTransformInfo()
* \see projStringToDatumTransformId()
*/
static QString datumTransformToProj( int datumTransformId );
/**
* Returns the datum transform ID corresponding to a specified proj \a string.
* Returns -1 if matching datum ID was not found.
* \see datumTransformToProj()
*/
static int projStringToDatumTransformId( const QString &string );
/**
* Returns detailed information about the specified \a datumTransformId.
* If \a datumTransformId was not a valid transform ID, a TransformInfo with TransformInfo::datumTransformId of
* -1 will be returned.
* \see datumTransformations()
* \see datumTransformToProj()
*/
static QgsDatumTransform::TransformInfo datumTransformInfo( int datumTransformId );
private:
static void searchDatumTransform( const QString &sql, QList< int > &transforms );
};
#endif // QGSDATUMTRANSFORM_H

View File

@ -46,7 +46,7 @@ QgsDatumTransformDialog::QgsDatumTransformDialog( const QgsCoordinateReferenceSy
//get list of datum transforms
mSourceCrs = sourceCrs;
mDestinationCrs = destinationCrs;
mDatumTransforms = QgsCoordinateTransform::datumTransformations( sourceCrs, destinationCrs );
mDatumTransforms = QgsDatumTransform::datumTransformations( sourceCrs, destinationCrs );
QApplication::setOverrideCursor( Qt::ArrowCursor );
@ -84,10 +84,10 @@ void QgsDatumTransformDialog::load( const QPair<int, int> &selectedDatumTransfor
if ( nr == -1 )
continue;
item->setText( i, QgsCoordinateTransform::datumTransformToProj( nr ) );
item->setText( i, QgsDatumTransform::datumTransformToProj( nr ) );
//Describe datums in a tooltip
QgsDatumTransform::TransformInfo info = QgsCoordinateTransform::datumTransformInfo( nr );
QgsDatumTransform::TransformInfo info = QgsDatumTransform::datumTransformInfo( nr );
if ( info.datumTransformId == -1 )
continue;
@ -266,7 +266,7 @@ void QgsDatumTransformDialog::mDatumTransformTreeWidget_currentItemChanged( QTre
void QgsDatumTransformDialog::setSourceCrs( const QgsCoordinateReferenceSystem &sourceCrs )
{
mSourceCrs = sourceCrs;
mDatumTransforms = QgsCoordinateTransform::datumTransformations( mSourceCrs, mDestinationCrs );
mDatumTransforms = QgsDatumTransform::datumTransformations( mSourceCrs, mDestinationCrs );
load();
setOKButtonEnabled();
}
@ -274,7 +274,7 @@ void QgsDatumTransformDialog::setSourceCrs( const QgsCoordinateReferenceSystem &
void QgsDatumTransformDialog::setDestinationCrs( const QgsCoordinateReferenceSystem &destinationCrs )
{
mDestinationCrs = destinationCrs;
mDatumTransforms = QgsCoordinateTransform::datumTransformations( mSourceCrs, mDestinationCrs );
mDatumTransforms = QgsDatumTransform::datumTransformations( mSourceCrs, mDestinationCrs );
load();
setOKButtonEnabled();
}

View File

@ -18,6 +18,7 @@ from qgis.core import (QgsRectangle,
QgsCoordinateReferenceSystem,
QgsCoordinateTransform,
QgsCoordinateTransformContext,
QgsDatumTransform,
QgsProject)
from qgis.testing import start_app, unittest
@ -209,27 +210,27 @@ class TestQgsCoordinateTransform(unittest.TestCase):
def testTransformInfo(self):
# hopefully this transform is available on all platforms!
transforms = QgsCoordinateTransform.datumTransformations(QgsCoordinateReferenceSystem(4613), QgsCoordinateReferenceSystem(4326))
transforms = QgsDatumTransform.datumTransformations(QgsCoordinateReferenceSystem(4613), QgsCoordinateReferenceSystem(4326))
self.assertTrue(len(transforms) > 0)
self.assertIn('+towgs84=-403,684,41', [QgsCoordinateTransform.datumTransformToProj(t.sourceTransformId) for t in transforms])
self.assertIn('+towgs84=-403,684,41', [QgsCoordinateTransform.datumTransformToProj(t.destinationTransformId) for t in transforms])
self.assertIn('EPSG:4613', [QgsCoordinateTransform.datumTransformInfo(t.destinationTransformId).sourceCrsAuthId for t in
self.assertIn('+towgs84=-403,684,41', [QgsDatumTransform.datumTransformToProj(t.sourceTransformId) for t in transforms])
self.assertIn('+towgs84=-403,684,41', [QgsDatumTransform.datumTransformToProj(t.destinationTransformId) for t in transforms])
self.assertIn('EPSG:4613', [QgsDatumTransform.datumTransformInfo(t.destinationTransformId).sourceCrsAuthId for t in
transforms])
self.assertIn('EPSG:4326', [QgsCoordinateTransform.datumTransformInfo(t.destinationTransformId).destinationCrsAuthId for t in
self.assertIn('EPSG:4326', [QgsDatumTransform.datumTransformInfo(t.destinationTransformId).destinationCrsAuthId for t in
transforms])
def testStringToTransformId(self):
"""
Test converting proj strings to corresponding datum IDs
"""
self.assertEqual(QgsCoordinateTransform.projStringToDatumTransformId(''), -1)
self.assertEqual(QgsCoordinateTransform.projStringToDatumTransformId('not'), -1)
self.assertEqual(QgsDatumTransform.projStringToDatumTransformId(''), -1)
self.assertEqual(QgsDatumTransform.projStringToDatumTransformId('not'), -1)
test_string = '+towgs84=-403,684,41'
id = QgsCoordinateTransform.projStringToDatumTransformId(test_string)
id = QgsDatumTransform.projStringToDatumTransformId(test_string)
self.assertNotEqual(id, -1)
string = QgsCoordinateTransform.datumTransformToProj(id)
string = QgsDatumTransform.datumTransformToProj(id)
self.assertEqual(string, test_string)
self.assertEqual(QgsCoordinateTransform.projStringToDatumTransformId(test_string.upper()), id)
self.assertEqual(QgsDatumTransform.projStringToDatumTransformId(test_string.upper()), id)
if __name__ == '__main__':

View File

@ -302,15 +302,15 @@ class TestQgsCoordinateTransformContext(unittest.TestCase):
# setup a context
context = QgsCoordinateTransformContext()
source_id_1 = QgsCoordinateTransform.datumTransformations(QgsCoordinateReferenceSystem(4204),
QgsCoordinateReferenceSystem(4326))[0].sourceTransformId
dest_id_1 = QgsCoordinateTransform.datumTransformations(QgsCoordinateReferenceSystem(4204),
QgsCoordinateReferenceSystem(4326))[0].destinationTransformId
source_id_1 = QgsDatumTransform.datumTransformations(QgsCoordinateReferenceSystem(4204),
QgsCoordinateReferenceSystem(4326))[0].sourceTransformId
dest_id_1 = QgsDatumTransform.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
source_id_2 = QgsDatumTransform.datumTransformations(QgsCoordinateReferenceSystem(4205),
QgsCoordinateReferenceSystem(4326))[0].sourceTransformId
dest_id_2 = QgsDatumTransform.datumTransformations(QgsCoordinateReferenceSystem(4205),
QgsCoordinateReferenceSystem(4326))[0].destinationTransformId
self.assertTrue(context.addSourceDestinationDatumTransform(QgsCoordinateReferenceSystem(4204),
QgsCoordinateReferenceSystem(4326), source_id_1, dest_id_1))
@ -373,15 +373,15 @@ class TestQgsCoordinateTransformContext(unittest.TestCase):
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_1 = QgsDatumTransform.datumTransformations(QgsCoordinateReferenceSystem(4204),
QgsCoordinateReferenceSystem(4326))[0].sourceTransformId
dest_id_1 = QgsDatumTransform.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
source_id_2 = QgsDatumTransform.datumTransformations(QgsCoordinateReferenceSystem(4205),
QgsCoordinateReferenceSystem(4326))[0].sourceTransformId
dest_id_2 = QgsDatumTransform.datumTransformations(QgsCoordinateReferenceSystem(4205),
QgsCoordinateReferenceSystem(4326))[0].destinationTransformId
# should be empty
self.assertEqual(context.sourceDestinationDatumTransforms(), {})