Skip to content

Commit

Permalink
Fixed #25874 -- Made GEOSGeometry read SRID from GeoJSON input.
Browse files Browse the repository at this point in the history
  • Loading branch information
sir-sigurd authored and timgraham committed Apr 1, 2017
1 parent ede4f6d commit 24023c6
Show file tree
Hide file tree
Showing 5 changed files with 51 additions and 4 deletions.
21 changes: 20 additions & 1 deletion django/contrib/gis/gdal/geometries.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
GDALException, OGRIndexError, SRSException,
)
from django.contrib.gis.gdal.geomtype import OGRGeomType
from django.contrib.gis.gdal.libgdal import GDAL_VERSION
from django.contrib.gis.gdal.prototypes import geom as capi, srs as srs_api
from django.contrib.gis.gdal.srs import CoordTransform, SpatialReference
from django.contrib.gis.geometry.regex import hex_regex, json_regex, wkt_regex
Expand Down Expand Up @@ -87,7 +88,7 @@ def __init__(self, geom_input, srs=None):
else:
g = capi.from_wkt(byref(c_char_p(wkt_m.group('wkt').encode())), None, byref(c_void_p()))
elif json_m:
g = capi.from_json(geom_input.encode())
g = self._from_json(geom_input.encode())
else:
# Seeing if the input is a valid short-hand string
# (e.g., 'Point', 'POLYGON').
Expand Down Expand Up @@ -139,13 +140,31 @@ def __setstate__(self, state):
def _from_wkb(cls, geom_input):
return capi.from_wkb(bytes(geom_input), None, byref(c_void_p()), len(geom_input))

@staticmethod
def _from_json(geom_input):
ptr = capi.from_json(geom_input)
if GDAL_VERSION < (2, 0):
has_srs = True
try:
capi.get_geom_srs(ptr)
except SRSException:
has_srs = False
if not has_srs:
srs = SpatialReference(4326)
capi.assign_srs(ptr, srs.ptr)
return ptr

@classmethod
def from_bbox(cls, bbox):
"Construct a Polygon from a bounding box (4-tuple)."
x0, y0, x1, y1 = bbox
return OGRGeometry('POLYGON((%s %s, %s %s, %s %s, %s %s, %s %s))' % (
x0, y0, x0, y1, x1, y1, x1, y0, x0, y0))

@staticmethod
def from_json(geom_input):
return OGRGeometry(OGRGeometry._from_json(force_bytes(geom_input)))

@classmethod
def from_gml(cls, gml_string):
return cls(capi.from_gml(force_bytes(gml_string)))
Expand Down
4 changes: 3 additions & 1 deletion django/contrib/gis/geos/geometry.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,9 @@ def __init__(self, geo_input, srid=None):
g = wkb_r().read(force_bytes(geo_input))
elif json_regex.match(geo_input):
# Handling GeoJSON input.
g = wkb_r().read(gdal.OGRGeometry(geo_input).wkb)
ogr = gdal.OGRGeometry.from_json(geo_input)
g = ogr._geos_ptr()
input_srid = ogr.srid
else:
raise ValueError('String input unrecognized as WKT EWKT, and HEXEWKB.')
elif isinstance(geo_input, GEOM_PTR):
Expand Down
11 changes: 10 additions & 1 deletion docs/ref/contrib/gis/geos.txt
Original file line number Diff line number Diff line change
Expand Up @@ -224,9 +224,18 @@ Format Input Type
WKT / EWKT ``str``
HEX / HEXEWKB ``str``
WKB / EWKB ``buffer``
GeoJSON ``str``
GeoJSON_ ``str``
======================= ==========

For the GeoJSON format, the SRID is set based on the ``crs`` member. If ``crs``
isn't provided, the SRID defaults to 4326.

.. versionchanged:: 2.0

In older versions, SRID isn't set for geometries initialized from GeoJSON.

.. _GeoJSON: https://tools.ietf.org/html/rfc7946

.. classmethod:: GEOSGeometry.from_gml(gml_string)

.. versionadded:: 1.11
Expand Down
3 changes: 3 additions & 0 deletions docs/releases/2.0.txt
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,9 @@ Minor features
* Added the :class:`~django.contrib.gis.db.models.functions.LineLocatePoint`
function, supported on PostGIS and SpatiaLite.

* Any :class:`~django.contrib.gis.geos.GEOSGeometry` imported from GeoJSON now
has its SRID set.

:mod:`django.contrib.messages`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Expand Down
16 changes: 15 additions & 1 deletion tests/gis_tests/geos_tests/test_geos.py
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,21 @@ def test_json(self):
# Loading jsons to prevent decimal differences
self.assertEqual(json.loads(g.json), json.loads(geom.json))
self.assertEqual(json.loads(g.json), json.loads(geom.geojson))
self.assertEqual(GEOSGeometry(g.wkt), GEOSGeometry(geom.json))
self.assertEqual(GEOSGeometry(g.wkt, 4326), GEOSGeometry(geom.json))

@skipUnless(HAS_GDAL, "GDAL is required.")
def test_json_srid(self):
geojson_data = {
"type": "Point",
"coordinates": [2, 49],
"crs": {
"type": "name",
"properties": {
"name": "urn:ogc:def:crs:EPSG::4322"
}
}
}
self.assertEqual(GEOSGeometry(json.dumps(geojson_data)), Point(2, 49, srid=4322))

def test_fromfile(self):
"Testing the fromfile() factory."
Expand Down

0 comments on commit 24023c6

Please sign in to comment.