1
0
mirror of https://github.com/django/django.git synced 2025-07-04 09:49:12 +00:00

gis: GEOSGeometry updates, improved initialization & tests, simplified some routines.

git-svn-id: http://code.djangoproject.com/svn/django/branches/gis@5474 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Justin Bronn 2007-06-15 03:49:25 +00:00
parent 6538a26a47
commit b0b7bbced7
3 changed files with 55 additions and 51 deletions

View File

@ -32,6 +32,7 @@ from ctypes import \
CDLL, CFUNCTYPE, byref, string_at, create_string_buffer, \
c_char_p, c_double, c_float, c_int, c_uint, c_size_t
import os, sys
from types import StringType, IntType, FloatType
"""
The goal of this module is to be a ctypes wrapper around the GEOS library
@ -120,32 +121,35 @@ class GEOSGeometry(object):
_g = 0 # Initially NULL
#### Python 'magic' routines ####
def __init__(self, input, geom_type='wkt'):
def __init__(self, input, input_type='wkt'):
"Takes an input and the type of the input for initialization."
if geom_type == 'wkt':
if isinstance(input, StringType):
if input_type == 'wkt':
# If the geometry is in WKT form
g = lgeos.GEOSGeomFromWKT(c_char_p(input))
elif geom_type == 'hex':
elif input_type == 'hex':
# If the geometry is in HEX form.
sz = c_size_t(len(input))
buf = create_string_buffer(input)
g = lgeos.GEOSGeomFromHEX_buf(buf, sz)
elif geom_type == 'geos':
else:
raise GEOSException, 'GEOS input geometry type "%s" not supported!' % input_type
elif isinstance(input, IntType):
# When the input is a C pointer (Python integer)
g = input
else:
# Invalid geometry type.
raise GEOSException, 'Improper geometry input type!'
raise GEOSException, 'Improper geometry input type: %s' % str(type(input))
# If the geometry pointer is NULL (0), then raise an exception.
# If the geometry pointer is NULL (0), raise an exception.
if not g:
raise GEOSException, 'Invalid %s given!' % geom_type.upper()
raise GEOSException, 'Invalid %s given!' % input_type.upper()
else:
self._g = g
# Setting the class type (e.g. 'Point', 'Polygon', etc.)
self.__class__ = GEO_CLASSES[self.geom_type]
self.__class__ = GEOS_CLASSES[self.geom_type]
def __del__(self):
"This cleans up the memory allocated for the geometry."
@ -184,6 +188,11 @@ class GEOSGeometry(object):
if n == -1: raise GEOSException, 'Error getting number of coordinates!'
else: return n
@property
def num_points(self):
"Returns the number points, or coordinates, in the geometry."
return self.num_coords
@property
def dims(self):
"Returns the dimension of this Geometry (0=point, 1=line, 2=surface)."
@ -327,44 +336,39 @@ 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)
"""
if type(width) != type(0.0):
if not isinstance(width, FloatType):
raise TypeError, 'width parameter must be a float'
if type(quadsegs) != type(0):
if not isinstance(quadsegs, IntType):
raise TypeError, 'quadsegs parameter must be an integer'
b = lgeos.GEOSBuffer(self._g, c_double(width), c_int(quadsegs))
return GEOSGeometry(b, 'geos')
return GEOSGeometry(b)
@property
def envelope(self):
"Return the geometries bounding box."
e = lgeos.GEOSEnvelope(self._g)
return GEOSGeometry(e, 'geos')
return GEOSGeometry(lgeos.GEOSEnvelope(self._g))
@property
def centroid(self):
"""The centroid is equal to the centroid of the set of component Geometrys
of highest dimension (since the lower-dimension geometries contribute zero
"weight" to the centroid)."""
g = lgeos.GEOSGetCentroid(self._g)
return GEOSGeometry(g, 'geos')
return GEOSGeometry(lgeos.GEOSGetCentroid(self._g))
@property
def boundary(self):
"Returns the boundary as a newly allocated Geometry object."
g = lgeos.GEOSBoundary(self._g)
return GEOSGeometry(g, 'geos')
return GEOSGeometry(lgeos.GEOSBoundary(self._g))
@property
def convex_hull(self):
"Returns the smallest convex Polygon that contains all the points in the Geometry."
g = lgeos.GEOSConvexHull(self._g)
return GEOSGeometry(g, 'geos')
return GEOSGeometry(lgeos.GEOSConvexHull(self._g))
@property
def point_on_surface(self):
"Computes an interior point of this Geometry."
g = lgeos.GEOSPointOnSurface(self._g)
return GEOSGeometry(g, 'geos')
return GEOSGeometry(lgeos.GEOSPointOnSurface(self._g))
def relate(self, other):
"Returns the DE-9IM intersection matrix for this geometry and the other."
@ -373,24 +377,20 @@ class GEOSGeometry(object):
def difference(self, other):
"""Returns a Geometry representing the points making up this Geometry
that do not make up other."""
d = lgeos.GEOSDifference(self._g, other._g)
return GEOSGeometry(d, 'geos')
return GEOSGeometry(lgeos.GEOSDifference(self._g, other._g))
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."""
d = lgeos.GEOSSymDifference(self._g, other._g)
return GEOSGeometry(d, 'geos')
return GEOSGeometry(lgeos.GEOSSymDifference(self._g, other._g))
def intersection(self, other):
"Returns a Geometry representing the points shared by this Geometry and other."
i = lgeos.GEOSIntersection(self._g, other._g)
return GEOSGeometry(i, 'geos')
return GEOSGeometry(lgeos.GEOSIntersection(self._g, other._g))
def union(self, other):
"Returns a Geometry representing all the points in this Geometry and other."
u = lgeos.GEOSUnion(self._g, other._g)
return GEOSGeometry(u, 'geos')
return GEOSGeometry(lgeos.GEOSUnion(self._g, other._g))
#### Other Routines ####
@property
@ -641,7 +641,6 @@ class Polygon(GEOSGeometry):
"Returns the number of rings in this Polygon."
return self.num_interior_rings + 1
def get_interior_ring(self, ring_i):
"Gets the interior ring at the specified index."
@ -698,8 +697,8 @@ class GeometryCollection(GEOSGeometry):
def __getitem__(self, index):
"For indexing on the multiple geometries."
self._checkindex(index)
item = lgeos.GEOSGeom_clone(lgeos.GEOSGetGeometryN(self._g, c_int(index)))
return GEOSGeometry(item, 'geos')
# Cloning the GEOS Geometry first, before returning it.
return GEOSGeometry(lgeos.GEOSGeom_clone(lgeos.GEOSGetGeometryN(self._g, c_int(index))))
def __len__(self):
"Returns the number of geometries in this collection."
@ -711,7 +710,7 @@ class MultiLineString(GeometryCollection): pass
class MultiPolygon(GeometryCollection): pass
# Class mapping dictionary
GEO_CLASSES = {'Point' : Point,
GEOS_CLASSES = {'Point' : Point,
'Polygon' : Polygon,
'LineString' : LineString,
'LinearRing' : LinearRing,

View File

@ -83,6 +83,12 @@ class GeosTest2(unittest.TestCase):
self.assertEqual(poly.ring, False)
self.assertEqual(p.n_i, poly.num_interior_rings)
self.assertEqual(p.n_i + 1, len(poly)) # Testing __len__
self.assertEqual(p.n_p, poly.num_points)
# Area & Centroid
self.assertAlmostEqual(p.area, poly.area, 9)
self.assertAlmostEqual(p.centroid[0], poly.centroid.tuple[0], 9)
self.assertAlmostEqual(p.centroid[1], poly.centroid.tuple[1], 9)
# Testing the geometry equivalence
self.assertEqual(True, poly == GEOSGeometry(p.wkt))
@ -145,7 +151,6 @@ class GeosTest2(unittest.TestCase):
self.assertAlmostEqual(l.centroid[0], ml.centroid.x, 9)
self.assertAlmostEqual(l.centroid[1], ml.centroid.y, 9)
self.assertEqual(True, ml == GEOSGeometry(l.wkt))
self.assertEqual(False, ml == prev)
prev = ml

View File

@ -3,7 +3,7 @@ from django.contrib.gis.geos import GEOSGeometry, hex_to_wkt, wkt_to_hex, centro
from geos import geomToWKT, geomToHEX, geomFromWKT, geomFromHEX
from geometries import swig_geoms as geos_geoms
class GeosTest(unittest.TestCase):
class GeosTestWithSwig(unittest.TestCase):
def test001_hex_to_wkt(self):
"Testing HEX to WKT conversion."
@ -20,7 +20,7 @@ class GeosTest(unittest.TestCase):
def test003_centroid(self):
"Testing the centroid property."
for g in geos_geoms:
wkt1 = (centroid(g.wkt, geom_type='wkt')).wkt
wkt1 = centroid(g.wkt, geom_type='wkt')
wkt2 = geomToWKT((geomFromWKT(g.wkt)).getCentroid())
self.assertEqual(wkt1, wkt2)
@ -60,7 +60,7 @@ class GeosTest(unittest.TestCase):
def suite():
s = unittest.TestSuite()
s.addTest(unittest.makeSuite(GeosTest))
s.addTest(unittest.makeSuite(GeosTestWithSwig))
return s
def run(verbosity=2):