29 #include <QDomElement> 30 #include <QApplication> 32 #include <QStringList> 35 #if PROJ_VERSION_MAJOR>=6 47 QReadWriteLock QgsCoordinateTransform::sCacheLock;
52 d =
new QgsCoordinateTransformPrivate();
58 d =
new QgsCoordinateTransformPrivate( source, destination, mContext );
63 if ( !d->checkValidity() )
67 #if PROJ_VERSION_MAJOR>=6 68 if ( !setFromCache( d->mSourceCRS, d->mDestCRS, d->mProjCoordinateOperation ) )
70 if ( !setFromCache( d->mSourceCRS, d->mDestCRS, d->mSourceDatumTransform, d->mDestinationDatumTransform ) )
82 d =
new QgsCoordinateTransformPrivate( source, destination, mContext );
88 if ( !d->checkValidity() )
92 #if PROJ_VERSION_MAJOR>=6 93 if ( !setFromCache( d->mSourceCRS, d->mDestCRS, d->mProjCoordinateOperation ) )
95 if ( !setFromCache( d->mSourceCRS, d->mDestCRS, d->mSourceDatumTransform, d->mDestinationDatumTransform ) )
106 d =
new QgsCoordinateTransformPrivate( source, destination, sourceDatumTransform, destinationDatumTransform );
111 if ( !d->checkValidity() )
115 #if PROJ_VERSION_MAJOR>=6 116 if ( !setFromCache( d->mSourceCRS, d->mDestCRS, d->mProjCoordinateOperation ) )
118 if ( !setFromCache( d->mSourceCRS, d->mDestCRS, d->mSourceDatumTransform, d->mDestinationDatumTransform ) )
128 : mContext( o.mContext )
130 , mHasContext( o.mHasContext )
140 mHasContext = o.mHasContext;
142 mContext = o.mContext;
152 if ( !d->checkValidity() )
155 d->calculateTransforms( mContext );
157 #if PROJ_VERSION_MAJOR>=6 158 if ( !setFromCache( d->mSourceCRS, d->mDestCRS, d->mProjCoordinateOperation ) )
160 if ( !setFromCache( d->mSourceCRS, d->mDestCRS, d->mSourceDatumTransform, d->mDestinationDatumTransform ) )
172 if ( !d->checkValidity() )
175 d->calculateTransforms( mContext );
177 #if PROJ_VERSION_MAJOR>=6 178 if ( !setFromCache( d->mSourceCRS, d->mDestCRS, d->mProjCoordinateOperation ) )
180 if ( !setFromCache( d->mSourceCRS, d->mDestCRS, d->mSourceDatumTransform, d->mDestinationDatumTransform ) )
196 if ( !d->checkValidity() )
199 d->calculateTransforms( mContext );
201 #if PROJ_VERSION_MAJOR>=6 202 if ( !setFromCache( d->mSourceCRS, d->mDestCRS, d->mProjCoordinateOperation ) )
204 if ( !setFromCache( d->mSourceCRS, d->mDestCRS, d->mSourceDatumTransform, d->mDestinationDatumTransform ) )
220 return d->mSourceCRS;
230 if ( !d->mIsValid || d->mShortCircuit )
234 double x = point.
x();
235 double y = point.
y();
244 QgsDebugMsg( QStringLiteral(
"rethrowing exception" ) );
261 QgsDebugMsg( QStringLiteral(
"rethrowing exception" ) );
268 if ( !d->mIsValid || d->mShortCircuit )
288 QgsDebugMsg( QStringLiteral(
"rethrowing exception" ) );
292 #ifdef COORDINATE_TRANSFORM_VERBOSE 293 QgsDebugMsg( QStringLiteral(
"Rect projection..." ) );
305 if ( !d->mIsValid || d->mShortCircuit )
318 QgsDebugMsg( QStringLiteral(
"rethrowing exception" ) );
326 double xd =
static_cast< double >( x ), yd = static_cast< double >( y );
335 if ( !d->mIsValid || d->mShortCircuit )
354 QgsDebugMsg( QStringLiteral(
"rethrowing exception" ) );
361 if ( !d->mIsValid || d->mShortCircuit )
367 int nVertices = poly.size();
369 QVector<double> x( nVertices );
370 QVector<double> y( nVertices );
371 QVector<double> z( nVertices );
372 double *destX = x.data();
373 double *destY = y.data();
374 double *destZ = z.data();
376 const QPointF *polyData = poly.constData();
377 for (
int i = 0; i < nVertices; ++i )
379 *destX++ = polyData->x();
380 *destY++ = polyData->y();
396 QPointF *destPoint = poly.data();
397 const double *srcX = x.constData();
398 const double *srcY = y.constData();
399 for (
int i = 0; i < nVertices; ++i )
401 destPoint->rx() = *srcX++;
402 destPoint->ry() = *srcY++;
407 if ( !err.isEmpty() )
412 QVector<double> &x, QVector<double> &y, QVector<double> &z,
416 if ( !d->mIsValid || d->mShortCircuit )
419 Q_ASSERT( x.size() == y.size() );
433 QgsDebugMsg( QStringLiteral(
"rethrowing exception" ) );
440 QVector<float> &x, QVector<float> &y, QVector<float> &z,
443 if ( !d->mIsValid || d->mShortCircuit )
446 Q_ASSERT( x.size() == y.size() );
456 int vectorSize = x.size();
457 QVector<double> xd( x.size() );
458 QVector<double> yd( y.size() );
459 QVector<double> zd( z.size() );
461 double *destX = xd.data();
462 double *destY = yd.data();
463 double *destZ = zd.data();
465 const float *srcX = x.constData();
466 const float *srcY = y.constData();
467 const float *srcZ = z.constData();
469 for (
int i = 0; i < vectorSize; ++i )
471 *destX++ =
static_cast< double >( *srcX++ );
472 *destY++ =
static_cast< double >( *srcY++ );
473 *destZ++ =
static_cast< double >( *srcZ++ );
479 float *destFX = x.data();
480 float *destFY = y.data();
481 float *destFZ = z.data();
482 const double *srcXD = xd.constData();
483 const double *srcYD = yd.constData();
484 const double *srcZD = zd.constData();
485 for (
int i = 0; i < vectorSize; ++i )
487 *destFX++ =
static_cast< float >( *srcXD++ );
488 *destFY++ =
static_cast< float >( *srcYD++ );
489 *destFZ++ =
static_cast< float >( *srcZD++ );
495 QgsDebugMsg( QStringLiteral(
"rethrowing exception" ) );
507 if ( !d->mIsValid || d->mShortCircuit )
520 const int nPoints = 1000;
521 double d = std::sqrt( ( rect.
width() * rect.
height() ) / std::pow( std::sqrt( static_cast< double >( nPoints ) ) - 1, 2.0 ) );
522 int nXPoints =
static_cast< int >( std::ceil( rect.
width() / d ) ) + 1;
523 int nYPoints =
static_cast< int >( std::ceil( rect.
height() / d ) ) + 1;
531 QVector<double> x( nXPoints * nYPoints );
532 QVector<double> y( nXPoints * nYPoints );
533 QVector<double> z( nXPoints * nYPoints );
535 QgsDebugMsgLevel( QStringLiteral(
"Entering transformBoundingBox..." ), 4 );
539 double dx = rect.
width() /
static_cast< double >( nXPoints - 1 );
540 double dy = rect.
height() /
static_cast< double >( nYPoints - 1 );
544 for (
int i = 0; i < nYPoints ; i++ )
550 for (
int j = 0; j < nXPoints; j++ )
552 x[( i * nXPoints ) + j] = pointX;
553 y[( i * nXPoints ) + j] = pointY;
555 z[( i * nXPoints ) + j] = 0.0;
566 transformCoords( nXPoints * nYPoints, x.data(), y.data(), z.data(), direction );
571 QgsDebugMsg( QStringLiteral(
"rethrowing exception" ) );
577 for (
int i = 0; i < nXPoints * nYPoints; i++ )
579 if ( !std::isfinite( x[i] ) || !std::isfinite( y[i] ) )
584 if ( handle180Crossover )
598 throw QgsCsException( QObject::tr(
"Could not transform bounding box to target CRS" ) );
601 if ( handle180Crossover )
622 if ( !d->mIsValid || d->mShortCircuit )
625 if ( !d->mSourceCRS.isValid() )
628 "The coordinates can not be reprojected. The CRS is: %1" )
629 .arg( d->mSourceCRS.toProj4() ), QObject::tr(
"CRS" ) );
632 if ( !d->mDestCRS.isValid() )
635 "The coordinates can not be reprojected. The CRS is: %1" ).arg( d->mDestCRS.toProj4() ), QObject::tr(
"CRS" ) );
639 #ifdef COORDINATE_TRANSFORM_VERBOSE 642 QgsDebugMsg( QStringLiteral(
"[[[[[[ Number of points to transform: %1 ]]]]]]" ).arg( numPoints ) );
647 QgsDebugMsgLevel( QStringLiteral(
"No QgsCoordinateTransformContext context set for transform" ), 4 );
654 ProjData projData = d->threadLocalProjData();
657 #if PROJ_VERSION_MAJOR>=6 658 proj_errno_reset( projData );
659 proj_trans_generic( projData, direction ==
ForwardTransform ? PJ_FWD : PJ_INV,
660 x,
sizeof(
double ), numPoints,
661 y,
sizeof(
double ), numPoints,
662 z,
sizeof(
double ), numPoints,
663 nullptr,
sizeof(
double ), 0 );
664 projResult = proj_errno( projData );
666 bool sourceIsLatLong =
false;
667 bool destIsLatLong =
false;
669 projPJ sourceProj = projData.first;
670 projPJ destProj = projData.second;
671 sourceIsLatLong = pj_is_latlong( sourceProj );
672 destIsLatLong = pj_is_latlong( destProj );
677 for (
int i = 0; i < numPoints; ++i )
685 #if PROJ_VERSION_MAJOR<6 688 projResult = pj_transform( destProj, sourceProj, numPoints, 0, x, y, z );
692 Q_ASSERT( sourceProj );
693 Q_ASSERT( destProj );
694 projResult = pj_transform( sourceProj, destProj, numPoints, 0, x, y, z );
698 if ( projResult != 0 )
703 for (
int i = 0; i < numPoints; ++i )
707 points += QStringLiteral(
"(%1, %2)\n" ).arg( x[i], 0,
'f' ).arg( y[i], 0,
'f' );
711 #if PROJ_VERSION_MAJOR>=6 712 points += QStringLiteral(
"(%1, %2)\n" ).arg( x[i], 0,
'f' ).arg( y[i], 0,
'f' );
714 points += QStringLiteral(
"(%1, %2)\n" ).arg( x[i] * RAD_TO_DEG, 0,
'f' ).arg( y[i] * RAD_TO_DEG, 0,
'f' );
719 QString dir = ( direction ==
ForwardTransform ) ? QObject::tr(
"forward transform" ) : QObject::tr(
"inverse transform" );
721 #if PROJ_VERSION_MAJOR>=6 722 QgsProjUtils::proj_pj_unique_ptr src( proj_get_source_crs(
QgsProjContext::get(), projData ) );
723 QgsProjUtils::proj_pj_unique_ptr dest( proj_get_source_crs(
QgsProjContext::get(), projData ) );
724 QString msg = QObject::tr(
"%1 of\n" 731 QString::fromUtf8( proj_errno_string( projResult ) ) );
733 char *srcdef = pj_get_def( sourceProj, 0 );
734 char *dstdef = pj_get_def( destProj, 0 );
736 QString msg = QObject::tr(
"%1 of\n" 743 QString::fromUtf8( pj_strerrno( projResult ) ) );
749 QgsDebugMsg(
"Projection failed emitting invalid transform signal: " + msg );
750 QgsDebugMsg( QStringLiteral(
"throwing exception" ) );
755 #if PROJ_VERSION_MAJOR<6 761 for (
int i = 0; i < numPoints; ++i )
768 #ifdef COORDINATE_TRANSFORM_VERBOSE 769 QgsDebugMsg( QStringLiteral(
"[[[[[[ Projected %1, %2 to %3, %4 ]]]]]]" )
770 .arg( xorg, 0,
'g', 15 ).arg( yorg, 0,
'g', 15 )
771 .arg( *x, 0,
'g', 15 ).arg( *y, 0,
'g', 15 ) );
782 return !d->mIsValid || d->mShortCircuit;
787 return d->mProjCoordinateOperation;
793 d->mProjCoordinateOperation = operation;
800 proj = QApplication::applicationDirPath()
801 +
"/share/proj/" + QString( name );
805 return proj.toUtf8();
808 #if PROJ_VERSION_MAJOR>=6 814 const QString sourceKey = src.
authid().isEmpty() ?
816 const QString destKey = dest.
authid().isEmpty() ?
819 if ( sourceKey.isEmpty() || destKey.isEmpty() )
822 sCacheLock.lockForRead();
823 const QList< QgsCoordinateTransform > values = sTransforms.values( qMakePair( sourceKey, destKey ) );
824 for (
auto valIt = values.constBegin(); valIt != values.constEnd(); ++valIt )
826 if ( ( *valIt ).coordinateOperation() == coordinateOperationProj )
831 bool hasContext = mHasContext;
838 mHasContext = hasContext;
853 const QString sourceKey = src.
authid().isEmpty() ?
855 const QString destKey = dest.
authid().isEmpty() ?
858 if ( sourceKey.isEmpty() || destKey.isEmpty() )
861 sCacheLock.lockForRead();
862 const QList< QgsCoordinateTransform > values = sTransforms.values( qMakePair( src.
authid(), dest.
authid() ) );
863 for (
auto valIt = values.constBegin(); valIt != values.constEnd(); ++valIt )
866 if ( ( *valIt ).sourceDatumTransformId() == srcDatumTransform &&
867 ( *valIt ).destinationDatumTransformId() == destDatumTransform )
872 bool hasContext = mHasContext;
879 mHasContext = hasContext;
891 void QgsCoordinateTransform::addToCache()
893 if ( !d->mSourceCRS.isValid() || !d->mDestCRS.isValid() )
896 const QString sourceKey = d->mSourceCRS.authid().isEmpty() ?
897 d->mSourceCRS.toWkt() : d->mSourceCRS.authid();
898 const QString destKey = d->mDestCRS.authid().isEmpty() ?
899 d->mDestCRS.toWkt() : d->mDestCRS.authid();
901 if ( sourceKey.isEmpty() || destKey.isEmpty() )
904 sCacheLock.lockForWrite();
905 sTransforms.insertMulti( qMakePair( sourceKey, destKey ), *
this );
912 return d->mSourceDatumTransform;
920 d->mSourceDatumTransform = dt;
927 return d->mDestinationDatumTransform;
935 d->mDestinationDatumTransform = dt;
941 sCacheLock.lockForWrite();
950 double distSourceUnits = std::sqrt( source1.sqrDist( source2 ) );
953 double distDestUnits = std::sqrt( dest1.sqrDist( dest2 ) );
954 return distDestUnits / distSourceUnits;
959 QgsCoordinateTransformPrivate::setCustomMissingRequiredGridHandler( handler );
964 QgsCoordinateTransformPrivate::setCustomMissingPreferredGridHandler( handler );
969 QgsCoordinateTransformPrivate::setCustomCoordinateOperationCreationErrorHandler( handler );
974 QgsCoordinateTransformPrivate::setCustomMissingGridUsedByContextHandler( handler );
A rectangle specified with double values.
void setMinimal()
Set a rectangle so that min corner is at max and max corner is at min.
void setXMaximum(double x)
Set the maximum x value.
A class to represent a 2D point.
#define Q_NOWARN_DEPRECATED_PUSH
const QgsCoordinateReferenceSystem & crs
#define QgsDebugMsgLevel(str, level)
bool isEmpty() const
Returns true if the rectangle is empty.
double width() const
Returns the width of the rectangle.
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::Warning, bool notifyUser=true)
Adds a message to the log instance (and creates it if necessary).
QString toString(int precision=16) const
Returns a string representation of form xmin,ymin : xmax,ymax Coordinates will be truncated to the sp...
Reads and writes project states.
Contains information about the context in which a coordinate transform is executed.
double yMinimum() const
Returns the y minimum value (bottom side of rectangle).
double xMaximum() const
Returns the x maximum value (right side of rectangle).
QgsCoordinateTransformContext transformContext
void combineExtentWith(const QgsRectangle &rect)
Expands the rectangle so that it covers both the original rectangle and the given rectangle...
#define Q_NOWARN_DEPRECATED_POP
This class represents a coordinate reference system (CRS).
QString toWkt() const
Returns a WKT representation of this CRS.
bool isNull() const
Test if the rectangle is null (all coordinates zero or after call to setMinimal()).
double xMinimum() const
Returns the x minimum value (left side of rectangle).
double yMaximum() const
Returns the y maximum value (top side of rectangle).
static PJ_CONTEXT * get()
Returns a thread local instance of a proj context, safe for use in the current thread.
Custom exception class for Coordinate Reference System related exceptions.
QString authid() const
Returns the authority identifier for the CRS.
void setXMinimum(double x)
Set the minimum x value.
double height() const
Returns the height of the rectangle.
bool isValid() const
Returns whether this CRS is correctly initialized and usable.