def transform(self, ct, clone=False): """ Requires GDAL. Transforms the geometry according to the given transformation object, which may be an integer SRID, and WKT or PROJ.4 string. By default, the geometry is transformed in-place and nothing is returned. However if the `clone` keyword is set, then this geometry will not be modified and a transformed clone will be returned instead. """ srid = self.srid if ct == srid: # short-circuit where source & dest SRIDs match if clone: return self.clone() else: return if (srid is None) or (srid < 0): raise GEOSException( "Calling transform() with no SRID set is not supported") if not gdal.HAS_GDAL: raise GEOSException( "GDAL library is not available to transform() geometry.") # Creating an OGR Geometry, which is then transformed. g = self.ogr g.transform(ct) # Getting a new GEOS pointer ptr = wkb_r().read(g.wkb) if clone: # User wants a cloned transformed geometry returned. return GEOSGeometry(ptr, srid=g.srid) if ptr: # Reassigning pointer, and performing post-initialization setup # again due to the reassignment. capi.destroy_geom(self.ptr) self.ptr = ptr self._post_init(g.srid) else: raise GEOSException('Transformed WKB was invalid.')
def transform(self, ct, clone=False): """ Requires GDAL. Transform the geometry according to the given transformation object, which may be an integer SRID, and WKT or PROJ.4 string. By default, transform the geometry in-place and return nothing. However if the `clone` keyword is set, don't modify the geometry and return a transformed clone instead. """ srid = self.srid if ct == srid: # short-circuit where source & dest SRIDs match if clone: return self.clone() else: return if isinstance(ct, gdal.CoordTransform): # We don't care about SRID because CoordTransform presupposes # source SRS. srid = None elif srid is None or srid < 0: raise GEOSException( "Calling transform() with no SRID set is not supported") # Creating an OGR Geometry, which is then transformed. g = gdal.OGRGeometry(self._ogr_ptr(), srid) g.transform(ct) # Getting a new GEOS pointer ptr = g._geos_ptr() if clone: # User wants a cloned transformed geometry returned. return GEOSGeometry(ptr, srid=g.srid) if ptr: # Reassigning pointer, and performing post-initialization setup # again due to the reassignment. capi.destroy_geom(self.ptr) self.ptr = ptr self._post_init() self.srid = g.srid else: raise GEOSException("Transformed WKB was invalid.")
def __init__(self, geo_input, srid=None): """ The base constructor for GEOS geometry objects, and may take the following inputs: * strings: - WKT - HEXEWKB (a PostGIS-specific canonical form) - GeoJSON (requires GDAL) * buffer: - WKB The `srid` keyword is used to specify the Source Reference Identifier (SRID) number for this Geometry. If not set, the SRID will be None. """ if isinstance(geo_input, bytes): geo_input = force_text(geo_input) if isinstance(geo_input, six.string_types): wkt_m = wkt_regex.match(geo_input) if wkt_m: # Handling WKT input. if wkt_m.group('srid'): srid = int(wkt_m.group('srid')) g = wkt_r().read(force_bytes(wkt_m.group('wkt'))) elif hex_regex.match(geo_input): # Handling HEXEWKB input. g = wkb_r().read(force_bytes(geo_input)) elif json_regex.match(geo_input): # Handling GeoJSON input. if not gdal.HAS_GDAL: raise ValueError('Initializing geometry from JSON input requires GDAL.') g = wkb_r().read(gdal.OGRGeometry(geo_input).wkb) else: raise ValueError('String or unicode input unrecognized as WKT EWKT, and HEXEWKB.') elif isinstance(geo_input, GEOM_PTR): # When the input is a pointer to a geometry (GEOM_PTR). g = geo_input elif isinstance(geo_input, six.memoryview): # When the input is a buffer (WKB). g = wkb_r().read(geo_input) elif isinstance(geo_input, GEOSGeometry): g = capi.geom_clone(geo_input.ptr) else: # Invalid geometry type. raise TypeError('Improper geometry input type: %s' % str(type(geo_input))) if g: # Setting the pointer object with a valid pointer. self.ptr = g else: raise GEOSException('Could not initialize GEOS Geometry with given input.') # Post-initialization setup. self._post_init(srid)
def geos_version_info(): """ Returns a dictionary containing the various version metadata parsed from the GEOS version string, including the version number, whether the version is a release candidate (and what number release candidate), and the C API version. """ ver = geos_version().decode() m = version_regex.match(ver) if not m: raise GEOSException('Could not parse version info string "%s"' % ver) return dict((key, m.group(key)) for key in ('version', 'release_candidate', 'capi_version', 'major', 'minor', 'subminor'))
def check_predicate(result, func, cargs): "Error checking for unary/binary predicate functions." val = ord(result) # getting the ordinal from the character if val == 1: return True elif val == 0: return False else: raise GEOSException( 'Error encountered on GEOS C predicate function "%s".' % func.__name__)
def __init__(self, geo_input, srid=None): """ The base constructor for GEOS geometry objects, and may take the following inputs: * string: WKT * string: HEXEWKB (a PostGIS-specific canonical form) * buffer: WKB The `srid` keyword is used to specify the Source Reference Identifier (SRID) number for this Geometry. If not set, the SRID will be None. """ if isinstance(geo_input, basestring): if isinstance(geo_input, UnicodeType): # Encoding to ASCII, WKT or HEXEWKB doesn't need any more. geo_input = geo_input.encode('ascii') wkt_m = wkt_regex.match(geo_input) if wkt_m: # Handling WKT input. if wkt_m.group('srid'): srid = int(wkt_m.group('srid')) g = from_wkt(wkt_m.group('wkt')) elif hex_regex.match(geo_input): # Handling HEXEWKB input. g = from_hex(geo_input, len(geo_input)) elif GEOJSON and json_regex.match(geo_input): # Handling GeoJSON input. wkb_input = str(OGRGeometry(geo_input).wkb) g = from_wkb(wkb_input, len(wkb_input)) else: raise ValueError( 'String or unicode input unrecognized as WKT EWKT, and HEXEWKB.' ) elif isinstance(geo_input, GEOM_PTR): # When the input is a pointer to a geomtry (GEOM_PTR). g = geo_input elif isinstance(geo_input, buffer): # When the input is a buffer (WKB). wkb_input = str(geo_input) g = from_wkb(wkb_input, len(wkb_input)) else: # Invalid geometry type. raise TypeError('Improper geometry input type: %s' % str(type(geo_input))) if bool(g): # Setting the pointer object with a valid pointer. self._ptr = g else: raise GEOSException( 'Could not initialize GEOS Geometry with given input.') # Post-initialization setup. self._post_init(srid)
def ptr(self): """ Property for controlling access to the GEOS geometry pointer. Using this raises an exception when the pointer is NULL, thus preventing the C library from attempting to access an invalid memory location. """ if self._ptr: return self._ptr else: raise GEOSException( 'NULL GEOS pointer encountered; was this geometry modified?')
def srs(self): "Returns the OSR SpatialReference for SRID of this Geometry." if not gdal.HAS_GDAL: raise GEOSException( 'GDAL required to return a SpatialReference object.') if self.srid: try: return gdal.SpatialReference(self.srid) except SRSException: pass return None
def _set_list(self, length, items): ptr = self._create_point(length, items) if ptr: srid = self.srid capi.destroy_geom(self.ptr) self._ptr = ptr if srid is not None: self.srid = srid self._post_init() else: # can this happen? raise GEOSException('Geometry resulting from slice deletion was invalid.')
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 libc.free(result) return s
def hexewkb(self): """ Returns the EWKB of this Geometry in hexadecimal form. This is an extension of the WKB specification that includes SRID and Z values that are a part of this geometry. """ if self.hasz: if not GEOS_PREPARE: # See: http://trac.osgeo.org/geos/ticket/216 raise GEOSException('Upgrade GEOS to 3.1 to get valid 3D HEXEWKB.') return ewkb_w3d().write_hex(self) else: return ewkb_w().write_hex(self)
def ewkb(self): """ Return the EWKB representation of this Geometry as a Python buffer. This is an extension of the WKB specification that includes any SRID and Z values that are a part of this geometry. """ if self.hasz: if not GEOS_PREPARE: # See: http://trac.osgeo.org/geos/ticket/216 raise GEOSException('Upgrade GEOS to 3.1 to get valid 3D EWKB.') return ewkb_w3d().write(self) else: return ewkb_w().write(self)
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 _set_list(self, length, items): ndim = self._cs.dims hasz = self._cs.hasz # I don't understand why these are different # create a new coordinate sequence and populate accordingly cs = GEOSCoordSeq(capi.create_cs(length, ndim), z=hasz) for i, c in enumerate(items): cs[i] = c ptr = self._init_func(cs.ptr) if ptr: capi.destroy_geom(self.ptr) self.ptr = ptr self._post_init(self.srid) else: # can this happen? raise GEOSException('Geometry resulting from slice deletion was invalid.')
def is_counterclockwise(self): """Return whether this coordinate sequence is counterclockwise.""" if geos_version_tuple() < (3, 7): # A modified shoelace algorithm to determine polygon orientation. # See https://en.wikipedia.org/wiki/Shoelace_formula. area = 0.0 n = len(self) for i in range(n): j = (i + 1) % n area += self[i][0] * self[j][1] area -= self[j][0] * self[i][1] return area > 0.0 ret = c_byte() if not capi.cs_is_ccw(self.ptr, byref(ret)): raise GEOSException('Error encountered in GEOS C function "%s".' % capi.cs_is_ccw.func_name) return ret.value == 1
def create_dive(self, geometry, name, depth, practice, structure, verbosity, eid): if geometry.geom_type != 'Point': raise GEOSException('Invalid Geometry type.') with transaction.atomic(): fields_without_eid = { 'name': name, 'depth': depth, 'practice': practice, 'geom': Point(geometry.x, geometry.y, srid=settings.SRID), } if eid: dive, created = Dive.objects.update_or_create( eid=eid, defaults=fields_without_eid) if verbosity > 0 and not created: self.stdout.write("Update : %s with eid %s" % (name, eid)) else: dive = Dive.objects.create(**fields_without_eid) self.counter += 1 return dive
def _checkdim(self, dim): "Check the given dimension." if dim < 0 or dim > 2: raise GEOSException('invalid ordinate dimension "%d"' % dim)
def closed(self): if geos_version_info()['version'] < '3.5': raise GEOSException( "MultiLineString.closed requires GEOS >= 3.5.0.") return super(MultiLineString, self).closed
cs = GEOSCoordSeq(capi.create_cs(length, ndim), z=hasz) for i, c in enumerate(items): cs[i] = c ptr = self._init_func(cs.ptr) if ptr: capi.destroy_geom(self.ptr) self.ptr = ptr <<<<<<< HEAD self._post_init(self.srid) ======= self._post_init() >>>>>>> 37c99181c9a6b95433d60f8c8ef9af5731096435 else: # can this happen? raise GEOSException('Geometry resulting from slice deletion was invalid.') def _set_single(self, index, value): <<<<<<< HEAD self._checkindex(index) ======= >>>>>>> 37c99181c9a6b95433d60f8c8ef9af5731096435 self._cs[index] = value def _checkdim(self, dim): if dim not in (2, 3): raise TypeError('Dimension mismatch.') # #### Sequence Properties #### @property def tuple(self):
def closed(self): if geos_version_tuple() < (3, 5): raise GEOSException( "MultiLineString.closed requires GEOS >= 3.5.0.") return super().closed
def update_bbox_extent(self, trigger, geometry, original_geometry, item): '''Updates the collection's spatial extent if needed when an item is updated. This function generates a new extent regarding all the items with the same collection foreign key. If there is no spatial bbox yet, the one of the geometry of the item is being used. Args: trigger: str Item trigger event, one of 'insert', 'update' or 'delete' geometry: GeometryField the geometry of the item original_geometry: the original geometry during an updated or None item: Item the item being treated Returns: bool: True if the collection temporal extent has been updated, false otherwise ''' updated = False try: # insert (as item_id is None) if trigger == 'insert': # the first item of this collection if self.extent_geometry is None: logger.info( 'Set collections extent_geometry with geometry %s, ' 'triggered by the first item insertion', GEOSGeometry(geometry).extent, extra={ 'collection': self.name, 'item': item.name, 'trigger': 'item-insert' }, ) self.extent_geometry = Polygon.from_bbox( GEOSGeometry(geometry).extent) # there is already a geometry in the collection a union of the geometries else: logger.info( 'Updating collections extent_geometry with geometry %s, ' 'triggered by an item insertion', GEOSGeometry(geometry).extent, extra={ 'collection': self.name, 'item': item.name, 'trigger': 'item-insert' }, ) self.extent_geometry = Polygon.from_bbox( GEOSGeometry(self.extent_geometry).union( GEOSGeometry(geometry)).extent) updated |= True # update if trigger == 'update' and geometry != original_geometry: # is the new bbox larger than (and covering) the existing if Polygon.from_bbox(GEOSGeometry(geometry).extent).covers( self.extent_geometry): logger.info( 'Updating collections extent_geometry with item geometry changed ' 'from %s to %s, (larger and covering bbox)', GEOSGeometry(original_geometry).extent, GEOSGeometry(geometry).extent, extra={ 'collection': self.name, 'item': item.name, 'trigger': 'item-update' }, ) self.extent_geometry = Polygon.from_bbox( GEOSGeometry(geometry).extent) # we need to iterate trough the items else: logger.warning( 'Updating collections extent_geometry with item geometry changed ' 'from %s to %s. We need to loop over all items of the collection, ' 'this may take a while !', GEOSGeometry(original_geometry).extent, GEOSGeometry(geometry).extent, extra={ 'collection': self.name, 'item': item.name, 'trigger': 'item-update' }, ) start = time.time() bbox_other_items = type(item).objects.filter( collection_id=self.pk).exclude(id=item.pk).only( 'geometry', 'collection').aggregate(Extent('geometry')) geometry_updated_item = GEOSGeometry(geometry) if bool(bbox_other_items['geometry__extent']): geometry_other_items = GEOSGeometry( Polygon.from_bbox( bbox_other_items['geometry__extent'])) self.extent_geometry = Polygon.from_bbox( geometry_updated_item.union( geometry_other_items).extent) else: self.extent_geometry = geometry_updated_item logger.info( 'Collection extent_geometry updated to %s in %ss, after item update', self.extent_geometry.extent, time.time() - start, extra={ 'collection': self.name, 'item': item.name, 'trigger': 'item-update' }, ) updated |= True # delete, we need to iterate trough the items if trigger == 'delete': logger.warning( 'Updating collections extent_geometry with removal of item geometry %s. ' 'We need to loop over all items of the collection, this may take a while !', GEOSGeometry(geometry).extent, extra={ 'collection': self.name, 'item': item.name, 'trigger': 'item-delete' }, ) start = time.time() bbox_other_items = type(item).objects.filter( collection_id=self.pk).exclude(id=item.pk).only( 'geometry', 'collection').aggregate(Extent('geometry')) if bool(bbox_other_items['geometry__extent']): self.extent_geometry = GEOSGeometry( Polygon.from_bbox( bbox_other_items['geometry__extent'])) else: self.extent_geometry = None logger.info( 'Collection extent_geometry updated to %s in %ss, after item deletion', self.extent_geometry.extent if self.extent_geometry else None, time.time() - start, extra={ 'collection': self.name, 'item': item.name, 'trigger': 'item-delete' }, ) updated |= True except GEOSException as error: logger.error( 'Failed to update spatial extend in collection %s with item %s, trigger=%s, ' 'current-extent=%s, new-geometry=%s, old-geometry=%s: %s', self.name, item.name, trigger, self.extent_geometry, GEOSGeometry(geometry).extent, GEOSGeometry(original_geometry).extent, error, extra={ 'collection': self.name, 'item': item.name, 'trigger': f'item-{trigger}' }, ) raise GEOSException( f'Failed to update spatial extend in colletion {self.name} with item ' f'{item.name}: {error}') return updated
# OS and POSIX platform we're running. if lib_name: pass elif os.name == 'nt': # Windows NT library lib_name = 'libgeos_c-1.dll' elif os.name == 'posix': platform = os.uname()[0] # Using os.uname() if platform == 'Darwin': # Mac OSX Shared Library (Thanks Matt!) lib_name = 'libgeos_c.dylib' else: # Attempting to use the .so extension for all other platforms lib_name = 'libgeos_c.so' else: raise GEOSException('Unsupported OS "%s"' % os.name) # 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_name) # 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, output_h=sys.stdout): try:
# MultiPoint, MultiLineString, and MultiPolygon class definitions. class MultiPoint(GeometryCollection): _allowed = Point _typeid = 4 class MultiLineString(LinearGeometryMixin, GeometryCollection): _allowed = (LineString, LinearRing) _typeid = 5 @property def closed(self): <<<<<<< HEAD if geos_version_info()['version'] < '3.5': raise GEOSException("MultiLineString.closed requires GEOS >= 3.5.0.") return super(MultiLineString, self).closed ======= if geos_version_tuple() < (3, 5): raise GEOSException("MultiLineString.closed requires GEOS >= 3.5.0.") return super().closed >>>>>>> 37c99181c9a6b95433d60f8c8ef9af5731096435 class MultiPolygon(GeometryCollection): _allowed = Polygon _typeid = 6 <<<<<<< HEAD @property def cascaded_union(self):
from django.conf import settings lib_path = settings.GEOS_LIBRARY_PATH except (AttributeError, EnvironmentError, ImportError): 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 = ['libgeos_c-1'] elif os.name == 'posix': # *NIX libraries lib_names = ['geos_c'] else: raise GEOSException('Unsupported OS "%s"' % os.name) # Using the ctypes `find_library` utility to find the the path to the GEOS # shared library. This is better than manually specifiying 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 not lib_path is None: break # No GEOS library could be found. if lib_path is None: raise GEOSException('Could not find the GEOS library (tried "%s"). ' 'Try setting GEOS_LIBRARY_PATH in your settings.' % '", "'.join(lib_names))
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_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 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)
def __init__(self, geo_input, srid=None): """ The base constructor for GEOS geometry objects. It may take the following inputs: * strings: - WKT - HEXEWKB (a PostGIS-specific canonical form) - GeoJSON (requires GDAL) * buffer: - WKB The `srid` keyword specifies the Source Reference Identifier (SRID) number for this Geometry. If not provided, it defaults to None. """ input_srid = None if isinstance(geo_input, bytes): geo_input = force_str(geo_input) if isinstance(geo_input, str): wkt_m = wkt_regex.match(geo_input) if wkt_m: # Handle WKT input. if wkt_m["srid"]: input_srid = int(wkt_m["srid"]) g = self._from_wkt(force_bytes(wkt_m["wkt"])) elif hex_regex.match(geo_input): # Handle HEXEWKB input. g = wkb_r().read(force_bytes(geo_input)) elif json_regex.match(geo_input): # Handle GeoJSON input. ogr = gdal.OGRGeometry.from_json(geo_input) g = ogr._geos_ptr() input_srid = ogr.srid else: raise ValueError( "String input unrecognized as WKT EWKT, and HEXEWKB.") elif isinstance(geo_input, GEOM_PTR): # When the input is a pointer to a geometry (GEOM_PTR). g = geo_input elif isinstance(geo_input, memoryview): # When the input is a buffer (WKB). g = wkb_r().read(geo_input) elif isinstance(geo_input, GEOSGeometry): g = capi.geom_clone(geo_input.ptr) else: raise TypeError("Improper geometry input type: %s" % type(geo_input)) if not g: raise GEOSException( "Could not initialize GEOS Geometry with given input.") input_srid = input_srid or capi.geos_get_srid(g) or None if input_srid and srid and input_srid != srid: raise ValueError("Input geometry already has SRID: %d." % input_srid) super().__init__(g, None) # Set the SRID, if given. srid = input_srid or srid if srid and isinstance(srid, int): self.srid = srid
def set_z(self, value): "Sets the Z component of the Point." if self.hasz: self._cs.setOrdinate(2, 0, value) else: raise GEOSException('Cannot set Z on 2D Point.')
def check_predicate(result, func, cargs): "Error checking for unary/binary predicate functions." <<<<<<< HEAD val = ord(result) # getting the ordinal from the character if val == 1: return True elif val == 0: ======= if result == 1: return True elif result == 0: >>>>>>> 37c99181c9a6b95433d60f8c8ef9af5731096435 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