1use super::*;
2
3impl Transform2D {
5 pub fn identity() -> Self {
7 Self {
8 a: 1.0,
9 b: 0.0,
10 c: 0.0,
11 d: 1.0,
12 e: 0.0,
13 f: 0.0,
14 }
15 }
16
17 pub fn translate(tx: f64, ty: f64) -> Self {
23 Self {
24 a: 1.0,
25 b: 0.0,
26 c: 0.0,
27 d: 1.0,
28 e: tx,
29 f: ty,
30 }
31 }
32
33 pub fn scale(sx: f64, sy: f64) -> Self {
39 Self {
40 a: sx,
41 b: 0.0,
42 c: 0.0,
43 d: sy,
44 e: 0.0,
45 f: 0.0,
46 }
47 }
48
49 pub fn rotate(angle: f64) -> Self {
55 let (sin, cos) = angle.sin_cos();
56 Self {
57 a: cos,
58 b: sin,
59 c: -sin,
60 d: cos,
61 e: 0.0,
62 f: 0.0,
63 }
64 }
65
66 pub fn from_rect_to_rect(from: BBox, to: BBox) -> Self {
73 let from_width: f64 = from.max_x - from.min_x;
74 let from_height: f64 = from.max_y - from.min_y;
75 if from_width <= 0.0 || from_height <= 0.0 {
76 return Self::identity();
77 }
78 let scale_x: f64 = (to.max_x - to.min_x) / from_width;
79 let scale_y: f64 = (to.max_y - to.min_y) / from_height;
80 Self {
81 a: scale_x,
82 b: 0.0,
83 c: 0.0,
84 d: scale_y,
85 e: to.min_x - from.min_x * scale_x,
86 f: to.min_y - from.min_y * scale_y,
87 }
88 }
89
90 pub fn then(&self, other: &Self) -> Self {
97 Self {
98 a: self.get_a() * other.get_a() + self.get_c() * other.get_b(),
99 b: self.get_b() * other.get_a() + self.get_d() * other.get_b(),
100 c: self.get_a() * other.get_c() + self.get_c() * other.get_d(),
101 d: self.get_b() * other.get_c() + self.get_d() * other.get_d(),
102 e: self.get_a() * other.get_e() + self.get_c() * other.get_f() + self.get_e(),
103 f: self.get_b() * other.get_e() + self.get_d() * other.get_f() + self.get_f(),
104 }
105 }
106
107 pub fn apply(&self, x: f64, y: f64) -> (f64, f64) {
117 (
118 self.get_a() * x + self.get_c() * y + self.get_e(),
119 self.get_b() * x + self.get_d() * y + self.get_f(),
120 )
121 }
122
123 pub fn apply_f32(&self, x: f32, y: f32) -> (f32, f32) {
133 let (x, y) = self.apply(x as f64, y as f64);
134 (x as f32, y as f32)
135 }
136
137 pub fn determinant(&self) -> f64 {
146 self.get_a() * self.get_d() - self.get_b() * self.get_c()
147 }
148
149 pub fn invert(&self) -> Option<Self> {
156 let determinant: f64 = self.determinant();
157 if determinant.abs() < f64::EPSILON {
158 return None;
159 }
160 let inverse: f64 = 1.0 / determinant;
161 Some(Self {
162 a: self.get_d() * inverse,
163 b: -self.get_b() * inverse,
164 c: -self.get_c() * inverse,
165 d: self.get_a() * inverse,
166 e: (self.get_c() * self.get_f() - self.get_d() * self.get_e()) * inverse,
167 f: (self.get_b() * self.get_e() - self.get_a() * self.get_f()) * inverse,
168 })
169 }
170}
171
172impl Default for BBox {
174 fn default() -> Self {
176 Self::empty()
177 }
178}
179
180impl BBox {
182 pub fn empty() -> Self {
188 Self {
189 min_x: f64::INFINITY,
190 min_y: f64::INFINITY,
191 max_x: f64::NEG_INFINITY,
192 max_y: f64::NEG_INFINITY,
193 }
194 }
195
196 pub fn from_min_size(min_x: f64, min_y: f64, width: f64, height: f64) -> Self {
202 Self {
203 min_x,
204 min_y,
205 max_x: min_x + width,
206 max_y: min_y + height,
207 }
208 }
209
210 pub fn from_corners(x0: f64, y0: f64, x1: f64, y1: f64) -> Self {
216 Self {
217 min_x: x0.min(x1),
218 min_y: y0.min(y1),
219 max_x: x0.max(x1),
220 max_y: y0.max(y1),
221 }
222 }
223
224 pub fn is_empty(&self) -> bool {
230 self.get_min_x() > self.get_max_x() || self.get_min_y() > self.get_max_y()
231 }
232
233 pub fn width(&self) -> f64 {
239 if self.is_empty() {
240 0.0
241 } else {
242 self.get_max_x() - self.get_min_x()
243 }
244 }
245
246 pub fn height(&self) -> f64 {
252 if self.is_empty() {
253 0.0
254 } else {
255 self.get_max_y() - self.get_min_y()
256 }
257 }
258
259 pub fn center_x(&self) -> f64 {
265 (self.get_min_x() + self.get_max_x()) * 0.5
266 }
267
268 pub fn center_y(&self) -> f64 {
274 (self.get_min_y() + self.get_max_y()) * 0.5
275 }
276
277 pub fn extend_point(&mut self, x: f64, y: f64) {
283 self.set_min_x(self.get_min_x().min(x));
284 self.set_min_y(self.get_min_y().min(y));
285 self.set_max_x(self.get_max_x().max(x));
286 self.set_max_y(self.get_max_y().max(y));
287 }
288
289 pub fn extend_box(&mut self, other: &BBox) {
295 if other.is_empty() {
296 return;
297 }
298 self.set_min_x(self.get_min_x().min(other.min_x));
299 self.set_min_y(self.get_min_y().min(other.min_y));
300 self.set_max_x(self.get_max_x().max(other.max_x));
301 self.set_max_y(self.get_max_y().max(other.max_y));
302 }
303
304 pub fn contains(&self, x: f64, y: f64) -> bool {
314 !self.is_empty()
315 && x >= self.get_min_x()
316 && x <= self.get_max_x()
317 && y >= self.get_min_y()
318 && y <= self.get_max_y()
319 }
320
321 pub fn intersects(&self, other: &BBox) -> bool {
331 !self.is_empty()
332 && !other.is_empty()
333 && self.get_min_x() <= other.max_x
334 && self.get_max_x() >= other.min_x
335 && self.get_min_y() <= other.max_y
336 && self.get_max_y() >= other.min_y
337 }
338
339 pub fn intersection(&self, other: &BBox) -> Option<BBox> {
350 if !self.intersects(other) {
351 return None;
352 }
353 Some(BBox {
354 min_x: self.get_min_x().max(other.min_x),
355 min_y: self.get_min_y().max(other.min_y),
356 max_x: self.get_max_x().min(other.max_x),
357 max_y: self.get_max_y().min(other.max_y),
358 })
359 }
360
361 pub fn union(&self, other: &BBox) -> BBox {
371 let mut result: BBox = *self;
372 result.extend_box(other);
373 result
374 }
375}
376
377impl Point {
379 pub fn new(x: f32, y: f32) -> Self {
385 Self { x, y }
386 }
387
388 pub fn distance_to(&self, other: &Point) -> f32 {
398 let dx: f32 = self.get_x() - other.x;
399 let dy: f32 = self.get_y() - other.y;
400 (dx * dx + dy * dy).sqrt()
401 }
402
403 pub fn distance_squared_to(&self, other: &Point) -> f32 {
413 let dx: f32 = self.get_x() - other.x;
414 let dy: f32 = self.get_y() - other.y;
415 dx * dx + dy * dy
416 }
417}
418
419impl Polygon {
421 pub fn from_coordinates(coordinates: &[f32]) -> Self {
427 let mut points: Vec<Point> = Vec::with_capacity(coordinates.len() / 2);
428 for pair in coordinates.as_chunks::<2>().0 {
429 points.push(Point::new(pair[0], pair[1]));
430 }
431 Self { points }
432 }
433
434 pub fn signed_area(&self) -> f64 {
443 let count: usize = self.get_points().len();
444 if count < 3 {
445 return 0.0;
446 }
447 let mut sum: f64 = 0.0;
448 for index in 0..count {
449 let current: Point = self.get_points()[index];
450 let next: Point = self.get_points()[(index + 1) % count];
451 sum += current.x as f64 * next.y as f64 - next.x as f64 * current.y as f64;
452 }
453 sum * 0.5
454 }
455
456 pub fn is_clockwise(&self) -> bool {
462 self.signed_area() > 0.0
463 }
464
465 pub fn reverse(&mut self) {
467 self.get_mut_points().reverse();
468 }
469}
470
471impl Path {
473 pub fn new() -> Self {
475 Self {
476 commands: Vec::new(),
477 fill_rule: FillRule::default(),
478 }
479 }
480
481 pub fn builder() -> PathBuilder {
487 PathBuilder::new()
488 }
489
490 pub fn commands(&self) -> &[PathCommand] {
496 self.get_commands()
497 }
498
499 pub fn fill_rule(&self) -> FillRule {
505 self.get_fill_rule()
506 }
507
508 pub fn is_empty(&self) -> bool {
514 self.get_commands().is_empty()
515 }
516
517 pub fn len(&self) -> usize {
523 self.get_commands().len()
524 }
525
526 pub fn bounds(&self) -> BBox {
538 let mut bounds: BBox = BBox::empty();
539 for command in self.get_commands() {
540 match *command {
541 PathCommand::MoveTo(x, y) | PathCommand::LineTo(x, y) => {
542 bounds.extend_point(x as f64, y as f64);
543 }
544 PathCommand::QuadTo(cx, cy, x, y) => {
545 bounds.extend_point(cx as f64, cy as f64);
546 bounds.extend_point(x as f64, y as f64);
547 }
548 PathCommand::CubicTo(c1x, c1y, c2x, c2y, x, y) => {
549 bounds.extend_point(c1x as f64, c1y as f64);
550 bounds.extend_point(c2x as f64, c2y as f64);
551 bounds.extend_point(x as f64, y as f64);
552 }
553 PathCommand::Close => {}
554 }
555 }
556 bounds
557 }
558
559 pub fn transformed(&self, transform: &Transform2D) -> Path {
573 let mut commands: Vec<PathCommand> = Vec::with_capacity(self.get_commands().len());
574 for command in self.get_commands() {
575 commands.push(match *command {
576 PathCommand::MoveTo(x, y) => {
577 let (x, y) = transform.apply_f32(x, y);
578 PathCommand::MoveTo(x, y)
579 }
580 PathCommand::LineTo(x, y) => {
581 let (x, y) = transform.apply_f32(x, y);
582 PathCommand::LineTo(x, y)
583 }
584 PathCommand::QuadTo(cx, cy, x, y) => {
585 let (cx, cy) = transform.apply_f32(cx, cy);
586 let (x, y) = transform.apply_f32(x, y);
587 PathCommand::QuadTo(cx, cy, x, y)
588 }
589 PathCommand::CubicTo(c1x, c1y, c2x, c2y, x, y) => {
590 let (c1x, c1y) = transform.apply_f32(c1x, c1y);
591 let (c2x, c2y) = transform.apply_f32(c2x, c2y);
592 let (x, y) = transform.apply_f32(x, y);
593 PathCommand::CubicTo(c1x, c1y, c2x, c2y, x, y)
594 }
595 PathCommand::Close => PathCommand::Close,
596 });
597 }
598 Path {
599 commands,
600 fill_rule: self.get_fill_rule(),
601 }
602 }
603}
604
605impl PathBuilder {
607 pub fn new() -> Self {
609 Self {
610 commands: Vec::with_capacity(PATH_COMMAND_CAPACITY),
615 fill_rule: FillRule::default(),
616 current: Point::default(),
617 start: Point::default(),
618 }
619 }
620
621 pub fn fill_rule(mut self, rule: FillRule) -> Self {
627 self.set_fill_rule(rule);
628 self
629 }
630
631 pub fn move_to(mut self, x: f32, y: f32) -> Self {
637 self.set_current(Point::new(x, y));
638 self.set_start(self.get_current());
639 self.get_mut_commands().push(PathCommand::MoveTo(x, y));
640 self
641 }
642
643 pub fn line_to(mut self, x: f32, y: f32) -> Self {
649 self.set_current(Point::new(x, y));
650 self.get_mut_commands().push(PathCommand::LineTo(x, y));
651 self
652 }
653
654 pub fn quad_to(mut self, control_x: f32, control_y: f32, x: f32, y: f32) -> Self {
660 self.set_current(Point::new(x, y));
661 self.get_mut_commands()
662 .push(PathCommand::QuadTo(control_x, control_y, x, y));
663 self
664 }
665
666 pub fn cubic_to(
672 mut self,
673 control1_x: f32,
674 control1_y: f32,
675 control2_x: f32,
676 control2_y: f32,
677 x: f32,
678 y: f32,
679 ) -> Self {
680 self.set_current(Point::new(x, y));
681 self.get_mut_commands().push(PathCommand::CubicTo(
682 control1_x, control1_y, control2_x, control2_y, x, y,
683 ));
684 self
685 }
686
687 pub fn close(mut self) -> Self {
689 self.set_current(self.get_start());
690 self.get_mut_commands().push(PathCommand::Close);
691 self
692 }
693
694 pub fn arc(
706 mut self,
707 center_x: f32,
708 center_y: f32,
709 radius_x: f32,
710 radius_y: f32,
711 start_angle: f64,
712 end_angle: f64,
713 ) -> Self {
714 let sweep: f64 = end_angle - start_angle;
715 if sweep == 0.0 {
716 return self;
717 }
718 let segments: usize = arc_segment_count(sweep, radius_x.max(radius_y) as f64, 0.1);
719 let (sin, cos) = start_angle.sin_cos();
720 let start_x: f64 = center_x as f64 + radius_x as f64 * cos;
721 let start_y: f64 = center_y as f64 + radius_y as f64 * sin;
722 if self.get_commands().is_empty() {
723 self.get_mut_commands()
724 .push(PathCommand::MoveTo(start_x as f32, start_y as f32));
725 } else {
726 self.get_mut_commands()
727 .push(PathCommand::LineTo(start_x as f32, start_y as f32));
728 }
729 self.set_current(Point::new(start_x as f32, start_y as f32));
730 self.set_start(self.get_current());
731
732 arc_to_cubic(
733 Ellipse {
734 center_x: center_x as f64,
735 center_y: center_y as f64,
736 radius_x: radius_x as f64,
737 radius_y: radius_y as f64,
738 },
739 start_angle,
740 sweep,
741 segments,
742 |c1x: f64, c1y: f64, c2x: f64, c2y: f64, x: f64, y: f64| {
743 self.get_mut_commands().push(PathCommand::CubicTo(
744 c1x as f32, c1y as f32, c2x as f32, c2y as f32, x as f32, y as f32,
745 ));
746 },
747 );
748 self
749 }
750
751 pub fn ellipse(mut self, center_x: f32, center_y: f32, radius_x: f32, radius_y: f32) -> Self {
757 let start: f64 = core::f64::consts::FRAC_PI_2;
758 self = self.move_to(center_x, center_y - radius_y);
759 self = self.arc(
760 center_x,
761 center_y,
762 radius_x,
763 radius_y,
764 start,
765 start + core::f64::consts::TAU,
766 );
767 self.close()
768 }
769
770 pub fn rect(mut self, x: f32, y: f32, width: f32, height: f32) -> Self {
776 self.get_mut_commands().push(PathCommand::MoveTo(x, y));
777 self.get_mut_commands()
778 .push(PathCommand::LineTo(x + width, y));
779 self.get_mut_commands()
780 .push(PathCommand::LineTo(x + width, y + height));
781 self.get_mut_commands()
782 .push(PathCommand::LineTo(x, y + height));
783 self.get_mut_commands().push(PathCommand::Close);
784 self
785 }
786
787 pub fn round_rect(mut self, x: f32, y: f32, width: f32, height: f32, radius: f32) -> Self {
793 let radius: f32 = radius.min(width * 0.5).min(height * 0.5);
794 if radius <= 0.0 {
795 return self.rect(x, y, width, height);
796 }
797 let right: f32 = x + width;
798 let bottom: f32 = y + height;
799 let kappa: f64 = radius as f64 * ARC_BEZIER_KAPPA;
800 self.get_mut_commands()
801 .push(PathCommand::MoveTo(x + radius, y));
802 self.get_mut_commands()
803 .push(PathCommand::LineTo(right - radius, y));
804 self.get_mut_commands().push(PathCommand::CubicTo(
805 right - radius + kappa as f32,
806 y,
807 right,
808 y + radius - kappa as f32,
809 right,
810 y + radius,
811 ));
812 self.get_mut_commands()
813 .push(PathCommand::LineTo(right, bottom - radius));
814 self.get_mut_commands().push(PathCommand::CubicTo(
815 right,
816 bottom - radius + kappa as f32,
817 right - radius + kappa as f32,
818 bottom,
819 right - radius,
820 bottom,
821 ));
822 self.get_mut_commands()
823 .push(PathCommand::LineTo(x + radius, bottom));
824 self.get_mut_commands().push(PathCommand::CubicTo(
825 x + radius - kappa as f32,
826 bottom,
827 x,
828 bottom - radius + kappa as f32,
829 x,
830 bottom - radius,
831 ));
832 self.get_mut_commands()
833 .push(PathCommand::LineTo(x, y + radius));
834 self.get_mut_commands().push(PathCommand::CubicTo(
835 x,
836 y + radius - kappa as f32,
837 x + radius - kappa as f32,
838 y,
839 x + radius,
840 y,
841 ));
842 self.get_mut_commands().push(PathCommand::Close);
843 self
844 }
845
846 pub fn polygon(mut self, points: &[Point]) -> Self {
852 if let Some(first) = points.first() {
853 self.get_mut_commands()
854 .push(PathCommand::MoveTo(first.x, first.y));
855 for point in &points[1..] {
856 self.get_mut_commands()
857 .push(PathCommand::LineTo(point.x, point.y));
858 }
859 self.get_mut_commands().push(PathCommand::Close);
860 }
861 self
862 }
863
864 pub fn build(self) -> Path {
870 let Self {
871 commands,
872 fill_rule,
873 ..
874 } = self;
875 Path {
876 commands,
877 fill_rule,
878 }
879 }
880}
881
882impl Default for PathBuilder {
884 fn default() -> Self {
886 Self::new()
887 }
888}
889
890impl DashPattern {
892 pub fn solid() -> Self {
894 Self {
895 pattern: Vec::new(),
896 offset: 0.0,
897 }
898 }
899
900 pub fn new(pattern: Vec<f32>, offset: f32) -> Self {
907 Self { pattern, offset }
908 }
909
910 pub fn is_solid(&self) -> bool {
916 self.get_pattern().is_empty()
917 }
918}