ST_Intersection(a, b) — return the geometry representing the shared area. Returns GeometryCollection with an empty geometries vec if there is no intersection.
(a: &Geometry, b: &Geometry)
| 22 | /// Returns GeometryCollection with an empty geometries vec if there is no |
| 23 | /// intersection. |
| 24 | pub fn st_intersection(a: &Geometry, b: &Geometry) -> Geometry { |
| 25 | match (a, b) { |
| 26 | // Polygon–Polygon: Sutherland-Hodgman clipping. |
| 27 | ( |
| 28 | Geometry::Polygon { |
| 29 | coordinates: rings_a, |
| 30 | }, |
| 31 | Geometry::Polygon { |
| 32 | coordinates: rings_b, |
| 33 | }, |
| 34 | ) => { |
| 35 | let Some(ext_a) = rings_a.first() else { |
| 36 | return empty_geometry(); |
| 37 | }; |
| 38 | let Some(ext_b) = rings_b.first() else { |
| 39 | return empty_geometry(); |
| 40 | }; |
| 41 | let clipped = sutherland_hodgman(ext_a, ext_b); |
| 42 | if clipped.len() < 3 { |
| 43 | return empty_geometry(); |
| 44 | } |
| 45 | // Close the ring. |
| 46 | let mut ring = clipped; |
| 47 | if ring.first() != ring.last() |
| 48 | && let Some(&first) = ring.first() |
| 49 | { |
| 50 | ring.push(first); |
| 51 | } |
| 52 | Geometry::Polygon { |
| 53 | coordinates: vec![ring], |
| 54 | } |
| 55 | } |
| 56 | |
| 57 | // Point–Polygon or reverse: if point is inside polygon, return point. |
| 58 | (Geometry::Point { coordinates: pt }, Geometry::Polygon { coordinates: rings }) |
| 59 | | (Geometry::Polygon { coordinates: rings }, Geometry::Point { coordinates: pt }) => { |
| 60 | if let Some(ext) = rings.first() |
| 61 | && (nodedb_types::geometry::point_in_polygon(pt[0], pt[1], ext) |
| 62 | || crate::predicates::edge::point_on_ring_boundary(*pt, ext)) |
| 63 | { |
| 64 | return Geometry::Point { coordinates: *pt }; |
| 65 | } |
| 66 | empty_geometry() |
| 67 | } |
| 68 | |
| 69 | // Point–Point: if identical, return point. |
| 70 | (Geometry::Point { coordinates: ca }, Geometry::Point { coordinates: cb }) => { |
| 71 | if (ca[0] - cb[0]).abs() < 1e-12 && (ca[1] - cb[1]).abs() < 1e-12 { |
| 72 | Geometry::Point { coordinates: *ca } |
| 73 | } else { |
| 74 | empty_geometry() |
| 75 | } |
| 76 | } |
| 77 | |
| 78 | // LineString–Polygon or reverse: clip line to polygon boundary. |
| 79 | (Geometry::LineString { coordinates: line }, Geometry::Polygon { coordinates: rings }) |
| 80 | | (Geometry::Polygon { coordinates: rings }, Geometry::LineString { coordinates: line }) => { |
| 81 | clip_linestring_to_polygon(line, rings) |