-
-
Notifications
You must be signed in to change notification settings - Fork 3.9k
Add Tetrahedron
primitive to bevy_math::primitives
#12688
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
Changes from all commits
9585bf7
d33340c
adcf691
bbc0eff
becf9af
f055624
95d15e8
04538fe
54bfc4b
9769517
cc5b52f
c9e36a4
27043bc
d98c958
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -3,7 +3,7 @@ use std::f32::consts::{FRAC_PI_3, PI}; | |||||||||||||||||
use super::{Circle, Primitive3d}; | ||||||||||||||||||
use crate::{ | ||||||||||||||||||
bounding::{Aabb3d, Bounded3d, BoundingSphere}, | ||||||||||||||||||
Dir3, InvalidDirectionError, Quat, Vec3, | ||||||||||||||||||
Dir3, InvalidDirectionError, Mat3, Quat, Vec3, | ||||||||||||||||||
}; | ||||||||||||||||||
|
||||||||||||||||||
/// A sphere primitive | ||||||||||||||||||
|
@@ -823,6 +823,86 @@ impl Bounded3d for Triangle3d { | |||||||||||||||||
} | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
/// A tetrahedron primitive. | ||||||||||||||||||
#[derive(Clone, Copy, Debug, PartialEq)] | ||||||||||||||||||
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] | ||||||||||||||||||
pub struct Tetrahedron { | ||||||||||||||||||
/// The vertices of the tetrahedron. | ||||||||||||||||||
pub vertices: [Vec3; 4], | ||||||||||||||||||
} | ||||||||||||||||||
impl Primitive3d for Tetrahedron {} | ||||||||||||||||||
|
||||||||||||||||||
impl Default for Tetrahedron { | ||||||||||||||||||
/// Returns the default [`Tetrahedron`] with the vertices | ||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||
/// `[0.0, 0.5, 0.0]`, `[-0.5, -0.5, 0.0]`, `[0.5, -0.5, 0.0]` and `[0.0, 0.0, 0.5]`. | ||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||
fn default() -> Self { | ||||||||||||||||||
Self { | ||||||||||||||||||
vertices: [ | ||||||||||||||||||
Vec3::new(0.0, 0.5, 0.0), | ||||||||||||||||||
Vec3::new(-0.5, -0.5, 0.0), | ||||||||||||||||||
Vec3::new(0.5, -0.5, 0.0), | ||||||||||||||||||
Vec3::new(0.0, 0.0, 0.5), | ||||||||||||||||||
Comment on lines
+841
to
+844
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm really confused as to why this is the default tetrahedron. I would expect a regular tetrahedron, centered at the origin. Or at least one that contains the origin. This one satisfies none of those properties. Can we have it be this instead?
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this was chosen so that, in particular, its base is the Default There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What @mweatherley said, in practice it's just I was thinking, if we go with your suggestion would it be possible to keep the tetrahedron upright? I think that's how people typically imagine this shape to look like. |
||||||||||||||||||
], | ||||||||||||||||||
} | ||||||||||||||||||
} | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
impl Tetrahedron { | ||||||||||||||||||
/// Create a new [`Tetrahedron`] from points `a`, `b`, `c` and `d`. | ||||||||||||||||||
#[inline(always)] | ||||||||||||||||||
pub fn new(a: Vec3, b: Vec3, c: Vec3, d: Vec3) -> Self { | ||||||||||||||||||
Self { | ||||||||||||||||||
vertices: [a, b, c, d], | ||||||||||||||||||
} | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
/// Get the surface area of the tetrahedron. | ||||||||||||||||||
#[inline(always)] | ||||||||||||||||||
pub fn area(&self) -> f32 { | ||||||||||||||||||
let [a, b, c, d] = self.vertices; | ||||||||||||||||||
let ab = b - a; | ||||||||||||||||||
let ac = c - a; | ||||||||||||||||||
let ad = d - a; | ||||||||||||||||||
let bc = c - b; | ||||||||||||||||||
let bd = d - b; | ||||||||||||||||||
(ab.cross(ac).length() | ||||||||||||||||||
+ ab.cross(ad).length() | ||||||||||||||||||
+ ac.cross(ad).length() | ||||||||||||||||||
+ bc.cross(bd).length()) | ||||||||||||||||||
/ 2.0 | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
/// Get the volume of the tetrahedron. | ||||||||||||||||||
#[inline(always)] | ||||||||||||||||||
pub fn volume(&self) -> f32 { | ||||||||||||||||||
self.signed_volume().abs() | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
/// Get the signed volume of the tetrahedron. | ||||||||||||||||||
/// | ||||||||||||||||||
/// If it's negative, the normal vector of the face defined by | ||||||||||||||||||
/// the first three points using the right-hand rule points | ||||||||||||||||||
/// away from the fourth vertex. | ||||||||||||||||||
#[inline(always)] | ||||||||||||||||||
pub fn signed_volume(&self) -> f32 { | ||||||||||||||||||
let [a, b, c, d] = self.vertices; | ||||||||||||||||||
let ab = b - a; | ||||||||||||||||||
let ac = c - a; | ||||||||||||||||||
let ad = d - a; | ||||||||||||||||||
Mat3::from_cols(ab, ac, ad).determinant() / 6.0 | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
/// Get the centroid of the tetrahedron. | ||||||||||||||||||
/// | ||||||||||||||||||
/// This function finds the geometric center of the tetrahedron | ||||||||||||||||||
/// by averaging the vertices: `centroid = (a + b + c + d) / 4`. | ||||||||||||||||||
#[doc(alias("center", "barycenter", "baricenter"))] | ||||||||||||||||||
#[inline(always)] | ||||||||||||||||||
pub fn centroid(&self) -> Vec3 { | ||||||||||||||||||
(self.vertices[0] + self.vertices[1] + self.vertices[2] + self.vertices[3]) / 4.0 | ||||||||||||||||||
} | ||||||||||||||||||
Chubercik marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
#[cfg(test)] | ||||||||||||||||||
mod tests { | ||||||||||||||||||
// Reference values were computed by hand and/or with external tools | ||||||||||||||||||
|
@@ -986,4 +1066,40 @@ mod tests { | |||||||||||||||||
assert_relative_eq!(torus.area(), 33.16187); | ||||||||||||||||||
assert_relative_eq!(torus.volume(), 4.97428, epsilon = 0.00001); | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
#[test] | ||||||||||||||||||
fn tetrahedron_math() { | ||||||||||||||||||
let tetrahedron = Tetrahedron { | ||||||||||||||||||
vertices: [ | ||||||||||||||||||
Vec3::new(0.3, 1.0, 1.7), | ||||||||||||||||||
Vec3::new(-2.0, -1.0, 0.0), | ||||||||||||||||||
Vec3::new(1.8, 0.5, 1.0), | ||||||||||||||||||
Vec3::new(-1.0, -2.0, 3.5), | ||||||||||||||||||
], | ||||||||||||||||||
}; | ||||||||||||||||||
assert_eq!(tetrahedron.area(), 19.251068, "incorrect area"); | ||||||||||||||||||
assert_eq!(tetrahedron.volume(), 3.2058334, "incorrect volume"); | ||||||||||||||||||
assert_eq!( | ||||||||||||||||||
tetrahedron.signed_volume(), | ||||||||||||||||||
3.2058334, | ||||||||||||||||||
"incorrect signed volume" | ||||||||||||||||||
); | ||||||||||||||||||
assert_relative_eq!(tetrahedron.centroid(), Vec3::new(-0.225, -0.375, 1.55)); | ||||||||||||||||||
|
||||||||||||||||||
assert_eq!(Tetrahedron::default().area(), 1.4659258, "incorrect area"); | ||||||||||||||||||
assert_eq!( | ||||||||||||||||||
Tetrahedron::default().volume(), | ||||||||||||||||||
0.083333336, | ||||||||||||||||||
"incorrect volume" | ||||||||||||||||||
); | ||||||||||||||||||
assert_eq!( | ||||||||||||||||||
Tetrahedron::default().signed_volume(), | ||||||||||||||||||
0.083333336, | ||||||||||||||||||
"incorrect signed volume" | ||||||||||||||||||
); | ||||||||||||||||||
assert_relative_eq!( | ||||||||||||||||||
Tetrahedron::default().centroid(), | ||||||||||||||||||
Vec3::new(0.0, -0.125, 0.125) | ||||||||||||||||||
); | ||||||||||||||||||
} | ||||||||||||||||||
Chubercik marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||
} |
Uh oh!
There was an error while loading. Please reload this page.