29 #include <QDomElement> 30 #include <QApplication> 32 #include <QStringList> 44 QReadWriteLock QgsCoordinateTransform::sCacheLock;
49 d =
new QgsCoordinateTransformPrivate();
56 if ( !d->checkValidity() )
59 if ( !setFromCache( d->mSourceCRS, d->mDestCRS, d->mSourceDatumTransform, d->mDestinationDatumTransform ) )
69 d =
new QgsCoordinateTransformPrivate( source, destination, mContext );
74 if ( !d->checkValidity() )
77 if ( !setFromCache( d->mSourceCRS, d->mDestCRS, d->mSourceDatumTransform, d->mDestinationDatumTransform ) )
87 d =
new QgsCoordinateTransformPrivate( source, destination, mContext );
93 if ( !d->checkValidity() )
96 if ( !setFromCache( d->mSourceCRS, d->mDestCRS, d->mSourceDatumTransform, d->mDestinationDatumTransform ) )
105 d =
new QgsCoordinateTransformPrivate( source, destination, sourceDatumTransform, destinationDatumTransform );
110 if ( !d->checkValidity() )
113 if ( !setFromCache( d->mSourceCRS, d->mDestCRS, d->mSourceDatumTransform, d->mDestinationDatumTransform ) )
121 : mContext( o.mContext )
123 , mHasContext( o.mHasContext )
133 mHasContext = o.mHasContext;
135 mContext = o.mContext;
145 if ( !d->checkValidity() )
148 d->calculateTransforms( mContext );
149 if ( !setFromCache( d->mSourceCRS, d->mDestCRS, d->mSourceDatumTransform, d->mDestinationDatumTransform ) )
159 if ( !d->checkValidity() )
162 d->calculateTransforms( mContext );
163 if ( !setFromCache( d->mSourceCRS, d->mDestCRS, d->mSourceDatumTransform, d->mDestinationDatumTransform ) )
177 if ( !d->checkValidity() )
180 d->calculateTransforms( mContext );
181 if ( !setFromCache( d->mSourceCRS, d->mDestCRS, d->mSourceDatumTransform, d->mDestinationDatumTransform ) )
190 return d->mSourceCRS;
200 if ( !d->mIsValid || d->mShortCircuit )
204 double x = point.
x();
205 double y = point.
y();
238 if ( !d->mIsValid || d->mShortCircuit )
262 #ifdef COORDINATE_TRANSFORM_VERBOSE 275 if ( !d->mIsValid || d->mShortCircuit )
296 double xd =
static_cast< double >( x ), yd = static_cast< double >( y );
305 if ( !d->mIsValid || d->mShortCircuit )
331 if ( !d->mIsValid || d->mShortCircuit )
337 int nVertices = poly.size();
339 QVector<double> x( nVertices );
340 QVector<double> y( nVertices );
341 QVector<double> z( nVertices );
343 for (
int i = 0; i < nVertices; ++i )
345 const QPointF &pt = poly.at( i );
362 for (
int i = 0; i < nVertices; ++i )
364 QPointF &pt = poly[i];
371 QVector<double> &x, QVector<double> &y, QVector<double> &z,
375 if ( !d->mIsValid || d->mShortCircuit )
378 Q_ASSERT( x.size() == y.size() );
399 QVector<float> &x, QVector<float> &y, QVector<float> &z,
402 if ( !d->mIsValid || d->mShortCircuit )
405 Q_ASSERT( x.size() == y.size() );
415 int vectorSize = x.size();
416 QVector<double> xd( x.size() );
417 QVector<double> yd( y.size() );
418 QVector<double> zd( z.size() );
419 for (
int i = 0; i < vectorSize; ++i )
428 for (
int i = 0; i < vectorSize; ++i )
450 if ( !d->mIsValid || d->mShortCircuit )
463 const int nPoints = 1000;
464 double d = std::sqrt( ( rect.
width() * rect.
height() ) / std::pow( std::sqrt( static_cast< double >( nPoints ) ) - 1, 2.0 ) );
465 int nXPoints =
static_cast< int >( std::ceil( rect.
width() / d ) ) + 1;
466 int nYPoints =
static_cast< int >( std::ceil( rect.
height() / d ) ) + 1;
474 QVector<double> x( nXPoints * nYPoints );
475 QVector<double> y( nXPoints * nYPoints );
476 QVector<double> z( nXPoints * nYPoints );
482 double dx = rect.
width() /
static_cast< double >( nXPoints - 1 );
483 double dy = rect.
height() /
static_cast< double >( nYPoints - 1 );
487 for (
int i = 0; i < nYPoints ; i++ )
493 for (
int j = 0; j < nXPoints; j++ )
495 x[( i * nXPoints ) + j] = pointX;
496 y[( i * nXPoints ) + j] = pointY;
498 z[( i * nXPoints ) + j] = 0.0;
509 transformCoords( nXPoints * nYPoints, x.data(), y.data(), z.data(), direction );
520 for (
int i = 0; i < nXPoints * nYPoints; i++ )
522 if ( !std::isfinite( x[i] ) || !std::isfinite( y[i] ) )
527 if ( handle180Crossover )
541 throw QgsCsException( QObject::tr(
"Could not transform bounding box to target CRS" ) );
544 if ( handle180Crossover )
565 if ( !d->mIsValid || d->mShortCircuit )
568 if ( !d->mSourceCRS.isValid() )
571 "The coordinates can not be reprojected. The CRS is: %1" )
572 .arg( d->mSourceCRS.toProj4() ), QObject::tr(
"CRS" ) );
575 if ( !d->mDestCRS.isValid() )
578 "The coordinates can not be reprojected. The CRS is: %1" ).arg( d->mDestCRS.toProj4() ), QObject::tr(
"CRS" ) );
582 #ifdef COORDINATE_TRANSFORM_VERBOSE 585 QgsDebugMsg( QString(
"[[[[[[ Number of points to transform: %1 ]]]]]]" ).arg( numPoints ) );
590 qWarning(
"No QgsCoordinateTransformContext context set for transform" );
597 QPair<projPJ, projPJ> projData = d->threadLocalProjData();
598 projPJ sourceProj = projData.first;
599 projPJ destProj = projData.second;
604 for (
int i = 0; i < numPoints; ++i )
614 projResult = pj_transform( destProj, sourceProj, numPoints, 0, x, y, z );
618 Q_ASSERT( sourceProj );
619 Q_ASSERT( destProj );
620 projResult = pj_transform( sourceProj, destProj, numPoints, 0, x, y, z );
623 if ( projResult != 0 )
628 for (
int i = 0; i < numPoints; ++i )
632 points += QStringLiteral(
"(%1, %2)\n" ).arg( x[i], 0,
'f' ).arg( y[i], 0,
'f' );
636 points += QStringLiteral(
"(%1, %2)\n" ).arg( x[i] * RAD_TO_DEG, 0,
'f' ).arg( y[i] * RAD_TO_DEG, 0,
'f' );
640 QString dir = ( direction ==
ForwardTransform ) ? QObject::tr(
"forward transform" ) : QObject::tr(
"inverse transform" );
642 char *srcdef = pj_get_def( sourceProj, 0 );
643 char *dstdef = pj_get_def( destProj, 0 );
645 QString msg = QObject::tr(
"%1 of\n" 652 QString::fromUtf8( pj_strerrno( projResult ) ) );
657 QgsDebugMsg(
"Projection failed emitting invalid transform signal: " + msg );
668 for (
int i = 0; i < numPoints; ++i )
674 #ifdef COORDINATE_TRANSFORM_VERBOSE 675 QgsDebugMsg( QString(
"[[[[[[ Projected %1, %2 to %3, %4 ]]]]]]" )
676 .arg( xorg, 0,
'g', 15 ).arg( yorg, 0,
'g', 15 )
677 .arg( *x, 0,
'g', 15 ).arg( *y, 0,
'g', 15 ) );
688 return !d->mIsValid || d->mShortCircuit;
695 proj = QApplication::applicationDirPath()
696 +
"/share/proj/" + QString( name );
700 return proj.toUtf8();
708 sCacheLock.lockForRead();
709 const QList< QgsCoordinateTransform > values = sTransforms.values( qMakePair( src.
authid(), dest.
authid() ) );
710 for (
auto valIt = values.constBegin(); valIt != values.constEnd(); ++valIt )
712 if ( ( *valIt ).sourceDatumTransformId() == srcDatumTransform &&
713 ( *valIt ).destinationDatumTransformId() == destDatumTransform )
718 bool hasContext = mHasContext;
725 mHasContext = hasContext;
735 void QgsCoordinateTransform::addToCache()
737 if ( !d->mSourceCRS.isValid() || !d->mDestCRS.isValid() )
740 sCacheLock.lockForWrite();
741 sTransforms.insertMulti( qMakePair( d->mSourceCRS.authid(), d->mDestCRS.authid() ), *
this );
747 return d->mSourceDatumTransform;
753 d->mSourceDatumTransform = dt;
758 return d->mDestinationDatumTransform;
764 d->mDestinationDatumTransform = dt;
769 sCacheLock.lockForWrite();
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.
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::Warning)
add a message to the instance (and create it if necessary)
QgsCoordinateTransformContext transformContext() const
Returns a copy of the project's coordinate transform context, which stores various information regard...
#define QgsDebugMsgLevel(str, level)
bool isEmpty() const
Returns true if the rectangle is empty.
double width() const
Returns the width of the rectangle.
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).
void combineExtentWith(const QgsRectangle &rect)
Expand the rectangle so that covers both the original rectangle and the given rectangle.
This class represents a coordinate reference system (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).
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.