1#![allow(clippy::excessive_precision)]
4
5use super::command::Command;
6use super::geometry::*;
7#[allow(unused)]
8use super::F32Ext;
9
10use core::borrow::Borrow;
11use core::f32;
12
13#[derive(Copy, Clone, Debug)]
16pub struct SegmentTime {
17 pub distance: f32,
18 pub time: f32,
19}
20
21#[derive(Copy, Clone, PartialEq, Debug)]
23pub struct Line {
24 pub a: Point,
25 pub b: Point,
26}
27
28impl Line {
29 pub fn new(a: impl Into<Vector>, b: impl Into<Vector>) -> Self {
31 Self {
32 a: a.into(),
33 b: b.into(),
34 }
35 }
36
37 pub fn length(&self) -> f32 {
39 (self.b - self.a).length()
40 }
41
42 #[allow(unused)]
44 pub fn slice(&self, start: f32, end: f32) -> Self {
45 let dir = self.b - self.a;
46 Self::new(self.a + dir * start, self.a + dir * end)
47 }
48
49 #[allow(unused)]
50 pub fn time(&self, distance: f32) -> SegmentTime {
51 let len = (self.b - self.a).length();
52 if distance > len {
53 return SegmentTime {
54 distance: len,
55 time: 1.,
56 };
57 }
58 SegmentTime {
59 distance,
60 time: distance / len,
61 }
62 }
63
64 #[allow(unused)]
65 pub fn reverse(&self) -> Self {
66 Self::new(self.b, self.a)
67 }
68}
69
70#[derive(Copy, Clone, PartialEq, Default, Debug)]
72pub struct Curve {
73 pub a: Point,
74 pub b: Point,
75 pub c: Point,
76 pub d: Point,
77}
78
79impl Curve {
80 pub fn new(
82 a: impl Into<Point>,
83 b: impl Into<Point>,
84 c: impl Into<Point>,
85 d: impl Into<Point>,
86 ) -> Self {
87 Curve {
88 a: a.into(),
89 b: b.into(),
90 c: c.into(),
91 d: d.into(),
92 }
93 }
94
95 pub fn from_quadratic(a: impl Into<Point>, b: impl Into<Point>, c: impl Into<Point>) -> Self {
97 let a = a.into();
98 let b = b.into();
99 let c = c.into();
100 Self {
101 a,
102 b: Point::new(a.x + 2. / 3. * (b.x - a.x), a.y + 2. / 3. * (b.y - a.y)),
103 c: Point::new(c.x + 2. / 3. * (b.x - c.x), c.y + 2. / 3. * (b.y - c.y)),
104 d: c,
105 }
106 }
107
108 pub fn length(&self) -> f32 {
110 let mut len = 0.;
111 let mut prev = self.a;
112 let steps = 64;
113 let step = 1. / steps as f32;
114 let mut t = 0.;
115 for _ in 0..=steps {
116 t += step;
117 let next = self.evaluate(t);
118 len += (next - prev).length();
119 prev = next;
120 }
121 len
122 }
123
124 pub fn slice(&self, start: f32, end: f32) -> Self {
126 let t0 = start;
127 let t1 = end;
128 let u0 = 1. - t0;
129 let u1 = 1. - t1;
130 let v0 = self.a;
131 let v1 = self.b;
132 let v2 = self.c;
133 let v3 = self.d;
134 Self::new(
135 (v0 * (u0 * u0 * u0))
136 + (v1 * (t0 * u0 * u0 + u0 * t0 * u0 + u0 * u0 * t0))
137 + (v2 * (t0 * t0 * u0 + u0 * t0 * t0 + t0 * u0 * t0))
138 + (v3 * (t0 * t0 * t0)),
139 (v0 * (u0 * u0 * u1))
140 + (v1 * (t0 * u0 * u1 + u0 * t0 * u1 + u0 * u0 * t1))
141 + (v2 * (t0 * t0 * u1 + u0 * t0 * t1 + t0 * u0 * t1))
142 + (v3 * (t0 * t0 * t1)),
143 (v0 * (u0 * u1 * u1))
144 + (v1 * (t0 * u1 * u1 + u0 * t1 * u1 + u0 * u1 * t1))
145 + (v2 * (t0 * t1 * u1 + u0 * t1 * t1 + t0 * u1 * t1))
146 + (v3 * (t0 * t1 * t1)),
147 (v0 * (u1 * u1 * u1))
148 + (v1 * (t1 * u1 * u1 + u1 * t1 * u1 + u1 * u1 * t1))
149 + (v2 * (t1 * t1 * u1 + u1 * t1 * t1 + t1 * u1 * t1))
150 + (v3 * (t1 * t1 * t1)),
151 )
152 }
153
154 #[allow(unused)]
156 pub fn reverse(&self) -> Self {
157 Self::new(self.d, self.c, self.b, self.a)
158 }
159
160 #[allow(unused)]
163 pub fn time(&self, distance: f32, tolerance: f32) -> SegmentTime {
164 let (distance, time) = self.time_impl(distance, tolerance, 1., 0);
165 SegmentTime { distance, time }
166 }
167
168 pub fn is_line(&self, tolerance: f32) -> bool {
171 let degen_ab = self.a.nearly_eq_by(self.b, tolerance);
172 let degen_bc = self.b.nearly_eq_by(self.c, tolerance);
173 let degen_cd = self.c.nearly_eq_by(self.d, tolerance);
174 degen_ab as u8 + degen_bc as u8 + degen_cd as u8 >= 2
175 }
176
177 pub fn evaluate(&self, time: f32) -> Point {
179 let t = time;
180 let t0 = 1. - t;
181 (self.a * (t0 * t0 * t0))
182 + (self.b * (3. * t0 * t0 * t))
183 + (self.c * (3. * t0 * t * t))
184 + (self.d * (t * t * t))
185 }
186
187 #[allow(clippy::wrong_self_convention)]
188 fn to_segment(&self, id: SegmentId) -> Option<Segment> {
189 if self.is_line(MERGE_EPSILON) {
190 if self.a.nearly_eq_by(self.d, MERGE_EPSILON) {
191 None
192 } else {
193 Some(Segment::Line(id, Line::new(self.a, self.d)))
194 }
195 } else {
196 Some(Segment::Curve(id, *self))
197 }
198 }
199
200 fn split_at_max_curvature(&self, splits: &mut [Curve; 4]) -> usize {
201 let mut tmp = [0f32; 3];
202 let count1 = self.max_curvature(&mut tmp);
203 let mut count = 0;
204 let mut ts = [0f32; 4];
205 for &t in &tmp[..count1] {
206 if t > 0. && t < 1. {
207 ts[count] = t;
208 count += 1;
209 }
210 }
211 if count == 0 {
212 splits[0] = *self;
213 } else {
214 let mut i = 0;
215 let mut last_t = 0.;
216 for &t in &ts[..count] {
217 splits[i] = self.slice(last_t, t);
218 i += 1;
219 last_t = t;
220 }
221 splits[i] = self.slice(last_t, 1.);
222 }
223 count + 1
224 }
225
226 fn split(&self, t: f32) -> (Self, Self) {
227 (self.slice(0., t), self.slice(t, 1.))
228 }
229
230 fn time_impl(&self, distance: f32, tolerance: f32, t: f32, level: u8) -> (f32, f32) {
231 if level < 5 && self.too_curvy(tolerance) {
232 let c0 = self.slice(0., 0.5);
233 let (dist0, t0) = c0.time_impl(distance, tolerance, t * 0.5, level + 1);
234 if dist0 < distance {
235 let c1 = self.slice(0.5, 1.);
236 let (dist1, t1) = c1.time_impl(distance - dist0, tolerance, t * 0.5, level + 1);
237 (dist0 + dist1, t0 + t1)
238 } else {
239 (dist0, t0)
240 }
241 } else {
242 let dist = (self.d - self.a).length();
243 if dist >= distance {
244 let s = distance / dist;
245 (distance, t * s)
246 } else {
247 (dist, t)
248 }
249 }
250 }
251
252 fn max_curvature(&self, ts: &mut [f32; 3]) -> usize {
253 let comps_x = [self.a.x, self.b.x, self.c.x, self.d.x];
254 let comps_y = [self.a.y, self.b.y, self.c.y, self.d.y];
255 fn get_coeffs(src: [f32; 4]) -> [f32; 4] {
256 let a = src[1] - src[0];
257 let b = src[2] - 2. * src[1] + src[0];
258 let c = src[3] + 3. * (src[1] - src[2]) - src[0];
259 [c * c, 3. * b * c, 2. * b * b + c * a, a * b]
260 }
261 let mut coeffs = get_coeffs(comps_x);
262 let coeffs_y = get_coeffs(comps_y);
263 for i in 0..4 {
264 coeffs[i] += coeffs_y[i];
265 }
266 Self::solve(coeffs, ts)
267 }
268
269 fn solve(coeff: [f32; 4], ts: &mut [f32; 3]) -> usize {
270 const PI: f32 = core::f32::consts::PI;
271 let i = 1. / coeff[0];
272 let a = coeff[1] * i;
273 let b = coeff[2] * i;
274 let c = coeff[3] * i;
275 let q = (a * a - b * 3.) / 9.;
276 let r = (2. * a * a * a - 9. * a * b + 27. * c) / 54.;
277 let q3 = q * q * q;
278 let r2_sub_q3 = r * r - q3;
279 let adiv3 = a / 3.;
280 if r2_sub_q3 < 0. {
281 let theta = satf32(r / q3.sqrt()).acos();
282 let neg2_root_q = -2. * q.sqrt();
283 ts[0] = satf32(neg2_root_q * (theta / 3.).cos() - adiv3);
284 ts[1] = satf32(neg2_root_q * ((theta + 2. * PI) / 3.).cos() - adiv3);
285 ts[2] = satf32(neg2_root_q * ((theta - 2. * PI) / 3.).cos() - adiv3);
286 ts.sort_unstable_by(|x, y| x.partial_cmp(y).unwrap_or(core::cmp::Ordering::Less));
287 let mut count = 3;
288 if ts[0] == ts[1] {
289 ts[1] = ts[2];
290 count -= 1;
291 }
292 if ts[1] == ts[2] {
293 count -= 1;
294 }
295 count
296 } else {
297 let mut a = r.abs() + r2_sub_q3.sqrt();
298 a = a.powf(0.3333333);
299 if r > 0. {
300 a = -a;
301 }
302 if a != 0. {
303 a += q / a;
304 }
305 ts[0] = satf32(a - adiv3);
306 1
307 }
308 }
309
310 fn too_curvy(&self, tolerance: f32) -> bool {
311 (2. * self.d.x - 3. * self.c.x + self.a.x).abs() > tolerance
312 || (2. * self.d.y - 3. * self.c.y + self.a.y).abs() > tolerance
313 || (self.d.x - 3. * self.b.x + 2. * self.a.x).abs() > tolerance
314 || (self.d.y - 3. * self.b.y + 2. * self.a.y).abs() > tolerance
315 }
316
317 fn needs_split(&self) -> bool {
318 if self.b.nearly_eq_by(self.c, MERGE_EPSILON) {
319 return true;
320 }
321 let normal_ab = normal(self.a, self.b);
322 let normal_bc = normal(self.b, self.c);
323 fn too_curvy(n0: Vector, n1: Vector) -> bool {
324 const FLAT_ENOUGH: f32 = f32::consts::SQRT_2 / 2. + 1. / 10.;
325 n0.dot(n1) <= FLAT_ENOUGH
326 }
327 too_curvy(normal_ab, normal_bc) || too_curvy(normal_bc, normal(self.c, self.d))
328 }
329}
330
331fn satf32(x: f32) -> f32 {
332 x.clamp(0., 1.)
333}
334
335pub type SegmentId = u8;
337
338#[derive(Copy, Clone, PartialEq, Debug)]
340pub enum Segment {
341 Line(SegmentId, Line),
343 Curve(SegmentId, Curve),
345 End(bool),
348}
349
350impl Segment {
351 pub fn length(&self) -> f32 {
352 match self {
353 Self::Line(_, line) => line.length(),
354 Self::Curve(_, curve) => curve.length(),
355 _ => 0.,
356 }
357 }
358
359 #[allow(unused)]
360 pub fn slice(&self, start: f32, end: f32) -> Self {
361 match self {
362 Self::Line(id, line) => Self::Line(*id, line.slice(start, end)),
363 Self::Curve(id, curve) => Self::Curve(*id, curve.slice(start, end)),
364 Self::End(..) => *self,
365 }
366 }
367
368 #[allow(unused)]
369 pub fn reverse(&self) -> Self {
370 match self {
371 Self::Line(id, line) => Self::Line(*id, line.reverse()),
372 Self::Curve(id, curve) => Self::Curve(*id, curve.reverse()),
373 Self::End(..) => *self,
374 }
375 }
376
377 #[allow(unused)]
378 pub fn time(&self, distance: f32, tolerance: f32) -> SegmentTime {
379 match self {
380 Self::Line(_, line) => line.time(distance),
381 Self::Curve(_, curve) => curve.time(distance, tolerance),
382 _ => SegmentTime {
383 distance: 0.,
384 time: 0.,
385 },
386 }
387 }
388
389 #[allow(unused)]
390 pub fn point_normal(&self, time: f32) -> (Point, Vector) {
391 match self {
392 Self::Line(_, line) => {
393 let dir = line.b - line.a;
394 let p = line.a + dir * time;
395 let n = normal(line.a, line.b);
396 (p, n)
397 }
398 Self::Curve(_, curve) => {
399 let p = curve.evaluate(time);
400 let a = curve.evaluate(time - 0.05);
401 let b = curve.evaluate(time + 0.05);
402 let n = normal(a, b);
403 (p, n)
404 }
405 Self::End(..) => (Point::ZERO, Vector::ZERO),
406 }
407 }
408}
409
410impl Default for Segment {
411 fn default() -> Self {
412 Self::End(false)
413 }
414}
415
416const MERGE_EPSILON: f32 = 0.01;
419
420pub fn segments<I>(commands: I, simplify_curves: bool) -> Segments<I>
423where
424 I: Iterator + Clone,
425 I::Item: Borrow<Command>,
426{
427 Segments::new(simplify_curves, commands)
428}
429
430#[derive(Clone)]
432pub struct Segments<I> {
433 commands: I,
434 start: Vector,
435 prev: Vector,
436 close: bool,
437 split: bool,
438 splits: [Curve; 16],
439 split_count: usize,
440 split_index: usize,
441 last_was_end: bool,
442 id: u8,
443 count: u32,
444}
445
446impl<I> Segments<I>
447where
448 I: Iterator + Clone,
449 I::Item: Borrow<Command>,
450{
451 fn new(split: bool, commands: I) -> Self {
452 Self {
453 commands,
454 start: Vector::ZERO,
455 prev: Vector::ZERO,
456 close: false,
457 split,
458 splits: [Curve::default(); 16],
459 split_count: 0,
460 split_index: 0,
461 last_was_end: true,
462 id: 0,
463 count: 0,
464 }
465 }
466
467 #[allow(clippy::needless_range_loop)]
468 fn split_curve(&mut self, id: SegmentId, c: &Curve) -> Option<Segment> {
469 if c.is_line(MERGE_EPSILON) {
470 if c.a.nearly_eq_by(c.d, MERGE_EPSILON) {
471 return None;
472 }
473 return Some(Segment::Line(id, Line::new(c.a, c.d)));
474 }
475 let mut splits = [Curve::default(); 4];
476 let count = c.split_at_max_curvature(&mut splits);
477 let mut i = 0;
478 for j in 0..count {
479 let curve = splits[j];
480 if curve.needs_split() {
481 let (a, b) = curve.split(0.5);
482 if a.needs_split() {
483 let (c, d) = a.split(0.5);
484 self.splits[i] = c;
485 self.splits[i + 1] = d;
486 i += 2;
487 } else {
488 self.splits[i] = a;
489 i += 1;
490 }
491 if b.needs_split() {
492 let (c, d) = b.split(0.5);
493 self.splits[i] = c;
494 self.splits[i + 1] = d;
495 i += 2;
496 } else {
497 self.splits[i] = b;
498 i += 1;
499 }
500 } else {
501 self.splits[i] = curve;
502 i += 1;
503 }
504 }
505 self.split_count = i;
506 self.split_index = 1;
507 self.splits[0].to_segment(id)
508 }
509
510 fn inc_id(&mut self) {
511 if self.id == 254 {
512 self.id = 0;
513 } else {
514 self.id += 1;
515 }
516 }
517}
518
519impl<I> Iterator for Segments<I>
520where
521 I: Iterator + Clone,
522 I::Item: Borrow<Command>,
523{
524 type Item = Segment;
525
526 fn next(&mut self) -> Option<Self::Item> {
527 use Command::*;
528 if self.close {
529 self.close = false;
530 self.last_was_end = true;
531 return Some(Segment::End(true));
532 }
533 if self.split {
534 loop {
535 if self.split_index < self.split_count {
536 let curve = self.splits[self.split_index];
537 self.split_index += 1;
538 if let Some(segment) = curve.to_segment(self.id) {
539 self.count += 1;
540 self.last_was_end = false;
541 self.prev = curve.d;
542 return Some(segment);
543 }
544 continue;
545 }
546 self.inc_id();
547 let id = self.id;
548 let from = self.prev;
549 match *self.commands.next()?.borrow() {
550 MoveTo(to) => {
551 self.start = to;
552 self.prev = to;
553 self.count = 0;
554 if !self.last_was_end {
555 self.last_was_end = true;
556 return Some(Segment::End(false));
557 }
558 }
559 LineTo(to) => {
560 if !from.nearly_eq_by(to, MERGE_EPSILON) {
561 self.count += 1;
562 self.prev = to;
563 self.last_was_end = false;
564 return Some(Segment::Line(id, Line::new(from, to)));
565 }
566 }
567 CurveTo(c1, c2, to) => {
568 if let Some(segment) = self.split_curve(id, &Curve::new(from, c1, c2, to)) {
569 self.count += 1;
570 self.prev = to;
571 self.last_was_end = false;
572 return Some(segment);
573 }
574 }
575 QuadTo(c, to) => {
576 if let Some(segment) =
577 self.split_curve(id, &Curve::from_quadratic(from, c, to))
578 {
579 self.count += 1;
580 self.prev = to;
581 self.last_was_end = false;
582 return Some(segment);
583 }
584 }
585 Close => {
586 self.prev = self.start;
587 if self.count == 0 || !from.nearly_eq_by(self.start, MERGE_EPSILON) {
588 self.close = true;
589 return Some(Segment::Line(id, Line::new(from, self.start)));
590 } else {
591 self.count = 0;
592 self.last_was_end = true;
593 return Some(Segment::End(true));
594 }
595 }
596 }
597 }
598 } else {
599 let id = self.id;
600 self.inc_id();
601 loop {
602 let from = self.prev;
603 match *self.commands.next()?.borrow() {
604 MoveTo(to) => {
605 self.start = to;
606 self.prev = to;
607 self.count = 0;
608 if !self.last_was_end {
609 self.last_was_end = true;
610 return Some(Segment::End(false));
611 }
612 }
613 LineTo(to) => {
614 if !from.nearly_eq_by(to, MERGE_EPSILON) {
615 self.count += 1;
616 self.prev = to;
617 self.last_was_end = false;
618 return Some(Segment::Line(id, Line::new(from, to)));
619 }
620 }
621 CurveTo(c1, c2, to) => {
622 let segment = Segment::Curve(id, Curve::new(from, c1, c2, to));
623 self.count += 1;
624 self.prev = to;
625 self.last_was_end = false;
626 return Some(segment);
627 }
628 QuadTo(c, to) => {
629 let segment = Segment::Curve(id, Curve::from_quadratic(from, c, to));
630 self.count += 1;
631 self.prev = to;
632 self.last_was_end = false;
633 return Some(segment);
634 }
635 Close => {
636 self.prev = self.start;
637 if self.count == 0 || !from.nearly_eq_by(self.start, 0.01) {
638 self.close = true;
639 return Some(Segment::Line(id, Line::new(from, self.start)));
640 } else {
641 self.count = 0;
642 self.last_was_end = true;
643 return Some(Segment::End(true));
644 }
645 }
646 }
647 }
648 }
649 }
650}