Skip to content

Commit 274f131

Browse files
Merge branch 'yaramo2' into detect-implausible-switches
# Conflicts: # test/node_test.py # yaramo/node.py
2 parents de0fac3 + bc9edae commit 274f131

File tree

14 files changed

+848
-579
lines changed

14 files changed

+848
-579
lines changed

poetry.lock

Lines changed: 337 additions & 357 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
[tool.poetry]
22
name = "yaramo"
3-
version = "0.2"
3+
version = "2.0"
44
description = "yaramo is a railway model focusing on interoperability between different existing planning formats."
55
authors = ["OSM at HPI <arne.boockmeyer@hpi.de>"]
66
readme = "README.md"
77
packages = [{include = "yaramo"}]
88

99
[tool.poetry.dependencies]
10-
python = "^3.9"
10+
python = "^3.11"
1111
pyproj = "^3.6.1"
1212
simplejson = "^3.19.2"
1313

@@ -16,7 +16,7 @@ simplejson = "^3.19.2"
1616
black = "^22.12.0"
1717
pylint = "^2.15.10"
1818
pre-commit = "^3.0.0"
19-
pytest = "^7.2.1"
19+
pytest = "^8.0.0"
2020

2121
[build-system]
2222
requires = ["poetry-core"]
@@ -28,11 +28,15 @@ line-length = 100
2828
[tool.pylint.format]
2929
max-line-length = "100"
3030

31-
3231
[tool.isort]
3332
multi_line_output = 3
3433
include_trailing_comma = true
3534
force_grid_wrap = 0
3635
use_parentheses = true
3736
ensure_newline_before_comments = true
3837
line_length = 100
38+
39+
[tool.pytest.ini_options]
40+
addopts = [
41+
"--import-mode=importlib",
42+
]

test/helper.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
from yaramo.model import Edge, Node, Wgs84GeoNode
2+
3+
4+
def create_geo_node(x, y):
5+
return Wgs84GeoNode(x, y)
6+
7+
8+
def create_node(x, y):
9+
return Node(geo_node=create_geo_node(x, y))
10+
11+
12+
def create_edge(node_a, node_b, inter_geo_nodes=None):
13+
return Edge(node_a, node_b, intermediate_geo_nodes=inter_geo_nodes)

test/node_test.py

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,13 @@
33
from pytest import raises
44

55
from yaramo.geo_node import Wgs84GeoNode
6-
from yaramo.node import Node
6+
from yaramo.model import Node
77

8-
9-
def create_node(x, y):
10-
return Node(geo_node=Wgs84GeoNode(x, y))
8+
from .helper import create_edge, create_node
119

1210

1311
def coords_str(node: Node):
14-
return f"({node.geo_node.geo_point.x}, {node.geo_node.geo_point.y})"
12+
return f"({node.geo_node.x}, {node.geo_node.y})"
1513

1614

1715
def test_anschluss():
@@ -105,10 +103,14 @@ def test_anschluss():
105103

106104
# apply offsets to base scenario, set up nodes and actually test
107105
for offset_x, offset_y in product(offsets, repeat=2):
108-
head = create_node(hx + offset_x, hy + offset_y)
109106
switch = create_node(sx + offset_x, sy + offset_y)
107+
108+
head = create_node(hx + offset_x, hy + offset_y)
109+
create_edge(switch, head)
110110
left = create_node(lx + offset_x, ly + offset_y)
111+
create_edge(switch, left)
111112
right = create_node(rx + offset_x, ry + offset_y)
113+
create_edge(switch, right)
112114

113115
print(
114116
"scenario:",
@@ -122,11 +124,8 @@ def test_anschluss():
122124
coords_str(right),
123125
)
124126

125-
# connect all nodes to the switch
126-
switch.connected_nodes.extend((head, left, right))
127-
128127
# finally call the procedure we want to test here
129-
switch.calc_anschluss_of_all_nodes()
128+
switch.calc_anschluss_of_all_edges()
130129

