Skip to content
Permalink
Browse files

Port QgsCoordinateTransform to proj 6 API

Sponsored by ICSM
  • Loading branch information
nyalldawson committed Mar 27, 2019
1 parent eabf56b commit 95c0d4f182849ced6e2941c83dc8394a88fdb0aa
Showing with 98 additions and 25 deletions.
  1. +50 −13 src/core/qgscoordinatetransform.cpp
  2. +32 −10 src/core/qgscoordinatetransform_p.cpp
  3. +16 −2 src/core/qgscoordinatetransform_p.h
@@ -32,13 +32,13 @@
#include <QStringList>
#include <QVector>

extern "C"
{
#ifndef ACCEPT_USE_OF_DEPRECATED_PROJ_API_H
#define ACCEPT_USE_OF_DEPRECATED_PROJ_API_H
#endif
#if PROJ_VERSION_MAJOR>=6
#include <proj.h>
#include "qgsprojutils.h"
#else
#include <proj_api.h>
}
#endif

#include <sqlite3.h>

// if defined shows all information about transform to stdout
@@ -625,21 +625,36 @@ void QgsCoordinateTransform::transformCoords( int numPoints, double *x, double *

// if the source/destination projection is lat/long, convert the points to radians
// prior to transforming
QPair<projPJ, projPJ> projData = d->threadLocalProjData();
ProjData projData = d->threadLocalProjData();
#if PROJ_VERSION_MAJOR<6
bool sourceIsLatLong = false;
bool destIsLatLong = false;

projPJ sourceProj = projData.first;
projPJ destProj = projData.second;
sourceIsLatLong = pj_is_latlong( sourceProj );
destIsLatLong = pj_is_latlong( destProj );

if ( ( pj_is_latlong( destProj ) && ( direction == ReverseTransform ) )
|| ( pj_is_latlong( sourceProj ) && ( direction == ForwardTransform ) ) )
if ( ( destIsLatLong && ( direction == ReverseTransform ) )
|| ( sourceIsLatLong && ( direction == ForwardTransform ) ) )
{
for ( int i = 0; i < numPoints; ++i )
{
x[i] *= DEG_TO_RAD;
y[i] *= DEG_TO_RAD;
}

}
int projResult;
#endif

int projResult = 0;
#if PROJ_VERSION_MAJOR>=6
proj_trans_generic( projData, direction == ForwardTransform ? PJ_FWD : PJ_INV,
x, sizeof( double ), numPoints,
y, sizeof( double ), numPoints,
z, sizeof( double ), numPoints,
nullptr, sizeof( double ), 0 );
projResult = proj_errno( projData );
#else
if ( direction == ReverseTransform )
{
projResult = pj_transform( destProj, sourceProj, numPoints, 0, x, y, z );
@@ -650,6 +665,7 @@ void QgsCoordinateTransform::transformCoords( int numPoints, double *x, double *
Q_ASSERT( destProj );
projResult = pj_transform( sourceProj, destProj, numPoints, 0, x, y, z );
}
#endif

if ( projResult != 0 )
{
@@ -664,12 +680,30 @@ void QgsCoordinateTransform::transformCoords( int numPoints, double *x, double *
}
else
{
#if PROJ_VERSION_MAJOR>=6
points += QStringLiteral( "(%1, %2)\n" ).arg( x[i], 0, 'f' ).arg( y[i], 0, 'f' );
#else
points += QStringLiteral( "(%1, %2)\n" ).arg( x[i] * RAD_TO_DEG, 0, 'f' ).arg( y[i] * RAD_TO_DEG, 0, 'f' );
#endif
}
}

QString dir = ( direction == ForwardTransform ) ? QObject::tr( "forward transform" ) : QObject::tr( "inverse transform" );

#if PROJ_VERSION_MAJOR>=6
PJ *src = proj_get_source_crs( QgsProjContext::get(), projData );
PJ *dest = proj_get_source_crs( QgsProjContext::get(), projData );
QString msg = QObject::tr( "%1 of\n"
"%2"
"PROJ: %3\n"
"Error: %4" )
.arg( dir,
points,
proj_as_proj_string( QgsProjContext::get(), projData, PJ_PROJ_5, nullptr ),
QString::fromUtf8( proj_errno_string( projResult ) ) );
proj_destroy( src );
proj_destroy( dest );
#else
char *srcdef = pj_get_def( sourceProj, 0 );
char *dstdef = pj_get_def( destProj, 0 );

@@ -684,24 +718,27 @@ void QgsCoordinateTransform::transformCoords( int numPoints, double *x, double *

pj_dalloc( srcdef );
pj_dalloc( dstdef );
#endif

QgsDebugMsg( "Projection failed emitting invalid transform signal: " + msg );
QgsDebugMsg( QStringLiteral( "throwing exception" ) );

throw QgsCsException( msg );
}

#if PROJ_VERSION_MAJOR<6
// if the result is lat/long, convert the results from radians back
// to degrees
if ( ( pj_is_latlong( destProj ) && ( direction == ForwardTransform ) )
|| ( pj_is_latlong( sourceProj ) && ( direction == ReverseTransform ) ) )
if ( ( destIsLatLong && ( direction == ForwardTransform ) )
|| ( sourceIsLatLong && ( direction == ReverseTransform ) ) )
{
for ( int i = 0; i < numPoints; ++i )
{
x[i] *= RAD_TO_DEG;
y[i] *= RAD_TO_DEG;
}
}
#endif
#ifdef COORDINATE_TRANSFORM_VERBOSE
QgsDebugMsg( QStringLiteral( "[[[[[[ Projected %1, %2 to %3, %4 ]]]]]]" )
.arg( xorg, 0, 'g', 15 ).arg( yorg, 0, 'g', 15 )
@@ -20,19 +20,20 @@
#include "qgsapplication.h"
#include "qgsreadwritelocker.h"

extern "C"
{
#ifndef ACCEPT_USE_OF_DEPRECATED_PROJ_API_H
#define ACCEPT_USE_OF_DEPRECATED_PROJ_API_H
#endif
#if PROJ_VERSION_MAJOR>=6
#include "qgsprojutils.h"
#include <proj.h>
#else
#include <proj_api.h>
}
#endif

#include <sqlite3.h>

#include <QStringList>

/// @cond PRIVATE

#if PROJ_VERSION_MAJOR<6
#ifdef USE_THREAD_LOCAL
thread_local QgsProjContextStore QgsCoordinateTransformPrivate::mProjContext;
#else
@@ -49,6 +50,8 @@ QgsProjContextStore::~QgsProjContextStore()
pj_ctx_free( context );
}

#endif

QgsCoordinateTransformPrivate::QgsCoordinateTransformPrivate()
{
setFinder();
@@ -163,17 +166,22 @@ bool QgsCoordinateTransformPrivate::initialize()
}

// create proj projections for current thread
QPair<projPJ, projPJ> res = threadLocalProjData();
ProjData res = threadLocalProjData();

#ifdef COORDINATE_TRANSFORM_VERBOSE
QgsDebugMsg( "From proj : " + mSourceCRS.toProj4() );
QgsDebugMsg( "To proj : " + mDestCRS.toProj4() );
#endif

#if PROJ_VERSION_MAJOR>=6
if ( !res )
mIsValid = false;
#else
if ( !res.first || !res.second )
{
mIsValid = false;
}
#endif

#ifdef COORDINATE_TRANSFORM_VERBOSE
if ( mIsValid )
@@ -224,10 +232,14 @@ void QgsCoordinateTransformPrivate::calculateTransforms( const QgsCoordinateTran
mDestinationDatumTransform = transforms.destinationTransformId;
}

QPair<projPJ, projPJ> QgsCoordinateTransformPrivate::threadLocalProjData()
ProjData QgsCoordinateTransformPrivate::threadLocalProjData()
{
QgsReadWriteLocker locker( mProjLock, QgsReadWriteLocker::Read );

#if PROJ_VERSION_MAJOR>=6
PJ_CONTEXT *context = QgsProjContext::get();
QMap < uintptr_t, ProjData >::const_iterator it = mProjProjections.constFind( reinterpret_cast< uintptr_t>( context ) );
#else
#ifdef USE_THREAD_LOCAL
QMap < uintptr_t, QPair< projPJ, projPJ > >::const_iterator it = mProjProjections.constFind( reinterpret_cast< uintptr_t>( mProjContext.get() ) );
#else
@@ -242,17 +254,22 @@ QPair<projPJ, projPJ> QgsCoordinateTransformPrivate::threadLocalProjData()
pContext = mProjContext.localData()->get();
}
QMap < uintptr_t, QPair< projPJ, projPJ > >::const_iterator it = mProjProjections.constFind( reinterpret_cast< uintptr_t>( pContext ) );
#endif
#endif

if ( it != mProjProjections.constEnd() )
{
QPair<projPJ, projPJ> res = it.value();
ProjData res = it.value();
return res;
}

// proj projections don't exist yet, so we need to create
locker.changeMode( QgsReadWriteLocker::Write );

#if PROJ_VERSION_MAJOR>=6
ProjData res = proj_create_crs_to_crs( context, mSourceProjString.toUtf8(), mDestProjString.toUtf8(), nullptr );
mProjProjections.insert( reinterpret_cast< uintptr_t>( context ), res );
#else
#ifdef USE_THREAD_LOCAL
QPair<projPJ, projPJ> res = qMakePair( pj_init_plus_ctx( mProjContext.get(), mSourceProjString.toUtf8() ),
pj_init_plus_ctx( mProjContext.get(), mDestProjString.toUtf8() ) );
@@ -261,6 +278,7 @@ QPair<projPJ, projPJ> QgsCoordinateTransformPrivate::threadLocalProjData()
QPair<projPJ, projPJ> res = qMakePair( pj_init_plus_ctx( pContext, mSourceProjString.toUtf8() ),
pj_init_plus_ctx( pContext, mDestProjString.toUtf8() ) );
mProjProjections.insert( reinterpret_cast< uintptr_t>( pContext ), res );
#endif
#endif
return res;
}
@@ -331,11 +349,15 @@ void QgsCoordinateTransformPrivate::setFinder()
void QgsCoordinateTransformPrivate::freeProj()
{
QgsReadWriteLocker locker( mProjLock, QgsReadWriteLocker::Write );
QMap < uintptr_t, QPair< projPJ, projPJ > >::const_iterator it = mProjProjections.constBegin();
QMap < uintptr_t, ProjData >::const_iterator it = mProjProjections.constBegin();
for ( ; it != mProjProjections.constEnd(); ++it )
{
#if PROJ_VERSION_MAJOR>=6
proj_destroy( it.value() );
#else
pj_free( it.value().first );
pj_free( it.value().second );
#endif
}
mProjProjections.clear();
}
@@ -33,13 +33,21 @@

#include <QSharedData>

#if PROJ_VERSION_MAJOR<6
#ifndef USE_THREAD_LOCAL
#include <QThreadStorage>
#endif
typedef QPair< projPJ, projPJ > ProjData;
#else
struct PJconsts;
typedef struct PJconsts PJ;
typedef PJ *ProjData;
#endif

#include "qgscoordinatereferencesystem.h"
#include "qgscoordinatetransformcontext.h"

#if PROJ_VERSION_MAJOR<6
typedef void *projPJ;
typedef void *projCtx;

@@ -61,6 +69,8 @@ class QgsProjContextStore
projCtx context;
};

#endif

class QgsCoordinateTransformPrivate : public QSharedData
{

@@ -89,7 +99,7 @@ class QgsCoordinateTransformPrivate : public QSharedData

void calculateTransforms( const QgsCoordinateTransformContext &context );

QPair< projPJ, projPJ > threadLocalProjData();
ProjData threadLocalProjData();

/**
* Flag to indicate whether the transform is valid (ie has a valid
@@ -115,6 +125,8 @@ class QgsCoordinateTransformPrivate : public QSharedData
int mSourceDatumTransform = -1;
int mDestinationDatumTransform = -1;

#if PROJ_VERSION_MAJOR<6

/**
* Thread local proj context storage. A new proj context will be created
* for every thread.
@@ -124,9 +136,11 @@ class QgsCoordinateTransformPrivate : public QSharedData
#else
static QThreadStorage< QgsProjContextStore * > mProjContext;
#endif
#endif


QReadWriteLock mProjLock;
QMap < uintptr_t, QPair< projPJ, projPJ > > mProjProjections;
QMap < uintptr_t, ProjData > mProjProjections;

private:

0 comments on commit 95c0d4f

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