Merged in patch from Aryeh Leib Taurog for #9877, adapting as necessary.
1 from ctypes import c_void_p
2 from types import NoneType
3 from django.contrib.gis.geos.error import GEOSException, GEOSIndexError
5 # Trying to import GDAL libraries, if available. Have to place in
6 # try/except since this package may be used outside GeoDjango.
8 from django.contrib.gis import gdal
10 # A 'dummy' gdal module.
11 class GDALInfo(object):
22 class GEOSBase(object):
24 Base object for GEOS objects that has a pointer access property
25 that controls access to the underlying C pointer.
27 # Initially the pointer is NULL.
30 # Default allowed pointer type.
33 # Pointer access property.
35 # Raise an exception if the pointer isn't valid don't
36 # want to be passing NULL pointers to routines --
38 if self._ptr: return self._ptr
39 else: raise GEOSException('NULL GEOS %s pointer encountered.' % self.__class__.__name__)
41 def _set_ptr(self, ptr):
42 # Only allow the pointer to be set with pointers of the
43 # compatible type or None (NULL).
44 if isinstance(ptr, int):
45 self._ptr = self.ptr_type(ptr)
46 elif isinstance(ptr, (self.ptr_type, NoneType)):
49 raise TypeError('Incompatible pointer type')
51 # Property for controlling access to the GEOS object pointers. Using
52 # this raises an exception when the pointer is NULL, thus preventing
53 # the C library from attempting to access an invalid memory location.
54 ptr = property(_get_ptr, _set_ptr)
56 class ListMixin(object):
60 def _setSingle_rebuild(self, index, value):
61 self._checkindex(index)
62 self._setSlice(slice(index, index + 1, 1), [value])
63 _setSingle = _setSingle_rebuild
65 def _checkindex(self, index):
66 if index < 0 or index >= len(self):
67 raise GEOSIndexError('invalid index: %s' % str(index))
69 def _checkAllowedTypes(self, items):
70 # Ensuring that only the permitted geometries are allowed in this collection
71 if hasattr(self, '_allowed'):
72 if False in [isinstance(geom, self._allowed) for geom in items]:
73 raise TypeError('Invalid Geometry type encountered in the arguments.')
75 def __getitem__(self, index):
76 "Gets the coordinates of the point(s) at the specified index/slice."
77 if isinstance(index, slice):
78 return [self._getItemExternal(i) for i in xrange(*index.indices(len(self)))]
82 return self._getItemExternal(index)
84 def __delitem__(self, index):
85 "Delete the point(s) at the specified index/slice."
86 if not isinstance(index, (int, long, slice)):
87 raise TypeError("%s is not a legal index" % index)
89 # calculate new length and dimensions
91 if isinstance(index, (int, long)):
92 if index < 0: index += origLen
93 if not 0 <= index < origLen:
94 raise GEOSIndexError('invalid index: %d' % index)
97 indexRange = range(*index.indices(origLen))
99 newLen = origLen - len(indexRange)
100 newItems = ( self._getItemInternal(i)
101 for i in xrange(origLen)
102 if i not in indexRange )
104 self._setCollection(newLen, newItems)
106 def __setitem__(self, index, geom):
107 "Sets the Geometry at the specified index."
108 if isinstance(index, slice):
109 self._setSlice(index, geom)
111 if index < 0: index += len(self)
112 self._setSingle(index, geom)
114 def _setSlice(self, index, values):
115 "Assign values to a slice of the object"
119 raise TypeError('can only assign an iterable to a slice')
121 self._checkAllowedTypes(values)
124 valueList = list(values)
125 start, stop, step = index.indices(origLen)
126 stop = max(0, stop) # stop will be -1 if out-of-bounds
127 # negative index is given
129 # CAREFUL: index.step and step are not the same!
130 # step will never be None
132 if index.step is None:
133 self._assignSimpleSlice(start, stop, valueList)
135 self._assignExtendedSlice(start, stop, step, valueList)
137 def _assignExtendedSlice(self, start, stop, step, valueList):
138 'Assign an extended slice by rebuilding entire list'
139 indexList = range(start, stop, step)
140 # extended slice, only allow assigning slice of same size
141 if len(valueList) != len(indexList):
142 raise ValueError('attempt to assign sequence of size %d '
143 'to extended slice of size %d'
144 % (len(valueList), len(indexList)))
146 # we're not changing the length of the sequence
148 newVals = dict(zip(indexList, valueList))
150 for i in xrange(newLen):
154 yield self._getItemInternal(i)
156 self._setCollection(newLen, newItems())
158 def _assignExtendedSlice_no_rebuild(self, start, stop, step, valueList):
159 'Assign an extended slice by re-assigning individual items'
160 indexList = range(start, stop, step)
161 # extended slice, only allow assigning slice of same size
162 if len(valueList) != len(indexList):
163 raise ValueError('attempt to assign sequence of size %d '
164 'to extended slice of size %d'
165 % (len(valueList), len(indexList)))
167 for i, val in zip(indexList, valueList):
168 self._setSingle(i, val)
170 def _assignSimpleSlice(self, start, stop, valueList):
171 'Assign a simple slice; Can assign slice of any length'
173 newLen = origLen - stop + start + len(valueList)
175 for i in xrange(origLen + 1):
177 for val in valueList:
181 if i < start or i >= stop:
182 yield self._getItemInternal(i)
184 self._setCollection(newLen, newItems())
186 def append(self, val):
187 "Standard list append method"
188 self[len(self):] = [val]
190 def extend(self, vals):
191 "Standard list extend method"
192 self[len(self):] = vals
194 def insert(self, index, val):
195 "Standard list insert method"
196 if not isinstance(index, (int, long)):
197 raise TypeError("%s is not a legal index" % index)
198 self[index:index] = [val]
200 def pop(self, index=-1):
201 "Standard list pop method"
206 def index(self, val):
207 "Standard list index method"
208 for i in xrange(0, len(self)):
209 if self[i] == val: return i
210 raise ValueError('%s not in geometry' % str(val))
212 def remove(self, val):
213 "Standard list remove method"
214 del self[self.index(val)]
217 "Standard list count method"