| 4 | use crate::graph::GeometryGraph; |
| 5 | |
| 6 | pub fn node<G, Direction: petgraph::EdgeType>(geoms: G) -> GeometryGraph<Direction> |
| 7 | where |
| 8 | G: IntoIterator<Item = Geometry>, |
| 9 | { |
| 10 | let collection = cxxbridge::GeometryCollectionShim::new(geoms); |
| 11 | let mut ffi_graph = unsafe { |
| 12 | // Setting the tolerance to 0 picks the IteratedNoder instead of the SnappingNoder. |
| 13 | // They both have pros and cons. |
| 14 | // * IteratedNoder might throw exceptions if it does not converge on pathological |
| 15 | // geometries |
| 16 | // * SnappingNoder doesn't handle POINT geometries, only LINESTRINGs and POLYGONs |
| 17 | let tolerance = 0.0; |
| 18 | cxxbridge::node(&collection, tolerance) |
| 19 | }; |
| 20 | |
| 21 | // Retry with the SnappingNoder |
| 22 | let mut insert_isolated_points = false; |
| 23 | if ffi_graph.is_null() { |
| 24 | insert_isolated_points = true; |
| 25 | let tolerance = 0.000001; |
| 26 | tracing::error!("GEOS IteratedNoder failed. Falling back on SnappingNoder"); |
| 27 | ffi_graph = unsafe { cxxbridge::node(&collection, tolerance) } |
| 28 | } |
| 29 | |
| 30 | let mut graph: GeometryGraph<Direction> = (&*ffi_graph).into(); |
| 31 | |
| 32 | // The SnappingNoder throws away isolated points, so add them back in. Unfortunately, this |
| 33 | // doesn't calculate any node-segment intersections, and may result in duplicate nodes. |
| 34 | if insert_isolated_points { |
| 35 | tracing::warn!("Adding isolated points back in ... may result in duplicate nodes"); |
| 36 | let points = collection.get_geo_points(); |
| 37 | for point in points.into_iter() { |
| 38 | graph.add_node(point); |
| 39 | } |
| 40 | } |
| 41 | |
| 42 | graph |
| 43 | } |
| 44 | |
| 45 | pub fn polygonize<Direction: petgraph::EdgeType>( |
| 46 | graph: &GeometryGraph<Direction>, |