Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extrusion #13270

Merged
merged 9 commits into from
May 7, 2024
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
196 changes: 104 additions & 92 deletions crates/bevy_math/src/primitives/dim2.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::f32::consts::PI;

use super::{Primitive2d, WindingOrder};
use super::{Measured2d, Primitive2d, WindingOrder};
use crate::{Dir2, Vec2};

/// A circle primitive
Expand Down Expand Up @@ -32,19 +32,6 @@ impl Circle {
2.0 * self.radius
}

/// Get the area of the circle
#[inline(always)]
pub fn area(&self) -> f32 {
PI * self.radius.powi(2)
}

/// Get the perimeter or circumference of the circle
#[inline(always)]
#[doc(alias = "circumference")]
pub fn perimeter(&self) -> f32 {
2.0 * PI * self.radius
}

/// Finds the point on the circle that is closest to the given `point`.
///
/// If the point is outside the circle, the returned point will be on the perimeter of the circle.
Expand All @@ -65,6 +52,21 @@ impl Circle {
}
}

impl Measured2d for Circle {
/// Get the area of the circle
#[inline(always)]
fn area(&self) -> f32 {
PI * self.radius.powi(2)
}

/// Get the perimeter or circumference of the circle
#[inline(always)]
#[doc(alias = "circumference")]
fn perimeter(&self) -> f32 {
2.0 * PI * self.radius
}
}

/// An ellipse primitive
#[derive(Clone, Copy, Debug, PartialEq)]
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
Expand Down Expand Up @@ -129,11 +131,31 @@ impl Ellipse {
(a * a - b * b).sqrt()
}

/// Returns the length of the semi-major axis. This corresponds to the longest radius of the ellipse.
#[inline(always)]
pub fn semi_major(&self) -> f32 {
self.half_size.max_element()
}

/// Returns the length of the semi-minor axis. This corresponds to the shortest radius of the ellipse.
#[inline(always)]
pub fn semi_minor(&self) -> f32 {
self.half_size.min_element()
}
}

impl Measured2d for Ellipse {
/// Get the area of the ellipse
#[inline(always)]
fn area(&self) -> f32 {
PI * self.half_size.x * self.half_size.y
}

#[inline(always)]
/// Get an approximation for the perimeter or circumference of the ellipse.
///
/// The approximation is reasonably precise with a relative error less than 0.007%, getting more precise as the eccentricity of the ellipse decreases.
pub fn perimeter(&self) -> f32 {
fn perimeter(&self) -> f32 {
let a = self.semi_major();
let b = self.semi_minor();

Expand Down Expand Up @@ -184,24 +206,6 @@ impl Ellipse {
.map(|i| BINOMIAL_COEFFICIENTS[i] * h.powi(i as i32))
.sum::<f32>()
}

/// Returns the length of the semi-major axis. This corresponds to the longest radius of the ellipse.
#[inline(always)]
pub fn semi_major(&self) -> f32 {
self.half_size.max_element()
}

/// Returns the length of the semi-minor axis. This corresponds to the shortest radius of the ellipse.
#[inline(always)]
pub fn semi_minor(&self) -> f32 {
self.half_size.min_element()
}

/// Get the area of the ellipse
#[inline(always)]
pub fn area(&self) -> f32 {
PI * self.half_size.x * self.half_size.y
}
}

/// A primitive shape formed by the region between two circles, also known as a ring.
Expand Down Expand Up @@ -248,20 +252,6 @@ impl Annulus {
self.outer_circle.radius - self.inner_circle.radius
}

/// Get the area of the annulus
#[inline(always)]
pub fn area(&self) -> f32 {
PI * (self.outer_circle.radius.powi(2) - self.inner_circle.radius.powi(2))
}

/// Get the perimeter or circumference of the annulus,
/// which is the sum of the perimeters of the inner and outer circles.
#[inline(always)]
#[doc(alias = "circumference")]
pub fn perimeter(&self) -> f32 {
2.0 * PI * (self.outer_circle.radius + self.inner_circle.radius)
}

/// Finds the point on the annulus that is closest to the given `point`:
///
/// - If the point is outside of the annulus completely, the returned point will be on the outer perimeter.
Expand Down Expand Up @@ -290,6 +280,22 @@ impl Annulus {
}
}

impl Measured2d for Annulus {
/// Get the area of the annulus
#[inline(always)]
fn area(&self) -> f32 {
PI * (self.outer_circle.radius.powi(2) - self.inner_circle.radius.powi(2))
}

/// Get the perimeter or circumference of the annulus,
/// which is the sum of the perimeters of the inner and outer circles.
#[inline(always)]
#[doc(alias = "circumference")]
fn perimeter(&self) -> f32 {
2.0 * PI * (self.outer_circle.radius + self.inner_circle.radius)
}
}

/// An unbounded plane in 2D space. It forms a separating surface through the origin,
/// stretching infinitely far
#[derive(Clone, Copy, Debug, PartialEq)]
Expand Down Expand Up @@ -471,25 +477,6 @@ impl Triangle2d {
}
}

