Path: blob/main/crates/bevy_math/src/primitives/inset.rs
7223 views
use crate::{1ops,2primitives::{3Capsule2d, Circle, CircularSegment, Primitive2d, Rectangle, RegularPolygon, Rhombus,4Triangle2d,5},6Vec2,7};89/// A primitive that can be resized uniformly.10///11/// See documentation on [`Inset::inset`].12///13/// See also [`ToRing`](crate::primitives::ToRing).14pub trait Inset: Primitive2d {15/// Create a new version of this primitive that is resized uniformly.16/// That is, it resizes the shape inwards such that for the lines between vertices,17/// it creates new parallel lines that are `distance` inwards from the original lines.18///19/// This is useful for creating smaller shapes or making outlines of `distance` thickness with [`Ring`](crate::primitives::Ring).20///21/// See also [`ToRing::to_ring`](crate::primitives::ToRing::to_ring)22fn inset(self, distance: f32) -> Self;23}2425impl Inset for Circle {26fn inset(mut self, distance: f32) -> Self {27self.radius -= distance;28self29}30}3132impl Inset for Triangle2d {33fn inset(self, distance: f32) -> Self {34fn find_inset_point(a: Vec2, b: Vec2, c: Vec2, distance: f32) -> Vec2 {35let unit_vector_ab = (b - a).normalize();36let unit_vector_ac = (c - a).normalize();37let half_angle_bac = unit_vector_ab.angle_to(unit_vector_ac) / 2.0;38let mean = (unit_vector_ab + unit_vector_ac) / 2.0;39let direction = mean.normalize();40let magnitude = distance / ops::sin(half_angle_bac);41a + direction * magnitude42}4344let [a, b, c] = self.vertices;4546let new_a = find_inset_point(a, b, c, distance);47let new_b = find_inset_point(b, c, a, distance);48let new_c = find_inset_point(c, a, b, distance);4950Self::new(new_a, new_b, new_c)51}52}5354impl Inset for Rhombus {55fn inset(mut self, distance: f32) -> Self {56let [half_width, half_height] = self.half_diagonals.into();57let angle = ops::atan(half_height / half_width);58let x_offset = distance / ops::sin(angle);59let y_offset = distance / ops::cos(angle);60self.half_diagonals -= Vec2::new(x_offset, y_offset);61self62}63}6465impl Inset for Capsule2d {66fn inset(mut self, distance: f32) -> Self {67self.radius -= distance;68self69}70}7172impl Inset for Rectangle {73fn inset(mut self, distance: f32) -> Self {74self.half_size -= Vec2::splat(distance);75self76}77}7879impl Inset for CircularSegment {80fn inset(self, distance: f32) -> Self {81let old_arc = self.arc;82let radius = old_arc.radius - distance;83let apothem = old_arc.apothem() + distance;84// https://en.wikipedia.org/wiki/Circular_segment85let half_angle = ops::acos(apothem / radius);86Self::new(radius, half_angle)87}88}8990impl Inset for RegularPolygon {91fn inset(mut self, distance: f32) -> Self {92let half_angle = self.internal_angle_radians() / 2.0;93let offset = distance / ops::sin(half_angle);94self.circumcircle.radius -= offset;95self96}97}9899100