änderung1
This commit is contained in:
1 parent
cc1d096bc3
commit
cbdda613b7
2098 files changed
+274524
No files matched your search
@@ -0,0 +1,27 @@
|
||||
Copyright (c) 2007-2009 Justin Bronn
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. Neither the name of GEOSGeometry nor the names of its contributors may be used
|
||||
to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
@@ -0,0 +1,15 @@
|
||||
"""
|
||||
The GeoDjango GEOS module. Please consult the GeoDjango documentation
|
||||
for more details: https://docs.djangoproject.com/en/dev/ref/contrib/gis/geos/
|
||||
"""
|
||||
from .collections import ( # NOQA
|
||||
GeometryCollection, MultiLineString, MultiPoint, MultiPolygon,
|
||||
)
|
||||
from .error import GEOSException # NOQA
|
||||
from .factory import fromfile, fromstr # NOQA
|
||||
from .geometry import GEOSGeometry, hex_regex, wkt_regex # NOQA
|
||||
from .io import WKBReader, WKBWriter, WKTReader, WKTWriter # NOQA
|
||||
from .libgeos import geos_version # NOQA
|
||||
from .linestring import LinearRing, LineString # NOQA
|
||||
from .point import Point # NOQA
|
||||
from .polygon import Polygon # NOQA
|
||||
@@ -0,0 +1,196 @@
|
||||
"""
|
||||
This module houses the GEOSCoordSeq object, which is used internally
|
||||
by GEOSGeometry to house the actual coordinates of the Point,
|
||||
LineString, and LinearRing geometries.
|
||||
"""
|
||||
from ctypes import byref, c_double, c_uint
|
||||
|
||||
from django.contrib.gis.geos import prototypes as capi
|
||||
from django.contrib.gis.geos.base import GEOSBase
|
||||
from django.contrib.gis.geos.error import GEOSException
|
||||
from django.contrib.gis.geos.libgeos import CS_PTR
|
||||
from django.contrib.gis.shortcuts import numpy
|
||||
|
||||
|
||||
class GEOSCoordSeq(GEOSBase):
|
||||
"The internal representation of a list of coordinates inside a Geometry."
|
||||
|
||||
ptr_type = CS_PTR
|
||||
|
||||
def __init__(self, ptr, z=False):
|
||||
"Initialize from a GEOS pointer."
|
||||
if not isinstance(ptr, CS_PTR):
|
||||
raise TypeError('Coordinate sequence should initialize with a CS_PTR.')
|
||||
self._ptr = ptr
|
||||
self._z = z
|
||||
|
||||
def __iter__(self):
|
||||
"Iterate over each point in the coordinate sequence."
|
||||
for i in range(self.size):
|
||||
yield self[i]
|
||||
|
||||
def __len__(self):
|
||||
"Return the number of points in the coordinate sequence."
|
||||
return int(self.size)
|
||||
|
||||
def __str__(self):
|
||||
"Return the string representation of the coordinate sequence."
|
||||
return str(self.tuple)
|
||||
|
||||
def __getitem__(self, index):
|
||||
"Return the coordinate sequence value at the given index."
|
||||
self._checkindex(index)
|
||||
return self._point_getter(index)
|
||||
|
||||
def __setitem__(self, index, value):
|
||||
"Set the coordinate sequence value at the given index."
|
||||
# Checking the input value
|
||||
if isinstance(value, (list, tuple)):
|
||||
pass
|
||||
elif numpy and isinstance(value, numpy.ndarray):
|
||||
pass
|
||||
else:
|
||||
raise TypeError('Must set coordinate with a sequence (list, tuple, or numpy array).')
|
||||
# Checking the dims of the input
|
||||
if self.dims == 3 and self._z:
|
||||
n_args = 3
|
||||
point_setter = self._set_point_3d
|
||||
else:
|
||||
n_args = 2
|
||||
point_setter = self._set_point_2d
|
||||
if len(value) != n_args:
|
||||
raise TypeError('Dimension of value does not match.')
|
||||
self._checkindex(index)
|
||||
point_setter(index, value)
|
||||
|
||||
# #### Internal Routines ####
|
||||
def _checkindex(self, index):
|
||||
"Check the given index."
|
||||
if not (0 <= index < self.size):
|
||||
raise IndexError('invalid GEOS Geometry index: %s' % index)
|
||||
|
||||
def _checkdim(self, dim):
|
||||
"Check the given dimension."
|
||||
if dim < 0 or dim > 2:
|
||||
raise GEOSException('invalid ordinate dimension "%d"' % dim)
|
||||
|
||||
def _get_x(self, index):
|
||||
return capi.cs_getx(self.ptr, index, byref(c_double()))
|
||||
|
||||
def _get_y(self, index):
|
||||
return capi.cs_gety(self.ptr, index, byref(c_double()))
|
||||
|
||||
def _get_z(self, index):
|
||||
return capi.cs_getz(self.ptr, index, byref(c_double()))
|
||||
|
||||
def _set_x(self, index, value):
|
||||
capi.cs_setx(self.ptr, index, value)
|
||||
|
||||
def _set_y(self, index, value):
|
||||
capi.cs_sety(self.ptr, index, value)
|
||||
|
||||
def _set_z(self, index, value):
|
||||
capi.cs_setz(self.ptr, index, value)
|
||||
|
||||
@property
|
||||
def _point_getter(self):
|
||||
return self._get_point_3d if self.dims == 3 and self._z else self._get_point_2d
|
||||
|
||||
def _get_point_2d(self, index):
|
||||
return (self._get_x(index), self._get_y(index))
|
||||
|
||||
def _get_point_3d(self, index):
|
||||
return (self._get_x(index), self._get_y(index), self._get_z(index))
|
||||
|
||||
def _set_point_2d(self, index, value):
|
||||
x, y = value
|
||||
self._set_x(index, x)
|
||||
self._set_y(index, y)
|
||||
|
||||
def _set_point_3d(self, index, value):
|
||||
x, y, z = value
|
||||
self._set_x(index, x)
|
||||
self._set_y(index, y)
|
||||
self._set_z(index, z)
|
||||
|
||||
# #### Ordinate getting and setting routines ####
|
||||
def getOrdinate(self, dimension, index):
|
||||
"Return the value for the given dimension and index."
|
||||
self._checkindex(index)
|
||||
self._checkdim(dimension)
|
||||
return capi.cs_getordinate(self.ptr, index, dimension, byref(c_double()))
|
||||
|
||||
def setOrdinate(self, dimension, index, value):
|
||||
"Set the value for the given dimension and index."
|
||||
self._checkindex(index)
|
||||
self._checkdim(dimension)
|
||||
capi.cs_setordinate(self.ptr, index, dimension, value)
|
||||
|
||||
def getX(self, index):
|
||||
"Get the X value at the index."
|
||||
return self.getOrdinate(0, index)
|
||||
|
||||
def setX(self, index, value):
|
||||
"Set X with the value at the given index."
|
||||
self.setOrdinate(0, index, value)
|
||||
|
||||
def getY(self, index):
|
||||
"Get the Y value at the given index."
|
||||
return self.getOrdinate(1, index)
|
||||
|
||||
def setY(self, index, value):
|
||||
"Set Y with the value at the given index."
|
||||
self.setOrdinate(1, index, value)
|
||||
|
||||
def getZ(self, index):
|
||||
"Get Z with the value at the given index."
|
||||
return self.getOrdinate(2, index)
|
||||
|
||||
def setZ(self, index, value):
|
||||
"Set Z with the value at the given index."
|
||||
self.setOrdinate(2, index, value)
|
||||
|
||||
# ### Dimensions ###
|
||||
@property
|
||||
def size(self):
|
||||
"Return the size of this coordinate sequence."
|
||||
return capi.cs_getsize(self.ptr, byref(c_uint()))
|
||||
|
||||
@property
|
||||
def dims(self):
|
||||
"Return the dimensions of this coordinate sequence."
|
||||
return capi.cs_getdims(self.ptr, byref(c_uint()))
|
||||
|
||||
@property
|
||||
def hasz(self):
|
||||
"""
|
||||
Return whether this coordinate sequence is 3D. This property value is
|
||||
inherited from the parent Geometry.
|
||||
"""
|
||||
return self._z
|
||||
|
||||
# ### Other Methods ###
|
||||
def clone(self):
|
||||
"Clone this coordinate sequence."
|
||||
return GEOSCoordSeq(capi.cs_clone(self.ptr), self.hasz)
|
||||
|
||||
@property
|
||||
def kml(self):
|
||||
"Return the KML representation for the coordinates."
|
||||
# Getting the substitution string depending on whether the coordinates have
|
||||
# a Z dimension.
|
||||
if self.hasz:
|
||||
substr = '%s,%s,%s '
|
||||
else:
|
||||
substr = '%s,%s,0 '
|
||||
return '<coordinates>%s</coordinates>' % \
|
||||
''.join(substr % self[i] for i in range(len(self))).strip()
|
||||
|
||||
@property
|
||||
def tuple(self):
|
||||
"Return a tuple version of this coordinate sequence."
|
||||
n = self.size
|
||||
get_point = self._point_getter
|
||||
if n == 1:
|
||||
return get_point(0)
|
||||
return tuple(get_point(i) for i in range(n))
|
||||
@@ -0,0 +1,175 @@
|
||||
"""
|
||||
This module houses the ctypes initialization procedures, as well
|
||||
as the notice and error handler function callbacks (get called
|
||||
when an error occurs in GEOS).
|
||||
|
||||
This module also houses GEOS Pointer utilities, including
|
||||
get_pointer_arr(), and GEOM_PTR.
|
||||
"""
|
||||
import logging
|
||||
import os
|
||||
from ctypes import CDLL, CFUNCTYPE, POINTER, Structure, c_char_p
|
||||
from ctypes.util import find_library
|
||||
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
from django.utils.functional import SimpleLazyObject, cached_property
|
||||
from django.utils.version import get_version_tuple
|
||||
|
||||
logger = logging.getLogger('django.contrib.gis')
|
||||
|
||||
|
||||
def load_geos():
|
||||
# Custom library path set?
|
||||
try:
|
||||
from django.conf import settings
|
||||
lib_path = settings.GEOS_LIBRARY_PATH
|
||||
except (AttributeError, EnvironmentError,
|
||||
ImportError, ImproperlyConfigured):
|
||||
lib_path = None
|
||||
|
||||
# Setting the appropriate names for the GEOS-C library.
|
||||
if lib_path:
|
||||
lib_names = None
|
||||
elif os.name == 'nt':
|
||||
# Windows NT libraries
|
||||
lib_names = ['geos_c', 'libgeos_c-1']
|
||||
elif os.name == 'posix':
|
||||
# *NIX libraries
|
||||
lib_names = ['geos_c', 'GEOS']
|
||||
else:
|
||||
raise ImportError('Unsupported OS "%s"' % os.name)
|
||||
|
||||
# Using the ctypes `find_library` utility to find the path to the GEOS
|
||||
# shared library. This is better than manually specifying each library name
|
||||
# and extension (e.g., libgeos_c.[so|so.1|dylib].).
|
||||
if lib_names:
|
||||
for lib_name in lib_names:
|
||||
lib_path = find_library(lib_name)
|
||||
if lib_path is not None:
|
||||
break
|
||||
|
||||
# No GEOS library could be found.
|
||||
if lib_path is None:
|
||||
raise ImportError(
|
||||
'Could not find the GEOS library (tried "%s"). '
|
||||
'Try setting GEOS_LIBRARY_PATH in your settings.' %
|
||||
'", "'.join(lib_names)
|
||||
)
|
||||
# Getting the GEOS C library. The C interface (CDLL) is used for
|
||||
# both *NIX and Windows.
|
||||
# See the GEOS C API source code for more details on the library function calls:
|
||||
# http://geos.refractions.net/ro/doxygen_docs/html/geos__c_8h-source.html
|
||||
_lgeos = CDLL(lib_path)
|
||||
# Here we set up the prototypes for the initGEOS_r and finishGEOS_r
|
||||
# routines. These functions aren't actually called until they are
|
||||
# attached to a GEOS context handle -- this actually occurs in
|
||||
# geos/prototypes/threadsafe.py.
|
||||
_lgeos.initGEOS_r.restype = CONTEXT_PTR
|
||||
_lgeos.finishGEOS_r.argtypes = [CONTEXT_PTR]
|
||||
# Set restype for compatibility across 32 and 64-bit platforms.
|
||||
_lgeos.GEOSversion.restype = c_char_p
|
||||
return _lgeos
|
||||
|
||||
|
||||
# The notice and error handler C function callback definitions.
|
||||
# Supposed to mimic the GEOS message handler (C below):
|
||||
# typedef void (*GEOSMessageHandler)(const char *fmt, ...);
|
||||
NOTICEFUNC = CFUNCTYPE(None, c_char_p, c_char_p)
|
||||
|
||||
|
||||
def notice_h(fmt, lst):
|
||||
fmt, lst = fmt.decode(), lst.decode()
|
||||
try:
|
||||
warn_msg = fmt % lst
|
||||
except TypeError:
|
||||
warn_msg = fmt
|
||||
logger.warning('GEOS_NOTICE: %s\n', warn_msg)
|
||||
|
||||
|
||||
notice_h = NOTICEFUNC(notice_h)
|
||||
|
||||
ERRORFUNC = CFUNCTYPE(None, c_char_p, c_char_p)
|
||||
|
||||
|
||||
def error_h(fmt, lst):
|
||||
fmt, lst = fmt.decode(), lst.decode()
|
||||
try:
|
||||
err_msg = fmt % lst
|
||||
except TypeError:
|
||||
err_msg = fmt
|
||||
logger.error('GEOS_ERROR: %s\n', err_msg)
|
||||
|
||||
|
||||
error_h = ERRORFUNC(error_h)
|
||||
|
||||
# #### GEOS Geometry C data structures, and utility functions. ####
|
||||
|
||||
|
||||
# Opaque GEOS geometry structures, used for GEOM_PTR and CS_PTR
|
||||
class GEOSGeom_t(Structure):
|
||||
pass
|
||||
|
||||
|
||||
class GEOSPrepGeom_t(Structure):
|
||||
pass
|
||||
|
||||
|
||||
class GEOSCoordSeq_t(Structure):
|
||||
pass
|
||||
|
||||
|
||||
class GEOSContextHandle_t(Structure):
|
||||
pass
|
||||
|
||||
|
||||
# Pointers to opaque GEOS geometry structures.
|
||||
GEOM_PTR = POINTER(GEOSGeom_t)
|
||||
PREPGEOM_PTR = POINTER(GEOSPrepGeom_t)
|
||||
CS_PTR = POINTER(GEOSCoordSeq_t)
|
||||
CONTEXT_PTR = POINTER(GEOSContextHandle_t)
|
||||
|
||||
|
||||
lgeos = SimpleLazyObject(load_geos)
|
||||
|
||||
|
||||
class GEOSFuncFactory:
|
||||
"""
|
||||
Lazy loading of GEOS functions.
|
||||
"""
|
||||
argtypes = None
|
||||
restype = None
|
||||
errcheck = None
|
||||
|
||||
def __init__(self, func_name, *args, restype=None, errcheck=None, argtypes=None, **kwargs):
|
||||
self.func_name = func_name
|
||||
if restype is not None:
|
||||
self.restype = restype
|
||||
if errcheck is not None:
|
||||
self.errcheck = errcheck
|
||||
if argtypes is not None:
|
||||
self.argtypes = argtypes
|
||||
self.args = args
|
||||
self.kwargs = kwargs
|
||||
|
||||
def __call__(self, *args, **kwargs):
|
||||
return self.func(*args, **kwargs)
|
||||
|
||||
@cached_property
|
||||
def func(self):
|
||||
from django.contrib.gis.geos.prototypes.threadsafe import GEOSFunc
|
||||
func = GEOSFunc(self.func_name)
|
||||
func.argtypes = self.argtypes or []
|
||||
func.restype = self.restype
|
||||
if self.errcheck:
|
||||
func.errcheck = self.errcheck
|
||||
return func
|
||||
|
||||
|
||||
def geos_version():
|
||||
"""Return the string version of the GEOS library."""
|
||||
return lgeos.GEOSversion()
|
||||
|
||||
|
||||
def geos_version_tuple():
|
||||
"""Return the GEOS version as a tuple (major, minor, subminor)."""
|
||||
return get_version_tuple(geos_version().decode())
|
||||
@@ -0,0 +1,157 @@
|
||||
from ctypes import c_uint
|
||||
|
||||
from django.contrib.gis import gdal
|
||||
from django.contrib.gis.geos import prototypes as capi
|
||||
from django.contrib.gis.geos.error import GEOSException
|
||||
from django.contrib.gis.geos.geometry import GEOSGeometry
|
||||
|
||||
|
||||
class Point(GEOSGeometry):
|
||||
_minlength = 2
|
||||
_maxlength = 3
|
||||
has_cs = True
|
||||
|
||||
def __init__(self, x=None, y=None, z=None, srid=None):
|
||||
"""
|
||||
The Point object may be initialized with either a tuple, or individual
|
||||
parameters.
|
||||
|
||||
For example:
|
||||
>>> p = Point((5, 23)) # 2D point, passed in as a tuple
|
||||
>>> p = Point(5, 23, 8) # 3D point, passed in with individual parameters
|
||||
"""
|
||||
if x is None:
|
||||
coords = []
|
||||
elif isinstance(x, (tuple, list)):
|
||||
# Here a tuple or list was passed in under the `x` parameter.
|
||||
coords = x
|
||||
elif isinstance(x, (float, int)) and isinstance(y, (float, int)):
|
||||
# Here X, Y, and (optionally) Z were passed in individually, as parameters.
|
||||
if isinstance(z, (float, int)):
|
||||
coords = [x, y, z]
|
||||
else:
|
||||
coords = [x, y]
|
||||
else:
|
||||
raise TypeError('Invalid parameters given for Point initialization.')
|
||||
|
||||
point = self._create_point(len(coords), coords)
|
||||
|
||||
# Initializing using the address returned from the GEOS
|
||||
# createPoint factory.
|
||||
super().__init__(point, srid=srid)
|
||||
|
||||
def _to_pickle_wkb(self):
|
||||
return None if self.empty else super()._to_pickle_wkb()
|
||||
|
||||
def _from_pickle_wkb(self, wkb):
|
||||
return self._create_empty() if wkb is None else super()._from_pickle_wkb(wkb)
|
||||
|
||||
def _ogr_ptr(self):
|
||||
return gdal.geometries.Point._create_empty() if self.empty else super()._ogr_ptr()
|
||||
|
||||
@classmethod
|
||||
def _create_empty(cls):
|
||||
return cls._create_point(None, None)
|
||||
|
||||
@classmethod
|
||||
def _create_point(cls, ndim, coords):
|
||||
"""
|
||||
Create a coordinate sequence, set X, Y, [Z], and create point
|
||||
"""
|
||||
if not ndim:
|
||||
return capi.create_point(None)
|
||||
|
||||
if ndim < 2 or ndim > 3:
|
||||
raise TypeError('Invalid point dimension: %s' % ndim)
|
||||
|
||||
cs = capi.create_cs(c_uint(1), c_uint(ndim))
|
||||
i = iter(coords)
|
||||
capi.cs_setx(cs, 0, next(i))
|
||||
capi.cs_sety(cs, 0, next(i))
|
||||
if ndim == 3:
|
||||
capi.cs_setz(cs, 0, next(i))
|
||||
|
||||
return capi.create_point(cs)
|
||||
|
||||
def _set_list(self, length, items):
|
||||
ptr = self._create_point(length, items)
|
||||
if ptr:
|
||||
capi.destroy_geom(self.ptr)
|
||||
self._ptr = ptr
|
||||
self._post_init()
|
||||
else:
|
||||
# can this happen?
|
||||
raise GEOSException('Geometry resulting from slice deletion was invalid.')
|
||||
|
||||
def _set_single(self, index, value):
|
||||
self._cs.setOrdinate(index, 0, value)
|
||||
|
||||
def __iter__(self):
|
||||
"Iterate over coordinates of this Point."
|
||||
for i in range(len(self)):
|
||||
yield self[i]
|
||||
|
||||
def __len__(self):
|
||||
"Return the number of dimensions for this Point (either 0, 2 or 3)."
|
||||
if self.empty:
|
||||
return 0
|
||||
if self.hasz:
|
||||
return 3
|
||||
else:
|
||||
return 2
|
||||
|
||||
def _get_single_external(self, index):
|
||||
if index == 0:
|
||||
return self.x
|
||||
elif index == 1:
|
||||
return self.y
|
||||
elif index == 2:
|
||||
return self.z
|
||||
|
||||
_get_single_internal = _get_single_external
|
||||
|
||||
@property
|
||||
def x(self):
|
||||
"Return the X component of the Point."
|
||||
return self._cs.getOrdinate(0, 0)
|
||||
|
||||
@x.setter
|
||||
def x(self, value):
|
||||
"Set the X component of the Point."
|
||||
self._cs.setOrdinate(0, 0, value)
|
||||
|
||||
@property
|
||||
def y(self):
|
||||
"Return the Y component of the Point."
|
||||
return self._cs.getOrdinate(1, 0)
|
||||
|
||||
@y.setter
|
||||
def y(self, value):
|
||||
"Set the Y component of the Point."
|
||||
self._cs.setOrdinate(1, 0, value)
|
||||
|
||||
@property
|
||||
def z(self):
|
||||
"Return the Z component of the Point."
|
||||
return self._cs.getOrdinate(2, 0) if self.hasz else None
|
||||
|
||||
@z.setter
|
||||
def z(self, value):
|
||||
"Set the Z component of the Point."
|
||||
if not self.hasz:
|
||||
raise GEOSException('Cannot set Z on 2D Point.')
|
||||
self._cs.setOrdinate(2, 0, value)
|
||||
|
||||
# ### Tuple setting and retrieval routines. ###
|
||||
@property
|
||||
def tuple(self):
|
||||
"Return a tuple of the point."
|
||||
return self._cs.tuple
|
||||
|
||||
@tuple.setter
|
||||
def tuple(self, tup):
|
||||
"Set the coordinates of the point with the given tuple."
|
||||
self._cs[0] = tup
|
||||
|
||||
# The tuple and coords properties
|
||||
coords = tuple
|
||||
@@ -0,0 +1,178 @@
|
||||
from ctypes import byref, c_uint
|
||||
|
||||
from django.contrib.gis.geos import prototypes as capi
|
||||
from django.contrib.gis.geos.geometry import GEOSGeometry
|
||||
from django.contrib.gis.geos.libgeos import GEOM_PTR
|
||||
from django.contrib.gis.geos.linestring import LinearRing
|
||||
|
||||
|
||||
class Polygon(GEOSGeometry):
|
||||
_minlength = 1
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
"""
|
||||
Initialize on an exterior ring and a sequence of holes (both
|
||||
instances may be either LinearRing instances, or a tuple/list
|
||||
that may be constructed into a LinearRing).
|
||||
|
||||
Examples of initialization, where shell, hole1, and hole2 are
|
||||
valid LinearRing geometries:
|
||||
>>> from django.contrib.gis.geos import LinearRing, Polygon
|
||||
>>> shell = hole1 = hole2 = LinearRing()
|
||||
>>> poly = Polygon(shell, hole1, hole2)
|
||||
>>> poly = Polygon(shell, (hole1, hole2))
|
||||
|
||||
>>> # Example where a tuple parameters are used:
|
||||
>>> poly = Polygon(((0, 0), (0, 10), (10, 10), (0, 10), (0, 0)),
|
||||
... ((4, 4), (4, 6), (6, 6), (6, 4), (4, 4)))
|
||||
"""
|
||||
if not args:
|
||||
super().__init__(self._create_polygon(0, None), **kwargs)
|
||||
return
|
||||
|
||||
# Getting the ext_ring and init_holes parameters from the argument list
|
||||
ext_ring, *init_holes = args
|
||||
n_holes = len(init_holes)
|
||||
|
||||
# If initialized as Polygon(shell, (LinearRing, LinearRing)) [for backward-compatibility]
|
||||
if n_holes == 1 and isinstance(init_holes[0], (tuple, list)):
|
||||
if not init_holes[0]:
|
||||
init_holes = ()
|
||||
n_holes = 0
|
||||
elif isinstance(init_holes[0][0], LinearRing):
|
||||
init_holes = init_holes[0]
|
||||
n_holes = len(init_holes)
|
||||
|
||||
polygon = self._create_polygon(n_holes + 1, [ext_ring, *init_holes])
|
||||
super().__init__(polygon, **kwargs)
|
||||
|
||||
def __iter__(self):
|
||||
"Iterate over each ring in the polygon."
|
||||
for i in range(len(self)):
|
||||
yield self[i]
|
||||
|
||||
def __len__(self):
|
||||
"Return the number of rings in this Polygon."
|
||||
return self.num_interior_rings + 1
|
||||
|
||||
@classmethod
|
||||
def from_bbox(cls, bbox):
|
||||
"Construct a Polygon from a bounding box (4-tuple)."
|
||||
x0, y0, x1, y1 = bbox
|
||||
for z in bbox:
|
||||
if not isinstance(z, (float, int)):
|
||||
return GEOSGeometry('POLYGON((%s %s, %s %s, %s %s, %s %s, %s %s))' %
|
||||
(x0, y0, x0, y1, x1, y1, x1, y0, x0, y0))
|
||||
return Polygon(((x0, y0), (x0, y1), (x1, y1), (x1, y0), (x0, y0)))
|
||||
|
||||
# ### These routines are needed for list-like operation w/ListMixin ###
|
||||
def _create_polygon(self, length, items):
|
||||
# Instantiate LinearRing objects if necessary, but don't clone them yet
|
||||
# _construct_ring will throw a TypeError if a parameter isn't a valid ring
|
||||
# If we cloned the pointers here, we wouldn't be able to clean up
|
||||
# in case of error.
|
||||
if not length:
|
||||
return capi.create_empty_polygon()
|
||||
|
||||
rings = []
|
||||
for r in items:
|
||||
if isinstance(r, GEOM_PTR):
|
||||
rings.append(r)
|
||||
else:
|
||||
rings.append(self._construct_ring(r))
|
||||
|
||||
shell = self._clone(rings.pop(0))
|
||||
|
||||
n_holes = length - 1
|
||||
if n_holes:
|
||||
holes = (GEOM_PTR * n_holes)(*[self._clone(r) for r in rings])
|
||||
holes_param = byref(holes)
|
||||
else:
|
||||
holes_param = None
|
||||
|
||||
return capi.create_polygon(shell, holes_param, c_uint(n_holes))
|
||||
|
||||
def _clone(self, g):
|
||||
if isinstance(g, GEOM_PTR):
|
||||
return capi.geom_clone(g)
|
||||
else:
|
||||
return capi.geom_clone(g.ptr)
|
||||
|
||||
def _construct_ring(self, param, msg=(
|
||||
'Parameter must be a sequence of LinearRings or objects that can initialize to LinearRings')):
|
||||
"Try to construct a ring from the given parameter."
|
||||
if isinstance(param, LinearRing):
|
||||
return param
|
||||
try:
|
||||
ring = LinearRing(param)
|
||||
return ring
|
||||
except TypeError:
|
||||
raise TypeError(msg)
|
||||
|
||||
def _set_list(self, length, items):
|
||||
# Getting the current pointer, replacing with the newly constructed
|
||||
# geometry, and destroying the old geometry.
|
||||
prev_ptr = self.ptr
|
||||
srid = self.srid
|
||||
self.ptr = self._create_polygon(length, items)
|
||||
if srid:
|
||||
self.srid = srid
|
||||
capi.destroy_geom(prev_ptr)
|
||||
|
||||
def _get_single_internal(self, index):
|
||||
"""
|
||||
Return the ring at the specified index. The first index, 0, will
|
||||
always return the exterior ring. Indices > 0 will return the
|
||||
interior ring at the given index (e.g., poly[1] and poly[2] would
|
||||
return the first and second interior ring, respectively).
|
||||
|
||||
CAREFUL: Internal/External are not the same as Interior/Exterior!
|
||||
Return a pointer from the existing geometries for use internally by the
|
||||
object's methods. _get_single_external() returns a clone of the same
|
||||
geometry for use by external code.
|
||||
"""
|
||||
if index == 0:
|
||||
return capi.get_extring(self.ptr)
|
||||
else:
|
||||
# Getting the interior ring, have to subtract 1 from the index.
|
||||
return capi.get_intring(self.ptr, index - 1)
|
||||
|
||||
def _get_single_external(self, index):
|
||||
return GEOSGeometry(capi.geom_clone(self._get_single_internal(index)), srid=self.srid)
|
||||
|
||||
_set_single = GEOSGeometry._set_single_rebuild
|
||||
_assign_extended_slice = GEOSGeometry._assign_extended_slice_rebuild
|
||||
|
||||
# #### Polygon Properties ####
|
||||
@property
|
||||
def num_interior_rings(self):
|
||||
"Return the number of interior rings."
|
||||
# Getting the number of rings
|
||||
return capi.get_nrings(self.ptr)
|
||||
|
||||
def _get_ext_ring(self):
|
||||
"Get the exterior ring of the Polygon."
|
||||
return self[0]
|
||||
|
||||
def _set_ext_ring(self, ring):
|
||||
"Set the exterior ring of the Polygon."
|
||||
self[0] = ring
|
||||
|
||||
# Properties for the exterior ring/shell.
|
||||
exterior_ring = property(_get_ext_ring, _set_ext_ring)
|
||||
shell = exterior_ring
|
||||
|
||||
@property
|
||||
def tuple(self):
|
||||
"Get the tuple for each ring in this Polygon."
|
||||
return tuple(self[i].tuple for i in range(len(self)))
|
||||
coords = tuple
|
||||
|
||||
@property
|
||||
def kml(self):
|
||||
"Return the KML representation of this Polygon."
|
||||
inner_kml = ''.join(
|
||||
"<innerBoundaryIs>%s</innerBoundaryIs>" % self[i + 1].kml
|
||||
for i in range(self.num_interior_rings)
|
||||
)
|
||||
return "<Polygon><outerBoundaryIs>%s</outerBoundaryIs>%s</Polygon>" % (self[0].kml, inner_kml)
|
||||
@@ -0,0 +1,49 @@
|
||||
from .base import GEOSBase
|
||||
from .prototypes import prepared as capi
|
||||
|
||||
|
||||
class PreparedGeometry(GEOSBase):
|
||||
"""
|
||||
A geometry that is prepared for performing certain operations.
|
||||
At the moment this includes the contains covers, and intersects
|
||||
operations.
|
||||
"""
|
||||
ptr_type = capi.PREPGEOM_PTR
|
||||
destructor = capi.prepared_destroy
|
||||
|
||||
def __init__(self, geom):
|
||||
# Keeping a reference to the original geometry object to prevent it
|
||||
# from being garbage collected which could then crash the prepared one
|
||||
# See #21662
|
||||
self._base_geom = geom
|
||||
from .geometry import GEOSGeometry
|
||||
if not isinstance(geom, GEOSGeometry):
|
||||
raise TypeError
|
||||
self.ptr = capi.geos_prepare(geom.ptr)
|
||||
|
||||
def contains(self, other):
|
||||
return capi.prepared_contains(self.ptr, other.ptr)
|
||||
|
||||
def contains_properly(self, other):
|
||||
return capi.prepared_contains_properly(self.ptr, other.ptr)
|
||||
|
||||
def covers(self, other):
|
||||
return capi.prepared_covers(self.ptr, other.ptr)
|
||||
|
||||
def intersects(self, other):
|
||||
return capi.prepared_intersects(self.ptr, other.ptr)
|
||||
|
||||
def crosses(self, other):
|
||||
return capi.prepared_crosses(self.ptr, other.ptr)
|
||||
|
||||
def disjoint(self, other):
|
||||
return capi.prepared_disjoint(self.ptr, other.ptr)
|
||||
|
||||
def overlaps(self, other):
|
||||
return capi.prepared_overlaps(self.ptr, other.ptr)
|
||||
|
||||
def touches(self, other):
|
||||
return capi.prepared_touches(self.ptr, other.ptr)
|
||||
|
||||
def within(self, other):
|
||||
return capi.prepared_within(self.ptr, other.ptr)
|
||||
@@ -0,0 +1,25 @@
|
||||
"""
|
||||
This module contains all of the GEOS ctypes function prototypes. Each
|
||||
prototype handles the interaction between the GEOS library and Python
|
||||
via ctypes.
|
||||
"""
|
||||
|
||||
from django.contrib.gis.geos.prototypes.coordseq import ( # NOQA
|
||||
create_cs, cs_clone, cs_getdims, cs_getordinate, cs_getsize, cs_getx,
|
||||
cs_gety, cs_getz, cs_setordinate, cs_setx, cs_sety, cs_setz, get_cs,
|
||||
)
|
||||
from django.contrib.gis.geos.prototypes.geom import ( # NOQA
|
||||
create_collection, create_empty_polygon, create_linearring,
|
||||
create_linestring, create_point, create_polygon, destroy_geom, geom_clone,
|
||||
geos_get_srid, geos_normalize, geos_set_srid, geos_type, geos_typeid,
|
||||
get_dims, get_extring, get_geomn, get_intring, get_nrings, get_num_coords,
|
||||
get_num_geoms,
|
||||
)
|
||||
from django.contrib.gis.geos.prototypes.misc import * # NOQA
|
||||
from django.contrib.gis.geos.prototypes.predicates import ( # NOQA
|
||||
geos_contains, geos_covers, geos_crosses, geos_disjoint, geos_equals,
|
||||
geos_equalsexact, geos_hasz, geos_intersects, geos_isclosed, geos_isempty,
|
||||
geos_isring, geos_issimple, geos_isvalid, geos_overlaps,
|
||||
geos_relatepattern, geos_touches, geos_within,
|
||||
)
|
||||
from django.contrib.gis.geos.prototypes.topology import * # NOQA
|
||||
@@ -0,0 +1,91 @@
|
||||
from ctypes import POINTER, c_double, c_int, c_uint
|
||||
|
||||
from django.contrib.gis.geos.libgeos import CS_PTR, GEOM_PTR, GEOSFuncFactory
|
||||
from django.contrib.gis.geos.prototypes.errcheck import (
|
||||
GEOSException, last_arg_byref,
|
||||
)
|
||||
|
||||
|
||||
# ## Error-checking routines specific to coordinate sequences. ##
|
||||
def check_cs_op(result, func, cargs):
|
||||
"Check the status code of a coordinate sequence operation."
|
||||
if result == 0:
|
||||
raise GEOSException('Could not set value on coordinate sequence')
|
||||
else:
|
||||
return result
|
||||
|
||||
|
||||
def check_cs_get(result, func, cargs):
|
||||
"Check the coordinate sequence retrieval."
|
||||
check_cs_op(result, func, cargs)
|
||||
# Object in by reference, return its value.
|
||||
return last_arg_byref(cargs)
|
||||
|
||||
|
||||
# ## Coordinate sequence prototype factory classes. ##
|
||||
class CsInt(GEOSFuncFactory):
|
||||
"For coordinate sequence routines that return an integer."
|
||||
argtypes = [CS_PTR, POINTER(c_uint)]
|
||||
restype = c_int
|
||||
errcheck = staticmethod(check_cs_get)
|
||||
|
||||
|
||||
class CsOperation(GEOSFuncFactory):
|
||||
"For coordinate sequence operations."
|
||||
restype = c_int
|
||||
|
||||
def __init__(self, *args, ordinate=False, get=False, **kwargs):
|
||||
if get:
|
||||
# Get routines have double parameter passed-in by reference.
|
||||
errcheck = check_cs_get
|
||||
dbl_param = POINTER(c_double)
|
||||
else:
|
||||
errcheck = check_cs_op
|
||||
dbl_param = c_double
|
||||
|
||||
if ordinate:
|
||||
# Get/Set ordinate routines have an extra uint parameter.
|
||||
argtypes = [CS_PTR, c_uint, c_uint, dbl_param]
|
||||
else:
|
||||
argtypes = [CS_PTR, c_uint, dbl_param]
|
||||
|
||||
super().__init__(*args, **{**kwargs, 'errcheck': errcheck, 'argtypes': argtypes})
|
||||
|
||||
|
||||
class CsOutput(GEOSFuncFactory):
|
||||
restype = CS_PTR
|
||||
|
||||
@staticmethod
|
||||
def errcheck(result, func, cargs):
|
||||
if not result:
|
||||
raise GEOSException(
|
||||
'Error encountered checking Coordinate Sequence returned from GEOS '
|
||||
'C function "%s".' % func.__name__
|
||||
)
|
||||
return result
|
||||
|
||||
|
||||
# ## Coordinate Sequence ctypes prototypes ##
|
||||
|
||||
# Coordinate Sequence constructors & cloning.
|
||||
cs_clone = CsOutput('GEOSCoordSeq_clone', argtypes=[CS_PTR])
|
||||
create_cs = CsOutput('GEOSCoordSeq_create', argtypes=[c_uint, c_uint])
|
||||
get_cs = CsOutput('GEOSGeom_getCoordSeq', argtypes=[GEOM_PTR])
|
||||
|
||||
# Getting, setting ordinate
|
||||
cs_getordinate = CsOperation('GEOSCoordSeq_getOrdinate', ordinate=True, get=True)
|
||||
cs_setordinate = CsOperation('GEOSCoordSeq_setOrdinate', ordinate=True)
|
||||
|
||||
# For getting, x, y, z
|
||||
cs_getx = CsOperation('GEOSCoordSeq_getX', get=True)
|
||||
cs_gety = CsOperation('GEOSCoordSeq_getY', get=True)
|
||||
cs_getz = CsOperation('GEOSCoordSeq_getZ', get=True)
|
||||
|
||||
# For setting, x, y, z
|
||||
cs_setx = CsOperation('GEOSCoordSeq_setX')
|
||||
cs_sety = CsOperation('GEOSCoordSeq_setY')
|
||||
cs_setz = CsOperation('GEOSCoordSeq_setZ')
|
||||
|
||||
# These routines return size & dimensions.
|
||||
cs_getsize = CsInt('GEOSCoordSeq_getSize')
|
||||
cs_getdims = CsInt('GEOSCoordSeq_getDimensions')
|
||||
@@ -0,0 +1,83 @@
|
||||
"""
|
||||
Error checking functions for GEOS ctypes prototype functions.
|
||||
"""
|
||||
from ctypes import c_void_p, string_at
|
||||
|
||||
from django.contrib.gis.geos.error import GEOSException
|
||||
from django.contrib.gis.geos.libgeos import GEOSFuncFactory
|
||||
|
||||
# Getting the `free` routine used to free the memory allocated for
|
||||
# string pointers returned by GEOS.
|
||||
free = GEOSFuncFactory('GEOSFree')
|
||||
free.argtypes = [c_void_p]
|
||||
|
||||
|
||||
def last_arg_byref(args):
|
||||
"Return the last C argument's value by reference."
|
||||
return args[-1]._obj.value
|
||||
|
||||
|
||||
def check_dbl(result, func, cargs):
|
||||
"Check the status code and returns the double value passed in by reference."
|
||||
# Checking the status code
|
||||
if result != 1:
|
||||
return None
|
||||
# Double passed in by reference, return its value.
|
||||
return last_arg_byref(cargs)
|
||||
|
||||
|
||||
def check_geom(result, func, cargs):
|
||||
"Error checking on routines that return Geometries."
|
||||
if not result:
|
||||
raise GEOSException('Error encountered checking Geometry returned from GEOS C function "%s".' % func.__name__)
|
||||
return result
|
||||
|
||||
|
||||
def check_minus_one(result, func, cargs):
|
||||
"Error checking on routines that should not return -1."
|
||||
if result == -1:
|
||||
raise GEOSException('Error encountered in GEOS C function "%s".' % func.__name__)
|
||||
else:
|
||||
return result
|
||||
|
||||
|
||||
def check_predicate(result, func, cargs):
|
||||
"Error checking for unary/binary predicate functions."
|
||||
if result == 1:
|
||||
return True
|
||||
elif result == 0:
|
||||
return False
|
||||
else:
|
||||
raise GEOSException('Error encountered on GEOS C predicate function "%s".' % func.__name__)
|
||||
|
||||
|
||||
def check_sized_string(result, func, cargs):
|
||||
"""
|
||||
Error checking for routines that return explicitly sized strings.
|
||||
|
||||
This frees the memory allocated by GEOS at the result pointer.
|
||||
"""
|
||||
if not result:
|
||||
raise GEOSException('Invalid string pointer returned by GEOS C function "%s"' % func.__name__)
|
||||
# A c_size_t object is passed in by reference for the second
|
||||
# argument on these routines, and its needed to determine the
|
||||
# correct size.
|
||||
s = string_at(result, last_arg_byref(cargs))
|
||||
# Freeing the memory allocated within GEOS
|
||||
free(result)
|
||||
return s
|
||||
|
||||
|
||||
def check_string(result, func, cargs):
|
||||
"""
|
||||
Error checking for routines that return strings.
|
||||
|
||||
This frees the memory allocated by GEOS at the result pointer.
|
||||
"""
|
||||
if not result:
|
||||
raise GEOSException('Error encountered checking string return value in GEOS C function "%s".' % func.__name__)
|
||||
# Getting the string value at the pointer address.
|
||||
s = string_at(result)
|
||||
# Freeing the memory allocated within GEOS
|
||||
free(result)
|
||||
return s
|
||||
@@ -0,0 +1,31 @@
|
||||
"""
|
||||
This module is for the miscellaneous GEOS routines, particularly the
|
||||
ones that return the area, distance, and length.
|
||||
"""
|
||||
from ctypes import POINTER, c_double, c_int
|
||||
|
||||
from django.contrib.gis.geos.libgeos import GEOM_PTR, GEOSFuncFactory
|
||||
from django.contrib.gis.geos.prototypes.errcheck import check_dbl, check_string
|
||||
from django.contrib.gis.geos.prototypes.geom import geos_char_p
|
||||
|
||||
__all__ = ['geos_area', 'geos_distance', 'geos_length', 'geos_isvalidreason']
|
||||
|
||||
|
||||
class DblFromGeom(GEOSFuncFactory):
|
||||
"""
|
||||
Argument is a Geometry, return type is double that is passed
|
||||
in by reference as the last argument.
|
||||
"""
|
||||
restype = c_int # Status code returned
|
||||
errcheck = staticmethod(check_dbl)
|
||||
|
||||
|
||||
# ### ctypes prototypes ###
|
||||
|
||||
# Area, distance, and length prototypes.
|
||||
geos_area = DblFromGeom('GEOSArea', argtypes=[GEOM_PTR, POINTER(c_double)])
|
||||
geos_distance = DblFromGeom('GEOSDistance', argtypes=[GEOM_PTR, GEOM_PTR, POINTER(c_double)])
|
||||
geos_length = DblFromGeom('GEOSLength', argtypes=[GEOM_PTR, POINTER(c_double)])
|
||||
geos_isvalidreason = GEOSFuncFactory(
|
||||
'GEOSisValidReason', restype=geos_char_p, errcheck=check_string, argtypes=[GEOM_PTR]
|
||||
)
|
||||
@@ -0,0 +1,28 @@
|
||||
from ctypes import c_byte
|
||||
|
||||
from django.contrib.gis.geos.libgeos import (
|
||||
GEOM_PTR, PREPGEOM_PTR, GEOSFuncFactory,
|
||||
)
|
||||
from django.contrib.gis.geos.prototypes.errcheck import check_predicate
|
||||
|
||||
# Prepared geometry constructor and destructors.
|
||||
geos_prepare = GEOSFuncFactory('GEOSPrepare', argtypes=[GEOM_PTR], restype=PREPGEOM_PTR)
|
||||
prepared_destroy = GEOSFuncFactory('GEOSPreparedGeom_destroy', argtypes=[PREPGEOM_PTR])
|
||||
|
||||
|
||||
# Prepared geometry binary predicate support.
|
||||
class PreparedPredicate(GEOSFuncFactory):
|
||||
argtypes = [PREPGEOM_PTR, GEOM_PTR]
|
||||
restype = c_byte
|
||||
errcheck = staticmethod(check_predicate)
|
||||
|
||||
|
||||
prepared_contains = PreparedPredicate('GEOSPreparedContains')
|
||||
prepared_contains_properly = PreparedPredicate('GEOSPreparedContainsProperly')
|
||||
prepared_covers = PreparedPredicate('GEOSPreparedCovers')
|
||||
prepared_crosses = PreparedPredicate('GEOSPreparedCrosses')
|
||||
prepared_disjoint = PreparedPredicate('GEOSPreparedDisjoint')
|
||||
prepared_intersects = PreparedPredicate('GEOSPreparedIntersects')
|
||||
prepared_overlaps = PreparedPredicate('GEOSPreparedOverlaps')
|
||||
prepared_touches = PreparedPredicate('GEOSPreparedTouches')
|
||||
prepared_within = PreparedPredicate('GEOSPreparedWithin')
|
||||
@@ -0,0 +1,77 @@
|
||||
import threading
|
||||
|
||||
from django.contrib.gis.geos.base import GEOSBase
|
||||
from django.contrib.gis.geos.libgeos import (
|
||||
CONTEXT_PTR, error_h, lgeos, notice_h,
|
||||
)
|
||||
|
||||
|
||||
class GEOSContextHandle(GEOSBase):
|
||||
"""Represent a GEOS context handle."""
|
||||
ptr_type = CONTEXT_PTR
|
||||
destructor = lgeos.finishGEOS_r
|
||||
|
||||
def __init__(self):
|
||||
# Initializing the context handler for this thread with
|
||||
# the notice and error handler.
|
||||
self.ptr = lgeos.initGEOS_r(notice_h, error_h)
|
||||
|
||||
|
||||
# Defining a thread-local object and creating an instance
|
||||
# to hold a reference to GEOSContextHandle for this thread.
|
||||
class GEOSContext(threading.local):
|
||||
handle = None
|
||||
|
||||
|
||||
thread_context = GEOSContext()
|
||||
|
||||
|
||||
class GEOSFunc:
|
||||
"""
|
||||
Serve as a wrapper for GEOS C Functions. Use thread-safe function
|
||||
variants when available.
|
||||
"""
|
||||
def __init__(self, func_name):
|
||||
# GEOS thread-safe function signatures end with '_r' and take an
|
||||
# additional context handle parameter.
|
||||
self.cfunc = getattr(lgeos, func_name + '_r')
|
||||
# Create a reference to thread_context so it's not garbage-collected
|
||||
# before an attempt to call this object.
|
||||
self.thread_context = thread_context
|
||||
|
||||
def __call__(self, *args):
|
||||
# Create a context handle if one doesn't exist for this thread.
|
||||
self.thread_context.handle = self.thread_context.handle or GEOSContextHandle()
|
||||
# Call the threaded GEOS routine with the pointer of the context handle
|
||||
# as the first argument.
|
||||
return self.cfunc(self.thread_context.handle.ptr, *args)
|
||||
|
||||
def __str__(self):
|
||||
return self.cfunc.__name__
|
||||
|
||||
# argtypes property
|
||||
def _get_argtypes(self):
|
||||
return self.cfunc.argtypes
|
||||
|
||||
def _set_argtypes(self, argtypes):
|
||||
self.cfunc.argtypes = [CONTEXT_PTR, *argtypes]
|
||||
|
||||
argtypes = property(_get_argtypes, _set_argtypes)
|
||||
|
||||
# restype property
|
||||
def _get_restype(self):
|
||||
return self.cfunc.restype
|
||||
|
||||
def _set_restype(self, restype):
|
||||
self.cfunc.restype = restype
|
||||
|
||||
restype = property(_get_restype, _set_restype)
|
||||
|
||||
# errcheck property
|
||||
def _get_errcheck(self):
|
||||
return self.cfunc.errcheck
|
||||
|
||||
def _set_errcheck(self, errcheck):
|
||||
self.cfunc.errcheck = errcheck
|
||||
|
||||
errcheck = property(_get_errcheck, _set_errcheck)
|
||||
Reference in new issue
Block a user