mirror of
https://github.com/bevyengine/bevy
synced 2024-11-10 07:04:33 +00:00
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 ![image](https://github.com/user-attachments/assets/84894c6d-42e4-451b-b3e2-811266486ede) where after the fix with ```rust my_gizmos.arc_2d(Isometry2d::IDENTITY, FRAC_PI_2, 75.0, ORANGE_RED); ``` we get ![image](https://github.com/user-attachments/assets/16b0aba0-f7b5-4600-ac49-a22be0315c40) 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
4 changed files with 41 additions and 55 deletions
|
@ -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 a new issue