-
-
Notifications
You must be signed in to change notification settings - Fork 261
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
CRS Support for OGC API Feature pygeoapi Provider #1174
Conversation
…ibutes to issue #1128 * #1128 provide conformance class for OAPIF Part 2 in /conformance page * #1128 bitten by flake8... * #1128 configurability CRS Feature Providers with syntax, defaults and tests * #1128 configurability CRS Feature Providers refine for default values * #1128 display supported CRSs in HTML Collection template * #1128 config, mmetadata and tests for storageCRS and storageCrsCoordinateEpoch * #1128 WIP for bbox-crs parameter support * #1128 utility function and tests for default/mandatory supprted CRS list * #1128 default supported CRS adaptation to OAPIF Part 2 standard * #1128 grr flake8 whitespace * #1128 start adding full API tests OGR for bbox-crs and crs parms * #1128 fix flake8 * #1128 fix flake8 - install GDAL in workflow main for OGR tests * #1128 fix flake8 - install GDAL in workflow main for OGR tests - need pip package? * #1128 fix flake8 - install GDAL in workflow main for OGR tests - using libgdal-dev gdal-bin * #1128 fix SensorThings test for main.yml Workflow * #1128 fix SensorThings test for main.yml Workflow nr 2 * #1128 make all OGR tests working again * #1128 make all OGR tests working again - flake8 * #1128 make all OGR tests working again - GeoSolutions WFS bbox * #1128 #1155 add documentation for OGC OAPIF Part 2 CRS CRS BBOX support * #1128 #1155 refine documentation for OGC OAPIF Part 2 CRS CRS BBOX support * #1128 #1155 refine documentation to align with #1149 * #1128 #1155 rework from review OAS and pygeoapi config schema * #1128 #1155 minor: compile Re for CRS URI only once as global var
* feat(ogcapi_features_crs): start implementing crs support from ogcapi features part2 * Pass input and output CRSs WKT instead of crs transformation object * fix longs lines and blank lines * fix typo * fix import for type annotation not supported by python version * fix variable visibility in local scope * fix tabs/spaces indentations * Add support for the crs parameter to OGRProvider * make flake8 happy * Make crs transformation mechanism more consistent between PostgreSQL and OGR providers * test(util): add two test functions in util.py New functions: test_get_crs_from_uri and test_get_transform_from_crs * fix too long lines... * Update get_crs_from_uri and corresponding test function * fix(get_crs_from_uri): make the error more explicit in if wrong crs uri format * flake8 again... * Keep support for source_srs/target_srs in config for OGRProvider * revert changes made to pygeoapi-config-0.x.yml, overlap with PR 1155 * test: add test data and update test config file * Extract 'crs' and 'storage_crs' and provider level instead of collection level * feat(crs): new decorator to support coordinates transformation of feature collections * feat(crs): 'crs' query parameter for CSVProvider * test(crs): add tests for 'crs' query parameter * test: update number of collections in test_describe_collections * test: update number of collections in test_filter_dict_by_key_value * fix(crs_transform): change the crs transformation decorator Change the logic of the decorator so that it works for both functions that return FeatureCollections and for functions tha return single Features. * test: add tests for get_collection_item end-point with 'crs' parameter * fix(test_get_collection_item_crs): id as path parameter, not query parameter * test: unpack coordinates to create point geometry * feat(crs): add suuport for crs query parameter for all providers of type 'feature' * docs(crs): add documentation to illustrate use of 'crs' query parameters * docs(crs): more data access examples * fix typo and add new line * refactor: specify None as default value for crs_transform_out parameter in _sqlalchemy_to_feature method * changes for PR 1149, test_api and style formatting * CRS84 as default crs also for test_get_collection_items_crs * test(crs): test coordinates transformation implementation of PostgreSQLProvider * test(crs): move tests to test_postgresql_provider * fix test function calls * change test to ensure returned features are the same * add json format to request object * test(crs): test coordinates transformation implementation of OGRProvider * refactor(crs): make more compact get_collection_item and get_collection_items Define two new static methods in API class, to create crs_transform_wkt and setting content-crs header. These methods can be re-used in both get_collection_item and get_collection_items methods and removes code duplication. --------- Co-authored-by: Just van den Broecke <[email protected]>
The CI is failing from what I think is a Proj/GDAL version issue. The test that fails is the OGR Provider which uses internal GDAL calls for the Transform (i.s.o. using Shapely/pyproj as in api.py) when a CrsTransform is passed on get() or query(). On my local system this unit test succeeds with versions:
The CI uses Ubuntu 20.04 without UbuntuGIS so may have different versions of these. |
Yes, reading about it, it definitely sounds like a GDAL/PROJ version issue. GDAL seems to throw an error when calling |
Probably best is to upgrade
But interesting, 2 errors in the WFS tests with the GeoSolutions WFS:
|
There is some confusion about axis-ordering in the GeoJSON response with the crs parameter. https://demo.ldproxy.net/daraa/collections/AgriculturePnt/items?f=json&crs=https://www.opengis.net/def/crs/EPSG/0/4326 (lat, lon) , would be lat, lon for e.g. 4258 (ETRS89 INSPIRE) Think pygeoapi needs to follow CRS Axis ordering in GeoJSON responses. Looks like all CRS is enforced xy order (using pyproj+Proj): https://apitestbed.geonovum.nl/pygeoapi/collections/AddressesNL/items?crs=https://www.opengis.net/def/crs/EPSG/0/4258&f=json (lon, lat) should be reversed IMO. https://apitestbed.geonovum.nl/pygeoapi/collections/AddressesNL/items?crs=https://www.opengis.net/def/crs/EPSG/0/4326&f=json (lon, lat) should be reversed IMO. For |
I agree with @justb4 , that the axis ordering in GeoJSON responses should follow the definition of the CRS, and not forced to lon/lat for geographic coordinate systems. The section Coordinate reference system information independent of the feature encoding introduces the As for a solution, pyproj can perfectly handle the axis ordering for different CRSs with the # Input CRS with lat/lon axis order
crs_in = pyproj.CRS.from_espg(4326)
# Output CRS with lon/lat axis order
crs_out = pyproj.CRS.from_authority("OGC", "CRS84")
# Create a pyproj.Transformer instance which forces lon/lat ordering
transformer_1 = pyproj.Transformer.from_crs(crs_in, crs_out, always_xy=True)
# Create a pyproj.Transformer instance which takes care of changing axis order if needed
transformer_2 = pyproj.Transformer.from_crs(crs_in, crs_out, always_xy=False)
>>> transformer_1.transform(5.0, 6.0)
(5.0, 6.0)
>>> transformer_2.transform(5.0, 6.0)
(6.0, 5.0) On the other hand, when looking at the implementation of the If we decide to follow @justb4 's convention, setting As for data stored in PostGIS, it looks like the |
Something else that came to my mind when reading the Part 2 of the standard OGC API - Features, is the implementation of pygeoapi when serving data in JSON for Linking Data format (JSON-LD). Currently, the |
@MTachon wrote:
Yes, this is my current plan for this PR/branch, and get all tests working, maybe add a few more. Like with BBOX-CRS I have several to check for CRS-compliant Axis ordering. |
Somehow the CRS Axis ordering when using OGR Transforms is not honoured it looks like. Maybe has to do as the it projection is loaded from WKT as passed to |
I have added some changes regarding JSON-LD and schema.org markup in branch https://github.com/MTachon/pygeoapi/tree/crs-features-ogc |
…ider - Axis ordering not honoured...
I do not think that it has something to do with the projection being loaded from WKT, but more with |
Have you seen the latest changes in Only 'gotcha' now may be |
So if I understand correctly, importing a CRS (into a |
Yes, that looks like it: importing from WKT gives either wrong (Axis ordering) result in Docker deploy or failure in
It follows from the unit tests. Using OGR with GPKG with several projections. You can see the testfile/URL here: My personal opinion is that WKT loading seems brittle among pyproj, Proj, GDAL. Users will run different versions. Will be hard to grasp this. That is why I suggested to to pass a |
With commit fd16159 All OGC CITE tests for Part 1 and Part 2 are now succeeding! |
@justb4 That's great, nice work!! :) |
@@ -130,6 +131,7 @@ def _load(self, skip_geometry=None, properties=[], select_properties=[]): | |||
if k in set(self.properties) | set(select_properties)} # noqa | |||
return data | |||
|
|||
@crs_transform |
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.
Does this decorate mean an extra hop for all provider query
and get
functions?
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 decorator iterates through the features
returned by the providers' query
and get
functions, transform the geometries' coordinates if needed (meaning that crs_transform_spec != None
in query()
and get()
calls in api.py
) before the Feature
/FeatureCollection
is assigned to the content
variable in api.py
. The decorator approach was used to avoid code duplication (fewer lines of code if the transformation logic is taken out of the providers' implementation), for simplicity and for supporting coordinates transformation for all providers. PostgreSQLProvider
has its own implementation and does not use the @crs_transform
decorator. The implementation for the PostgreSQL
provider is more optimized as it does not re-iterate through the returned features
, and we may want to optimize the coordinates transformation implementation of other providers later, especially if these providers have native support for coordinates transformation. In practice, re-iterating through some thousands of features would not result in much overhead.
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.
Yes, agree. Also the OGRProvider does its own transforms. Our plan is to first have #1174 merged, having a stable version, CITE and INSPIRE compliant. Then do refactoring in separate PRs:
- move all CRS-dedicated/related functionality and constants spread over
util.py
andapi.py
into a new modulepygeoapi/crs.py
- enhance
CrsTransformSpec
with direct-to-call transform functions aspartials
(e.g. for Shapely and GeoJSON dicts) that Providers without native CRS-support can call in their Feature-Collection loop - upgrade Providers to using the CrsTransformSpec-based transforms, removing the Decorator, maybe even completely
Thanks @GeoSander ! Yes, will be quite a merge from master, but seen these changes from #1152 before, IntelliJ will be my friend. I'll let know. |
FYI @justb4: I did a working tree diff with the current master this morning and did not find anything wrong or missing (during the merge), so in that sense it looks good to me 👍 |
@GeoSander that is good to hear! Hopefully @tomkralidis finds some time to look at the last resolutions from the review. |
CI failures are unrelated (https://lists.osgeo.org/pipermail/mapserver-users/2023-April/083094.html). |
Overview
See PRs #1155 and #1149.
This PR combines these two as together they provide support
for the complete standard OGC API - Features - Part 2: Coordinate Reference Systems by Reference.
Related Issue / Discussion
Issue #1128 - See PRs 1155 and #1149.
Additional Information
See related PRs above.
Contributions and Licensing
(as per https://github.com/geopython/pygeoapi/blob/master/CONTRIBUTING.md#contributions-and-licensing)