Skip to main content

stt_core/
geometry.rs

1//! Geometry processing utilities
2//!
3//! This module provides functions for processing and simplifying geometric data
4//! for use in spatiotemporal tiles. Uses standard geo/geo-types crates.
5//!
6//! Earlier revisions exposed `encode_coordinates` / `zigzag_encode` for a
7//! quantized geometry encoding that was never wired into the v2 build path
8//! (which emits real f64 lon/lat in Arrow). Those have been removed; the
9//! format-v3 work (Track B) is rebuilding quantized coordinate encoding on
10//! top of fixed-precision Arrow columns, not the old zigzag delta format.
11
12use geo::algorithm::simplify::Simplify;
13use geo::{LineString, Polygon};
14
15/// Simplify a linestring using the Douglas-Peucker algorithm
16///
17/// This uses the standard `geo` crate's Simplify trait for consistent,
18/// well-tested simplification.
19pub fn simplify_linestring(line: &LineString<f64>, epsilon: f64) -> LineString<f64> {
20    let num_coords = line.coords().count();
21    if num_coords <= 2 {
22        return line.clone();
23    }
24    line.simplify(&epsilon)
25}
26
27/// Simplify a polygon using the Douglas-Peucker algorithm
28///
29/// This uses the standard `geo` crate's Simplify trait for consistent,
30/// well-tested simplification.
31pub fn simplify_polygon(polygon: &Polygon<f64>, epsilon: f64) -> Polygon<f64> {
32    polygon.simplify(&epsilon)
33}
34
35/// Calculate the bounding box of a linestring using geo types
36pub fn bounding_box_line(line: &LineString<f64>) -> crate::types::BoundingBox {
37    use geo::algorithm::bounding_rect::BoundingRect;
38
39    if let Some(rect) = line.bounding_rect() {
40        crate::types::BoundingBox::new(rect.min().x, rect.min().y, rect.max().x, rect.max().y)
41    } else {
42        crate::types::BoundingBox::default()
43    }
44}
45
46/// Calculate the bounding box of a polygon using geo types
47pub fn bounding_box_polygon(polygon: &Polygon<f64>) -> crate::types::BoundingBox {
48    use geo::algorithm::bounding_rect::BoundingRect;
49
50    if let Some(rect) = polygon.bounding_rect() {
51        crate::types::BoundingBox::new(rect.min().x, rect.min().y, rect.max().x, rect.max().y)
52    } else {
53        crate::types::BoundingBox::default()
54    }
55}
56
57#[cfg(test)]
58mod tests {
59    use super::*;
60
61    #[test]
62    fn test_simplify_linestring() {
63        let line: LineString<f64> =
64            vec![(0.0, 0.0), (1.0, 0.1), (2.0, 0.0), (3.0, 0.1), (4.0, 0.0)].into();
65        let simplified = simplify_linestring(&line, 0.5);
66        let num_coords = simplified.coords().count();
67        let orig_coords = line.coords().count();
68        assert!(num_coords < orig_coords);
69    }
70
71}