Skip to main content

transit_grid/graphs/transit_network/
mod.rs

1use super::{PhysicalGraph, TopologyGraph};
2use crate::{
3    core::{Accessability, EdgeId, NodeId, TransitEdge, TransitNode},
4    operations::TransitNetworkModifier,
5};
6use geo::CoordNum;
7
8pub mod repair;
9
10/// Represents a transit network as a graph with transit nodes and edges.
11///
12/// The struct holds a physical graph and a topological graph which are lower-level representations of the network.
13/// `TransitNetwork` provides a higher-level interface to the physical graph and topological graph.
14///
15/// The struct implements `TransitNetworkModifier` trait for modifying the underlying physical graph.
16///
17/// # Generics
18///
19/// `R`: Copyable trait bound. This represents the type of the data associated with the network's routes.
20/// `T`: This represents the type of the coordinates used in the network. It's expected to implement `CoordNum` trait.
21///
22/// # Fields
23///
24/// * `physical_graph: PhysicalGraph<R, T>` - The physical graph representing the transit network.
25/// * `topology_graph: TopologyGraph` - The topological graph representing the transit network.
26#[derive(Debug, Clone)]
27pub struct TransitNetwork<R: Copy, T: CoordNum> {
28    /// The physical graph representing the transit network.
29    pub physical_graph: PhysicalGraph<R, T>,
30    /// The topological graph representing the transit network.
31    pub topology_graph: TopologyGraph,
32}
33
34impl<R: Copy, T: CoordNum> PartialEq for TransitNetwork<R, T> {
35    fn eq(&self, other: &Self) -> bool {
36        self.physical_graph.graph.node_count() == other.physical_graph.graph.node_count()
37            && self.topology_graph.graph.edge_count() == other.topology_graph.graph.edge_count()
38    }
39}
40
41impl<R: Copy, T: CoordNum> TransitNetwork<R, T> {
42    /// Constructs a new `TransitNetwork` with an empty `PhysicalGraph` and `TopologyGraph`.
43    ///
44    /// # Returns
45    ///
46    /// A new `TransitNetwork` instance.
47    pub fn new() -> Self {
48        TransitNetwork {
49            physical_graph: PhysicalGraph::new(),
50            topology_graph: TopologyGraph::new(),
51        }
52    }
53
54    /// Returns a reference to the `TransitNode` with the given ID.
55    pub fn get_edge_by_id(&self, edge_id: EdgeId) -> Option<&TransitEdge<T>> {
56        self.physical_graph.get_transit_edge_by_id(edge_id)
57    }
58}
59
60impl<R: Copy, T: CoordNum> Default for TransitNetwork<R, T> {
61    fn default() -> Self {
62        Self::new()
63    }
64}
65
66/// Implementation of `TransitNetworkModifier` trait for `TransitNetwork`.
67///
68/// This implementation delegates the operations to the underlying physical graph.
69impl<R: Copy, T: CoordNum> TransitNetworkModifier<R, T> for TransitNetwork<R, T> {
70    /// Adds a `TransitNode` to the physical graph of the network.
71    ///
72    /// # Arguments
73    ///
74    /// * `node` - The `TransitNode` to be added to the network.
75    ///
76    /// # Returns
77    ///
78    /// * `NodeId` - The ID of the added node.
79    fn add_node(&mut self, node: TransitNode<R>) -> NodeId {
80        let node_id = node.id;
81        self.physical_graph.add_transit_node(node);
82        self.topology_graph.add_node(node_id);
83        node_id
84    }
85
86    /// Adds a `TransitEdge` to the physical graph of the network.
87    ///
88    /// # Arguments
89    ///
90    /// * `edge` - The `TransitEdge` to be added to the network.
91    fn add_edge(&mut self, edge: TransitEdge<T>) {
92        self.physical_graph.add_transit_edge(edge.clone());
93        self.topology_graph
94            .add_edge(edge.id, edge.source, edge.target);
95    }
96
97    fn add_edge_with_accessibility(&mut self, edge: TransitEdge<T>, accessability: Accessability) {
98        self.physical_graph.add_transit_edge(edge.clone());
99        self.topology_graph.add_edge_with_accessibility(
100            edge.id,
101            edge.source,
102            edge.target,
103            accessability,
104        );
105    }
106}
107
108#[cfg(test)]
109mod tests {
110    use super::*;
111    use geo::{coord, point, LineString};
112    use petgraph::visit::IntoEdgeReferences;
113
114    #[test]
115    fn test_transit_network() {
116        // Create a new TransitNetwork
117        let mut network = TransitNetwork::new();
118
119        // Define some nodes
120        let node1 = TransitNode {
121            id: 1,
122            location: point!(x: 0.0, y: 0.0),
123        };
124
125        let node2 = TransitNode {
126            id: 2,
127            location: point!(x: 1.0, y: 1.0),
128        };
129
130        // Add nodes to the network
131        let node1_id = network.add_node(node1);
132        let node2_id = network.add_node(node2);
133
134        // Check that the nodes were added successfully
135        assert_eq!(node1_id, 1);
136        assert_eq!(node2_id, 2);
137
138        // Define an edge
139        let edge = TransitEdge {
140            id: 1,
141            source: 1,
142            target: 2,
143            length: 1.0,
144            path: LineString(vec![coord! {x: 0.0, y: 0.0}, coord! {x: 1.0, y: 1.0}]),
145        };
146
147        // Add edge to the network
148        network.add_edge(edge);
149
150        // Check that the edge was added successfully
151        assert_eq!(network.physical_graph.graph.edge_count(), 1);
152
153        // Check that the topology graph was populated correctly
154        assert_eq!(network.topology_graph.graph.node_count(), 4);
155        assert_eq!(network.topology_graph.graph.edge_count(), 2);
156    }
157
158    #[test]
159    fn test_transit_network_edge_addition() {
160        // Create a new TransitNetwork
161        let mut network = TransitNetwork::new();
162
163        // Define some nodes
164        let node1 = TransitNode {
165            id: 1,
166            location: point!(x: 0.0, y: 0.0),
167        };
168
169        let node2 = TransitNode {
170            id: 2,
171            location: point!(x: 1.0, y: 1.0),
172        };
173
174        let node3 = TransitNode {
175            id: 3,
176            location: point!(x: 2.0, y: 2.0),
177        };
178
179        // Add nodes to the network
180        network.add_node(node1);
181        network.add_node(node2);
182        network.add_node(node3);
183
184        // Define edges
185        let edge1 = TransitEdge {
186            id: 1,
187            source: 1,
188            target: 2,
189            length: 1.0,
190            path: LineString(vec![coord! {x: 0.0, y: 0.0}, coord! {x: 1.0, y: 1.0}]),
191        };
192
193        let edge2 = TransitEdge {
194            id: 2,
195            source: 2,
196            target: 3,
197            length: 1.0,
198            path: LineString(vec![coord! {x: 0.0, y: 0.0}, coord! {x: 2.0, y: 2.0}]),
199        };
200
201        // Add edges to the network
202        network.add_edge(edge1);
203        network.add_edge(edge2);
204
205        // Check that the edges were added successfully
206        assert_eq!(network.physical_graph.graph.edge_count(), 2);
207
208        // Check that the topology graph was populated correctly
209        assert_eq!(network.topology_graph.graph.node_count(), 6);
210        assert_eq!(network.topology_graph.graph.edge_count(), 4);
211
212        // Check that the topology edges were computed correctly
213        let edge_ids: Vec<_> = network
214            .topology_graph
215            .graph
216            .edge_references()
217            .map(|edge| edge.weight().edge_id)
218            .collect();
219        assert_eq!(edge_ids, vec![1, 1, 2, 2]);
220    }
221
222    #[test]
223    fn test_add_edge_with_accessibility() {
224        // Create a new TransitNetwork
225
226        let mut network = TransitNetwork::new();
227
228        // Define some nodes
229        let node0 = TransitNode {
230            id: 0,
231            location: point!(x: 0.0, y: 0.0),
232        };
233
234        let node1 = TransitNode {
235            id: 1,
236            location: point!(x: 1.0, y: 1.0),
237        };
238
239        let node2 = TransitNode {
240            id: 2,
241            location: point!(x: 2.0, y: 2.0),
242        };
243
244        let node3 = TransitNode {
245            id: 3,
246            location: point!(x: 3.0, y: 3.0),
247        };
248
249        let node4 = TransitNode {
250            id: 4,
251            location: point!(x: 4.0, y: 4.0),
252        };
253
254        // Add nodes to the network
255        network.add_node(node0);
256        network.add_node(node1);
257        network.add_node(node2);
258        network.add_node(node3);
259        network.add_node(node4);
260
261        // Define edges
262        let edge01 = TransitEdge {
263            id: 1,
264            source: 0,
265            target: 1,
266            length: 1.0,
267            path: LineString(vec![coord! {x: 0.0, y: 0.0}, coord! {x: 1.0, y: 1.0}]),
268        };
269
270        let edge14 = TransitEdge {
271            id: 2,
272            source: 1,
273            target: 4,
274            length: 1.0,
275            path: LineString(vec![coord! {x: 1.0, y: 1.0}, coord! {x: 4.0, y: 4.0}]),
276        };
277
278        let edge12 = TransitEdge {
279            id: 3,
280            source: 1,
281            target: 2,
282            length: 1.0,
283            path: LineString(vec![coord! {x: 1.0, y: 1.0}, coord! {x: 2.0, y: 2.0}]),
284        };
285
286        let edge13 = TransitEdge {
287            id: 4,
288            source: 1,
289            target: 3,
290            length: 1.0,
291            path: LineString(vec![coord! {x: 1.0, y: 1.0}, coord! {x: 3.0, y: 3.0}]),
292        };
293
294        // Add edges to the network
295        network.add_edge(edge01);
296        network.add_edge(edge14);
297        network.add_edge(edge12);
298        network.add_edge(edge13);
299
300        // Add edge with accessibility
301        let edge40 = TransitEdge {
302            id: 5,
303            source: 4,
304            target: 0,
305            length: 1.0,
306            path: LineString(vec![coord! {x: 4.0, y: 4.0}, coord! {x: 0.0, y: 0.0}]),
307        };
308
309        network.add_edge_with_accessibility(edge40, Accessability::ReachableNodes(vec![2, 3]));
310
311        // Check that the edges were added successfully
312        assert_eq!(network.physical_graph.graph.edge_count(), 5);
313
314        // Check that the topology graph was populated correctly
315        assert_eq!(network.topology_graph.graph.node_count(), 10);
316        assert_eq!(network.topology_graph.graph.edge_count(), 10);
317
318        // Check that the topology edges were computed correctly
319        let edge_ids: Vec<_> = network
320            .topology_graph
321            .graph
322            .edge_references()
323            .map(|edge| edge.weight().edge_id)
324            .collect();
325        assert_eq!(edge_ids, vec![1, 1, 2, 2, 3, 3, 4, 4, 5, 5]);
326    }
327
328    #[test]
329    fn test_default() {
330        let network: TransitNetwork<u32, f64> = TransitNetwork::default();
331
332        assert_eq!(network.physical_graph.graph.node_count(), 0);
333        assert_eq!(network.physical_graph.graph.edge_count(), 0);
334        assert_eq!(network.topology_graph.graph.node_count(), 0);
335        assert_eq!(network.topology_graph.graph.edge_count(), 0);
336    }
337}