geometry_kernel/
pure_rust.rs1use 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}