Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_math/src/primitives/inset.rs
7223 views
1
use crate::{
2
ops,
3
primitives::{
4
Capsule2d, Circle, CircularSegment, Primitive2d, Rectangle, RegularPolygon, Rhombus,
5
Triangle2d,
6
},
7
Vec2,
8
};
9
10
/// A primitive that can be resized uniformly.
11
///
12
/// See documentation on [`Inset::inset`].
13
///
14
/// See also [`ToRing`](crate::primitives::ToRing).
15
pub trait Inset: Primitive2d {
16
/// Create a new version of this primitive that is resized uniformly.
17
/// That is, it resizes the shape inwards such that for the lines between vertices,
18
/// it creates new parallel lines that are `distance` inwards from the original lines.
19
///
20
/// This is useful for creating smaller shapes or making outlines of `distance` thickness with [`Ring`](crate::primitives::Ring).
21
///
22
/// See also [`ToRing::to_ring`](crate::primitives::ToRing::to_ring)
23
fn inset(self, distance: f32) -> Self;
24
}
25
26
impl Inset for Circle {
27
fn inset(mut self, distance: f32) -> Self {
28
self.radius -= distance;
29
self
30
}
31
}
32
33
impl Inset for Triangle2d {
34
fn inset(self, distance: f32) -> Self {
35
fn find_inset_point(a: Vec2, b: Vec2, c: Vec2, distance: f32) -> Vec2 {
36
let unit_vector_ab = (b - a).normalize();
37
let unit_vector_ac = (c - a).normalize();
38
let half_angle_bac = unit_vector_ab.angle_to(unit_vector_ac) / 2.0;
39
let mean = (unit_vector_ab + unit_vector_ac) / 2.0;
40
let direction = mean.normalize();
41
let magnitude = distance / ops::sin(half_angle_bac);
42
a + direction * magnitude
43
}
44
45
let [a, b, c] = self.vertices;
46
47
let new_a = find_inset_point(a, b, c, distance);
48
let new_b = find_inset_point(b, c, a, distance);
49
let new_c = find_inset_point(c, a, b, distance);
50
51
Self::new(new_a, new_b, new_c)
52
}
53
}
54
55
impl Inset for Rhombus {
56
fn inset(mut self, distance: f32) -> Self {
57
let [half_width, half_height] = self.half_diagonals.into();
58
let angle = ops::atan(half_height / half_width);
59
let x_offset = distance / ops::sin(angle);
60
let y_offset = distance / ops::cos(angle);
61
self.half_diagonals -= Vec2::new(x_offset, y_offset);
62
self
63
}
64
}
65
66
impl Inset for Capsule2d {
67
fn inset(mut self, distance: f32) -> Self {
68
self.radius -= distance;
69
self
70
}
71
}
72
73
impl Inset for Rectangle {
74
fn inset(mut self, distance: f32) -> Self {
75
self.half_size -= Vec2::splat(distance);
76
self
77
}
78
}
79
80
impl Inset for CircularSegment {
81
fn inset(self, distance: f32) -> Self {
82
let old_arc = self.arc;
83
let radius = old_arc.radius - distance;
84
let apothem = old_arc.apothem() + distance;
85
// https://en.wikipedia.org/wiki/Circular_segment
86
let half_angle = ops::acos(apothem / radius);
87
Self::new(radius, half_angle)
88
}
89
}
90
91
impl Inset for RegularPolygon {
92
fn inset(mut self, distance: f32) -> Self {
93
let half_angle = self.internal_angle_radians() / 2.0;
94
let offset = distance / ops::sin(half_angle);
95
self.circumcircle.radius -= offset;
96
self
97
}
98
}
99
100