Skip to content
Snippets Groups Projects
test_gis_modify.py 118 KiB
Newer Older
  • Learn to ignore specific revisions
  • Pedro Magalhães's avatar
    Pedro Magalhães committed
    # imports
    
    # standard
    
    from math import isclose
    import random
    from statistics import mean
    
    # local, external
    
    from shapely.geometry import Point, LineString
    from shapely import length
    import networkx as nx
    import osmnx as ox
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
    # from osmnx.utils_graph import get_undirected
    
    # local, internal
    
    import src.topupopt.data.gis.osm as osm
    import src.topupopt.data.gis.modify as gis_mod
    import src.topupopt.data.gis.calculate as gis_calc
    import src.topupopt.data.gis.identify as gis_iden
    import src.topupopt.problems.esipp.utils as prob_utils
    
    # *****************************************************************************
    # *****************************************************************************
    
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
    class TestGisModify:
        # *************************************************************************
        # *************************************************************************
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
        def test_create_reverse_edges(self):
            network = nx.MultiDiGraph()
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
            node_key0 = 0
    
    Pedro L. Magalhães's avatar
    Pedro L. Magalhães committed
            node_key0_dict = {osm.KEY_OSMNX_X: 55, osm.KEY_OSMNX_Y: 25}
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
            node_key1 = 1
    
    Pedro L. Magalhães's avatar
    Pedro L. Magalhães committed
            node_key1_dict = {osm.KEY_OSMNX_X: 55.001, osm.KEY_OSMNX_Y: 25.001}
    
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
            network.add_node(node_key0, **node_key0_dict)
            network.add_node(node_key1, **node_key1_dict)
            # create a line between node 0 and node 1
    
    Pedro L. Magalhães's avatar
    Pedro L. Magalhães committed
            geo_line = LineString(
                [
                    (node_key0_dict[osm.KEY_OSMNX_X], node_key0_dict[osm.KEY_OSMNX_Y]),
                    (node_key1_dict[osm.KEY_OSMNX_X], node_key1_dict[osm.KEY_OSMNX_Y]),
                ]
            )
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
            # the same line, reversed
            geo_line_reversed = geo_line.reverse()
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
            k_no_geo = network.add_edge(
    
    Pedro L. Magalhães's avatar
    Pedro L. Magalhães committed
                0,
                1,
                **{
                    osm.KEY_OSMNX_LENGTH: 3,
                    osm.KEY_OSMNX_REVERSED: False,
                    osm.KEY_OSMNX_OSMID: 1,
                    osm.KEY_OSMNX_ONEWAY: False,
                }
            )
    
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
            k_normal = network.add_edge(
    
    Pedro L. Magalhães's avatar
    Pedro L. Magalhães committed
                0,
                1,
                **{
                    osm.KEY_OSMNX_LENGTH: 3,
                    osm.KEY_OSMNX_ONEWAY: False,
                    osm.KEY_OSMNX_OSMID: 1,
                    osm.KEY_OSMNX_REVERSED: [True, False],
                    osm.KEY_OSMNX_GEOMETRY: geo_line,
                }
            )
    
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
            k_reversed = network.add_edge(
    
    Pedro L. Magalhães's avatar
    Pedro L. Magalhães committed
                0,
                1,
                **{
                    osm.KEY_OSMNX_LENGTH: 3,
                    osm.KEY_OSMNX_OSMID: 1,
                    osm.KEY_OSMNX_ONEWAY: False,
                    osm.KEY_OSMNX_REVERSED: True,
                    osm.KEY_OSMNX_GEOMETRY: geo_line_reversed,
                }
            )
    
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
            # edge without geometry should be consistent
            edge_key = (node_key0, node_key1, k_no_geo)
            assert gis_iden.is_edge_osmnx_compliant(network, edge_key)
            new_edges = gis_mod.create_reverse_edges(network, edge_keys=[edge_key])
            for new_edge in new_edges:
                assert gis_iden.is_edge_osmnx_compliant(network, new_edge)
            network.remove_edges_from(new_edges)
            # edge with normal geometry should be consistent
            edge_key = (node_key0, node_key1, k_normal)
            assert gis_iden.is_edge_osmnx_compliant(network, edge_key)
            new_edges = gis_mod.create_reverse_edges(network, edge_keys=[edge_key])
            for new_edge in new_edges:
                assert gis_iden.is_edge_osmnx_compliant(network, new_edge)
            network.remove_edges_from(new_edges)
            # edge with reversed geometry should not be consistent
            edge_key = (node_key0, node_key1, k_reversed)
            assert gis_iden.is_edge_osmnx_compliant(network, edge_key)
            new_edges = gis_mod.create_reverse_edges(network, edge_keys=[edge_key])
            for new_edge in new_edges:
                assert gis_iden.is_edge_osmnx_compliant(network, new_edge)
            network.remove_edges_from(new_edges)
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
            assert network.number_of_edges() == 3
            new_edges = gis_mod.create_reverse_edges(network)
            assert len(new_edges) == 3
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
            # trigger no edge found error
            error_raised = False
            try:
    
    Pedro L. Magalhães's avatar
    Pedro L. Magalhães committed
                edge_key = (node_key0, node_key1, k_no_geo - 1)
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
                gis_mod.create_reverse_edges(network, [edge_key])
            except ValueError:
                error_raised = True
            assert error_raised
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
            # trigger valuerror due to incorrect reversed type
            k_error = network.add_edge(
    
    Pedro L. Magalhães's avatar
    Pedro L. Magalhães committed
                0,
                1,
                **{
                    osm.KEY_OSMNX_LENGTH: 3,
                    osm.KEY_OSMNX_REVERSED: {True, False},
                    osm.KEY_OSMNX_ONEWAY: False,
                    osm.KEY_OSMNX_OSMID: 1,
                    osm.KEY_OSMNX_GEOMETRY: geo_line,
                }
            )
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
            error_raised = False
            try:
                edge_key = (node_key0, node_key1, k_error)
                gis_mod.create_reverse_edges(network, [edge_key])
            except ValueError:
                error_raised = True
            assert error_raised
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
        # *************************************************************************
        # *************************************************************************
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
        def test_replace_paths_osmnx(self):
            # get the network
            _net = ox.graph_from_point(
    
    Pedro L. Magalhães's avatar
    Pedro L. Magalhães committed
                network_type="drive",
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
                custom_filter='["highway"~"residential|tertiary|unclassified|service"]',
    
    Pedro L. Magalhães's avatar
    Pedro L. Magalhães committed
                truncate_by_edge=True,
            )
    
    
            # define the settings
            ignore_self_loops = False
            consider_reversed_edges = True
    
            # find paths
            paths = gis_iden.find_simplifiable_paths(
    
    Pedro L. Magalhães's avatar
    Pedro L. Magalhães committed
                _net,
    
                ignore_self_loops=ignore_self_loops,
    
    Pedro L. Magalhães's avatar
    Pedro L. Magalhães committed
                consider_reversed_edges=consider_reversed_edges,
            )
    
    
            # verify the paths
            for path in paths:
                gis_iden.is_path_straight(
    
    Pedro L. Magalhães's avatar
    Pedro L. Magalhães committed
                    _net,
                    path,
                    consider_reversed_edges=consider_reversed_edges,
                    ignore_self_loops=ignore_self_loops,
                )
    
    
            # modify an edge in one of the paths to have list attributes
    
    Pedro L. Magalhães's avatar
    Pedro L. Magalhães committed
            _edge_key = tuple(
                gis_iden.get_edges_from_a_to_b(
                    _net,
                    paths[0][0],  # first path, first node
                    paths[0][1],  # first paht, second node
    
    Pedro L. Magalhães's avatar
    Pedro L. Magalhães committed
            )[0]
            _net.add_edge(
                *_edge_key,
                **{
                    osm.KEY_OSMNX_ONEWAY: [_net.edges[_edge_key][osm.KEY_OSMNX_ONEWAY]],
                    osm.KEY_OSMNX_REVERSED: [_net.edges[_edge_key][osm.KEY_OSMNX_REVERSED]],
                }
            )
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
            # measure the distances
    
    Pedro L. Magalhães's avatar
    Pedro L. Magalhães committed
            true_path_lengths = [gis_calc.node_path_length(_net, path) for path in paths]
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
            # replace the paths
    
    Pedro L. Magalhães's avatar
    Pedro L. Magalhães committed
            new_path_edges = [gis_mod.replace_path(_net, path) for path in paths]
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
            # compare
    
            for edge_key, true_length in zip(new_path_edges, true_path_lengths):
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
                assert isclose(
    
                    _net.edges[edge_key][gis_iden.osm.KEY_OSMNX_LENGTH],
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
                    true_length,
    
    Pedro L. Magalhães's avatar
    Pedro L. Magalhães committed
                    abs_tol=1e-3,  # 23.400000000000034
                )
    
    
        # *************************************************************************
        # *************************************************************************
    
        def test_replace_nonsimplifiable_path(self):
            _net = nx.MultiDiGraph()
    
            error_raised = False
            try:
                gis_mod.replace_path(_net, path)
            except ValueError:
                error_raised = True
            assert error_raised
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
        # *************************************************************************
        # *************************************************************************
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
        def example_replace_paths(self, project_the_graph: bool = False):
            # *********************************************************************
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
            # smallest possible path
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
            network = nx.MultiDiGraph()
    
    Pedro L. Magalhães's avatar
    Pedro L. Magalhães committed
            network.graph["crs"] = "EPSG:4326"
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
            network.graph["simplified"] = False
            # add nodes
    
    Pedro L. Magalhães's avatar
    Pedro L. Magalhães committed
            network.add_nodes_from(
                [
                    (0, {osm.KEY_OSMNX_Y: 56.00, osm.KEY_OSMNX_X: 12.00}),
                    (1, {osm.KEY_OSMNX_Y: 56.01, osm.KEY_OSMNX_X: 12.00}),
                    (2, {osm.KEY_OSMNX_Y: 56.02, osm.KEY_OSMNX_X: 12.01}),
                ]
            )
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
            # add edges
    
    Pedro L. Magalhães's avatar
    Pedro L. Magalhães committed
            network.add_edges_from(
                [
                    (
                        0,
                        1,
                        0,
                        {
                            osm.KEY_OSMNX_OSMID: 1,
                            osm.KEY_OSMNX_LENGTH: 3,
                            osm.KEY_OSMNX_REVERSED: False,
                            osm.KEY_OSMNX_ONEWAY: False,
                        },
                    ),
                    (
                        1,
                        2,
                        0,
                        {
                            osm.KEY_OSMNX_OSMID: 2,
                            osm.KEY_OSMNX_LENGTH: 4,
                            osm.KEY_OSMNX_REVERSED: False,
                            osm.KEY_OSMNX_ONEWAY: False,
                        },
                    ),
                ]
            )
            lengths = gis_calc.edge_lengths(network, edge_keys=[(0, 1, 0), (1, 2, 0)])
            network.edges[(0, 1, 0)][osm.KEY_OSMNX_LENGTH] = lengths[(0, 1, 0)]
            network.edges[(1, 2, 0)][osm.KEY_OSMNX_LENGTH] = lengths[(1, 2, 0)]
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
            number_edges = network.number_of_edges()
            if project_the_graph:
                network = ox.project_graph(G=network)
    
    Pedro L. Magalhães's avatar
    Pedro L. Magalhães committed
            path = [0, 1, 2]
    
            new_edge_key = gis_mod.replace_path(network, path=path)
            # a new edge should exist
            assert network.has_edge(*new_edge_key)
            # assert that two edges are removed and one is created
    
    Pedro L. Magalhães's avatar
    Pedro L. Magalhães committed
            assert network.number_of_edges() - number_edges == 1 - 2
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
            # intermediate nodes should not exist any longer
            for node in path[1:-1]:
                assert not network.has_node(node)
            # the distances need to match
            assert isclose(
                sum(lengths.values()),
    
                network.edges[new_edge_key][osm.KEY_OSMNX_LENGTH],
    
    Pedro L. Magalhães's avatar
    Pedro L. Magalhães committed
                abs_tol=1e-3,
            )
    
            # the new edge needs to have a geometry because it is not simple
            assert osm.KEY_OSMNX_GEOMETRY in network.edges[new_edge_key]
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
            # the geometry must have 3 points
    
    Pedro L. Magalhães's avatar
    Pedro L. Magalhães committed
            assert (
                len(tuple(network.edges[new_edge_key][osm.KEY_OSMNX_GEOMETRY].coords)) == 3
            )
            new_edge_key_lengths = gis_calc.edge_lengths(network, edge_keys=[new_edge_key])
    
            # the geometry's length needs to match that of the edge's
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
            assert isclose(
    
                network.edges[new_edge_key][osm.KEY_OSMNX_LENGTH],
                new_edge_key_lengths[new_edge_key],
    
    Pedro L. Magalhães's avatar
    Pedro L. Magalhães committed
                abs_tol=1 if not project_the_graph else 3.861,  # 3.8601244551728087
            )
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
            # print('hallo1')
    
            # print(tuple(network.edges[new_edge_key][osm.KEY_OSMNX_GEOMETRY].coords))
            # print(network.edges[new_edge_key][osm.KEY_OSMNX_LENGTH])
            # print(new_edge_key_lengths[new_edge_key])
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
            # *********************************************************************
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
            network = nx.MultiDiGraph()
    
    Pedro L. Magalhães's avatar
    Pedro L. Magalhães committed
            network.graph["crs"] = "EPSG:4326"
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
            network.graph["simplified"] = False
            # add nodes
    
    Pedro L. Magalhães's avatar
    Pedro L. Magalhães committed
            network.add_nodes_from(
                [
                    (0, {osm.KEY_OSMNX_Y: 56.00, osm.KEY_OSMNX_X: 12.00}),
                    (1, {osm.KEY_OSMNX_Y: 56.01, osm.KEY_OSMNX_X: 12.00}),
                    (2, {osm.KEY_OSMNX_Y: 56.02, osm.KEY_OSMNX_X: 12.01}),
                    (3, {osm.KEY_OSMNX_Y: 56.04, osm.KEY_OSMNX_X: 12.02}),
                ]
            )
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
            # add edges
    
    Pedro L. Magalhães's avatar
    Pedro L. Magalhães committed
            network.add_edges_from(
                [
                    (
                        0,
                        1,
                        0,
                        {
                            osm.KEY_OSMNX_OSMID: 1,
                            osm.KEY_OSMNX_LENGTH: 3,
                            osm.KEY_OSMNX_REVERSED: False,
                            osm.KEY_OSMNX_ONEWAY: False,
                        },
                    ),
                    (
                        1,
                        2,
                        0,
                        {
                            osm.KEY_OSMNX_OSMID: 2,
                            osm.KEY_OSMNX_LENGTH: 4,
                            osm.KEY_OSMNX_REVERSED: False,
                            osm.KEY_OSMNX_ONEWAY: False,
                        },
                    ),
                    (
                        2,
                        3,
                        0,
                        {
                            osm.KEY_OSMNX_OSMID: 3,
                            osm.KEY_OSMNX_LENGTH: 5,
                            osm.KEY_OSMNX_REVERSED: False,
                            osm.KEY_OSMNX_ONEWAY: False,
                        },
                    ),
                ]
            )
            lengths = gis_calc.edge_lengths(
                network, edge_keys=[(0, 1, 0), (1, 2, 0), (2, 3, 0)]
            )
            network.edges[(0, 1, 0)][osm.KEY_OSMNX_LENGTH] = lengths[(0, 1, 0)]
            network.edges[(1, 2, 0)][osm.KEY_OSMNX_LENGTH] = lengths[(1, 2, 0)]
            network.edges[(2, 3, 0)][osm.KEY_OSMNX_LENGTH] = lengths[(2, 3, 0)]
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
            number_edges = network.number_of_edges()
            if project_the_graph:
                network = ox.project_graph(G=network)
    
    Pedro L. Magalhães's avatar
    Pedro L. Magalhães committed
            path = [0, 1, 2, 3]
    
            new_edge_key = gis_mod.replace_path(network, path=path)
            # a new edge should exist
            assert network.has_edge(*new_edge_key)
            # assert that two edges are removed and one is created
    
    Pedro L. Magalhães's avatar
    Pedro L. Magalhães committed
            assert network.number_of_edges() - number_edges == 1 - 3
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
            # intermediate nodes should not exist any longer
            for node in path[1:-1]:
                assert not network.has_node(node)
            # the distances need to match
            assert isclose(
                sum(lengths.values()),
    
                network.edges[new_edge_key][osm.KEY_OSMNX_LENGTH],
    
    Pedro L. Magalhães's avatar
    Pedro L. Magalhães committed
                abs_tol=1e-3,
            )
    
            # the new edge needs to have a geometry because it is not simple
            assert osm.KEY_OSMNX_GEOMETRY in network.edges[new_edge_key]
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
            # the geometry must have 4 points
    
    Pedro L. Magalhães's avatar
    Pedro L. Magalhães committed
            assert (
                len(tuple(network.edges[new_edge_key][osm.KEY_OSMNX_GEOMETRY].coords)) == 4
            )
            new_edge_key_lengths = gis_calc.edge_lengths(network, edge_keys=[new_edge_key])
    
            # the geometry's length needs to match that of the edge's
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
            assert isclose(
    
                network.edges[new_edge_key][osm.KEY_OSMNX_LENGTH],
                new_edge_key_lengths[new_edge_key],
    
    Pedro L. Magalhães's avatar
    Pedro L. Magalhães committed
                abs_tol=1 if not project_the_graph else 7.33,  # 7.327521377403173
            )
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
            # print('hallo2')
    
            # print(tuple(network.edges[new_edge_key][osm.KEY_OSMNX_GEOMETRY].coords))
            # print(network.edges[new_edge_key][osm.KEY_OSMNX_LENGTH])
            # print(new_edge_key_lengths[new_edge_key])
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
            # # *********************************************************************
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
            # smallest possible path, but featuring simplified geometries already
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
            network = nx.MultiDiGraph()
    
    Pedro L. Magalhães's avatar
    Pedro L. Magalhães committed
            network.graph["crs"] = "EPSG:4326"
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
            network.graph["simplified"] = True
            # add nodes
    
    Pedro L. Magalhães's avatar
    Pedro L. Magalhães committed
            network.add_nodes_from(
                [
                    (0, {osm.KEY_OSMNX_Y: 56.00, osm.KEY_OSMNX_X: 12.00}),
                    (1, {osm.KEY_OSMNX_Y: 56.01, osm.KEY_OSMNX_X: 12.00}),
                    (2, {osm.KEY_OSMNX_Y: 56.02, osm.KEY_OSMNX_X: 12.01}),
                ]
            )
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
            # add edges
    
    Pedro L. Magalhães's avatar
    Pedro L. Magalhães committed
            network.add_edges_from(
                [
                    (
                        0,
                        1,
                        0,
                        {
                            osm.KEY_OSMNX_OSMID: 1,
                            osm.KEY_OSMNX_LENGTH: 5,
                            osm.KEY_OSMNX_REVERSED: False,
                            osm.KEY_OSMNX_ONEWAY: False,
                        },
                    ),
                    (
                        1,
                        2,
                        0,
                        {
                            osm.KEY_OSMNX_OSMID: 2,
                            osm.KEY_OSMNX_LENGTH: 10,
                            osm.KEY_OSMNX_REVERSED: False,
                            osm.KEY_OSMNX_ONEWAY: False,
                        },
                    ),
                ]
            )
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
            # build create geometries
    
    Pedro L. Magalhães's avatar
    Pedro L. Magalhães committed
            edge01_geo = LineString([(12.00, 56.00), (11.99, 56.00), (12.00, 56.01)])
            edge12_geo = LineString([(12.00, 56.01), (12.02, 56.00), (12.01, 56.02)])
            network.edges[(0, 1, 0)][osm.KEY_OSMNX_GEOMETRY] = edge01_geo
            network.edges[(1, 2, 0)][osm.KEY_OSMNX_GEOMETRY] = edge12_geo
            lengths = gis_calc.edge_lengths(network, edge_keys=[(0, 1, 0), (1, 2, 0)])
            network.edges[(0, 1, 0)][osm.KEY_OSMNX_LENGTH] = lengths[(0, 1, 0)]
            network.edges[(1, 2, 0)][osm.KEY_OSMNX_LENGTH] = lengths[(1, 2, 0)]
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
            number_edges = network.number_of_edges()
            if project_the_graph:
                network = ox.project_graph(G=network)
    
    Pedro L. Magalhães's avatar
    Pedro L. Magalhães committed
            path = [0, 1, 2]
    
            new_edge_key = gis_mod.replace_path(network, path=path)
            # a new edge should exist
            assert network.has_edge(*new_edge_key)
            # assert that two edges are removed and one is created
    
    Pedro L. Magalhães's avatar
    Pedro L. Magalhães committed
            assert network.number_of_edges() - number_edges == 1 - 2
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
            # intermediate nodes should not exist any longer
            for node in path[1:-1]:
                assert not network.has_node(node)
            # the distances need to match
            assert isclose(
                sum(lengths.values()),
    
                network.edges[new_edge_key][osm.KEY_OSMNX_LENGTH],
    
    Pedro L. Magalhães's avatar
    Pedro L. Magalhães committed
                abs_tol=1e-3,  # 1 if not project_the_graph else 1e-3
            )
    
            # the new edge needs to have a geometry because it is not simple
            assert osm.KEY_OSMNX_GEOMETRY in network.edges[new_edge_key]
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
            # the geometry must have 5 points
    
    Pedro L. Magalhães's avatar
    Pedro L. Magalhães committed
            assert (
                len(tuple(network.edges[new_edge_key][osm.KEY_OSMNX_GEOMETRY].coords)) == 5
            )
            new_edge_key_lengths = gis_calc.edge_lengths(network, edge_keys=[new_edge_key])
    
            # the geometry's length needs to match that of the edge's
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
            assert isclose(
    
                network.edges[new_edge_key][osm.KEY_OSMNX_LENGTH],
                new_edge_key_lengths[new_edge_key],
    
    Pedro L. Magalhães's avatar
    Pedro L. Magalhães committed
                abs_tol=1 if not project_the_graph else 12.2,  # -12.178460200064364
            )
    
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
            # *********************************************************************
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
            # smallest possible path, but featuring reversed geometries already (#1)
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
            network = nx.MultiDiGraph()
    
    Pedro L. Magalhães's avatar
    Pedro L. Magalhães committed
            network.graph["crs"] = "EPSG:4326"
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
            network.graph["simplified"] = True
            # add nodes
    
    Pedro L. Magalhães's avatar
    Pedro L. Magalhães committed
            network.add_nodes_from(
                [
                    (0, {osm.KEY_OSMNX_Y: 56.00, osm.KEY_OSMNX_X: 12.00}),
                    (1, {osm.KEY_OSMNX_Y: 56.01, osm.KEY_OSMNX_X: 12.00}),
                    (2, {osm.KEY_OSMNX_Y: 56.02, osm.KEY_OSMNX_X: 12.01}),
                ]
            )
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
            # add edges
    
    Pedro L. Magalhães's avatar
    Pedro L. Magalhães committed
            network.add_edges_from(
                [
                    (
                        0,
                        1,
                        0,
                        {
                            osm.KEY_OSMNX_OSMID: 1,
                            osm.KEY_OSMNX_LENGTH: 3,
                            osm.KEY_OSMNX_REVERSED: False,
                            osm.KEY_OSMNX_ONEWAY: False,
                        },
                    ),
                    (
                        1,
                        2,
                        0,
                        {
                            osm.KEY_OSMNX_OSMID: 2,
                            osm.KEY_OSMNX_LENGTH: 4,
                            osm.KEY_OSMNX_REVERSED: False,
                            osm.KEY_OSMNX_ONEWAY: False,
                        },
                    ),
                ]
            )
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
            # build create geometries
    
    Pedro L. Magalhães's avatar
    Pedro L. Magalhães committed
            edge01_geo = LineString([(12.00, 56.00), (11.99, 56.00), (12.00, 56.01)])
            edge12_geo = LineString([(12.01, 56.02), (12.02, 56.00), (12.00, 56.01)])
            network.edges[(0, 1, 0)][osm.KEY_OSMNX_GEOMETRY] = edge01_geo
            network.edges[(1, 2, 0)][osm.KEY_OSMNX_GEOMETRY] = edge12_geo
            network.edges[(0, 1, 0)][osm.KEY_OSMNX_REVERSED] = False
            network.edges[(1, 2, 0)][osm.KEY_OSMNX_REVERSED] = True
            lengths = gis_calc.edge_lengths(network, edge_keys=[(0, 1, 0), (1, 2, 0)])
            network.edges[(0, 1, 0)][osm.KEY_OSMNX_LENGTH] = lengths[(0, 1, 0)]
            network.edges[(1, 2, 0)][osm.KEY_OSMNX_LENGTH] = lengths[(1, 2, 0)]
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
            number_edges = network.number_of_edges()
            if project_the_graph:
                network = ox.project_graph(G=network)
    
    Pedro L. Magalhães's avatar
    Pedro L. Magalhães committed
            path = [0, 1, 2]
    
            new_edge_key = gis_mod.replace_path(network, path=path)
            # a new edge should exist
            assert network.has_edge(*new_edge_key)
            # assert that two edges are removed and one is created
    
    Pedro L. Magalhães's avatar
    Pedro L. Magalhães committed
            assert network.number_of_edges() - number_edges == 1 - 2
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
            # intermediate nodes should not exist any longer
            for node in path[1:-1]:
                assert not network.has_node(node)
            # the distances need to match
            assert isclose(
                sum(lengths.values()),
    
                network.edges[new_edge_key][osm.KEY_OSMNX_LENGTH],
    
    Pedro L. Magalhães's avatar
    Pedro L. Magalhães committed
                abs_tol=1e-3,
            )
    
            # the new edge needs to have a geometry because it is not simple
            assert osm.KEY_OSMNX_GEOMETRY in network.edges[new_edge_key]
    
    Pedro L. Magalhães's avatar
    Pedro L. Magalhães committed
            assert (
                len(tuple(network.edges[new_edge_key][osm.KEY_OSMNX_GEOMETRY].coords)) == 5
            )
            new_edge_key_lengths = gis_calc.edge_lengths(network, edge_keys=[new_edge_key])
    
            # the geometry's length needs to match that of the edge's
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
            assert isclose(
    
                network.edges[new_edge_key][osm.KEY_OSMNX_LENGTH],
                new_edge_key_lengths[new_edge_key],
    
    Pedro L. Magalhães's avatar
    Pedro L. Magalhães committed
                abs_tol=1 if not project_the_graph else 12.2,  # -12.178460200064364
            )
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
            # print('hallo4')
    
            # print(tuple(network.edges[new_edge_key][osm.KEY_OSMNX_GEOMETRY].coords))
            # print(network.edges[new_edge_key][osm.KEY_OSMNX_LENGTH])
            # print(new_edge_key_lengths[new_edge_key])
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
            # *********************************************************************
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
            # smallest possible path, but featuring reversed geometries already (#2)
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
            network = nx.MultiDiGraph()
    
    Pedro L. Magalhães's avatar
    Pedro L. Magalhães committed
            network.graph["crs"] = "EPSG:4326"
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
            network.graph["simplified"] = True
            # add nodes
    
    Pedro L. Magalhães's avatar
    Pedro L. Magalhães committed
            network.add_nodes_from(
                [
                    (0, {osm.KEY_OSMNX_Y: 56.00, osm.KEY_OSMNX_X: 12.00}),
                    (1, {osm.KEY_OSMNX_Y: 56.01, osm.KEY_OSMNX_X: 12.00}),
                    (2, {osm.KEY_OSMNX_Y: 56.02, osm.KEY_OSMNX_X: 12.01}),
                ]
            )
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
            # add edges
    
    Pedro L. Magalhães's avatar
    Pedro L. Magalhães committed
            network.add_edges_from(
                [
                    (
                        0,
                        1,
                        0,
                        {
                            osm.KEY_OSMNX_OSMID: 1,
                            osm.KEY_OSMNX_LENGTH: 3,
                            osm.KEY_OSMNX_REVERSED: False,
                            osm.KEY_OSMNX_ONEWAY: False,
                        },
                    ),
                    (
                        1,
                        2,
                        0,
                        {
                            osm.KEY_OSMNX_OSMID: 2,
                            osm.KEY_OSMNX_LENGTH: 4,
                            osm.KEY_OSMNX_REVERSED: False,
                            osm.KEY_OSMNX_ONEWAY: False,
                        },
                    ),
                ]
            )
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
            # build create geometries
    
    Pedro L. Magalhães's avatar
    Pedro L. Magalhães committed
            edge01_geo = LineString([(12.00, 56.01), (11.99, 56.00), (12.00, 56.00)])
            edge12_geo = LineString([(12.00, 56.01), (12.02, 56.00), (12.01, 56.02)])
            network.edges[(0, 1, 0)][osm.KEY_OSMNX_GEOMETRY] = edge01_geo
            network.edges[(1, 2, 0)][osm.KEY_OSMNX_GEOMETRY] = edge12_geo
            network.edges[(0, 1, 0)][osm.KEY_OSMNX_REVERSED] = True
            network.edges[(1, 2, 0)][osm.KEY_OSMNX_REVERSED] = False
            lengths = gis_calc.edge_lengths(network, edge_keys=[(0, 1, 0), (1, 2, 0)])
            network.edges[(0, 1, 0)][osm.KEY_OSMNX_LENGTH] = lengths[(0, 1, 0)]
            network.edges[(1, 2, 0)][osm.KEY_OSMNX_LENGTH] = lengths[(1, 2, 0)]
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
            number_edges = network.number_of_edges()
            if project_the_graph:
                network = ox.project_graph(G=network)
    
    Pedro L. Magalhães's avatar
    Pedro L. Magalhães committed
            path = [0, 1, 2]
    
            new_edge_key = gis_mod.replace_path(network, path=path)
            # a new edge should exist
            assert network.has_edge(*new_edge_key)
            # assert that two edges are removed and one is created
    
    Pedro L. Magalhães's avatar
    Pedro L. Magalhães committed
            assert network.number_of_edges() - number_edges == 1 - 2
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
            # intermediate nodes should not exist any longer
            for node in path[1:-1]:
                assert not network.has_node(node)
            # the distances need to match
            assert isclose(
                sum(lengths.values()),
    
                network.edges[new_edge_key][osm.KEY_OSMNX_LENGTH],
    
    Pedro L. Magalhães's avatar
    Pedro L. Magalhães committed
                abs_tol=1e-3,
            )
    
            # the new edge needs to have a geometry because it is not simple
            assert osm.KEY_OSMNX_GEOMETRY in network.edges[new_edge_key]
    
    Pedro L. Magalhães's avatar
    Pedro L. Magalhães committed
            assert (
                len(tuple(network.edges[new_edge_key][osm.KEY_OSMNX_GEOMETRY].coords)) == 5
            )
            new_edge_key_lengths = gis_calc.edge_lengths(network, edge_keys=[new_edge_key])
    
            # the geometry's length needs to match that of the edge's
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
            assert isclose(
    
                network.edges[new_edge_key][osm.KEY_OSMNX_LENGTH],
                new_edge_key_lengths[new_edge_key],
    
    Pedro L. Magalhães's avatar
    Pedro L. Magalhães committed
                abs_tol=1 if not project_the_graph else 12.2,  # -12.178460200064364
            )
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
            # print('hallo5')
    
            # print(tuple(network.edges[new_edge_key][osm.KEY_OSMNX_GEOMETRY].coords))
            # print(network.edges[new_edge_key][osm.KEY_OSMNX_LENGTH])
            # print(new_edge_key_lengths[new_edge_key])
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
            # *********************************************************************
    
            # small path with 3 edges, but featuring reversed geometries already
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
            network = nx.MultiDiGraph()
    
    Pedro L. Magalhães's avatar
    Pedro L. Magalhães committed
            network.graph["crs"] = "EPSG:4326"
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
            network.graph["simplified"] = True
            # add nodes
    
    Pedro L. Magalhães's avatar
    Pedro L. Magalhães committed
            network.add_nodes_from(
                [
                    (0, {osm.KEY_OSMNX_Y: 56.00, osm.KEY_OSMNX_X: 12.00}),
                    (1, {osm.KEY_OSMNX_Y: 56.01, osm.KEY_OSMNX_X: 12.00}),
                    (2, {osm.KEY_OSMNX_Y: 56.02, osm.KEY_OSMNX_X: 12.01}),
                    (3, {osm.KEY_OSMNX_Y: 56.04, osm.KEY_OSMNX_X: 12.02}),
                ]
            )
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
            # add edges
    
    Pedro L. Magalhães's avatar
    Pedro L. Magalhães committed
            network.add_edges_from(
                [
                    (
                        0,
                        1,
                        0,
                        {
                            osm.KEY_OSMNX_OSMID: 1,
                            osm.KEY_OSMNX_LENGTH: 6,
                            osm.KEY_OSMNX_REVERSED: False,
                            osm.KEY_OSMNX_ONEWAY: False,
                        },
                    ),
                    (
                        1,
                        2,
                        0,
                        {
                            osm.KEY_OSMNX_OSMID: 2,
                            osm.KEY_OSMNX_LENGTH: 7,
                            osm.KEY_OSMNX_REVERSED: False,
                            osm.KEY_OSMNX_ONEWAY: False,
                        },
                    ),
                    (
                        2,
                        3,
                        0,
                        {
                            osm.KEY_OSMNX_OSMID: 3,
                            osm.KEY_OSMNX_LENGTH: 8,
                            osm.KEY_OSMNX_REVERSED: False,
                            osm.KEY_OSMNX_ONEWAY: False,
                        },
                    ),
                ]
            )
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
            # build create geometries
    
    Pedro L. Magalhães's avatar
    Pedro L. Magalhães committed
            edge01_geo = LineString([(12.00, 56.00), (11.99, 56.02), (12.00, 56.01)])
            edge12_geo = LineString([(12.00, 56.01), (12.02, 56.00), (12.01, 56.02)])
            edge23_geo = LineString([(12.01, 56.02), (12.05, 56.10), (12.02, 56.04)])
            network.edges[(0, 1, 0)][osm.KEY_OSMNX_GEOMETRY] = edge01_geo
            network.edges[(1, 2, 0)][osm.KEY_OSMNX_GEOMETRY] = edge12_geo
            network.edges[(2, 3, 0)][osm.KEY_OSMNX_GEOMETRY] = edge23_geo
            network.edges[(0, 1, 0)][osm.KEY_OSMNX_REVERSED] = False
            network.edges[(1, 2, 0)][osm.KEY_OSMNX_REVERSED] = True
            network.edges[(2, 3, 0)][osm.KEY_OSMNX_REVERSED] = False
            lengths = gis_calc.edge_lengths(
                network, edge_keys=[(0, 1, 0), (1, 2, 0), (2, 3, 0)]
            )
            network.edges[(0, 1, 0)][osm.KEY_OSMNX_LENGTH] = lengths[(0, 1, 0)]
            network.edges[(1, 2, 0)][osm.KEY_OSMNX_LENGTH] = lengths[(1, 2, 0)]
            network.edges[(2, 3, 0)][osm.KEY_OSMNX_LENGTH] = lengths[(2, 3, 0)]
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
            number_edges = network.number_of_edges()
            if project_the_graph:
                network = ox.project_graph(G=network)
    
    Pedro L. Magalhães's avatar
    Pedro L. Magalhães committed
            path = [0, 1, 2, 3]
    
            new_edge_key = gis_mod.replace_path(network, path=path)
            # a new edge should exist
            assert network.has_edge(*new_edge_key)
            # assert that two edges are removed and one is created
    
    Pedro L. Magalhães's avatar
    Pedro L. Magalhães committed
            assert network.number_of_edges() - number_edges == 1 - 3
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
            # intermediate nodes should not exist any longer
            for node in path[1:-1]:
                assert not network.has_node(node)
            # the distances need to match
            assert isclose(
                sum(lengths.values()),
    
                network.edges[new_edge_key][osm.KEY_OSMNX_LENGTH],
    
    Pedro L. Magalhães's avatar
    Pedro L. Magalhães committed
                abs_tol=1e-3,
            )
    
            # the new edge needs to have a geometry because it is not simple
            assert osm.KEY_OSMNX_GEOMETRY in network.edges[new_edge_key]
    
    Pedro L. Magalhães's avatar
    Pedro L. Magalhães committed
            assert (
                len(tuple(network.edges[new_edge_key][osm.KEY_OSMNX_GEOMETRY].coords)) == 7
            )
            new_edge_key_lengths = gis_calc.edge_lengths(network, edge_keys=[new_edge_key])
    
            # the geometry's length needs to match that of the edge's
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
            assert isclose(
    
                network.edges[new_edge_key][osm.KEY_OSMNX_LENGTH],
                new_edge_key_lengths[new_edge_key],
    
    Pedro L. Magalhães's avatar
    Pedro L. Magalhães committed
                abs_tol=1 if not project_the_graph else 37.77,  # -37.76434146326574
            )
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
            # print('hallo6')
    
            # print(tuple(network.edges[new_edge_key][osm.KEY_OSMNX_GEOMETRY].coords))
            # print(network.edges[new_edge_key][osm.KEY_OSMNX_LENGTH])
            # print(new_edge_key_lengths[new_edge_key])
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
            # *********************************************************************
            # *********************************************************************
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
        # *************************************************************************
        # *************************************************************************
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
        def test_replace_paths_unprojected(self):
            self.example_replace_paths(project_the_graph=False)
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
            # *********************************************************************
            # *********************************************************************
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
        # *************************************************************************
        # *************************************************************************
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
        def test_replace_paths_projected(self):
            self.example_replace_paths(project_the_graph=True)
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
            # *********************************************************************
            # *********************************************************************
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
        # *************************************************************************
        # *************************************************************************
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
        def test_remove_reversed_edges(self):
            # get the network
            network = ox.graph_from_point(
    
    Pedro L. Magalhães's avatar
    Pedro L. Magalhães committed
                (55.71654, 9.11728),
                network_type="drive",
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
                custom_filter='["highway"~"residential|tertiary|unclassified|service"]',
    
    Pedro L. Magalhães's avatar
    Pedro L. Magalhães committed
                truncate_by_edge=True,
            )
    
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
            _net = network.copy()
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
            reversed_attribute = False
            removed_edges = gis_mod.remove_reversed_edges(
    
    Pedro L. Magalhães's avatar
    Pedro L. Magalhães committed
                network=_net, reversed_attr=reversed_attribute
            )
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
            # verify that all edges have the correct attribute
            for edge_key in removed_edges:
                # confirm that there is at least one edge in reverse
                reverse_edge_found = False
    
    pmag's avatar
    pmag committed
                for other_edge_key in gis_iden.get_edges_from_a_to_b(
    
    Pedro L. Magalhães's avatar
    Pedro L. Magalhães committed
                    network, edge_key[1], edge_key[0]
                ):
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
                    if gis_iden.edges_are_in_reverse(
    
    Pedro L. Magalhães's avatar
    Pedro L. Magalhães committed
                        network, edge_key, other_edge_key
                    ) and _net.has_edge(*other_edge_key):
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
                        # other_edge_key is a reversed edge and is still on _net
                        reverse_edge_found = True
                        break
                assert reverse_edge_found
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
            # *********************************************************************
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
            # repeat for True argument
            _net = network.copy()
            reversed_attribute = True
            removed_edges = gis_mod.remove_reversed_edges(
    
    Pedro L. Magalhães's avatar
    Pedro L. Magalhães committed
                network=_net, reversed_attr=reversed_attribute
            )
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
            # verify that all edges have the correct attribute
            for edge_key in removed_edges:
                # confirm that there is at least one edge in reverse
                reverse_edge_found = False
    
    pmag's avatar
    pmag committed
                for other_edge_key in gis_iden.get_edges_from_a_to_b(
    
    Pedro L. Magalhães's avatar
    Pedro L. Magalhães committed
                    network, edge_key[1], edge_key[0]
                ):
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
                    if gis_iden.edges_are_in_reverse(
    
    Pedro L. Magalhães's avatar
    Pedro L. Magalhães committed
                        network, edge_key, other_edge_key
                    ) and _net.has_edge(*other_edge_key):
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
                        # other_edge_key is a reversed edge and is still on _net
                        reverse_edge_found = True
                        break
                assert reverse_edge_found
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
        # *************************************************************************
        # *************************************************************************
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
        def test_remove_self_loops(self):
            # find one self-loop
            network = nx.MultiDiGraph()
    
    Pedro L. Magalhães's avatar
    Pedro L. Magalhães committed
            network.add_edges_from([(0, 1, 0), (1, 2, 0), (2, 0, 0), (1, 1, 0)])
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
            true_selflooping_nodes = [1]
            selflooping_nodes = gis_mod.remove_self_loops(network)
            assert len(selflooping_nodes) == len(true_selflooping_nodes)
            for node_key in selflooping_nodes:
                assert node_key in true_selflooping_nodes
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
            # find two self-loops
            network = nx.MultiDiGraph()
    
    Pedro L. Magalhães's avatar
    Pedro L. Magalhães committed
            network.add_edges_from([(0, 1, 0), (1, 2, 0), (2, 0, 0), (1, 1, 0), (2, 2, 0)])
            true_selflooping_nodes = [1, 2]
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
            selflooping_nodes = gis_mod.remove_self_loops(network)
            assert len(selflooping_nodes) == len(true_selflooping_nodes)
    
    Pedro L. Magalhães's avatar
    Pedro L. Magalhães committed
            for node_key in selflooping_nodes:
                assert node_key in true_selflooping_nodes
    
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
            # find no self-loops
            network = nx.MultiDiGraph()
    
    Pedro L. Magalhães's avatar
    Pedro L. Magalhães committed
            network.add_edges_from([(0, 1, 0), (1, 2, 0), (2, 0, 0)])
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
            selflooping_nodes = gis_mod.remove_self_loops(network)
            assert len(selflooping_nodes) == 0
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
        # *************************************************************************
        # *************************************************************************
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
            # simple example
            network = nx.MultiDiGraph()
    
    Pedro L. Magalhães's avatar
    Pedro L. Magalhães committed
            network.add_edges_from(
                [
                    (0, 1, 0, {"length": 3}),
                    (1, 2, 0, {"length": 4}),
                    (2, 0, 0, {"length": 5}),
                    # additional edges
                    (0, 1, 1, {"length": 4}),
                    (1, 2, 1, {"length": 5}),
                    (2, 0, 1, {"length": 6}),
                ]
            )
    
            initial_number_edges = network.number_of_edges()
    
    Pedro L. Magalhães's avatar
    Pedro L. Magalhães committed
            true_edges_removed = [(0, 1, 1), (1, 2, 1), (2, 0, 1)]
    
            edges_removed = gis_mod.remove_longer_parallel_edges(network)
            assert len(edges_removed) == len(true_edges_removed)
            for edge_key in edges_removed:
                assert edge_key in true_edges_removed
            assert network.number_of_edges() == initial_number_edges - len(edges_removed)
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
            # example with more than one alternative
            network = nx.MultiDiGraph()
    
    Pedro L. Magalhães's avatar
    Pedro L. Magalhães committed
            network.add_edges_from(
                [
                    (0, 1, 0, {"length": 3}),
                    (1, 2, 0, {"length": 4}),
                    (2, 0, 0, {"length": 5}),
                    # additional edges
                    (0, 1, 1, {"length": 4}),
                    (0, 1, 2, {"length": 5}),
                    (0, 1, 3, {"length": 6}),
                ]
            )
    
            initial_number_edges = network.number_of_edges()
    
    Pedro L. Magalhães's avatar
    Pedro L. Magalhães committed
            true_edges_removed = [(0, 1, 1), (0, 1, 2), (0, 1, 3)]
    
            edges_removed = gis_mod.remove_longer_parallel_edges(network)
            assert len(edges_removed) == len(true_edges_removed)
            for edge_key in edges_removed:
                assert edge_key in true_edges_removed
            assert network.number_of_edges() == initial_number_edges - len(edges_removed)
    
            # example with opposite edges (that won't be removed)
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
            network = nx.MultiDiGraph()
    
    Pedro L. Magalhães's avatar
    Pedro L. Magalhães committed
            network.add_edges_from(
                [
                    (0, 1, 0, {"length": 3}),
                    (1, 2, 0, {"length": 4}),
                    (2, 0, 0, {"length": 5}),
                    # additional edges
                    (0, 1, 1, {"length": 4}),
                    (1, 2, 1, {"length": 5}),
                    (2, 0, 1, {"length": 6}),
                    # oppposite edges
                    (1, 0, 0, {"length": 7}),
                    (2, 1, 0, {"length": 8}),
                    (0, 2, 0, {"length": 9}),
                ]
            )
    
            initial_number_edges = network.number_of_edges()
    
    Pedro L. Magalhães's avatar
    Pedro L. Magalhães committed
            true_edges_removed = [(0, 1, 1), (1, 2, 1), (2, 0, 1)]
    
            edges_removed = gis_mod.remove_longer_parallel_edges(network)
            assert len(edges_removed) == len(true_edges_removed)
            for edge_key in edges_removed:
                assert edge_key in true_edges_removed
            assert network.number_of_edges() == initial_number_edges - len(edges_removed)
    
            # example with opposite edges (that will be removed)
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
            network = nx.MultiDiGraph()
    
    Pedro L. Magalhães's avatar
    Pedro L. Magalhães committed
            network.add_edges_from(
                [
                    (0, 1, 0, {"length": 3}),
                    (1, 2, 0, {"length": 4}),
                    (2, 0, 0, {"length": 5}),
                    # additional edges
                    (0, 1, 1, {"length": 4}),
                    (1, 2, 1, {"length": 5}),
                    (2, 0, 1, {"length": 6}),
                    # oppposite edges
                    (1, 0, 0, {"length": 7}),
                    (2, 1, 0, {"length": 8}),
                    (0, 2, 0, {"length": 9}),
                ]
            )
    
            initial_number_edges = network.number_of_edges()
            true_edges_removed = [
    
    Pedro L. Magalhães's avatar
    Pedro L. Magalhães committed
                (0, 1, 1),
                (1, 2, 1),
                (2, 0, 1),
                (1, 0, 0),
                (2, 1, 0),
                (0, 2, 0),
            ]
    
            edges_removed = gis_mod.remove_longer_parallel_edges(network, True)
            assert len(edges_removed) == len(true_edges_removed)
            for edge_key in edges_removed:
                assert edge_key in true_edges_removed
            assert network.number_of_edges() == initial_number_edges - len(edges_removed)
    
    Pedro Magalhães's avatar
    Pedro Magalhães committed
            # test using non-integers as node keys
            network = nx.MultiDiGraph()
    
    Pedro L. Magalhães's avatar
    Pedro L. Magalhães committed
            network.add_edges_from(
                [
                    (0, "a", 0, {"length": 3}),
                    ("a", "b", 0, {"length": 4}),
                    ("b", 0, 0, {"length": 5}),
                    # additional edges
                    (0, "a", 1, {"length": 4}),
                    ("a", "b", 1, {"length": 5}),
                    ("b", 0, 1, {"length": 6}),
                    # oppposite edges
                    ("a", 0, 0, {"length": 7}),
                    ("b", "a", 0, {"length": 8}),
                    (0, "b", 0, {"length": 9}),
                ]
            )
    
            initial_number_edges = network.number_of_edges()
            true_edges_removed = [
    
    Pedro L. Magalhães's avatar
    Pedro L. Magalhães committed
                (0, "a", 1),
                ("a", "b", 1),
                ("b", 0, 1),
                ("a", 0, 0),
                ("b", "a", 0),
                (0, "b", 0),
            ]
    
            edges_removed = gis_mod.remove_longer_parallel_edges(network, True)
            assert len(edges_removed) == len(true_edges_removed)
    
    Pedro L. Magalhães's avatar
    Pedro L. Magalhães committed
            for edge_key in edges_removed:
    
                assert edge_key in true_edges_removed
            assert network.number_of_edges() == initial_number_edges - len(edges_removed)