diff --git a/ra2ce/network/network_wrappers/network_wrapper_protocol.py b/ra2ce/network/network_wrappers/network_wrapper_protocol.py index f32a25d03..b6159869d 100644 --- a/ra2ce/network/network_wrappers/network_wrapper_protocol.py +++ b/ra2ce/network/network_wrappers/network_wrapper_protocol.py @@ -18,55 +18,14 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . """ -import logging -import math -from typing import Optional, Protocol, Union, runtime_checkable +from typing import Protocol, runtime_checkable from geopandas import GeoDataFrame from networkx import MultiGraph -from ra2ce.network.segmentation import Segmentation - @runtime_checkable class NetworkWrapperProtocol(Protocol): - def segment_graph( - self, - edges: GeoDataFrame, - export_link_table: bool, - link_tables: Optional[tuple] = None, - ) -> Union[GeoDataFrame, tuple[GeoDataFrame, tuple]]: - """ - Segments a complex graph based on the given segmentation length. - - Args: - - segmentation_length (Optional[float]): The length to segment the graph edges. If None, no segmentation is applied. - - edges_complex (gpd.GeoDataFrame): The GeoDataFrame containing the complex graph edges. - - crs (str): The coordinate reference system to apply if the CRS is missing after segmentation. - - Returns: - - gpd.GeoDataFrame: The segmented edges_complex GeoDataFrame. - """ - if not math.isnan(self.segmentation_length): - segmentation = Segmentation(edges, self.segmentation_length) - segmented_edges = segmentation.apply_segmentation() - if segmented_edges.crs is None: # The CRS might have disappeared. - segmented_edges.crs = self.crs # set the right CRS - - if export_link_table: - updated_link_tables = segmentation.generate_link_tables() - segmented_edges.drop(columns=["rfid_c"], inplace=True) - segmented_edges.rename(columns={"splt_id": "rfid_c"}, inplace=True) - return segmented_edges, updated_link_tables - return segmented_edges - elif export_link_table and link_tables: - return edges, link_tables - elif export_link_table and not link_tables: - logging.warning("empty link_tables is passed") - return edges, tuple() - else: - return edges - def get_network(self) -> tuple[MultiGraph, GeoDataFrame]: """ Gets a network built within this wrapper instance. No arguments are accepted, the `__init__` method is meant to assign all required attributes for a wrapper. diff --git a/ra2ce/network/network_wrappers/osm_network_wrapper/osm_network_wrapper.py b/ra2ce/network/network_wrappers/osm_network_wrapper/osm_network_wrapper.py index 952e882cd..2538c40bb 100644 --- a/ra2ce/network/network_wrappers/osm_network_wrapper/osm_network_wrapper.py +++ b/ra2ce/network/network_wrappers/osm_network_wrapper/osm_network_wrapper.py @@ -46,6 +46,7 @@ is_endnode_check, modify_graph, ) +from ra2ce.network.segmentation import Segmentation class OsmNetworkWrapper(NetworkWrapperProtocol): @@ -160,8 +161,12 @@ def get_network(self) -> tuple[MultiGraph, GeoDataFrame]: logging.info("Finished converting the graph to a geodataframe") # Segment the complex graph - edges_complex, link_tables = self.segment_graph( - edges_complex, export_link_table=True, link_tables=link_tables + edges_complex, link_tables = Segmentation.segment_graph( + self.segmentation_length, + self.crs, + edges_complex, + export_link_table=True, + link_tables=link_tables, ) # Save the link tables linking complex and simple IDs diff --git a/ra2ce/network/network_wrappers/shp_network_wrapper.py b/ra2ce/network/network_wrappers/shp_network_wrapper.py index 3d05d201e..bf3a1fc09 100644 --- a/ra2ce/network/network_wrappers/shp_network_wrapper.py +++ b/ra2ce/network/network_wrappers/shp_network_wrapper.py @@ -31,6 +31,7 @@ from ra2ce.network.network_wrappers.network_wrapper_protocol import ( NetworkWrapperProtocol, ) +from ra2ce.network.segmentation import Segmentation class ShpNetworkWrapper(NetworkWrapperProtocol): @@ -188,6 +189,8 @@ def get_network( graph_complex, edges_complex = self._get_complex_graph_and_edges(edges, id_name) - edges_complex = self.segment_graph(edges_complex, export_link_table=False) + edges_complex = Segmentation.segment_graph( + self.segmentation_length, self.crs, edges_complex, export_link_table=False + ) return graph_complex, edges_complex diff --git a/ra2ce/network/network_wrappers/trails_network_wrapper.py b/ra2ce/network/network_wrappers/trails_network_wrapper.py index bb3245421..2ffa3c835 100644 --- a/ra2ce/network/network_wrappers/trails_network_wrapper.py +++ b/ra2ce/network/network_wrappers/trails_network_wrapper.py @@ -30,6 +30,7 @@ NetworkWrapperProtocol, ) from ra2ce.network.networks_utils import graph_from_gdf +from ra2ce.network.segmentation import Segmentation class TrailsNetworkWrapper(NetworkWrapperProtocol): @@ -90,7 +91,9 @@ def get_network(self) -> tuple[MultiGraph, GeoDataFrame]: ) # Segment the complex graph - edges_complex = self.segment_graph(edges, export_link_table=False) + edges_complex = Segmentation.segment_graph( + self.segmentation_length, self.crs, edges, export_link_table=False + ) graph_complex = graph_simple # NOTE THAT DIFFERENCE # BETWEEN SIMPLE AND COMPLEX DOES NOT EXIST WHEN IMPORTING WITH TRAILS diff --git a/ra2ce/network/network_wrappers/vector_network_wrapper.py b/ra2ce/network/network_wrappers/vector_network_wrapper.py index b2955aa75..9b1fede2a 100644 --- a/ra2ce/network/network_wrappers/vector_network_wrapper.py +++ b/ra2ce/network/network_wrappers/vector_network_wrapper.py @@ -39,6 +39,7 @@ from ra2ce.network.network_wrappers.network_wrapper_protocol import ( NetworkWrapperProtocol, ) +from ra2ce.network.segmentation import Segmentation class VectorNetworkWrapper(NetworkWrapperProtocol): @@ -129,8 +130,12 @@ def get_network( logging.info("Finished converting the graph to a geodataframe") # Segment the complex graph - edges_complex, link_tables = self.segment_graph( - edges_complex, export_link_table=True, link_tables=link_tables + edges_complex, link_tables = Segmentation.segment_graph( + self.segmentation_length, + self.crs, + edges_complex, + export_link_table=True, + link_tables=link_tables, ) # Save the link tables linking complex and simple IDs diff --git a/ra2ce/network/segmentation.py b/ra2ce/network/segmentation.py index 34edc8271..fa5ec379e 100644 --- a/ra2ce/network/segmentation.py +++ b/ra2ce/network/segmentation.py @@ -20,8 +20,9 @@ """ import logging +import math from decimal import Decimal -from typing import Union +from typing import Optional, Union import geopandas as gpd from geopy import distance @@ -46,6 +47,45 @@ class Segmentation: # Todo: more naturally, this would be METHOD of the network """ + @staticmethod + def segment_graph( + segmentation_length: float, + crs: float, + edges: gpd.GeoDataFrame, + export_link_table: bool, + link_tables: Optional[tuple] = None, + ) -> Union[gpd.GeoDataFrame, tuple[gpd.GeoDataFrame, tuple]]: + """ + Segments a complex graph based on the given segmentation length. + + Args: + - segmentation_length (Optional[float]): The length to segment the graph edges. If None, no segmentation is applied. + - edges_complex (gpd.GeoDataFrame): The GeoDataFrame containing the complex graph edges. + - crs (str): The coordinate reference system to apply if the CRS is missing after segmentation. + + Returns: + - gpd.GeoDataFrame: The segmented edges_complex GeoDataFrame. + """ + if not math.isnan(segmentation_length): + segmentation = Segmentation(edges, segmentation_length) + segmented_edges = segmentation.apply_segmentation() + if segmented_edges.crs is None: # The CRS might have disappeared. + segmented_edges.crs = crs # set the right CRS + + if export_link_table: + updated_link_tables = segmentation.generate_link_tables() + segmented_edges.drop(columns=["rfid_c"], inplace=True) + segmented_edges.rename(columns={"splt_id": "rfid_c"}, inplace=True) + return segmented_edges, updated_link_tables + return segmented_edges + elif export_link_table and link_tables: + return edges, link_tables + elif export_link_table and not link_tables: + logging.warning("empty link_tables is passed") + return edges, tuple() + else: + return edges + def __init__( self, edges_input: gpd.GeoDataFrame, diff --git a/tests/test_data/1_network_shape/network.ini b/tests/test_data/1_network_shape/network.ini index af7bb01a8..789155f9b 100644 --- a/tests/test_data/1_network_shape/network.ini +++ b/tests/test_data/1_network_shape/network.ini @@ -28,6 +28,6 @@ hazard_crs = None [cleanup] snapping_threshold = None pruning_threshold = None -segmentation_length = 0.0001 +segmentation_length = 100 merge_lines = False cut_at_intersections = True \ No newline at end of file diff --git a/tests/test_data/2_network_shape/network.ini b/tests/test_data/2_network_shape/network.ini index 50ed06fa4..f5517e9d7 100644 --- a/tests/test_data/2_network_shape/network.ini +++ b/tests/test_data/2_network_shape/network.ini @@ -31,6 +31,6 @@ hazard_crs = None [cleanup] snapping_threshold = None pruning_threshold = None -segmentation_length = 0.0001 +segmentation_length = 100 merge_lines = True cut_at_intersections = True \ No newline at end of file