1use std::ops::Add;
2
3use geo::bounding_rect::BoundingRect;
4use geo::concave_hull::ConcaveHull;
5use geo_types::{Coord, MultiPoint, MultiPolygon, Point, Polygon, Rect};
6use num_traits::Zero;
7use rayon::prelude::*;
8use serde::{Deserialize, Serialize};
9use smallvec::{smallvec, SmallVec};
10
11use h3ron::collections::compressed::Decompressor;
12use h3ron::collections::hashbrown::hash_map::Entry;
13use h3ron::collections::{H3Treemap, HashMap};
14use h3ron::iter::H3DirectedEdgesBuilder;
15use h3ron::{H3Cell, H3DirectedEdge, HasH3Resolution, ToCoordinate};
16
17use crate::algorithm::covered_area::{cells_covered_area, CoveredArea};
18use crate::error::Error;
19use crate::graph::longedge::LongEdge;
20use crate::graph::node::NodeType;
21use crate::graph::{
22 EdgeWeight, GetCellEdges, GetCellNode, GetStats, GraphStats, H3EdgeGraph, IterateCellNodes,
23};
24
25#[derive(Serialize, Deserialize, Clone)]
26struct OwnedEdgeWeight<W> {
27 pub weight: W,
28
29 pub longedge: Option<Box<(LongEdge, W)>>,
36}
37
38impl<'a, W> From<&'a OwnedEdgeWeight<W>> for EdgeWeight<'a, W>
39where
40 W: Copy,
41{
42 fn from(owned_edge_value: &'a OwnedEdgeWeight<W>) -> Self {
43 EdgeWeight {
44 weight: owned_edge_value.weight,
45 longedge: owned_edge_value
46 .longedge
47 .as_ref()
48 .map(|boxed| (&boxed.0, boxed.1)),
49 }
50 }
51}
52
53type OwnedEdgeTuple<W> = (H3DirectedEdge, OwnedEdgeWeight<W>);
54
55type OwnedEdgeTupleList<W> = SmallVec<[OwnedEdgeTuple<W>; 2]>;
58
59#[doc=include_str!("../../doc/images/edges-and-longedges.svg")]
67#[doc=include_str!("../../doc/images/prepared_h3_edge_graph.svg")]
71#[derive(Serialize, Deserialize, Clone)]
74pub struct PreparedH3EdgeGraph<W> {
75 outgoing_edges: HashMap<H3Cell, OwnedEdgeTupleList<W>>,
76 h3_resolution: u8,
77 graph_nodes: HashMap<H3Cell, NodeType>,
78}
79
80unsafe impl<W> Sync for PreparedH3EdgeGraph<W> where W: Sync {}
81
82impl<W> PreparedH3EdgeGraph<W> {
83 pub fn count_edges(&self) -> (usize, usize) {
87 let mut num_edges = 0usize;
88 let mut num_long_edges = 0usize;
89
90 for (_cell, oevs) in self.outgoing_edges.iter() {
91 num_edges += oevs.len();
92 num_long_edges += oevs
93 .iter()
94 .filter(|(_, oev)| oev.longedge.is_some())
95 .count();
96 }
97 (num_edges, num_long_edges)
98 }
99}
100
101impl<W> PreparedH3EdgeGraph<W>
102where
103 W: Copy,
104{
105 pub fn iter_edges(&self) -> impl Iterator<Item = (H3DirectedEdge, EdgeWeight<W>)> {
107 self.outgoing_edges
108 .iter()
109 .flat_map(|(_, oevs)| oevs.iter().map(|(edge, oev)| (*edge, oev.into())))
110 }
111
112 pub fn iter_edges_non_overlapping(
118 &self,
119 ) -> Result<impl Iterator<Item = (H3DirectedEdge, EdgeWeight<W>)>, Error> {
120 let mut covered_edges = H3Treemap::<H3DirectedEdge>::default();
121 let mut decompressor = Decompressor::default();
122 for (_, owned_edge_values) in self.outgoing_edges.iter() {
123 for (_, owned_edge_value) in owned_edge_values.iter() {
124 if let Some(boxed_longedge) = owned_edge_value.longedge.as_ref() {
125 for edge in decompressor
126 .decompress_block(&boxed_longedge.0.edge_path)?
127 .skip(1)
128 {
129 covered_edges.insert(edge);
130 }
131 }
132 }
133 }
134 Ok(self.iter_edges().filter_map(move |(edge, weight)| {
135 if covered_edges.contains(&edge) {
136 None
137 } else {
138 Some((edge, weight))
139 }
140 }))
141 }
142}
143
144pub type FromIterItem<W> = (H3DirectedEdge, W, Option<(Vec<H3DirectedEdge>, W)>);
146
147impl<W> PreparedH3EdgeGraph<W>
148where
149 W: Copy + Send + Sync,
150{
151 pub fn try_from_iter<I>(iter: I) -> Result<Self, Error>
152 where
153 I: Iterator<Item = FromIterItem<W>>,
154 {
155 let mut h3_resolution = None;
156 let mut outgoing_edges: HashMap<H3Cell, OwnedEdgeTupleList<W>> = Default::default();
157 let mut graph_nodes: HashMap<H3Cell, NodeType> = Default::default();
158
159 for (edge, edge_weight, longedge_components) in iter {
160 let edge_cells = edge.cells()?;
161
162 if let Some(h3_resolution) = h3_resolution {
164 if h3_resolution != edge_cells.origin.h3_resolution() {
165 return Err(Error::MixedH3Resolutions(
166 h3_resolution,
167 edge_cells.origin.h3_resolution(),
168 ));
169 }
170 } else {
171 h3_resolution = Some(edge_cells.origin.h3_resolution());
172 }
173
174 graph_nodes
175 .entry(edge_cells.origin)
176 .and_modify(|nt| *nt += NodeType::Origin)
177 .or_insert(NodeType::Origin);
178 graph_nodes
179 .entry(edge_cells.destination)
180 .and_modify(|nt| *nt += NodeType::Destination)
181 .or_insert(NodeType::Destination);
182
183 let edge_with_weight = (
184 edge,
185 OwnedEdgeWeight {
186 weight: edge_weight,
187 longedge: match longedge_components {
188 Some((le_edges, le_weight)) => {
189 Some(Box::new((LongEdge::try_from(le_edges)?, le_weight)))
190 }
191 None => None,
192 },
193 },
194 );
195 match outgoing_edges.entry(edge_cells.origin) {
196 Entry::Occupied(mut occ) => {
197 occ.get_mut().push(edge_with_weight);
198 }
199 Entry::Vacant(vac) => {
200 vac.insert(smallvec![edge_with_weight]);
201 }
202 }
203 }
204
205 remove_duplicated_edges(&mut outgoing_edges);
206
207 if let Some(h3_resolution) = h3_resolution {
208 Ok(Self {
209 outgoing_edges,
210 h3_resolution,
211 graph_nodes,
212 })
213 } else {
214 Err(Error::InsufficientNumberOfEdges)
215 }
216 }
217}
218
219impl<W> HasH3Resolution for PreparedH3EdgeGraph<W> {
220 fn h3_resolution(&self) -> u8 {
221 self.h3_resolution
222 }
223}
224
225impl<W> GetStats for PreparedH3EdgeGraph<W> {
226 fn get_stats(&self) -> Result<GraphStats, Error> {
227 Ok(GraphStats {
228 h3_resolution: self.h3_resolution,
229 num_nodes: self.graph_nodes.len(),
230 num_edges: self.count_edges().0,
231 })
232 }
233}
234
235impl<W> GetCellNode for PreparedH3EdgeGraph<W> {
236 fn get_cell_node(&self, cell: &H3Cell) -> Option<NodeType> {
237 self.graph_nodes.get(cell).copied()
238 }
239}
240
241impl<W: Copy> GetCellEdges for PreparedH3EdgeGraph<W> {
242 type EdgeWeightType = W;
243
244 fn get_edges_originating_from(
245 &self,
246 cell: &H3Cell,
247 ) -> Result<Vec<(H3DirectedEdge, EdgeWeight<Self::EdgeWeightType>)>, Error> {
248 let mut out_vec = Vec::with_capacity(7);
249 if let Some(edges_with_weights) = self.outgoing_edges.get(cell) {
250 out_vec.extend(
251 edges_with_weights
252 .iter()
253 .map(|(edge, owv)| (*edge, owv.into())),
254 );
255 }
256 Ok(out_vec)
257 }
258}
259
260const MIN_LONGEDGE_LENGTH: usize = 3;
261
262fn to_longedge_edges<W>(
263 input_graph: H3EdgeGraph<W>,
264 min_longedge_length: usize,
265) -> Result<HashMap<H3Cell, OwnedEdgeTupleList<W>>, Error>
266where
267 W: PartialOrd + PartialEq + Add<Output = W> + Copy + Send + Sync,
268{
269 if min_longedge_length < MIN_LONGEDGE_LENGTH {
270 return Err(Error::Other(format!(
271 "minimum longedge length must be >= {}",
272 MIN_LONGEDGE_LENGTH
273 )));
274 }
275
276 let outgoing_edge_vecs = input_graph
277 .edges
278 .par_iter()
279 .try_fold(
280 || (Vec::new(), H3DirectedEdgesBuilder::new()),
281 |(mut output_vec, mut edge_builder), (edge, weight)| {
282 assemble_edge_with_longedge(
283 &input_graph.edges,
284 min_longedge_length,
285 edge,
286 weight,
287 &mut edge_builder,
288 )
289 .map(|cell_edge| {
290 output_vec.push(cell_edge);
291 (output_vec, edge_builder)
292 })
293 },
294 )
295 .collect::<Result<Vec<_>, _>>()?;
296
297 let mut outgoing_edges: HashMap<H3Cell, OwnedEdgeTupleList<W>> = Default::default();
298 for (outgoing_edge_vec, _) in outgoing_edge_vecs.into_iter() {
299 for (cell, edge_with_weight) in outgoing_edge_vec.into_iter() {
300 match outgoing_edges.entry(cell) {
301 Entry::Occupied(mut occ) => occ.get_mut().push(edge_with_weight),
302 Entry::Vacant(vac) => {
303 vac.insert(smallvec![edge_with_weight]);
304 }
305 }
306 }
307 }
308
309 remove_duplicated_edges(&mut outgoing_edges);
310
311 Ok(outgoing_edges)
312}
313
314fn remove_duplicated_edges<W>(outgoing_edges: &mut HashMap<H3Cell, OwnedEdgeTupleList<W>>)
316where
317 W: Send + Sync,
318{
319 outgoing_edges
320 .par_iter_mut()
321 .for_each(|(_cell, edges_with_weights)| {
322 edges_with_weights.sort_unstable_by_key(|eww| eww.0);
323 edges_with_weights.dedup_by(|a, b| a.0 == b.0);
324 edges_with_weights.shrink_to_fit();
325 });
326}
327
328fn assemble_edge_with_longedge<W>(
329 input_edges: &HashMap<H3DirectedEdge, W>,
330 min_longedge_length: usize,
331 edge: &H3DirectedEdge,
332 weight: &W,
333 edge_builder: &mut H3DirectedEdgesBuilder,
334) -> Result<(H3Cell, OwnedEdgeTuple<W>), Error>
335where
336 W: PartialOrd + PartialEq + Add<Output = W> + Copy,
337{
338 let mut graph_entry = OwnedEdgeWeight {
339 weight: *weight,
340 longedge: None,
341 };
342
343 let origin_cell = edge.origin_cell()?;
344
345 let num_edges_leading_to_this_one = edge_builder
347 .from_origin_cell(&origin_cell)?
348 .filter(|new_edge| new_edge != edge) .filter(|new_edge| {
350 new_edge
351 .reversed()
352 .ok()
353 .map(|rev_edge| input_edges.get(&rev_edge).is_some())
354 .unwrap_or(false)
355 })
356 .count();
357
358 if num_edges_leading_to_this_one != 1 {
361 let mut edge_path = vec![*edge];
362 let mut longedge_weight = *weight;
363
364 let mut last_edge = *edge;
365 loop {
366 let last_edge_reverse = last_edge.reversed()?;
367 let following_edges: Vec<_> = edge_builder
369 .from_origin_cell(&last_edge.destination_cell()?)?
370 .filter_map(|this_edge| {
371 if this_edge != last_edge_reverse {
372 input_edges.get_key_value(&this_edge)
373 } else {
374 None
375 }
376 })
377 .collect();
378
379 if following_edges.len() != 1 {
381 break;
382 }
383 let following_edge = *(following_edges[0].0);
384
385 if edge_path.contains(&following_edge) {
387 break;
388 }
389
390 edge_path.push(following_edge);
391 longedge_weight = *(following_edges[0].1) + longedge_weight;
392 last_edge = following_edge;
394 }
395
396 if edge_path.len() >= min_longedge_length {
397 graph_entry.longedge =
398 Some(Box::new((LongEdge::try_from(edge_path)?, longedge_weight)));
399 }
400 }
401 Ok((origin_cell, (*edge, graph_entry)))
402}
403
404impl<W> PreparedH3EdgeGraph<W>
405where
406 W: PartialOrd + PartialEq + Add + Copy + Ord + Zero + Send + Sync,
407{
408 pub fn from_h3edge_graph(
409 graph: H3EdgeGraph<W>,
410 min_longedge_length: usize,
411 ) -> Result<Self, Error> {
412 let h3_resolution = graph.h3_resolution();
413 let graph_nodes = graph.nodes()?;
414 let outgoing_edges = to_longedge_edges(graph, min_longedge_length)?;
415 Ok(Self {
416 graph_nodes,
417 h3_resolution,
418 outgoing_edges,
419 })
420 }
421}
422
423impl<W> TryFrom<H3EdgeGraph<W>> for PreparedH3EdgeGraph<W>
424where
425 W: PartialOrd + PartialEq + Add + Copy + Ord + Zero + Send + Sync,
426{
427 type Error = Error;
428
429 fn try_from(graph: H3EdgeGraph<W>) -> Result<Self, Self::Error> {
430 Self::from_h3edge_graph(graph, 4)
431 }
432}
433
434impl<W> From<PreparedH3EdgeGraph<W>> for H3EdgeGraph<W>
435where
436 W: PartialOrd + PartialEq + Add + Copy + Ord + Zero,
437{
438 fn from(prepared_graph: PreparedH3EdgeGraph<W>) -> Self {
439 Self {
440 edges: prepared_graph
441 .iter_edges()
442 .map(|(edge, edge_value)| (edge, edge_value.weight))
443 .collect(),
444 h3_resolution: prepared_graph.h3_resolution,
445 }
446 }
447}
448
449impl<W> CoveredArea for PreparedH3EdgeGraph<W> {
450 type Error = Error;
451
452 fn covered_area(&self, reduce_resolution_by: u8) -> Result<MultiPolygon<f64>, Self::Error> {
453 cells_covered_area(
454 self.graph_nodes.iter().map(|(cell, _)| cell),
455 self.h3_resolution(),
456 reduce_resolution_by,
457 )
458 }
459}
460
461impl<'a, W> IterateCellNodes<'a> for PreparedH3EdgeGraph<W> {
462 type CellNodeIterator = h3ron::collections::hashbrown::hash_map::Iter<'a, H3Cell, NodeType>;
463
464 fn iter_cell_nodes(&'a self) -> Self::CellNodeIterator {
465 self.graph_nodes.iter()
466 }
467}
468
469impl<W> ConcaveHull for PreparedH3EdgeGraph<W> {
470 type Scalar = f64;
471
472 fn concave_hull(&self, concavity: Self::Scalar) -> Polygon<Self::Scalar> {
474 let mpoint = MultiPoint::from(
475 self.iter_cell_nodes()
476 .filter_map(|(cell, _)| cell.to_coordinate().ok().map(Point::from))
477 .collect::<Vec<_>>(),
478 );
479 mpoint.concave_hull(concavity)
480 }
481}
482
483impl<W> BoundingRect<f64> for PreparedH3EdgeGraph<W> {
484 type Output = Option<Rect<f64>>;
485
486 fn bounding_rect(&self) -> Self::Output {
487 let mut iter = self.iter_cell_nodes();
488 let mut rect = {
489 if let Some(coord) = iter.find_map(|(cell, _)| cell.to_coordinate().ok()) {
491 Point::from(coord).bounding_rect()
492 } else {
493 return None;
494 }
495 };
496
497 for (cell, _) in iter {
498 if let Ok(coord) = cell.to_coordinate() {
499 rect = Rect::new(
500 Coord {
501 x: if coord.x < rect.min().x {
502 coord.x
503 } else {
504 rect.min().x
505 },
506 y: if coord.y < rect.min().y {
507 coord.y
508 } else {
509 rect.min().y
510 },
511 },
512 Coord {
513 x: if coord.x > rect.max().x {
514 coord.x
515 } else {
516 rect.max().x
517 },
518 y: if coord.y > rect.max().y {
519 coord.y
520 } else {
521 rect.max().y
522 },
523 },
524 );
525 }
526 }
527 Some(rect)
528 }
529}
530
531#[cfg(test)]
532mod tests {
533 use std::convert::TryInto;
534
535 use geo_types::{Coord, LineString};
536
537 use crate::graph::{H3EdgeGraph, PreparedH3EdgeGraph};
538
539 fn build_line_prepared_graph() -> PreparedH3EdgeGraph<u32> {
540 let full_h3_res = 8;
541 let cells: Vec<_> = h3ron::line(
542 &LineString::from(vec![Coord::from((23.3, 12.3)), Coord::from((24.2, 12.2))]),
543 full_h3_res,
544 )
545 .unwrap()
546 .into();
547 assert!(cells.len() > 100);
548
549 let mut graph = H3EdgeGraph::new(full_h3_res);
550 for w in cells.windows(2) {
551 graph.add_edge_using_cells(w[0], w[1], 20u32).unwrap();
552 }
553 assert!(graph.num_edges() > 50);
554 let prep_graph: PreparedH3EdgeGraph<_> = graph.try_into().unwrap();
555 assert_eq!(prep_graph.count_edges().1, 1);
556 prep_graph
557 }
558
559 #[test]
560 fn test_iter_edges() {
561 let graph = build_line_prepared_graph();
562 assert!(graph.iter_edges().count() > 50);
563 }
564
565 #[test]
566 fn test_iter_non_overlapping_edges() {
567 let graph = build_line_prepared_graph();
568 assert_eq!(graph.iter_edges_non_overlapping().unwrap().count(), 1);
569 }
570}