Source code for flopy.utils.geospatial_utils

try:
    import shapely
    from shapely.geometry import (
        MultiPolygon,
        Polygon,
        Point,
        MultiPoint,
        LineString,
        MultiLineString,
    )
except:
    shapely = None

try:
    import geojson
except:
    geojson = None

import numpy as np
from flopy.utils.geometry import Shape, Collection


geojson_classes = {}
if geojson is not None:
    geojson_classes = {
        "polygon": geojson.Polygon,
        "multipolygon": geojson.MultiPolygon,
        "point": geojson.Point,
        "multipoint": geojson.MultiPoint,
        "linestring": geojson.LineString,
        "multilinestring": geojson.MultiLineString,
    }

shape_types = {
    "multipolygon": "MultiPolygon",
    "polygon": "Polygon",
    "point": "Point",
    "multipoint": "MultiPoint",
    "linestring": "LineString",
    "multilinestring": "MultiLineString",
}


[docs]class GeoSpatialUtil: """ Geospatial utils are a unifying method to provide conversion between commonly used geospatial input types Parameters ---------- obj : geospatial object obj can accept any of the following objects: shapefile.Shape object flopy.utils.geometry objects list of vertices geojson geometry objects shapely.geometry objects shapetype : str shapetype is required when a list of vertices is supplied for obj """ def __init__(self, obj, shapetype=None): from ..export.shapefile_utils import import_shapefile self.__shapefile = import_shapefile() self.__obj = obj self.__geo_interface = {} self._geojson = None self._shapely = None self._shape = None self._flopy_geometry = None self._points = None self.__shapetype = None if shapetype is not None: shapetype = shapetype.lower() if isinstance(obj, self.__shapefile.Shape): self.__geo_interface = self.__obj.__geo_interface__ elif isinstance(obj, (Shape, Collection)): geo_interface = obj.__geo_interface__ if geo_interface["type"] == "GeometryCollection": raise TypeError("GeometryCollections are not supported") self.__geo_interface = geo_interface elif isinstance(obj, (np.ndarray, list, tuple)): if shapetype is None or shapetype not in shape_types: err = "shapetype must be one of the following: " + " , ".join( geojson_classes.keys() ) raise AssertionError(err) self.__geo_interface = { "type": shape_types[shapetype], "coordinates": list(obj), } if geojson is not None: if isinstance(obj, geojson.Feature): self.__geo_interface = { "type": obj.geometry.type, "coordinates": obj.geometry.coordinates, } elif isinstance( obj, ( geojson.Point, geojson.MultiPoint, geojson.Polygon, geojson.MultiPolygon, geojson.LineString, geojson.MultiLineString, ), ): self.__geo_interface = { "type": obj.type, "coordinates": obj.coordinates, } if shapely is not None: if isinstance( obj, ( Point, MultiPoint, Polygon, MultiPolygon, LineString, MultiLineString, ), ): self.__geo_interface = obj.__geo_interface__ else: raise ModuleNotFoundError("shapely is not installed") @property def __geo_interface__(self): """ Geojson standard representation of a geometry Returns ------- dict """ return self.__geo_interface @property def shapetype(self): """ Shapetype string for a geometry Returns ------- str """ if self.__shapetype is None: self.__shapetype = self.__geo_interface["type"] return self.__shapetype @property def points(self): """ Returns a list of vertices to the user Returns ------- list """ if self._points is None: self._points = self.__geo_interface["coordinates"] return self._points @property def shapely(self): """ Returns a shapely.geometry object to the user Returns ------- shapely.geometry.<shape> """ if shapely is not None: if self._shapely is None: self._shapely = shapely.geometry.shape(self.__geo_interface) return self._shapely else: raise ModuleNotFoundError("shapely is not installed") @property def geojson(self): """ Returns a geojson object to the user Returns ------- geojson.<shape> """ if geojson is not None: if self._geojson is None: cls = geojson_classes[self.__geo_interface["type"].lower()] self._geojson = cls(self.__geo_interface["coordinates"]) return self._geojson else: raise ModuleNotFoundError("geojson is not installed") @property def shape(self): """ Returns a shapefile.Shape object to the user Returns ------- shapefile.shape """ if self._shape is None: self._shape = self.__shapefile.Shape._from_geojson( self.__geo_interface ) return self._shape @property def flopy_geometry(self): """ Returns a flopy geometry object to the user Returns ------- flopy.utils.geometry.<Shape> """ if self._flopy_geometry is None: self._flopy_geometry = Shape.from_geojson(self.__geo_interface) return self._flopy_geometry
[docs]class GeoSpatialCollection: """ The GeoSpatialCollection class allows a user to convert between Collection objects from common geospatial libraries. Parameters ---------- obj : collection object obj can accept the following types str : shapefile name shapefile.Reader object list of [shapefile.Shape, shapefile.Shape,] shapefile.Shapes object flopy.utils.geometry.Collection object list of [flopy.utils.geometry, ...] objects geojson.GeometryCollection object geojson.FeatureCollection object shapely.GeometryCollection object list of [[vertices], ...] shapetype : list optional list of shapetypes that is required when vertices are supplied to the class as the obj parameter """ def __init__(self, obj, shapetype=None): from ..export.shapefile_utils import import_shapefile self.__shapefile = import_shapefile() self.__obj = obj self.__collection = [] self._geojson = None self._shapely = None self._shape = None self._flopy_geometry = None self._points = None self.__shapetype = None if isinstance(obj, str): with self.__shapefile.Reader(obj) as r: for shape in r.shapes(): self.__collection.append(GeoSpatialUtil(shape)) elif isinstance(obj, self.__shapefile.Reader): for shape in obj.shapes(): self.__collection.append(GeoSpatialUtil(shape)) elif isinstance(obj, self.__shapefile.Shapes): for shape in obj: self.__collection.append(GeoSpatialUtil(shape)) elif isinstance(obj, Collection): for shape in obj: self.__collection.append(GeoSpatialUtil(shape)) elif isinstance(obj, (np.ndarray, list, tuple)): if isinstance(obj[0], (Shape, Collection, self.__shapefile.Shape)): for shape in obj: self.__collection.append(GeoSpatialUtil(shape)) else: if shapetype is None: err = "a list of shapetypes must be provided" raise AssertionError(err) elif isinstance(shapetype, str): shapetype = [shapetype] * len(obj) for ix, geom in enumerate(obj): self.__collection.append( GeoSpatialUtil(geom, shapetype[ix]) ) if geojson is not None: if isinstance( obj, ( geojson.GeometryCollection, geojson.FeatureCollection, geojson.MultiLineString, geojson.MultiPoint, geojson.MultiPolygon, ), ): for geom in obj.geometries: self.__collection.append(GeoSpatialUtil(geom)) if shapely is not None: if isinstance( obj, ( shapely.geometry.collection.GeometryCollection, MultiPoint, MultiLineString, MultiPolygon, ), ): for geom in obj.geoms: self.__collection.append(GeoSpatialUtil(geom)) else: raise ModuleNotFoundError("shapely is no installed") def __iter__(self): """ Iterator method that allows the user to get a list of GeoSpatialUtil objects from the GeoSpatialCollection object Returns ------- GeoSpatialUtil """ yield from self.__collection @property def shapetype(self): """ Returns a list of shapetypes to the user Returns ------- list of str """ if self.__shapetype is None: self.__shapetype = [i.shapetype for i in self.__collection] return self.__shapetype @property def points(self): """ Property returns a multidimensional list of vertices Returns ------- list of vertices """ if self._points is None: self._points = [i.points for i in self.__collection] return self._points @property def shapely(self): """ Property that returns a shapely.geometry.collection.GeometryCollection object to the user Returns ------- shapely.geometry.collection.GeometryCollection object """ if shapely is not None: if self._shapely is None: self._shapely = shapely.geometry.collection.GeometryCollection( [i.shapely for i in self.__collection] ) else: raise ModuleNotFoundError("shapely is not installed") return self._shapely @property def geojson(self): """ Property that returns a geojson.GeometryCollection object to the user Returns ------- geojson.GeometryCollection """ if geojson is not None: if self._geojson is None: self._geojson = geojson.GeometryCollection( [i.geojson for i in self.__collection] ) else: raise ModuleNotFoundError("geojson is not installed") return self._geojson @property def shape(self): """ Property that returns a shapefile.Shapes object Returns ------- shapefile.Shapes object """ if self._shape is None: self._shape = self.__shapefile.Shapes() for geom in self.__collection: self._shape.append(geom.shape) return self._shape @property def flopy_geometry(self): """ Property that returns a flopy.util.geometry.Collection object Returns ------- flopy.util.geometry.Collectionnos object """ if self._flopy_geometry is None: self._flopy_geometry = Collection( [i.flopy_geometry for i in self.__collection] ) return self._flopy_geometry