Skip to content

Commit 330b46b

Browse files
committed
raster projector improved, also fixes #9101
1 parent fd6e37c commit 330b46b

File tree

4 files changed

+55
-35
lines changed

4 files changed

+55
-35
lines changed

src/core/raster/qgsrasterblock.cpp

+3-1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
#include "qgslogger.h"
2424
#include "qgsrasterblock.h"
2525

26+
const QRgb QgsRasterBlock::mNoDataColor = qRgba( 255, 255, 255, 0 );
27+
2628
QgsRasterBlock::QgsRasterBlock()
2729
: mValid( true )
2830
, mDataType( QGis::UnknownDataType )
@@ -464,7 +466,7 @@ bool QgsRasterBlock::setIsNoData()
464466
return false;
465467
}
466468
QgsDebugMsg( "Fill image" );
467-
mImage->fill( qRgba( 0, 0, 0, 0 ) );
469+
mImage->fill( mNoDataColor );
468470
return true;
469471
}
470472
}

src/core/raster/qgsrasterblock.h

+2
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,8 @@ class CORE_EXPORT QgsRasterBlock
357357
// No data value
358358
double mNoDataValue;
359359

360+
static const QRgb mNoDataColor;
361+
360362
// Data block for numerical data types, not used with image data types
361363
// QByteArray does not seem to be intended for large data blocks, does it?
362364
void * mData;

src/core/raster/qgsrasterprojector.cpp

+43-30
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,9 @@ void QgsRasterProjector::calcSrcExtent()
290290
}
291291
// Expand a bit to avoid possible approx coords falling out because of representation error?
292292

293+
// Combine with maximum source extent
294+
mSrcExtent = mSrcExtent.intersect( &mExtent );
295+
293296
// If mMaxSrcXRes, mMaxSrcYRes are defined (fixed src resolution)
294297
// align extent to src resolution to avoid jumping of reprojected pixels
295298
// when shifting resampled grid.
@@ -464,19 +467,19 @@ void QgsRasterProjector::nextHelper()
464467
mHelperTopRow++;
465468
}
466469

467-
void QgsRasterProjector::srcRowCol( int theDestRow, int theDestCol, int *theSrcRow, int *theSrcCol, const QgsCoordinateTransform* ct )
470+
bool QgsRasterProjector::srcRowCol( int theDestRow, int theDestCol, int *theSrcRow, int *theSrcCol, const QgsCoordinateTransform* ct )
468471
{
469472
if ( mApproximate )
470473
{
471-
approximateSrcRowCol( theDestRow, theDestCol, theSrcRow, theSrcCol );
474+
return approximateSrcRowCol( theDestRow, theDestCol, theSrcRow, theSrcCol );
472475
}
473476
else
474477
{
475-
preciseSrcRowCol( theDestRow, theDestCol, theSrcRow, theSrcCol, ct );
478+
return preciseSrcRowCol( theDestRow, theDestCol, theSrcRow, theSrcCol, ct );
476479
}
477480
}
478481

