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 /// # Arguments
/// - `position` sets the center of this circle. /// - `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. /// the vector from `position` to the midpoint of the arc.
/// - `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.
@ -128,8 +128,10 @@ fn arc_2d_inner(
(0..resolution + 1).map(move |i| { (0..resolution + 1).map(move |i| {
let start = direction_angle - arc_angle / 2.; let start = direction_angle - arc_angle / 2.;
let angle = start + (i as f32 * (arc_angle / resolution as f32)); let angle =
Vec2::from(angle.sin_cos()) * radius 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_color::Color;
use bevy_math::primitives::{ use bevy_math::primitives::{
Annulus, BoxedPolygon, BoxedPolyline2d, Capsule2d, Circle, Ellipse, Line2d, Plane2d, Polygon, Annulus, Arc2d, BoxedPolygon, BoxedPolyline2d, Capsule2d, Circle, CircularSector,
Polyline2d, Primitive2d, Rectangle, RegularPolygon, Rhombus, Segment2d, Triangle2d, CircularSegment, Ellipse, Line2d, Plane2d, Polygon, Polyline2d, Primitive2d, Rectangle,
RegularPolygon, Rhombus, Segment2d, Triangle2d,
}; };
use bevy_math::{Dir2, Mat2, Vec2}; 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 // circle 2d
impl<'w, 's, Config, Clear> GizmoPrimitive2d<Circle> for Gizmos<'w, 's, Config, Clear> 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 // ellipse 2d
impl<'w, 's, Config, Clear> GizmoPrimitive2d<Ellipse> for Gizmos<'w, 's, Config, Clear> impl<'w, 's, Config, Clear> GizmoPrimitive2d<Ellipse> for Gizmos<'w, 's, Config, Clear>
@ -192,8 +302,6 @@ where
return; return;
} }
let rotation = Mat2::from_angle(angle);
// transform points from the reference unit square to capsule "rectangle" // transform points from the reference unit square to capsule "rectangle"
let [top_left, top_right, bottom_left, bottom_right, top_center, bottom_center] = [ let [top_left, top_right, bottom_left, bottom_right, top_center, bottom_center] = [
[-1.0, 1.0], [-1.0, 1.0],
@ -215,11 +323,8 @@ 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);
// if the capsule is rotated we have to start the arc at a different offset angle, let start_angle_top = angle;
// calculate that here let start_angle_bottom = PI + angle;
let angle_offset = (rotation * Vec2::Y).angle_between(Vec2::Y);
let start_angle_top = angle_offset;
let start_angle_bottom = PI + angle_offset;
// draw arcs // draw arcs
self.arc_2d( self.arc_2d(

View File

@ -85,6 +85,9 @@ enum PrimitiveSelected {
ConicalFrustum, ConicalFrustum,
Torus, Torus,
Tetrahedron, Tetrahedron,
Arc,
CircularSector,
CircularSegment,
} }
impl std::fmt::Display for PrimitiveSelected { impl std::fmt::Display for PrimitiveSelected {
@ -99,7 +102,7 @@ impl std::fmt::Display for PrimitiveSelected {
} }
impl PrimitiveSelected { impl PrimitiveSelected {
const ALL: [Self; 16] = [ const ALL: [Self; 19] = [
Self::RectangleAndCuboid, Self::RectangleAndCuboid,
Self::CircleAndSphere, Self::CircleAndSphere,
Self::Ellipse, Self::Ellipse,
@ -116,6 +119,9 @@ impl PrimitiveSelected {
Self::ConicalFrustum, Self::ConicalFrustum,
Self::Torus, Self::Torus,
Self::Tetrahedron, Self::Tetrahedron,
Self::Arc,
Self::CircularSector,
Self::CircularSegment,
]; ];
fn next(self) -> Self { 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) { fn setup_cameras(mut commands: Commands) {
let start_in_2d = true; let start_in_2d = true;
let make_camera = |is_active| Camera { 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::ConicalFrustum => {}
PrimitiveSelected::Torus => gizmos.primitive_2d(&ANNULUS, POSITION, angle, color), PrimitiveSelected::Torus => gizmos.primitive_2d(&ANNULUS, POSITION, angle, color),
PrimitiveSelected::Tetrahedron => {} 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 => { PrimitiveSelected::Tetrahedron => {
gizmos.primitive_3d(&TETRAHEDRON, POSITION, rotation, color); gizmos.primitive_3d(&TETRAHEDRON, POSITION, rotation, color);
} }
PrimitiveSelected::Arc => {}
PrimitiveSelected::CircularSector => {}
PrimitiveSelected::CircularSegment => {}
} }
} }