mirror of
https://github.com/django/django.git
synced 2025-07-04 17:59:13 +00:00
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
This commit is contained in:
parent
39f9d48e4e
commit
522400d8ef
@ -30,7 +30,7 @@
|
|||||||
# Trying not to pollute the namespace.
|
# Trying not to pollute the namespace.
|
||||||
from ctypes import \
|
from ctypes import \
|
||||||
CDLL, CFUNCTYPE, byref, string_at, create_string_buffer, \
|
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
|
import os, sys
|
||||||
|
|
||||||
"""
|
"""
|
||||||
@ -43,10 +43,10 @@ import os, sys
|
|||||||
installation of SWIG.
|
installation of SWIG.
|
||||||
(2) The PCL implementation is over 2K+ lines of C and would make
|
(2) The PCL implementation is over 2K+ lines of C and would make
|
||||||
PCL a requisite package for the GeoDjango application stack.
|
PCL a requisite package for the GeoDjango application stack.
|
||||||
(3) Windows compatibility becomes substantially easier, and does not require the
|
(3) Windows and Mac compatibility becomes substantially easier, and does not
|
||||||
additional compilation of PCL or GEOS and SWIG -- all that is needed is
|
require the additional compilation of PCL or GEOS and SWIG -- all that
|
||||||
a Win32 compiled GEOS C library (dll) in a location that Python can read
|
is needed is a Win32 or Mac compiled GEOS C library (dll or dylib)
|
||||||
(e.g. C:\Python25).
|
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
|
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).
|
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
|
# 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':
|
if os.name == 'nt':
|
||||||
# Windows NT library
|
# Windows NT library
|
||||||
lib_name = 'libgeos_c-1.dll'
|
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:
|
else:
|
||||||
# Linux shared library
|
raise GEOSException, 'Unsupported OS "%s"' % os.name
|
||||||
lib_name = 'libgeos_c.so'
|
|
||||||
|
|
||||||
# Getting the GEOS C library. The C interface (CDLL) is used for
|
# Getting the GEOS C library. The C interface (CDLL) is used for
|
||||||
# both *NIX and Windows.
|
# both *NIX and Windows.
|
||||||
@ -79,7 +88,7 @@ else:
|
|||||||
# http://geos.refractions.net/ro/doxygen_docs/html/geos__c_8h-source.html
|
# http://geos.refractions.net/ro/doxygen_docs/html/geos__c_8h-source.html
|
||||||
lgeos = CDLL(lib_name)
|
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):
|
# Supposed to mimic the GEOS message handler (C below):
|
||||||
# "typedef void (*GEOSMessageHandler)(const char *fmt, ...);"
|
# "typedef void (*GEOSMessageHandler)(const char *fmt, ...);"
|
||||||
NOTICEFUNC = CFUNCTYPE(None, c_char_p, c_char_p)
|
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)
|
ERRORFUNC = CFUNCTYPE(None, c_char_p, c_char_p)
|
||||||
def error_h(fmt, list):
|
def error_h(fmt, list):
|
||||||
|
# TODO: Figure out why improper format code given w/some GEOS errors
|
||||||
if not list:
|
if not list:
|
||||||
sys.stderr.write(fmt)
|
sys.stderr.write(fmt)
|
||||||
else:
|
else:
|
||||||
@ -102,6 +112,7 @@ error_h = ERRORFUNC(error_h)
|
|||||||
lgeos.initGEOS(notice_h, error_h)
|
lgeos.initGEOS(notice_h, error_h)
|
||||||
|
|
||||||
class GEOSException:
|
class GEOSException:
|
||||||
|
"Exception class for any GEOS-related errors."
|
||||||
def __init__(self, msg):
|
def __init__(self, msg):
|
||||||
self.msg = msg
|
self.msg = msg
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
@ -289,7 +300,7 @@ class GEOSGeometry:
|
|||||||
if s == 0:
|
if s == 0:
|
||||||
return None
|
return None
|
||||||
else:
|
else:
|
||||||
return lgeos.GEOSGetSRID(self._g)
|
return s
|
||||||
|
|
||||||
def set_srid(self, srid):
|
def set_srid(self, srid):
|
||||||
"Sets the SRID for the geometry."
|
"Sets the SRID for the geometry."
|
||||||
@ -408,14 +419,11 @@ class GEOSCoordSeq:
|
|||||||
yield self.__getitem__(i)
|
yield self.__getitem__(i)
|
||||||
|
|
||||||
def __len__(self):
|
def __len__(self):
|
||||||
return self.size
|
return int(self.size)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
"The string representation of the coordinate sequence."
|
"The string representation of the coordinate sequence."
|
||||||
rep = []
|
return str(self.tuple)
|
||||||
for i in xrange(self.size):
|
|
||||||
rep.append(self.__getitem__(i))
|
|
||||||
return str(tuple(rep))
|
|
||||||
|
|
||||||
def _checkindex(self, index):
|
def _checkindex(self, index):
|
||||||
"Checks the index."
|
"Checks the index."
|
||||||
@ -445,9 +453,9 @@ class GEOSCoordSeq:
|
|||||||
set_3d = False
|
set_3d = False
|
||||||
if len(value) != n_args:
|
if len(value) != n_args:
|
||||||
raise GEOSException, 'Improper value given!'
|
raise GEOSException, 'Improper value given!'
|
||||||
self.setX(index, value)
|
self.setX(index, value[0])
|
||||||
self.setY(index, value)
|
self.setY(index, value[1])
|
||||||
if set_3d: self.setZ(index, value)
|
if set_3d: self.setZ(index, value[2])
|
||||||
|
|
||||||
# Getting and setting the X coordinate for the given index.
|
# Getting and setting the X coordinate for the given index.
|
||||||
def getX(self, index):
|
def getX(self, index):
|
||||||
@ -460,15 +468,15 @@ class GEOSCoordSeq:
|
|||||||
def getY(self, index):
|
def getY(self, index):
|
||||||
return self.getOrdinate(1, index)
|
return self.getOrdinate(1, index)
|
||||||
|
|
||||||
def setY(self, index):
|
def setY(self, index, value):
|
||||||
self.setOrdinate(1, index)
|
self.setOrdinate(1, index, value)
|
||||||
|
|
||||||
# Getting and setting the Z coordinate for the given index
|
# Getting and setting the Z coordinate for the given index
|
||||||
def getZ(self, index):
|
def getZ(self, index):
|
||||||
return self.getOrdinate(2, index)
|
return self.getOrdinate(2, index)
|
||||||
|
|
||||||
def setZ(self, index):
|
def setZ(self, index, value):
|
||||||
self.setOrdinate(2, index)
|
self.setOrdinate(2, index, value)
|
||||||
|
|
||||||
def getOrdinate(self, dimension, index):
|
def getOrdinate(self, dimension, index):
|
||||||
"Gets the value for the given dimension and index."
|
"Gets the value for the given dimension and index."
|
||||||
@ -488,16 +496,15 @@ class GEOSCoordSeq:
|
|||||||
|
|
||||||
def setOrdinate(self, dimension, index, value):
|
def setOrdinate(self, dimension, index, value):
|
||||||
"Sets the value for the given dimension and index."
|
"Sets the value for the given dimension and index."
|
||||||
self._checkindex(idnex)
|
self._checkindex(index)
|
||||||
self._checkdim(dimension)
|
self._checkdim(dimension)
|
||||||
|
|
||||||
# Wrapping the dimension, index
|
# Wrapping the dimension, index
|
||||||
dim = c_uint(dimension)
|
dim = c_uint(dimension)
|
||||||
idx = c_uint(index)
|
idx = c_uint(index)
|
||||||
|
|
||||||
# 'd' is the value of the point
|
# Setting the ordinate
|
||||||
d = c_double(value)
|
status = lgeos.GEOSCoordSeq_setOrdinate(self._cs, idx, dim, c_double(value))
|
||||||
status = lgeos.GEOSCoordSeq_getOrdinate(self._cs, idx, dim, byref(d))
|
|
||||||
if status == 0:
|
if status == 0:
|
||||||
raise GEOSException, 'Could not set the ordinate for (dim, index): (%d, %d)' % (dimension, index)
|
raise GEOSException, 'Could not set the ordinate for (dim, index): (%d, %d)' % (dimension, index)
|
||||||
|
|
||||||
|
@ -149,6 +149,28 @@ class GeosTest2(unittest.TestCase):
|
|||||||
# "Testing LinearRing objects."
|
# "Testing LinearRing objects."
|
||||||
# pass
|
# 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):
|
def test09_relate_pattern(self):
|
||||||
"Testing relate() and relate_pattern()."
|
"Testing relate() and relate_pattern()."
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user