def from_online_srtm_database(bounds, path_to_dem_file=DEFAULT_OUTPUT, product="SRTM1", margin=0, no_data_value=-32768): """ Import DEM tile from SRTM3 or SRTM1 online dataset Based on "elevation" module. Be careful that at the moment, SRTM3 product does not seem to work properly. :param bounds: :param path_to_dem_file: :param product: "SRTM1" or "SRTM3" :param margin: margin (in %) around DEM :param no_data_value: no data filling value (default = -32768) :return: """ from subprocess import CalledProcessError import elevation try: check_string(product, {'SRTM1', 'SRTM3'}) except ValueError as e: raise DigitalElevationModelError("Invalid product name '%s': %s" % (product, e)) try: elevation.clip(bounds, output=path_to_dem_file, margin="%s" % (margin/100), product=product) except CalledProcessError as e: raise DigitalElevationModelError("Internal subprocess error: %s" % e) except (ValueError, TypeError, KeyError) as e: raise DigitalElevationModelError("Invalid input argument: %s" % e) # Return instance of DigitalElevationModel return DigitalElevationModel(path_to_dem_file, no_data_value=no_data_value)
def get_shortest_path_length(self, node_start, node_end, method: str = "networkx"): """ Get dijkstra shortest path length :param node_start: shapely Point :param node_end: shapely Point :param method: {'internal', 'networkx'} :return: length of path in m """ check_string(method, ("internal", "networkx")) if method == "internal": edge_path = self.get_shortest_path(node_start, node_end) length = 0 if edge_path is not None and edge_path != []: for edge in edge_path.geometry: length += edge.length elif edge_path is None: return None else: node_start = (node_start.x, node_start.y) node_end = (node_end.x, node_end.y) length = nx.dijkstra_path_length(self.graph, node_start, node_end) return length
def find_disconnected_islands_and_fix(self, tolerance=None, method="delete"): """ Find disconnected components in network Find disconnected components/islands graphs in multi-graph and apply method (fix/reconnect, keep, delete) with respect to a given tolerance :param tolerance: :param method: :return: """ method = check_string( method, {'reconnect_and_delete', 'reconnect_and_keep', 'delete'}) sub_graphs = list((self._graph.subgraph(c) for c in nx.connected_components(self._graph))) main_component = max(sub_graphs, key=len) sub_graphs.remove(main_component) idx_edge = [] if method == "delete": for graph in sub_graphs: for edge in graph.edges: try: idx_edge.append(self.from_to.index((edge[0], edge[1]))) except ValueError: idx_edge.append(self.from_to.index((edge[1], edge[0]))) elif method == 'reconnect_and_delete': pass elif method == 'reconnect_and_keep': pass return self.drop(self.index[idx_edge])
def compute_slope(self, slope_format="percent"): """ Compute slope from DEM :return: """ slope_format = check_string(slope_format, {'percent', 'degree'}) return self._compute_slope(slope_format)
def ql_query(osm_type, tag, values=None, bounds=None, polygon_coord=None, timeout=180): """ QL query (thanks to https://github.com/yannforget/OSMxtract for inspiration !) :param osm_type: OSM geometry type str {'node', 'way', 'relation', 'nwr'} :param tag: OSM tag to query :param values: str/list of possible values for the provided OSM tag :param bounds: geometry bounds :param polygon_coord: location's polygon list of coordinates :param timeout: :return: """ osm_type = check_string(osm_type, ('node', 'way', 'relation', 'nwr')) if isinstance(values, str): values = [values] if bounds and not polygon_coord: west, south, east, north = bounds boundary = f'({south:.6f},{west:.6f},{north:.6f},{east:.6f})' elif polygon_coord and not bounds: boundary = f'(poly:"{polygon_coord}")' else: raise QlQueryError("Must define either geometry bounds or polygon coordinates") if values: if len(values) > 1: tags = f'["{ tag }"~"{ "|".join(values) }"]' else: tags = f'["{ tag }"="{ values[0] }"]' else: tags = f'["{tag}"]' return f'[out:json][timeout:{timeout}];{osm_type}{tags}{boundary};out geom;'
def set_max_speed(self, attr_name, speed_dic, speed_format='km/h'): """ Set max allowed speed at intersection :param attr_name: :param speed_dic: :param speed_format: :return: """ check_string(speed_format, ('m/s', 'km/h')) self._check_attr_and_dic(attr_name, speed_dic) for key in speed_dic.keys(): if not isinstance(speed_dic[key], (float, int)): raise RoadNodeError("Speed value must be numeric but is '%s'" % type(speed_dic[key])) self._gpd_df.loc[ self[attr_name] == key, "max_speed"] = speed_dic[key] / SPEED_RATIO[speed_format]
def __init__(self, ellipsoid_model: str): ellipsoid_model = check_string(ellipsoid_model, list(REF_ELLIPSOID.keys())) self._f = 1 / REF_ELLIPSOID[ellipsoid_model]['rf'] self._a = REF_ELLIPSOID[ellipsoid_model]['a'] self._b = self._a - self._a * self._f self._e = math.sqrt(1 - (self._b**2 / self._a**2)) self._model = ellipsoid_model
def json_to_geodataframe(response, geometry_type): """ Convert JSON responses to :param response: json response :param geometry_type: type of geometry to extract ('point', 'linestring', 'polygon', 'multipolygon') :return: """ geometry_type = check_string(geometry_type, ('point', 'linestring', 'polygon')) if geometry_type == 'point': return gpd.GeoDataFrame.from_features(_to_point_features(response), crs=default_crs) else: return gpd.GeoDataFrame.from_features(_to_features(response, geometry_type), crs=default_crs)
def table_to_layer(self, table_name, schema=None, geom_type=None, bounds=None, polygon_extent=None): """ Convert table from database to GeoLayer instance :param table_name: name of table (case sensitive) :param schema: database schema (case sensitive) :param geom_type: geometry type :param bounds: bounding box (x_min, y_min, x_max, y_max) :param polygon_extent: shapely polygon :return: """ if schema is None: schema = "public" if bounds is not None and polygon_extent is None: sql_string = f'SELECT * FROM "{schema}"."{table_name}" WHERE "{schema}"."{table_name}".geom && ' \ f'ST_MakeEnvelope({bounds[0]}, {bounds[1]}, {bounds[2]}, {bounds[3]})' elif polygon_extent is not None and bounds is None: sql_string = f'SELECT * FROM "{schema}"."{table_name}" WHERE ST_Within("{schema}"."{table_name}".geom, ' \ f'{polygon_extent})' else: sql_string = f'SELECT * FROM "{schema}"."{table_name}"' df = GeoDataFrame.from_postgis(sql_string, self.engine) if table_name in self.get_table_names(schema) and geom_type is None: try: layer = PolygonLayer(df, name=table_name) except GeoLayerError: try: layer = LineLayer(df, name=table_name) except GeoLayerError: layer = PointLayer(df, name=table_name) elif table_name in self.get_table_names(schema) and geom_type is not None: try: geom_type = check_string(geom_type, ("point", "line", "polygon")) except ValueError: raise SpatialDatabaseError("Invalid geometry type '%s'. Must be 'point', 'line' or 'polygon'." % geom_type) layer = self.layer_class[geom_type](df, name=table_name) else: raise SpatialDatabaseError("No table named '%s' in database '%s'" % (table_name, self.db_name)) return layer