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

Reworked Segment types into their cartesian forms #17404

Open
wants to merge 47 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 43 commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
82d5518
Reworked Segment2d into it's cartesian form
Sigma-dev Jan 16, 2025
a33987b
fixed extrusion
Sigma-dev Jan 16, 2025
be0416c
fix commit order mistake
Sigma-dev Jan 16, 2025
b3d4deb
fix typo
Sigma-dev Jan 16, 2025
e3d8464
fix changed method name and fixed method docs
Sigma-dev Jan 16, 2025
b9e3cdf
apply from_direction rename
Sigma-dev Jan 16, 2025
4619993
Update crates/bevy_math/src/primitives/dim2.rs
Sigma-dev Jan 16, 2025
e54a5fc
rework segment3d
Sigma-dev Jan 16, 2025
cde65c0
Merge branch 'cartesian-segments' of https://github.com/Sigma-dev/bev…
Sigma-dev Jan 16, 2025
bd971f6
fix segment3d render primitive
Sigma-dev Jan 16, 2025
334de9b
Update crates/bevy_gizmos/src/primitives/dim3.rs
Sigma-dev Jan 16, 2025
42b9ef1
optimized bounding circle computation for segment2d
Sigma-dev Jan 17, 2025
c460228
missing import
Sigma-dev Jan 17, 2025
08dd3d7
Merge branch 'cartesian-segments' of https://github.com/Sigma-dev/bev…
Sigma-dev Jan 17, 2025
02783a4
Update crates/bevy_math/src/bounding/bounded3d/primitive_impls.rs
Sigma-dev Jan 17, 2025
c0418c6
Update crates/bevy_math/src/primitives/dim2.rs
Sigma-dev Jan 17, 2025
c7f1e2a
Update crates/bevy_math/src/primitives/dim3.rs
Sigma-dev Jan 17, 2025
f976e99
revert example change
Sigma-dev Jan 17, 2025
bd1f029
Merge branch 'cartesian-segments' of https://github.com/Sigma-dev/bev…
Sigma-dev Jan 17, 2025
b9ce954
deprecated from_points of Segment3d
Sigma-dev Jan 17, 2025
3da4e46
unified segment2d and 3d from_points implementation
Sigma-dev Jan 17, 2025
a5e6cad
revert change
Sigma-dev Jan 17, 2025
7ec709f
optimized segment3d bounding sphere generation
Sigma-dev Jan 17, 2025
2ce9647
Update crates/bevy_math/src/primitives/dim2.rs
Sigma-dev Jan 17, 2025
070f9e8
fix deprecation version number
Sigma-dev Jan 17, 2025
c00a6ee
Update crates/bevy_math/src/primitives/dim2.rs
Sigma-dev Jan 17, 2025
e2537f4
Merge branch 'cartesian-segments' of https://github.com/Sigma-dev/bev…
Sigma-dev Jan 17, 2025
f1686ca
Update crates/bevy_math/src/primitives/dim2.rs
Sigma-dev Jan 17, 2025
8b25949
apply translated rename
Sigma-dev Jan 17, 2025
2988fd0
more renaming translated
Sigma-dev Jan 17, 2025
c9431c9
renaming and adding new rotation methods
Sigma-dev Jan 17, 2025
ff8bd4c
Update crates/bevy_math/src/primitives/dim2.rs
Sigma-dev Jan 17, 2025
7a77935
improve segment3d methods
Sigma-dev Jan 17, 2025
7804e7e
removed deprecated method call
Sigma-dev Jan 17, 2025
681f4d3
added midpoint alias
Sigma-dev Jan 17, 2025
fdabe19
changed internal segment representation to an array
Sigma-dev Jan 17, 2025
1fd5de3
implement representation changes
Sigma-dev Jan 17, 2025
dbe951f
fixed version
Sigma-dev Jan 17, 2025
fd63766
fixed internal change
Sigma-dev Jan 18, 2025
1721259
Update crates/bevy_math/src/primitives/dim3.rs
Sigma-dev Jan 18, 2025
35c0f3c
Update crates/bevy_math/src/primitives/dim3.rs
Sigma-dev Jan 18, 2025
00cfaa0
added resized method to segment3d
Sigma-dev Jan 18, 2025
2fc35ba
fixed segment2d bounding circle
Sigma-dev Jan 18, 2025
6f6e781
Update crates/bevy_gizmos/src/primitives/dim3.rs
Sigma-dev Jan 18, 2025
eccfd2b
Update crates/bevy_math/src/primitives/dim3.rs
Sigma-dev Jan 18, 2025
af65238
Update crates/bevy_math/src/primitives/dim2.rs
Sigma-dev Jan 18, 2025
58d6243
Update crates/bevy_gizmos/src/primitives/dim2.rs
Sigma-dev Jan 18, 2025
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
25 changes: 12 additions & 13 deletions crates/bevy_gizmos/src/primitives/dim2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -540,10 +540,7 @@ where
}
// draw normal of the plane (orthogonal to the plane itself)
let normal = primitive.normal;
let normal_segment = Segment2d {
direction: normal,
half_length: HALF_MIN_LINE_LEN,
};
let normal_segment = Segment2d::from_direction_and_length(normal, HALF_MIN_LINE_LEN * 2.);
self.primitive_2d(
&normal_segment,
// offset the normal so it starts on the plane line
Expand Down Expand Up @@ -577,8 +574,8 @@ where
{
gizmos: &'a mut GizmoBuffer<Config, Clear>,

direction: Dir2, // Direction of the line segment
half_length: f32, // Half-length of the line segment
point1: Vec2, // First point of the segment
point2: Vec2, // Second point of the segment

isometry: Isometry2d, // isometric transformation of the line segment
color: Color, // color of the line segment
Expand Down Expand Up @@ -616,8 +613,8 @@ where
) -> Self::Output<'_> {
Segment2dBuilder {
gizmos: self,
direction: primitive.direction,
half_length: primitive.half_length,
point1: primitive.point1(),
point2: primitive.point2(),

isometry: isometry.into(),
color: color.into(),
Expand All @@ -637,14 +634,16 @@ where
return;
}

let direction = self.direction * self.half_length;
let start = self.isometry * (-direction);
let end = self.isometry * direction;
let segment = Segment2d::new(self.point1, self.point2)
.translated(self.isometry.translation)
.rotated_around_center(self.isometry.rotation);
Sigma-dev marked this conversation as resolved.
Show resolved Hide resolved

if self.draw_arrow {
self.gizmos.arrow_2d(start, end, self.color);
self.gizmos
.arrow_2d(segment.point1(), segment.point2(), self.color);
} else {
self.gizmos.line_2d(start, end, self.color);
self.gizmos
.line_2d(segment.point1(), segment.point2(), self.color);
}
}
}
Expand Down
8 changes: 5 additions & 3 deletions crates/bevy_gizmos/src/primitives/dim3.rs
Original file line number Diff line number Diff line change
Expand Up @@ -228,9 +228,11 @@ where
return;
}

