use std::ops::Neg; use crate::{ commands::{DrawElement, MoveCommand, TurtleSegment}, general::{angle::Angle, length::Length, Precision}, }; #[derive(Default, Debug)] pub struct TurtlePlan { /** * A turtle Plan contains the segments of a turtle drawing. * The segments in turn contain the commands to draw the graph. */ commands: Vec, } pub trait WithCommands { fn get_mut_commands(&mut self) -> &mut Vec; fn get_commands(self) -> Vec; } impl WithCommands for TurtlePlan { fn get_mut_commands(&mut self) -> &mut Vec { &mut self.commands } fn get_commands(self) -> Vec { self.commands } } impl TurtlePlan { pub fn new() -> TurtlePlan { TurtlePlan { commands: vec![] } } } pub trait DirectionalMovement: WithCommands { fn forward(&mut self, length: IntoDistance) -> &mut Self where Length: From, { let length: Length = length.into(); self.get_mut_commands() .push(TurtleSegment::Single(DrawElement::Draw( crate::commands::MoveCommand::Forward(length), ))); self } fn backward(&mut self, length: IntoDistance) -> &mut Self where Length: From, { let length: Length = length.into(); self.get_mut_commands() .push(TurtleSegment::Single(DrawElement::Draw( crate::commands::MoveCommand::Backward(length), ))); self } } impl DirectionalMovement for TurtlePlan {} pub trait Turnable: WithCommands { fn right(&mut self, angle: IntoAngle) -> &mut Self where Angle: From, { let angle: Angle = angle.into(); self.get_mut_commands() .push(TurtleSegment::Single(DrawElement::Orient( crate::commands::OrientationCommand::Right(angle), ))); self } fn left(&mut self, angle: IntoAngle) -> &mut Self where Angle: From, { let angle: Angle = angle.into(); self.get_mut_commands() .push(TurtleSegment::Single(DrawElement::Orient( crate::commands::OrientationCommand::Left(angle), ))); self } } impl Turnable for TurtlePlan {} pub trait CurvedMovement: WithCommands { fn circle( &mut self, radius: IntoDistance, extend: IntoAngle, ) -> &mut Self where Angle: From, Length: From, { let angle: Angle = extend.into(); let radius: Length = radius.into(); self.get_mut_commands() .push(TurtleSegment::Single(DrawElement::Draw( MoveCommand::Circle { radius, angle }, ))); self } fn circle_right>( &mut self, radius: IntoDistance, extend: IntoAngle, ) -> &mut Self where Angle: From, Length: From, { self.circle(-radius, extend); println!("Warning: circle with right arc not working yet..."); self } } impl CurvedMovement for TurtlePlan {} pub trait StopLine where T: WithCommands, { fn pen_up(self) -> InvisibleLinesPlan; } impl StopLine for TurtlePlan { fn pen_up(self) -> InvisibleLinesPlan { { InvisibleLinesPlan { before: self, commands: vec![], } } } } pub trait StartLine { fn pen_down(self) -> T; } impl StartLine for InvisibleLinesPlan where T: WithCommands, { fn pen_down(mut self) -> T { self.before.get_mut_commands().append(&mut self.commands); self.before } } pub struct InvisibleLinesPlan { before: T, commands: Vec, } impl WithCommands for InvisibleLinesPlan where T: WithCommands, { fn get_mut_commands(&mut self) -> &mut Vec { &mut self.commands } fn get_commands(self) -> Vec { self.commands } } impl InvisibleLinesPlan where T: WithCommands, { pub fn new(before: T) -> Self { InvisibleLinesPlan { before, commands: vec![], } } } impl Turnable for InvisibleLinesPlan {} impl DirectionalMovement for InvisibleLinesPlan where T: WithCommands, { fn forward(&mut self, length: IntoDistance) -> &mut Self where Length: From, { let length: Length = length.into(); self.get_mut_commands() .push(TurtleSegment::Single(DrawElement::Move( crate::commands::MoveCommand::Forward(length), ))); self } fn backward(&mut self, length: IntoDistance) -> &mut Self where Length: From, { let length: Length = length.into(); self.get_mut_commands() .push(TurtleSegment::Single(DrawElement::Move( crate::commands::MoveCommand::Backward(length), ))); self } } impl CurvedMovement for InvisibleLinesPlan where T: WithCommands, { fn circle( &mut self, radius: IntoDistance, extend: IntoAngle, ) -> &mut Self where Angle: From, Length: From, { let angle: Angle = extend.into(); let radius: Length = radius.into(); self.get_mut_commands() .push(TurtleSegment::Single(DrawElement::Move( MoveCommand::Circle { radius, angle }, ))); self } fn circle_right>( &mut self, radius: IntoDistance, extend: IntoAngle, ) -> &mut Self where Angle: From, Length: From, { self.circle(-radius, extend); println!("Warning: circle with right arc not working yet..."); self } }