mirror of
https://github.com/django/django.git
synced 2025-07-04 09:49:12 +00:00
gis: geos: all pointer access is now done via the ptr
property to prevent calling GEOS routines on NULL pointers; added the geos_version_info
routine; added __copy__
and __deepcopy__
interfaces that return clones (for compatibility w/queryset-refactor); __eq__
may now compare WKT strings (for compatibility w/newforms-admin); made tests compatible w/GEOS 3.0.0 release.
git-svn-id: http://code.djangoproject.com/svn/django/branches/gis@6978 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
24617b1667
commit
31111857cb
@ -32,7 +32,7 @@ from django.contrib.gis.geos.base import GEOSGeometry, wkt_regex, hex_regex
|
||||
from django.contrib.gis.geos.geometries import Point, LineString, LinearRing, Polygon, HAS_NUMPY
|
||||
from django.contrib.gis.geos.collections import GeometryCollection, MultiPoint, MultiLineString, MultiPolygon
|
||||
from django.contrib.gis.geos.error import GEOSException, GEOSIndexError
|
||||
from django.contrib.gis.geos.libgeos import geos_version
|
||||
from django.contrib.gis.geos.libgeos import geos_version, geos_version_info
|
||||
|
||||
def fromfile(file_name):
|
||||
"""
|
||||
|
@ -91,6 +91,18 @@ class GEOSGeometry(object):
|
||||
# geometries that do not have coordinate sequences)
|
||||
self._set_cs()
|
||||
|
||||
@property
|
||||
def ptr(self):
|
||||
"""
|
||||
Property for controlling access to the GEOS geometry pointer. Using
|
||||
this raises an exception when the pointer is NULL, thus preventing
|
||||
the C library from attempting to access an invalid memory location.
|
||||
"""
|
||||
if self._ptr:
|
||||
return self._ptr
|
||||
else:
|
||||
raise GEOSException('NULL GEOS pointer encountered; was this geometry modified?')
|
||||
|
||||
def __del__(self):
|
||||
"""
|
||||
Destroys this Geometry; in other words, frees the memory used by the
|
||||
@ -98,22 +110,43 @@ class GEOSGeometry(object):
|
||||
"""
|
||||
if self._ptr: destroy_geom(self._ptr)
|
||||
|
||||
def __copy__(self):
|
||||
"""
|
||||
Returns a clone because the copy of a GEOSGeometry may contain an
|
||||
invalid pointer location if the original is garbage collected.
|
||||
"""
|
||||
return self.clone()
|
||||
|
||||
def __deepcopy__(self, memodict):
|
||||
"""
|
||||
The `deepcopy` routine is used by the `Node` class of django.utils.tree;
|
||||
thus, the protocol routine needs to be implemented to return correct
|
||||
copies (clones) of these GEOS objects, which use C pointers.
|
||||
"""
|
||||
return self.clone()
|
||||
|
||||
def __str__(self):
|
||||
"WKT is used for the string representation."
|
||||
return self.wkt
|
||||
|
||||
def __repr__(self):
|
||||
"Short-hand representation because WKT may be very large."
|
||||
return '<%s object at %s>' % (self.geom_type, hex(addressof(self._ptr)))
|
||||
return '<%s object at %s>' % (self.geom_type, hex(addressof(self.ptr)))
|
||||
|
||||
# Comparison operators
|
||||
def __eq__(self, other):
|
||||
"Equivalence testing."
|
||||
return self.equals_exact(other)
|
||||
"""
|
||||
Equivalence testing, a Geometry may be compared with another Geometry
|
||||
or a WKT representation.
|
||||
"""
|
||||
if isinstance(other, basestring):
|
||||
return self.wkt == other
|
||||
else:
|
||||
return self.equals_exact(other)
|
||||
|
||||
def __ne__(self, other):
|
||||
"The not equals operator."
|
||||
return not self.equals_exact(other)
|
||||
return not (self == other)
|
||||
|
||||
### Geometry set-like operations ###
|
||||
# Thanks to Sean Gillies for inspiration:
|
||||
@ -151,7 +184,7 @@ class GEOSGeometry(object):
|
||||
def _set_cs(self):
|
||||
"Sets the coordinate sequence for this Geometry."
|
||||
if self.has_cs:
|
||||
self._cs = GEOSCoordSeq(get_cs(self._ptr), self.hasz)
|
||||
self._cs = GEOSCoordSeq(get_cs(self.ptr), self.hasz)
|
||||
else:
|
||||
self._cs = None
|
||||
|
||||
@ -164,22 +197,22 @@ class GEOSGeometry(object):
|
||||
@property
|
||||
def geom_type(self):
|
||||
"Returns a string representing the Geometry type, e.g. 'Polygon'"
|
||||
return geos_type(self._ptr)
|
||||
return geos_type(self.ptr)
|
||||
|
||||
@property
|
||||
def geom_typeid(self):
|
||||
"Returns an integer representing the Geometry type."
|
||||
return geos_typeid(self._ptr)
|
||||
return geos_typeid(self.ptr)
|
||||
|
||||
@property
|
||||
def num_geom(self):
|
||||
"Returns the number of geometries in the Geometry."
|
||||
return get_num_geoms(self._ptr)
|
||||
return get_num_geoms(self.ptr)
|
||||
|
||||
@property
|
||||
def num_coords(self):
|
||||
"Returns the number of coordinates in the Geometry."
|
||||
return get_num_coords(self._ptr)
|
||||
return get_num_coords(self.ptr)
|
||||
|
||||
@property
|
||||
def num_points(self):
|
||||
@ -189,11 +222,11 @@ class GEOSGeometry(object):
|
||||
@property
|
||||
def dims(self):
|
||||
"Returns the dimension of this Geometry (0=point, 1=line, 2=surface)."
|
||||
return get_dims(self._ptr)
|
||||
return get_dims(self.ptr)
|
||||
|
||||
def normalize(self):
|
||||
"Converts this Geometry to normal form (or canonical form)."
|
||||
return geos_normalize(self._ptr)
|
||||
return geos_normalize(self.ptr)
|
||||
|
||||
#### Unary predicates ####
|
||||
@property
|
||||
@ -202,32 +235,32 @@ class GEOSGeometry(object):
|
||||
Returns a boolean indicating whether the set of points in this Geometry
|
||||
are empty.
|
||||
"""
|
||||
return geos_isempty(self._ptr)
|
||||
return geos_isempty(self.ptr)
|
||||
|
||||
@property
|
||||
def hasz(self):
|
||||
"Returns whether the geometry has a 3D dimension."
|
||||
return geos_hasz(self._ptr)
|
||||
return geos_hasz(self.ptr)
|
||||
|
||||
@property
|
||||
def ring(self):
|
||||
"Returns whether or not the geometry is a ring."
|
||||
return geos_isring(self._ptr)
|
||||
return geos_isring(self.ptr)
|
||||
|
||||
@property
|
||||
def simple(self):
|
||||
"Returns false if the Geometry not simple."
|
||||
return geos_issimple(self._ptr)
|
||||
return geos_issimple(self.ptr)
|
||||
|
||||
@property
|
||||
def valid(self):
|
||||
"This property tests the validity of this Geometry."
|
||||
return geos_isvalid(self._ptr)
|
||||
return geos_isvalid(self.ptr)
|
||||
|
||||
#### Binary predicates. ####
|
||||
def contains(self, other):
|
||||
"Returns true if other.within(this) returns true."
|
||||
return geos_contains(self._ptr, other._ptr)
|
||||
return geos_contains(self.ptr, other.ptr)
|
||||
|
||||
def crosses(self, other):
|
||||
"""
|
||||
@ -235,39 +268,39 @@ class GEOSGeometry(object):
|
||||
is T*T****** (for a point and a curve,a point and an area or a line and
|
||||
an area) 0******** (for two curves).
|
||||
"""
|
||||
return geos_crosses(self._ptr, other._ptr)
|
||||
return geos_crosses(self.ptr, other.ptr)
|
||||
|
||||
def disjoint(self, other):
|
||||
"""
|
||||
Returns true if the DE-9IM intersection matrix for the two Geometries
|
||||
is FF*FF****.
|
||||
"""
|
||||
return geos_disjoint(self._ptr, other._ptr)
|
||||
return geos_disjoint(self.ptr, other.ptr)
|
||||
|
||||
def equals(self, other):
|
||||
"""
|
||||
Returns true if the DE-9IM intersection matrix for the two Geometries
|
||||
is T*F**FFF*.
|
||||
"""
|
||||
return geos_equals(self._ptr, other._ptr)
|
||||
return geos_equals(self.ptr, other.ptr)
|
||||
|
||||
def equals_exact(self, other, tolerance=0):
|
||||
"""
|
||||
Returns true if the two Geometries are exactly equal, up to a
|
||||
specified tolerance.
|
||||
"""
|
||||
return geos_equalsexact(self._ptr, other._ptr, float(tolerance))
|
||||
return geos_equalsexact(self.ptr, other.ptr, float(tolerance))
|
||||
|
||||
def intersects(self, other):
|
||||
"Returns true if disjoint returns false."
|
||||
return geos_intersects(self._ptr, other._ptr)
|
||||
return geos_intersects(self.ptr, other.ptr)
|
||||
|
||||
def overlaps(self, other):
|
||||
"""
|
||||
Returns true if the DE-9IM intersection matrix for the two Geometries
|
||||
is T*T***T** (for two points or two surfaces) 1*T***T** (for two curves).
|
||||
"""
|
||||
return geos_overlaps(self._ptr, other._ptr)
|
||||
return geos_overlaps(self.ptr, other.ptr)
|
||||
|
||||
def relate_pattern(self, other, pattern):
|
||||
"""
|
||||
@ -276,32 +309,32 @@ class GEOSGeometry(object):
|
||||
"""
|
||||
if not isinstance(pattern, StringType) or len(pattern) > 9:
|
||||
raise GEOSException('invalid intersection matrix pattern')
|
||||
return geos_relatepattern(self._ptr, other._ptr, pattern)
|
||||
return geos_relatepattern(self.ptr, other.ptr, pattern)
|
||||
|
||||
def touches(self, other):
|
||||
"""
|
||||
Returns true if the DE-9IM intersection matrix for the two Geometries
|
||||
is FT*******, F**T***** or F***T****.
|
||||
"""
|
||||
return geos_touches(self._ptr, other._ptr)
|
||||
return geos_touches(self.ptr, other.ptr)
|
||||
|
||||
def within(self, other):
|
||||
"""
|
||||
Returns true if the DE-9IM intersection matrix for the two Geometries
|
||||
is T*F**F***.
|
||||
"""
|
||||
return geos_within(self._ptr, other._ptr)
|
||||
return geos_within(self.ptr, other.ptr)
|
||||
|
||||
#### SRID Routines ####
|
||||
def get_srid(self):
|
||||
"Gets the SRID for the geometry, returns None if no SRID is set."
|
||||
s = geos_get_srid(self._ptr)
|
||||
s = geos_get_srid(self.ptr)
|
||||
if s == 0: return None
|
||||
else: return s
|
||||
|
||||
def set_srid(self, srid):
|
||||
"Sets the SRID for the geometry."
|
||||
geos_set_srid(self._ptr, srid)
|
||||
geos_set_srid(self.ptr, srid)
|
||||
srid = property(get_srid, set_srid)
|
||||
|
||||
#### Output Routines ####
|
||||
@ -314,7 +347,7 @@ class GEOSGeometry(object):
|
||||
@property
|
||||
def wkt(self):
|
||||
"Returns the WKT (Well-Known Text) of the Geometry."
|
||||
return to_wkt(self._ptr)
|
||||
return to_wkt(self.ptr)
|
||||
|
||||
@property
|
||||
def hex(self):
|
||||
@ -325,12 +358,12 @@ class GEOSGeometry(object):
|
||||
"""
|
||||
# A possible faster, all-python, implementation:
|
||||
# str(self.wkb).encode('hex')
|
||||
return to_hex(self._ptr, byref(c_size_t()))
|
||||
return to_hex(self.ptr, byref(c_size_t()))
|
||||
|
||||
@property
|
||||
def wkb(self):
|
||||
"Returns the WKB of the Geometry as a buffer."
|
||||
bin = to_wkb(self._ptr, byref(c_size_t()))
|
||||
bin = to_wkb(self.ptr, byref(c_size_t()))
|
||||
return buffer(bin)
|
||||
|
||||
@property
|
||||
@ -374,7 +407,7 @@ class GEOSGeometry(object):
|
||||
ptr = from_wkb(wkb, len(wkb))
|
||||
if ptr:
|
||||
# Reassigning pointer, and resetting the SRID.
|
||||
destroy_geom(self._ptr)
|
||||
destroy_geom(self.ptr)
|
||||
self._ptr = ptr
|
||||
self.srid = g.srid
|
||||
else:
|
||||
@ -388,7 +421,7 @@ class GEOSGeometry(object):
|
||||
@property
|
||||
def boundary(self):
|
||||
"Returns the boundary as a newly allocated Geometry object."
|
||||
return self._topology(geos_boundary(self._ptr))
|
||||
return self._topology(geos_boundary(self.ptr))
|
||||
|
||||
def buffer(self, width, quadsegs=8):
|
||||
"""
|
||||
@ -398,7 +431,7 @@ class GEOSGeometry(object):
|
||||
the number of segment used to approximate a quarter circle (defaults to 8).
|
||||
(Text from PostGIS documentation at ch. 6.1.3)
|
||||
"""
|
||||
return self._topology(geos_buffer(self._ptr, width, quadsegs))
|
||||
return self._topology(geos_buffer(self.ptr, width, quadsegs))
|
||||
|
||||
@property
|
||||
def centroid(self):
|
||||
@ -407,7 +440,7 @@ class GEOSGeometry(object):
|
||||
of highest dimension (since the lower-dimension geometries contribute zero
|
||||
"weight" to the centroid).
|
||||
"""
|
||||
return self._topology(geos_centroid(self._ptr))
|
||||
return self._topology(geos_centroid(self.ptr))
|
||||
|
||||
@property
|
||||
def convex_hull(self):
|
||||
@ -415,32 +448,32 @@ class GEOSGeometry(object):
|
||||
Returns the smallest convex Polygon that contains all the points
|
||||
in the Geometry.
|
||||
"""
|
||||
return self._topology(geos_convexhull(self._ptr))
|
||||
return self._topology(geos_convexhull(self.ptr))
|
||||
|
||||
def difference(self, other):
|
||||
"""
|
||||
Returns a Geometry representing the points making up this Geometry
|
||||
that do not make up other.
|
||||
"""
|
||||
return self._topology(geos_difference(self._ptr, other._ptr))
|
||||
return self._topology(geos_difference(self.ptr, other.ptr))
|
||||
|
||||
@property
|
||||
def envelope(self):
|
||||
"Return the envelope for this geometry (a polygon)."
|
||||
return self._topology(geos_envelope(self._ptr))
|
||||
return self._topology(geos_envelope(self.ptr))
|
||||
|
||||
def intersection(self, other):
|
||||
"Returns a Geometry representing the points shared by this Geometry and other."
|
||||
return self._topology(geos_intersection(self._ptr, other._ptr))
|
||||
return self._topology(geos_intersection(self.ptr, other.ptr))
|
||||
|
||||
@property
|
||||
def point_on_surface(self):
|
||||
"Computes an interior point of this Geometry."
|
||||
return self._topology(geos_pointonsurface(self._ptr))
|
||||
return self._topology(geos_pointonsurface(self.ptr))
|
||||
|
||||
def relate(self, other):
|
||||
"Returns the DE-9IM intersection matrix for this Geometry and the other."
|
||||
return geos_relate(self._ptr, other._ptr)
|
||||
return geos_relate(self.ptr, other.ptr)
|
||||
|
||||
def simplify(self, tolerance=0.0, preserve_topology=False):
|
||||
"""
|
||||
@ -455,26 +488,26 @@ class GEOSGeometry(object):
|
||||
input. This is significantly slower.
|
||||
"""
|
||||
if preserve_topology:
|
||||
return self._topology(geos_preservesimplify(self._ptr, tolerance))
|
||||
return self._topology(geos_preservesimplify(self.ptr, tolerance))
|
||||
else:
|
||||
return self._topology(geos_simplify(self._ptr, tolerance))
|
||||
return self._topology(geos_simplify(self.ptr, tolerance))
|
||||
|
||||
def sym_difference(self, other):
|
||||
"""
|
||||
Returns a set combining the points in this Geometry not in other,
|
||||
and the points in other not in this Geometry.
|
||||
"""
|
||||
return self._topology(geos_symdifference(self._ptr, other._ptr))
|
||||
return self._topology(geos_symdifference(self.ptr, other.ptr))
|
||||
|
||||
def union(self, other):
|
||||
"Returns a Geometry representing all the points in this Geometry and other."
|
||||
return self._topology(geos_union(self._ptr, other._ptr))
|
||||
return self._topology(geos_union(self.ptr, other.ptr))
|
||||
|
||||
#### Other Routines ####
|
||||
@property
|
||||
def area(self):
|
||||
"Returns the area of the Geometry."
|
||||
return geos_area(self._ptr, byref(c_double()))
|
||||
return geos_area(self.ptr, byref(c_double()))
|
||||
|
||||
def distance(self, other):
|
||||
"""
|
||||
@ -484,7 +517,7 @@ class GEOSGeometry(object):
|
||||
"""
|
||||
if not isinstance(other, GEOSGeometry):
|
||||
raise TypeError('distance() works only on other GEOS Geometries.')
|
||||
return geos_distance(self._ptr, other._ptr, byref(c_double()))
|
||||
return geos_distance(self.ptr, other.ptr, byref(c_double()))
|
||||
|
||||
@property
|
||||
def length(self):
|
||||
@ -492,11 +525,11 @@ class GEOSGeometry(object):
|
||||
Returns the length of this Geometry (e.g., 0 for point, or the
|
||||
circumfrence of a Polygon).
|
||||
"""
|
||||
return geos_length(self._ptr, byref(c_double()))
|
||||
return geos_length(self.ptr, byref(c_double()))
|
||||
|
||||
def clone(self):
|
||||
"Clones this Geometry."
|
||||
return GEOSGeometry(geom_clone(self._ptr), srid=self.srid)
|
||||
return GEOSGeometry(geom_clone(self.ptr), srid=self.srid)
|
||||
|
||||
# Class mapping dictionary
|
||||
from django.contrib.gis.geos.geometries import Point, Polygon, LineString, LinearRing
|
||||
|
@ -38,14 +38,14 @@ class GeometryCollection(GEOSGeometry):
|
||||
# Creating the geometry pointer array.
|
||||
ngeoms = len(init_geoms)
|
||||
geoms = get_pointer_arr(ngeoms)
|
||||
for i in xrange(ngeoms): geoms[i] = geom_clone(init_geoms[i]._ptr)
|
||||
for i in xrange(ngeoms): geoms[i] = geom_clone(init_geoms[i].ptr)
|
||||
super(GeometryCollection, self).__init__(create_collection(c_int(self._typeid), byref(geoms), c_uint(ngeoms)), **kwargs)
|
||||
|
||||
def __getitem__(self, index):
|
||||
"Returns the Geometry from this Collection at the given index (0-based)."
|
||||
# Checking the index and returning the corresponding GEOS geometry.
|
||||
self._checkindex(index)
|
||||
return GEOSGeometry(geom_clone(get_geomn(self._ptr, index)), srid=self.srid)
|
||||
return GEOSGeometry(geom_clone(get_geomn(self.ptr, index)), srid=self.srid)
|
||||
|
||||
def __setitem__(self, index, geom):
|
||||
"Sets the Geometry at the specified index."
|
||||
@ -57,12 +57,12 @@ class GeometryCollection(GEOSGeometry):
|
||||
geoms = get_pointer_arr(ngeoms)
|
||||
for i in xrange(ngeoms):
|
||||
if i == index:
|
||||
geoms[i] = geom_clone(geom._ptr)
|
||||
geoms[i] = geom_clone(geom.ptr)
|
||||
else:
|
||||
geoms[i] = geom_clone(get_geomn(self._ptr, i))
|
||||
geoms[i] = geom_clone(get_geomn(self.ptr, i))
|
||||
|
||||
# Creating a new collection, and destroying the contents of the previous poiner.
|
||||
prev_ptr = self._ptr
|
||||
prev_ptr = self.ptr
|
||||
srid = self.srid
|
||||
self._ptr = create_collection(c_int(self._typeid), byref(geoms), c_uint(ngeoms))
|
||||
if srid: self.srid = srid
|
||||
|
@ -76,18 +76,27 @@ class GEOSCoordSeq(object):
|
||||
if dim < 0 or dim > 2:
|
||||
raise GEOSException('invalid ordinate dimension "%d"' % dim)
|
||||
|
||||
@property
|
||||
def ptr(self):
|
||||
"""
|
||||
Property for controlling access to coordinate sequence pointer,
|
||||
preventing attempted access to a NULL memory location.
|
||||
"""
|
||||
if self._ptr: return self._ptr
|
||||
else: raise GEOSException('NULL coordinate sequence pointer encountered.')
|
||||
|
||||
#### Ordinate getting and setting routines ####
|
||||
def getOrdinate(self, dimension, index):
|
||||
"Returns the value for the given dimension and index."
|
||||
self._checkindex(index)
|
||||
self._checkdim(dimension)
|
||||
return cs_getordinate(self._ptr, index, dimension, byref(c_double()))
|
||||
return cs_getordinate(self.ptr, index, dimension, byref(c_double()))
|
||||
|
||||
def setOrdinate(self, dimension, index, value):
|
||||
"Sets the value for the given dimension and index."
|
||||
self._checkindex(index)
|
||||
self._checkdim(dimension)
|
||||
cs_setordinate(self._ptr, index, dimension, value)
|
||||
cs_setordinate(self.ptr, index, dimension, value)
|
||||
|
||||
def getX(self, index):
|
||||
"Get the X value at the index."
|
||||
@ -117,12 +126,12 @@ class GEOSCoordSeq(object):
|
||||
@property
|
||||
def size(self):
|
||||
"Returns the size of this coordinate sequence."
|
||||
return cs_getsize(self._ptr, byref(c_uint()))
|
||||
return cs_getsize(self.ptr, byref(c_uint()))
|
||||
|
||||
@property
|
||||
def dims(self):
|
||||
"Returns the dimensions of this coordinate sequence."
|
||||
return cs_getdims(self._ptr, byref(c_uint()))
|
||||
return cs_getdims(self.ptr, byref(c_uint()))
|
||||
|
||||
@property
|
||||
def hasz(self):
|
||||
@ -135,7 +144,7 @@ class GEOSCoordSeq(object):
|
||||
### Other Methods ###
|
||||
def clone(self):
|
||||
"Clones this coordinate sequence."
|
||||
return GEOSCoordSeq(cs_clone(self._ptr), self.hasz)
|
||||
return GEOSCoordSeq(cs_clone(self.ptr), self.hasz)
|
||||
|
||||
@property
|
||||
def kml(self):
|
||||
|
@ -166,7 +166,7 @@ class LineString(GEOSGeometry):
|
||||
|
||||
# Calling the base geometry initialization with the returned pointer
|
||||
# from the function.
|
||||
super(LineString, self).__init__(func(cs._ptr), srid=srid)
|
||||
super(LineString, self).__init__(func(cs.ptr), srid=srid)
|
||||
|
||||
def __getitem__(self, index):
|
||||
"Gets the point at the specified index."
|
||||
@ -263,10 +263,10 @@ class Polygon(GEOSGeometry):
|
||||
# Getting the holes array.
|
||||
nholes = len(init_holes)
|
||||
holes = get_pointer_arr(nholes)
|
||||
for i in xrange(nholes): holes[i] = geom_clone(init_holes[i]._ptr)
|
||||
for i in xrange(nholes): holes[i] = geom_clone(init_holes[i].ptr)
|
||||
|
||||
# Getting the shell pointer address,
|
||||
shell = geom_clone(ext_ring._ptr)
|
||||
shell = geom_clone(ext_ring.ptr)
|
||||
|
||||
# Calling with the GEOS createPolygon factory.
|
||||
super(Polygon, self).__init__(create_polygon(shell, byref(holes), c_uint(nholes)), **kwargs)
|
||||
@ -291,9 +291,9 @@ class Polygon(GEOSGeometry):
|
||||
|
||||
# Getting the shell
|
||||
if index == 0:
|
||||
shell = geom_clone(ring._ptr)
|
||||
shell = geom_clone(ring.ptr)
|
||||
else:
|
||||
shell = geom_clone(get_extring(self._ptr))
|
||||
shell = geom_clone(get_extring(self.ptr))
|
||||
|
||||
# Getting the interior rings (holes)
|
||||
nholes = len(self)-1
|
||||
@ -301,16 +301,16 @@ class Polygon(GEOSGeometry):
|
||||
holes = get_pointer_arr(nholes)
|
||||
for i in xrange(nholes):
|
||||
if i == (index-1):
|
||||
holes[i] = geom_clone(ring._ptr)
|
||||
holes[i] = geom_clone(ring.ptr)
|
||||
else:
|
||||
holes[i] = geom_clone(get_intring(self._ptr, i))
|
||||
holes[i] = geom_clone(get_intring(self.ptr, i))
|
||||
holes_param = byref(holes)
|
||||
else:
|
||||
holes_param = None
|
||||
|
||||
# Getting the current pointer, replacing with the newly constructed
|
||||
# geometry, and destroying the old geometry.
|
||||
prev_ptr = self._ptr
|
||||
prev_ptr = self.ptr
|
||||
srid = self.srid
|
||||
self._ptr = create_polygon(shell, holes_param, c_uint(nholes))
|
||||
if srid: self.srid = srid
|
||||
@ -336,18 +336,18 @@ class Polygon(GEOSGeometry):
|
||||
interior ring, not the exterior ring.
|
||||
"""
|
||||
self._checkindex(ring_i+1)
|
||||
return GEOSGeometry(geom_clone(get_intring(self._ptr, ring_i)), srid=self.srid)
|
||||
return GEOSGeometry(geom_clone(get_intring(self.ptr, ring_i)), srid=self.srid)
|
||||
|
||||
#### Polygon Properties ####
|
||||
@property
|
||||
def num_interior_rings(self):
|
||||
"Returns the number of interior rings."
|
||||
# Getting the number of rings
|
||||
return get_nrings(self._ptr)
|
||||
return get_nrings(self.ptr)
|
||||
|
||||
def get_ext_ring(self):
|
||||
"Gets the exterior ring of the Polygon."
|
||||
return GEOSGeometry(geom_clone(get_extring(self._ptr)), srid=self.srid)
|
||||
return GEOSGeometry(geom_clone(get_extring(self.ptr)), srid=self.srid)
|
||||
|
||||
def set_ext_ring(self, ring):
|
||||
"Sets the exterior ring of the Polygon."
|
||||
|
@ -6,7 +6,7 @@
|
||||
This module also houses GEOS Pointer utilities, including
|
||||
get_pointer_arr(), and GEOM_PTR.
|
||||
"""
|
||||
import atexit, os, sys
|
||||
import atexit, os, re, sys
|
||||
from ctypes import c_char_p, string_at, Structure, CDLL, CFUNCTYPE, POINTER
|
||||
from django.contrib.gis.geos.error import GEOSException
|
||||
|
||||
@ -21,7 +21,7 @@ except ImportError:
|
||||
try:
|
||||
from django.conf import settings
|
||||
lib_name = settings.GEOS_LIBRARY_PATH
|
||||
except (AttributeError, EnvironmentError):
|
||||
except (AttributeError, EnvironmentError, ImportError):
|
||||
lib_name = None
|
||||
|
||||
# Setting the appropriate name for the GEOS-C library, depending on which
|
||||
@ -96,5 +96,20 @@ def geos_version():
|
||||
"Returns the string version of GEOS."
|
||||
return string_at(lgeos.GEOSversion())
|
||||
|
||||
# Regular expression should be able to parse version strings such as
|
||||
# '3.0.0rc4-CAPI-1.3.3', or '3.0.0-CAPI-1.4.1'
|
||||
version_regex = re.compile(r'^(?P<version>\d+\.\d+\.\d+)(rc(?P<release_candidate>\d+))?-CAPI-(?P<capi_version>\d+\.\d+\.\d+)$')
|
||||
def geos_version_info():
|
||||
"""
|
||||
Returns a dictionary containing the various version metadata parsed from
|
||||
the GEOS version string, including the version number, whether the version
|
||||
is a release candidate (and what number release candidate), and the C API
|
||||
version.
|
||||
"""
|
||||
ver = geos_version()
|
||||
m = version_regex.match(ver)
|
||||
if not m: raise GEOSException('Could not parse version info string "%s"' % ver)
|
||||
return dict((key, m.group(key)) for key in ('version', 'release_candidate', 'capi_version'))
|
||||
|
||||
# Calling the finishGEOS() upon exit of the interpreter.
|
||||
atexit.register(lgeos.finishGEOS)
|
||||
|
@ -49,6 +49,12 @@ def string_from_geom(func):
|
||||
|
||||
### ctypes prototypes ###
|
||||
|
||||
# TODO: Tell all users to use GEOS 3.0.0, instead of the release
|
||||
# candidates, and use the new Reader and Writer APIs (e.g.,
|
||||
# GEOSWKT[Reader|Writer], GEOSWKB[Reader|Writer]). A good time
|
||||
# to do this will be when Refractions releases a Windows PostGIS
|
||||
# installer using GEOS 3.0.0.
|
||||
|
||||
# Creation routines from WKB, HEX, WKT
|
||||
from_hex = bin_constructor(lgeos.GEOSGeomFromHEX_buf)
|
||||
from_wkb = bin_constructor(lgeos.GEOSGeomFromWKB_buf)
|
||||
|
@ -1,10 +1,6 @@
|
||||
import random, unittest, sys
|
||||
from ctypes import ArgumentError
|
||||
from django.contrib.gis.geos import \
|
||||
GEOSException, GEOSIndexError, \
|
||||
GEOSGeometry, Point, LineString, LinearRing, Polygon, \
|
||||
MultiPoint, MultiLineString, MultiPolygon, GeometryCollection, \
|
||||
fromstr, geos_version, HAS_NUMPY
|
||||
from django.contrib.gis.geos import *
|
||||
from django.contrib.gis.geos.base import HAS_GDAL
|
||||
from django.contrib.gis.tests.geometries import *
|
||||
|
||||
@ -89,6 +85,15 @@ class GEOSTest(unittest.TestCase):
|
||||
self.assertEqual(srid, poly.shell.srid)
|
||||
self.assertEqual(srid, fromstr(poly.ewkt).srid) # Checking export
|
||||
|
||||
def test01i_eq(self):
|
||||
"Testing equivalence with WKT."
|
||||
p = fromstr('POINT(5 23)')
|
||||
self.assertEqual(p, p.wkt)
|
||||
self.assertNotEqual(p, 'foo')
|
||||
ls = fromstr('LINESTRING(0 0, 1 1, 5 5)')
|
||||
self.assertEqual(ls, ls.wkt)
|
||||
self.assertNotEqual(p, 'bar')
|
||||
|
||||
def test02a_points(self):
|
||||
"Testing Point objects."
|
||||
prev = fromstr('POINT(0 0)')
|
||||
@ -478,9 +483,17 @@ class GEOSTest(unittest.TestCase):
|
||||
|
||||
# However, when HEX is exported, the SRID information is lost
|
||||
# and set to -1. Essentially, the 'E' of the EWKB is not
|
||||
# encoded in HEX by the GEOS C library for some reason.
|
||||
# encoded in HEX by the GEOS C library unless the GEOSWKBWriter
|
||||
# method is used. GEOS 3.0.0 will not encode -1 in the HEX
|
||||
# as is done in the release candidates.
|
||||
info = geos_version_info()
|
||||
if info['version'] == '3.0.0' and info['release_candidate']:
|
||||
exp_srid = -1
|
||||
else:
|
||||
exp_srid = None
|
||||
|
||||
p2 = fromstr(p1.hex)
|
||||
self.assertEqual(-1, p2.srid)
|
||||
self.assertEqual(exp_srid, p2.srid)
|
||||
p3 = fromstr(p1.hex, srid=-1) # -1 is intended.
|
||||
self.assertEqual(-1, p3.srid)
|
||||
|
||||
@ -651,6 +664,15 @@ class GEOSTest(unittest.TestCase):
|
||||
self.assertEqual(g2.hex, g2.ogr.hex)
|
||||
self.assertEqual('WGS 84', g2.srs.name)
|
||||
|
||||
def test22_copy(self):
|
||||
"Testing use with the Python `copy` module."
|
||||
import copy
|
||||
poly = GEOSGeometry('POLYGON((0 0, 0 23, 23 23, 23 0, 0 0), (5 5, 5 10, 10 10, 10 5, 5 5))')
|
||||
cpy1 = copy.copy(poly)
|
||||
cpy2 = copy.deepcopy(poly)
|
||||
self.assertNotEqual(poly._ptr, cpy1._ptr)
|
||||
self.assertNotEqual(poly._ptr, cpy2._ptr)
|
||||
|
||||
def suite():
|
||||
s = unittest.TestSuite()
|
||||
s.addTest(unittest.makeSuite(GEOSTest))
|
||||
|
Loading…
x
Reference in New Issue
Block a user