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);
33 current_point = Some(p);
34 }
35 LinePathCommand::LineTo(p) => {
36 let p0 = current_point.replace(p).unwrap();
37 if self.push_events_for_segment(LineSegment::new(p0, p)){
38 return false
39 }
40 }
41 LinePathCommand::Close => {
42 let p = initial_point.take().unwrap();
43 let p0 = current_point.replace(p).unwrap();
44 if self.push_events_for_segment(LineSegment::new(p0, p)){
45 return false
46 }
47 }
48 }
49 true
50 }){
51 return None
52 };
53 Some(Trapezoidate {
54 trapezoidator: self,
55 })
56 }
57
58 fn push_events_for_segment(&mut self, segment: LineSegment)->bool {
59 let (winding, p0, p1) = match segment.p0.partial_cmp(&segment.p1) {
60 None => return true,
61 Some(Ordering::Less) => (1, segment.p0, segment.p1),
62 Some(Ordering::Equal) => return false,
63 Some(Ordering::Greater) => (-1, segment.p1, segment.p0),
64 };
65 self.event_queue.push(Event {
66 point: p0,
67 pending_segment: Some(PendingSegment { winding, p1 }),
68 });
69 self.event_queue.push(Event {
70 point: p1,
71 pending_segment: None,
72 });
73 false
74 }
75
76 fn pop_events_for_point(
77 &mut self,
78 pending_segments: &mut Vec<PendingSegment>,
79 ) -> Option<Point> {
80 self.event_queue.pop().map(|event| {
81 if let Some(pending_segment) = event.pending_segment {
82 pending_segments.push(pending_segment)
83 }
84 while let Some(&next_event) = self.event_queue.peek() {
85 if next_event != event {
86 break;
87 }
88 self.event_queue.pop();
89 if let Some(pending_segment) = next_event.pending_segment {
90 pending_segments.push(pending_segment);
91 }
92 }
93 event.point
94 })
95 }
96
97 fn handle_events_for_point<F>(
98 &mut self,
99 point: Point,
100 right_segments: &mut Vec<PendingSegment>,
101 trapezoid_segments: &mut Vec<ActiveSegment>,
102 f: &mut F,
103 ) -> bool
104 where
105 F: FnMut(Trapezoid) -> bool,
106 {
107 let mut incident_segment_range = self.find_incident_segment_range(point);
108 if let Some(trapezoid_segment) =
109 self.find_lower_trapezoid_segment(point, incident_segment_range.start)
110 {
111 trapezoid_segments.push(trapezoid_segment);
112 }
113 self.remove_incident_segments(
114 point,
115 &mut incident_segment_range,
116 right_segments,
117 trapezoid_segments,
118 );
119 self.sort_right_segments(point, right_segments);
120 self.insert_right_segments(point, &mut incident_segment_range, right_segments);
121 if let Some(trapezoid_segment) =
122 self.find_upper_trapezoid_segment(point, incident_segment_range.end)
123 {
124 trapezoid_segments.push(trapezoid_segment);
125 }
126 self.generate_trapezoids(trapezoid_segments, f)
127 }
128
129 fn find_incident_segment_range(&self, point: Point) -> Range<usize> {
130 Range {
131 start: self
132 .active_segments
133 .iter()
134 .position(|active_segment| {
135 active_segment.segment.compare_to_point(point).unwrap() != Ordering::Less
136 })
137 .unwrap_or(self.active_segments.len()),
138 end: self
139 .active_segments
140 .iter()
141 .rposition(|active_segment| {
142 active_segment.segment.compare_to_point(point).unwrap() != Ordering::Greater
143 })
144 .map_or(0, |index| index + 1),
145 }
146 }
147
148 fn find_lower_trapezoid_segment(
149 &mut self,
150 point: Point,
151 incident_segment_start: usize,
152 ) -> Option<ActiveSegment> {
153 if 0 == incident_segment_start
154 || !self.active_segments[incident_segment_start - 1]
155 .upper_region
156 .is_inside
157 {
158 return None;
159 }
160 let intersection = self.active_segments[incident_segment_start - 1]
161 .segment
162 .intersect_with_vertical_line(point.x)
163 .unwrap();
164 self.active_segments[incident_segment_start - 1].split_front_mut(intersection)
165 }
166
167 fn remove_incident_segments(
168 &mut self,
169 point: Point,
170 incident_segment_range: &mut Range<usize>,
171 pending_segments: &mut Vec<PendingSegment>,
172 trapezoid_segments: &mut Vec<ActiveSegment>,
173 ) {
174 trapezoid_segments.extend(
175 Iterator::map(
176 self.active_segments.drain(incident_segment_range.clone()),
177 |mut active_segment| {
178 if let Some(pending_segment) = active_segment.split_back_mut(point) {
179 pending_segments.push(pending_segment);
180 }
181 active_segment
182 },
183 )
184 .filter(|active_segment| active_segment.segment.p0.x != active_segment.segment.p1.x),
185 );
186 incident_segment_range.end = incident_segment_range.start;
187 }
188
189 fn sort_right_segments(&mut self, point: Point, right_segments: &mut Vec<PendingSegment>) {
190 right_segments.sort_by(|&right_segment_0, &right_segment_1| {
191 right_segment_0.compare(right_segment_1, point).unwrap()
192 });
193 let mut index_0 = 0;
194 for index_1 in 1..right_segments.len() {
195 let right_segment_1 = right_segments[index_1];
196 let right_segment_0 = &mut right_segments[index_0];
197 if right_segment_0.overlaps(right_segment_1, point) {
198 if let Some(event) = right_segment_0.splice_mut(right_segment_1) {
199 self.event_queue.push(event);
200 }
201 } else {
202 index_0 += 1;
203 right_segments[index_0] = right_segment_1;
204 }
205 }
206 right_segments.truncate(index_0 + 1);
207 }
208
209 fn insert_right_segments(
210 &mut self,
211 point: Point,
212 incident_segment_range: &mut Range<usize>,
213 right_segments: &[PendingSegment],
214 ) {
215 let mut lower_region = if incident_segment_range.end == 0 {
216 Region {
217 is_inside: false,
218 winding: 0,
219 }
220 } else {
221 self.active_segments[incident_segment_range.end - 1].upper_region
222 };
223 self.active_segments.splice(
224 incident_segment_range.end..incident_segment_range.end,
225 Iterator::map(right_segments.iter(), |right_segment| {
226 let upper_region = {
227 let winding = lower_region.winding + right_segment.winding;
228 Region {
229 is_inside: winding != 0,
230 winding,
231 }
232 };
233 let right_segment = ActiveSegment {
234 winding: right_segment.winding,
235 segment: LineSegment::new(point, right_segment.p1),
236 upper_region,
237 };
238 lower_region = upper_region;
239 right_segment
240 }),
241 );
242 incident_segment_range.end += right_segments.len();
243 }
244
245 fn find_upper_trapezoid_segment(
246 &mut self,
247 point: Point,
248 incident_segment_end: usize,
249 ) -> Option<ActiveSegment> {
250 if 0 == incident_segment_end
251 || !self.active_segments[incident_segment_end - 1]
252 .upper_region
253 .is_inside
254 {
255 return None;
256 }
257 let intersection = self.active_segments[incident_segment_end]
258 .segment
259 .intersect_with_vertical_line(point.x)
260 .unwrap();
261 if let Some(pending_segment) =
262 self.active_segments[incident_segment_end].split_back_mut(intersection)
263 {
264 self.event_queue.push(Event {
265 point: intersection,
266 pending_segment: Some(pending_segment),
267 });
268 }
269 Some(self.active_segments[incident_segment_end])
270 }
271
272 fn generate_trapezoids<F>(&self, trapezoid_segments: &[ActiveSegment], f: &mut F) -> bool
273 where
274 F: FnMut(Trapezoid) -> bool,
275 {
276 for trapezoid_segment_pair in trapezoid_segments.windows(2) {
277 if !trapezoid_segment_pair[0].upper_region.is_inside {
278 continue;
279 }
280 let lower_segment = trapezoid_segment_pair[0].segment;
281 let upper_segment = trapezoid_segment_pair[1].segment;
282 if !f(Trapezoid {
283 xs: [lower_segment.p0.x as f32, lower_segment.p1.x as f32],
284 ys: [
285 lower_segment.p0.y as f32,
286 lower_segment.p1.y as f32,
287 upper_segment.p0.y as f32,
288 upper_segment.p1.y as f32,
289 ],
290 }) {
291 return false;
292 }
293 }
294 true
295 }
296}
297
298#[derive(Debug)]
300pub struct Trapezoidate<'a> {
301 trapezoidator: &'a mut Trapezoidator,
302}
303
304impl<'a> InternalIterator for Trapezoidate<'a> {
305 type Item = Trapezoid;
306
307 fn for_each<F>(self, f: &mut F) -> bool
308 where
309 F: FnMut(Trapezoid) -> bool,
310 {
311 let mut right_segments = Vec::new();
312 let mut trapezoid_segments = Vec::new();
313 while let Some(point) = self.trapezoidator.pop_events_for_point(&mut right_segments) {
314 let ok = self.trapezoidator.handle_events_for_point(
315 point,
316 &mut right_segments,
317 &mut trapezoid_segments,
318 f,
319 );
320 right_segments.clear();
321 trapezoid_segments.clear();
322 if !ok {
323 return false;
324 }
325 }
326 true
327 }
328}
329
330#[derive(Clone, Copy, Debug)]
331struct Event {
332 point: Point,
333 pending_segment: Option<PendingSegment>,
334}
335
336impl Eq for Event {}
337
338impl Ord for Event {
339 fn cmp(&self, other: &Event) -> Ordering {
340 self.point.partial_cmp(&other.point).unwrap().reverse()
341 }
342}
343
344impl PartialEq for Event {
345 fn eq(&self, other: &Event) -> bool {
346 self.cmp(other) == Ordering::Equal
347 }
348}
349
350impl PartialOrd for Event {
351 fn partial_cmp(&self, other: &Event) -> Option<Ordering> {
352 Some(self.cmp(other))
353 }
354}
355
356#[derive(Clone, Copy, Debug, PartialEq)]
357struct PendingSegment {
358 winding: i32,
359 p1: Point,
360}
361
362impl PendingSegment {
363 fn to_segment(self, p0: Point) -> LineSegment {
364 LineSegment::new(p0, self.p1)
365 }
366
367 fn overlaps(self, other: PendingSegment, p0: Point) -> bool {
368 self.compare(other, p0) == Some(Ordering::Equal)
369 }
370
371 fn compare(self, other: PendingSegment, p0: Point) -> Option<Ordering> {
372 if self.p1 <= other.p1 {
373 other
374 .to_segment(p0)
375 .compare_to_point(self.p1)
376 .map(|ordering| ordering.reverse())
377 } else {
378 self.to_segment(p0).compare_to_point(other.p1)
379 }
380 }
381
382 fn splice_mut(&mut self, mut other: Self) -> Option<Event> {
383 if other.p1 < self.p1 {
384 mem::swap(self, &mut other);
385 }
386 self.winding += other.winding;
387 if self.p1 == other.p1 {
388 return None;
389 }
390 Some(Event {
391 point: self.p1,
392 pending_segment: Some(other),
393 })
394 }
395}
396
397#[derive(Clone, Copy, Debug, PartialEq)]
398struct ActiveSegment {
399 winding: i32,
400 segment: LineSegment,
401 upper_region: Region,
402}
403
404impl ActiveSegment {
405 fn split_front_mut(&mut self, p: Point) -> Option<ActiveSegment> {
406 let p0 = self.segment.p0;
407 if p == p0 {
408 return None;
409 }
410 self.segment.p0 = p;
411 Some(ActiveSegment {
412 winding: self.winding,
413 segment: LineSegment::new(p0, p),
414 upper_region: self.upper_region,
415 })
416 }
417
418 fn split_back_mut(&mut self, p: Point) -> Option<PendingSegment> {
419 let p1 = self.segment.p1;
420 if p == p1 {
421 return None;
422 }
423 self.segment.p1 = p;
424 Some(PendingSegment {
425 winding: self.winding,
426 p1,
427 })
428 }
429}
430
431#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
432struct Region {
433 is_inside: bool,
434 winding: i32,
435}
436