Skip to content

Commit fdeac81

Browse files
committed
Fix incorrect raster reprojection after drawing raster previews
Moved all temporary projector members to a private class, so even recursive block() calls will not affect each other (there is no new performance penalty as block() call always recomputes the temporary control point matrix anyway)
1 parent 6bb291f commit fdeac81

File tree

3 files changed

+108
-120
lines changed

3 files changed

+108
-120
lines changed

python/core/raster/qgsrasterprojector.sip

-3
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,6 @@ class QgsRasterProjector : QgsRasterInterface
4343
/** \brief Get destination CRS */
4444
QgsCoordinateReferenceSystem destinationCrs() const;
4545

46-
/** \brief set maximum source resolution */
47-
void setMaxSrcRes( double theMaxSrcXRes, double theMaxSrcYRes );
48-
4946
Precision precision() const;
5047
void setPrecision( Precision precision );
5148
// Translated precision mode, for use in ComboBox etc.

src/core/raster/qgsrasterprojector.cpp

+66-85
Original file line numberDiff line numberDiff line change
@@ -24,31 +24,11 @@
2424
#include "qgscsexception.h"
2525

2626

27-
2827
QgsRasterProjector::QgsRasterProjector()
2928
: QgsRasterInterface( nullptr )
3029
, mSrcDatumTransform( -1 )
3130
, mDestDatumTransform( -1 )
3231
, mPrecision( Approximate )
33-
, mApproximate( false )
34-
, mDestRows( 0 )
35-
, mDestCols( 0 )
36-
, mDestXRes( 0.0 )
37-
, mDestYRes( 0.0 )
38-
, mSrcRows( 0 )
39-
, mSrcCols( 0 )
40-
, mSrcXRes( 0.0 )
41-
, mSrcYRes( 0.0 )
42-
, mDestRowsPerMatrixRow( 0.0 )
43-
, mDestColsPerMatrixCol( 0.0 )
44-
, pHelperTop( nullptr )
45-
, pHelperBottom( nullptr )
46-
, mHelperTopRow( 0 )
47-
, mCPCols( 0 )
48-
, mCPRows( 0 )
49-
, mSqrTolerance( 0.0 )
50-
, mMaxSrcXRes( 0 )
51-
, mMaxSrcYRes( 0 )
5232
{
5333
QgsDebugMsgLevel( "Entered", 4 );
5434
}
@@ -62,17 +42,12 @@ QgsRasterProjector* QgsRasterProjector::clone() const
6242
projector->mDestCRS = mDestCRS;
6343
projector->mSrcDatumTransform = mSrcDatumTransform;
6444
projector->mDestDatumTransform = mDestDatumTransform;
65-
projector->mMaxSrcXRes = mMaxSrcXRes;
66-
projector->mMaxSrcYRes = mMaxSrcYRes;
67-
projector->mExtent = mExtent;
6845
projector->mPrecision = mPrecision;
6946
return projector;
7047
}
7148

7249
QgsRasterProjector::~QgsRasterProjector()
7350
{
74-
delete[] pHelperTop;
75-
delete[] pHelperBottom;
7651
}
7752

7853
int QgsRasterProjector::bandCount() const
@@ -97,22 +72,36 @@ void QgsRasterProjector::setCrs( const QgsCoordinateReferenceSystem & theSrcCRS,
9772
mDestDatumTransform = destDatumTransform;
9873
}
9974

