h3ron_graph/graph/
modifiers.rs

1use std::marker::PhantomData;
2
3use crate::error::Error;
4use h3ron::collections::H3Treemap;
5use h3ron::{H3Cell, H3DirectedEdge, HasH3Resolution};
6
7use crate::graph::node::NodeType;
8use crate::graph::{EdgeWeight, GetCellEdges, GetCellNode};
9
10/// wrapper to exclude cells from traversal during routing
11pub struct ExcludeCells<'a, G, W> {
12    cells_to_exclude: &'a H3Treemap<H3Cell>,
13    inner_graph: &'a G,
14    phantom_weight: PhantomData<W>,
15}
16
17impl<'a, G, W> ExcludeCells<'a, G, W>
18where
19    G: GetCellNode + GetCellEdges<EdgeWeightType = W> + HasH3Resolution,
20{
21    pub fn new(inner_graph: &'a G, cells_to_exclude: &'a H3Treemap<H3Cell>) -> Self {
22        Self {
23            cells_to_exclude,
24            inner_graph,
25            phantom_weight: Default::default(),
26        }
27    }
28}
29
30impl<'a, G, W> GetCellNode for ExcludeCells<'a, G, W>
31where
32    G: GetCellNode,
33{
34    fn get_cell_node(&self, cell: &H3Cell) -> Option<NodeType> {
35        if self.cells_to_exclude.contains(cell) {
36            None
37        } else {
38            self.inner_graph.get_cell_node(cell)
39        }
40    }
41}
42
43impl<'a, G, W> GetCellEdges for ExcludeCells<'a, G, W>
44where
45    G: GetCellEdges<EdgeWeightType = W>,
46{
47    type EdgeWeightType = G::EdgeWeightType;
48
49    fn get_edges_originating_from(
50        &self,
51        cell: &H3Cell,
52    ) -> Result<Vec<(H3DirectedEdge, EdgeWeight<Self::EdgeWeightType>)>, Error> {
53        if self.cells_to_exclude.contains(cell) {
54            Ok(vec![])
55        } else {
56            let found = self.inner_graph.get_edges_originating_from(cell)?;
57            let mut not_excluded = Vec::with_capacity(found.len());
58            for (edge, edge_value) in found {
59                if self.cells_to_exclude.contains(&edge.destination_cell()?) {
60                    continue;
61                }
62
63                // remove the longedge when it contains any excluded cell
64                let filtered_longedge_opt =
65                    if let Some((longedge, longedge_weight)) = edge_value.longedge {
66                        if longedge.is_disjoint(self.cells_to_exclude) {
67                            Some((longedge, longedge_weight))
68                        } else {
69                            None
70                        }
71                    } else {
72                        None
73                    };
74
75                not_excluded.push((
76                    edge,
77                    EdgeWeight {
78                        weight: edge_value.weight,
79                        longedge: filtered_longedge_opt,
80                    },
81                ));
82            }
83            Ok(not_excluded)
84        }
85    }
86}
87
88impl<'a, G, W> HasH3Resolution for ExcludeCells<'a, G, W>
89where
90    G: HasH3Resolution,
91{
92    fn h3_resolution(&self) -> u8 {
93        self.inner_graph.h3_resolution()
94    }
95}