Newer
Older
# 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
# 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
# *****************************************************************************
# *****************************************************************************
class TestGisModify:
# *************************************************************************
# *************************************************************************
def test_create_reverse_edges(self):
network = nx.MultiDiGraph()
node_key0_dict = {osm.KEY_OSMNX_X: 55, osm.KEY_OSMNX_Y: 25}
node_key1_dict = {osm.KEY_OSMNX_X: 55.001, osm.KEY_OSMNX_Y: 25.001}
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
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]),
]
)
# the same line, reversed
geo_line_reversed = geo_line.reverse()
0,
1,
**{
osm.KEY_OSMNX_LENGTH: 3,
osm.KEY_OSMNX_REVERSED: False,
osm.KEY_OSMNX_OSMID: 1,
osm.KEY_OSMNX_ONEWAY: False,
}
)
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,
}
)
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,
}
)
# 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)
assert network.number_of_edges() == 3
new_edges = gis_mod.create_reverse_edges(network)
assert len(new_edges) == 3
# trigger no edge found error
error_raised = False
try:
gis_mod.create_reverse_edges(network, [edge_key])
except ValueError:
error_raised = True
assert error_raised
# trigger valuerror due to incorrect reversed type
k_error = network.add_edge(
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,
}
)
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
# *************************************************************************
# *************************************************************************
def test_replace_paths_osmnx(self):
# get the network
_net = ox.graph_from_point(
Pedro L. Magalhães
committed
(55.71654, 9.11728),
custom_filter='["highway"~"residential|tertiary|unclassified|service"]',
# define the settings
ignore_self_loops = False
consider_reversed_edges = True
Pedro L. Magalhães
committed
# find paths
paths = gis_iden.find_simplifiable_paths(
Pedro L. Magalhães
committed
excluded_nodes=[],
ignore_self_loops=ignore_self_loops,
consider_reversed_edges=consider_reversed_edges,
)
# verify the paths
for path in paths:
gis_iden.is_path_straight(
_net,
path,
consider_reversed_edges=consider_reversed_edges,
ignore_self_loops=ignore_self_loops,
)
Pedro L. Magalhães
committed
# modify an edge in one of the paths to have list attributes
_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
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]],
}
)
true_path_lengths = [gis_calc.node_path_length(_net, path) for path in paths]
new_path_edges = [gis_mod.replace_path(_net, path) for path in paths]
Pedro L. Magalhães
committed
for edge_key, true_length in zip(new_path_edges, true_path_lengths):
Pedro L. Magalhães
committed
_net.edges[edge_key][gis_iden.osm.KEY_OSMNX_LENGTH],
Pedro L. Magalhães
committed
# *************************************************************************
# *************************************************************************
Pedro L. Magalhães
committed
def test_replace_nonsimplifiable_path(self):
_net = nx.MultiDiGraph()
Pedro L. Magalhães
committed
path = [0, 1]
Pedro L. Magalhães
committed
error_raised = False
try:
gis_mod.replace_path(_net, path)
except ValueError:
error_raised = True
assert error_raised
# *************************************************************************
# *************************************************************************
def example_replace_paths(self, project_the_graph: bool = False):
# *********************************************************************
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}),
]
)
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
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)]
number_edges = network.number_of_edges()
if project_the_graph:
network = ox.project_graph(G=network)
Pedro L. Magalhães
committed
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
assert network.number_of_edges() - number_edges == 1 - 2
# 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()),
Pedro L. Magalhães
committed
network.edges[new_edge_key][osm.KEY_OSMNX_LENGTH],
Pedro L. Magalhães
committed
# the new edge needs to have a geometry because it is not simple
assert osm.KEY_OSMNX_GEOMETRY in network.edges[new_edge_key]
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])
Pedro L. Magalhães
committed
# the geometry's length needs to match that of the edge's
Pedro L. Magalhães
committed
network.edges[new_edge_key][osm.KEY_OSMNX_LENGTH],
new_edge_key_lengths[new_edge_key],
abs_tol=1 if not project_the_graph else 3.861, # 3.8601244551728087
)
Pedro L. Magalhães
committed
# 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 L. Magalhães
committed
# small path with 3 edges
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}),
]
)
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
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)]
number_edges = network.number_of_edges()
if project_the_graph:
network = ox.project_graph(G=network)
Pedro L. Magalhães
committed
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
assert network.number_of_edges() - number_edges == 1 - 3
# 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()),
Pedro L. Magalhães
committed
network.edges[new_edge_key][osm.KEY_OSMNX_LENGTH],
Pedro L. Magalhães
committed
# the new edge needs to have a geometry because it is not simple
assert osm.KEY_OSMNX_GEOMETRY in network.edges[new_edge_key]
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])
Pedro L. Magalhães
committed
# the geometry's length needs to match that of the edge's
Pedro L. Magalhães
committed
network.edges[new_edge_key][osm.KEY_OSMNX_LENGTH],
new_edge_key_lengths[new_edge_key],
abs_tol=1 if not project_the_graph else 7.33, # 7.327521377403173
)
Pedro L. Magalhães
committed
# 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])
# # *********************************************************************
# smallest possible path, but featuring simplified geometries already
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}),
]
)
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
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,
},
),
]
)
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)]
number_edges = network.number_of_edges()
if project_the_graph:
network = ox.project_graph(G=network)
Pedro L. Magalhães
committed
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
assert network.number_of_edges() - number_edges == 1 - 2
# 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()),
Pedro L. Magalhães
committed
network.edges[new_edge_key][osm.KEY_OSMNX_LENGTH],
abs_tol=1e-3, # 1 if not project_the_graph else 1e-3
)
Pedro L. Magalhães
committed
# the new edge needs to have a geometry because it is not simple
assert osm.KEY_OSMNX_GEOMETRY in network.edges[new_edge_key]
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])
Pedro L. Magalhães
committed
# the geometry's length needs to match that of the edge's
Pedro L. Magalhães
committed
network.edges[new_edge_key][osm.KEY_OSMNX_LENGTH],
new_edge_key_lengths[new_edge_key],
abs_tol=1 if not project_the_graph else 12.2, # -12.178460200064364
)
# *********************************************************************
# smallest possible path, but featuring reversed geometries already (#1)
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}),
]
)
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
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,
},
),
]
)
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)]
number_edges = network.number_of_edges()
if project_the_graph:
network = ox.project_graph(G=network)
Pedro L. Magalhães
committed
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
assert network.number_of_edges() - number_edges == 1 - 2
# 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()),
Pedro L. Magalhães
committed
network.edges[new_edge_key][osm.KEY_OSMNX_LENGTH],
Pedro L. Magalhães
committed
# the new edge needs to have a geometry because it is not simple
assert osm.KEY_OSMNX_GEOMETRY in network.edges[new_edge_key]
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])
Pedro L. Magalhães
committed
# the geometry's length needs to match that of the edge's
Pedro L. Magalhães
committed
network.edges[new_edge_key][osm.KEY_OSMNX_LENGTH],
new_edge_key_lengths[new_edge_key],
abs_tol=1 if not project_the_graph else 12.2, # -12.178460200064364
)
Pedro L. Magalhães
committed
# 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])
# *********************************************************************
# smallest possible path, but featuring reversed geometries already (#2)
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}),
]
)
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
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,
},
),
]
)
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)]
number_edges = network.number_of_edges()
if project_the_graph:
network = ox.project_graph(G=network)
Pedro L. Magalhães
committed
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
assert network.number_of_edges() - number_edges == 1 - 2
# 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()),
Pedro L. Magalhães
committed
network.edges[new_edge_key][osm.KEY_OSMNX_LENGTH],
Pedro L. Magalhães
committed
# the new edge needs to have a geometry because it is not simple
assert osm.KEY_OSMNX_GEOMETRY in network.edges[new_edge_key]
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])
Pedro L. Magalhães
committed
# the geometry's length needs to match that of the edge's
Pedro L. Magalhães
committed
network.edges[new_edge_key][osm.KEY_OSMNX_LENGTH],
new_edge_key_lengths[new_edge_key],
abs_tol=1 if not project_the_graph else 12.2, # -12.178460200064364
)
Pedro L. Magalhães
committed
# 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 L. Magalhães
committed
# small path with 3 edges, but featuring reversed geometries already
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}),
]
)
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
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,
},
),
]
)
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)]
number_edges = network.number_of_edges()
if project_the_graph:
network = ox.project_graph(G=network)
Pedro L. Magalhães
committed
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
assert network.number_of_edges() - number_edges == 1 - 3
# 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()),
Pedro L. Magalhães
committed
network.edges[new_edge_key][osm.KEY_OSMNX_LENGTH],
Pedro L. Magalhães
committed
# the new edge needs to have a geometry because it is not simple
assert osm.KEY_OSMNX_GEOMETRY in network.edges[new_edge_key]
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])
Pedro L. Magalhães
committed
# the geometry's length needs to match that of the edge's
Pedro L. Magalhães
committed
network.edges[new_edge_key][osm.KEY_OSMNX_LENGTH],
new_edge_key_lengths[new_edge_key],
abs_tol=1 if not project_the_graph else 37.77, # -37.76434146326574
)
Pedro L. Magalhães
committed
# 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])
# *********************************************************************
# *********************************************************************
# *************************************************************************
# *************************************************************************
def test_replace_paths_unprojected(self):
self.example_replace_paths(project_the_graph=False)
# *********************************************************************
# *********************************************************************
# *************************************************************************
# *************************************************************************
def test_replace_paths_projected(self):
self.example_replace_paths(project_the_graph=True)
# *********************************************************************
# *********************************************************************
# *************************************************************************
# *************************************************************************
def test_remove_reversed_edges(self):
# get the network
network = ox.graph_from_point(
custom_filter='["highway"~"residential|tertiary|unclassified|service"]',
reversed_attribute = False
removed_edges = gis_mod.remove_reversed_edges(
network=_net, reversed_attr=reversed_attribute
)
# 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
network, edge_key, other_edge_key
) and _net.has_edge(*other_edge_key):
# other_edge_key is a reversed edge and is still on _net
reverse_edge_found = True
break
assert reverse_edge_found
# *********************************************************************
# repeat for True argument
_net = network.copy()
reversed_attribute = True
removed_edges = gis_mod.remove_reversed_edges(
network=_net, reversed_attr=reversed_attribute
)
# 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
network, edge_key, other_edge_key
) and _net.has_edge(*other_edge_key):
# other_edge_key is a reversed edge and is still on _net
reverse_edge_found = True
break
assert reverse_edge_found
# *************************************************************************
# *************************************************************************
def test_remove_self_loops(self):
# find one self-loop
network = nx.MultiDiGraph()
network.add_edges_from([(0, 1, 0), (1, 2, 0), (2, 0, 0), (1, 1, 0)])
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
# find two self-loops
network = nx.MultiDiGraph()
network.add_edges_from([(0, 1, 0), (1, 2, 0), (2, 0, 0), (1, 1, 0), (2, 2, 0)])
true_selflooping_nodes = [1, 2]
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
network.add_edges_from([(0, 1, 0), (1, 2, 0), (2, 0, 0)])
selflooping_nodes = gis_mod.remove_self_loops(network)
assert len(selflooping_nodes) == 0
# *************************************************************************
# *************************************************************************
Pedro L. Magalhães
committed
def test_remove_longer_edges(self):
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}),
]
)
Pedro L. Magalhães
committed
initial_number_edges = network.number_of_edges()
true_edges_removed = [(0, 1, 1), (1, 2, 1), (2, 0, 1)]
Pedro L. Magalhães
committed
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 more than one alternative
network = nx.MultiDiGraph()
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}),
]
)
Pedro L. Magalhães
committed
initial_number_edges = network.number_of_edges()
true_edges_removed = [(0, 1, 1), (0, 1, 2), (0, 1, 3)]
Pedro L. Magalhães
committed
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 L. Magalhães
committed
# example with opposite edges (that won't be removed)
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}),
]
)
Pedro L. Magalhães
committed
initial_number_edges = network.number_of_edges()
true_edges_removed = [(0, 1, 1), (1, 2, 1), (2, 0, 1)]
Pedro L. Magalhães
committed
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 L. Magalhães
committed
# example with opposite edges (that will be removed)
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}),
]
)
Pedro L. Magalhães
committed
initial_number_edges = network.number_of_edges()
true_edges_removed = [
(0, 1, 1),
(1, 2, 1),
(2, 0, 1),
(1, 0, 0),
(2, 1, 0),
(0, 2, 0),
]
Pedro L. Magalhães
committed
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)
# test using non-integers as node keys
network = nx.MultiDiGraph()
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}),
]
)
Pedro L. Magalhães
committed
initial_number_edges = network.number_of_edges()
true_edges_removed = [
(0, "a", 1),
("a", "b", 1),
("b", 0, 1),
("a", 0, 0),
("b", "a", 0),
(0, "b", 0),
]
Pedro L. Magalhães
committed
edges_removed = gis_mod.remove_longer_parallel_edges(network, True)
assert len(edges_removed) == len(true_edges_removed)
Pedro L. Magalhães
committed
assert edge_key in true_edges_removed
assert network.number_of_edges() == initial_number_edges - len(edges_removed)