479-
void QgsRasterProjector::preciseSrcRowCol( int theDestRow, int theDestCol, int *theSrcRow, int *theSrcCol, const QgsCoordinateTransform* ct )
482+
bool QgsRasterProjector::preciseSrcRowCol( int theDestRow, int theDestCol, int *theSrcRow, int *theSrcCol, const QgsCoordinateTransform* ct )
480483
{
481484
#ifdef QGISDEBUG
482485
QgsDebugMsgLevel( QString( "theDestRow = %1" ).arg( theDestRow ), 5 );
@@ -501,31 +504,31 @@ void QgsRasterProjector::preciseSrcRowCol( int theDestRow, int theDestCol, int *
501504
QgsDebugMsgLevel( QString( "x = %1 y = %2" ).arg( x ).arg( y ), 5 );
502505
#endif
503506

507+
if ( !mExtent.contains( QgsPoint( x, y ) ) )
508+
{
509+
return false;
510+
}
504511
// Get source row col
505512
*theSrcRow = ( int ) floor(( mSrcExtent.yMaximum() - y ) / mSrcYRes );
506513
*theSrcCol = ( int ) floor(( x - mSrcExtent.xMinimum() ) / mSrcXRes );
507514
#ifdef QGISDEBUG
508-
QgsDebugMsgLevel( QString( "mSrcExtent.yMaximum() = %1 mSrcYRes = %2" ).arg( mSrcExtent.yMaximum() ).arg( mSrcYRes ), 5 );
515+
QgsDebugMsgLevel( QString( "mSrcExtent.yMinimum() = %1 mSrcExtent.yMaximum() = %2 mSrcYRes = %3" ).arg( mSrcExtent.yMinimum() ).arg( mSrcExtent.yMaximum() ).arg( mSrcYRes ), 5 );
509516
QgsDebugMsgLevel( QString( "theSrcRow = %1 theSrcCol = %2" ).arg( *theSrcRow ).arg( *theSrcCol ), 5 );
510517
#endif
511518

512519
// With epsg 32661 (Polar Stereographic) it was happening that *theSrcCol == mSrcCols
513520
// For now silently correct limits to avoid crashes
514521
// TODO: review
515-
if ( *theSrcRow >= mSrcRows )
516-
*theSrcRow = mSrcRows - 1;
517-
if ( *theSrcRow < 0 )
518-
*theSrcRow = 0;
519-
if ( *theSrcCol >= mSrcCols )
520-
*theSrcCol = mSrcCols - 1;
521-
if ( *theSrcCol < 0 )
522-
*theSrcCol = 0;
522+
// should not happen
523+
if ( *theSrcRow >= mSrcRows ) return false;
524+
if ( *theSrcRow < 0 ) return false;
525+
if ( *theSrcCol >= mSrcCols ) return false;
526+
if ( *theSrcCol < 0 ) return false;
523527

524-
Q_ASSERT( *theSrcRow < mSrcRows );
525-
Q_ASSERT( *theSrcCol < mSrcCols );
528+
return true;
526529
}
527530

528-
void QgsRasterProjector::approximateSrcRowCol( int theDestRow, int theDestCol, int *theSrcRow, int *theSrcCol )
531+
bool QgsRasterProjector::approximateSrcRowCol( int theDestRow, int theDestCol, int *theSrcRow, int *theSrcCol )
529532
{
530533
int myMatrixRow = matrixRow( theDestRow );
531534
int myMatrixCol = matrixCol( theDestCol );
@@ -561,23 +564,25 @@ void QgsRasterProjector::approximateSrcRowCol( int theDestRow, int theDestCol, i
561564
double mySrcX = bx + ( tx - bx ) * yfrac;
562565
double mySrcY = by + ( ty - by ) * yfrac;
563566

567+
if ( !mExtent.contains( QgsPoint( mySrcX, mySrcY ) ) )
568+
{
569+
return false;
570+
}
571+
564572
// TODO: check again cell selection (coor is in the middle)
565573

566574
*theSrcRow = ( int ) floor(( mSrcExtent.yMaximum() - mySrcY ) / mSrcYRes );
567575
*theSrcCol = ( int ) floor(( mySrcX - mSrcExtent.xMinimum() ) / mSrcXRes );
568576

569577
// For now silently correct limits to avoid crashes
570578
// TODO: review
571-
if ( *theSrcRow >= mSrcRows )
572-
*theSrcRow = mSrcRows - 1;
573-
if ( *theSrcRow < 0 )
574-
*theSrcRow = 0;
575-
if ( *theSrcCol >= mSrcCols )
576-
*theSrcCol = mSrcCols - 1;
577-
if ( *theSrcCol < 0 )
578-
*theSrcCol = 0;
579-
Q_ASSERT( *theSrcRow < mSrcRows );
580-
Q_ASSERT( *theSrcCol < mSrcCols );
579+
// should not happen
580+
if ( *theSrcRow >= mSrcRows ) return false;
581+
if ( *theSrcRow < 0 ) return false;
582+
if ( *theSrcCol >= mSrcCols ) return false;
583+
if ( *theSrcCol < 0 ) return false;
584+
585+
return true;
581586
}
582587

583588
void QgsRasterProjector::insertRows( const QgsCoordinateTransform* ct )
@@ -816,7 +821,11 @@ QgsRasterBlock * QgsRasterProjector::block( int bandNo, QgsRectangle const & ex
816821
return outputBlock;
817822
}
818823

819-
// No data:
824+
// set output to no data, it should be fast
825+
outputBlock->setIsNoData();
826+
827+
// No data: because isNoData()/setIsNoData() is slow with respect to simple memcpy,
828+
// we use if only if necessary:
820829
// 1) no data value exists (numerical) -> memcpy, not necessary isNoData()/setIsNoData()
821830
// 2) no data value does not exist but it may contain no data (numerical no data bitmap)
822831
// -> must use isNoData()/setIsNoData()
@@ -825,27 +834,31 @@ QgsRasterBlock * QgsRasterProjector::block( int bandNo, QgsRectangle const & ex
825834

826835
// To copy no data values stored in bitmaps we have to use isNoData()/setIsNoData(),
827836
// we cannot fill output block with no data because we use memcpy for data, not setValue().
828-
bool doNoData = inputBlock->hasNoData() && !inputBlock->hasNoDataValue();
837+
bool doNoData = !QgsRasterBlock::typeIsNumeric( inputBlock->dataType() ) && inputBlock->hasNoData() && !inputBlock->hasNoDataValue();
829838

830839
const QgsCoordinateTransform* ct = 0;
831840
if ( !mApproximate )
832841
{
833842
ct = QgsCoordinateTransformCache::instance()->transform( mDestCRS.authid(), mSrcCRS.authid(), mDestDatumTransform, mSrcDatumTransform );
834843
}
835844

845+
outputBlock->setIsNoData();
846+
836847
int srcRow, srcCol;
837848
for ( int i = 0; i < height; ++i )
838849
{
839850
for ( int j = 0; j < width; ++j )
840851
{
841-
srcRowCol( i, j, &srcRow, &srcCol, ct );
852+
bool inside = srcRowCol( i, j, &srcRow, &srcCol, ct );
853+
if ( !inside ) continue; // we have everything set to no data
854+
842855
qgssize srcIndex = ( qgssize )srcRow * mSrcCols + srcCol;
843856
QgsDebugMsgLevel( QString( "row = %1 col = %2 srcRow = %3 srcCol = %4" ).arg( i ).arg( j ).arg( srcRow ).arg( srcCol ), 5 );
844857

845858
// isNoData() may be slow so we check doNoData first
846859
if ( doNoData && inputBlock->isNoData( srcRow, srcCol ) )
847860
{
848-
outputBlock->setIsNoData( srcRow, srcCol );
861+
outputBlock->setIsNoData( i, j );
849862
continue ;
850863
}
851864

src/core/raster/qgsrasterprojector.h

+7-4
Original file line numberDiff line numberDiff line change
@@ -113,8 +113,11 @@ class CORE_EXPORT QgsRasterProjector : public QgsRasterInterface
113113
void setSrcRows( int theRows ) { mSrcRows = theRows; mSrcXRes = mSrcExtent.height() / mSrcRows; }
114114
void setSrcCols( int theCols ) { mSrcCols = theCols; mSrcYRes = mSrcExtent.width() / mSrcCols; }
115115

116-
/** \brief Get source row and column indexes for current source extent and resolution */
117-
void srcRowCol( int theDestRow, int theDestCol, int *theSrcRow, int *theSrcCol, const QgsCoordinateTransform* ct );
116+
/** \brief Get source row and column indexes for current source extent and resolution
117+
If source pixel is outside source extent theSrcRow and theSrcCol are left unchanged.
118+
@return true if inside source
119+
*/
120+
bool srcRowCol( int theDestRow, int theDestCol, int *theSrcRow, int *theSrcCol, const QgsCoordinateTransform* ct );
118121

119122
int dstRows() const { return mDestRows; }
120123
int dstCols() const { return mDestCols; }
@@ -130,10 +133,10 @@ class CORE_EXPORT QgsRasterProjector : public QgsRasterInterface
130133
QgsPoint srcPoint( int theRow, int theCol );
131134

132135
/** \brief Get precise source row and column indexes for current source extent and resolution */
133-
inline void preciseSrcRowCol( int theDestRow, int theDestCol, int *theSrcRow, int *theSrcCol, const QgsCoordinateTransform* ct );
136+
inline bool preciseSrcRowCol( int theDestRow, int theDestCol, int *theSrcRow, int *theSrcCol, const QgsCoordinateTransform* ct );
134137

135138
/** \brief Get approximate source row and column indexes for current source extent and resolution */
136-
inline void approximateSrcRowCol( int theDestRow, int theDestCol, int *theSrcRow, int *theSrcCol );
139+
inline bool approximateSrcRowCol( int theDestRow, int theDestCol, int *theSrcRow, int *theSrcCol );
137140

138141
/** \brief Calculate matrix */
139142
void calc();

0 commit comments

Comments
 (0)