Fixed #10923 -- The GEOS bindings now use the thread-safe API, when applicable. Thanks, Tuure Laurinolli, for assistance in developing this patch.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@12214 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
418bfa2819
commit
32e0117abb
|
@ -21,6 +21,10 @@ from django.contrib.gis.geos.mutable_list import ListMixin
|
||||||
# the underlying GEOS library.
|
# the underlying GEOS library.
|
||||||
from django.contrib.gis.geos import prototypes as capi
|
from django.contrib.gis.geos import prototypes as capi
|
||||||
|
|
||||||
|
# These functions provide access to a thread-local instance
|
||||||
|
# of their corresponding GEOS I/O class.
|
||||||
|
from django.contrib.gis.geos.prototypes.io import wkt_r, wkt_w, wkb_r, wkb_w, ewkb_w, ewkb_w3d
|
||||||
|
|
||||||
# Regular expression for recognizing HEXEWKB and WKT. A prophylactic measure
|
# Regular expression for recognizing HEXEWKB and WKT. A prophylactic measure
|
||||||
# to prevent potentially malicious input from reaching the underlying C
|
# to prevent potentially malicious input from reaching the underlying C
|
||||||
# library. Not a substitute for good web security programming practices.
|
# library. Not a substitute for good web security programming practices.
|
||||||
|
@ -61,13 +65,13 @@ class GEOSGeometry(GEOSBase, ListMixin):
|
||||||
if wkt_m:
|
if wkt_m:
|
||||||
# Handling WKT input.
|
# Handling WKT input.
|
||||||
if wkt_m.group('srid'): srid = int(wkt_m.group('srid'))
|
if wkt_m.group('srid'): srid = int(wkt_m.group('srid'))
|
||||||
g = wkt_r.read(wkt_m.group('wkt'))
|
g = wkt_r().read(wkt_m.group('wkt'))
|
||||||
elif hex_regex.match(geo_input):
|
elif hex_regex.match(geo_input):
|
||||||
# Handling HEXEWKB input.
|
# Handling HEXEWKB input.
|
||||||
g = wkb_r.read(geo_input)
|
g = wkb_r().read(geo_input)
|
||||||
elif gdal.GEOJSON and gdal.geometries.json_regex.match(geo_input):
|
elif gdal.GEOJSON and gdal.geometries.json_regex.match(geo_input):
|
||||||
# Handling GeoJSON input.
|
# Handling GeoJSON input.
|
||||||
g = wkb_r.read(gdal.OGRGeometry(geo_input).wkb)
|
g = wkb_r().read(gdal.OGRGeometry(geo_input).wkb)
|
||||||
else:
|
else:
|
||||||
raise ValueError('String or unicode input unrecognized as WKT EWKT, and HEXEWKB.')
|
raise ValueError('String or unicode input unrecognized as WKT EWKT, and HEXEWKB.')
|
||||||
elif isinstance(geo_input, GEOM_PTR):
|
elif isinstance(geo_input, GEOM_PTR):
|
||||||
|
@ -75,7 +79,7 @@ class GEOSGeometry(GEOSBase, ListMixin):
|
||||||
g = geo_input
|
g = geo_input
|
||||||
elif isinstance(geo_input, buffer):
|
elif isinstance(geo_input, buffer):
|
||||||
# When the input is a buffer (WKB).
|
# When the input is a buffer (WKB).
|
||||||
g = wkb_r.read(geo_input)
|
g = wkb_r().read(geo_input)
|
||||||
elif isinstance(geo_input, GEOSGeometry):
|
elif isinstance(geo_input, GEOSGeometry):
|
||||||
g = capi.geom_clone(geo_input.ptr)
|
g = capi.geom_clone(geo_input.ptr)
|
||||||
else:
|
else:
|
||||||
|
@ -368,7 +372,7 @@ class GEOSGeometry(GEOSBase, ListMixin):
|
||||||
@property
|
@property
|
||||||
def wkt(self):
|
def wkt(self):
|
||||||
"Returns the WKT (Well-Known Text) representation of this Geometry."
|
"Returns the WKT (Well-Known Text) representation of this Geometry."
|
||||||
return wkt_w.write(self)
|
return wkt_w().write(self)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def hex(self):
|
def hex(self):
|
||||||
|
@ -380,7 +384,7 @@ class GEOSGeometry(GEOSBase, ListMixin):
|
||||||
"""
|
"""
|
||||||
# A possible faster, all-python, implementation:
|
# A possible faster, all-python, implementation:
|
||||||
# str(self.wkb).encode('hex')
|
# str(self.wkb).encode('hex')
|
||||||
return wkb_w.write_hex(self)
|
return wkb_w().write_hex(self)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def hexewkb(self):
|
def hexewkb(self):
|
||||||
|
@ -393,9 +397,9 @@ class GEOSGeometry(GEOSBase, ListMixin):
|
||||||
if not GEOS_PREPARE:
|
if not GEOS_PREPARE:
|
||||||
# See: http://trac.osgeo.org/geos/ticket/216
|
# See: http://trac.osgeo.org/geos/ticket/216
|
||||||
raise GEOSException('Upgrade GEOS to 3.1 to get valid 3D HEXEWKB.')
|
raise GEOSException('Upgrade GEOS to 3.1 to get valid 3D HEXEWKB.')
|
||||||
return ewkb_w3d.write_hex(self)
|
return ewkb_w3d().write_hex(self)
|
||||||
else:
|
else:
|
||||||
return ewkb_w.write_hex(self)
|
return ewkb_w().write_hex(self)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def json(self):
|
def json(self):
|
||||||
|
@ -416,7 +420,7 @@ class GEOSGeometry(GEOSBase, ListMixin):
|
||||||
as a Python buffer. SRID and Z values are not included, use the
|
as a Python buffer. SRID and Z values are not included, use the
|
||||||
`ewkb` property instead.
|
`ewkb` property instead.
|
||||||
"""
|
"""
|
||||||
return wkb_w.write(self)
|
return wkb_w().write(self)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def ewkb(self):
|
def ewkb(self):
|
||||||
|
@ -429,9 +433,9 @@ class GEOSGeometry(GEOSBase, ListMixin):
|
||||||
if not GEOS_PREPARE:
|
if not GEOS_PREPARE:
|
||||||
# See: http://trac.osgeo.org/geos/ticket/216
|
# See: http://trac.osgeo.org/geos/ticket/216
|
||||||
raise GEOSException('Upgrade GEOS to 3.1 to get valid 3D EWKB.')
|
raise GEOSException('Upgrade GEOS to 3.1 to get valid 3D EWKB.')
|
||||||
return ewkb_w3d.write(self)
|
return ewkb_w3d().write(self)
|
||||||
else:
|
else:
|
||||||
return ewkb_w.write(self)
|
return ewkb_w().write(self)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def kml(self):
|
def kml(self):
|
||||||
|
@ -493,7 +497,7 @@ class GEOSGeometry(GEOSBase, ListMixin):
|
||||||
g = gdal.OGRGeometry(self.wkb, srid)
|
g = gdal.OGRGeometry(self.wkb, srid)
|
||||||
g.transform(ct)
|
g.transform(ct)
|
||||||
# Getting a new GEOS pointer
|
# Getting a new GEOS pointer
|
||||||
ptr = wkb_r.read(g.wkb)
|
ptr = wkb_r().read(g.wkb)
|
||||||
if clone:
|
if clone:
|
||||||
# User wants a cloned transformed geometry returned.
|
# User wants a cloned transformed geometry returned.
|
||||||
return GEOSGeometry(ptr, srid=g.srid)
|
return GEOSGeometry(ptr, srid=g.srid)
|
||||||
|
@ -655,9 +659,6 @@ GEOS_CLASSES = {0 : Point,
|
||||||
7 : GeometryCollection,
|
7 : GeometryCollection,
|
||||||
}
|
}
|
||||||
|
|
||||||
# Similarly, import the GEOS I/O instances here to avoid conflicts.
|
|
||||||
from django.contrib.gis.geos.io import wkt_r, wkt_w, wkb_r, wkb_w, ewkb_w, ewkb_w3d
|
|
||||||
|
|
||||||
# If supported, import the PreparedGeometry class.
|
# If supported, import the PreparedGeometry class.
|
||||||
if GEOS_PREPARE:
|
if GEOS_PREPARE:
|
||||||
from django.contrib.gis.geos.prepared import PreparedGeometry
|
from django.contrib.gis.geos.prepared import PreparedGeometry
|
||||||
|
|
|
@ -3,128 +3,18 @@ Module that holds classes for performing I/O operations on GEOS geometry
|
||||||
objects. Specifically, this has Python implementations of WKB/WKT
|
objects. Specifically, this has Python implementations of WKB/WKT
|
||||||
reader and writer classes.
|
reader and writer classes.
|
||||||
"""
|
"""
|
||||||
from ctypes import byref, c_size_t
|
|
||||||
from django.contrib.gis.geos.base import GEOSBase
|
|
||||||
from django.contrib.gis.geos.error import GEOSException
|
|
||||||
from django.contrib.gis.geos.geometry import GEOSGeometry
|
from django.contrib.gis.geos.geometry import GEOSGeometry
|
||||||
from django.contrib.gis.geos.libgeos import GEOM_PTR
|
from django.contrib.gis.geos.prototypes.io import _WKTReader, _WKBReader, WKBWriter, WKTWriter
|
||||||
from django.contrib.gis.geos.prototypes import io as capi
|
|
||||||
|
|
||||||
class IOBase(GEOSBase):
|
# Public classes for (WKB|WKT)Reader, which return GEOSGeometry
|
||||||
"Base class for GEOS I/O objects."
|
class WKBReader(_WKBReader):
|
||||||
def __init__(self):
|
def read(self, wkb):
|
||||||
# Getting the pointer with the constructor.
|
"Returns a GEOSGeometry for the given WKB buffer."
|
||||||
self.ptr = self._constructor()
|
return GEOSGeometry(super(WKBReader, self).read(wkb))
|
||||||
|
|
||||||
def __del__(self):
|
|
||||||
# Cleaning up with the appropriate destructor.
|
|
||||||
if self._ptr: self._destructor(self._ptr)
|
|
||||||
|
|
||||||
### WKT Reading and Writing objects ###
|
|
||||||
|
|
||||||
# Non-public class for internal use because its `read` method returns
|
|
||||||
# _pointers_ instead of a GEOSGeometry object.
|
|
||||||
class _WKTReader(IOBase):
|
|
||||||
_constructor = capi.wkt_reader_create
|
|
||||||
_destructor = capi.wkt_reader_destroy
|
|
||||||
ptr_type = capi.WKT_READ_PTR
|
|
||||||
|
|
||||||
def read(self, wkt):
|
|
||||||
if not isinstance(wkt, basestring): raise TypeError
|
|
||||||
return capi.wkt_reader_read(self.ptr, wkt)
|
|
||||||
|
|
||||||
class WKTReader(_WKTReader):
|
class WKTReader(_WKTReader):
|
||||||
def read(self, wkt):
|
def read(self, wkt):
|
||||||
"Returns a GEOSGeometry for the given WKT string."
|
"Returns a GEOSGeometry for the given WKT string."
|
||||||
return GEOSGeometry(super(WKTReader, self).read(wkt))
|
return GEOSGeometry(super(WKTReader, self).read(wkt))
|
||||||
|
|
||||||
class WKTWriter(IOBase):
|
|
||||||
_constructor = capi.wkt_writer_create
|
|
||||||
_destructor = capi.wkt_writer_destroy
|
|
||||||
ptr_type = capi.WKT_WRITE_PTR
|
|
||||||
|
|
||||||
def write(self, geom):
|
|
||||||
"Returns the WKT representation of the given geometry."
|
|
||||||
return capi.wkt_writer_write(self.ptr, geom.ptr)
|
|
||||||
|
|
||||||
### WKB Reading and Writing objects ###
|
|
||||||
|
|
||||||
# Non-public class for the same reason as _WKTReader above.
|
|
||||||
class _WKBReader(IOBase):
|
|
||||||
_constructor = capi.wkb_reader_create
|
|
||||||
_destructor = capi.wkb_reader_destroy
|
|
||||||
ptr_type = capi.WKB_READ_PTR
|
|
||||||
|
|
||||||
def read(self, wkb):
|
|
||||||
"Returns a _pointer_ to C GEOS Geometry object from the given WKB."
|
|
||||||
if isinstance(wkb, buffer):
|
|
||||||
wkb_s = str(wkb)
|
|
||||||
return capi.wkb_reader_read(self.ptr, wkb_s, len(wkb_s))
|
|
||||||
elif isinstance(wkb, basestring):
|
|
||||||
return capi.wkb_reader_read_hex(self.ptr, wkb, len(wkb))
|
|
||||||
else:
|
|
||||||
raise TypeError
|
|
||||||
|
|
||||||
class WKBReader(_WKBReader):
|
|
||||||
def read(self, wkb):
|
|
||||||
"Returns a GEOSGeometry for the given WKB buffer."
|
|
||||||
return GEOSGeometry(super(WKBReader, self).read(wkb))
|
|
||||||
|
|
||||||
class WKBWriter(IOBase):
|
|
||||||
_constructor = capi.wkb_writer_create
|
|
||||||
_destructor = capi.wkb_writer_destroy
|
|
||||||
ptr_type = capi.WKB_WRITE_PTR
|
|
||||||
|
|
||||||
def write(self, geom):
|
|
||||||
"Returns the WKB representation of the given geometry."
|
|
||||||
return buffer(capi.wkb_writer_write(self.ptr, geom.ptr, byref(c_size_t())))
|
|
||||||
|
|
||||||
def write_hex(self, geom):
|
|
||||||
"Returns the HEXEWKB representation of the given geometry."
|
|
||||||
return capi.wkb_writer_write_hex(self.ptr, geom.ptr, byref(c_size_t()))
|
|
||||||
|
|
||||||
### WKBWriter Properties ###
|
|
||||||
|
|
||||||
# Property for getting/setting the byteorder.
|
|
||||||
def _get_byteorder(self):
|
|
||||||
return capi.wkb_writer_get_byteorder(self.ptr)
|
|
||||||
|
|
||||||
def _set_byteorder(self, order):
|
|
||||||
if not order in (0, 1): raise ValueError('Byte order parameter must be 0 (Big Endian) or 1 (Little Endian).')
|
|
||||||
capi.wkb_writer_set_byteorder(self.ptr, order)
|
|
||||||
|
|
||||||
byteorder = property(_get_byteorder, _set_byteorder)
|
|
||||||
|
|
||||||
# Property for getting/setting the output dimension.
|
|
||||||
def _get_outdim(self):
|
|
||||||
return capi.wkb_writer_get_outdim(self.ptr)
|
|
||||||
|
|
||||||
def _set_outdim(self, new_dim):
|
|
||||||
if not new_dim in (2, 3): raise ValueError('WKB output dimension must be 2 or 3')
|
|
||||||
capi.wkb_writer_set_outdim(self.ptr, new_dim)
|
|
||||||
|
|
||||||
outdim = property(_get_outdim, _set_outdim)
|
|
||||||
|
|
||||||
# Property for getting/setting the include srid flag.
|
|
||||||
def _get_include_srid(self):
|
|
||||||
return bool(ord(capi.wkb_writer_get_include_srid(self.ptr)))
|
|
||||||
|
|
||||||
def _set_include_srid(self, include):
|
|
||||||
if bool(include): flag = chr(1)
|
|
||||||
else: flag = chr(0)
|
|
||||||
capi.wkb_writer_set_include_srid(self.ptr, flag)
|
|
||||||
|
|
||||||
srid = property(_get_include_srid, _set_include_srid)
|
|
||||||
|
|
||||||
# Instances of the WKT and WKB reader/writer objects.
|
|
||||||
wkt_r = _WKTReader()
|
|
||||||
wkt_w = WKTWriter()
|
|
||||||
wkb_r = _WKBReader()
|
|
||||||
wkb_w = WKBWriter()
|
|
||||||
|
|
||||||
# These instances are for writing EWKB in 2D and 3D.
|
|
||||||
ewkb_w = WKBWriter()
|
|
||||||
ewkb_w.srid = True
|
|
||||||
ewkb_w3d = WKBWriter()
|
|
||||||
ewkb_w3d.srid = True
|
|
||||||
ewkb_w3d.outdim = 3
|
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
This module also houses GEOS Pointer utilities, including
|
This module also houses GEOS Pointer utilities, including
|
||||||
get_pointer_arr(), and GEOM_PTR.
|
get_pointer_arr(), and GEOM_PTR.
|
||||||
"""
|
"""
|
||||||
import atexit, os, re, sys
|
import os, re, sys
|
||||||
from ctypes import c_char_p, Structure, CDLL, CFUNCTYPE, POINTER
|
from ctypes import c_char_p, Structure, CDLL, CFUNCTYPE, POINTER
|
||||||
from ctypes.util import find_library
|
from ctypes.util import find_library
|
||||||
from django.contrib.gis.geos.error import GEOSException
|
from django.contrib.gis.geos.error import GEOSException
|
||||||
|
@ -45,14 +45,14 @@ if lib_path is None:
|
||||||
'", "'.join(lib_names))
|
'", "'.join(lib_names))
|
||||||
|
|
||||||
# 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.
|
||||||
# See the GEOS C API source code for more details on the library function calls:
|
# See the GEOS C API source code for more details on the library function calls:
|
||||||
# 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_path)
|
lgeos = CDLL(lib_path)
|
||||||
|
|
||||||
# The notice and error handler C function callback definitions.
|
# 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)
|
||||||
def notice_h(fmt, lst, output_h=sys.stdout):
|
def notice_h(fmt, lst, output_h=sys.stdout):
|
||||||
try:
|
try:
|
||||||
|
@ -71,23 +71,19 @@ def error_h(fmt, lst, output_h=sys.stderr):
|
||||||
output_h.write('GEOS_ERROR: %s\n' % err_msg)
|
output_h.write('GEOS_ERROR: %s\n' % err_msg)
|
||||||
error_h = ERRORFUNC(error_h)
|
error_h = ERRORFUNC(error_h)
|
||||||
|
|
||||||
# The initGEOS routine should be called first, however, that routine takes
|
|
||||||
# the notice and error functions as parameters. Here is the C code that
|
|
||||||
# is wrapped:
|
|
||||||
# "extern void GEOS_DLL initGEOS(GEOSMessageHandler notice_function, GEOSMessageHandler error_function);"
|
|
||||||
lgeos.initGEOS(notice_h, error_h)
|
|
||||||
|
|
||||||
#### GEOS Geometry C data structures, and utility functions. ####
|
#### GEOS Geometry C data structures, and utility functions. ####
|
||||||
|
|
||||||
# Opaque GEOS geometry structures, used for GEOM_PTR and CS_PTR
|
# Opaque GEOS geometry structures, used for GEOM_PTR and CS_PTR
|
||||||
class GEOSGeom_t(Structure): pass
|
class GEOSGeom_t(Structure): pass
|
||||||
class GEOSPrepGeom_t(Structure): pass
|
class GEOSPrepGeom_t(Structure): pass
|
||||||
class GEOSCoordSeq_t(Structure): pass
|
class GEOSCoordSeq_t(Structure): pass
|
||||||
|
class GEOSContextHandle_t(Structure): pass
|
||||||
|
|
||||||
# Pointers to opaque GEOS geometry structures.
|
# Pointers to opaque GEOS geometry structures.
|
||||||
GEOM_PTR = POINTER(GEOSGeom_t)
|
GEOM_PTR = POINTER(GEOSGeom_t)
|
||||||
PREPGEOM_PTR = POINTER(GEOSPrepGeom_t)
|
PREPGEOM_PTR = POINTER(GEOSPrepGeom_t)
|
||||||
CS_PTR = POINTER(GEOSCoordSeq_t)
|
CS_PTR = POINTER(GEOSCoordSeq_t)
|
||||||
|
CONTEXT_PTR = POINTER(GEOSContextHandle_t)
|
||||||
|
|
||||||
# Used specifically by the GEOSGeom_createPolygon and GEOSGeom_createCollection
|
# Used specifically by the GEOSGeom_createPolygon and GEOSGeom_createCollection
|
||||||
# GEOS routines
|
# GEOS routines
|
||||||
|
@ -126,5 +122,20 @@ del _verinfo
|
||||||
GEOS_VERSION = (GEOS_MAJOR_VERSION, GEOS_MINOR_VERSION, GEOS_SUBMINOR_VERSION)
|
GEOS_VERSION = (GEOS_MAJOR_VERSION, GEOS_MINOR_VERSION, GEOS_SUBMINOR_VERSION)
|
||||||
GEOS_PREPARE = GEOS_VERSION >= (3, 1, 0)
|
GEOS_PREPARE = GEOS_VERSION >= (3, 1, 0)
|
||||||
|
|
||||||
# Calling the finishGEOS() upon exit of the interpreter.
|
if GEOS_PREPARE:
|
||||||
atexit.register(lgeos.finishGEOS)
|
# Here we set up the prototypes for the initGEOS_r and finishGEOS_r
|
||||||
|
# routines. These functions aren't actually called until they are
|
||||||
|
# attached to a GEOS context handle -- this actually occurs in
|
||||||
|
# geos/prototypes/threadsafe.py.
|
||||||
|
lgeos.initGEOS_r.restype = CONTEXT_PTR
|
||||||
|
lgeos.finishGEOS_r.argtypes = [CONTEXT_PTR]
|
||||||
|
else:
|
||||||
|
# When thread-safety isn't available, the initGEOS routine must be called
|
||||||
|
# first. This function takes the notice and error functions, defined
|
||||||
|
# as Python callbacks above, as parameters. Here is the C code that is
|
||||||
|
# wrapped:
|
||||||
|
# extern void GEOS_DLL initGEOS(GEOSMessageHandler notice_function, GEOSMessageHandler error_function);
|
||||||
|
lgeos.initGEOS(notice_h, error_h)
|
||||||
|
# Calling finishGEOS() upon exit of the interpreter.
|
||||||
|
import atexit
|
||||||
|
atexit.register(lgeos.finishGEOS)
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
from ctypes import c_double, c_int, c_uint, POINTER
|
from ctypes import c_double, c_int, c_uint, POINTER
|
||||||
from django.contrib.gis.geos.libgeos import lgeos, GEOM_PTR, CS_PTR
|
from django.contrib.gis.geos.libgeos import GEOM_PTR, CS_PTR
|
||||||
from django.contrib.gis.geos.prototypes.errcheck import last_arg_byref, GEOSException
|
from django.contrib.gis.geos.prototypes.errcheck import last_arg_byref, GEOSException
|
||||||
|
from django.contrib.gis.geos.prototypes.threadsafe import GEOSFunc
|
||||||
|
|
||||||
## Error-checking routines specific to coordinate sequences. ##
|
## Error-checking routines specific to coordinate sequences. ##
|
||||||
def check_cs_ptr(result, func, cargs):
|
def check_cs_ptr(result, func, cargs):
|
||||||
|
@ -59,24 +60,24 @@ def cs_output(func, argtypes):
|
||||||
## Coordinate Sequence ctypes prototypes ##
|
## Coordinate Sequence ctypes prototypes ##
|
||||||
|
|
||||||
# Coordinate Sequence constructors & cloning.
|
# Coordinate Sequence constructors & cloning.
|
||||||
cs_clone = cs_output(lgeos.GEOSCoordSeq_clone, [CS_PTR])
|
cs_clone = cs_output(GEOSFunc('GEOSCoordSeq_clone'), [CS_PTR])
|
||||||
create_cs = cs_output(lgeos.GEOSCoordSeq_create, [c_uint, c_uint])
|
create_cs = cs_output(GEOSFunc('GEOSCoordSeq_create'), [c_uint, c_uint])
|
||||||
get_cs = cs_output(lgeos.GEOSGeom_getCoordSeq, [GEOM_PTR])
|
get_cs = cs_output(GEOSFunc('GEOSGeom_getCoordSeq'), [GEOM_PTR])
|
||||||
|
|
||||||
# Getting, setting ordinate
|
# Getting, setting ordinate
|
||||||
cs_getordinate = cs_operation(lgeos.GEOSCoordSeq_getOrdinate, ordinate=True, get=True)
|
cs_getordinate = cs_operation(GEOSFunc('GEOSCoordSeq_getOrdinate'), ordinate=True, get=True)
|
||||||
cs_setordinate = cs_operation(lgeos.GEOSCoordSeq_setOrdinate, ordinate=True)
|
cs_setordinate = cs_operation(GEOSFunc('GEOSCoordSeq_setOrdinate'), ordinate=True)
|
||||||
|
|
||||||
# For getting, x, y, z
|
# For getting, x, y, z
|
||||||
cs_getx = cs_operation(lgeos.GEOSCoordSeq_getX, get=True)
|
cs_getx = cs_operation(GEOSFunc('GEOSCoordSeq_getX'), get=True)
|
||||||
cs_gety = cs_operation(lgeos.GEOSCoordSeq_getY, get=True)
|
cs_gety = cs_operation(GEOSFunc('GEOSCoordSeq_getY'), get=True)
|
||||||
cs_getz = cs_operation(lgeos.GEOSCoordSeq_getZ, get=True)
|
cs_getz = cs_operation(GEOSFunc('GEOSCoordSeq_getZ'), get=True)
|
||||||
|
|
||||||
# For setting, x, y, z
|
# For setting, x, y, z
|
||||||
cs_setx = cs_operation(lgeos.GEOSCoordSeq_setX)
|
cs_setx = cs_operation(GEOSFunc('GEOSCoordSeq_setX'))
|
||||||
cs_sety = cs_operation(lgeos.GEOSCoordSeq_setY)
|
cs_sety = cs_operation(GEOSFunc('GEOSCoordSeq_setY'))
|
||||||
cs_setz = cs_operation(lgeos.GEOSCoordSeq_setZ)
|
cs_setz = cs_operation(GEOSFunc('GEOSCoordSeq_setZ'))
|
||||||
|
|
||||||
# These routines return size & dimensions.
|
# These routines return size & dimensions.
|
||||||
cs_getsize = cs_int(lgeos.GEOSCoordSeq_getSize)
|
cs_getsize = cs_int(GEOSFunc('GEOSCoordSeq_getSize'))
|
||||||
cs_getdims = cs_int(lgeos.GEOSCoordSeq_getDimensions)
|
cs_getdims = cs_int(GEOSFunc('GEOSCoordSeq_getDimensions'))
|
||||||
|
|
|
@ -4,14 +4,15 @@
|
||||||
import os
|
import os
|
||||||
from ctypes import c_void_p, string_at, CDLL
|
from ctypes import c_void_p, string_at, CDLL
|
||||||
from django.contrib.gis.geos.error import GEOSException
|
from django.contrib.gis.geos.error import GEOSException
|
||||||
from django.contrib.gis.geos.libgeos import lgeos, GEOS_VERSION
|
from django.contrib.gis.geos.libgeos import GEOS_VERSION
|
||||||
|
from django.contrib.gis.geos.prototypes.threadsafe import GEOSFunc
|
||||||
|
|
||||||
# Getting the `free` routine used to free the memory allocated for
|
# Getting the `free` routine used to free the memory allocated for
|
||||||
# string pointers returned by GEOS.
|
# string pointers returned by GEOS.
|
||||||
if GEOS_VERSION >= (3, 1, 1):
|
if GEOS_VERSION >= (3, 1, 1):
|
||||||
# In versions 3.1.1 and above, `GEOSFree` was added to the C API
|
# In versions 3.1.1 and above, `GEOSFree` was added to the C API
|
||||||
# because `free` isn't always available on all platforms.
|
# because `free` isn't always available on all platforms.
|
||||||
free = lgeos.GEOSFree
|
free = GEOSFunc('GEOSFree')
|
||||||
free.argtypes = [c_void_p]
|
free.argtypes = [c_void_p]
|
||||||
free.restype = None
|
free.restype = None
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
from ctypes import c_char_p, c_int, c_size_t, c_ubyte, c_uint, POINTER
|
from ctypes import c_char_p, c_int, c_size_t, c_ubyte, c_uint, POINTER
|
||||||
from django.contrib.gis.geos.libgeos import lgeos, CS_PTR, GEOM_PTR, PREPGEOM_PTR, GEOS_PREPARE
|
from django.contrib.gis.geos.libgeos import CS_PTR, GEOM_PTR, PREPGEOM_PTR, GEOS_PREPARE
|
||||||
from django.contrib.gis.geos.prototypes.errcheck import \
|
from django.contrib.gis.geos.prototypes.errcheck import \
|
||||||
check_geom, check_minus_one, check_sized_string, check_string, check_zero
|
check_geom, check_minus_one, check_sized_string, check_string, check_zero
|
||||||
|
from django.contrib.gis.geos.prototypes.threadsafe import GEOSFunc
|
||||||
|
|
||||||
# This is the return type used by binary output (WKB, HEX) routines.
|
# This is the return type used by binary output (WKB, HEX) routines.
|
||||||
c_uchar_p = POINTER(c_ubyte)
|
c_uchar_p = POINTER(c_ubyte)
|
||||||
|
@ -62,56 +63,57 @@ def string_from_geom(func):
|
||||||
|
|
||||||
### ctypes prototypes ###
|
### ctypes prototypes ###
|
||||||
|
|
||||||
# Deprecated creation and output routines from WKB, HEX, WKT
|
# Deprecated creation routines from WKB, HEX, WKT
|
||||||
from_hex = bin_constructor(lgeos.GEOSGeomFromHEX_buf)
|
from_hex = bin_constructor(GEOSFunc('GEOSGeomFromHEX_buf'))
|
||||||
from_wkb = bin_constructor(lgeos.GEOSGeomFromWKB_buf)
|
from_wkb = bin_constructor(GEOSFunc('GEOSGeomFromWKB_buf'))
|
||||||
from_wkt = geom_output(lgeos.GEOSGeomFromWKT, [c_char_p])
|
from_wkt = geom_output(GEOSFunc('GEOSGeomFromWKT'), [c_char_p])
|
||||||
|
|
||||||
to_hex = bin_output(lgeos.GEOSGeomToHEX_buf)
|
# Deprecated output routines
|
||||||
to_wkb = bin_output(lgeos.GEOSGeomToWKB_buf)
|
to_hex = bin_output(GEOSFunc('GEOSGeomToHEX_buf'))
|
||||||
to_wkt = string_from_geom(lgeos.GEOSGeomToWKT)
|
to_wkb = bin_output(GEOSFunc('GEOSGeomToWKB_buf'))
|
||||||
|
to_wkt = string_from_geom(GEOSFunc('GEOSGeomToWKT'))
|
||||||
|
|
||||||
# The GEOS geometry type, typeid, num_coordinates and number of geometries
|
# The GEOS geometry type, typeid, num_coordites and number of geometries
|
||||||
geos_normalize = int_from_geom(lgeos.GEOSNormalize)
|
geos_normalize = int_from_geom(GEOSFunc('GEOSNormalize'))
|
||||||
geos_type = string_from_geom(lgeos.GEOSGeomType)
|
geos_type = string_from_geom(GEOSFunc('GEOSGeomType'))
|
||||||
geos_typeid = int_from_geom(lgeos.GEOSGeomTypeId)
|
geos_typeid = int_from_geom(GEOSFunc('GEOSGeomTypeId'))
|
||||||
get_dims = int_from_geom(lgeos.GEOSGeom_getDimensions, zero=True)
|
get_dims = int_from_geom(GEOSFunc('GEOSGeom_getDimensions'), zero=True)
|
||||||
get_num_coords = int_from_geom(lgeos.GEOSGetNumCoordinates)
|
get_num_coords = int_from_geom(GEOSFunc('GEOSGetNumCoordinates'))
|
||||||
get_num_geoms = int_from_geom(lgeos.GEOSGetNumGeometries)
|
get_num_geoms = int_from_geom(GEOSFunc('GEOSGetNumGeometries'))
|
||||||
|
|
||||||
# Geometry creation factories
|
# Geometry creation factories
|
||||||
create_point = geom_output(lgeos.GEOSGeom_createPoint, [CS_PTR])
|
create_point = geom_output(GEOSFunc('GEOSGeom_createPoint'), [CS_PTR])
|
||||||
create_linestring = geom_output(lgeos.GEOSGeom_createLineString, [CS_PTR])
|
create_linestring = geom_output(GEOSFunc('GEOSGeom_createLineString'), [CS_PTR])
|
||||||
create_linearring = geom_output(lgeos.GEOSGeom_createLinearRing, [CS_PTR])
|
create_linearring = geom_output(GEOSFunc('GEOSGeom_createLinearRing'), [CS_PTR])
|
||||||
|
|
||||||
# Polygon and collection creation routines are special and will not
|
# Polygon and collection creation routines are special and will not
|
||||||
# have their argument types defined.
|
# have their argument types defined.
|
||||||
create_polygon = geom_output(lgeos.GEOSGeom_createPolygon, None)
|
create_polygon = geom_output(GEOSFunc('GEOSGeom_createPolygon'), None)
|
||||||
create_collection = geom_output(lgeos.GEOSGeom_createCollection, None)
|
create_collection = geom_output(GEOSFunc('GEOSGeom_createCollection'), None)
|
||||||
|
|
||||||
# Ring routines
|
# Ring routines
|
||||||
get_extring = geom_output(lgeos.GEOSGetExteriorRing, [GEOM_PTR])
|
get_extring = geom_output(GEOSFunc('GEOSGetExteriorRing'), [GEOM_PTR])
|
||||||
get_intring = geom_index(lgeos.GEOSGetInteriorRingN)
|
get_intring = geom_index(GEOSFunc('GEOSGetInteriorRingN'))
|
||||||
get_nrings = int_from_geom(lgeos.GEOSGetNumInteriorRings)
|
get_nrings = int_from_geom(GEOSFunc('GEOSGetNumInteriorRings'))
|
||||||
|
|
||||||
# Collection Routines
|
# Collection Routines
|
||||||
get_geomn = geom_index(lgeos.GEOSGetGeometryN)
|
get_geomn = geom_index(GEOSFunc('GEOSGetGeometryN'))
|
||||||
|
|
||||||
# Cloning
|
# Cloning
|
||||||
geom_clone = lgeos.GEOSGeom_clone
|
geom_clone = GEOSFunc('GEOSGeom_clone')
|
||||||
geom_clone.argtypes = [GEOM_PTR]
|
geom_clone.argtypes = [GEOM_PTR]
|
||||||
geom_clone.restype = GEOM_PTR
|
geom_clone.restype = GEOM_PTR
|
||||||
|
|
||||||
# Destruction routine.
|
# Destruction routine.
|
||||||
destroy_geom = lgeos.GEOSGeom_destroy
|
destroy_geom = GEOSFunc('GEOSGeom_destroy')
|
||||||
destroy_geom.argtypes = [GEOM_PTR]
|
destroy_geom.argtypes = [GEOM_PTR]
|
||||||
destroy_geom.restype = None
|
destroy_geom.restype = None
|
||||||
|
|
||||||
# SRID routines
|
# SRID routines
|
||||||
geos_get_srid = lgeos.GEOSGetSRID
|
geos_get_srid = GEOSFunc('GEOSGetSRID')
|
||||||
geos_get_srid.argtypes = [GEOM_PTR]
|
geos_get_srid.argtypes = [GEOM_PTR]
|
||||||
geos_get_srid.restype = c_int
|
geos_get_srid.restype = c_int
|
||||||
|
|
||||||
geos_set_srid = lgeos.GEOSSetSRID
|
geos_set_srid = GEOSFunc('GEOSSetSRID')
|
||||||
geos_set_srid.argtypes = [GEOM_PTR, c_int]
|
geos_set_srid.argtypes = [GEOM_PTR, c_int]
|
||||||
geos_set_srid.restype = None
|
geos_set_srid.restype = None
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
from ctypes import c_char_p, c_int, c_char, c_size_t, Structure, POINTER
|
import threading
|
||||||
from django.contrib.gis.geos.libgeos import lgeos, GEOM_PTR
|
from ctypes import byref, c_char_p, c_int, c_char, c_size_t, Structure, POINTER
|
||||||
|
from django.contrib.gis.geos.base import GEOSBase
|
||||||
|
from django.contrib.gis.geos.libgeos import GEOM_PTR
|
||||||
from django.contrib.gis.geos.prototypes.errcheck import check_geom, check_string, check_sized_string
|
from django.contrib.gis.geos.prototypes.errcheck import check_geom, check_string, check_sized_string
|
||||||
from django.contrib.gis.geos.prototypes.geom import c_uchar_p, geos_char_p
|
from django.contrib.gis.geos.prototypes.geom import c_uchar_p, geos_char_p
|
||||||
|
from django.contrib.gis.geos.prototypes.threadsafe import GEOSFunc
|
||||||
|
|
||||||
### The WKB/WKT Reader/Writer structures and pointers ###
|
### The WKB/WKT Reader/Writer structures and pointers ###
|
||||||
class WKTReader_st(Structure): pass
|
class WKTReader_st(Structure): pass
|
||||||
|
@ -15,34 +18,34 @@ WKB_READ_PTR = POINTER(WKBReader_st)
|
||||||
WKB_WRITE_PTR = POINTER(WKBReader_st)
|
WKB_WRITE_PTR = POINTER(WKBReader_st)
|
||||||
|
|
||||||
### WKTReader routines ###
|
### WKTReader routines ###
|
||||||
wkt_reader_create = lgeos.GEOSWKTReader_create
|
wkt_reader_create = GEOSFunc('GEOSWKTReader_create')
|
||||||
wkt_reader_create.restype = WKT_READ_PTR
|
wkt_reader_create.restype = WKT_READ_PTR
|
||||||
|
|
||||||
wkt_reader_destroy = lgeos.GEOSWKTReader_destroy
|
wkt_reader_destroy = GEOSFunc('GEOSWKTReader_destroy')
|
||||||
wkt_reader_destroy.argtypes = [WKT_READ_PTR]
|
wkt_reader_destroy.argtypes = [WKT_READ_PTR]
|
||||||
|
|
||||||
wkt_reader_read = lgeos.GEOSWKTReader_read
|
wkt_reader_read = GEOSFunc('GEOSWKTReader_read')
|
||||||
wkt_reader_read.argtypes = [WKT_READ_PTR, c_char_p]
|
wkt_reader_read.argtypes = [WKT_READ_PTR, c_char_p]
|
||||||
wkt_reader_read.restype = GEOM_PTR
|
wkt_reader_read.restype = GEOM_PTR
|
||||||
wkt_reader_read.errcheck = check_geom
|
wkt_reader_read.errcheck = check_geom
|
||||||
|
|
||||||
### WKTWriter routines ###
|
### WKTWriter routines ###
|
||||||
wkt_writer_create = lgeos.GEOSWKTWriter_create
|
wkt_writer_create = GEOSFunc('GEOSWKTWriter_create')
|
||||||
wkt_writer_create.restype = WKT_WRITE_PTR
|
wkt_writer_create.restype = WKT_WRITE_PTR
|
||||||
|
|
||||||
wkt_writer_destroy = lgeos.GEOSWKTWriter_destroy
|
wkt_writer_destroy = GEOSFunc('GEOSWKTWriter_destroy')
|
||||||
wkt_writer_destroy.argtypes = [WKT_WRITE_PTR]
|
wkt_writer_destroy.argtypes = [WKT_WRITE_PTR]
|
||||||
|
|
||||||
wkt_writer_write = lgeos.GEOSWKTWriter_write
|
wkt_writer_write = GEOSFunc('GEOSWKTWriter_write')
|
||||||
wkt_writer_write.argtypes = [WKT_WRITE_PTR, GEOM_PTR]
|
wkt_writer_write.argtypes = [WKT_WRITE_PTR, GEOM_PTR]
|
||||||
wkt_writer_write.restype = geos_char_p
|
wkt_writer_write.restype = geos_char_p
|
||||||
wkt_writer_write.errcheck = check_string
|
wkt_writer_write.errcheck = check_string
|
||||||
|
|
||||||
### WKBReader routines ###
|
### WKBReader routines ###
|
||||||
wkb_reader_create = lgeos.GEOSWKBReader_create
|
wkb_reader_create = GEOSFunc('GEOSWKBReader_create')
|
||||||
wkb_reader_create.restype = WKB_READ_PTR
|
wkb_reader_create.restype = WKB_READ_PTR
|
||||||
|
|
||||||
wkb_reader_destroy = lgeos.GEOSWKBReader_destroy
|
wkb_reader_destroy = GEOSFunc('GEOSWKBReader_destroy')
|
||||||
wkb_reader_destroy.argtypes = [WKB_READ_PTR]
|
wkb_reader_destroy.argtypes = [WKB_READ_PTR]
|
||||||
|
|
||||||
def wkb_read_func(func):
|
def wkb_read_func(func):
|
||||||
|
@ -56,14 +59,14 @@ def wkb_read_func(func):
|
||||||
func.errcheck = check_geom
|
func.errcheck = check_geom
|
||||||
return func
|
return func
|
||||||
|
|
||||||
wkb_reader_read = wkb_read_func(lgeos.GEOSWKBReader_read)
|
wkb_reader_read = wkb_read_func(GEOSFunc('GEOSWKBReader_read'))
|
||||||
wkb_reader_read_hex = wkb_read_func(lgeos.GEOSWKBReader_readHEX)
|
wkb_reader_read_hex = wkb_read_func(GEOSFunc('GEOSWKBReader_readHEX'))
|
||||||
|
|
||||||
### WKBWriter routines ###
|
### WKBWriter routines ###
|
||||||
wkb_writer_create = lgeos.GEOSWKBWriter_create
|
wkb_writer_create = GEOSFunc('GEOSWKBWriter_create')
|
||||||
wkb_writer_create.restype = WKB_WRITE_PTR
|
wkb_writer_create.restype = WKB_WRITE_PTR
|
||||||
|
|
||||||
wkb_writer_destroy = lgeos.GEOSWKBWriter_destroy
|
wkb_writer_destroy = GEOSFunc('GEOSWKBWriter_destroy')
|
||||||
wkb_writer_destroy.argtypes = [WKB_WRITE_PTR]
|
wkb_writer_destroy.argtypes = [WKB_WRITE_PTR]
|
||||||
|
|
||||||
# WKB Writing prototypes.
|
# WKB Writing prototypes.
|
||||||
|
@ -73,8 +76,8 @@ def wkb_write_func(func):
|
||||||
func.errcheck = check_sized_string
|
func.errcheck = check_sized_string
|
||||||
return func
|
return func
|
||||||
|
|
||||||
wkb_writer_write = wkb_write_func(lgeos.GEOSWKBWriter_write)
|
wkb_writer_write = wkb_write_func(GEOSFunc('GEOSWKBWriter_write'))
|
||||||
wkb_writer_write_hex = wkb_write_func(lgeos.GEOSWKBWriter_writeHEX)
|
wkb_writer_write_hex = wkb_write_func(GEOSFunc('GEOSWKBWriter_writeHEX'))
|
||||||
|
|
||||||
# WKBWriter property getter/setter prototypes.
|
# WKBWriter property getter/setter prototypes.
|
||||||
def wkb_writer_get(func, restype=c_int):
|
def wkb_writer_get(func, restype=c_int):
|
||||||
|
@ -86,9 +89,154 @@ def wkb_writer_set(func, argtype=c_int):
|
||||||
func.argtypes = [WKB_WRITE_PTR, argtype]
|
func.argtypes = [WKB_WRITE_PTR, argtype]
|
||||||
return func
|
return func
|
||||||
|
|
||||||
wkb_writer_get_byteorder = wkb_writer_get(lgeos.GEOSWKBWriter_getByteOrder)
|
wkb_writer_get_byteorder = wkb_writer_get(GEOSFunc('GEOSWKBWriter_getByteOrder'))
|
||||||
wkb_writer_set_byteorder = wkb_writer_set(lgeos.GEOSWKBWriter_setByteOrder)
|
wkb_writer_set_byteorder = wkb_writer_set(GEOSFunc('GEOSWKBWriter_setByteOrder'))
|
||||||
wkb_writer_get_outdim = wkb_writer_get(lgeos.GEOSWKBWriter_getOutputDimension)
|
wkb_writer_get_outdim = wkb_writer_get(GEOSFunc('GEOSWKBWriter_getOutputDimension'))
|
||||||
wkb_writer_set_outdim = wkb_writer_set(lgeos.GEOSWKBWriter_setOutputDimension)
|
wkb_writer_set_outdim = wkb_writer_set(GEOSFunc('GEOSWKBWriter_setOutputDimension'))
|
||||||
wkb_writer_get_include_srid = wkb_writer_get(lgeos.GEOSWKBWriter_getIncludeSRID, restype=c_char)
|
wkb_writer_get_include_srid = wkb_writer_get(GEOSFunc('GEOSWKBWriter_getIncludeSRID'), restype=c_char)
|
||||||
wkb_writer_set_include_srid = wkb_writer_set(lgeos.GEOSWKBWriter_setIncludeSRID, argtype=c_char)
|
wkb_writer_set_include_srid = wkb_writer_set(GEOSFunc('GEOSWKBWriter_setIncludeSRID'), argtype=c_char)
|
||||||
|
|
||||||
|
### Base I/O Class ###
|
||||||
|
class IOBase(GEOSBase):
|
||||||
|
"Base class for GEOS I/O objects."
|
||||||
|
def __init__(self):
|
||||||
|
# Getting the pointer with the constructor.
|
||||||
|
self.ptr = self._constructor()
|
||||||
|
|
||||||
|
def __del__(self):
|
||||||
|
# Cleaning up with the appropriate destructor.
|
||||||
|
if self._ptr: self._destructor(self._ptr)
|
||||||
|
|
||||||
|
### Base WKB/WKT Reading and Writing objects ###
|
||||||
|
|
||||||
|
# Non-public WKB/WKT reader classes for internal use because
|
||||||
|
# their `read` methods return _pointers_ instead of GEOSGeometry
|
||||||
|
# objects.
|
||||||
|
class _WKTReader(IOBase):
|
||||||
|
_constructor = wkt_reader_create
|
||||||
|
_destructor = wkt_reader_destroy
|
||||||
|
ptr_type = WKT_READ_PTR
|
||||||
|
|
||||||
|
def read(self, wkt):
|
||||||
|
if not isinstance(wkt, basestring): raise TypeError
|
||||||
|
return wkt_reader_read(self.ptr, wkt)
|
||||||
|
|
||||||
|
class _WKBReader(IOBase):
|
||||||
|
_constructor = wkb_reader_create
|
||||||
|
_destructor = wkb_reader_destroy
|
||||||
|
ptr_type = WKB_READ_PTR
|
||||||
|
|
||||||
|
def read(self, wkb):
|
||||||
|
"Returns a _pointer_ to C GEOS Geometry object from the given WKB."
|
||||||
|
if isinstance(wkb, buffer):
|
||||||
|
wkb_s = str(wkb)
|
||||||
|
return wkb_reader_read(self.ptr, wkb_s, len(wkb_s))
|
||||||
|
elif isinstance(wkb, basestring):
|
||||||
|
return wkb_reader_read_hex(self.ptr, wkb, len(wkb))
|
||||||
|
else:
|
||||||
|
raise TypeError
|
||||||
|
|
||||||
|
### WKB/WKT Writer Classes ###
|
||||||
|
class WKTWriter(IOBase):
|
||||||
|
_constructor = wkt_writer_create
|
||||||
|
_destructor = wkt_writer_destroy
|
||||||
|
ptr_type = WKT_WRITE_PTR
|
||||||
|
|
||||||
|
def write(self, geom):
|
||||||
|
"Returns the WKT representation of the given geometry."
|
||||||
|
return wkt_writer_write(self.ptr, geom.ptr)
|
||||||
|
|
||||||
|
class WKBWriter(IOBase):
|
||||||
|
_constructor = wkb_writer_create
|
||||||
|
_destructor = wkb_writer_destroy
|
||||||
|
ptr_type = WKB_WRITE_PTR
|
||||||
|
|
||||||
|
def write(self, geom):
|
||||||
|
"Returns the WKB representation of the given geometry."
|
||||||
|
return buffer(wkb_writer_write(self.ptr, geom.ptr, byref(c_size_t())))
|
||||||
|
|
||||||
|
def write_hex(self, geom):
|
||||||
|
"Returns the HEXEWKB representation of the given geometry."
|
||||||
|
return wkb_writer_write_hex(self.ptr, geom.ptr, byref(c_size_t()))
|
||||||
|
|
||||||
|
### WKBWriter Properties ###
|
||||||
|
|
||||||
|
# Property for getting/setting the byteorder.
|
||||||
|
def _get_byteorder(self):
|
||||||
|
return wkb_writer_get_byteorder(self.ptr)
|
||||||
|
|
||||||
|
def _set_byteorder(self, order):
|
||||||
|
if not order in (0, 1): raise ValueError('Byte order parameter must be 0 (Big Endian) or 1 (Little Endian).')
|
||||||
|
wkb_writer_set_byteorder(self.ptr, order)
|
||||||
|
|
||||||
|
byteorder = property(_get_byteorder, _set_byteorder)
|
||||||
|
|
||||||
|
# Property for getting/setting the output dimension.
|
||||||
|
def _get_outdim(self):
|
||||||
|
return wkb_writer_get_outdim(self.ptr)
|
||||||
|
|
||||||
|
def _set_outdim(self, new_dim):
|
||||||
|
if not new_dim in (2, 3): raise ValueError('WKB output dimension must be 2 or 3')
|
||||||
|
wkb_writer_set_outdim(self.ptr, new_dim)
|
||||||
|
|
||||||
|
outdim = property(_get_outdim, _set_outdim)
|
||||||
|
|
||||||
|
# Property for getting/setting the include srid flag.
|
||||||
|
def _get_include_srid(self):
|
||||||
|
return bool(ord(wkb_writer_get_include_srid(self.ptr)))
|
||||||
|
|
||||||
|
def _set_include_srid(self, include):
|
||||||
|
if bool(include): flag = chr(1)
|
||||||
|
else: flag = chr(0)
|
||||||
|
wkb_writer_set_include_srid(self.ptr, flag)
|
||||||
|
|
||||||
|
srid = property(_get_include_srid, _set_include_srid)
|
||||||
|
|
||||||
|
# `ThreadLocalIO` object holds instances of the WKT and WKB reader/writer
|
||||||
|
# objects that are local to the thread. The `GEOSGeometry` internals
|
||||||
|
# access these instances by calling the module-level functions, defined
|
||||||
|
# below.
|
||||||
|
class ThreadLocalIO(threading.local):
|
||||||
|
wkt_r = None
|
||||||
|
wkt_w = None
|
||||||
|
wkb_r = None
|
||||||
|
wkb_w = None
|
||||||
|
ewkb_w = None
|
||||||
|
ewkb_w3d = None
|
||||||
|
|
||||||
|
thread_context = ThreadLocalIO()
|
||||||
|
|
||||||
|
# These module-level routines return the I/O object that is local to the
|
||||||
|
# the thread. If the I/O object does not exist yet it will be initialized.
|
||||||
|
def wkt_r():
|
||||||
|
if not thread_context.wkt_r:
|
||||||
|
thread_context.wkt_r = _WKTReader()
|
||||||
|
return thread_context.wkt_r
|
||||||
|
|
||||||
|
def wkt_w():
|
||||||
|
if not thread_context.wkt_w:
|
||||||
|
thread_context.wkt_w = WKTWriter()
|
||||||
|
return thread_context.wkt_w
|
||||||
|
|
||||||
|
def wkb_r():
|
||||||
|
if not thread_context.wkb_r:
|
||||||
|
thread_context.wkb_r = _WKBReader()
|
||||||
|
return thread_context.wkb_r
|
||||||
|
|
||||||
|
def wkb_w():
|
||||||
|
if not thread_context.wkb_w:
|
||||||
|
thread_context.wkb_w = WKBWriter()
|
||||||
|
return thread_context.wkb_w
|
||||||
|
|
||||||
|
def ewkb_w():
|
||||||
|
if not thread_context.ewkb_w:
|
||||||
|
thread_context.ewkb_w = WKBWriter()
|
||||||
|
thread_context.ewkb_w.srid = True
|
||||||
|
return thread_context.ewkb_w
|
||||||
|
|
||||||
|
def ewkb_w3d():
|
||||||
|
if not thread_context.ewkb_w3d:
|
||||||
|
thread_context.ewkb_w3d = WKBWriter()
|
||||||
|
thread_context.ewkb_w3d.srid = True
|
||||||
|
thread_context.ewkb_w3d.outdim = 3
|
||||||
|
return thread_context.ewkb_w3d
|
||||||
|
|
|
@ -3,8 +3,9 @@
|
||||||
ones that return the area, distance, and length.
|
ones that return the area, distance, and length.
|
||||||
"""
|
"""
|
||||||
from ctypes import c_int, c_double, POINTER
|
from ctypes import c_int, c_double, POINTER
|
||||||
from django.contrib.gis.geos.libgeos import lgeos, GEOM_PTR
|
from django.contrib.gis.geos.libgeos import GEOM_PTR
|
||||||
from django.contrib.gis.geos.prototypes.errcheck import check_dbl
|
from django.contrib.gis.geos.prototypes.errcheck import check_dbl
|
||||||
|
from django.contrib.gis.geos.prototypes.threadsafe import GEOSFunc
|
||||||
|
|
||||||
### ctypes generator function ###
|
### ctypes generator function ###
|
||||||
def dbl_from_geom(func, num_geom=1):
|
def dbl_from_geom(func, num_geom=1):
|
||||||
|
@ -22,6 +23,6 @@ def dbl_from_geom(func, num_geom=1):
|
||||||
### ctypes prototypes ###
|
### ctypes prototypes ###
|
||||||
|
|
||||||
# Area, distance, and length prototypes.
|
# Area, distance, and length prototypes.
|
||||||
geos_area = dbl_from_geom(lgeos.GEOSArea)
|
geos_area = dbl_from_geom(GEOSFunc('GEOSArea'))
|
||||||
geos_distance = dbl_from_geom(lgeos.GEOSDistance, num_geom=2)
|
geos_distance = dbl_from_geom(GEOSFunc('GEOSDistance'), num_geom=2)
|
||||||
geos_length = dbl_from_geom(lgeos.GEOSLength)
|
geos_length = dbl_from_geom(GEOSFunc('GEOSLength'))
|
||||||
|
|
|
@ -3,8 +3,9 @@
|
||||||
unary and binary predicate operations on geometries.
|
unary and binary predicate operations on geometries.
|
||||||
"""
|
"""
|
||||||
from ctypes import c_char, c_char_p, c_double
|
from ctypes import c_char, c_char_p, c_double
|
||||||
from django.contrib.gis.geos.libgeos import lgeos, GEOM_PTR
|
from django.contrib.gis.geos.libgeos import GEOM_PTR
|
||||||
from django.contrib.gis.geos.prototypes.errcheck import check_predicate
|
from django.contrib.gis.geos.prototypes.errcheck import check_predicate
|
||||||
|
from django.contrib.gis.geos.prototypes.threadsafe import GEOSFunc
|
||||||
|
|
||||||
## Binary & unary predicate functions ##
|
## Binary & unary predicate functions ##
|
||||||
def binary_predicate(func, *args):
|
def binary_predicate(func, *args):
|
||||||
|
@ -24,20 +25,20 @@ def unary_predicate(func):
|
||||||
return func
|
return func
|
||||||
|
|
||||||
## Unary Predicates ##
|
## Unary Predicates ##
|
||||||
geos_hasz = unary_predicate(lgeos.GEOSHasZ)
|
geos_hasz = unary_predicate(GEOSFunc('GEOSHasZ'))
|
||||||
geos_isempty = unary_predicate(lgeos.GEOSisEmpty)
|
geos_isempty = unary_predicate(GEOSFunc('GEOSisEmpty'))
|
||||||
geos_isring = unary_predicate(lgeos.GEOSisRing)
|
geos_isring = unary_predicate(GEOSFunc('GEOSisRing'))
|
||||||
geos_issimple = unary_predicate(lgeos.GEOSisSimple)
|
geos_issimple = unary_predicate(GEOSFunc('GEOSisSimple'))
|
||||||
geos_isvalid = unary_predicate(lgeos.GEOSisValid)
|
geos_isvalid = unary_predicate(GEOSFunc('GEOSisValid'))
|
||||||
|
|
||||||
## Binary Predicates ##
|
## Binary Predicates ##
|
||||||
geos_contains = binary_predicate(lgeos.GEOSContains)
|
geos_contains = binary_predicate(GEOSFunc('GEOSContains'))
|
||||||
geos_crosses = binary_predicate(lgeos.GEOSCrosses)
|
geos_crosses = binary_predicate(GEOSFunc('GEOSCrosses'))
|
||||||
geos_disjoint = binary_predicate(lgeos.GEOSDisjoint)
|
geos_disjoint = binary_predicate(GEOSFunc('GEOSDisjoint'))
|
||||||
geos_equals = binary_predicate(lgeos.GEOSEquals)
|
geos_equals = binary_predicate(GEOSFunc('GEOSEquals'))
|
||||||
geos_equalsexact = binary_predicate(lgeos.GEOSEqualsExact, c_double)
|
geos_equalsexact = binary_predicate(GEOSFunc('GEOSEqualsExact'), c_double)
|
||||||
geos_intersects = binary_predicate(lgeos.GEOSIntersects)
|
geos_intersects = binary_predicate(GEOSFunc('GEOSIntersects'))
|
||||||
geos_overlaps = binary_predicate(lgeos.GEOSOverlaps)
|
geos_overlaps = binary_predicate(GEOSFunc('GEOSOverlaps'))
|
||||||
geos_relatepattern = binary_predicate(lgeos.GEOSRelatePattern, c_char_p)
|
geos_relatepattern = binary_predicate(GEOSFunc('GEOSRelatePattern'), c_char_p)
|
||||||
geos_touches = binary_predicate(lgeos.GEOSTouches)
|
geos_touches = binary_predicate(GEOSFunc('GEOSTouches'))
|
||||||
geos_within = binary_predicate(lgeos.GEOSWithin)
|
geos_within = binary_predicate(GEOSFunc('GEOSWithin'))
|
||||||
|
|
|
@ -1,13 +1,14 @@
|
||||||
from ctypes import c_char
|
from ctypes import c_char
|
||||||
from django.contrib.gis.geos.libgeos import lgeos, GEOM_PTR, PREPGEOM_PTR
|
from django.contrib.gis.geos.libgeos import GEOM_PTR, PREPGEOM_PTR
|
||||||
from django.contrib.gis.geos.prototypes.errcheck import check_predicate
|
from django.contrib.gis.geos.prototypes.errcheck import check_predicate
|
||||||
|
from django.contrib.gis.geos.prototypes.threadsafe import GEOSFunc
|
||||||
|
|
||||||
# Prepared geometry constructor and destructors.
|
# Prepared geometry constructor and destructors.
|
||||||
geos_prepare = lgeos.GEOSPrepare
|
geos_prepare = GEOSFunc('GEOSPrepare')
|
||||||
geos_prepare.argtypes = [GEOM_PTR]
|
geos_prepare.argtypes = [GEOM_PTR]
|
||||||
geos_prepare.restype = PREPGEOM_PTR
|
geos_prepare.restype = PREPGEOM_PTR
|
||||||
|
|
||||||
prepared_destroy = lgeos.GEOSPreparedGeom_destroy
|
prepared_destroy = GEOSFunc('GEOSPreparedGeom_destroy')
|
||||||
prepared_destroy.argtpes = [PREPGEOM_PTR]
|
prepared_destroy.argtpes = [PREPGEOM_PTR]
|
||||||
prepared_destroy.restype = None
|
prepared_destroy.restype = None
|
||||||
|
|
||||||
|
@ -18,7 +19,7 @@ def prepared_predicate(func):
|
||||||
func.errcheck = check_predicate
|
func.errcheck = check_predicate
|
||||||
return func
|
return func
|
||||||
|
|
||||||
prepared_contains = prepared_predicate(lgeos.GEOSPreparedContains)
|
prepared_contains = prepared_predicate(GEOSFunc('GEOSPreparedContains'))
|
||||||
prepared_contains_properly = prepared_predicate(lgeos.GEOSPreparedContainsProperly)
|
prepared_contains_properly = prepared_predicate(GEOSFunc('GEOSPreparedContainsProperly'))
|
||||||
prepared_covers = prepared_predicate(lgeos.GEOSPreparedCovers)
|
prepared_covers = prepared_predicate(GEOSFunc('GEOSPreparedCovers'))
|
||||||
prepared_intersects = prepared_predicate(lgeos.GEOSPreparedIntersects)
|
prepared_intersects = prepared_predicate(GEOSFunc('GEOSPreparedIntersects'))
|
||||||
|
|
|
@ -0,0 +1,90 @@
|
||||||
|
import threading
|
||||||
|
from django.contrib.gis.geos.libgeos import lgeos, notice_h, error_h, CONTEXT_PTR
|
||||||
|
|
||||||
|
class GEOSContextHandle(object):
|
||||||
|
"""
|
||||||
|
Python object representing a GEOS context handle.
|
||||||
|
"""
|
||||||
|
def __init__(self):
|
||||||
|
# Initializing the context handler for this thread with
|
||||||
|
# the notice and error handler.
|
||||||
|
self.ptr = lgeos.initGEOS_r(notice_h, error_h)
|
||||||
|
|
||||||
|
def __del__(self):
|
||||||
|
if self.ptr: lgeos.finishGEOS_r(self.ptr)
|
||||||
|
|
||||||
|
# Defining a thread-local object and creating an instance
|
||||||
|
# to hold a reference to GEOSContextHandle for this thread.
|
||||||
|
class GEOSContext(threading.local):
|
||||||
|
handle = None
|
||||||
|
|
||||||
|
thread_context = GEOSContext()
|
||||||
|
|
||||||
|
def call_geos_threaded(cfunc, args):
|
||||||
|
"""
|
||||||
|
This module-level routine calls the specified GEOS C thread-safe
|
||||||
|
function with the context for this current thread.
|
||||||
|
"""
|
||||||
|
# If a context handle does not exist for this thread, initialize one.
|
||||||
|
if not thread_context.handle:
|
||||||
|
thread_context.handle = GEOSContextHandle()
|
||||||
|
# Call the threaded GEOS routine with pointer of the context handle
|
||||||
|
# as the first argument.
|
||||||
|
return cfunc(thread_context.handle.ptr, *args)
|
||||||
|
|
||||||
|
class GEOSFunc(object):
|
||||||
|
"""
|
||||||
|
Class that serves as a wrapper for GEOS C Functions, and will
|
||||||
|
use thread-safe function variants when available.
|
||||||
|
"""
|
||||||
|
def __init__(self, func_name):
|
||||||
|
try:
|
||||||
|
# GEOS thread-safe function signatures end with '_r', and
|
||||||
|
# take an additional context handle parameter.
|
||||||
|
self.cfunc = getattr(lgeos, func_name + '_r')
|
||||||
|
self.threaded = True
|
||||||
|
except AttributeError:
|
||||||
|
# Otherwise, use usual function.
|
||||||
|
self.cfunc = getattr(lgeos, func_name)
|
||||||
|
self.threaded = False
|
||||||
|
|
||||||
|
def __call__(self, *args):
|
||||||
|
if self.threaded:
|
||||||
|
return call_geos_threaded(self.cfunc, args)
|
||||||
|
else:
|
||||||
|
return self.cfunc(*args)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.cfunc.__name__
|
||||||
|
|
||||||
|
# argtypes property
|
||||||
|
def _get_argtypes(self):
|
||||||
|
return self.cfunc.argtypes
|
||||||
|
|
||||||
|
def _set_argtypes(self, argtypes):
|
||||||
|
if self.threaded:
|
||||||
|
new_argtypes = [CONTEXT_PTR]
|
||||||
|
new_argtypes.extend(argtypes)
|
||||||
|
self.cfunc.argtypes = new_argtypes
|
||||||
|
else:
|
||||||
|
self.cfunc.argtypes = argtypes
|
||||||
|
|
||||||
|
argtypes = property(_get_argtypes, _set_argtypes)
|
||||||
|
|
||||||
|
# restype property
|
||||||
|
def _get_restype(self):
|
||||||
|
return self.cfunc.restype
|
||||||
|
|
||||||
|
def _set_restype(self, restype):
|
||||||
|
self.cfunc.restype = restype
|
||||||
|
|
||||||
|
restype = property(_get_restype, _set_restype)
|
||||||
|
|
||||||
|
# errcheck property
|
||||||
|
def _get_errcheck(self):
|
||||||
|
return self.cfunc.errcheck
|
||||||
|
|
||||||
|
def _set_errcheck(self, errcheck):
|
||||||
|
self.cfunc.errcheck = errcheck
|
||||||
|
|
||||||
|
errcheck = property(_get_errcheck, _set_errcheck)
|
|
@ -8,9 +8,10 @@ __all__ = ['geos_boundary', 'geos_buffer', 'geos_centroid', 'geos_convexhull',
|
||||||
'geos_simplify', 'geos_symdifference', 'geos_union', 'geos_relate']
|
'geos_simplify', 'geos_symdifference', 'geos_union', 'geos_relate']
|
||||||
|
|
||||||
from ctypes import c_char_p, c_double, c_int
|
from ctypes import c_char_p, c_double, c_int
|
||||||
from django.contrib.gis.geos.libgeos import lgeos, GEOM_PTR, GEOS_PREPARE
|
from django.contrib.gis.geos.libgeos import GEOM_PTR, GEOS_PREPARE
|
||||||
from django.contrib.gis.geos.prototypes.errcheck import check_geom, check_string
|
from django.contrib.gis.geos.prototypes.errcheck import check_geom, check_string
|
||||||
from django.contrib.gis.geos.prototypes.geom import geos_char_p
|
from django.contrib.gis.geos.prototypes.geom import geos_char_p
|
||||||
|
from django.contrib.gis.geos.prototypes.threadsafe import GEOSFunc
|
||||||
|
|
||||||
def topology(func, *args):
|
def topology(func, *args):
|
||||||
"For GEOS unary topology functions."
|
"For GEOS unary topology functions."
|
||||||
|
@ -22,29 +23,29 @@ def topology(func, *args):
|
||||||
return func
|
return func
|
||||||
|
|
||||||
### Topology Routines ###
|
### Topology Routines ###
|
||||||
geos_boundary = topology(lgeos.GEOSBoundary)
|
geos_boundary = topology(GEOSFunc('GEOSBoundary'))
|
||||||
geos_buffer = topology(lgeos.GEOSBuffer, c_double, c_int)
|
geos_buffer = topology(GEOSFunc('GEOSBuffer'), c_double, c_int)
|
||||||
geos_centroid = topology(lgeos.GEOSGetCentroid)
|
geos_centroid = topology(GEOSFunc('GEOSGetCentroid'))
|
||||||
geos_convexhull = topology(lgeos.GEOSConvexHull)
|
geos_convexhull = topology(GEOSFunc('GEOSConvexHull'))
|
||||||
geos_difference = topology(lgeos.GEOSDifference, GEOM_PTR)
|
geos_difference = topology(GEOSFunc('GEOSDifference'), GEOM_PTR)
|
||||||
geos_envelope = topology(lgeos.GEOSEnvelope)
|
geos_envelope = topology(GEOSFunc('GEOSEnvelope'))
|
||||||
geos_intersection = topology(lgeos.GEOSIntersection, GEOM_PTR)
|
geos_intersection = topology(GEOSFunc('GEOSIntersection'), GEOM_PTR)
|
||||||
geos_linemerge = topology(lgeos.GEOSLineMerge)
|
geos_linemerge = topology(GEOSFunc('GEOSLineMerge'))
|
||||||
geos_pointonsurface = topology(lgeos.GEOSPointOnSurface)
|
geos_pointonsurface = topology(GEOSFunc('GEOSPointOnSurface'))
|
||||||
geos_preservesimplify = topology(lgeos.GEOSTopologyPreserveSimplify, c_double)
|
geos_preservesimplify = topology(GEOSFunc('GEOSTopologyPreserveSimplify'), c_double)
|
||||||
geos_simplify = topology(lgeos.GEOSSimplify, c_double)
|
geos_simplify = topology(GEOSFunc('GEOSSimplify'), c_double)
|
||||||
geos_symdifference = topology(lgeos.GEOSSymDifference, GEOM_PTR)
|
geos_symdifference = topology(GEOSFunc('GEOSSymDifference'), GEOM_PTR)
|
||||||
geos_union = topology(lgeos.GEOSUnion, GEOM_PTR)
|
geos_union = topology(GEOSFunc('GEOSUnion'), GEOM_PTR)
|
||||||
|
|
||||||
# GEOSRelate returns a string, not a geometry.
|
# GEOSRelate returns a string, not a geometry.
|
||||||
geos_relate = lgeos.GEOSRelate
|
geos_relate = GEOSFunc('GEOSRelate')
|
||||||
geos_relate.argtypes = [GEOM_PTR, GEOM_PTR]
|
geos_relate.argtypes = [GEOM_PTR, GEOM_PTR]
|
||||||
geos_relate.restype = geos_char_p
|
geos_relate.restype = geos_char_p
|
||||||
geos_relate.errcheck = check_string
|
geos_relate.errcheck = check_string
|
||||||
|
|
||||||
# Routines only in GEOS 3.1+
|
# Routines only in GEOS 3.1+
|
||||||
if GEOS_PREPARE:
|
if GEOS_PREPARE:
|
||||||
geos_cascaded_union = lgeos.GEOSUnionCascaded
|
geos_cascaded_union = GEOSFunc('GEOSUnionCascaded')
|
||||||
geos_cascaded_union.argtypes = [GEOM_PTR]
|
geos_cascaded_union.argtypes = [GEOM_PTR]
|
||||||
geos_cascaded_union.restype = GEOM_PTR
|
geos_cascaded_union.restype = GEOM_PTR
|
||||||
__all__.append('geos_cascaded_union')
|
__all__.append('geos_cascaded_union')
|
||||||
|
|
Loading…
Reference in New Issue