1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
use crate::Reachable;
use crate::transition::candidate::*;
use geo::LineString;
use routers_network::Edge;
use routers_network::Network;
use routers_network::{Entry, Metadata};
/// The collapsed solution to a transition graph.
pub struct CollapsedPath<E>
where
E: Entry,
{
/// The solved cost of the collapsed route.
/// This value is not actionable by the consumer but rather indicative of how confident
/// the system is in the route chosen.
pub cost: u32,
/// The route as a vector of [`CandidateId`]s.
/// To obtain the list of [`Candidate`]s, use [`CollapsedPath::matched`]
pub route: Vec<CandidateId>,
/// The interpolated nodes of the collapsed route.
/// This exists as a vector of [`Reachable`] nodes which represent each layer transition.
/// Each node contains the interpolated path between the candidates in those layers.
///
/// To obtain the geographic representation of this interpolation,
/// use the [`CollapsedPath::interpolated`] method.
pub interpolated: Vec<Reachable<E>>,
/// All considered routes between candidates, regardless of whether they were
/// chosen for the final path. This is useful for visualisation and debugging.
#[cfg(debug_assertions)]
pub considered: Vec<Reachable<E>>,
pub candidates: Candidates<E>,
}
impl<E> CollapsedPath<E>
where
E: Entry,
{
pub(crate) fn new(
cost: u32,
interpolated: Vec<Reachable<E>>,
route: Vec<CandidateId>,
candidates: Candidates<E>,
#[cfg(debug_assertions)] considered: Vec<Reachable<E>>,
) -> Self {
Self {
cost,
interpolated,
route,
candidates,
#[cfg(debug_assertions)]
considered,
}
}
/// Returns the vector of [`Candidate`]s involved in a match.
/// Each candidate represents the matched position of every input node.
///
/// This includes further information such as the edge it matched to,
/// costing and the identifier for the candidate.
pub fn matched(&self) -> Vec<Candidate<E>> {
self.route
.iter()
.filter_map(|node| self.candidates.lookup.get(node))
.map(|can| *can)
.collect::<Vec<_>>()
}
pub fn collapsed(&self) -> LineString {
self.matched()
.iter()
.map(|candidate| candidate.position)
.collect::<LineString>()
}
/// Returns the interpolated route from the collapse as a [`LineString`].
/// This can therefore be used to show the expected turn decisions made by the provided input.
pub fn interpolated<M: Metadata>(&self, map: &impl Network<E, M>) -> LineString {
self.interpolated
.iter()
.enumerate()
.flat_map(|(index, reachable)| {
let source = self.candidates.candidate(&reachable.source).unwrap();
let target = self.candidates.candidate(&reachable.target).unwrap();
let path = reachable.path_nodes().filter_map(|node| map.point(&node));
core::iter::repeat_n(source.position, if index == 0 { 1 } else { 0 })
.chain(path)
.chain(core::iter::once(target.position))
})
.collect::<LineString>()
}
pub fn edges(self) -> impl Iterator<Item = Edge<E>> {
self.interpolated
.into_iter()
.flat_map(|reachable| reachable.path)
}
}