django/contrib/gis/geos/base.py
branchtrunk
changeset 138 466bece04a15
parent 123 9ec2cb291fb8
child 139 1574381fb26c
     1.1 --- a/django/contrib/gis/geos/base.py	Thu Jan 29 14:54:26 2009 -0600
     1.2 +++ b/django/contrib/gis/geos/base.py	Sat Jan 31 15:18:50 2009 -0600
     1.3 @@ -1,6 +1,6 @@
     1.4  from ctypes import c_void_p
     1.5  from types import NoneType
     1.6 -from django.contrib.gis.geos.error import GEOSException
     1.7 +from django.contrib.gis.geos.error import GEOSException, GEOSIndexError
     1.8  
     1.9  # Trying to import GDAL libraries, if available.  Have to place in
    1.10  # try/except since this package may be used outside GeoDjango.
    1.11 @@ -52,3 +52,167 @@
    1.12      # this raises an exception when the pointer is NULL, thus preventing
    1.13      # the C library from attempting to access an invalid memory location.
    1.14      ptr = property(_get_ptr, _set_ptr)
    1.15 +
    1.16 +class ListMixin(object):
    1.17 +
    1.18 +    _canSetSingle = False
    1.19 +    
    1.20 +    def _setSingle_rebuild(self, index, value):
    1.21 +        self._checkindex(index)
    1.22 +        self._setSlice(slice(index, index + 1, 1), [value])        
    1.23 +    _setSingle = _setSingle_rebuild
    1.24 +
    1.25 +    def _checkindex(self, index):
    1.26 +        if index < 0 or index >= len(self):
    1.27 +            raise GEOSIndexError('invalid index: %s' % str(index))
    1.28 +
    1.29 +    def _checkAllowedTypes(self, items):
    1.30 +        # Ensuring that only the permitted geometries are allowed in this collection
    1.31 +        if hasattr(self, '_allowed'):
    1.32 +            if False in [isinstance(geom, self._allowed) for geom in items]:
    1.33 +                raise TypeError('Invalid Geometry type encountered in the arguments.')
    1.34 +
    1.35 +    def __getitem__(self, index):
    1.36 +        "Gets the coordinates of the point(s) at the specified index/slice."
    1.37 +        if isinstance(index, slice):
    1.38 +            return [self._getItemExternal(i) for i in xrange(*index.indices(len(self)))]
    1.39 +        else:
    1.40 +            if index < 0:
    1.41 +                index += len(self)
    1.42 +            return self._getItemExternal(index)
    1.43 +
    1.44 +    def __delitem__(self, index):
    1.45 +        "Delete the point(s) at the specified index/slice."
    1.46 +        if not isinstance(index, (int, long, slice)):
    1.47 +            raise TypeError("%s is not a legal index" % index)
    1.48 +
    1.49 +        # calculate new length and dimensions
    1.50 +        origLen     = len(self)
    1.51 +        if isinstance(index, (int, long)):
    1.52 +            if index < 0: index += origLen
    1.53 +            if not 0 <= index < origLen:
    1.54 +                raise GEOSIndexError('invalid index: %d' % index)
    1.55 +            indexRange  = [index]
    1.56 +        else:
    1.57 +            indexRange  = range(*index.indices(origLen))
    1.58 +
    1.59 +        newLen      = origLen - len(indexRange)
    1.60 +        newItems    = ( self._getItemInternal(i)
    1.61 +                        for i in xrange(origLen)
    1.62 +                        if i not in indexRange )
    1.63 +
    1.64 +        self._setCollection(newLen, newItems)
    1.65 +
    1.66 +    def __setitem__(self, index, geom):
    1.67 +        "Sets the Geometry at the specified index."
    1.68 +        if isinstance(index, slice):
    1.69 +            self._setSlice(index, geom)
    1.70 +        else:
    1.71 +            if index < 0: index += len(self)
    1.72 +            self._setSingle(index, geom)
    1.73 +
    1.74 +    def _setSlice(self, index, values):
    1.75 +        "Assign values to a slice of the object"
    1.76 +        try:
    1.77 +            iter(values)
    1.78 +        except TypeError:
    1.79 +            raise TypeError('can only assign an iterable to a slice')
    1.80 +
    1.81 +        self._checkAllowedTypes(values)
    1.82 +
    1.83 +        origLen     = len(self)
    1.84 +        valueList   = list(values)
    1.85 +        start, stop, step = index.indices(origLen)
    1.86 +        stop = max(0, stop) # stop will be -1 if out-of-bounds
    1.87 +                            # negative index is given
    1.88 +
    1.89 +        # CAREFUL: index.step and step are not the same!
    1.90 +        # step will never be None
    1.91 +        #
    1.92 +        if index.step is None:
    1.93 +            self._assignSimpleSlice(start, stop, valueList)
    1.94 +        else:
    1.95 +            self._assignExtendedSlice(start, stop, step, valueList)
    1.96 +
    1.97 +    def _assignExtendedSlice(self, start, stop, step, valueList):
    1.98 +        'Assign an extended slice by rebuilding entire list'
    1.99 +        indexList   = range(start, stop, step)
   1.100 +        # extended slice, only allow assigning slice of same size
   1.101 +        if len(valueList) != len(indexList):
   1.102 +            raise ValueError('attempt to assign sequence of size %d '
   1.103 +                             'to extended slice of size %d'
   1.104 +                             % (len(valueList), len(indexList)))
   1.105 +
   1.106 +        # we're not changing the length of the sequence
   1.107 +        newLen  = len(self)
   1.108 +        newVals = dict(zip(indexList, valueList))
   1.109 +        def newItems():
   1.110 +            for i in xrange(newLen):
   1.111 +                if i in newVals:
   1.112 +                    yield newVals[i]
   1.113 +                else:
   1.114 +                    yield self._getItemInternal(i)
   1.115 +
   1.116 +        self._setCollection(newLen, newItems())
   1.117 +
   1.118 +    def _assignExtendedSlice_no_rebuild(self, start, stop, step, valueList):
   1.119 +        'Assign an extended slice by re-assigning individual items'
   1.120 +        indexList   = range(start, stop, step)
   1.121 +        # extended slice, only allow assigning slice of same size
   1.122 +        if len(valueList) != len(indexList):
   1.123 +            raise ValueError('attempt to assign sequence of size %d '
   1.124 +                             'to extended slice of size %d'
   1.125 +                             % (len(valueList), len(indexList)))
   1.126 +
   1.127 +        for i, val in zip(indexList, valueList):
   1.128 +            self._setSingle(i, val)
   1.129 +
   1.130 +    def _assignSimpleSlice(self, start, stop, valueList):
   1.131 +        'Assign a simple slice; Can assign slice of any length'
   1.132 +        origLen = len(self)
   1.133 +        newLen  = origLen - stop + start + len(valueList)
   1.134 +        def newItems():
   1.135 +            for i in xrange(origLen + 1):
   1.136 +                if i == start:
   1.137 +                    for val in valueList:
   1.138 +                        yield val
   1.139 +
   1.140 +                if i < origLen:
   1.141 +                    if i < start or i >= stop:
   1.142 +                        yield self._getItemInternal(i)
   1.143 +
   1.144 +        self._setCollection(newLen, newItems())
   1.145 +
   1.146 +    def append(self, val):
   1.147 +        "Standard list append method"
   1.148 +        self[len(self):] = [val]
   1.149 +
   1.150 +    def extend(self, vals):
   1.151 +        "Standard list extend method"
   1.152 +        self[len(self):] = vals
   1.153 +
   1.154 +    def insert(self, index, val):
   1.155 +        "Standard list insert method"
   1.156 +        if not isinstance(index, (int, long)):
   1.157 +            raise TypeError("%s is not a legal index" % index)
   1.158 +        self[index:index] = [val]
   1.159 +
   1.160 +    def pop(self, index=-1):
   1.161 +        "Standard list pop method"
   1.162 +        result = self[index]
   1.163 +        del self[index]
   1.164 +        return result
   1.165 +
   1.166 +    def index(self, val):
   1.167 +        "Standard list index method"
   1.168 +        for i in xrange(0, len(self)):
   1.169 +            if self[i] == val: return i
   1.170 +        raise ValueError('%s not in geometry' % str(val))
   1.171 +
   1.172 +    def remove(self, val):
   1.173 +        "Standard list remove method"
   1.174 +        del self[self.index(val)]
   1.175 +
   1.176 +    def count(self):
   1.177 +        "Standard list count method"
   1.178 +        return len(self)