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)