2
This module houses the ctypes initialization procedures, as well
3
as the notice and error handler function callbacks (get called
4
when an error occurs in GEOS).
6
This module also houses GEOS Pointer utilities, including
7
get_pointer_arr(), and GEOM_PTR.
9
import atexit, os, re, sys
10
from ctypes import c_char_p, Structure, CDLL, CFUNCTYPE, POINTER
11
from ctypes.util import find_library
12
from django.contrib.gis.geos.error import GEOSException
16
from numpy import array, ndarray
21
# Custom library path set?
23
from django.conf import settings
24
lib_path = settings.GEOS_LIBRARY_PATH
25
except (AttributeError, EnvironmentError, ImportError):
28
# Setting the appropriate names for the GEOS-C library.
32
# Windows NT libraries
33
lib_names = ['libgeos_c-1']
34
elif os.name == 'posix':
36
lib_names = ['geos_c']
38
raise ImportError('Unsupported OS "%s"' % os.name)
40
# Using the ctypes `find_library` utility to find the the path to the GEOS
41
# shared library. This is better than manually specifiying each library name
42
# and extension (e.g., libgeos_c.[so|so.1|dylib].).
44
for lib_name in lib_names:
45
lib_path = find_library(lib_name)
46
if not lib_path is None: break
48
# No GEOS library could be found.
50
raise ImportError('Could not find the GEOS library (tried "%s"). '
51
'Try setting GEOS_LIBRARY_PATH in your settings.' %
52
'", "'.join(lib_names))
54
# Getting the GEOS C library. The C interface (CDLL) is used for
55
# both *NIX and Windows.
56
# See the GEOS C API source code for more details on the library function calls:
57
# http://geos.refractions.net/ro/doxygen_docs/html/geos__c_8h-source.html
58
lgeos = CDLL(lib_path)
60
# The notice and error handler C function callback definitions.
61
# Supposed to mimic the GEOS message handler (C below):
62
# "typedef void (*GEOSMessageHandler)(const char *fmt, ...);"
63
NOTICEFUNC = CFUNCTYPE(None, c_char_p, c_char_p)
64
def notice_h(fmt, lst, output_h=sys.stdout):
69
output_h.write('GEOS_NOTICE: %s\n' % warn_msg)
70
notice_h = NOTICEFUNC(notice_h)
72
ERRORFUNC = CFUNCTYPE(None, c_char_p, c_char_p)
73
def error_h(fmt, lst, output_h=sys.stderr):
78
output_h.write('GEOS_ERROR: %s\n' % err_msg)
79
error_h = ERRORFUNC(error_h)
81
# The initGEOS routine should be called first, however, that routine takes
82
# the notice and error functions as parameters. Here is the C code that
84
# "extern void GEOS_DLL initGEOS(GEOSMessageHandler notice_function, GEOSMessageHandler error_function);"
85
lgeos.initGEOS(notice_h, error_h)
87
#### GEOS Geometry C data structures, and utility functions. ####
89
# Opaque GEOS geometry structures, used for GEOM_PTR and CS_PTR
90
class GEOSGeom_t(Structure): pass
91
class GEOSCoordSeq_t(Structure): pass
93
# Pointers to opaque GEOS geometry structures.
94
GEOM_PTR = POINTER(GEOSGeom_t)
95
CS_PTR = POINTER(GEOSCoordSeq_t)
97
# Used specifically by the GEOSGeom_createPolygon and GEOSGeom_createCollection
99
def get_pointer_arr(n):
100
"Gets a ctypes pointer array (of length `n`) for GEOSGeom_t opaque pointer."
101
GeomArr = GEOM_PTR * n
104
# Returns the string version of the GEOS library. Have to set the restype
105
# explicitly to c_char_p to ensure compatibility accross 32 and 64-bit platforms.
106
geos_version = lgeos.GEOSversion
107
geos_version.argtypes = None
108
geos_version.restype = c_char_p
110
# Regular expression should be able to parse version strings such as
111
# '3.0.0rc4-CAPI-1.3.3', or '3.0.0-CAPI-1.4.1'
112
version_regex = re.compile(r'^(?P<version>\d+\.\d+\.\d+)(rc(?P<release_candidate>\d+))?-CAPI-(?P<capi_version>\d+\.\d+\.\d+)$')
113
def geos_version_info():
115
Returns a dictionary containing the various version metadata parsed from
116
the GEOS version string, including the version number, whether the version
117
is a release candidate (and what number release candidate), and the C API
121
m = version_regex.match(ver)
122
if not m: raise GEOSException('Could not parse version info string "%s"' % ver)
123
return dict((key, m.group(key)) for key in ('version', 'release_candidate', 'capi_version'))
125
# Calling the finishGEOS() upon exit of the interpreter.
126
atexit.register(lgeos.finishGEOS)