/// Get the area of the triangle
#[inline(always)]
pub fn area(&self) -> f32 {
let [a, b, c] = self.vertices;
(a.x * (b.y - c.y) + b.x * (c.y - a.y) + c.x * (a.y - b.y)).abs() / 2.0
}

/// Get the perimeter of the triangle
#[inline(always)]
pub fn perimeter(&self) -> f32 {
let [a, b, c] = self.vertices;

let ab = a.distance(b);
let bc = b.distance(c);
let ca = c.distance(a);

ab + bc + ca
}

/// Get the [`WindingOrder`] of the triangle
#[inline(always)]
#[doc(alias = "orientation")]
Expand Down Expand Up @@ -548,6 +535,27 @@ impl Triangle2d {
}
}

impl Measured2d for Triangle2d {
/// Get the area of the triangle
#[inline(always)]
fn area(&self) -> f32 {
let [a, b, c] = self.vertices;
(a.x * (b.y - c.y) + b.x * (c.y - a.y) + c.x * (a.y - b.y)).abs() / 2.0
}

/// Get the perimeter of the triangle
#[inline(always)]
fn perimeter(&self) -> f32 {
let [a, b, c] = self.vertices;

let ab = a.distance(b);
let bc = b.distance(c);
let ca = c.distance(a);

ab + bc + ca
}
}

/// A rectangle primitive
#[derive(Clone, Copy, Debug, PartialEq)]
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
Expand Down Expand Up @@ -605,18 +613,6 @@ impl Rectangle {
2.0 * self.half_size
}

/// Get the area of the rectangle
#[inline(always)]
pub fn area(&self) -> f32 {
4.0 * self.half_size.x * self.half_size.y
}

/// Get the perimeter of the rectangle
#[inline(always)]
pub fn perimeter(&self) -> f32 {
4.0 * (self.half_size.x + self.half_size.y)
}

/// Finds the point on the rectangle that is closest to the given `point`.
///
/// If the point is outside the rectangle, the returned point will be on the perimeter of the rectangle.
Expand All @@ -628,6 +624,20 @@ impl Rectangle {
}
}

impl Measured2d for Rectangle {
/// Get the area of the rectangle
#[inline(always)]
fn area(&self) -> f32 {
4.0 * self.half_size.x * self.half_size.y
}

/// Get the perimeter of the rectangle
#[inline(always)]
fn perimeter(&self) -> f32 {
4.0 * (self.half_size.x + self.half_size.y)
}
}

/// A polygon with N vertices.
///
/// For a version without generics: [`BoxedPolygon`]
Expand Down Expand Up @@ -749,20 +759,6 @@ impl RegularPolygon {
2.0 * self.circumradius() * (PI / self.sides as f32).sin()
}

/// Get the area of the regular polygon
#[inline(always)]
pub fn area(&self) -> f32 {
let angle: f32 = 2.0 * PI / (self.sides as f32);
(self.sides as f32) * self.circumradius().powi(2) * angle.sin() / 2.0
}

/// Get the perimeter of the regular polygon.
/// This is the sum of its sides
#[inline(always)]
pub fn perimeter(&self) -> f32 {
self.sides as f32 * self.side_length()
}

/// Get the internal angle of the regular polygon in degrees.
///
/// This is the angle formed by two adjacent sides with points
Expand Down Expand Up @@ -816,6 +812,22 @@ impl RegularPolygon {
}
}

impl Measured2d for RegularPolygon {
/// Get the area of the regular polygon
#[inline(always)]
fn area(&self) -> f32 {
let angle: f32 = 2.0 * PI / (self.sides as f32);
(self.sides as f32) * self.circumradius().powi(2) * angle.sin() / 2.0
}

/// Get the perimeter of the regular polygon.
/// This is the sum of its sides
#[inline(always)]
fn perimeter(&self) -> f32 {
self.sides as f32 * self.side_length()
}
}

/// A 2D capsule primitive, also known as a stadium or pill shape.
///
/// A two-dimensional capsule is defined as a neighborhood of points at a distance (radius) from a line
Expand Down
Loading