100-
void QgsRasterProjector::calc()
75+
76+
ProjectorData::ProjectorData( const QgsRectangle& extent, int width, int height, QgsRasterInterface* input, const QgsCoordinateTransform& inverseCt, QgsRasterProjector::Precision precision )
77+
: mApproximate( false )
78+
, mInverseCt( new QgsCoordinateTransform( inverseCt ) )
79+
, mDestExtent( extent )
80+
, mDestRows( height )
81+
, mDestCols( width )
82+
, mDestXRes( 0.0 )
83+
, mDestYRes( 0.0 )
84+
, mSrcRows( 0 )
85+
, mSrcCols( 0 )
86+
, mSrcXRes( 0.0 )
87+
, mSrcYRes( 0.0 )
88+
, mDestRowsPerMatrixRow( 0.0 )
89+
, mDestColsPerMatrixCol( 0.0 )
90+
, pHelperTop( nullptr )
91+
, pHelperBottom( nullptr )
92+
, mHelperTopRow( 0 )
93+
, mCPCols( 0 )
94+
, mCPRows( 0 )
95+
, mSqrTolerance( 0.0 )
96+
, mMaxSrcXRes( 0 )
97+
, mMaxSrcYRes( 0 )
10198
{
10299
QgsDebugMsgLevel( "Entered", 4 );
103-
mCPMatrix.clear();
104-
mCPLegalMatrix.clear();
105-
delete[] pHelperTop;
106-
pHelperTop = nullptr;
107-
delete[] pHelperBottom;
108-
pHelperBottom = nullptr;
109100

110101
// Get max source resolution and extent if possible
111-
mMaxSrcXRes = 0;
112-
mMaxSrcYRes = 0;
113-
if ( mInput )
102+
if ( input )
114103
{
115-
QgsRasterDataProvider *provider = dynamic_cast<QgsRasterDataProvider*>( mInput->sourceInput() );
104+
QgsRasterDataProvider *provider = dynamic_cast<QgsRasterDataProvider*>( input->sourceInput() );
116105
if ( provider )
117106
{
118107
if ( provider->capabilities() & QgsRasterDataProvider::Size )
@@ -138,9 +127,7 @@ void QgsRasterProjector::calc()
138127
double myDestRes = mDestXRes < mDestYRes ? mDestXRes : mDestYRes;
139128
mSqrTolerance = myDestRes * myDestRes;
140129

141-
QgsCoordinateTransform inverseCt = QgsCoordinateTransformCache::instance()->transform( mDestCRS.authid(), mSrcCRS.authid(), mDestDatumTransform, mSrcDatumTransform );
142-
143-
if ( mPrecision == Approximate )
130+
if ( precision == QgsRasterProjector::Approximate )
144131
{
145132
mApproximate = true;
146133
}
@@ -219,7 +206,15 @@ void QgsRasterProjector::calc()
219206
mSrcXRes = mSrcExtent.width() / mSrcCols;
220207
}
221208

222-
void QgsRasterProjector::calcSrcExtent()
209+
ProjectorData::~ProjectorData()
210+
{
211+
delete[] pHelperTop;
212+
delete[] pHelperBottom;
213+
delete mInverseCt;
214+
}
215+
216+
217+
void ProjectorData::calcSrcExtent()
223218
{
224219
/* Run around the mCPMatrix and find source extent */
225220
// Attention, source limits are not necessarily on destination edges, e.g.
@@ -283,7 +278,7 @@ void QgsRasterProjector::calcSrcExtent()
283278
QgsDebugMsgLevel( "mSrcExtent = " + mSrcExtent.toString(), 4 );
284279
}
285280

286-
QString QgsRasterProjector::cpToString()
281+
QString ProjectorData::cpToString()
287282
{
288283
QString myString;
289284
for ( int i = 0; i < mCPRows; i++ )
@@ -308,7 +303,7 @@ QString QgsRasterProjector::cpToString()
308303
return myString;
309304
}
310305

311-
void QgsRasterProjector::calcSrcRowsCols()
306+
void ProjectorData::calcSrcRowsCols()
312307
{
313308
// Wee need to calculate minimum cell size in the source
314309
// TODO: Think it over better, what is the right source resolution?
@@ -347,11 +342,10 @@ void QgsRasterProjector::calcSrcRowsCols()
347342
else
348343
{
349344
// take highest from corners, points in in the middle of corners and center (3 x 3 )
350-
QgsCoordinateTransform inverseCt = QgsCoordinateTransformCache::instance()->transform( mDestCRS.authid(), mSrcCRS.authid(), mDestDatumTransform, mSrcDatumTransform );
351345
//double
352346
QgsRectangle srcExtent;
353347
int srcXSize, srcYSize;
354-
if ( extentSize( inverseCt, mDestExtent, mDestCols, mDestRows, srcExtent, srcXSize, srcYSize ) )
348+
if ( QgsRasterProjector::extentSize( *mInverseCt, mDestExtent, mDestCols, mDestRows, srcExtent, srcXSize, srcYSize ) )
355349
{
356350
double srcXRes = srcExtent.width() / srcXSize;
357351
double srcYRes = srcExtent.height() / srcYSize;
@@ -383,29 +377,22 @@ void QgsRasterProjector::calcSrcRowsCols()
383377
}
384378

385379

386-
inline void QgsRasterProjector::destPointOnCPMatrix( int theRow, int theCol, double *theX, double *theY )
380+
inline void ProjectorData::destPointOnCPMatrix( int theRow, int theCol, double *theX, double *theY )
387381
{
388382
*theX = mDestExtent.xMinimum() + theCol * mDestExtent.width() / ( mCPCols - 1 );
389383
*theY = mDestExtent.yMaximum() - theRow * mDestExtent.height() / ( mCPRows - 1 );
390384
}
391385

392-
inline int QgsRasterProjector::matrixRow( int theDestRow )
386+
inline int ProjectorData::matrixRow( int theDestRow )
393387
{
394388
return static_cast< int >( floor(( theDestRow + 0.5 ) / mDestRowsPerMatrixRow ) );
395389
}
396-
inline int QgsRasterProjector::matrixCol( int theDestCol )
390+
inline int ProjectorData::matrixCol( int theDestCol )
397391
{
398392
return static_cast< int >( floor(( theDestCol + 0.5 ) / mDestColsPerMatrixCol ) );
399393
}
400394

401-
QgsPoint QgsRasterProjector::srcPoint( int theDestRow, int theCol )
402-
{
403-
Q_UNUSED( theDestRow );
404-
Q_UNUSED( theCol );
405-
return QgsPoint();
406-
}
407-
408-
void QgsRasterProjector::calcHelper( int theMatrixRow, QgsPoint *thePoints )
395+
void ProjectorData::calcHelper( int theMatrixRow, QgsPoint *thePoints )
409396
{
410397
// TODO?: should we also precalc dest cell center coordinates for x and y?
411398
for ( int myDestCol = 0; myDestCol < mDestCols; myDestCol++ )
@@ -430,7 +417,8 @@ void QgsRasterProjector::calcHelper( int theMatrixRow, QgsPoint *thePoints )
430417
thePoints[myDestCol].setY( t );
431418
}
432419
}
433-
void QgsRasterProjector::nextHelper()
420+
421+
void ProjectorData::nextHelper()
434422
{
435423
// We just switch pHelperTop and pHelperBottom, memory is not lost
436424
QgsPoint *tmp;
@@ -441,19 +429,19 @@ void QgsRasterProjector::nextHelper()
441429
mHelperTopRow++;
442430
}
443431

444-
bool QgsRasterProjector::srcRowCol( int theDestRow, int theDestCol, int *theSrcRow, int *theSrcCol, const QgsCoordinateTransform& ct )
432+
bool ProjectorData::srcRowCol( int theDestRow, int theDestCol, int *theSrcRow, int *theSrcCol )
445433
{
446434
if ( mApproximate )
447435
{
448436
return approximateSrcRowCol( theDestRow, theDestCol, theSrcRow, theSrcCol );
449437
}
450438
else
451439
{
452-
return preciseSrcRowCol( theDestRow, theDestCol, theSrcRow, theSrcCol, ct );
440+
return preciseSrcRowCol( theDestRow, theDestCol, theSrcRow, theSrcCol );
453441
}
454442
}
455443

456-
bool QgsRasterProjector::preciseSrcRowCol( int theDestRow, int theDestCol, int *theSrcRow, int *theSrcCol, const QgsCoordinateTransform& ct )
444+
bool ProjectorData::preciseSrcRowCol( int theDestRow, int theDestCol, int *theSrcRow, int *theSrcCol )
457445
{
458446
#ifdef QGISDEBUG
459447
QgsDebugMsgLevel( QString( "theDestRow = %1" ).arg( theDestRow ), 5 );
@@ -469,9 +457,9 @@ bool QgsRasterProjector::preciseSrcRowCol( int theDestRow, int theDestCol, int *
469457
QgsDebugMsgLevel( QString( "x = %1 y = %2" ).arg( x ).arg( y ), 5 );
470458
#endif
471459

472-
if ( ct.isValid() )
460+
if ( mInverseCt->isValid() )
473461
{
474-
ct.transformInPlace( x, y, z );
462+
mInverseCt->transformInPlace( x, y, z );
475463
}
476464

477465
#ifdef QGISDEBUG
@@ -502,7 +490,7 @@ bool QgsRasterProjector::preciseSrcRowCol( int theDestRow, int theDestCol, int *
502490
return true;
503491
}
504492

505-
bool QgsRasterProjector::approximateSrcRowCol( int theDestRow, int theDestCol, int *theSrcRow, int *theSrcCol )
493+
bool ProjectorData::approximateSrcRowCol( int theDestRow, int theDestCol, int *theSrcRow, int *theSrcCol )
506494
{
507495
int myMatrixRow = matrixRow( theDestRow );
508496
int myMatrixCol = matrixCol( theDestCol );
@@ -559,7 +547,7 @@ bool QgsRasterProjector::approximateSrcRowCol( int theDestRow, int theDestCol, i
559547
return true;
560548
}
561549

562-
void QgsRasterProjector::insertRows( const QgsCoordinateTransform& ct )
550+
void ProjectorData::insertRows( const QgsCoordinateTransform& ct )
563551
{
564552
for ( int r = 0; r < mCPRows - 1; r++ )
565553
{
@@ -583,7 +571,7 @@ void QgsRasterProjector::insertRows( const QgsCoordinateTransform& ct )
583571
}
584572
}
585573

586-
void QgsRasterProjector::insertCols( const QgsCoordinateTransform& ct )
574+
void ProjectorData::insertCols( const QgsCoordinateTransform& ct )
587575
{
588576
for ( int r = 0; r < mCPRows; r++ )
589577
{
@@ -601,7 +589,7 @@ void QgsRasterProjector::insertCols( const QgsCoordinateTransform& ct )
601589

602590
}
603591

604-
void QgsRasterProjector::calcCP( int theRow, int theCol, const QgsCoordinateTransform& ct )
592+
void ProjectorData::calcCP( int theRow, int theCol, const QgsCoordinateTransform& ct )
605593
{
606594
double myDestX, myDestY;
607595
destPointOnCPMatrix( theRow, theCol, &myDestX, &myDestY );
@@ -626,7 +614,7 @@ void QgsRasterProjector::calcCP( int theRow, int theCol, const QgsCoordinateTran
626614
}
627615
}
628616

629-
bool QgsRasterProjector::calcRow( int theRow, const QgsCoordinateTransform& ct )
617+
bool ProjectorData::calcRow( int theRow, const QgsCoordinateTransform& ct )
630618
{
631619
QgsDebugMsgLevel( QString( "theRow = %1" ).arg( theRow ), 3 );
632620
for ( int i = 0; i < mCPCols; i++ )
@@ -637,7 +625,7 @@ bool QgsRasterProjector::calcRow( int theRow, const QgsCoordinateTransform& ct )
637625
return true;
638626
}
639627

640-
bool QgsRasterProjector::calcCol( int theCol, const QgsCoordinateTransform& ct )
628+
bool ProjectorData::calcCol( int theCol, const QgsCoordinateTransform& ct )
641629
{
642630
QgsDebugMsgLevel( QString( "theCol = %1" ).arg( theCol ), 3 );
643631
for ( int i = 0; i < mCPRows; i++ )
@@ -648,7 +636,7 @@ bool QgsRasterProjector::calcCol( int theCol, const QgsCoordinateTransform& ct )
648636
return true;
649637
}
650638

651-
bool QgsRasterProjector::checkCols( const QgsCoordinateTransform& ct )
639+
bool ProjectorData::checkCols( const QgsCoordinateTransform& ct )
652640
{
653641
if ( !ct.isValid() )
654642
{
@@ -693,7 +681,7 @@ bool QgsRasterProjector::checkCols( const QgsCoordinateTransform& ct )
693681
return true;
694682
}
695683

696-
bool QgsRasterProjector::checkRows( const QgsCoordinateTransform& ct )
684+
bool ProjectorData::checkRows( const QgsCoordinateTransform& ct )
697685
{
698686
if ( !ct.isValid() )
699687
{
@@ -766,22 +754,21 @@ QgsRasterBlock * QgsRasterProjector::block( int bandNo, QgsRectangle const & ex
766754
return mInput->block( bandNo, extent, width, height, feedback );
767755
}
768756

769-
mDestExtent = extent;
770-
mDestRows = height;
771-
mDestCols = width;
772-
calc();
757+
QgsCoordinateTransform inverseCt = QgsCoordinateTransformCache::instance()->transform( mDestCRS.authid(), mSrcCRS.authid(), mDestDatumTransform, mSrcDatumTransform );
758+
759+
ProjectorData pd( extent, width, height, mInput, inverseCt, mPrecision );
773760

774-
QgsDebugMsgLevel( QString( "srcExtent:\n%1" ).arg( mSrcExtent.toString() ), 4 );
775-
QgsDebugMsgLevel( QString( "srcCols = %1 srcRows = %2" ).arg( mSrcCols ).arg( mSrcRows ), 4 );
761+
QgsDebugMsgLevel( QString( "srcExtent:\n%1" ).arg( pd.srcExtent().toString() ), 4 );
762+
QgsDebugMsgLevel( QString( "srcCols = %1 srcRows = %2" ).arg( pd.srcCols() ).arg( pd.srcRows() ), 4 );
776763

777764
// If we zoom out too much, projector srcRows / srcCols maybe 0, which can cause problems in providers
778-
if ( mSrcRows <= 0 || mSrcCols <= 0 )
765+
if ( pd.srcRows() <= 0 || pd.srcCols() <= 0 )
779766
{
780767
QgsDebugMsgLevel( "Zero srcRows or srcCols", 4 );
781768
return new QgsRasterBlock();
782769
}
783770

784-
QgsRasterBlock *inputBlock = mInput->block( bandNo, mSrcExtent, mSrcCols, mSrcRows, feedback );
771+
QgsRasterBlock *inputBlock = mInput->block( bandNo, pd.srcExtent(), pd.srcCols(), pd.srcRows(), feedback );
785772
if ( !inputBlock || inputBlock->isEmpty() )
786773
{
787774
QgsDebugMsg( "No raster data!" );
@@ -822,23 +809,17 @@ QgsRasterBlock * QgsRasterProjector::block( int bandNo, QgsRectangle const & ex
822809
// we cannot fill output block with no data because we use memcpy for data, not setValue().
823810
bool doNoData = !QgsRasterBlock::typeIsNumeric( inputBlock->dataType() ) && inputBlock->hasNoData() && !inputBlock->hasNoDataValue();
824811

825-
QgsCoordinateTransform inverseCt;
826-
if ( !mApproximate )
827-
{
828-
inverseCt = QgsCoordinateTransformCache::instance()->transform( mDestCRS.authid(), mSrcCRS.authid(), mDestDatumTransform, mSrcDatumTransform );
829-
}
830-
831812
outputBlock->setIsNoData();
832813

833814
int srcRow, srcCol;
834815
for ( int i = 0; i < height; ++i )
835816
{
836817
for ( int j = 0; j < width; ++j )
837818
{
838-
bool inside = srcRowCol( i, j, &srcRow, &srcCol, inverseCt );
819+
bool inside = pd.srcRowCol( i, j, &srcRow, &srcCol );
839820
if ( !inside ) continue; // we have everything set to no data
840821

841-
qgssize srcIndex = static_cast< qgssize >( srcRow ) * mSrcCols + srcCol;
822+
qgssize srcIndex = static_cast< qgssize >( srcRow ) * pd.srcCols() + srcCol;
842823
QgsDebugMsgLevel( QString( "row = %1 col = %2 srcRow = %3 srcCol = %4" ).arg( i ).arg( j ).arg( srcRow ).arg( srcCol ), 5 );
843824

844825
// isNoData() may be slow so we check doNoData first

0 commit comments

Comments
 (0)