Skip to content

Commit 87302ac

Browse files
committed
Fixed #12312 -- Set the coordinate dimension on each component of geometry collections after transform (refines GDAL bug workaround introduced in r11628). Thanks, yourcelf for bug report.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@12878 bcc190cf-cafb-0310-a4f2-bffc1f526a37
1 parent 7d25682 commit 87302ac

File tree

2 files changed

+52
-16
lines changed

2 files changed

+52
-16
lines changed

django/contrib/gis/gdal/geometries.py

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,11 +48,11 @@
4848
from django.contrib.gis.gdal.envelope import Envelope, OGREnvelope
4949
from django.contrib.gis.gdal.error import OGRException, OGRIndexError, SRSException
5050
from django.contrib.gis.gdal.geomtype import OGRGeomType
51+
from django.contrib.gis.gdal.libgdal import GEOJSON, GDAL_VERSION
5152
from django.contrib.gis.gdal.srs import SpatialReference, CoordTransform
5253

5354
# Getting the ctypes prototype functions that interface w/the GDAL C library.
5455
from django.contrib.gis.gdal.prototypes import geom as capi, srs as srs_api
55-
GEOJSON = capi.GEOJSON
5656

5757
# For recognizing geometry input.
5858
from django.contrib.gis.geometry.regex import hex_regex, wkt_regex, json_regex
@@ -400,7 +400,8 @@ def transform(self, coord_trans, clone=False):
400400
# afterwards. This is done because of GDAL bug (in versions prior
401401
# to 1.7) that turns geometries 3D after transformation, see:
402402
# http://trac.osgeo.org/gdal/changeset/17792
403-
orig_dim = self.coord_dim
403+
if GDAL_VERSION < (1, 7):
404+
orig_dim = self.coord_dim
404405

405406
# Depending on the input type, use the appropriate OGR routine
406407
# to perform the transformation.
@@ -412,11 +413,22 @@ def transform(self, coord_trans, clone=False):
412413
sr = SpatialReference(coord_trans)
413414
capi.geom_transform_to(self.ptr, sr.ptr)
414415
else:
415-
raise TypeError('Transform only accepts CoordTransform, SpatialReference, string, and integer objects.')
416+
raise TypeError('Transform only accepts CoordTransform, '
417+
'SpatialReference, string, and integer objects.')
416418

417419
# Setting with original dimension, see comment above.
418-
if self.coord_dim != orig_dim:
419-
self.coord_dim = orig_dim
420+
if GDAL_VERSION < (1, 7):
421+
if isinstance(self, GeometryCollection):
422+
# With geometry collections have to set dimension on
423+
# each internal geometry reference, as the collection
424+
# dimension isn't affected.
425+
for i in xrange(len(self)):
426+
internal_ptr = capi.get_geom_ref(self.ptr, i)
427+
if orig_dim != capi.get_coord_dim(internal_ptr):
428+
capi.set_coord_dim(internal_ptr, orig_dim)
429+
else:
430+
if self.coord_dim != orig_dim:
431+
self.coord_dim = orig_dim
420432

421433
def transform_to(self, srs):
422434
"For backwards-compatibility."

django/contrib/gis/gdal/tests/test_geom.py

Lines changed: 35 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ def test03_multipoints(self):
136136
self.assertEqual(mgeom1, mgeom3)
137137
self.assertEqual(mp.points, mgeom2.tuple)
138138
self.assertEqual(mp.n_p, mgeom2.point_count)
139-
139+
140140
def test04_linestring(self):
141141
"Testing LineString objects."
142142
prev = OGRGeometry('POINT(0 0)')
@@ -172,7 +172,7 @@ def test05_multilinestring(self):
172172
for ls in mlinestr:
173173
self.assertEqual(2, ls.geom_type)
174174
self.assertEqual('LINESTRING', ls.geom_name)
175-
self.assertRaises(OGRIndexError, mlinestr.__getitem__, len(mlinestr))
175+
self.assertRaises(OGRIndexError, mlinestr.__getitem__, len(mlinestr))
176176

177177
def test06_linearring(self):
178178
"Testing LinearRing objects."
@@ -190,7 +190,7 @@ def test07a_polygons(self):
190190
"Testing Polygon objects."
191191

192192
# Testing `from_bbox` class method
193-
bbox = (-180,-90,180,90)
193+
bbox = (-180,-90,180,90)
194194
p = OGRGeometry.from_bbox( bbox )
195195
self.assertEqual(bbox, p.extent)
196196

