1#[cfg(feature = "alloc")]
2use {
3super::{Measured2d, Triangle2d},
4 alloc::{collections::BTreeMap, vec::Vec},
5core::cmp::Ordering,
6};
78use crate::Vec2;
910#[derive(#[automatically_derived]
impl ::core::fmt::Debug for Endpoint {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::write_str(f,
match self {
Endpoint::Left => "Left",
Endpoint::Right => "Right",
})
}
}Debug, #[automatically_derived]
impl ::core::clone::Clone for Endpoint {
#[inline]
fn clone(&self) -> Endpoint { *self }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for Endpoint { }Copy)]
11#[cfg(feature = "alloc")]
12enum Endpoint {
13 Left,
14 Right,
15}
1617/// An event in the [`EventQueue`] is either the left or right vertex of an edge of the polygon.
18///
19/// Events are ordered so that any event `e1` which is to the left of another event `e2` is less than that event.
20/// If `e1.position().x == e2.position().x` the events are ordered from bottom to top.
21///
22/// This is the order expected by the [`SweepLine`].
23#[cfg(feature = "alloc")]
24#[derive(#[automatically_derived]
impl ::core::fmt::Debug for SweepLineEvent {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field2_finish(f,
"SweepLineEvent", "segment", &self.segment, "endpoint",
&&self.endpoint)
}
}Debug, #[automatically_derived]
impl ::core::clone::Clone for SweepLineEvent {
#[inline]
fn clone(&self) -> SweepLineEvent {
let _: ::core::clone::AssertParamIsClone<Segment>;
let _: ::core::clone::AssertParamIsClone<Endpoint>;
*self
}
}Clone, #[automatically_derived]
impl ::core::marker::Copy for SweepLineEvent { }Copy)]
25struct SweepLineEvent {
26 segment: Segment,
27/// Type of the vertex (left or right)
28endpoint: Endpoint,
29}
3031#[cfg(feature = "alloc")]
32impl SweepLineEvent {
33fn position(&self) -> Vec2 {
34match self.endpoint {
35 Endpoint::Left => self.segment.left,
36 Endpoint::Right => self.segment.right,
37 }
38 }
39}
4041#[cfg(feature = "alloc")]
42impl PartialEqfor SweepLineEvent {
43fn eq(&self, other: &Self) -> bool {
44self.position() == other.position()
45 }
46}
4748#[cfg(feature = "alloc")]
49impl Eqfor SweepLineEvent {}
5051#[cfg(feature = "alloc")]
52impl PartialOrdfor SweepLineEvent {
53fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
54Some(self.cmp(other))
55 }
56}
5758#[cfg(feature = "alloc")]
59impl Ordfor SweepLineEvent {
60fn cmp(&self, other: &Self) -> Ordering {
61xy_order(self.position(), other.position())
62 }
63}
6465/// Orders 2D points according to the order expected by the sweep line and event queue from -X to +X and then -Y to Y.
66#[cfg(feature = "alloc")]
67fn xy_order(a: Vec2, b: Vec2) -> Ordering {
68a.x.total_cmp(&b.x).then_with(|| a.y.total_cmp(&b.y))
69}
7071/// The event queue holds an ordered list of all events the [`SweepLine`] will encounter when checking the current polygon.
72#[cfg(feature = "alloc")]
73#[derive(#[automatically_derived]
impl ::core::fmt::Debug for EventQueue {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field1_finish(f, "EventQueue",
"events", &&self.events)
}
}Debug, #[automatically_derived]
impl ::core::clone::Clone for EventQueue {
#[inline]
fn clone(&self) -> EventQueue {
EventQueue { events: ::core::clone::Clone::clone(&self.events) }
}
}Clone)]
74struct EventQueue {
75 events: Vec<SweepLineEvent>,
76}
77#[cfg(feature = "alloc")]
78impl EventQueue {
79/// Initialize a new `EventQueue` with all events from the polygon represented by `vertices`.
80 ///
81 /// The events in the event queue will be ordered.
82fn new(vertices: &[Vec2]) -> Self {
83if vertices.is_empty() {
84return Self { events: Vec::new() };
85 }
8687let mut events = Vec::with_capacity(vertices.len() * 2);
88for i in 0..vertices.len() {
89let v1 = vertices[i];
90let v2 = *vertices.get(i + 1).unwrap_or(&vertices[0]);
91let (left, right) = if xy_order(v1, v2) == Ordering::Less {
92 (v1, v2)
93 } else {
94 (v2, v1)
95 };
9697let segment = Segment {
98 edge_index: i,
99 left,
100 right,
101 };
102 events.push(SweepLineEvent {
103 segment,
104 endpoint: Endpoint::Left,
105 });
106 events.push(SweepLineEvent {
107 segment,
108 endpoint: Endpoint::Right,
109 });
110 }
111112events.sort();
113114Self { events }
115 }
116}
117118/// Represents a segment or rather an edge of the polygon in the [`SweepLine`].
119///
120/// Segments are ordered from bottom to top based on their left vertices if possible.
121/// If their y values are identical, the segments are ordered based on the y values of their right vertices.
122#[derive(#[automatically_derived]
impl ::core::fmt::Debug for Segment {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field3_finish(f, "Segment",
"edge_index", &self.edge_index, "left", &self.left, "right",
&&self.right)
}
}Debug, #[automatically_derived]
impl ::core::clone::Clone for Segment {
#[inline]
fn clone(&self) -> Segment {
let _: ::core::clone::AssertParamIsClone<usize>;
let _: ::core::clone::AssertParamIsClone<Vec2>;
*self
}
}Clone, #[automatically_derived]
impl ::core::marker::Copy for Segment { }Copy)]
123#[cfg(feature = "alloc")]
124struct Segment {
125 edge_index: usize,
126 left: Vec2,
127 right: Vec2,
128}
129130#[cfg(feature = "alloc")]
131impl PartialEqfor Segment {
132fn eq(&self, other: &Self) -> bool {
133self.edge_index == other.edge_index
134 }
135}
136137#[cfg(feature = "alloc")]
138impl Eqfor Segment {}
139140#[cfg(feature = "alloc")]
141impl PartialOrdfor Segment {
142fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
143Some(self.cmp(other))
144 }
145}
146147#[cfg(feature = "alloc")]
148impl Ordfor Segment {
149fn cmp(&self, other: &Self) -> Ordering {
150self.left
151 .y
152 .total_cmp(&other.left.y)
153 .then_with(|| self.right.y.total_cmp(&other.right.y))
154 }
155}
156157/// Holds information about which segment is above and which is below a given [`Segment`]
158#[cfg(feature = "alloc")]
159#[derive(#[automatically_derived]
impl ::core::fmt::Debug for SegmentOrder {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field2_finish(f, "SegmentOrder",
"above", &self.above, "below", &&self.below)
}
}Debug, #[automatically_derived]
impl ::core::clone::Clone for SegmentOrder {
#[inline]
fn clone(&self) -> SegmentOrder {
let _: ::core::clone::AssertParamIsClone<Option<usize>>;
let _: ::core::clone::AssertParamIsClone<Option<usize>>;
*self
}
}Clone, #[automatically_derived]
impl ::core::marker::Copy for SegmentOrder { }Copy)]
160struct SegmentOrder {
161 above: Option<usize>,
162 below: Option<usize>,
163}
164165/// A sweep line allows for an efficient search for intersections between [segments](`Segment`).
166///
167/// It can be thought of as a vertical line sweeping from -X to +X across the polygon that keeps track of the order of the segments
168/// the sweep line is intersecting at any given moment.
169#[derive(#[automatically_derived]
impl<'a> ::core::fmt::Debug for SweepLine<'a> {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field2_finish(f, "SweepLine",
"vertices", &self.vertices, "tree", &&self.tree)
}
}Debug, #[automatically_derived]
impl<'a> ::core::clone::Clone for SweepLine<'a> {
#[inline]
fn clone(&self) -> SweepLine<'a> {
SweepLine {
vertices: ::core::clone::Clone::clone(&self.vertices),
tree: ::core::clone::Clone::clone(&self.tree),
}
}
}Clone)]
170#[cfg(feature = "alloc")]
171struct SweepLine<'a> {
172 vertices: &'a [Vec2],
173 tree: BTreeMap<Segment, SegmentOrder>,
174}
175#[cfg(feature = "alloc")]
176impl<'a> SweepLine<'a> {
177const fn new(vertices: &'a [Vec2]) -> Self {
178Self {
179vertices,
180 tree: BTreeMap::new(),
181 }
182 }
183184/// Determine whether the given edges of the polygon intersect.
185fn intersects(&self, edge1: Option<usize>, edge2: Option<usize>) -> bool {
186let Some(edge1) = edge1else {
187return false;
188 };
189let Some(edge2) = edge2else {
190return false;
191 };
192193// All adjacent edges intersect at their shared vertex
194 // but these intersections do not count so we ignore them here.
195 // Likewise a segment will always intersect itself / an identical edge.
196if edge1 == edge2197 || (edge1 + 1) % self.vertices.len() == edge2198 || (edge2 + 1) % self.vertices.len() == edge1199 {
200return false;
201 }
202203let s11 = self.vertices[edge1];
204let s12 = *self.vertices.get(edge1 + 1).unwrap_or(&self.vertices[0]);
205let s21 = self.vertices[edge2];
206let s22 = *self.vertices.get(edge2 + 1).unwrap_or(&self.vertices[0]);
207208// When both points of the second edge are on the same side of the first edge, no intersection is possible.
209if point_side(s11, s12, s21) * point_side(s11, s12, s22) > 0.0 {
210return false;
211 }
212if point_side(s21, s22, s11) * point_side(s21, s22, s12) > 0.0 {
213return false;
214 }
215216true
217}
218219/// Add a new segment to the sweep line
220fn add(&mut self, s: Segment) -> SegmentOrder {
221let above = if let Some((next_s, next_ord)) = self.tree.range_mut(s..).next() {
222next_ord.below.replace(s.edge_index);
223Some(next_s.edge_index)
224 } else {
225None226 };
227let below = if let Some((prev_s, prev_ord)) = self.tree.range_mut(..s).next_back() {
228prev_ord.above.replace(s.edge_index);
229Some(prev_s.edge_index)
230 } else {
231None232 };
233234let s_ord = SegmentOrder { above, below };
235self.tree.insert(s, s_ord);
236s_ord237 }
238239/// Get the segment order for the given segment.
240 ///
241 /// If `s` has not been added to the [`SweepLine`] `None` will be returned.
242fn find(&self, s: &Segment) -> Option<&SegmentOrder> {
243self.tree.get(s)
244 }
245246/// Remove `s` from the [`SweepLine`].
247fn remove(&mut self, s: &Segment) {
248let Some(s_ord) = self.tree.get(s).copied() else {
249return;
250 };
251252if let Some((_, above_ord)) = self.tree.range_mut(s..).next() {
253above_ord.below = s_ord.below;
254 }
255if let Some((_, below_ord)) = self.tree.range_mut(..s).next_back() {
256below_ord.above = s_ord.above;
257 }
258259self.tree.remove(s);
260 }
261}
262263/// Test what side of the line through `p1` and `p2` `q` is.
264///
265/// The result will be `0` if the `q` is on the segment, negative for one side and positive for the other.
266#[cfg_attr(
267 not(feature = "alloc"),
268 expect(
269 dead_code,
270 reason = "this function is only used with the alloc feature"
271)
272)]
273#[inline]
274const fn point_side(p1: Vec2, p2: Vec2, q: Vec2) -> f32 {
275 (p2.x - p1.x) * (q.y - p1.y) - (q.x - p1.x) * (p2.y - p1.y)
276}
277278/// Tests whether the `vertices` describe a simple polygon.
279/// The last vertex must not be equal to the first vertex.
280///
281/// A polygon is simple if it is not self intersecting and not self tangent.
282/// As such, no two edges of the polygon may cross each other and each vertex must not lie on another edge.
283///
284/// Any 'polygon' with less than three vertices is simple.
285///
286/// The algorithm used is the Shamos-Hoey algorithm, a version of the Bentley-Ottman algorithm adapted to only detect whether any intersections exist.
287/// This function will run in O(n * log n)
288#[cfg(feature = "alloc")]
289pub fn is_polygon_simple(vertices: &[Vec2]) -> bool {
290if vertices.len() < 3 {
291return true;
292 }
293if vertices.len() == 3 {
294return Triangle2d::new(vertices[0], vertices[1], vertices[2]).area() > 0.0;
295 }
296297let event_queue = EventQueue::new(vertices);
298let mut sweep_line = SweepLine::new(vertices);
299300for e in event_queue.events {
301match e.endpoint {
302 Endpoint::Left => {
303let s = sweep_line.add(e.segment);
304if sweep_line.intersects(Some(e.segment.edge_index), s.above)
305 || sweep_line.intersects(Some(e.segment.edge_index), s.below)
306 {
307return false;
308 }
309 }
310 Endpoint::Right => {
311if let Some(s) = sweep_line.find(&e.segment) {
312if sweep_line.intersects(s.above, s.below) {
313return false;
314 }
315 sweep_line.remove(&e.segment);
316 }
317 }
318 }
319 }
320321true
322}
323324#[cfg(test)]
325mod tests {
326use crate::{primitives::polygon::is_polygon_simple, Vec2};
327328#[test]
329fn complex_polygon() {
330// A square with one side punching through the opposite side.
331let verts = [Vec2::ZERO, Vec2::X, Vec2::ONE, Vec2::Y, Vec2::new(2.0, 0.5)];
332assert!(!is_polygon_simple(&verts));
333334// A square with a vertex from one side touching the opposite side.
335let verts = [Vec2::ZERO, Vec2::X, Vec2::ONE, Vec2::Y, Vec2::new(1.0, 0.5)];
336assert!(!is_polygon_simple(&verts));
337338// A square with one side touching the opposite side.
339let verts = [
340 Vec2::ZERO,
341 Vec2::X,
342 Vec2::ONE,
343 Vec2::Y,
344 Vec2::new(1.0, 0.6),
345 Vec2::new(1.0, 0.4),
346 ];
347assert!(!is_polygon_simple(&verts));
348349// Four points lying on a line
350let verts = [Vec2::ONE, Vec2::new(3., 2.), Vec2::new(5., 3.), Vec2::NEG_X];
351assert!(!is_polygon_simple(&verts));
352353// Three points lying on a line
354let verts = [Vec2::ONE, Vec2::new(3., 2.), Vec2::NEG_X];
355assert!(!is_polygon_simple(&verts));
356357// Two identical points and one other point
358let verts = [Vec2::ONE, Vec2::ONE, Vec2::NEG_X];
359assert!(!is_polygon_simple(&verts));
360361// Two triangles with one shared side
362let verts = [Vec2::ZERO, Vec2::X, Vec2::Y, Vec2::ONE, Vec2::X, Vec2::Y];
363assert!(!is_polygon_simple(&verts));
364 }
365366#[test]
367fn simple_polygon() {
368// A square
369let verts = [Vec2::ZERO, Vec2::X, Vec2::ONE, Vec2::Y];
370assert!(is_polygon_simple(&verts));
371372let verts = [];
373assert!(is_polygon_simple(&verts));
374 }
375}