Implemented GizmoPrimitive2d for Arc2d, CircularSegment, CircularSector, and make arc_2d use counter-clockwise angle. (#13610)

# Objective

Fixes #13606.
Also Fixes #13614.

## Solution

Added the missing trait impls, and made `gizmos.arc_2d()` work with a
counter-clockwise angle.
## Testing

- Updated the render_primitives example, and it works.
This commit is contained in:
Olle Lukowski 2024-06-01 14:30:34 +02:00 committed by GitHub
parent 178959b53a
commit 4b996c75ab
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 156 additions and 13 deletions

View File

@ -22,7 +22,7 @@ where
///
/// # Arguments
/// - `position` sets the center of this circle.
/// - `direction_angle` sets the clockwise angle in radians between `Vec2::Y` and
/// - `direction_angle` sets the counter-clockwise angle in radians between `Vec2::Y` and
/// the vector from `position` to the midpoint of the arc.
/// - `arc_angle` sets the length of this arc, in radians.
/// - `radius` controls the distance from `position` to this arc, and thus its curvature.
@ -128,8 +128,10 @@ fn arc_2d_inner(
(0..resolution + 1).map(move |i| {
let start = direction_angle - arc_angle / 2.;
let angle = start + (i as f32 * (arc_angle / resolution as f32));
Vec2::from(angle.sin_cos()) * radius
let angle =
start + (i as f32 * (arc_angle / resolution as f32)) + std::f32::consts::FRAC_PI_2;
Vec2::new(angle.cos(), angle.sin()) * radius
})
}

View File

@ -6,8 +6,9 @@ use super::helpers::*;
use bevy_color::Color;
use bevy_math::primitives::{
Annulus, BoxedPolygon, BoxedPolyline2d, Capsule2d, Circle, Ellipse, Line2d, Plane2d, Polygon,
Polyline2d, Primitive2d, Rectangle, RegularPolygon, Rhombus, Segment2d, Triangle2d,
Annulus, Arc2d, BoxedPolygon, BoxedPolyline2d, Capsule2d, Circle, CircularSector,
CircularSegment, Ellipse, Line2d, Plane2d, Polygon, Polyline2d, Primitive2d, Rectangle,
RegularPolygon, Rhombus, Segment2d, Triangle2d,
};
use bevy_math::{Dir2, Mat2, Vec2};
@ -64,6 +65,36 @@ where
}
}
// arc 2d
impl<'w, 's, Config, Clear> GizmoPrimitive2d<Arc2d> for Gizmos<'w, 's, Config, Clear>
where
Config: GizmoConfigGroup,
Clear: 'static + Send + Sync,
{
type Output<'a> = () where Self: 'a;
fn primitive_2d(
&mut self,
primitive: &Arc2d,
position: Vec2,
angle: f32,
color: impl Into<Color>,
) -> Self::Output<'_> {
if !self.enabled {
return;
}
self.arc_2d(
position,
angle,
primitive.half_angle * 2.0,
primitive.radius,
color,
);
}
}
// circle 2d
impl<'w, 's, Config, Clear> GizmoPrimitive2d<Circle> for Gizmos<'w, 's, Config, Clear>
@ -88,6 +119,85 @@ where
}
}
// circular sector 2d
impl<'w, 's, Config, Clear> GizmoPrimitive2d<CircularSector> for Gizmos<'w, 's, Config, Clear>
where
Config: GizmoConfigGroup,
Clear: 'static + Send + Sync,
{
type Output<'a> = () where Self: 'a;
fn primitive_2d(
&mut self,
primitive: &CircularSector,
position: Vec2,
angle: f32,
color: impl Into<Color>,
) -> Self::Output<'_> {
if !self.enabled {
return;
}
let color = color.into();
// we need to draw the arc part of the sector, and the two lines connecting the arc and the center
self.arc_2d(
position,
angle,
primitive.arc.half_angle * 2.0,
primitive.arc.radius,
color,
);
let start = position
+ primitive.arc.radius * Mat2::from_angle(angle - primitive.arc.half_angle) * Vec2::Y;
let end = position
+ primitive.arc.radius * Mat2::from_angle(angle + primitive.arc.half_angle) * Vec2::Y;
self.line_2d(position, start, color);
self.line_2d(position, end, color);
}
}
// circular segment 2d
impl<'w, 's, Config, Clear> GizmoPrimitive2d<CircularSegment> for Gizmos<'w, 's, Config, Clear>
where
Config: GizmoConfigGroup,
Clear: 'static + Send + Sync,
{
type Output<'a> = () where Self: 'a;
fn primitive_2d(
&mut self,
primitive: &CircularSegment,
position: Vec2,
angle: f32,
color: impl Into<Color>,
) -> Self::Output<'_> {
if !self.enabled {
return;
}
let color = color.into();
// we need to draw the arc part of the segment, and the line connecting the two ends
self.arc_2d(
position,
angle,
primitive.arc.half_angle * 2.0,
primitive.arc.radius,
color,
);
let start = position
+ primitive.arc.radius * Mat2::from_angle(angle - primitive.arc.half_angle) * Vec2::Y;
let end = position
+ primitive.arc.radius * Mat2::from_angle(angle + primitive.arc.half_angle) * Vec2::Y;
self.line_2d(end, start, color);
}
}
// ellipse 2d
impl<'w, 's, Config, Clear> GizmoPrimitive2d<Ellipse> for Gizmos<'w, 's, Config, Clear>
@ -192,8 +302,6 @@ where
return;
}
let rotation = Mat2::from_angle(angle);
// transform points from the reference unit square to capsule "rectangle"
let [top_left, top_right, bottom_left, bottom_right, top_center, bottom_center] = [
[-1.0, 1.0],
@ -215,11 +323,8 @@ where
self.line_2d(bottom_left, top_left, polymorphic_color);
self.line_2d(bottom_right, top_right, polymorphic_color);
// if the capsule is rotated we have to start the arc at a different offset angle,
// calculate that here
let angle_offset = (rotation * Vec2::Y).angle_between(Vec2::Y);
let start_angle_top = angle_offset;
let start_angle_bottom = PI + angle_offset;
let start_angle_top = angle;
let start_angle_bottom = PI + angle;
// draw arcs
self.arc_2d(

View File

@ -85,6 +85,9 @@ enum PrimitiveSelected {
ConicalFrustum,
Torus,
Tetrahedron,
Arc,
CircularSector,
CircularSegment,
}
impl std::fmt::Display for PrimitiveSelected {
@ -99,7 +102,7 @@ impl std::fmt::Display for PrimitiveSelected {
}
impl PrimitiveSelected {
const ALL: [Self; 16] = [
const ALL: [Self; 19] = [
Self::RectangleAndCuboid,
Self::CircleAndSphere,
Self::Ellipse,
@ -116,6 +119,9 @@ impl PrimitiveSelected {
Self::ConicalFrustum,
Self::Torus,
Self::Tetrahedron,
Self::Arc,
Self::CircularSector,
Self::CircularSegment,
];
fn next(self) -> Self {
@ -269,6 +275,25 @@ const TETRAHEDRON: Tetrahedron = Tetrahedron {
],
};
const ARC: Arc2d = Arc2d {
radius: BIG_2D,
half_angle: std::f32::consts::FRAC_PI_4,
};
const CIRCULAR_SECTOR: CircularSector = CircularSector {
arc: Arc2d {
radius: BIG_2D,
half_angle: std::f32::consts::FRAC_PI_4,
},
};
const CIRCULAR_SEGMENT: CircularSegment = CircularSegment {
arc: Arc2d {
radius: BIG_2D,
half_angle: std::f32::consts::FRAC_PI_4,
},
};
fn setup_cameras(mut commands: Commands) {
let start_in_2d = true;
let make_camera = |is_active| Camera {
@ -446,6 +471,13 @@ fn draw_gizmos_2d(mut gizmos: Gizmos, state: Res<State<PrimitiveSelected>>, time
PrimitiveSelected::ConicalFrustum => {}
PrimitiveSelected::Torus => gizmos.primitive_2d(&ANNULUS, POSITION, angle, color),
PrimitiveSelected::Tetrahedron => {}
PrimitiveSelected::Arc => gizmos.primitive_2d(&ARC, POSITION, angle, color),
PrimitiveSelected::CircularSector => {
gizmos.primitive_2d(&CIRCULAR_SECTOR, POSITION, angle, color);
}
PrimitiveSelected::CircularSegment => {
gizmos.primitive_2d(&CIRCULAR_SEGMENT, POSITION, angle, color);
}
}
}
@ -675,5 +707,9 @@ fn draw_gizmos_3d(mut gizmos: Gizmos, state: Res<State<PrimitiveSelected>>, time
PrimitiveSelected::Tetrahedron => {
gizmos.primitive_3d(&TETRAHEDRON, POSITION, rotation, color);
}
PrimitiveSelected::Arc => {}
PrimitiveSelected::CircularSector => {}
PrimitiveSelected::CircularSegment => {}
}
}