web/lib/django/contrib/gis/geos/geometry.py
changeset 29 cc9b7e14412b
parent 0 0d40e90630ef
--- a/web/lib/django/contrib/gis/geos/geometry.py	Wed May 19 17:43:59 2010 +0200
+++ b/web/lib/django/contrib/gis/geos/geometry.py	Tue May 25 02:43:45 2010 +0200
@@ -21,11 +21,12 @@
 # the underlying GEOS library.
 from django.contrib.gis.geos import prototypes as capi
 
-# Regular expression for recognizing HEXEWKB and WKT.  A prophylactic measure
-# to prevent potentially malicious input from reaching the underlying C
-# library.  Not a substitute for good web security programming practices.
-hex_regex = re.compile(r'^[0-9A-F]+$', re.I)
-wkt_regex = re.compile(r'^(SRID=(?P<srid>\d+);)?(?P<wkt>(POINT|LINESTRING|LINEARRING|POLYGON|MULTIPOINT|MULTILINESTRING|MULTIPOLYGON|GEOMETRYCOLLECTION)[ACEGIMLONPSRUTY\d,\.\-\(\) ]+)$', re.I)
+# These functions provide access to a thread-local instance
+# of their corresponding GEOS I/O class.
+from django.contrib.gis.geos.prototypes.io import wkt_r, wkt_w, wkb_r, wkb_w, ewkb_w, ewkb_w3d
+
+# For recognizing geometry input.
+from django.contrib.gis.geometry.regex import hex_regex, wkt_regex, json_regex
 
 class GEOSGeometry(GEOSBase, ListMixin):
     "A class that, generally, encapsulates a GEOS geometry."
@@ -61,13 +62,13 @@
             if wkt_m:
                 # Handling WKT input.
                 if wkt_m.group('srid'): srid = int(wkt_m.group('srid'))
-                g = wkt_r.read(wkt_m.group('wkt'))
+                g = wkt_r().read(wkt_m.group('wkt'))
             elif hex_regex.match(geo_input):
                 # Handling HEXEWKB input.
-                g = wkb_r.read(geo_input)
-            elif gdal.GEOJSON and gdal.geometries.json_regex.match(geo_input):
+                g = wkb_r().read(geo_input)
+            elif gdal.GEOJSON and json_regex.match(geo_input):
                 # Handling GeoJSON input.
-                g = wkb_r.read(gdal.OGRGeometry(geo_input).wkb)
+                g = wkb_r().read(gdal.OGRGeometry(geo_input).wkb)
             else:
                 raise ValueError('String or unicode input unrecognized as WKT EWKT, and HEXEWKB.')
         elif isinstance(geo_input, GEOM_PTR):
@@ -75,7 +76,7 @@
             g = geo_input
         elif isinstance(geo_input, buffer):
             # When the input is a buffer (WKB).
-            g = wkb_r.read(geo_input)
+            g = wkb_r().read(geo_input)
         elif isinstance(geo_input, GEOSGeometry):
             g = capi.geom_clone(geo_input.ptr)
         else:
@@ -142,7 +143,7 @@
     def __setstate__(self, state):
         # Instantiating from the tuple state that was pickled.
         wkb, srid = state
-        ptr = capi.from_wkb(wkb, len(wkb))
+        ptr = wkb_r().read(buffer(wkb))
         if not ptr: raise GEOSException('Invalid Geometry loaded from pickled state.')
         self.ptr = ptr
         self._post_init(srid)
@@ -357,25 +358,45 @@
     #### Output Routines ####
     @property
     def ewkt(self):
-        "Returns the EWKT (WKT + SRID) of the Geometry."
+        """
+        Returns the EWKT (WKT + SRID) of the Geometry.  Note that Z values
+        are *not* included in this representation because GEOS does not yet
+        support serializing them.
+        """
         if self.get_srid(): return 'SRID=%s;%s' % (self.srid, self.wkt)
         else: return self.wkt
 
     @property
     def wkt(self):
-        "Returns the WKT (Well-Known Text) of the Geometry."
-        return wkt_w.write(self)
+        "Returns the WKT (Well-Known Text) representation of this Geometry."
+        return wkt_w().write(self)
 
     @property
     def hex(self):
         """
-        Returns the HEX of the Geometry -- please note that the SRID is not
-        included in this representation, because the GEOS C library uses
-        -1 by default, even if the SRID is set.
+        Returns the WKB of this Geometry in hexadecimal form.  Please note
+        that the SRID and Z values are not included in this representation
+        because it is not a part of the OGC specification (use the `hexewkb` 
+        property instead).
         """
         # A possible faster, all-python, implementation:
         #  str(self.wkb).encode('hex')
-        return wkb_w.write_hex(self)
+        return wkb_w().write_hex(self)
+
+    @property
+    def hexewkb(self):
+        """
+        Returns the EWKB of this Geometry in hexadecimal form.  This is an 
+        extension of the WKB specification that includes SRID and Z values 
+        that are a part of this geometry.
+        """
+        if self.hasz:
+            if not GEOS_PREPARE:
+                # See: http://trac.osgeo.org/geos/ticket/216
+                raise GEOSException('Upgrade GEOS to 3.1 to get valid 3D HEXEWKB.')               
+            return ewkb_w3d().write_hex(self)
+        else:
+            return ewkb_w().write_hex(self)
 
     @property
     def json(self):
@@ -383,7 +404,7 @@
         Returns GeoJSON representation of this Geometry if GDAL 1.5+
         is installed.
         """
-        if gdal.GEOJSON: 
+        if gdal.GEOJSON:
             return self.ogr.json
         else:
             raise GEOSException('GeoJSON output only supported on GDAL 1.5+.')
@@ -391,8 +412,27 @@
 
     @property
     def wkb(self):
-        "Returns the WKB of the Geometry as a buffer."
-        return wkb_w.write(self)
+        """
+        Returns the WKB (Well-Known Binary) representation of this Geometry
+        as a Python buffer.  SRID and Z values are not included, use the
+        `ewkb` property instead.
+        """
+        return wkb_w().write(self)
+
+    @property
+    def ewkb(self):
+        """
+        Return the EWKB representation of this Geometry as a Python buffer.
+        This is an extension of the WKB specification that includes any SRID
+        and Z values that are a part of this geometry.
+        """
+        if self.hasz:
+            if not GEOS_PREPARE:
+                # See: http://trac.osgeo.org/geos/ticket/216
+                raise GEOSException('Upgrade GEOS to 3.1 to get valid 3D EWKB.')
+            return ewkb_w3d().write(self)
+        else:
+            return ewkb_w().write(self)
 
     @property
     def kml(self):
@@ -454,7 +494,7 @@
             g = gdal.OGRGeometry(self.wkb, srid)
             g.transform(ct)
             # Getting a new GEOS pointer
-            ptr = wkb_r.read(g.wkb)
+            ptr = wkb_r().read(g.wkb)
             if clone:
                 # User wants a cloned transformed geometry returned.
                 return GEOSGeometry(ptr, srid=g.srid)
@@ -616,9 +656,6 @@
                 7 : GeometryCollection,
                 }
 
-# Similarly, import the GEOS I/O instances here to avoid conflicts.
-from django.contrib.gis.geos.io import wkt_r, wkt_w, wkb_r, wkb_w
-
 # If supported, import the PreparedGeometry class.
 if GEOS_PREPARE:
     from django.contrib.gis.geos.prepared import PreparedGeometry