Skip to content
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

GeoHEIF: Fixed respecting CRS axis order (e.g., for EPSG:4326) #11384

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

jerstlouis
Copy link
Contributor

@jerstlouis jerstlouis commented Nov 28, 2024

What does this PR do?

Fixes an axis-ordering bug in GeoHEIF driver, in particular for EPSG:4326 CRS.

What are related issues/pull requests?

https://gitlab.ogc.org/ogc/T20-GIMI/-/issues/59

Tasklist

  • ADD YOUR TASKS HERE
  • Make sure code is correctly formatted (cf pre-commit configuration)
  • Add test case(s)
  • [N/A] Add documentation
  • [N/A] Updated Python API documentation (swig/include/python/docs/)
  • Review
  • Adjust for comments
  • All CI builds and checks have passed

Environment

N/A

@@ -857,6 +865,10 @@ CPLErr GDALHEIFDataset::GetGeoTransform(double *padfTransform)
/************************************************************************/
const OGRSpatialReference *GDALHEIFDataset::GetSpatialRef() const
{
// REVIEW: This function being declared this-const should mean
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand that comment. "const" means that it does not change the observable state of the object (that is the GDALHEIFDataset instance). What observable side effects does GetSpatialRef() cause ?

Copy link
Contributor Author

@jerstlouis jerstlouis Nov 28, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure how the "observable state of the object" is defined in C++ and whether this "set things up the first time" is an OK practice (assuming it's done in a thread-safe manner).

The main issue is that this function might not be thread-safe, since if it's called for the first time by two different threads, they both might be trying to modify the geoHEIF member of the instance at the same time.

But as it turns out and was the source of the problem I chased for the last few hours, there was a very observable side-effect causing problems. Calling GDALGetGeoTransform() before and after calling GetSpatialRef() yielded a completely different result since geoHEIF.m_oSRS was null before and non-null after.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The main issue is that this function might not be thread-safe,

that's by design. No GDAL objects are thread-safe unless otherwise stated: cf https://gdal.org/en/stable/user/multithreading.html#gdal-api-re-entrant-but-generally-not-thread-safe

Calling GDALGetGeoTransform() before and after calling GetSpatialRef() yielded a completely different result since geoHEIF.m_oSRS was null before and non-null after.

That's a different thing, an implementation bug. I believe the comment in GetGeoTransform() is sufficient, and the one in GetSpatialRef() can be removed

Actually looking further at that code, I believe that GDALHEIFDataset::GetGeoTransform() should not call GDALHEIFDataset::GetSpatialRef() itself. But rather GeoHEIF::GetGeoTransform() should make sure that its m_oSRS member is properly initialized if it needs it to access it, since that's the one that needs the SRS. Perhaps the right thing to do is to set m_oSRS as mutable in the GeoHEIF class itself, and make GeoHEIF::GetGeoTransform() call GeoHEIF::GetSpatialRef()

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps the right thing to do is to set m_oSRS as mutable in the GeoHEIF class itself, and make GeoHEIF::GetGeoTransform() call GeoHEIF::GetSpatialRef()

yes we definitely want to do that since the GeoHEIF class is also used by the AVIF driver, and thus we don't want to do the same hack in both drivers.

Copy link
Contributor Author

@jerstlouis jerstlouis Nov 28, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't it be simpler / preferable to automatically set up the SRS when initializing the dataset, before either of these methods can get called?

No GDAL objects are thread-safe unless otherwise stated

Even after reading this, I would have been very surprised that a method declared const behaves this way.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't it be simpler / preferable to automatically set up the SRS when initializing the dataset, before either of these methods can get called?

Actually I do see my suggestion of calling GeoHEIF::GetSpatialRef() from GeoHEIF::GetGeoTransform() woudn't work since the geoHEIF.extractSRS() must be called with the relevant metadata first. So, I'm backing away my latest suggestion. I believe you're current fix is OK. (and the AVIF driver doesn't need a fix since it has a method processProperties() that feeds all needed metadata to the GeoHEIF instance)

@rouault
Copy link
Member

rouault commented Nov 28, 2024

This would deserve a new test case in autotest/gdrivers/heif.py reading a file with EPSG:4326 cheking that:
assert srs.GetDataAxisToSRSAxisMapping() == [2, 1]
and that the ds.GetGeoTransform() is such that its coefficient at index 0 is a longitude
to use the "GIS friendly order" used by all other GDAL raster drivers

@rouault
Copy link
Member

rouault commented Nov 28, 2024

CC @bradh

Copy link
Member

@rouault rouault left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@coveralls
Copy link
Collaborator

Coverage Status

coverage: 74.173%. remained the same
when pulling 7186330 on jerstlouis:master
into 4aee058 on OSGeo:master.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants