web/lib/django/contrib/gis/geos/linestring.py
changeset 0 0d40e90630ef
equal deleted inserted replaced
-1:000000000000 0:0d40e90630ef
       
     1 from django.contrib.gis.geos.base import numpy
       
     2 from django.contrib.gis.geos.coordseq import GEOSCoordSeq
       
     3 from django.contrib.gis.geos.error import GEOSException
       
     4 from django.contrib.gis.geos.geometry import GEOSGeometry
       
     5 from django.contrib.gis.geos.point import Point
       
     6 from django.contrib.gis.geos import prototypes as capi
       
     7 
       
     8 class LineString(GEOSGeometry):
       
     9     _init_func = capi.create_linestring
       
    10     _minlength = 2
       
    11 
       
    12     #### Python 'magic' routines ####
       
    13     def __init__(self, *args, **kwargs):
       
    14         """
       
    15         Initializes on the given sequence -- may take lists, tuples, NumPy arrays
       
    16         of X,Y pairs, or Point objects.  If Point objects are used, ownership is
       
    17         _not_ transferred to the LineString object.
       
    18 
       
    19         Examples:
       
    20          ls = LineString((1, 1), (2, 2))
       
    21          ls = LineString([(1, 1), (2, 2)])
       
    22          ls = LineString(array([(1, 1), (2, 2)]))
       
    23          ls = LineString(Point(1, 1), Point(2, 2))
       
    24         """
       
    25         # If only one argument provided, set the coords array appropriately
       
    26         if len(args) == 1: coords = args[0]
       
    27         else: coords = args
       
    28 
       
    29         if isinstance(coords, (tuple, list)):
       
    30             # Getting the number of coords and the number of dimensions -- which
       
    31             #  must stay the same, e.g., no LineString((1, 2), (1, 2, 3)).
       
    32             ncoords = len(coords)
       
    33             if coords: ndim = len(coords[0])
       
    34             else: raise TypeError('Cannot initialize on empty sequence.')
       
    35             self._checkdim(ndim)
       
    36             # Incrementing through each of the coordinates and verifying
       
    37             for i in xrange(1, ncoords):
       
    38                 if not isinstance(coords[i], (tuple, list, Point)):
       
    39                     raise TypeError('each coordinate should be a sequence (list or tuple)')
       
    40                 if len(coords[i]) != ndim: raise TypeError('Dimension mismatch.')
       
    41             numpy_coords = False
       
    42         elif numpy and isinstance(coords, numpy.ndarray):
       
    43             shape = coords.shape # Using numpy's shape.
       
    44             if len(shape) != 2: raise TypeError('Too many dimensions.')
       
    45             self._checkdim(shape[1])
       
    46             ncoords = shape[0]
       
    47             ndim = shape[1]
       
    48             numpy_coords = True
       
    49         else:
       
    50             raise TypeError('Invalid initialization input for LineStrings.')
       
    51 
       
    52         # Creating a coordinate sequence object because it is easier to
       
    53         # set the points using GEOSCoordSeq.__setitem__().
       
    54         cs = GEOSCoordSeq(capi.create_cs(ncoords, ndim), z=bool(ndim==3))
       
    55 
       
    56         for i in xrange(ncoords):
       
    57             if numpy_coords: cs[i] = coords[i,:]
       
    58             elif isinstance(coords[i], Point): cs[i] = coords[i].tuple
       
    59             else: cs[i] = coords[i]
       
    60 
       
    61         # If SRID was passed in with the keyword arguments
       
    62         srid = kwargs.get('srid', None)
       
    63 
       
    64         # Calling the base geometry initialization with the returned pointer
       
    65         #  from the function.
       
    66         super(LineString, self).__init__(self._init_func(cs.ptr), srid=srid)
       
    67 
       
    68     def __iter__(self):
       
    69         "Allows iteration over this LineString."
       
    70         for i in xrange(len(self)):
       
    71             yield self[i]
       
    72 
       
    73     def __len__(self):
       
    74         "Returns the number of points in this LineString."
       
    75         return len(self._cs)
       
    76 
       
    77     def _get_single_external(self, index):
       
    78         return self._cs[index]
       
    79 
       
    80     _get_single_internal = _get_single_external
       
    81 
       
    82     def _set_list(self, length, items):
       
    83         ndim = self._cs.dims #
       
    84         hasz = self._cs.hasz # I don't understand why these are different
       
    85 
       
    86         # create a new coordinate sequence and populate accordingly
       
    87         cs = GEOSCoordSeq(capi.create_cs(length, ndim), z=hasz)
       
    88         for i, c in enumerate(items):
       
    89             cs[i] = c
       
    90 
       
    91         ptr = self._init_func(cs.ptr)
       
    92         if ptr:
       
    93             capi.destroy_geom(self.ptr)
       
    94             self.ptr = ptr
       
    95             self._post_init(self.srid)
       
    96         else:
       
    97             # can this happen?
       
    98             raise GEOSException('Geometry resulting from slice deletion was invalid.')
       
    99 
       
   100     def _set_single(self, index, value):
       
   101         self._checkindex(index)
       
   102         self._cs[index] = value
       
   103 
       
   104     def _checkdim(self, dim):
       
   105         if dim not in (2, 3): raise TypeError('Dimension mismatch.')
       
   106 
       
   107     #### Sequence Properties ####
       
   108     @property
       
   109     def tuple(self):
       
   110         "Returns a tuple version of the geometry from the coordinate sequence."
       
   111         return self._cs.tuple
       
   112     coords = tuple
       
   113 
       
   114     def _listarr(self, func):
       
   115         """
       
   116         Internal routine that returns a sequence (list) corresponding with
       
   117         the given function.  Will return a numpy array if possible.
       
   118         """
       
   119         lst = [func(i) for i in xrange(len(self))]
       
   120         if numpy: return numpy.array(lst) # ARRRR!
       
   121         else: return lst
       
   122 
       
   123     @property
       
   124     def array(self):
       
   125         "Returns a numpy array for the LineString."
       
   126         return self._listarr(self._cs.__getitem__)
       
   127 
       
   128     @property
       
   129     def merged(self):
       
   130         "Returns the line merge of this LineString."
       
   131         return self._topology(capi.geos_linemerge(self.ptr))   
       
   132 
       
   133     @property
       
   134     def x(self):
       
   135         "Returns a list or numpy array of the X variable."
       
   136         return self._listarr(self._cs.getX)
       
   137 
       
   138     @property
       
   139     def y(self):
       
   140         "Returns a list or numpy array of the Y variable."
       
   141         return self._listarr(self._cs.getY)
       
   142 
       
   143     @property
       
   144     def z(self):
       
   145         "Returns a list or numpy array of the Z variable."
       
   146         if not self.hasz: return None
       
   147         else: return self._listarr(self._cs.getZ)
       
   148 
       
   149 # LinearRings are LineStrings used within Polygons.
       
   150 class LinearRing(LineString):
       
   151     _minLength = 4
       
   152     _init_func = capi.create_linearring