Skip to main content

transit_grid/core/
edge.rs

1use geo::{Coord, CoordNum, LineString};
2use serde::{Deserialize, Serialize};
3
4use super::{IdType, NodeId};
5
6/// Type alias for an edge identifier.
7pub type EdgeId = IdType;
8
9/// Structure representing a connection between two `TransitNode` instances.
10///
11/// Each edge has a unique identifier and a path represented as a `LineString`.
12/// The `LineString` type `T` is generic and can be any type that implements the `CoordNum` trait.
13///
14/// # Examples
15///
16/// ```
17/// use geo::{coord, LineString};
18/// use transit_grid::core::TransitEdge;
19///
20/// let edge = TransitEdge {
21///     id: 1,
22///     source: 1,
23///     target: 2,
24///     length: 1.0,
25///     path: LineString(vec![coord! { x: 0.0, y: 0.0 }, coord! { x: 1.0, y: 1.0 }]),
26/// };
27/// assert_eq!(edge.id, 1);
28/// assert_eq!(edge.source, 1);
29/// assert_eq!(edge.target, 2);
30/// assert_eq!(edge.path, LineString(vec![coord! { x: 0.0, y: 0.0 }, coord! { x: 1.0, y: 1.0 }]));
31/// ```
32#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
33pub struct TransitEdge<T: CoordNum> {
34    /// A unique identifier for the edge.
35    pub id: EdgeId,
36
37    /// The identifier of the node where the edge starts.
38    pub source: NodeId,
39
40    /// The identifier of the node where the edge ends.
41    pub target: NodeId,
42
43    /// The length of the edge.
44    pub length: T,
45
46    /// The path of the edge, represented as a `LineString`.
47    pub path: LineString<T>,
48}
49
50impl<T: CoordNum> Default for TransitEdge<T> {
51    fn default() -> Self {
52        Self {
53            id: 0,
54            source: 0,
55            target: 0,
56            length: T::zero(),
57            path: LineString(vec![]),
58        }
59    }
60}
61
62/// Trait providing a way to get the coordinates of the source and target nodes of a path.
63///
64/// `PathCoordinates` can be implemented by any type that has a source and target coordinate.
65/// This is useful in graph algorithms where you need to know the start and end point of an edge.
66///
67pub trait PathCoordinates<T: CoordNum> {
68    /// Returns the source coordinate of the path.
69    fn source_coordinate(&self) -> Coord<T>;
70    /// Returns the target coordinate of the path.
71    fn target_coordinate(&self) -> Coord<T>;
72}
73
74impl<T: CoordNum> PathCoordinates<T> for TransitEdge<T> {
75    fn source_coordinate(&self) -> Coord<T> {
76        self.path.points().next().unwrap().0
77    }
78
79    fn target_coordinate(&self) -> Coord<T> {
80        self.path.points().last().unwrap().0
81    }
82}
83
84#[cfg(test)]
85mod tests {
86    use super::*;
87    use geo::coord;
88
89    #[test]
90    fn test_edge() {
91        let edge = TransitEdge {
92            id: 1,
93            source: 1,
94            target: 2,
95            length: 1.0,
96            path: LineString(vec![coord! { x:0.0, y:0.0}, coord! { x:1.0, y:1.0}]),
97        };
98        assert_eq!(edge.id, 1);
99        assert_eq!(edge.source, 1);
100        assert_eq!(edge.target, 2);
101        assert_eq!(edge.length, 1.0);
102        assert_eq!(
103            edge.path,
104            LineString(vec![coord! { x:0.0, y:0.0}, coord! { x:1.0, y:1.0}])
105        );
106    }
107
108    #[test]
109    fn test_edge_default() {
110        let edge = TransitEdge::<f64>::default();
111        assert_eq!(edge.id, 0);
112        assert_eq!(edge.source, 0);
113        assert_eq!(edge.target, 0);
114        assert_eq!(edge.path, LineString::<f64>(vec![]));
115    }
116
117    #[test]
118    fn test_edge_coordinates() {
119        let edge = TransitEdge {
120            id: 1,
121            source: 1,
122            target: 2,
123            length: 1.0,
124            path: LineString(vec![coord! { x: 0.0, y: 0.0 }, coord! { x: 1.0, y: 1.0 }]),
125        };
126        assert_eq!(edge.source_coordinate(), coord! { x: 0.0, y: 0.0 });
127        assert_eq!(edge.target_coordinate(), coord! { x: 1.0, y: 1.0 });
128    }
129}