summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJustin Bronn <jbronn@gmail.com>2007-04-18 00:13:25 +0000
committerJustin Bronn <jbronn@gmail.com>2007-04-18 00:13:25 +0000
commit522400d8ef6e1557984da13da793f20f94233f7a (patch)
treece0a3f6dc071741d063dcbb10bbb043f632ec46f
parent39f9d48e4e60a1d82a16f831f3c6153ac21f9148 (diff)
gis: fixed bugs in GEOSCoordSeq (and added a test case). added preliminary support for Mac OSX compiled GEOS libraries.
git-svn-id: http://code.djangoproject.com/svn/django/branches/gis@5023 bcc190cf-cafb-0310-a4f2-bffc1f526a37
-rw-r--r--django/contrib/gis/geos/GEOSGeometry.py59
-rw-r--r--django/contrib/gis/tests/test_geos.py22
2 files changed, 55 insertions, 26 deletions
diff --git a/django/contrib/gis/geos/GEOSGeometry.py b/django/contrib/gis/geos/GEOSGeometry.py
index 034267d73b..1cb62a855b 100644
--- a/django/contrib/gis/geos/GEOSGeometry.py
+++ b/django/contrib/gis/geos/GEOSGeometry.py
@@ -30,7 +30,7 @@
# Trying not to pollute the namespace.
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, c_ubyte
+ c_char_p, c_double, c_float, c_int, c_uint, c_size_t
import os, sys
"""
@@ -43,10 +43,10 @@ import os, sys
installation of SWIG.
(2) The PCL implementation is over 2K+ lines of C and would make
PCL a requisite package for the GeoDjango application stack.
- (3) Windows compatibility becomes substantially easier, and does not require the
- additional compilation of PCL or GEOS and SWIG -- all that is needed is
- a Win32 compiled GEOS C library (dll) in a location that Python can read
- (e.g. C:\Python25).
+ (3) Windows and Mac compatibility becomes substantially easier, and does not
+ require the additional compilation of PCL or GEOS and SWIG -- all that
+ is needed is a Win32 or Mac compiled GEOS C library (dll or dylib)
+ in a location that Python can read (e.g. 'C:\Python25').
In summary, I wanted to wrap GEOS in a more maintainable and portable way using
only Python and the excellent ctypes library (now standard in Python 2.5).
@@ -65,13 +65,22 @@ import os, sys
"""
# Setting the appropriate name for the GEOS-C library, depending on which
-# platform we're running.
+# OS and POSIX platform we're running.
if os.name == 'nt':
# Windows NT library
lib_name = 'libgeos_c-1.dll'
+elif os.name == 'posix':
+ platform = os.uname()[0] # Using os.uname()
+ if platform == 'Linux':
+ # Linux shared library
+ lib_name = 'libgeos_c.so'
+ elif platform == 'Darwin':
+ # Mac OSX Shared Library (Thanks Matt!)
+ lib_name = 'libgeos_c.dylib'
+ else:
+ raise GEOSException, 'Unknown POSIX platform "%s"' % platform
else:
- # Linux shared library
- lib_name = 'libgeos_c.so'
+ raise GEOSException, 'Unsupported OS "%s"' % os.name
# Getting the GEOS C library. The C interface (CDLL) is used for
# both *NIX and Windows.
@@ -79,7 +88,7 @@ else:
# http://geos.refractions.net/ro/doxygen_docs/html/geos__c_8h-source.html
lgeos = CDLL(lib_name)
-# The notice and error handlers
+# The notice and error handler C function callback definitions.
# Supposed to mimic the GEOS message handler (C below):
# "typedef void (*GEOSMessageHandler)(const char *fmt, ...);"
NOTICEFUNC = CFUNCTYPE(None, c_char_p, c_char_p)
@@ -89,6 +98,7 @@ notice_h = NOTICEFUNC(notice_h)
ERRORFUNC = CFUNCTYPE(None, c_char_p, c_char_p)
def error_h(fmt, list):
+ # TODO: Figure out why improper format code given w/some GEOS errors
if not list:
sys.stderr.write(fmt)
else:
@@ -102,6 +112,7 @@ error_h = ERRORFUNC(error_h)
lgeos.initGEOS(notice_h, error_h)
class GEOSException:
+ "Exception class for any GEOS-related errors."
def __init__(self, msg):
self.msg = msg
def __str__(self):
@@ -289,7 +300,7 @@ class GEOSGeometry:
if s == 0:
return None
else:
- return lgeos.GEOSGetSRID(self._g)
+ return s
def set_srid(self, srid):
"Sets the SRID for the geometry."
@@ -408,14 +419,11 @@ class GEOSCoordSeq:
yield self.__getitem__(i)
def __len__(self):
- return self.size
+ return int(self.size)
def __str__(self):
"The string representation of the coordinate sequence."
- rep = []
- for i in xrange(self.size):
- rep.append(self.__getitem__(i))
- return str(tuple(rep))
+ return str(self.tuple)
def _checkindex(self, index):
"Checks the index."
@@ -445,9 +453,9 @@ class GEOSCoordSeq:
set_3d = False
if len(value) != n_args:
raise GEOSException, 'Improper value given!'
- self.setX(index, value)
- self.setY(index, value)
- if set_3d: self.setZ(index, value)
+ self.setX(index, value[0])
+ self.setY(index, value[1])
+ if set_3d: self.setZ(index, value[2])
# Getting and setting the X coordinate for the given index.
def getX(self, index):
@@ -460,15 +468,15 @@ class GEOSCoordSeq:
def getY(self, index):
return self.getOrdinate(1, index)
- def setY(self, index):
- self.setOrdinate(1, index)
+ def setY(self, index, value):
+ self.setOrdinate(1, index, value)
# Getting and setting the Z coordinate for the given index
def getZ(self, index):
return self.getOrdinate(2, index)
- def setZ(self, index):
- self.setOrdinate(2, index)
+ def setZ(self, index, value):
+ self.setOrdinate(2, index, value)
def getOrdinate(self, dimension, index):
"Gets the value for the given dimension and index."
@@ -488,16 +496,15 @@ class GEOSCoordSeq:
def setOrdinate(self, dimension, index, value):
"Sets the value for the given dimension and index."
- self._checkindex(idnex)
+ self._checkindex(index)
self._checkdim(dimension)
# Wrapping the dimension, index
dim = c_uint(dimension)
idx = c_uint(index)
- # 'd' is the value of the point
- d = c_double(value)
- status = lgeos.GEOSCoordSeq_getOrdinate(self._cs, idx, dim, byref(d))
+ # Setting the ordinate
+ status = lgeos.GEOSCoordSeq_setOrdinate(self._cs, idx, dim, c_double(value))
if status == 0:
raise GEOSException, 'Could not set the ordinate for (dim, index): (%d, %d)' % (dimension, index)
diff --git a/django/contrib/gis/tests/test_geos.py b/django/contrib/gis/tests/test_geos.py
index ffe9465a99..2ec443b29e 100644
--- a/django/contrib/gis/tests/test_geos.py
+++ b/django/contrib/gis/tests/test_geos.py
@@ -149,6 +149,28 @@ class GeosTest2(unittest.TestCase):
# "Testing LinearRing objects."
# pass
+ def test08_coord_seq(self):
+ "Testing Coordinate Sequence objects."
+ for p in polygons:
+ if p.ext_ring_cs:
+ poly = GEOSGeometry(p.wkt)
+ cs = poly.exterior_ring.coord_seq
+
+ self.assertEqual(p.ext_ring_cs, cs.tuple) # done in the Polygon test too.
+ self.assertEqual(len(p.ext_ring_cs), len(cs)) # Making sure __len__ works
+
+ # Checks __getitem__ and __setitem__
+ for i in xrange(len(p.ext_ring_cs)):
+ c1 = p.ext_ring_cs[i]
+ c2 = cs[i]
+ self.assertEqual(c1, c2)
+ if len(c1) == 2: tset = (5, 23)
+ else: tset = (5, 23, 8)
+ cs[i] = tset
+ for j in range(len(tset)):
+ cs[i] = tset
+ self.assertEqual(tset, cs[i])
+
def test09_relate_pattern(self):
"Testing relate() and relate_pattern()."