131130
# assert ``calc_anschluss_of_all_nodes`` did what it should
132131
assert switch.connected_on_head == head, (
@@ -144,11 +143,11 @@ def test_implausible_anschluss():
144143
"""Assert that detection of "Anschluss" (head, left, right) raises
145144
an exception on really implausible geographies."""
146145
head = create_node(0, 0) # layout:
147-
switch = create_node(2, 2) # l
146+
point = create_node(2, 2) # l
148147
left = create_node(1, 3) # s r
149148
right = create_node(3, 2) # h
150149

151-
switch.connected_nodes.extend((head, left, right))
150+
point.connected_nodes.extend((head, left, right))
152151

153152
with raises(Exception) as exception:
154-
switch.calc_anschluss_of_all_nodes()
153+
point.calc_anschluss_of_all_nodes()

test/point_test.py

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
import pytest
2+
3+
from yaramo.edge import Edge
4+
from yaramo.node import Node
5+
from yaramo.topology import Topology
6+
7+
from .helper import create_node
8+
9+
10+
@pytest.fixture
11+
def straight_track():
12+
# Note that this kind of topology shouldn't exist
13+
node1 = Node()
14+
node2 = Node()
15+
node3 = Node()
16+
17+
edge1 = Edge(node1, node2, length=100)
18+
edge2 = Edge(node2, node3, length=100)
19+
20+
topology = Topology()
21+
topology.add_node(node1)
22+
topology.add_node(node2)
23+
topology.add_node(node3)
24+
topology.add_edge(edge1)
25+
topology.add_edge(edge2)
26+
27+
return topology
28+
29+
30+
@pytest.fixture
31+
def point():
32+
node1 = create_node(0, 10)
33+
point = create_node(50, 10)
34+
node2 = create_node(100, 10)
35+
node3 = create_node(100, 20)
36+
37+
edge1 = Edge(node1, point, length=50)
38+
edge2 = Edge(point, node2, length=50)
39+
edge3 = Edge(point, node3, length=50)
40+
41+
topology = Topology()
42+
topology.add_node(node1)
43+
topology.add_node(point)
44+
topology.add_node(node2)
45+
topology.add_node(node3)
46+
topology.add_edge(edge1)
47+
topology.add_edge(edge2)
48+
topology.add_edge(edge3)
49+
50+
return topology
51+
52+
53+
if __name__ == "__main__":
54+
straight_track()
55+
point()
56+
57+
58+
def test_detect_switch(point):
59+
topology = point
60+
61+
point_count = 0
62+
63+
for node in topology.nodes.values():
64+
if node.is_point():
65+
point_count += 1
66+
67+
assert point_count == 1
68+
69+
70+
def test_dont_detect_straight(straight_track):
71+
topology = straight_track
72+
73+
point_count = 0
74+
75+
for node in topology.nodes.values():
76+
if node.is_point():
77+
point_count += 1
78+
79+
assert point_count == 0

test/topology_test.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
from yaramo.model import Edge, Node, Topology
22

3+
from .helper import create_edge, create_geo_node, create_node
4+
35

46
def test_get_edge_by_nodes():
57
topology = Topology()
@@ -42,3 +44,42 @@ def test_json_export_and_import():
4244
assert len(topology.edges) == len(topology_copy.edges)
4345
assert len(topology.signals) == len(topology_copy.signals)
4446
assert len(topology.routes) == len(topology_copy.routes)
47+
48+
49+
def test_station_topology():
50+
"""
51+
This test creates this kind of topology:
52+
______
53+
____/______\\____
54+
This kind wouldn't be possible in yaramo 1, since
55+
two edges connect the same points.
56+
"""
57+
end_a = create_node(0, 0)
58+
point_a = create_node(10, 0)
59+
inter_geo_node_a = create_geo_node(13, 1)
60+
inter_geo_node_b = create_geo_node(17, 1)
61+
point_b = create_node(20, 0)
62+
end_b = create_node(30, 0)
63+
64+
edge_1 = create_edge(end_a, point_a)
65+
edge_2a = create_edge(point_a, point_b)
66+
edge_2b = create_edge(point_a, point_b, inter_geo_nodes=[inter_geo_node_a, inter_geo_node_b])
67+
edge_3 = create_edge(point_b, end_b)
68+
69+
end_a.calc_anschluss_of_all_edges()
70+
point_a.calc_anschluss_of_all_edges()
71+
point_b.calc_anschluss_of_all_edges()
72+
end_b.calc_anschluss_of_all_edges()
73+
74+
assert len(end_a.connected_edges) == 1
75+
assert end_a.connected_edge_on_head == edge_1
76+
assert len(point_a.connected_edges) == 3
77+
assert point_a.connected_edge_on_head == edge_1
78+
assert point_a.connected_edge_on_left == edge_2b
79+
assert point_a.connected_edge_on_right == edge_2a
80+
assert len(point_b.connected_edges) == 3
81+
assert point_b.connected_edge_on_head == edge_3
82+
assert point_b.connected_edge_on_right == edge_2b
83+
assert point_b.connected_edge_on_left == edge_2a
84+
assert len(end_b.connected_edges) == 1
85+
assert end_b.connected_edge_on_head == edge_3

yaramo/edge.py

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,9 @@ def __init__(
4242
super().__init__(**kwargs)
4343
self.intermediate_geo_nodes = intermediate_geo_nodes or []
4444
self.node_a = node_a
45+
self.node_a.connected_edges.append(self)
4546
self.node_b = node_b
47+
self.node_b.connected_edges.append(self)
4648
self.signals = signals or []
4749
self.length = length
4850
self.maximum_speed = maximum_speed
@@ -77,6 +79,15 @@ def __get_length(self) -> float:
7779
)
7880
return total_length
7981

82+
def get_direction_based_on_start_node(self, start: "Node") -> "SignalDirection":
83+
from yaramo.signal import SignalDirection
84+
85+
if self.node_a.uuid == start.uuid:
86+
return SignalDirection.IN
87+
elif self.node_b.uuid == start.uuid:
88+
return SignalDirection.GEGEN
89+
return None
90+
8091
def get_direction_based_on_nodes(self, node_a: "Node", node_b: "Node") -> "SignalDirection":
8192
"""Returns the direction according to whether the order of node_a and node_b is the same as in self
8293
@@ -132,6 +143,45 @@ def get_signals_with_direction_in_order(self, direction: "SignalDirection") -> L
132143
result.sort(key=lambda x: x.distance_edge, reverse=(direction == SignalDirection.GEGEN))
133144
return result
134145

146+
def get_opposite_node(self, node: "Node") -> "Node":
147+
"""Returns the opposite Node of the given Node
148+
149+
Parameters
150+
----------
151+
node : Node
152+
The Node to get the opposite Node of
153+
154+
Returns
155+
-------
156+
Node
157+
The opposite Node
158+
"""
159+
160+
if self.node_a.uuid == node.uuid:
161+
return self.node_b
162+
return self.node_a
163+
164+
def get_next_geo_node(self, node: "Node") -> "GeoNode":
165+
"""Returns the next GeoNode on Edgeof the given Top Node
166+
167+
Parameters
168+
----------
169+
geo_node : Node
170+
The Top Node to get the next GeoNode of
171+
172+
Returns
173+
-------
174+
GeoNode
175+
The next GeoNode
176+
"""
177+
if len(self.intermediate_geo_nodes) < 2:
178+
return self.get_opposite_node(node).geo_node
179+
if self.node_a.uuid == node.uuid:
180+
return self.intermediate_geo_nodes[1]
181+
if self.node_b.uuid == node.uuid:
182+
return self.intermediate_geo_nodes[-2]
183+
return None
184+
135185
def to_serializable(self):
136186
"""See the description in the BaseElement class.
137187

0 commit comments

Comments
 (0)