Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

The `OGRGeometry.coord_dim` property may now be set; implemented a wo…

…rk-around for an OGR bug that changed geometries to 3D after transformation. Refs #11433.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@11628 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit 69535b7b1383c6d74fac4f5a1b1a89c2c9956e23 1 parent e5ab340
Justin Bronn authored
53  django/contrib/gis/gdal/geometries.py
@@ -29,7 +29,7 @@
29 29
   +proj=longlat +ellps=clrk66 +datum=NAD27 +no_defs
30 30
   >>> print mpnt
31 31
   MULTIPOINT (-89.999930378602485 29.999797886557641,-89.999930378602485 29.999797886557641)
32  
-  
  32
+
33 33
   The OGRGeomType class is to make it easy to specify an OGR geometry type:
34 34
   >>> from django.contrib.gis.gdal import OGRGeomType
35 35
   >>> gt1 = OGRGeomType(3) # Using an integer for the type
@@ -78,7 +78,7 @@ def __init__(self, geom_input, srs=None):
78 78
             geom_input = buffer(a2b_hex(geom_input.upper()))
79 79
             str_instance = False
80 80
 
81  
-        # Constructing the geometry, 
  81
+        # Constructing the geometry,
82 82
         if str_instance:
83 83
             # Checking if unicode
84 84
             if isinstance(geom_input, unicode):
@@ -130,12 +130,12 @@ def __init__(self, geom_input, srs=None):
130 130
         self.__class__ = GEO_CLASSES[self.geom_type.num]
131 131
 
132 132
     @classmethod
133  
-    def from_bbox(cls, bbox):   
  133
+    def from_bbox(cls, bbox):
134 134
         "Constructs a Polygon from a bounding box (4-tuple)."
135 135
         x0, y0, x1, y1 = bbox
136 136
         return OGRGeometry( 'POLYGON((%s %s, %s %s, %s %s, %s %s, %s %s))' %  (
137 137
                 x0, y0, x0, y1, x1, y1, x1, y0, x0, y0) )
138  
- 
  138
+
139 139
     def __del__(self):
140 140
         "Deletes this Geometry."
141 141
         if self._ptr: capi.destroy_geom(self._ptr)
@@ -179,10 +179,17 @@ def dimension(self):
179 179
         "Returns 0 for points, 1 for lines, and 2 for surfaces."
180 180
         return capi.get_dims(self.ptr)
181 181
 
182  
-    @property
183  
-    def coord_dim(self):
  182
+    def _get_coord_dim(self):
184 183
         "Returns the coordinate dimension of the Geometry."
185  
-        return capi.get_coord_dims(self.ptr)
  184
+        return capi.get_coord_dim(self.ptr)
  185
+
  186
+    def _set_coord_dim(self, dim):
  187
+        "Sets the coordinate dimension of this Geometry."
  188
+        if not dim in (2, 3):
  189
+            raise ValueError('Geometry dimension must be either 2 or 3')
  190
+        capi.set_coord_dim(self.ptr, dim)
  191
+
  192
+    coord_dim = property(_get_coord_dim, _set_coord_dim)
186 193
 
187 194
     @property
188 195
     def geom_count(self):
@@ -237,7 +244,7 @@ def extent(self):
237 244
         return self.envelope.tuple
238 245
 
239 246
     #### SpatialReference-related Properties ####
240  
-    
  247
+
241 248
     # The SRS property
242 249
     def _get_srs(self):
243 250
         "Returns the Spatial Reference for this Geometry."
@@ -298,7 +305,7 @@ def json(self):
298 305
         Returns the GeoJSON representation of this Geometry (requires
299 306
         GDAL 1.5+).
300 307
         """
301  
-        if GEOJSON: 
  308
+        if GEOJSON:
302 309
             return capi.to_json(self.ptr)
303 310
         else:
304 311
             raise NotImplementedError('GeoJSON output only supported on GDAL 1.5+.')
@@ -335,7 +342,7 @@ def wkb(self):
335 342
     def wkt(self):
336 343
         "Returns the WKT representation of the Geometry."
337 344
         return capi.to_wkt(self.ptr, byref(c_char_p()))
338  
-    
  345
+
339 346
     #### Geometry Methods ####
340 347
     def clone(self):
341 348
         "Clones this OGR Geometry."
@@ -363,6 +370,16 @@ def transform(self, coord_trans, clone=False):
363 370
             klone = self.clone()
364 371
             klone.transform(coord_trans)
365 372
             return klone
  373
+
  374
+        # Have to get the coordinate dimension of the original geometry
  375
+        # so it can be used to reset the transformed geometry's dimension
  376
+        # afterwards.  This is done because of GDAL bug (in versions prior
  377
+        # to 1.7) that turns geometries 3D after transformation, see:
  378
+        #  http://trac.osgeo.org/gdal/changeset/17792
  379
+        orig_dim = self.coord_dim
  380
+
  381
+        # Depending on the input type, use the appropriate OGR routine
  382
+        # to perform the transformation.
366 383
         if isinstance(coord_trans, CoordTransform):
367 384
             capi.geom_transform(self.ptr, coord_trans.ptr)
368 385
         elif isinstance(coord_trans, SpatialReference):
@@ -373,6 +390,10 @@ def transform(self, coord_trans, clone=False):
373 390
         else:
374 391
             raise TypeError('Transform only accepts CoordTransform, SpatialReference, string, and integer objects.')
375 392
 
  393
+        # Setting with original dimension, see comment above.
  394
+        if self.coord_dim != orig_dim:
  395
+            self.coord_dim = orig_dim
  396
+
376 397
     def transform_to(self, srs):
377 398
         "For backwards-compatibility."
378 399
         self.transform(srs)
@@ -391,7 +412,7 @@ def _topology(self, func, other):
391 412
     def intersects(self, other):
392 413
         "Returns True if this geometry intersects with the other."
393 414
         return self._topology(capi.ogr_intersects, other)
394  
-    
  415
+
395 416
     def equals(self, other):
396 417
         "Returns True if this geometry is equivalent to the other."
397 418
         return self._topology(capi.ogr_equals, other)
@@ -436,7 +457,7 @@ def boundary(self):
436 457
     @property
437 458
     def convex_hull(self):
438 459
         """
