Skip to content
Permalink
Browse files
Revert "Utilise thread safe proj API within QgsCoordinateTransform"
This reverts commit af3370d.

This commit is not safe for 2.18.9 - remerge after release
  • Loading branch information
nyalldawson committed May 25, 2017
1 parent 6768c89 commit 2480e268c9b958b25de14464ae846588e54fa735
Showing with 54 additions and 115 deletions.
  1. +3 −8 src/core/qgscoordinatereferencesystem.cpp
  2. +43 −82 src/core/qgscoordinatetransform.cpp
  3. +8 −25 src/core/qgscoordinatetransform.h
@@ -907,8 +907,7 @@ void QgsCoordinateReferenceSystem::setProj4String( const QString& theProj4String
// e.g if they lack a +ellps parameter, it will automatically add +ellps=WGS84, but as
// we use the original mProj4 with QgsCoordinateTransform, it will fail to initialize
// so better detect it now.
projCtx pContext = pj_ctx_alloc();
projPJ theProj = pj_init_plus_ctx( pContext, theProj4String.trimmed().toLatin1().constData() );
projPJ theProj = pj_init_plus( theProj4String.trimmed().toLatin1().constData() );
if ( !theProj )
{
QgsDebugMsg( "proj.4 string rejected by pj_init_plus()" );
@@ -918,7 +917,6 @@ void QgsCoordinateReferenceSystem::setProj4String( const QString& theProj4String
{
pj_free( theProj );
}
pj_ctx_free( pContext );
d->mWkt.clear();
setMapUnits();

@@ -1860,8 +1858,6 @@ int QgsCoordinateReferenceSystem::syncDb()
sqlite3_errmsg( database ) );
}

projCtx pContext = pj_ctx_alloc();

#if !defined(PJ_VERSION) || PJ_VERSION!=470
sql = QString( "select auth_name,auth_id,parameters from tbl_srs WHERE auth_name<>'EPSG' AND NOT deprecated AND NOT noupdate" );
if ( sqlite3_prepare( database, sql.toAscii(), sql.size(), &select, &tail ) == SQLITE_OK )
@@ -1873,11 +1869,11 @@ int QgsCoordinateReferenceSystem::syncDb()
const char *params = reinterpret_cast< const char * >( sqlite3_column_text( select, 2 ) );

QString input = QString( "+init=%1:%2" ).arg( QString( auth_name ).toLower(), auth_id );
projPJ pj = pj_init_plus_ctx( pContext, input.toAscii() );
projPJ pj = pj_init_plus( input.toAscii() );
if ( !pj )
{
input = QString( "+init=%1:%2" ).arg( QString( auth_name ).toUpper(), auth_id );
pj = pj_init_plus_ctx( pContext, input.toAscii() );
pj = pj_init_plus( input.toAscii() );
}

if ( pj )
@@ -1940,7 +1936,6 @@ int QgsCoordinateReferenceSystem::syncDb()
#endif

OSRDestroySpatialReference( crs );
pj_ctx_free( pContext );

if ( sqlite3_exec( database, "COMMIT", nullptr, nullptr, nullptr ) != SQLITE_OK )
{
@@ -37,12 +37,12 @@ extern "C"
// if defined shows all information about transform to stdout
// #define COORDINATE_TRANSFORM_VERBOSE

QThreadStorage< QgsCoordinateTransform::QgsProjContextStore* > QgsCoordinateTransform::mProjContext;

QgsCoordinateTransform::QgsCoordinateTransform()
: QObject()
, mShortCircuit( false )
, mInitialisedFlag( false )
, mSourceProjection( nullptr )
, mDestinationProjection( nullptr )
, mSourceDatumTransform( -1 )
, mDestinationDatumTransform( -1 )
{
@@ -53,6 +53,8 @@ QgsCoordinateTransform::QgsCoordinateTransform( const QgsCoordinateReferenceSyst
: QObject()
, mShortCircuit( false )
, mInitialisedFlag( false )
, mSourceProjection( nullptr )
, mDestinationProjection( nullptr )
, mSourceDatumTransform( -1 )
, mDestinationDatumTransform( -1 )
{
@@ -67,6 +69,8 @@ QgsCoordinateTransform::QgsCoordinateTransform( long theSourceSrsId, long theDes
, mInitialisedFlag( false )
, mSourceCRS( QgsCRSCache::instance()->crsBySrsId( theSourceSrsId ) )
, mDestCRS( QgsCRSCache::instance()->crsBySrsId( theDestSrsId ) )
, mSourceProjection( nullptr )
, mDestinationProjection( nullptr )
, mSourceDatumTransform( -1 )
, mDestinationDatumTransform( -1 )
{
@@ -76,6 +80,8 @@ QgsCoordinateTransform::QgsCoordinateTransform( long theSourceSrsId, long theDes
QgsCoordinateTransform::QgsCoordinateTransform( const QString& theSourceCRS, const QString& theDestCRS )
: QObject()
, mInitialisedFlag( false )
, mSourceProjection( nullptr )
, mDestinationProjection( nullptr )
, mSourceDatumTransform( -1 )
, mDestinationDatumTransform( -1 )
{
@@ -94,6 +100,8 @@ QgsCoordinateTransform::QgsCoordinateTransform( long theSourceSrid,
QgsCoordinateReferenceSystem::CrsType theSourceCRSType )
: QObject()
, mInitialisedFlag( false )
, mSourceProjection( nullptr )
, mDestinationProjection( nullptr )
, mSourceDatumTransform( -1 )
, mDestinationDatumTransform( -1 )
{
@@ -110,7 +118,15 @@ QgsCoordinateTransform::QgsCoordinateTransform( long theSourceSrid,

QgsCoordinateTransform::~QgsCoordinateTransform()
{
freeProj();
// free the proj objects
if ( mSourceProjection )
{
pj_free( mSourceProjection );
}
if ( mDestinationProjection )
{
pj_free( mDestinationProjection );
}
}

QgsCoordinateTransform* QgsCoordinateTransform::clone() const
@@ -164,47 +180,49 @@ void QgsCoordinateTransform::initialise()

bool useDefaultDatumTransform = ( mSourceDatumTransform == - 1 && mDestinationDatumTransform == -1 );

freeProj();
// init the projections (destination and source)

mSourceProjString = mSourceCRS.toProj4();
pj_free( mSourceProjection );
QString sourceProjString = mSourceCRS.toProj4();
if ( !useDefaultDatumTransform )
{
mSourceProjString = stripDatumTransform( mSourceProjString );
sourceProjString = stripDatumTransform( sourceProjString );
}
if ( mSourceDatumTransform != -1 )
{
mSourceProjString += ( ' ' + datumTransformString( mSourceDatumTransform ) );
sourceProjString += ( ' ' + datumTransformString( mSourceDatumTransform ) );
}

mDestProjString = mDestCRS.toProj4();
pj_free( mDestinationProjection );
QString destProjString = mDestCRS.toProj4();
if ( !useDefaultDatumTransform )
{
mDestProjString = stripDatumTransform( mDestProjString );
destProjString = stripDatumTransform( destProjString );
}
if ( mDestinationDatumTransform != -1 )
{
mDestProjString += ( ' ' + datumTransformString( mDestinationDatumTransform ) );
destProjString += ( ' ' + datumTransformString( mDestinationDatumTransform ) );
}

if ( !useDefaultDatumTransform )
{
addNullGridShifts( mSourceProjString, mDestProjString );
addNullGridShifts( sourceProjString, destProjString );
}

// create proj projections for current thread
QPair< projPJ, projPJ > res = threadLocalProjData();
mSourceProjection = pj_init_plus( sourceProjString.toUtf8() );
mDestinationProjection = pj_init_plus( destProjString.toUtf8() );

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

mInitialisedFlag = true;
if ( !res.second )
if ( !mDestinationProjection )
{
mInitialisedFlag = false;
}
if ( !res.first )
if ( !mSourceProjection )
{
mInitialisedFlag = false;
}
@@ -643,12 +661,8 @@ void QgsCoordinateTransform::transformCoords( int numPoints, double *x, double *
QString dir;
// if the source/destination projection is lat/long, convert the points to radians
// prior to transforming
QPair< projPJ, projPJ > projData = threadLocalProjData();
projPJ sourceProj = projData.first;
projPJ destProj = projData.second;

if (( pj_is_latlong( destProj ) && ( direction == ReverseTransform ) )
|| ( pj_is_latlong( sourceProj ) && ( direction == ForwardTransform ) ) )
if (( pj_is_latlong( mDestinationProjection ) && ( direction == ReverseTransform ) )
|| ( pj_is_latlong( mSourceProjection ) && ( direction == ForwardTransform ) ) )
{
for ( int i = 0; i < numPoints; ++i )
{
@@ -660,13 +674,13 @@ void QgsCoordinateTransform::transformCoords( int numPoints, double *x, double *
int projResult;
if ( direction == ReverseTransform )
{
projResult = pj_transform( destProj, sourceProj, numPoints, 0, x, y, z );
projResult = pj_transform( mDestinationProjection, mSourceProjection, numPoints, 0, x, y, z );
}
else
{
Q_ASSERT( sourceProj );
Q_ASSERT( destProj );
projResult = pj_transform( sourceProj, destProj, numPoints, 0, x, y, z );
Q_ASSERT( mSourceProjection );
Q_ASSERT( mDestinationProjection );
projResult = pj_transform( mSourceProjection, mDestinationProjection, numPoints, 0, x, y, z );
}

if ( projResult != 0 )
@@ -688,8 +702,8 @@ void QgsCoordinateTransform::transformCoords( int numPoints, double *x, double *

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

char *srcdef = pj_get_def( sourceProj, 0 );
char *dstdef = pj_get_def( destProj, 0 );
char *srcdef = pj_get_def( mSourceProjection, 0 );
char *dstdef = pj_get_def( mDestinationProjection, 0 );

QString msg = tr( "%1 of\n"
"%2"
@@ -714,8 +728,8 @@ void QgsCoordinateTransform::transformCoords( int numPoints, double *x, double *

// 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 (( pj_is_latlong( mDestinationProjection ) && ( direction == ForwardTransform ) )
|| ( pj_is_latlong( mSourceProjection ) && ( direction == ReverseTransform ) ) )
{
for ( int i = 0; i < numPoints; ++i )
{
@@ -1041,56 +1055,3 @@ void QgsCoordinateTransform::addNullGridShifts( QString& srcProjString, QString&
destProjString += " +nadgrids=@null";
}
}

QPair<projPJ, projPJ> QgsCoordinateTransform::threadLocalProjData() const
{
mProjLock.lockForRead();
projCtx pContext = nullptr;
if ( mProjContext.hasLocalData() )
pContext = mProjContext.localData()->get();
else
{
mProjContext.setLocalData( new QgsProjContextStore() );
pContext = mProjContext.localData()->get();
}

QMap< uintptr_t, QPair< projPJ, projPJ > >::const_iterator it = mProjProjections.constFind( reinterpret_cast< uintptr_t >( pContext ) );
if ( it != mProjProjections.constEnd() )
{
QPair< projPJ, projPJ > res = it.value();
mProjLock.unlock();
return res;
}

// proj projections don't exist yet, so we need to create
mProjLock.unlock();
mProjLock.lockForWrite();
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 );
mProjLock.unlock();
return res;
}

void QgsCoordinateTransform::freeProj()
{
mProjLock.lockForWrite();
QMap< uintptr_t, QPair< projPJ, projPJ > >::const_iterator it = mProjProjections.constBegin();
for ( ; it != mProjProjections.constEnd(); ++it )
{
pj_free( it.value().first );
pj_free( it.value().second );
}
mProjProjections.clear();
mProjLock.unlock();
}

QgsCoordinateTransform::QgsProjContextStore::QgsProjContextStore()
{
context = pj_ctx_alloc();
}

QgsCoordinateTransform::QgsProjContextStore::~QgsProjContextStore()
{
pj_ctx_free( context );
}
@@ -19,8 +19,6 @@

//qt includes
#include <QObject>
#include <QThreadStorage>
#include <QReadWriteLock>

//qgis includes
#include "qgspoint.h"
@@ -36,7 +34,6 @@ class QPolygonF;
#include <vector>

typedef void* projPJ;
typedef void* projCtx;
class QString;

/** \ingroup core
@@ -277,26 +274,15 @@ class CORE_EXPORT QgsCoordinateTransform : public QObject
*/
QgsCoordinateReferenceSystem mDestCRS;

QString mSourceProjString;
QString mDestProjString;

class QgsProjContextStore
{
public:

QgsProjContextStore();
~QgsProjContextStore();

projCtx get() { return context; }

private:

projCtx context;
};
/*!
* Proj4 data structure of the source projection (layer coordinate system)
*/
projPJ mSourceProjection;

static QThreadStorage< QgsProjContextStore* > mProjContext;
mutable QReadWriteLock mProjLock;
mutable QMap< uintptr_t, QPair< projPJ, projPJ > > mProjProjections;
/*!
* Proj4 data structure of the destination projection (map canvas coordinate system)
*/
projPJ mDestinationProjection;

int mSourceDatumTransform;
int mDestinationDatumTransform;
@@ -311,9 +297,6 @@ class CORE_EXPORT QgsCoordinateTransform : public QObject
static void searchDatumTransform( const QString& sql, QList< int >& transforms );
/** In certain situations, null grid shifts have to be added to src / dst proj string*/
void addNullGridShifts( QString& srcProjString, QString& destProjString );

QPair< projPJ, projPJ > threadLocalProjData() const;
void freeProj();
};

//! Output stream operator

0 comments on commit 2480e26

Please sign in to comment.