37 projector->mSrcCRS = mSrcCRS;
38 projector->mDestCRS = mDestCRS;
39 projector->mSrcDatumTransform = mSrcDatumTransform;
40 projector->mDestDatumTransform = mDestDatumTransform;
41 projector->mPrecision = mPrecision;
67 mSrcDatumTransform = srcDatumTransform;
68 mDestDatumTransform = destDatumTransform;
73 : mApproximate(
false )
74 , mInverseCt( inverseCt )
75 , mDestExtent( extent )
84 , mDestRowsPerMatrixRow( 0.0 )
85 , mDestColsPerMatrixCol( 0.0 )
89 , mSqrTolerance( 0.0 )
107 if ( mExtent.isEmpty() )
109 mExtent = provider->
extent();
114 mDestXRes = mDestExtent.
width() / ( mDestCols );
115 mDestYRes = mDestExtent.height() / ( mDestRows );
121 double myDestRes = mDestXRes < mDestYRes ? mDestXRes : mDestYRes;
122 mSqrTolerance = myDestRes * myDestRes;
130 mApproximate =
false;
135 mCPCols = mCPRows = 3;
136 for (
int i = 0; i < mCPRows; i++ )
138 QList<QgsPointXY> myRow;
142 mCPMatrix.insert( i, myRow );
144 QList<bool> myLegalRow;
145 myLegalRow.append(
bool(
false ) );
146 myLegalRow.append(
bool(
false ) );
147 myLegalRow.append(
bool(
false ) );
148 mCPLegalMatrix.insert( i, myLegalRow );
150 for (
int i = 0; i < mCPRows; i++ )
152 calcRow( i, inverseCt );
157 bool myColsOK = checkCols( inverseCt );
160 insertRows( inverseCt );
162 bool myRowsOK = checkRows( inverseCt );
165 insertCols( inverseCt );
167 if ( myColsOK && myRowsOK )
174 if ( mCPRows * mCPCols > 0.25 * mDestRows * mDestCols )
178 mApproximate =
false;
182 QgsDebugMsgLevel( QString(
"CPMatrix size: mCPRows = %1 mCPCols = %2" ).arg( mCPRows ).arg( mCPCols ), 4 );
183 mDestRowsPerMatrixRow =
static_cast< float >( mDestRows ) / ( mCPRows - 1 );
184 mDestColsPerMatrixCol =
static_cast< float >( mDestCols ) / ( mCPCols - 1 );
192 calcHelper( 0, pHelperTop );
193 calcHelper( 1, pHelperBottom );
199 mSrcYRes = mSrcExtent.height() / mSrcRows;
200 mSrcXRes = mSrcExtent.width() / mSrcCols;
203 ProjectorData::~ProjectorData()
206 delete[] pHelperBottom;
210 void ProjectorData::calcSrcExtent()
221 mSrcExtent =
QgsRectangle( myPoint.
x(), myPoint.
y(), myPoint.
x(), myPoint.
y() );
222 for (
int i = 0; i < mCPRows; i++ )
224 for (
int j = 0; j < mCPCols ; j++ )
226 myPoint = mCPMatrix[i][j];
227 if ( mCPLegalMatrix[i][j] )
229 mSrcExtent.combineExtentWith( myPoint.
x(), myPoint.
y() );
236 mSrcExtent = mSrcExtent.intersect( &mExtent );
247 if ( !mExtent.isEmpty() )
249 if ( mMaxSrcXRes > 0 )
252 double col = std::floor( ( mSrcExtent.xMinimum() - mExtent.xMinimum() ) / mMaxSrcXRes );
253 double x = mExtent.xMinimum() + col * mMaxSrcXRes;
254 mSrcExtent.setXMinimum( x );
256 col = std::ceil( ( mSrcExtent.xMaximum() - mExtent.xMinimum() ) / mMaxSrcXRes );
257 x = mExtent.xMinimum() + col * mMaxSrcXRes;
258 mSrcExtent.setXMaximum( x );
260 if ( mMaxSrcYRes > 0 )
262 double row = std::floor( ( mExtent.yMaximum() - mSrcExtent.yMaximum() ) / mMaxSrcYRes );
263 double y = mExtent.yMaximum() - row * mMaxSrcYRes;
264 mSrcExtent.setYMaximum( y );
266 row = std::ceil( ( mExtent.yMaximum() - mSrcExtent.yMinimum() ) / mMaxSrcYRes );
267 y = mExtent.yMaximum() - row * mMaxSrcYRes;
268 mSrcExtent.setYMinimum( y );
274 QString ProjectorData::cpToString()
277 for (
int i = 0; i < mCPRows; i++ )
281 for (
int j = 0; j < mCPCols; j++ )
284 myString += QLatin1String(
" " );
286 if ( mCPLegalMatrix[i][j] )
292 myString += QLatin1String(
"(-,-)" );
299 void ProjectorData::calcSrcRowsCols()
307 double myMinSize = std::numeric_limits<double>::max();
312 double myDestColsPerMatrixCell =
static_cast< double >( mDestCols ) / mCPCols;
313 double myDestRowsPerMatrixCell =
static_cast< double >( mDestRows ) / mCPRows;
314 QgsDebugMsgLevel( QString(
"myDestColsPerMatrixCell = %1 myDestRowsPerMatrixCell = %2" ).arg( myDestColsPerMatrixCell ).arg( myDestRowsPerMatrixCell ), 4 );
315 for (
int i = 0; i < mCPRows - 1; i++ )
317 for (
int j = 0; j < mCPCols - 1; j++ )
322 if ( mCPLegalMatrix[i][j] && mCPLegalMatrix[i][j + 1] && mCPLegalMatrix[i + 1][j] )
324 double mySize = std::sqrt( myPointA.
sqrDist( myPointB ) ) / myDestColsPerMatrixCell;
325 if ( mySize < myMinSize )
328 mySize = std::sqrt( myPointA.
sqrDist( myPointC ) ) / myDestRowsPerMatrixCell;
329 if ( mySize < myMinSize )
340 int srcXSize, srcYSize;
343 double srcXRes = srcExtent.
width() / srcXSize;
344 double srcYRes = srcExtent.
height() / srcYSize;
345 myMinSize = std::min( srcXRes, srcYRes );
358 QgsDebugMsgLevel( QString(
"mMaxSrcXRes = %1 mMaxSrcYRes = %2" ).arg( mMaxSrcXRes ).arg( mMaxSrcYRes ), 4 );
360 double myMinXSize = mMaxSrcXRes > myMinSize ? mMaxSrcXRes : myMinSize;
361 double myMinYSize = mMaxSrcYRes > myMinSize ? mMaxSrcYRes : myMinSize;
362 QgsDebugMsgLevel( QString(
"myMinXSize = %1 myMinYSize = %2" ).arg( myMinXSize ).arg( myMinYSize ), 4 );
363 QgsDebugMsgLevel( QString(
"mSrcExtent.width = %1 mSrcExtent.height = %2" ).arg( mSrcExtent.width() ).arg( mSrcExtent.height() ), 4 );
366 mSrcRows =
static_cast< int >( std::round( mSrcExtent.height() / myMinYSize ) );
367 mSrcCols =
static_cast< int >( std::round( mSrcExtent.width() / myMinXSize ) );
369 QgsDebugMsgLevel( QString(
"mSrcRows = %1 mSrcCols = %2" ).arg( mSrcRows ).arg( mSrcCols ), 4 );
373 inline void ProjectorData::destPointOnCPMatrix(
int row,
int col,
double *theX,
double *theY )
375 *theX = mDestExtent.xMinimum() + col * mDestExtent.width() / ( mCPCols - 1 );
376 *theY = mDestExtent.yMaximum() - row * mDestExtent.height() / ( mCPRows - 1 );
379 inline int ProjectorData::matrixRow(
int destRow )
381 return static_cast< int >( std::floor( ( destRow + 0.5 ) / mDestRowsPerMatrixRow ) );
383 inline int ProjectorData::matrixCol(
int destCol )
385 return static_cast< int >( std::floor( ( destCol + 0.5 ) / mDestColsPerMatrixCol ) );
388 void ProjectorData::calcHelper(
int matrixRow,
QgsPointXY *points )
391 for (
int myDestCol = 0; myDestCol < mDestCols; myDestCol++ )
393 double myDestX = mDestExtent.xMinimum() + ( myDestCol + 0.5 ) * mDestXRes;
395 int myMatrixCol = matrixCol( myDestCol );
397 double myDestXMin, myDestYMin, myDestXMax, myDestYMax;
399 destPointOnCPMatrix( matrixRow, myMatrixCol, &myDestXMin, &myDestYMin );
400 destPointOnCPMatrix( matrixRow, myMatrixCol + 1, &myDestXMax, &myDestYMax );
402 double xfrac = ( myDestX - myDestXMin ) / ( myDestXMax - myDestXMin );
404 QgsPointXY &mySrcPoint0 = mCPMatrix[matrixRow][myMatrixCol];
405 QgsPointXY &mySrcPoint1 = mCPMatrix[matrixRow][myMatrixCol + 1];
406 double s = mySrcPoint0.
x() + ( mySrcPoint1.
x() - mySrcPoint0.
x() ) * xfrac;
407 double t = mySrcPoint0.
y() + ( mySrcPoint1.
y() - mySrcPoint0.
y() ) * xfrac;
409 points[myDestCol].
setX( s );
410 points[myDestCol].
setY( t );
414 void ProjectorData::nextHelper()
419 pHelperTop = pHelperBottom;
421 calcHelper( mHelperTopRow + 2, pHelperBottom );
425 bool ProjectorData::srcRowCol(
int destRow,
int destCol,
int *srcRow,
int *srcCol )
429 return approximateSrcRowCol( destRow, destCol, srcRow, srcCol );
433 return preciseSrcRowCol( destRow, destCol, srcRow, srcCol );
437 bool ProjectorData::preciseSrcRowCol(
int destRow,
int destCol,
int *srcRow,
int *srcCol )
441 QgsDebugMsgLevel( QString(
"theDestRow = %1 mDestExtent.yMaximum() = %2 mDestYRes = %3" ).arg( destRow ).arg( mDestExtent.yMaximum() ).arg( mDestYRes ), 5 );
445 double x = mDestExtent.xMinimum() + ( destCol + 0.5 ) * mDestXRes;
446 double y = mDestExtent.yMaximum() - ( destRow + 0.5 ) * mDestYRes;
453 if ( mInverseCt.isValid() )
455 mInverseCt.transformInPlace( x, y, z );
462 if ( !mExtent.contains(
QgsPointXY( x, y ) ) )
467 *srcRow =
static_cast< int >( std::floor( ( mSrcExtent.yMaximum() - y ) / mSrcYRes ) );
468 *srcCol =
static_cast< int >( std::floor( ( x - mSrcExtent.xMinimum() ) / mSrcXRes ) );
470 QgsDebugMsgLevel( QString(
"mSrcExtent.yMinimum() = %1 mSrcExtent.yMaximum() = %2 mSrcYRes = %3" ).arg( mSrcExtent.yMinimum() ).arg( mSrcExtent.yMaximum() ).arg( mSrcYRes ), 5 );
471 QgsDebugMsgLevel( QString(
"theSrcRow = %1 srcCol = %2" ).arg( *srcRow ).arg( *srcCol ), 5 );
478 if ( *srcRow >= mSrcRows )
return false;
479 if ( *srcRow < 0 )
return false;
480 if ( *srcCol >= mSrcCols )
return false;
481 if ( *srcCol < 0 )
return false;
486 bool ProjectorData::approximateSrcRowCol(
int destRow,
int destCol,
int *srcRow,
int *srcCol )
488 int myMatrixRow = matrixRow( destRow );
489 int myMatrixCol = matrixCol( destCol );
491 if ( myMatrixRow > mHelperTopRow )
497 double myDestY = mDestExtent.yMaximum() - ( destRow + 0.5 ) * mDestYRes;
501 double myDestXMin, myDestYMin, myDestXMax, myDestYMax;
503 destPointOnCPMatrix( myMatrixRow + 1, myMatrixCol, &myDestXMin, &myDestYMin );
504 destPointOnCPMatrix( myMatrixRow, myMatrixCol + 1, &myDestXMax, &myDestYMax );
506 double yfrac = ( myDestY - myDestYMin ) / ( myDestYMax - myDestYMin );
515 double tx = myTop.
x();
516 double ty = myTop.
y();
517 double bx = myBot.
x();
518 double by = myBot.
y();
519 double mySrcX = bx + ( tx - bx ) * yfrac;
520 double mySrcY = by + ( ty - by ) * yfrac;
522 if ( !mExtent.contains(
QgsPointXY( mySrcX, mySrcY ) ) )
529 *srcRow =
static_cast< int >( std::floor( ( mSrcExtent.yMaximum() - mySrcY ) / mSrcYRes ) );
530 *srcCol =
static_cast< int >( std::floor( ( mySrcX - mSrcExtent.xMinimum() ) / mSrcXRes ) );
535 if ( *srcRow >= mSrcRows )
return false;
536 if ( *srcRow < 0 )
return false;
537 if ( *srcCol >= mSrcCols )
return false;
538 if ( *srcCol < 0 )
return false;
545 for (
int r = 0; r < mCPRows - 1; r++ )
547 QList<QgsPointXY> myRow;
548 QList<bool> myLegalRow;
549 myRow.reserve( mCPCols );
550 myLegalRow.reserve( mCPCols );
551 for (
int c = 0; c < mCPCols; ++c )
554 myLegalRow.append(
false );
557 mCPMatrix.insert( 1 + r * 2, myRow );
558 mCPLegalMatrix.insert( 1 + r * 2, myLegalRow );
560 mCPRows += mCPRows - 1;
561 for (
int r = 1; r < mCPRows - 1; r += 2 )
569 for (
int r = 0; r < mCPRows; r++ )
571 for (
int c = 0; c < mCPCols - 1; c++ )
573 mCPMatrix[r].insert( 1 + c * 2,
QgsPointXY() );
574 mCPLegalMatrix[r].insert( 1 + c * 2,
false );
577 mCPCols += mCPCols - 1;
578 for (
int c = 1; c < mCPCols - 1; c += 2 )
587 double myDestX, myDestY;
588 destPointOnCPMatrix( row, col, &myDestX, &myDestY );
594 mCPMatrix[row][col] = ct.
transform( myDestPoint );
595 mCPLegalMatrix[row][col] =
true;
599 mCPLegalMatrix[row][col] =
false;
606 mCPLegalMatrix[row][col] =
false;
613 for (
int i = 0; i < mCPCols; i++ )
615 calcCP( row, i, ct );
624 for (
int i = 0; i < mCPRows; i++ )
626 calcCP( i, col, ct );
639 for (
int c = 0; c < mCPCols; c++ )
641 for (
int r = 1; r < mCPRows - 1; r += 2 )
643 double myDestX, myDestY;
644 destPointOnCPMatrix( r, c, &myDestX, &myDestY );
651 QgsPointXY mySrcApprox( ( mySrcPoint1.
x() + mySrcPoint3.
x() ) / 2, ( mySrcPoint1.
y() + mySrcPoint3.
y() ) / 2 );
652 if ( !mCPLegalMatrix[r - 1][c] || !mCPLegalMatrix[r][c] || !mCPLegalMatrix[r + 1][c] )
660 double mySqrDist = myDestApprox.
sqrDist( myDestPoint );
661 if ( mySqrDist > mSqrTolerance )
684 for (
int r = 0; r < mCPRows; r++ )
686 for (
int c = 1; c < mCPCols - 1; c += 2 )
688 double myDestX, myDestY;
689 destPointOnCPMatrix( r, c, &myDestX, &myDestY );
696 QgsPointXY mySrcApprox( ( mySrcPoint1.
x() + mySrcPoint3.
x() ) / 2, ( mySrcPoint1.
y() + mySrcPoint3.
y() ) / 2 );
697 if ( !mCPLegalMatrix[r][c - 1] || !mCPLegalMatrix[r][c] || !mCPLegalMatrix[r][c + 1] )
705 double mySqrDist = myDestApprox.
sqrDist( myDestPoint );
706 if ( mySqrDist > mSqrTolerance )
730 return tr(
"Approximate" );
732 return tr(
"Exact" );
734 return QStringLiteral(
"Unknown" );
740 QgsDebugMsgLevel( QString(
"width = %1 height = %2" ).arg( width ).arg( height ), 4 );
750 if ( ! mSrcCRS.
isValid() || ! mDestCRS.
isValid() || mSrcCRS == mDestCRS )
753 return mInput->
block( bandNo, extent, width, height, feedback );
758 ProjectorData pd( extent, width, height,
mInput, inverseCt, mPrecision );
760 QgsDebugMsgLevel( QString(
"srcExtent:\n%1" ).arg( pd.srcExtent().toString() ), 4 );
761 QgsDebugMsgLevel( QString(
"srcCols = %1 srcRows = %2" ).arg( pd.srcCols() ).arg( pd.srcRows() ), 4 );
764 if ( pd.srcRows() <= 0 || pd.srcCols() <= 0 )
770 std::unique_ptr< QgsRasterBlock > inputBlock(
mInput->
block( bandNo, pd.srcExtent(), pd.srcCols(), pd.srcRows(), feedback ) );
771 if ( !inputBlock || inputBlock->isEmpty() )
779 std::unique_ptr< QgsRasterBlock > outputBlock(
new QgsRasterBlock( inputBlock->dataType(), width, height ) );
780 if ( inputBlock->hasNoDataValue() )
782 outputBlock->setNoDataValue( inputBlock->noDataValue() );
784 if ( !outputBlock->isValid() )
787 return outputBlock.release();
791 outputBlock->setIsNoData();
805 outputBlock->setIsNoData();
808 for (
int i = 0; i < height; ++i )
812 for (
int j = 0; j < width; ++j )
814 bool inside = pd.srcRowCol( i, j, &srcRow, &srcCol );
815 if ( !inside )
continue;
817 qgssize srcIndex =
static_cast< qgssize >( srcRow ) * pd.srcCols() + srcCol;
820 if ( doNoData && inputBlock->isNoData( srcRow, srcCol ) )
822 outputBlock->setIsNoData( i, j );
827 char *srcBits = inputBlock->bits( srcIndex );
828 char *destBits = outputBlock->bits( destIndex );
839 memcpy( destBits, srcBits, pixelSize );
840 outputBlock->setIsData( i, j );
844 return outputBlock.release();
848 QgsRectangle &destExtent,
int &destXSize,
int &destYSize )
850 if ( srcExtent.
isEmpty() || srcXSize <= 0 || srcYSize <= 0 )
856 return extentSize( ct, srcExtent, srcXSize, srcYSize, destExtent, destXSize, destYSize );
860 const QgsRectangle &srcExtent,
int srcXSize,
int srcYSize,
861 QgsRectangle &destExtent,
int &destXSize,
int &destYSize )
863 if ( srcExtent.
isEmpty() || srcXSize <= 0 || srcYSize <= 0 )
872 double srcXStep = srcExtent.
width() / 3;
873 double srcYStep = srcExtent.
height() / 3;
874 double srcXRes = srcExtent.
width() / srcXSize;
875 double srcYRes = srcExtent.
height() / srcYSize;
876 double destXRes = std::numeric_limits<double>::max();
877 double destYRes = std::numeric_limits<double>::max();
879 for (
int i = 0; i < 3; i++ )
881 double x = srcExtent.
xMinimum() + i * srcXStep;
882 for (
int j = 0; j < 3; j++ )
884 double y = srcExtent.
yMinimum() + j * srcYStep;
885 QgsRectangle srcRectangle( x - srcXRes / 2, y - srcYRes / 2, x + srcXRes / 2, y + srcYRes / 2 );
887 if ( destRectangle.
width() > 0 )
889 destXRes = std::min( destXRes, destRectangle.
width() );
891 if ( destRectangle.
height() > 0 )
893 destYRes = std::min( destYRes, destRectangle.
height() );
897 destXSize = std::max( 1, static_cast< int >( destExtent.
width() / destYRes ) );
898 destYSize = std::max( 1, static_cast< int >( destExtent.
height() / destYRes ) );
virtual int bandCount() const =0
Get number of bands.
A rectangle specified with double values.
Precision precision() const
Approximate (default), fast but possibly inaccurate.
virtual QgsRectangle extent() const
Get the extent of the interface.
A class to represent a 2D point.
static bool typeIsNumeric(Qgis::DataType type)
Returns true if data type is numeric.
virtual QgsRasterInterface * input() const
Current input.
DataType
Raster data types.
virtual int ySize() const
QString toString(int precision=-1) const
Returns a string representation of the point (x, y) with a preset precision.
virtual Qgis::DataType dataType(int bandNo) const =0
Returns data type for the band specified by number.
void setCrs(const QgsCoordinateReferenceSystem &srcCRS, const QgsCoordinateReferenceSystem &destCRS, int srcDatumTransform=-1, int destDatumTransform=-1)
set source and destination CRS
double sqrDist(double x, double y) const
Returns the squared distance between this point a specified x, y coordinate.
Qgis::DataType dataType(int bandNo) const override
Returns data type for the band specified by number.
#define QgsDebugMsgLevel(str, level)
bool isEmpty() const
Returns true if the rectangle is empty.
virtual QgsRasterBlock * block(int bandNo, const QgsRectangle &extent, int width, int height, QgsRasterBlockFeedback *feedback=nullptr)=0
Read block of data using given extent and size.
virtual int capabilities() const
Returns a bitmask containing the supported capabilities.
QgsRectangle extent() const override=0
Returns the extent of the layer.
double width() const
Returns the width of the rectangle.
void setY(double y)
Sets the y value of the point.
QString toString(int precision=16) const
Returns a string representation of form xmin,ymin : xmax,ymax Coordinates will be truncated to the sp...
Unknown or unspecified type.
static int typeSize(int dataType)
Base class for processing filters like renderers, reprojector, resampler etc.
QgsRasterBlock * block(int bandNo, const QgsRectangle &extent, int width, int height, QgsRasterBlockFeedback *feedback=nullptr) override
Read block of data using given extent and size.
void setX(double x)
Sets the x value of the point.
unsigned long long qgssize
Qgssize is used instead of size_t, because size_t is stdlib type, unknown by SIP, and it would be har...
double yMinimum() const
Returns the y minimum value (bottom side of rectangle).
static bool extentSize(const QgsCoordinateTransform &ct, const QgsRectangle &srcExtent, int srcXSize, int srcYSize, QgsRectangle &destExtent, int &destXSize, int &destYSize)
Calculate destination extent and size from source extent and size.
QgsRasterProjector implements approximate projection support for it calculates grid of points in sour...
QgsRasterProjector * clone() const override
Clone itself, create deep copy.
Precision
Precision defines if each pixel is reprojected or approximate reprojection based on an approximation ...
bool isCanceled() const
Tells whether the operation has been canceled already.
This class represents a coordinate reference system (CRS).
double xMinimum() const
Returns the x minimum value (left side of rectangle).
Custom exception class for Coordinate Reference System related exceptions.
QgsRasterInterface * mInput
Feedback object tailored for raster block reading.
virtual int xSize() const
Get raster size.
bool destExtentSize(const QgsRectangle &srcExtent, int srcXSize, int srcYSize, QgsRectangle &destExtent, int &destXSize, int &destYSize)
Calculate destination extent and size from source extent and size.
static QString precisionLabel(Precision precision)
virtual const QgsRasterInterface * sourceInput() const
Get source / raw input, the first in pipe, usually provider.
double height() const
Returns the height of the rectangle.
int bandCount() const override
Get number of bands.
Base class for raster data providers.
bool isValid() const
Returns whether this CRS is correctly initialized and usable.