bevy/crates
Joona Aalto f89af0567b
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
..
bevy_a11y Bump Version after Release (#12020) 2024-02-21 20:58:59 +00:00
bevy_animation Implement the AnimationGraph, allowing for multiple animations to be blended together. (#11989) 2024-03-07 20:22:42 +00:00
bevy_app Add "all-features = true" to docs.rs metadata for most crates (#12366) 2024-03-08 20:03:09 +00:00
bevy_asset Fix doc comment on AssetActionMinimal (#11105) 2024-03-11 18:59:27 +00:00
bevy_audio Fix leftover references to children when despawning audio entities (#12407) 2024-03-11 18:16:13 +00:00
bevy_color Fix green colors becoming darker in various examples (#12328) 2024-03-05 23:42:03 +00:00
bevy_core Add "all-features = true" to docs.rs metadata for most crates (#12366) 2024-03-08 20:03:09 +00:00
bevy_core_pipeline Add "all-features = true" to docs.rs metadata for most crates (#12366) 2024-03-08 20:03:09 +00:00
bevy_derive Bump Version after Release (#12020) 2024-02-21 20:58:59 +00:00
bevy_dev_tools CI testing: don't crash if screenshot manager resource is not available (#12385) 2024-03-08 23:38:56 +00:00
bevy_diagnostic Add "all-features = true" to docs.rs metadata for most crates (#12366) 2024-03-08 20:03:09 +00:00
bevy_dylib Bump Version after Release (#12020) 2024-02-21 20:58:59 +00:00
bevy_dynamic_plugin Document all members of bevy_dynamic_plugin (#12029) 2024-02-22 13:28:52 +00:00
bevy_ecs Query Joins (#11535) 2024-03-11 19:07:36 +00:00
bevy_ecs_compile_fail_tests Remove APIs deprecated in 0.13 (#11974) 2024-02-19 19:04:47 +00:00
bevy_encase_derive Bump Version after Release (#12020) 2024-02-21 20:58:59 +00:00
bevy_gilrs Replace bevy_log's tracing reexport with bevy_utils' (#12254) 2024-03-02 18:38:04 +00:00
bevy_gizmos Add Rotation2d (#11658) 2024-03-11 19:11:57 +00:00
bevy_gltf Add "all-features = true" to docs.rs metadata for most crates (#12366) 2024-03-08 20:03:09 +00:00
bevy_hierarchy Add "all-features = true" to docs.rs metadata for most crates (#12366) 2024-03-08 20:03:09 +00:00
bevy_input Add table showing complexity of methods for Input (#10126) 2024-03-10 23:00:20 +00:00
bevy_internal move ci testing to dev_tools (#12371) 2024-03-07 22:38:21 +00:00
bevy_log Add "all-features = true" to docs.rs metadata for most crates (#12366) 2024-03-08 20:03:09 +00:00
bevy_macro_utils fix deprecations from toml_edit (#12421) 2024-03-11 17:53:38 +00:00
bevy_macros_compile_fail_tests Standardize toml format with taplo (#10594) 2023-11-21 01:04:14 +00:00
bevy_math Add Rotation2d (#11658) 2024-03-11 19:11:57 +00:00
bevy_mikktspace fix some typos (#12038) 2024-02-22 18:55:22 +00:00
bevy_pbr try_insert NoAutomaticBatching (#12396) 2024-03-10 02:14:33 +00:00
bevy_ptr Clean up pointer use in BundleSpawner/BundleInserter (#12269) 2024-03-06 05:52:18 +00:00
bevy_reflect Add Rotation2d (#11658) 2024-03-11 19:11:57 +00:00
bevy_reflect_compile_fail_tests bevy_reflect: Recursive registration (#5781) 2024-03-04 19:04:10 +00:00
bevy_render Update ruzstd requirement from 0.5.0 to 0.6.0 (#12416) 2024-03-11 06:35:56 +00:00
bevy_scene Add "all-features = true" to docs.rs metadata for most crates (#12366) 2024-03-08 20:03:09 +00:00
bevy_sprite Fix docs for atlas + slicing support (#12325) 2024-03-05 18:04:22 +00:00
bevy_tasks Add "all-features = true" to docs.rs metadata for most crates (#12366) 2024-03-08 20:03:09 +00:00
bevy_text Add "all-features = true" to docs.rs metadata for most crates (#12366) 2024-03-08 20:03:09 +00:00
bevy_time Add "all-features = true" to docs.rs metadata for most crates (#12366) 2024-03-08 20:03:09 +00:00
bevy_transform Add "all-features = true" to docs.rs metadata for most crates (#12366) 2024-03-08 20:03:09 +00:00
bevy_ui don't attempt to set cursor relative position for zero sized nodes (#12395) 2024-03-10 02:18:40 +00:00
bevy_utils Disentangle bevy_utils/bevy_core's reexported dependencies (#12313) 2024-03-07 02:30:15 +00:00
bevy_window Add "all-features = true" to docs.rs metadata for most crates (#12366) 2024-03-08 20:03:09 +00:00
bevy_winit Add "all-features = true" to docs.rs metadata for most crates (#12366) 2024-03-08 20:03:09 +00:00