#34302 closed Bug (fixed)
SpatialReference.srid incorrectly assumes first AUTHORITY value to be projection SRID
Reported by: | Stefan Brand | Owned by: | Stefan Brand |
---|---|---|---|
Component: | GIS | Version: | dev |
Severity: | Normal | Keywords: | |
Cc: | Triage Stage: | Ready for checkin | |
Has patch: | yes | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
Problem
When reading data into our PostGIS database, we noticed strange locations for our geometries. The data was supposed to be EPSG:31287
, but investigation showed that Django was assuming EPSG:6312
. This led to wrong EWKTs when saving geometries to PostGIS.
It turns out that the dataset did not have any SRID stored for the projection, just for the DATUM. Django assumed the DATUM's AUTHORITY value to be the SRID of the dataset's projection. This contradicts the documentation for SpatialReference.srid
:
Returns the SRID of top-level authority, or None if undefined.
Since the layer's srid
cannot be set to a different value, the only workaround is to set the srid
for each OGRGeometry
individually.
Current Result
`SpatialReference.srid` calls int(self.attr_value("AUTHORITY", 1))
, which returns 6312
(wrong SRID).
Expected Result
SpatialReference.srid
should call auth_code(target=None)
to get the top-level SRID.
Django should not assume a wrong SRID if the projection does not have a SRID. For example, QGIS reads the whole spatial reference information, correctly projects the data, but displays "Unknown CRS" because it does not assume any AUTHORITY value to be the dataset SRID.
Steps to reproduce
from django.contrib.gis.gdal import SpatialReference WKT = """PROJCRS["MGI / Austria Lambert", BASEGEOGCRS["MGI", DATUM["Militar-Geographische Institut", ELLIPSOID["Bessel 1841",6377397.155,299.1528128, LENGTHUNIT["metre",1]], ID["EPSG",6312]], PRIMEM["Greenwich",0, ANGLEUNIT["Degree",0.0174532925199433]]], CONVERSION["unnamed", METHOD["Lambert Conic Conformal (2SP)", ID["EPSG",9802]], PARAMETER["Latitude of false origin",47.5, ANGLEUNIT["Degree",0.0174532925199433], ID["EPSG",8821]], PARAMETER["Longitude of false origin",13.3333333333333, ANGLEUNIT["Degree",0.0174532925199433], ID["EPSG",8822]], PARAMETER["Latitude of 1st standard parallel",49, ANGLEUNIT["Degree",0.0174532925199433], ID["EPSG",8823]], PARAMETER["Latitude of 2nd standard parallel",46, ANGLEUNIT["Degree",0.0174532925199433], ID["EPSG",8824]], PARAMETER["Easting at false origin",400000, LENGTHUNIT["metre",1], ID["EPSG",8826]], PARAMETER["Northing at false origin",400000, LENGTHUNIT["metre",1], ID["EPSG",8827]]], CS[Cartesian,2], AXIS["easting",east, ORDER[1], LENGTHUNIT["metre",1, ID["EPSG",9001]]], AXIS["northing",north, ORDER[2], LENGTHUNIT["metre",1, ID["EPSG",9001]]]]""" geodjango_srs = SpatialReference(WKT) geodjango_srs.validate() # raises for invalid SRS print(geodjango_srs.attr_value("AUTHORITY", 1)) print(geodjango_srs.auth_code(target=None))
6312
None
Change History (8)
comment:1 by , 22 months ago
Triage Stage: | Unreviewed → Accepted |
---|---|
Version: | 4.1 → dev |
comment:2 by , 22 months ago
Thanks for asking, yes, I would like that. I hope I can tackle it this week. If I don't find time, someone else feel free to create a PR.
comment:3 by , 22 months ago
Owner: | changed from | to
---|---|
Status: | new → assigned |
While applying the change, I got a failing test. It turns out that GeoDjango has a different behaviour than the GDAL Python bindings.
Compare:
from django.contrib.gis.gdal import SpatialReference from osgeo import ogr WEB_MERCATOR = """PROJCS["WGS 84 / Pseudo-Mercator", GEOGCS["WGS 84", DATUM["WGS_1984", SPHEROID["WGS 84",6378137,298.257223563, AUTHORITY["EPSG","7030"]], AUTHORITY["EPSG","6326"]], PRIMEM["Greenwich",0, AUTHORITY["EPSG","8901"]], UNIT["degree",0.0174532925199433, AUTHORITY["EPSG","9122"]], AUTHORITY["EPSG","4326"]], PROJECTION["Mercator_1SP"], PARAMETER["central_meridian",0], PARAMETER["scale_factor",1], PARAMETER["false_easting",0], PARAMETER["false_northing",0], UNIT["metre",1, AUTHORITY["EPSG","9001"]], AXIS["Easting",EAST], AXIS["Northing",NORTH], EXTENSION["PROJ4","+proj=merc +a=6378137 +b=6378137 +lat_ts=0 +lon_0=0 +x_0=0 +y_0=0 +k=1 +units=m +nadgrids=@null +wktext +no_defs"], AUTHORITY["EPSG","3857"]]""" geodjango_srs = SpatialReference(WEB_MERCATOR) geodjango_srs.validate() # raises for invalid SRS print(geodjango_srs.attr_value("AUTHORITY", 1)) print(geodjango_srs.auth_code(target=None)) ogr_srs = ogr.osr.SpatialReference(WEB_MERCATOR) if ogr_srs.Validate(): raise print(ogr_srs.GetAttrValue("AUTHORITY", 1)) print(ogr_srs.GetAuthorityCode(None))
3857
None
3857
3857
The reason is that `django/utils/force_bytes` turns None
into the byte string b'None'
. Since ctypes.c_char_p
also accepts None
, we can bypass force_bytes
if target is None
.
I will do some more testing and push a patch tomorrow.
Thanks for the report. Would you like to prepare a pull request for Django?