439  
-        Returns the smallest convex Polygon that contains all the points in 
  460
+        Returns the smallest convex Polygon that contains all the points in
440 461
         this Geometry.
441 462
         """
442 463
         return self._geomgen(capi.geom_convex_hull)
@@ -456,7 +477,7 @@ def intersection(self, other):
456 477
         return self._geomgen(capi.geom_intersection, other)
457 478
 
458 479
     def sym_difference(self, other):
459  
-        """                                                                                                                                                
  480
+        """
460 481
         Returns a new geometry which is the symmetric difference of this
461 482
         geometry and the other.
462 483
         """
@@ -545,7 +566,7 @@ def x(self):
545 566
     def y(self):
546 567
         "Returns the Y coordinates in a list."
547 568
         return self._listarr(capi.gety)
548  
-    
  569
+
549 570
     @property
550 571
     def z(self):
551 572
         "Returns the Z coordinates in a list."
@@ -610,7 +631,7 @@ def __getitem__(self, index):
610 631
             raise OGRIndexError('index out of range: %s' % index)
611 632
         else:
612 633
             return OGRGeometry(capi.clone_geom(capi.get_geom_ref(self.ptr, index)), self.srs)
613  
-        
  634
+
614 635
     def __iter__(self):
615 636
         "Iterates over each Geometry."
616 637
         for i in xrange(self.geom_count):
@@ -658,5 +679,5 @@ class MultiPolygon(GeometryCollection): pass
658 679
                5 : MultiLineString,
659 680
                6 : MultiPolygon,
660 681
                7 : GeometryCollection,
661  
-               101: LinearRing, 
  682
+               101: LinearRing,
662 683
                }
3  django/contrib/gis/gdal/prototypes/geom.py
@@ -83,7 +83,8 @@ def topology_func(f):
83 83
 get_area = double_output(lgdal.OGR_G_GetArea, [c_void_p])
84 84
 get_centroid = void_output(lgdal.OGR_G_Centroid, [c_void_p, c_void_p])
85 85
 get_dims = int_output(lgdal.OGR_G_GetDimension, [c_void_p])
86  
-get_coord_dims = int_output(lgdal.OGR_G_GetCoordinateDimension, [c_void_p])
  86
+get_coord_dim = int_output(lgdal.OGR_G_GetCoordinateDimension, [c_void_p])
  87
+set_coord_dim = void_output(lgdal.OGR_G_SetCoordinateDimension, [c_void_p, c_int], errcheck=False)
87 88
 
88 89
 get_geom_count = int_output(lgdal.OGR_G_GetGeometryCount, [c_void_p])
89 90
 get_geom_name = const_string_output(lgdal.OGR_G_GetGeometryName, [c_void_p])
12  django/contrib/gis/gdal/tests/test_geom.py
@@ -319,6 +319,18 @@ def test09b_srs_transform(self):
319 319
             self.assertAlmostEqual(trans.x, p.x, prec)
320 320
             self.assertAlmostEqual(trans.y, p.y, prec)
321 321
 
  322
+    def test09c_transform_dim(self):
  323
+        "Testing coordinate dimension is the same on transformed geometries."
  324
+        ls_orig = OGRGeometry('LINESTRING(-104.609 38.255)', 4326)
  325
+        ls_trans = OGRGeometry('LINESTRING(992385.4472045 481455.4944650)', 2774)
  326
+        
  327
+        prec = 3
  328
+        ls_orig.transform(ls_trans.srs)
  329
+        # Making sure the coordinate dimension is still 2D.
  330
+        self.assertEqual(2, ls_orig.coord_dim)
  331
+        self.assertAlmostEqual(ls_trans.x[0], ls_orig.x[0], prec)
  332
+        self.assertAlmostEqual(ls_trans.y[0], ls_orig.y[0], prec)
  333
+
322 334
     def test10_difference(self):
323 335
         "Testing difference()."
324 336
         for i in xrange(len(topology_geoms)):

0 notes on commit 69535b7

Please sign in to comment.
Something went wrong with that request. Please try again.