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
This commit is contained in:
Justin Bronn 2010-03-29 17:33:59 +00:00
parent 7d25682108
commit 87302ac009
2 changed files with 52 additions and 16 deletions

View File

@ -48,11 +48,11 @@ from django.contrib.gis.gdal.base import GDALBase
from django.contrib.gis.gdal.envelope import Envelope, OGREnvelope from django.contrib.gis.gdal.envelope import Envelope, OGREnvelope
from django.contrib.gis.gdal.error import OGRException, OGRIndexError, SRSException from django.contrib.gis.gdal.error import OGRException, OGRIndexError, SRSException
from django.contrib.gis.gdal.geomtype import OGRGeomType from django.contrib.gis.gdal.geomtype import OGRGeomType
from django.contrib.gis.gdal.libgdal import GEOJSON, GDAL_VERSION
from django.contrib.gis.gdal.srs import SpatialReference, CoordTransform from django.contrib.gis.gdal.srs import SpatialReference, CoordTransform
# Getting the ctypes prototype functions that interface w/the GDAL C library. # Getting the ctypes prototype functions that interface w/the GDAL C library.
from django.contrib.gis.gdal.prototypes import geom as capi, srs as srs_api from django.contrib.gis.gdal.prototypes import geom as capi, srs as srs_api
GEOJSON = capi.GEOJSON
# For recognizing geometry input. # For recognizing geometry input.
from django.contrib.gis.geometry.regex import hex_regex, wkt_regex, json_regex from django.contrib.gis.geometry.regex import hex_regex, wkt_regex, json_regex
@ -400,7 +400,8 @@ class OGRGeometry(GDALBase):
# afterwards. This is done because of GDAL bug (in versions prior # afterwards. This is done because of GDAL bug (in versions prior
# to 1.7) that turns geometries 3D after transformation, see: # to 1.7) that turns geometries 3D after transformation, see:
# http://trac.osgeo.org/gdal/changeset/17792 # http://trac.osgeo.org/gdal/changeset/17792
orig_dim = self.coord_dim if GDAL_VERSION < (1, 7):
orig_dim = self.coord_dim
# Depending on the input type, use the appropriate OGR routine # Depending on the input type, use the appropriate OGR routine
# to perform the transformation. # to perform the transformation.
@ -412,11 +413,22 @@ class OGRGeometry(GDALBase):
sr = SpatialReference(coord_trans) sr = SpatialReference(coord_trans)
capi.geom_transform_to(self.ptr, sr.ptr) capi.geom_transform_to(self.ptr, sr.ptr)
else: else:
raise TypeError('Transform only accepts CoordTransform, SpatialReference, string, and integer objects.') raise TypeError('Transform only accepts CoordTransform, '
'SpatialReference, string, and integer objects.')
# Setting with original dimension, see comment above. # Setting with original dimension, see comment above.
if self.coord_dim != orig_dim: if GDAL_VERSION < (1, 7):
self.coord_dim = orig_dim if isinstance(self, GeometryCollection):
# With geometry collections have to set dimension on
# each internal geometry reference, as the collection
# dimension isn't affected.
for i in xrange(len(self)):
internal_ptr = capi.get_geom_ref(self.ptr, i)
if orig_dim != capi.get_coord_dim(internal_ptr):
capi.set_coord_dim(internal_ptr, orig_dim)
else:
if self.coord_dim != orig_dim:
self.coord_dim = orig_dim
def transform_to(self, srs): def transform_to(self, srs):
"For backwards-compatibility." "For backwards-compatibility."

View File

