Skip to content

Commit

Permalink
Revert "Utilise thread safe proj API within QgsCoordinateTransform"
Browse files Browse the repository at this point in the history
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 2480e26
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 115 deletions.
11 changes: 3 additions & 8 deletions src/core/qgscoordinatereferencesystem.cpp
Expand Up @@ -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()" );
Expand All @@ -918,7 +917,6 @@ void QgsCoordinateReferenceSystem::setProj4String( const QString& theProj4String
{
pj_free( theProj );
}
pj_ctx_free( pContext );
d->mWkt.clear();
setMapUnits();

Expand Down Expand Up @@ -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 )
Expand All @@ -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 )
Expand Down Expand Up @@ -1940,7 +1936,6 @@ int QgsCoordinateReferenceSystem::syncDb()
#endif

OSRDestroySpatialReference( crs );
pj_ctx_free( pContext );

if ( sqlite3_exec( database, "COMMIT", nullptr, nullptr, nullptr ) != SQLITE_OK )
{
Expand Down
125 changes: 43 additions & 82 deletions src/core/qgscoordinatetransform.cpp
Expand Up @@ -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 )
{
Expand All @@ -53,6 +53,8 @@ QgsCoordinateTransform::QgsCoordinateTransform( const QgsCoordinateReferenceSyst
: QObject()
, mShortCircuit( false )
, mInitialisedFlag( false )
, mSourceProjection( nullptr )
, mDestinationProjection( nullptr )
, mSourceDatumTransform( -1 )
, mDestinationDatumTransform( -1 )
{
Expand All @@ -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 )
{
Expand All @@ -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 )
{
Expand All @@ -94,6 +100,8 @@ QgsCoordinateTransform::QgsCoordinateTransform( long theSourceSrid,
QgsCoordinateReferenceSystem::CrsType theSourceCRSType )
: QObject()
, mInitialisedFlag( false )
, mSourceProjection( nullptr )
, mDestinationProjection( nullptr )
, mSourceDatumTransform( -1 )
, mDestinationDatumTransform( -1 )
{
Expand All @@ -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
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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 )
{
Expand All @@ -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 )
Expand All @@ -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"
Expand All @@ -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 )
{
Expand Down Expand Up @@ -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 );
}
33 changes: 8 additions & 25 deletions src/core/qgscoordinatetransform.h
Expand Up @@ -19,8 +19,6 @@

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

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

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

/** \ingroup core
Expand Down Expand Up @@ -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;
Expand All @@ -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
Expand Down

0 comments on commit 2480e26

Please sign in to comment.