diff -r 000000000000 -r 0d40e90630ef web/lib/django/contrib/gis/geos/polygon.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/web/lib/django/contrib/gis/geos/polygon.py Wed Jan 20 00:34:04 2010 +0100
@@ -0,0 +1,166 @@
+from ctypes import c_uint, byref
+from django.contrib.gis.geos.error import GEOSIndexError
+from django.contrib.gis.geos.geometry import GEOSGeometry
+from django.contrib.gis.geos.libgeos import get_pointer_arr, GEOM_PTR
+from django.contrib.gis.geos.linestring import LinearRing
+from django.contrib.gis.geos import prototypes as capi
+
+class Polygon(GEOSGeometry):
+ _minlength = 1
+
+ def __init__(self, *args, **kwargs):
+ """
+ Initializes on an exterior ring and a sequence of holes (both
+ instances may be either LinearRing instances, or a tuple/list
+ that may be constructed into a LinearRing).
+
+ Examples of initialization, where shell, hole1, and hole2 are
+ valid LinearRing geometries:
+ >>> poly = Polygon(shell, hole1, hole2)
+ >>> poly = Polygon(shell, (hole1, hole2))
+
+ Example where a tuple parameters are used:
+ >>> poly = Polygon(((0, 0), (0, 10), (10, 10), (0, 10), (0, 0)),
+ ((4, 4), (4, 6), (6, 6), (6, 4), (4, 4)))
+ """
+ if not args:
+ raise TypeError('Must provide at least one LinearRing, or a tuple, to initialize a Polygon.')
+
+ # Getting the ext_ring and init_holes parameters from the argument list
+ ext_ring = args[0]
+ init_holes = args[1:]
+ n_holes = len(init_holes)
+
+ # If initialized as Polygon(shell, (LinearRing, LinearRing)) [for backward-compatibility]
+ if n_holes == 1 and isinstance(init_holes[0], (tuple, list)):
+ if len(init_holes[0]) == 0:
+ init_holes = ()
+ n_holes = 0
+ elif isinstance(init_holes[0][0], LinearRing):
+ init_holes = init_holes[0]
+ n_holes = len(init_holes)
+
+ polygon = self._create_polygon(n_holes + 1, (ext_ring,) + init_holes)
+ super(Polygon, self).__init__(polygon, **kwargs)
+
+ def __iter__(self):
+ "Iterates over each ring in the polygon."
+ for i in xrange(len(self)):
+ yield self[i]
+
+ def __len__(self):
+ "Returns the number of rings in this Polygon."
+ return self.num_interior_rings + 1
+
+ @classmethod
+ def from_bbox(cls, bbox):
+ "Constructs a Polygon from a bounding box (4-tuple)."
+ x0, y0, x1, y1 = bbox
+ return GEOSGeometry( 'POLYGON((%s %s, %s %s, %s %s, %s %s, %s %s))' % (
+ x0, y0, x0, y1, x1, y1, x1, y0, x0, y0) )
+
+ ### These routines are needed for list-like operation w/ListMixin ###
+ def _create_polygon(self, length, items):
+ # Instantiate LinearRing objects if necessary, but don't clone them yet
+ # _construct_ring will throw a TypeError if a parameter isn't a valid ring
+ # If we cloned the pointers here, we wouldn't be able to clean up
+ # in case of error.
+ rings = []
+ for r in items:
+ if isinstance(r, GEOM_PTR):
+ rings.append(r)
+ else:
+ rings.append(self._construct_ring(r))
+
+ shell = self._clone(rings.pop(0))
+
+ n_holes = length - 1
+ if n_holes:
+ holes = get_pointer_arr(n_holes)
+ for i, r in enumerate(rings):
+ holes[i] = self._clone(r)
+ holes_param = byref(holes)
+ else:
+ holes_param = None
+
+ return capi.create_polygon(shell, holes_param, c_uint(n_holes))
+
+ def _clone(self, g):
+ if isinstance(g, GEOM_PTR):
+ return capi.geom_clone(g)
+ else:
+ return capi.geom_clone(g.ptr)
+
+ def _construct_ring(self, param, msg='Parameter must be a sequence of LinearRings or objects that can initialize to LinearRings'):
+ "Helper routine for trying to construct a ring from the given parameter."
+ if isinstance(param, LinearRing): return param
+ try:
+ ring = LinearRing(param)
+ return ring
+ except TypeError:
+ raise TypeError(msg)
+
+ def _set_list(self, length, items):
+ # Getting the current pointer, replacing with the newly constructed
+ # geometry, and destroying the old geometry.
+ prev_ptr = self.ptr
+ srid = self.srid
+ self.ptr = self._create_polygon(length, items)
+ if srid: self.srid = srid
+ capi.destroy_geom(prev_ptr)
+
+ def _get_single_internal(self, index):
+ """
+ Returns the ring at the specified index. The first index, 0, will
+ always return the exterior ring. Indices > 0 will return the
+ interior ring at the given index (e.g., poly[1] and poly[2] would
+ return the first and second interior ring, respectively).
+
+ CAREFUL: Internal/External are not the same as Interior/Exterior!
+ _get_single_internal returns a pointer from the existing geometries for use
+ internally by the object's methods. _get_single_external returns a clone
+ of the same geometry for use by external code.
+ """
+ if index == 0:
+ return capi.get_extring(self.ptr)
+ else:
+ # Getting the interior ring, have to subtract 1 from the index.
+ return capi.get_intring(self.ptr, index-1)
+
+ def _get_single_external(self, index):
+ return GEOSGeometry(capi.geom_clone(self._get_single_internal(index)), srid=self.srid)
+
+ _set_single = GEOSGeometry._set_single_rebuild
+ _assign_extended_slice = GEOSGeometry._assign_extended_slice_rebuild
+
+ #### Polygon Properties ####
+ @property
+ def num_interior_rings(self):
+ "Returns the number of interior rings."
+ # Getting the number of rings
+ return capi.get_nrings(self.ptr)
+
+ def _get_ext_ring(self):
+ "Gets the exterior ring of the Polygon."
+ return self[0]
+
+ def _set_ext_ring(self, ring):
+ "Sets the exterior ring of the Polygon."
+ self[0] = ring
+
+ # Properties for the exterior ring/shell.
+ exterior_ring = property(_get_ext_ring, _set_ext_ring)
+ shell = exterior_ring
+
+ @property
+ def tuple(self):
+ "Gets the tuple for each ring in this Polygon."
+ return tuple([self[i].tuple for i in xrange(len(self))])
+ coords = tuple
+
+ @property
+ def kml(self):
+ "Returns the KML representation of this Polygon."
+ inner_kml = ''.join(["%s" % self[i+1].kml
+ for i in xrange(self.num_interior_rings)])
+ return "%s%s" % (self[0].kml, inner_kml)