diff --git a/django/contrib/gis/geos/__init__.py b/django/contrib/gis/geos/__init__.py index 832b8906e6..6d746dfd4a 100644 --- a/django/contrib/gis/geos/__init__.py +++ b/django/contrib/gis/geos/__init__.py @@ -34,9 +34,9 @@ from geometries import Point, LineString, LinearRing, Polygon, HAS_NUMPY from collections import GeometryCollection, MultiPoint, MultiLineString, MultiPolygon from error import GEOSException, GEOSGeometryIndexError -def fromstr(wkt_or_hex): +def fromstr(wkt_or_hex, **kwargs): "Given a string value (wkt or hex), returns a GEOSGeometry object." - return GEOSGeometry(wkt_or_hex) + return GEOSGeometry(wkt_or_hex, **kwargs) def hex_to_wkt(hex): "Converts HEXEWKB into WKT." diff --git a/django/contrib/gis/geos/base.py b/django/contrib/gis/geos/base.py index 274d4c146b..fdc52e1b2b 100644 --- a/django/contrib/gis/geos/base.py +++ b/django/contrib/gis/geos/base.py @@ -12,7 +12,7 @@ from types import StringType, IntType, FloatType # Python and 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.libgeos import lgeos, GEOSPointer, HAS_NUMPY, ISQLQuote 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 @@ -24,7 +24,7 @@ class GEOSGeometry(object): "A class that, generally, encapsulates a GEOS geometry." #### Python 'magic' routines #### - def __init__(self, geo_input, input_type=False, parent=False): + def __init__(self, geo_input, input_type=False, parent=None, srid=None): """The constructor for GEOS geometry objects. May take the following strings as inputs, WKT ("wkt"), HEXEWKB ("hex", PostGIS-specific canonical form). @@ -72,6 +72,9 @@ class GEOSGeometry(object): else: self._parent = GEOSPointer(0) + # Setting the SRID, if given. + if srid and isinstance(srid, int): self.srid = srid + # Setting the class type (e.g., 'Point', 'Polygon', etc.) self.__class__ = GEOS_CLASSES[self.geom_type] @@ -126,6 +129,18 @@ class GEOSGeometry(object): def __xor__(self, other): "Return the symmetric difference of this Geometry and the other." return self.sym_difference(other) + + #### Psycopg2 database adaptor routines #### + def __conform__(self, proto): + # Does the given protocol conform to what Psycopg2 expects? + if proto == ISQLQuote: + return self + else: + raise GEOSException, 'Error implementing psycopg2 protocol. Is psycopg2 installed?' + + def getquoted(self): + "Returns a properly quoted string for use in PostgresSQL/PostGIS." + return "GeometryFromText('%s', %s)" % (self.wkt, self.srid or -1) #### Coordinate Sequence Routines #### @property diff --git a/django/contrib/gis/geos/collections.py b/django/contrib/gis/geos/collections.py index 9105b34b2f..070147837d 100644 --- a/django/contrib/gis/geos/collections.py +++ b/django/contrib/gis/geos/collections.py @@ -28,7 +28,7 @@ class GeometryCollection(GEOSGeometry): _allowed = (Point, LineString, LinearRing, Polygon) _typeid = 7 - def __init__(self, *args): + def __init__(self, *args, **kwargs): self._ptr = GEOSPointer(0) # Initially NULL self._geoms = {} self._parent = False @@ -61,7 +61,7 @@ class GeometryCollection(GEOSGeometry): geoms[i] = cast(init_from_geom(init_geoms[i]), GEOM_PTR) # Calling the parent class, using the pointer returned from GEOS createCollection() - super(GeometryCollection, self).__init__(lgeos.GEOSGeom_createCollection(c_int(self._typeid), byref(geoms), c_uint(ngeom))) + super(GeometryCollection, self).__init__(lgeos.GEOSGeom_createCollection(c_int(self._typeid), byref(geoms), c_uint(ngeom)), **kwargs) def __del__(self): "Overloaded deletion method for Geometry Collections." @@ -85,7 +85,7 @@ class GeometryCollection(GEOSGeometry): "For indexing on the multiple geometries." # Checking the index and returning the corresponding GEOS geometry. self._checkindex(index) - return GEOSGeometry(self._geoms[index], parent=self._ptr) + return GEOSGeometry(self._geoms[index], parent=self._ptr, srid=self.srid) def __iter__(self): "For iteration on the multiple geometries." diff --git a/django/contrib/gis/geos/geometries.py b/django/contrib/gis/geos/geometries.py index cdd3d49922..635297e58b 100644 --- a/django/contrib/gis/geos/geometries.py +++ b/django/contrib/gis/geos/geometries.py @@ -14,7 +14,7 @@ if HAS_NUMPY: from numpy import ndarray, array class Point(GEOSGeometry): - def __init__(self, x, y=None, z=None): + def __init__(self, x, y=None, z=None, srid=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 @@ -56,7 +56,7 @@ class Point(GEOSGeometry): 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)) + super(Point, self).__init__(lgeos.GEOSGeom_createPoint(cs), srid=srid) def __len__(self): "Returns the number of dimensions for this Point (either 2 or 3)." @@ -175,9 +175,12 @@ class LineString(GEOSGeometry): func = lgeos.GEOSGeom_createLinearRing else: func = lgeos.GEOSGeom_createLineString + + # If SRID was passed in with the keyword arguments + srid = kwargs.get('srid', None) # Calling the base geometry initialization with the returned pointer from the function. - super(LineString, self).__init__(func(cs._ptr.coordseq())) + super(LineString, self).__init__(func(cs._ptr.coordseq()), srid=srid) def __getitem__(self, index): "Gets the point at the specified index." @@ -235,14 +238,14 @@ class LineString(GEOSGeometry): # LinearRings are LineStrings used within Polygons. class LinearRing(LineString): - def __init__(self, *args): + def __init__(self, *args, **kwargs): "Overriding the initialization function to set the ring keyword." - kwargs = {'ring' : True} + kwargs['ring'] = True # Setting the ring keyword argument to True super(LinearRing, self).__init__(*args, **kwargs) class Polygon(GEOSGeometry): - def __init__(self, *args): + def __init__(self, *args, **kwargs): """Initializes on an exterior ring and a sequence of holes (both instances of LinearRings. All LinearRing instances used for creation will become owned by this Polygon. @@ -280,7 +283,7 @@ class Polygon(GEOSGeometry): shell = init_from_geom(ext_ring) # Calling with the GEOS createPolygon factory. - super(Polygon, self).__init__(lgeos.GEOSGeom_createPolygon(shell, byref(holes), c_uint(nholes))) + super(Polygon, self).__init__(lgeos.GEOSGeom_createPolygon(shell, byref(holes), c_uint(nholes)), **kwargs) def __del__(self): "Overloaded deletion method for Polygons." @@ -340,7 +343,7 @@ class Polygon(GEOSGeometry): # Returning the ring from the internal ring dictionary (have to # add one to the index) - return GEOSGeometry(self._rings[ring_i+1], parent=self._ptr) + return GEOSGeometry(self._rings[ring_i+1], parent=self._ptr, srid=self.srid) #### Polygon Properties #### @property @@ -356,7 +359,7 @@ class Polygon(GEOSGeometry): def get_ext_ring(self): "Gets the exterior ring of the Polygon." - return GEOSGeometry(self._rings[0], parent=self._ptr) + return GEOSGeometry(self._rings[0], parent=self._ptr, srid=self.srid) def set_ext_ring(self): "Sets the exterior ring of the Polygon." diff --git a/django/contrib/gis/geos/libgeos.py b/django/contrib/gis/geos/libgeos.py index 141d3fa55c..6728da3d29 100644 --- a/django/contrib/gis/geos/libgeos.py +++ b/django/contrib/gis/geos/libgeos.py @@ -2,6 +2,9 @@ This module houses the ctypes initialization procedures, as well as the notice and error handler function callbacks (get called when an error occurs in GEOS). + + This module also houses GEOS Pointer utilities, including the + GEOSPointer class, get_pointer_arr(), GEOM_PTR, and init_from_geom(). """ from django.contrib.gis.geos.error import GEOSException @@ -15,6 +18,12 @@ try: except ImportError: HAS_NUMPY = False +# Psycopg2 supported? +try: + from psycopg2.extensions import ISQLQuote +except ImportError: + ISQLQuote = None + # Setting the appropriate name for the GEOS-C library, depending on which # OS and POSIX platform we're running. if os.name == 'nt': @@ -118,7 +127,7 @@ class GEOSPointer(object): if bool(self.address): return True else: return False - ### Coordinate Sequence properties ### + ### Coordinate Sequence routines and properties ### def coordseq(self): "If the coordinate sequence pointer is NULL (0), an exception will be raised." if self.coordseq_valid: return self.coordseq_address