web/lib/django/contrib/gis/geos/geometry.py
changeset 29 cc9b7e14412b
parent 0 0d40e90630ef
equal deleted inserted replaced
28:b758351d191f 29:cc9b7e14412b
    19 # All other functions in this module come from the ctypes
    19 # All other functions in this module come from the ctypes
    20 # prototypes module -- which handles all interaction with
    20 # prototypes module -- which handles all interaction with
    21 # the underlying GEOS library.
    21 # the underlying GEOS library.
    22 from django.contrib.gis.geos import prototypes as capi
    22 from django.contrib.gis.geos import prototypes as capi
    23 
    23 
    24 # Regular expression for recognizing HEXEWKB and WKT.  A prophylactic measure
    24 # These functions provide access to a thread-local instance
    25 # to prevent potentially malicious input from reaching the underlying C
    25 # of their corresponding GEOS I/O class.
    26 # library.  Not a substitute for good web security programming practices.
    26 from django.contrib.gis.geos.prototypes.io import wkt_r, wkt_w, wkb_r, wkb_w, ewkb_w, ewkb_w3d
    27 hex_regex = re.compile(r'^[0-9A-F]+$', re.I)
    27 
    28 wkt_regex = re.compile(r'^(SRID=(?P<srid>\d+);)?(?P<wkt>(POINT|LINESTRING|LINEARRING|POLYGON|MULTIPOINT|MULTILINESTRING|MULTIPOLYGON|GEOMETRYCOLLECTION)[ACEGIMLONPSRUTY\d,\.\-\(\) ]+)$', re.I)
    28 # For recognizing geometry input.
       
    29 from django.contrib.gis.geometry.regex import hex_regex, wkt_regex, json_regex
    29 
    30 
    30 class GEOSGeometry(GEOSBase, ListMixin):
    31 class GEOSGeometry(GEOSBase, ListMixin):
    31     "A class that, generally, encapsulates a GEOS geometry."
    32     "A class that, generally, encapsulates a GEOS geometry."
    32 
    33 
    33     # Raise GEOSIndexError instead of plain IndexError
    34     # Raise GEOSIndexError instead of plain IndexError
    59 
    60 
    60             wkt_m = wkt_regex.match(geo_input)
    61             wkt_m = wkt_regex.match(geo_input)
    61             if wkt_m:
    62             if wkt_m:
    62                 # Handling WKT input.
    63                 # Handling WKT input.
    63                 if wkt_m.group('srid'): srid = int(wkt_m.group('srid'))
    64                 if wkt_m.group('srid'): srid = int(wkt_m.group('srid'))
    64                 g = wkt_r.read(wkt_m.group('wkt'))
    65                 g = wkt_r().read(wkt_m.group('wkt'))
    65             elif hex_regex.match(geo_input):
    66             elif hex_regex.match(geo_input):
    66                 # Handling HEXEWKB input.
    67                 # Handling HEXEWKB input.
    67                 g = wkb_r.read(geo_input)
    68                 g = wkb_r().read(geo_input)
    68             elif gdal.GEOJSON and gdal.geometries.json_regex.match(geo_input):
    69             elif gdal.GEOJSON and json_regex.match(geo_input):
    69                 # Handling GeoJSON input.
    70                 # Handling GeoJSON input.
    70                 g = wkb_r.read(gdal.OGRGeometry(geo_input).wkb)
    71                 g = wkb_r().read(gdal.OGRGeometry(geo_input).wkb)
    71             else:
    72             else:
    72                 raise ValueError('String or unicode input unrecognized as WKT EWKT, and HEXEWKB.')
    73                 raise ValueError('String or unicode input unrecognized as WKT EWKT, and HEXEWKB.')
    73         elif isinstance(geo_input, GEOM_PTR):
    74         elif isinstance(geo_input, GEOM_PTR):
    74             # When the input is a pointer to a geomtry (GEOM_PTR).
    75             # When the input is a pointer to a geomtry (GEOM_PTR).
    75             g = geo_input
    76             g = geo_input
    76         elif isinstance(geo_input, buffer):
    77         elif isinstance(geo_input, buffer):
    77             # When the input is a buffer (WKB).
    78             # When the input is a buffer (WKB).
    78             g = wkb_r.read(geo_input)
    79             g = wkb_r().read(geo_input)
    79         elif isinstance(geo_input, GEOSGeometry):
    80         elif isinstance(geo_input, GEOSGeometry):
    80             g = capi.geom_clone(geo_input.ptr)
    81             g = capi.geom_clone(geo_input.ptr)
    81         else:
    82         else:
    82             # Invalid geometry type.
    83             # Invalid geometry type.
    83             raise TypeError('Improper geometry input type: %s' % str(type(geo_input)))
    84             raise TypeError('Improper geometry input type: %s' % str(type(geo_input)))
   140         return str(self.wkb), self.srid
   141         return str(self.wkb), self.srid
   141 
   142 
   142     def __setstate__(self, state):
   143     def __setstate__(self, state):
   143         # Instantiating from the tuple state that was pickled.
   144         # Instantiating from the tuple state that was pickled.
   144         wkb, srid = state
   145         wkb, srid = state
   145         ptr = capi.from_wkb(wkb, len(wkb))
   146         ptr = wkb_r().read(buffer(wkb))
   146         if not ptr: raise GEOSException('Invalid Geometry loaded from pickled state.')
   147         if not ptr: raise GEOSException('Invalid Geometry loaded from pickled state.')
   147         self.ptr = ptr
   148         self.ptr = ptr
   148         self._post_init(srid)
   149         self._post_init(srid)
   149 
   150 
   150     # Comparison operators
   151     # Comparison operators
   355     srid = property(get_srid, set_srid)
   356     srid = property(get_srid, set_srid)
   356 
   357 
   357     #### Output Routines ####
   358     #### Output Routines ####
   358     @property
   359     @property
   359     def ewkt(self):
   360     def ewkt(self):
   360         "Returns the EWKT (WKT + SRID) of the Geometry."
   361         """
       
   362         Returns the EWKT (WKT + SRID) of the Geometry.  Note that Z values
       
   363         are *not* included in this representation because GEOS does not yet
       
   364         support serializing them.
       
   365         """
   361         if self.get_srid(): return 'SRID=%s;%s' % (self.srid, self.wkt)
   366         if self.get_srid(): return 'SRID=%s;%s' % (self.srid, self.wkt)
   362         else: return self.wkt
   367         else: return self.wkt
   363 
   368 
   364     @property
   369     @property
   365     def wkt(self):
   370     def wkt(self):
   366         "Returns the WKT (Well-Known Text) of the Geometry."
   371         "Returns the WKT (Well-Known Text) representation of this Geometry."
   367         return wkt_w.write(self)
   372         return wkt_w().write(self)
   368 
   373 
   369     @property
   374     @property
   370     def hex(self):
   375     def hex(self):
   371         """
   376         """
   372         Returns the HEX of the Geometry -- please note that the SRID is not
   377         Returns the WKB of this Geometry in hexadecimal form.  Please note
   373         included in this representation, because the GEOS C library uses
   378         that the SRID and Z values are not included in this representation
   374         -1 by default, even if the SRID is set.
   379         because it is not a part of the OGC specification (use the `hexewkb` 
       
   380         property instead).
   375         """
   381         """
   376         # A possible faster, all-python, implementation:
   382         # A possible faster, all-python, implementation:
   377         #  str(self.wkb).encode('hex')
   383         #  str(self.wkb).encode('hex')
   378         return wkb_w.write_hex(self)
   384         return wkb_w().write_hex(self)
       
   385 
       
   386     @property
       
   387     def hexewkb(self):
       
   388         """
       
   389         Returns the EWKB of this Geometry in hexadecimal form.  This is an 
       
   390         extension of the WKB specification that includes SRID and Z values 
       
   391         that are a part of this geometry.
       
   392         """
       
   393         if self.hasz:
       
   394             if not GEOS_PREPARE:
       
   395                 # See: http://trac.osgeo.org/geos/ticket/216
       
   396                 raise GEOSException('Upgrade GEOS to 3.1 to get valid 3D HEXEWKB.')               
       
   397             return ewkb_w3d().write_hex(self)
       
   398         else:
       
   399             return ewkb_w().write_hex(self)
   379 
   400 
   380     @property
   401     @property
   381     def json(self):
   402     def json(self):
   382         """
   403         """
   383         Returns GeoJSON representation of this Geometry if GDAL 1.5+
   404         Returns GeoJSON representation of this Geometry if GDAL 1.5+
   384         is installed.
   405         is installed.
   385         """
   406         """
   386         if gdal.GEOJSON: 
   407         if gdal.GEOJSON:
   387             return self.ogr.json
   408             return self.ogr.json
   388         else:
   409         else:
   389             raise GEOSException('GeoJSON output only supported on GDAL 1.5+.')
   410             raise GEOSException('GeoJSON output only supported on GDAL 1.5+.')
   390     geojson = json
   411     geojson = json
   391 
   412 
   392     @property
   413     @property
   393     def wkb(self):
   414     def wkb(self):
   394         "Returns the WKB of the Geometry as a buffer."
   415         """
   395         return wkb_w.write(self)
   416         Returns the WKB (Well-Known Binary) representation of this Geometry
       
   417         as a Python buffer.  SRID and Z values are not included, use the
       
   418         `ewkb` property instead.
       
   419         """
       
   420         return wkb_w().write(self)
       
   421 
       
   422     @property
       
   423     def ewkb(self):
       
   424         """
       
   425         Return the EWKB representation of this Geometry as a Python buffer.
       
   426         This is an extension of the WKB specification that includes any SRID
       
   427         and Z values that are a part of this geometry.
       
   428         """
       
   429         if self.hasz:
       
   430             if not GEOS_PREPARE:
       
   431                 # See: http://trac.osgeo.org/geos/ticket/216
       
   432                 raise GEOSException('Upgrade GEOS to 3.1 to get valid 3D EWKB.')
       
   433             return ewkb_w3d().write(self)
       
   434         else:
       
   435             return ewkb_w().write(self)
   396 
   436 
   397     @property
   437     @property
   398     def kml(self):
   438     def kml(self):
   399         "Returns the KML representation of this Geometry."
   439         "Returns the KML representation of this Geometry."
   400         gtype = self.geom_type
   440         gtype = self.geom_type
   452         if gdal.HAS_GDAL and srid:
   492         if gdal.HAS_GDAL and srid:
   453             # Creating an OGR Geometry, which is then transformed.
   493             # Creating an OGR Geometry, which is then transformed.
   454             g = gdal.OGRGeometry(self.wkb, srid)
   494             g = gdal.OGRGeometry(self.wkb, srid)
   455             g.transform(ct)
   495             g.transform(ct)
   456             # Getting a new GEOS pointer
   496             # Getting a new GEOS pointer
   457             ptr = wkb_r.read(g.wkb)
   497             ptr = wkb_r().read(g.wkb)
   458             if clone:
   498             if clone:
   459                 # User wants a cloned transformed geometry returned.
   499                 # User wants a cloned transformed geometry returned.
   460                 return GEOSGeometry(ptr, srid=g.srid)
   500                 return GEOSGeometry(ptr, srid=g.srid)
   461             if ptr:
   501             if ptr:
   462                 # Reassigning pointer, and performing post-initialization setup
   502                 # Reassigning pointer, and performing post-initialization setup
   614                 5 : MultiLineString,
   654                 5 : MultiLineString,
   615                 6 : MultiPolygon,
   655                 6 : MultiPolygon,
   616                 7 : GeometryCollection,
   656                 7 : GeometryCollection,
   617                 }
   657                 }
   618 
   658 
   619 # Similarly, import the GEOS I/O instances here to avoid conflicts.
       
   620 from django.contrib.gis.geos.io import wkt_r, wkt_w, wkb_r, wkb_w
       
   621 
       
   622 # If supported, import the PreparedGeometry class.
   659 # If supported, import the PreparedGeometry class.
   623 if GEOS_PREPARE:
   660 if GEOS_PREPARE:
   624     from django.contrib.gis.geos.prepared import PreparedGeometry
   661     from django.contrib.gis.geos.prepared import PreparedGeometry