1use alloc::{collections::BTreeMap, vec::Vec};
2use bevy_math::{ops, Vec2};
3use core::cmp::Ordering;
4
5#[derive(Debug, Clone, Copy)]
6enum Endpoint {
7 Left,
8 Right,
9}
10
11#[derive(Debug, Clone, Copy)]
18struct SweepLineEvent {
19 segment: Segment,
20 endpoint: Endpoint,
22}
23
24impl SweepLineEvent {
25 const fn position(&self) -> Vec2 {
26 match self.endpoint {
27 Endpoint::Left => self.segment.left,
28 Endpoint::Right => self.segment.right,
29 }
30 }
31}
32
33impl PartialEq for SweepLineEvent {
34 fn eq(&self, other: &Self) -> bool {
35 self.position() == other.position()
36 }
37}
38
39impl Eq for SweepLineEvent {}
40
41impl PartialOrd for SweepLineEvent {
42 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
43 Some(self.cmp(other))
44 }
45}
46
47impl Ord for SweepLineEvent {
48 fn cmp(&self, other: &Self) -> Ordering {
49 xy_order(self.position(), other.position())
50 }
51}
52
53fn xy_order(a: Vec2, b: Vec2) -> Ordering {
55 a.x.total_cmp(&b.x).then_with(|| a.y.total_cmp(&b.y))
56}
57
58#[derive(Debug, Clone)]
60struct EventQueue {
61 events: Vec<SweepLineEvent>,
62}
63impl EventQueue {
64 fn new(vertices: &[Vec2]) -> Self {
68 if vertices.is_empty() {
69 return Self { events: Vec::new() };
70 }
71
72 let mut events = Vec::with_capacity(vertices.len() * 2);
73 for i in 0..vertices.len() {
74 let v1 = vertices[i];
75 let v2 = *vertices.get(i + 1).unwrap_or(&vertices[0]);
76 let (left, right) = if xy_order(v1, v2) == Ordering::Less {
77 (v1, v2)
78 } else {
79 (v2, v1)
80 };
81
82 let segment = Segment {
83 edge_index: i,
84 left,
85 right,
86 };
87 events.push(SweepLineEvent {
88 segment,
89 endpoint: Endpoint::Left,
90 });
91 events.push(SweepLineEvent {
92 segment,
93 endpoint: Endpoint::Right,
94 });
95 }
96
97 events.sort();
98
99 Self { events }
100 }
101}
102
103#[derive(Debug, Clone, Copy)]
108struct Segment {
109 edge_index: usize,
110 left: Vec2,
111 right: Vec2,
112}
113
114impl PartialEq for Segment {
115 fn eq(&self, other: &Self) -> bool {
116 self.edge_index == other.edge_index
117 }
118}
119
120impl Eq for Segment {}
121
122impl PartialOrd for Segment {
123 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
124 Some(self.cmp(other))
125 }
126}
127
128impl Ord for Segment {
129 fn cmp(&self, other: &Self) -> Ordering {
130 self.left
131 .y
132 .total_cmp(&other.left.y)
133 .then_with(|| self.right.y.total_cmp(&other.right.y))
134 }
135}
136
137#[derive(Debug, Clone, Copy)]
139struct SegmentOrder {
140 above: Option<usize>,
141 below: Option<usize>,
142}
143
144#[derive(Debug, Clone)]
149struct SweepLine<'a> {
150 vertices: &'a [Vec2],
151 tree: BTreeMap<Segment, SegmentOrder>,
152}
153
154impl<'a> SweepLine<'a> {
155 const fn new(vertices: &'a [Vec2]) -> Self {
156 Self {
157 vertices,
158 tree: BTreeMap::new(),
159 }
160 }
161
162 fn intersects(&self, edge1: Option<usize>, edge2: Option<usize>) -> bool {
164 let Some(edge1) = edge1 else {
165 return false;
166 };
167 let Some(edge2) = edge2 else {
168 return false;
169 };
170
171 if edge1 == edge2
175 || (edge1 + 1) % self.vertices.len() == edge2
176 || (edge2 + 1) % self.vertices.len() == edge1
177 {
178 return false;
179 }
180
181 let s11 = self.vertices[edge1];
182 let s12 = *self.vertices.get(edge1 + 1).unwrap_or(&self.vertices[0]);
183 let s21 = self.vertices[edge2];
184 let s22 = *self.vertices.get(edge2 + 1).unwrap_or(&self.vertices[0]);
185
186 if point_side(s11, s12, s21) * point_side(s11, s12, s22) > 0.0 {
188 return false;
189 }
190 if point_side(s21, s22, s11) * point_side(s21, s22, s12) > 0.0 {
191 return false;
192 }
193
194 true
195 }
196
197 fn add(&mut self, s: Segment) -> SegmentOrder {
199 let above = if let Some((next_s, next_ord)) = self.tree.range_mut(s..).next() {
200 next_ord.below.replace(s.edge_index);
201 Some(next_s.edge_index)
202 } else {
203 None
204 };
205 let below = if let Some((prev_s, prev_ord)) = self.tree.range_mut(..s).next_back() {
206 prev_ord.above.replace(s.edge_index);
207 Some(prev_s.edge_index)
208 } else {
209 None
210 };
211
212 let s_ord = SegmentOrder { above, below };
213 self.tree.insert(s, s_ord);
214 s_ord
215 }
216
217 fn find(&self, s: &Segment) -> Option<&SegmentOrder> {
221 self.tree.get(s)
222 }
223
224 fn remove(&mut self, s: &Segment) {
226 let Some(s_ord) = self.tree.get(s).copied() else {
227 return;
228 };
229
230 if let Some((_, above_ord)) = self.tree.range_mut(s..).next() {
231 above_ord.below = s_ord.below;
232 }
233 if let Some((_, below_ord)) = self.tree.range_mut(..s).next_back() {
234 below_ord.above = s_ord.above;
235 }
236
237 self.tree.remove(s);
238 }
239}
240
241#[inline]
245const fn point_side(p1: Vec2, p2: Vec2, q: Vec2) -> f32 {
246 (p2.x - p1.x) * (q.y - p1.y) - (q.x - p1.x) * (p2.y - p1.y)
247}
248
249pub fn is_polygon_simple(vertices: &[Vec2]) -> bool {
260 if vertices.len() < 3 {
261 return true;
262 }
263 if vertices.len() == 3 {
264 let [a, b, c] = [vertices[0], vertices[1], vertices[2]];
265 let triangle_area =
266 ops::abs(a.x * (b.y - c.y) + b.x * (c.y - a.y) + c.x * (a.y - b.y)) / 2.0;
267 return triangle_area > 0.0;
268 }
269
270 let event_queue = EventQueue::new(vertices);
271 let mut sweep_line = SweepLine::new(vertices);
272
273 for e in event_queue.events {
274 match e.endpoint {
275 Endpoint::Left => {
276 let s = sweep_line.add(e.segment);
277 if sweep_line.intersects(Some(e.segment.edge_index), s.above)
278 || sweep_line.intersects(Some(e.segment.edge_index), s.below)
279 {
280 return false;
281 }
282 }
283 Endpoint::Right => {
284 if let Some(s) = sweep_line.find(&e.segment) {
285 if sweep_line.intersects(s.above, s.below) {
286 return false;
287 }
288 sweep_line.remove(&e.segment);
289 }
290 }
291 }
292 }
293
294 true
295}
296
297#[cfg(test)]
298mod tests {
299 use super::*;
300 use bevy_math::Vec2;
301
302 #[test]
303 fn complex_polygon() {
304 let verts = [Vec2::ZERO, Vec2::X, Vec2::ONE, Vec2::Y, Vec2::new(2.0, 0.5)];
306 assert!(!is_polygon_simple(&verts));
307
308 let verts = [Vec2::ZERO, Vec2::X, Vec2::ONE, Vec2::Y, Vec2::new(1.0, 0.5)];
310 assert!(!is_polygon_simple(&verts));
311
312 let verts = [
314 Vec2::ZERO,
315 Vec2::X,
316 Vec2::ONE,
317 Vec2::Y,
318 Vec2::new(1.0, 0.6),
319 Vec2::new(1.0, 0.4),
320 ];
321 assert!(!is_polygon_simple(&verts));
322
323 let verts = [Vec2::ONE, Vec2::new(3., 2.), Vec2::new(5., 3.), Vec2::NEG_X];
325 assert!(!is_polygon_simple(&verts));
326
327 let verts = [Vec2::ONE, Vec2::new(3., 2.), Vec2::NEG_X];
329 assert!(!is_polygon_simple(&verts));
330
331 let verts = [Vec2::ONE, Vec2::ONE, Vec2::NEG_X];
333 assert!(!is_polygon_simple(&verts));
334
335 let verts = [Vec2::ZERO, Vec2::X, Vec2::Y, Vec2::ONE, Vec2::X, Vec2::Y];
337 assert!(!is_polygon_simple(&verts));
338 }
339
340 #[test]
341 fn simple_polygon() {
342 let verts = [Vec2::ZERO, Vec2::X, Vec2::ONE, Vec2::Y];
344 assert!(is_polygon_simple(&verts));
345
346 let verts = [];
347 assert!(is_polygon_simple(&verts));
348 }
349}