1use crate::{
2 Capsule2d, Circle, CircularSegment, Primitive2d, Rectangle, RegularPolygon, Rhombus, Triangle2d,
3};
4use bevy_math::{ops, Vec2};
5
6pub trait Inset: Primitive2d {
12 fn inset(self, distance: f32) -> Self;
20}
21
22impl Inset for Circle {
23 fn inset(mut self, distance: f32) -> Self {
24 self.radius -= distance;
25 self
26 }
27}
28
29impl Inset for Triangle2d {
30 fn inset(self, distance: f32) -> Self {
31 fn find_inset_point(a: Vec2, b: Vec2, c: Vec2, distance: f32) -> Vec2 {
32 let unit_vector_ab = (b - a).normalize();
33 let unit_vector_ac = (c - a).normalize();
34 let half_angle_bac = unit_vector_ab.angle_to(unit_vector_ac) / 2.0;
35 let mean = (unit_vector_ab + unit_vector_ac) / 2.0;
36 let direction = mean.normalize();
37 let magnitude = distance / ops::sin(half_angle_bac);
38 a + direction * magnitude
39 }
40
41 let [a, b, c] = self.vertices;
42
43 let new_a = find_inset_point(a, b, c, distance);
44 let new_b = find_inset_point(b, c, a, distance);
45 let new_c = find_inset_point(c, a, b, distance);
46
47 Self::new(new_a, new_b, new_c)
48 }
49}
50
51impl Inset for Rhombus {
52 fn inset(mut self, distance: f32) -> Self {
53 let [half_width, half_height] = self.half_diagonals.into();
54 let angle = ops::atan(half_height / half_width);
55 let x_offset = distance / ops::sin(angle);
56 let y_offset = distance / ops::cos(angle);
57 self.half_diagonals -= Vec2::new(x_offset, y_offset);
58 self
59 }
60}
61
62impl Inset for Capsule2d {
63 fn inset(mut self, distance: f32) -> Self {
64 self.radius -= distance;
65 self
66 }
67}
68
69impl Inset for Rectangle {
70 fn inset(mut self, distance: f32) -> Self {
71 self.half_size -= Vec2::splat(distance);
72 self
73 }
74}
75
76impl Inset for CircularSegment {
77 fn inset(self, distance: f32) -> Self {
78 let old_arc = self.arc;
79 let radius = old_arc.radius - distance;
80 let apothem = old_arc.apothem() + distance;
81 let half_angle = ops::acos(apothem / radius);
83 Self::new(radius, half_angle)
84 }
85}
86
87impl Inset for RegularPolygon {
88 fn inset(mut self, distance: f32) -> Self {
89 let half_angle = self.internal_angle_radians() / 2.0;
90 let offset = distance / ops::sin(half_angle);
91 self.circumcircle.radius -= offset;
92 self
93 }
94}