1use core::f32::consts::{FRAC_1_SQRT_2, FRAC_PI_2, FRAC_PI_3, PI};
2use derive_more::derive::From;
3#[cfg(feature = "alloc")]
4use thiserror::Error;
5
6use super::{Measured2d, Primitive2d, WindingOrder};
7use crate::{
8    ops::{self, FloatPow},
9    Dir2, InvalidDirectionError, Isometry2d, Ray2d, Rot2, Vec2,
10};
11
12#[cfg(feature = "alloc")]
13use super::polygon::is_polygon_simple;
14
15#[cfg(feature = "bevy_reflect")]
16use bevy_reflect::{std_traits::ReflectDefault, Reflect};
17#[cfg(all(feature = "serialize", feature = "bevy_reflect"))]
18use bevy_reflect::{ReflectDeserialize, ReflectSerialize};
19
20#[cfg(feature = "alloc")]
21use alloc::vec::Vec;
22
23#[derive(Clone, Copy, Debug, PartialEq)]
25#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
26#[cfg_attr(
27    feature = "bevy_reflect",
28    derive(Reflect),
29    reflect(Debug, PartialEq, Default, Clone)
30)]
31#[cfg_attr(
32    all(feature = "serialize", feature = "bevy_reflect"),
33    reflect(Serialize, Deserialize)
34)]
35pub struct Circle {
36    pub radius: f32,
38}
39
40impl Primitive2d for Circle {}
41
42impl Default for Circle {
43    fn default() -> Self {
45        Self { radius: 0.5 }
46    }
47}
48
49impl Circle {
50    #[inline(always)]
52    pub const fn new(radius: f32) -> Self {
53        Self { radius }
54    }
55
56    #[inline(always)]
58    pub const fn diameter(&self) -> f32 {
59        2.0 * self.radius
60    }
61
62    #[inline(always)]
67    pub fn closest_point(&self, point: Vec2) -> Vec2 {
68        let distance_squared = point.length_squared();
69
70        if distance_squared <= self.radius.squared() {
71            point
73        } else {
74            let dir_to_point = point / ops::sqrt(distance_squared);
77            self.radius * dir_to_point
78        }
79    }
80}
81
82impl Measured2d for Circle {
83    #[inline(always)]
85    fn area(&self) -> f32 {
86        PI * self.radius.squared()
87    }
88
89    #[inline(always)]
91    #[doc(alias = "circumference")]
92    fn perimeter(&self) -> f32 {
93        2.0 * PI * self.radius
94    }
95}
96
97#[derive(Clone, Copy, Debug, PartialEq)]
112#[doc(alias("CircularArc", "CircleArc"))]
113#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
114#[cfg_attr(
115    feature = "bevy_reflect",
116    derive(Reflect),
117    reflect(Debug, PartialEq, Default, Clone)
118)]
119#[cfg_attr(
120    all(feature = "serialize", feature = "bevy_reflect"),
121    reflect(Serialize, Deserialize)
122)]
123pub struct Arc2d {
124    pub radius: f32,
126    pub half_angle: f32,
128}
129
130impl Primitive2d for Arc2d {}
131
132impl Default for Arc2d {
133    fn default() -> Self {
135        Self {
136            radius: 0.5,
137            half_angle: 2.0 * FRAC_PI_3,
138        }
139    }
140}
141
142impl Arc2d {
143    #[inline(always)]
145    pub const fn new(radius: f32, half_angle: f32) -> Self {
146        Self { radius, half_angle }
147    }
148
149    #[inline(always)]
151    pub const fn from_radians(radius: f32, angle: f32) -> Self {
152        Self {
153            radius,
154            half_angle: angle / 2.0,
155        }
156    }
157
158    #[inline(always)]
160    pub const fn from_degrees(radius: f32, angle: f32) -> Self {
161        Self {
162            radius,
163            half_angle: angle.to_radians() / 2.0,
164        }
165    }
166
167    #[inline(always)]
171    pub const fn from_turns(radius: f32, fraction: f32) -> Self {
172        Self {
173            radius,
174            half_angle: fraction * PI,
175        }
176    }
177
178    #[inline(always)]
180    pub const fn angle(&self) -> f32 {
181        self.half_angle * 2.0
182    }
183
184    #[inline(always)]
186    pub const fn length(&self) -> f32 {
187        self.angle() * self.radius
188    }
189
190    #[inline(always)]
192    pub fn right_endpoint(&self) -> Vec2 {
193        self.radius * Vec2::from_angle(FRAC_PI_2 - self.half_angle)
194    }
195
196    #[inline(always)]
198    pub fn left_endpoint(&self) -> Vec2 {
199        self.radius * Vec2::from_angle(FRAC_PI_2 + self.half_angle)
200    }
201
202    #[inline(always)]
204    pub fn endpoints(&self) -> [Vec2; 2] {
205        [self.left_endpoint(), self.right_endpoint()]
206    }
207
208    #[inline]
210    pub fn midpoint(&self) -> Vec2 {
211        self.radius * Vec2::Y
212    }
213
214    #[inline(always)]
216    pub fn half_chord_length(&self) -> f32 {
217        self.radius * ops::sin(self.half_angle)
218    }
219
220    #[inline(always)]
222    pub fn chord_length(&self) -> f32 {
223        2.0 * self.half_chord_length()
224    }
225
226    #[inline(always)]
228    pub fn chord_midpoint(&self) -> Vec2 {
229        self.apothem() * Vec2::Y
230    }
231
232    #[inline(always)]
238    pub fn apothem(&self) -> f32 {
242        let sign = if self.is_minor() { 1.0 } else { -1.0 };
243        sign * ops::sqrt(self.radius.squared() - self.half_chord_length().squared())
244    }
245
246    pub fn sagitta(&self) -> f32 {
252        self.radius - self.apothem()
253    }
254
255    #[inline(always)]
259    pub const fn is_minor(&self) -> bool {
260        self.half_angle <= FRAC_PI_2
261    }
262
263    #[inline(always)]
267    pub const fn is_major(&self) -> bool {
268        self.half_angle >= FRAC_PI_2
269    }
270}
271
272#[derive(Clone, Copy, Debug, PartialEq, From)]
281#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
282#[cfg_attr(
283    feature = "bevy_reflect",
284    derive(Reflect),
285    reflect(Debug, PartialEq, Default, Clone)
286)]
287#[cfg_attr(
288    all(feature = "serialize", feature = "bevy_reflect"),
289    reflect(Serialize, Deserialize)
290)]
291pub struct CircularSector {
292    #[cfg_attr(all(feature = "serialize", feature = "alloc"), serde(flatten))]
294    pub arc: Arc2d,
295}
296
297impl Primitive2d for CircularSector {}
298
299impl Default for CircularSector {
300    fn default() -> Self {
302        Self::from(Arc2d::default())
303    }
304}
305
306impl Measured2d for CircularSector {
307    #[inline(always)]
308    fn area(&self) -> f32 {
309        self.arc.radius.squared() * self.arc.half_angle
310    }
311
312    #[inline(always)]
313    fn perimeter(&self) -> f32 {
314        if self.half_angle() >= PI {
315            self.arc.radius * 2.0 * PI
316        } else {
317            2.0 * self.radius() + self.arc_length()
318        }
319    }
320}
321
322impl CircularSector {
323    #[inline(always)]
325    pub const fn new(radius: f32, angle: f32) -> Self {
326        Self {
327            arc: Arc2d::new(radius, angle),
328        }
329    }
330
331    #[inline(always)]
333    pub const fn from_radians(radius: f32, angle: f32) -> Self {
334        Self {
335            arc: Arc2d::from_radians(radius, angle),
336        }
337    }
338
339    #[inline(always)]
341    pub const fn from_degrees(radius: f32, angle: f32) -> Self {
342        Self {
343            arc: Arc2d::from_degrees(radius, angle),
344        }
345    }
346
347    #[inline(always)]
351    pub const fn from_turns(radius: f32, fraction: f32) -> Self {
352        Self {
353            arc: Arc2d::from_turns(radius, fraction),
354        }
355    }
356
357    #[inline(always)]
359    pub const fn half_angle(&self) -> f32 {
360        self.arc.half_angle
361    }
362
363    #[inline(always)]
365    pub const fn angle(&self) -> f32 {
366        self.arc.angle()
367    }
368
369    #[inline(always)]
371    pub const fn radius(&self) -> f32 {
372        self.arc.radius
373    }
374
375    #[inline(always)]
377    pub const fn arc_length(&self) -> f32 {
378        self.arc.length()
379    }
380
381    #[inline(always)]
385    pub fn half_chord_length(&self) -> f32 {
386        self.arc.half_chord_length()
387    }
388
389    #[inline(always)]
393    pub fn chord_length(&self) -> f32 {
394        self.arc.chord_length()
395    }
396
397    #[inline(always)]
401    pub fn chord_midpoint(&self) -> Vec2 {
402        self.arc.chord_midpoint()
403    }
404
405    #[inline(always)]
409    pub fn apothem(&self) -> f32 {
410        self.arc.apothem()
411    }
412
413    #[inline(always)]
417    pub fn sagitta(&self) -> f32 {
418        self.arc.sagitta()
419    }
420}
421
422#[derive(Clone, Copy, Debug, PartialEq, From)]
433#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
434#[cfg_attr(
435    feature = "bevy_reflect",
436    derive(Reflect),
437    reflect(Debug, PartialEq, Default, Clone)
438)]
439#[cfg_attr(
440    all(feature = "serialize", feature = "bevy_reflect"),
441    reflect(Serialize, Deserialize)
442)]
443pub struct CircularSegment {
444    #[cfg_attr(all(feature = "serialize", feature = "alloc"), serde(flatten))]
446    pub arc: Arc2d,
447}
448
449impl Primitive2d for CircularSegment {}
450
451impl Default for CircularSegment {
452    fn default() -> Self {
454        Self::from(Arc2d::default())
455    }
456}
457
458impl Measured2d for CircularSegment {
459    #[inline(always)]
460    fn area(&self) -> f32 {
461        0.5 * self.arc.radius.squared() * (self.arc.angle() - ops::sin(self.arc.angle()))
462    }
463
464    #[inline(always)]
465    fn perimeter(&self) -> f32 {
466        self.chord_length() + self.arc_length()
467    }
468}
469
470impl CircularSegment {
471    #[inline(always)]
473    pub const fn new(radius: f32, angle: f32) -> Self {
474        Self {
475            arc: Arc2d::new(radius, angle),
476        }
477    }
478
479    #[inline(always)]
481    pub const fn from_radians(radius: f32, angle: f32) -> Self {
482        Self {
483            arc: Arc2d::from_radians(radius, angle),
484        }
485    }
486
487    #[inline(always)]
489    pub const fn from_degrees(radius: f32, angle: f32) -> Self {
490        Self {
491            arc: Arc2d::from_degrees(radius, angle),
492        }
493    }
494
495    #[inline(always)]
499    pub const fn from_turns(radius: f32, fraction: f32) -> Self {
500        Self {
501            arc: Arc2d::from_turns(radius, fraction),
502        }
503    }
504
505    #[inline(always)]
507    pub const fn half_angle(&self) -> f32 {
508        self.arc.half_angle
509    }
510
511    #[inline(always)]
513    pub const fn angle(&self) -> f32 {
514        self.arc.angle()
515    }
516
517    #[inline(always)]
519    pub const fn radius(&self) -> f32 {
520        self.arc.radius
521    }
522
523    #[inline(always)]
525    pub const fn arc_length(&self) -> f32 {
526        self.arc.length()
527    }
528
529    #[inline(always)]
531    #[doc(alias = "half_base_length")]
532    pub fn half_chord_length(&self) -> f32 {
533        self.arc.half_chord_length()
534    }
535
536    #[inline(always)]
538    #[doc(alias = "base_length")]
539    #[doc(alias = "base")]
540    pub fn chord_length(&self) -> f32 {
541        self.arc.chord_length()
542    }
543
544    #[inline(always)]
546    #[doc(alias = "base_midpoint")]
547    pub fn chord_midpoint(&self) -> Vec2 {
548        self.arc.chord_midpoint()
549    }
550
551    #[inline(always)]
556    pub fn apothem(&self) -> f32 {
557        self.arc.apothem()
558    }
559
560    #[inline(always)]
564    #[doc(alias = "height")]
565    pub fn sagitta(&self) -> f32 {
566        self.arc.sagitta()
567    }
568}
569
570#[cfg(test)]
571mod arc_tests {
572    use core::f32::consts::FRAC_PI_4;
573    use core::f32::consts::SQRT_2;
574
575    use approx::assert_abs_diff_eq;
576
577    use super::*;
578
579    struct ArcTestCase {
580        radius: f32,
581        half_angle: f32,
582        angle: f32,
583        length: f32,
584        right_endpoint: Vec2,
585        left_endpoint: Vec2,
586        endpoints: [Vec2; 2],
587        midpoint: Vec2,
588        half_chord_length: f32,
589        chord_length: f32,
590        chord_midpoint: Vec2,
591        apothem: f32,
592        sagitta: f32,
593        is_minor: bool,
594        is_major: bool,
595        sector_area: f32,
596        sector_perimeter: f32,
597        segment_area: f32,
598        segment_perimeter: f32,
599    }
600
601    impl ArcTestCase {
602        fn check_arc(&self, arc: Arc2d) {
603            assert_abs_diff_eq!(self.radius, arc.radius);
604            assert_abs_diff_eq!(self.half_angle, arc.half_angle);
605            assert_abs_diff_eq!(self.angle, arc.angle());
606            assert_abs_diff_eq!(self.length, arc.length());
607            assert_abs_diff_eq!(self.right_endpoint, arc.right_endpoint());
608            assert_abs_diff_eq!(self.left_endpoint, arc.left_endpoint());
609            assert_abs_diff_eq!(self.endpoints[0], arc.endpoints()[0]);
610            assert_abs_diff_eq!(self.endpoints[1], arc.endpoints()[1]);
611            assert_abs_diff_eq!(self.midpoint, arc.midpoint());
612            assert_abs_diff_eq!(self.half_chord_length, arc.half_chord_length());
613            assert_abs_diff_eq!(self.chord_length, arc.chord_length(), epsilon = 0.00001);
614            assert_abs_diff_eq!(self.chord_midpoint, arc.chord_midpoint());
615            assert_abs_diff_eq!(self.apothem, arc.apothem());
616            assert_abs_diff_eq!(self.sagitta, arc.sagitta());
617            assert_eq!(self.is_minor, arc.is_minor());
618            assert_eq!(self.is_major, arc.is_major());
619        }
620
621        fn check_sector(&self, sector: CircularSector) {
622            assert_abs_diff_eq!(self.radius, sector.radius());
623            assert_abs_diff_eq!(self.half_angle, sector.half_angle());
624            assert_abs_diff_eq!(self.angle, sector.angle());
625            assert_abs_diff_eq!(self.half_chord_length, sector.half_chord_length());
626            assert_abs_diff_eq!(self.chord_length, sector.chord_length(), epsilon = 0.00001);
627            assert_abs_diff_eq!(self.chord_midpoint, sector.chord_midpoint());
628            assert_abs_diff_eq!(self.apothem, sector.apothem());
629            assert_abs_diff_eq!(self.sagitta, sector.sagitta());
630            assert_abs_diff_eq!(self.sector_area, sector.area());
631            assert_abs_diff_eq!(self.sector_perimeter, sector.perimeter());
632        }
633
634        fn check_segment(&self, segment: CircularSegment) {
635            assert_abs_diff_eq!(self.radius, segment.radius());
636            assert_abs_diff_eq!(self.half_angle, segment.half_angle());
637            assert_abs_diff_eq!(self.angle, segment.angle());
638            assert_abs_diff_eq!(self.half_chord_length, segment.half_chord_length());
639            assert_abs_diff_eq!(self.chord_length, segment.chord_length(), epsilon = 0.00001);
640            assert_abs_diff_eq!(self.chord_midpoint, segment.chord_midpoint());
641            assert_abs_diff_eq!(self.apothem, segment.apothem());
642            assert_abs_diff_eq!(self.sagitta, segment.sagitta());
643            assert_abs_diff_eq!(self.segment_area, segment.area());
644            assert_abs_diff_eq!(self.segment_perimeter, segment.perimeter());
645        }
646    }
647
648    #[test]
649    fn zero_angle() {
650        let tests = ArcTestCase {
651            radius: 1.0,
652            half_angle: 0.0,
653            angle: 0.0,
654            length: 0.0,
655            left_endpoint: Vec2::Y,
656            right_endpoint: Vec2::Y,
657            endpoints: [Vec2::Y, Vec2::Y],
658            midpoint: Vec2::Y,
659            half_chord_length: 0.0,
660            chord_length: 0.0,
661            chord_midpoint: Vec2::Y,
662            apothem: 1.0,
663            sagitta: 0.0,
664            is_minor: true,
665            is_major: false,
666            sector_area: 0.0,
667            sector_perimeter: 2.0,
668            segment_area: 0.0,
669            segment_perimeter: 0.0,
670        };
671
672        tests.check_arc(Arc2d::new(1.0, 0.0));
673        tests.check_sector(CircularSector::new(1.0, 0.0));
674        tests.check_segment(CircularSegment::new(1.0, 0.0));
675    }
676
677    #[test]
678    fn zero_radius() {
679        let tests = ArcTestCase {
680            radius: 0.0,
681            half_angle: FRAC_PI_4,
682            angle: FRAC_PI_2,
683            length: 0.0,
684            left_endpoint: Vec2::ZERO,
685            right_endpoint: Vec2::ZERO,
686            endpoints: [Vec2::ZERO, Vec2::ZERO],
687            midpoint: Vec2::ZERO,
688            half_chord_length: 0.0,
689            chord_length: 0.0,
690            chord_midpoint: Vec2::ZERO,
691            apothem: 0.0,
692            sagitta: 0.0,
693            is_minor: true,
694            is_major: false,
695            sector_area: 0.0,
696            sector_perimeter: 0.0,
697            segment_area: 0.0,
698            segment_perimeter: 0.0,
699        };
700
701        tests.check_arc(Arc2d::new(0.0, FRAC_PI_4));
702        tests.check_sector(CircularSector::new(0.0, FRAC_PI_4));
703        tests.check_segment(CircularSegment::new(0.0, FRAC_PI_4));
704    }
705
706    #[test]
707    fn quarter_circle() {
708        let sqrt_half: f32 = ops::sqrt(0.5);
709        let tests = ArcTestCase {
710            radius: 1.0,
711            half_angle: FRAC_PI_4,
712            angle: FRAC_PI_2,
713            length: FRAC_PI_2,
714            left_endpoint: Vec2::new(-sqrt_half, sqrt_half),
715            right_endpoint: Vec2::splat(sqrt_half),
716            endpoints: [Vec2::new(-sqrt_half, sqrt_half), Vec2::splat(sqrt_half)],
717            midpoint: Vec2::Y,
718            half_chord_length: sqrt_half,
719            chord_length: ops::sqrt(2.0),
720            chord_midpoint: Vec2::new(0.0, sqrt_half),
721            apothem: sqrt_half,
722            sagitta: 1.0 - sqrt_half,
723            is_minor: true,
724            is_major: false,
725            sector_area: FRAC_PI_4,
726            sector_perimeter: FRAC_PI_2 + 2.0,
727            segment_area: FRAC_PI_4 - 0.5,
728            segment_perimeter: FRAC_PI_2 + SQRT_2,
729        };
730
731        tests.check_arc(Arc2d::from_turns(1.0, 0.25));
732        tests.check_sector(CircularSector::from_turns(1.0, 0.25));
733        tests.check_segment(CircularSegment::from_turns(1.0, 0.25));
734    }
735
736    #[test]
737    fn half_circle() {
738        let tests = ArcTestCase {
739            radius: 1.0,
740            half_angle: FRAC_PI_2,
741            angle: PI,
742            length: PI,
743            left_endpoint: Vec2::NEG_X,
744            right_endpoint: Vec2::X,
745            endpoints: [Vec2::NEG_X, Vec2::X],
746            midpoint: Vec2::Y,
747            half_chord_length: 1.0,
748            chord_length: 2.0,
749            chord_midpoint: Vec2::ZERO,
750            apothem: 0.0,
751            sagitta: 1.0,
752            is_minor: true,
753            is_major: true,
754            sector_area: FRAC_PI_2,
755            sector_perimeter: PI + 2.0,
756            segment_area: FRAC_PI_2,
757            segment_perimeter: PI + 2.0,
758        };
759
760        tests.check_arc(Arc2d::from_radians(1.0, PI));
761        tests.check_sector(CircularSector::from_radians(1.0, PI));
762        tests.check_segment(CircularSegment::from_radians(1.0, PI));
763    }
764
765    #[test]
766    fn full_circle() {
767        let tests = ArcTestCase {
768            radius: 1.0,
769            half_angle: PI,
770            angle: 2.0 * PI,
771            length: 2.0 * PI,
772            left_endpoint: Vec2::NEG_Y,
773            right_endpoint: Vec2::NEG_Y,
774            endpoints: [Vec2::NEG_Y, Vec2::NEG_Y],
775            midpoint: Vec2::Y,
776            half_chord_length: 0.0,
777            chord_length: 0.0,
778            chord_midpoint: Vec2::NEG_Y,
779            apothem: -1.0,
780            sagitta: 2.0,
781            is_minor: false,
782            is_major: true,
783            sector_area: PI,
784            sector_perimeter: 2.0 * PI,
785            segment_area: PI,
786            segment_perimeter: 2.0 * PI,
787        };
788
789        tests.check_arc(Arc2d::from_degrees(1.0, 360.0));
790        tests.check_sector(CircularSector::from_degrees(1.0, 360.0));
791        tests.check_segment(CircularSegment::from_degrees(1.0, 360.0));
792    }
793}
794
795#[derive(Clone, Copy, Debug, PartialEq)]
797#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
798#[cfg_attr(
799    feature = "bevy_reflect",
800    derive(Reflect),
801    reflect(Debug, PartialEq, Default, Clone)
802)]
803#[cfg_attr(
804    all(feature = "serialize", feature = "bevy_reflect"),
805    reflect(Serialize, Deserialize)
806)]
807pub struct Ellipse {
808    pub half_size: Vec2,
812}
813
814impl Primitive2d for Ellipse {}
815
816impl Default for Ellipse {
817    fn default() -> Self {
819        Self {
820            half_size: Vec2::new(1.0, 0.5),
821        }
822    }
823}
824
825impl Ellipse {
826    #[inline(always)]
830    pub const fn new(half_width: f32, half_height: f32) -> Self {
831        Self {
832            half_size: Vec2::new(half_width, half_height),
833        }
834    }
835
836    #[inline(always)]
840    pub const fn from_size(size: Vec2) -> Self {
841        Self {
842            half_size: Vec2::new(size.x / 2.0, size.y / 2.0),
843        }
844    }
845
846    #[inline(always)]
847    pub fn eccentricity(&self) -> f32 {
852        let a = self.semi_major();
853        let b = self.semi_minor();
854
855        ops::sqrt(a * a - b * b) / a
856    }
857
858    #[inline(always)]
859    pub fn focal_length(&self) -> f32 {
863        let a = self.semi_major();
864        let b = self.semi_minor();
865
866        ops::sqrt(a * a - b * b)
867    }
868
869    #[inline(always)]
871    pub fn semi_major(&self) -> f32 {
872        self.half_size.max_element()
873    }
874
875    #[inline(always)]
877    pub fn semi_minor(&self) -> f32 {
878        self.half_size.min_element()
879    }
880}
881
882impl Measured2d for Ellipse {
883    #[inline(always)]
885    fn area(&self) -> f32 {
886        PI * self.half_size.x * self.half_size.y
887    }
888
889    #[inline(always)]
890    fn perimeter(&self) -> f32 {
894        let a = self.semi_major();
895        let b = self.semi_minor();
896
897        if a / b - 1. < 1e-5 {
899            return PI * (a + b);
900        };
901
902        if a / b > 1e4 {
904            return 4. * a;
905        };
906
907        const BINOMIAL_COEFFICIENTS: [f32; 21] = [
911            1.,
912            0.25,
913            0.015625,
914            0.00390625,
915            0.0015258789,
916            0.00074768066,
917            0.00042057037,
918            0.00025963783,
919            0.00017140154,
920            0.000119028846,
921            0.00008599834,
922            0.00006414339,
923            0.000049109784,
924            0.000038430585,
925            0.000030636627,
926            0.000024815668,
927            0.000020380836,
928            0.000016942893,
929            0.000014236736,
930            0.000012077564,
931            0.000010333865,
932        ];
933
934        let h = ((a - b) / (a + b)).squared();
938
939        PI * (a + b)
940            * (0..=20)
941                .map(|i| BINOMIAL_COEFFICIENTS[i] * ops::powf(h, i as f32))
942                .sum::<f32>()
943    }
944}
945
946#[derive(Clone, Copy, Debug, PartialEq)]
948#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
949#[cfg_attr(
950    feature = "bevy_reflect",
951    derive(Reflect),
952    reflect(Debug, PartialEq, Default, Clone)
953)]
954#[cfg_attr(
955    all(feature = "serialize", feature = "bevy_reflect"),
956    reflect(Serialize, Deserialize)
957)]
958#[doc(alias = "Ring")]
959pub struct Annulus {
960    pub inner_circle: Circle,
962    pub outer_circle: Circle,
964}
965
966impl Primitive2d for Annulus {}
967
968impl Default for Annulus {
969    fn default() -> Self {
971        Self {
972            inner_circle: Circle::new(0.5),
973            outer_circle: Circle::new(1.0),
974        }
975    }
976}
977
978impl Annulus {
979    #[inline(always)]
981    pub const fn new(inner_radius: f32, outer_radius: f32) -> Self {
982        Self {
983            inner_circle: Circle::new(inner_radius),
984            outer_circle: Circle::new(outer_radius),
985        }
986    }
987
988    #[inline(always)]
990    pub const fn diameter(&self) -> f32 {
991        self.outer_circle.diameter()
992    }
993
994    #[inline(always)]
996    pub const fn thickness(&self) -> f32 {
997        self.outer_circle.radius - self.inner_circle.radius
998    }
999
1000    #[inline(always)]
1006    pub fn closest_point(&self, point: Vec2) -> Vec2 {
1007        let distance_squared = point.length_squared();
1008
1009        if self.inner_circle.radius.squared() <= distance_squared {
1010            if distance_squared <= self.outer_circle.radius.squared() {
1011                point
1013            } else {
1014                let dir_to_point = point / ops::sqrt(distance_squared);
1017                self.outer_circle.radius * dir_to_point
1018            }
1019        } else {
1020            let dir_to_point = point / ops::sqrt(distance_squared);
1023            self.inner_circle.radius * dir_to_point
1024        }
1025    }
1026}
1027
1028impl Measured2d for Annulus {
1029    #[inline(always)]
1031    fn area(&self) -> f32 {
1032        PI * (self.outer_circle.radius.squared() - self.inner_circle.radius.squared())
1033    }
1034
1035    #[inline(always)]
1038    #[doc(alias = "circumference")]
1039    fn perimeter(&self) -> f32 {
1040        2.0 * PI * (self.outer_circle.radius + self.inner_circle.radius)
1041    }
1042}
1043
1044#[derive(Clone, Copy, Debug, PartialEq)]
1048#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
1049#[cfg_attr(
1050    feature = "bevy_reflect",
1051    derive(Reflect),
1052    reflect(Debug, PartialEq, Default, Clone)
1053)]
1054#[cfg_attr(
1055    all(feature = "serialize", feature = "bevy_reflect"),
1056    reflect(Serialize, Deserialize)
1057)]
1058#[doc(alias = "Diamond")]
1059pub struct Rhombus {
1060    pub half_diagonals: Vec2,
1062}
1063
1064impl Primitive2d for Rhombus {}
1065
1066impl Default for Rhombus {
1067    fn default() -> Self {
1069        Self {
1070            half_diagonals: Vec2::splat(0.5),
1071        }
1072    }
1073}
1074
1075impl Rhombus {
1076    #[inline(always)]
1078    pub const fn new(horizontal_diagonal: f32, vertical_diagonal: f32) -> Self {
1079        Self {
1080            half_diagonals: Vec2::new(horizontal_diagonal / 2.0, vertical_diagonal / 2.0),
1081        }
1082    }
1083
1084    #[inline(always)]
1086    pub const fn from_side(side: f32) -> Self {
1087        Self {
1088            half_diagonals: Vec2::splat(side * FRAC_1_SQRT_2),
1089        }
1090    }
1091
1092    #[inline(always)]
1094    pub const fn from_inradius(inradius: f32) -> Self {
1095        let half_diagonal = inradius * 2.0 / core::f32::consts::SQRT_2;
1096        Self {
1097            half_diagonals: Vec2::new(half_diagonal, half_diagonal),
1098        }
1099    }
1100
1101    #[inline(always)]
1103    pub fn side(&self) -> f32 {
1104        self.half_diagonals.length()
1105    }
1106
1107    #[inline(always)]
1110    pub const fn circumradius(&self) -> f32 {
1111        self.half_diagonals.x.max(self.half_diagonals.y)
1112    }
1113
1114    #[inline(always)]
1117    #[doc(alias = "apothem")]
1118    pub fn inradius(&self) -> f32 {
1119        let side = self.side();
1120        if side == 0.0 {
1121            0.0
1122        } else {
1123            (self.half_diagonals.x * self.half_diagonals.y) / side
1124        }
1125    }
1126
1127    #[inline(always)]
1132    pub fn closest_point(&self, point: Vec2) -> Vec2 {
1133        let point_abs = point.abs();
1135        let half_diagonals = self.half_diagonals.abs(); let normal = Vec2::new(half_diagonals.y, half_diagonals.x);
1139        let normal_magnitude_squared = normal.length_squared();
1140        if normal_magnitude_squared == 0.0 {
1141            return Vec2::ZERO; }
1143
1144        let distance_unnormalised = normal.dot(point_abs) - half_diagonals.x * half_diagonals.y;
1146
1147        if distance_unnormalised <= 0.0 {
1149            return point;
1150        }
1151
1152        let mut result = point_abs - normal * distance_unnormalised / normal_magnitude_squared;
1154
1155        if result.x <= 0.0 {
1158            result = Vec2::new(0.0, half_diagonals.y);
1159        } else if result.y <= 0.0 {
1160            result = Vec2::new(half_diagonals.x, 0.0);
1161        }
1162
1163        result.copysign(point)
1165    }
1166}
1167
1168impl Measured2d for Rhombus {
1169    #[inline(always)]
1171    fn area(&self) -> f32 {
1172        2.0 * self.half_diagonals.x * self.half_diagonals.y
1173    }
1174
1175    #[inline(always)]
1177    fn perimeter(&self) -> f32 {
1178        4.0 * self.side()
1179    }
1180}
1181
1182#[derive(Clone, Copy, Debug, PartialEq)]
1185#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
1186#[cfg_attr(
1187    feature = "bevy_reflect",
1188    derive(Reflect),
1189    reflect(Debug, PartialEq, Default, Clone)
1190)]
1191#[cfg_attr(
1192    all(feature = "serialize", feature = "bevy_reflect"),
1193    reflect(Serialize, Deserialize)
1194)]
1195pub struct Plane2d {
1196    pub normal: Dir2,
1198}
1199
1200impl Primitive2d for Plane2d {}
1201
1202impl Default for Plane2d {
1203    fn default() -> Self {
1205        Self { normal: Dir2::Y }
1206    }
1207}
1208
1209impl Plane2d {
1210    #[inline(always)]
1216    pub fn new(normal: Vec2) -> Self {
1217        Self {
1218            normal: Dir2::new(normal).expect("normal must be nonzero and finite"),
1219        }
1220    }
1221}
1222
1223#[derive(Clone, Copy, Debug, PartialEq)]
1227#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
1228#[cfg_attr(
1229    feature = "bevy_reflect",
1230    derive(Reflect),
1231    reflect(Debug, PartialEq, Clone)
1232)]
1233#[cfg_attr(
1234    all(feature = "serialize", feature = "bevy_reflect"),
1235    reflect(Serialize, Deserialize)
1236)]
1237pub struct Line2d {
1238    pub direction: Dir2,
1241}
1242
1243impl Primitive2d for Line2d {}
1244
1245#[derive(Clone, Copy, Debug, PartialEq)]
1247#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
1248#[cfg_attr(
1249    feature = "bevy_reflect",
1250    derive(Reflect),
1251    reflect(Debug, PartialEq, Clone)
1252)]
1253#[cfg_attr(
1254    all(feature = "serialize", feature = "bevy_reflect"),
1255    reflect(Serialize, Deserialize)
1256)]
1257#[doc(alias = "LineSegment2d")]
1258pub struct Segment2d {
1259    pub vertices: [Vec2; 2],
1261}
1262
1263impl Primitive2d for Segment2d {}
1264
1265impl Default for Segment2d {
1266    fn default() -> Self {
1267        Self {
1268            vertices: [Vec2::new(-0.5, 0.0), Vec2::new(0.5, 0.0)],
1269        }
1270    }
1271}
1272
1273impl Segment2d {
1274    #[inline(always)]
1276    pub const fn new(point1: Vec2, point2: Vec2) -> Self {
1277        Self {
1278            vertices: [point1, point2],
1279        }
1280    }
1281
1282    #[inline(always)]
1286    pub fn from_direction_and_length(direction: Dir2, length: f32) -> Self {
1287        let endpoint = 0.5 * length * direction;
1288        Self {
1289            vertices: [-endpoint, endpoint],
1290        }
1291    }
1292
1293    #[inline(always)]
1298    pub fn from_scaled_direction(scaled_direction: Vec2) -> Self {
1299        let endpoint = 0.5 * scaled_direction;
1300        Self {
1301            vertices: [-endpoint, endpoint],
1302        }
1303    }
1304
1305    #[inline(always)]
1310    pub fn from_ray_and_length(ray: Ray2d, length: f32) -> Self {
1311        Self {
1312            vertices: [ray.origin, ray.get_point(length)],
1313        }
1314    }
1315
1316    #[inline(always)]
1318    pub const fn point1(&self) -> Vec2 {
1319        self.vertices[0]
1320    }
1321
1322    #[inline(always)]
1324    pub const fn point2(&self) -> Vec2 {
1325        self.vertices[1]
1326    }
1327
1328    #[inline(always)]
1330    #[doc(alias = "midpoint")]
1331    pub fn center(&self) -> Vec2 {
1332        self.point1().midpoint(self.point2())
1333    }
1334
1335    #[inline(always)]
1337    pub fn length(&self) -> f32 {
1338        self.point1().distance(self.point2())
1339    }
1340
1341    #[inline(always)]
1343    pub fn length_squared(&self) -> f32 {
1344        self.point1().distance_squared(self.point2())
1345    }
1346
1347    #[inline(always)]
1355    pub fn direction(&self) -> Dir2 {
1356        self.try_direction().unwrap_or_else(|err| {
1357            panic!("Failed to compute the direction of a line segment: {err}")
1358        })
1359    }
1360
1361    #[inline(always)]
1366    pub fn try_direction(&self) -> Result<Dir2, InvalidDirectionError> {
1367        Dir2::new(self.scaled_direction())
1368    }
1369
1370    #[inline(always)]
1372    pub fn scaled_direction(&self) -> Vec2 {
1373        self.point2() - self.point1()
1374    }
1375
1376    #[inline(always)]
1384    pub fn left_normal(&self) -> Dir2 {
1385        self.try_left_normal().unwrap_or_else(|err| {
1386            panic!("Failed to compute the left-hand side normal of a line segment: {err}")
1387        })
1388    }
1389
1390    #[inline(always)]
1395    pub fn try_left_normal(&self) -> Result<Dir2, InvalidDirectionError> {
1396        Dir2::new(self.scaled_left_normal())
1397    }
1398
1399    #[inline(always)]
1403    pub fn scaled_left_normal(&self) -> Vec2 {
1404        let scaled_direction = self.scaled_direction();
1405        Vec2::new(-scaled_direction.y, scaled_direction.x)
1406    }
1407
1408    #[inline(always)]
1416    pub fn right_normal(&self) -> Dir2 {
1417        self.try_right_normal().unwrap_or_else(|err| {
1418            panic!("Failed to compute the right-hand side normal of a line segment: {err}")
1419        })
1420    }
1421
1422    #[inline(always)]
1427    pub fn try_right_normal(&self) -> Result<Dir2, InvalidDirectionError> {
1428        Dir2::new(self.scaled_right_normal())
1429    }
1430
1431    #[inline(always)]
1435    pub fn scaled_right_normal(&self) -> Vec2 {
1436        let scaled_direction = self.scaled_direction();
1437        Vec2::new(scaled_direction.y, -scaled_direction.x)
1438    }
1439
1440    #[inline(always)]
1442    pub fn transformed(&self, isometry: impl Into<Isometry2d>) -> Self {
1443        let isometry: Isometry2d = isometry.into();
1444        Self::new(
1445            isometry.transform_point(self.point1()),
1446            isometry.transform_point(self.point2()),
1447        )
1448    }
1449
1450    #[inline(always)]
1452    pub fn translated(&self, translation: Vec2) -> Segment2d {
1453        Self::new(self.point1() + translation, self.point2() + translation)
1454    }
1455
1456    #[inline(always)]
1458    pub fn rotated(&self, rotation: Rot2) -> Segment2d {
1459        Segment2d::new(rotation * self.point1(), rotation * self.point2())
1460    }
1461
1462    #[inline(always)]
1464    pub fn rotated_around(&self, rotation: Rot2, point: Vec2) -> Segment2d {
1465        let offset = self.translated(-point);
1467        let rotated = offset.rotated(rotation);
1468        rotated.translated(point)
1469    }
1470
1471    #[inline(always)]
1473    pub fn rotated_around_center(&self, rotation: Rot2) -> Segment2d {
1474        self.rotated_around(rotation, self.center())
1475    }
1476
1477    #[inline(always)]
1479    pub fn centered(&self) -> Segment2d {
1480        let center = self.center();
1481        self.translated(-center)
1482    }
1483
1484    #[inline(always)]
1486    pub fn resized(&self, length: f32) -> Segment2d {
1487        let offset_from_origin = self.center();
1488        let centered = self.translated(-offset_from_origin);
1489        let ratio = length / self.length();
1490        let segment = Segment2d::new(centered.point1() * ratio, centered.point2() * ratio);
1491        segment.translated(offset_from_origin)
1492    }
1493
1494    #[inline(always)]
1496    pub fn reverse(&mut self) {
1497        let [point1, point2] = &mut self.vertices;
1498        core::mem::swap(point1, point2);
1499    }
1500
1501    #[inline(always)]
1503    #[must_use]
1504    pub fn reversed(mut self) -> Self {
1505        self.reverse();
1506        self
1507    }
1508
1509    #[inline(always)]
1511    pub fn closest_point(&self, point: Vec2) -> Vec2 {
1512        let segment_vector = self.vertices[1] - self.vertices[0];
1521        let offset = point - self.vertices[0];
1522        let projection_scaled = segment_vector.dot(offset);
1524
1525        if projection_scaled <= 0.0 {
1527            return self.vertices[0];
1528        }
1529
1530        let length_squared = segment_vector.length_squared();
1531        if projection_scaled >= length_squared {
1533            return self.vertices[1];
1534        }
1535
1536        let t = projection_scaled / length_squared;
1538        self.vertices[0] + t * segment_vector
1539    }
1540}
1541
1542impl From<[Vec2; 2]> for Segment2d {
1543    #[inline(always)]
1544    fn from(vertices: [Vec2; 2]) -> Self {
1545        Self { vertices }
1546    }
1547}
1548
1549impl From<(Vec2, Vec2)> for Segment2d {
1550    #[inline(always)]
1551    fn from((point1, point2): (Vec2, Vec2)) -> Self {
1552        Self::new(point1, point2)
1553    }
1554}
1555
1556#[cfg(feature = "alloc")]
1558#[derive(Clone, Debug, PartialEq)]
1559#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
1560#[cfg_attr(
1561    feature = "bevy_reflect",
1562    derive(Reflect),
1563    reflect(Debug, PartialEq, Clone)
1564)]
1565#[cfg_attr(
1566    all(feature = "serialize", feature = "bevy_reflect"),
1567    reflect(Serialize, Deserialize)
1568)]
1569pub struct Polyline2d {
1570    pub vertices: Vec<Vec2>,
1572}
1573
1574#[cfg(feature = "alloc")]
1575impl Primitive2d for Polyline2d {}
1576
1577#[cfg(feature = "alloc")]
1578impl FromIterator<Vec2> for Polyline2d {
1579    fn from_iter<I: IntoIterator<Item = Vec2>>(iter: I) -> Self {
1580        Self {
1581            vertices: iter.into_iter().collect(),
1582        }
1583    }
1584}
1585
1586#[cfg(feature = "alloc")]
1587impl Default for Polyline2d {
1588    fn default() -> Self {
1589        Self {
1590            vertices: Vec::from([Vec2::new(-0.5, 0.0), Vec2::new(0.5, 0.0)]),
1591        }
1592    }
1593}
1594
1595#[cfg(feature = "alloc")]
1596impl Polyline2d {
1597    pub fn new(vertices: impl IntoIterator<Item = Vec2>) -> Self {
1599        Self::from_iter(vertices)
1600    }
1601
1602    pub fn with_subdivisions(start: Vec2, end: Vec2, subdivisions: usize) -> Self {
1606        let total_vertices = subdivisions + 2;
1607        let mut vertices = Vec::with_capacity(total_vertices);
1608
1609        let step = (end - start) / (subdivisions + 1) as f32;
1610        for i in 0..total_vertices {
1611            vertices.push(start + step * i as f32);
1612        }
1613
1614        Self { vertices }
1615    }
1616}
1617
1618#[derive(Clone, Copy, Debug, PartialEq)]
1620#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
1621#[cfg_attr(
1622    feature = "bevy_reflect",
1623    derive(Reflect),
1624    reflect(Debug, PartialEq, Default, Clone)
1625)]
1626#[cfg_attr(
1627    all(feature = "serialize", feature = "bevy_reflect"),
1628    reflect(Serialize, Deserialize)
1629)]
1630pub struct Triangle2d {
1631    pub vertices: [Vec2; 3],
1633}
1634
1635impl Primitive2d for Triangle2d {}
1636
1637impl Default for Triangle2d {
1638    fn default() -> Self {
1640        Self {
1641            vertices: [Vec2::Y * 0.5, Vec2::new(-0.5, -0.5), Vec2::new(0.5, -0.5)],
1642        }
1643    }
1644}
1645
1646impl Triangle2d {
1647    #[inline(always)]
1649    pub const fn new(a: Vec2, b: Vec2, c: Vec2) -> Self {
1650        Self {
1651            vertices: [a, b, c],
1652        }
1653    }
1654
1655    #[inline(always)]
1657    #[doc(alias = "orientation")]
1658    pub fn winding_order(&self) -> WindingOrder {
1659        let [a, b, c] = self.vertices;
1660        let area = (b - a).perp_dot(c - a);
1661        if area > f32::EPSILON {
1662            WindingOrder::CounterClockwise
1663        } else if area < -f32::EPSILON {
1664            WindingOrder::Clockwise
1665        } else {
1666            WindingOrder::Invalid
1667        }
1668    }
1669
1670    pub fn circumcircle(&self) -> (Circle, Vec2) {
1673        let a = self.vertices[0];
1687        let (b, c) = (self.vertices[1] - a, self.vertices[2] - a);
1688        let b_length_sq = b.length_squared();
1689        let c_length_sq = c.length_squared();
1690
1691        let inv_d = (2.0 * (b.x * c.y - b.y * c.x)).recip();
1693        let ux = inv_d * (c.y * b_length_sq - b.y * c_length_sq);
1694        let uy = inv_d * (b.x * c_length_sq - c.x * b_length_sq);
1695        let u = Vec2::new(ux, uy);
1696
1697        let center = u + a;
1700        let radius = u.length();
1701
1702        (Circle { radius }, center)
1703    }
1704
1705    #[inline(always)]
1710    pub fn is_degenerate(&self) -> bool {
1711        let [a, b, c] = self.vertices;
1712        let ab = (b - a).extend(0.);
1713        let ac = (c - a).extend(0.);
1714        ab.cross(ac).length() < 10e-7
1715    }
1716
1717    #[inline(always)]
1719    pub fn is_acute(&self) -> bool {
1720        let [a, b, c] = self.vertices;
1721        let ab = b - a;
1722        let bc = c - b;
1723        let ca = a - c;
1724
1725        let mut side_lengths = [
1727            ab.length_squared(),
1728            bc.length_squared(),
1729            ca.length_squared(),
1730        ];
1731        side_lengths.sort_by(|a, b| a.partial_cmp(b).unwrap());
1732        side_lengths[0] + side_lengths[1] > side_lengths[2]
1733    }
1734
1735    #[inline(always)]
1737    pub fn is_obtuse(&self) -> bool {
1738        let [a, b, c] = self.vertices;
1739        let ab = b - a;
1740        let bc = c - b;
1741        let ca = a - c;
1742
1743        let mut side_lengths = [
1745            ab.length_squared(),
1746            bc.length_squared(),
1747            ca.length_squared(),
1748        ];
1749        side_lengths.sort_by(|a, b| a.partial_cmp(b).unwrap());
1750        side_lengths[0] + side_lengths[1] < side_lengths[2]
1751    }
1752
1753    #[inline(always)]
1756    pub fn reverse(&mut self) {
1757        self.vertices.swap(0, 2);
1758    }
1759
1760    #[inline(always)]
1762    #[must_use]
1763    pub fn reversed(mut self) -> Self {
1764        self.reverse();
1765        self
1766    }
1767}
1768
1769impl Measured2d for Triangle2d {
1770    #[inline(always)]
1772    fn area(&self) -> f32 {
1773        let [a, b, c] = self.vertices;
1774        ops::abs(a.x * (b.y - c.y) + b.x * (c.y - a.y) + c.x * (a.y - b.y)) / 2.0
1775    }
1776
1777    #[inline(always)]
1779    fn perimeter(&self) -> f32 {
1780        let [a, b, c] = self.vertices;
1781
1782        let ab = a.distance(b);
1783        let bc = b.distance(c);
1784        let ca = c.distance(a);
1785
1786        ab + bc + ca
1787    }
1788}
1789
1790#[derive(Clone, Copy, Debug, PartialEq)]
1792#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
1793#[cfg_attr(
1794    feature = "bevy_reflect",
1795    derive(Reflect),
1796    reflect(Debug, PartialEq, Default, Clone)
1797)]
1798#[cfg_attr(
1799    all(feature = "serialize", feature = "bevy_reflect"),
1800    reflect(Serialize, Deserialize)
1801)]
1802#[doc(alias = "Quad")]
1803pub struct Rectangle {
1804    pub half_size: Vec2,
1806}
1807
1808impl Primitive2d for Rectangle {}
1809
1810impl Default for Rectangle {
1811    fn default() -> Self {
1813        Self {
1814            half_size: Vec2::splat(0.5),
1815        }
1816    }
1817}
1818
1819impl Rectangle {
1820    #[inline(always)]
1822    pub const fn new(width: f32, height: f32) -> Self {
1823        Self::from_size(Vec2::new(width, height))
1824    }
1825
1826    #[inline(always)]
1828    pub const fn from_size(size: Vec2) -> Self {
1829        Self {
1830            half_size: Vec2::new(size.x / 2.0, size.y / 2.0),
1831        }
1832    }
1833
1834    #[inline(always)]
1836    pub fn from_corners(point1: Vec2, point2: Vec2) -> Self {
1837        Self {
1838            half_size: (point2 - point1).abs() / 2.0,
1839        }
1840    }
1841
1842    #[inline(always)]
1845    pub const fn from_length(length: f32) -> Self {
1846        Self {
1847            half_size: Vec2::splat(length / 2.0),
1848        }
1849    }
1850
1851    #[inline(always)]
1853    pub fn size(&self) -> Vec2 {
1854        2.0 * self.half_size
1855    }
1856
1857    #[inline(always)]
1862    pub fn closest_point(&self, point: Vec2) -> Vec2 {
1863        point.clamp(-self.half_size, self.half_size)
1865    }
1866}
1867
1868impl Measured2d for Rectangle {
1869    #[inline(always)]
1871    fn area(&self) -> f32 {
1872        4.0 * self.half_size.x * self.half_size.y
1873    }
1874
1875    #[inline(always)]
1877    fn perimeter(&self) -> f32 {
1878        4.0 * (self.half_size.x + self.half_size.y)
1879    }
1880}
1881
1882#[cfg(feature = "alloc")]
1884#[derive(Clone, Debug, PartialEq)]
1885#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
1886#[cfg_attr(
1887    feature = "bevy_reflect",
1888    derive(Reflect),
1889    reflect(Debug, PartialEq, Clone)
1890)]
1891#[cfg_attr(
1892    all(feature = "serialize", feature = "bevy_reflect"),
1893    reflect(Serialize, Deserialize)
1894)]
1895pub struct Polygon {
1896    pub vertices: Vec<Vec2>,
1898}
1899
1900#[cfg(feature = "alloc")]
1901impl Primitive2d for Polygon {}
1902
1903#[cfg(feature = "alloc")]
1904impl FromIterator<Vec2> for Polygon {
1905    fn from_iter<I: IntoIterator<Item = Vec2>>(iter: I) -> Self {
1906        Self {
1907            vertices: iter.into_iter().collect(),
1908        }
1909    }
1910}
1911
1912#[cfg(feature = "alloc")]
1913impl Polygon {
1914    pub fn new(vertices: impl IntoIterator<Item = Vec2>) -> Self {
1916        Self::from_iter(vertices)
1917    }
1918
1919    #[cfg(feature = "alloc")]
1924    pub fn is_simple(&self) -> bool {
1925        is_polygon_simple(&self.vertices)
1926    }
1927}
1928
1929#[cfg(feature = "alloc")]
1930impl From<ConvexPolygon> for Polygon {
1931    fn from(val: ConvexPolygon) -> Self {
1932        Polygon {
1933            vertices: val.vertices,
1934        }
1935    }
1936}
1937
1938#[cfg(feature = "alloc")]
1940#[derive(Clone, Debug, PartialEq)]
1941#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
1942#[cfg_attr(
1943    feature = "bevy_reflect",
1944    derive(Reflect),
1945    reflect(Debug, PartialEq, Clone)
1946)]
1947#[cfg_attr(
1948    all(feature = "serialize", feature = "bevy_reflect"),
1949    reflect(Serialize, Deserialize)
1950)]
1951pub struct ConvexPolygon {
1952    vertices: Vec<Vec2>,
1954}
1955
1956#[cfg(feature = "alloc")]
1957impl Primitive2d for ConvexPolygon {}
1958
1959#[cfg(feature = "alloc")]
1961#[derive(Error, Debug, Clone)]
1962pub enum ConvexPolygonError {
1963    #[error("The created polygon is not convex")]
1965    Concave,
1966}
1967
1968#[cfg(feature = "alloc")]
1969impl ConvexPolygon {
1970    fn triangle_winding_order(
1971        &self,
1972        a_index: usize,
1973        b_index: usize,
1974        c_index: usize,
1975    ) -> WindingOrder {
1976        let a = self.vertices[a_index];
1977        let b = self.vertices[b_index];
1978        let c = self.vertices[c_index];
1979        Triangle2d::new(a, b, c).winding_order()
1980    }
1981
1982    pub fn new(vertices: impl IntoIterator<Item = Vec2>) -> Result<Self, ConvexPolygonError> {
1988        let polygon = Self::new_unchecked(vertices);
1989        let len = polygon.vertices.len();
1990        let ref_winding_order = polygon.triangle_winding_order(len - 1, 0, 1);
1991        for i in 1..len {
1992            let winding_order = polygon.triangle_winding_order(i - 1, i, (i + 1) % len);
1993            if winding_order != ref_winding_order {
1994                return Err(ConvexPolygonError::Concave);
1995            }
1996        }
1997        Ok(polygon)
1998    }
1999
2000    #[inline(always)]
2003    pub fn new_unchecked(vertices: impl IntoIterator<Item = Vec2>) -> Self {
2004        Self {
2005            vertices: vertices.into_iter().collect(),
2006        }
2007    }
2008
2009    #[inline(always)]
2011    pub fn vertices(&self) -> &[Vec2] {
2012        &self.vertices
2013    }
2014}
2015
2016#[cfg(feature = "alloc")]
2017impl TryFrom<Polygon> for ConvexPolygon {
2018    type Error = ConvexPolygonError;
2019
2020    fn try_from(val: Polygon) -> Result<Self, Self::Error> {
2021        ConvexPolygon::new(val.vertices)
2022    }
2023}
2024
2025#[derive(Clone, Copy, Debug, PartialEq)]
2027#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
2028#[cfg_attr(
2029    feature = "bevy_reflect",
2030    derive(Reflect),
2031    reflect(Debug, PartialEq, Default, Clone)
2032)]
2033#[cfg_attr(
2034    all(feature = "serialize", feature = "bevy_reflect"),
2035    reflect(Serialize, Deserialize)
2036)]
2037pub struct RegularPolygon {
2038    pub circumcircle: Circle,
2040    pub sides: u32,
2042}
2043
2044impl Primitive2d for RegularPolygon {}
2045
2046impl Default for RegularPolygon {
2047    fn default() -> Self {
2049        Self {
2050            circumcircle: Circle { radius: 0.5 },
2051            sides: 6,
2052        }
2053    }
2054}
2055
2056impl RegularPolygon {
2057    #[inline(always)]
2064    pub const fn new(circumradius: f32, sides: u32) -> Self {
2065        assert!(
2066            circumradius.is_sign_positive(),
2067            "polygon has a negative radius"
2068        );
2069        assert!(sides > 2, "polygon has less than 3 sides");
2070
2071        Self {
2072            circumcircle: Circle {
2073                radius: circumradius,
2074            },
2075            sides,
2076        }
2077    }
2078
2079    #[inline(always)]
2082    pub const fn circumradius(&self) -> f32 {
2083        self.circumcircle.radius
2084    }
2085
2086    #[inline(always)]
2090    #[doc(alias = "apothem")]
2091    pub fn inradius(&self) -> f32 {
2092        self.circumradius() * ops::cos(PI / self.sides as f32)
2093    }
2094
2095    #[inline(always)]
2097    pub fn side_length(&self) -> f32 {
2098        2.0 * self.circumradius() * ops::sin(PI / self.sides as f32)
2099    }
2100
2101    #[inline(always)]
2106    pub const fn internal_angle_degrees(&self) -> f32 {
2107        (self.sides - 2) as f32 / self.sides as f32 * 180.0
2108    }
2109
2110    #[inline(always)]
2115    pub const fn internal_angle_radians(&self) -> f32 {
2116        (self.sides - 2) as f32 * PI / self.sides as f32
2117    }
2118
2119    #[inline(always)]
2124    pub const fn external_angle_degrees(&self) -> f32 {
2125        360.0 / self.sides as f32
2126    }
2127
2128    #[inline(always)]
2133    pub const fn external_angle_radians(&self) -> f32 {
2134        2.0 * PI / self.sides as f32
2135    }
2136
2137    pub fn vertices(self, rotation: f32) -> impl IntoIterator<Item = Vec2> {
2142        let start_angle = rotation + FRAC_PI_2;
2144        let step = core::f32::consts::TAU / self.sides as f32;
2145
2146        (0..self.sides).map(move |i| {
2147            let theta = start_angle + i as f32 * step;
2148            let (sin, cos) = ops::sin_cos(theta);
2149            Vec2::new(cos, sin) * self.circumcircle.radius
2150        })
2151    }
2152}
2153
2154impl Measured2d for RegularPolygon {
2155    #[inline(always)]
2157    fn area(&self) -> f32 {
2158        let angle: f32 = 2.0 * PI / (self.sides as f32);
2159        (self.sides as f32) * self.circumradius().squared() * ops::sin(angle) / 2.0
2160    }
2161
2162    #[inline(always)]
2165    fn perimeter(&self) -> f32 {
2166        self.sides as f32 * self.side_length()
2167    }
2168}
2169
2170#[derive(Clone, Copy, Debug, PartialEq)]
2174#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
2175#[cfg_attr(
2176    feature = "bevy_reflect",
2177    derive(Reflect),
2178    reflect(Debug, PartialEq, Default, Clone)
2179)]
2180#[cfg_attr(
2181    all(feature = "serialize", feature = "bevy_reflect"),
2182    reflect(Serialize, Deserialize)
2183)]
2184#[doc(alias = "stadium", alias = "pill")]
2185pub struct Capsule2d {
2186    pub radius: f32,
2188    pub half_length: f32,
2190}
2191
2192impl Primitive2d for Capsule2d {}
2193
2194impl Default for Capsule2d {
2195    fn default() -> Self {
2198        Self {
2199            radius: 0.5,
2200            half_length: 0.5,
2201        }
2202    }
2203}
2204
2205impl Capsule2d {
2206    pub const fn new(radius: f32, length: f32) -> Self {
2208        Self {
2209            radius,
2210            half_length: length / 2.0,
2211        }
2212    }
2213
2214    #[inline]
2216    pub const fn to_inner_rectangle(&self) -> Rectangle {
2217        Rectangle::new(self.radius * 2.0, self.half_length * 2.0)
2218    }
2219}
2220
2221impl Measured2d for Capsule2d {
2222    #[inline]
2224    fn area(&self) -> f32 {
2225        PI * self.radius.squared() + self.to_inner_rectangle().area()
2227    }
2228
2229    #[inline]
2231    fn perimeter(&self) -> f32 {
2232        2.0 * PI * self.radius + 4.0 * self.half_length
2234    }
2235}
2236
2237#[cfg(test)]
2238mod tests {
2239    use super::*;
2242    use approx::{assert_abs_diff_eq, assert_relative_eq};
2243
2244    #[test]
2245    fn rectangle_closest_point() {
2246        let rectangle = Rectangle::new(2.0, 2.0);
2247        assert_eq!(rectangle.closest_point(Vec2::X * 10.0), Vec2::X);
2248        assert_eq!(rectangle.closest_point(Vec2::NEG_ONE * 10.0), Vec2::NEG_ONE);
2249        assert_eq!(
2250            rectangle.closest_point(Vec2::new(0.25, 0.1)),
2251            Vec2::new(0.25, 0.1)
2252        );
2253    }
2254
2255    #[test]
2256    fn circle_closest_point() {
2257        let circle = Circle { radius: 1.0 };
2258        assert_eq!(circle.closest_point(Vec2::X * 10.0), Vec2::X);
2259        assert_eq!(
2260            circle.closest_point(Vec2::NEG_ONE * 10.0),
2261            Vec2::NEG_ONE.normalize()
2262        );
2263        assert_eq!(
2264            circle.closest_point(Vec2::new(0.25, 0.1)),
2265            Vec2::new(0.25, 0.1)
2266        );
2267    }
2268
2269    #[test]
2270    fn annulus_closest_point() {
2271        let annulus = Annulus::new(1.5, 2.0);
2272        assert_eq!(annulus.closest_point(Vec2::X * 10.0), Vec2::X * 2.0);
2273        assert_eq!(
2274            annulus.closest_point(Vec2::NEG_ONE),
2275            Vec2::NEG_ONE.normalize() * 1.5
2276        );
2277        assert_eq!(
2278            annulus.closest_point(Vec2::new(1.55, 0.85)),
2279            Vec2::new(1.55, 0.85)
2280        );
2281    }
2282
2283    #[test]
2284    fn rhombus_closest_point() {
2285        let rhombus = Rhombus::new(2.0, 1.0);
2286        assert_eq!(rhombus.closest_point(Vec2::X * 10.0), Vec2::X);
2287        assert_eq!(
2288            rhombus.closest_point(Vec2::NEG_ONE * 0.2),
2289            Vec2::NEG_ONE * 0.2
2290        );
2291        assert_eq!(
2292            rhombus.closest_point(Vec2::new(-0.55, 0.35)),
2293            Vec2::new(-0.5, 0.25)
2294        );
2295
2296        let rhombus = Rhombus::new(0.0, 0.0);
2297        assert_eq!(rhombus.closest_point(Vec2::X * 10.0), Vec2::ZERO);
2298        assert_eq!(rhombus.closest_point(Vec2::NEG_ONE * 0.2), Vec2::ZERO);
2299        assert_eq!(rhombus.closest_point(Vec2::new(-0.55, 0.35)), Vec2::ZERO);
2300    }
2301
2302    #[test]
2303    fn segment_closest_point() {
2304        assert_eq!(
2305            Segment2d::new(Vec2::new(0.0, 0.0), Vec2::new(3.0, 0.0))
2306                .closest_point(Vec2::new(1.0, 6.0)),
2307            Vec2::new(1.0, 0.0)
2308        );
2309
2310        let segments = [
2311            Segment2d::new(Vec2::new(0.0, 0.0), Vec2::new(0.0, 0.0)),
2312            Segment2d::new(Vec2::new(0.0, 0.0), Vec2::new(1.0, 0.0)),
2313            Segment2d::new(Vec2::new(1.0, 0.0), Vec2::new(0.0, 1.0)),
2314            Segment2d::new(Vec2::new(1.0, 0.0), Vec2::new(1.0, 5.0 * f32::EPSILON)),
2315        ];
2316        let points = [
2317            Vec2::new(0.0, 0.0),
2318            Vec2::new(1.0, 0.0),
2319            Vec2::new(-1.0, 1.0),
2320            Vec2::new(1.0, 1.0),
2321            Vec2::new(-1.0, 0.0),
2322            Vec2::new(5.0, -1.0),
2323            Vec2::new(1.0, f32::EPSILON),
2324        ];
2325
2326        for point in points.iter() {
2327            for segment in segments.iter() {
2328                let closest = segment.closest_point(*point);
2329                assert!(
2330                    point.distance_squared(closest) <= point.distance_squared(segment.point1()),
2331                    "Closest point must always be at least as close as either vertex."
2332                );
2333                assert!(
2334                    point.distance_squared(closest) <= point.distance_squared(segment.point2()),
2335                    "Closest point must always be at least as close as either vertex."
2336                );
2337                assert!(
2338                    point.distance_squared(closest) <= point.distance_squared(segment.center()),
2339                    "Closest point must always be at least as close as the center."
2340                );
2341                let closest_to_closest = segment.closest_point(closest);
2342                assert_relative_eq!(closest_to_closest, closest);
2344            }
2345        }
2346    }
2347
2348    #[test]
2349    fn circle_math() {
2350        let circle = Circle { radius: 3.0 };
2351        assert_eq!(circle.diameter(), 6.0, "incorrect diameter");
2352        assert_eq!(circle.area(), 28.274334, "incorrect area");
2353        assert_eq!(circle.perimeter(), 18.849556, "incorrect perimeter");
2354    }
2355
2356    #[test]
2357    fn capsule_math() {
2358        let capsule = Capsule2d::new(2.0, 9.0);
2359        assert_eq!(
2360            capsule.to_inner_rectangle(),
2361            Rectangle::new(4.0, 9.0),
2362            "rectangle wasn't created correctly from a capsule"
2363        );
2364        assert_eq!(capsule.area(), 48.566371, "incorrect area");
2365        assert_eq!(capsule.perimeter(), 30.566371, "incorrect perimeter");
2366    }
2367
2368    #[test]
2369    fn annulus_math() {
2370        let annulus = Annulus::new(2.5, 3.5);
2371        assert_eq!(annulus.diameter(), 7.0, "incorrect diameter");
2372        assert_eq!(annulus.thickness(), 1.0, "incorrect thickness");
2373        assert_eq!(annulus.area(), 18.849556, "incorrect area");
2374        assert_eq!(annulus.perimeter(), 37.699112, "incorrect perimeter");
2375    }
2376
2377    #[test]
2378    fn rhombus_math() {
2379        let rhombus = Rhombus::new(3.0, 4.0);
2380        assert_eq!(rhombus.area(), 6.0, "incorrect area");
2381        assert_eq!(rhombus.perimeter(), 10.0, "incorrect perimeter");
2382        assert_eq!(rhombus.side(), 2.5, "incorrect side");
2383        assert_eq!(rhombus.inradius(), 1.2, "incorrect inradius");
2384        assert_eq!(rhombus.circumradius(), 2.0, "incorrect circumradius");
2385        let rhombus = Rhombus::new(0.0, 0.0);
2386        assert_eq!(rhombus.area(), 0.0, "incorrect area");
2387        assert_eq!(rhombus.perimeter(), 0.0, "incorrect perimeter");
2388        assert_eq!(rhombus.side(), 0.0, "incorrect side");
2389        assert_eq!(rhombus.inradius(), 0.0, "incorrect inradius");
2390        assert_eq!(rhombus.circumradius(), 0.0, "incorrect circumradius");
2391        let rhombus = Rhombus::from_side(core::f32::consts::SQRT_2);
2392        assert_abs_diff_eq!(rhombus.half_diagonals, Vec2::new(1.0, 1.0));
2393        assert_abs_diff_eq!(
2394            rhombus.half_diagonals,
2395            Rhombus::from_inradius(FRAC_1_SQRT_2).half_diagonals
2396        );
2397    }
2398
2399    #[test]
2400    fn ellipse_math() {
2401        let ellipse = Ellipse::new(3.0, 1.0);
2402        assert_eq!(ellipse.area(), 9.424778, "incorrect area");
2403
2404        assert_eq!(ellipse.eccentricity(), 0.94280905, "incorrect eccentricity");
2405
2406        let line = Ellipse::new(1., 0.);
2407        assert_eq!(line.eccentricity(), 1., "incorrect line eccentricity");
2408
2409        let circle = Ellipse::new(2., 2.);
2410        assert_eq!(circle.eccentricity(), 0., "incorrect circle eccentricity");
2411    }
2412
2413    #[test]
2414    fn ellipse_perimeter() {
2415        let circle = Ellipse::new(1., 1.);
2416        assert_relative_eq!(circle.perimeter(), 6.2831855);
2417
2418        let line = Ellipse::new(75_000., 0.5);
2419        assert_relative_eq!(line.perimeter(), 300_000.);
2420
2421        let ellipse = Ellipse::new(0.5, 2.);
2422        assert_relative_eq!(ellipse.perimeter(), 8.578423);
2423
2424        let ellipse = Ellipse::new(5., 3.);
2425        assert_relative_eq!(ellipse.perimeter(), 25.526999);
2426    }
2427
2428    #[test]
2429    fn triangle_math() {
2430        let triangle = Triangle2d::new(
2431            Vec2::new(-2.0, -1.0),
2432            Vec2::new(1.0, 4.0),
2433            Vec2::new(7.0, 0.0),
2434        );
2435        assert_eq!(triangle.area(), 21.0, "incorrect area");
2436        assert_eq!(triangle.perimeter(), 22.097439, "incorrect perimeter");
2437
2438        let degenerate_triangle =
2439            Triangle2d::new(Vec2::new(-1., 0.), Vec2::new(0., 0.), Vec2::new(1., 0.));
2440        assert!(degenerate_triangle.is_degenerate());
2441
2442        let acute_triangle =
2443            Triangle2d::new(Vec2::new(-1., 0.), Vec2::new(1., 0.), Vec2::new(0., 5.));
2444        let obtuse_triangle =
2445            Triangle2d::new(Vec2::new(-1., 0.), Vec2::new(1., 0.), Vec2::new(0., 0.5));
2446
2447        assert!(acute_triangle.is_acute());
2448        assert!(!acute_triangle.is_obtuse());
2449        assert!(!obtuse_triangle.is_acute());
2450        assert!(obtuse_triangle.is_obtuse());
2451    }
2452
2453    #[test]
2454    fn triangle_winding_order() {
2455        let mut cw_triangle = Triangle2d::new(
2456            Vec2::new(0.0, 2.0),
2457            Vec2::new(-0.5, -1.2),
2458            Vec2::new(-1.0, -1.0),
2459        );
2460        assert_eq!(cw_triangle.winding_order(), WindingOrder::Clockwise);
2461
2462        let ccw_triangle = Triangle2d::new(
2463            Vec2::new(-1.0, -1.0),
2464            Vec2::new(-0.5, -1.2),
2465            Vec2::new(0.0, 2.0),
2466        );
2467        assert_eq!(ccw_triangle.winding_order(), WindingOrder::CounterClockwise);
2468
2469        cw_triangle.reverse();
2472        assert_eq!(cw_triangle, ccw_triangle);
2473
2474        let invalid_triangle = Triangle2d::new(
2475            Vec2::new(0.0, 2.0),
2476            Vec2::new(0.0, -1.0),
2477            Vec2::new(0.0, -1.2),
2478        );
2479        assert_eq!(invalid_triangle.winding_order(), WindingOrder::Invalid);
2480    }
2481
2482    #[test]
2483    fn rectangle_math() {
2484        let rectangle = Rectangle::new(3.0, 7.0);
2485        assert_eq!(
2486            rectangle,
2487            Rectangle::from_corners(Vec2::new(-1.5, -3.5), Vec2::new(1.5, 3.5))
2488        );
2489        assert_eq!(rectangle.area(), 21.0, "incorrect area");
2490        assert_eq!(rectangle.perimeter(), 20.0, "incorrect perimeter");
2491    }
2492
2493    #[test]
2494    fn regular_polygon_math() {
2495        let polygon = RegularPolygon::new(3.0, 6);
2496        assert_eq!(polygon.inradius(), 2.598076, "incorrect inradius");
2497        assert_eq!(polygon.side_length(), 3.0, "incorrect side length");
2498        assert_relative_eq!(polygon.area(), 23.38268, epsilon = 0.00001);
2499        assert_eq!(polygon.perimeter(), 18.0, "incorrect perimeter");
2500        assert_eq!(
2501            polygon.internal_angle_degrees(),
2502            120.0,
2503            "incorrect internal angle"
2504        );
2505        assert_eq!(
2506            polygon.internal_angle_radians(),
2507            120_f32.to_radians(),
2508            "incorrect internal angle"
2509        );
2510        assert_eq!(
2511            polygon.external_angle_degrees(),
2512            60.0,
2513            "incorrect external angle"
2514        );
2515        assert_eq!(
2516            polygon.external_angle_radians(),
2517            60_f32.to_radians(),
2518            "incorrect external angle"
2519        );
2520    }
2521
2522    #[test]
2523    fn triangle_circumcenter() {
2524        let triangle = Triangle2d::new(
2525            Vec2::new(10.0, 2.0),
2526            Vec2::new(-5.0, -3.0),
2527            Vec2::new(2.0, -1.0),
2528        );
2529        let (Circle { radius }, circumcenter) = triangle.circumcircle();
2530
2531        assert_eq!(radius, 98.34887);
2533        assert_eq!(circumcenter, Vec2::new(-28.5, 92.5));
2534    }
2535
2536    #[test]
2537    fn regular_polygon_vertices() {
2538        let polygon = RegularPolygon::new(1.0, 4);
2539
2540        let mut vertices = polygon.vertices(0.0).into_iter();
2542        assert!((vertices.next().unwrap() - Vec2::Y).length() < 1e-7);
2543
2544        let mut rotated_vertices = polygon.vertices(core::f32::consts::FRAC_PI_4).into_iter();
2546
2547        let side_distance = FRAC_1_SQRT_2;
2549        assert!(
2550            (rotated_vertices.next().unwrap() - Vec2::new(-side_distance, side_distance)).length()
2551                < 1e-7,
2552        );
2553    }
2554}