bevy/crates/bevy_math/src/isometry.rs

688 lines
21 KiB
Rust
Raw Normal View History

Basic isometry types (#14269) # Objective Introduce isometry types for describing relative and absolute position in mathematical contexts. ## Solution For the time being, this is a very minimal implementation. This implements the following faculties for two- and three-dimensional isometry types: - Identity transformations - Creation from translations and/or rotations - Inverses - Multiplication (composition) of isometries with each other - Application of isometries to points (as vectors) - Conversion of isometries to affine transformations There is obviously a lot more that could be added, so I erred on the side of adding things that I knew would be useful, with the idea of expanding this in the near future as needed. (I also fixed some random doc problems in `bevy_math`.) --- ## Design One point of interest here is the matter of if/when to use aligned types. In the implementation of 3d isometries, I used `Vec3A` rather than `Vec3` because it has no impact on size/alignment, but I'm still not sure about that decision (although it is easily changed). For 2d isometries — which are encoded by four floats — the idea of shoving them into a single 128-bit buffer (`__m128` or whatever) sounds kind of enticing, but it's more involved and would involve writing unsafe code, so I didn't do that for now. ## Future work - Expand the API to include shortcuts like `inverse_mul` and `inverse_transform` for efficiency reasons. - Include more convenience constructors and methods (e.g. `from_xy`, `from_xyz`). - Refactor `bevy_math::bounding` to use the isometry types. - Add conversions to/from isometries for `Transform`/`GlobalTransform` in `bevy_transform`.
2024-07-14 15:27:42 +00:00
//! Isometry types for expressing rigid motions in two and three dimensions.
use crate::{Affine2, Affine3, Affine3A, Dir2, Dir3, Mat3, Mat3A, Quat, Rot2, Vec2, Vec3, Vec3A};
Add `core` and `alloc` over `std` Lints (#15281) # Objective - Fixes #6370 - Closes #6581 ## Solution - Added the following lints to the workspace: - `std_instead_of_core` - `std_instead_of_alloc` - `alloc_instead_of_core` - Used `cargo +nightly fmt` with [item level use formatting](https://rust-lang.github.io/rustfmt/?version=v1.6.0&search=#Item%5C%3A) to split all `use` statements into single items. - Used `cargo clippy --workspace --all-targets --all-features --fix --allow-dirty` to _attempt_ to resolve the new linting issues, and intervened where the lint was unable to resolve the issue automatically (usually due to needing an `extern crate alloc;` statement in a crate root). - Manually removed certain uses of `std` where negative feature gating prevented `--all-features` from finding the offending uses. - Used `cargo +nightly fmt` with [crate level use formatting](https://rust-lang.github.io/rustfmt/?version=v1.6.0&search=#Crate%5C%3A) to re-merge all `use` statements matching Bevy's previous styling. - Manually fixed cases where the `fmt` tool could not re-merge `use` statements due to conditional compilation attributes. ## Testing - Ran CI locally ## Migration Guide The MSRV is now 1.81. Please update to this version or higher. ## Notes - This is a _massive_ change to try and push through, which is why I've outlined the semi-automatic steps I used to create this PR, in case this fails and someone else tries again in the future. - Making this change has no impact on user code, but does mean Bevy contributors will be warned to use `core` and `alloc` instead of `std` where possible. - This lint is a critical first step towards investigating `no_std` options for Bevy. --------- Co-authored-by: François Mockers <francois.mockers@vleue.com>
2024-09-27 00:59:59 +00:00
use core::ops::Mul;
Basic isometry types (#14269) # Objective Introduce isometry types for describing relative and absolute position in mathematical contexts. ## Solution For the time being, this is a very minimal implementation. This implements the following faculties for two- and three-dimensional isometry types: - Identity transformations - Creation from translations and/or rotations - Inverses - Multiplication (composition) of isometries with each other - Application of isometries to points (as vectors) - Conversion of isometries to affine transformations There is obviously a lot more that could be added, so I erred on the side of adding things that I knew would be useful, with the idea of expanding this in the near future as needed. (I also fixed some random doc problems in `bevy_math`.) --- ## Design One point of interest here is the matter of if/when to use aligned types. In the implementation of 3d isometries, I used `Vec3A` rather than `Vec3` because it has no impact on size/alignment, but I'm still not sure about that decision (although it is easily changed). For 2d isometries — which are encoded by four floats — the idea of shoving them into a single 128-bit buffer (`__m128` or whatever) sounds kind of enticing, but it's more involved and would involve writing unsafe code, so I didn't do that for now. ## Future work - Expand the API to include shortcuts like `inverse_mul` and `inverse_transform` for efficiency reasons. - Include more convenience constructors and methods (e.g. `from_xy`, `from_xyz`). - Refactor `bevy_math::bounding` to use the isometry types. - Add conversions to/from isometries for `Transform`/`GlobalTransform` in `bevy_transform`.
2024-07-14 15:27:42 +00:00
#[cfg(feature = "approx")]
use approx::{AbsDiffEq, RelativeEq, UlpsEq};
#[cfg(feature = "bevy_reflect")]
use bevy_reflect::{std_traits::ReflectDefault, Reflect};
#[cfg(all(feature = "bevy_reflect", feature = "serialize"))]
use bevy_reflect::{ReflectDeserialize, ReflectSerialize};
/// An isometry in two dimensions, representing a rotation followed by a translation.
/// This can often be useful for expressing relative positions and transformations from one position to another.
///
/// In particular, this type represents a distance-preserving transformation known as a *rigid motion* or a *direct motion*,
/// and belongs to the special [Euclidean group] SE(2). This includes translation and rotation, but excludes reflection.
///
/// For the three-dimensional version, see [`Isometry3d`].
///
/// [Euclidean group]: https://en.wikipedia.org/wiki/Euclidean_group
///
/// # Example
///
/// Isometries can be created from a given translation and rotation:
///
/// ```
/// # use bevy_math::{Isometry2d, Rot2, Vec2};
/// #
/// let iso = Isometry2d::new(Vec2::new(2.0, 1.0), Rot2::degrees(90.0));
/// ```
///
/// Or from separate parts:
///
/// ```
/// # use bevy_math::{Isometry2d, Rot2, Vec2};
/// #
/// let iso1 = Isometry2d::from_translation(Vec2::new(2.0, 1.0));
/// let iso2 = Isometry2d::from_rotation(Rot2::degrees(90.0));
/// ```
///
/// The isometries can be used to transform points:
///
/// ```
/// # use approx::assert_abs_diff_eq;
/// # use bevy_math::{Isometry2d, Rot2, Vec2};
/// #
/// let iso = Isometry2d::new(Vec2::new(2.0, 1.0), Rot2::degrees(90.0));
/// let point = Vec2::new(4.0, 4.0);
///
/// // These are equivalent
/// let result = iso.transform_point(point);
/// let result = iso * point;
///
/// assert_eq!(result, Vec2::new(-2.0, 5.0));
/// ```
///
/// Isometries can also be composed together:
///
/// ```
/// # use bevy_math::{Isometry2d, Rot2, Vec2};
/// #
/// # let iso = Isometry2d::new(Vec2::new(2.0, 1.0), Rot2::degrees(90.0));
/// # let iso1 = Isometry2d::from_translation(Vec2::new(2.0, 1.0));
/// # let iso2 = Isometry2d::from_rotation(Rot2::degrees(90.0));
/// #
/// assert_eq!(iso1 * iso2, iso);
/// ```
///
/// One common operation is to compute an isometry representing the relative positions of two objects
/// for things like intersection tests. This can be done with an inverse transformation:
///
/// ```
/// # use bevy_math::{Isometry2d, Rot2, Vec2};
/// #
/// let circle_iso = Isometry2d::from_translation(Vec2::new(2.0, 1.0));
/// let rectangle_iso = Isometry2d::from_rotation(Rot2::degrees(90.0));
///
/// // Compute the relative position and orientation between the two shapes
/// let relative_iso = circle_iso.inverse() * rectangle_iso;
///
/// // Or alternatively, to skip an extra rotation operation:
/// let relative_iso = circle_iso.inverse_mul(rectangle_iso);
/// ```
Basic isometry types (#14269) # Objective Introduce isometry types for describing relative and absolute position in mathematical contexts. ## Solution For the time being, this is a very minimal implementation. This implements the following faculties for two- and three-dimensional isometry types: - Identity transformations - Creation from translations and/or rotations - Inverses - Multiplication (composition) of isometries with each other - Application of isometries to points (as vectors) - Conversion of isometries to affine transformations There is obviously a lot more that could be added, so I erred on the side of adding things that I knew would be useful, with the idea of expanding this in the near future as needed. (I also fixed some random doc problems in `bevy_math`.) --- ## Design One point of interest here is the matter of if/when to use aligned types. In the implementation of 3d isometries, I used `Vec3A` rather than `Vec3` because it has no impact on size/alignment, but I'm still not sure about that decision (although it is easily changed). For 2d isometries — which are encoded by four floats — the idea of shoving them into a single 128-bit buffer (`__m128` or whatever) sounds kind of enticing, but it's more involved and would involve writing unsafe code, so I didn't do that for now. ## Future work - Expand the API to include shortcuts like `inverse_mul` and `inverse_transform` for efficiency reasons. - Include more convenience constructors and methods (e.g. `from_xy`, `from_xyz`). - Refactor `bevy_math::bounding` to use the isometry types. - Add conversions to/from isometries for `Transform`/`GlobalTransform` in `bevy_transform`.
2024-07-14 15:27:42 +00:00
#[derive(Copy, Clone, Default, Debug, PartialEq)]
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(
feature = "bevy_reflect",
derive(Reflect),
reflect(Debug, PartialEq, Default)
)]
#[cfg_attr(
all(feature = "serialize", feature = "bevy_reflect"),
reflect(Serialize, Deserialize)
)]
pub struct Isometry2d {
/// The rotational part of a two-dimensional isometry.
pub rotation: Rot2,
/// The translational part of a two-dimensional isometry.
pub translation: Vec2,
}
impl Isometry2d {
/// The identity isometry which represents the rigid motion of not doing anything.
pub const IDENTITY: Self = Isometry2d {
rotation: Rot2::IDENTITY,
translation: Vec2::ZERO,
};
/// Create a two-dimensional isometry from a rotation and a translation.
#[inline]
pub fn new(translation: Vec2, rotation: Rot2) -> Self {
Isometry2d {
rotation,
translation,
}
}
/// Create a two-dimensional isometry from a rotation.
#[inline]
pub fn from_rotation(rotation: Rot2) -> Self {
Isometry2d {
rotation,
translation: Vec2::ZERO,
}
}
/// Create a two-dimensional isometry from a translation.
#[inline]
pub fn from_translation(translation: Vec2) -> Self {
Isometry2d {
rotation: Rot2::IDENTITY,
translation,
}
}
/// Create a two-dimensional isometry from a translation with the given `x` and `y` components.
#[inline]
pub fn from_xy(x: f32, y: f32) -> Self {
Isometry2d {
rotation: Rot2::IDENTITY,
translation: Vec2::new(x, y),
}
}
Basic isometry types (#14269) # Objective Introduce isometry types for describing relative and absolute position in mathematical contexts. ## Solution For the time being, this is a very minimal implementation. This implements the following faculties for two- and three-dimensional isometry types: - Identity transformations - Creation from translations and/or rotations - Inverses - Multiplication (composition) of isometries with each other - Application of isometries to points (as vectors) - Conversion of isometries to affine transformations There is obviously a lot more that could be added, so I erred on the side of adding things that I knew would be useful, with the idea of expanding this in the near future as needed. (I also fixed some random doc problems in `bevy_math`.) --- ## Design One point of interest here is the matter of if/when to use aligned types. In the implementation of 3d isometries, I used `Vec3A` rather than `Vec3` because it has no impact on size/alignment, but I'm still not sure about that decision (although it is easily changed). For 2d isometries — which are encoded by four floats — the idea of shoving them into a single 128-bit buffer (`__m128` or whatever) sounds kind of enticing, but it's more involved and would involve writing unsafe code, so I didn't do that for now. ## Future work - Expand the API to include shortcuts like `inverse_mul` and `inverse_transform` for efficiency reasons. - Include more convenience constructors and methods (e.g. `from_xy`, `from_xyz`). - Refactor `bevy_math::bounding` to use the isometry types. - Add conversions to/from isometries for `Transform`/`GlobalTransform` in `bevy_transform`.
2024-07-14 15:27:42 +00:00
/// The inverse isometry that undoes this one.
#[inline]
pub fn inverse(&self) -> Self {
let inv_rot = self.rotation.inverse();
Isometry2d {
rotation: inv_rot,
translation: inv_rot * -self.translation,
}
}
/// Compute `iso1.inverse() * iso2` in a more efficient way for one-shot cases.
///
/// If the same isometry is used multiple times, it is more efficient to instead compute
/// the inverse once and use that for each transformation.
#[inline]
pub fn inverse_mul(&self, rhs: Self) -> Self {
let inv_rot = self.rotation.inverse();
let delta_translation = rhs.translation - self.translation;
Self::new(inv_rot * delta_translation, inv_rot * rhs.rotation)
}
Basic isometry types (#14269) # Objective Introduce isometry types for describing relative and absolute position in mathematical contexts. ## Solution For the time being, this is a very minimal implementation. This implements the following faculties for two- and three-dimensional isometry types: - Identity transformations - Creation from translations and/or rotations - Inverses - Multiplication (composition) of isometries with each other - Application of isometries to points (as vectors) - Conversion of isometries to affine transformations There is obviously a lot more that could be added, so I erred on the side of adding things that I knew would be useful, with the idea of expanding this in the near future as needed. (I also fixed some random doc problems in `bevy_math`.) --- ## Design One point of interest here is the matter of if/when to use aligned types. In the implementation of 3d isometries, I used `Vec3A` rather than `Vec3` because it has no impact on size/alignment, but I'm still not sure about that decision (although it is easily changed). For 2d isometries — which are encoded by four floats — the idea of shoving them into a single 128-bit buffer (`__m128` or whatever) sounds kind of enticing, but it's more involved and would involve writing unsafe code, so I didn't do that for now. ## Future work - Expand the API to include shortcuts like `inverse_mul` and `inverse_transform` for efficiency reasons. - Include more convenience constructors and methods (e.g. `from_xy`, `from_xyz`). - Refactor `bevy_math::bounding` to use the isometry types. - Add conversions to/from isometries for `Transform`/`GlobalTransform` in `bevy_transform`.
2024-07-14 15:27:42 +00:00
/// Transform a point by rotating and translating it using this isometry.
#[inline]
pub fn transform_point(&self, point: Vec2) -> Vec2 {
self.rotation * point + self.translation
}
/// Transform a point by rotating and translating it using the inverse of this isometry.
///
/// This is more efficient than `iso.inverse().transform_point(point)` for one-shot cases.
/// If the same isometry is used multiple times, it is more efficient to instead compute
/// the inverse once and use that for each transformation.
#[inline]
pub fn inverse_transform_point(&self, point: Vec2) -> Vec2 {
self.rotation.inverse() * (point - self.translation)
}
Basic isometry types (#14269) # Objective Introduce isometry types for describing relative and absolute position in mathematical contexts. ## Solution For the time being, this is a very minimal implementation. This implements the following faculties for two- and three-dimensional isometry types: - Identity transformations - Creation from translations and/or rotations - Inverses - Multiplication (composition) of isometries with each other - Application of isometries to points (as vectors) - Conversion of isometries to affine transformations There is obviously a lot more that could be added, so I erred on the side of adding things that I knew would be useful, with the idea of expanding this in the near future as needed. (I also fixed some random doc problems in `bevy_math`.) --- ## Design One point of interest here is the matter of if/when to use aligned types. In the implementation of 3d isometries, I used `Vec3A` rather than `Vec3` because it has no impact on size/alignment, but I'm still not sure about that decision (although it is easily changed). For 2d isometries — which are encoded by four floats — the idea of shoving them into a single 128-bit buffer (`__m128` or whatever) sounds kind of enticing, but it's more involved and would involve writing unsafe code, so I didn't do that for now. ## Future work - Expand the API to include shortcuts like `inverse_mul` and `inverse_transform` for efficiency reasons. - Include more convenience constructors and methods (e.g. `from_xy`, `from_xyz`). - Refactor `bevy_math::bounding` to use the isometry types. - Add conversions to/from isometries for `Transform`/`GlobalTransform` in `bevy_transform`.
2024-07-14 15:27:42 +00:00
}
impl From<Isometry2d> for Affine2 {
#[inline]
fn from(iso: Isometry2d) -> Self {
Affine2 {
matrix2: iso.rotation.into(),
translation: iso.translation,
}
}
}
impl From<Vec2> for Isometry2d {
#[inline]
fn from(translation: Vec2) -> Self {
Isometry2d::from_translation(translation)
}
}
impl From<Rot2> for Isometry2d {
#[inline]
fn from(rotation: Rot2) -> Self {
Isometry2d::from_rotation(rotation)
}
}
Basic isometry types (#14269) # Objective Introduce isometry types for describing relative and absolute position in mathematical contexts. ## Solution For the time being, this is a very minimal implementation. This implements the following faculties for two- and three-dimensional isometry types: - Identity transformations - Creation from translations and/or rotations - Inverses - Multiplication (composition) of isometries with each other - Application of isometries to points (as vectors) - Conversion of isometries to affine transformations There is obviously a lot more that could be added, so I erred on the side of adding things that I knew would be useful, with the idea of expanding this in the near future as needed. (I also fixed some random doc problems in `bevy_math`.) --- ## Design One point of interest here is the matter of if/when to use aligned types. In the implementation of 3d isometries, I used `Vec3A` rather than `Vec3` because it has no impact on size/alignment, but I'm still not sure about that decision (although it is easily changed). For 2d isometries — which are encoded by four floats — the idea of shoving them into a single 128-bit buffer (`__m128` or whatever) sounds kind of enticing, but it's more involved and would involve writing unsafe code, so I didn't do that for now. ## Future work - Expand the API to include shortcuts like `inverse_mul` and `inverse_transform` for efficiency reasons. - Include more convenience constructors and methods (e.g. `from_xy`, `from_xyz`). - Refactor `bevy_math::bounding` to use the isometry types. - Add conversions to/from isometries for `Transform`/`GlobalTransform` in `bevy_transform`.
2024-07-14 15:27:42 +00:00
impl Mul for Isometry2d {
type Output = Self;
#[inline]
fn mul(self, rhs: Self) -> Self::Output {
Isometry2d {
rotation: self.rotation * rhs.rotation,
translation: self.rotation * rhs.translation + self.translation,
}
}
}
impl Mul<Vec2> for Isometry2d {
type Output = Vec2;
#[inline]
fn mul(self, rhs: Vec2) -> Self::Output {
self.transform_point(rhs)
}
}
impl Mul<Dir2> for Isometry2d {
type Output = Dir2;
#[inline]
fn mul(self, rhs: Dir2) -> Self::Output {
self.rotation * rhs
}
}
#[cfg(feature = "approx")]
impl AbsDiffEq for Isometry2d {
type Epsilon = <f32 as AbsDiffEq>::Epsilon;
fn default_epsilon() -> Self::Epsilon {
f32::default_epsilon()
}
fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool {
self.rotation.abs_diff_eq(&other.rotation, epsilon)
&& self.translation.abs_diff_eq(other.translation, epsilon)
}
}
#[cfg(feature = "approx")]
impl RelativeEq for Isometry2d {
fn default_max_relative() -> Self::Epsilon {
Self::default_epsilon()
}
fn relative_eq(
&self,
other: &Self,
epsilon: Self::Epsilon,
max_relative: Self::Epsilon,
) -> bool {
self.rotation
.relative_eq(&other.rotation, epsilon, max_relative)
&& self
.translation
.relative_eq(&other.translation, epsilon, max_relative)
}
}
#[cfg(feature = "approx")]
impl UlpsEq for Isometry2d {
fn default_max_ulps() -> u32 {
4
}
fn ulps_eq(&self, other: &Self, epsilon: Self::Epsilon, max_ulps: u32) -> bool {
self.rotation.ulps_eq(&other.rotation, epsilon, max_ulps)
&& self
.translation
.ulps_eq(&other.translation, epsilon, max_ulps)
}
}
/// An isometry in three dimensions, representing a rotation followed by a translation.
/// This can often be useful for expressing relative positions and transformations from one position to another.
///
/// In particular, this type represents a distance-preserving transformation known as a *rigid motion* or a *direct motion*,
/// and belongs to the special [Euclidean group] SE(3). This includes translation and rotation, but excludes reflection.
///
/// For the two-dimensional version, see [`Isometry2d`].
///
/// [Euclidean group]: https://en.wikipedia.org/wiki/Euclidean_group
///
/// # Example
///
/// Isometries can be created from a given translation and rotation:
///
/// ```
/// # use bevy_math::{Isometry3d, Quat, Vec3};
Add `core` and `alloc` over `std` Lints (#15281) # Objective - Fixes #6370 - Closes #6581 ## Solution - Added the following lints to the workspace: - `std_instead_of_core` - `std_instead_of_alloc` - `alloc_instead_of_core` - Used `cargo +nightly fmt` with [item level use formatting](https://rust-lang.github.io/rustfmt/?version=v1.6.0&search=#Item%5C%3A) to split all `use` statements into single items. - Used `cargo clippy --workspace --all-targets --all-features --fix --allow-dirty` to _attempt_ to resolve the new linting issues, and intervened where the lint was unable to resolve the issue automatically (usually due to needing an `extern crate alloc;` statement in a crate root). - Manually removed certain uses of `std` where negative feature gating prevented `--all-features` from finding the offending uses. - Used `cargo +nightly fmt` with [crate level use formatting](https://rust-lang.github.io/rustfmt/?version=v1.6.0&search=#Crate%5C%3A) to re-merge all `use` statements matching Bevy's previous styling. - Manually fixed cases where the `fmt` tool could not re-merge `use` statements due to conditional compilation attributes. ## Testing - Ran CI locally ## Migration Guide The MSRV is now 1.81. Please update to this version or higher. ## Notes - This is a _massive_ change to try and push through, which is why I've outlined the semi-automatic steps I used to create this PR, in case this fails and someone else tries again in the future. - Making this change has no impact on user code, but does mean Bevy contributors will be warned to use `core` and `alloc` instead of `std` where possible. - This lint is a critical first step towards investigating `no_std` options for Bevy. --------- Co-authored-by: François Mockers <francois.mockers@vleue.com>
2024-09-27 00:59:59 +00:00
/// # use std::f32::consts::FRAC_PI_2;
/// #
/// let iso = Isometry3d::new(Vec3::new(2.0, 1.0, 3.0), Quat::from_rotation_z(FRAC_PI_2));
/// ```
///
/// Or from separate parts:
///
/// ```
/// # use bevy_math::{Isometry3d, Quat, Vec3};
Add `core` and `alloc` over `std` Lints (#15281) # Objective - Fixes #6370 - Closes #6581 ## Solution - Added the following lints to the workspace: - `std_instead_of_core` - `std_instead_of_alloc` - `alloc_instead_of_core` - Used `cargo +nightly fmt` with [item level use formatting](https://rust-lang.github.io/rustfmt/?version=v1.6.0&search=#Item%5C%3A) to split all `use` statements into single items. - Used `cargo clippy --workspace --all-targets --all-features --fix --allow-dirty` to _attempt_ to resolve the new linting issues, and intervened where the lint was unable to resolve the issue automatically (usually due to needing an `extern crate alloc;` statement in a crate root). - Manually removed certain uses of `std` where negative feature gating prevented `--all-features` from finding the offending uses. - Used `cargo +nightly fmt` with [crate level use formatting](https://rust-lang.github.io/rustfmt/?version=v1.6.0&search=#Crate%5C%3A) to re-merge all `use` statements matching Bevy's previous styling. - Manually fixed cases where the `fmt` tool could not re-merge `use` statements due to conditional compilation attributes. ## Testing - Ran CI locally ## Migration Guide The MSRV is now 1.81. Please update to this version or higher. ## Notes - This is a _massive_ change to try and push through, which is why I've outlined the semi-automatic steps I used to create this PR, in case this fails and someone else tries again in the future. - Making this change has no impact on user code, but does mean Bevy contributors will be warned to use `core` and `alloc` instead of `std` where possible. - This lint is a critical first step towards investigating `no_std` options for Bevy. --------- Co-authored-by: François Mockers <francois.mockers@vleue.com>
2024-09-27 00:59:59 +00:00
/// # use std::f32::consts::FRAC_PI_2;
/// #
/// let iso1 = Isometry3d::from_translation(Vec3::new(2.0, 1.0, 3.0));
/// let iso2 = Isometry3d::from_rotation(Quat::from_rotation_z(FRAC_PI_2));
/// ```
///
/// The isometries can be used to transform points:
///
/// ```
/// # use approx::assert_relative_eq;
/// # use bevy_math::{Isometry3d, Quat, Vec3};
Add `core` and `alloc` over `std` Lints (#15281) # Objective - Fixes #6370 - Closes #6581 ## Solution - Added the following lints to the workspace: - `std_instead_of_core` - `std_instead_of_alloc` - `alloc_instead_of_core` - Used `cargo +nightly fmt` with [item level use formatting](https://rust-lang.github.io/rustfmt/?version=v1.6.0&search=#Item%5C%3A) to split all `use` statements into single items. - Used `cargo clippy --workspace --all-targets --all-features --fix --allow-dirty` to _attempt_ to resolve the new linting issues, and intervened where the lint was unable to resolve the issue automatically (usually due to needing an `extern crate alloc;` statement in a crate root). - Manually removed certain uses of `std` where negative feature gating prevented `--all-features` from finding the offending uses. - Used `cargo +nightly fmt` with [crate level use formatting](https://rust-lang.github.io/rustfmt/?version=v1.6.0&search=#Crate%5C%3A) to re-merge all `use` statements matching Bevy's previous styling. - Manually fixed cases where the `fmt` tool could not re-merge `use` statements due to conditional compilation attributes. ## Testing - Ran CI locally ## Migration Guide The MSRV is now 1.81. Please update to this version or higher. ## Notes - This is a _massive_ change to try and push through, which is why I've outlined the semi-automatic steps I used to create this PR, in case this fails and someone else tries again in the future. - Making this change has no impact on user code, but does mean Bevy contributors will be warned to use `core` and `alloc` instead of `std` where possible. - This lint is a critical first step towards investigating `no_std` options for Bevy. --------- Co-authored-by: François Mockers <francois.mockers@vleue.com>
2024-09-27 00:59:59 +00:00
/// # use std::f32::consts::FRAC_PI_2;
/// #
/// let iso = Isometry3d::new(Vec3::new(2.0, 1.0, 3.0), Quat::from_rotation_z(FRAC_PI_2));
/// let point = Vec3::new(4.0, 4.0, 4.0);
///
/// // These are equivalent
/// let result = iso.transform_point(point);
/// let result = iso * point;
///
/// assert_relative_eq!(result, Vec3::new(-2.0, 5.0, 7.0));
/// ```
///
/// Isometries can also be composed together:
///
/// ```
/// # use bevy_math::{Isometry3d, Quat, Vec3};
Add `core` and `alloc` over `std` Lints (#15281) # Objective - Fixes #6370 - Closes #6581 ## Solution - Added the following lints to the workspace: - `std_instead_of_core` - `std_instead_of_alloc` - `alloc_instead_of_core` - Used `cargo +nightly fmt` with [item level use formatting](https://rust-lang.github.io/rustfmt/?version=v1.6.0&search=#Item%5C%3A) to split all `use` statements into single items. - Used `cargo clippy --workspace --all-targets --all-features --fix --allow-dirty` to _attempt_ to resolve the new linting issues, and intervened where the lint was unable to resolve the issue automatically (usually due to needing an `extern crate alloc;` statement in a crate root). - Manually removed certain uses of `std` where negative feature gating prevented `--all-features` from finding the offending uses. - Used `cargo +nightly fmt` with [crate level use formatting](https://rust-lang.github.io/rustfmt/?version=v1.6.0&search=#Crate%5C%3A) to re-merge all `use` statements matching Bevy's previous styling. - Manually fixed cases where the `fmt` tool could not re-merge `use` statements due to conditional compilation attributes. ## Testing - Ran CI locally ## Migration Guide The MSRV is now 1.81. Please update to this version or higher. ## Notes - This is a _massive_ change to try and push through, which is why I've outlined the semi-automatic steps I used to create this PR, in case this fails and someone else tries again in the future. - Making this change has no impact on user code, but does mean Bevy contributors will be warned to use `core` and `alloc` instead of `std` where possible. - This lint is a critical first step towards investigating `no_std` options for Bevy. --------- Co-authored-by: François Mockers <francois.mockers@vleue.com>
2024-09-27 00:59:59 +00:00
/// # use std::f32::consts::FRAC_PI_2;
/// #
/// # let iso = Isometry3d::new(Vec3::new(2.0, 1.0, 3.0), Quat::from_rotation_z(FRAC_PI_2));
/// # let iso1 = Isometry3d::from_translation(Vec3::new(2.0, 1.0, 3.0));
/// # let iso2 = Isometry3d::from_rotation(Quat::from_rotation_z(FRAC_PI_2));
/// #
/// assert_eq!(iso1 * iso2, iso);
/// ```
///
/// One common operation is to compute an isometry representing the relative positions of two objects
/// for things like intersection tests. This can be done with an inverse transformation:
///
/// ```
/// # use bevy_math::{Isometry3d, Quat, Vec3};
Add `core` and `alloc` over `std` Lints (#15281) # Objective - Fixes #6370 - Closes #6581 ## Solution - Added the following lints to the workspace: - `std_instead_of_core` - `std_instead_of_alloc` - `alloc_instead_of_core` - Used `cargo +nightly fmt` with [item level use formatting](https://rust-lang.github.io/rustfmt/?version=v1.6.0&search=#Item%5C%3A) to split all `use` statements into single items. - Used `cargo clippy --workspace --all-targets --all-features --fix --allow-dirty` to _attempt_ to resolve the new linting issues, and intervened where the lint was unable to resolve the issue automatically (usually due to needing an `extern crate alloc;` statement in a crate root). - Manually removed certain uses of `std` where negative feature gating prevented `--all-features` from finding the offending uses. - Used `cargo +nightly fmt` with [crate level use formatting](https://rust-lang.github.io/rustfmt/?version=v1.6.0&search=#Crate%5C%3A) to re-merge all `use` statements matching Bevy's previous styling. - Manually fixed cases where the `fmt` tool could not re-merge `use` statements due to conditional compilation attributes. ## Testing - Ran CI locally ## Migration Guide The MSRV is now 1.81. Please update to this version or higher. ## Notes - This is a _massive_ change to try and push through, which is why I've outlined the semi-automatic steps I used to create this PR, in case this fails and someone else tries again in the future. - Making this change has no impact on user code, but does mean Bevy contributors will be warned to use `core` and `alloc` instead of `std` where possible. - This lint is a critical first step towards investigating `no_std` options for Bevy. --------- Co-authored-by: François Mockers <francois.mockers@vleue.com>
2024-09-27 00:59:59 +00:00
/// # use std::f32::consts::FRAC_PI_2;
/// #
/// let sphere_iso = Isometry3d::from_translation(Vec3::new(2.0, 1.0, 3.0));
/// let cuboid_iso = Isometry3d::from_rotation(Quat::from_rotation_z(FRAC_PI_2));
///
/// // Compute the relative position and orientation between the two shapes
/// let relative_iso = sphere_iso.inverse() * cuboid_iso;
///
/// // Or alternatively, to skip an extra rotation operation:
/// let relative_iso = sphere_iso.inverse_mul(cuboid_iso);
/// ```
Basic isometry types (#14269) # Objective Introduce isometry types for describing relative and absolute position in mathematical contexts. ## Solution For the time being, this is a very minimal implementation. This implements the following faculties for two- and three-dimensional isometry types: - Identity transformations - Creation from translations and/or rotations - Inverses - Multiplication (composition) of isometries with each other - Application of isometries to points (as vectors) - Conversion of isometries to affine transformations There is obviously a lot more that could be added, so I erred on the side of adding things that I knew would be useful, with the idea of expanding this in the near future as needed. (I also fixed some random doc problems in `bevy_math`.) --- ## Design One point of interest here is the matter of if/when to use aligned types. In the implementation of 3d isometries, I used `Vec3A` rather than `Vec3` because it has no impact on size/alignment, but I'm still not sure about that decision (although it is easily changed). For 2d isometries — which are encoded by four floats — the idea of shoving them into a single 128-bit buffer (`__m128` or whatever) sounds kind of enticing, but it's more involved and would involve writing unsafe code, so I didn't do that for now. ## Future work - Expand the API to include shortcuts like `inverse_mul` and `inverse_transform` for efficiency reasons. - Include more convenience constructors and methods (e.g. `from_xy`, `from_xyz`). - Refactor `bevy_math::bounding` to use the isometry types. - Add conversions to/from isometries for `Transform`/`GlobalTransform` in `bevy_transform`.
2024-07-14 15:27:42 +00:00
#[derive(Copy, Clone, Default, Debug, PartialEq)]
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(
feature = "bevy_reflect",
derive(Reflect),
reflect(Debug, PartialEq, Default)
)]
#[cfg_attr(
all(feature = "serialize", feature = "bevy_reflect"),
reflect(Serialize, Deserialize)
)]
pub struct Isometry3d {
/// The rotational part of a three-dimensional isometry.
pub rotation: Quat,
/// The translational part of a three-dimensional isometry.
pub translation: Vec3A,
}
impl Isometry3d {
/// The identity isometry which represents the rigid motion of not doing anything.
pub const IDENTITY: Self = Isometry3d {
rotation: Quat::IDENTITY,
translation: Vec3A::ZERO,
};
/// Create a three-dimensional isometry from a rotation and a translation.
#[inline]
pub fn new(translation: impl Into<Vec3A>, rotation: Quat) -> Self {
Isometry3d {
rotation,
translation: translation.into(),
}
}
/// Create a three-dimensional isometry from a rotation.
#[inline]
pub fn from_rotation(rotation: Quat) -> Self {
Isometry3d {
rotation,
translation: Vec3A::ZERO,
}
}
/// Create a three-dimensional isometry from a translation.
#[inline]
pub fn from_translation(translation: impl Into<Vec3A>) -> Self {
Isometry3d {
rotation: Quat::IDENTITY,
translation: translation.into(),
}
}
/// Create a three-dimensional isometry from a translation with the given `x`, `y`, and `z` components.
#[inline]
pub fn from_xyz(x: f32, y: f32, z: f32) -> Self {
Isometry3d {
rotation: Quat::IDENTITY,
translation: Vec3A::new(x, y, z),
}
}
Basic isometry types (#14269) # Objective Introduce isometry types for describing relative and absolute position in mathematical contexts. ## Solution For the time being, this is a very minimal implementation. This implements the following faculties for two- and three-dimensional isometry types: - Identity transformations - Creation from translations and/or rotations - Inverses - Multiplication (composition) of isometries with each other - Application of isometries to points (as vectors) - Conversion of isometries to affine transformations There is obviously a lot more that could be added, so I erred on the side of adding things that I knew would be useful, with the idea of expanding this in the near future as needed. (I also fixed some random doc problems in `bevy_math`.) --- ## Design One point of interest here is the matter of if/when to use aligned types. In the implementation of 3d isometries, I used `Vec3A` rather than `Vec3` because it has no impact on size/alignment, but I'm still not sure about that decision (although it is easily changed). For 2d isometries — which are encoded by four floats — the idea of shoving them into a single 128-bit buffer (`__m128` or whatever) sounds kind of enticing, but it's more involved and would involve writing unsafe code, so I didn't do that for now. ## Future work - Expand the API to include shortcuts like `inverse_mul` and `inverse_transform` for efficiency reasons. - Include more convenience constructors and methods (e.g. `from_xy`, `from_xyz`). - Refactor `bevy_math::bounding` to use the isometry types. - Add conversions to/from isometries for `Transform`/`GlobalTransform` in `bevy_transform`.
2024-07-14 15:27:42 +00:00
/// The inverse isometry that undoes this one.
#[inline]
pub fn inverse(&self) -> Self {
let inv_rot = self.rotation.inverse();
Isometry3d {
rotation: inv_rot,
translation: inv_rot * -self.translation,
}
}
/// Compute `iso1.inverse() * iso2` in a more efficient way for one-shot cases.
///
/// If the same isometry is used multiple times, it is more efficient to instead compute
/// the inverse once and use that for each transformation.
#[inline]
pub fn inverse_mul(&self, rhs: Self) -> Self {
let inv_rot = self.rotation.inverse();
let delta_translation = rhs.translation - self.translation;
Self::new(inv_rot * delta_translation, inv_rot * rhs.rotation)
}
Basic isometry types (#14269) # Objective Introduce isometry types for describing relative and absolute position in mathematical contexts. ## Solution For the time being, this is a very minimal implementation. This implements the following faculties for two- and three-dimensional isometry types: - Identity transformations - Creation from translations and/or rotations - Inverses - Multiplication (composition) of isometries with each other - Application of isometries to points (as vectors) - Conversion of isometries to affine transformations There is obviously a lot more that could be added, so I erred on the side of adding things that I knew would be useful, with the idea of expanding this in the near future as needed. (I also fixed some random doc problems in `bevy_math`.) --- ## Design One point of interest here is the matter of if/when to use aligned types. In the implementation of 3d isometries, I used `Vec3A` rather than `Vec3` because it has no impact on size/alignment, but I'm still not sure about that decision (although it is easily changed). For 2d isometries — which are encoded by four floats — the idea of shoving them into a single 128-bit buffer (`__m128` or whatever) sounds kind of enticing, but it's more involved and would involve writing unsafe code, so I didn't do that for now. ## Future work - Expand the API to include shortcuts like `inverse_mul` and `inverse_transform` for efficiency reasons. - Include more convenience constructors and methods (e.g. `from_xy`, `from_xyz`). - Refactor `bevy_math::bounding` to use the isometry types. - Add conversions to/from isometries for `Transform`/`GlobalTransform` in `bevy_transform`.
2024-07-14 15:27:42 +00:00
/// Transform a point by rotating and translating it using this isometry.
#[inline]
pub fn transform_point(&self, point: impl Into<Vec3A>) -> Vec3A {
self.rotation * point.into() + self.translation
}
/// Transform a point by rotating and translating it using the inverse of this isometry.
///
/// This is more efficient than `iso.inverse().transform_point(point)` for one-shot cases.
/// If the same isometry is used multiple times, it is more efficient to instead compute
/// the inverse once and use that for each transformation.
#[inline]
pub fn inverse_transform_point(&self, point: impl Into<Vec3A>) -> Vec3A {
self.rotation.inverse() * (point.into() - self.translation)
}
Basic isometry types (#14269) # Objective Introduce isometry types for describing relative and absolute position in mathematical contexts. ## Solution For the time being, this is a very minimal implementation. This implements the following faculties for two- and three-dimensional isometry types: - Identity transformations - Creation from translations and/or rotations - Inverses - Multiplication (composition) of isometries with each other - Application of isometries to points (as vectors) - Conversion of isometries to affine transformations There is obviously a lot more that could be added, so I erred on the side of adding things that I knew would be useful, with the idea of expanding this in the near future as needed. (I also fixed some random doc problems in `bevy_math`.) --- ## Design One point of interest here is the matter of if/when to use aligned types. In the implementation of 3d isometries, I used `Vec3A` rather than `Vec3` because it has no impact on size/alignment, but I'm still not sure about that decision (although it is easily changed). For 2d isometries — which are encoded by four floats — the idea of shoving them into a single 128-bit buffer (`__m128` or whatever) sounds kind of enticing, but it's more involved and would involve writing unsafe code, so I didn't do that for now. ## Future work - Expand the API to include shortcuts like `inverse_mul` and `inverse_transform` for efficiency reasons. - Include more convenience constructors and methods (e.g. `from_xy`, `from_xyz`). - Refactor `bevy_math::bounding` to use the isometry types. - Add conversions to/from isometries for `Transform`/`GlobalTransform` in `bevy_transform`.
2024-07-14 15:27:42 +00:00
}
impl From<Isometry3d> for Affine3 {
#[inline]
fn from(iso: Isometry3d) -> Self {
Affine3 {
matrix3: Mat3::from_quat(iso.rotation),
translation: iso.translation.into(),
}
}
}
impl From<Isometry3d> for Affine3A {
#[inline]
fn from(iso: Isometry3d) -> Self {
Affine3A {
matrix3: Mat3A::from_quat(iso.rotation),
translation: iso.translation,
}
}
}
impl From<Vec3> for Isometry3d {
#[inline]
fn from(translation: Vec3) -> Self {
Isometry3d::from_translation(translation)
}
}
impl From<Vec3A> for Isometry3d {
#[inline]
fn from(translation: Vec3A) -> Self {
Isometry3d::from_translation(translation)
}
}
impl From<Quat> for Isometry3d {
#[inline]
fn from(rotation: Quat) -> Self {
Isometry3d::from_rotation(rotation)
}
}
Basic isometry types (#14269) # Objective Introduce isometry types for describing relative and absolute position in mathematical contexts. ## Solution For the time being, this is a very minimal implementation. This implements the following faculties for two- and three-dimensional isometry types: - Identity transformations - Creation from translations and/or rotations - Inverses - Multiplication (composition) of isometries with each other - Application of isometries to points (as vectors) - Conversion of isometries to affine transformations There is obviously a lot more that could be added, so I erred on the side of adding things that I knew would be useful, with the idea of expanding this in the near future as needed. (I also fixed some random doc problems in `bevy_math`.) --- ## Design One point of interest here is the matter of if/when to use aligned types. In the implementation of 3d isometries, I used `Vec3A` rather than `Vec3` because it has no impact on size/alignment, but I'm still not sure about that decision (although it is easily changed). For 2d isometries — which are encoded by four floats — the idea of shoving them into a single 128-bit buffer (`__m128` or whatever) sounds kind of enticing, but it's more involved and would involve writing unsafe code, so I didn't do that for now. ## Future work - Expand the API to include shortcuts like `inverse_mul` and `inverse_transform` for efficiency reasons. - Include more convenience constructors and methods (e.g. `from_xy`, `from_xyz`). - Refactor `bevy_math::bounding` to use the isometry types. - Add conversions to/from isometries for `Transform`/`GlobalTransform` in `bevy_transform`.
2024-07-14 15:27:42 +00:00
impl Mul for Isometry3d {
type Output = Self;
#[inline]
fn mul(self, rhs: Self) -> Self::Output {
Isometry3d {
rotation: self.rotation * rhs.rotation,
translation: self.rotation * rhs.translation + self.translation,
}
}
}
impl Mul<Vec3A> for Isometry3d {
type Output = Vec3A;
#[inline]
fn mul(self, rhs: Vec3A) -> Self::Output {
self.transform_point(rhs)
}
}
impl Mul<Vec3> for Isometry3d {
type Output = Vec3;
#[inline]
fn mul(self, rhs: Vec3) -> Self::Output {
self.transform_point(rhs).into()
}
}
impl Mul<Dir3> for Isometry3d {
type Output = Dir3;
#[inline]
fn mul(self, rhs: Dir3) -> Self::Output {
self.rotation * rhs
}
}
#[cfg(feature = "approx")]
impl AbsDiffEq for Isometry3d {
type Epsilon = <f32 as AbsDiffEq>::Epsilon;
fn default_epsilon() -> Self::Epsilon {
f32::default_epsilon()
}
fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool {
self.rotation.abs_diff_eq(other.rotation, epsilon)
&& self.translation.abs_diff_eq(other.translation, epsilon)
}
}
#[cfg(feature = "approx")]
impl RelativeEq for Isometry3d {
fn default_max_relative() -> Self::Epsilon {
Self::default_epsilon()
}
fn relative_eq(
&self,
other: &Self,
epsilon: Self::Epsilon,
max_relative: Self::Epsilon,
) -> bool {
self.rotation
.relative_eq(&other.rotation, epsilon, max_relative)
&& self
.translation
.relative_eq(&other.translation, epsilon, max_relative)
}
}
#[cfg(feature = "approx")]
impl UlpsEq for Isometry3d {
fn default_max_ulps() -> u32 {
4
}
fn ulps_eq(&self, other: &Self, epsilon: Self::Epsilon, max_ulps: u32) -> bool {
self.rotation.ulps_eq(&other.rotation, epsilon, max_ulps)
&& self
.translation
.ulps_eq(&other.translation, epsilon, max_ulps)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{vec2, vec3, vec3a};
Basic isometry types (#14269) # Objective Introduce isometry types for describing relative and absolute position in mathematical contexts. ## Solution For the time being, this is a very minimal implementation. This implements the following faculties for two- and three-dimensional isometry types: - Identity transformations - Creation from translations and/or rotations - Inverses - Multiplication (composition) of isometries with each other - Application of isometries to points (as vectors) - Conversion of isometries to affine transformations There is obviously a lot more that could be added, so I erred on the side of adding things that I knew would be useful, with the idea of expanding this in the near future as needed. (I also fixed some random doc problems in `bevy_math`.) --- ## Design One point of interest here is the matter of if/when to use aligned types. In the implementation of 3d isometries, I used `Vec3A` rather than `Vec3` because it has no impact on size/alignment, but I'm still not sure about that decision (although it is easily changed). For 2d isometries — which are encoded by four floats — the idea of shoving them into a single 128-bit buffer (`__m128` or whatever) sounds kind of enticing, but it's more involved and would involve writing unsafe code, so I didn't do that for now. ## Future work - Expand the API to include shortcuts like `inverse_mul` and `inverse_transform` for efficiency reasons. - Include more convenience constructors and methods (e.g. `from_xy`, `from_xyz`). - Refactor `bevy_math::bounding` to use the isometry types. - Add conversions to/from isometries for `Transform`/`GlobalTransform` in `bevy_transform`.
2024-07-14 15:27:42 +00:00
use approx::assert_abs_diff_eq;
Add `core` and `alloc` over `std` Lints (#15281) # Objective - Fixes #6370 - Closes #6581 ## Solution - Added the following lints to the workspace: - `std_instead_of_core` - `std_instead_of_alloc` - `alloc_instead_of_core` - Used `cargo +nightly fmt` with [item level use formatting](https://rust-lang.github.io/rustfmt/?version=v1.6.0&search=#Item%5C%3A) to split all `use` statements into single items. - Used `cargo clippy --workspace --all-targets --all-features --fix --allow-dirty` to _attempt_ to resolve the new linting issues, and intervened where the lint was unable to resolve the issue automatically (usually due to needing an `extern crate alloc;` statement in a crate root). - Manually removed certain uses of `std` where negative feature gating prevented `--all-features` from finding the offending uses. - Used `cargo +nightly fmt` with [crate level use formatting](https://rust-lang.github.io/rustfmt/?version=v1.6.0&search=#Crate%5C%3A) to re-merge all `use` statements matching Bevy's previous styling. - Manually fixed cases where the `fmt` tool could not re-merge `use` statements due to conditional compilation attributes. ## Testing - Ran CI locally ## Migration Guide The MSRV is now 1.81. Please update to this version or higher. ## Notes - This is a _massive_ change to try and push through, which is why I've outlined the semi-automatic steps I used to create this PR, in case this fails and someone else tries again in the future. - Making this change has no impact on user code, but does mean Bevy contributors will be warned to use `core` and `alloc` instead of `std` where possible. - This lint is a critical first step towards investigating `no_std` options for Bevy. --------- Co-authored-by: François Mockers <francois.mockers@vleue.com>
2024-09-27 00:59:59 +00:00
use core::f32::consts::{FRAC_PI_2, FRAC_PI_3};
Basic isometry types (#14269) # Objective Introduce isometry types for describing relative and absolute position in mathematical contexts. ## Solution For the time being, this is a very minimal implementation. This implements the following faculties for two- and three-dimensional isometry types: - Identity transformations - Creation from translations and/or rotations - Inverses - Multiplication (composition) of isometries with each other - Application of isometries to points (as vectors) - Conversion of isometries to affine transformations There is obviously a lot more that could be added, so I erred on the side of adding things that I knew would be useful, with the idea of expanding this in the near future as needed. (I also fixed some random doc problems in `bevy_math`.) --- ## Design One point of interest here is the matter of if/when to use aligned types. In the implementation of 3d isometries, I used `Vec3A` rather than `Vec3` because it has no impact on size/alignment, but I'm still not sure about that decision (although it is easily changed). For 2d isometries — which are encoded by four floats — the idea of shoving them into a single 128-bit buffer (`__m128` or whatever) sounds kind of enticing, but it's more involved and would involve writing unsafe code, so I didn't do that for now. ## Future work - Expand the API to include shortcuts like `inverse_mul` and `inverse_transform` for efficiency reasons. - Include more convenience constructors and methods (e.g. `from_xy`, `from_xyz`). - Refactor `bevy_math::bounding` to use the isometry types. - Add conversions to/from isometries for `Transform`/`GlobalTransform` in `bevy_transform`.
2024-07-14 15:27:42 +00:00
#[test]
fn mul_2d() {
let iso1 = Isometry2d::new(vec2(1.0, 0.0), Rot2::FRAC_PI_2);
let iso2 = Isometry2d::new(vec2(0.0, 1.0), Rot2::FRAC_PI_2);
let expected = Isometry2d::new(vec2(0.0, 0.0), Rot2::PI);
assert_abs_diff_eq!(iso1 * iso2, expected);
}
#[test]
fn inverse_mul_2d() {
let iso1 = Isometry2d::new(vec2(1.0, 0.0), Rot2::FRAC_PI_2);
let iso2 = Isometry2d::new(vec2(0.0, 0.0), Rot2::PI);
let expected = Isometry2d::new(vec2(0.0, 1.0), Rot2::FRAC_PI_2);
assert_abs_diff_eq!(iso1.inverse_mul(iso2), expected);
}
Basic isometry types (#14269) # Objective Introduce isometry types for describing relative and absolute position in mathematical contexts. ## Solution For the time being, this is a very minimal implementation. This implements the following faculties for two- and three-dimensional isometry types: - Identity transformations - Creation from translations and/or rotations - Inverses - Multiplication (composition) of isometries with each other - Application of isometries to points (as vectors) - Conversion of isometries to affine transformations There is obviously a lot more that could be added, so I erred on the side of adding things that I knew would be useful, with the idea of expanding this in the near future as needed. (I also fixed some random doc problems in `bevy_math`.) --- ## Design One point of interest here is the matter of if/when to use aligned types. In the implementation of 3d isometries, I used `Vec3A` rather than `Vec3` because it has no impact on size/alignment, but I'm still not sure about that decision (although it is easily changed). For 2d isometries — which are encoded by four floats — the idea of shoving them into a single 128-bit buffer (`__m128` or whatever) sounds kind of enticing, but it's more involved and would involve writing unsafe code, so I didn't do that for now. ## Future work - Expand the API to include shortcuts like `inverse_mul` and `inverse_transform` for efficiency reasons. - Include more convenience constructors and methods (e.g. `from_xy`, `from_xyz`). - Refactor `bevy_math::bounding` to use the isometry types. - Add conversions to/from isometries for `Transform`/`GlobalTransform` in `bevy_transform`.
2024-07-14 15:27:42 +00:00
#[test]
fn mul_3d() {
let iso1 = Isometry3d::new(vec3(1.0, 0.0, 0.0), Quat::from_rotation_x(FRAC_PI_2));
let iso2 = Isometry3d::new(vec3(0.0, 1.0, 0.0), Quat::IDENTITY);
let expected = Isometry3d::new(vec3(1.0, 0.0, 1.0), Quat::from_rotation_x(FRAC_PI_2));
assert_abs_diff_eq!(iso1 * iso2, expected);
}
#[test]
fn inverse_mul_3d() {
let iso1 = Isometry3d::new(vec3(1.0, 0.0, 0.0), Quat::from_rotation_x(FRAC_PI_2));
let iso2 = Isometry3d::new(vec3(1.0, 0.0, 1.0), Quat::from_rotation_x(FRAC_PI_2));
let expected = Isometry3d::new(vec3(0.0, 1.0, 0.0), Quat::IDENTITY);
assert_abs_diff_eq!(iso1.inverse_mul(iso2), expected);
}
Basic isometry types (#14269) # Objective Introduce isometry types for describing relative and absolute position in mathematical contexts. ## Solution For the time being, this is a very minimal implementation. This implements the following faculties for two- and three-dimensional isometry types: - Identity transformations - Creation from translations and/or rotations - Inverses - Multiplication (composition) of isometries with each other - Application of isometries to points (as vectors) - Conversion of isometries to affine transformations There is obviously a lot more that could be added, so I erred on the side of adding things that I knew would be useful, with the idea of expanding this in the near future as needed. (I also fixed some random doc problems in `bevy_math`.) --- ## Design One point of interest here is the matter of if/when to use aligned types. In the implementation of 3d isometries, I used `Vec3A` rather than `Vec3` because it has no impact on size/alignment, but I'm still not sure about that decision (although it is easily changed). For 2d isometries — which are encoded by four floats — the idea of shoving them into a single 128-bit buffer (`__m128` or whatever) sounds kind of enticing, but it's more involved and would involve writing unsafe code, so I didn't do that for now. ## Future work - Expand the API to include shortcuts like `inverse_mul` and `inverse_transform` for efficiency reasons. - Include more convenience constructors and methods (e.g. `from_xy`, `from_xyz`). - Refactor `bevy_math::bounding` to use the isometry types. - Add conversions to/from isometries for `Transform`/`GlobalTransform` in `bevy_transform`.
2024-07-14 15:27:42 +00:00
#[test]
fn identity_2d() {
let iso = Isometry2d::new(vec2(-1.0, -0.5), Rot2::degrees(75.0));
assert_abs_diff_eq!(Isometry2d::IDENTITY * iso, iso);
assert_abs_diff_eq!(iso * Isometry2d::IDENTITY, iso);
}
#[test]
fn identity_3d() {
let iso = Isometry3d::new(vec3(-1.0, 2.5, 3.3), Quat::from_rotation_z(FRAC_PI_3));
assert_abs_diff_eq!(Isometry3d::IDENTITY * iso, iso);
assert_abs_diff_eq!(iso * Isometry3d::IDENTITY, iso);
}
#[test]
fn inverse_2d() {
let iso = Isometry2d::new(vec2(-1.0, -0.5), Rot2::degrees(75.0));
let inv = iso.inverse();
assert_abs_diff_eq!(iso * inv, Isometry2d::IDENTITY);
assert_abs_diff_eq!(inv * iso, Isometry2d::IDENTITY);
}
#[test]
fn inverse_3d() {
let iso = Isometry3d::new(vec3(-1.0, 2.5, 3.3), Quat::from_rotation_z(FRAC_PI_3));
let inv = iso.inverse();
assert_abs_diff_eq!(iso * inv, Isometry3d::IDENTITY);
assert_abs_diff_eq!(inv * iso, Isometry3d::IDENTITY);
}
#[test]
fn transform_2d() {
let iso = Isometry2d::new(vec2(0.5, -0.5), Rot2::FRAC_PI_2);
let point = vec2(1.0, 1.0);
assert_abs_diff_eq!(vec2(-0.5, 0.5), iso * point);
}
#[test]
fn inverse_transform_2d() {
let iso = Isometry2d::new(vec2(0.5, -0.5), Rot2::FRAC_PI_2);
let point = vec2(-0.5, 0.5);
assert_abs_diff_eq!(vec2(1.0, 1.0), iso.inverse_transform_point(point));
}
Basic isometry types (#14269) # Objective Introduce isometry types for describing relative and absolute position in mathematical contexts. ## Solution For the time being, this is a very minimal implementation. This implements the following faculties for two- and three-dimensional isometry types: - Identity transformations - Creation from translations and/or rotations - Inverses - Multiplication (composition) of isometries with each other - Application of isometries to points (as vectors) - Conversion of isometries to affine transformations There is obviously a lot more that could be added, so I erred on the side of adding things that I knew would be useful, with the idea of expanding this in the near future as needed. (I also fixed some random doc problems in `bevy_math`.) --- ## Design One point of interest here is the matter of if/when to use aligned types. In the implementation of 3d isometries, I used `Vec3A` rather than `Vec3` because it has no impact on size/alignment, but I'm still not sure about that decision (although it is easily changed). For 2d isometries — which are encoded by four floats — the idea of shoving them into a single 128-bit buffer (`__m128` or whatever) sounds kind of enticing, but it's more involved and would involve writing unsafe code, so I didn't do that for now. ## Future work - Expand the API to include shortcuts like `inverse_mul` and `inverse_transform` for efficiency reasons. - Include more convenience constructors and methods (e.g. `from_xy`, `from_xyz`). - Refactor `bevy_math::bounding` to use the isometry types. - Add conversions to/from isometries for `Transform`/`GlobalTransform` in `bevy_transform`.
2024-07-14 15:27:42 +00:00
#[test]
fn transform_3d() {
let iso = Isometry3d::new(vec3(1.0, 0.0, 0.0), Quat::from_rotation_y(FRAC_PI_2));
let point = vec3(1.0, 1.0, 1.0);
assert_abs_diff_eq!(vec3(2.0, 1.0, -1.0), iso * point);
}
#[test]
fn inverse_transform_3d() {
let iso = Isometry3d::new(vec3(1.0, 0.0, 0.0), Quat::from_rotation_y(FRAC_PI_2));
let point = vec3(2.0, 1.0, -1.0);
assert_abs_diff_eq!(vec3a(1.0, 1.0, 1.0), iso.inverse_transform_point(point));
}
Basic isometry types (#14269) # Objective Introduce isometry types for describing relative and absolute position in mathematical contexts. ## Solution For the time being, this is a very minimal implementation. This implements the following faculties for two- and three-dimensional isometry types: - Identity transformations - Creation from translations and/or rotations - Inverses - Multiplication (composition) of isometries with each other - Application of isometries to points (as vectors) - Conversion of isometries to affine transformations There is obviously a lot more that could be added, so I erred on the side of adding things that I knew would be useful, with the idea of expanding this in the near future as needed. (I also fixed some random doc problems in `bevy_math`.) --- ## Design One point of interest here is the matter of if/when to use aligned types. In the implementation of 3d isometries, I used `Vec3A` rather than `Vec3` because it has no impact on size/alignment, but I'm still not sure about that decision (although it is easily changed). For 2d isometries — which are encoded by four floats — the idea of shoving them into a single 128-bit buffer (`__m128` or whatever) sounds kind of enticing, but it's more involved and would involve writing unsafe code, so I didn't do that for now. ## Future work - Expand the API to include shortcuts like `inverse_mul` and `inverse_transform` for efficiency reasons. - Include more convenience constructors and methods (e.g. `from_xy`, `from_xyz`). - Refactor `bevy_math::bounding` to use the isometry types. - Add conversions to/from isometries for `Transform`/`GlobalTransform` in `bevy_transform`.
2024-07-14 15:27:42 +00:00
}