Author: jbronn
Date: 2007-06-24 20:29:01 -0500 (Sun, 24 Jun 2007)
New Revision: 5527
Added:
django/branches/gis/django/contrib/gis/gdal/Envelope.py
Modified:
django/branches/gis/django/contrib/gis/gdal/Layer.py
django/branches/gis/django/contrib/gis/gdal/OGRGeometry.py
django/branches/gis/django/contrib/gis/gdal/__init__.py
django/branches/gis/django/contrib/gis/tests/test_gdal_ds.py
Log:
gis: added the Envelope class, used in getting layer and geometry extents; also
added boundary and convex_hull properties.
Added: django/branches/gis/django/contrib/gis/gdal/Envelope.py
===================================================================
--- django/branches/gis/django/contrib/gis/gdal/Envelope.py
(rev 0)
+++ django/branches/gis/django/contrib/gis/gdal/Envelope.py 2007-06-25
01:29:01 UTC (rev 5527)
@@ -0,0 +1,112 @@
+from ctypes import Structure, c_double
+from types import TupleType
+
+"""
+ The GDAL/OGR library uses an Envelope structure to hold the bounding
+ box information for a geometry. The envelope (bounding box) contains
+ two pairs of coordinates, one for the lower left coordinate and one
+ for the upper right coordinate:
+
+ +----------o Upper right; (max_x, max_y)
+ | |
+ | |
+ | |
+ Lower left (min_x, min_y) o----------+
+
+"""
+
+# The OGR definition of an Envelope is a C structure containing four doubles.
+# See the 'ogr_core.h' source file for more information:
+# http://www.gdal.org/ogr/ogr__core_8h-source.html
+class OGREnvelope(Structure):
+ "Represents the OGREnvelope C Structure."
+ _fields_ = [("MinX", c_double),
+ ("MaxX", c_double),
+ ("MinY", c_double),
+ ("MaxY", c_double),
+ ]
+
+class Envelope(object):
+ "A class that will wrap an OGR Envelope structure."
+
+ def __init__(self, *args):
+ if len(args) == 1:
+ if isinstance(args[0], OGREnvelope):
+ # OGREnvelope (a ctypes Structure) was passed in.
+ self._envelope = args[0]
+ elif isinstance(args[0], TupleType) and len(args[0]) == 4:
+ # A Tuple was passed in
+ self._from_tuple(args[0])
+ else:
+ raise OGRException, 'Incorrect type of argument: %s' %
str(type(args[0]))
+ elif len(args) == 4:
+ self._from_tuple(args)
+ else:
+ raise OGRException, 'Incorrect number of arguments!'
+
+ def __eq__(self, other):
+ "Returns true if the envelopes are equivalent; can compare against
other Envelopes and 4-tuples."
+ if isinstance(other, Envelope):
+ return (self.min_x == other.min_x) and (self.min_y == other.min_y)
and \
+ (self.max_x == other.max_x) and (self.max_y == other.max_y)
+ elif isinstance(other, TupleType) and len(other) == 4:
+ return (self.min_x == other[0]) and (self.min_y == other[1]) and \
+ (self.max_x == other[2]) and (self.max_y == other[3])
+ else:
+ raise OGRException, 'Equivalence testing only works with other
Envelopes.'
+
+ def __str__(self):
+ "Returns a string representation of the tuple."
+ return str(self.tuple)
+
+ def _from_tuple(self, tup):
+ "Initializes the C OGR Envelope structure from the given tuple."
+ self._envelope = OGREnvelope()
+ self._envelope.MinX = tup[0]
+ self._envelope.MinY = tup[1]
+ self._envelope.MaxX = tup[2]
+ self._envelope.MaxY = tup[3]
+
+ @property
+ def min_x(self):
+ "Returns the value of the minimum X coordinate."
+ return self._envelope.MinX
+
+ @property
+ def min_y(self):
+ "Returns the value of the minimum Y coordinate."
+ return self._envelope.MinY
+
+ @property
+ def max_x(self):
+ "Returns the value of the maximum X coordinate."
+ return self._envelope.MaxX
+
+ @property
+ def max_y(self):
+ "Returns the value of the maximum Y coordinate."
+ return self._envelope.MaxY
+
+ @property
+ def ur(self):
+ "Returns the upper-right coordinate."
+ return (self.max_x, self.max_y)
+
+ @property
+ def ll(self):
+ "Returns the lower-left coordinate."
+ return (self.min_x, self.min_y)
+
+ @property
+ def tuple(self):
+ "Returns a tuple representing the envelope."
+ return (self.min_x, self.min_y, self.max_x, self.max_y)
+
+ @property
+ def wkt(self):
+ "Returns WKT representing a Polygon for this envelope."
+ # TODO: Fix significant figures.
+ return 'POLYGON((%f %f,%f %f,%f %f,%f %f,%f %f))' % (self.min_x,
self.min_y, self.min_x, self.max_y,
+ self.max_x,
self.max_y, self.max_x, self.min_y,
+ self.min_x,
self.min_y)
+
Modified: django/branches/gis/django/contrib/gis/gdal/Layer.py
===================================================================
--- django/branches/gis/django/contrib/gis/gdal/Layer.py 2007-06-24
12:38:11 UTC (rev 5526)
+++ django/branches/gis/django/contrib/gis/gdal/Layer.py 2007-06-25
01:29:01 UTC (rev 5527)
@@ -1,12 +1,13 @@
# Needed ctypes routines
-from ctypes import c_int, c_long, c_void_p, string_at
+from ctypes import c_int, c_long, c_void_p, byref, string_at
# The GDAL C Library
from django.contrib.gis.gdal.libgdal import lgdal
# Other GDAL imports.
+from django.contrib.gis.gdal.Envelope import Envelope, OGREnvelope
from django.contrib.gis.gdal.Feature import Feature
-from django.contrib.gis.gdal.OGRError import OGRException
+from django.contrib.gis.gdal.OGRError import OGRException, check_err
from django.contrib.gis.gdal.SpatialReference import SpatialReference
# For more information, see the OGR C API source code:
@@ -58,6 +59,13 @@
#### Layer properties ####
@property
+ def extent(self):
+ "Returns the extent (an Envelope) of this layer."
+ env = OGREnvelope()
+ check_err(lgdal.OGR_L_GetExtent(self._layer, byref(env), c_int(1)))
+ return Envelope(env)
+
+ @property
def name(self):
"Returns the name of this layer in the Data Source."
return string_at(lgdal.OGR_FD_GetName(self._ldefn))
Modified: django/branches/gis/django/contrib/gis/gdal/OGRGeometry.py
===================================================================
--- django/branches/gis/django/contrib/gis/gdal/OGRGeometry.py 2007-06-24
12:38:11 UTC (rev 5526)
+++ django/branches/gis/django/contrib/gis/gdal/OGRGeometry.py 2007-06-25
01:29:01 UTC (rev 5527)
@@ -4,6 +4,7 @@
# Getting the GDAL C library and error checking facilities
from django.contrib.gis.gdal.libgdal import lgdal
+from django.contrib.gis.gdal.Envelope import Envelope, OGREnvelope
from django.contrib.gis.gdal.OGRError import check_err, OGRException
from django.contrib.gis.gdal.SpatialReference import SpatialReference,
CoordTransform
@@ -248,6 +249,13 @@
"Returns the area for a LinearRing, Polygon, or MultiPolygon; 0
otherwise."
a = lgdal.OGR_G_GetArea(self._g)
return a.value
+
+ @property
+ def envelope(self):
+ "Returns the envelope for this Geometry."
+ env = OGREnvelope()
+ lgdal.OGR_G_GetEnvelope(self._g, byref(env))
+ return Envelope(env)
#### Geometry Methods ####
def clone(self):
@@ -322,11 +330,23 @@
return self._topology(lgdal.OGR_G_Overlaps, other)
#### Geometry-generation Methods ####
- def _geomgen(self, gen_func, other):
- if not isinstance(other, OGRGeometry):
- raise OGRException, 'Must use another OGRGeometry object for
geometry-generating operations!'
- return OGRGeometry(gen_func(self._g, other._g))
+ def _geomgen(self, gen_func, other=None):
+ "A helper routine for the OGR routines that generate geometries."
+ if isinstance(other, OGRGeometry):
+ return OGRGeometry(gen_func(self._g, other._g))
+ else:
+ return OGRGeometry(gen_func(self._g))
+ @property
+ def boundary(self):
+ "Returns the boundary of this geometry."
+ return self._geomgen(lgdal.OGR_G_GetBoundary)
+
+ @property
+ def convex_hull(self):
+ "Returns the smallest convex Polygon that contains all the points in
the Geometry."
+ return self._geomgen(lgdal.OGR_G_ConvexHull)
+
def union(self, other):
"""Returns a new geometry consisting of the region which is the union
of
this geometry and the other."""
Modified: django/branches/gis/django/contrib/gis/gdal/__init__.py
===================================================================
--- django/branches/gis/django/contrib/gis/gdal/__init__.py 2007-06-24
12:38:11 UTC (rev 5526)
+++ django/branches/gis/django/contrib/gis/gdal/__init__.py 2007-06-25
01:29:01 UTC (rev 5527)
@@ -1,4 +1,5 @@
from Driver import Driver
+from Envelope import Envelope
from DataSource import DataSource
from SpatialReference import SpatialReference, CoordTransform
from OGRGeometry import OGRGeometry, OGRGeomType
Modified: django/branches/gis/django/contrib/gis/tests/test_gdal_ds.py
===================================================================
--- django/branches/gis/django/contrib/gis/tests/test_gdal_ds.py
2007-06-24 12:38:11 UTC (rev 5526)
+++ django/branches/gis/django/contrib/gis/tests/test_gdal_ds.py
2007-06-25 01:29:01 UTC (rev 5527)
@@ -1,5 +1,6 @@
import os, os.path, unittest
from django.contrib.gis.gdal import DataSource, OGRException
+from django.contrib.gis.gdal.Envelope import Envelope
from django.contrib.gis.gdal.Field import OFTReal, OFTInteger, OFTString
# Path for SHP files
@@ -16,8 +17,10 @@
# List of acceptable data sources.
ds_list = (TestSHP('test_point', nfeat=5, nfld=3, geom='POINT', gtype=1,
fields={'dbl' : OFTReal, 'int' : OFTReal, 'str' : OFTString,},
+ extent=(-1.35011,0.166623,-0.524093,0.824508), # Got extent
from QGIS
srs_wkt='GEOGCS["GCS_WGS_1984",DATUM["WGS_1984",SPHEROID["WGS_1984",6378137,298.257223563]],PRIMEM["Greenwich",0],UNIT["Degree",0.017453292519943295]]'),
TestSHP('test_poly', nfeat=3, nfld=3, geom='POLYGON', gtype=3,
fields={'float' : OFTReal, 'int' : OFTReal, 'str' : OFTString,},
+ extent=(-1.01513,-0.558245,0.161876,0.839637), # Got extent
from QGIS
srs_wkt='GEOGCS["GCS_WGS_1984",DATUM["WGS_1984",SPHEROID["WGS_1984",6378137,298.257223563]],PRIMEM["Greenwich",0],UNIT["Degree",0.017453292519943295]]'),
)
@@ -67,9 +70,16 @@
self.assertEqual(len(layer), source.nfeat)
# Making sure we get the number of fields we expect
- self.assertEqual(layer.num_fields, source.nfld)
- self.assertEqual(len(layer.fields), source.nfld)
+ self.assertEqual(source.nfld, layer.num_fields)
+ self.assertEqual(source.nfld, len(layer.fields))
+ # Testing the layer's extent (an Envelope), and it's properties
+ self.assertEqual(True, isinstance(layer.extent, Envelope))
+ self.assertAlmostEqual(source.extent[0], layer.extent.min_x, 5)
+ self.assertAlmostEqual(source.extent[1], layer.extent.min_y, 5)
+ self.assertAlmostEqual(source.extent[2], layer.extent.max_x, 5)
+ self.assertAlmostEqual(source.extent[3], layer.extent.max_y, 5)
+
# Now checking the field names.
flds = layer.fields
for f in flds: self.assertEqual(True, f in source.fields)
@@ -113,7 +123,7 @@
# Making sure the SpatialReference is as expected.
self.assertEqual(source.srs_wkt, g.srs.wkt)
-
+
def suite():
s = unittest.TestSuite()
s.addTest(unittest.makeSuite(DataSourceTest))
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups
"Django updates" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at
http://groups.google.com/group/django-updates?hl=en
-~----------~----~----~----~------~----~------~--~---