-
-
Notifications
You must be signed in to change notification settings - Fork 2.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add NoData support to QgsVirtualRasterProvider #50590
Conversation
@kikitte thank you! Can you add a unit test covering this too? |
@nyalldawson Yes, and the identify method is add to the virtualrasterprovider too. |
The QGIS project highly values your contribution and would love to see this work merged! Unfortunately this PR has not had any activity in the last 14 days and is being automatically marked as "stale". If you think this pull request should be merged, please check
|
Hi @nyalldawson, do you have any idea about this PR? This PR add nodata related code to QgsVirtualRasterProvider and fix the identification logic, that is the value returned by QgsRasterDataProvider::identify should be compared with the QgsVirtualRasterProvider's nodata vlaue. I am willing to hear your suggestions. |
The QGIS project highly values your contribution and would love to see this work merged! Unfortunately this PR has not had any activity in the last 14 days and is being automatically marked as "stale". If you think this pull request should be merged, please check
|
While we hate to see this happen, this PR has been automatically closed because it has not had any activity in the last 21 days. If this pull request should be reconsidered, please follow the guidelines in the previous comment and reopen this pull request. Or, if you have any further questions, just ask! We love to help, and if there's anything the QGIS project can do to help push this PR forward please let us know how we can assist. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Except for less autos
this looks good to me, excellent job!
Can you please fix the spelling errors reported from the CI tests ? |
@kikitte you need to replace QgsRaster::IdentifyFormat with Qgis::RasterIdentifyFormat from <qgis.h> |
Head branch was pushed to by a user without write access
Oh, I am forgot to sync the branch to the newest, now it should be fixed. |
|
||
// Checking the value returned by QgsRasterDataProvider::identify | ||
// If it is NoData value, replace it with QVariant() | ||
QMap<int, QVariant> bandValues = result.results(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, I missed this: did you check if is there a possibility that bandValues
is empty or it does not have an item with index 1
?
If the answer is yes you'll need to check it before calling bandValues[1]
or it will crash.
The same goes for mSrcNoDataValue[0]
(just check if mSrcNoDataValue
can be empty).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The QgsVirtualRasterProvider supports IdentifyValue only, and I think any other code that want to call QgsVirtualRasterProvider::identify should check the provider's capability before calling and that code should pass Qgis::RasterIdentifyFormat::Value as the format.
QGIS/src/providers/virtualraster/qgsvirtualrasterprovider.cpp
Lines 327 to 331 in 7d81fdd
int QgsVirtualRasterProvider::capabilities() const | |
{ | |
const int capability = QgsRasterDataProvider::Identify | |
| QgsRasterDataProvider::IdentifyValue | |
| QgsRasterDataProvider::Size |
When we look into the implementation of QgsRasterDataProvider::identify, the only case that bandValues
will be empty is the format not equals to Qgis::RasterIdentifyFormat::Value(line 276). However, that should not be happend acoording to the above explaination. Note that the band number of QgsVirtualRasterProvider is always 1, so the execution of QgsRasterDataProvider::identify ensures that bandValues
has only one item. .
QGIS/src/core/raster/qgsrasterdataprovider.cpp
Lines 269 to 333 in 7d81fdd
QgsRasterIdentifyResult QgsRasterDataProvider::identify( const QgsPointXY &point, Qgis::RasterIdentifyFormat format, const QgsRectangle &boundingBox, int width, int height, int /*dpi*/ ) | |
{ | |
QGIS_PROTECT_QOBJECT_THREAD_ACCESS | |
QgsDebugMsgLevel( QStringLiteral( "Entered" ), 4 ); | |
QMap<int, QVariant> results; | |
if ( format != Qgis::RasterIdentifyFormat::Value || !( capabilities() & IdentifyValue ) ) | |
{ | |
QgsDebugMsg( QStringLiteral( "Format not supported" ) ); | |
return QgsRasterIdentifyResult( ERR( tr( "Format not supported" ) ) ); | |
} | |
if ( !extent().contains( point ) ) | |
{ | |
// Outside the raster | |
for ( int bandNo = 1; bandNo <= bandCount(); bandNo++ ) | |
{ | |
results.insert( bandNo, QVariant() ); | |
} | |
return QgsRasterIdentifyResult( Qgis::RasterIdentifyFormat::Value, results ); | |
} | |
QgsRectangle finalExtent = boundingBox; | |
if ( finalExtent.isEmpty() ) | |
finalExtent = extent(); | |
if ( width == 0 ) | |
{ | |
width = capabilities() & Size ? xSize() : 1000; | |
} | |
if ( height == 0 ) | |
{ | |
height = capabilities() & Size ? ySize() : 1000; | |
} | |
// Calculate the row / column where the point falls | |
const double xres = ( finalExtent.width() ) / width; | |
const double yres = ( finalExtent.height() ) / height; | |
const int col = static_cast< int >( std::floor( ( point.x() - finalExtent.xMinimum() ) / xres ) ); | |
const int row = static_cast< int >( std::floor( ( finalExtent.yMaximum() - point.y() ) / yres ) ); | |
const double xMin = finalExtent.xMinimum() + col * xres; | |
const double xMax = xMin + xres; | |
const double yMax = finalExtent.yMaximum() - row * yres; | |
const double yMin = yMax - yres; | |
const QgsRectangle pixelExtent( xMin, yMin, xMax, yMax ); | |
for ( int bandNumber = 1; bandNumber <= bandCount(); bandNumber++ ) | |
{ | |
std::unique_ptr< QgsRasterBlock > bandBlock( block( bandNumber, pixelExtent, 1, 1 ) ); | |
if ( bandBlock ) | |
{ | |
const double value = bandBlock->value( 0 ); | |
results.insert( bandNumber, value ); | |
} | |
else | |
{ | |
results.insert( bandNumber, QVariant() ); | |
} | |
} | |
return QgsRasterIdentifyResult( Qgis::RasterIdentifyFormat::Value, results ); | |
} |
Since QgsVirtualRasterProvider has only one band, mSrcNoDataValue
is initialized with one value in the constructor, it can't be empty.
May be we should check if the bandValues
is empty, and no need to check mSrcNoDataValue.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This patch has committed.
The QGIS project highly values your contribution and would love to see this work merged! Unfortunately this PR has not had any activity in the last 14 days and is being automatically marked as "stale". If you think this pull request should be merged, please check
|
While we hate to see this happen, this PR has been automatically closed because it has not had any activity in the last 21 days. If this pull request should be reconsidered, please follow the guidelines in the previous comment and reopen this pull request. Or, if you have any further questions, just ask! We love to help, and if there's anything the QGIS project can do to help push this PR forward please let us know how we can assist. |
This PR adds nodata support to the QgsVirtualRasterProvider, Fixes #46813.
During this work, another problem relevant to QgsVirtualRasterProvider is identification, that is the identification result of
virtual raster layer always shows its real value instead of 'no data' string if value equals the nodata value. Currently QgsVirtualRasterProvider inherits from QgsRasterDataProvider, and QgsRasterDataProvider::identify just check the block reading result without checking the value.
QGIS/src/core/raster/qgsrasterdataprovider.cpp
Lines 318 to 329 in 1f22e06
QVariant()
should be inserted, the logic from QgsGdalProvider may be more reasonable.QGIS/src/core/providers/gdal/qgsgdalprovider.cpp
Lines 1365 to 1390 in 1f22e06
So, I think there are two ways to fix this problem, the first way is override the identify method in QgsVirtualRasterProvider with nodata value checking, the second way is modify the logic of the QgsRasterDataProvider::identify just like QgsGdalProvider does. I prefer the second way because it is in the right direction, but the first way is error-prone. Hopes to hear your thoughts!