Fix arc_2d Gizmos (#14731)
# Objective
`arc_2d` wasn't actually doing what the docs were saying. The arc wasn't
offset by what was previously `direction_angle` but by `direction_angle
- arc_angle / 2.0`. This meant that the arcs center was laying on the
`Vec2::Y` axis and then it was offset. This was probably done to fit the
behavior of the `Arc2D` primitive. I would argue that this isn't
desirable for the plain `arc_2d` gizmo method since
- a) the docs get longer to explain the weird centering
- b) the mental model the user has to know gets bigger with more
implicit assumptions
given the code
```rust
my_gizmos.arc_2d(Vec2::ZERO, 0.0, FRAC_PI_2, 75.0, ORANGE_RED);
```
we get

where after the fix with
```rust
my_gizmos.arc_2d(Isometry2d::IDENTITY, FRAC_PI_2, 75.0, ORANGE_RED);
```
we get

To get the same result with the previous implementation you would have
to randomly add `arc_angle / 2.0` to the `direction_angle`.
```rust
my_gizmos.arc_2d(Vec2::ZERO, FRAC_PI_4, FRAC_PI_2, 75.0, ORANGE_RED);
```
This makes constructing similar helping functions as they already exist
in 3D like
- `long_arc_2d_between`
- `short_arc_2d_between`
much harder.
## Solution
- Make the arc really start at `Vec2::Y * radius` in counter-clockwise
direction + offset by an angle as the docs state it
- Use `Isometry2d` instead of `position : Vec2` and `direction_angle :
f32` to reduce the chance of messing up rotation/translation
- Adjust the docs for the changes above
- Adjust the gizmo rendering of some primitives
## Testing
- check `2d_gizmos.rs` and `render_primitives.rs` examples
## Migration Guide
- users have to adjust their usages of `arc_2d`:
- before:
```rust
arc_2d(
pos,
angle,
arc_angle,
radius,
color
)
```
- after:
```rust
arc_2d(
// this `+ arc_angle * 0.5` quirk is only if you want to preserve the
previous behavior
// with the new API.
// feel free to try to fix this though since your current calls to this
function most likely
// involve some computations to counter-act that quirk in the first
place
Isometry2d::new(pos, Rot2::radians(angle + arc_angle * 0.5),
arc_angle,
radius,
color
)
```
This commit is contained in:
parent
2e36b2719c
commit
6819e998c0
@ -6,8 +6,8 @@
|
|||||||
use crate::circles::DEFAULT_CIRCLE_RESOLUTION;
|
use crate::circles::DEFAULT_CIRCLE_RESOLUTION;
|
||||||
use crate::prelude::{GizmoConfigGroup, Gizmos};
|
use crate::prelude::{GizmoConfigGroup, Gizmos};
|
||||||
use bevy_color::Color;
|
use bevy_color::Color;
|
||||||
use bevy_math::{Quat, Vec2, Vec3};
|
use bevy_math::{Isometry2d, Quat, Vec2, Vec3};
|
||||||
use std::f32::consts::TAU;
|
use std::f32::consts::{FRAC_PI_2, TAU};
|
||||||
|
|
||||||
// === 2D ===
|
// === 2D ===
|
||||||
|
|
||||||
@ -21,9 +21,9 @@ where
|
|||||||
/// This should be called for each frame the arc needs to be rendered.
|
/// This should be called for each frame the arc needs to be rendered.
|
||||||
///
|
///
|
||||||
/// # Arguments
|
/// # Arguments
|
||||||
/// - `position` sets the center of this circle.
|
/// - `isometry` defines the translation and rotation of the arc.
|
||||||
/// - `direction_angle` sets the counter-clockwise angle in radians between `Vec2::Y` and
|
/// - the translation specifies the center of the arc
|
||||||
/// the vector from `position` to the midpoint of the arc.
|
/// - the rotation is counter-clockwise starting from `Vec2::Y`
|
||||||
/// - `arc_angle` sets the length of this arc, in radians.
|
/// - `arc_angle` sets the length of this arc, in radians.
|
||||||
/// - `radius` controls the distance from `position` to this arc, and thus its curvature.
|
/// - `radius` controls the distance from `position` to this arc, and thus its curvature.
|
||||||
/// - `color` sets the color to draw the arc.
|
/// - `color` sets the color to draw the arc.
|
||||||
@ -32,15 +32,15 @@ where
|
|||||||
/// ```
|
/// ```
|
||||||
/// # use bevy_gizmos::prelude::*;
|
/// # use bevy_gizmos::prelude::*;
|
||||||
/// # use bevy_math::prelude::*;
|
/// # use bevy_math::prelude::*;
|
||||||
/// # use std::f32::consts::PI;
|
/// # use std::f32::consts::FRAC_PI_4;
|
||||||
/// # use bevy_color::palettes::basic::{GREEN, RED};
|
/// # use bevy_color::palettes::basic::{GREEN, RED};
|
||||||
/// fn system(mut gizmos: Gizmos) {
|
/// fn system(mut gizmos: Gizmos) {
|
||||||
/// gizmos.arc_2d(Vec2::ZERO, 0., PI / 4., 1., GREEN);
|
/// gizmos.arc_2d(Isometry2d::IDENTITY, FRAC_PI_4, 1., GREEN);
|
||||||
///
|
///
|
||||||
/// // Arcs have 32 line-segments by default.
|
/// // Arcs have 32 line-segments by default.
|
||||||
/// // You may want to increase this for larger arcs.
|
/// // You may want to increase this for larger arcs.
|
||||||
/// gizmos
|
/// gizmos
|
||||||
/// .arc_2d(Vec2::ZERO, 0., PI / 4., 5., RED)
|
/// .arc_2d(Isometry2d::IDENTITY, FRAC_PI_4, 5., RED)
|
||||||
/// .resolution(64);
|
/// .resolution(64);
|
||||||
/// }
|
/// }
|
||||||
/// # bevy_ecs::system::assert_is_system(system);
|
/// # bevy_ecs::system::assert_is_system(system);
|
||||||
@ -48,16 +48,14 @@ where
|
|||||||
#[inline]
|
#[inline]
|
||||||
pub fn arc_2d(
|
pub fn arc_2d(
|
||||||
&mut self,
|
&mut self,
|
||||||
position: Vec2,
|
isometry: Isometry2d,
|
||||||
direction_angle: f32,
|
|
||||||
arc_angle: f32,
|
arc_angle: f32,
|
||||||
radius: f32,
|
radius: f32,
|
||||||
color: impl Into<Color>,
|
color: impl Into<Color>,
|
||||||
) -> Arc2dBuilder<'_, 'w, 's, Config, Clear> {
|
) -> Arc2dBuilder<'_, 'w, 's, Config, Clear> {
|
||||||
Arc2dBuilder {
|
Arc2dBuilder {
|
||||||
gizmos: self,
|
gizmos: self,
|
||||||
position,
|
isometry,
|
||||||
direction_angle,
|
|
||||||
arc_angle,
|
arc_angle,
|
||||||
radius,
|
radius,
|
||||||
color: color.into(),
|
color: color.into(),
|
||||||
@ -73,8 +71,7 @@ where
|
|||||||
Clear: 'static + Send + Sync,
|
Clear: 'static + Send + Sync,
|
||||||
{
|
{
|
||||||
gizmos: &'a mut Gizmos<'w, 's, Config, Clear>,
|
gizmos: &'a mut Gizmos<'w, 's, Config, Clear>,
|
||||||
position: Vec2,
|
isometry: Isometry2d,
|
||||||
direction_angle: f32,
|
|
||||||
arc_angle: f32,
|
arc_angle: f32,
|
||||||
radius: f32,
|
radius: f32,
|
||||||
color: Color,
|
color: Color,
|
||||||
@ -107,31 +104,19 @@ where
|
|||||||
.resolution
|
.resolution
|
||||||
.unwrap_or_else(|| resolution_from_angle(self.arc_angle));
|
.unwrap_or_else(|| resolution_from_angle(self.arc_angle));
|
||||||
|
|
||||||
let positions = arc_2d_inner(
|
let positions =
|
||||||
self.direction_angle,
|
arc_2d_inner(self.arc_angle, self.radius, resolution).map(|vec2| self.isometry * vec2);
|
||||||
self.arc_angle,
|
|
||||||
self.radius,
|
|
||||||
resolution,
|
|
||||||
)
|
|
||||||
.map(|vec2| (vec2 + self.position));
|
|
||||||
self.gizmos.linestrip_2d(positions, self.color);
|
self.gizmos.linestrip_2d(positions, self.color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn arc_2d_inner(
|
fn arc_2d_inner(arc_angle: f32, radius: f32, resolution: u32) -> impl Iterator<Item = Vec2> {
|
||||||
direction_angle: f32,
|
(0..=resolution)
|
||||||
arc_angle: f32,
|
.map(move |n| arc_angle * n as f32 / resolution as f32)
|
||||||
radius: f32,
|
.map(|angle| angle + FRAC_PI_2)
|
||||||
resolution: u32,
|
.map(f32::sin_cos)
|
||||||
) -> impl Iterator<Item = Vec2> {
|
.map(|(sin, cos)| Vec2::new(cos, sin))
|
||||||
(0..resolution + 1).map(move |i| {
|
.map(move |vec2| vec2 * radius)
|
||||||
let start = direction_angle - arc_angle / 2.;
|
|
||||||
|
|
||||||
let angle =
|
|
||||||
start + (i as f32 * (arc_angle / resolution as f32)) + std::f32::consts::FRAC_PI_2;
|
|
||||||
|
|
||||||
Vec2::new(angle.cos(), angle.sin()) * radius
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// === 3D ===
|
// === 3D ===
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
//! A module for rendering each of the 2D [`bevy_math::primitives`] with [`Gizmos`].
|
//! A module for rendering each of the 2D [`bevy_math::primitives`] with [`Gizmos`].
|
||||||
|
|
||||||
use std::f32::consts::PI;
|
use std::f32::consts::{FRAC_PI_2, PI};
|
||||||
|
|
||||||
use super::helpers::*;
|
use super::helpers::*;
|
||||||
|
|
||||||
@ -10,7 +10,7 @@ use bevy_math::primitives::{
|
|||||||
CircularSegment, Ellipse, Line2d, Plane2d, Polygon, Polyline2d, Primitive2d, Rectangle,
|
CircularSegment, Ellipse, Line2d, Plane2d, Polygon, Polyline2d, Primitive2d, Rectangle,
|
||||||
RegularPolygon, Rhombus, Segment2d, Triangle2d,
|
RegularPolygon, Rhombus, Segment2d, Triangle2d,
|
||||||
};
|
};
|
||||||
use bevy_math::{Dir2, Mat2, Vec2};
|
use bevy_math::{Dir2, Isometry2d, Mat2, Rot2, Vec2};
|
||||||
|
|
||||||
use crate::prelude::{GizmoConfigGroup, Gizmos};
|
use crate::prelude::{GizmoConfigGroup, Gizmos};
|
||||||
|
|
||||||
@ -86,8 +86,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.arc_2d(
|
self.arc_2d(
|
||||||
position,
|
Isometry2d::new(position, Rot2::radians(angle - primitive.half_angle)),
|
||||||
angle,
|
|
||||||
primitive.half_angle * 2.0,
|
primitive.half_angle * 2.0,
|
||||||
primitive.radius,
|
primitive.radius,
|
||||||
color,
|
color,
|
||||||
@ -139,8 +138,7 @@ where
|
|||||||
|
|
||||||
// we need to draw the arc part of the sector, and the two lines connecting the arc and the center
|
// we need to draw the arc part of the sector, and the two lines connecting the arc and the center
|
||||||
self.arc_2d(
|
self.arc_2d(
|
||||||
position,
|
Isometry2d::new(position, Rot2::radians(angle - primitive.arc.half_angle)),
|
||||||
angle,
|
|
||||||
primitive.arc.half_angle * 2.0,
|
primitive.arc.half_angle * 2.0,
|
||||||
primitive.arc.radius,
|
primitive.arc.radius,
|
||||||
color,
|
color,
|
||||||
@ -179,8 +177,7 @@ where
|
|||||||
|
|
||||||
// we need to draw the arc part of the segment, and the line connecting the two ends
|
// we need to draw the arc part of the segment, and the line connecting the two ends
|
||||||
self.arc_2d(
|
self.arc_2d(
|
||||||
position,
|
Isometry2d::new(position, Rot2::radians(angle - primitive.arc.half_angle)),
|
||||||
angle,
|
|
||||||
primitive.arc.half_angle * 2.0,
|
primitive.arc.half_angle * 2.0,
|
||||||
primitive.arc.radius,
|
primitive.arc.radius,
|
||||||
color,
|
color,
|
||||||
@ -386,20 +383,18 @@ where
|
|||||||
self.line_2d(bottom_left, top_left, polymorphic_color);
|
self.line_2d(bottom_left, top_left, polymorphic_color);
|
||||||
self.line_2d(bottom_right, top_right, polymorphic_color);
|
self.line_2d(bottom_right, top_right, polymorphic_color);
|
||||||
|
|
||||||
let start_angle_top = angle;
|
let start_angle_top = angle - FRAC_PI_2;
|
||||||
let start_angle_bottom = PI + angle;
|
let start_angle_bottom = angle + FRAC_PI_2;
|
||||||
|
|
||||||
// draw arcs
|
// draw arcs
|
||||||
self.arc_2d(
|
self.arc_2d(
|
||||||
top_center,
|
Isometry2d::new(top_center, Rot2::radians(start_angle_top)),
|
||||||
start_angle_top,
|
|
||||||
PI,
|
PI,
|
||||||
primitive.radius,
|
primitive.radius,
|
||||||
polymorphic_color,
|
polymorphic_color,
|
||||||
);
|
);
|
||||||
self.arc_2d(
|
self.arc_2d(
|
||||||
bottom_center,
|
Isometry2d::new(bottom_center, Rot2::radians(start_angle_bottom)),
|
||||||
start_angle_bottom,
|
|
||||||
PI,
|
PI,
|
||||||
primitive.radius,
|
primitive.radius,
|
||||||
polymorphic_color,
|
polymorphic_color,
|
||||||
|
|||||||
@ -57,9 +57,9 @@ pub mod prelude {
|
|||||||
},
|
},
|
||||||
direction::{Dir2, Dir3, Dir3A},
|
direction::{Dir2, Dir3, Dir3A},
|
||||||
primitives::*,
|
primitives::*,
|
||||||
BVec2, BVec3, BVec4, EulerRot, FloatExt, IRect, IVec2, IVec3, IVec4, Mat2, Mat3, Mat4,
|
BVec2, BVec3, BVec4, EulerRot, FloatExt, IRect, IVec2, IVec3, IVec4, Isometry2d,
|
||||||
Quat, Ray2d, Ray3d, Rect, Rot2, StableInterpolate, URect, UVec2, UVec3, UVec4, Vec2,
|
Isometry3d, Mat2, Mat3, Mat4, Quat, Ray2d, Ray3d, Rect, Rot2, StableInterpolate, URect,
|
||||||
Vec2Swizzles, Vec3, Vec3Swizzles, Vec4, Vec4Swizzles,
|
UVec2, UVec3, UVec4, Vec2, Vec2Swizzles, Vec3, Vec3Swizzles, Vec4, Vec4Swizzles,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
//! This example demonstrates Bevy's immediate mode drawing API intended for visual debugging.
|
//! This example demonstrates Bevy's immediate mode drawing API intended for visual debugging.
|
||||||
|
|
||||||
use std::f32::consts::{PI, TAU};
|
use std::f32::consts::{FRAC_PI_2, PI, TAU};
|
||||||
|
|
||||||
use bevy::{color::palettes::css::*, prelude::*};
|
use bevy::{color::palettes::css::*, math::Isometry2d, prelude::*};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
App::new()
|
App::new()
|
||||||
@ -87,7 +87,13 @@ fn draw_example_collection(
|
|||||||
|
|
||||||
// Arcs default resolution is linearly interpolated between
|
// Arcs default resolution is linearly interpolated between
|
||||||
// 1 and 32, using the arc length as scalar.
|
// 1 and 32, using the arc length as scalar.
|
||||||
my_gizmos.arc_2d(Vec2::ZERO, sin / 10., PI / 2., 310., ORANGE_RED);
|
my_gizmos.arc_2d(
|
||||||
|
Isometry2d::from_rotation(Rot2::radians(sin / 10.)),
|
||||||
|
FRAC_PI_2,
|
||||||
|
310.,
|
||||||
|
ORANGE_RED,
|
||||||
|
);
|
||||||
|
my_gizmos.arc_2d(Isometry2d::IDENTITY, FRAC_PI_2, 75.0, ORANGE_RED);
|
||||||
|
|
||||||
gizmos.arrow_2d(
|
gizmos.arrow_2d(
|
||||||
Vec2::ZERO,
|
Vec2::ZERO,
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user