From d3049cb323db8c32c3b020d3ee91bb79dcaf057d Mon Sep 17 00:00:00 2001 From: Alan Gutierrez Date: Sun, 26 Oct 2025 22:58:58 -0500 Subject: [PATCH] Triangulation is not just a conversion. The triangulation function in `triangle.rs` is now called `delaunay_to_triangles` and it accepts the output of a Delaunay triangulation from `i_triangle` and not a GeoRust multi-polygon. The translation of user polygons to `i_triangle` polygons and subsequent triangulation will take place outside of `triangle.rs`. --- src/spatial/triangle.rs | 92 +++++++++++++++-------------------------- 1 file changed, 33 insertions(+), 59 deletions(-) diff --git a/src/spatial/triangle.rs b/src/spatial/triangle.rs index e25d9734f..562d55b85 100644 --- a/src/spatial/triangle.rs +++ b/src/spatial/triangle.rs @@ -5,9 +5,7 @@ //! contain an additional vertex and packed reconstruction metadata, allowing exact triangle //! recovery when needed. -use geo_types::MultiPolygon; -use i_triangle::i_overlay::i_float::int::point::IntPoint; -use i_triangle::int::triangulatable::IntTriangulatable; +use i_triangle::advanced::delaunay::IntDelaunay; use robust::{orient2d, Coord}; const MINY_MINX_MAXY_MAXX_Y_X: i32 = 0; @@ -303,65 +301,37 @@ impl Triangle { } } -/// Triangulates a geographic polygon into encoded triangles for block kd-tree indexing. +/// Encodes the triangles of a Delaunay triangulation into block kd-tree triangles. /// -/// This function is used by applications to convert a `MultiPolygon` into triangles for indexing -/// in the block kd-tree. Once triangulated, the encoded triangles can be inserted into the block -/// kd-tree and queries against the block kd-tree will return the associated `doc_id`. +/// Takes the output of a Delaunay triangulation from `i_triangle` and encodes each triangle into +/// the normalized triangle used by the block kd-tree. Each triangle includes its bounding box, +/// vertex coordinates, and boundary edge flags that distinguish original polygon edges from +/// internal tessellation edges. /// -/// Takes a polygon with floating-point lat/lon coordinates, converts to integer coordinates with -/// millimeter precision (using 2^32 scaling), performs constrained Delaunay triangulation, and -/// encodes the resulting triangles with boundary edge information. -/// -/// Handles polygons with holes correctly, preserving which triangle edges lie on the original -/// polygon boundaries versus internal tessellation edges. -pub fn triangulate(doc_id: u32, geometry: G, triangles: &mut Vec) -where G: Into> { - let multi = geometry.into(); - for polygon in multi { - let exterior: Vec = polygon - .exterior() - .coords() - .map(|coord| { - let lat = (coord.y / (180.0 / (1i64 << 32) as f64)).floor() as i32; - let lon = (coord.x / (360.0 / (1i64 << 32) as f64)).floor() as i32; - IntPoint::new(lon, lat) - }) - .collect(); - let mut i_polygon = vec![exterior]; - for interior in polygon.interiors() { - let hole: Vec = interior - .coords() - .map(|coord| { - let lat = (coord.y / (180.0 / (1i64 << 32) as f64)).floor() as i32; - let lon = (coord.x / (360.0 / (1i64 << 32) as f64)).floor() as i32; - IntPoint::new(lon, lat) - }) - .collect(); - i_polygon.push(hole); - } - let delaunay = i_polygon.triangulate().into_delaunay(); - for (_, triangle) in delaunay.triangles.iter().enumerate() { - let bounds = [ - triangle.neighbors[0] == usize::MAX, - triangle.neighbors[1] == usize::MAX, - triangle.neighbors[2] == usize::MAX, - ]; - let v0 = &delaunay.points[triangle.vertices[0].index]; - let v1 = &delaunay.points[triangle.vertices[1].index]; - let v2 = &delaunay.points[triangle.vertices[2].index]; - triangles.push(Triangle::new( - doc_id, - [v0.y, v0.x, v1.y, v1.x, v2.y, v2.x], - bounds, - )) - } +/// The boundary edge information provided by the `i_triangle` Delaunay triangulation is essential +/// for CONTAINS and WITHIN queries to work correctly. +pub fn delaunay_to_triangles(doc_id: u32, delaunay: &IntDelaunay, triangles: &mut Vec) { + for triangle in delaunay.triangles.iter() { + let bounds = [ + triangle.neighbors[0] == usize::MAX, + triangle.neighbors[1] == usize::MAX, + triangle.neighbors[2] == usize::MAX, + ]; + let v0 = &delaunay.points[triangle.vertices[0].index]; + let v1 = &delaunay.points[triangle.vertices[1].index]; + let v2 = &delaunay.points[triangle.vertices[2].index]; + triangles.push(Triangle::new( + doc_id, + [v0.y, v0.x, v1.y, v1.x, v2.y, v2.x], + bounds, + )) } } #[cfg(test)] mod tests { - use geo_types::polygon; + use i_triangle::i_overlay::i_float::int::point::IntPoint; + use i_triangle::int::triangulatable::IntTriangulatable; use super::*; @@ -437,11 +407,15 @@ mod tests { #[test] fn triangulate_box() { - let polygon = polygon![ - (x: 0.0, y: 0.0), (x: 10.0, y: 0.0), (x: 10.0, y: 10.0), (x: 0.0, y: 10.0) - ]; + let i_polygon = vec![vec![ + IntPoint::new(0, 0), + IntPoint::new(10, 0), + IntPoint::new(10, 10), + IntPoint::new(0, 10), + ]]; let mut triangles = Vec::new(); - triangulate(1, polygon, &mut triangles); + let delaunay = i_polygon.triangulate().into_delaunay(); + delaunay_to_triangles(1, &delaunay, &mut triangles); assert_eq!(triangles.len(), 2); } }