PageRenderTime 33ms CodeModel.GetById 21ms app.highlight 9ms RepoModel.GetById 1ms app.codeStats 0ms

/django/contrib/gis/geos/libgeos.py

https://code.google.com/p/mango-py/
Python | 141 lines | 77 code | 15 blank | 49 comment | 12 complexity | 81382c02e1d9c3926d18e2b47d821db8 MD5 | raw file
  1"""
  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).
  5
  6 This module also houses GEOS Pointer utilities, including
  7 get_pointer_arr(), and GEOM_PTR.
  8"""
  9import os, re, sys
 10from ctypes import c_char_p, Structure, CDLL, CFUNCTYPE, POINTER
 11from ctypes.util import find_library
 12from django.contrib.gis.geos.error import GEOSException
 13
 14# Custom library path set?
 15try:
 16    from django.conf import settings
 17    lib_path = settings.GEOS_LIBRARY_PATH
 18except (AttributeError, EnvironmentError, ImportError):
 19    lib_path = None
 20
 21# Setting the appropriate names for the GEOS-C library.
 22if lib_path:
 23    lib_names = None
 24elif os.name == 'nt':
 25    # Windows NT libraries
 26    lib_names = ['geos_c', 'libgeos_c-1']
 27elif os.name == 'posix':
 28    # *NIX libraries
 29    lib_names = ['geos_c', 'GEOS']
 30else:
 31    raise ImportError('Unsupported OS "%s"' % os.name)
 32
 33# Using the ctypes `find_library` utility to find the path to the GEOS
 34# shared library.  This is better than manually specifiying each library name
 35# and extension (e.g., libgeos_c.[so|so.1|dylib].).
 36if lib_names:
 37    for lib_name in lib_names:
 38        lib_path = find_library(lib_name)
 39        if not lib_path is None: break
 40
 41# No GEOS library could be found.
 42if lib_path is None:
 43    raise ImportError('Could not find the GEOS library (tried "%s"). '
 44                        'Try setting GEOS_LIBRARY_PATH in your settings.' %
 45                        '", "'.join(lib_names))
 46
 47# Getting the GEOS C library.  The C interface (CDLL) is used for
 48# both *NIX and Windows.
 49# See the GEOS C API source code for more details on the library function calls:
 50#  http://geos.refractions.net/ro/doxygen_docs/html/geos__c_8h-source.html
 51lgeos = CDLL(lib_path)
 52
 53# The notice and error handler C function callback definitions.
 54# Supposed to mimic the GEOS message handler (C below):
 55#  typedef void (*GEOSMessageHandler)(const char *fmt, ...);
 56NOTICEFUNC = CFUNCTYPE(None, c_char_p, c_char_p)
 57def notice_h(fmt, lst, output_h=sys.stdout):
 58    try:
 59        warn_msg = fmt % lst
 60    except:
 61        warn_msg = fmt
 62    output_h.write('GEOS_NOTICE: %s\n' % warn_msg)
 63notice_h = NOTICEFUNC(notice_h)
 64
 65ERRORFUNC = CFUNCTYPE(None, c_char_p, c_char_p)
 66def error_h(fmt, lst, output_h=sys.stderr):
 67    try:
 68        err_msg = fmt % lst
 69    except:
 70        err_msg = fmt
 71    output_h.write('GEOS_ERROR: %s\n' % err_msg)
 72error_h = ERRORFUNC(error_h)
 73
 74#### GEOS Geometry C data structures, and utility functions. ####
 75
 76# Opaque GEOS geometry structures, used for GEOM_PTR and CS_PTR
 77class GEOSGeom_t(Structure): pass
 78class GEOSPrepGeom_t(Structure): pass
 79class GEOSCoordSeq_t(Structure): pass
 80class GEOSContextHandle_t(Structure): pass
 81
 82# Pointers to opaque GEOS geometry structures.
 83GEOM_PTR = POINTER(GEOSGeom_t)
 84PREPGEOM_PTR = POINTER(GEOSPrepGeom_t)
 85CS_PTR = POINTER(GEOSCoordSeq_t)
 86CONTEXT_PTR  = POINTER(GEOSContextHandle_t)
 87
 88# Used specifically by the GEOSGeom_createPolygon and GEOSGeom_createCollection
 89#  GEOS routines
 90def get_pointer_arr(n):
 91    "Gets a ctypes pointer array (of length `n`) for GEOSGeom_t opaque pointer."
 92    GeomArr = GEOM_PTR * n
 93    return GeomArr()
 94
 95# Returns the string version of the GEOS library. Have to set the restype
 96# explicitly to c_char_p to ensure compatibility accross 32 and 64-bit platforms.
 97geos_version = lgeos.GEOSversion
 98geos_version.argtypes = None
 99geos_version.restype = c_char_p
100
101# Regular expression should be able to parse version strings such as
102# '3.0.0rc4-CAPI-1.3.3', or '3.0.0-CAPI-1.4.1'
103version_regex = re.compile(r'^(?P<version>(?P<major>\d+)\.(?P<minor>\d+)\.(?P<subminor>\d+))(rc(?P<release_candidate>\d+))?-CAPI-(?P<capi_version>\d+\.\d+\.\d+)$')
104def geos_version_info():
105    """
106    Returns a dictionary containing the various version metadata parsed from
107    the GEOS version string, including the version number, whether the version
108    is a release candidate (and what number release candidate), and the C API
109    version.
110    """
111    ver = geos_version()
112    m = version_regex.match(ver)
113    if not m: raise GEOSException('Could not parse version info string "%s"' % ver)
114    return dict((key, m.group(key)) for key in ('version', 'release_candidate', 'capi_version', 'major', 'minor', 'subminor'))
115
116# Version numbers and whether or not prepared geometry support is available.
117_verinfo = geos_version_info()
118GEOS_MAJOR_VERSION = int(_verinfo['major'])
119GEOS_MINOR_VERSION = int(_verinfo['minor'])
120GEOS_SUBMINOR_VERSION = int(_verinfo['subminor'])
121del _verinfo
122GEOS_VERSION = (GEOS_MAJOR_VERSION, GEOS_MINOR_VERSION, GEOS_SUBMINOR_VERSION)
123GEOS_PREPARE = GEOS_VERSION >= (3, 1, 0)
124
125if GEOS_PREPARE:
126    # Here we set up the prototypes for the initGEOS_r and finishGEOS_r
127    # routines.  These functions aren't actually called until they are
128    # attached to a GEOS context handle -- this actually occurs in
129    # geos/prototypes/threadsafe.py.
130    lgeos.initGEOS_r.restype = CONTEXT_PTR
131    lgeos.finishGEOS_r.argtypes = [CONTEXT_PTR]
132else:
133    # When thread-safety isn't available, the initGEOS routine must be called
134    # first.  This function takes the notice and error functions, defined
135    # as Python callbacks above, as parameters. Here is the C code that is
136    # wrapped:
137    #  extern void GEOS_DLL initGEOS(GEOSMessageHandler notice_function, GEOSMessageHandler error_function);
138    lgeos.initGEOS(notice_h, error_h)
139    # Calling finishGEOS() upon exit of the interpreter.
140    import atexit
141    atexit.register(lgeos.finishGEOS)