makepad_vector/trapezoidator/
mod.rs1use crate::geometry::{LineSegment, Point, Trapezoid};
2use crate::internal_iter::InternalIterator;
3use crate::path::{LinePathCommand, LinePathIterator};
4use std::cmp::Ordering;
5use std::collections::BinaryHeap;
6use std::mem;
7use std::ops::Range;
8
9#[derive(Clone, Debug, Default)]
12pub struct Trapezoidator {
13 event_queue: BinaryHeap<Event>,
14 active_segments: Vec<ActiveSegment>,
15}
16
17impl Trapezoidator {
18 pub fn new() -> Trapezoidator {
20 Trapezoidator::default()
21 }
22
23 pub fn trapezoidate<P: LinePathIterator>(&mut self, path: P) -> Option<Trapezoidate> {
26 let mut initial_point = None;
27 let mut current_point = None;
28 if !path.for_each(&mut |command| {
29 match command {
30 LinePathCommand::MoveTo(p) => {
31 initial_point = Some(p);
32 current_point = Some(p);
33 }
34 LinePathCommand::LineTo(p) => {
35 let p0 = current_point.replace(p).unwrap();
36 if !self.push_events_for_segment(LineSegment::new(p0, p)) {
37 return false;
38 }
39 }
40 LinePathCommand::Close => {
41 let p = initial_point.take().unwrap();
42 let p0 = current_point.replace(p).unwrap();
43 if !self.push_events_for_segment(LineSegment::new(p0, p)) {
44 return false;
45 }
46 }
47 }
48 true
49 }){
50 return None
51 };
52 Some(Trapezoidate {
53 trapezoidator: self,
54 })
55 }
56
57 fn push_events_for_segment(&mut self, segment: LineSegment) -> bool {
59 let (winding, p0, p1) = match segment.p0.partial_cmp(&segment.p1) {
69 None => {
70 return false;
74 },
75 Some(Ordering::Less) => (1, segment.p0, segment.p1),
76 Some(Ordering::Equal) => {
77 return true;
81 }
82 Some(Ordering::Greater) => (-1, segment.p1, segment.p0),
83 };
84 self.event_queue.push(Event {
87 point: p0,
88 pending_segment: Some(PendingSegment { winding, p1 }),
89 });
90 self.event_queue.push(Event {
93 point: p1,
94 pending_segment: None,
95 });
96 true
97 }
98
99 fn pop_events_for_next_point(
105 &mut self,
106 pending_segments: &mut Vec<PendingSegment>,
107 ) -> Option<Point> {
108 self.event_queue.pop().map(|event| {
110 if let Some(pending_segment) = event.pending_segment {
113 pending_segments.push(pending_segment)
114 }
115 while let Some(&next_event) = self.event_queue.peek() {
117 if next_event != event {
118 break;
119 }
120 self.event_queue.pop();
121 if let Some(pending_segment) = next_event.pending_segment {
124 pending_segments.push(pending_segment);
125 }
126 }
127 event.point
128 })
129 }
130
131 fn handle_events_for_point<F>(
135 &mut self,
136 point: Point,
137 right_segments: &mut Vec<PendingSegment>,
138 trapezoid_segments: &mut Vec<ActiveSegment>,
139 f: &mut F,
140 ) -> bool
141 where
142 F: FnMut(Trapezoid) -> bool,
143 {
144 let mut incident_segment_range = self.find_incident_segment_range(point);
146 if let Some(trapezoid_segment) =
151 self.find_trapezoid_segment_below(point, incident_segment_range.start)
152 {
153 trapezoid_segments.push(trapezoid_segment);
154 }
155 self.remove_incident_segments(
160 point,
161 &mut incident_segment_range,
162 right_segments,
163 trapezoid_segments,
164 );
165 self.sort_right_segments(point, right_segments);
167 self.insert_right_segments(point, &mut incident_segment_range, right_segments);
170 if let Some(trapezoid_segment) =
175 self.find_trapezoid_segment_above(point, incident_segment_range.end)
176 {
177 trapezoid_segments.push(trapezoid_segment);
178 }
179 self.generate_trapezoids(trapezoid_segments, f)
183 }
184
185 fn find_incident_segment_range(&self, point: Point) -> Range<usize> {
187 Range {
188 start: self
190 .active_segments
191 .iter()
192 .position(|active_segment| {
193 active_segment.segment.compare_to_point(point).unwrap() != Ordering::Less
194 })
195 .unwrap_or(self.active_segments.len()),
196 end: self
198 .active_segments
199 .iter()
200 .rposition(|active_segment| {
201 active_segment.segment.compare_to_point(point).unwrap() != Ordering::Greater
202 })
203 .map_or(0, |index| index + 1),
204 }
205 }
206
207 fn find_trapezoid_segment_below(
212 &mut self,
213 point: Point,
214 incident_segment_start: usize,
215 ) -> Option<ActiveSegment> {
216 if incident_segment_start == 0
217 || !self.active_segments[incident_segment_start - 1].region_above.is_inside {
218 return None;
219 }
220 let intersection = self.active_segments[incident_segment_start - 1]
221 .segment
222 .intersect_with_vertical_line(point.x)
223 .unwrap_or(point);
224 self.active_segments[incident_segment_start - 1].split_left_mut(intersection)
225 }
226
227 fn remove_incident_segments(
232 &mut self,
233 point: Point,
234 incident_segment_range: &mut Range<usize>,
235 right_segments: &mut Vec<PendingSegment>,
236 trapezoid_segments: &mut Vec<ActiveSegment>,
237 ) {
238 trapezoid_segments.extend(
239 Iterator::map(
240 self.active_segments.drain(incident_segment_range.clone()),
241 |mut active_segment| {
242 if let Some(pending_segment) = active_segment.split_right_mut(point) {
243 right_segments.push(pending_segment);
244 }
245 active_segment
246 },
247 )
248 .filter(|active_segment| active_segment.segment.p0.x != active_segment.segment.p1.x),
249 );
250 incident_segment_range.end = incident_segment_range.start;
251 }
252
253 fn sort_right_segments(&mut self, point: Point, right_segments: &mut Vec<PendingSegment>) {
256 right_segments.sort_by(|&right_segment_0, &right_segment_1| {
257 right_segment_0.compare(right_segment_1, point).unwrap()
258 });
259 let mut index_0 = 0;
260 for index_1 in 1..right_segments.len() {
261 let right_segment_1 = right_segments[index_1];
262 let right_segment_0 = &mut right_segments[index_0];
263 if right_segment_0.overlaps(right_segment_1, point) {
264 if let Some(event) = right_segment_0.splice_mut(right_segment_1) {
265 self.event_queue.push(event);
266 }
267 } else {
268 index_0 += 1;
269 right_segments[index_0] = right_segment_1;
270 }
271 }
272 right_segments.truncate(index_0 + 1);
273 }
274
275 fn insert_right_segments(
278 &mut self,
279 point: Point,
280 incident_segment_range: &mut Range<usize>,
281 right_segments: &[PendingSegment],
282 ) {
283 let mut lower_region = if incident_segment_range.end == 0 {
284 Region {
285 is_inside: false,
286 winding: 0,
287 }
288 } else {
289 self.active_segments[incident_segment_range.end - 1].region_above
290 };
291 self.active_segments.splice(
292 incident_segment_range.end..incident_segment_range.end,
293 Iterator::map(right_segments.iter(), |right_segment| {
294 let upper_region = {
295 let winding = lower_region.winding + right_segment.winding;
296 Region {
297 is_inside: winding != 0,
298 winding,
299 }
300 };
301 let right_segment = ActiveSegment {
302 winding: right_segment.winding,
303 segment: LineSegment::new(point, right_segment.p1),
304 region_above: upper_region,
305 };
306 lower_region = upper_region;
307 right_segment
308 }),
309 );
310 incident_segment_range.end += right_segments.len();
311 }
312
313 fn find_trapezoid_segment_above(
318 &mut self,
319 point: Point,
320 incident_segment_end: usize,
321 ) -> Option<ActiveSegment> {
322 if incident_segment_end == self.active_segments.len()
323 || incident_segment_end == 0
324 || !self.active_segments[incident_segment_end - 1].region_above.is_inside
325 {
326 return None;
327 }
328 let intersection = self.active_segments[incident_segment_end]
329 .segment
330 .intersect_with_vertical_line(point.x)
331 .unwrap();
332 if let Some(pending_segment) =
333 self.active_segments[incident_segment_end].split_right_mut(intersection)
334 {
335 self.event_queue.push(Event {
336 point: intersection,
337 pending_segment: Some(pending_segment),
338 });
339 }
340 Some(self.active_segments[incident_segment_end])
341 }
342
343 fn generate_trapezoids<F>(&self, trapezoid_segments: &[ActiveSegment], f: &mut F) -> bool
344 where
345 F: FnMut(Trapezoid) -> bool,
346 {
347 for trapezoid_segment_pair in trapezoid_segments.windows(2) {
348 if !trapezoid_segment_pair[0].region_above.is_inside {
349 continue;
350 }
351 let lower_segment = trapezoid_segment_pair[0].segment;
352 let upper_segment = trapezoid_segment_pair[1].segment;
353 if !f(Trapezoid {
354 xs: [lower_segment.p0.x as f32, lower_segment.p1.x as f32],
355 ys: [
356 lower_segment.p0.y as f32,
357 lower_segment.p1.y as f32,
358 upper_segment.p0.y as f32,
359 upper_segment.p1.y as f32,
360 ],
361 }) {
362 return false;
363 }
364 }
365 true
366 }
367}
368
369#[derive(Debug)]
371pub struct Trapezoidate<'a> {
372 trapezoidator: &'a mut Trapezoidator,
373}
374
375impl<'a> InternalIterator for Trapezoidate<'a> {
376 type Item = Trapezoid;
377
378 fn for_each<F>(self, f: &mut F) -> bool
379 where
380 F: FnMut(Trapezoid) -> bool,
381 {
382 let mut right_segments = Vec::new();
383 let mut trapezoid_segments = Vec::new();
384 while let Some(point) = self.trapezoidator.pop_events_for_next_point(&mut right_segments) {
385 let ok = self.trapezoidator.handle_events_for_point(
386 point,
387 &mut right_segments,
388 &mut trapezoid_segments,
389 f,
390 );
391 right_segments.clear();
392 trapezoid_segments.clear();
393 if !ok {
394 return false;
395 }
396 }
397 true
398 }
399}
400
401#[derive(Clone, Copy, Debug)]
403struct Event {
404 point: Point,
406 pending_segment: Option<PendingSegment>,
408}
409
410impl Eq for Event {}
411
412impl Ord for Event {
413 fn cmp(&self, other: &Event) -> Ordering {
414 self.point.partial_cmp(&other.point).unwrap().reverse()
415 }
416}
417
418impl PartialEq for Event {
419 fn eq(&self, other: &Event) -> bool {
420 self.cmp(other) == Ordering::Equal
421 }
422}
423
424impl PartialOrd for Event {
425 fn partial_cmp(&self, other: &Event) -> Option<Ordering> {
426 Some(self.cmp(other))
427 }
428}
429
430#[derive(Clone, Copy, Debug, PartialEq)]
435struct PendingSegment {
436 winding: i32,
438 p1: Point,
440}
441
442impl PendingSegment {
443 fn to_segment(self, p0: Point) -> LineSegment {
444 LineSegment::new(p0, self.p1)
445 }
446
447 fn overlaps(self, other: PendingSegment, p0: Point) -> bool {
448 self.compare(other, p0) == Some(Ordering::Equal)
449 }
450
451 fn compare(self, other: PendingSegment, p0: Point) -> Option<Ordering> {
452 if self.p1 <= other.p1 {
453 other
454 .to_segment(p0)
455 .compare_to_point(self.p1)
456 .map(|ordering| ordering.reverse())
457 } else {
458 self.to_segment(p0).compare_to_point(other.p1)
459 }
460 }
461
462 fn splice_mut(&mut self, mut other: Self) -> Option<Event> {
463 if other.p1 < self.p1 {
464 mem::swap(self, &mut other);
465 }
466 self.winding += other.winding;
467 if self.p1 == other.p1 {
468 return None;
469 }
470 Some(Event {
471 point: self.p1,
472 pending_segment: Some(other),
473 })
474 }
475}
476
477#[derive(Clone, Copy, Debug, PartialEq)]
479struct ActiveSegment {
480 winding: i32,
481 segment: LineSegment,
482 region_above: Region,
483}
484
485impl ActiveSegment {
486 fn split_left_mut(&mut self, p: Point) -> Option<ActiveSegment> {
488 let p0 = self.segment.p0;
489 if p == p0 {
490 return None;
491 }
492 self.segment.p0 = p;
493 Some(ActiveSegment {
494 winding: self.winding,
495 segment: LineSegment::new(p0, p),
496 region_above: self.region_above,
497 })
498 }
499
500 fn split_right_mut(&mut self, p: Point) -> Option<PendingSegment> {
502 let p1 = self.segment.p1;
503 if p == p1 {
504 return None;
505 }
506 self.segment.p1 = p;
507 Some(PendingSegment {
508 winding: self.winding,
509 p1,
510 })
511 }
512}
513
514#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
515struct Region {
516 is_inside: bool,
517 winding: i32,
518}
519
520#[cfg(test)]
521mod tests {
522 use super::*;
523 use crate::path::{Path, PathIterator};
524
525 #[test]
526 fn test_square() {
527 let mut path = Path::new();
528 path.move_to(Point::new(0.0, 0.0));
529 path.line_to(Point::new(1.0, 0.0));
530 path.line_to(Point::new(1.0, 1.0));
531 path.line_to(Point::new(0.0, 1.0));
532 path.close();
533 let mut trapezoidator = Trapezoidator::new();
534 let trapezoids: Vec<_> = trapezoidator
535 .trapezoidate(path.commands().linearize(0.1))
536 .unwrap()
537 .collect();
538 assert_eq!(trapezoids, [
539 Trapezoid { xs: [0.0, 1.0], ys: [0.0, 0.0, 1.0, 1.0] }
540 ]);
541 }
542}