2024-02-26 13:57:49 +00:00
|
|
|
use crate::{
|
|
|
|
primitives::{Primitive2d, Primitive3d},
|
2024-06-05 21:51:13 +00:00
|
|
|
Quat, Rot2, Vec2, Vec3, Vec3A,
|
2024-02-26 13:57:49 +00:00
|
|
|
};
|
|
|
|
|
2024-06-03 15:14:13 +00:00
|
|
|
use core::f32::consts::FRAC_1_SQRT_2;
|
|
|
|
|
2024-05-27 14:15:22 +00:00
|
|
|
#[cfg(feature = "bevy_reflect")]
|
|
|
|
use bevy_reflect::Reflect;
|
|
|
|
#[cfg(all(feature = "serialize", feature = "bevy_reflect"))]
|
|
|
|
use bevy_reflect::{ReflectDeserialize, ReflectSerialize};
|
|
|
|
|
2024-02-26 13:57:49 +00:00
|
|
|
/// An error indicating that a direction is invalid.
|
|
|
|
#[derive(Debug, PartialEq)]
|
|
|
|
pub enum InvalidDirectionError {
|
|
|
|
/// The length of the direction vector is zero or very close to zero.
|
|
|
|
Zero,
|
|
|
|
/// The length of the direction vector is `std::f32::INFINITY`.
|
|
|
|
Infinite,
|
|
|
|
/// The length of the direction vector is `NaN`.
|
|
|
|
NaN,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl InvalidDirectionError {
|
|
|
|
/// Creates an [`InvalidDirectionError`] from the length of an invalid direction vector.
|
|
|
|
pub fn from_length(length: f32) -> Self {
|
|
|
|
if length.is_nan() {
|
|
|
|
InvalidDirectionError::NaN
|
|
|
|
} else if !length.is_finite() {
|
|
|
|
// If the direction is non-finite but also not NaN, it must be infinite
|
|
|
|
InvalidDirectionError::Infinite
|
|
|
|
} else {
|
|
|
|
// If the direction is invalid but neither NaN nor infinite, it must be zero
|
|
|
|
InvalidDirectionError::Zero
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-09-27 00:59:59 +00:00
|
|
|
impl core::fmt::Display for InvalidDirectionError {
|
|
|
|
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
2024-02-26 13:57:49 +00:00
|
|
|
write!(
|
|
|
|
f,
|
|
|
|
"Direction can not be zero (or very close to zero), or non-finite."
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Improve error messages for denormalized directions (#12278)
# Objective
`Dir3` and `Dir3A` can be rotated using `Quat`s. However, if enough
floating point error accumulates or (more commonly) the rotation itself
is degenerate (like not normalized), the resulting direction can also
become denormalized.
Currently, with debug assertions enabled, it panics in these cases with
the message `rotated.is_normalized()`. This error message is unclear,
doesn't give information about *how* it is denormalized (like is the
length too large, NaN, or something else), and is overall not very
helpful. Panicking for small-ish error might also be a bit too strict,
and has lead to unwanted crashes in crates like `bevy_xpbd` (although it
has also helped in finding actual bugs).
The error message should be clearer and give more context, and it
shouldn't cause unwanted crashes.
## Solution
Change the `debug_assert!` to a warning for small error with a (squared
length) threshold of 2e-4 and a panic for clear error with a threshold
of 2e-2. The warnings mention the direction type and the length of the
denormalized vector.
Here's what the error and warning look like:
```
Error: `Dir3` is denormalized after rotation. The length is 1.014242.
```
```
Warning: `Dir3A` is denormalized after rotation. The length is 1.0001414.
```
I gave the same treatment to `new_unchecked`:
```
Error: The vector given to `Dir3::new_unchecked` is not normalized. The length is 1.014242.
```
```
Warning: The vector given to `Dir3A::new_unchecked` is not normalized. The length is 1.0001414.
```
---
## Discussion
### Threshold values
The thresholds are somewhat arbitrary. 2e-4 is what Glam uses for the
squared length in `is_normalized` (after I corrected it in
bitshifter/glam-rs#480), and 2e-2 is just what I thought could be a
clear sign of something being critically wrong. I can definitely tune
them if there are better thresholds though.
### Logging
`bevy_math` doesn't have `bevy_log`, so we can't use `warn!` or
`error!`. This is why I made it use just `eprintln!` and `panic!` for
now. Let me know if there's a better way of logging errors in
`bevy_math`.
2024-03-04 00:01:32 +00:00
|
|
|
/// Checks that a vector with the given squared length is normalized.
|
|
|
|
///
|
|
|
|
/// Warns for small error with a length threshold of approximately `1e-4`,
|
|
|
|
/// and panics for large error with a length threshold of approximately `1e-2`.
|
|
|
|
///
|
|
|
|
/// The format used for the logged warning is `"Warning: {warning} The length is {length}`,
|
|
|
|
/// and similarly for the error.
|
|
|
|
#[cfg(debug_assertions)]
|
|
|
|
fn assert_is_normalized(message: &str, length_squared: f32) {
|
|
|
|
let length_error_squared = (length_squared - 1.0).abs();
|
|
|
|
|
|
|
|
// Panic for large error and warn for slight error.
|
|
|
|
if length_error_squared > 2e-2 || length_error_squared.is_nan() {
|
|
|
|
// Length error is approximately 1e-2 or more.
|
|
|
|
panic!("Error: {message} The length is {}.", length_squared.sqrt());
|
|
|
|
} else if length_error_squared > 2e-4 {
|
|
|
|
// Length error is approximately 1e-4 or more.
|
|
|
|
eprintln!(
|
|
|
|
"Warning: {message} The length is {}.",
|
|
|
|
length_squared.sqrt()
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Rename `Direction2d/3d` to `Dir2/3` (#12189)
# Objective
Split up from #12017, rename Bevy's direction types.
Currently, Bevy has the `Direction2d`, `Direction3d`, and `Direction3dA`
types, which provide a type-level guarantee that their contained vectors
remain normalized. They can be very useful for a lot of APIs for safety,
explicitness, and in some cases performance, as they can sometimes avoid
unnecessary normalizations.
However, many consider them to be inconvenient to use, and opt for
standard vector types like `Vec3` because of this. One reason is that
the direction type names are a bit long and can be annoying to write (of
course you can use autocomplete, but just typing `Vec3` is still nicer),
and in some intances, the extra characters can make formatting worse.
The naming is also inconsistent with Glam's shorter type names, and
results in names like `Direction3dA`, which (in my opinion) are
difficult to read and even a bit ugly.
This PR proposes renaming the types to `Dir2`, `Dir3`, and `Dir3A`.
These names are nice and easy to write, consistent with Glam, and work
well for variants like the SIMD aligned `Dir3A`. As a bonus, it can also
result in nicer formatting in a lot of cases, which can be seen from the
diff of this PR.
Some examples of what it looks like: (copied from #12017)
```rust
// Before
let ray_cast = RayCast2d::new(Vec2::ZERO, Direction2d::X, 5.0);
// After
let ray_cast = RayCast2d::new(Vec2::ZERO, Dir2::X, 5.0);
```
```rust
// Before (an example using Bevy XPBD)
let hit = spatial_query.cast_ray(
Vec3::ZERO,
Direction3d::X,
f32::MAX,
true,
SpatialQueryFilter::default(),
);
// After
let hit = spatial_query.cast_ray(
Vec3::ZERO,
Dir3::X,
f32::MAX,
true,
SpatialQueryFilter::default(),
);
```
```rust
// Before
self.circle(
Vec3::new(0.0, -2.0, 0.0),
Direction3d::Y,
5.0,
Color::TURQUOISE,
);
// After (formatting is collapsed in this case)
self.circle(Vec3::new(0.0, -2.0, 0.0), Dir3::Y, 5.0, Color::TURQUOISE);
```
## Solution
Rename `Direction2d`, `Direction3d`, and `Direction3dA` to `Dir2`,
`Dir3`, and `Dir3A`.
---
## Migration Guide
The `Direction2d` and `Direction3d` types have been renamed to `Dir2`
and `Dir3`.
## Additional Context
This has been brought up on the Discord a few times, and we had a small
[poll](https://discord.com/channels/691052431525675048/1203087353850364004/1212465038711984158)
on this. `Dir2`/`Dir3`/`Dir3A` was quite unanimously chosen as the best
option, but of course it was a very small poll and inconclusive, so
other opinions are certainly welcome too.
---------
Co-authored-by: IceSentry <c.giguere42@gmail.com>
2024-02-28 22:48:43 +00:00
|
|
|
/// A normalized vector pointing in a direction in 2D space
|
|
|
|
#[deprecated(
|
|
|
|
since = "0.14.0",
|
|
|
|
note = "`Direction2d` has been renamed. Please use `Dir2` instead."
|
|
|
|
)]
|
|
|
|
pub type Direction2d = Dir2;
|
|
|
|
|
|
|
|
/// A normalized vector pointing in a direction in 3D space
|
|
|
|
#[deprecated(
|
|
|
|
since = "0.14.0",
|
|
|
|
note = "`Direction3d` has been renamed. Please use `Dir3` instead."
|
|
|
|
)]
|
|
|
|
pub type Direction3d = Dir3;
|
|
|
|
|
2024-02-26 13:57:49 +00:00
|
|
|
/// A normalized vector pointing in a direction in 2D space
|
|
|
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
|
|
|
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
|
2024-05-27 14:15:22 +00:00
|
|
|
#[cfg_attr(feature = "bevy_reflect", derive(Reflect), reflect(Debug, PartialEq))]
|
|
|
|
#[cfg_attr(
|
|
|
|
all(feature = "serialize", feature = "bevy_reflect"),
|
|
|
|
reflect(Serialize, Deserialize)
|
|
|
|
)]
|
Rename `Direction2d/3d` to `Dir2/3` (#12189)
# Objective
Split up from #12017, rename Bevy's direction types.
Currently, Bevy has the `Direction2d`, `Direction3d`, and `Direction3dA`
types, which provide a type-level guarantee that their contained vectors
remain normalized. They can be very useful for a lot of APIs for safety,
explicitness, and in some cases performance, as they can sometimes avoid
unnecessary normalizations.
However, many consider them to be inconvenient to use, and opt for
standard vector types like `Vec3` because of this. One reason is that
the direction type names are a bit long and can be annoying to write (of
course you can use autocomplete, but just typing `Vec3` is still nicer),
and in some intances, the extra characters can make formatting worse.
The naming is also inconsistent with Glam's shorter type names, and
results in names like `Direction3dA`, which (in my opinion) are
difficult to read and even a bit ugly.
This PR proposes renaming the types to `Dir2`, `Dir3`, and `Dir3A`.
These names are nice and easy to write, consistent with Glam, and work
well for variants like the SIMD aligned `Dir3A`. As a bonus, it can also
result in nicer formatting in a lot of cases, which can be seen from the
diff of this PR.
Some examples of what it looks like: (copied from #12017)
```rust
// Before
let ray_cast = RayCast2d::new(Vec2::ZERO, Direction2d::X, 5.0);
// After
let ray_cast = RayCast2d::new(Vec2::ZERO, Dir2::X, 5.0);
```
```rust
// Before (an example using Bevy XPBD)
let hit = spatial_query.cast_ray(
Vec3::ZERO,
Direction3d::X,
f32::MAX,
true,
SpatialQueryFilter::default(),
);
// After
let hit = spatial_query.cast_ray(
Vec3::ZERO,
Dir3::X,
f32::MAX,
true,
SpatialQueryFilter::default(),
);
```
```rust
// Before
self.circle(
Vec3::new(0.0, -2.0, 0.0),
Direction3d::Y,
5.0,
Color::TURQUOISE,
);
// After (formatting is collapsed in this case)
self.circle(Vec3::new(0.0, -2.0, 0.0), Dir3::Y, 5.0, Color::TURQUOISE);
```
## Solution
Rename `Direction2d`, `Direction3d`, and `Direction3dA` to `Dir2`,
`Dir3`, and `Dir3A`.
---
## Migration Guide
The `Direction2d` and `Direction3d` types have been renamed to `Dir2`
and `Dir3`.
## Additional Context
This has been brought up on the Discord a few times, and we had a small
[poll](https://discord.com/channels/691052431525675048/1203087353850364004/1212465038711984158)
on this. `Dir2`/`Dir3`/`Dir3A` was quite unanimously chosen as the best
option, but of course it was a very small poll and inconclusive, so
other opinions are certainly welcome too.
---------
Co-authored-by: IceSentry <c.giguere42@gmail.com>
2024-02-28 22:48:43 +00:00
|
|
|
#[doc(alias = "Direction2d")]
|
|
|
|
pub struct Dir2(Vec2);
|
|
|
|
impl Primitive2d for Dir2 {}
|
2024-02-26 13:57:49 +00:00
|
|
|
|
Rename `Direction2d/3d` to `Dir2/3` (#12189)
# Objective
Split up from #12017, rename Bevy's direction types.
Currently, Bevy has the `Direction2d`, `Direction3d`, and `Direction3dA`
types, which provide a type-level guarantee that their contained vectors
remain normalized. They can be very useful for a lot of APIs for safety,
explicitness, and in some cases performance, as they can sometimes avoid
unnecessary normalizations.
However, many consider them to be inconvenient to use, and opt for
standard vector types like `Vec3` because of this. One reason is that
the direction type names are a bit long and can be annoying to write (of
course you can use autocomplete, but just typing `Vec3` is still nicer),
and in some intances, the extra characters can make formatting worse.
The naming is also inconsistent with Glam's shorter type names, and
results in names like `Direction3dA`, which (in my opinion) are
difficult to read and even a bit ugly.
This PR proposes renaming the types to `Dir2`, `Dir3`, and `Dir3A`.
These names are nice and easy to write, consistent with Glam, and work
well for variants like the SIMD aligned `Dir3A`. As a bonus, it can also
result in nicer formatting in a lot of cases, which can be seen from the
diff of this PR.
Some examples of what it looks like: (copied from #12017)
```rust
// Before
let ray_cast = RayCast2d::new(Vec2::ZERO, Direction2d::X, 5.0);
// After
let ray_cast = RayCast2d::new(Vec2::ZERO, Dir2::X, 5.0);
```
```rust
// Before (an example using Bevy XPBD)
let hit = spatial_query.cast_ray(
Vec3::ZERO,
Direction3d::X,
f32::MAX,
true,
SpatialQueryFilter::default(),
);
// After
let hit = spatial_query.cast_ray(
Vec3::ZERO,
Dir3::X,
f32::MAX,
true,
SpatialQueryFilter::default(),
);
```
```rust
// Before
self.circle(
Vec3::new(0.0, -2.0, 0.0),
Direction3d::Y,
5.0,
Color::TURQUOISE,
);
// After (formatting is collapsed in this case)
self.circle(Vec3::new(0.0, -2.0, 0.0), Dir3::Y, 5.0, Color::TURQUOISE);
```
## Solution
Rename `Direction2d`, `Direction3d`, and `Direction3dA` to `Dir2`,
`Dir3`, and `Dir3A`.
---
## Migration Guide
The `Direction2d` and `Direction3d` types have been renamed to `Dir2`
and `Dir3`.
## Additional Context
This has been brought up on the Discord a few times, and we had a small
[poll](https://discord.com/channels/691052431525675048/1203087353850364004/1212465038711984158)
on this. `Dir2`/`Dir3`/`Dir3A` was quite unanimously chosen as the best
option, but of course it was a very small poll and inconclusive, so
other opinions are certainly welcome too.
---------
Co-authored-by: IceSentry <c.giguere42@gmail.com>
2024-02-28 22:48:43 +00:00
|
|
|
impl Dir2 {
|
2024-02-26 13:57:49 +00:00
|
|
|
/// A unit vector pointing along the positive X axis.
|
|
|
|
pub const X: Self = Self(Vec2::X);
|
|
|
|
/// A unit vector pointing along the positive Y axis.
|
|
|
|
pub const Y: Self = Self(Vec2::Y);
|
|
|
|
/// A unit vector pointing along the negative X axis.
|
|
|
|
pub const NEG_X: Self = Self(Vec2::NEG_X);
|
|
|
|
/// A unit vector pointing along the negative Y axis.
|
|
|
|
pub const NEG_Y: Self = Self(Vec2::NEG_Y);
|
2024-05-09 23:30:44 +00:00
|
|
|
/// The directional axes.
|
|
|
|
pub const AXES: [Self; 2] = [Self::X, Self::Y];
|
2024-02-26 13:57:49 +00:00
|
|
|
|
2024-06-03 15:14:13 +00:00
|
|
|
/// The "north" direction, equivalent to [`Dir2::Y`].
|
|
|
|
pub const NORTH: Self = Self(Vec2::Y);
|
|
|
|
/// The "south" direction, equivalent to [`Dir2::NEG_Y`].
|
|
|
|
pub const SOUTH: Self = Self(Vec2::NEG_Y);
|
|
|
|
/// The "east" direction, equivalent to [`Dir2::X`].
|
|
|
|
pub const EAST: Self = Self(Vec2::X);
|
|
|
|
/// The "west" direction, equivalent to [`Dir2::NEG_X`].
|
|
|
|
pub const WEST: Self = Self(Vec2::NEG_X);
|
|
|
|
/// The "north-east" direction, between [`Dir2::NORTH`] and [`Dir2::EAST`].
|
|
|
|
pub const NORTH_EAST: Self = Self(Vec2::new(FRAC_1_SQRT_2, FRAC_1_SQRT_2));
|
|
|
|
/// The "north-west" direction, between [`Dir2::NORTH`] and [`Dir2::WEST`].
|
|
|
|
pub const NORTH_WEST: Self = Self(Vec2::new(-FRAC_1_SQRT_2, FRAC_1_SQRT_2));
|
|
|
|
/// The "south-east" direction, between [`Dir2::SOUTH`] and [`Dir2::EAST`].
|
|
|
|
pub const SOUTH_EAST: Self = Self(Vec2::new(FRAC_1_SQRT_2, -FRAC_1_SQRT_2));
|
|
|
|
/// The "south-west" direction, between [`Dir2::SOUTH`] and [`Dir2::WEST`].
|
|
|
|
pub const SOUTH_WEST: Self = Self(Vec2::new(-FRAC_1_SQRT_2, -FRAC_1_SQRT_2));
|
|
|
|
|
2024-05-23 15:20:21 +00:00
|
|
|
/// Create a direction from a finite, nonzero [`Vec2`], normalizing it.
|
2024-02-26 13:57:49 +00:00
|
|
|
///
|
|
|
|
/// Returns [`Err(InvalidDirectionError)`](InvalidDirectionError) if the length
|
|
|
|
/// of the given vector is zero (or very close to zero), infinite, or `NaN`.
|
|
|
|
pub fn new(value: Vec2) -> Result<Self, InvalidDirectionError> {
|
|
|
|
Self::new_and_length(value).map(|(dir, _)| dir)
|
|
|
|
}
|
|
|
|
|
Rename `Direction2d/3d` to `Dir2/3` (#12189)
# Objective
Split up from #12017, rename Bevy's direction types.
Currently, Bevy has the `Direction2d`, `Direction3d`, and `Direction3dA`
types, which provide a type-level guarantee that their contained vectors
remain normalized. They can be very useful for a lot of APIs for safety,
explicitness, and in some cases performance, as they can sometimes avoid
unnecessary normalizations.
However, many consider them to be inconvenient to use, and opt for
standard vector types like `Vec3` because of this. One reason is that
the direction type names are a bit long and can be annoying to write (of
course you can use autocomplete, but just typing `Vec3` is still nicer),
and in some intances, the extra characters can make formatting worse.
The naming is also inconsistent with Glam's shorter type names, and
results in names like `Direction3dA`, which (in my opinion) are
difficult to read and even a bit ugly.
This PR proposes renaming the types to `Dir2`, `Dir3`, and `Dir3A`.
These names are nice and easy to write, consistent with Glam, and work
well for variants like the SIMD aligned `Dir3A`. As a bonus, it can also
result in nicer formatting in a lot of cases, which can be seen from the
diff of this PR.
Some examples of what it looks like: (copied from #12017)
```rust
// Before
let ray_cast = RayCast2d::new(Vec2::ZERO, Direction2d::X, 5.0);
// After
let ray_cast = RayCast2d::new(Vec2::ZERO, Dir2::X, 5.0);
```
```rust
// Before (an example using Bevy XPBD)
let hit = spatial_query.cast_ray(
Vec3::ZERO,
Direction3d::X,
f32::MAX,
true,
SpatialQueryFilter::default(),
);
// After
let hit = spatial_query.cast_ray(
Vec3::ZERO,
Dir3::X,
f32::MAX,
true,
SpatialQueryFilter::default(),
);
```
```rust
// Before
self.circle(
Vec3::new(0.0, -2.0, 0.0),
Direction3d::Y,
5.0,
Color::TURQUOISE,
);
// After (formatting is collapsed in this case)
self.circle(Vec3::new(0.0, -2.0, 0.0), Dir3::Y, 5.0, Color::TURQUOISE);
```
## Solution
Rename `Direction2d`, `Direction3d`, and `Direction3dA` to `Dir2`,
`Dir3`, and `Dir3A`.
---
## Migration Guide
The `Direction2d` and `Direction3d` types have been renamed to `Dir2`
and `Dir3`.
## Additional Context
This has been brought up on the Discord a few times, and we had a small
[poll](https://discord.com/channels/691052431525675048/1203087353850364004/1212465038711984158)
on this. `Dir2`/`Dir3`/`Dir3A` was quite unanimously chosen as the best
option, but of course it was a very small poll and inconclusive, so
other opinions are certainly welcome too.
---------
Co-authored-by: IceSentry <c.giguere42@gmail.com>
2024-02-28 22:48:43 +00:00
|
|
|
/// Create a [`Dir2`] from a [`Vec2`] that is already normalized.
|
2024-02-26 13:57:49 +00:00
|
|
|
///
|
|
|
|
/// # Warning
|
|
|
|
///
|
Improve error messages for denormalized directions (#12278)
# Objective
`Dir3` and `Dir3A` can be rotated using `Quat`s. However, if enough
floating point error accumulates or (more commonly) the rotation itself
is degenerate (like not normalized), the resulting direction can also
become denormalized.
Currently, with debug assertions enabled, it panics in these cases with
the message `rotated.is_normalized()`. This error message is unclear,
doesn't give information about *how* it is denormalized (like is the
length too large, NaN, or something else), and is overall not very
helpful. Panicking for small-ish error might also be a bit too strict,
and has lead to unwanted crashes in crates like `bevy_xpbd` (although it
has also helped in finding actual bugs).
The error message should be clearer and give more context, and it
shouldn't cause unwanted crashes.
## Solution
Change the `debug_assert!` to a warning for small error with a (squared
length) threshold of 2e-4 and a panic for clear error with a threshold
of 2e-2. The warnings mention the direction type and the length of the
denormalized vector.
Here's what the error and warning look like:
```
Error: `Dir3` is denormalized after rotation. The length is 1.014242.
```
```
Warning: `Dir3A` is denormalized after rotation. The length is 1.0001414.
```
I gave the same treatment to `new_unchecked`:
```
Error: The vector given to `Dir3::new_unchecked` is not normalized. The length is 1.014242.
```
```
Warning: The vector given to `Dir3A::new_unchecked` is not normalized. The length is 1.0001414.
```
---
## Discussion
### Threshold values
The thresholds are somewhat arbitrary. 2e-4 is what Glam uses for the
squared length in `is_normalized` (after I corrected it in
bitshifter/glam-rs#480), and 2e-2 is just what I thought could be a
clear sign of something being critically wrong. I can definitely tune
them if there are better thresholds though.
### Logging
`bevy_math` doesn't have `bevy_log`, so we can't use `warn!` or
`error!`. This is why I made it use just `eprintln!` and `panic!` for
now. Let me know if there's a better way of logging errors in
`bevy_math`.
2024-03-04 00:01:32 +00:00
|
|
|
/// `value` must be normalized, i.e its length must be `1.0`.
|
2024-02-26 13:57:49 +00:00
|
|
|
pub fn new_unchecked(value: Vec2) -> Self {
|
Improve error messages for denormalized directions (#12278)
# Objective
`Dir3` and `Dir3A` can be rotated using `Quat`s. However, if enough
floating point error accumulates or (more commonly) the rotation itself
is degenerate (like not normalized), the resulting direction can also
become denormalized.
Currently, with debug assertions enabled, it panics in these cases with
the message `rotated.is_normalized()`. This error message is unclear,
doesn't give information about *how* it is denormalized (like is the
length too large, NaN, or something else), and is overall not very
helpful. Panicking for small-ish error might also be a bit too strict,
and has lead to unwanted crashes in crates like `bevy_xpbd` (although it
has also helped in finding actual bugs).
The error message should be clearer and give more context, and it
shouldn't cause unwanted crashes.
## Solution
Change the `debug_assert!` to a warning for small error with a (squared
length) threshold of 2e-4 and a panic for clear error with a threshold
of 2e-2. The warnings mention the direction type and the length of the
denormalized vector.
Here's what the error and warning look like:
```
Error: `Dir3` is denormalized after rotation. The length is 1.014242.
```
```
Warning: `Dir3A` is denormalized after rotation. The length is 1.0001414.
```
I gave the same treatment to `new_unchecked`:
```
Error: The vector given to `Dir3::new_unchecked` is not normalized. The length is 1.014242.
```
```
Warning: The vector given to `Dir3A::new_unchecked` is not normalized. The length is 1.0001414.
```
---
## Discussion
### Threshold values
The thresholds are somewhat arbitrary. 2e-4 is what Glam uses for the
squared length in `is_normalized` (after I corrected it in
bitshifter/glam-rs#480), and 2e-2 is just what I thought could be a
clear sign of something being critically wrong. I can definitely tune
them if there are better thresholds though.
### Logging
`bevy_math` doesn't have `bevy_log`, so we can't use `warn!` or
`error!`. This is why I made it use just `eprintln!` and `panic!` for
now. Let me know if there's a better way of logging errors in
`bevy_math`.
2024-03-04 00:01:32 +00:00
|
|
|
#[cfg(debug_assertions)]
|
|
|
|
assert_is_normalized(
|
|
|
|
"The vector given to `Dir2::new_unchecked` is not normalized.",
|
|
|
|
value.length_squared(),
|
|
|
|
);
|
2024-02-26 13:57:49 +00:00
|
|
|
|
|
|
|
Self(value)
|
|
|
|
}
|
|
|
|
|
2024-05-23 15:20:21 +00:00
|
|
|
/// Create a direction from a finite, nonzero [`Vec2`], normalizing it and
|
|
|
|
/// also returning its original length.
|
2024-02-26 13:57:49 +00:00
|
|
|
///
|
|
|
|
/// Returns [`Err(InvalidDirectionError)`](InvalidDirectionError) if the length
|
|
|
|
/// of the given vector is zero (or very close to zero), infinite, or `NaN`.
|
|
|
|
pub fn new_and_length(value: Vec2) -> Result<(Self, f32), InvalidDirectionError> {
|
|
|
|
let length = value.length();
|
|
|
|
let direction = (length.is_finite() && length > 0.0).then_some(value / length);
|
|
|
|
|
|
|
|
direction
|
|
|
|
.map(|dir| (Self(dir), length))
|
|
|
|
.ok_or(InvalidDirectionError::from_length(length))
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Create a direction from its `x` and `y` components.
|
|
|
|
///
|
|
|
|
/// Returns [`Err(InvalidDirectionError)`](InvalidDirectionError) if the length
|
|
|
|
/// of the vector formed by the components is zero (or very close to zero), infinite, or `NaN`.
|
|
|
|
pub fn from_xy(x: f32, y: f32) -> Result<Self, InvalidDirectionError> {
|
|
|
|
Self::new(Vec2::new(x, y))
|
|
|
|
}
|
2024-03-18 17:49:58 +00:00
|
|
|
|
2024-08-02 13:10:13 +00:00
|
|
|
/// Create a direction from its `x` and `y` components, assuming the resulting vector is normalized.
|
|
|
|
///
|
|
|
|
/// # Warning
|
|
|
|
///
|
|
|
|
/// The vector produced from `x` and `y` must be normalized, i.e its length must be `1.0`.
|
|
|
|
pub fn from_xy_unchecked(x: f32, y: f32) -> Self {
|
|
|
|
Self::new_unchecked(Vec2::new(x, y))
|
|
|
|
}
|
|
|
|
|
2024-03-18 17:49:58 +00:00
|
|
|
/// Returns the inner [`Vec2`]
|
|
|
|
pub const fn as_vec2(&self) -> Vec2 {
|
|
|
|
self.0
|
|
|
|
}
|
2024-05-21 21:13:32 +00:00
|
|
|
|
|
|
|
/// Performs a spherical linear interpolation between `self` and `rhs`
|
|
|
|
/// based on the value `s`.
|
|
|
|
///
|
|
|
|
/// This corresponds to interpolating between the two directions at a constant angular velocity.
|
|
|
|
///
|
|
|
|
/// When `s == 0.0`, the result will be equal to `self`.
|
|
|
|
/// When `s == 1.0`, the result will be equal to `rhs`.
|
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// # use bevy_math::Dir2;
|
|
|
|
/// # use approx::{assert_relative_eq, RelativeEq};
|
|
|
|
/// #
|
|
|
|
/// let dir1 = Dir2::X;
|
|
|
|
/// let dir2 = Dir2::Y;
|
|
|
|
///
|
|
|
|
/// let result1 = dir1.slerp(dir2, 1.0 / 3.0);
|
|
|
|
/// assert_relative_eq!(result1, Dir2::from_xy(0.75_f32.sqrt(), 0.5).unwrap());
|
|
|
|
///
|
|
|
|
/// let result2 = dir1.slerp(dir2, 0.5);
|
|
|
|
/// assert_relative_eq!(result2, Dir2::from_xy(0.5_f32.sqrt(), 0.5_f32.sqrt()).unwrap());
|
|
|
|
/// ```
|
|
|
|
#[inline]
|
|
|
|
pub fn slerp(self, rhs: Self, s: f32) -> Self {
|
2024-08-06 01:28:00 +00:00
|
|
|
let angle = self.angle_to(rhs.0);
|
2024-06-05 21:51:13 +00:00
|
|
|
Rot2::radians(angle * s) * self
|
2024-05-21 21:13:32 +00:00
|
|
|
}
|
2024-06-04 14:44:29 +00:00
|
|
|
|
|
|
|
/// Get the rotation that rotates this direction to `other`.
|
|
|
|
#[inline]
|
2024-06-05 21:51:13 +00:00
|
|
|
pub fn rotation_to(self, other: Self) -> Rot2 {
|
2024-06-04 14:44:29 +00:00
|
|
|
// Rotate `self` to X-axis, then X-axis to `other`:
|
|
|
|
other.rotation_from_x() * self.rotation_to_x()
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Get the rotation that rotates `other` to this direction.
|
|
|
|
#[inline]
|
2024-06-05 21:51:13 +00:00
|
|
|
pub fn rotation_from(self, other: Self) -> Rot2 {
|
2024-06-04 14:44:29 +00:00
|
|
|
other.rotation_to(self)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Get the rotation that rotates the X-axis to this direction.
|
|
|
|
#[inline]
|
2024-06-05 21:51:13 +00:00
|
|
|
pub fn rotation_from_x(self) -> Rot2 {
|
|
|
|
Rot2::from_sin_cos(self.0.y, self.0.x)
|
2024-06-04 14:44:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Get the rotation that rotates this direction to the X-axis.
|
|
|
|
#[inline]
|
2024-06-05 21:51:13 +00:00
|
|
|
pub fn rotation_to_x(self) -> Rot2 {
|
2024-06-04 14:44:29 +00:00
|
|
|
// (This is cheap, it just negates one component.)
|
|
|
|
self.rotation_from_x().inverse()
|
|
|
|
}
|
|
|
|
|
2024-07-14 17:00:41 +00:00
|
|
|
/// Get the rotation that rotates the Y-axis to this direction.
|
2024-06-04 14:44:29 +00:00
|
|
|
#[inline]
|
2024-06-05 21:51:13 +00:00
|
|
|
pub fn rotation_from_y(self) -> Rot2 {
|
2024-06-04 14:44:29 +00:00
|
|
|
// `x <- y`, `y <- -x` correspond to rotating clockwise by pi/2;
|
|
|
|
// this transforms the Y-axis into the X-axis, maintaining the relative position
|
|
|
|
// of our direction. Then we just use the same technique as `rotation_from_x`.
|
2024-06-05 21:51:13 +00:00
|
|
|
Rot2::from_sin_cos(-self.0.x, self.0.y)
|
2024-06-04 14:44:29 +00:00
|
|
|
}
|
|
|
|
|
2024-07-14 17:00:41 +00:00
|
|
|
/// Get the rotation that rotates this direction to the Y-axis.
|
2024-06-04 14:44:29 +00:00
|
|
|
#[inline]
|
2024-06-05 21:51:13 +00:00
|
|
|
pub fn rotation_to_y(self) -> Rot2 {
|
2024-06-04 14:44:29 +00:00
|
|
|
self.rotation_from_y().inverse()
|
|
|
|
}
|
2024-07-22 18:42:48 +00:00
|
|
|
|
|
|
|
/// Returns `self` after an approximate normalization, assuming the value is already nearly normalized.
|
|
|
|
/// Useful for preventing numerical error accumulation.
|
|
|
|
/// See [`Dir3::fast_renormalize`] for an example of when such error accumulation might occur.
|
|
|
|
#[inline]
|
|
|
|
pub fn fast_renormalize(self) -> Self {
|
|
|
|
let length_squared = self.0.length_squared();
|
|
|
|
// Based on a Taylor approximation of the inverse square root, see [`Dir3::fast_renormalize`] for more details.
|
|
|
|
Self(self * (0.5 * (3.0 - length_squared)))
|
|
|
|
}
|
2024-02-26 13:57:49 +00:00
|
|
|
}
|
|
|
|
|
Rename `Direction2d/3d` to `Dir2/3` (#12189)
# Objective
Split up from #12017, rename Bevy's direction types.
Currently, Bevy has the `Direction2d`, `Direction3d`, and `Direction3dA`
types, which provide a type-level guarantee that their contained vectors
remain normalized. They can be very useful for a lot of APIs for safety,
explicitness, and in some cases performance, as they can sometimes avoid
unnecessary normalizations.
However, many consider them to be inconvenient to use, and opt for
standard vector types like `Vec3` because of this. One reason is that
the direction type names are a bit long and can be annoying to write (of
course you can use autocomplete, but just typing `Vec3` is still nicer),
and in some intances, the extra characters can make formatting worse.
The naming is also inconsistent with Glam's shorter type names, and
results in names like `Direction3dA`, which (in my opinion) are
difficult to read and even a bit ugly.
This PR proposes renaming the types to `Dir2`, `Dir3`, and `Dir3A`.
These names are nice and easy to write, consistent with Glam, and work
well for variants like the SIMD aligned `Dir3A`. As a bonus, it can also
result in nicer formatting in a lot of cases, which can be seen from the
diff of this PR.
Some examples of what it looks like: (copied from #12017)
```rust
// Before
let ray_cast = RayCast2d::new(Vec2::ZERO, Direction2d::X, 5.0);
// After
let ray_cast = RayCast2d::new(Vec2::ZERO, Dir2::X, 5.0);
```
```rust
// Before (an example using Bevy XPBD)
let hit = spatial_query.cast_ray(
Vec3::ZERO,
Direction3d::X,
f32::MAX,
true,
SpatialQueryFilter::default(),
);
// After
let hit = spatial_query.cast_ray(
Vec3::ZERO,
Dir3::X,
f32::MAX,
true,
SpatialQueryFilter::default(),
);
```
```rust
// Before
self.circle(
Vec3::new(0.0, -2.0, 0.0),
Direction3d::Y,
5.0,
Color::TURQUOISE,
);
// After (formatting is collapsed in this case)
self.circle(Vec3::new(0.0, -2.0, 0.0), Dir3::Y, 5.0, Color::TURQUOISE);
```
## Solution
Rename `Direction2d`, `Direction3d`, and `Direction3dA` to `Dir2`,
`Dir3`, and `Dir3A`.
---
## Migration Guide
The `Direction2d` and `Direction3d` types have been renamed to `Dir2`
and `Dir3`.
## Additional Context
This has been brought up on the Discord a few times, and we had a small
[poll](https://discord.com/channels/691052431525675048/1203087353850364004/1212465038711984158)
on this. `Dir2`/`Dir3`/`Dir3A` was quite unanimously chosen as the best
option, but of course it was a very small poll and inconclusive, so
other opinions are certainly welcome too.
---------
Co-authored-by: IceSentry <c.giguere42@gmail.com>
2024-02-28 22:48:43 +00:00
|
|
|
impl TryFrom<Vec2> for Dir2 {
|
2024-02-26 13:57:49 +00:00
|
|
|
type Error = InvalidDirectionError;
|
|
|
|
|
|
|
|
fn try_from(value: Vec2) -> Result<Self, Self::Error> {
|
|
|
|
Self::new(value)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-03-20 14:21:50 +00:00
|
|
|
impl From<Dir2> for Vec2 {
|
|
|
|
fn from(value: Dir2) -> Self {
|
|
|
|
value.as_vec2()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-09-27 00:59:59 +00:00
|
|
|
impl core::ops::Deref for Dir2 {
|
2024-02-26 13:57:49 +00:00
|
|
|
type Target = Vec2;
|
|
|
|
fn deref(&self) -> &Self::Target {
|
|
|
|
&self.0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-09-27 00:59:59 +00:00
|
|
|
impl core::ops::Neg for Dir2 {
|
2024-02-26 13:57:49 +00:00
|
|
|
type Output = Self;
|
|
|
|
fn neg(self) -> Self::Output {
|
|
|
|
Self(-self.0)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-09-27 00:59:59 +00:00
|
|
|
impl core::ops::Mul<f32> for Dir2 {
|
2024-03-03 17:44:16 +00:00
|
|
|
type Output = Vec2;
|
|
|
|
fn mul(self, rhs: f32) -> Self::Output {
|
|
|
|
self.0 * rhs
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-09-27 00:59:59 +00:00
|
|
|
impl core::ops::Mul<Dir2> for f32 {
|
2024-03-03 17:44:16 +00:00
|
|
|
type Output = Vec2;
|
|
|
|
fn mul(self, rhs: Dir2) -> Self::Output {
|
|
|
|
self * rhs.0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-09-27 00:59:59 +00:00
|
|
|
impl core::ops::Mul<Dir2> for Rot2 {
|
Add `Rotation2d` (#11658)
# Objective
Rotating vectors is a very common task. It is required for a variety of
things both within Bevy itself and in many third party plugins, for
example all over physics and collision detection, and for things like
Bevy's bounding volumes and several gizmo implementations.
For 3D, we can do this using a `Quat`, but for 2D, we do not have a
clear and efficient option. `Mat2` can be used for rotating vectors if
created using `Mat2::from_angle`, but this is not obvious to many users,
it doesn't have many rotation helpers, and the type does not give any
guarantees that it represents a valid rotation.
We should have a proper type for 2D rotations. In addition to allowing
for potential optimization, it would allow us to have a consistent and
explicitly documented representation used throughout the engine, i.e.
counterclockwise and in radians.
## Representation
The mathematical formula for rotating a 2D vector is the following:
```
new_x = x * cos - y * sin
new_y = x * sin + y * cos
```
Here, `sin` and `cos` are the sine and cosine of the rotation angle.
Computing these every time when a vector needs to be rotated can be
expensive, so the rotation shouldn't be just an `f32` angle. Instead, it
is often more efficient to represent the rotation using the sine and
cosine of the angle instead of storing the angle itself. This can be
freely passed around and reused without unnecessary computations.
The two options are either a 2x2 rotation matrix or a unit complex
number where the cosine is the real part and the sine is the imaginary
part. These are equivalent for the most part, but the unit complex
representation is a bit more memory efficient (two `f32`s instead of
four), so I chose that. This is like Nalgebra's
[`UnitComplex`](https://docs.rs/nalgebra/latest/nalgebra/geometry/type.UnitComplex.html)
type, which can be used for the
[`Rotation2`](https://docs.rs/nalgebra/latest/nalgebra/geometry/type.Rotation2.html)
type.
## Implementation
Add a `Rotation2d` type represented as a unit complex number:
```rust
/// A counterclockwise 2D rotation in radians.
///
/// The rotation angle is wrapped to be within the `]-pi, pi]` range.
pub struct Rotation2d {
/// The cosine of the rotation angle in radians.
///
/// This is the real part of the unit complex number representing the rotation.
pub cos: f32,
/// The sine of the rotation angle in radians.
///
/// This is the imaginary part of the unit complex number representing the rotation.
pub sin: f32,
}
```
Using it is similar to using `Quat`, but in 2D:
```rust
let rotation = Rotation2d::radians(PI / 2.0);
// Rotate vector (also works on Direction2d!)
assert_eq!(rotation * Vec2::X, Vec2::Y);
// Get angle as degrees
assert_eq!(rotation.as_degrees(), 90.0);
// Getting sin and cos is free
let (sin, cos) = rotation.sin_cos();
// "Subtract" rotations
let rotation2 = Rotation2d::FRAC_PI_4; // there are constants!
let diff = rotation * rotation2.inverse();
assert_eq!(diff.as_radians(), PI / 4.0);
// This is equivalent to the above
assert_eq!(rotation2.angle_between(rotation), PI / 4.0);
// Lerp
let rotation1 = Rotation2d::IDENTITY;
let rotation2 = Rotation2d::FRAC_PI_2;
let result = rotation1.lerp(rotation2, 0.5);
assert_eq!(result.as_radians(), std::f32::consts::FRAC_PI_4);
// Slerp
let rotation1 = Rotation2d::FRAC_PI_4);
let rotation2 = Rotation2d::degrees(-180.0); // we can use degrees too!
let result = rotation1.slerp(rotation2, 1.0 / 3.0);
assert_eq!(result.as_radians(), std::f32::consts::FRAC_PI_2);
```
There's also a `From<f32>` implementation for `Rotation2d`, which means
that methods can still accept radians as floats if the argument uses
`impl Into<Rotation2d>`. This means that adding `Rotation2d` shouldn't
even be a breaking change.
---
## Changelog
- Added `Rotation2d`
- Bounding volume methods now take an `impl Into<Rotation2d>`
- Gizmo methods with rotation now take an `impl Into<Rotation2d>`
## Future use cases
- Collision detection (a type like this is quite essential considering
how common vector rotations are)
- `Transform` helpers (e.g. return a 2D rotation about the Z axis from a
`Transform`)
- The rotation used for `Transform2d` (#8268)
- More gizmos, maybe meshes... everything in 2D that uses rotation
---------
Co-authored-by: Tristan Guichaoua <33934311+tguichaoua@users.noreply.github.com>
Co-authored-by: Robert Walter <robwalter96@gmail.com>
Co-authored-by: IQuick 143 <IQuick143cz@gmail.com>
2024-03-11 19:11:57 +00:00
|
|
|
type Output = Dir2;
|
|
|
|
|
2024-06-05 21:51:13 +00:00
|
|
|
/// Rotates the [`Dir2`] using a [`Rot2`].
|
Add `Rotation2d` (#11658)
# Objective
Rotating vectors is a very common task. It is required for a variety of
things both within Bevy itself and in many third party plugins, for
example all over physics and collision detection, and for things like
Bevy's bounding volumes and several gizmo implementations.
For 3D, we can do this using a `Quat`, but for 2D, we do not have a
clear and efficient option. `Mat2` can be used for rotating vectors if
created using `Mat2::from_angle`, but this is not obvious to many users,
it doesn't have many rotation helpers, and the type does not give any
guarantees that it represents a valid rotation.
We should have a proper type for 2D rotations. In addition to allowing
for potential optimization, it would allow us to have a consistent and
explicitly documented representation used throughout the engine, i.e.
counterclockwise and in radians.
## Representation
The mathematical formula for rotating a 2D vector is the following:
```
new_x = x * cos - y * sin
new_y = x * sin + y * cos
```
Here, `sin` and `cos` are the sine and cosine of the rotation angle.
Computing these every time when a vector needs to be rotated can be
expensive, so the rotation shouldn't be just an `f32` angle. Instead, it
is often more efficient to represent the rotation using the sine and
cosine of the angle instead of storing the angle itself. This can be
freely passed around and reused without unnecessary computations.
The two options are either a 2x2 rotation matrix or a unit complex
number where the cosine is the real part and the sine is the imaginary
part. These are equivalent for the most part, but the unit complex
representation is a bit more memory efficient (two `f32`s instead of
four), so I chose that. This is like Nalgebra's
[`UnitComplex`](https://docs.rs/nalgebra/latest/nalgebra/geometry/type.UnitComplex.html)
type, which can be used for the
[`Rotation2`](https://docs.rs/nalgebra/latest/nalgebra/geometry/type.Rotation2.html)
type.
## Implementation
Add a `Rotation2d` type represented as a unit complex number:
```rust
/// A counterclockwise 2D rotation in radians.
///
/// The rotation angle is wrapped to be within the `]-pi, pi]` range.
pub struct Rotation2d {
/// The cosine of the rotation angle in radians.
///
/// This is the real part of the unit complex number representing the rotation.
pub cos: f32,
/// The sine of the rotation angle in radians.
///
/// This is the imaginary part of the unit complex number representing the rotation.
pub sin: f32,
}
```
Using it is similar to using `Quat`, but in 2D:
```rust
let rotation = Rotation2d::radians(PI / 2.0);
// Rotate vector (also works on Direction2d!)
assert_eq!(rotation * Vec2::X, Vec2::Y);
// Get angle as degrees
assert_eq!(rotation.as_degrees(), 90.0);
// Getting sin and cos is free
let (sin, cos) = rotation.sin_cos();
// "Subtract" rotations
let rotation2 = Rotation2d::FRAC_PI_4; // there are constants!
let diff = rotation * rotation2.inverse();
assert_eq!(diff.as_radians(), PI / 4.0);
// This is equivalent to the above
assert_eq!(rotation2.angle_between(rotation), PI / 4.0);
// Lerp
let rotation1 = Rotation2d::IDENTITY;
let rotation2 = Rotation2d::FRAC_PI_2;
let result = rotation1.lerp(rotation2, 0.5);
assert_eq!(result.as_radians(), std::f32::consts::FRAC_PI_4);
// Slerp
let rotation1 = Rotation2d::FRAC_PI_4);
let rotation2 = Rotation2d::degrees(-180.0); // we can use degrees too!
let result = rotation1.slerp(rotation2, 1.0 / 3.0);
assert_eq!(result.as_radians(), std::f32::consts::FRAC_PI_2);
```
There's also a `From<f32>` implementation for `Rotation2d`, which means
that methods can still accept radians as floats if the argument uses
`impl Into<Rotation2d>`. This means that adding `Rotation2d` shouldn't
even be a breaking change.
---
## Changelog
- Added `Rotation2d`
- Bounding volume methods now take an `impl Into<Rotation2d>`
- Gizmo methods with rotation now take an `impl Into<Rotation2d>`
## Future use cases
- Collision detection (a type like this is quite essential considering
how common vector rotations are)
- `Transform` helpers (e.g. return a 2D rotation about the Z axis from a
`Transform`)
- The rotation used for `Transform2d` (#8268)
- More gizmos, maybe meshes... everything in 2D that uses rotation
---------
Co-authored-by: Tristan Guichaoua <33934311+tguichaoua@users.noreply.github.com>
Co-authored-by: Robert Walter <robwalter96@gmail.com>
Co-authored-by: IQuick 143 <IQuick143cz@gmail.com>
2024-03-11 19:11:57 +00:00
|
|
|
fn mul(self, direction: Dir2) -> Self::Output {
|
|
|
|
let rotated = self * *direction;
|
|
|
|
|
|
|
|
#[cfg(debug_assertions)]
|
|
|
|
assert_is_normalized(
|
|
|
|
"`Dir2` is denormalized after rotation.",
|
|
|
|
rotated.length_squared(),
|
|
|
|
);
|
|
|
|
|
|
|
|
Dir2(rotated)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-05-23 16:12:46 +00:00
|
|
|
#[cfg(any(feature = "approx", test))]
|
Rename `Direction2d/3d` to `Dir2/3` (#12189)
# Objective
Split up from #12017, rename Bevy's direction types.
Currently, Bevy has the `Direction2d`, `Direction3d`, and `Direction3dA`
types, which provide a type-level guarantee that their contained vectors
remain normalized. They can be very useful for a lot of APIs for safety,
explicitness, and in some cases performance, as they can sometimes avoid
unnecessary normalizations.
However, many consider them to be inconvenient to use, and opt for
standard vector types like `Vec3` because of this. One reason is that
the direction type names are a bit long and can be annoying to write (of
course you can use autocomplete, but just typing `Vec3` is still nicer),
and in some intances, the extra characters can make formatting worse.
The naming is also inconsistent with Glam's shorter type names, and
results in names like `Direction3dA`, which (in my opinion) are
difficult to read and even a bit ugly.
This PR proposes renaming the types to `Dir2`, `Dir3`, and `Dir3A`.
These names are nice and easy to write, consistent with Glam, and work
well for variants like the SIMD aligned `Dir3A`. As a bonus, it can also
result in nicer formatting in a lot of cases, which can be seen from the
diff of this PR.
Some examples of what it looks like: (copied from #12017)
```rust
// Before
let ray_cast = RayCast2d::new(Vec2::ZERO, Direction2d::X, 5.0);
// After
let ray_cast = RayCast2d::new(Vec2::ZERO, Dir2::X, 5.0);
```
```rust
// Before (an example using Bevy XPBD)
let hit = spatial_query.cast_ray(
Vec3::ZERO,
Direction3d::X,
f32::MAX,
true,
SpatialQueryFilter::default(),
);
// After
let hit = spatial_query.cast_ray(
Vec3::ZERO,
Dir3::X,
f32::MAX,
true,
SpatialQueryFilter::default(),
);
```
```rust
// Before
self.circle(
Vec3::new(0.0, -2.0, 0.0),
Direction3d::Y,
5.0,
Color::TURQUOISE,
);
// After (formatting is collapsed in this case)
self.circle(Vec3::new(0.0, -2.0, 0.0), Dir3::Y, 5.0, Color::TURQUOISE);
```
## Solution
Rename `Direction2d`, `Direction3d`, and `Direction3dA` to `Dir2`,
`Dir3`, and `Dir3A`.
---
## Migration Guide
The `Direction2d` and `Direction3d` types have been renamed to `Dir2`
and `Dir3`.
## Additional Context
This has been brought up on the Discord a few times, and we had a small
[poll](https://discord.com/channels/691052431525675048/1203087353850364004/1212465038711984158)
on this. `Dir2`/`Dir3`/`Dir3A` was quite unanimously chosen as the best
option, but of course it was a very small poll and inconclusive, so
other opinions are certainly welcome too.
---------
Co-authored-by: IceSentry <c.giguere42@gmail.com>
2024-02-28 22:48:43 +00:00
|
|
|
impl approx::AbsDiffEq for Dir2 {
|
2024-02-26 13:57:49 +00:00
|
|
|
type Epsilon = f32;
|
|
|
|
fn default_epsilon() -> f32 {
|
|
|
|
f32::EPSILON
|
|
|
|
}
|
|
|
|
fn abs_diff_eq(&self, other: &Self, epsilon: f32) -> bool {
|
|
|
|
self.as_ref().abs_diff_eq(other.as_ref(), epsilon)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-05-23 16:12:46 +00:00
|
|
|
#[cfg(any(feature = "approx", test))]
|
Rename `Direction2d/3d` to `Dir2/3` (#12189)
# Objective
Split up from #12017, rename Bevy's direction types.
Currently, Bevy has the `Direction2d`, `Direction3d`, and `Direction3dA`
types, which provide a type-level guarantee that their contained vectors
remain normalized. They can be very useful for a lot of APIs for safety,
explicitness, and in some cases performance, as they can sometimes avoid
unnecessary normalizations.
However, many consider them to be inconvenient to use, and opt for
standard vector types like `Vec3` because of this. One reason is that
the direction type names are a bit long and can be annoying to write (of
course you can use autocomplete, but just typing `Vec3` is still nicer),
and in some intances, the extra characters can make formatting worse.
The naming is also inconsistent with Glam's shorter type names, and
results in names like `Direction3dA`, which (in my opinion) are
difficult to read and even a bit ugly.
This PR proposes renaming the types to `Dir2`, `Dir3`, and `Dir3A`.
These names are nice and easy to write, consistent with Glam, and work
well for variants like the SIMD aligned `Dir3A`. As a bonus, it can also
result in nicer formatting in a lot of cases, which can be seen from the
diff of this PR.
Some examples of what it looks like: (copied from #12017)
```rust
// Before
let ray_cast = RayCast2d::new(Vec2::ZERO, Direction2d::X, 5.0);
// After
let ray_cast = RayCast2d::new(Vec2::ZERO, Dir2::X, 5.0);
```
```rust
// Before (an example using Bevy XPBD)
let hit = spatial_query.cast_ray(
Vec3::ZERO,
Direction3d::X,
f32::MAX,
true,
SpatialQueryFilter::default(),
);
// After
let hit = spatial_query.cast_ray(
Vec3::ZERO,
Dir3::X,
f32::MAX,
true,
SpatialQueryFilter::default(),
);
```
```rust
// Before
self.circle(
Vec3::new(0.0, -2.0, 0.0),
Direction3d::Y,
5.0,
Color::TURQUOISE,
);
// After (formatting is collapsed in this case)
self.circle(Vec3::new(0.0, -2.0, 0.0), Dir3::Y, 5.0, Color::TURQUOISE);
```
## Solution
Rename `Direction2d`, `Direction3d`, and `Direction3dA` to `Dir2`,
`Dir3`, and `Dir3A`.
---
## Migration Guide
The `Direction2d` and `Direction3d` types have been renamed to `Dir2`
and `Dir3`.
## Additional Context
This has been brought up on the Discord a few times, and we had a small
[poll](https://discord.com/channels/691052431525675048/1203087353850364004/1212465038711984158)
on this. `Dir2`/`Dir3`/`Dir3A` was quite unanimously chosen as the best
option, but of course it was a very small poll and inconclusive, so
other opinions are certainly welcome too.
---------
Co-authored-by: IceSentry <c.giguere42@gmail.com>
2024-02-28 22:48:43 +00:00
|
|
|
impl approx::RelativeEq for Dir2 {
|
2024-02-26 13:57:49 +00:00
|
|
|
fn default_max_relative() -> f32 {
|
|
|
|
f32::EPSILON
|
|
|
|
}
|
|
|
|
fn relative_eq(&self, other: &Self, epsilon: f32, max_relative: f32) -> bool {
|
|
|
|
self.as_ref()
|
|
|
|
.relative_eq(other.as_ref(), epsilon, max_relative)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-05-23 16:12:46 +00:00
|
|
|
#[cfg(any(feature = "approx", test))]
|
Rename `Direction2d/3d` to `Dir2/3` (#12189)
# Objective
Split up from #12017, rename Bevy's direction types.
Currently, Bevy has the `Direction2d`, `Direction3d`, and `Direction3dA`
types, which provide a type-level guarantee that their contained vectors
remain normalized. They can be very useful for a lot of APIs for safety,
explicitness, and in some cases performance, as they can sometimes avoid
unnecessary normalizations.
However, many consider them to be inconvenient to use, and opt for
standard vector types like `Vec3` because of this. One reason is that
the direction type names are a bit long and can be annoying to write (of
course you can use autocomplete, but just typing `Vec3` is still nicer),
and in some intances, the extra characters can make formatting worse.
The naming is also inconsistent with Glam's shorter type names, and
results in names like `Direction3dA`, which (in my opinion) are
difficult to read and even a bit ugly.
This PR proposes renaming the types to `Dir2`, `Dir3`, and `Dir3A`.
These names are nice and easy to write, consistent with Glam, and work
well for variants like the SIMD aligned `Dir3A`. As a bonus, it can also
result in nicer formatting in a lot of cases, which can be seen from the
diff of this PR.
Some examples of what it looks like: (copied from #12017)
```rust
// Before
let ray_cast = RayCast2d::new(Vec2::ZERO, Direction2d::X, 5.0);
// After
let ray_cast = RayCast2d::new(Vec2::ZERO, Dir2::X, 5.0);
```
```rust
// Before (an example using Bevy XPBD)
let hit = spatial_query.cast_ray(
Vec3::ZERO,
Direction3d::X,
f32::MAX,
true,
SpatialQueryFilter::default(),
);
// After
let hit = spatial_query.cast_ray(
Vec3::ZERO,
Dir3::X,
f32::MAX,
true,
SpatialQueryFilter::default(),
);
```
```rust
// Before
self.circle(
Vec3::new(0.0, -2.0, 0.0),
Direction3d::Y,
5.0,
Color::TURQUOISE,
);
// After (formatting is collapsed in this case)
self.circle(Vec3::new(0.0, -2.0, 0.0), Dir3::Y, 5.0, Color::TURQUOISE);
```
## Solution
Rename `Direction2d`, `Direction3d`, and `Direction3dA` to `Dir2`,
`Dir3`, and `Dir3A`.
---
## Migration Guide
The `Direction2d` and `Direction3d` types have been renamed to `Dir2`
and `Dir3`.
## Additional Context
This has been brought up on the Discord a few times, and we had a small
[poll](https://discord.com/channels/691052431525675048/1203087353850364004/1212465038711984158)
on this. `Dir2`/`Dir3`/`Dir3A` was quite unanimously chosen as the best
option, but of course it was a very small poll and inconclusive, so
other opinions are certainly welcome too.
---------
Co-authored-by: IceSentry <c.giguere42@gmail.com>
2024-02-28 22:48:43 +00:00
|
|
|
impl approx::UlpsEq for Dir2 {
|
2024-02-26 13:57:49 +00:00
|
|
|
fn default_max_ulps() -> u32 {
|
|
|
|
4
|
|
|
|
}
|
|
|
|
fn ulps_eq(&self, other: &Self, epsilon: f32, max_ulps: u32) -> bool {
|
|
|
|
self.as_ref().ulps_eq(other.as_ref(), epsilon, max_ulps)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// A normalized vector pointing in a direction in 3D space
|
|
|
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
|
|
|
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
|
2024-05-27 14:15:22 +00:00
|
|
|
#[cfg_attr(feature = "bevy_reflect", derive(Reflect), reflect(Debug, PartialEq))]
|
|
|
|
#[cfg_attr(
|
|
|
|
all(feature = "serialize", feature = "bevy_reflect"),
|
|
|
|
reflect(Serialize, Deserialize)
|
|
|
|
)]
|
Rename `Direction2d/3d` to `Dir2/3` (#12189)
# Objective
Split up from #12017, rename Bevy's direction types.
Currently, Bevy has the `Direction2d`, `Direction3d`, and `Direction3dA`
types, which provide a type-level guarantee that their contained vectors
remain normalized. They can be very useful for a lot of APIs for safety,
explicitness, and in some cases performance, as they can sometimes avoid
unnecessary normalizations.
However, many consider them to be inconvenient to use, and opt for
standard vector types like `Vec3` because of this. One reason is that
the direction type names are a bit long and can be annoying to write (of
course you can use autocomplete, but just typing `Vec3` is still nicer),
and in some intances, the extra characters can make formatting worse.
The naming is also inconsistent with Glam's shorter type names, and
results in names like `Direction3dA`, which (in my opinion) are
difficult to read and even a bit ugly.
This PR proposes renaming the types to `Dir2`, `Dir3`, and `Dir3A`.
These names are nice and easy to write, consistent with Glam, and work
well for variants like the SIMD aligned `Dir3A`. As a bonus, it can also
result in nicer formatting in a lot of cases, which can be seen from the
diff of this PR.
Some examples of what it looks like: (copied from #12017)
```rust
// Before
let ray_cast = RayCast2d::new(Vec2::ZERO, Direction2d::X, 5.0);
// After
let ray_cast = RayCast2d::new(Vec2::ZERO, Dir2::X, 5.0);
```
```rust
// Before (an example using Bevy XPBD)
let hit = spatial_query.cast_ray(
Vec3::ZERO,
Direction3d::X,
f32::MAX,
true,
SpatialQueryFilter::default(),
);
// After
let hit = spatial_query.cast_ray(
Vec3::ZERO,
Dir3::X,
f32::MAX,
true,
SpatialQueryFilter::default(),
);
```
```rust
// Before
self.circle(
Vec3::new(0.0, -2.0, 0.0),
Direction3d::Y,
5.0,
Color::TURQUOISE,
);
// After (formatting is collapsed in this case)
self.circle(Vec3::new(0.0, -2.0, 0.0), Dir3::Y, 5.0, Color::TURQUOISE);
```
## Solution
Rename `Direction2d`, `Direction3d`, and `Direction3dA` to `Dir2`,
`Dir3`, and `Dir3A`.
---
## Migration Guide
The `Direction2d` and `Direction3d` types have been renamed to `Dir2`
and `Dir3`.
## Additional Context
This has been brought up on the Discord a few times, and we had a small
[poll](https://discord.com/channels/691052431525675048/1203087353850364004/1212465038711984158)
on this. `Dir2`/`Dir3`/`Dir3A` was quite unanimously chosen as the best
option, but of course it was a very small poll and inconclusive, so
other opinions are certainly welcome too.
---------
Co-authored-by: IceSentry <c.giguere42@gmail.com>
2024-02-28 22:48:43 +00:00
|
|
|
#[doc(alias = "Direction3d")]
|
|
|
|
pub struct Dir3(Vec3);
|
|
|
|
impl Primitive3d for Dir3 {}
|
2024-02-26 13:57:49 +00:00
|
|
|
|
Rename `Direction2d/3d` to `Dir2/3` (#12189)
# Objective
Split up from #12017, rename Bevy's direction types.
Currently, Bevy has the `Direction2d`, `Direction3d`, and `Direction3dA`
types, which provide a type-level guarantee that their contained vectors
remain normalized. They can be very useful for a lot of APIs for safety,
explicitness, and in some cases performance, as they can sometimes avoid
unnecessary normalizations.
However, many consider them to be inconvenient to use, and opt for
standard vector types like `Vec3` because of this. One reason is that
the direction type names are a bit long and can be annoying to write (of
course you can use autocomplete, but just typing `Vec3` is still nicer),
and in some intances, the extra characters can make formatting worse.
The naming is also inconsistent with Glam's shorter type names, and
results in names like `Direction3dA`, which (in my opinion) are
difficult to read and even a bit ugly.
This PR proposes renaming the types to `Dir2`, `Dir3`, and `Dir3A`.
These names are nice and easy to write, consistent with Glam, and work
well for variants like the SIMD aligned `Dir3A`. As a bonus, it can also
result in nicer formatting in a lot of cases, which can be seen from the
diff of this PR.
Some examples of what it looks like: (copied from #12017)
```rust
// Before
let ray_cast = RayCast2d::new(Vec2::ZERO, Direction2d::X, 5.0);
// After
let ray_cast = RayCast2d::new(Vec2::ZERO, Dir2::X, 5.0);
```
```rust
// Before (an example using Bevy XPBD)
let hit = spatial_query.cast_ray(
Vec3::ZERO,
Direction3d::X,
f32::MAX,
true,
SpatialQueryFilter::default(),
);
// After
let hit = spatial_query.cast_ray(
Vec3::ZERO,
Dir3::X,
f32::MAX,
true,
SpatialQueryFilter::default(),
);
```
```rust
// Before
self.circle(
Vec3::new(0.0, -2.0, 0.0),
Direction3d::Y,
5.0,
Color::TURQUOISE,
);
// After (formatting is collapsed in this case)
self.circle(Vec3::new(0.0, -2.0, 0.0), Dir3::Y, 5.0, Color::TURQUOISE);
```
## Solution
Rename `Direction2d`, `Direction3d`, and `Direction3dA` to `Dir2`,
`Dir3`, and `Dir3A`.
---
## Migration Guide
The `Direction2d` and `Direction3d` types have been renamed to `Dir2`
and `Dir3`.
## Additional Context
This has been brought up on the Discord a few times, and we had a small
[poll](https://discord.com/channels/691052431525675048/1203087353850364004/1212465038711984158)
on this. `Dir2`/`Dir3`/`Dir3A` was quite unanimously chosen as the best
option, but of course it was a very small poll and inconclusive, so
other opinions are certainly welcome too.
---------
Co-authored-by: IceSentry <c.giguere42@gmail.com>
2024-02-28 22:48:43 +00:00
|
|
|
impl Dir3 {
|
2024-02-26 13:57:49 +00:00
|
|
|
/// A unit vector pointing along the positive X axis.
|
|
|
|
pub const X: Self = Self(Vec3::X);
|
|
|
|
/// A unit vector pointing along the positive Y axis.
|
|
|
|
pub const Y: Self = Self(Vec3::Y);
|
|
|
|
/// A unit vector pointing along the positive Z axis.
|
|
|
|
pub const Z: Self = Self(Vec3::Z);
|
|
|
|
/// A unit vector pointing along the negative X axis.
|
|
|
|
pub const NEG_X: Self = Self(Vec3::NEG_X);
|
|
|
|
/// A unit vector pointing along the negative Y axis.
|
|
|
|
pub const NEG_Y: Self = Self(Vec3::NEG_Y);
|
|
|
|
/// A unit vector pointing along the negative Z axis.
|
|
|
|
pub const NEG_Z: Self = Self(Vec3::NEG_Z);
|
2024-05-09 23:30:44 +00:00
|
|
|
/// The directional axes.
|
|
|
|
pub const AXES: [Self; 3] = [Self::X, Self::Y, Self::Z];
|
2024-02-26 13:57:49 +00:00
|
|
|
|
2024-05-23 15:20:21 +00:00
|
|
|
/// Create a direction from a finite, nonzero [`Vec3`], normalizing it.
|
2024-02-26 13:57:49 +00:00
|
|
|
///
|
|
|
|
/// Returns [`Err(InvalidDirectionError)`](InvalidDirectionError) if the length
|
|
|
|
/// of the given vector is zero (or very close to zero), infinite, or `NaN`.
|
|
|
|
pub fn new(value: Vec3) -> Result<Self, InvalidDirectionError> {
|
|
|
|
Self::new_and_length(value).map(|(dir, _)| dir)
|
|
|
|
}
|
|
|
|
|
Rename `Direction2d/3d` to `Dir2/3` (#12189)
# Objective
Split up from #12017, rename Bevy's direction types.
Currently, Bevy has the `Direction2d`, `Direction3d`, and `Direction3dA`
types, which provide a type-level guarantee that their contained vectors
remain normalized. They can be very useful for a lot of APIs for safety,
explicitness, and in some cases performance, as they can sometimes avoid
unnecessary normalizations.
However, many consider them to be inconvenient to use, and opt for
standard vector types like `Vec3` because of this. One reason is that
the direction type names are a bit long and can be annoying to write (of
course you can use autocomplete, but just typing `Vec3` is still nicer),
and in some intances, the extra characters can make formatting worse.
The naming is also inconsistent with Glam's shorter type names, and
results in names like `Direction3dA`, which (in my opinion) are
difficult to read and even a bit ugly.
This PR proposes renaming the types to `Dir2`, `Dir3`, and `Dir3A`.
These names are nice and easy to write, consistent with Glam, and work
well for variants like the SIMD aligned `Dir3A`. As a bonus, it can also
result in nicer formatting in a lot of cases, which can be seen from the
diff of this PR.
Some examples of what it looks like: (copied from #12017)
```rust
// Before
let ray_cast = RayCast2d::new(Vec2::ZERO, Direction2d::X, 5.0);
// After
let ray_cast = RayCast2d::new(Vec2::ZERO, Dir2::X, 5.0);
```
```rust
// Before (an example using Bevy XPBD)
let hit = spatial_query.cast_ray(
Vec3::ZERO,
Direction3d::X,
f32::MAX,
true,
SpatialQueryFilter::default(),
);
// After
let hit = spatial_query.cast_ray(
Vec3::ZERO,
Dir3::X,
f32::MAX,
true,
SpatialQueryFilter::default(),
);
```
```rust
// Before
self.circle(
Vec3::new(0.0, -2.0, 0.0),
Direction3d::Y,
5.0,
Color::TURQUOISE,
);
// After (formatting is collapsed in this case)
self.circle(Vec3::new(0.0, -2.0, 0.0), Dir3::Y, 5.0, Color::TURQUOISE);
```
## Solution
Rename `Direction2d`, `Direction3d`, and `Direction3dA` to `Dir2`,
`Dir3`, and `Dir3A`.
---
## Migration Guide
The `Direction2d` and `Direction3d` types have been renamed to `Dir2`
and `Dir3`.
## Additional Context
This has been brought up on the Discord a few times, and we had a small
[poll](https://discord.com/channels/691052431525675048/1203087353850364004/1212465038711984158)
on this. `Dir2`/`Dir3`/`Dir3A` was quite unanimously chosen as the best
option, but of course it was a very small poll and inconclusive, so
other opinions are certainly welcome too.
---------
Co-authored-by: IceSentry <c.giguere42@gmail.com>
2024-02-28 22:48:43 +00:00
|
|
|
/// Create a [`Dir3`] from a [`Vec3`] that is already normalized.
|
2024-02-26 13:57:49 +00:00
|
|
|
///
|
|
|
|
/// # Warning
|
|
|
|
///
|
Improve error messages for denormalized directions (#12278)
# Objective
`Dir3` and `Dir3A` can be rotated using `Quat`s. However, if enough
floating point error accumulates or (more commonly) the rotation itself
is degenerate (like not normalized), the resulting direction can also
become denormalized.
Currently, with debug assertions enabled, it panics in these cases with
the message `rotated.is_normalized()`. This error message is unclear,
doesn't give information about *how* it is denormalized (like is the
length too large, NaN, or something else), and is overall not very
helpful. Panicking for small-ish error might also be a bit too strict,
and has lead to unwanted crashes in crates like `bevy_xpbd` (although it
has also helped in finding actual bugs).
The error message should be clearer and give more context, and it
shouldn't cause unwanted crashes.
## Solution
Change the `debug_assert!` to a warning for small error with a (squared
length) threshold of 2e-4 and a panic for clear error with a threshold
of 2e-2. The warnings mention the direction type and the length of the
denormalized vector.
Here's what the error and warning look like:
```
Error: `Dir3` is denormalized after rotation. The length is 1.014242.
```
```
Warning: `Dir3A` is denormalized after rotation. The length is 1.0001414.
```
I gave the same treatment to `new_unchecked`:
```
Error: The vector given to `Dir3::new_unchecked` is not normalized. The length is 1.014242.
```
```
Warning: The vector given to `Dir3A::new_unchecked` is not normalized. The length is 1.0001414.
```
---
## Discussion
### Threshold values
The thresholds are somewhat arbitrary. 2e-4 is what Glam uses for the
squared length in `is_normalized` (after I corrected it in
bitshifter/glam-rs#480), and 2e-2 is just what I thought could be a
clear sign of something being critically wrong. I can definitely tune
them if there are better thresholds though.
### Logging
`bevy_math` doesn't have `bevy_log`, so we can't use `warn!` or
`error!`. This is why I made it use just `eprintln!` and `panic!` for
now. Let me know if there's a better way of logging errors in
`bevy_math`.
2024-03-04 00:01:32 +00:00
|
|
|
/// `value` must be normalized, i.e its length must be `1.0`.
|
2024-02-26 13:57:49 +00:00
|
|
|
pub fn new_unchecked(value: Vec3) -> Self {
|
Improve error messages for denormalized directions (#12278)
# Objective
`Dir3` and `Dir3A` can be rotated using `Quat`s. However, if enough
floating point error accumulates or (more commonly) the rotation itself
is degenerate (like not normalized), the resulting direction can also
become denormalized.
Currently, with debug assertions enabled, it panics in these cases with
the message `rotated.is_normalized()`. This error message is unclear,
doesn't give information about *how* it is denormalized (like is the
length too large, NaN, or something else), and is overall not very
helpful. Panicking for small-ish error might also be a bit too strict,
and has lead to unwanted crashes in crates like `bevy_xpbd` (although it
has also helped in finding actual bugs).
The error message should be clearer and give more context, and it
shouldn't cause unwanted crashes.
## Solution
Change the `debug_assert!` to a warning for small error with a (squared
length) threshold of 2e-4 and a panic for clear error with a threshold
of 2e-2. The warnings mention the direction type and the length of the
denormalized vector.
Here's what the error and warning look like:
```
Error: `Dir3` is denormalized after rotation. The length is 1.014242.
```
```
Warning: `Dir3A` is denormalized after rotation. The length is 1.0001414.
```
I gave the same treatment to `new_unchecked`:
```
Error: The vector given to `Dir3::new_unchecked` is not normalized. The length is 1.014242.
```
```
Warning: The vector given to `Dir3A::new_unchecked` is not normalized. The length is 1.0001414.
```
---
## Discussion
### Threshold values
The thresholds are somewhat arbitrary. 2e-4 is what Glam uses for the
squared length in `is_normalized` (after I corrected it in
bitshifter/glam-rs#480), and 2e-2 is just what I thought could be a
clear sign of something being critically wrong. I can definitely tune
them if there are better thresholds though.
### Logging
`bevy_math` doesn't have `bevy_log`, so we can't use `warn!` or
`error!`. This is why I made it use just `eprintln!` and `panic!` for
now. Let me know if there's a better way of logging errors in
`bevy_math`.
2024-03-04 00:01:32 +00:00
|
|
|
#[cfg(debug_assertions)]
|
|
|
|
assert_is_normalized(
|
|
|
|
"The vector given to `Dir3::new_unchecked` is not normalized.",
|
|
|
|
value.length_squared(),
|
|
|
|
);
|
2024-02-26 13:57:49 +00:00
|
|
|
|
|
|
|
Self(value)
|
|
|
|
}
|
|
|
|
|
2024-05-23 15:20:21 +00:00
|
|
|
/// Create a direction from a finite, nonzero [`Vec3`], normalizing it and
|
|
|
|
/// also returning its original length.
|
2024-02-26 13:57:49 +00:00
|
|
|
///
|
|
|
|
/// Returns [`Err(InvalidDirectionError)`](InvalidDirectionError) if the length
|
|
|
|
/// of the given vector is zero (or very close to zero), infinite, or `NaN`.
|
|
|
|
pub fn new_and_length(value: Vec3) -> Result<(Self, f32), InvalidDirectionError> {
|
|
|
|
let length = value.length();
|
|
|
|
let direction = (length.is_finite() && length > 0.0).then_some(value / length);
|
|
|
|
|
|
|
|
direction
|
|
|
|
.map(|dir| (Self(dir), length))
|
|
|
|
.ok_or(InvalidDirectionError::from_length(length))
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Create a direction from its `x`, `y`, and `z` components.
|
|
|
|
///
|
|
|
|
/// Returns [`Err(InvalidDirectionError)`](InvalidDirectionError) if the length
|
|
|
|
/// of the vector formed by the components is zero (or very close to zero), infinite, or `NaN`.
|
|
|
|
pub fn from_xyz(x: f32, y: f32, z: f32) -> Result<Self, InvalidDirectionError> {
|
|
|
|
Self::new(Vec3::new(x, y, z))
|
|
|
|
}
|
2024-03-18 17:49:58 +00:00
|
|
|
|
2024-08-02 13:10:13 +00:00
|
|
|
/// Create a direction from its `x`, `y`, and `z` components, assuming the resulting vector is normalized.
|
|
|
|
///
|
|
|
|
/// # Warning
|
|
|
|
///
|
|
|
|
/// The vector produced from `x`, `y`, and `z` must be normalized, i.e its length must be `1.0`.
|
|
|
|
pub fn from_xyz_unchecked(x: f32, y: f32, z: f32) -> Self {
|
|
|
|
Self::new_unchecked(Vec3::new(x, y, z))
|
|
|
|
}
|
|
|
|
|
2024-03-18 17:49:58 +00:00
|
|
|
/// Returns the inner [`Vec3`]
|
|
|
|
pub const fn as_vec3(&self) -> Vec3 {
|
|
|
|
self.0
|
|
|
|
}
|
2024-05-21 21:13:32 +00:00
|
|
|
|
|
|
|
/// Performs a spherical linear interpolation between `self` and `rhs`
|
|
|
|
/// based on the value `s`.
|
|
|
|
///
|
|
|
|
/// This corresponds to interpolating between the two directions at a constant angular velocity.
|
|
|
|
///
|
|
|
|
/// When `s == 0.0`, the result will be equal to `self`.
|
|
|
|
/// When `s == 1.0`, the result will be equal to `rhs`.
|
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// # use bevy_math::Dir3;
|
|
|
|
/// # use approx::{assert_relative_eq, RelativeEq};
|
|
|
|
/// #
|
|
|
|
/// let dir1 = Dir3::X;
|
|
|
|
/// let dir2 = Dir3::Y;
|
|
|
|
///
|
|
|
|
/// let result1 = dir1.slerp(dir2, 1.0 / 3.0);
|
|
|
|
/// assert_relative_eq!(
|
|
|
|
/// result1,
|
|
|
|
/// Dir3::from_xyz(0.75_f32.sqrt(), 0.5, 0.0).unwrap(),
|
|
|
|
/// epsilon = 0.000001
|
|
|
|
/// );
|
|
|
|
///
|
|
|
|
/// let result2 = dir1.slerp(dir2, 0.5);
|
|
|
|
/// assert_relative_eq!(result2, Dir3::from_xyz(0.5_f32.sqrt(), 0.5_f32.sqrt(), 0.0).unwrap());
|
|
|
|
/// ```
|
|
|
|
#[inline]
|
|
|
|
pub fn slerp(self, rhs: Self, s: f32) -> Self {
|
|
|
|
let quat = Quat::IDENTITY.slerp(Quat::from_rotation_arc(self.0, rhs.0), s);
|
|
|
|
Dir3(quat.mul_vec3(self.0))
|
|
|
|
}
|
2024-07-22 18:42:48 +00:00
|
|
|
|
|
|
|
/// Returns `self` after an approximate normalization, assuming the value is already nearly normalized.
|
|
|
|
/// Useful for preventing numerical error accumulation.
|
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
/// The following seemingly benign code would start accumulating errors over time,
|
|
|
|
/// leading to `dir` eventually not being normalized anymore.
|
|
|
|
/// ```
|
|
|
|
/// # use bevy_math::prelude::*;
|
|
|
|
/// # let N: usize = 200;
|
|
|
|
/// let mut dir = Dir3::X;
|
|
|
|
/// let quaternion = Quat::from_euler(EulerRot::XYZ, 1.0, 2.0, 3.0);
|
|
|
|
/// for i in 0..N {
|
|
|
|
/// dir = quaternion * dir;
|
|
|
|
/// }
|
|
|
|
/// ```
|
|
|
|
/// Instead, do the following.
|
|
|
|
/// ```
|
|
|
|
/// # use bevy_math::prelude::*;
|
|
|
|
/// # let N: usize = 200;
|
|
|
|
/// let mut dir = Dir3::X;
|
|
|
|
/// let quaternion = Quat::from_euler(EulerRot::XYZ, 1.0, 2.0, 3.0);
|
|
|
|
/// for i in 0..N {
|
|
|
|
/// dir = quaternion * dir;
|
|
|
|
/// dir = dir.fast_renormalize();
|
|
|
|
/// }
|
|
|
|
/// ```
|
|
|
|
#[inline]
|
|
|
|
pub fn fast_renormalize(self) -> Self {
|
|
|
|
// We numerically approximate the inverse square root by a Taylor series around 1
|
|
|
|
// As we expect the error (x := length_squared - 1) to be small
|
|
|
|
// inverse_sqrt(length_squared) = (1 + x)^(-1/2) = 1 - 1/2 x + O(x²)
|
|
|
|
// inverse_sqrt(length_squared) ≈ 1 - 1/2 (length_squared - 1) = 1/2 (3 - length_squared)
|
|
|
|
|
|
|
|
// Iterative calls to this method quickly converge to a normalized value,
|
|
|
|
// so long as the denormalization is not large ~ O(1/10).
|
|
|
|
// One iteration can be described as:
|
|
|
|
// l_sq <- l_sq * (1 - 1/2 (l_sq - 1))²;
|
|
|
|
// Rewriting in terms of the error x:
|
|
|
|
// 1 + x <- (1 + x) * (1 - 1/2 x)²
|
|
|
|
// 1 + x <- (1 + x) * (1 - x + 1/4 x²)
|
|
|
|
// 1 + x <- 1 - x + 1/4 x² + x - x² + 1/4 x³
|
|
|
|
// x <- -1/4 x² (3 - x)
|
|
|
|
// If the error is small, say in a range of (-1/2, 1/2), then:
|
|
|
|
// |-1/4 x² (3 - x)| <= (3/4 + 1/4 * |x|) * x² <= (3/4 + 1/4 * 1/2) * x² < x² < 1/2 x
|
|
|
|
// Therefore the sequence of iterates converges to 0 error as a second order method.
|
|
|
|
|
|
|
|
let length_squared = self.0.length_squared();
|
|
|
|
Self(self * (0.5 * (3.0 - length_squared)))
|
|
|
|
}
|
2024-02-26 13:57:49 +00:00
|
|
|
}
|
|
|
|
|
Rename `Direction2d/3d` to `Dir2/3` (#12189)
# Objective
Split up from #12017, rename Bevy's direction types.
Currently, Bevy has the `Direction2d`, `Direction3d`, and `Direction3dA`
types, which provide a type-level guarantee that their contained vectors
remain normalized. They can be very useful for a lot of APIs for safety,
explicitness, and in some cases performance, as they can sometimes avoid
unnecessary normalizations.
However, many consider them to be inconvenient to use, and opt for
standard vector types like `Vec3` because of this. One reason is that
the direction type names are a bit long and can be annoying to write (of
course you can use autocomplete, but just typing `Vec3` is still nicer),
and in some intances, the extra characters can make formatting worse.
The naming is also inconsistent with Glam's shorter type names, and
results in names like `Direction3dA`, which (in my opinion) are
difficult to read and even a bit ugly.
This PR proposes renaming the types to `Dir2`, `Dir3`, and `Dir3A`.
These names are nice and easy to write, consistent with Glam, and work
well for variants like the SIMD aligned `Dir3A`. As a bonus, it can also
result in nicer formatting in a lot of cases, which can be seen from the
diff of this PR.
Some examples of what it looks like: (copied from #12017)
```rust
// Before
let ray_cast = RayCast2d::new(Vec2::ZERO, Direction2d::X, 5.0);
// After
let ray_cast = RayCast2d::new(Vec2::ZERO, Dir2::X, 5.0);
```
```rust
// Before (an example using Bevy XPBD)
let hit = spatial_query.cast_ray(
Vec3::ZERO,
Direction3d::X,
f32::MAX,
true,
SpatialQueryFilter::default(),
);
// After
let hit = spatial_query.cast_ray(
Vec3::ZERO,
Dir3::X,
f32::MAX,
true,
SpatialQueryFilter::default(),
);
```
```rust
// Before
self.circle(
Vec3::new(0.0, -2.0, 0.0),
Direction3d::Y,
5.0,
Color::TURQUOISE,
);
// After (formatting is collapsed in this case)
self.circle(Vec3::new(0.0, -2.0, 0.0), Dir3::Y, 5.0, Color::TURQUOISE);
```
## Solution
Rename `Direction2d`, `Direction3d`, and `Direction3dA` to `Dir2`,
`Dir3`, and `Dir3A`.
---
## Migration Guide
The `Direction2d` and `Direction3d` types have been renamed to `Dir2`
and `Dir3`.
## Additional Context
This has been brought up on the Discord a few times, and we had a small
[poll](https://discord.com/channels/691052431525675048/1203087353850364004/1212465038711984158)
on this. `Dir2`/`Dir3`/`Dir3A` was quite unanimously chosen as the best
option, but of course it was a very small poll and inconclusive, so
other opinions are certainly welcome too.
---------
Co-authored-by: IceSentry <c.giguere42@gmail.com>
2024-02-28 22:48:43 +00:00
|
|
|
impl TryFrom<Vec3> for Dir3 {
|
2024-02-26 13:57:49 +00:00
|
|
|
type Error = InvalidDirectionError;
|
|
|
|
|
|
|
|
fn try_from(value: Vec3) -> Result<Self, Self::Error> {
|
|
|
|
Self::new(value)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Rename `Direction2d/3d` to `Dir2/3` (#12189)
# Objective
Split up from #12017, rename Bevy's direction types.
Currently, Bevy has the `Direction2d`, `Direction3d`, and `Direction3dA`
types, which provide a type-level guarantee that their contained vectors
remain normalized. They can be very useful for a lot of APIs for safety,
explicitness, and in some cases performance, as they can sometimes avoid
unnecessary normalizations.
However, many consider them to be inconvenient to use, and opt for
standard vector types like `Vec3` because of this. One reason is that
the direction type names are a bit long and can be annoying to write (of
course you can use autocomplete, but just typing `Vec3` is still nicer),
and in some intances, the extra characters can make formatting worse.
The naming is also inconsistent with Glam's shorter type names, and
results in names like `Direction3dA`, which (in my opinion) are
difficult to read and even a bit ugly.
This PR proposes renaming the types to `Dir2`, `Dir3`, and `Dir3A`.
These names are nice and easy to write, consistent with Glam, and work
well for variants like the SIMD aligned `Dir3A`. As a bonus, it can also
result in nicer formatting in a lot of cases, which can be seen from the
diff of this PR.
Some examples of what it looks like: (copied from #12017)
```rust
// Before
let ray_cast = RayCast2d::new(Vec2::ZERO, Direction2d::X, 5.0);
// After
let ray_cast = RayCast2d::new(Vec2::ZERO, Dir2::X, 5.0);
```
```rust
// Before (an example using Bevy XPBD)
let hit = spatial_query.cast_ray(
Vec3::ZERO,
Direction3d::X,
f32::MAX,
true,
SpatialQueryFilter::default(),
);
// After
let hit = spatial_query.cast_ray(
Vec3::ZERO,
Dir3::X,
f32::MAX,
true,
SpatialQueryFilter::default(),
);
```
```rust
// Before
self.circle(
Vec3::new(0.0, -2.0, 0.0),
Direction3d::Y,
5.0,
Color::TURQUOISE,
);
// After (formatting is collapsed in this case)
self.circle(Vec3::new(0.0, -2.0, 0.0), Dir3::Y, 5.0, Color::TURQUOISE);
```
## Solution
Rename `Direction2d`, `Direction3d`, and `Direction3dA` to `Dir2`,
`Dir3`, and `Dir3A`.
---
## Migration Guide
The `Direction2d` and `Direction3d` types have been renamed to `Dir2`
and `Dir3`.
## Additional Context
This has been brought up on the Discord a few times, and we had a small
[poll](https://discord.com/channels/691052431525675048/1203087353850364004/1212465038711984158)
on this. `Dir2`/`Dir3`/`Dir3A` was quite unanimously chosen as the best
option, but of course it was a very small poll and inconclusive, so
other opinions are certainly welcome too.
---------
Co-authored-by: IceSentry <c.giguere42@gmail.com>
2024-02-28 22:48:43 +00:00
|
|
|
impl From<Dir3> for Vec3 {
|
|
|
|
fn from(value: Dir3) -> Self {
|
2024-02-26 13:57:49 +00:00
|
|
|
value.0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-09-27 00:59:59 +00:00
|
|
|
impl core::ops::Deref for Dir3 {
|
2024-02-26 13:57:49 +00:00
|
|
|
type Target = Vec3;
|
|
|
|
fn deref(&self) -> &Self::Target {
|
|
|
|
&self.0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-09-27 00:59:59 +00:00
|
|
|
impl core::ops::Neg for Dir3 {
|
2024-02-26 13:57:49 +00:00
|
|
|
type Output = Self;
|
|
|
|
fn neg(self) -> Self::Output {
|
|
|
|
Self(-self.0)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-09-27 00:59:59 +00:00
|
|
|
impl core::ops::Mul<f32> for Dir3 {
|
2024-02-26 13:57:49 +00:00
|
|
|
type Output = Vec3;
|
|
|
|
fn mul(self, rhs: f32) -> Self::Output {
|
|
|
|
self.0 * rhs
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-09-27 00:59:59 +00:00
|
|
|
impl core::ops::Mul<Dir3> for f32 {
|
2024-03-03 17:44:16 +00:00
|
|
|
type Output = Vec3;
|
|
|
|
fn mul(self, rhs: Dir3) -> Self::Output {
|
|
|
|
self * rhs.0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-09-27 00:59:59 +00:00
|
|
|
impl core::ops::Mul<Dir3> for Quat {
|
Rename `Direction2d/3d` to `Dir2/3` (#12189)
# Objective
Split up from #12017, rename Bevy's direction types.
Currently, Bevy has the `Direction2d`, `Direction3d`, and `Direction3dA`
types, which provide a type-level guarantee that their contained vectors
remain normalized. They can be very useful for a lot of APIs for safety,
explicitness, and in some cases performance, as they can sometimes avoid
unnecessary normalizations.
However, many consider them to be inconvenient to use, and opt for
standard vector types like `Vec3` because of this. One reason is that
the direction type names are a bit long and can be annoying to write (of
course you can use autocomplete, but just typing `Vec3` is still nicer),
and in some intances, the extra characters can make formatting worse.
The naming is also inconsistent with Glam's shorter type names, and
results in names like `Direction3dA`, which (in my opinion) are
difficult to read and even a bit ugly.
This PR proposes renaming the types to `Dir2`, `Dir3`, and `Dir3A`.
These names are nice and easy to write, consistent with Glam, and work
well for variants like the SIMD aligned `Dir3A`. As a bonus, it can also
result in nicer formatting in a lot of cases, which can be seen from the
diff of this PR.
Some examples of what it looks like: (copied from #12017)
```rust
// Before
let ray_cast = RayCast2d::new(Vec2::ZERO, Direction2d::X, 5.0);
// After
let ray_cast = RayCast2d::new(Vec2::ZERO, Dir2::X, 5.0);
```
```rust
// Before (an example using Bevy XPBD)
let hit = spatial_query.cast_ray(
Vec3::ZERO,
Direction3d::X,
f32::MAX,
true,
SpatialQueryFilter::default(),
);
// After
let hit = spatial_query.cast_ray(
Vec3::ZERO,
Dir3::X,
f32::MAX,
true,
SpatialQueryFilter::default(),
);
```
```rust
// Before
self.circle(
Vec3::new(0.0, -2.0, 0.0),
Direction3d::Y,
5.0,
Color::TURQUOISE,
);
// After (formatting is collapsed in this case)
self.circle(Vec3::new(0.0, -2.0, 0.0), Dir3::Y, 5.0, Color::TURQUOISE);
```
## Solution
Rename `Direction2d`, `Direction3d`, and `Direction3dA` to `Dir2`,
`Dir3`, and `Dir3A`.
---
## Migration Guide
The `Direction2d` and `Direction3d` types have been renamed to `Dir2`
and `Dir3`.
## Additional Context
This has been brought up on the Discord a few times, and we had a small
[poll](https://discord.com/channels/691052431525675048/1203087353850364004/1212465038711984158)
on this. `Dir2`/`Dir3`/`Dir3A` was quite unanimously chosen as the best
option, but of course it was a very small poll and inconclusive, so
other opinions are certainly welcome too.
---------
Co-authored-by: IceSentry <c.giguere42@gmail.com>
2024-02-28 22:48:43 +00:00
|
|
|
type Output = Dir3;
|
2024-02-26 13:57:49 +00:00
|
|
|
|
Rename `Direction2d/3d` to `Dir2/3` (#12189)
# Objective
Split up from #12017, rename Bevy's direction types.
Currently, Bevy has the `Direction2d`, `Direction3d`, and `Direction3dA`
types, which provide a type-level guarantee that their contained vectors
remain normalized. They can be very useful for a lot of APIs for safety,
explicitness, and in some cases performance, as they can sometimes avoid
unnecessary normalizations.
However, many consider them to be inconvenient to use, and opt for
standard vector types like `Vec3` because of this. One reason is that
the direction type names are a bit long and can be annoying to write (of
course you can use autocomplete, but just typing `Vec3` is still nicer),
and in some intances, the extra characters can make formatting worse.
The naming is also inconsistent with Glam's shorter type names, and
results in names like `Direction3dA`, which (in my opinion) are
difficult to read and even a bit ugly.
This PR proposes renaming the types to `Dir2`, `Dir3`, and `Dir3A`.
These names are nice and easy to write, consistent with Glam, and work
well for variants like the SIMD aligned `Dir3A`. As a bonus, it can also
result in nicer formatting in a lot of cases, which can be seen from the
diff of this PR.
Some examples of what it looks like: (copied from #12017)
```rust
// Before
let ray_cast = RayCast2d::new(Vec2::ZERO, Direction2d::X, 5.0);
// After
let ray_cast = RayCast2d::new(Vec2::ZERO, Dir2::X, 5.0);
```
```rust
// Before (an example using Bevy XPBD)
let hit = spatial_query.cast_ray(
Vec3::ZERO,
Direction3d::X,
f32::MAX,
true,
SpatialQueryFilter::default(),
);
// After
let hit = spatial_query.cast_ray(
Vec3::ZERO,
Dir3::X,
f32::MAX,
true,
SpatialQueryFilter::default(),
);
```
```rust
// Before
self.circle(
Vec3::new(0.0, -2.0, 0.0),
Direction3d::Y,
5.0,
Color::TURQUOISE,
);
// After (formatting is collapsed in this case)
self.circle(Vec3::new(0.0, -2.0, 0.0), Dir3::Y, 5.0, Color::TURQUOISE);
```
## Solution
Rename `Direction2d`, `Direction3d`, and `Direction3dA` to `Dir2`,
`Dir3`, and `Dir3A`.
---
## Migration Guide
The `Direction2d` and `Direction3d` types have been renamed to `Dir2`
and `Dir3`.
## Additional Context
This has been brought up on the Discord a few times, and we had a small
[poll](https://discord.com/channels/691052431525675048/1203087353850364004/1212465038711984158)
on this. `Dir2`/`Dir3`/`Dir3A` was quite unanimously chosen as the best
option, but of course it was a very small poll and inconclusive, so
other opinions are certainly welcome too.
---------
Co-authored-by: IceSentry <c.giguere42@gmail.com>
2024-02-28 22:48:43 +00:00
|
|
|
/// Rotates the [`Dir3`] using a [`Quat`].
|
|
|
|
fn mul(self, direction: Dir3) -> Self::Output {
|
2024-02-26 13:57:49 +00:00
|
|
|
let rotated = self * *direction;
|
|
|
|
|
Improve error messages for denormalized directions (#12278)
# Objective
`Dir3` and `Dir3A` can be rotated using `Quat`s. However, if enough
floating point error accumulates or (more commonly) the rotation itself
is degenerate (like not normalized), the resulting direction can also
become denormalized.
Currently, with debug assertions enabled, it panics in these cases with
the message `rotated.is_normalized()`. This error message is unclear,
doesn't give information about *how* it is denormalized (like is the
length too large, NaN, or something else), and is overall not very
helpful. Panicking for small-ish error might also be a bit too strict,
and has lead to unwanted crashes in crates like `bevy_xpbd` (although it
has also helped in finding actual bugs).
The error message should be clearer and give more context, and it
shouldn't cause unwanted crashes.
## Solution
Change the `debug_assert!` to a warning for small error with a (squared
length) threshold of 2e-4 and a panic for clear error with a threshold
of 2e-2. The warnings mention the direction type and the length of the
denormalized vector.
Here's what the error and warning look like:
```
Error: `Dir3` is denormalized after rotation. The length is 1.014242.
```
```
Warning: `Dir3A` is denormalized after rotation. The length is 1.0001414.
```
I gave the same treatment to `new_unchecked`:
```
Error: The vector given to `Dir3::new_unchecked` is not normalized. The length is 1.014242.
```
```
Warning: The vector given to `Dir3A::new_unchecked` is not normalized. The length is 1.0001414.
```
---
## Discussion
### Threshold values
The thresholds are somewhat arbitrary. 2e-4 is what Glam uses for the
squared length in `is_normalized` (after I corrected it in
bitshifter/glam-rs#480), and 2e-2 is just what I thought could be a
clear sign of something being critically wrong. I can definitely tune
them if there are better thresholds though.
### Logging
`bevy_math` doesn't have `bevy_log`, so we can't use `warn!` or
`error!`. This is why I made it use just `eprintln!` and `panic!` for
now. Let me know if there's a better way of logging errors in
`bevy_math`.
2024-03-04 00:01:32 +00:00
|
|
|
#[cfg(debug_assertions)]
|
|
|
|
assert_is_normalized(
|
|
|
|
"`Dir3` is denormalized after rotation.",
|
|
|
|
rotated.length_squared(),
|
|
|
|
);
|
2024-02-26 13:57:49 +00:00
|
|
|
|
Improve error messages for denormalized directions (#12278)
# Objective
`Dir3` and `Dir3A` can be rotated using `Quat`s. However, if enough
floating point error accumulates or (more commonly) the rotation itself
is degenerate (like not normalized), the resulting direction can also
become denormalized.
Currently, with debug assertions enabled, it panics in these cases with
the message `rotated.is_normalized()`. This error message is unclear,
doesn't give information about *how* it is denormalized (like is the
length too large, NaN, or something else), and is overall not very
helpful. Panicking for small-ish error might also be a bit too strict,
and has lead to unwanted crashes in crates like `bevy_xpbd` (although it
has also helped in finding actual bugs).
The error message should be clearer and give more context, and it
shouldn't cause unwanted crashes.
## Solution
Change the `debug_assert!` to a warning for small error with a (squared
length) threshold of 2e-4 and a panic for clear error with a threshold
of 2e-2. The warnings mention the direction type and the length of the
denormalized vector.
Here's what the error and warning look like:
```
Error: `Dir3` is denormalized after rotation. The length is 1.014242.
```
```
Warning: `Dir3A` is denormalized after rotation. The length is 1.0001414.
```
I gave the same treatment to `new_unchecked`:
```
Error: The vector given to `Dir3::new_unchecked` is not normalized. The length is 1.014242.
```
```
Warning: The vector given to `Dir3A::new_unchecked` is not normalized. The length is 1.0001414.
```
---
## Discussion
### Threshold values
The thresholds are somewhat arbitrary. 2e-4 is what Glam uses for the
squared length in `is_normalized` (after I corrected it in
bitshifter/glam-rs#480), and 2e-2 is just what I thought could be a
clear sign of something being critically wrong. I can definitely tune
them if there are better thresholds though.
### Logging
`bevy_math` doesn't have `bevy_log`, so we can't use `warn!` or
`error!`. This is why I made it use just `eprintln!` and `panic!` for
now. Let me know if there's a better way of logging errors in
`bevy_math`.
2024-03-04 00:01:32 +00:00
|
|
|
Dir3(rotated)
|
2024-02-26 13:57:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(feature = "approx")]
|
Rename `Direction2d/3d` to `Dir2/3` (#12189)
# Objective
Split up from #12017, rename Bevy's direction types.
Currently, Bevy has the `Direction2d`, `Direction3d`, and `Direction3dA`
types, which provide a type-level guarantee that their contained vectors
remain normalized. They can be very useful for a lot of APIs for safety,
explicitness, and in some cases performance, as they can sometimes avoid
unnecessary normalizations.
However, many consider them to be inconvenient to use, and opt for
standard vector types like `Vec3` because of this. One reason is that
the direction type names are a bit long and can be annoying to write (of
course you can use autocomplete, but just typing `Vec3` is still nicer),
and in some intances, the extra characters can make formatting worse.
The naming is also inconsistent with Glam's shorter type names, and
results in names like `Direction3dA`, which (in my opinion) are
difficult to read and even a bit ugly.
This PR proposes renaming the types to `Dir2`, `Dir3`, and `Dir3A`.
These names are nice and easy to write, consistent with Glam, and work
well for variants like the SIMD aligned `Dir3A`. As a bonus, it can also
result in nicer formatting in a lot of cases, which can be seen from the
diff of this PR.
Some examples of what it looks like: (copied from #12017)
```rust
// Before
let ray_cast = RayCast2d::new(Vec2::ZERO, Direction2d::X, 5.0);
// After
let ray_cast = RayCast2d::new(Vec2::ZERO, Dir2::X, 5.0);
```
```rust
// Before (an example using Bevy XPBD)
let hit = spatial_query.cast_ray(
Vec3::ZERO,
Direction3d::X,
f32::MAX,
true,
SpatialQueryFilter::default(),
);
// After
let hit = spatial_query.cast_ray(
Vec3::ZERO,
Dir3::X,
f32::MAX,
true,
SpatialQueryFilter::default(),
);
```
```rust
// Before
self.circle(
Vec3::new(0.0, -2.0, 0.0),
Direction3d::Y,
5.0,
Color::TURQUOISE,
);
// After (formatting is collapsed in this case)
self.circle(Vec3::new(0.0, -2.0, 0.0), Dir3::Y, 5.0, Color::TURQUOISE);
```
## Solution
Rename `Direction2d`, `Direction3d`, and `Direction3dA` to `Dir2`,
`Dir3`, and `Dir3A`.
---
## Migration Guide
The `Direction2d` and `Direction3d` types have been renamed to `Dir2`
and `Dir3`.
## Additional Context
This has been brought up on the Discord a few times, and we had a small
[poll](https://discord.com/channels/691052431525675048/1203087353850364004/1212465038711984158)
on this. `Dir2`/`Dir3`/`Dir3A` was quite unanimously chosen as the best
option, but of course it was a very small poll and inconclusive, so
other opinions are certainly welcome too.
---------
Co-authored-by: IceSentry <c.giguere42@gmail.com>
2024-02-28 22:48:43 +00:00
|
|
|
impl approx::AbsDiffEq for Dir3 {
|
2024-02-26 13:57:49 +00:00
|
|
|
type Epsilon = f32;
|
|
|
|
fn default_epsilon() -> f32 {
|
|
|
|
f32::EPSILON
|
|
|
|
}
|
|
|
|
fn abs_diff_eq(&self, other: &Self, epsilon: f32) -> bool {
|
|
|
|
self.as_ref().abs_diff_eq(other.as_ref(), epsilon)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(feature = "approx")]
|
Rename `Direction2d/3d` to `Dir2/3` (#12189)
# Objective
Split up from #12017, rename Bevy's direction types.
Currently, Bevy has the `Direction2d`, `Direction3d`, and `Direction3dA`
types, which provide a type-level guarantee that their contained vectors
remain normalized. They can be very useful for a lot of APIs for safety,
explicitness, and in some cases performance, as they can sometimes avoid
unnecessary normalizations.
However, many consider them to be inconvenient to use, and opt for
standard vector types like `Vec3` because of this. One reason is that
the direction type names are a bit long and can be annoying to write (of
course you can use autocomplete, but just typing `Vec3` is still nicer),
and in some intances, the extra characters can make formatting worse.
The naming is also inconsistent with Glam's shorter type names, and
results in names like `Direction3dA`, which (in my opinion) are
difficult to read and even a bit ugly.
This PR proposes renaming the types to `Dir2`, `Dir3`, and `Dir3A`.
These names are nice and easy to write, consistent with Glam, and work
well for variants like the SIMD aligned `Dir3A`. As a bonus, it can also
result in nicer formatting in a lot of cases, which can be seen from the
diff of this PR.
Some examples of what it looks like: (copied from #12017)
```rust
// Before
let ray_cast = RayCast2d::new(Vec2::ZERO, Direction2d::X, 5.0);
// After
let ray_cast = RayCast2d::new(Vec2::ZERO, Dir2::X, 5.0);
```
```rust
// Before (an example using Bevy XPBD)
let hit = spatial_query.cast_ray(
Vec3::ZERO,
Direction3d::X,
f32::MAX,
true,
SpatialQueryFilter::default(),
);
// After
let hit = spatial_query.cast_ray(
Vec3::ZERO,
Dir3::X,
f32::MAX,
true,
SpatialQueryFilter::default(),
);
```
```rust
// Before
self.circle(
Vec3::new(0.0, -2.0, 0.0),
Direction3d::Y,
5.0,
Color::TURQUOISE,
);
// After (formatting is collapsed in this case)
self.circle(Vec3::new(0.0, -2.0, 0.0), Dir3::Y, 5.0, Color::TURQUOISE);
```
## Solution
Rename `Direction2d`, `Direction3d`, and `Direction3dA` to `Dir2`,
`Dir3`, and `Dir3A`.
---
## Migration Guide
The `Direction2d` and `Direction3d` types have been renamed to `Dir2`
and `Dir3`.
## Additional Context
This has been brought up on the Discord a few times, and we had a small
[poll](https://discord.com/channels/691052431525675048/1203087353850364004/1212465038711984158)
on this. `Dir2`/`Dir3`/`Dir3A` was quite unanimously chosen as the best
option, but of course it was a very small poll and inconclusive, so
other opinions are certainly welcome too.
---------
Co-authored-by: IceSentry <c.giguere42@gmail.com>
2024-02-28 22:48:43 +00:00
|
|
|
impl approx::RelativeEq for Dir3 {
|
2024-02-26 13:57:49 +00:00
|
|
|
fn default_max_relative() -> f32 {
|
|
|
|
f32::EPSILON
|
|
|
|
}
|
|
|
|
fn relative_eq(&self, other: &Self, epsilon: f32, max_relative: f32) -> bool {
|
|
|
|
self.as_ref()
|
|
|
|
.relative_eq(other.as_ref(), epsilon, max_relative)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(feature = "approx")]
|
Rename `Direction2d/3d` to `Dir2/3` (#12189)
# Objective
Split up from #12017, rename Bevy's direction types.
Currently, Bevy has the `Direction2d`, `Direction3d`, and `Direction3dA`
types, which provide a type-level guarantee that their contained vectors
remain normalized. They can be very useful for a lot of APIs for safety,
explicitness, and in some cases performance, as they can sometimes avoid
unnecessary normalizations.
However, many consider them to be inconvenient to use, and opt for
standard vector types like `Vec3` because of this. One reason is that
the direction type names are a bit long and can be annoying to write (of
course you can use autocomplete, but just typing `Vec3` is still nicer),
and in some intances, the extra characters can make formatting worse.
The naming is also inconsistent with Glam's shorter type names, and
results in names like `Direction3dA`, which (in my opinion) are
difficult to read and even a bit ugly.
This PR proposes renaming the types to `Dir2`, `Dir3`, and `Dir3A`.
These names are nice and easy to write, consistent with Glam, and work
well for variants like the SIMD aligned `Dir3A`. As a bonus, it can also
result in nicer formatting in a lot of cases, which can be seen from the
diff of this PR.
Some examples of what it looks like: (copied from #12017)
```rust
// Before
let ray_cast = RayCast2d::new(Vec2::ZERO, Direction2d::X, 5.0);
// After
let ray_cast = RayCast2d::new(Vec2::ZERO, Dir2::X, 5.0);
```
```rust
// Before (an example using Bevy XPBD)
let hit = spatial_query.cast_ray(
Vec3::ZERO,
Direction3d::X,
f32::MAX,
true,
SpatialQueryFilter::default(),
);
// After
let hit = spatial_query.cast_ray(
Vec3::ZERO,
Dir3::X,
f32::MAX,
true,
SpatialQueryFilter::default(),
);
```
```rust
// Before
self.circle(
Vec3::new(0.0, -2.0, 0.0),
Direction3d::Y,
5.0,
Color::TURQUOISE,
);
// After (formatting is collapsed in this case)
self.circle(Vec3::new(0.0, -2.0, 0.0), Dir3::Y, 5.0, Color::TURQUOISE);
```
## Solution
Rename `Direction2d`, `Direction3d`, and `Direction3dA` to `Dir2`,
`Dir3`, and `Dir3A`.
---
## Migration Guide
The `Direction2d` and `Direction3d` types have been renamed to `Dir2`
and `Dir3`.
## Additional Context
This has been brought up on the Discord a few times, and we had a small
[poll](https://discord.com/channels/691052431525675048/1203087353850364004/1212465038711984158)
on this. `Dir2`/`Dir3`/`Dir3A` was quite unanimously chosen as the best
option, but of course it was a very small poll and inconclusive, so
other opinions are certainly welcome too.
---------
Co-authored-by: IceSentry <c.giguere42@gmail.com>
2024-02-28 22:48:43 +00:00
|
|
|
impl approx::UlpsEq for Dir3 {
|
2024-02-26 13:57:49 +00:00
|
|
|
fn default_max_ulps() -> u32 {
|
|
|
|
4
|
|
|
|
}
|
|
|
|
fn ulps_eq(&self, other: &Self, epsilon: f32, max_ulps: u32) -> bool {
|
|
|
|
self.as_ref().ulps_eq(other.as_ref(), epsilon, max_ulps)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// A normalized SIMD vector pointing in a direction in 3D space.
|
|
|
|
///
|
|
|
|
/// This type stores a 16 byte aligned [`Vec3A`].
|
Rename `Direction2d/3d` to `Dir2/3` (#12189)
# Objective
Split up from #12017, rename Bevy's direction types.
Currently, Bevy has the `Direction2d`, `Direction3d`, and `Direction3dA`
types, which provide a type-level guarantee that their contained vectors
remain normalized. They can be very useful for a lot of APIs for safety,
explicitness, and in some cases performance, as they can sometimes avoid
unnecessary normalizations.
However, many consider them to be inconvenient to use, and opt for
standard vector types like `Vec3` because of this. One reason is that
the direction type names are a bit long and can be annoying to write (of
course you can use autocomplete, but just typing `Vec3` is still nicer),
and in some intances, the extra characters can make formatting worse.
The naming is also inconsistent with Glam's shorter type names, and
results in names like `Direction3dA`, which (in my opinion) are
difficult to read and even a bit ugly.
This PR proposes renaming the types to `Dir2`, `Dir3`, and `Dir3A`.
These names are nice and easy to write, consistent with Glam, and work
well for variants like the SIMD aligned `Dir3A`. As a bonus, it can also
result in nicer formatting in a lot of cases, which can be seen from the
diff of this PR.
Some examples of what it looks like: (copied from #12017)
```rust
// Before
let ray_cast = RayCast2d::new(Vec2::ZERO, Direction2d::X, 5.0);
// After
let ray_cast = RayCast2d::new(Vec2::ZERO, Dir2::X, 5.0);
```
```rust
// Before (an example using Bevy XPBD)
let hit = spatial_query.cast_ray(
Vec3::ZERO,
Direction3d::X,
f32::MAX,
true,
SpatialQueryFilter::default(),
);
// After
let hit = spatial_query.cast_ray(
Vec3::ZERO,
Dir3::X,
f32::MAX,
true,
SpatialQueryFilter::default(),
);
```
```rust
// Before
self.circle(
Vec3::new(0.0, -2.0, 0.0),
Direction3d::Y,
5.0,
Color::TURQUOISE,
);
// After (formatting is collapsed in this case)
self.circle(Vec3::new(0.0, -2.0, 0.0), Dir3::Y, 5.0, Color::TURQUOISE);
```
## Solution
Rename `Direction2d`, `Direction3d`, and `Direction3dA` to `Dir2`,
`Dir3`, and `Dir3A`.
---
## Migration Guide
The `Direction2d` and `Direction3d` types have been renamed to `Dir2`
and `Dir3`.
## Additional Context
This has been brought up on the Discord a few times, and we had a small
[poll](https://discord.com/channels/691052431525675048/1203087353850364004/1212465038711984158)
on this. `Dir2`/`Dir3`/`Dir3A` was quite unanimously chosen as the best
option, but of course it was a very small poll and inconclusive, so
other opinions are certainly welcome too.
---------
Co-authored-by: IceSentry <c.giguere42@gmail.com>
2024-02-28 22:48:43 +00:00
|
|
|
/// This may or may not be faster than [`Dir3`]: make sure to benchmark!
|
2024-02-26 13:57:49 +00:00
|
|
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
|
|
|
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
|
2024-05-27 14:15:22 +00:00
|
|
|
#[cfg_attr(feature = "bevy_reflect", derive(Reflect), reflect(Debug, PartialEq))]
|
|
|
|
#[cfg_attr(
|
|
|
|
all(feature = "serialize", feature = "bevy_reflect"),
|
|
|
|
reflect(Serialize, Deserialize)
|
|
|
|
)]
|
Rename `Direction2d/3d` to `Dir2/3` (#12189)
# Objective
Split up from #12017, rename Bevy's direction types.
Currently, Bevy has the `Direction2d`, `Direction3d`, and `Direction3dA`
types, which provide a type-level guarantee that their contained vectors
remain normalized. They can be very useful for a lot of APIs for safety,
explicitness, and in some cases performance, as they can sometimes avoid
unnecessary normalizations.
However, many consider them to be inconvenient to use, and opt for
standard vector types like `Vec3` because of this. One reason is that
the direction type names are a bit long and can be annoying to write (of
course you can use autocomplete, but just typing `Vec3` is still nicer),
and in some intances, the extra characters can make formatting worse.
The naming is also inconsistent with Glam's shorter type names, and
results in names like `Direction3dA`, which (in my opinion) are
difficult to read and even a bit ugly.
This PR proposes renaming the types to `Dir2`, `Dir3`, and `Dir3A`.
These names are nice and easy to write, consistent with Glam, and work
well for variants like the SIMD aligned `Dir3A`. As a bonus, it can also
result in nicer formatting in a lot of cases, which can be seen from the
diff of this PR.
Some examples of what it looks like: (copied from #12017)
```rust
// Before
let ray_cast = RayCast2d::new(Vec2::ZERO, Direction2d::X, 5.0);
// After
let ray_cast = RayCast2d::new(Vec2::ZERO, Dir2::X, 5.0);
```
```rust
// Before (an example using Bevy XPBD)
let hit = spatial_query.cast_ray(
Vec3::ZERO,
Direction3d::X,
f32::MAX,
true,
SpatialQueryFilter::default(),
);
// After
let hit = spatial_query.cast_ray(
Vec3::ZERO,
Dir3::X,
f32::MAX,
true,
SpatialQueryFilter::default(),
);
```
```rust
// Before
self.circle(
Vec3::new(0.0, -2.0, 0.0),
Direction3d::Y,
5.0,
Color::TURQUOISE,
);
// After (formatting is collapsed in this case)
self.circle(Vec3::new(0.0, -2.0, 0.0), Dir3::Y, 5.0, Color::TURQUOISE);
```
## Solution
Rename `Direction2d`, `Direction3d`, and `Direction3dA` to `Dir2`,
`Dir3`, and `Dir3A`.
---
## Migration Guide
The `Direction2d` and `Direction3d` types have been renamed to `Dir2`
and `Dir3`.
## Additional Context
This has been brought up on the Discord a few times, and we had a small
[poll](https://discord.com/channels/691052431525675048/1203087353850364004/1212465038711984158)
on this. `Dir2`/`Dir3`/`Dir3A` was quite unanimously chosen as the best
option, but of course it was a very small poll and inconclusive, so
other opinions are certainly welcome too.
---------
Co-authored-by: IceSentry <c.giguere42@gmail.com>
2024-02-28 22:48:43 +00:00
|
|
|
#[doc(alias = "Direction3dA")]
|
|
|
|
pub struct Dir3A(Vec3A);
|
|
|
|
impl Primitive3d for Dir3A {}
|
2024-02-26 13:57:49 +00:00
|
|
|
|
Rename `Direction2d/3d` to `Dir2/3` (#12189)
# Objective
Split up from #12017, rename Bevy's direction types.
Currently, Bevy has the `Direction2d`, `Direction3d`, and `Direction3dA`
types, which provide a type-level guarantee that their contained vectors
remain normalized. They can be very useful for a lot of APIs for safety,
explicitness, and in some cases performance, as they can sometimes avoid
unnecessary normalizations.
However, many consider them to be inconvenient to use, and opt for
standard vector types like `Vec3` because of this. One reason is that
the direction type names are a bit long and can be annoying to write (of
course you can use autocomplete, but just typing `Vec3` is still nicer),
and in some intances, the extra characters can make formatting worse.
The naming is also inconsistent with Glam's shorter type names, and
results in names like `Direction3dA`, which (in my opinion) are
difficult to read and even a bit ugly.
This PR proposes renaming the types to `Dir2`, `Dir3`, and `Dir3A`.
These names are nice and easy to write, consistent with Glam, and work
well for variants like the SIMD aligned `Dir3A`. As a bonus, it can also
result in nicer formatting in a lot of cases, which can be seen from the
diff of this PR.
Some examples of what it looks like: (copied from #12017)
```rust
// Before
let ray_cast = RayCast2d::new(Vec2::ZERO, Direction2d::X, 5.0);
// After
let ray_cast = RayCast2d::new(Vec2::ZERO, Dir2::X, 5.0);
```
```rust
// Before (an example using Bevy XPBD)
let hit = spatial_query.cast_ray(
Vec3::ZERO,
Direction3d::X,
f32::MAX,
true,
SpatialQueryFilter::default(),
);
// After
let hit = spatial_query.cast_ray(
Vec3::ZERO,
Dir3::X,
f32::MAX,
true,
SpatialQueryFilter::default(),
);
```
```rust
// Before
self.circle(
Vec3::new(0.0, -2.0, 0.0),
Direction3d::Y,
5.0,
Color::TURQUOISE,
);
// After (formatting is collapsed in this case)
self.circle(Vec3::new(0.0, -2.0, 0.0), Dir3::Y, 5.0, Color::TURQUOISE);
```
## Solution
Rename `Direction2d`, `Direction3d`, and `Direction3dA` to `Dir2`,
`Dir3`, and `Dir3A`.
---
## Migration Guide
The `Direction2d` and `Direction3d` types have been renamed to `Dir2`
and `Dir3`.
## Additional Context
This has been brought up on the Discord a few times, and we had a small
[poll](https://discord.com/channels/691052431525675048/1203087353850364004/1212465038711984158)
on this. `Dir2`/`Dir3`/`Dir3A` was quite unanimously chosen as the best
option, but of course it was a very small poll and inconclusive, so
other opinions are certainly welcome too.
---------
Co-authored-by: IceSentry <c.giguere42@gmail.com>
2024-02-28 22:48:43 +00:00
|
|
|
impl Dir3A {
|
2024-02-26 13:57:49 +00:00
|
|
|
/// A unit vector pointing along the positive X axis.
|
|
|
|
pub const X: Self = Self(Vec3A::X);
|
|
|
|
/// A unit vector pointing along the positive Y axis.
|
|
|
|
pub const Y: Self = Self(Vec3A::Y);
|
|
|
|
/// A unit vector pointing along the positive Z axis.
|
|
|
|
pub const Z: Self = Self(Vec3A::Z);
|
|
|
|
/// A unit vector pointing along the negative X axis.
|
|
|
|
pub const NEG_X: Self = Self(Vec3A::NEG_X);
|
|
|
|
/// A unit vector pointing along the negative Y axis.
|
|
|
|
pub const NEG_Y: Self = Self(Vec3A::NEG_Y);
|
|
|
|
/// A unit vector pointing along the negative Z axis.
|
|
|
|
pub const NEG_Z: Self = Self(Vec3A::NEG_Z);
|
2024-05-09 23:30:44 +00:00
|
|
|
/// The directional axes.
|
|
|
|
pub const AXES: [Self; 3] = [Self::X, Self::Y, Self::Z];
|
2024-02-26 13:57:49 +00:00
|
|
|
|
2024-05-23 15:20:21 +00:00
|
|
|
/// Create a direction from a finite, nonzero [`Vec3A`], normalizing it.
|
2024-02-26 13:57:49 +00:00
|
|
|
///
|
|
|
|
/// Returns [`Err(InvalidDirectionError)`](InvalidDirectionError) if the length
|
|
|
|
/// of the given vector is zero (or very close to zero), infinite, or `NaN`.
|
|
|
|
pub fn new(value: Vec3A) -> Result<Self, InvalidDirectionError> {
|
|
|
|
Self::new_and_length(value).map(|(dir, _)| dir)
|
|
|
|
}
|
|
|
|
|
Rename `Direction2d/3d` to `Dir2/3` (#12189)
# Objective
Split up from #12017, rename Bevy's direction types.
Currently, Bevy has the `Direction2d`, `Direction3d`, and `Direction3dA`
types, which provide a type-level guarantee that their contained vectors
remain normalized. They can be very useful for a lot of APIs for safety,
explicitness, and in some cases performance, as they can sometimes avoid
unnecessary normalizations.
However, many consider them to be inconvenient to use, and opt for
standard vector types like `Vec3` because of this. One reason is that
the direction type names are a bit long and can be annoying to write (of
course you can use autocomplete, but just typing `Vec3` is still nicer),
and in some intances, the extra characters can make formatting worse.
The naming is also inconsistent with Glam's shorter type names, and
results in names like `Direction3dA`, which (in my opinion) are
difficult to read and even a bit ugly.
This PR proposes renaming the types to `Dir2`, `Dir3`, and `Dir3A`.
These names are nice and easy to write, consistent with Glam, and work
well for variants like the SIMD aligned `Dir3A`. As a bonus, it can also
result in nicer formatting in a lot of cases, which can be seen from the
diff of this PR.
Some examples of what it looks like: (copied from #12017)
```rust
// Before
let ray_cast = RayCast2d::new(Vec2::ZERO, Direction2d::X, 5.0);
// After
let ray_cast = RayCast2d::new(Vec2::ZERO, Dir2::X, 5.0);
```
```rust
// Before (an example using Bevy XPBD)
let hit = spatial_query.cast_ray(
Vec3::ZERO,
Direction3d::X,
f32::MAX,
true,
SpatialQueryFilter::default(),
);
// After
let hit = spatial_query.cast_ray(
Vec3::ZERO,
Dir3::X,
f32::MAX,
true,
SpatialQueryFilter::default(),
);
```
```rust
// Before
self.circle(
Vec3::new(0.0, -2.0, 0.0),
Direction3d::Y,
5.0,
Color::TURQUOISE,
);
// After (formatting is collapsed in this case)
self.circle(Vec3::new(0.0, -2.0, 0.0), Dir3::Y, 5.0, Color::TURQUOISE);
```
## Solution
Rename `Direction2d`, `Direction3d`, and `Direction3dA` to `Dir2`,
`Dir3`, and `Dir3A`.
---
## Migration Guide
The `Direction2d` and `Direction3d` types have been renamed to `Dir2`
and `Dir3`.
## Additional Context
This has been brought up on the Discord a few times, and we had a small
[poll](https://discord.com/channels/691052431525675048/1203087353850364004/1212465038711984158)
on this. `Dir2`/`Dir3`/`Dir3A` was quite unanimously chosen as the best
option, but of course it was a very small poll and inconclusive, so
other opinions are certainly welcome too.
---------
Co-authored-by: IceSentry <c.giguere42@gmail.com>
2024-02-28 22:48:43 +00:00
|
|
|
/// Create a [`Dir3A`] from a [`Vec3A`] that is already normalized.
|
2024-02-26 13:57:49 +00:00
|
|
|
///
|
|
|
|
/// # Warning
|
|
|
|
///
|
Improve error messages for denormalized directions (#12278)
# Objective
`Dir3` and `Dir3A` can be rotated using `Quat`s. However, if enough
floating point error accumulates or (more commonly) the rotation itself
is degenerate (like not normalized), the resulting direction can also
become denormalized.
Currently, with debug assertions enabled, it panics in these cases with
the message `rotated.is_normalized()`. This error message is unclear,
doesn't give information about *how* it is denormalized (like is the
length too large, NaN, or something else), and is overall not very
helpful. Panicking for small-ish error might also be a bit too strict,
and has lead to unwanted crashes in crates like `bevy_xpbd` (although it
has also helped in finding actual bugs).
The error message should be clearer and give more context, and it
shouldn't cause unwanted crashes.
## Solution
Change the `debug_assert!` to a warning for small error with a (squared
length) threshold of 2e-4 and a panic for clear error with a threshold
of 2e-2. The warnings mention the direction type and the length of the
denormalized vector.
Here's what the error and warning look like:
```
Error: `Dir3` is denormalized after rotation. The length is 1.014242.
```
```
Warning: `Dir3A` is denormalized after rotation. The length is 1.0001414.
```
I gave the same treatment to `new_unchecked`:
```
Error: The vector given to `Dir3::new_unchecked` is not normalized. The length is 1.014242.
```
```
Warning: The vector given to `Dir3A::new_unchecked` is not normalized. The length is 1.0001414.
```
---
## Discussion
### Threshold values
The thresholds are somewhat arbitrary. 2e-4 is what Glam uses for the
squared length in `is_normalized` (after I corrected it in
bitshifter/glam-rs#480), and 2e-2 is just what I thought could be a
clear sign of something being critically wrong. I can definitely tune
them if there are better thresholds though.
### Logging
`bevy_math` doesn't have `bevy_log`, so we can't use `warn!` or
`error!`. This is why I made it use just `eprintln!` and `panic!` for
now. Let me know if there's a better way of logging errors in
`bevy_math`.
2024-03-04 00:01:32 +00:00
|
|
|
/// `value` must be normalized, i.e its length must be `1.0`.
|
2024-02-26 13:57:49 +00:00
|
|
|
pub fn new_unchecked(value: Vec3A) -> Self {
|
Improve error messages for denormalized directions (#12278)
# Objective
`Dir3` and `Dir3A` can be rotated using `Quat`s. However, if enough
floating point error accumulates or (more commonly) the rotation itself
is degenerate (like not normalized), the resulting direction can also
become denormalized.
Currently, with debug assertions enabled, it panics in these cases with
the message `rotated.is_normalized()`. This error message is unclear,
doesn't give information about *how* it is denormalized (like is the
length too large, NaN, or something else), and is overall not very
helpful. Panicking for small-ish error might also be a bit too strict,
and has lead to unwanted crashes in crates like `bevy_xpbd` (although it
has also helped in finding actual bugs).
The error message should be clearer and give more context, and it
shouldn't cause unwanted crashes.
## Solution
Change the `debug_assert!` to a warning for small error with a (squared
length) threshold of 2e-4 and a panic for clear error with a threshold
of 2e-2. The warnings mention the direction type and the length of the
denormalized vector.
Here's what the error and warning look like:
```
Error: `Dir3` is denormalized after rotation. The length is 1.014242.
```
```
Warning: `Dir3A` is denormalized after rotation. The length is 1.0001414.
```
I gave the same treatment to `new_unchecked`:
```
Error: The vector given to `Dir3::new_unchecked` is not normalized. The length is 1.014242.
```
```
Warning: The vector given to `Dir3A::new_unchecked` is not normalized. The length is 1.0001414.
```
---
## Discussion
### Threshold values
The thresholds are somewhat arbitrary. 2e-4 is what Glam uses for the
squared length in `is_normalized` (after I corrected it in
bitshifter/glam-rs#480), and 2e-2 is just what I thought could be a
clear sign of something being critically wrong. I can definitely tune
them if there are better thresholds though.
### Logging
`bevy_math` doesn't have `bevy_log`, so we can't use `warn!` or
`error!`. This is why I made it use just `eprintln!` and `panic!` for
now. Let me know if there's a better way of logging errors in
`bevy_math`.
2024-03-04 00:01:32 +00:00
|
|
|
#[cfg(debug_assertions)]
|
|
|
|
assert_is_normalized(
|
|
|
|
"The vector given to `Dir3A::new_unchecked` is not normalized.",
|
|
|
|
value.length_squared(),
|
|
|
|
);
|
2024-02-26 13:57:49 +00:00
|
|
|
|
|
|
|
Self(value)
|
|
|
|
}
|
|
|
|
|
2024-05-23 15:20:21 +00:00
|
|
|
/// Create a direction from a finite, nonzero [`Vec3A`], normalizing it and
|
|
|
|
/// also returning its original length.
|
2024-02-26 13:57:49 +00:00
|
|
|
///
|
|
|
|
/// Returns [`Err(InvalidDirectionError)`](InvalidDirectionError) if the length
|
|
|
|
/// of the given vector is zero (or very close to zero), infinite, or `NaN`.
|
|
|
|
pub fn new_and_length(value: Vec3A) -> Result<(Self, f32), InvalidDirectionError> {
|
|
|
|
let length = value.length();
|
|
|
|
let direction = (length.is_finite() && length > 0.0).then_some(value / length);
|
|
|
|
|
|
|
|
direction
|
|
|
|
.map(|dir| (Self(dir), length))
|
|
|
|
.ok_or(InvalidDirectionError::from_length(length))
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Create a direction from its `x`, `y`, and `z` components.
|
|
|
|
///
|
|
|
|
/// Returns [`Err(InvalidDirectionError)`](InvalidDirectionError) if the length
|
|
|
|
/// of the vector formed by the components is zero (or very close to zero), infinite, or `NaN`.
|
|
|
|
pub fn from_xyz(x: f32, y: f32, z: f32) -> Result<Self, InvalidDirectionError> {
|
|
|
|
Self::new(Vec3A::new(x, y, z))
|
|
|
|
}
|
2024-03-18 17:49:58 +00:00
|
|
|
|
2024-08-02 13:10:13 +00:00
|
|
|
/// Create a direction from its `x`, `y`, and `z` components, assuming the resulting vector is normalized.
|
|
|
|
///
|
|
|
|
/// # Warning
|
|
|
|
///
|
|
|
|
/// The vector produced from `x`, `y`, and `z` must be normalized, i.e its length must be `1.0`.
|
|
|
|
pub fn from_xyz_unchecked(x: f32, y: f32, z: f32) -> Self {
|
|
|
|
Self::new_unchecked(Vec3A::new(x, y, z))
|
|
|
|
}
|
|
|
|
|
2024-03-18 17:49:58 +00:00
|
|
|
/// Returns the inner [`Vec3A`]
|
|
|
|
pub const fn as_vec3a(&self) -> Vec3A {
|
|
|
|
self.0
|
|
|
|
}
|
2024-05-21 21:13:32 +00:00
|
|
|
|
|
|
|
/// Performs a spherical linear interpolation between `self` and `rhs`
|
|
|
|
/// based on the value `s`.
|
|
|
|
///
|
|
|
|
/// This corresponds to interpolating between the two directions at a constant angular velocity.
|
|
|
|
///
|
|
|
|
/// When `s == 0.0`, the result will be equal to `self`.
|
|
|
|
/// When `s == 1.0`, the result will be equal to `rhs`.
|
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// # use bevy_math::Dir3A;
|
|
|
|
/// # use approx::{assert_relative_eq, RelativeEq};
|
|
|
|
/// #
|
|
|
|
/// let dir1 = Dir3A::X;
|
|
|
|
/// let dir2 = Dir3A::Y;
|
|
|
|
///
|
|
|
|
/// let result1 = dir1.slerp(dir2, 1.0 / 3.0);
|
|
|
|
/// assert_relative_eq!(
|
|
|
|
/// result1,
|
|
|
|
/// Dir3A::from_xyz(0.75_f32.sqrt(), 0.5, 0.0).unwrap(),
|
|
|
|
/// epsilon = 0.000001
|
|
|
|
/// );
|
|
|
|
///
|
|
|
|
/// let result2 = dir1.slerp(dir2, 0.5);
|
|
|
|
/// assert_relative_eq!(result2, Dir3A::from_xyz(0.5_f32.sqrt(), 0.5_f32.sqrt(), 0.0).unwrap());
|
|
|
|
/// ```
|
|
|
|
#[inline]
|
|
|
|
pub fn slerp(self, rhs: Self, s: f32) -> Self {
|
|
|
|
let quat = Quat::IDENTITY.slerp(
|
|
|
|
Quat::from_rotation_arc(Vec3::from(self.0), Vec3::from(rhs.0)),
|
|
|
|
s,
|
|
|
|
);
|
|
|
|
Dir3A(quat.mul_vec3a(self.0))
|
|
|
|
}
|
2024-07-22 18:42:48 +00:00
|
|
|
|
|
|
|
/// Returns `self` after an approximate normalization, assuming the value is already nearly normalized.
|
|
|
|
/// Useful for preventing numerical error accumulation.
|
|
|
|
///
|
|
|
|
/// See [`Dir3::fast_renormalize`] for an example of when such error accumulation might occur.
|
|
|
|
#[inline]
|
|
|
|
pub fn fast_renormalize(self) -> Self {
|
|
|
|
let length_squared = self.0.length_squared();
|
|
|
|
// Based on a Taylor approximation of the inverse square root, see [`Dir3::fast_renormalize`] for more details.
|
|
|
|
Self(self * (0.5 * (3.0 - length_squared)))
|
|
|
|
}
|
2024-02-26 13:57:49 +00:00
|
|
|
}
|
|
|
|
|
2024-04-25 18:56:58 +00:00
|
|
|
impl From<Dir3> for Dir3A {
|
|
|
|
fn from(value: Dir3) -> Self {
|
|
|
|
Self(value.0.into())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<Dir3A> for Dir3 {
|
|
|
|
fn from(value: Dir3A) -> Self {
|
|
|
|
Self(value.0.into())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Rename `Direction2d/3d` to `Dir2/3` (#12189)
# Objective
Split up from #12017, rename Bevy's direction types.
Currently, Bevy has the `Direction2d`, `Direction3d`, and `Direction3dA`
types, which provide a type-level guarantee that their contained vectors
remain normalized. They can be very useful for a lot of APIs for safety,
explicitness, and in some cases performance, as they can sometimes avoid
unnecessary normalizations.
However, many consider them to be inconvenient to use, and opt for
standard vector types like `Vec3` because of this. One reason is that
the direction type names are a bit long and can be annoying to write (of
course you can use autocomplete, but just typing `Vec3` is still nicer),
and in some intances, the extra characters can make formatting worse.
The naming is also inconsistent with Glam's shorter type names, and
results in names like `Direction3dA`, which (in my opinion) are
difficult to read and even a bit ugly.
This PR proposes renaming the types to `Dir2`, `Dir3`, and `Dir3A`.
These names are nice and easy to write, consistent with Glam, and work
well for variants like the SIMD aligned `Dir3A`. As a bonus, it can also
result in nicer formatting in a lot of cases, which can be seen from the
diff of this PR.
Some examples of what it looks like: (copied from #12017)
```rust
// Before
let ray_cast = RayCast2d::new(Vec2::ZERO, Direction2d::X, 5.0);
// After
let ray_cast = RayCast2d::new(Vec2::ZERO, Dir2::X, 5.0);
```
```rust
// Before (an example using Bevy XPBD)
let hit = spatial_query.cast_ray(
Vec3::ZERO,
Direction3d::X,
f32::MAX,
true,
SpatialQueryFilter::default(),
);
// After
let hit = spatial_query.cast_ray(
Vec3::ZERO,
Dir3::X,
f32::MAX,
true,
SpatialQueryFilter::default(),
);
```
```rust
// Before
self.circle(
Vec3::new(0.0, -2.0, 0.0),
Direction3d::Y,
5.0,
Color::TURQUOISE,
);
// After (formatting is collapsed in this case)
self.circle(Vec3::new(0.0, -2.0, 0.0), Dir3::Y, 5.0, Color::TURQUOISE);
```
## Solution
Rename `Direction2d`, `Direction3d`, and `Direction3dA` to `Dir2`,
`Dir3`, and `Dir3A`.
---
## Migration Guide
The `Direction2d` and `Direction3d` types have been renamed to `Dir2`
and `Dir3`.
## Additional Context
This has been brought up on the Discord a few times, and we had a small
[poll](https://discord.com/channels/691052431525675048/1203087353850364004/1212465038711984158)
on this. `Dir2`/`Dir3`/`Dir3A` was quite unanimously chosen as the best
option, but of course it was a very small poll and inconclusive, so
other opinions are certainly welcome too.
---------
Co-authored-by: IceSentry <c.giguere42@gmail.com>
2024-02-28 22:48:43 +00:00
|
|
|
impl TryFrom<Vec3A> for Dir3A {
|
2024-02-26 13:57:49 +00:00
|
|
|
type Error = InvalidDirectionError;
|
|
|
|
|
|
|
|
fn try_from(value: Vec3A) -> Result<Self, Self::Error> {
|
|
|
|
Self::new(value)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Rename `Direction2d/3d` to `Dir2/3` (#12189)
# Objective
Split up from #12017, rename Bevy's direction types.
Currently, Bevy has the `Direction2d`, `Direction3d`, and `Direction3dA`
types, which provide a type-level guarantee that their contained vectors
remain normalized. They can be very useful for a lot of APIs for safety,
explicitness, and in some cases performance, as they can sometimes avoid
unnecessary normalizations.
However, many consider them to be inconvenient to use, and opt for
standard vector types like `Vec3` because of this. One reason is that
the direction type names are a bit long and can be annoying to write (of
course you can use autocomplete, but just typing `Vec3` is still nicer),
and in some intances, the extra characters can make formatting worse.
The naming is also inconsistent with Glam's shorter type names, and
results in names like `Direction3dA`, which (in my opinion) are
difficult to read and even a bit ugly.
This PR proposes renaming the types to `Dir2`, `Dir3`, and `Dir3A`.
These names are nice and easy to write, consistent with Glam, and work
well for variants like the SIMD aligned `Dir3A`. As a bonus, it can also
result in nicer formatting in a lot of cases, which can be seen from the
diff of this PR.
Some examples of what it looks like: (copied from #12017)
```rust
// Before
let ray_cast = RayCast2d::new(Vec2::ZERO, Direction2d::X, 5.0);
// After
let ray_cast = RayCast2d::new(Vec2::ZERO, Dir2::X, 5.0);
```
```rust
// Before (an example using Bevy XPBD)
let hit = spatial_query.cast_ray(
Vec3::ZERO,
Direction3d::X,
f32::MAX,
true,
SpatialQueryFilter::default(),
);
// After
let hit = spatial_query.cast_ray(
Vec3::ZERO,
Dir3::X,
f32::MAX,
true,
SpatialQueryFilter::default(),
);
```
```rust
// Before
self.circle(
Vec3::new(0.0, -2.0, 0.0),
Direction3d::Y,
5.0,
Color::TURQUOISE,
);
// After (formatting is collapsed in this case)
self.circle(Vec3::new(0.0, -2.0, 0.0), Dir3::Y, 5.0, Color::TURQUOISE);
```
## Solution
Rename `Direction2d`, `Direction3d`, and `Direction3dA` to `Dir2`,
`Dir3`, and `Dir3A`.
---
## Migration Guide
The `Direction2d` and `Direction3d` types have been renamed to `Dir2`
and `Dir3`.
## Additional Context
This has been brought up on the Discord a few times, and we had a small
[poll](https://discord.com/channels/691052431525675048/1203087353850364004/1212465038711984158)
on this. `Dir2`/`Dir3`/`Dir3A` was quite unanimously chosen as the best
option, but of course it was a very small poll and inconclusive, so
other opinions are certainly welcome too.
---------
Co-authored-by: IceSentry <c.giguere42@gmail.com>
2024-02-28 22:48:43 +00:00
|
|
|
impl From<Dir3A> for Vec3A {
|
|
|
|
fn from(value: Dir3A) -> Self {
|
2024-02-26 13:57:49 +00:00
|
|
|
value.0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-09-27 00:59:59 +00:00
|
|
|
impl core::ops::Deref for Dir3A {
|
2024-02-26 13:57:49 +00:00
|
|
|
type Target = Vec3A;
|
|
|
|
fn deref(&self) -> &Self::Target {
|
|
|
|
&self.0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-09-27 00:59:59 +00:00
|
|
|
impl core::ops::Neg for Dir3A {
|
2024-02-26 13:57:49 +00:00
|
|
|
type Output = Self;
|
|
|
|
fn neg(self) -> Self::Output {
|
|
|
|
Self(-self.0)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-09-27 00:59:59 +00:00
|
|
|
impl core::ops::Mul<f32> for Dir3A {
|
2024-02-26 13:57:49 +00:00
|
|
|
type Output = Vec3A;
|
|
|
|
fn mul(self, rhs: f32) -> Self::Output {
|
|
|
|
self.0 * rhs
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-09-27 00:59:59 +00:00
|
|
|
impl core::ops::Mul<Dir3A> for f32 {
|
2024-03-03 17:44:16 +00:00
|
|
|
type Output = Vec3A;
|
|
|
|
fn mul(self, rhs: Dir3A) -> Self::Output {
|
|
|
|
self * rhs.0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-09-27 00:59:59 +00:00
|
|
|
impl core::ops::Mul<Dir3A> for Quat {
|
Rename `Direction2d/3d` to `Dir2/3` (#12189)
# Objective
Split up from #12017, rename Bevy's direction types.
Currently, Bevy has the `Direction2d`, `Direction3d`, and `Direction3dA`
types, which provide a type-level guarantee that their contained vectors
remain normalized. They can be very useful for a lot of APIs for safety,
explicitness, and in some cases performance, as they can sometimes avoid
unnecessary normalizations.
However, many consider them to be inconvenient to use, and opt for
standard vector types like `Vec3` because of this. One reason is that
the direction type names are a bit long and can be annoying to write (of
course you can use autocomplete, but just typing `Vec3` is still nicer),
and in some intances, the extra characters can make formatting worse.
The naming is also inconsistent with Glam's shorter type names, and
results in names like `Direction3dA`, which (in my opinion) are
difficult to read and even a bit ugly.
This PR proposes renaming the types to `Dir2`, `Dir3`, and `Dir3A`.
These names are nice and easy to write, consistent with Glam, and work
well for variants like the SIMD aligned `Dir3A`. As a bonus, it can also
result in nicer formatting in a lot of cases, which can be seen from the
diff of this PR.
Some examples of what it looks like: (copied from #12017)
```rust
// Before
let ray_cast = RayCast2d::new(Vec2::ZERO, Direction2d::X, 5.0);
// After
let ray_cast = RayCast2d::new(Vec2::ZERO, Dir2::X, 5.0);
```
```rust
// Before (an example using Bevy XPBD)
let hit = spatial_query.cast_ray(
Vec3::ZERO,
Direction3d::X,
f32::MAX,
true,
SpatialQueryFilter::default(),
);
// After
let hit = spatial_query.cast_ray(
Vec3::ZERO,
Dir3::X,
f32::MAX,
true,
SpatialQueryFilter::default(),
);
```
```rust
// Before
self.circle(
Vec3::new(0.0, -2.0, 0.0),
Direction3d::Y,
5.0,
Color::TURQUOISE,
);
// After (formatting is collapsed in this case)
self.circle(Vec3::new(0.0, -2.0, 0.0), Dir3::Y, 5.0, Color::TURQUOISE);
```
## Solution
Rename `Direction2d`, `Direction3d`, and `Direction3dA` to `Dir2`,
`Dir3`, and `Dir3A`.
---
## Migration Guide
The `Direction2d` and `Direction3d` types have been renamed to `Dir2`
and `Dir3`.
## Additional Context
This has been brought up on the Discord a few times, and we had a small
[poll](https://discord.com/channels/691052431525675048/1203087353850364004/1212465038711984158)
on this. `Dir2`/`Dir3`/`Dir3A` was quite unanimously chosen as the best
option, but of course it was a very small poll and inconclusive, so
other opinions are certainly welcome too.
---------
Co-authored-by: IceSentry <c.giguere42@gmail.com>
2024-02-28 22:48:43 +00:00
|
|
|
type Output = Dir3A;
|
2024-02-26 13:57:49 +00:00
|
|
|
|
Rename `Direction2d/3d` to `Dir2/3` (#12189)
# Objective
Split up from #12017, rename Bevy's direction types.
Currently, Bevy has the `Direction2d`, `Direction3d`, and `Direction3dA`
types, which provide a type-level guarantee that their contained vectors
remain normalized. They can be very useful for a lot of APIs for safety,
explicitness, and in some cases performance, as they can sometimes avoid
unnecessary normalizations.
However, many consider them to be inconvenient to use, and opt for
standard vector types like `Vec3` because of this. One reason is that
the direction type names are a bit long and can be annoying to write (of
course you can use autocomplete, but just typing `Vec3` is still nicer),
and in some intances, the extra characters can make formatting worse.
The naming is also inconsistent with Glam's shorter type names, and
results in names like `Direction3dA`, which (in my opinion) are
difficult to read and even a bit ugly.
This PR proposes renaming the types to `Dir2`, `Dir3`, and `Dir3A`.
These names are nice and easy to write, consistent with Glam, and work
well for variants like the SIMD aligned `Dir3A`. As a bonus, it can also
result in nicer formatting in a lot of cases, which can be seen from the
diff of this PR.
Some examples of what it looks like: (copied from #12017)
```rust
// Before
let ray_cast = RayCast2d::new(Vec2::ZERO, Direction2d::X, 5.0);
// After
let ray_cast = RayCast2d::new(Vec2::ZERO, Dir2::X, 5.0);
```
```rust
// Before (an example using Bevy XPBD)
let hit = spatial_query.cast_ray(
Vec3::ZERO,
Direction3d::X,
f32::MAX,
true,
SpatialQueryFilter::default(),
);
// After
let hit = spatial_query.cast_ray(
Vec3::ZERO,
Dir3::X,
f32::MAX,
true,
SpatialQueryFilter::default(),
);
```
```rust
// Before
self.circle(
Vec3::new(0.0, -2.0, 0.0),
Direction3d::Y,
5.0,
Color::TURQUOISE,
);
// After (formatting is collapsed in this case)
self.circle(Vec3::new(0.0, -2.0, 0.0), Dir3::Y, 5.0, Color::TURQUOISE);
```
## Solution
Rename `Direction2d`, `Direction3d`, and `Direction3dA` to `Dir2`,
`Dir3`, and `Dir3A`.
---
## Migration Guide
The `Direction2d` and `Direction3d` types have been renamed to `Dir2`
and `Dir3`.
## Additional Context
This has been brought up on the Discord a few times, and we had a small
[poll](https://discord.com/channels/691052431525675048/1203087353850364004/1212465038711984158)
on this. `Dir2`/`Dir3`/`Dir3A` was quite unanimously chosen as the best
option, but of course it was a very small poll and inconclusive, so
other opinions are certainly welcome too.
---------
Co-authored-by: IceSentry <c.giguere42@gmail.com>
2024-02-28 22:48:43 +00:00
|
|
|
/// Rotates the [`Dir3A`] using a [`Quat`].
|
|
|
|
fn mul(self, direction: Dir3A) -> Self::Output {
|
2024-02-26 13:57:49 +00:00
|
|
|
let rotated = self * *direction;
|
|
|
|
|
Improve error messages for denormalized directions (#12278)
# Objective
`Dir3` and `Dir3A` can be rotated using `Quat`s. However, if enough
floating point error accumulates or (more commonly) the rotation itself
is degenerate (like not normalized), the resulting direction can also
become denormalized.
Currently, with debug assertions enabled, it panics in these cases with
the message `rotated.is_normalized()`. This error message is unclear,
doesn't give information about *how* it is denormalized (like is the
length too large, NaN, or something else), and is overall not very
helpful. Panicking for small-ish error might also be a bit too strict,
and has lead to unwanted crashes in crates like `bevy_xpbd` (although it
has also helped in finding actual bugs).
The error message should be clearer and give more context, and it
shouldn't cause unwanted crashes.
## Solution
Change the `debug_assert!` to a warning for small error with a (squared
length) threshold of 2e-4 and a panic for clear error with a threshold
of 2e-2. The warnings mention the direction type and the length of the
denormalized vector.
Here's what the error and warning look like:
```
Error: `Dir3` is denormalized after rotation. The length is 1.014242.
```
```
Warning: `Dir3A` is denormalized after rotation. The length is 1.0001414.
```
I gave the same treatment to `new_unchecked`:
```
Error: The vector given to `Dir3::new_unchecked` is not normalized. The length is 1.014242.
```
```
Warning: The vector given to `Dir3A::new_unchecked` is not normalized. The length is 1.0001414.
```
---
## Discussion
### Threshold values
The thresholds are somewhat arbitrary. 2e-4 is what Glam uses for the
squared length in `is_normalized` (after I corrected it in
bitshifter/glam-rs#480), and 2e-2 is just what I thought could be a
clear sign of something being critically wrong. I can definitely tune
them if there are better thresholds though.
### Logging
`bevy_math` doesn't have `bevy_log`, so we can't use `warn!` or
`error!`. This is why I made it use just `eprintln!` and `panic!` for
now. Let me know if there's a better way of logging errors in
`bevy_math`.
2024-03-04 00:01:32 +00:00
|
|
|
#[cfg(debug_assertions)]
|
|
|
|
assert_is_normalized(
|
|
|
|
"`Dir3A` is denormalized after rotation.",
|
|
|
|
rotated.length_squared(),
|
|
|
|
);
|
2024-02-26 13:57:49 +00:00
|
|
|
|
Improve error messages for denormalized directions (#12278)
# Objective
`Dir3` and `Dir3A` can be rotated using `Quat`s. However, if enough
floating point error accumulates or (more commonly) the rotation itself
is degenerate (like not normalized), the resulting direction can also
become denormalized.
Currently, with debug assertions enabled, it panics in these cases with
the message `rotated.is_normalized()`. This error message is unclear,
doesn't give information about *how* it is denormalized (like is the
length too large, NaN, or something else), and is overall not very
helpful. Panicking for small-ish error might also be a bit too strict,
and has lead to unwanted crashes in crates like `bevy_xpbd` (although it
has also helped in finding actual bugs).
The error message should be clearer and give more context, and it
shouldn't cause unwanted crashes.
## Solution
Change the `debug_assert!` to a warning for small error with a (squared
length) threshold of 2e-4 and a panic for clear error with a threshold
of 2e-2. The warnings mention the direction type and the length of the
denormalized vector.
Here's what the error and warning look like:
```
Error: `Dir3` is denormalized after rotation. The length is 1.014242.
```
```
Warning: `Dir3A` is denormalized after rotation. The length is 1.0001414.
```
I gave the same treatment to `new_unchecked`:
```
Error: The vector given to `Dir3::new_unchecked` is not normalized. The length is 1.014242.
```
```
Warning: The vector given to `Dir3A::new_unchecked` is not normalized. The length is 1.0001414.
```
---
## Discussion
### Threshold values
The thresholds are somewhat arbitrary. 2e-4 is what Glam uses for the
squared length in `is_normalized` (after I corrected it in
bitshifter/glam-rs#480), and 2e-2 is just what I thought could be a
clear sign of something being critically wrong. I can definitely tune
them if there are better thresholds though.
### Logging
`bevy_math` doesn't have `bevy_log`, so we can't use `warn!` or
`error!`. This is why I made it use just `eprintln!` and `panic!` for
now. Let me know if there's a better way of logging errors in
`bevy_math`.
2024-03-04 00:01:32 +00:00
|
|
|
Dir3A(rotated)
|
2024-02-26 13:57:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(feature = "approx")]
|
Rename `Direction2d/3d` to `Dir2/3` (#12189)
# Objective
Split up from #12017, rename Bevy's direction types.
Currently, Bevy has the `Direction2d`, `Direction3d`, and `Direction3dA`
types, which provide a type-level guarantee that their contained vectors
remain normalized. They can be very useful for a lot of APIs for safety,
explicitness, and in some cases performance, as they can sometimes avoid
unnecessary normalizations.
However, many consider them to be inconvenient to use, and opt for
standard vector types like `Vec3` because of this. One reason is that
the direction type names are a bit long and can be annoying to write (of
course you can use autocomplete, but just typing `Vec3` is still nicer),
and in some intances, the extra characters can make formatting worse.
The naming is also inconsistent with Glam's shorter type names, and
results in names like `Direction3dA`, which (in my opinion) are
difficult to read and even a bit ugly.
This PR proposes renaming the types to `Dir2`, `Dir3`, and `Dir3A`.
These names are nice and easy to write, consistent with Glam, and work
well for variants like the SIMD aligned `Dir3A`. As a bonus, it can also
result in nicer formatting in a lot of cases, which can be seen from the
diff of this PR.
Some examples of what it looks like: (copied from #12017)
```rust
// Before
let ray_cast = RayCast2d::new(Vec2::ZERO, Direction2d::X, 5.0);
// After
let ray_cast = RayCast2d::new(Vec2::ZERO, Dir2::X, 5.0);
```
```rust
// Before (an example using Bevy XPBD)
let hit = spatial_query.cast_ray(
Vec3::ZERO,
Direction3d::X,
f32::MAX,
true,
SpatialQueryFilter::default(),
);
// After
let hit = spatial_query.cast_ray(
Vec3::ZERO,
Dir3::X,
f32::MAX,
true,
SpatialQueryFilter::default(),
);
```
```rust
// Before
self.circle(
Vec3::new(0.0, -2.0, 0.0),
Direction3d::Y,
5.0,
Color::TURQUOISE,
);
// After (formatting is collapsed in this case)
self.circle(Vec3::new(0.0, -2.0, 0.0), Dir3::Y, 5.0, Color::TURQUOISE);
```
## Solution
Rename `Direction2d`, `Direction3d`, and `Direction3dA` to `Dir2`,
`Dir3`, and `Dir3A`.
---
## Migration Guide
The `Direction2d` and `Direction3d` types have been renamed to `Dir2`
and `Dir3`.
## Additional Context
This has been brought up on the Discord a few times, and we had a small
[poll](https://discord.com/channels/691052431525675048/1203087353850364004/1212465038711984158)
on this. `Dir2`/`Dir3`/`Dir3A` was quite unanimously chosen as the best
option, but of course it was a very small poll and inconclusive, so
other opinions are certainly welcome too.
---------
Co-authored-by: IceSentry <c.giguere42@gmail.com>
2024-02-28 22:48:43 +00:00
|
|
|
impl approx::AbsDiffEq for Dir3A {
|
2024-02-26 13:57:49 +00:00
|
|
|
type Epsilon = f32;
|
|
|
|
fn default_epsilon() -> f32 {
|
|
|
|
f32::EPSILON
|
|
|
|
}
|
|
|
|
fn abs_diff_eq(&self, other: &Self, epsilon: f32) -> bool {
|
|
|
|
self.as_ref().abs_diff_eq(other.as_ref(), epsilon)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(feature = "approx")]
|
Rename `Direction2d/3d` to `Dir2/3` (#12189)
# Objective
Split up from #12017, rename Bevy's direction types.
Currently, Bevy has the `Direction2d`, `Direction3d`, and `Direction3dA`
types, which provide a type-level guarantee that their contained vectors
remain normalized. They can be very useful for a lot of APIs for safety,
explicitness, and in some cases performance, as they can sometimes avoid
unnecessary normalizations.
However, many consider them to be inconvenient to use, and opt for
standard vector types like `Vec3` because of this. One reason is that
the direction type names are a bit long and can be annoying to write (of
course you can use autocomplete, but just typing `Vec3` is still nicer),
and in some intances, the extra characters can make formatting worse.
The naming is also inconsistent with Glam's shorter type names, and
results in names like `Direction3dA`, which (in my opinion) are
difficult to read and even a bit ugly.
This PR proposes renaming the types to `Dir2`, `Dir3`, and `Dir3A`.
These names are nice and easy to write, consistent with Glam, and work
well for variants like the SIMD aligned `Dir3A`. As a bonus, it can also
result in nicer formatting in a lot of cases, which can be seen from the
diff of this PR.
Some examples of what it looks like: (copied from #12017)
```rust
// Before
let ray_cast = RayCast2d::new(Vec2::ZERO, Direction2d::X, 5.0);
// After
let ray_cast = RayCast2d::new(Vec2::ZERO, Dir2::X, 5.0);
```
```rust
// Before (an example using Bevy XPBD)
let hit = spatial_query.cast_ray(
Vec3::ZERO,
Direction3d::X,
f32::MAX,
true,
SpatialQueryFilter::default(),
);
// After
let hit = spatial_query.cast_ray(
Vec3::ZERO,
Dir3::X,
f32::MAX,
true,
SpatialQueryFilter::default(),
);
```
```rust
// Before
self.circle(
Vec3::new(0.0, -2.0, 0.0),
Direction3d::Y,
5.0,
Color::TURQUOISE,
);
// After (formatting is collapsed in this case)
self.circle(Vec3::new(0.0, -2.0, 0.0), Dir3::Y, 5.0, Color::TURQUOISE);
```
## Solution
Rename `Direction2d`, `Direction3d`, and `Direction3dA` to `Dir2`,
`Dir3`, and `Dir3A`.
---
## Migration Guide
The `Direction2d` and `Direction3d` types have been renamed to `Dir2`
and `Dir3`.
## Additional Context
This has been brought up on the Discord a few times, and we had a small
[poll](https://discord.com/channels/691052431525675048/1203087353850364004/1212465038711984158)
on this. `Dir2`/`Dir3`/`Dir3A` was quite unanimously chosen as the best
option, but of course it was a very small poll and inconclusive, so
other opinions are certainly welcome too.
---------
Co-authored-by: IceSentry <c.giguere42@gmail.com>
2024-02-28 22:48:43 +00:00
|
|
|
impl approx::RelativeEq for Dir3A {
|
2024-02-26 13:57:49 +00:00
|
|
|
fn default_max_relative() -> f32 {
|
|
|
|
f32::EPSILON
|
|
|
|
}
|
|
|
|
fn relative_eq(&self, other: &Self, epsilon: f32, max_relative: f32) -> bool {
|
|
|
|
self.as_ref()
|
|
|
|
.relative_eq(other.as_ref(), epsilon, max_relative)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(feature = "approx")]
|
Rename `Direction2d/3d` to `Dir2/3` (#12189)
# Objective
Split up from #12017, rename Bevy's direction types.
Currently, Bevy has the `Direction2d`, `Direction3d`, and `Direction3dA`
types, which provide a type-level guarantee that their contained vectors
remain normalized. They can be very useful for a lot of APIs for safety,
explicitness, and in some cases performance, as they can sometimes avoid
unnecessary normalizations.
However, many consider them to be inconvenient to use, and opt for
standard vector types like `Vec3` because of this. One reason is that
the direction type names are a bit long and can be annoying to write (of
course you can use autocomplete, but just typing `Vec3` is still nicer),
and in some intances, the extra characters can make formatting worse.
The naming is also inconsistent with Glam's shorter type names, and
results in names like `Direction3dA`, which (in my opinion) are
difficult to read and even a bit ugly.
This PR proposes renaming the types to `Dir2`, `Dir3`, and `Dir3A`.
These names are nice and easy to write, consistent with Glam, and work
well for variants like the SIMD aligned `Dir3A`. As a bonus, it can also
result in nicer formatting in a lot of cases, which can be seen from the
diff of this PR.
Some examples of what it looks like: (copied from #12017)
```rust
// Before
let ray_cast = RayCast2d::new(Vec2::ZERO, Direction2d::X, 5.0);
// After
let ray_cast = RayCast2d::new(Vec2::ZERO, Dir2::X, 5.0);
```
```rust
// Before (an example using Bevy XPBD)
let hit = spatial_query.cast_ray(
Vec3::ZERO,
Direction3d::X,
f32::MAX,
true,
SpatialQueryFilter::default(),
);
// After
let hit = spatial_query.cast_ray(
Vec3::ZERO,
Dir3::X,
f32::MAX,
true,
SpatialQueryFilter::default(),
);
```
```rust
// Before
self.circle(
Vec3::new(0.0, -2.0, 0.0),
Direction3d::Y,
5.0,
Color::TURQUOISE,
);
// After (formatting is collapsed in this case)
self.circle(Vec3::new(0.0, -2.0, 0.0), Dir3::Y, 5.0, Color::TURQUOISE);
```
## Solution
Rename `Direction2d`, `Direction3d`, and `Direction3dA` to `Dir2`,
`Dir3`, and `Dir3A`.
---
## Migration Guide
The `Direction2d` and `Direction3d` types have been renamed to `Dir2`
and `Dir3`.
## Additional Context
This has been brought up on the Discord a few times, and we had a small
[poll](https://discord.com/channels/691052431525675048/1203087353850364004/1212465038711984158)
on this. `Dir2`/`Dir3`/`Dir3A` was quite unanimously chosen as the best
option, but of course it was a very small poll and inconclusive, so
other opinions are certainly welcome too.
---------
Co-authored-by: IceSentry <c.giguere42@gmail.com>
2024-02-28 22:48:43 +00:00
|
|
|
impl approx::UlpsEq for Dir3A {
|
2024-02-26 13:57:49 +00:00
|
|
|
fn default_max_ulps() -> u32 {
|
|
|
|
4
|
|
|
|
}
|
|
|
|
fn ulps_eq(&self, other: &Self, epsilon: f32, max_ulps: u32) -> bool {
|
|
|
|
self.as_ref().ulps_eq(other.as_ref(), epsilon, max_ulps)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
Make bevy_math's `libm` feature use `libm` for all `f32`methods with unspecified precision (#14693)
# Objective
Closes #14474
Previously, the `libm` feature of bevy_math would just pass the same
feature flag down to glam. However, bevy_math itself had many uses of
floating-point arithmetic with unspecified precision. For example,
`f32::sin_cos` and `f32::powi` have unspecified precision, which means
that the exact details of their output are not guaranteed to be stable
across different systems and/or versions of Rust. This means that users
of bevy_math could observe slightly different behavior on different
systems if these methods were used.
The goal of this PR is to make it so that the `libm` feature flag
actually guarantees some degree of determinacy within bevy_math itself
by switching to the libm versions of these functions when the `libm`
feature is enabled.
## Solution
bevy_math now has an internal module `bevy_math::ops`, which re-exports
either the standard versions of the operations or the libm versions
depending on whether the `libm` feature is enabled. For example,
`ops::sin` compiles to `f32::sin` without the `libm` feature and to
`libm::sinf` with it.
This approach has a small shortfall, which is that `f32::powi` (integer
powers of floating point numbers) does not have an equivalent in `libm`.
On the other hand, this method is only used for squaring and cubing
numbers in bevy_math. Accordingly, this deficit is covered by the
introduction of a trait `ops::FloatPow`:
```rust
pub(crate) trait FloatPow {
fn squared(self) -> Self;
fn cubed(self) -> Self;
}
```
Next, each current usage of the unspecified-precision methods has been
replaced by its equivalent in `ops`, so that when `libm` is enabled, the
libm version is used instead. The exception, of course, is that
`.powi(2)`/`.powi(3)` have been replaced with `.squared()`/`.cubed()`.
Finally, the usage of the plain `f32` methods with unspecified precision
is now linted out of bevy_math (and hence disallowed in CI). For
example, using `f32::sin` within bevy_math produces a warning that tells
the user to use the `ops::sin` version instead.
## Testing
Ran existing tests. It would be nice to check some benchmarks on NURBS
things once #14677 merges. I'm happy to wait until then if the rest of
this PR is fine.
---
## Discussion
In the future, it might make sense to actually expose `bevy_math::ops`
as public if any downstream Bevy crates want to provide similar
determinacy guarantees. For now, it's all just `pub(crate)`.
This PR also only covers `f32`. If we find ourselves using `f64`
internally in parts of bevy_math for better robustness, we could extend
the module and lints to cover the `f64` versions easily enough.
I don't know how feasible it is, but it would also be nice if we could
standardize the bevy_math tests with the `libm` feature in CI, since
their success is currently platform-dependent (e.g. 8 of them fail on my
machine when run locally).
---------
Co-authored-by: IQuick 143 <IQuick143cz@gmail.com>
2024-08-12 16:13:36 +00:00
|
|
|
use crate::ops;
|
|
|
|
|
2024-02-26 13:57:49 +00:00
|
|
|
use super::*;
|
2024-05-21 21:13:32 +00:00
|
|
|
use approx::assert_relative_eq;
|
2024-02-26 13:57:49 +00:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn dir2_creation() {
|
Rename `Direction2d/3d` to `Dir2/3` (#12189)
# Objective
Split up from #12017, rename Bevy's direction types.
Currently, Bevy has the `Direction2d`, `Direction3d`, and `Direction3dA`
types, which provide a type-level guarantee that their contained vectors
remain normalized. They can be very useful for a lot of APIs for safety,
explicitness, and in some cases performance, as they can sometimes avoid
unnecessary normalizations.
However, many consider them to be inconvenient to use, and opt for
standard vector types like `Vec3` because of this. One reason is that
the direction type names are a bit long and can be annoying to write (of
course you can use autocomplete, but just typing `Vec3` is still nicer),
and in some intances, the extra characters can make formatting worse.
The naming is also inconsistent with Glam's shorter type names, and
results in names like `Direction3dA`, which (in my opinion) are
difficult to read and even a bit ugly.
This PR proposes renaming the types to `Dir2`, `Dir3`, and `Dir3A`.
These names are nice and easy to write, consistent with Glam, and work
well for variants like the SIMD aligned `Dir3A`. As a bonus, it can also
result in nicer formatting in a lot of cases, which can be seen from the
diff of this PR.
Some examples of what it looks like: (copied from #12017)
```rust
// Before
let ray_cast = RayCast2d::new(Vec2::ZERO, Direction2d::X, 5.0);
// After
let ray_cast = RayCast2d::new(Vec2::ZERO, Dir2::X, 5.0);
```
```rust
// Before (an example using Bevy XPBD)
let hit = spatial_query.cast_ray(
Vec3::ZERO,
Direction3d::X,
f32::MAX,
true,
SpatialQueryFilter::default(),
);
// After
let hit = spatial_query.cast_ray(
Vec3::ZERO,
Dir3::X,
f32::MAX,
true,
SpatialQueryFilter::default(),
);
```
```rust
// Before
self.circle(
Vec3::new(0.0, -2.0, 0.0),
Direction3d::Y,
5.0,
Color::TURQUOISE,
);
// After (formatting is collapsed in this case)
self.circle(Vec3::new(0.0, -2.0, 0.0), Dir3::Y, 5.0, Color::TURQUOISE);
```
## Solution
Rename `Direction2d`, `Direction3d`, and `Direction3dA` to `Dir2`,
`Dir3`, and `Dir3A`.
---
## Migration Guide
The `Direction2d` and `Direction3d` types have been renamed to `Dir2`
and `Dir3`.
## Additional Context
This has been brought up on the Discord a few times, and we had a small
[poll](https://discord.com/channels/691052431525675048/1203087353850364004/1212465038711984158)
on this. `Dir2`/`Dir3`/`Dir3A` was quite unanimously chosen as the best
option, but of course it was a very small poll and inconclusive, so
other opinions are certainly welcome too.
---------
Co-authored-by: IceSentry <c.giguere42@gmail.com>
2024-02-28 22:48:43 +00:00
|
|
|
assert_eq!(Dir2::new(Vec2::X * 12.5), Ok(Dir2::X));
|
2024-02-26 13:57:49 +00:00
|
|
|
assert_eq!(
|
Rename `Direction2d/3d` to `Dir2/3` (#12189)
# Objective
Split up from #12017, rename Bevy's direction types.
Currently, Bevy has the `Direction2d`, `Direction3d`, and `Direction3dA`
types, which provide a type-level guarantee that their contained vectors
remain normalized. They can be very useful for a lot of APIs for safety,
explicitness, and in some cases performance, as they can sometimes avoid
unnecessary normalizations.
However, many consider them to be inconvenient to use, and opt for
standard vector types like `Vec3` because of this. One reason is that
the direction type names are a bit long and can be annoying to write (of
course you can use autocomplete, but just typing `Vec3` is still nicer),
and in some intances, the extra characters can make formatting worse.
The naming is also inconsistent with Glam's shorter type names, and
results in names like `Direction3dA`, which (in my opinion) are
difficult to read and even a bit ugly.
This PR proposes renaming the types to `Dir2`, `Dir3`, and `Dir3A`.
These names are nice and easy to write, consistent with Glam, and work
well for variants like the SIMD aligned `Dir3A`. As a bonus, it can also
result in nicer formatting in a lot of cases, which can be seen from the
diff of this PR.
Some examples of what it looks like: (copied from #12017)
```rust
// Before
let ray_cast = RayCast2d::new(Vec2::ZERO, Direction2d::X, 5.0);
// After
let ray_cast = RayCast2d::new(Vec2::ZERO, Dir2::X, 5.0);
```
```rust
// Before (an example using Bevy XPBD)
let hit = spatial_query.cast_ray(
Vec3::ZERO,
Direction3d::X,
f32::MAX,
true,
SpatialQueryFilter::default(),
);
// After
let hit = spatial_query.cast_ray(
Vec3::ZERO,
Dir3::X,
f32::MAX,
true,
SpatialQueryFilter::default(),
);
```
```rust
// Before
self.circle(
Vec3::new(0.0, -2.0, 0.0),
Direction3d::Y,
5.0,
Color::TURQUOISE,
);
// After (formatting is collapsed in this case)
self.circle(Vec3::new(0.0, -2.0, 0.0), Dir3::Y, 5.0, Color::TURQUOISE);
```
## Solution
Rename `Direction2d`, `Direction3d`, and `Direction3dA` to `Dir2`,
`Dir3`, and `Dir3A`.
---
## Migration Guide
The `Direction2d` and `Direction3d` types have been renamed to `Dir2`
and `Dir3`.
## Additional Context
This has been brought up on the Discord a few times, and we had a small
[poll](https://discord.com/channels/691052431525675048/1203087353850364004/1212465038711984158)
on this. `Dir2`/`Dir3`/`Dir3A` was quite unanimously chosen as the best
option, but of course it was a very small poll and inconclusive, so
other opinions are certainly welcome too.
---------
Co-authored-by: IceSentry <c.giguere42@gmail.com>
2024-02-28 22:48:43 +00:00
|
|
|
Dir2::new(Vec2::new(0.0, 0.0)),
|
2024-02-26 13:57:49 +00:00
|
|
|
Err(InvalidDirectionError::Zero)
|
|
|
|
);
|
|
|
|
assert_eq!(
|
Rename `Direction2d/3d` to `Dir2/3` (#12189)
# Objective
Split up from #12017, rename Bevy's direction types.
Currently, Bevy has the `Direction2d`, `Direction3d`, and `Direction3dA`
types, which provide a type-level guarantee that their contained vectors
remain normalized. They can be very useful for a lot of APIs for safety,
explicitness, and in some cases performance, as they can sometimes avoid
unnecessary normalizations.
However, many consider them to be inconvenient to use, and opt for
standard vector types like `Vec3` because of this. One reason is that
the direction type names are a bit long and can be annoying to write (of
course you can use autocomplete, but just typing `Vec3` is still nicer),
and in some intances, the extra characters can make formatting worse.
The naming is also inconsistent with Glam's shorter type names, and
results in names like `Direction3dA`, which (in my opinion) are
difficult to read and even a bit ugly.
This PR proposes renaming the types to `Dir2`, `Dir3`, and `Dir3A`.
These names are nice and easy to write, consistent with Glam, and work
well for variants like the SIMD aligned `Dir3A`. As a bonus, it can also
result in nicer formatting in a lot of cases, which can be seen from the
diff of this PR.
Some examples of what it looks like: (copied from #12017)
```rust
// Before
let ray_cast = RayCast2d::new(Vec2::ZERO, Direction2d::X, 5.0);
// After
let ray_cast = RayCast2d::new(Vec2::ZERO, Dir2::X, 5.0);
```
```rust
// Before (an example using Bevy XPBD)
let hit = spatial_query.cast_ray(
Vec3::ZERO,
Direction3d::X,
f32::MAX,
true,
SpatialQueryFilter::default(),
);
// After
let hit = spatial_query.cast_ray(
Vec3::ZERO,
Dir3::X,
f32::MAX,
true,
SpatialQueryFilter::default(),
);
```
```rust
// Before
self.circle(
Vec3::new(0.0, -2.0, 0.0),
Direction3d::Y,
5.0,
Color::TURQUOISE,
);
// After (formatting is collapsed in this case)
self.circle(Vec3::new(0.0, -2.0, 0.0), Dir3::Y, 5.0, Color::TURQUOISE);
```
## Solution
Rename `Direction2d`, `Direction3d`, and `Direction3dA` to `Dir2`,
`Dir3`, and `Dir3A`.
---
## Migration Guide
The `Direction2d` and `Direction3d` types have been renamed to `Dir2`
and `Dir3`.
## Additional Context
This has been brought up on the Discord a few times, and we had a small
[poll](https://discord.com/channels/691052431525675048/1203087353850364004/1212465038711984158)
on this. `Dir2`/`Dir3`/`Dir3A` was quite unanimously chosen as the best
option, but of course it was a very small poll and inconclusive, so
other opinions are certainly welcome too.
---------
Co-authored-by: IceSentry <c.giguere42@gmail.com>
2024-02-28 22:48:43 +00:00
|
|
|
Dir2::new(Vec2::new(f32::INFINITY, 0.0)),
|
2024-02-26 13:57:49 +00:00
|
|
|
Err(InvalidDirectionError::Infinite)
|
|
|
|
);
|
|
|
|
assert_eq!(
|
Rename `Direction2d/3d` to `Dir2/3` (#12189)
# Objective
Split up from #12017, rename Bevy's direction types.
Currently, Bevy has the `Direction2d`, `Direction3d`, and `Direction3dA`
types, which provide a type-level guarantee that their contained vectors
remain normalized. They can be very useful for a lot of APIs for safety,
explicitness, and in some cases performance, as they can sometimes avoid
unnecessary normalizations.
However, many consider them to be inconvenient to use, and opt for
standard vector types like `Vec3` because of this. One reason is that
the direction type names are a bit long and can be annoying to write (of
course you can use autocomplete, but just typing `Vec3` is still nicer),
and in some intances, the extra characters can make formatting worse.
The naming is also inconsistent with Glam's shorter type names, and
results in names like `Direction3dA`, which (in my opinion) are
difficult to read and even a bit ugly.
This PR proposes renaming the types to `Dir2`, `Dir3`, and `Dir3A`.
These names are nice and easy to write, consistent with Glam, and work
well for variants like the SIMD aligned `Dir3A`. As a bonus, it can also
result in nicer formatting in a lot of cases, which can be seen from the
diff of this PR.
Some examples of what it looks like: (copied from #12017)
```rust
// Before
let ray_cast = RayCast2d::new(Vec2::ZERO, Direction2d::X, 5.0);
// After
let ray_cast = RayCast2d::new(Vec2::ZERO, Dir2::X, 5.0);
```
```rust
// Before (an example using Bevy XPBD)
let hit = spatial_query.cast_ray(
Vec3::ZERO,
Direction3d::X,
f32::MAX,
true,
SpatialQueryFilter::default(),
);
// After
let hit = spatial_query.cast_ray(
Vec3::ZERO,
Dir3::X,
f32::MAX,
true,
SpatialQueryFilter::default(),
);
```
```rust
// Before
self.circle(
Vec3::new(0.0, -2.0, 0.0),
Direction3d::Y,
5.0,
Color::TURQUOISE,
);
// After (formatting is collapsed in this case)
self.circle(Vec3::new(0.0, -2.0, 0.0), Dir3::Y, 5.0, Color::TURQUOISE);
```
## Solution
Rename `Direction2d`, `Direction3d`, and `Direction3dA` to `Dir2`,
`Dir3`, and `Dir3A`.
---
## Migration Guide
The `Direction2d` and `Direction3d` types have been renamed to `Dir2`
and `Dir3`.
## Additional Context
This has been brought up on the Discord a few times, and we had a small
[poll](https://discord.com/channels/691052431525675048/1203087353850364004/1212465038711984158)
on this. `Dir2`/`Dir3`/`Dir3A` was quite unanimously chosen as the best
option, but of course it was a very small poll and inconclusive, so
other opinions are certainly welcome too.
---------
Co-authored-by: IceSentry <c.giguere42@gmail.com>
2024-02-28 22:48:43 +00:00
|
|
|
Dir2::new(Vec2::new(f32::NEG_INFINITY, 0.0)),
|
2024-02-26 13:57:49 +00:00
|
|
|
Err(InvalidDirectionError::Infinite)
|
|
|
|
);
|
|
|
|
assert_eq!(
|
Rename `Direction2d/3d` to `Dir2/3` (#12189)
# Objective
Split up from #12017, rename Bevy's direction types.
Currently, Bevy has the `Direction2d`, `Direction3d`, and `Direction3dA`
types, which provide a type-level guarantee that their contained vectors
remain normalized. They can be very useful for a lot of APIs for safety,
explicitness, and in some cases performance, as they can sometimes avoid
unnecessary normalizations.
However, many consider them to be inconvenient to use, and opt for
standard vector types like `Vec3` because of this. One reason is that
the direction type names are a bit long and can be annoying to write (of
course you can use autocomplete, but just typing `Vec3` is still nicer),
and in some intances, the extra characters can make formatting worse.
The naming is also inconsistent with Glam's shorter type names, and
results in names like `Direction3dA`, which (in my opinion) are
difficult to read and even a bit ugly.
This PR proposes renaming the types to `Dir2`, `Dir3`, and `Dir3A`.
These names are nice and easy to write, consistent with Glam, and work
well for variants like the SIMD aligned `Dir3A`. As a bonus, it can also
result in nicer formatting in a lot of cases, which can be seen from the
diff of this PR.
Some examples of what it looks like: (copied from #12017)
```rust
// Before
let ray_cast = RayCast2d::new(Vec2::ZERO, Direction2d::X, 5.0);
// After
let ray_cast = RayCast2d::new(Vec2::ZERO, Dir2::X, 5.0);
```
```rust
// Before (an example using Bevy XPBD)
let hit = spatial_query.cast_ray(
Vec3::ZERO,
Direction3d::X,
f32::MAX,
true,
SpatialQueryFilter::default(),
);
// After
let hit = spatial_query.cast_ray(
Vec3::ZERO,
Dir3::X,
f32::MAX,
true,
SpatialQueryFilter::default(),
);
```
```rust
// Before
self.circle(
Vec3::new(0.0, -2.0, 0.0),
Direction3d::Y,
5.0,
Color::TURQUOISE,
);
// After (formatting is collapsed in this case)
self.circle(Vec3::new(0.0, -2.0, 0.0), Dir3::Y, 5.0, Color::TURQUOISE);
```
## Solution
Rename `Direction2d`, `Direction3d`, and `Direction3dA` to `Dir2`,
`Dir3`, and `Dir3A`.
---
## Migration Guide
The `Direction2d` and `Direction3d` types have been renamed to `Dir2`
and `Dir3`.
## Additional Context
This has been brought up on the Discord a few times, and we had a small
[poll](https://discord.com/channels/691052431525675048/1203087353850364004/1212465038711984158)
on this. `Dir2`/`Dir3`/`Dir3A` was quite unanimously chosen as the best
option, but of course it was a very small poll and inconclusive, so
other opinions are certainly welcome too.
---------
Co-authored-by: IceSentry <c.giguere42@gmail.com>
2024-02-28 22:48:43 +00:00
|
|
|
Dir2::new(Vec2::new(f32::NAN, 0.0)),
|
2024-02-26 13:57:49 +00:00
|
|
|
Err(InvalidDirectionError::NaN)
|
|
|
|
);
|
Rename `Direction2d/3d` to `Dir2/3` (#12189)
# Objective
Split up from #12017, rename Bevy's direction types.
Currently, Bevy has the `Direction2d`, `Direction3d`, and `Direction3dA`
types, which provide a type-level guarantee that their contained vectors
remain normalized. They can be very useful for a lot of APIs for safety,
explicitness, and in some cases performance, as they can sometimes avoid
unnecessary normalizations.
However, many consider them to be inconvenient to use, and opt for
standard vector types like `Vec3` because of this. One reason is that
the direction type names are a bit long and can be annoying to write (of
course you can use autocomplete, but just typing `Vec3` is still nicer),
and in some intances, the extra characters can make formatting worse.
The naming is also inconsistent with Glam's shorter type names, and
results in names like `Direction3dA`, which (in my opinion) are
difficult to read and even a bit ugly.
This PR proposes renaming the types to `Dir2`, `Dir3`, and `Dir3A`.
These names are nice and easy to write, consistent with Glam, and work
well for variants like the SIMD aligned `Dir3A`. As a bonus, it can also
result in nicer formatting in a lot of cases, which can be seen from the
diff of this PR.
Some examples of what it looks like: (copied from #12017)
```rust
// Before
let ray_cast = RayCast2d::new(Vec2::ZERO, Direction2d::X, 5.0);
// After
let ray_cast = RayCast2d::new(Vec2::ZERO, Dir2::X, 5.0);
```
```rust
// Before (an example using Bevy XPBD)
let hit = spatial_query.cast_ray(
Vec3::ZERO,
Direction3d::X,
f32::MAX,
true,
SpatialQueryFilter::default(),
);
// After
let hit = spatial_query.cast_ray(
Vec3::ZERO,
Dir3::X,
f32::MAX,
true,
SpatialQueryFilter::default(),
);
```
```rust
// Before
self.circle(
Vec3::new(0.0, -2.0, 0.0),
Direction3d::Y,
5.0,
Color::TURQUOISE,
);
// After (formatting is collapsed in this case)
self.circle(Vec3::new(0.0, -2.0, 0.0), Dir3::Y, 5.0, Color::TURQUOISE);
```
## Solution
Rename `Direction2d`, `Direction3d`, and `Direction3dA` to `Dir2`,
`Dir3`, and `Dir3A`.
---
## Migration Guide
The `Direction2d` and `Direction3d` types have been renamed to `Dir2`
and `Dir3`.
## Additional Context
This has been brought up on the Discord a few times, and we had a small
[poll](https://discord.com/channels/691052431525675048/1203087353850364004/1212465038711984158)
on this. `Dir2`/`Dir3`/`Dir3A` was quite unanimously chosen as the best
option, but of course it was a very small poll and inconclusive, so
other opinions are certainly welcome too.
---------
Co-authored-by: IceSentry <c.giguere42@gmail.com>
2024-02-28 22:48:43 +00:00
|
|
|
assert_eq!(Dir2::new_and_length(Vec2::X * 6.5), Ok((Dir2::X, 6.5)));
|
2024-02-26 13:57:49 +00:00
|
|
|
}
|
|
|
|
|
2024-05-21 21:13:32 +00:00
|
|
|
#[test]
|
|
|
|
fn dir2_slerp() {
|
|
|
|
assert_relative_eq!(
|
|
|
|
Dir2::X.slerp(Dir2::Y, 0.5),
|
|
|
|
Dir2::from_xy(0.5_f32.sqrt(), 0.5_f32.sqrt()).unwrap()
|
|
|
|
);
|
|
|
|
assert_eq!(Dir2::Y.slerp(Dir2::X, 0.0), Dir2::Y);
|
|
|
|
assert_relative_eq!(Dir2::X.slerp(Dir2::Y, 1.0), Dir2::Y);
|
|
|
|
assert_relative_eq!(
|
|
|
|
Dir2::Y.slerp(Dir2::X, 1.0 / 3.0),
|
|
|
|
Dir2::from_xy(0.5, 0.75_f32.sqrt()).unwrap()
|
|
|
|
);
|
|
|
|
assert_relative_eq!(
|
|
|
|
Dir2::X.slerp(Dir2::Y, 2.0 / 3.0),
|
|
|
|
Dir2::from_xy(0.5, 0.75_f32.sqrt()).unwrap()
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2024-06-04 14:44:29 +00:00
|
|
|
#[test]
|
|
|
|
fn dir2_to_rotation2d() {
|
2024-06-05 21:51:13 +00:00
|
|
|
assert_relative_eq!(Dir2::EAST.rotation_to(Dir2::NORTH_EAST), Rot2::FRAC_PI_4);
|
|
|
|
assert_relative_eq!(Dir2::NORTH.rotation_from(Dir2::NORTH_EAST), Rot2::FRAC_PI_4);
|
|
|
|
assert_relative_eq!(Dir2::SOUTH.rotation_to_x(), Rot2::FRAC_PI_2);
|
|
|
|
assert_relative_eq!(Dir2::SOUTH.rotation_to_y(), Rot2::PI);
|
|
|
|
assert_relative_eq!(Dir2::NORTH_WEST.rotation_from_x(), Rot2::degrees(135.0));
|
|
|
|
assert_relative_eq!(Dir2::NORTH_WEST.rotation_from_y(), Rot2::FRAC_PI_4);
|
2024-06-04 14:44:29 +00:00
|
|
|
}
|
|
|
|
|
2024-07-22 18:42:48 +00:00
|
|
|
#[test]
|
|
|
|
fn dir2_renorm() {
|
|
|
|
// Evil denormalized Rot2
|
Make bevy_math's `libm` feature use `libm` for all `f32`methods with unspecified precision (#14693)
# Objective
Closes #14474
Previously, the `libm` feature of bevy_math would just pass the same
feature flag down to glam. However, bevy_math itself had many uses of
floating-point arithmetic with unspecified precision. For example,
`f32::sin_cos` and `f32::powi` have unspecified precision, which means
that the exact details of their output are not guaranteed to be stable
across different systems and/or versions of Rust. This means that users
of bevy_math could observe slightly different behavior on different
systems if these methods were used.
The goal of this PR is to make it so that the `libm` feature flag
actually guarantees some degree of determinacy within bevy_math itself
by switching to the libm versions of these functions when the `libm`
feature is enabled.
## Solution
bevy_math now has an internal module `bevy_math::ops`, which re-exports
either the standard versions of the operations or the libm versions
depending on whether the `libm` feature is enabled. For example,
`ops::sin` compiles to `f32::sin` without the `libm` feature and to
`libm::sinf` with it.
This approach has a small shortfall, which is that `f32::powi` (integer
powers of floating point numbers) does not have an equivalent in `libm`.
On the other hand, this method is only used for squaring and cubing
numbers in bevy_math. Accordingly, this deficit is covered by the
introduction of a trait `ops::FloatPow`:
```rust
pub(crate) trait FloatPow {
fn squared(self) -> Self;
fn cubed(self) -> Self;
}
```
Next, each current usage of the unspecified-precision methods has been
replaced by its equivalent in `ops`, so that when `libm` is enabled, the
libm version is used instead. The exception, of course, is that
`.powi(2)`/`.powi(3)` have been replaced with `.squared()`/`.cubed()`.
Finally, the usage of the plain `f32` methods with unspecified precision
is now linted out of bevy_math (and hence disallowed in CI). For
example, using `f32::sin` within bevy_math produces a warning that tells
the user to use the `ops::sin` version instead.
## Testing
Ran existing tests. It would be nice to check some benchmarks on NURBS
things once #14677 merges. I'm happy to wait until then if the rest of
this PR is fine.
---
## Discussion
In the future, it might make sense to actually expose `bevy_math::ops`
as public if any downstream Bevy crates want to provide similar
determinacy guarantees. For now, it's all just `pub(crate)`.
This PR also only covers `f32`. If we find ourselves using `f64`
internally in parts of bevy_math for better robustness, we could extend
the module and lints to cover the `f64` versions easily enough.
I don't know how feasible it is, but it would also be nice if we could
standardize the bevy_math tests with the `libm` feature in CI, since
their success is currently platform-dependent (e.g. 8 of them fail on my
machine when run locally).
---------
Co-authored-by: IQuick 143 <IQuick143cz@gmail.com>
2024-08-12 16:13:36 +00:00
|
|
|
let (sin, cos) = ops::sin_cos(1.0_f32);
|
2024-07-22 18:42:48 +00:00
|
|
|
let rot2 = Rot2::from_sin_cos(sin * (1.0 + 1e-5), cos * (1.0 + 1e-5));
|
|
|
|
let mut dir_a = Dir2::X;
|
|
|
|
let mut dir_b = Dir2::X;
|
|
|
|
|
|
|
|
// We test that renormalizing an already normalized dir doesn't do anything
|
|
|
|
assert_relative_eq!(dir_b, dir_b.fast_renormalize(), epsilon = 0.000001);
|
|
|
|
|
|
|
|
for _ in 0..50 {
|
|
|
|
dir_a = rot2 * dir_a;
|
|
|
|
dir_b = rot2 * dir_b;
|
|
|
|
dir_b = dir_b.fast_renormalize();
|
|
|
|
}
|
|
|
|
|
|
|
|
// `dir_a` should've gotten denormalized, meanwhile `dir_b` should stay normalized.
|
|
|
|
assert!(
|
|
|
|
!dir_a.is_normalized(),
|
|
|
|
"Dernormalization doesn't work, test is faulty"
|
|
|
|
);
|
|
|
|
assert!(dir_b.is_normalized(), "Renormalisation did not work.");
|
|
|
|
}
|
|
|
|
|
2024-02-26 13:57:49 +00:00
|
|
|
#[test]
|
|
|
|
fn dir3_creation() {
|
Rename `Direction2d/3d` to `Dir2/3` (#12189)
# Objective
Split up from #12017, rename Bevy's direction types.
Currently, Bevy has the `Direction2d`, `Direction3d`, and `Direction3dA`
types, which provide a type-level guarantee that their contained vectors
remain normalized. They can be very useful for a lot of APIs for safety,
explicitness, and in some cases performance, as they can sometimes avoid
unnecessary normalizations.
However, many consider them to be inconvenient to use, and opt for
standard vector types like `Vec3` because of this. One reason is that
the direction type names are a bit long and can be annoying to write (of
course you can use autocomplete, but just typing `Vec3` is still nicer),
and in some intances, the extra characters can make formatting worse.
The naming is also inconsistent with Glam's shorter type names, and
results in names like `Direction3dA`, which (in my opinion) are
difficult to read and even a bit ugly.
This PR proposes renaming the types to `Dir2`, `Dir3`, and `Dir3A`.
These names are nice and easy to write, consistent with Glam, and work
well for variants like the SIMD aligned `Dir3A`. As a bonus, it can also
result in nicer formatting in a lot of cases, which can be seen from the
diff of this PR.
Some examples of what it looks like: (copied from #12017)
```rust
// Before
let ray_cast = RayCast2d::new(Vec2::ZERO, Direction2d::X, 5.0);
// After
let ray_cast = RayCast2d::new(Vec2::ZERO, Dir2::X, 5.0);
```
```rust
// Before (an example using Bevy XPBD)
let hit = spatial_query.cast_ray(
Vec3::ZERO,
Direction3d::X,
f32::MAX,
true,
SpatialQueryFilter::default(),
);
// After
let hit = spatial_query.cast_ray(
Vec3::ZERO,
Dir3::X,
f32::MAX,
true,
SpatialQueryFilter::default(),
);
```
```rust
// Before
self.circle(
Vec3::new(0.0, -2.0, 0.0),
Direction3d::Y,
5.0,
Color::TURQUOISE,
);
// After (formatting is collapsed in this case)
self.circle(Vec3::new(0.0, -2.0, 0.0), Dir3::Y, 5.0, Color::TURQUOISE);
```
## Solution
Rename `Direction2d`, `Direction3d`, and `Direction3dA` to `Dir2`,
`Dir3`, and `Dir3A`.
---
## Migration Guide
The `Direction2d` and `Direction3d` types have been renamed to `Dir2`
and `Dir3`.
## Additional Context
This has been brought up on the Discord a few times, and we had a small
[poll](https://discord.com/channels/691052431525675048/1203087353850364004/1212465038711984158)
on this. `Dir2`/`Dir3`/`Dir3A` was quite unanimously chosen as the best
option, but of course it was a very small poll and inconclusive, so
other opinions are certainly welcome too.
---------
Co-authored-by: IceSentry <c.giguere42@gmail.com>
2024-02-28 22:48:43 +00:00
|
|
|
assert_eq!(Dir3::new(Vec3::X * 12.5), Ok(Dir3::X));
|
2024-02-26 13:57:49 +00:00
|
|
|
assert_eq!(
|
Rename `Direction2d/3d` to `Dir2/3` (#12189)
# Objective
Split up from #12017, rename Bevy's direction types.
Currently, Bevy has the `Direction2d`, `Direction3d`, and `Direction3dA`
types, which provide a type-level guarantee that their contained vectors
remain normalized. They can be very useful for a lot of APIs for safety,
explicitness, and in some cases performance, as they can sometimes avoid
unnecessary normalizations.
However, many consider them to be inconvenient to use, and opt for
standard vector types like `Vec3` because of this. One reason is that
the direction type names are a bit long and can be annoying to write (of
course you can use autocomplete, but just typing `Vec3` is still nicer),
and in some intances, the extra characters can make formatting worse.
The naming is also inconsistent with Glam's shorter type names, and
results in names like `Direction3dA`, which (in my opinion) are
difficult to read and even a bit ugly.
This PR proposes renaming the types to `Dir2`, `Dir3`, and `Dir3A`.
These names are nice and easy to write, consistent with Glam, and work
well for variants like the SIMD aligned `Dir3A`. As a bonus, it can also
result in nicer formatting in a lot of cases, which can be seen from the
diff of this PR.
Some examples of what it looks like: (copied from #12017)
```rust
// Before
let ray_cast = RayCast2d::new(Vec2::ZERO, Direction2d::X, 5.0);
// After
let ray_cast = RayCast2d::new(Vec2::ZERO, Dir2::X, 5.0);
```
```rust
// Before (an example using Bevy XPBD)
let hit = spatial_query.cast_ray(
Vec3::ZERO,
Direction3d::X,
f32::MAX,
true,
SpatialQueryFilter::default(),
);
// After
let hit = spatial_query.cast_ray(
Vec3::ZERO,
Dir3::X,
f32::MAX,
true,
SpatialQueryFilter::default(),
);
```
```rust
// Before
self.circle(
Vec3::new(0.0, -2.0, 0.0),
Direction3d::Y,
5.0,
Color::TURQUOISE,
);
// After (formatting is collapsed in this case)
self.circle(Vec3::new(0.0, -2.0, 0.0), Dir3::Y, 5.0, Color::TURQUOISE);
```
## Solution
Rename `Direction2d`, `Direction3d`, and `Direction3dA` to `Dir2`,
`Dir3`, and `Dir3A`.
---
## Migration Guide
The `Direction2d` and `Direction3d` types have been renamed to `Dir2`
and `Dir3`.
## Additional Context
This has been brought up on the Discord a few times, and we had a small
[poll](https://discord.com/channels/691052431525675048/1203087353850364004/1212465038711984158)
on this. `Dir2`/`Dir3`/`Dir3A` was quite unanimously chosen as the best
option, but of course it was a very small poll and inconclusive, so
other opinions are certainly welcome too.
---------
Co-authored-by: IceSentry <c.giguere42@gmail.com>
2024-02-28 22:48:43 +00:00
|
|
|
Dir3::new(Vec3::new(0.0, 0.0, 0.0)),
|
2024-02-26 13:57:49 +00:00
|
|
|
Err(InvalidDirectionError::Zero)
|
|
|
|
);
|
|
|
|
assert_eq!(
|
Rename `Direction2d/3d` to `Dir2/3` (#12189)
# Objective
Split up from #12017, rename Bevy's direction types.
Currently, Bevy has the `Direction2d`, `Direction3d`, and `Direction3dA`
types, which provide a type-level guarantee that their contained vectors
remain normalized. They can be very useful for a lot of APIs for safety,
explicitness, and in some cases performance, as they can sometimes avoid
unnecessary normalizations.
However, many consider them to be inconvenient to use, and opt for
standard vector types like `Vec3` because of this. One reason is that
the direction type names are a bit long and can be annoying to write (of
course you can use autocomplete, but just typing `Vec3` is still nicer),
and in some intances, the extra characters can make formatting worse.
The naming is also inconsistent with Glam's shorter type names, and
results in names like `Direction3dA`, which (in my opinion) are
difficult to read and even a bit ugly.
This PR proposes renaming the types to `Dir2`, `Dir3`, and `Dir3A`.
These names are nice and easy to write, consistent with Glam, and work
well for variants like the SIMD aligned `Dir3A`. As a bonus, it can also
result in nicer formatting in a lot of cases, which can be seen from the
diff of this PR.
Some examples of what it looks like: (copied from #12017)
```rust
// Before
let ray_cast = RayCast2d::new(Vec2::ZERO, Direction2d::X, 5.0);
// After
let ray_cast = RayCast2d::new(Vec2::ZERO, Dir2::X, 5.0);
```
```rust
// Before (an example using Bevy XPBD)
let hit = spatial_query.cast_ray(
Vec3::ZERO,
Direction3d::X,
f32::MAX,
true,
SpatialQueryFilter::default(),
);
// After
let hit = spatial_query.cast_ray(
Vec3::ZERO,
Dir3::X,
f32::MAX,
true,
SpatialQueryFilter::default(),
);
```
```rust
// Before
self.circle(
Vec3::new(0.0, -2.0, 0.0),
Direction3d::Y,
5.0,
Color::TURQUOISE,
);
// After (formatting is collapsed in this case)
self.circle(Vec3::new(0.0, -2.0, 0.0), Dir3::Y, 5.0, Color::TURQUOISE);
```
## Solution
Rename `Direction2d`, `Direction3d`, and `Direction3dA` to `Dir2`,
`Dir3`, and `Dir3A`.
---
## Migration Guide
The `Direction2d` and `Direction3d` types have been renamed to `Dir2`
and `Dir3`.
## Additional Context
This has been brought up on the Discord a few times, and we had a small
[poll](https://discord.com/channels/691052431525675048/1203087353850364004/1212465038711984158)
on this. `Dir2`/`Dir3`/`Dir3A` was quite unanimously chosen as the best
option, but of course it was a very small poll and inconclusive, so
other opinions are certainly welcome too.
---------
Co-authored-by: IceSentry <c.giguere42@gmail.com>
2024-02-28 22:48:43 +00:00
|
|
|
Dir3::new(Vec3::new(f32::INFINITY, 0.0, 0.0)),
|
2024-02-26 13:57:49 +00:00
|
|
|
Err(InvalidDirectionError::Infinite)
|
|
|
|
);
|
|
|
|
assert_eq!(
|
Rename `Direction2d/3d` to `Dir2/3` (#12189)
# Objective
Split up from #12017, rename Bevy's direction types.
Currently, Bevy has the `Direction2d`, `Direction3d`, and `Direction3dA`
types, which provide a type-level guarantee that their contained vectors
remain normalized. They can be very useful for a lot of APIs for safety,
explicitness, and in some cases performance, as they can sometimes avoid
unnecessary normalizations.
However, many consider them to be inconvenient to use, and opt for
standard vector types like `Vec3` because of this. One reason is that
the direction type names are a bit long and can be annoying to write (of
course you can use autocomplete, but just typing `Vec3` is still nicer),
and in some intances, the extra characters can make formatting worse.
The naming is also inconsistent with Glam's shorter type names, and
results in names like `Direction3dA`, which (in my opinion) are
difficult to read and even a bit ugly.
This PR proposes renaming the types to `Dir2`, `Dir3`, and `Dir3A`.
These names are nice and easy to write, consistent with Glam, and work
well for variants like the SIMD aligned `Dir3A`. As a bonus, it can also
result in nicer formatting in a lot of cases, which can be seen from the
diff of this PR.
Some examples of what it looks like: (copied from #12017)
```rust
// Before
let ray_cast = RayCast2d::new(Vec2::ZERO, Direction2d::X, 5.0);
// After
let ray_cast = RayCast2d::new(Vec2::ZERO, Dir2::X, 5.0);
```
```rust
// Before (an example using Bevy XPBD)
let hit = spatial_query.cast_ray(
Vec3::ZERO,
Direction3d::X,
f32::MAX,
true,
SpatialQueryFilter::default(),
);
// After
let hit = spatial_query.cast_ray(
Vec3::ZERO,
Dir3::X,
f32::MAX,
true,
SpatialQueryFilter::default(),
);
```
```rust
// Before
self.circle(
Vec3::new(0.0, -2.0, 0.0),
Direction3d::Y,
5.0,
Color::TURQUOISE,
);
// After (formatting is collapsed in this case)
self.circle(Vec3::new(0.0, -2.0, 0.0), Dir3::Y, 5.0, Color::TURQUOISE);
```
## Solution
Rename `Direction2d`, `Direction3d`, and `Direction3dA` to `Dir2`,
`Dir3`, and `Dir3A`.
---
## Migration Guide
The `Direction2d` and `Direction3d` types have been renamed to `Dir2`
and `Dir3`.
## Additional Context
This has been brought up on the Discord a few times, and we had a small
[poll](https://discord.com/channels/691052431525675048/1203087353850364004/1212465038711984158)
on this. `Dir2`/`Dir3`/`Dir3A` was quite unanimously chosen as the best
option, but of course it was a very small poll and inconclusive, so
other opinions are certainly welcome too.
---------
Co-authored-by: IceSentry <c.giguere42@gmail.com>
2024-02-28 22:48:43 +00:00
|
|
|
Dir3::new(Vec3::new(f32::NEG_INFINITY, 0.0, 0.0)),
|
2024-02-26 13:57:49 +00:00
|
|
|
Err(InvalidDirectionError::Infinite)
|
|
|
|
);
|
|
|
|
assert_eq!(
|
Rename `Direction2d/3d` to `Dir2/3` (#12189)
# Objective
Split up from #12017, rename Bevy's direction types.
Currently, Bevy has the `Direction2d`, `Direction3d`, and `Direction3dA`
types, which provide a type-level guarantee that their contained vectors
remain normalized. They can be very useful for a lot of APIs for safety,
explicitness, and in some cases performance, as they can sometimes avoid
unnecessary normalizations.
However, many consider them to be inconvenient to use, and opt for
standard vector types like `Vec3` because of this. One reason is that
the direction type names are a bit long and can be annoying to write (of
course you can use autocomplete, but just typing `Vec3` is still nicer),
and in some intances, the extra characters can make formatting worse.
The naming is also inconsistent with Glam's shorter type names, and
results in names like `Direction3dA`, which (in my opinion) are
difficult to read and even a bit ugly.
This PR proposes renaming the types to `Dir2`, `Dir3`, and `Dir3A`.
These names are nice and easy to write, consistent with Glam, and work
well for variants like the SIMD aligned `Dir3A`. As a bonus, it can also
result in nicer formatting in a lot of cases, which can be seen from the
diff of this PR.
Some examples of what it looks like: (copied from #12017)
```rust
// Before
let ray_cast = RayCast2d::new(Vec2::ZERO, Direction2d::X, 5.0);
// After
let ray_cast = RayCast2d::new(Vec2::ZERO, Dir2::X, 5.0);
```
```rust
// Before (an example using Bevy XPBD)
let hit = spatial_query.cast_ray(
Vec3::ZERO,
Direction3d::X,
f32::MAX,
true,
SpatialQueryFilter::default(),
);
// After
let hit = spatial_query.cast_ray(
Vec3::ZERO,
Dir3::X,
f32::MAX,
true,
SpatialQueryFilter::default(),
);
```
```rust
// Before
self.circle(
Vec3::new(0.0, -2.0, 0.0),
Direction3d::Y,
5.0,
Color::TURQUOISE,
);
// After (formatting is collapsed in this case)
self.circle(Vec3::new(0.0, -2.0, 0.0), Dir3::Y, 5.0, Color::TURQUOISE);
```
## Solution
Rename `Direction2d`, `Direction3d`, and `Direction3dA` to `Dir2`,
`Dir3`, and `Dir3A`.
---
## Migration Guide
The `Direction2d` and `Direction3d` types have been renamed to `Dir2`
and `Dir3`.
## Additional Context
This has been brought up on the Discord a few times, and we had a small
[poll](https://discord.com/channels/691052431525675048/1203087353850364004/1212465038711984158)
on this. `Dir2`/`Dir3`/`Dir3A` was quite unanimously chosen as the best
option, but of course it was a very small poll and inconclusive, so
other opinions are certainly welcome too.
---------
Co-authored-by: IceSentry <c.giguere42@gmail.com>
2024-02-28 22:48:43 +00:00
|
|
|
Dir3::new(Vec3::new(f32::NAN, 0.0, 0.0)),
|
2024-02-26 13:57:49 +00:00
|
|
|
Err(InvalidDirectionError::NaN)
|
|
|
|
);
|
Rename `Direction2d/3d` to `Dir2/3` (#12189)
# Objective
Split up from #12017, rename Bevy's direction types.
Currently, Bevy has the `Direction2d`, `Direction3d`, and `Direction3dA`
types, which provide a type-level guarantee that their contained vectors
remain normalized. They can be very useful for a lot of APIs for safety,
explicitness, and in some cases performance, as they can sometimes avoid
unnecessary normalizations.
However, many consider them to be inconvenient to use, and opt for
standard vector types like `Vec3` because of this. One reason is that
the direction type names are a bit long and can be annoying to write (of
course you can use autocomplete, but just typing `Vec3` is still nicer),
and in some intances, the extra characters can make formatting worse.
The naming is also inconsistent with Glam's shorter type names, and
results in names like `Direction3dA`, which (in my opinion) are
difficult to read and even a bit ugly.
This PR proposes renaming the types to `Dir2`, `Dir3`, and `Dir3A`.
These names are nice and easy to write, consistent with Glam, and work
well for variants like the SIMD aligned `Dir3A`. As a bonus, it can also
result in nicer formatting in a lot of cases, which can be seen from the
diff of this PR.
Some examples of what it looks like: (copied from #12017)
```rust
// Before
let ray_cast = RayCast2d::new(Vec2::ZERO, Direction2d::X, 5.0);
// After
let ray_cast = RayCast2d::new(Vec2::ZERO, Dir2::X, 5.0);
```
```rust
// Before (an example using Bevy XPBD)
let hit = spatial_query.cast_ray(
Vec3::ZERO,
Direction3d::X,
f32::MAX,
true,
SpatialQueryFilter::default(),
);
// After
let hit = spatial_query.cast_ray(
Vec3::ZERO,
Dir3::X,
f32::MAX,
true,
SpatialQueryFilter::default(),
);
```
```rust
// Before
self.circle(
Vec3::new(0.0, -2.0, 0.0),
Direction3d::Y,
5.0,
Color::TURQUOISE,
);
// After (formatting is collapsed in this case)
self.circle(Vec3::new(0.0, -2.0, 0.0), Dir3::Y, 5.0, Color::TURQUOISE);
```
## Solution
Rename `Direction2d`, `Direction3d`, and `Direction3dA` to `Dir2`,
`Dir3`, and `Dir3A`.
---
## Migration Guide
The `Direction2d` and `Direction3d` types have been renamed to `Dir2`
and `Dir3`.
## Additional Context
This has been brought up on the Discord a few times, and we had a small
[poll](https://discord.com/channels/691052431525675048/1203087353850364004/1212465038711984158)
on this. `Dir2`/`Dir3`/`Dir3A` was quite unanimously chosen as the best
option, but of course it was a very small poll and inconclusive, so
other opinions are certainly welcome too.
---------
Co-authored-by: IceSentry <c.giguere42@gmail.com>
2024-02-28 22:48:43 +00:00
|
|
|
assert_eq!(Dir3::new_and_length(Vec3::X * 6.5), Ok((Dir3::X, 6.5)));
|
2024-02-26 13:57:49 +00:00
|
|
|
|
|
|
|
// Test rotation
|
|
|
|
assert!(
|
2024-09-27 00:59:59 +00:00
|
|
|
(Quat::from_rotation_z(core::f32::consts::FRAC_PI_2) * Dir3::X)
|
2024-02-26 13:57:49 +00:00
|
|
|
.abs_diff_eq(Vec3::Y, 10e-6)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2024-05-21 21:13:32 +00:00
|
|
|
#[test]
|
|
|
|
fn dir3_slerp() {
|
|
|
|
assert_relative_eq!(
|
|
|
|
Dir3::X.slerp(Dir3::Y, 0.5),
|
|
|
|
Dir3::from_xyz(0.5f32.sqrt(), 0.5f32.sqrt(), 0.0).unwrap()
|
|
|
|
);
|
|
|
|
assert_relative_eq!(Dir3::Y.slerp(Dir3::Z, 0.0), Dir3::Y);
|
|
|
|
assert_relative_eq!(Dir3::Z.slerp(Dir3::X, 1.0), Dir3::X, epsilon = 0.000001);
|
|
|
|
assert_relative_eq!(
|
|
|
|
Dir3::X.slerp(Dir3::Z, 1.0 / 3.0),
|
|
|
|
Dir3::from_xyz(0.75f32.sqrt(), 0.0, 0.5).unwrap(),
|
|
|
|
epsilon = 0.000001
|
|
|
|
);
|
|
|
|
assert_relative_eq!(
|
|
|
|
Dir3::Z.slerp(Dir3::Y, 2.0 / 3.0),
|
|
|
|
Dir3::from_xyz(0.0, 0.75f32.sqrt(), 0.5).unwrap()
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2024-07-22 18:42:48 +00:00
|
|
|
#[test]
|
|
|
|
fn dir3_renorm() {
|
|
|
|
// Evil denormalized quaternion
|
|
|
|
let rot3 = Quat::from_euler(glam::EulerRot::XYZ, 1.0, 2.0, 3.0) * (1.0 + 1e-5);
|
|
|
|
let mut dir_a = Dir3::X;
|
|
|
|
let mut dir_b = Dir3::X;
|
|
|
|
|
|
|
|
// We test that renormalizing an already normalized dir doesn't do anything
|
|
|
|
assert_relative_eq!(dir_b, dir_b.fast_renormalize(), epsilon = 0.000001);
|
|
|
|
|
|
|
|
for _ in 0..50 {
|
|
|
|
dir_a = rot3 * dir_a;
|
|
|
|
dir_b = rot3 * dir_b;
|
|
|
|
dir_b = dir_b.fast_renormalize();
|
|
|
|
}
|
|
|
|
|
|
|
|
// `dir_a` should've gotten denormalized, meanwhile `dir_b` should stay normalized.
|
|
|
|
assert!(
|
|
|
|
!dir_a.is_normalized(),
|
|
|
|
"Dernormalization doesn't work, test is faulty"
|
|
|
|
);
|
|
|
|
assert!(dir_b.is_normalized(), "Renormalisation did not work.");
|
|
|
|
}
|
|
|
|
|
2024-02-26 13:57:49 +00:00
|
|
|
#[test]
|
|
|
|
fn dir3a_creation() {
|
Rename `Direction2d/3d` to `Dir2/3` (#12189)
# Objective
Split up from #12017, rename Bevy's direction types.
Currently, Bevy has the `Direction2d`, `Direction3d`, and `Direction3dA`
types, which provide a type-level guarantee that their contained vectors
remain normalized. They can be very useful for a lot of APIs for safety,
explicitness, and in some cases performance, as they can sometimes avoid
unnecessary normalizations.
However, many consider them to be inconvenient to use, and opt for
standard vector types like `Vec3` because of this. One reason is that
the direction type names are a bit long and can be annoying to write (of
course you can use autocomplete, but just typing `Vec3` is still nicer),
and in some intances, the extra characters can make formatting worse.
The naming is also inconsistent with Glam's shorter type names, and
results in names like `Direction3dA`, which (in my opinion) are
difficult to read and even a bit ugly.
This PR proposes renaming the types to `Dir2`, `Dir3`, and `Dir3A`.
These names are nice and easy to write, consistent with Glam, and work
well for variants like the SIMD aligned `Dir3A`. As a bonus, it can also
result in nicer formatting in a lot of cases, which can be seen from the
diff of this PR.
Some examples of what it looks like: (copied from #12017)
```rust
// Before
let ray_cast = RayCast2d::new(Vec2::ZERO, Direction2d::X, 5.0);
// After
let ray_cast = RayCast2d::new(Vec2::ZERO, Dir2::X, 5.0);
```
```rust
// Before (an example using Bevy XPBD)
let hit = spatial_query.cast_ray(
Vec3::ZERO,
Direction3d::X,
f32::MAX,
true,
SpatialQueryFilter::default(),
);
// After
let hit = spatial_query.cast_ray(
Vec3::ZERO,
Dir3::X,
f32::MAX,
true,
SpatialQueryFilter::default(),
);
```
```rust
// Before
self.circle(
Vec3::new(0.0, -2.0, 0.0),
Direction3d::Y,
5.0,
Color::TURQUOISE,
);
// After (formatting is collapsed in this case)
self.circle(Vec3::new(0.0, -2.0, 0.0), Dir3::Y, 5.0, Color::TURQUOISE);
```
## Solution
Rename `Direction2d`, `Direction3d`, and `Direction3dA` to `Dir2`,
`Dir3`, and `Dir3A`.
---
## Migration Guide
The `Direction2d` and `Direction3d` types have been renamed to `Dir2`
and `Dir3`.
## Additional Context
This has been brought up on the Discord a few times, and we had a small
[poll](https://discord.com/channels/691052431525675048/1203087353850364004/1212465038711984158)
on this. `Dir2`/`Dir3`/`Dir3A` was quite unanimously chosen as the best
option, but of course it was a very small poll and inconclusive, so
other opinions are certainly welcome too.
---------
Co-authored-by: IceSentry <c.giguere42@gmail.com>
2024-02-28 22:48:43 +00:00
|
|
|
assert_eq!(Dir3A::new(Vec3A::X * 12.5), Ok(Dir3A::X));
|
2024-02-26 13:57:49 +00:00
|
|
|
assert_eq!(
|
Rename `Direction2d/3d` to `Dir2/3` (#12189)
# Objective
Split up from #12017, rename Bevy's direction types.
Currently, Bevy has the `Direction2d`, `Direction3d`, and `Direction3dA`
types, which provide a type-level guarantee that their contained vectors
remain normalized. They can be very useful for a lot of APIs for safety,
explicitness, and in some cases performance, as they can sometimes avoid
unnecessary normalizations.
However, many consider them to be inconvenient to use, and opt for
standard vector types like `Vec3` because of this. One reason is that
the direction type names are a bit long and can be annoying to write (of
course you can use autocomplete, but just typing `Vec3` is still nicer),
and in some intances, the extra characters can make formatting worse.
The naming is also inconsistent with Glam's shorter type names, and
results in names like `Direction3dA`, which (in my opinion) are
difficult to read and even a bit ugly.
This PR proposes renaming the types to `Dir2`, `Dir3`, and `Dir3A`.
These names are nice and easy to write, consistent with Glam, and work
well for variants like the SIMD aligned `Dir3A`. As a bonus, it can also
result in nicer formatting in a lot of cases, which can be seen from the
diff of this PR.
Some examples of what it looks like: (copied from #12017)
```rust
// Before
let ray_cast = RayCast2d::new(Vec2::ZERO, Direction2d::X, 5.0);
// After
let ray_cast = RayCast2d::new(Vec2::ZERO, Dir2::X, 5.0);
```
```rust
// Before (an example using Bevy XPBD)
let hit = spatial_query.cast_ray(
Vec3::ZERO,
Direction3d::X,
f32::MAX,
true,
SpatialQueryFilter::default(),
);
// After
let hit = spatial_query.cast_ray(
Vec3::ZERO,
Dir3::X,
f32::MAX,
true,
SpatialQueryFilter::default(),
);
```
```rust
// Before
self.circle(
Vec3::new(0.0, -2.0, 0.0),
Direction3d::Y,
5.0,
Color::TURQUOISE,
);
// After (formatting is collapsed in this case)
self.circle(Vec3::new(0.0, -2.0, 0.0), Dir3::Y, 5.0, Color::TURQUOISE);
```
## Solution
Rename `Direction2d`, `Direction3d`, and `Direction3dA` to `Dir2`,
`Dir3`, and `Dir3A`.
---
## Migration Guide
The `Direction2d` and `Direction3d` types have been renamed to `Dir2`
and `Dir3`.
## Additional Context
This has been brought up on the Discord a few times, and we had a small
[poll](https://discord.com/channels/691052431525675048/1203087353850364004/1212465038711984158)
on this. `Dir2`/`Dir3`/`Dir3A` was quite unanimously chosen as the best
option, but of course it was a very small poll and inconclusive, so
other opinions are certainly welcome too.
---------
Co-authored-by: IceSentry <c.giguere42@gmail.com>
2024-02-28 22:48:43 +00:00
|
|
|
Dir3A::new(Vec3A::new(0.0, 0.0, 0.0)),
|
2024-02-26 13:57:49 +00:00
|
|
|
Err(InvalidDirectionError::Zero)
|
|
|
|
);
|
|
|
|
assert_eq!(
|
Rename `Direction2d/3d` to `Dir2/3` (#12189)
# Objective
Split up from #12017, rename Bevy's direction types.
Currently, Bevy has the `Direction2d`, `Direction3d`, and `Direction3dA`
types, which provide a type-level guarantee that their contained vectors
remain normalized. They can be very useful for a lot of APIs for safety,
explicitness, and in some cases performance, as they can sometimes avoid
unnecessary normalizations.
However, many consider them to be inconvenient to use, and opt for
standard vector types like `Vec3` because of this. One reason is that
the direction type names are a bit long and can be annoying to write (of
course you can use autocomplete, but just typing `Vec3` is still nicer),
and in some intances, the extra characters can make formatting worse.
The naming is also inconsistent with Glam's shorter type names, and
results in names like `Direction3dA`, which (in my opinion) are
difficult to read and even a bit ugly.
This PR proposes renaming the types to `Dir2`, `Dir3`, and `Dir3A`.
These names are nice and easy to write, consistent with Glam, and work
well for variants like the SIMD aligned `Dir3A`. As a bonus, it can also
result in nicer formatting in a lot of cases, which can be seen from the
diff of this PR.
Some examples of what it looks like: (copied from #12017)
```rust
// Before
let ray_cast = RayCast2d::new(Vec2::ZERO, Direction2d::X, 5.0);
// After
let ray_cast = RayCast2d::new(Vec2::ZERO, Dir2::X, 5.0);
```
```rust
// Before (an example using Bevy XPBD)
let hit = spatial_query.cast_ray(
Vec3::ZERO,
Direction3d::X,
f32::MAX,
true,
SpatialQueryFilter::default(),
);
// After
let hit = spatial_query.cast_ray(
Vec3::ZERO,
Dir3::X,
f32::MAX,
true,
SpatialQueryFilter::default(),
);
```
```rust
// Before
self.circle(
Vec3::new(0.0, -2.0, 0.0),
Direction3d::Y,
5.0,
Color::TURQUOISE,
);
// After (formatting is collapsed in this case)
self.circle(Vec3::new(0.0, -2.0, 0.0), Dir3::Y, 5.0, Color::TURQUOISE);
```
## Solution
Rename `Direction2d`, `Direction3d`, and `Direction3dA` to `Dir2`,
`Dir3`, and `Dir3A`.
---
## Migration Guide
The `Direction2d` and `Direction3d` types have been renamed to `Dir2`
and `Dir3`.
## Additional Context
This has been brought up on the Discord a few times, and we had a small
[poll](https://discord.com/channels/691052431525675048/1203087353850364004/1212465038711984158)
on this. `Dir2`/`Dir3`/`Dir3A` was quite unanimously chosen as the best
option, but of course it was a very small poll and inconclusive, so
other opinions are certainly welcome too.
---------
Co-authored-by: IceSentry <c.giguere42@gmail.com>
2024-02-28 22:48:43 +00:00
|
|
|
Dir3A::new(Vec3A::new(f32::INFINITY, 0.0, 0.0)),
|
2024-02-26 13:57:49 +00:00
|
|
|
Err(InvalidDirectionError::Infinite)
|
|
|
|
);
|
|
|
|
assert_eq!(
|
Rename `Direction2d/3d` to `Dir2/3` (#12189)
# Objective
Split up from #12017, rename Bevy's direction types.
Currently, Bevy has the `Direction2d`, `Direction3d`, and `Direction3dA`
types, which provide a type-level guarantee that their contained vectors
remain normalized. They can be very useful for a lot of APIs for safety,
explicitness, and in some cases performance, as they can sometimes avoid
unnecessary normalizations.
However, many consider them to be inconvenient to use, and opt for
standard vector types like `Vec3` because of this. One reason is that
the direction type names are a bit long and can be annoying to write (of
course you can use autocomplete, but just typing `Vec3` is still nicer),
and in some intances, the extra characters can make formatting worse.
The naming is also inconsistent with Glam's shorter type names, and
results in names like `Direction3dA`, which (in my opinion) are
difficult to read and even a bit ugly.
This PR proposes renaming the types to `Dir2`, `Dir3`, and `Dir3A`.
These names are nice and easy to write, consistent with Glam, and work
well for variants like the SIMD aligned `Dir3A`. As a bonus, it can also
result in nicer formatting in a lot of cases, which can be seen from the
diff of this PR.
Some examples of what it looks like: (copied from #12017)
```rust
// Before
let ray_cast = RayCast2d::new(Vec2::ZERO, Direction2d::X, 5.0);
// After
let ray_cast = RayCast2d::new(Vec2::ZERO, Dir2::X, 5.0);
```
```rust
// Before (an example using Bevy XPBD)
let hit = spatial_query.cast_ray(
Vec3::ZERO,
Direction3d::X,
f32::MAX,
true,
SpatialQueryFilter::default(),
);
// After
let hit = spatial_query.cast_ray(
Vec3::ZERO,
Dir3::X,
f32::MAX,
true,
SpatialQueryFilter::default(),
);
```
```rust
// Before
self.circle(
Vec3::new(0.0, -2.0, 0.0),
Direction3d::Y,
5.0,
Color::TURQUOISE,
);
// After (formatting is collapsed in this case)
self.circle(Vec3::new(0.0, -2.0, 0.0), Dir3::Y, 5.0, Color::TURQUOISE);
```
## Solution
Rename `Direction2d`, `Direction3d`, and `Direction3dA` to `Dir2`,
`Dir3`, and `Dir3A`.
---
## Migration Guide
The `Direction2d` and `Direction3d` types have been renamed to `Dir2`
and `Dir3`.
## Additional Context
This has been brought up on the Discord a few times, and we had a small
[poll](https://discord.com/channels/691052431525675048/1203087353850364004/1212465038711984158)
on this. `Dir2`/`Dir3`/`Dir3A` was quite unanimously chosen as the best
option, but of course it was a very small poll and inconclusive, so
other opinions are certainly welcome too.
---------
Co-authored-by: IceSentry <c.giguere42@gmail.com>
2024-02-28 22:48:43 +00:00
|
|
|
Dir3A::new(Vec3A::new(f32::NEG_INFINITY, 0.0, 0.0)),
|
2024-02-26 13:57:49 +00:00
|
|
|
Err(InvalidDirectionError::Infinite)
|
|
|
|
);
|
|
|
|
assert_eq!(
|
Rename `Direction2d/3d` to `Dir2/3` (#12189)
# Objective
Split up from #12017, rename Bevy's direction types.
Currently, Bevy has the `Direction2d`, `Direction3d`, and `Direction3dA`
types, which provide a type-level guarantee that their contained vectors
remain normalized. They can be very useful for a lot of APIs for safety,
explicitness, and in some cases performance, as they can sometimes avoid
unnecessary normalizations.
However, many consider them to be inconvenient to use, and opt for
standard vector types like `Vec3` because of this. One reason is that
the direction type names are a bit long and can be annoying to write (of
course you can use autocomplete, but just typing `Vec3` is still nicer),
and in some intances, the extra characters can make formatting worse.
The naming is also inconsistent with Glam's shorter type names, and
results in names like `Direction3dA`, which (in my opinion) are
difficult to read and even a bit ugly.
This PR proposes renaming the types to `Dir2`, `Dir3`, and `Dir3A`.
These names are nice and easy to write, consistent with Glam, and work
well for variants like the SIMD aligned `Dir3A`. As a bonus, it can also
result in nicer formatting in a lot of cases, which can be seen from the
diff of this PR.
Some examples of what it looks like: (copied from #12017)
```rust
// Before
let ray_cast = RayCast2d::new(Vec2::ZERO, Direction2d::X, 5.0);
// After
let ray_cast = RayCast2d::new(Vec2::ZERO, Dir2::X, 5.0);
```
```rust
// Before (an example using Bevy XPBD)
let hit = spatial_query.cast_ray(
Vec3::ZERO,
Direction3d::X,
f32::MAX,
true,
SpatialQueryFilter::default(),
);
// After
let hit = spatial_query.cast_ray(
Vec3::ZERO,
Dir3::X,
f32::MAX,
true,
SpatialQueryFilter::default(),
);
```
```rust
// Before
self.circle(
Vec3::new(0.0, -2.0, 0.0),
Direction3d::Y,
5.0,
Color::TURQUOISE,
);
// After (formatting is collapsed in this case)
self.circle(Vec3::new(0.0, -2.0, 0.0), Dir3::Y, 5.0, Color::TURQUOISE);
```
## Solution
Rename `Direction2d`, `Direction3d`, and `Direction3dA` to `Dir2`,
`Dir3`, and `Dir3A`.
---
## Migration Guide
The `Direction2d` and `Direction3d` types have been renamed to `Dir2`
and `Dir3`.
## Additional Context
This has been brought up on the Discord a few times, and we had a small
[poll](https://discord.com/channels/691052431525675048/1203087353850364004/1212465038711984158)
on this. `Dir2`/`Dir3`/`Dir3A` was quite unanimously chosen as the best
option, but of course it was a very small poll and inconclusive, so
other opinions are certainly welcome too.
---------
Co-authored-by: IceSentry <c.giguere42@gmail.com>
2024-02-28 22:48:43 +00:00
|
|
|
Dir3A::new(Vec3A::new(f32::NAN, 0.0, 0.0)),
|
2024-02-26 13:57:49 +00:00
|
|
|
Err(InvalidDirectionError::NaN)
|
|
|
|
);
|
Rename `Direction2d/3d` to `Dir2/3` (#12189)
# Objective
Split up from #12017, rename Bevy's direction types.
Currently, Bevy has the `Direction2d`, `Direction3d`, and `Direction3dA`
types, which provide a type-level guarantee that their contained vectors
remain normalized. They can be very useful for a lot of APIs for safety,
explicitness, and in some cases performance, as they can sometimes avoid
unnecessary normalizations.
However, many consider them to be inconvenient to use, and opt for
standard vector types like `Vec3` because of this. One reason is that
the direction type names are a bit long and can be annoying to write (of
course you can use autocomplete, but just typing `Vec3` is still nicer),
and in some intances, the extra characters can make formatting worse.
The naming is also inconsistent with Glam's shorter type names, and
results in names like `Direction3dA`, which (in my opinion) are
difficult to read and even a bit ugly.
This PR proposes renaming the types to `Dir2`, `Dir3`, and `Dir3A`.
These names are nice and easy to write, consistent with Glam, and work
well for variants like the SIMD aligned `Dir3A`. As a bonus, it can also
result in nicer formatting in a lot of cases, which can be seen from the
diff of this PR.
Some examples of what it looks like: (copied from #12017)
```rust
// Before
let ray_cast = RayCast2d::new(Vec2::ZERO, Direction2d::X, 5.0);
// After
let ray_cast = RayCast2d::new(Vec2::ZERO, Dir2::X, 5.0);
```
```rust
// Before (an example using Bevy XPBD)
let hit = spatial_query.cast_ray(
Vec3::ZERO,
Direction3d::X,
f32::MAX,
true,
SpatialQueryFilter::default(),
);
// After
let hit = spatial_query.cast_ray(
Vec3::ZERO,
Dir3::X,
f32::MAX,
true,
SpatialQueryFilter::default(),
);
```
```rust
// Before
self.circle(
Vec3::new(0.0, -2.0, 0.0),
Direction3d::Y,
5.0,
Color::TURQUOISE,
);
// After (formatting is collapsed in this case)
self.circle(Vec3::new(0.0, -2.0, 0.0), Dir3::Y, 5.0, Color::TURQUOISE);
```
## Solution
Rename `Direction2d`, `Direction3d`, and `Direction3dA` to `Dir2`,
`Dir3`, and `Dir3A`.
---
## Migration Guide
The `Direction2d` and `Direction3d` types have been renamed to `Dir2`
and `Dir3`.
## Additional Context
This has been brought up on the Discord a few times, and we had a small
[poll](https://discord.com/channels/691052431525675048/1203087353850364004/1212465038711984158)
on this. `Dir2`/`Dir3`/`Dir3A` was quite unanimously chosen as the best
option, but of course it was a very small poll and inconclusive, so
other opinions are certainly welcome too.
---------
Co-authored-by: IceSentry <c.giguere42@gmail.com>
2024-02-28 22:48:43 +00:00
|
|
|
assert_eq!(Dir3A::new_and_length(Vec3A::X * 6.5), Ok((Dir3A::X, 6.5)));
|
2024-02-26 13:57:49 +00:00
|
|
|
|
|
|
|
// Test rotation
|
|
|
|
assert!(
|
2024-09-27 00:59:59 +00:00
|
|
|
(Quat::from_rotation_z(core::f32::consts::FRAC_PI_2) * Dir3A::X)
|
2024-02-26 13:57:49 +00:00
|
|
|
.abs_diff_eq(Vec3A::Y, 10e-6)
|
|
|
|
);
|
|
|
|
}
|
2024-05-21 21:13:32 +00:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn dir3a_slerp() {
|
|
|
|
assert_relative_eq!(
|
|
|
|
Dir3A::X.slerp(Dir3A::Y, 0.5),
|
|
|
|
Dir3A::from_xyz(0.5f32.sqrt(), 0.5f32.sqrt(), 0.0).unwrap()
|
|
|
|
);
|
|
|
|
assert_relative_eq!(Dir3A::Y.slerp(Dir3A::Z, 0.0), Dir3A::Y);
|
|
|
|
assert_relative_eq!(Dir3A::Z.slerp(Dir3A::X, 1.0), Dir3A::X, epsilon = 0.000001);
|
|
|
|
assert_relative_eq!(
|
|
|
|
Dir3A::X.slerp(Dir3A::Z, 1.0 / 3.0),
|
|
|
|
Dir3A::from_xyz(0.75f32.sqrt(), 0.0, 0.5).unwrap(),
|
|
|
|
epsilon = 0.000001
|
|
|
|
);
|
|
|
|
assert_relative_eq!(
|
|
|
|
Dir3A::Z.slerp(Dir3A::Y, 2.0 / 3.0),
|
|
|
|
Dir3A::from_xyz(0.0, 0.75f32.sqrt(), 0.5).unwrap()
|
|
|
|
);
|
|
|
|
}
|
2024-07-22 18:42:48 +00:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn dir3a_renorm() {
|
|
|
|
// Evil denormalized quaternion
|
|
|
|
let rot3 = Quat::from_euler(glam::EulerRot::XYZ, 1.0, 2.0, 3.0) * (1.0 + 1e-5);
|
|
|
|
let mut dir_a = Dir3A::X;
|
|
|
|
let mut dir_b = Dir3A::X;
|
|
|
|
|
|
|
|
// We test that renormalizing an already normalized dir doesn't do anything
|
|
|
|
assert_relative_eq!(dir_b, dir_b.fast_renormalize(), epsilon = 0.000001);
|
|
|
|
|
|
|
|
for _ in 0..50 {
|
|
|
|
dir_a = rot3 * dir_a;
|
|
|
|
dir_b = rot3 * dir_b;
|
|
|
|
dir_b = dir_b.fast_renormalize();
|
|
|
|
}
|
|
|
|
|
|
|
|
// `dir_a` should've gotten denormalized, meanwhile `dir_b` should stay normalized.
|
|
|
|
assert!(
|
|
|
|
!dir_a.is_normalized(),
|
|
|
|
"Dernormalization doesn't work, test is faulty"
|
|
|
|
);
|
|
|
|
assert!(dir_b.is_normalized(), "Renormalisation did not work.");
|
|
|
|
}
|
2024-02-26 13:57:49 +00:00
|
|
|
}
|