Django

Code

Changeset 5655

Show
Ignore:
Timestamp:
07/12/07 01:05:42 (1 year ago)
Author:
jbronn
Message:

gis: no more camelcase module names; GEOSGeometry now autodetects WKT or HEXEWKB (hex).

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • django/branches/gis/django/contrib/gis/geos/base.py

    r5637 r5655  
    22from ctypes import \ 
    33     byref, string_at, create_string_buffer, pointer, \ 
    4      c_char_p, c_double, c_float, c_int, c_uint, c_size_t 
     4     c_char_p, c_double, c_int, c_size_t 
    55from types import StringType, IntType, FloatType, TupleType, ListType 
    66 
    77# Getting GEOS-related dependencies. 
     8import re 
     9from warnings import warn 
    810from django.contrib.gis.geos.libgeos import lgeos, GEOSPointer, HAS_NUMPY 
    9 from django.contrib.gis.geos.GEOSError import GEOSException 
    10 from django.contrib.gis.geos.GEOSCoordSeq import GEOSCoordSeq, create_cs 
     11from django.contrib.gis.geos.error import GEOSException, GEOSGeometryIndexError 
     12from django.contrib.gis.geos.coordseq import GEOSCoordSeq, create_cs 
    1113 
    1214if HAS_NUMPY: 
    1315    from numpy import ndarray, array 
     16 
     17# For recognizing HEXEWKB. 
     18hex_regex = re.compile(r'^[0-9A-Fa-f]+') 
    1419 
    1520class GEOSGeometry(object): 
     
    1722     
    1823    #### Python 'magic' routines #### 
    19     def __init__(self, geo_input, input_type='wkt', child=False): 
     24    def __init__(self, geo_input, input_type=False, child=False): 
    2025        """The constructor for GEOS geometry objects.  May take the following 
    2126        strings as inputs, WKT ("wkt"), HEXEWKB ("hex", PostGIS-specific canonical form). 
    2227 
    23         When a hex string is to be used, the `input_type` keyword should be set with 'hex'
     28        The `input_type` keyword has been deprecated -- geometry type is now auto-detected
    2429 
    2530        The `child` keyword is for internal use only, and indicates to the garbage collector 
     
    3237 
    3338        if isinstance(geo_input, StringType): 
    34             if input_type == 'wkt': 
    35                 # If the geometry is in WKT form 
    36                 g = lgeos.GEOSGeomFromWKT(c_char_p(geo_input)) 
    37             elif input_type == 'hex': 
    38                 # If the geometry is in HEX form. 
     39            if input_type: warn('input_type keyword is deprecated') 
     40 
     41            if hex_regex.match(geo_input): 
     42                # If the regex matches, the geometry is in HEX form. 
    3943                sz = c_size_t(len(geo_input)) 
    4044                buf = create_string_buffer(geo_input) 
    4145                g = lgeos.GEOSGeomFromHEX_buf(buf, sz) 
    4246            else: 
    43                 raise TypeError, 'GEOS input geometry type "%s" not supported.' % input_type 
     47                # Otherwise, the geometry is in WKT form. 
     48                g = lgeos.GEOSGeomFromWKT(c_char_p(geo_input)) 
     49 
    4450        elif isinstance(geo_input, (IntType, GEOSPointer)): 
    4551            # When the input is either a raw pointer value (an integer), or a GEOSPointer object. 
     
    340346        return GEOSGeometry(lgeos.GEOSGeom_clone(self._ptr())) 
    341347     
    342 class Point(GEOSGeometry): 
    343  
    344     def __init__(self, x, y=None, z=None): 
    345         """The Point object may be initialized with either a tuple, or individual 
    346         parameters.  For example: 
    347           >>> p = Point((5, 23)) # 2D point, passed in as a tuple 
    348           >>> p = Point(5, 23, 8) # 3D point, passed in with individual parameters 
    349         """ 
    350          
    351         if isinstance(x, (TupleType, ListType)): 
    352             # Here a tuple or list was passed in under the ``x`` parameter. 
    353             ndim = len(x) 
    354             if ndim < 2 or ndim > 3: 
    355                 raise TypeError, 'Invalid sequence parameter: %s' % str(x) 
    356             coords = x 
    357         elif isinstance(x, (IntType, FloatType)) and isinstance(y, (IntType, FloatType)): 
    358             # Here X, Y, and (optionally) Z were passed in individually as parameters. 
    359             if isinstance(z, (IntType, FloatType)): 
    360                 ndim = 3 
    361                 coords = [x, y, z] 
    362             else: 
    363                 ndim = 2 
    364                 coords = [x, y] 
    365         else: 
    366             raise TypeError, 'Invalid parameters given for Point initialization.' 
    367  
    368         # Creating the coordinate sequence 
    369         cs = create_cs(c_uint(1), c_uint(ndim)) 
    370  
    371         # Setting the X 
    372         status = lgeos.GEOSCoordSeq_setX(cs, c_uint(0), c_double(coords[0])) 
    373         if not status: raise GEOSException, 'Could not set X during Point initialization.' 
    374  
    375         # Setting the Y 
    376         status = lgeos.GEOSCoordSeq_setY(cs, c_uint(0), c_double(coords[1])) 
    377         if not status: raise GEOSException, 'Could not set Y during Point initialization.' 
    378  
    379         # Setting the Z 
    380         if ndim == 3: 
    381             status = lgeos.GEOSCoordSeq_setZ(cs, c_uint(0), c_double(coords[2])) 
    382  
    383         # Initializing from the geometry, and getting a Python object 
    384         super(Point, self).__init__(lgeos.GEOSGeom_createPoint(cs)) 
    385  
    386     def _getOrdinate(self, dim, idx): 
    387         "The coordinate sequence getOrdinate() wrapper." 
    388         self._cache_cs() 
    389         return self._cs.getOrdinate(dim, idx) 
    390  
    391     def _setOrdinate(self, dim, idx, value): 
    392         "The coordinate sequence setOrdinate() wrapper." 
    393         self._cache_cs() 
    394         self._cs.setOrdinate(dim, idx, value) 
    395  
    396     def get_x(self): 
    397         "Returns the X component of the Point." 
    398         return self._getOrdinate(0, 0) 
    399  
    400     def set_x(self, value): 
    401         "Sets the X component of the Point." 
    402         self._setOrdinate(0, 0, value) 
    403  
    404     def get_y(self): 
    405         "Returns the Y component of the Point." 
    406         return self._getOrdinate(1, 0) 
    407  
    408     def set_y(self, value): 
    409         "Sets the Y component of the Point." 
    410         self._setOrdinate(1, 0, value) 
    411  
    412     def get_z(self): 
    413         "Returns the Z component of the Point." 
    414         if self.hasz: 
    415             return self._getOrdinate(2, 0) 
    416         else: 
    417             return None 
    418  
    419     def set_z(self, value): 
    420         "Sets the Z component of the Point." 
    421         if self.hasz: 
    422             self._setOrdinate(2, 0, value) 
    423         else: 
    424             raise GEOSException, 'Cannot set Z on 2D Point.' 
    425      
    426     # X, Y, Z properties 
    427     x = property(get_x, set_x) 
    428     y = property(get_y, set_y) 
    429     z = property(get_z, set_z) 
    430  
    431     @property 
    432     def tuple(self): 
    433         "Returns a tuple of the point." 
    434         self._cache_cs() 
    435         return self._cs.tuple 
    436  
    437 class LineString(GEOSGeometry): 
    438  
    439     #### Python 'magic' routines #### 
    440     def __init__(self, coords, ring=False): 
    441         """Initializes on the given sequence, may take lists, tuples, or NumPy arrays 
    442         of X,Y pairs.""" 
    443  
    444         if isinstance(coords, (TupleType, ListType)): 
    445             ncoords = len(coords) 
    446             first = True 
    447             for coord in coords: 
    448                 if not isinstance(coord, (TupleType, ListType)): 
    449                     raise TypeError, 'each coordinate should be a sequence (list or tuple)' 
    450                 if first: 
    451                     ndim = len(coord) 
    452                     self._checkdim(ndim) 
    453                     first = False 
    454                 else: 
    455                     if len(coord) != ndim: raise TypeError, 'Dimension mismatch.' 
    456             numpy_coords = False 
    457         elif HAS_NUMPY and isinstance(coords, ndarray): 
    458             shape = coords.shape 
    459             if len(shape) != 2: raise TypeError, 'Too many dimensions.' 
    460             self._checkdim(shape[1]) 
    461             ncoords = shape[0] 
    462             ndim = shape[1] 
    463             numpy_coords = True 
    464         else: 
    465             raise TypeError, 'Invalid initialization input for LineStrings.' 
    466  
    467         # Creating the coordinate sequence 
    468         cs = GEOSCoordSeq(GEOSPointer(create_cs(c_uint(ncoords), c_uint(ndim)))) 
    469  
    470         # Setting each point in the coordinate sequence 
    471         for i in xrange(ncoords): 
    472             if numpy_coords: cs[i] = coords[i,:] 
    473             else: cs[i] = coords[i]         
    474  
    475         # Getting the initialization function 
    476         if ring: 
    477             func = lgeos.GEOSGeom_createLinearRing 
    478         else: 
    479             func = lgeos.GEOSGeom_createLineString 
    480         
    481         # Calling the base geometry initialization with the returned pointer from the function. 
    482         super(LineString, self).__init__(func(cs._ptr())) 
    483  
    484     def __getitem__(self, index): 
    485         "Gets the point at the specified index." 
    486         self._cache_cs() 
    487         return self._cs[index] 
    488  
    489     def __setitem__(self, index, value): 
    490         "Sets the point at the specified index, e.g., line_str[0] = (1, 2)." 
    491         self._cache_cs() 
    492         self._cs[index] = value 
    493  
    494     def __iter__(self): 
    495         "Allows iteration over this LineString." 
    496         for i in xrange(self.__len__()): 
    497             yield self.__getitem__(index) 
    498  
    499     def __len__(self): 
    500         "Returns the number of points in this LineString." 
    501         self._cache_cs() 
    502         return len(self._cs) 
    503  
    504     def _checkdim(self, dim): 
    505         if dim not in (2, 3): raise TypeError, 'Dimension mismatch.' 
    506  
    507     #### Sequence Properties #### 
    508     @property 
    509     def tuple(self): 
    510         "Returns a tuple version of the geometry from the coordinate sequence." 
    511         self._cache_cs() 
    512         return self._cs.tuple 
    513  
    514     def _listarr(self, func): 
    515         """Internal routine that returns a sequence (list) corresponding with 
    516         the given function.  Will return a numpy array if possible.""" 
    517         lst = [func(i) for i in xrange(self.__len__())] # constructing the list, using the function 
    518         if HAS_NUMPY: return array(lst) # ARRRR! 
    519         else: return lst 
    520  
    521     @property 
    522     def array(self): 
    523         "Returns a numpy array for the LineString." 
    524         self._cache_cs() 
    525         return self._listarr(self._cs.__getitem__) 
    526  
    527     @property 
    528     def x(self): 
    529         "Returns a list or numpy array of the X variable." 
    530         self._cache_cs() 
    531         return self._listarr(self._cs.getX) 
    532      
    533     @property 
    534     def y(self): 
    535         "Returns a list or numpy array of the Y variable." 
    536         self._cache_cs() 
    537         return self._listarr(self._cs.getY) 
    538  
    539     @property 
    540     def z(self): 
    541         "Returns a list or numpy array of the Z variable." 
    542         self._cache_cs() 
    543         if not self.hasz: return None 
    544         else: return self._listarr(self._cs.getZ) 
    545  
    546 # LinearRings are LineStrings used within Polygons. 
    547 class LinearRing(LineString): 
    548     def __init__(self, coords): 
    549         "Overriding the initialization function to set the ring keyword." 
    550         super(LinearRing, self).__init__(coords, ring=True) 
    551  
    552 class Polygon(GEOSGeometry): 
    553  
    554     def __del__(self): 
    555         "Override the GEOSGeometry delete routine to safely take care of any spawned rings." 
    556         # Nullifying the pointers to internal rings, preventing any attempted future access 
    557         for k in self._rings: self._rings[k].nullify() 
    558         super(Polygon, self).__del__() # Calling the parent __del__() method. 
    559      
    560     def __getitem__(self, index): 
    561         """Returns the ring at the specified index.  The first index, 0, will always 
    562         return the exterior ring.  Indices > 0 will return the interior ring.""" 
    563         if index < 0 or index > self.num_interior_rings: 
    564             raise GEOSGeometryIndexError, 'invalid GEOS Geometry index: %s' % str(index) 
    565         else: 
    566             if index == 0: 
    567                 return self.exterior_ring 
    568             else: 
    569                 # Getting the interior ring, have to subtract 1 from the index. 
    570                 return self.get_interior_ring(index-1)  
    571  
    572     def __iter__(self): 
    573         "Iterates over each ring in the polygon." 
    574         for i in xrange(self.__len__()): 
    575             yield self.__getitem__(i) 
    576  
    577     def __len__(self): 
    578         "Returns the number of rings in this Polygon." 
    579         return self.num_interior_rings + 1 
    580  
    581     def get_interior_ring(self, ring_i): 
    582         """Gets the interior ring at the specified index, 
    583         0 is for the first interior ring, not the exterior ring.""" 
    584  
    585         # Making sure the ring index is within range 
    586         if ring_i < 0 or ring_i >= self.num_interior_rings: 
    587             raise IndexError, 'ring index out of range' 
    588  
    589         # Placing the ring in internal rings dictionary. 
    590         idx = ring_i+1 # the index for the polygon is +1 because of the exterior ring 
    591         if not idx in self._rings: 
    592             self._rings[idx] = GEOSPointer(lgeos.GEOSGetInteriorRingN(self._ptr(), c_int(ring_i))) 
    593  
    594         # Returning the ring at the given index. 
    595         return GEOSGeometry(self._rings[idx], child=True) 
    596                                                          
    597     #### Polygon Properties #### 
    598     @property 
    599     def num_interior_rings(self): 
    600         "Returns the number of interior rings." 
    601  
    602         # Getting the number of rings 
    603         n = lgeos.GEOSGetNumInteriorRings(self._ptr()) 
    604  
    605         # -1 indicates an exception occurred 
    606         if n == -1: raise GEOSException, 'Error getting the number of interior rings.' 
    607         else: return n 
    608  
    609     @property 
    610     def exterior_ring(self): 
    611         "Gets the exterior ring of the Polygon." 
    612         # Returns exterior ring  
    613         self._rings[0] = GEOSPointer(lgeos.GEOSGetExteriorRing((self._ptr()))) 
    614         return GEOSGeometry(self._rings[0], child=True) 
    615  
    616     @property 
    617     def shell(self): 
    618         "Gets the shell (exterior ring) of the Polygon." 
    619         return self.exterior_ring 
    620      
    621     @property 
    622     def tuple(self): 
    623         "Gets the tuple for each ring in this Polygon." 
    624         return tuple(self.__getitem__(i).tuple for i in xrange(self.__len__())) 
    625  
    626 class GeometryCollection(GEOSGeometry): 
    627  
    628     def __del__(self): 
    629         "Override the GEOSGeometry delete routine to safely take care of any spawned geometries." 
    630         # Nullifying the pointers to internal geometries, preventing any attempted future access 
    631         for k in self._geoms: self._geoms[k].nullify() 
    632         super(GeometryCollection, self).__del__() # Calling the parent __del__() method. 
    633  
    634     def __getitem__(self, index): 
    635         "For indexing on the multiple geometries." 
    636         self._checkindex(index) 
    637  
    638         # Setting an entry in the _geoms dictionary for the requested geometry. 
    639         if not index in self._geoms: 
    640             self._geoms[index] = GEOSPointer(lgeos.GEOSGetGeometryN(self._ptr(), c_int(index))) 
    641  
    642         # Cloning the GEOS Geometry first, before returning it. 
    643         return GEOSGeometry(self._geoms[index], child=True) 
    644  
    645     def __iter__(self): 
    646         "For iteration on the multiple geometries." 
    647         for i in xrange(self.__len__()): 
    648             yield self.__getitem__(i) 
    649  
    650     def __len__(self): 
    651         "Returns the number of geometries in this collection." 
    652         return self.num_geom 
    653  
    654     def _checkindex(self, index): 
    655         "Checks the given geometry index." 
    656         if index < 0 or index >= self.num_geom: 
    657             raise GEOSGeometryIndexError, 'invalid GEOS Geometry index: %s' % str(index) 
    658  
    659 # MultiPoint, MultiLineString, and MultiPolygon class definitions. 
    660 class MultiPoint(GeometryCollection): pass 
    661 class MultiLineString(GeometryCollection): pass 
    662 class MultiPolygon(GeometryCollection): pass 
    663  
    664348# Class mapping dictionary 
     349from django.contrib.gis.geos.geometries import Point, Polygon, LineString, LinearRing 
     350from django.contrib.gis.geos.collections import GeometryCollection, MultiPoint, MultiLineString, MultiPolygon 
    665351GEOS_CLASSES = {'Point' : Point, 
    666352                'Polygon' : Polygon, 
  • django/branches/gis/django/contrib/gis/geos/coordseq.py

    r5637 r5655  
    11from django.contrib.gis.geos.libgeos import lgeos 
    2 from django.contrib.gis.geos.GEOSError import GEOSException, GEOSGeometryIndexError 
     2from django.contrib.gis.geos.error import GEOSException, GEOSGeometryIndexError 
    33from ctypes import c_double, c_int, c_uint, byref 
    44 
  • django/branches/gis/django/contrib/gis/geos/__init__.py

    r5637 r5655  
    3030""" 
    3131 
    32 from GEOSGeometry import GEOSGeometry, Point, LineString, LinearRing, HAS_NUMPY 
    33 from GEOSError import GEOSException 
     32from base import GEOSGeometry 
     33from geometries import Point, LineString, LinearRing, HAS_NUMPY 
     34from error import GEOSException 
    3435 
    3536def hex_to_wkt(hex): 
    3637    "Converts HEXEWKB into WKT." 
    37     return GEOSGeometry(hex, 'hex').wkt 
     38    return GEOSGeometry(hex).wkt 
    3839 
    3940def wkt_to_hex(wkt): 
    4041    "Converts WKT into HEXEWKB." 
    41     return GEOSGeometry(wkt, 'wkt').hex 
     42    return GEOSGeometry(wkt).hex 
    4243 
    43 def centroid(input, geom_type='hex'): 
     44def centroid(input): 
    4445    "Returns the centroid of the geometry (given in HEXEWKB)." 
    45     return GEOSGeometry(input, geom_type).centroid.wkt 
     46    return GEOSGeometry(input).centroid.wkt 
    4647 
    47 def area(input, geom_type='hex'): 
     48def area(input): 
    4849    "Returns the area of the geometry (given in HEXEWKB)." 
    49     return GEOSGeometry(input, geom_type).area 
     50    return GEOSGeometry(input).area 
    5051     
  • django/branches/gis/django/contrib/gis/geos/libgeos.py

    r5637 r5655  
    55""" 
    66 
    7 from django.contrib.gis.geos.GEOSError import GEOSException 
     7from django.contrib.gis.geos.error import GEOSException 
    88from ctypes import \ 
    99     c_char_p, c_int, c_size_t, c_ubyte, pointer, addressof, \ 
  • django/branches/gis/django/contrib/gis/tests/test_geos.py

    r5637 r5655  
    2525        for err in errors: 
    2626            if err.hex: 
    27                 self.assertRaises(GEOSException, GEOSGeometry, err.wkt, 'hex'
     27                self.assertRaises(GEOSException, GEOSGeometry, err.wkt
    2828            else: 
    2929                self.assertRaises(GEOSException, GEOSGeometry, err.wkt)