Angle as proper type
This commit is contained in:
parent
a5a1be2392
commit
d16607ff4d
21
Cargo.lock
generated
21
Cargo.lock
generated
@ -4,9 +4,9 @@ version = 3
|
||||
|
||||
[[package]]
|
||||
name = "ab_glyph"
|
||||
version = "0.2.15"
|
||||
version = "0.2.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "24606928a235e73cdef55a0c909719cadd72fce573e5713d58cb2952d8f5794c"
|
||||
checksum = "846ffacb9d0c8b879ef9e565b59e18fb76d6a61013e5bd24ecc659864e6b1a1f"
|
||||
dependencies = [
|
||||
"ab_glyph_rasterizer",
|
||||
"owned_ttf_parser",
|
||||
@ -594,9 +594,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "bevy_pbr"
|
||||
version = "0.8.0"
|
||||
version = "0.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed9a81bbd02f5e0a57899a41aec37d9cb14965e1e4d510547f3f680323d05c0f"
|
||||
checksum = "176073021a4caeb8b448f24ce790fb57fde74b114f345064a8b102d2f7bed905"
|
||||
dependencies = [
|
||||
"bevy_app",
|
||||
"bevy_asset",
|
||||
@ -741,9 +741,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "bevy_sprite"
|
||||
version = "0.8.0"
|
||||
version = "0.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1f83dfe8897d6c0d9d5ce3818d49a13e58ae2b9b9ecf4f4bb85aa31bb0678f68"
|
||||
checksum = "69c419f3db09d7ac1f4d45e0874d349d5d6f47f48bc10d55cd0da36413e2331e"
|
||||
dependencies = [
|
||||
"bevy_app",
|
||||
"bevy_asset",
|
||||
@ -841,9 +841,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "bevy_ui"
|
||||
version = "0.8.0"
|
||||
version = "0.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac181a7b637da61fad72981ff9d2e5b899283ca7d54b2b7ea49c431121331c53"
|
||||
checksum = "062ce086de1a4a470e5df48cb5c16a1dc97ab610e635cafabdef26c4a1ef5756"
|
||||
dependencies = [
|
||||
"bevy_app",
|
||||
"bevy_asset",
|
||||
@ -883,9 +883,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "bevy_window"
|
||||
version = "0.8.0"
|
||||
version = "0.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a3bdc3a220a9bb2fad9bd30d5f44c6645725398fe1bc588fc87abf09f092696e"
|
||||
checksum = "707dbbebfac72b1e63e874e7a11a345feab8c440355c0bd71e6dff26709fba9a"
|
||||
dependencies = [
|
||||
"bevy_app",
|
||||
"bevy_ecs",
|
||||
@ -3238,6 +3238,7 @@ dependencies = [
|
||||
"bevy-inspector-egui",
|
||||
"bevy_prototype_lyon",
|
||||
"bevy_tweening",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -11,6 +11,7 @@ bevy = { version = "0.8", features = ["dynamic"] }
|
||||
bevy-inspector-egui = "0.12.1"
|
||||
bevy_prototype_lyon = "0.6"
|
||||
bevy_tweening = "0.5.0"
|
||||
num-traits = "0.2"
|
||||
|
||||
# Enable a small amount of optimization in debug mode
|
||||
[profile.dev]
|
||||
|
1
src/datatypes.rs
Normal file
1
src/datatypes.rs
Normal file
@ -0,0 +1 @@
|
||||
pub mod angle;
|
154
src/datatypes/angle.rs
Normal file
154
src/datatypes/angle.rs
Normal file
@ -0,0 +1,154 @@
|
||||
use bevy_inspector_egui::Inspectable;
|
||||
use std::ops::{Add, Div, Mul, Neg, Rem, Sub};
|
||||
|
||||
#[derive(Inspectable, Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub enum AngleUnit<T: Default> {
|
||||
Degrees(T),
|
||||
Radians(T),
|
||||
}
|
||||
|
||||
impl<T: Default> Default for AngleUnit<T> {
|
||||
fn default() -> Self {
|
||||
Self::Degrees(Default::default())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Inspectable, Copy, Default, Clone, Debug, PartialEq, Eq)]
|
||||
pub struct Angle<T: Default> {
|
||||
value: AngleUnit<T>,
|
||||
}
|
||||
|
||||
impl<T: Default + Clone + Rem<T, Output = T>> Rem<T> for Angle<T> {
|
||||
type Output = Self;
|
||||
|
||||
fn rem(self, rhs: T) -> Self::Output {
|
||||
match self.value {
|
||||
AngleUnit::Degrees(v) => Self::Output::degrees(v % rhs),
|
||||
AngleUnit::Radians(v) => Self::Output::radians(v % rhs),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Default + Clone + Mul<T, Output = T>> Mul<T> for Angle<T> {
|
||||
type Output = Self;
|
||||
|
||||
fn mul(self, rhs: T) -> Self::Output {
|
||||
match self.value {
|
||||
AngleUnit::Degrees(v) => Self::Output::degrees(v * rhs),
|
||||
AngleUnit::Radians(v) => Self::Output::radians(v * rhs),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Default + Clone + Div<T, Output = T>> Div<T> for Angle<T> {
|
||||
type Output = Self;
|
||||
|
||||
fn div(self, rhs: T) -> Self::Output {
|
||||
match self.value {
|
||||
AngleUnit::Degrees(v) => Self::Output::degrees(v / rhs),
|
||||
AngleUnit::Radians(v) => Self::Output::radians(v / rhs),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Default + Clone + std::ops::Neg<Output = T>> Neg for Angle<T> {
|
||||
type Output = Self;
|
||||
|
||||
fn neg(self) -> Self::Output {
|
||||
match self.value {
|
||||
AngleUnit::Degrees(v) => Self::Output::degrees(-v),
|
||||
AngleUnit::Radians(v) => Self::Output::radians(-v),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Default + Clone + std::ops::Neg<Output = T>> Neg for &Angle<T> {
|
||||
type Output = Angle<T>;
|
||||
|
||||
fn neg(self) -> Self::Output {
|
||||
match self.value.clone() {
|
||||
AngleUnit::Degrees(v) => Self::Output::degrees(-v),
|
||||
AngleUnit::Radians(v) => Self::Output::radians(-v),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Default + Clone> Angle<T> {
|
||||
pub fn degrees(value: T) -> Angle<T> {
|
||||
Self {
|
||||
value: AngleUnit::Degrees(value),
|
||||
}
|
||||
}
|
||||
pub fn radians(value: T) -> Angle<T> {
|
||||
Self {
|
||||
value: AngleUnit::Radians(value),
|
||||
}
|
||||
}
|
||||
pub fn value(&self) -> T {
|
||||
match self.value.clone() {
|
||||
AngleUnit::Degrees(v) => v,
|
||||
AngleUnit::Radians(v) => v,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Default + num_traits::float::Float> Angle<T> {
|
||||
pub fn to_radians(self) -> Self {
|
||||
match self.value {
|
||||
AngleUnit::Degrees(v) => Self {
|
||||
value: AngleUnit::Radians(v.to_radians()),
|
||||
},
|
||||
AngleUnit::Radians(_) => self,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Add<Output = T> + Default + num_traits::float::Float> Add for Angle<T> {
|
||||
type Output = Angle<T>;
|
||||
|
||||
fn add(self, rhs: Self) -> Self::Output {
|
||||
match (self.value, rhs.value) {
|
||||
(AngleUnit::Degrees(v), AngleUnit::Degrees(o)) => Self::Output {
|
||||
value: AngleUnit::Degrees(v + o),
|
||||
},
|
||||
(AngleUnit::Degrees(v), AngleUnit::Radians(o)) => Self::Output {
|
||||
value: AngleUnit::Radians(v.to_radians() + o),
|
||||
},
|
||||
(AngleUnit::Radians(v), AngleUnit::Degrees(o)) => Self::Output {
|
||||
value: AngleUnit::Radians(v + o.to_radians()),
|
||||
},
|
||||
(AngleUnit::Radians(v), AngleUnit::Radians(o)) => Self::Output {
|
||||
value: AngleUnit::Radians(v + o),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Sub<Output = T> + Default + num_traits::float::Float> Sub for Angle<T> {
|
||||
type Output = Angle<T>;
|
||||
|
||||
fn sub(self, rhs: Self) -> Self::Output {
|
||||
match (self.value, rhs.value) {
|
||||
(AngleUnit::Degrees(v), AngleUnit::Degrees(o)) => Self::Output {
|
||||
value: AngleUnit::Degrees(v - o),
|
||||
},
|
||||
(AngleUnit::Degrees(v), AngleUnit::Radians(o)) => Self::Output {
|
||||
value: AngleUnit::Radians(v.to_radians() - o),
|
||||
},
|
||||
(AngleUnit::Radians(v), AngleUnit::Degrees(o)) => Self::Output {
|
||||
value: AngleUnit::Radians(v - o.to_radians()),
|
||||
},
|
||||
(AngleUnit::Radians(v), AngleUnit::Radians(o)) => Self::Output {
|
||||
value: AngleUnit::Radians(v - o),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn convert_to_radians() {
|
||||
let radi = Angle::radians(30f32.to_radians());
|
||||
let degr = Angle::degrees(30f32);
|
||||
let converted = degr.to_radians();
|
||||
assert_eq!(radi, converted)
|
||||
}
|
0
src/datatypes/length.rs
Normal file
0
src/datatypes/length.rs
Normal file
@ -1,3 +1,4 @@
|
||||
mod datatypes;
|
||||
mod debug;
|
||||
mod primitives;
|
||||
mod turtle;
|
||||
|
@ -6,7 +6,7 @@ use bevy_prototype_lyon::{
|
||||
};
|
||||
use bevy_tweening::Lens;
|
||||
|
||||
use crate::turtle::Angle;
|
||||
use crate::datatypes::angle::Angle;
|
||||
|
||||
pub(crate) struct LineAnimationLens {
|
||||
start: Vec2,
|
||||
@ -58,8 +58,8 @@ pub(crate) struct CircleAnimationLens {
|
||||
pub start_pos: Vec2,
|
||||
pub center: Vec2,
|
||||
pub radii: Vec2,
|
||||
pub start: Angle,
|
||||
pub end: Angle,
|
||||
pub start: Angle<f32>,
|
||||
pub end: Angle<f32>,
|
||||
}
|
||||
|
||||
impl Lens<Path> for CircleAnimationLens {
|
||||
@ -70,7 +70,9 @@ impl Lens<Path> for CircleAnimationLens {
|
||||
path_builder.arc(
|
||||
self.center,
|
||||
self.radii,
|
||||
(self.start.0 + ((self.end.0 - self.start.0) * ratio)).to_radians(),
|
||||
(self.start + ((self.end - self.start) * ratio))
|
||||
.to_radians()
|
||||
.value(),
|
||||
0.,
|
||||
);
|
||||
let line = path_builder.build();
|
||||
@ -81,17 +83,17 @@ impl Lens<Path> for CircleAnimationLens {
|
||||
pub(crate) struct CircleMovementLens {
|
||||
pub center: Vec2,
|
||||
pub start: Transform,
|
||||
pub end: Angle,
|
||||
pub end: Angle<f32>,
|
||||
}
|
||||
|
||||
impl Lens<Transform> for CircleMovementLens {
|
||||
fn lerp(&mut self, target: &mut Transform, ratio: f32) {
|
||||
let angle = self.end.0 * ratio;
|
||||
let angle = self.end * ratio;
|
||||
let mut rotated = self.start;
|
||||
|
||||
rotated.rotate_around(
|
||||
self.center.extend(0.),
|
||||
Quat::from_rotation_z(angle.to_radians()),
|
||||
Quat::from_rotation_z(angle.to_radians().value()),
|
||||
);
|
||||
|
||||
*target = rotated;
|
||||
@ -114,7 +116,7 @@ impl TurtleDrawCircle {
|
||||
pub(crate) fn new(
|
||||
center: Vec2,
|
||||
radii: Vec2,
|
||||
angle: Angle,
|
||||
angle: Angle<f32>,
|
||||
index: u64,
|
||||
start: Vec2,
|
||||
end: Vec2,
|
||||
@ -122,7 +124,7 @@ impl TurtleDrawCircle {
|
||||
let mut path_builder = PathBuilder::new();
|
||||
path_builder.move_to(start);
|
||||
// The center point of the radius, then the radii in x and y direction, then the angle that will be drawn, then the x_rotation ?
|
||||
path_builder.arc(center, radii, angle.0.to_radians(), 0.);
|
||||
path_builder.arc(center, radii, angle.to_radians().value(), 0.);
|
||||
|
||||
/* println!("The radiuses: {}", radii);
|
||||
path_builder.move_to(Vec2::ZERO);
|
||||
|
@ -9,6 +9,7 @@ use bevy_tweening::{
|
||||
};
|
||||
|
||||
use crate::{
|
||||
datatypes::angle::Angle,
|
||||
primitives::{CircleAnimationLens, LineAnimationLens, TurtleDrawCircle, TurtleDrawLine},
|
||||
turtle_shapes,
|
||||
};
|
||||
@ -44,19 +45,19 @@ impl Default for Turtle {
|
||||
TurtleCommand::Forward(Length(-100.)),
|
||||
TurtleCommand::Circle {
|
||||
radius: Length(150.),
|
||||
angle: Angle(30.),
|
||||
angle: Angle::degrees(30.),
|
||||
},
|
||||
TurtleCommand::Forward(Length(100.)),
|
||||
TurtleCommand::Circle {
|
||||
radius: Length(70.),
|
||||
angle: Angle(60.),
|
||||
angle: Angle::degrees(60.),
|
||||
},
|
||||
TurtleCommand::Forward(Length(100.)),
|
||||
TurtleCommand::Right(Angle(90.)),
|
||||
TurtleCommand::Right(Angle::degrees(70.)),
|
||||
//TurtleCommand::PenDown,
|
||||
TurtleCommand::Circle {
|
||||
radius: Length(30.),
|
||||
angle: Angle(360. - 46.),
|
||||
angle: Angle::degrees(360. - 46.),
|
||||
},
|
||||
/* TurtleCommand::Backward(Length(100.)),
|
||||
TurtleCommand::Right(Angle(90.)),
|
||||
@ -111,7 +112,7 @@ pub struct TurtleCommands {
|
||||
#[derive(Inspectable)]
|
||||
pub struct TurtleState {
|
||||
pub start: Vec2,
|
||||
pub heading: f32,
|
||||
pub heading: Angle<f32>,
|
||||
pub index: u64,
|
||||
pub drawing: bool,
|
||||
}
|
||||
@ -123,7 +124,7 @@ impl TurtleCommands {
|
||||
lines: vec![],
|
||||
state: TurtleState {
|
||||
start: Vec2::ZERO,
|
||||
heading: 0f32.to_radians(),
|
||||
heading: Angle::degrees(0.),
|
||||
index: 0,
|
||||
drawing: true,
|
||||
},
|
||||
@ -144,11 +145,11 @@ impl TurtleCommands {
|
||||
TurtleCommand::Backward(Length(x)) => {
|
||||
crate::turtle_movement::turtle_move(&mut self.state, -*x as f32)
|
||||
}
|
||||
TurtleCommand::Left(Angle(x)) => {
|
||||
crate::turtle_movement::turtle_turn(&mut self.state, *x as f32)
|
||||
TurtleCommand::Left(angle) => {
|
||||
crate::turtle_movement::turtle_turn(&mut self.state, *angle)
|
||||
}
|
||||
TurtleCommand::Right(Angle(x)) => {
|
||||
crate::turtle_movement::turtle_turn(&mut self.state, -*x as f32)
|
||||
TurtleCommand::Right(angle) => {
|
||||
crate::turtle_movement::turtle_turn(&mut self.state, -angle)
|
||||
}
|
||||
TurtleCommand::PenUp => {
|
||||
self.state.drawing = false;
|
||||
@ -182,7 +183,7 @@ pub enum TurtleGraphElement {
|
||||
end: Vec2,
|
||||
center: Vec2,
|
||||
radii: Vec2,
|
||||
angle: Angle,
|
||||
angle: Angle<f32>,
|
||||
},
|
||||
#[default]
|
||||
Noop,
|
||||
@ -199,22 +200,20 @@ pub struct Colors {
|
||||
|
||||
#[derive(Inspectable, Default, Copy, Clone, Debug)]
|
||||
pub struct Length(f32);
|
||||
#[derive(Inspectable, Default, Copy, Clone, Debug)]
|
||||
pub struct Angle(pub f32);
|
||||
|
||||
#[derive(Component, Inspectable, Default)]
|
||||
pub enum TurtleCommand {
|
||||
Forward(Length),
|
||||
Backward(Length),
|
||||
Left(Angle),
|
||||
Right(Angle),
|
||||
Left(Angle<f32>),
|
||||
Right(Angle<f32>),
|
||||
PenUp,
|
||||
PenDown,
|
||||
#[default]
|
||||
Pause,
|
||||
Circle {
|
||||
radius: Length,
|
||||
angle: Angle,
|
||||
angle: Angle<f32>,
|
||||
},
|
||||
}
|
||||
|
||||
@ -284,7 +283,7 @@ fn draw_lines(
|
||||
start_pos: start,
|
||||
center,
|
||||
radii,
|
||||
start: Angle(0.),
|
||||
start: Angle::degrees(0.),
|
||||
end: angle,
|
||||
},
|
||||
));
|
||||
@ -292,7 +291,7 @@ fn draw_lines(
|
||||
.spawn_bundle(TurtleDrawCircle::new(
|
||||
center,
|
||||
radii,
|
||||
Angle(0.),
|
||||
Angle::degrees(0.),
|
||||
tcmd.state.index,
|
||||
start,
|
||||
end,
|
||||
@ -324,7 +323,7 @@ fn keypresses(
|
||||
let mut tcmd = tcmd.single_mut();
|
||||
tcmd.state = TurtleState {
|
||||
start: Vec2::ZERO,
|
||||
heading: 0.,
|
||||
heading: Angle::degrees(0.),
|
||||
index: 0,
|
||||
drawing: true,
|
||||
};
|
||||
|
@ -7,13 +7,14 @@ use bevy_tweening::{
|
||||
};
|
||||
|
||||
use crate::{
|
||||
datatypes::angle::Angle,
|
||||
primitives::{CircleAnimationLens, CircleMovementLens},
|
||||
turtle::{Angle, TurtleGraphElement, TurtleState},
|
||||
turtle::{TurtleGraphElement, TurtleState},
|
||||
};
|
||||
|
||||
pub fn turtle_turn(
|
||||
state: &mut TurtleState,
|
||||
angle_to_turn: f32,
|
||||
angle_to_turn: Angle<f32>,
|
||||
) -> (Option<Tween<Transform>>, Option<TurtleGraphElement>) {
|
||||
let start = state.heading;
|
||||
let end = state.heading + (angle_to_turn * PI / 180.);
|
||||
@ -24,7 +25,10 @@ pub fn turtle_turn(
|
||||
// Animation time
|
||||
Duration::from_millis(500),
|
||||
// Rotate the turtle
|
||||
TransformRotateZLens { start, end },
|
||||
TransformRotateZLens {
|
||||
start: start.value(),
|
||||
end: end.value(),
|
||||
},
|
||||
)
|
||||
.with_completed_event(state.index as u64);
|
||||
// Dont move and draw
|
||||
@ -39,7 +43,7 @@ pub fn turtle_move(
|
||||
length: f32,
|
||||
) -> (Option<Tween<Transform>>, Option<TurtleGraphElement>) {
|
||||
let start = state.start;
|
||||
let end = state.start + (Vec2::from_angle(state.heading) * length);
|
||||
let end = state.start + (Vec2::from_angle(state.heading.to_radians().value()) * length);
|
||||
let turtle_movement_animation = Tween::new(
|
||||
// accelerate and decelerate
|
||||
EaseFunction::QuadraticInOut,
|
||||
@ -66,14 +70,15 @@ pub fn turtle_move(
|
||||
pub fn turtle_circle(
|
||||
state: &mut TurtleState,
|
||||
radius: f32,
|
||||
angle: Angle,
|
||||
angle: Angle<f32>,
|
||||
) -> (Option<Tween<Transform>>, Option<TurtleGraphElement>) {
|
||||
let radius_tuple = Vec2::ONE * radius.abs();
|
||||
let left_right = if radius >= 0. { 90f32 } else { -90. };
|
||||
println!("Heading: {}", state.heading);
|
||||
let left_right = Angle::degrees(if radius >= 0. { 90. } else { -90. });
|
||||
println!("Heading: {}", state.heading.value());
|
||||
let center = state.start
|
||||
+ (Vec2::new(radius.abs(), 0.)
|
||||
.rotate(Vec2::from_angle(state.heading + left_right.to_radians())));
|
||||
+ (Vec2::new(radius.abs(), 0.).rotate(Vec2::from_angle(
|
||||
(state.heading + left_right.to_radians()).value(),
|
||||
)));
|
||||
|
||||
let turtle_movement_animation = Tween::new(
|
||||
// accelerate and decelerate
|
||||
@ -85,7 +90,7 @@ pub fn turtle_circle(
|
||||
CircleMovementLens {
|
||||
start: Transform {
|
||||
translation: state.start.extend(0.),
|
||||
rotation: Quat::from_rotation_z(state.heading),
|
||||
rotation: Quat::from_rotation_z(state.heading.to_radians().value()),
|
||||
scale: Vec3::ONE,
|
||||
},
|
||||
end: angle,
|
||||
@ -105,6 +110,10 @@ pub fn turtle_circle(
|
||||
} else {
|
||||
TurtleGraphElement::Noop
|
||||
};
|
||||
// TODO update end_position : state.start = end;
|
||||
let end_pos = center
|
||||
+ Vec2::new(radius.abs(), 0.).rotate(Vec2::from_angle(
|
||||
(state.heading + angle).to_radians().value(),
|
||||
));
|
||||
state.start = end_pos;
|
||||
(Some(turtle_movement_animation), Some(line))
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user