Amsterdam / django-gisserver

Django speaking WFS 2.0 to expose geo data
Mozilla Public License 2.0
39 stars 10 forks source link

Coordinate axis order in northing/easting (Y/X) in WFS/GML #16

Open travenin opened 1 year ago

travenin commented 1 year ago

My project for City of Helsinki uses coordinate reference system EPSG:3879. We have a problem with latitude and longitude axis order in WFS GML output when using django-gisserver version 1.2.4.

WFS 2.0.0 (with GML 3.2) should respects the axis order defined by the EPSG definition (unlike WFS 1.0.0 which is always easting/northing or (X,Y)). EPSG:3879 defines coordinate axis order as northing/easting (Y,X).

For query <server url>/wfs/?SERVICE=WFS&VERSION=2.0.0&REQUEST=GetFeature&TYPENAMES=signpost&OUTPUTFORMAT=application/gml+xml&srsName=urn:ogc:def:crs:EPSG::3879 we are expecting:

*snip*
<app:location>
  <gml:Point srsName="urn:ogc:def:crs:EPSG::3879" gml:id="signpost.1">
    <gml:pos srsDimension="3">6673364.2700978 25494172.7053077 0</gml:pos>
  </gml:Point>
</app:location>
*snip*

where 6673364.2700978 is latitude (Y) and 25494172.7053077 is longitude (X).

However, the actual result has invert latitude and longitude:

*snip*
<app:location>
  <gml:Point srsName="urn:ogc:def:crs:EPSG::3879" gml:id="signpost.1">
    <gml:pos srsDimension="3">25494172.7053077 6673364.2700978 0</gml:pos>
  </gml:Point>
</app:location>
*snip*

Do I have something wrong in my configuration? Or is this a missing feature or bug in django-gisserver?

lbam commented 1 year ago

Looks like missing functionality. We just render the coordinates in the order django.contrib.gis.geos.Point.coords has them.

vdboor commented 1 year ago

Another factor here might be the used Django version and GDAL version. As of GDAL 3, the axis ordering was changed. Django 3.1 and later have support for that.

In gisserver/geometries.py you'll find some comments regarding this issue. What you might be able to do, is pass a custom backend to the constructed CRS object. For example:

from django.contrib.gis.gdal import AxisOrder, SpatialReference
from gisserver.geometries import CRS

# Define the actual GDAL backend yourself, so the CRS object will use that:
gk25fin = CRS("EPSG:3879", backend=SpatialReference(3879, srs_type="epsg", axis_order=AxisOrder.AUTHORITY))

# Pass the CRS object to the feature type:
feature_types = [
    FeatureType(
        ...,
        crs=gk25fin,
        other_crs=[..., gk25fin],  # or this one.
    )
]

The rest of the code really just reads what GDAL will provide (like @lbam mentioned).

For some background info, see:

Hope this helps!

and bye the way, we love that you guys started using this project too! (and for that matter completely extended it as well, exactly as the design intended).