web/lib/django/contrib/gis/geos/libgeos.py
changeset 0 0d40e90630ef
child 29 cc9b7e14412b
equal deleted inserted replaced
-1:000000000000 0:0d40e90630ef
       
     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 # Custom library path set?
       
    15 try:
       
    16     from django.conf import settings
       
    17     lib_path = settings.GEOS_LIBRARY_PATH
       
    18 except (AttributeError, EnvironmentError, ImportError):
       
    19     lib_path = None
       
    20 
       
    21 # Setting the appropriate names for the GEOS-C library.
       
    22 if lib_path:
       
    23     lib_names = None
       
    24 elif os.name == 'nt':
       
    25     # Windows NT libraries
       
    26     lib_names = ['libgeos_c-1']
       
    27 elif os.name == 'posix':
       
    28     # *NIX libraries
       
    29     lib_names = ['geos_c', 'GEOS']
       
    30 else:
       
    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].).
       
    36 if 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.
       
    42 if 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
       
    51 lgeos = 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, ...);"
       
    56 NOTICEFUNC = CFUNCTYPE(None, c_char_p, c_char_p)
       
    57 def 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)
       
    63 notice_h = NOTICEFUNC(notice_h)
       
    64 
       
    65 ERRORFUNC = CFUNCTYPE(None, c_char_p, c_char_p)
       
    66 def 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)
       
    72 error_h = ERRORFUNC(error_h)
       
    73 
       
    74 # The initGEOS routine should be called first, however, that routine takes
       
    75 #  the notice and error functions as parameters.  Here is the C code that
       
    76 #  is wrapped:
       
    77 #  "extern void GEOS_DLL initGEOS(GEOSMessageHandler notice_function, GEOSMessageHandler error_function);"
       
    78 lgeos.initGEOS(notice_h, error_h)
       
    79 
       
    80 #### GEOS Geometry C data structures, and utility functions. ####
       
    81 
       
    82 # Opaque GEOS geometry structures, used for GEOM_PTR and CS_PTR
       
    83 class GEOSGeom_t(Structure): pass
       
    84 class GEOSPrepGeom_t(Structure): pass
       
    85 class GEOSCoordSeq_t(Structure): pass
       
    86 
       
    87 # Pointers to opaque GEOS geometry structures.
       
    88 GEOM_PTR = POINTER(GEOSGeom_t)
       
    89 PREPGEOM_PTR = POINTER(GEOSPrepGeom_t)
       
    90 CS_PTR = POINTER(GEOSCoordSeq_t)
       
    91 
       
    92 # Used specifically by the GEOSGeom_createPolygon and GEOSGeom_createCollection
       
    93 #  GEOS routines
       
    94 def get_pointer_arr(n):
       
    95     "Gets a ctypes pointer array (of length `n`) for GEOSGeom_t opaque pointer."
       
    96     GeomArr = GEOM_PTR * n
       
    97     return GeomArr()
       
    98 
       
    99 # Returns the string version of the GEOS library. Have to set the restype
       
   100 # explicitly to c_char_p to ensure compatibility accross 32 and 64-bit platforms.
       
   101 geos_version = lgeos.GEOSversion
       
   102 geos_version.argtypes = None
       
   103 geos_version.restype = c_char_p
       
   104 
       
   105 # Regular expression should be able to parse version strings such as
       
   106 # '3.0.0rc4-CAPI-1.3.3', or '3.0.0-CAPI-1.4.1'
       
   107 version_regex = re.compile(r'^(?P<version>(?P<major>\d+)\.(?P<minor>\d+)\.\d+)(rc(?P<release_candidate>\d+))?-CAPI-(?P<capi_version>\d+\.\d+\.\d+)$')
       
   108 def geos_version_info():
       
   109     """
       
   110     Returns a dictionary containing the various version metadata parsed from
       
   111     the GEOS version string, including the version number, whether the version
       
   112     is a release candidate (and what number release candidate), and the C API
       
   113     version.
       
   114     """
       
   115     ver = geos_version()
       
   116     m = version_regex.match(ver)
       
   117     if not m: raise GEOSException('Could not parse version info string "%s"' % ver)
       
   118     return dict((key, m.group(key)) for key in ('version', 'release_candidate', 'capi_version', 'major', 'minor'))
       
   119 
       
   120 # Version numbers and whether or not prepared geometry support is available.
       
   121 _verinfo = geos_version_info()
       
   122 GEOS_MAJOR_VERSION = int(_verinfo['major'])
       
   123 GEOS_MINOR_VERSION = int(_verinfo['minor'])
       
   124 del _verinfo
       
   125 GEOS_PREPARE = GEOS_MAJOR_VERSION > 3 or GEOS_MAJOR_VERSION == 3 and GEOS_MINOR_VERSION >= 1
       
   126 
       
   127 # Calling the finishGEOS() upon exit of the interpreter.
       
   128 atexit.register(lgeos.finishGEOS)