QGIS API Documentation  3.26.3-Buenos Aires (65e4edfdad)
qgsrasterprojector.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsrasterprojector.cpp - Raster projector
3  --------------------------------------
4  Date : Jan 16, 2011
5  Copyright : (C) 2005 by Radim Blazek
6  email : radim dot blazek at gmail dot com
7  ***************************************************************************/
8 
9 /***************************************************************************
10  * *
11  * This program is free software; you can redistribute it and/or modify *
12  * it under the terms of the GNU General Public License as published by *
13  * the Free Software Foundation; either version 2 of the License, or *
14  * (at your option) any later version. *
15  * *
16  ***************************************************************************/
17 #include <algorithm>
18 
19 #include "qgsrasterdataprovider.h"
20 #include "qgslogger.h"
21 #include "qgsrasterprojector.h"
22 #include "qgscoordinatetransform.h"
23 #include "qgsexception.h"
24 
25 Q_NOWARN_DEPRECATED_PUSH // because of deprecated members
27  : QgsRasterInterface( nullptr )
28 {
29  QgsDebugMsgLevel( QStringLiteral( "Entered" ), 4 );
30 }
32 
33 
35 {
36  QgsDebugMsgLevel( QStringLiteral( "Entered" ), 4 );
37  QgsRasterProjector *projector = new QgsRasterProjector;
38  projector->mSrcCRS = mSrcCRS;
39  projector->mDestCRS = mDestCRS;
40  projector->mTransformContext = mTransformContext;
41 
43  projector->mSrcDatumTransform = mSrcDatumTransform;
44  projector->mDestDatumTransform = mDestDatumTransform;
46 
47  projector->mPrecision = mPrecision;
48  return projector;
49 }
50 
52 {
53  if ( mInput ) return mInput->bandCount();
54 
55  return 0;
56 }
57 
59 {
60  if ( mInput ) return mInput->dataType( bandNo );
61 
63 }
64 
65 
67 
69  const QgsCoordinateReferenceSystem &destCRS,
70  int srcDatumTransform,
71  int destDatumTransform )
72 {
73  mSrcCRS = srcCRS;
74  mDestCRS = destCRS;
76  mSrcDatumTransform = srcDatumTransform;
77  mDestDatumTransform = destDatumTransform;
79 }
80 
82 {
83  mSrcCRS = srcCRS;
84  mDestCRS = destCRS;
85  mTransformContext = transformContext;
87  mSrcDatumTransform = -1;
88  mDestDatumTransform = -1;
90 }
91 
92 
93 ProjectorData::ProjectorData( const QgsRectangle &extent, int width, int height, QgsRasterInterface *input, const QgsCoordinateTransform &inverseCt, QgsRasterProjector::Precision precision, QgsRasterBlockFeedback *feedback )
94  : mApproximate( false )
95  , mInverseCt( inverseCt )
96  , mDestExtent( extent )
97  , mDestRows( height )
98  , mDestCols( width )
99  , mDestXRes( 0.0 )
100  , mDestYRes( 0.0 )
101  , mSrcRows( 0 )
102  , mSrcCols( 0 )
103  , mSrcXRes( 0.0 )
104  , mSrcYRes( 0.0 )
105  , mDestRowsPerMatrixRow( 0.0 )
106  , mDestColsPerMatrixCol( 0.0 )
107  , mHelperTopRow( 0 )
108  , mCPCols( 0 )
109  , mCPRows( 0 )
110  , mSqrTolerance( 0.0 )
111  , mMaxSrcXRes( 0 )
112  , mMaxSrcYRes( 0 )
113 {
114  QgsDebugMsgLevel( QStringLiteral( "Entered" ), 4 );
115 
116  // Get max source resolution and extent if possible
117  if ( input )
118  {
119  QgsRasterDataProvider *provider = dynamic_cast<QgsRasterDataProvider *>( input->sourceInput() );
120  if ( provider )
121  {
122  // If provider-side resampling is possible, we will get a much better looking
123  // result by not requesting at the maximum resolution and then doing nearest
124  // resampling here. A real fix would be to do resampling during reprojection
125  // however.
127  ( provider->capabilities() & QgsRasterDataProvider::Size ) )
128  {
129  mMaxSrcXRes = provider->extent().width() / provider->xSize();
130  mMaxSrcYRes = provider->extent().height() / provider->ySize();
131  }
132  // Get source extent
133  if ( mExtent.isEmpty() )
134  {
135  mExtent = provider->extent();
136  }
137  }
138  }
139 
140  mDestXRes = mDestExtent.width() / ( mDestCols );
141  mDestYRes = mDestExtent.height() / ( mDestRows );
142 
143  // Calculate tolerance
144  // TODO: Think it over better
145  // Note: we are checking on matrix each even point, that means that the real error
146  // in that moment is approximately half size
147  const double myDestRes = mDestXRes < mDestYRes ? mDestXRes : mDestYRes;
148  mSqrTolerance = myDestRes * myDestRes;
149 
151  {
152  mApproximate = true;
153  }
154  else
155  {
156  mApproximate = false;
157  }
158 
159  // Always try to calculate mCPMatrix, it is used in calcSrcExtent() for both Approximate and Exact
160  // Initialize the matrix by corners and middle points
161  mCPCols = mCPRows = 3;
162 
163  // For WebMercator to geographic, if the bounding box is symmetric in Y,
164  // and we only use 3 sample points, we would believe that there is perfect
165  // linear approximation, resulting in wrong reprojection
166  // (see https://github.com/qgis/QGIS/issues/34518).
167  // But if we use 5 sample points, we will detect the non-linearity and will
168  // refine the CPMatrix appropriately.
169  if ( std::fabs( -mDestExtent.yMinimum() - mDestExtent.yMaximum() ) / height < 0.5 * mDestYRes )
170  mCPRows = 5;
171 
172  for ( int i = 0; i < mCPRows; i++ )
173  {
174  QList<QgsPointXY> myRow;
175  myRow.append( QgsPointXY() );
176  myRow.append( QgsPointXY() );
177  myRow.append( QgsPointXY() );
178  mCPMatrix.insert( i, myRow );
179  // And the legal points
180  QList<bool> myLegalRow;
181  myLegalRow.append( bool( false ) );
182  myLegalRow.append( bool( false ) );
183  myLegalRow.append( bool( false ) );
184  mCPLegalMatrix.insert( i, myLegalRow );
185  }
186  for ( int i = 0; i < mCPRows; i++ )
187  {
188  calcRow( i, inverseCt );
189  }
190 
191  while ( true )
192  {
193  const bool myColsOK = checkCols( inverseCt );
194  if ( !myColsOK )
195  {
196  insertRows( inverseCt );
197  }
198  const bool myRowsOK = checkRows( inverseCt );
199  if ( !myRowsOK )
200  {
201  insertCols( inverseCt );
202  }
203  if ( myColsOK && myRowsOK )
204  {
205  QgsDebugMsgLevel( QStringLiteral( "CP matrix within tolerance" ), 4 );
206  break;
207  }
208  // What is the maximum reasonable size of transformatio matrix?
209  // TODO: consider better when to break - ratio
210  if ( mCPRows * mCPCols > 0.25 * mDestRows * mDestCols )
211  //if ( mCPRows * mCPCols > mDestRows * mDestCols )
212  {
213  QgsDebugMsgLevel( QStringLiteral( "Too large CP matrix" ), 4 );
214  mApproximate = false;
215  break;
216  }
217  if ( feedback && feedback->isCanceled() )
218  {
219  return;
220  }
221  }
222  QgsDebugMsgLevel( QStringLiteral( "CPMatrix size: mCPRows = %1 mCPCols = %2" ).arg( mCPRows ).arg( mCPCols ), 4 );
223  mDestRowsPerMatrixRow = static_cast< double >( mDestRows ) / ( mCPRows - 1 );
224  mDestColsPerMatrixCol = static_cast< double >( mDestCols ) / ( mCPCols - 1 );
225 
226 #if 0
227  QgsDebugMsgLevel( QStringLiteral( "CPMatrix:" ), 5 );
228  QgsDebugMsgLevel( cpToString(), 5 );
229 #endif
230 
231  // init helper points
232  pHelperTop = new QgsPointXY[mDestCols];
233  pHelperBottom = new QgsPointXY[mDestCols];
234  calcHelper( 0, pHelperTop );
235  calcHelper( 1, pHelperBottom );
236  mHelperTopRow = 0;
237 
238  // Calculate source dimensions
239  calcSrcExtent();
240  calcSrcRowsCols();
241  mSrcYRes = mSrcExtent.height() / mSrcRows;
242  mSrcXRes = mSrcExtent.width() / mSrcCols;
243 }
244 
245 ProjectorData::~ProjectorData()
246 {
247  delete[] pHelperTop;
248  delete[] pHelperBottom;
249 }
250 
251 
252 void ProjectorData::calcSrcExtent()
253 {
254  /* Run around the mCPMatrix and find source extent */
255  // Attention, source limits are not necessarily on destination edges, e.g.
256  // for destination EPSG:32661 Polar Stereographic and source EPSG:4326,
257  // the maximum y may be in the middle of destination extent
258  // TODO: How to find extent exactly and quickly?
259  // For now, we run through all matrix
260  // mCPMatrix is used for both Approximate and Exact because QgsCoordinateTransform::transformBoundingBox()
261  // is not precise enough, see #13665
262  QgsPointXY myPoint = mCPMatrix[0][0];
263  mSrcExtent = QgsRectangle( myPoint.x(), myPoint.y(), myPoint.x(), myPoint.y() );
264  for ( int i = 0; i < mCPRows; i++ )
265  {
266  for ( int j = 0; j < mCPCols ; j++ )
267  {
268  myPoint = mCPMatrix[i][j];
269  if ( mCPLegalMatrix[i][j] )
270  {
271  mSrcExtent.combineExtentWith( myPoint.x(), myPoint.y() );
272  }
273  }
274  }
275  // Expand a bit to avoid possible approx coords falling out because of representation error?
276 
277  // Combine with maximum source extent
278  mSrcExtent = mSrcExtent.intersect( mExtent );
279 
280  // If mMaxSrcXRes, mMaxSrcYRes are defined (fixed src resolution)
281  // align extent to src resolution to avoid jumping of reprojected pixels
282  // when shifting resampled grid.
283  // Important especially if we are over mMaxSrcXRes, mMaxSrcYRes limits
284  // Note however, that preceding filters (like resampler) may read data
285  // on different resolution.
286 
287  QgsDebugMsgLevel( "mSrcExtent = " + mSrcExtent.toString(), 4 );
288  QgsDebugMsgLevel( "mExtent = " + mExtent.toString(), 4 );
289  if ( !mExtent.isEmpty() )
290  {
291  if ( mMaxSrcXRes > 0 )
292  {
293  // with floor/ceil it should work correctly also for mSrcExtent.xMinimum() < mExtent.xMinimum()
294  double col = std::floor( ( mSrcExtent.xMinimum() - mExtent.xMinimum() ) / mMaxSrcXRes );
295  double x = mExtent.xMinimum() + col * mMaxSrcXRes;
296  mSrcExtent.setXMinimum( x );
297 
298  col = std::ceil( ( mSrcExtent.xMaximum() - mExtent.xMinimum() ) / mMaxSrcXRes );
299  x = mExtent.xMinimum() + col * mMaxSrcXRes;
300  mSrcExtent.setXMaximum( x );
301  }
302  if ( mMaxSrcYRes > 0 )
303  {
304  double row = std::floor( ( mExtent.yMaximum() - mSrcExtent.yMaximum() ) / mMaxSrcYRes );
305  double y = mExtent.yMaximum() - row * mMaxSrcYRes;
306  mSrcExtent.setYMaximum( y );
307 
308  row = std::ceil( ( mExtent.yMaximum() - mSrcExtent.yMinimum() ) / mMaxSrcYRes );
309  y = mExtent.yMaximum() - row * mMaxSrcYRes;
310  mSrcExtent.setYMinimum( y );
311  }
312  }
313  QgsDebugMsgLevel( "mSrcExtent = " + mSrcExtent.toString(), 4 );
314 }
315 
316 QString ProjectorData::cpToString() const
317 {
318  QString myString;
319  for ( int i = 0; i < mCPRows; i++ )
320  {
321  if ( i > 0 )
322  myString += '\n';
323  for ( int j = 0; j < mCPCols; j++ )
324  {
325  if ( j > 0 )
326  myString += QLatin1String( " " );
327  const QgsPointXY myPoint = mCPMatrix[i][j];
328  if ( mCPLegalMatrix[i][j] )
329  {
330  myString += myPoint.toString();
331  }
332  else
333  {
334  myString += QLatin1String( "(-,-)" );
335  }
336  }
337  }
338  return myString;
339 }
340 
341 void ProjectorData::calcSrcRowsCols()
342 {
343  // Wee need to calculate minimum cell size in the source
344  // TODO: Think it over better, what is the right source resolution?
345  // Taking distances between cell centers projected to source along source
346  // axis would result in very high resolution
347  // TODO: different resolution for rows and cols ?
348 
349  double myMinSize = std::numeric_limits<double>::max();
350 
351  if ( mApproximate )
352  {
353  double myMaxSize = 0;
354 
355  // For now, we take cell sizes projected to source but not to source axes
356  const double myDestColsPerMatrixCell = static_cast< double >( mDestCols ) / mCPCols;
357  const double myDestRowsPerMatrixCell = static_cast< double >( mDestRows ) / mCPRows;
358  QgsDebugMsgLevel( QStringLiteral( "myDestColsPerMatrixCell = %1 myDestRowsPerMatrixCell = %2" ).arg( myDestColsPerMatrixCell ).arg( myDestRowsPerMatrixCell ), 4 );
359  for ( int i = 0; i < mCPRows - 1; i++ )
360  {
361  for ( int j = 0; j < mCPCols - 1; j++ )
362  {
363  const QgsPointXY myPointA = mCPMatrix[i][j];
364  const QgsPointXY myPointB = mCPMatrix[i][j + 1];
365  const QgsPointXY myPointC = mCPMatrix[i + 1][j];
366  if ( mCPLegalMatrix[i][j] && mCPLegalMatrix[i][j + 1] && mCPLegalMatrix[i + 1][j] )
367  {
368  double mySize = std::sqrt( myPointA.sqrDist( myPointB ) ) / myDestColsPerMatrixCell;
369  if ( mySize < myMinSize )
370  myMinSize = mySize;
371  if ( mySize > myMaxSize )
372  myMaxSize = mySize;
373 
374  mySize = std::sqrt( myPointA.sqrDist( myPointC ) ) / myDestRowsPerMatrixCell;
375  if ( mySize < myMinSize )
376  myMinSize = mySize;
377  if ( mySize > myMaxSize )
378  myMaxSize = mySize;
379  }
380  }
381  }
382  // Limit resolution to 1/10th of the maximum resolution to avoid issues
383  // with for example WebMercator at high northings that result in very small
384  // latitude differences.
385  if ( myMinSize < 0.1 * myMaxSize )
386  myMinSize = 0.1 * myMaxSize;
387  }
388  else
389  {
390  // take highest from corners, points in in the middle of corners and center (3 x 3 )
391  //double
392  QgsRectangle srcExtent;
393  int srcXSize, srcYSize;
394  if ( QgsRasterProjector::extentSize( mInverseCt, mDestExtent, mDestCols, mDestRows, srcExtent, srcXSize, srcYSize ) )
395  {
396  const double srcXRes = srcExtent.width() / srcXSize;
397  const double srcYRes = srcExtent.height() / srcYSize;
398  myMinSize = std::min( srcXRes, srcYRes );
399  }
400  else
401  {
402  QgsDebugMsg( QStringLiteral( "Cannot get src extent/size" ) );
403  }
404  }
405 
406  // Make it a bit higher resolution
407  // TODO: find the best coefficient, attention, increasing resolution for WMS
408  // is changing WMS content
409  myMinSize *= 0.75;
410 
411  QgsDebugMsgLevel( QStringLiteral( "mMaxSrcXRes = %1 mMaxSrcYRes = %2" ).arg( mMaxSrcXRes ).arg( mMaxSrcYRes ), 4 );
412  // mMaxSrcXRes, mMaxSrcYRes may be 0 - no limit (WMS)
413  const double myMinXSize = mMaxSrcXRes > myMinSize ? mMaxSrcXRes : myMinSize;
414  const double myMinYSize = mMaxSrcYRes > myMinSize ? mMaxSrcYRes : myMinSize;
415  QgsDebugMsgLevel( QStringLiteral( "myMinXSize = %1 myMinYSize = %2" ).arg( myMinXSize ).arg( myMinYSize ), 4 );
416  QgsDebugMsgLevel( QStringLiteral( "mSrcExtent.width = %1 mSrcExtent.height = %2" ).arg( mSrcExtent.width() ).arg( mSrcExtent.height() ), 4 );
417 
418  // we have to round to keep alignment set in calcSrcExtent
419  // Limit to 10x the source dimensions to avoid excessive memory allocation
420  // and processing time.
421  double dblSrcRows = mSrcExtent.height() / myMinYSize;
422  if ( dblSrcRows > mDestRows * 10 )
423  mSrcRows = mDestRows * 10;
424  else
425  mSrcRows = static_cast< int >( std::round( dblSrcRows ) );
426 
427  double dblSrcCols = mSrcExtent.width() / myMinXSize;
428  if ( dblSrcCols > mDestCols * 10 )
429  mSrcCols = mDestCols * 10;
430  else
431  mSrcCols = static_cast< int >( std::round( dblSrcCols ) );
432 
433  QgsDebugMsgLevel( QStringLiteral( "mSrcRows = %1 mSrcCols = %2" ).arg( mSrcRows ).arg( mSrcCols ), 4 );
434 }
435 
436 
437 inline void ProjectorData::destPointOnCPMatrix( int row, int col, double *theX, double *theY )
438 {
439  *theX = mDestExtent.xMinimum() + col * mDestExtent.width() / ( mCPCols - 1 );
440  *theY = mDestExtent.yMaximum() - row * mDestExtent.height() / ( mCPRows - 1 );
441 }
442 
443 inline int ProjectorData::matrixRow( int destRow )
444 {
445  return static_cast< int >( std::floor( ( destRow + 0.5 ) / mDestRowsPerMatrixRow ) );
446 }
447 inline int ProjectorData::matrixCol( int destCol )
448 {
449  return static_cast< int >( std::floor( ( destCol + 0.5 ) / mDestColsPerMatrixCol ) );
450 }
451 
452 void ProjectorData::calcHelper( int matrixRow, QgsPointXY *points )
453 {
454  // TODO?: should we also precalc dest cell center coordinates for x and y?
455  for ( int myDestCol = 0; myDestCol < mDestCols; myDestCol++ )
456  {
457  const double myDestX = mDestExtent.xMinimum() + ( myDestCol + 0.5 ) * mDestXRes;
458 
459  const int myMatrixCol = matrixCol( myDestCol );
460 
461  double myDestXMin, myDestYMin, myDestXMax, myDestYMax;
462 
463  destPointOnCPMatrix( matrixRow, myMatrixCol, &myDestXMin, &myDestYMin );
464  destPointOnCPMatrix( matrixRow, myMatrixCol + 1, &myDestXMax, &myDestYMax );
465 
466  const double xfrac = ( myDestX - myDestXMin ) / ( myDestXMax - myDestXMin );
467 
468  const QgsPointXY &mySrcPoint0 = mCPMatrix[matrixRow][myMatrixCol];
469  const QgsPointXY &mySrcPoint1 = mCPMatrix[matrixRow][myMatrixCol + 1];
470  const double s = mySrcPoint0.x() + ( mySrcPoint1.x() - mySrcPoint0.x() ) * xfrac;
471  const double t = mySrcPoint0.y() + ( mySrcPoint1.y() - mySrcPoint0.y() ) * xfrac;
472 
473  points[myDestCol].setX( s );
474  points[myDestCol].setY( t );
475  }
476 }
477 
478 void ProjectorData::nextHelper()
479 {
480  // We just switch pHelperTop and pHelperBottom, memory is not lost
481  QgsPointXY *tmp = nullptr;
482  tmp = pHelperTop;
483  pHelperTop = pHelperBottom;
484  pHelperBottom = tmp;
485  calcHelper( mHelperTopRow + 2, pHelperBottom );
486  mHelperTopRow++;
487 }
488 
489 bool ProjectorData::srcRowCol( int destRow, int destCol, int *srcRow, int *srcCol )
490 {
491  if ( mApproximate )
492  {
493  return approximateSrcRowCol( destRow, destCol, srcRow, srcCol );
494  }
495  else
496  {
497  return preciseSrcRowCol( destRow, destCol, srcRow, srcCol );
498  }
499 }
500 
501 bool ProjectorData::preciseSrcRowCol( int destRow, int destCol, int *srcRow, int *srcCol )
502 {
503 #if 0 // too slow, even if we only run it on debug builds!
504  QgsDebugMsgLevel( QStringLiteral( "theDestRow = %1" ).arg( destRow ), 5 );
505  QgsDebugMsgLevel( QStringLiteral( "theDestRow = %1 mDestExtent.yMaximum() = %2 mDestYRes = %3" ).arg( destRow ).arg( mDestExtent.yMaximum() ).arg( mDestYRes ), 5 );
506 #endif
507 
508  // Get coordinate of center of destination cell
509  double x = mDestExtent.xMinimum() + ( destCol + 0.5 ) * mDestXRes;
510  double y = mDestExtent.yMaximum() - ( destRow + 0.5 ) * mDestYRes;
511  double z = 0;
512 
513 #if 0
514  QgsDebugMsgLevel( QStringLiteral( "x = %1 y = %2" ).arg( x ).arg( y ), 5 );
515 #endif
516 
517  if ( mInverseCt.isValid() )
518  {
519  try
520  {
521  mInverseCt.transformInPlace( x, y, z );
522  }
523  catch ( QgsCsException & )
524  {
525  return false;
526  }
527  }
528 
529 #if 0
530  QgsDebugMsgLevel( QStringLiteral( "x = %1 y = %2" ).arg( x ).arg( y ), 5 );
531 #endif
532 
533  if ( !mExtent.contains( x, y ) )
534  {
535  return false;
536  }
537  // Get source row col
538  *srcRow = static_cast< int >( std::floor( ( mSrcExtent.yMaximum() - y ) / mSrcYRes ) );
539  *srcCol = static_cast< int >( std::floor( ( x - mSrcExtent.xMinimum() ) / mSrcXRes ) );
540 #if 0
541  QgsDebugMsgLevel( QStringLiteral( "mSrcExtent.yMinimum() = %1 mSrcExtent.yMaximum() = %2 mSrcYRes = %3" ).arg( mSrcExtent.yMinimum() ).arg( mSrcExtent.yMaximum() ).arg( mSrcYRes ), 5 );
542  QgsDebugMsgLevel( QStringLiteral( "theSrcRow = %1 srcCol = %2" ).arg( *srcRow ).arg( *srcCol ), 5 );
543 #endif
544 
545  // With epsg 32661 (Polar Stereographic) it was happening that *srcCol == mSrcCols
546  // For now silently correct limits to avoid crashes
547  // TODO: review
548  // should not happen
549  if ( *srcRow >= mSrcRows ) return false;
550  if ( *srcRow < 0 ) return false;
551  if ( *srcCol >= mSrcCols ) return false;
552  if ( *srcCol < 0 ) return false;
553 
554  return true;
555 }
556 
557 bool ProjectorData::approximateSrcRowCol( int destRow, int destCol, int *srcRow, int *srcCol )
558 {
559  const int myMatrixRow = matrixRow( destRow );
560  const int myMatrixCol = matrixCol( destCol );
561 
562  if ( myMatrixRow > mHelperTopRow )
563  {
564  // TODO: make it more robust (for random, not sequential reading)
565  nextHelper();
566  }
567 
568  const double myDestY = mDestExtent.yMaximum() - ( destRow + 0.5 ) * mDestYRes;
569 
570  // See the schema in javax.media.jai.WarpGrid doc (but up side down)
571  // TODO: use some kind of cache of values which can be reused
572  double myDestXMin, myDestYMin, myDestXMax, myDestYMax;
573 
574  destPointOnCPMatrix( myMatrixRow + 1, myMatrixCol, &myDestXMin, &myDestYMin );
575  destPointOnCPMatrix( myMatrixRow, myMatrixCol + 1, &myDestXMax, &myDestYMax );
576 
577  const double yfrac = ( myDestY - myDestYMin ) / ( myDestYMax - myDestYMin );
578 
579  const QgsPointXY &myTop = pHelperTop[destCol];
580  const QgsPointXY &myBot = pHelperBottom[destCol];
581 
582  // Warning: this is very SLOW compared to the following code!:
583  //double mySrcX = myBot.x() + (myTop.x() - myBot.x()) * yfrac;
584  //double mySrcY = myBot.y() + (myTop.y() - myBot.y()) * yfrac;
585 
586  const double tx = myTop.x();
587  const double ty = myTop.y();
588  const double bx = myBot.x();
589  const double by = myBot.y();
590  const double mySrcX = bx + ( tx - bx ) * yfrac;
591  const double mySrcY = by + ( ty - by ) * yfrac;
592 
593  if ( !mExtent.contains( mySrcX, mySrcY ) )
594  {
595  return false;
596  }
597 
598  // TODO: check again cell selection (coor is in the middle)
599 
600  *srcRow = static_cast< int >( std::floor( ( mSrcExtent.yMaximum() - mySrcY ) / mSrcYRes ) );
601  *srcCol = static_cast< int >( std::floor( ( mySrcX - mSrcExtent.xMinimum() ) / mSrcXRes ) );
602 
603  // For now silently correct limits to avoid crashes
604  // TODO: review
605  // should not happen
606  if ( *srcRow >= mSrcRows ) return false;
607  if ( *srcRow < 0 ) return false;
608  if ( *srcCol >= mSrcCols ) return false;
609  if ( *srcCol < 0 ) return false;
610 
611  return true;
612 }
613 
614 void ProjectorData::insertRows( const QgsCoordinateTransform &ct )
615 {
616  for ( int r = 0; r < mCPRows - 1; r++ )
617  {
618  QList<QgsPointXY> myRow;
619  QList<bool> myLegalRow;
620  myRow.reserve( mCPCols );
621  myLegalRow.reserve( mCPCols );
622  for ( int c = 0; c < mCPCols; ++c )
623  {
624  myRow.append( QgsPointXY() );
625  myLegalRow.append( false );
626  }
627  QgsDebugMsgLevel( QStringLiteral( "insert new row at %1" ).arg( 1 + r * 2 ), 3 );
628  mCPMatrix.insert( 1 + r * 2, myRow );
629  mCPLegalMatrix.insert( 1 + r * 2, myLegalRow );
630  }
631  mCPRows += mCPRows - 1;
632  for ( int r = 1; r < mCPRows - 1; r += 2 )
633  {
634  calcRow( r, ct );
635  }
636 }
637 
638 void ProjectorData::insertCols( const QgsCoordinateTransform &ct )
639 {
640  for ( int r = 0; r < mCPRows; r++ )
641  {
642  for ( int c = 0; c < mCPCols - 1; c++ )
643  {
644  mCPMatrix[r].insert( 1 + c * 2, QgsPointXY() );
645  mCPLegalMatrix[r].insert( 1 + c * 2, false );
646  }
647  }
648  mCPCols += mCPCols - 1;
649  for ( int c = 1; c < mCPCols - 1; c += 2 )
650  {
651  calcCol( c, ct );
652  }
653 
654 }
655 
656 void ProjectorData::calcCP( int row, int col, const QgsCoordinateTransform &ct )
657 {
658  double myDestX, myDestY;
659  destPointOnCPMatrix( row, col, &myDestX, &myDestY );
660  const QgsPointXY myDestPoint( myDestX, myDestY );
661  try
662  {
663  if ( ct.isValid() )
664  {
665  mCPMatrix[row][col] = ct.transform( myDestPoint );
666  mCPLegalMatrix[row][col] = true;
667  }
668  else
669  {
670  mCPLegalMatrix[row][col] = false;
671  }
672  }
673  catch ( QgsCsException &e )
674  {
675  Q_UNUSED( e )
676  // Caught an error in transform
677  mCPLegalMatrix[row][col] = false;
678  }
679 }
680 
681 bool ProjectorData::calcRow( int row, const QgsCoordinateTransform &ct )
682 {
683  QgsDebugMsgLevel( QStringLiteral( "theRow = %1" ).arg( row ), 3 );
684  for ( int i = 0; i < mCPCols; i++ )
685  {
686  calcCP( row, i, ct );
687  }
688 
689  return true;
690 }
691 
692 bool ProjectorData::calcCol( int col, const QgsCoordinateTransform &ct )
693 {
694  QgsDebugMsgLevel( QStringLiteral( "theCol = %1" ).arg( col ), 3 );
695  for ( int i = 0; i < mCPRows; i++ )
696  {
697  calcCP( i, col, ct );
698  }
699 
700  return true;
701 }
702 
703 bool ProjectorData::checkCols( const QgsCoordinateTransform &ct )
704 {
705  if ( !ct.isValid() )
706  {
707  return false;
708  }
709 
710  for ( int c = 0; c < mCPCols; c++ )
711  {
712  for ( int r = 1; r < mCPRows - 1; r += 2 )
713  {
714  double myDestX, myDestY;
715  destPointOnCPMatrix( r, c, &myDestX, &myDestY );
716  const QgsPointXY myDestPoint( myDestX, myDestY );
717 
718  const QgsPointXY mySrcPoint1 = mCPMatrix[r - 1][c];
719  const QgsPointXY mySrcPoint2 = mCPMatrix[r][c];
720  const QgsPointXY mySrcPoint3 = mCPMatrix[r + 1][c];
721 
722  const QgsPointXY mySrcApprox( ( mySrcPoint1.x() + mySrcPoint3.x() ) / 2, ( mySrcPoint1.y() + mySrcPoint3.y() ) / 2 );
723  if ( !mCPLegalMatrix[r - 1][c] || !mCPLegalMatrix[r][c] || !mCPLegalMatrix[r + 1][c] )
724  {
725  // There was an error earlier in transform, just abort
726  return false;
727  }
728  try
729  {
730  const QgsPointXY myDestApprox = ct.transform( mySrcApprox, Qgis::TransformDirection::Reverse );
731  const double mySqrDist = myDestApprox.sqrDist( myDestPoint );
732  if ( mySqrDist > mSqrTolerance )
733  {
734  return false;
735  }
736  }
737  catch ( QgsCsException &e )
738  {
739  Q_UNUSED( e )
740  // Caught an error in transform
741  return false;
742  }
743  }
744  }
745  return true;
746 }
747 
748 bool ProjectorData::checkRows( const QgsCoordinateTransform &ct )
749 {
750  if ( !ct.isValid() )
751  {
752  return false;
753  }
754 
755  for ( int r = 0; r < mCPRows; r++ )
756  {
757  for ( int c = 1; c < mCPCols - 1; c += 2 )
758  {
759  double myDestX, myDestY;
760  destPointOnCPMatrix( r, c, &myDestX, &myDestY );
761 
762  const QgsPointXY myDestPoint( myDestX, myDestY );
763  const QgsPointXY mySrcPoint1 = mCPMatrix[r][c - 1];
764  const QgsPointXY mySrcPoint2 = mCPMatrix[r][c];
765  const QgsPointXY mySrcPoint3 = mCPMatrix[r][c + 1];
766 
767  const QgsPointXY mySrcApprox( ( mySrcPoint1.x() + mySrcPoint3.x() ) / 2, ( mySrcPoint1.y() + mySrcPoint3.y() ) / 2 );
768  if ( !mCPLegalMatrix[r][c - 1] || !mCPLegalMatrix[r][c] || !mCPLegalMatrix[r][c + 1] )
769  {
770  // There was an error earlier in transform, just abort
771  return false;
772  }
773  try
774  {
775  const QgsPointXY myDestApprox = ct.transform( mySrcApprox, Qgis::TransformDirection::Reverse );
776  const double mySqrDist = myDestApprox.sqrDist( myDestPoint );
777  if ( mySqrDist > mSqrTolerance )
778  {
779  return false;
780  }
781  }
782  catch ( QgsCsException &e )
783  {
784  Q_UNUSED( e )
785  // Caught an error in transform
786  return false;
787  }
788  }
789  }
790  return true;
791 }
792 
794 
795 
797 {
798  switch ( precision )
799  {
800  case Approximate:
801  return tr( "Approximate" );
802  case Exact:
803  return tr( "Exact" );
804  }
805  return QStringLiteral( "Unknown" );
806 }
807 
808 QgsRasterBlock *QgsRasterProjector::block( int bandNo, QgsRectangle const &extent, int width, int height, QgsRasterBlockFeedback *feedback )
809 {
810  QgsDebugMsgLevel( QStringLiteral( "extent:\n%1" ).arg( extent.toString() ), 4 );
811  QgsDebugMsgLevel( QStringLiteral( "width = %1 height = %2" ).arg( width ).arg( height ), 4 );
812  if ( !mInput )
813  {
814  QgsDebugMsgLevel( QStringLiteral( "Input not set" ), 4 );
815  return new QgsRasterBlock();
816  }
817 
818  if ( feedback && feedback->isCanceled() )
819  return new QgsRasterBlock();
820 
821  if ( ! mSrcCRS.isValid() || ! mDestCRS.isValid() || mSrcCRS == mDestCRS )
822  {
823  QgsDebugMsgLevel( QStringLiteral( "No projection necessary" ), 4 );
824  return mInput->block( bandNo, extent, width, height, feedback );
825  }
826 
828  const QgsCoordinateTransform inverseCt = mSrcDatumTransform != -1 || mDestDatumTransform != -1 ?
829  QgsCoordinateTransform( mDestCRS, mSrcCRS, mDestDatumTransform, mSrcDatumTransform ) : QgsCoordinateTransform( mDestCRS, mSrcCRS, mTransformContext ) ;
831 
832  ProjectorData pd( extent, width, height, mInput, inverseCt, mPrecision, feedback );
833 
834  if ( feedback && feedback->isCanceled() )
835  return new QgsRasterBlock();
836 
837  QgsDebugMsgLevel( QStringLiteral( "srcExtent:\n%1" ).arg( pd.srcExtent().toString() ), 4 );
838  QgsDebugMsgLevel( QStringLiteral( "srcCols = %1 srcRows = %2" ).arg( pd.srcCols() ).arg( pd.srcRows() ), 4 );
839 
840  // If we zoom out too much, projector srcRows / srcCols maybe 0, which can cause problems in providers
841  if ( pd.srcRows() <= 0 || pd.srcCols() <= 0 )
842  {
843  QgsDebugMsgLevel( QStringLiteral( "Zero srcRows or srcCols" ), 4 );
844  return new QgsRasterBlock();
845  }
846 
847  std::unique_ptr< QgsRasterBlock > inputBlock( mInput->block( bandNo, pd.srcExtent(), pd.srcCols(), pd.srcRows(), feedback ) );
848  if ( !inputBlock || inputBlock->isEmpty() )
849  {
850  QgsDebugMsg( QStringLiteral( "No raster data!" ) );
851  return new QgsRasterBlock();
852  }
853 
854  const qgssize pixelSize = static_cast<qgssize>( QgsRasterBlock::typeSize( mInput->dataType( bandNo ) ) );
855 
856  std::unique_ptr< QgsRasterBlock > outputBlock( new QgsRasterBlock( inputBlock->dataType(), width, height ) );
857  if ( inputBlock->hasNoDataValue() )
858  {
859  outputBlock->setNoDataValue( inputBlock->noDataValue() );
860  }
861  if ( !outputBlock->isValid() )
862  {
863  QgsDebugMsg( QStringLiteral( "Cannot create block" ) );
864  return outputBlock.release();
865  }
866 
867  // set output to no data, it should be fast
868  outputBlock->setIsNoData();
869 
870  // No data: because isNoData()/setIsNoData() is slow with respect to simple memcpy,
871  // we use if only if necessary:
872  // 1) no data value exists (numerical) -> memcpy, not necessary isNoData()/setIsNoData()
873  // 2) no data value does not exist but it may contain no data (numerical no data bitmap)
874  // -> must use isNoData()/setIsNoData()
875  // 3) no data are not used (no no data value, no no data bitmap) -> simple memcpy
876  // 4) image - simple memcpy
877 
878  // To copy no data values stored in bitmaps we have to use isNoData()/setIsNoData(),
879  // we cannot fill output block with no data because we use memcpy for data, not setValue().
880  const bool doNoData = !QgsRasterBlock::typeIsNumeric( inputBlock->dataType() ) && inputBlock->hasNoData() && !inputBlock->hasNoDataValue();
881 
882  outputBlock->setIsNoData();
883 
884  int srcRow, srcCol;
885  for ( int i = 0; i < height; ++i )
886  {
887  if ( feedback && feedback->isCanceled() )
888  break;
889  for ( int j = 0; j < width; ++j )
890  {
891  const bool inside = pd.srcRowCol( i, j, &srcRow, &srcCol );
892  if ( !inside ) continue; // we have everything set to no data
893 
894  const qgssize srcIndex = static_cast< qgssize >( srcRow ) * pd.srcCols() + srcCol;
895 
896  // isNoData() may be slow so we check doNoData first
897  if ( doNoData && inputBlock->isNoData( srcRow, srcCol ) )
898  {
899  outputBlock->setIsNoData( i, j );
900  continue;
901  }
902 
903  const qgssize destIndex = static_cast< qgssize >( i ) * width + j;
904  char *srcBits = inputBlock->bits( srcIndex );
905  char *destBits = outputBlock->bits( destIndex );
906  if ( !srcBits )
907  {
908  // QgsDebugMsg( QStringLiteral( "Cannot get input block data: row = %1 col = %2" ).arg( i ).arg( j ) );
909  continue;
910  }
911  if ( !destBits )
912  {
913  // QgsDebugMsg( QStringLiteral( "Cannot set output block data: srcRow = %1 srcCol = %2" ).arg( srcRow ).arg( srcCol ) );
914  continue;
915  }
916  memcpy( destBits, srcBits, pixelSize );
917  outputBlock->setIsData( i, j );
918  }
919  }
920 
921  return outputBlock.release();
922 }
923 
924 bool QgsRasterProjector::destExtentSize( const QgsRectangle &srcExtent, int srcXSize, int srcYSize,
925  QgsRectangle &destExtent, int &destXSize, int &destYSize )
926 {
927  if ( srcExtent.isEmpty() || srcXSize <= 0 || srcYSize <= 0 )
928  {
929  return false;
930  }
931 
933  const QgsCoordinateTransform ct = mSrcDatumTransform != -1 || mDestDatumTransform != -1 ?
934  QgsCoordinateTransform( mSrcCRS, mDestCRS, mSrcDatumTransform, mDestDatumTransform ) : QgsCoordinateTransform( mSrcCRS, mDestCRS, mTransformContext ) ;
936 
937  return extentSize( ct, srcExtent, srcXSize, srcYSize, destExtent, destXSize, destYSize );
938 }
939 
941  const QgsRectangle &srcExtent, int srcXSize, int srcYSize,
942  QgsRectangle &destExtent, int &destXSize, int &destYSize )
943 {
944  if ( srcExtent.isEmpty() || srcXSize <= 0 || srcYSize <= 0 )
945  {
946  return false;
947  }
948 
949  QgsCoordinateTransform extentTransform = ct;
950  extentTransform.setBallparkTransformsAreAppropriate( true );
951 
952  destExtent = extentTransform.transformBoundingBox( srcExtent );
953 
954  // We reproject pixel rectangle from 9 points matrix of source extent, of course, it gives
955  // bigger xRes,yRes than reprojected edges (envelope)
956  constexpr int steps = 3;
957  const double srcXStep = srcExtent.width() / steps;
958  const double srcYStep = srcExtent.height() / steps;
959  const double srcXRes = srcExtent.width() / srcXSize;
960  const double srcYRes = srcExtent.height() / srcYSize;
961  double destXRes = std::numeric_limits<double>::max();
962  double destYRes = std::numeric_limits<double>::max();
963  double maxXRes = 0;
964  double maxYRes = 0;
965 
966  for ( int i = 0; i < steps; i++ )
967  {
968  const double x = srcExtent.xMinimum() + i * srcXStep;
969  for ( int j = 0; j < steps; j++ )
970  {
971  const double y = srcExtent.yMinimum() + j * srcYStep;
972  const QgsRectangle srcRectangle( x - srcXRes / 2, y - srcYRes / 2, x + srcXRes / 2, y + srcYRes / 2 );
973  try
974  {
975  const QgsRectangle destRectangle = extentTransform.transformBoundingBox( srcRectangle );
976  if ( destRectangle.width() > 0 )
977  {
978  destXRes = std::min( destXRes, destRectangle.width() );
979  if ( destRectangle.width() > maxXRes )
980  maxXRes = destRectangle.width();
981  }
982  if ( destRectangle.height() > 0 )
983  {
984  destYRes = std::min( destYRes, destRectangle.height() );
985  if ( destRectangle.height() > maxYRes )
986  maxYRes = destRectangle.height();
987  }
988  }
989  catch ( QgsCsException & )
990  {
991 
992  }
993  }
994  }
995 
996  // Limit resolution to 1/10th of the maximum resolution to avoid issues
997  // with for example WebMercator at high northings that result in very small
998  // latitude differences.
999  if ( destXRes < 0.1 * maxXRes )
1000  {
1001  destXRes = 0.1 * maxXRes;
1002  }
1003  if ( destYRes < 0.1 * maxYRes )
1004  {
1005  destYRes = 0.1 * maxYRes;
1006  }
1007  if ( destXRes == 0 || destExtent.width() / destXRes > std::numeric_limits<int>::max() )
1008  return false;
1009  if ( destYRes == 0 || destExtent.height() / destYRes > std::numeric_limits<int>::max() )
1010  return false;
1011 
1012  destXSize = std::max( 1, static_cast< int >( destExtent.width() / destXRes ) );
1013  destYSize = std::max( 1, static_cast< int >( destExtent.height() / destYRes ) );
1014 
1015  return true;
1016 }
1017 
qgsrasterprojector.h
QgsRectangle::height
double height() const SIP_HOLDGIL
Returns the height of the rectangle.
Definition: qgsrectangle.h:230
QgsPointXY::y
double y
Definition: qgspointxy.h:63
QgsCoordinateTransformContext
Contains information about the context in which a coordinate transform is executed.
Definition: qgscoordinatetransformcontext.h:57
QgsRasterInterface::Size
@ Size
Original data source size (and thus resolution) is known, it is not always available,...
Definition: qgsrasterinterface.h:205
QgsRasterInterface::mInput
QgsRasterInterface * mInput
Definition: qgsrasterinterface.h:500
QgsDebugMsgLevel
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
QgsRasterProjector::destExtentSize
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.
Definition: qgsrasterprojector.cpp:924
QgsRasterBlock::typeIsNumeric
static bool typeIsNumeric(Qgis::DataType type)
Returns true if data type is numeric.
Definition: qgsrasterblock.cpp:139
QgsRasterDataProvider::ProviderHintCanPerformProviderResampling
@ ProviderHintCanPerformProviderResampling
Provider can perform resampling (to be opposed to post rendering resampling) (since QGIS 3....
Definition: qgsrasterdataprovider.h:104
QgsRectangle::yMinimum
double yMinimum() const SIP_HOLDGIL
Returns the y minimum value (bottom side of rectangle).
Definition: qgsrectangle.h:198
QgsCoordinateTransform::transformBoundingBox
QgsRectangle transformBoundingBox(const QgsRectangle &rectangle, Qgis::TransformDirection direction=Qgis::TransformDirection::Forward, bool handle180Crossover=false) const SIP_THROW(QgsCsException)
Transforms a rectangle from the source CRS to the destination CRS.
Definition: qgscoordinatetransform.cpp:560
Qgis::DataType
DataType
Raster data types.
Definition: qgis.h:128
QgsRasterDataProvider::extent
QgsRectangle extent() const override=0
Returns the extent of the layer.
QgsPointXY::setY
void setY(double y) SIP_HOLDGIL
Sets the y value of the point.
Definition: qgspointxy.h:132
QgsFeedback::isCanceled
bool isCanceled() const SIP_HOLDGIL
Tells whether the operation has been canceled already.
Definition: qgsfeedback.h:67
QgsRasterBlock::typeSize
static int typeSize(Qgis::DataType dataType) SIP_HOLDGIL
Returns the size in bytes for the specified dataType.
Definition: qgsrasterblock.h:83
QgsDebugMsg
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
QgsCoordinateTransform::isValid
bool isValid() const
Returns true if the coordinate transform is valid, ie both the source and destination CRS have been s...
Definition: qgscoordinatetransform.cpp:900
QgsPointXY::setX
void setX(double x) SIP_HOLDGIL
Sets the x value of the point.
Definition: qgspointxy.h:122
QgsRectangle
A rectangle specified with double values.
Definition: qgsrectangle.h:41
QgsPointXY::sqrDist
double sqrDist(double x, double y) const SIP_HOLDGIL
Returns the squared distance between this point a specified x, y coordinate.
Definition: qgspointxy.h:190
QgsRasterProjector
QgsRasterProjector implements approximate projection support for it calculates grid of points in sour...
Definition: qgsrasterprojector.h:47
Q_NOWARN_DEPRECATED_POP
#define Q_NOWARN_DEPRECATED_POP
Definition: qgis.h:2820
precision
int precision
Definition: qgswfsgetfeature.cpp:103
QgsRasterInterface::sourceInput
virtual const QgsRasterInterface * sourceInput() const
Gets source / raw input, the first in pipe, usually provider.
Definition: qgsrasterinterface.h:316
QgsCsException
Custom exception class for Coordinate Reference System related exceptions.
Definition: qgsexception.h:65
QgsRasterProjector::dataType
Qgis::DataType dataType(int bandNo) const override
Returns data type for the band specified by number.
Definition: qgsrasterprojector.cpp:58
QgsRasterProjector::bandCount
int bandCount() const override
Gets number of bands.
Definition: qgsrasterprojector.cpp:51
QgsRasterProjector::QgsRasterProjector
QgsRasterProjector()
Definition: qgsrasterprojector.cpp:26
QgsCoordinateTransform::setBallparkTransformsAreAppropriate
void setBallparkTransformsAreAppropriate(bool appropriate)
Sets whether approximate "ballpark" results are appropriate for this coordinate transform.
Definition: qgscoordinatetransform.cpp:939
QgsRasterProjector::precisionLabel
static QString precisionLabel(Precision precision)
Definition: qgsrasterprojector.cpp:796
QgsRasterInterface::xSize
virtual int xSize() const
Gets raster size.
Definition: qgsrasterinterface.h:263
QgsRasterDataProvider::providerCapabilities
virtual QgsRasterDataProvider::ProviderCapabilities providerCapabilities() const
Returns flags containing the supported capabilities of the data provider.
Definition: qgsrasterdataprovider.cpp:250
QgsPointXY::toString
QString toString(int precision=-1) const
Returns a string representation of the point (x, y) with a preset precision.
Definition: qgspointxy.cpp:51
QgsRasterInterface::dataType
virtual Qgis::DataType dataType(int bandNo) const =0
Returns data type for the band specified by number.
Qgis::DataType::UnknownDataType
@ UnknownDataType
Unknown or unspecified type.
QgsCoordinateReferenceSystem::isValid
bool isValid() const
Returns whether this CRS is correctly initialized and usable.
Definition: qgscoordinatereferencesystem.cpp:977
QgsRasterProjector::setCrs
Q_DECL_DEPRECATED void setCrs(const QgsCoordinateReferenceSystem &srcCRS, const QgsCoordinateReferenceSystem &destCRS, int srcDatumTransform=-1, int destDatumTransform=-1)
Sets the source and destination CRS.
qgscoordinatetransform.h
QgsRectangle::xMinimum
double xMinimum() const SIP_HOLDGIL
Returns the x minimum value (left side of rectangle).
Definition: qgsrectangle.h:188
QgsCoordinateReferenceSystem
This class represents a coordinate reference system (CRS).
Definition: qgscoordinatereferencesystem.h:211
QgsRasterInterface::ySize
virtual int ySize() const
Definition: qgsrasterinterface.h:264
QgsRectangle::toString
QString toString(int precision=16) const
Returns a string representation of form xmin,ymin : xmax,ymax Coordinates will be truncated to the sp...
Definition: qgsrectangle.cpp:127
QgsPointXY
A class to represent a 2D point.
Definition: qgspointxy.h:58
QgsRasterProjector::precision
Precision precision() const
Definition: qgsrasterprojector.h:92
QgsRasterInterface
Base class for processing filters like renderers, reprojector, resampler etc.
Definition: qgsrasterinterface.h:135
c
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
Definition: porting_processing.dox:1
QgsRectangle::width
double width() const SIP_HOLDGIL
Returns the width of the rectangle.
Definition: qgsrectangle.h:223
QgsRasterProjector::Exact
@ Exact
Exact, precise but slow.
Definition: qgsrasterprojector.h:60
QgsRasterInterface::input
virtual QgsRasterInterface * input() const
Current input.
Definition: qgsrasterinterface.h:302
QgsPointXY::x
double x
Definition: qgspointxy.h:62
QgsRasterBlockFeedback
Feedback object tailored for raster block reading.
Definition: qgsrasterinterface.h:41
qgsexception.h
QgsRasterInterface::bandCount
virtual int bandCount() const =0
Gets number of bands.
QgsRasterInterface::block
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.
qgslogger.h
QgsCoordinateTransform::transform
QgsPointXY transform(const QgsPointXY &point, Qgis::TransformDirection direction=Qgis::TransformDirection::Forward) const SIP_THROW(QgsCsException)
Transform the point from the source CRS to the destination CRS.
Definition: qgscoordinatetransform.cpp:272
QgsRasterProjector::block
QgsRasterBlock * block(int bandNo, const QgsRectangle &extent, int width, int height, QgsRasterBlockFeedback *feedback=nullptr) override
Read block of data using given extent and size.
Definition: qgsrasterprojector.cpp:808
QgsCoordinateTransform
Class for doing transforms between two map coordinate systems.
Definition: qgscoordinatetransform.h:57
Q_NOWARN_DEPRECATED_PUSH
#define Q_NOWARN_DEPRECATED_PUSH
Definition: qgis.h:2819
QgsRectangle::isEmpty
bool isEmpty() const
Returns true if the rectangle is empty.
Definition: qgsrectangle.h:469
QgsRasterInterface::capabilities
virtual int capabilities() const
Returns a bitmask containing the supported capabilities.
Definition: qgsrasterinterface.h:225
QgsRasterDataProvider
Base class for raster data providers.
Definition: qgsrasterdataprovider.h:88
QgsRasterProjector::clone
QgsRasterProjector * clone() const override
Clone itself, create deep copy.
Definition: qgsrasterprojector.cpp:34
QgsRasterBlock
Raster data container.
Definition: qgsrasterblock.h:36
QgsRasterInterface::extent
virtual QgsRectangle extent() const
Gets the extent of the interface.
Definition: qgsrasterinterface.h:248
QgsRasterProjector::Approximate
@ Approximate
Approximate (default), fast but possibly inaccurate.
Definition: qgsrasterprojector.h:59
QgsRasterProjector::extentSize
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.
Definition: qgsrasterprojector.cpp:940
qgsrasterdataprovider.h
qgssize
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...
Definition: qgis.h:2791
QgsRasterProjector::Precision
Precision
Precision defines if each pixel is reprojected or approximate reprojection based on an approximation ...
Definition: qgsrasterprojector.h:57