PageRenderTime 50ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 1ms

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

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