~ubuntu-branches/ubuntu/quantal/python-django/quantal

« back to all changes in this revision

Viewing changes to django/contrib/gis/gdal/geometries.py

  • Committer: Bazaar Package Importer
  • Author(s): Chris Lamb
  • Date: 2009-07-29 11:26:28 UTC
  • mfrom: (1.1.8 upstream) (4.1.5 sid)
  • Revision ID: james.westby@ubuntu.com-20090729112628-pg09ino8sz0sj21t
Tags: 1.1-1
* New upstream release.
* Merge from experimental:
  - Ship FastCGI initscript and /etc/default file in python-django's examples
    directory (Closes: #538863)
  - Drop "05_10539-sphinx06-compatibility.diff"; it has been applied
    upstream.
  - Bump Standards-Version to 3.8.2.

Show diffs side-by-side

added added

removed removed

Lines of Context:
44
44
from ctypes import byref, string_at, c_char_p, c_double, c_ubyte, c_void_p
45
45
 
46
46
# Getting GDAL prerequisites
 
47
from django.contrib.gis.gdal.base import GDALBase
47
48
from django.contrib.gis.gdal.envelope import Envelope, OGREnvelope
48
49
from django.contrib.gis.gdal.error import OGRException, OGRIndexError, SRSException
49
50
from django.contrib.gis.gdal.geomtype import OGRGeomType
50
51
from django.contrib.gis.gdal.srs import SpatialReference, CoordTransform
51
52
 
52
53
# Getting the ctypes prototype functions that interface w/the GDAL C library.
53
 
from django.contrib.gis.gdal.prototypes.geom import *
54
 
from django.contrib.gis.gdal.prototypes.srs import clone_srs
 
54
from django.contrib.gis.gdal.prototypes import geom as capi, srs as srs_api
 
55
GEOJSON = capi.GEOJSON
55
56
 
56
57
# For more information, see the OGR C API source code:
57
58
#  http://www.gdal.org/ogr/ogr__api_8h.html
64
65
json_regex = re.compile(r'^(\s+)?\{[\s\w,\[\]\{\}\-\."\':]+\}(\s+)?$')
65
66
 
66
67
#### OGRGeometry Class ####
67
 
class OGRGeometry(object):
 
68
class OGRGeometry(GDALBase):
68
69
    "Generally encapsulates an OGR geometry."
69
70
 
70
71
    def __init__(self, geom_input, srs=None):
71
72
        "Initializes Geometry on either WKT or an OGR pointer as input."
72
73
 
73
 
        self._ptr = c_void_p(None) # Initially NULL
74
74
        str_instance = isinstance(geom_input, basestring)
75
75
 
76
76
        # If HEX, unpack input to to a binary buffer.
91
91
                if wkt_m.group('type').upper() == 'LINEARRING':
92
92
                    # OGR_G_CreateFromWkt doesn't work with LINEARRING WKT.
93
93
                    #  See http://trac.osgeo.org/gdal/ticket/1992.
94
 
                    g = create_geom(OGRGeomType(wkt_m.group('type')).num)
95
 
                    import_wkt(g, byref(c_char_p(geom_input)))
 
94
                    g = capi.create_geom(OGRGeomType(wkt_m.group('type')).num)
 
95
                    capi.import_wkt(g, byref(c_char_p(geom_input)))
96
96
                else:
97
 
                    g = from_wkt(byref(c_char_p(geom_input)), None, byref(c_void_p()))
 
97
                    g = capi.from_wkt(byref(c_char_p(geom_input)), None, byref(c_void_p()))
98
98
            elif json_m:
99
99
                if GEOJSON:
100
 
                    g = from_json(geom_input)
 
100
                    g = capi.from_json(geom_input)
101
101
                else:
102
102
                    raise NotImplementedError('GeoJSON input only supported on GDAL 1.5+.')
103
103
            else:
104
104
                # Seeing if the input is a valid short-hand string
105
105
                # (e.g., 'Point', 'POLYGON').
106
106
                ogr_t = OGRGeomType(geom_input)
107
 
                g = create_geom(OGRGeomType(geom_input).num)
 
107
                g = capi.create_geom(OGRGeomType(geom_input).num)
108
108
        elif isinstance(geom_input, buffer):
109
109
            # WKB was passed in
110
 
            g = from_wkb(str(geom_input), None, byref(c_void_p()), len(geom_input))
 
110
            g = capi.from_wkb(str(geom_input), None, byref(c_void_p()), len(geom_input))
111
111
        elif isinstance(geom_input, OGRGeomType):
112
112
            # OGRGeomType was passed in, an empty geometry will be created.
113
 
            g = create_geom(geom_input.num)
114
 
        elif isinstance(geom_input, c_void_p):
 
113
            g = capi.create_geom(geom_input.num)
 
114
        elif isinstance(geom_input, self.ptr_type):
115
115
            # OGR pointer (c_void_p) was the input.
116
116
            g = geom_input
117
117
        else:
121
121
        # by setting the pointer for the object.
122
122
        if not g:
123
123
            raise OGRException('Cannot create OGR Geometry from input: %s' % str(geom_input))
124
 
        self._ptr = g
 
124
        self.ptr = g
125
125
 
126
126
        # Assigning the SpatialReference object to the geometry, if valid.
127
127
        if bool(srs): self.srs = srs
129
129
        # Setting the class depending upon the OGR Geometry Type
130
130
        self.__class__ = GEO_CLASSES[self.geom_type.num]
131
131
 
 
132
    @classmethod
 
133
    def from_bbox(cls, bbox):   
 
134
        "Constructs a Polygon from a bounding box (4-tuple)."
 
135
        x0, y0, x1, y1 = bbox
 
136
        return OGRGeometry( 'POLYGON((%s %s, %s %s, %s %s, %s %s, %s %s))' %  (
 
137
                x0, y0, x0, y1, x1, y1, x1, y0, x0, y0) )
 
138
 
132
139
    def __del__(self):
133
140
        "Deletes this Geometry."
134
 
        if self._ptr: destroy_geom(self._ptr)
 
141
        if self._ptr: capi.destroy_geom(self._ptr)
135
142
 
136
143
    ### Geometry set-like operations ###
137
144
    # g = g1 | g2
170
177
    @property
171
178
    def dimension(self):
172
179
        "Returns 0 for points, 1 for lines, and 2 for surfaces."
173
 
        return get_dims(self._ptr)
 
180
        return capi.get_dims(self.ptr)
174
181
 
175
182
    @property
176
183
    def coord_dim(self):
177
184
        "Returns the coordinate dimension of the Geometry."
178
 
        return get_coord_dims(self._ptr)
 
185
        return capi.get_coord_dims(self.ptr)
179
186
 
180
187
    @property
181
188
    def geom_count(self):
182
189
        "The number of elements in this Geometry."
183
 
        return get_geom_count(self._ptr)
 
190
        return capi.get_geom_count(self.ptr)
184
191
 
185
192
    @property
186
193
    def point_count(self):
187
194
        "Returns the number of Points in this Geometry."
188
 
        return get_point_count(self._ptr)
 
195
        return capi.get_point_count(self.ptr)
189
196
 
190
197
    @property
191
198
    def num_points(self):
201
208
    def geom_type(self):
202
209
        "Returns the Type for this Geometry."
203
210
        try:
204
 
            return OGRGeomType(get_geom_type(self._ptr))
 
211
            return OGRGeomType(capi.get_geom_type(self.ptr))
205
212
        except OGRException:
206
213
            # VRT datasources return an invalid geometry type
207
214
            # number, but a valid name -- we'll try that instead.
208
215
            # See: http://trac.osgeo.org/gdal/ticket/2491
209
 
            return OGRGeomType(get_geom_name(self._ptr))
 
216
            return OGRGeomType(capi.get_geom_name(self.ptr))
210
217
 
211
218
    @property
212
219
    def geom_name(self):
213
220
        "Returns the Name of this Geometry."
214
 
        return get_geom_name(self._ptr)
 
221
        return capi.get_geom_name(self.ptr)
215
222
 
216
223
    @property
217
224
    def area(self):
218
225
        "Returns the area for a LinearRing, Polygon, or MultiPolygon; 0 otherwise."
219
 
        return get_area(self._ptr)
 
226
        return capi.get_area(self.ptr)
220
227
 
221
228
    @property
222
229
    def envelope(self):
223
230
        "Returns the envelope for this Geometry."
224
231
        # TODO: Fix Envelope() for Point geometries.
225
 
        return Envelope(get_envelope(self._ptr, byref(OGREnvelope())))
 
232
        return Envelope(capi.get_envelope(self.ptr, byref(OGREnvelope())))
226
233
 
227
234
    @property
228
235
    def extent(self):
232
239
    #### SpatialReference-related Properties ####
233
240
    
234
241
    # The SRS property
235
 
    def get_srs(self):
 
242
    def _get_srs(self):
236
243
        "Returns the Spatial Reference for this Geometry."
237
244
        try:
238
 
            srs_ptr = get_geom_srs(self._ptr)
239
 
            return SpatialReference(clone_srs(srs_ptr))
 
245
            srs_ptr = capi.get_geom_srs(self.ptr)
 
246
            return SpatialReference(srs_api.clone_srs(srs_ptr))
240
247
        except SRSException:
241
248
            return None
242
249
 
243
 
    def set_srs(self, srs):
 
250
    def _set_srs(self, srs):
244
251
        "Sets the SpatialReference for this geometry."
245
252
        if isinstance(srs, SpatialReference):
246
 
            srs_ptr = clone_srs(srs._ptr)
 
253
            srs_ptr = srs_api.clone_srs(srs.ptr)
247
254
        elif isinstance(srs, (int, long, basestring)):
248
255
            sr = SpatialReference(srs)
249
 
            srs_ptr = clone_srs(sr._ptr)
 
256
            srs_ptr = srs_api.clone_srs(sr.ptr)
250
257
        else:
251
258
            raise TypeError('Cannot assign spatial reference with object of type: %s' % type(srs))
252
 
        assign_srs(self._ptr, srs_ptr)
 
259
        capi.assign_srs(self.ptr, srs_ptr)
253
260
 
254
 
    srs = property(get_srs, set_srs)
 
261
    srs = property(_get_srs, _set_srs)
255
262
 
256
263
    # The SRID property
257
 
    def get_srid(self):
258
 
        if self.srs: return self.srs.srid
259
 
        else: return None
 
264
    def _get_srid(self):
 
265
        srs = self.srs
 
266
        if srs: return srs.srid
 
267
        return None
260
268
 
261
 
    def set_srid(self, srid):
 
269
    def _set_srid(self, srid):
262
270
        if isinstance(srid, (int, long)):
263
271
            self.srs = srid
264
272
        else:
265
273
            raise TypeError('SRID must be set with an integer.')
266
274
 
267
 
    srid = property(get_srid, set_srid)
 
275
    srid = property(_get_srid, _set_srid)
268
276
 
269
277
    #### Output Methods ####
270
278
    @property
276
284
    @property
277
285
    def gml(self):
278
286
        "Returns the GML representation of the Geometry."
279
 
        return to_gml(self._ptr)
 
287
        return capi.to_gml(self.ptr)
280
288
 
281
289
    @property
282
290
    def hex(self):
286
294
 
287
295
    @property
288
296
    def json(self):
 
297
        """
 
298
        Returns the GeoJSON representation of this Geometry (requires
 
299
        GDAL 1.5+).
 
300
        """
289
301
        if GEOJSON: 
290
 
            return to_json(self._ptr)
 
302
            return capi.to_json(self.ptr)
291
303
        else:
292
304
            raise NotImplementedError('GeoJSON output only supported on GDAL 1.5+.')
293
305
    geojson = json
294
306
 
295
307
    @property
 
308
    def kml(self):
 
309
        "Returns the KML representation of the Geometry."
 
310
        if GEOJSON:
 
311
            return capi.to_kml(self.ptr, None)
 
312
        else:
 
313
            raise NotImplementedError('KML output only supported on GDAL 1.5+.')
 
314
 
 
315
    @property
296
316
    def wkb_size(self):
297
317
        "Returns the size of the WKB buffer."
298
 
        return get_wkbsize(self._ptr)
 
318
        return capi.get_wkbsize(self.ptr)
299
319
 
300
320
    @property
301
321
    def wkb(self):
307
327
        sz = self.wkb_size
308
328
        # Creating the unsigned character buffer, and passing it in by reference.
309
329
        buf = (c_ubyte * sz)()
310
 
        wkb = to_wkb(self._ptr, byteorder, byref(buf))
 
330
        wkb = capi.to_wkb(self.ptr, byteorder, byref(buf))
311
331
        # Returning a buffer of the string at the pointer.
312
332
        return buffer(string_at(buf, sz))
313
333
 
314
334
    @property
315
335
    def wkt(self):
316
336
        "Returns the WKT representation of the Geometry."
317
 
        return to_wkt(self._ptr, byref(c_char_p()))
 
337
        return capi.to_wkt(self.ptr, byref(c_char_p()))
318
338
    
319
339
    #### Geometry Methods ####
320
340
    def clone(self):
321
341
        "Clones this OGR Geometry."
322
 
        return OGRGeometry(clone_geom(self._ptr), self.srs)
 
342
        return OGRGeometry(capi.clone_geom(self.ptr), self.srs)
323
343
 
324
344
    def close_rings(self):
325
345
        """
328
348
        end.
329
349
        """
330
350
        # Closing the open rings.
331
 
        geom_close_rings(self._ptr)
 
351
        capi.geom_close_rings(self.ptr)
332
352
 
333
353
    def transform(self, coord_trans, clone=False):
334
354
        """
344
364
            klone.transform(coord_trans)
345
365
            return klone
346
366
        if isinstance(coord_trans, CoordTransform):
347
 
            geom_transform(self._ptr, coord_trans._ptr)
 
367
            capi.geom_transform(self.ptr, coord_trans.ptr)
348
368
        elif isinstance(coord_trans, SpatialReference):
349
 
            geom_transform_to(self._ptr, coord_trans._ptr)
 
369
            capi.geom_transform_to(self.ptr, coord_trans.ptr)
350
370
        elif isinstance(coord_trans, (int, long, basestring)):
351
371
            sr = SpatialReference(coord_trans)
352
 
            geom_transform_to(self._ptr, sr._ptr)
 
372
            capi.geom_transform_to(self.ptr, sr.ptr)
353
373
        else:
354
374
            raise TypeError('Transform only accepts CoordTransform, SpatialReference, string, and integer objects.')
355
375
 
366
386
 
367
387
        # Returning the output of the given function with the other geometry's
368
388
        # pointer.
369
 
        return func(self._ptr, other._ptr)
 
389
        return func(self.ptr, other.ptr)
370
390
 
371
391
    def intersects(self, other):
372
392
        "Returns True if this geometry intersects with the other."
373
 
        return self._topology(ogr_intersects, other)
 
393
        return self._topology(capi.ogr_intersects, other)
374
394
    
375
395
    def equals(self, other):
376
396
        "Returns True if this geometry is equivalent to the other."
377
 
        return self._topology(ogr_equals, other)
 
397
        return self._topology(capi.ogr_equals, other)
378
398
 
379
399
    def disjoint(self, other):
380
400
        "Returns True if this geometry and the other are spatially disjoint."
381
 
        return self._topology(ogr_disjoint, other)
 
401
        return self._topology(capi.ogr_disjoint, other)
382
402
 
383
403
    def touches(self, other):
384
404
        "Returns True if this geometry touches the other."
385
 
        return self._topology(ogr_touches, other)
 
405
        return self._topology(capi.ogr_touches, other)
386
406
 
387
407
    def crosses(self, other):
388
408
        "Returns True if this geometry crosses the other."
389
 
        return self._topology(ogr_crosses, other)
 
409
        return self._topology(capi.ogr_crosses, other)
390
410
 
391
411
    def within(self, other):
392
412
        "Returns True if this geometry is within the other."
393
 
        return self._topology(ogr_within, other)
 
413
        return self._topology(capi.ogr_within, other)
394
414
 
395
415
    def contains(self, other):
396
416
        "Returns True if this geometry contains the other."
397
 
        return self._topology(ogr_contains, other)
 
417
        return self._topology(capi.ogr_contains, other)
398
418
 
399
419
    def overlaps(self, other):
400
420
        "Returns True if this geometry overlaps the other."
401
 
        return self._topology(ogr_overlaps, other)
 
421
        return self._topology(capi.ogr_overlaps, other)
402
422
 
403
423
    #### Geometry-generation Methods ####
404
424
    def _geomgen(self, gen_func, other=None):
405
425
        "A helper routine for the OGR routines that generate geometries."
406
426
        if isinstance(other, OGRGeometry):
407
 
            return OGRGeometry(gen_func(self._ptr, other._ptr), self.srs)
 
427
            return OGRGeometry(gen_func(self.ptr, other.ptr), self.srs)
408
428
        else:
409
 
            return OGRGeometry(gen_func(self._ptr), self.srs)
 
429
            return OGRGeometry(gen_func(self.ptr), self.srs)
410
430
 
411
431
    @property
412
432
    def boundary(self):
413
433
        "Returns the boundary of this geometry."
414
 
        return self._geomgen(get_boundary)
 
434
        return self._geomgen(capi.get_boundary)
415
435
 
416
436
    @property
417
437
    def convex_hull(self):
419
439
        Returns the smallest convex Polygon that contains all the points in 
420
440
        this Geometry.
421
441
        """
422
 
        return self._geomgen(geom_convex_hull)
 
442
        return self._geomgen(capi.geom_convex_hull)
423
443
 
424
444
    def difference(self, other):
425
445
        """
426
446
        Returns a new geometry consisting of the region which is the difference
427
447
        of this geometry and the other.
428
448
        """
429
 
        return self._geomgen(geom_diff, other)
 
449
        return self._geomgen(capi.geom_diff, other)
430
450
 
431
451
    def intersection(self, other):
432
452
        """
433
453
        Returns a new geometry consisting of the region of intersection of this
434
454
        geometry and the other.
435
455
        """
436
 
        return self._geomgen(geom_intersection, other)
 
456
        return self._geomgen(capi.geom_intersection, other)
437
457
 
438
458
    def sym_difference(self, other):
439
459
        """                                                                                                                                                
440
460
        Returns a new geometry which is the symmetric difference of this
441
461
        geometry and the other.
442
462
        """
443
 
        return self._geomgen(geom_sym_diff, other)
 
463
        return self._geomgen(capi.geom_sym_diff, other)
444
464
 
445
465
    def union(self, other):
446
466
        """
447
467
        Returns a new geometry consisting of the region which is the union of
448
468
        this geometry and the other.
449
469
        """
450
 
        return self._geomgen(geom_union, other)
 
470
        return self._geomgen(capi.geom_union, other)
451
471
 
452
472
# The subclasses for OGR Geometry.
453
473
class Point(OGRGeometry):
455
475
    @property
456
476
    def x(self):
457
477
        "Returns the X coordinate for this Point."
458
 
        return getx(self._ptr, 0)
 
478
        return capi.getx(self.ptr, 0)
459
479
 
460
480
    @property
461
481
    def y(self):
462
482
        "Returns the Y coordinate for this Point."
463
 
        return gety(self._ptr, 0)
 
483
        return capi.gety(self.ptr, 0)
464
484
 
465
485
    @property
466
486
    def z(self):
467
487
        "Returns the Z coordinate for this Point."
468
488
        if self.coord_dim == 3:
469
 
            return getz(self._ptr, 0)
 
489
            return capi.getz(self.ptr, 0)
470
490
 
471
491
    @property
472
492
    def tuple(self):
483
503
        "Returns the Point at the given index."
484
504
        if index >= 0 and index < self.point_count:
485
505
            x, y, z = c_double(), c_double(), c_double()
486
 
            get_point(self._ptr, index, byref(x), byref(y), byref(z))
 
506
            capi.get_point(self.ptr, index, byref(x), byref(y), byref(z))
487
507
            dim = self.coord_dim
488
508
            if dim == 1:
489
509
                return (x.value,)
514
534
        Internal routine that returns a sequence (list) corresponding with
515
535
        the given function.
516
536
        """
517
 
        return [func(self._ptr, i) for i in xrange(len(self))]
 
537
        return [func(self.ptr, i) for i in xrange(len(self))]
518
538
 
519
539
    @property
520
540
    def x(self):
521
541
        "Returns the X coordinates in a list."
522
 
        return self._listarr(getx)
 
542
        return self._listarr(capi.getx)
523
543
 
524
544
    @property
525
545
    def y(self):
526
546
        "Returns the Y coordinates in a list."
527
 
        return self._listarr(gety)
 
547
        return self._listarr(capi.gety)
528
548
    
529
549
    @property
530
550
    def z(self):
531
551
        "Returns the Z coordinates in a list."
532
552
        if self.coord_dim == 3:
533
 
            return self._listarr(getz)
 
553
            return self._listarr(capi.getz)
534
554
 
535
555
# LinearRings are used in Polygons.
536
556
class LinearRing(LineString): pass
551
571
        if index < 0 or index >= self.geom_count:
552
572
            raise OGRIndexError('index out of range: %s' % index)
553
573
        else:
554
 
            return OGRGeometry(clone_geom(get_geom_ref(self._ptr, index)), self.srs)
 
574
            return OGRGeometry(capi.clone_geom(capi.get_geom_ref(self.ptr, index)), self.srs)
555
575
 
556
576
    # Polygon Properties
557
577
    @property
577
597
        "Returns the centroid (a Point) of this Polygon."
578
598
        # The centroid is a Point, create a geometry for this.
579
599
        p = OGRGeometry(OGRGeomType('Point'))
580
 
        get_centroid(self._ptr, p._ptr)
 
600
        capi.get_centroid(self.ptr, p.ptr)
581
601
        return p
582
602
 
583
603
# Geometry Collection base class.
589
609
        if index < 0 or index >= self.geom_count:
590
610
            raise OGRIndexError('index out of range: %s' % index)
591
611
        else:
592
 
            return OGRGeometry(clone_geom(get_geom_ref(self._ptr, index)), self.srs)
 
612
            return OGRGeometry(capi.clone_geom(capi.get_geom_ref(self.ptr, index)), self.srs)
593
613
        
594
614
    def __iter__(self):
595
615
        "Iterates over each Geometry."
604
624
        "Add the geometry to this Geometry Collection."
605
625
        if isinstance(geom, OGRGeometry):
606
626
            if isinstance(geom, self.__class__):
607
 
                for g in geom: add_geom(self._ptr, g._ptr)
 
627
                for g in geom: capi.add_geom(self.ptr, g.ptr)
608
628
            else:
609
 
                add_geom(self._ptr, geom._ptr)
 
629
                capi.add_geom(self.ptr, geom.ptr)
610
630
        elif isinstance(geom, basestring):
611
631
            tmp = OGRGeometry(geom)
612
 
            add_geom(self._ptr, tmp._ptr)
 
632
            capi.add_geom(self.ptr, tmp.ptr)
613
633
        else:
614
634
            raise OGRException('Must add an OGRGeometry.')
615
635