def mappy_construct(lines: geopandas.GeoDataFrame, points: geopandas.GeoDataFrame, output: str, units_field: str, layer_name="geomap", auto_extend=0, overwrite=False, debug=False): log.info("Executing mappy construct") log.info(f"CRS lines: {lines.crs}") log.info(f"CRS points: {points.crs}") out_args = {} out_args["layers"] = [] if lines.crs != points.crs: log.warning("points and lines layers has different CRS, reprojecting...") points = points.to_crs(lines.crs) if os.path.exists(output): log.debug(f"File {output} exists!") existing_layers = fiona.listlayers(output) if layer_name in existing_layers and overwrite is not True: log.error(f"output geopackage {output} already contains a layer named {layer_name}.") return out_args if auto_extend != 0: log.info("extend_lines enabled, lines are extended") lines = extend_lines(lines, auto_extend) if debug: lines.to_file(output, layer="debug_extended_lines", driver="GPKG") out_args["layers"].append(lines) if debug: intersections = compute_self_intersections_points(lines) intersections.to_file(output, layer="debug_self_intersections", driver="GPKG") out_args["layers"].append("debug_self_intersections") polygons = polygonize(lines) if debug: polygons.to_file(output, layer="debug_polygons", driver="GPKG") out_args["layers"].append("debug_polygons") out = transfer_units_to_polygons(polygons, points, units_field) out.crs = None # for now, then use the same as lines # from mappy.dev_tests import test_geopandas_save_gpkg # test_geopandas_save_gpkg() try: out.to_file(output, layer=layer_name, driver="GPKG") except Exception as e: print(e) raise e out_args["layers"].append(layer_name) out_args["gpkg"] = output return out_args
def extend(p1: np.ndarray, p2: np.ndarray, distance: float): """ from p1 to p2 extended by dist. """ if np.linalg.norm(p2 - p1) < 1e-16: log.warning("two points are equal, cannot extend") raise ValueError("two points are equal, cannot extend") v = p2 - p1 v = v / np.linalg.norm(v) * distance news = p2 + v return news
def test_modules(): available_modules = [] for a in OptionalModules: log.debug(f"testing import {a.name}") try: doimport(a.name) available_modules.append(a) except: log.warning("cannot import") return available_modules
def extend_lines(geodataframe: geopandas.GeoDataFrame, distance: float): """ Extends begin and end segments of the line by the given distance. :param geodataframe: :param distance: :return: """ from copy import deepcopy allg = explode_all(geodataframe.geometry) geodataframe = geopandas.GeoDataFrame(geometry=allg) outframe = deepcopy(geodataframe) out = [] # the collection of extended LineStrings for f in geodataframe.geometry: if f.is_closed is True: log.warning("shape is closed. skip - no need to extend it") l = LineString(np.row_stack([f.xy]).T) out.append(l) continue if not f.is_valid: # if the shape is no valid for some reason we remove it. log.warning("a not valid shape was found") raise ValueError("a not valid shape was found") pts = np.row_stack([f.xy]).T pts = drop_duplicated_points( pts) # be sure we dont' have duplicated points wich might # be a problem expecially at the end and beginning (we would not be able to extend the feature) start = pts[:2][::-1] end = pts[::-1][:2][::-1] news = extend(start[0], start[1], distance) newe = extend(end[0], end[1], distance) extended = np.row_stack([news, pts, newe]) if np.isnan(extended).any(): log.warning("Extended line containing nans, should not happen") l = LineString(extended) if not l.is_valid: log.warning("line not valid") out.append(l) outframe["geometry"] = out return outframe
def transfer_units_to_polygons(polygons: geopandas.GeoDataFrame, units: geopandas.GeoDataFrame, units_field: str): """ this could be obtained with a spatial joint, but with this we have more control to perform checks and know what is going on e.g. geopandas.sjoin( polygons, units, how="left", op='contains').plot(column= units_field) :param polygons: :param units: :param units_field: :return: A copy of polygons with the units """ outids = [] for pol in polygons.geometry: ids = get_points_inside(pol, units.geometry) log.info(f"found {len(ids)} polygon_ids: {ids}") thisunit = units[units_field][ids].values log.info(f"thisunit {thisunit}") if len(ids) > 1: log.warning("more than two points were found in the same polygon") if np.all(thisunit == thisunit[0]): log.warning("no prob, because point to the same unit") else: log.warning("The unit contains points with mismatched indicator points. Setting to None") thisunit = [None] if len(ids) < 1: log.error("cannot associate some polygons to an unit, missing points in unit definition file?") thisunit = [None] myunit = thisunit[0] outids.append(myunit) from copy import deepcopy out_polygons = deepcopy(polygons) out_polygons[units_field] = outids return out_polygons
def check_validity_of_geometries(data: geopandas.GeoDataFrame): for pol in data.geometry: if not pol.is_valid: log.warning("found invalid geometry")