@@ -211,13 +211,13 @@ def test07a_polygons(self):
211211
# Testing equivalence
212212
self.assertEqual(True, poly == OGRGeometry(p.wkt))
213213
self.assertEqual(True, poly != prev)
214-
214+
215215
if p.ext_ring_cs:
216216
ring = poly[0]
217217
self.assertEqual(p.ext_ring_cs, ring.tuple)
218218
self.assertEqual(p.ext_ring_cs, poly[0].tuple)
219219
self.assertEqual(len(p.ext_ring_cs), ring.point_count)
220-
220+
221221
for r in poly:
222222
self.assertEqual('LINEARRING', r.geom_name)
223223

@@ -269,11 +269,11 @@ def test09a_srs(self):
269269
sr = SpatialReference('WGS84')
270270
mpoly = OGRGeometry(mp.wkt, sr)
271271
self.assertEqual(sr.wkt, mpoly.srs.wkt)
272-
272+
273273
# Ensuring that SRS is propagated to clones.
274274
klone = mpoly.clone()
275275
self.assertEqual(sr.wkt, klone.srs.wkt)
276-
276+
277277
# Ensuring all children geometries (polygons and their rings) all
278278
# return the assigned spatial reference as well.
279279
for poly in mpoly:
@@ -295,7 +295,7 @@ def test09a_srs(self):
295295
mpoly.srs = SpatialReference(4269)
296296
self.assertEqual(4269, mpoly.srid)
297297
self.assertEqual('NAD83', mpoly.srs.name)
298-
298+
299299
# Incrementing through the multipolyogn after the spatial reference
300300
# has been re-assigned.
301301
for poly in mpoly:
@@ -341,7 +341,7 @@ def test09c_transform_dim(self):
341341
"Testing coordinate dimension is the same on transformed geometries."
342342
ls_orig = OGRGeometry('LINESTRING(-104.609 38.255)', 4326)
343343
ls_trans = OGRGeometry('LINESTRING(992385.4472045 481455.4944650)', 2774)
344-
344+
345345
prec = 3
346346
ls_orig.transform(ls_trans.srs)
347347
# Making sure the coordinate dimension is still 2D.
@@ -388,7 +388,7 @@ def test12_symdifference(self):
388388
self.assertEqual(d1, a ^ b) # __xor__ is symmetric difference operator
389389
a ^= b # testing __ixor__
390390
self.assertEqual(d1, a)
391-
391+
392392
def test13_union(self):
393393
"Testing union()."
394394
for i in xrange(len(topology_geoms)):
@@ -455,7 +455,31 @@ def test17_pickle(self):
455455
self.assertEqual(g1, g2)
456456
self.assertEqual(4326, g2.srs.srid)
457457
self.assertEqual(g1.srs.wkt, g2.srs.wkt)
458-
458+
459+
def test18_ogrgeometry_transform_workaround(self):
460+
"Testing coordinate dimensions on geometries after transformation."
461+
# A bug in GDAL versions prior to 1.7 changes the coordinate
462+
# dimension of a geometry after it has been transformed.
463+
# This test ensures that the bug workarounds employed within
464+
# `OGRGeometry.transform` indeed work.
465+
wkt_2d = "MULTILINESTRING ((0 0,1 1,2 2))"
466+
wkt_3d = "MULTILINESTRING ((0 0 0,1 1 1,2 2 2))"
467+
srid = 4326
468+
469+
# For both the 2D and 3D MultiLineString, ensure _both_ the dimension
470+
# of the collection and the component LineString have the expected
471+
# coordinate dimension after transform.
472+
geom = OGRGeometry(wkt_2d, srid)
473+
geom.transform(srid)
474+
self.assertEqual(2, geom.coord_dim)
475+
self.assertEqual(2, geom[0].coord_dim)
476+
self.assertEqual(wkt_2d, geom.wkt)
477+
478+
geom = OGRGeometry(wkt_3d, srid)
479+
geom.transform(srid)
480+
self.assertEqual(3, geom.coord_dim)
481+
self.assertEqual(3, geom[0].coord_dim)
482+
self.assertEqual(wkt_3d, geom.wkt)
459483

460484
def suite():
461485
s = unittest.TestSuite()

0 commit comments

Comments
 (0)