38 projector->mSrcCRS = mSrcCRS;
39 projector->mDestCRS = mDestCRS;
40 projector->mTransformContext = mTransformContext;
43 projector->mSrcDatumTransform = mSrcDatumTransform;
44 projector->mDestDatumTransform = mDestDatumTransform;
47 projector->mPrecision = mPrecision;
70 int srcDatumTransform,
71 int destDatumTransform )
76 mSrcDatumTransform = srcDatumTransform;
77 mDestDatumTransform = destDatumTransform;
85 mTransformContext = transformContext;
87 mSrcDatumTransform = -1;
88 mDestDatumTransform = -1;
94 : mApproximate(
false )
95 , mInverseCt( inverseCt )
96 , mDestExtent( extent )
105 , mDestRowsPerMatrixRow( 0.0 )
106 , mDestColsPerMatrixCol( 0.0 )
110 , mSqrTolerance( 0.0 )
128 if ( mExtent.isEmpty() )
130 mExtent = provider->
extent();
135 mDestXRes = mDestExtent.
width() / ( mDestCols );
136 mDestYRes = mDestExtent.height() / ( mDestRows );
142 double myDestRes = mDestXRes < mDestYRes ? mDestXRes : mDestYRes;
143 mSqrTolerance = myDestRes * myDestRes;
151 mApproximate =
false;
156 mCPCols = mCPRows = 3;
157 for (
int i = 0; i < mCPRows; i++ )
159 QList<QgsPointXY> myRow;
163 mCPMatrix.insert( i, myRow );
165 QList<bool> myLegalRow;
166 myLegalRow.append(
bool(
false ) );
167 myLegalRow.append(
bool(
false ) );
168 myLegalRow.append(
bool(
false ) );
169 mCPLegalMatrix.insert( i, myLegalRow );
171 for (
int i = 0; i < mCPRows; i++ )
173 calcRow( i, inverseCt );
178 bool myColsOK = checkCols( inverseCt );
181 insertRows( inverseCt );
183 bool myRowsOK = checkRows( inverseCt );
186 insertCols( inverseCt );
188 if ( myColsOK && myRowsOK )
195 if ( mCPRows * mCPCols > 0.25 * mDestRows * mDestCols )
199 mApproximate =
false;
203 QgsDebugMsgLevel( QStringLiteral(
"CPMatrix size: mCPRows = %1 mCPCols = %2" ).arg( mCPRows ).arg( mCPCols ), 4 );
204 mDestRowsPerMatrixRow =
static_cast< double >( mDestRows ) / ( mCPRows - 1 );
205 mDestColsPerMatrixCol =
static_cast< double >( mDestCols ) / ( mCPCols - 1 );
213 calcHelper( 0, pHelperTop );
214 calcHelper( 1, pHelperBottom );
220 mSrcYRes = mSrcExtent.height() / mSrcRows;
221 mSrcXRes = mSrcExtent.width() / mSrcCols;
224 ProjectorData::~ProjectorData()
227 delete[] pHelperBottom;
231 void ProjectorData::calcSrcExtent()
242 mSrcExtent =
QgsRectangle( myPoint.
x(), myPoint.
y(), myPoint.
x(), myPoint.
y() );
243 for (
int i = 0; i < mCPRows; i++ )
245 for (
int j = 0; j < mCPCols ; j++ )
247 myPoint = mCPMatrix[i][j];
248 if ( mCPLegalMatrix[i][j] )
250 mSrcExtent.combineExtentWith( myPoint.
x(), myPoint.
y() );
257 mSrcExtent = mSrcExtent.intersect( mExtent );
268 if ( !mExtent.isEmpty() )
270 if ( mMaxSrcXRes > 0 )
273 double col = std::floor( ( mSrcExtent.xMinimum() - mExtent.xMinimum() ) / mMaxSrcXRes );
274 double x = mExtent.xMinimum() + col * mMaxSrcXRes;
275 mSrcExtent.setXMinimum( x );
277 col = std::ceil( ( mSrcExtent.xMaximum() - mExtent.xMinimum() ) / mMaxSrcXRes );
278 x = mExtent.xMinimum() + col * mMaxSrcXRes;
279 mSrcExtent.setXMaximum( x );
281 if ( mMaxSrcYRes > 0 )
283 double row = std::floor( ( mExtent.yMaximum() - mSrcExtent.yMaximum() ) / mMaxSrcYRes );
284 double y = mExtent.yMaximum() - row * mMaxSrcYRes;
285 mSrcExtent.setYMaximum( y );
287 row = std::ceil( ( mExtent.yMaximum() - mSrcExtent.yMinimum() ) / mMaxSrcYRes );
288 y = mExtent.yMaximum() - row * mMaxSrcYRes;
289 mSrcExtent.setYMinimum( y );
295 QString ProjectorData::cpToString()
298 for (
int i = 0; i < mCPRows; i++ )
302 for (
int j = 0; j < mCPCols; j++ )
305 myString += QLatin1String(
" " );
307 if ( mCPLegalMatrix[i][j] )
313 myString += QLatin1String(
"(-,-)" );
320 void ProjectorData::calcSrcRowsCols()
328 double myMinSize = std::numeric_limits<double>::max();
333 double myDestColsPerMatrixCell =
static_cast< double >( mDestCols ) / mCPCols;
334 double myDestRowsPerMatrixCell =
static_cast< double >( mDestRows ) / mCPRows;
335 QgsDebugMsgLevel( QStringLiteral(
"myDestColsPerMatrixCell = %1 myDestRowsPerMatrixCell = %2" ).arg( myDestColsPerMatrixCell ).arg( myDestRowsPerMatrixCell ), 4 );
336 for (
int i = 0; i < mCPRows - 1; i++ )
338 for (
int j = 0; j < mCPCols - 1; j++ )
343 if ( mCPLegalMatrix[i][j] && mCPLegalMatrix[i][j + 1] && mCPLegalMatrix[i + 1][j] )
345 double mySize = std::sqrt( myPointA.
sqrDist( myPointB ) ) / myDestColsPerMatrixCell;
346 if ( mySize < myMinSize )
349 mySize = std::sqrt( myPointA.
sqrDist( myPointC ) ) / myDestRowsPerMatrixCell;
350 if ( mySize < myMinSize )
361 int srcXSize, srcYSize;
364 double srcXRes = srcExtent.
width() / srcXSize;
365 double srcYRes = srcExtent.
height() / srcYSize;
366 myMinSize = std::min( srcXRes, srcYRes );
370 QgsDebugMsg( QStringLiteral(
"Cannot get src extent/size" ) );
379 QgsDebugMsgLevel( QStringLiteral(
"mMaxSrcXRes = %1 mMaxSrcYRes = %2" ).arg( mMaxSrcXRes ).arg( mMaxSrcYRes ), 4 );
381 double myMinXSize = mMaxSrcXRes > myMinSize ? mMaxSrcXRes : myMinSize;
382 double myMinYSize = mMaxSrcYRes > myMinSize ? mMaxSrcYRes : myMinSize;
383 QgsDebugMsgLevel( QStringLiteral(
"myMinXSize = %1 myMinYSize = %2" ).arg( myMinXSize ).arg( myMinYSize ), 4 );
384 QgsDebugMsgLevel( QStringLiteral(
"mSrcExtent.width = %1 mSrcExtent.height = %2" ).arg( mSrcExtent.width() ).arg( mSrcExtent.height() ), 4 );
387 mSrcRows =
static_cast< int >( std::round( mSrcExtent.height() / myMinYSize ) );
388 mSrcCols =
static_cast< int >( std::round( mSrcExtent.width() / myMinXSize ) );
390 QgsDebugMsgLevel( QStringLiteral(
"mSrcRows = %1 mSrcCols = %2" ).arg( mSrcRows ).arg( mSrcCols ), 4 );
394 inline void ProjectorData::destPointOnCPMatrix(
int row,
int col,
double *theX,
double *theY )
396 *theX = mDestExtent.xMinimum() + col * mDestExtent.width() / ( mCPCols - 1 );
397 *theY = mDestExtent.yMaximum() - row * mDestExtent.height() / ( mCPRows - 1 );
400 inline int ProjectorData::matrixRow(
int destRow )
402 return static_cast< int >( std::floor( ( destRow + 0.5 ) / mDestRowsPerMatrixRow ) );
404 inline int ProjectorData::matrixCol(
int destCol )
406 return static_cast< int >( std::floor( ( destCol + 0.5 ) / mDestColsPerMatrixCol ) );
409 void ProjectorData::calcHelper(
int matrixRow,
QgsPointXY *points )
412 for (
int myDestCol = 0; myDestCol < mDestCols; myDestCol++ )
414 double myDestX = mDestExtent.xMinimum() + ( myDestCol + 0.5 ) * mDestXRes;
416 int myMatrixCol = matrixCol( myDestCol );
418 double myDestXMin, myDestYMin, myDestXMax, myDestYMax;
420 destPointOnCPMatrix( matrixRow, myMatrixCol, &myDestXMin, &myDestYMin );
421 destPointOnCPMatrix( matrixRow, myMatrixCol + 1, &myDestXMax, &myDestYMax );
423 double xfrac = ( myDestX - myDestXMin ) / ( myDestXMax - myDestXMin );
425 QgsPointXY &mySrcPoint0 = mCPMatrix[matrixRow][myMatrixCol];
426 QgsPointXY &mySrcPoint1 = mCPMatrix[matrixRow][myMatrixCol + 1];
427 double s = mySrcPoint0.
x() + ( mySrcPoint1.
x() - mySrcPoint0.
x() ) * xfrac;
428 double t = mySrcPoint0.
y() + ( mySrcPoint1.
y() - mySrcPoint0.
y() ) * xfrac;
430 points[myDestCol].
setX( s );
431 points[myDestCol].
setY( t );
435 void ProjectorData::nextHelper()
440 pHelperTop = pHelperBottom;
442 calcHelper( mHelperTopRow + 2, pHelperBottom );
446 bool ProjectorData::srcRowCol(
int destRow,
int destCol,
int *srcRow,
int *srcCol )
450 return approximateSrcRowCol( destRow, destCol, srcRow, srcCol );
454 return preciseSrcRowCol( destRow, destCol, srcRow, srcCol );
458 bool ProjectorData::preciseSrcRowCol(
int destRow,
int destCol,
int *srcRow,
int *srcCol )
462 QgsDebugMsgLevel( QStringLiteral(
"theDestRow = %1 mDestExtent.yMaximum() = %2 mDestYRes = %3" ).arg( destRow ).arg( mDestExtent.yMaximum() ).arg( mDestYRes ), 5 );
466 double x = mDestExtent.xMinimum() + ( destCol + 0.5 ) * mDestXRes;
467 double y = mDestExtent.yMaximum() - ( destRow + 0.5 ) * mDestYRes;
474 if ( mInverseCt.isValid() )
476 mInverseCt.transformInPlace( x, y, z );
483 if ( !mExtent.contains(
QgsPointXY( x, y ) ) )
488 *srcRow =
static_cast< int >( std::floor( ( mSrcExtent.yMaximum() - y ) / mSrcYRes ) );
489 *srcCol =
static_cast< int >( std::floor( ( x - mSrcExtent.xMinimum() ) / mSrcXRes ) );
491 QgsDebugMsgLevel( QStringLiteral(
"mSrcExtent.yMinimum() = %1 mSrcExtent.yMaximum() = %2 mSrcYRes = %3" ).arg( mSrcExtent.yMinimum() ).arg( mSrcExtent.yMaximum() ).arg( mSrcYRes ), 5 );
492 QgsDebugMsgLevel( QStringLiteral(
"theSrcRow = %1 srcCol = %2" ).arg( *srcRow ).arg( *srcCol ), 5 );
499 if ( *srcRow >= mSrcRows )
return false;
500 if ( *srcRow < 0 )
return false;
501 if ( *srcCol >= mSrcCols )
return false;
502 if ( *srcCol < 0 )
return false;
507 bool ProjectorData::approximateSrcRowCol(
int destRow,
int destCol,
int *srcRow,
int *srcCol )
509 int myMatrixRow = matrixRow( destRow );
510 int myMatrixCol = matrixCol( destCol );
512 if ( myMatrixRow > mHelperTopRow )
518 double myDestY = mDestExtent.yMaximum() - ( destRow + 0.5 ) * mDestYRes;
522 double myDestXMin, myDestYMin, myDestXMax, myDestYMax;
524 destPointOnCPMatrix( myMatrixRow + 1, myMatrixCol, &myDestXMin, &myDestYMin );
525 destPointOnCPMatrix( myMatrixRow, myMatrixCol + 1, &myDestXMax, &myDestYMax );
527 double yfrac = ( myDestY - myDestYMin ) / ( myDestYMax - myDestYMin );
536 double tx = myTop.
x();
537 double ty = myTop.
y();
538 double bx = myBot.
x();
539 double by = myBot.
y();
540 double mySrcX = bx + ( tx - bx ) * yfrac;
541 double mySrcY = by + ( ty - by ) * yfrac;
543 if ( !mExtent.contains(
QgsPointXY( mySrcX, mySrcY ) ) )
550 *srcRow =
static_cast< int >( std::floor( ( mSrcExtent.yMaximum() - mySrcY ) / mSrcYRes ) );
551 *srcCol =
static_cast< int >( std::floor( ( mySrcX - mSrcExtent.xMinimum() ) / mSrcXRes ) );
556 if ( *srcRow >= mSrcRows )
return false;
557 if ( *srcRow < 0 )
return false;
558 if ( *srcCol >= mSrcCols )
return false;
559 if ( *srcCol < 0 )
return false;
566 for (
int r = 0; r < mCPRows - 1; r++ )
568 QList<QgsPointXY> myRow;
569 QList<bool> myLegalRow;
570 myRow.reserve( mCPCols );
571 myLegalRow.reserve( mCPCols );
572 for (
int c = 0;
c < mCPCols; ++
c )
575 myLegalRow.append(
false );
577 QgsDebugMsgLevel( QStringLiteral(
"insert new row at %1" ).arg( 1 + r * 2 ), 3 );
578 mCPMatrix.insert( 1 + r * 2, myRow );
579 mCPLegalMatrix.insert( 1 + r * 2, myLegalRow );
581 mCPRows += mCPRows - 1;
582 for (
int r = 1; r < mCPRows - 1; r += 2 )
590 for (
int r = 0; r < mCPRows; r++ )
592 for (
int c = 0;
c < mCPCols - 1;
c++ )
595 mCPLegalMatrix[r].insert( 1 +
c * 2,
false );
598 mCPCols += mCPCols - 1;
599 for (
int c = 1;
c < mCPCols - 1;
c += 2 )
608 double myDestX, myDestY;
609 destPointOnCPMatrix( row, col, &myDestX, &myDestY );
615 mCPMatrix[row][col] = ct.
transform( myDestPoint );
616 mCPLegalMatrix[row][col] =
true;
620 mCPLegalMatrix[row][col] =
false;
627 mCPLegalMatrix[row][col] =
false;
634 for (
int i = 0; i < mCPCols; i++ )
636 calcCP( row, i, ct );
645 for (
int i = 0; i < mCPRows; i++ )
647 calcCP( i, col, ct );
660 for (
int c = 0;
c < mCPCols;
c++ )
662 for (
int r = 1; r < mCPRows - 1; r += 2 )
664 double myDestX, myDestY;
665 destPointOnCPMatrix( r,
c, &myDestX, &myDestY );
672 QgsPointXY mySrcApprox( ( mySrcPoint1.
x() + mySrcPoint3.
x() ) / 2, ( mySrcPoint1.
y() + mySrcPoint3.
y() ) / 2 );
673 if ( !mCPLegalMatrix[r - 1][
c] || !mCPLegalMatrix[r][
c] || !mCPLegalMatrix[r + 1][
c] )
681 double mySqrDist = myDestApprox.
sqrDist( myDestPoint );
682 if ( mySqrDist > mSqrTolerance )
705 for (
int r = 0; r < mCPRows; r++ )
707 for (
int c = 1;
c < mCPCols - 1;
c += 2 )
709 double myDestX, myDestY;
710 destPointOnCPMatrix( r,
c, &myDestX, &myDestY );
717 QgsPointXY mySrcApprox( ( mySrcPoint1.
x() + mySrcPoint3.
x() ) / 2, ( mySrcPoint1.
y() + mySrcPoint3.
y() ) / 2 );
718 if ( !mCPLegalMatrix[r][
c - 1] || !mCPLegalMatrix[r][
c] || !mCPLegalMatrix[r][
c + 1] )
726 double mySqrDist = myDestApprox.
sqrDist( myDestPoint );
727 if ( mySqrDist > mSqrTolerance )
751 return tr(
"Approximate" );
753 return tr(
"Exact" );
755 return QStringLiteral(
"Unknown" );
761 QgsDebugMsgLevel( QStringLiteral(
"width = %1 height = %2" ).arg( width ).arg( height ), 4 );
771 if ( ! mSrcCRS.
isValid() || ! mDestCRS.
isValid() || mSrcCRS == mDestCRS )
774 return mInput->
block( bandNo, extent, width, height, feedback );
782 ProjectorData pd( extent, width, height,
mInput, inverseCt, mPrecision );
784 QgsDebugMsgLevel( QStringLiteral(
"srcExtent:\n%1" ).arg( pd.srcExtent().toString() ), 4 );
785 QgsDebugMsgLevel( QStringLiteral(
"srcCols = %1 srcRows = %2" ).arg( pd.srcCols() ).arg( pd.srcRows() ), 4 );
788 if ( pd.srcRows() <= 0 || pd.srcCols() <= 0 )
794 std::unique_ptr< QgsRasterBlock > inputBlock(
mInput->
block( bandNo, pd.srcExtent(), pd.srcCols(), pd.srcRows(), feedback ) );
795 if ( !inputBlock || inputBlock->isEmpty() )
797 QgsDebugMsg( QStringLiteral(
"No raster data!" ) );
803 std::unique_ptr< QgsRasterBlock > outputBlock(
new QgsRasterBlock( inputBlock->dataType(), width, height ) );
804 if ( inputBlock->hasNoDataValue() )
806 outputBlock->setNoDataValue( inputBlock->noDataValue() );
808 if ( !outputBlock->isValid() )
810 QgsDebugMsg( QStringLiteral(
"Cannot create block" ) );
811 return outputBlock.release();
815 outputBlock->setIsNoData();
829 outputBlock->setIsNoData();
832 for (
int i = 0; i < height; ++i )
836 for (
int j = 0; j < width; ++j )
838 bool inside = pd.srcRowCol( i, j, &srcRow, &srcCol );
839 if ( !inside )
continue;
841 qgssize srcIndex =
static_cast< qgssize >( srcRow * pd.srcCols() + srcCol );
844 if ( doNoData && inputBlock->isNoData( srcRow, srcCol ) )
846 outputBlock->setIsNoData( i, j );
851 char *srcBits = inputBlock->bits( srcIndex );
852 char *destBits = outputBlock->bits( destIndex );
863 memcpy( destBits, srcBits, pixelSize );
864 outputBlock->setIsData( i, j );
868 return outputBlock.release();
872 QgsRectangle &destExtent,
int &destXSize,
int &destYSize )
874 if ( srcExtent.
isEmpty() || srcXSize <= 0 || srcYSize <= 0 )
884 return extentSize( ct, srcExtent, srcXSize, srcYSize, destExtent, destXSize, destYSize );
888 const QgsRectangle &srcExtent,
int srcXSize,
int srcYSize,
889 QgsRectangle &destExtent,
int &destXSize,
int &destYSize )
891 if ( srcExtent.
isEmpty() || srcXSize <= 0 || srcYSize <= 0 )
900 double srcXStep = srcExtent.
width() / 3;
901 double srcYStep = srcExtent.
height() / 3;
902 double srcXRes = srcExtent.
width() / srcXSize;
903 double srcYRes = srcExtent.
height() / srcYSize;
904 double destXRes = std::numeric_limits<double>::max();
905 double destYRes = std::numeric_limits<double>::max();
907 for (
int i = 0; i < 3; i++ )
909 double x = srcExtent.
xMinimum() + i * srcXStep;
910 for (
int j = 0; j < 3; j++ )
912 double y = srcExtent.
yMinimum() + j * srcYStep;
913 QgsRectangle srcRectangle( x - srcXRes / 2, y - srcYRes / 2, x + srcXRes / 2, y + srcYRes / 2 );
915 if ( destRectangle.
width() > 0 )
917 destXRes = std::min( destXRes, destRectangle.
width() );
919 if ( destRectangle.
height() > 0 )
921 destYRes = std::min( destYRes, destRectangle.
height() );
925 destXSize = std::max( 1, static_cast< int >( destExtent.
width() / destYRes ) );
926 destYSize = std::max( 1, static_cast< int >( destExtent.
height() / destYRes ) );
virtual int bandCount() const =0
Gets number of bands.
A rectangle specified with double values.
Precision precision() const
Approximate (default), fast but possibly inaccurate.
virtual QgsRectangle extent() const
Gets the extent of the interface.
A class to represent a 2D point.
QgsRasterProjector * clone() const override
Clone itself, create deep copy.
static bool typeIsNumeric(Qgis::DataType type)
Returns true if data type is numeric.
virtual QgsRasterInterface * input() const
Current input.
#define Q_NOWARN_DEPRECATED_PUSH
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.
double sqrDist(double x, double y) const
Returns the squared distance between this point a specified x, y coordinate.
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c
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)
Contains information about the context in which a coordinate transform is executed.
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...
#define Q_NOWARN_DEPRECATED_POP
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
Gets 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
Gets source / raw input, the first in pipe, usually provider.
double height() const
Returns the height of the rectangle.
Q_DECL_DEPRECATED void setCrs(const QgsCoordinateReferenceSystem &srcCRS, const QgsCoordinateReferenceSystem &destCRS, int srcDatumTransform=-1, int destDatumTransform=-1)
Sets the source and destination CRS.
int bandCount() const override
Gets number of bands.
Base class for raster data providers.
bool isValid() const
Returns whether this CRS is correctly initialized and usable.