~ubuntu-branches/ubuntu/quantal/python-django/quantal

« back to all changes in this revision

Viewing changes to django/contrib/gis/geos/libgeos.py

  • Committer: Bazaar Package Importer
  • Author(s): Scott James Remnant, Eddy Mulyono
  • Date: 2008-09-16 12:18:47 UTC
  • mfrom: (1.1.5 upstream) (4.1.1 lenny)
  • Revision ID: james.westby@ubuntu.com-20080916121847-mg225rg5mnsdqzr0
Tags: 1.0-1ubuntu1
* Merge from Debian (LP: #264191), remaining changes:
  - Run test suite on build.

[Eddy Mulyono]
* Update patch to workaround network test case failures.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
"""
 
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
 
13
 
 
14
# NumPy supported?
 
15
try:
 
16
    from numpy import array, ndarray
 
17
    HAS_NUMPY = True
 
18
except ImportError:
 
19
    HAS_NUMPY = False
 
20
 
 
21
# Custom library path set?
 
22
try:
 
23
    from django.conf import settings
 
24
    lib_path = settings.GEOS_LIBRARY_PATH
 
25
except (AttributeError, EnvironmentError, ImportError):
 
26
    lib_path = None
 
27
 
 
28
# Setting the appropriate names for the GEOS-C library.
 
29
if lib_path:
 
30
    lib_names = None
 
31
elif os.name == 'nt':
 
32
    # Windows NT libraries
 
33
    lib_names = ['libgeos_c-1']
 
34
elif os.name == 'posix':
 
35
    # *NIX libraries
 
36
    lib_names = ['geos_c']
 
37
else:
 
38
    raise ImportError('Unsupported OS "%s"' % os.name)
 
39
 
 
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].).
 
43
if lib_names: 
 
44
    for lib_name in lib_names:
 
45
        lib_path = find_library(lib_name)
 
46
        if not lib_path is None: break
 
47
 
 
48
# No GEOS library could be found.
 
49
if lib_path is None: 
 
50
    raise ImportError('Could not find the GEOS library (tried "%s"). '
 
51
                        'Try setting GEOS_LIBRARY_PATH in your settings.' % 
 
52
                        '", "'.join(lib_names))
 
53
 
 
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)
 
59
 
 
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):
 
65
    try:
 
66
        warn_msg = fmt % lst
 
67
    except:
 
68
        warn_msg = fmt 
 
69
    output_h.write('GEOS_NOTICE: %s\n' % warn_msg)
 
70
notice_h = NOTICEFUNC(notice_h)
 
71
 
 
72
ERRORFUNC = CFUNCTYPE(None, c_char_p, c_char_p)
 
73
def error_h(fmt, lst, output_h=sys.stderr):
 
74
    try:
 
75
        err_msg = fmt % lst
 
76
    except:
 
77
        err_msg = fmt
 
78
    output_h.write('GEOS_ERROR: %s\n' % err_msg)
 
79
error_h = ERRORFUNC(error_h)
 
80
 
 
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
 
83
#  is wrapped:
 
84
#  "extern void GEOS_DLL initGEOS(GEOSMessageHandler notice_function, GEOSMessageHandler error_function);"
 
85
lgeos.initGEOS(notice_h, error_h)
 
86
 
 
87
#### GEOS Geometry C data structures, and utility functions. ####
 
88
 
 
89
# Opaque GEOS geometry structures, used for GEOM_PTR and CS_PTR
 
90
class GEOSGeom_t(Structure): pass
 
91
class GEOSCoordSeq_t(Structure): pass
 
92
 
 
93
# Pointers to opaque GEOS geometry structures.
 
94
GEOM_PTR = POINTER(GEOSGeom_t)
 
95
CS_PTR = POINTER(GEOSCoordSeq_t)
 
96
 
 
97
# Used specifically by the GEOSGeom_createPolygon and GEOSGeom_createCollection 
 
98
#  GEOS routines
 
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
 
102
    return GeomArr()
 
103
 
 
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
 
109
 
 
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():
 
114
    """
 
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
 
118
    version.
 
119
    """
 
120
    ver = geos_version()
 
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'))
 
124
 
 
125
# Calling the finishGEOS() upon exit of the interpreter.
 
126
atexit.register(lgeos.finishGEOS)