Skip to main content

geometry_kernel/
pure_rust.rs

1use crate::buffer::{self, BufferOptions};
2use crate::canonicalize::canonicalize_polygon;
3use crate::error::Result;
4use crate::kernel::{GeometryKernel, KernelBackend};
5use crate::overlay;
6use crate::precision::PrecisionModel;
7use crate::predicates::{polygon_area, segment_intersection, SegmentIntersection};
8use crate::types::{Coord, LineString, MultiPolygon, Polygon};
9
10#[derive(Debug, Clone, Copy, PartialEq)]
11pub struct PureRustKernel {
12    precision: PrecisionModel,
13}
14
15impl PureRustKernel {
16    pub const fn new(precision: PrecisionModel) -> Self {
17        Self { precision }
18    }
19}
20
21impl Default for PureRustKernel {
22    fn default() -> Self {
23        Self::new(PrecisionModel::floating())
24    }
25}
26
27impl GeometryKernel for PureRustKernel {
28    fn backend(&self) -> KernelBackend {
29        KernelBackend::PureRust
30    }
31
32    fn precision(&self) -> PrecisionModel {
33        self.precision
34    }
35
36    fn canonicalize_polygon(&self, polygon: &Polygon) -> Polygon {
37        canonicalize_polygon(polygon, self.precision)
38    }
39
40    fn polygon_area(&self, polygon: &Polygon) -> Result<f64> {
41        Ok(polygon_area(polygon))
42    }
43
44    fn largest_polygon(&self, multi_polygon: &MultiPolygon) -> Result<Option<Polygon>> {
45        Ok(multi_polygon
46            .polygons
47            .iter()
48            .max_by(|left, right| {
49                polygon_area(left)
50                    .partial_cmp(&polygon_area(right))
51                    .unwrap_or(std::cmp::Ordering::Equal)
52            })
53            .cloned())
54    }
55
56    fn buffer_polygon(
57        &self,
58        polygon: &Polygon,
59        distance: f64,
60        options: BufferOptions,
61    ) -> Result<MultiPolygon> {
62        buffer::buffer_polygon(polygon, distance, options, self.precision)
63    }
64
65    fn line_buffer(
66        &self,
67        line: &LineString,
68        distance: f64,
69        options: BufferOptions,
70    ) -> Result<MultiPolygon> {
71        buffer::line_buffer(line, distance, options, self.precision)
72    }
73
74    fn intersection(&self, subject: &MultiPolygon, clip: &MultiPolygon) -> Result<MultiPolygon> {
75        overlay::intersection(subject, clip, self.precision)
76    }
77
78    fn difference(&self, subject: &MultiPolygon, clip: &MultiPolygon) -> Result<MultiPolygon> {
79        overlay::difference(subject, clip, self.precision)
80    }
81
82    fn line_polygon_intersections(
83        &self,
84        line: &LineString,
85        polygon: &Polygon,
86    ) -> Result<Vec<Coord>> {
87        let mut points = Vec::new();
88
89        for (line_start, line_end) in line.segments() {
90            for ring in std::iter::once(&polygon.exterior).chain(polygon.holes.iter()) {
91                for (ring_start, ring_end) in ring.segments() {
92                    match segment_intersection(
93                        line_start,
94                        line_end,
95                        ring_start,
96                        ring_end,
97                        self.precision,
98                    ) {
99                        Some(SegmentIntersection::Point(point)) => {
100                            push_unique(&mut points, point, self.precision);
101                        }
102                        Some(SegmentIntersection::Overlap(start, end)) => {
103                            push_unique(&mut points, start, self.precision);
104                            push_unique(&mut points, end, self.precision);
105                        }
106                        None => {}
107                    }
108                }
109            }
110        }
111
112        Ok(points)
113    }
114}
115
116fn push_unique(points: &mut Vec<Coord>, point: Coord, precision: PrecisionModel) {
117    let point = precision.snap_coord(point);
118    if !points
119        .iter()
120        .any(|existing| precision.same_coord(*existing, point))
121    {
122        points.push(point);
123    }
124}