Skip to main content

geometry_kernel/
precision.rs

1use crate::types::{Coord, LineString, LinearRing, MultiPolygon, Polygon};
2
3#[derive(Debug, Clone, Copy, PartialEq)]
4pub struct PrecisionModel {
5    grid_size: Option<f64>,
6    epsilon: f64,
7}
8
9impl PrecisionModel {
10    pub const fn floating() -> Self {
11        Self {
12            grid_size: None,
13            epsilon: 1.0e-9,
14        }
15    }
16
17    pub fn fixed(grid_size: f64) -> Self {
18        assert!(grid_size.is_finite() && grid_size > 0.0);
19        Self {
20            grid_size: Some(grid_size),
21            epsilon: grid_size * 0.5,
22        }
23    }
24
25    pub const fn epsilon(self) -> f64 {
26        self.epsilon
27    }
28
29    pub fn snap_value(self, value: f64) -> f64 {
30        match self.grid_size {
31            Some(grid) => (value / grid).round() * grid,
32            None => value,
33        }
34    }
35
36    pub fn snap_coord(self, coord: Coord) -> Coord {
37        Coord::new(self.snap_value(coord.x), self.snap_value(coord.y))
38    }
39
40    pub fn same_coord(self, a: Coord, b: Coord) -> bool {
41        a.distance_squared(b) <= self.epsilon * self.epsilon
42    }
43
44    pub fn snap_line(self, line: &LineString) -> LineString {
45        LineString::new(line.coords.iter().map(|c| self.snap_coord(*c)).collect())
46    }
47
48    pub fn snap_ring(self, ring: &LinearRing) -> LinearRing {
49        LinearRing::new(ring.coords.iter().map(|c| self.snap_coord(*c)).collect())
50    }
51
52    pub fn snap_polygon(self, polygon: &Polygon) -> Polygon {
53        Polygon::new(
54            self.snap_ring(&polygon.exterior),
55            polygon
56                .holes
57                .iter()
58                .map(|ring| self.snap_ring(ring))
59                .collect(),
60        )
61    }
62
63    pub fn snap_multi_polygon(self, multi_polygon: &MultiPolygon) -> MultiPolygon {
64        MultiPolygon::new(
65            multi_polygon
66                .polygons
67                .iter()
68                .map(|polygon| self.snap_polygon(polygon))
69                .collect(),
70        )
71    }
72}
73
74impl Default for PrecisionModel {
75    fn default() -> Self {
76        Self::floating()
77    }
78}