30 #include <QDomElement> 31 #include <QApplication> 33 #include <QStringList> 38 #ifndef ACCEPT_USE_OF_DEPRECATED_PROJ_API_H 39 #define ACCEPT_USE_OF_DEPRECATED_PROJ_API_H 48 QReadWriteLock QgsCoordinateTransform::sCacheLock;
50 bool QgsCoordinateTransform::sDisableCache =
false;
54 d =
new QgsCoordinateTransformPrivate();
61 if ( !d->checkValidity() )
64 if ( !setFromCache( d->mSourceCRS, d->mDestCRS, d->mSourceDatumTransform, d->mDestinationDatumTransform ) )
74 d =
new QgsCoordinateTransformPrivate( source, destination, mContext );
79 if ( !d->checkValidity() )
82 if ( !setFromCache( d->mSourceCRS, d->mDestCRS, d->mSourceDatumTransform, d->mDestinationDatumTransform ) )
92 d =
new QgsCoordinateTransformPrivate( source, destination, mContext );
98 if ( !d->checkValidity() )
101 if ( !setFromCache( d->mSourceCRS, d->mDestCRS, d->mSourceDatumTransform, d->mDestinationDatumTransform ) )
110 d =
new QgsCoordinateTransformPrivate( source, destination, sourceDatumTransform, destinationDatumTransform );
115 if ( !d->checkValidity() )
118 if ( !setFromCache( d->mSourceCRS, d->mDestCRS, d->mSourceDatumTransform, d->mDestinationDatumTransform ) )
126 : mContext( o.mContext )
128 , mHasContext( o.mHasContext )
138 mHasContext = o.mHasContext;
140 mContext = o.mContext;
150 if ( !d->checkValidity() )
153 d->calculateTransforms( mContext );
154 if ( !setFromCache( d->mSourceCRS, d->mDestCRS, d->mSourceDatumTransform, d->mDestinationDatumTransform ) )
164 if ( !d->checkValidity() )
167 d->calculateTransforms( mContext );
168 if ( !setFromCache( d->mSourceCRS, d->mDestCRS, d->mSourceDatumTransform, d->mDestinationDatumTransform ) )
182 if ( !d->checkValidity() )
185 d->calculateTransforms( mContext );
186 if ( !setFromCache( d->mSourceCRS, d->mDestCRS, d->mSourceDatumTransform, d->mDestinationDatumTransform ) )
200 return d->mSourceCRS;
210 if ( !d->mIsValid || d->mShortCircuit )
214 double x = point.
x();
215 double y = point.
y();
224 QgsDebugMsg( QStringLiteral(
"rethrowing exception" ) );
241 QgsDebugMsg( QStringLiteral(
"rethrowing exception" ) );
248 if ( !d->mIsValid || d->mShortCircuit )
268 QgsDebugMsg( QStringLiteral(
"rethrowing exception" ) );
272 #ifdef COORDINATE_TRANSFORM_VERBOSE 273 QgsDebugMsg( QStringLiteral(
"Rect projection..." ) );
285 if ( !d->mIsValid || d->mShortCircuit )
298 QgsDebugMsg( QStringLiteral(
"rethrowing exception" ) );
306 double xd =
static_cast< double >( x ), yd = static_cast< double >( y );
315 if ( !d->mIsValid || d->mShortCircuit )
334 QgsDebugMsg( QStringLiteral(
"rethrowing exception" ) );
341 if ( !d->mIsValid || d->mShortCircuit )
347 int nVertices = poly.size();
349 QVector<double> x( nVertices );
350 QVector<double> y( nVertices );
351 QVector<double> z( nVertices );
352 double *destX = x.data();
353 double *destY = y.data();
354 double *destZ = z.data();
356 const QPointF *polyData = poly.constData();
357 for (
int i = 0; i < nVertices; ++i )
359 *destX++ = polyData->x();
360 *destY++ = polyData->y();
372 QgsDebugMsg( QStringLiteral(
"rethrowing exception" ) );
376 QPointF *destPoint = poly.data();
377 const double *srcX = x.constData();
378 const double *srcY = y.constData();
379 for (
int i = 0; i < nVertices; ++i )
381 destPoint->rx() = *srcX++;
382 destPoint->ry() = *srcY++;
388 QVector<double> &x, QVector<double> &y, QVector<double> &z,
392 if ( !d->mIsValid || d->mShortCircuit )
395 Q_ASSERT( x.size() == y.size() );
409 QgsDebugMsg( QStringLiteral(
"rethrowing exception" ) );
416 QVector<float> &x, QVector<float> &y, QVector<float> &z,
419 if ( !d->mIsValid || d->mShortCircuit )
422 Q_ASSERT( x.size() == y.size() );
432 int vectorSize = x.size();
433 QVector<double> xd( x.size() );
434 QVector<double> yd( y.size() );
435 QVector<double> zd( z.size() );
437 double *destX = xd.data();
438 double *destY = yd.data();
439 double *destZ = zd.data();
441 const float *srcX = x.constData();
442 const float *srcY = y.constData();
443 const float *srcZ = z.constData();
445 for (
int i = 0; i < vectorSize; ++i )
447 *destX++ =
static_cast< double >( *srcX++ );
448 *destY++ =
static_cast< double >( *srcY++ );
449 *destZ++ =
static_cast< double >( *srcZ++ );
455 float *destFX = x.data();
456 float *destFY = y.data();
457 float *destFZ = z.data();
458 const double *srcXD = xd.constData();
459 const double *srcYD = yd.constData();
460 const double *srcZD = zd.constData();
461 for (
int i = 0; i < vectorSize; ++i )
463 *destFX++ =
static_cast< float >( *srcXD++ );
464 *destFY++ =
static_cast< float >( *srcYD++ );
465 *destFZ++ =
static_cast< float >( *srcZD++ );
471 QgsDebugMsg( QStringLiteral(
"rethrowing exception" ) );
483 if ( !d->mIsValid || d->mShortCircuit )
496 const int nPoints = 1000;
497 double d = std::sqrt( ( rect.
width() * rect.
height() ) / std::pow( std::sqrt( static_cast< double >( nPoints ) ) - 1, 2.0 ) );
498 int nXPoints = std::min( static_cast< int >( std::ceil( rect.
width() / d ) ) + 1, 1000 );
499 int nYPoints = std::min( static_cast< int >( std::ceil( rect.
height() / d ) ) + 1, 1000 );
506 QVector<double> x( nXPoints * nYPoints );
507 QVector<double> y( nXPoints * nYPoints );
508 QVector<double> z( nXPoints * nYPoints );
510 QgsDebugMsgLevel( QStringLiteral(
"Entering transformBoundingBox..." ), 4 );
514 double dx = rect.
width() /
static_cast< double >( nXPoints - 1 );
515 double dy = rect.
height() /
static_cast< double >( nYPoints - 1 );
519 for (
int i = 0; i < nYPoints ; i++ )
525 for (
int j = 0; j < nXPoints; j++ )
527 x[( i * nXPoints ) + j] = pointX;
528 y[( i * nXPoints ) + j] = pointY;
530 z[( i * nXPoints ) + j] = 0.0;
541 transformCoords( nXPoints * nYPoints, x.data(), y.data(), z.data(), direction );
546 QgsDebugMsg( QStringLiteral(
"rethrowing exception" ) );
552 for (
int i = 0; i < nXPoints * nYPoints; i++ )
554 if ( !std::isfinite( x[i] ) || !std::isfinite( y[i] ) )
559 if ( handle180Crossover )
562 bb_rect.combineExtentWith( x[i] >= 0.0 ? x[i] : x[i] + 360.0, y[i] );
566 bb_rect.combineExtentWith( x[i], y[i] );
570 if ( bb_rect.isNull() )
573 throw QgsCsException( QObject::tr(
"Could not transform bounding box to target CRS" ) );
576 if ( handle180Crossover )
579 if ( bb_rect.xMinimum() > 180.0 )
580 bb_rect.setXMinimum( bb_rect.xMinimum() - 360.0 );
581 if ( bb_rect.xMaximum() > 180.0 )
582 bb_rect.setXMaximum( bb_rect.xMaximum() - 360.0 );
587 if ( bb_rect.isEmpty() )
597 if ( !d->mIsValid || d->mShortCircuit )
600 if ( !d->mSourceCRS.isValid() )
603 "The coordinates can not be reprojected. The CRS is: %1" )
604 .arg( d->mSourceCRS.toProj4() ), QObject::tr(
"CRS" ) );
607 if ( !d->mDestCRS.isValid() )
610 "The coordinates can not be reprojected. The CRS is: %1" ).arg( d->mDestCRS.toProj4() ), QObject::tr(
"CRS" ) );
614 #ifdef COORDINATE_TRANSFORM_VERBOSE 617 QgsDebugMsg( QStringLiteral(
"[[[[[[ Number of points to transform: %1 ]]]]]]" ).arg( numPoints ) );
622 QgsDebugMsgLevel( QStringLiteral(
"No QgsCoordinateTransformContext context set for transform" ), 4 );
629 QPair<projPJ, projPJ> projData = d->threadLocalProjData();
630 projPJ sourceProj = projData.first;
631 projPJ destProj = projData.second;
636 for (
int i = 0; i < numPoints; ++i )
646 projResult = pj_transform( destProj, sourceProj, numPoints, 0, x, y, z );
650 Q_ASSERT( sourceProj );
651 Q_ASSERT( destProj );
652 projResult = pj_transform( sourceProj, destProj, numPoints, 0, x, y, z );
655 if ( projResult != 0 )
660 for (
int i = 0; i < numPoints; ++i )
664 points += QStringLiteral(
"(%1, %2)\n" ).arg( x[i], 0,
'f' ).arg( y[i], 0,
'f' );
668 points += QStringLiteral(
"(%1, %2)\n" ).arg( x[i] * RAD_TO_DEG, 0,
'f' ).arg( y[i] * RAD_TO_DEG, 0,
'f' );
672 QString dir = ( direction ==
ForwardTransform ) ? QObject::tr(
"forward transform" ) : QObject::tr(
"inverse transform" );
674 char *srcdef = pj_get_def( sourceProj, 0 );
675 char *dstdef = pj_get_def( destProj, 0 );
677 QString msg = QObject::tr(
"%1 of\n" 684 QString::fromUtf8( pj_strerrno( projResult ) ) );
689 QgsDebugMsg(
"Projection failed emitting invalid transform signal: " + msg );
690 QgsDebugMsg( QStringLiteral(
"throwing exception" ) );
700 for (
int i = 0; i < numPoints; ++i )
706 #ifdef COORDINATE_TRANSFORM_VERBOSE 707 QgsDebugMsg( QStringLiteral(
"[[[[[[ Projected %1, %2 to %3, %4 ]]]]]]" )
708 .arg( xorg, 0,
'g', 15 ).arg( yorg, 0,
'g', 15 )
709 .arg( *x, 0,
'g', 15 ).arg( *y, 0,
'g', 15 ) );
720 return !d->mIsValid || d->mShortCircuit;
727 proj = QApplication::applicationDirPath()
728 +
"/share/proj/" + QString( name );
732 return proj.toUtf8();
740 const QString sourceKey = src.
authid().isEmpty() ?
742 const QString destKey = dest.
authid().isEmpty() ?
745 if ( sourceKey.isEmpty() || destKey.isEmpty() )
752 const QList< QgsCoordinateTransform > values = sTransforms.values( qMakePair( sourceKey, destKey ) );
753 for (
auto valIt = values.constBegin(); valIt != values.constEnd(); ++valIt )
755 if ( ( *valIt ).sourceDatumTransformId() == srcDatumTransform &&
756 ( *valIt ).destinationDatumTransformId() == destDatumTransform )
761 bool hasContext = mHasContext;
768 mHasContext = hasContext;
777 void QgsCoordinateTransform::addToCache()
779 if ( !d->mSourceCRS.isValid() || !d->mDestCRS.isValid() )
782 const QString sourceKey = d->mSourceCRS.authid().isEmpty() ?
783 d->mSourceCRS.toWkt() : d->mSourceCRS.authid();
784 const QString destKey = d->mDestCRS.authid().isEmpty() ?
785 d->mDestCRS.toWkt() : d->mDestCRS.authid();
787 if ( sourceKey.isEmpty() || destKey.isEmpty() )
794 sTransforms.insertMulti( qMakePair( sourceKey, destKey ), *
this );
799 return d->mSourceDatumTransform;
805 d->mSourceDatumTransform = dt;
810 return d->mDestinationDatumTransform;
816 d->mDestinationDatumTransform = dt;
827 sDisableCache =
true;
837 double distSourceUnits = std::sqrt( source1.sqrDist( source2 ) );
840 double distDestUnits = std::sqrt( dest1.sqrDist( dest2 ) );
841 return distDestUnits / distSourceUnits;
A rectangle specified with double values.
bool isEmpty() const
Returns true if the rectangle is empty.
void setMinimal()
Set a rectangle so that min corner is at max and max corner is at min.
double yMaximum() const
Returns the y maximum value (top side of rectangle).
A class to represent a 2D point.
QString toWkt() const
Returns a WKT representation of this CRS.
const QgsCoordinateReferenceSystem & crs
The QgsReadWriteLocker class is a convenience class that simplifies locking and unlocking QReadWriteL...
double yMinimum() const
Returns the y minimum value (bottom side of rectangle).
double xMaximum() const
Returns the x maximum value (right side of rectangle).
#define QgsDebugMsgLevel(str, level)
QString toString(int precision=16) const
Returns a string representation of form xmin,ymin : xmax,ymax Coordinates will be truncated to the sp...
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).
Reads and writes project states.
Contains information about the context in which a coordinate transform is executed.
QgsCoordinateTransformContext transformContext
void unlock()
Unlocks the lock.
bool isValid() const
Returns whether this CRS is correctly initialized and usable.
This class represents a coordinate reference system (CRS).
QString authid() const
Returns the authority identifier for the CRS.
Custom exception class for Coordinate Reference System related exceptions.
double width() const
Returns the width of the rectangle.
double xMinimum() const
Returns the x minimum value (left side of rectangle).
double height() const
Returns the height of the rectangle.