@ -136,7 +136,7 @@ class OGRGeomTest(unittest.TestCase):
self.assertEqual(mgeom1, mgeom3) self.assertEqual(mgeom1, mgeom3)
self.assertEqual(mp.points, mgeom2.tuple) self.assertEqual(mp.points, mgeom2.tuple)
self.assertEqual(mp.n_p, mgeom2.point_count) self.assertEqual(mp.n_p, mgeom2.point_count)
def test04_linestring(self): def test04_linestring(self):
"Testing LineString objects." "Testing LineString objects."
prev = OGRGeometry('POINT(0 0)') prev = OGRGeometry('POINT(0 0)')
@ -172,7 +172,7 @@ class OGRGeomTest(unittest.TestCase):
for ls in mlinestr: for ls in mlinestr:
self.assertEqual(2, ls.geom_type) self.assertEqual(2, ls.geom_type)
self.assertEqual('LINESTRING', ls.geom_name) self.assertEqual('LINESTRING', ls.geom_name)
self.assertRaises(OGRIndexError, mlinestr.__getitem__, len(mlinestr)) self.assertRaises(OGRIndexError, mlinestr.__getitem__, len(mlinestr))
def test06_linearring(self): def test06_linearring(self):
"Testing LinearRing objects." "Testing LinearRing objects."
@ -190,7 +190,7 @@ class OGRGeomTest(unittest.TestCase):
"Testing Polygon objects." "Testing Polygon objects."
# Testing `from_bbox` class method # Testing `from_bbox` class method
bbox = (-180,-90,180,90) bbox = (-180,-90,180,90)
p = OGRGeometry.from_bbox( bbox ) p = OGRGeometry.from_bbox( bbox )
self.assertEqual(bbox, p.extent) self.assertEqual(bbox, p.extent)
@ -211,13 +211,13 @@ class OGRGeomTest(unittest.TestCase):
# Testing equivalence # Testing equivalence
self.assertEqual(True, poly == OGRGeometry(p.wkt)) self.assertEqual(True, poly == OGRGeometry(p.wkt))
self.assertEqual(True, poly != prev) self.assertEqual(True, poly != prev)
if p.ext_ring_cs: if p.ext_ring_cs:
ring = poly[0] ring = poly[0]
self.assertEqual(p.ext_ring_cs, ring.tuple) self.assertEqual(p.ext_ring_cs, ring.tuple)
self.assertEqual(p.ext_ring_cs, poly[0].tuple) self.assertEqual(p.ext_ring_cs, poly[0].tuple)
self.assertEqual(len(p.ext_ring_cs), ring.point_count) self.assertEqual(len(p.ext_ring_cs), ring.point_count)
for r in poly: for r in poly:
self.assertEqual('LINEARRING', r.geom_name) self.assertEqual('LINEARRING', r.geom_name)
@ -269,11 +269,11 @@ class OGRGeomTest(unittest.TestCase):
sr = SpatialReference('WGS84') sr = SpatialReference('WGS84')
mpoly = OGRGeometry(mp.wkt, sr) mpoly = OGRGeometry(mp.wkt, sr)
self.assertEqual(sr.wkt, mpoly.srs.wkt) self.assertEqual(sr.wkt, mpoly.srs.wkt)
# Ensuring that SRS is propagated to clones. # Ensuring that SRS is propagated to clones.
klone = mpoly.clone() klone = mpoly.clone()
self.assertEqual(sr.wkt, klone.srs.wkt) self.assertEqual(sr.wkt, klone.srs.wkt)
# Ensuring all children geometries (polygons and their rings) all # Ensuring all children geometries (polygons and their rings) all
# return the assigned spatial reference as well. # return the assigned spatial reference as well.
for poly in mpoly: for poly in mpoly:
@ -295,7 +295,7 @@ class OGRGeomTest(unittest.TestCase):
mpoly.srs = SpatialReference(4269) mpoly.srs = SpatialReference(4269)
self.assertEqual(4269, mpoly.srid) self.assertEqual(4269, mpoly.srid)
self.assertEqual('NAD83', mpoly.srs.name) self.assertEqual('NAD83', mpoly.srs.name)
# Incrementing through the multipolyogn after the spatial reference # Incrementing through the multipolyogn after the spatial reference
# has been re-assigned. # has been re-assigned.
for poly in mpoly: for poly in mpoly:
@ -341,7 +341,7 @@ class OGRGeomTest(unittest.TestCase):
"Testing coordinate dimension is the same on transformed geometries." "Testing coordinate dimension is the same on transformed geometries."
ls_orig = OGRGeometry('LINESTRING(-104.609 38.255)', 4326) ls_orig = OGRGeometry('LINESTRING(-104.609 38.255)', 4326)
ls_trans = OGRGeometry('LINESTRING(992385.4472045 481455.4944650)', 2774) ls_trans = OGRGeometry('LINESTRING(992385.4472045 481455.4944650)', 2774)
prec = 3 prec = 3
ls_orig.transform(ls_trans.srs) ls_orig.transform(ls_trans.srs)
# Making sure the coordinate dimension is still 2D. # Making sure the coordinate dimension is still 2D.
@ -388,7 +388,7 @@ class OGRGeomTest(unittest.TestCase):
self.assertEqual(d1, a ^ b) # __xor__ is symmetric difference operator self.assertEqual(d1, a ^ b) # __xor__ is symmetric difference operator
a ^= b # testing __ixor__ a ^= b # testing __ixor__
self.assertEqual(d1, a) self.assertEqual(d1, a)
def test13_union(self): def test13_union(self):
"Testing union()." "Testing union()."
for i in xrange(len(topology_geoms)): for i in xrange(len(topology_geoms)):
@ -455,7 +455,31 @@ class OGRGeomTest(unittest.TestCase):
self.assertEqual(g1, g2) self.assertEqual(g1, g2)
self.assertEqual(4326, g2.srs.srid) self.assertEqual(4326, g2.srs.srid)
self.assertEqual(g1.srs.wkt, g2.srs.wkt) self.assertEqual(g1.srs.wkt, g2.srs.wkt)
def test18_ogrgeometry_transform_workaround(self):
"Testing coordinate dimensions on geometries after transformation."
# A bug in GDAL versions prior to 1.7 changes the coordinate
# dimension of a geometry after it has been transformed.
# This test ensures that the bug workarounds employed within
# `OGRGeometry.transform` indeed work.
wkt_2d = "MULTILINESTRING ((0 0,1 1,2 2))"
wkt_3d = "MULTILINESTRING ((0 0 0,1 1 1,2 2 2))"
srid = 4326
# For both the 2D and 3D MultiLineString, ensure _both_ the dimension
# of the collection and the component LineString have the expected
# coordinate dimension after transform.
geom = OGRGeometry(wkt_2d, srid)
geom.transform(srid)
self.assertEqual(2, geom.coord_dim)
self.assertEqual(2, geom[0].coord_dim)
self.assertEqual(wkt_2d, geom.wkt)
geom = OGRGeometry(wkt_3d, srid)
geom.transform(srid)
self.assertEqual(3, geom.coord_dim)
self.assertEqual(3, geom[0].coord_dim)
self.assertEqual(wkt_3d, geom.wkt)
def suite(): def suite():
s = unittest.TestSuite() s = unittest.TestSuite()