let isometry = isometry.into();
let direction = primitive.direction.as_vec3();
self.line(isometry * direction, isometry * (-direction), color);
let isometry: Isometry3d = isometry.into();
let transformed = primitive
.translated(isometry.translation.into())
.rotated_around_center(isometry.rotation);
Sigma-dev marked this conversation as resolved.
Show resolved Hide resolved
self.line(transformed.point1(), transformed.point2(), color);
}
}

Expand Down
31 changes: 14 additions & 17 deletions crates/bevy_math/src/bounding/bounded2d/primitive_impls.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
//! Contains [`Bounded2d`] implementations for [geometric primitives](crate::primitives).

use crate::{
bounding::BoundingVolume,
ops,
primitives::{
Annulus, Arc2d, Capsule2d, Circle, CircularSector, CircularSegment, Ellipse, Line2d,
Expand Down Expand Up @@ -265,18 +266,15 @@ impl Bounded2d for Line2d {

impl Bounded2d for Segment2d {
fn aabb_2d(&self, isometry: impl Into<Isometry2d>) -> Aabb2d {
let isometry = isometry.into();

// Rotate the segment by `rotation`
let direction = isometry.rotation * *self.direction;
let half_size = (self.half_length * direction).abs();

Aabb2d::new(isometry.translation, half_size)
Aabb2d::from_point_cloud(isometry, &[self.point1(), self.point2()])
}

fn bounding_circle(&self, isometry: impl Into<Isometry2d>) -> BoundingCircle {
let isometry = isometry.into();
BoundingCircle::new(isometry.translation, self.half_length)
let isometry: Isometry2d = isometry.into();
let local_center = self.center();
let radius = local_center.distance(self.point1());
let local_circle = BoundingCircle::new(local_center, radius);
local_circle.transformed_by(isometry.translation, isometry.rotation)
}
}

Expand Down Expand Up @@ -336,8 +334,8 @@ impl Bounded2d for Triangle2d {
if let Some((point1, point2)) = side_opposite_to_non_acute {
// The triangle is obtuse or right, so the minimum bounding circle's diameter is equal to the longest side.
// We can compute the minimum bounding circle from the line segment of the longest side.
let (segment, center) = Segment2d::from_points(point1, point2);
segment.bounding_circle(isometry * Isometry2d::from_translation(center))
let segment = Segment2d::new(point1, point2);
segment.bounding_circle(isometry)
} else {
// The triangle is acute, so the smallest bounding circle is the circumcircle.
let (Circle { radius }, circumcenter) = self.circumcircle();
Expand Down Expand Up @@ -417,11 +415,10 @@ impl Bounded2d for Capsule2d {
let isometry = isometry.into();

// Get the line segment between the semicircles of the rotated capsule
let segment = Segment2d {
// Multiplying a normalized vector (Vec2::Y) with a rotation returns a normalized vector.
direction: isometry.rotation * Dir2::Y,
half_length: self.half_length,
};
let segment = Segment2d::from_direction_and_length(
isometry.rotation * Dir2::Y,
self.half_length * 2.,
);
let (a, b) = (segment.point1(), segment.point2());

// Expand the line segment by the capsule radius to get the capsule half-extents
Expand Down Expand Up @@ -886,7 +883,7 @@ mod tests {
fn segment() {
let translation = Vec2::new(2.0, 1.0);
let isometry = Isometry2d::from_translation(translation);
let segment = Segment2d::from_points(Vec2::new(-1.0, -0.5), Vec2::new(1.0, 0.5)).0;
let segment = Segment2d::new(Vec2::new(-1.0, -0.5), Vec2::new(1.0, 0.5));

let aabb = segment.aabb_2d(isometry);
assert_eq!(aabb.min, Vec2::new(1.0, 0.5));
Expand Down
5 changes: 4 additions & 1 deletion crates/bevy_math/src/bounding/bounded3d/extrusion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -348,7 +348,10 @@ mod tests {

#[test]
fn segment() {
let extrusion = Extrusion::new(Segment2d::new(Dir2::new_unchecked(Vec2::NEG_Y), 3.), 4.0);
let extrusion = Extrusion::new(
Segment2d::from_direction_and_length(Dir2::new_unchecked(Vec2::NEG_Y), 3.),
4.0,
);
let translation = Vec3::new(3., 4., 5.);
let rotation = Quat::from_rotation_x(FRAC_PI_4);
let isometry = Isometry3d::new(translation, rotation);
Expand Down
16 changes: 5 additions & 11 deletions crates/bevy_math/src/bounding/bounded3d/primitive_impls.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! Contains [`Bounded3d`] implementations for [geometric primitives](crate::primitives).

use crate::{
bounding::{Bounded2d, BoundingCircle},
bounding::{Bounded2d, BoundingCircle, BoundingVolume},
ops,
primitives::{
Capsule3d, Cone, ConicalFrustum, Cuboid, Cylinder, InfinitePlane3d, Line3d, Polyline3d,
Expand Down Expand Up @@ -76,18 +76,13 @@ impl Bounded3d for Line3d {

impl Bounded3d for Segment3d {
fn aabb_3d(&self, isometry: impl Into<Isometry3d>) -> Aabb3d {
let isometry = isometry.into();

// Rotate the segment by `rotation`
let direction = isometry.rotation * *self.direction;
let half_size = (self.half_length * direction).abs();

Aabb3d::new(isometry.translation, half_size)
Aabb3d::from_point_cloud(isometry, [self.point1(), self.point2()].iter().copied())
Sigma-dev marked this conversation as resolved.
Show resolved Hide resolved
}

fn bounding_sphere(&self, isometry: impl Into<Isometry3d>) -> BoundingSphere {
let isometry = isometry.into();
BoundingSphere::new(isometry.translation, self.half_length)
let local_sphere = BoundingSphere::new(self.center(), self.length() / 2.);
local_sphere.transformed_by(isometry.translation, isometry.rotation)
}
}

Expand Down Expand Up @@ -464,8 +459,7 @@ mod tests {
fn segment() {
let translation = Vec3::new(2.0, 1.0, 0.0);

let segment =
Segment3d::from_points(Vec3::new(-1.0, -0.5, 0.0), Vec3::new(1.0, 0.5, 0.0)).0;
let segment = Segment3d::new(Vec3::new(-1.0, -0.5, 0.0), Vec3::new(1.0, 0.5, 0.0));

let aabb = segment.aabb_3d(translation);
assert_eq!(aabb.min, Vec3A::new(1.0, 0.5, 0.0));
Expand Down
101 changes: 82 additions & 19 deletions crates/bevy_math/src/primitives/dim2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use thiserror::Error;
use super::{Measured2d, Primitive2d, WindingOrder};
use crate::{
ops::{self, FloatPow},
Dir2, Vec2,
Dir2, Rot2, Vec2,
};

#[cfg(feature = "alloc")]
Expand Down Expand Up @@ -1221,21 +1221,17 @@ impl Primitive2d for Line2d {}
)]
#[doc(alias = "LineSegment2d")]
pub struct Segment2d {
Sigma-dev marked this conversation as resolved.
Show resolved Hide resolved
/// The direction of the line segment
pub direction: Dir2,
/// Half the length of the line segment. The segment extends by this amount in both
/// the given direction and its opposite direction
pub half_length: f32,
/// The endpoints of the line segment.
pub vertices: [Vec2; 2],
}
impl Primitive2d for Segment2d {}

impl Segment2d {
/// Create a new `Segment2d` from a direction and full length of the segment
/// Create a new `Segment2d` from its endpoints
#[inline(always)]
pub fn new(direction: Dir2, length: f32) -> Self {
pub const fn new(point1: Vec2, point2: Vec2) -> Self {
Self {
direction,
half_length: length / 2.0,
vertices: [point1, point2],
}
}

Expand All @@ -1245,27 +1241,94 @@ impl Segment2d {
///
/// Panics if `point1 == point2`
#[inline(always)]
#[deprecated(since = "0.16.0", note = "Use the `new` constructor instead")]
pub fn from_points(point1: Vec2, point2: Vec2) -> (Self, Vec2) {
let diff = point2 - point1;
let length = diff.length();
(Self::new(point1, point2), (point1 + point2) / 2.)
}

(
// We are dividing by the length here, so the vector is normalized.
Self::new(Dir2::new_unchecked(diff / length), length),
(point1 + point2) / 2.,
)
/// Create a new `Segment2d` at the origin from a `direction` and `length`
#[inline(always)]
pub fn from_direction_and_length(direction: Dir2, length: f32) -> Segment2d {
let half_length = length / 2.;
Self::new(direction * -half_length, direction * half_length)
}

/// Get the position of the first point on the line segment
#[inline(always)]
pub fn point1(&self) -> Vec2 {
*self.direction * -self.half_length
self.vertices[0]
}

/// Get the position of the second point on the line segment
#[inline(always)]
pub fn point2(&self) -> Vec2 {
*self.direction * self.half_length
self.vertices[1]
}

/// Get the segment's center
#[inline(always)]
#[doc(alias = "midpoint")]
pub fn center(&self) -> Vec2 {
(self.point1() + self.point2()) / 2.
}

/// Get the segment's length
#[inline(always)]
pub fn length(&self) -> f32 {
self.point1().distance(self.point2())
}

/// Get the segment translated by the given vector
#[inline(always)]
pub fn translated(&self, translation: Vec2) -> Segment2d {
Self::new(self.point1() + translation, self.point2() + translation)
}

/// Compute a new segment, based on the original segment rotated around the origin
#[inline(always)]
pub fn rotated(&self, rotation: Rot2) -> Segment2d {
pub fn rotate_point(p: Vec2, rotation: Rot2) -> Vec2 {
Vec2::new(
p.x * rotation.cos - p.y * rotation.sin,
p.x * rotation.sin + p.y * rotation.cos,
)
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's no need for this function. Rot2 is intended to abstract 2D rotations much like Quat in 3D, so you can just do rotation * p.

Copy link
Contributor Author

@Sigma-dev Sigma-dev Jan 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried but I got cannot multiply glam::Vec2 by Rot2, maybe i'm doing something wrong

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you should probably multiply Rot2 by glam::Vec2

Segment2d::new(
rotate_point(self.point1(), rotation),
rotate_point(self.point2(), rotation),
)
}
Sigma-dev marked this conversation as resolved.
Show resolved Hide resolved

/// Compute a new segment, based on the original segment rotated around a given point
#[inline(always)]
pub fn rotated_around(&self, rotation: Rot2, point: Vec2) -> Segment2d {
// We offset our segment so that our segment is rotated as if from the origin, then we can apply the offset back
let offset = self.translated(-point);
let rotated = offset.rotated(rotation);
rotated.translated(point)
}

/// Compute a new segment, based on the original segment rotated around its center
#[inline(always)]
pub fn rotated_around_center(&self, rotation: Rot2) -> Segment2d {
self.rotated_around(rotation, self.center())
}

/// Get the segment with its center at the origin
#[inline(always)]
pub fn centered(&self) -> Segment2d {
let center = self.center();
self.translated(-center)
}

/// Get the segment with a new length
#[inline(always)]
pub fn resized(&self, length: f32) -> Segment2d {
let offset_from_origin = self.center();
let centered = self.centered();
let ratio = length / self.length();
let segment = Segment2d::new(centered.point1() * ratio, centered.point2() * ratio);
segment.translated(offset_from_origin)
}
}

Expand Down
Loading
Loading