Gizmos: arc_2d utility helpers (#14932)

# Objective

Since https://github.com/bevyengine/bevy/pull/14731 is merged, it
unblocked a few utility methods for 2D arcs. In 2D the pendant to
`long_arc_3d_between` and `short_arc_3d_between` are missing. Since
`arc_2d` can be a bit hard to use, this PR is trying to plug some holes
in the `arcs` API.

## Solution

Implement

- `long_arc_2d_between(center, from, tp, color)`
- `short_arc_2d_between(center, from, tp, color)`

## Testing

- There are new doc tests
- The `2d_gizmos` example has been extended a bit to include a few more
arcs which can easily be checked with respect to the grid

---

## Showcase


![image](https://github.com/user-attachments/assets/b90ad8b1-86c2-4304-a481-4f9a5246c457)

Code related to the screenshot (from outer = first line to inner = last
line)

```rust
    my_gizmos.arc_2d(Isometry2d::IDENTITY, FRAC_PI_2, 80.0, ORANGE_RED);
    my_gizmos.short_arc_2d_between(Vec2::ZERO, Vec2::X * 40.0, Vec2::Y * 40.0, ORANGE_RED);
    my_gizmos.long_arc_2d_between(Vec2::ZERO, Vec2::X * 20.0, Vec2::Y * 20.0, ORANGE_RED);
```
This commit is contained in:
Robert Walter 2024-08-28 11:33:11 +00:00 committed by GitHub
parent 419359b9a7
commit 210c79c9f9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 126 additions and 2 deletions

View file

@ -6,7 +6,7 @@
use crate::circles::DEFAULT_CIRCLE_RESOLUTION;
use crate::prelude::{GizmoConfigGroup, Gizmos};
use bevy_color::Color;
use bevy_math::{Isometry2d, Isometry3d, Quat, Vec2, Vec3};
use bevy_math::{Isometry2d, Isometry3d, Quat, Rot2, Vec2, Vec3};
use std::f32::consts::{FRAC_PI_2, TAU};
// === 2D ===
@ -321,6 +321,128 @@ where
resolution: None,
}
}
/// Draws the shortest arc between two points (`from` and `to`) relative to a specified `center` point.
///
/// # Arguments
///
/// - `center`: The center point around which the arc is drawn.
/// - `from`: The starting point of the arc.
/// - `to`: The ending point of the arc.
/// - `color`: color of the arc
///
/// # Builder methods
/// The resolution of the arc (i.e. the level of detail) can be adjusted with the
/// `.resolution(...)` method.
///
/// # Examples
/// ```
/// # use bevy_gizmos::prelude::*;
/// # use bevy_math::prelude::*;
/// # use bevy_color::palettes::css::ORANGE;
/// fn system(mut gizmos: Gizmos) {
/// gizmos.short_arc_2d_between(
/// Vec2::ZERO,
/// Vec2::X,
/// Vec2::Y,
/// ORANGE
/// )
/// .resolution(100);
/// }
/// # bevy_ecs::system::assert_is_system(system);
/// ```
///
/// # Notes
/// - This method assumes that the points `from` and `to` are distinct from `center`. If one of
/// the points is coincident with `center`, nothing is rendered.
/// - The arc is drawn as a portion of a circle with a radius equal to the distance from the
/// `center` to `from`. If the distance from `center` to `to` is not equal to the radius, then
/// the results will behave as if this were the case
#[inline]
pub fn short_arc_2d_between(
&mut self,
center: Vec2,
from: Vec2,
to: Vec2,
color: impl Into<Color>,
) -> Arc2dBuilder<'_, 'w, 's, Config, Clear> {
self.arc_2d_from_to(center, from, to, color, std::convert::identity)
}
/// Draws the longest arc between two points (`from` and `to`) relative to a specified `center` point.
///
/// # Arguments
/// - `center`: The center point around which the arc is drawn.
/// - `from`: The starting point of the arc.
/// - `to`: The ending point of the arc.
/// - `color`: color of the arc
///
/// # Builder methods
/// The resolution of the arc (i.e. the level of detail) can be adjusted with the
/// `.resolution(...)` method.
///
/// # Examples
/// ```
/// # use bevy_gizmos::prelude::*;
/// # use bevy_math::prelude::*;
/// # use bevy_color::palettes::css::ORANGE;
/// fn system(mut gizmos: Gizmos) {
/// gizmos.long_arc_2d_between(
/// Vec2::ZERO,
/// Vec2::X,
/// Vec2::Y,
/// ORANGE
/// )
/// .resolution(100);
/// }
/// # bevy_ecs::system::assert_is_system(system);
/// ```
///
/// # Notes
/// - This method assumes that the points `from` and `to` are distinct from `center`. If one of
/// the points is coincident with `center`, nothing is rendered.
/// - The arc is drawn as a portion of a circle with a radius equal to the distance from the
/// `center` to `from`. If the distance from `center` to `to` is not equal to the radius, then
/// the results will behave as if this were the case.
#[inline]
pub fn long_arc_2d_between(
&mut self,
center: Vec2,
from: Vec2,
to: Vec2,
color: impl Into<Color>,
) -> Arc2dBuilder<'_, 'w, 's, Config, Clear> {
self.arc_2d_from_to(center, from, to, color, |angle| angle - TAU)
}
#[inline]
fn arc_2d_from_to(
&mut self,
center: Vec2,
from: Vec2,
to: Vec2,
color: impl Into<Color>,
angle_fn: impl Fn(f32) -> f32,
) -> Arc2dBuilder<'_, 'w, 's, Config, Clear> {
// `from` and `to` can be the same here since in either case nothing gets rendered and the
// orientation ambiguity of `up` doesn't matter
let from_axis = (from - center).normalize_or_zero();
let to_axis = (to - center).normalize_or_zero();
let rotation = Vec2::Y.angle_to(from_axis);
let arc_angle_raw = from_axis.angle_to(to_axis);
let arc_angle = angle_fn(arc_angle_raw);
let radius = center.distance(from);
Arc2dBuilder {
gizmos: self,
isometry: Isometry2d::new(center, Rot2::radians(rotation)),
arc_angle,
radius,
color: color.into(),
resolution: None,
}
}
}
/// A builder returned by [`Gizmos::arc_2d`].

View file

@ -97,7 +97,9 @@ fn draw_example_collection(
310.,
ORANGE_RED,
);
my_gizmos.arc_2d(Isometry2d::IDENTITY, FRAC_PI_2, 75.0, ORANGE_RED);
my_gizmos.arc_2d(Isometry2d::IDENTITY, FRAC_PI_2, 80.0, ORANGE_RED);
my_gizmos.long_arc_2d_between(Vec2::ZERO, Vec2::X * 20.0, Vec2::Y * 20.0, ORANGE_RED);
my_gizmos.short_arc_2d_between(Vec2::ZERO, Vec2::X * 40.0, Vec2::Y * 40.0, ORANGE_RED);
gizmos.arrow_2d(
Vec2::ZERO,