summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJustin Bronn <jbronn@gmail.com>2007-07-12 06:05:42 +0000
committerJustin Bronn <jbronn@gmail.com>2007-07-12 06:05:42 +0000
commit382632a26e0b4446d45f8a43bb0bc01dbc05d798 (patch)
treef16884395d6c47201b6a8a8fa82728d25c0a28da
parent342dbc6738d5a7bccb7f1d2c7b6d9c2fbbc9496d (diff)
gis: no more camelcase module names; GEOSGeometry now autodetects WKT or HEXEWKB (hex).
git-svn-id: http://code.djangoproject.com/svn/django/branches/gis@5655 bcc190cf-cafb-0310-a4f2-bffc1f526a37
-rw-r--r--django/contrib/gis/geos/__init__.py17
-rw-r--r--django/contrib/gis/geos/base.py (renamed from django/contrib/gis/geos/GEOSGeometry.py)352
-rw-r--r--django/contrib/gis/geos/coordseq.py (renamed from django/contrib/gis/geos/GEOSCoordSeq.py)2
-rw-r--r--django/contrib/gis/geos/error.py (renamed from django/contrib/gis/geos/GEOSError.py)0
-rw-r--r--django/contrib/gis/geos/libgeos.py2
-rw-r--r--django/contrib/gis/tests/test_geos.py2
6 files changed, 31 insertions, 344 deletions
diff --git a/django/contrib/gis/geos/__init__.py b/django/contrib/gis/geos/__init__.py
index d6ba06ca7a..12714ed94a 100644
--- a/django/contrib/gis/geos/__init__.py
+++ b/django/contrib/gis/geos/__init__.py
@@ -29,22 +29,23 @@
http://zcologia.com/news/429/geometries-for-python-update/
"""
-from GEOSGeometry import GEOSGeometry, Point, LineString, LinearRing, HAS_NUMPY
-from GEOSError import GEOSException
+from base import GEOSGeometry
+from geometries import Point, LineString, LinearRing, HAS_NUMPY
+from error import GEOSException
def hex_to_wkt(hex):
"Converts HEXEWKB into WKT."
- return GEOSGeometry(hex, 'hex').wkt
+ return GEOSGeometry(hex).wkt
def wkt_to_hex(wkt):
"Converts WKT into HEXEWKB."
- return GEOSGeometry(wkt, 'wkt').hex
+ return GEOSGeometry(wkt).hex
-def centroid(input, geom_type='hex'):
+def centroid(input):
"Returns the centroid of the geometry (given in HEXEWKB)."
- return GEOSGeometry(input, geom_type).centroid.wkt
+ return GEOSGeometry(input).centroid.wkt
-def area(input, geom_type='hex'):
+def area(input):
"Returns the area of the geometry (given in HEXEWKB)."
- return GEOSGeometry(input, geom_type).area
+ return GEOSGeometry(input).area
diff --git a/django/contrib/gis/geos/GEOSGeometry.py b/django/contrib/gis/geos/base.py
index 8ee2b566b6..ef4c81118e 100644
--- a/django/contrib/gis/geos/GEOSGeometry.py
+++ b/django/contrib/gis/geos/base.py
@@ -1,26 +1,31 @@
# Trying not to pollute the namespace.
from ctypes import \
byref, string_at, create_string_buffer, pointer, \
- c_char_p, c_double, c_float, c_int, c_uint, c_size_t
+ c_char_p, c_double, c_int, c_size_t
from types import StringType, IntType, FloatType, TupleType, ListType
# Getting GEOS-related dependencies.
+import re
+from warnings import warn
from django.contrib.gis.geos.libgeos import lgeos, GEOSPointer, HAS_NUMPY
-from django.contrib.gis.geos.GEOSError import GEOSException
-from django.contrib.gis.geos.GEOSCoordSeq import GEOSCoordSeq, create_cs
+from django.contrib.gis.geos.error import GEOSException, GEOSGeometryIndexError
+from django.contrib.gis.geos.coordseq import GEOSCoordSeq, create_cs
if HAS_NUMPY:
from numpy import ndarray, array
+# For recognizing HEXEWKB.
+hex_regex = re.compile(r'^[0-9A-Fa-f]+')
+
class GEOSGeometry(object):
"A class that, generally, encapsulates a GEOS geometry."
#### Python 'magic' routines ####
- def __init__(self, geo_input, input_type='wkt', child=False):
+ def __init__(self, geo_input, input_type=False, child=False):
"""The constructor for GEOS geometry objects. May take the following
strings as inputs, WKT ("wkt"), HEXEWKB ("hex", PostGIS-specific canonical form).
- When a hex string is to be used, the `input_type` keyword should be set with 'hex'.
+ The `input_type` keyword has been deprecated -- geometry type is now auto-detected.
The `child` keyword is for internal use only, and indicates to the garbage collector
not to delete this geometry if it was spawned from a parent (e.g., the exterior
@@ -31,16 +36,17 @@ class GEOSGeometry(object):
self._ptr = GEOSPointer(0)
if isinstance(geo_input, StringType):
- if input_type == 'wkt':
- # If the geometry is in WKT form
- g = lgeos.GEOSGeomFromWKT(c_char_p(geo_input))
- elif input_type == 'hex':
- # If the geometry is in HEX form.
+ if input_type: warn('input_type keyword is deprecated')
+
+ if hex_regex.match(geo_input):
+ # If the regex matches, the geometry is in HEX form.
sz = c_size_t(len(geo_input))
buf = create_string_buffer(geo_input)
g = lgeos.GEOSGeomFromHEX_buf(buf, sz)
else:
- raise TypeError, 'GEOS input geometry type "%s" not supported.' % input_type
+ # Otherwise, the geometry is in WKT form.
+ g = lgeos.GEOSGeomFromWKT(c_char_p(geo_input))
+
elif isinstance(geo_input, (IntType, GEOSPointer)):
# When the input is either a raw pointer value (an integer), or a GEOSPointer object.
g = geo_input
@@ -339,329 +345,9 @@ class GEOSGeometry(object):
"Clones this Geometry."
return GEOSGeometry(lgeos.GEOSGeom_clone(self._ptr()))
-class Point(GEOSGeometry):
-
- def __init__(self, x, y=None, z=None):
- """The Point object may be initialized with either a tuple, or individual
- parameters. For example:
- >>> p = Point((5, 23)) # 2D point, passed in as a tuple
- >>> p = Point(5, 23, 8) # 3D point, passed in with individual parameters
- """
-
- if isinstance(x, (TupleType, ListType)):
- # Here a tuple or list was passed in under the ``x`` parameter.
- ndim = len(x)
- if ndim < 2 or ndim > 3:
- raise TypeError, 'Invalid sequence parameter: %s' % str(x)
- coords = x
- elif isinstance(x, (IntType, FloatType)) and isinstance(y, (IntType, FloatType)):
- # Here X, Y, and (optionally) Z were passed in individually as parameters.
- if isinstance(z, (IntType, FloatType)):
- ndim = 3
- coords = [x, y, z]
- else:
- ndim = 2
- coords = [x, y]
- else:
- raise TypeError, 'Invalid parameters given for Point initialization.'
-
- # Creating the coordinate sequence
- cs = create_cs(c_uint(1), c_uint(ndim))
-
- # Setting the X
- status = lgeos.GEOSCoordSeq_setX(cs, c_uint(0), c_double(coords[0]))
- if not status: raise GEOSException, 'Could not set X during Point initialization.'
-
- # Setting the Y
- status = lgeos.GEOSCoordSeq_setY(cs, c_uint(0), c_double(coords[1]))
- if not status: raise GEOSException, 'Could not set Y during Point initialization.'
-
- # Setting the Z
- if ndim == 3:
- status = lgeos.GEOSCoordSeq_setZ(cs, c_uint(0), c_double(coords[2]))
-
- # Initializing from the geometry, and getting a Python object
- super(Point, self).__init__(lgeos.GEOSGeom_createPoint(cs))
-
- def _getOrdinate(self, dim, idx):
- "The coordinate sequence getOrdinate() wrapper."
- self._cache_cs()
- return self._cs.getOrdinate(dim, idx)
-
- def _setOrdinate(self, dim, idx, value):
- "The coordinate sequence setOrdinate() wrapper."
- self._cache_cs()
- self._cs.setOrdinate(dim, idx, value)
-
- def get_x(self):
- "Returns the X component of the Point."
- return self._getOrdinate(0, 0)
-
- def set_x(self, value):
- "Sets the X component of the Point."
- self._setOrdinate(0, 0, value)
-
- def get_y(self):
- "Returns the Y component of the Point."
- return self._getOrdinate(1, 0)
-
- def set_y(self, value):
- "Sets the Y component of the Point."
- self._setOrdinate(1, 0, value)
-
- def get_z(self):
- "Returns the Z component of the Point."
- if self.hasz:
- return self._getOrdinate(2, 0)
- else:
- return None
-
- def set_z(self, value):
- "Sets the Z component of the Point."
- if self.hasz:
- self._setOrdinate(2, 0, value)
- else:
- raise GEOSException, 'Cannot set Z on 2D Point.'
-
- # X, Y, Z properties
- x = property(get_x, set_x)
- y = property(get_y, set_y)
- z = property(get_z, set_z)
-
- @property
- def tuple(self):
- "Returns a tuple of the point."
- self._cache_cs()
- return self._cs.tuple
-
-class LineString(GEOSGeometry):
-
- #### Python 'magic' routines ####
- def __init__(self, coords, ring=False):
- """Initializes on the given sequence, may take lists, tuples, or NumPy arrays
- of X,Y pairs."""
-
- if isinstance(coords, (TupleType, ListType)):
- ncoords = len(coords)
- first = True
- for coord in coords:
- if not isinstance(coord, (TupleType, ListType)):
- raise TypeError, 'each coordinate should be a sequence (list or tuple)'
- if first:
- ndim = len(coord)
- self._checkdim(ndim)
- first = False
- else:
- if len(coord) != ndim: raise TypeError, 'Dimension mismatch.'
- numpy_coords = False
- elif HAS_NUMPY and isinstance(coords, ndarray):
- shape = coords.shape
- if len(shape) != 2: raise TypeError, 'Too many dimensions.'
- self._checkdim(shape[1])
- ncoords = shape[0]
- ndim = shape[1]
- numpy_coords = True
- else:
- raise TypeError, 'Invalid initialization input for LineStrings.'
-
- # Creating the coordinate sequence
- cs = GEOSCoordSeq(GEOSPointer(create_cs(c_uint(ncoords), c_uint(ndim))))
-
- # Setting each point in the coordinate sequence
- for i in xrange(ncoords):
- if numpy_coords: cs[i] = coords[i,:]
- else: cs[i] = coords[i]
-
- # Getting the initialization function
- if ring:
- func = lgeos.GEOSGeom_createLinearRing
- else:
- func = lgeos.GEOSGeom_createLineString
-
- # Calling the base geometry initialization with the returned pointer from the function.
- super(LineString, self).__init__(func(cs._ptr()))
-
- def __getitem__(self, index):
- "Gets the point at the specified index."
- self._cache_cs()
- return self._cs[index]
-
- def __setitem__(self, index, value):
- "Sets the point at the specified index, e.g., line_str[0] = (1, 2)."
- self._cache_cs()
- self._cs[index] = value
-
- def __iter__(self):
- "Allows iteration over this LineString."
- for i in xrange(self.__len__()):
- yield self.__getitem__(index)
-
- def __len__(self):
- "Returns the number of points in this LineString."
- self._cache_cs()
- return len(self._cs)
-
- def _checkdim(self, dim):
- if dim not in (2, 3): raise TypeError, 'Dimension mismatch.'
-
- #### Sequence Properties ####
- @property
- def tuple(self):
- "Returns a tuple version of the geometry from the coordinate sequence."
- self._cache_cs()
- return self._cs.tuple
-
- def _listarr(self, func):
- """Internal routine that returns a sequence (list) corresponding with
- the given function. Will return a numpy array if possible."""
- lst = [func(i) for i in xrange(self.__len__())] # constructing the list, using the function
- if HAS_NUMPY: return array(lst) # ARRRR!
- else: return lst
-
- @property
- def array(self):
- "Returns a numpy array for the LineString."
- self._cache_cs()
- return self._listarr(self._cs.__getitem__)
-
- @property
- def x(self):
- "Returns a list or numpy array of the X variable."
- self._cache_cs()
- return self._listarr(self._cs.getX)
-
- @property
- def y(self):
- "Returns a list or numpy array of the Y variable."
- self._cache_cs()
- return self._listarr(self._cs.getY)
-
- @property
- def z(self):
- "Returns a list or numpy array of the Z variable."
- self._cache_cs()
- if not self.hasz: return None
- else: return self._listarr(self._cs.getZ)
-
-# LinearRings are LineStrings used within Polygons.
-class LinearRing(LineString):
- def __init__(self, coords):
- "Overriding the initialization function to set the ring keyword."
- super(LinearRing, self).__init__(coords, ring=True)
-
-class Polygon(GEOSGeometry):
-
- def __del__(self):
- "Override the GEOSGeometry delete routine to safely take care of any spawned rings."
- # Nullifying the pointers to internal rings, preventing any attempted future access
- for k in self._rings: self._rings[k].nullify()
- super(Polygon, self).__del__() # Calling the parent __del__() method.
-
- def __getitem__(self, index):
- """Returns the ring at the specified index. The first index, 0, will always
- return the exterior ring. Indices > 0 will return the interior ring."""
- if index < 0 or index > self.num_interior_rings:
- raise GEOSGeometryIndexError, 'invalid GEOS Geometry index: %s' % str(index)
- else:
- if index == 0:
- return self.exterior_ring
- else:
- # Getting the interior ring, have to subtract 1 from the index.
- return self.get_interior_ring(index-1)
-
- def __iter__(self):
- "Iterates over each ring in the polygon."
- for i in xrange(self.__len__()):
- yield self.__getitem__(i)
-
- def __len__(self):
- "Returns the number of rings in this Polygon."
- return self.num_interior_rings + 1
-
- def get_interior_ring(self, ring_i):
- """Gets the interior ring at the specified index,
- 0 is for the first interior ring, not the exterior ring."""
-
- # Making sure the ring index is within range
- if ring_i < 0 or ring_i >= self.num_interior_rings:
- raise IndexError, 'ring index out of range'
-
- # Placing the ring in internal rings dictionary.
- idx = ring_i+1 # the index for the polygon is +1 because of the exterior ring
- if not idx in self._rings:
- self._rings[idx] = GEOSPointer(lgeos.GEOSGetInteriorRingN(self._ptr(), c_int(ring_i)))
-
- # Returning the ring at the given index.
- return GEOSGeometry(self._rings[idx], child=True)
-
- #### Polygon Properties ####
- @property
- def num_interior_rings(self):
- "Returns the number of interior rings."
-
- # Getting the number of rings
- n = lgeos.GEOSGetNumInteriorRings(self._ptr())
-
- # -1 indicates an exception occurred
- if n == -1: raise GEOSException, 'Error getting the number of interior rings.'
- else: return n
-
- @property
- def exterior_ring(self):
- "Gets the exterior ring of the Polygon."
- # Returns exterior ring
- self._rings[0] = GEOSPointer(lgeos.GEOSGetExteriorRing((self._ptr())))
- return GEOSGeometry(self._rings[0], child=True)
-
- @property
- def shell(self):
- "Gets the shell (exterior ring) of the Polygon."
- return self.exterior_ring
-
- @property
- def tuple(self):
- "Gets the tuple for each ring in this Polygon."
- return tuple(self.__getitem__(i).tuple for i in xrange(self.__len__()))
-
-class GeometryCollection(GEOSGeometry):
-
- def __del__(self):
- "Override the GEOSGeometry delete routine to safely take care of any spawned geometries."
- # Nullifying the pointers to internal geometries, preventing any attempted future access
- for k in self._geoms: self._geoms[k].nullify()
- super(GeometryCollection, self).__del__() # Calling the parent __del__() method.
-
- def __getitem__(self, index):
- "For indexing on the multiple geometries."
- self._checkindex(index)
-
- # Setting an entry in the _geoms dictionary for the requested geometry.
- if not index in self._geoms:
- self._geoms[index] = GEOSPointer(lgeos.GEOSGetGeometryN(self._ptr(), c_int(index)))
-
- # Cloning the GEOS Geometry first, before returning it.
- return GEOSGeometry(self._geoms[index], child=True)
-
- def __iter__(self):
- "For iteration on the multiple geometries."
- for i in xrange(self.__len__()):
- yield self.__getitem__(i)
-
- def __len__(self):
- "Returns the number of geometries in this collection."
- return self.num_geom
-
- def _checkindex(self, index):
- "Checks the given geometry index."
- if index < 0 or index >= self.num_geom:
- raise GEOSGeometryIndexError, 'invalid GEOS Geometry index: %s' % str(index)
-
-# MultiPoint, MultiLineString, and MultiPolygon class definitions.
-class MultiPoint(GeometryCollection): pass
-class MultiLineString(GeometryCollection): pass
-class MultiPolygon(GeometryCollection): pass
-
# Class mapping dictionary
+from django.contrib.gis.geos.geometries import Point, Polygon, LineString, LinearRing
+from django.contrib.gis.geos.collections import GeometryCollection, MultiPoint, MultiLineString, MultiPolygon
GEOS_CLASSES = {'Point' : Point,
'Polygon' : Polygon,
'LineString' : LineString,
diff --git a/django/contrib/gis/geos/GEOSCoordSeq.py b/django/contrib/gis/geos/coordseq.py
index faacccc471..eba49f768b 100644
--- a/django/contrib/gis/geos/GEOSCoordSeq.py
+++ b/django/contrib/gis/geos/coordseq.py
@@ -1,5 +1,5 @@
from django.contrib.gis.geos.libgeos import lgeos
-from django.contrib.gis.geos.GEOSError import GEOSException, GEOSGeometryIndexError
+from django.contrib.gis.geos.error import GEOSException, GEOSGeometryIndexError
from ctypes import c_double, c_int, c_uint, byref
"""
diff --git a/django/contrib/gis/geos/GEOSError.py b/django/contrib/gis/geos/error.py
index 219a71929c..219a71929c 100644
--- a/django/contrib/gis/geos/GEOSError.py
+++ b/django/contrib/gis/geos/error.py
diff --git a/django/contrib/gis/geos/libgeos.py b/django/contrib/gis/geos/libgeos.py
index 17c8898cf6..f0d8642e59 100644
--- a/django/contrib/gis/geos/libgeos.py
+++ b/django/contrib/gis/geos/libgeos.py
@@ -4,7 +4,7 @@
when an error occurs in GEOS).
"""
-from django.contrib.gis.geos.GEOSError import GEOSException
+from django.contrib.gis.geos.error import GEOSException
from ctypes import \
c_char_p, c_int, c_size_t, c_ubyte, pointer, addressof, \
CDLL, CFUNCTYPE, POINTER, Structure
diff --git a/django/contrib/gis/tests/test_geos.py b/django/contrib/gis/tests/test_geos.py
index b356cac208..103c789f55 100644
--- a/django/contrib/gis/tests/test_geos.py
+++ b/django/contrib/gis/tests/test_geos.py
@@ -24,7 +24,7 @@ class GEOSTest(unittest.TestCase):
print "\nBEGIN - expecting GEOS_ERROR; safe to ignore.\n"
for err in errors:
if err.hex:
- self.assertRaises(GEOSException, GEOSGeometry, err.wkt, 'hex')
+ self.assertRaises(GEOSException, GEOSGeometry, err.wkt)
else:
self.assertRaises(GEOSException, GEOSGeometry, err.wkt)
print "\nEND - expecting GEOS_ERROR; safe to ignore.\n"