Add circle drawing
This commit is contained in:
parent
043e44b7f2
commit
75771e8556
@ -1,5 +1,7 @@
|
|||||||
|
use std::ops::Neg;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
commands::{DrawElement, TurtleSegment},
|
commands::{DrawElement, MoveCommand, TurtleSegment},
|
||||||
general::{angle::Angle, length::Length, Precision},
|
general::{angle::Angle, length::Length, Precision},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -82,3 +84,38 @@ pub trait Turnable: WithCommands {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Turnable for TurtlePlan {}
|
impl Turnable for TurtlePlan {}
|
||||||
|
|
||||||
|
pub trait CurvedMovement: WithCommands {
|
||||||
|
fn circle<IntoAngle, IntoDistance>(
|
||||||
|
&mut self,
|
||||||
|
radius: IntoDistance,
|
||||||
|
extend: IntoAngle,
|
||||||
|
) -> &mut Self
|
||||||
|
where
|
||||||
|
Angle<Precision>: From<IntoAngle>,
|
||||||
|
Length: From<IntoDistance>,
|
||||||
|
{
|
||||||
|
let angle: Angle<Precision> = extend.into();
|
||||||
|
let radius: Length = radius.into();
|
||||||
|
self.get_mut_commands()
|
||||||
|
.push(TurtleSegment::Single(DrawElement::Draw(
|
||||||
|
MoveCommand::Circle { radius, angle },
|
||||||
|
)));
|
||||||
|
self
|
||||||
|
}
|
||||||
|
fn circle_right<IntoAngle, IntoDistance: Neg + Neg<Output = IntoDistance>>(
|
||||||
|
&mut self,
|
||||||
|
radius: IntoDistance,
|
||||||
|
extend: IntoAngle,
|
||||||
|
) -> &mut Self
|
||||||
|
where
|
||||||
|
Angle<Precision>: From<IntoAngle>,
|
||||||
|
Length: From<IntoDistance>,
|
||||||
|
{
|
||||||
|
self.circle(-radius, extend);
|
||||||
|
println!("Warning: circle with right arc not working yet...");
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CurvedMovement for TurtlePlan {}
|
||||||
|
|||||||
@ -2,11 +2,11 @@ use bevy::prelude::Component;
|
|||||||
use bevy_inspector_egui::Inspectable;
|
use bevy_inspector_egui::Inspectable;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
builders::WithCommands,
|
||||||
drawing::{
|
drawing::{
|
||||||
self,
|
|
||||||
animation::{
|
animation::{
|
||||||
draw_straight_segment, move_straight_segment, turtle_turn, ToAnimationSegment,
|
draw_circle_segment, draw_straight_segment, move_straight_segment, turtle_turn,
|
||||||
TurtleAnimationSegment,
|
ToAnimationSegment, TurtleAnimationSegment,
|
||||||
},
|
},
|
||||||
TurtleGraphElement,
|
TurtleGraphElement,
|
||||||
},
|
},
|
||||||
@ -80,7 +80,9 @@ impl ToAnimationSegment for DrawElement {
|
|||||||
DrawElement::Draw(e) => match e {
|
DrawElement::Draw(e) => match e {
|
||||||
MoveCommand::Forward(length) => draw_straight_segment(state, length.0),
|
MoveCommand::Forward(length) => draw_straight_segment(state, length.0),
|
||||||
MoveCommand::Backward(length) => draw_straight_segment(state, -length.0),
|
MoveCommand::Backward(length) => draw_straight_segment(state, -length.0),
|
||||||
MoveCommand::Circle { radius, angle } => todo!(),
|
MoveCommand::Circle { radius, angle } => {
|
||||||
|
draw_circle_segment(state, *radius, *angle)
|
||||||
|
}
|
||||||
MoveCommand::Goto(coord) => todo!(),
|
MoveCommand::Goto(coord) => todo!(),
|
||||||
},
|
},
|
||||||
DrawElement::Move(e) => match e {
|
DrawElement::Move(e) => match e {
|
||||||
@ -170,3 +172,13 @@ impl Iterator for TurtleCommands {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl WithCommands for TurtleCommands {
|
||||||
|
fn get_mut_commands(&mut self) -> &mut Vec<TurtleSegment> {
|
||||||
|
&mut self.commands
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_commands(self) -> Vec<TurtleSegment> {
|
||||||
|
self.commands
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -1,18 +1,15 @@
|
|||||||
mod circle_lens;
|
mod circle_lens;
|
||||||
mod line_lens;
|
mod line_lens;
|
||||||
|
|
||||||
use bevy::{
|
use bevy::prelude::{Quat, Transform, Vec2, Vec3};
|
||||||
prelude::{Quat, Transform, Vec2, Vec3},
|
|
||||||
render::render_resource::encase::rts_array::Length,
|
|
||||||
};
|
|
||||||
use bevy_prototype_lyon::prelude::Path;
|
use bevy_prototype_lyon::prelude::Path;
|
||||||
use bevy_tweening::{
|
use bevy_tweening::{
|
||||||
lens::{TransformPositionLens, TransformRotateZLens},
|
lens::{TransformPositionLens, TransformRotateZLens},
|
||||||
Animator, EaseFunction, RepeatCount, RepeatStrategy, Tween,
|
Animator, EaseFunction, Tween,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
general::{angle::Angle, Coordinate, Precision},
|
general::{angle::Angle, length::Length, Coordinate, Precision},
|
||||||
state::TurtleState,
|
state::TurtleState,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -85,9 +82,25 @@ pub fn draw_straight_segment(state: &mut TurtleState, length: Precision) -> Turt
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn draw_circle_segment(
|
||||||
|
state: &mut TurtleState,
|
||||||
|
radius: Length,
|
||||||
|
angle: Angle<Precision>,
|
||||||
|
) -> TurtleAnimationSegment {
|
||||||
|
let animation = MoveCircleTurtleAnimation::new(state, radius, angle);
|
||||||
|
let line_animation = MoveCircleLineAnimation::new(state, radius, angle);
|
||||||
|
state.set_position(animation.end);
|
||||||
|
state.set_heading(animation.end_heading);
|
||||||
|
TurtleAnimationSegment {
|
||||||
|
turtle_animation: Some(animation.animation),
|
||||||
|
line_segment: Some(TurtleGraphElement::TurtleCircle(line_animation.line)),
|
||||||
|
line_animation: Some(Animator::new(line_animation.animation)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct MoveStraightLineAnimation {
|
struct MoveStraightLineAnimation {
|
||||||
start: Coordinate,
|
_start: Coordinate,
|
||||||
end: Coordinate,
|
_end: Coordinate,
|
||||||
line: TurtleDrawLine,
|
line: TurtleDrawLine,
|
||||||
animation: Tween<Path>,
|
animation: Tween<Path>,
|
||||||
}
|
}
|
||||||
@ -95,7 +108,7 @@ struct MoveStraightLineAnimation {
|
|||||||
impl MoveStraightLineAnimation {
|
impl MoveStraightLineAnimation {
|
||||||
fn new(
|
fn new(
|
||||||
state: &TurtleState,
|
state: &TurtleState,
|
||||||
length: Precision,
|
_length: Precision,
|
||||||
turtle_animation: &MoveStraightTurtleAnimation,
|
turtle_animation: &MoveStraightTurtleAnimation,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let line = TurtleDrawLine::new(turtle_animation.start, turtle_animation.end);
|
let line = TurtleDrawLine::new(turtle_animation.start, turtle_animation.end);
|
||||||
@ -107,8 +120,8 @@ impl MoveStraightLineAnimation {
|
|||||||
/* .with_repeat_strategy(RepeatStrategy::MirroredRepeat)
|
/* .with_repeat_strategy(RepeatStrategy::MirroredRepeat)
|
||||||
.with_repeat_count(RepeatCount::Infinite)*/;
|
.with_repeat_count(RepeatCount::Infinite)*/;
|
||||||
Self {
|
Self {
|
||||||
start: turtle_animation.start,
|
_start: turtle_animation.start,
|
||||||
end: turtle_animation.end,
|
_end: turtle_animation.end,
|
||||||
line,
|
line,
|
||||||
animation: line_animation,
|
animation: line_animation,
|
||||||
}
|
}
|
||||||
@ -142,18 +155,69 @@ impl MoveStraightTurtleAnimation {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn turtle_circle(
|
struct MoveCircleLineAnimation {
|
||||||
state: &mut TurtleState,
|
_start: Coordinate,
|
||||||
radius: Precision,
|
_end: Coordinate,
|
||||||
angle: Angle<Precision>,
|
line: TurtleDrawCircle,
|
||||||
) -> TurtleAnimationSegment {
|
animation: Tween<Path>,
|
||||||
let radii = Vec2::ONE * radius.abs();
|
}
|
||||||
let left_right = Angle::degrees(if radius >= 0. { 90. } else { -90. });
|
|
||||||
|
impl MoveCircleLineAnimation {
|
||||||
|
fn new(state: &TurtleState, radius: Length, angle: Angle<Precision>) -> Self {
|
||||||
|
let radii = Vec2::ONE * radius.0.abs();
|
||||||
|
let start = state.position();
|
||||||
|
let left_right = Angle::degrees(if radius.0 >= 0. { 90. } else { -90. });
|
||||||
let center = state.position()
|
let center = state.position()
|
||||||
+ (Vec2::new(radius.abs(), 0.).rotate(Vec2::from_angle(
|
+ (Vec2::new(radius.0.abs(), 0.).rotate(Vec2::from_angle(
|
||||||
((state.heading() + left_right).to_radians()).value(),
|
((state.heading() + left_right).to_radians()).value(),
|
||||||
)));
|
)));
|
||||||
|
let end_pos = center
|
||||||
|
+ Vec2::new(radius.0.abs(), 0.).rotate(Vec2::from_angle(
|
||||||
|
(state.heading() + angle - left_right).to_radians().value(),
|
||||||
|
));
|
||||||
|
|
||||||
|
let line =
|
||||||
|
TurtleDrawCircle::new(center, radii, Angle::degrees(0.), state.position(), end_pos);
|
||||||
|
let line_animator = Tween::new(
|
||||||
|
EaseFunction::QuadraticInOut,
|
||||||
|
state.animation_duration(),
|
||||||
|
CircleAnimationLens {
|
||||||
|
start_pos: state.position(),
|
||||||
|
center,
|
||||||
|
radii,
|
||||||
|
start: Angle::degrees(0.),
|
||||||
|
end: if radius.0 > 0. { angle } else { -angle },
|
||||||
|
},
|
||||||
|
);
|
||||||
|
Self {
|
||||||
|
_start: start,
|
||||||
|
_end: end_pos,
|
||||||
|
line,
|
||||||
|
animation: line_animator,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct MoveCircleTurtleAnimation {
|
||||||
|
_start: Coordinate,
|
||||||
|
end: Coordinate,
|
||||||
|
end_heading: Angle<Precision>,
|
||||||
|
animation: Tween<Transform>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MoveCircleTurtleAnimation {
|
||||||
|
fn new(state: &TurtleState, radius: Length, angle: Angle<Precision>) -> Self {
|
||||||
|
let start = state.position();
|
||||||
|
let left_right = Angle::degrees(if radius.0 >= 0. { 90. } else { -90. });
|
||||||
|
let center = state.position()
|
||||||
|
+ (Vec2::new(radius.0.abs(), 0.).rotate(Vec2::from_angle(
|
||||||
|
((state.heading() + left_right).to_radians()).value(),
|
||||||
|
)));
|
||||||
|
let end_heading = state.heading() + if radius.0 > 0. { angle } else { -angle };
|
||||||
|
let end_pos = center
|
||||||
|
+ Vec2::new(radius.0.abs(), 0.).rotate(Vec2::from_angle(
|
||||||
|
(state.heading() + angle - left_right).to_radians().value(),
|
||||||
|
));
|
||||||
let turtle_movement_animation = Tween::new(
|
let turtle_movement_animation = Tween::new(
|
||||||
EaseFunction::QuadraticInOut,
|
EaseFunction::QuadraticInOut,
|
||||||
state.animation_duration(),
|
state.animation_duration(),
|
||||||
@ -163,42 +227,16 @@ pub fn turtle_circle(
|
|||||||
rotation: Quat::from_rotation_z(state.heading().to_radians().value()),
|
rotation: Quat::from_rotation_z(state.heading().to_radians().value()),
|
||||||
scale: Vec3::ONE,
|
scale: Vec3::ONE,
|
||||||
},
|
},
|
||||||
end: angle,
|
end: if radius.0 > 0. { angle } else { -angle },
|
||||||
center,
|
center,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.with_completed_event(state.segment_index());
|
.with_completed_event(state.segment_index() as u64);
|
||||||
let end_pos = center
|
Self {
|
||||||
+ Vec2::new(radius.abs(), 0.).rotate(Vec2::from_angle(
|
_start: start,
|
||||||
(state.heading() + angle - left_right).to_radians().value(),
|
end: end_pos,
|
||||||
));
|
end_heading,
|
||||||
let line = /* if state.drawing { */
|
animation: turtle_movement_animation,
|
||||||
TurtleGraphElement::TurtleCircle(TurtleDrawCircle::new(
|
}
|
||||||
center,
|
|
||||||
radii,
|
|
||||||
Angle::degrees(0.),
|
|
||||||
state.position(),
|
|
||||||
end_pos,
|
|
||||||
))
|
|
||||||
/* } else {
|
|
||||||
TurtleGraphElement::Noop
|
|
||||||
} */;
|
|
||||||
let line_animator = Animator::new(Tween::new(
|
|
||||||
EaseFunction::QuadraticInOut,
|
|
||||||
state.animation_duration(),
|
|
||||||
CircleAnimationLens {
|
|
||||||
start_pos: state.position(),
|
|
||||||
center,
|
|
||||||
radii,
|
|
||||||
start: Angle::degrees(0.),
|
|
||||||
end: angle,
|
|
||||||
},
|
|
||||||
));
|
|
||||||
state.set_position(end_pos);
|
|
||||||
state.set_heading(state.heading() + angle);
|
|
||||||
TurtleAnimationSegment {
|
|
||||||
turtle_animation: Some(turtle_movement_animation),
|
|
||||||
line_segment: Some(line),
|
|
||||||
line_animation: Some(line_animator),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,3 +10,10 @@ impl From<i16> for Length {
|
|||||||
Self(Precision::from(i))
|
Self(Precision::from(i))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<f32> for Length {
|
||||||
|
fn from(i: f32) -> Self {
|
||||||
|
#[allow(clippy::useless_conversion)]
|
||||||
|
Self(Precision::from(i))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -7,9 +7,9 @@ use bevy_prototype_lyon::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
builders::{TurtlePlan, WithCommands},
|
builders::{CurvedMovement, DirectionalMovement, Turnable, TurtlePlan, WithCommands},
|
||||||
commands::{DrawElement, MoveCommand, TurtleCommands, TurtleSegment},
|
commands::{TurtleCommands, TurtleSegment},
|
||||||
general::{length::Length, Speed},
|
general::Speed,
|
||||||
shapes::{self, TurtleColors},
|
shapes::{self, TurtleColors},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -52,12 +52,6 @@ impl TurtleBundle {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl TurtleBundle {
|
impl TurtleBundle {
|
||||||
pub fn forward(&mut self, len: f32) -> &mut Self {
|
|
||||||
self.commands.push(TurtleSegment::Single(DrawElement::Draw(
|
|
||||||
MoveCommand::Forward(Length(len)),
|
|
||||||
)));
|
|
||||||
self
|
|
||||||
}
|
|
||||||
pub fn set_speed(&mut self, speed: Speed) {
|
pub fn set_speed(&mut self, speed: Speed) {
|
||||||
self.commands.set_speed(speed);
|
self.commands.set_speed(speed);
|
||||||
}
|
}
|
||||||
@ -83,3 +77,17 @@ impl DerefMut for AnimatedTurtle {
|
|||||||
&mut self.turtle_bundle
|
&mut self.turtle_bundle
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl WithCommands for TurtleBundle {
|
||||||
|
fn get_mut_commands(&mut self) -> &mut Vec<TurtleSegment> {
|
||||||
|
self.commands.get_mut_commands()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_commands(self) -> Vec<TurtleSegment> {
|
||||||
|
self.commands.get_commands()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DirectionalMovement for TurtleBundle {}
|
||||||
|
impl Turnable for TurtleBundle {}
|
||||||
|
impl CurvedMovement for TurtleBundle {}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user