refactor for simpler circle command and removed duplicated code
This commit is contained in:
parent
25753b47ce
commit
7da0dcf141
@ -61,10 +61,11 @@ pub trait CurvedMovement: WithCommands {
|
||||
{
|
||||
let r: Precision = radius.into();
|
||||
let a: Precision = angle.into();
|
||||
self.get_commands_mut().push(TurtleCommand::CircleLeft {
|
||||
self.get_commands_mut().push(TurtleCommand::Circle {
|
||||
radius: r,
|
||||
angle: a,
|
||||
steps,
|
||||
direction: crate::circle_geometry::CircleDirection::Left,
|
||||
});
|
||||
self
|
||||
}
|
||||
@ -76,10 +77,11 @@ pub trait CurvedMovement: WithCommands {
|
||||
{
|
||||
let r: Precision = radius.into();
|
||||
let a: Precision = angle.into();
|
||||
self.get_commands_mut().push(TurtleCommand::CircleRight {
|
||||
self.get_commands_mut().push(TurtleCommand::Circle {
|
||||
radius: r,
|
||||
angle: a,
|
||||
steps,
|
||||
direction: crate::circle_geometry::CircleDirection::Right,
|
||||
});
|
||||
self
|
||||
}
|
||||
|
||||
@ -15,15 +15,11 @@ pub enum TurtleCommand {
|
||||
Right(Precision), // degrees
|
||||
|
||||
// Circle drawing
|
||||
CircleLeft {
|
||||
radius: Precision,
|
||||
angle: Precision, // degrees
|
||||
steps: usize,
|
||||
},
|
||||
CircleRight {
|
||||
Circle {
|
||||
radius: Precision,
|
||||
angle: Precision, // degrees
|
||||
steps: usize,
|
||||
direction: crate::circle_geometry::CircleDirection,
|
||||
},
|
||||
|
||||
// Pen control
|
||||
|
||||
@ -144,21 +144,14 @@ pub(crate) fn render_world_with_tween(
|
||||
if let Some(tween) = active_tween {
|
||||
if tween.start_state.pen_down {
|
||||
match &tween.command {
|
||||
crate::commands::TurtleCommand::CircleLeft {
|
||||
crate::commands::TurtleCommand::Circle {
|
||||
radius,
|
||||
angle,
|
||||
steps,
|
||||
direction,
|
||||
} => {
|
||||
// Draw arc segments from start to current position
|
||||
draw_tween_arc_left(tween, *radius, *angle, *steps);
|
||||
}
|
||||
crate::commands::TurtleCommand::CircleRight {
|
||||
radius,
|
||||
angle,
|
||||
steps,
|
||||
} => {
|
||||
// Draw arc segments from start to current position
|
||||
draw_tween_arc_right(tween, *radius, *angle, *steps);
|
||||
draw_tween_arc(tween, *radius, *angle, *steps, *direction);
|
||||
}
|
||||
_ if should_draw_tween_line(&tween.command) => {
|
||||
// Draw straight line for other movement commands
|
||||
@ -200,59 +193,19 @@ fn should_draw_tween_line(command: &crate::commands::TurtleCommand) -> bool {
|
||||
)
|
||||
}
|
||||
|
||||
/// Draw arc segments for circle_left tween animation
|
||||
fn draw_tween_arc_left(
|
||||
/// Draw arc segments for circle tween animation
|
||||
fn draw_tween_arc(
|
||||
tween: &crate::tweening::CommandTween,
|
||||
radius: f32,
|
||||
total_angle: f32,
|
||||
steps: usize,
|
||||
direction: CircleDirection,
|
||||
) {
|
||||
let geom = CircleGeometry::new(
|
||||
tween.start_state.position,
|
||||
tween.start_state.heading,
|
||||
radius,
|
||||
CircleDirection::Left,
|
||||
);
|
||||
|
||||
// Debug: draw center
|
||||
draw_circle(geom.center.x, geom.center.y, 5.0, GRAY);
|
||||
|
||||
// Calculate how much of the arc we've traveled based on tween progress
|
||||
// Use the same eased progress as the turtle position for synchronized animation
|
||||
let elapsed = (get_time() - tween.start_time) as f32;
|
||||
let t = (elapsed / tween.duration as f32).min(1.0);
|
||||
let progress = CubicInOut.tween(1.0, t); // tween from 0 to 1
|
||||
let angle_traveled = total_angle.to_radians() * progress;
|
||||
let (rotation_degrees, arc_degrees) = geom.draw_arc_params_partial(angle_traveled);
|
||||
|
||||
// Adjust radius inward by half the line width so the line sits on the turtle's path
|
||||
let draw_radius = radius - tween.start_state.pen_width / 2.0;
|
||||
|
||||
// Draw the partial arc
|
||||
draw_arc(
|
||||
geom.center.x,
|
||||
geom.center.y,
|
||||
steps as u8,
|
||||
draw_radius,
|
||||
rotation_degrees,
|
||||
tween.start_state.pen_width,
|
||||
arc_degrees,
|
||||
tween.start_state.color,
|
||||
);
|
||||
}
|
||||
|
||||
/// Draw arc segments for circle_right tween animation
|
||||
fn draw_tween_arc_right(
|
||||
tween: &crate::tweening::CommandTween,
|
||||
radius: f32,
|
||||
total_angle: f32,
|
||||
steps: usize,
|
||||
) {
|
||||
let geom = CircleGeometry::new(
|
||||
tween.start_state.position,
|
||||
tween.start_state.heading,
|
||||
radius,
|
||||
CircleDirection::Right,
|
||||
direction,
|
||||
);
|
||||
|
||||
// Debug: draw center
|
||||
|
||||
@ -62,18 +62,14 @@ pub fn execute_command(command: &TurtleCommand, state: &mut TurtleState, world:
|
||||
state.heading += degrees.to_radians();
|
||||
}
|
||||
|
||||
TurtleCommand::CircleLeft {
|
||||
TurtleCommand::Circle {
|
||||
radius,
|
||||
angle,
|
||||
steps,
|
||||
direction,
|
||||
} => {
|
||||
let start_heading = state.heading;
|
||||
let geom = CircleGeometry::new(
|
||||
state.position,
|
||||
start_heading,
|
||||
*radius,
|
||||
CircleDirection::Left,
|
||||
);
|
||||
let geom = CircleGeometry::new(state.position, start_heading, *radius, *direction);
|
||||
|
||||
if state.pen_down {
|
||||
let (rotation_degrees, arc_degrees) = geom.draw_arc_params(*angle);
|
||||
@ -91,39 +87,10 @@ pub fn execute_command(command: &TurtleCommand, state: &mut TurtleState, world:
|
||||
|
||||
// Update turtle position and heading
|
||||
state.position = geom.position_at_angle(angle.to_radians());
|
||||
state.heading = start_heading - angle.to_radians();
|
||||
}
|
||||
|
||||
TurtleCommand::CircleRight {
|
||||
radius,
|
||||
angle,
|
||||
steps,
|
||||
} => {
|
||||
let start_heading = state.heading;
|
||||
let geom = CircleGeometry::new(
|
||||
state.position,
|
||||
start_heading,
|
||||
*radius,
|
||||
CircleDirection::Right,
|
||||
);
|
||||
|
||||
if state.pen_down {
|
||||
let (rotation_degrees, arc_degrees) = geom.draw_arc_params(*angle);
|
||||
|
||||
world.add_command(DrawCommand::Arc {
|
||||
center: geom.center,
|
||||
radius: *radius - state.pen_width, // Adjust radius for pen width to keep arc inside
|
||||
rotation: rotation_degrees,
|
||||
arc: arc_degrees,
|
||||
color: state.color,
|
||||
width: state.pen_width,
|
||||
sides: *steps as u8,
|
||||
});
|
||||
}
|
||||
|
||||
// Update turtle position and heading
|
||||
state.position = geom.position_at_angle(angle.to_radians());
|
||||
state.heading = start_heading + angle.to_radians();
|
||||
state.heading = match direction {
|
||||
CircleDirection::Left => start_heading - angle.to_radians(),
|
||||
CircleDirection::Right => start_heading + angle.to_radians(),
|
||||
};
|
||||
}
|
||||
|
||||
TurtleCommand::PenUp => {
|
||||
@ -225,56 +192,18 @@ pub fn add_draw_for_completed_tween(
|
||||
});
|
||||
}
|
||||
}
|
||||
TurtleCommand::CircleLeft {
|
||||
TurtleCommand::Circle {
|
||||
radius,
|
||||
angle,
|
||||
steps,
|
||||
direction,
|
||||
} => {
|
||||
if start_state.pen_down {
|
||||
let geom = CircleGeometry::new(
|
||||
start_state.position,
|
||||
start_state.heading,
|
||||
*radius,
|
||||
CircleDirection::Left,
|
||||
);
|
||||
let (rotation_degrees, arc_degrees) = geom.draw_arc_params(*angle);
|
||||
|
||||
world.add_command(DrawCommand::Arc {
|
||||
center: geom.center,
|
||||
radius: *radius - start_state.pen_width / 2.0,
|
||||
rotation: rotation_degrees,
|
||||
arc: arc_degrees,
|
||||
color: start_state.color,
|
||||
width: start_state.pen_width,
|
||||
sides: *steps as u8,
|
||||
});
|
||||
|
||||
// Add endpoint circles for smooth joins
|
||||
world.add_command(DrawCommand::Circle {
|
||||
center: start_state.position,
|
||||
radius: start_state.pen_width / 2.0,
|
||||
color: start_state.color,
|
||||
filled: true,
|
||||
});
|
||||
world.add_command(DrawCommand::Circle {
|
||||
center: end_state.position,
|
||||
radius: start_state.pen_width / 2.0,
|
||||
color: start_state.color,
|
||||
filled: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
TurtleCommand::CircleRight {
|
||||
radius,
|
||||
angle,
|
||||
steps,
|
||||
} => {
|
||||
if start_state.pen_down {
|
||||
let geom = CircleGeometry::new(
|
||||
start_state.position,
|
||||
start_state.heading,
|
||||
*radius,
|
||||
CircleDirection::Right,
|
||||
*direction,
|
||||
);
|
||||
let (rotation_degrees, arc_degrees) = geom.draw_arc_params(*angle);
|
||||
|
||||
|
||||
@ -84,22 +84,19 @@ impl TweenController {
|
||||
let progress = tween.heading_tweener.move_to(elapsed);
|
||||
|
||||
state.position = match &tween.command {
|
||||
TurtleCommand::CircleLeft { radius, angle, .. } => {
|
||||
TurtleCommand::Circle {
|
||||
radius,
|
||||
angle,
|
||||
direction,
|
||||
..
|
||||
} => {
|
||||
let angle_traveled = angle.to_radians() * progress;
|
||||
calculate_circle_left_position(
|
||||
tween.start_state.position,
|
||||
tween.start_state.heading,
|
||||
*radius,
|
||||
angle_traveled,
|
||||
)
|
||||
}
|
||||
TurtleCommand::CircleRight { radius, angle, .. } => {
|
||||
let angle_traveled = angle.to_radians() * progress;
|
||||
calculate_circle_right_position(
|
||||
calculate_circle_position(
|
||||
tween.start_state.position,
|
||||
tween.start_state.heading,
|
||||
*radius,
|
||||
angle_traveled,
|
||||
*direction,
|
||||
)
|
||||
}
|
||||
_ => {
|
||||
@ -110,12 +107,16 @@ impl TweenController {
|
||||
|
||||
// Heading changes proportionally with progress for all commands
|
||||
state.heading = match &tween.command {
|
||||
TurtleCommand::CircleLeft { angle, .. } => {
|
||||
TurtleCommand::Circle {
|
||||
angle, direction, ..
|
||||
} => match direction {
|
||||
CircleDirection::Left => {
|
||||
tween.start_state.heading - angle.to_radians() * progress
|
||||
}
|
||||
TurtleCommand::CircleRight { angle, .. } => {
|
||||
CircleDirection::Right => {
|
||||
tween.start_state.heading + angle.to_radians() * progress
|
||||
}
|
||||
},
|
||||
TurtleCommand::Left(angle) => {
|
||||
tween.start_state.heading - angle.to_radians() * progress
|
||||
}
|
||||
@ -219,8 +220,7 @@ impl TweenController {
|
||||
command,
|
||||
TurtleCommand::Forward(_)
|
||||
| TurtleCommand::Backward(_)
|
||||
| TurtleCommand::CircleLeft { .. }
|
||||
| TurtleCommand::CircleRight { .. }
|
||||
| TurtleCommand::Circle { .. }
|
||||
| TurtleCommand::Goto(_)
|
||||
)
|
||||
}
|
||||
@ -234,8 +234,7 @@ impl TweenController {
|
||||
// Rotation speed: assume 180 degrees per second at speed 100
|
||||
angle.abs() / (speed * 1.8)
|
||||
}
|
||||
TurtleCommand::CircleLeft { radius, angle, .. }
|
||||
| TurtleCommand::CircleRight { radius, angle, .. } => {
|
||||
TurtleCommand::Circle { radius, angle, .. } => {
|
||||
let arc_length = radius * angle.to_radians().abs();
|
||||
arc_length / speed
|
||||
}
|
||||
@ -272,25 +271,24 @@ impl TweenController {
|
||||
TurtleCommand::Right(angle) => {
|
||||
target.heading += angle.to_radians();
|
||||
}
|
||||
TurtleCommand::CircleLeft { radius, angle, .. } => {
|
||||
TurtleCommand::Circle {
|
||||
radius,
|
||||
angle,
|
||||
direction,
|
||||
..
|
||||
} => {
|
||||
// Use helper function to calculate final position
|
||||
target.position = calculate_circle_left_position(
|
||||
target.position = calculate_circle_position(
|
||||
current.position,
|
||||
current.heading,
|
||||
*radius,
|
||||
angle.to_radians(),
|
||||
*direction,
|
||||
);
|
||||
target.heading = current.heading - angle.to_radians();
|
||||
}
|
||||
TurtleCommand::CircleRight { radius, angle, .. } => {
|
||||
// Use helper function to calculate final position
|
||||
target.position = calculate_circle_right_position(
|
||||
current.position,
|
||||
current.heading,
|
||||
*radius,
|
||||
angle.to_radians(),
|
||||
);
|
||||
target.heading = current.heading + angle.to_radians();
|
||||
target.heading = match direction {
|
||||
CircleDirection::Left => current.heading - angle.to_radians(),
|
||||
CircleDirection::Right => current.heading + angle.to_radians(),
|
||||
};
|
||||
}
|
||||
TurtleCommand::Goto(coord) => {
|
||||
target.position = *coord;
|
||||
@ -331,24 +329,14 @@ impl TweenController {
|
||||
}
|
||||
}
|
||||
|
||||
/// Calculate position on a circular arc for circle_left
|
||||
fn calculate_circle_left_position(
|
||||
/// Calculate position on a circular arc
|
||||
fn calculate_circle_position(
|
||||
start_pos: Vec2,
|
||||
start_heading: f32,
|
||||
radius: f32,
|
||||
angle_traveled: f32, // How much of the total angle we've traveled (in radians)
|
||||
direction: CircleDirection,
|
||||
) -> Vec2 {
|
||||
let geom = CircleGeometry::new(start_pos, start_heading, radius, CircleDirection::Left);
|
||||
geom.position_at_angle(angle_traveled)
|
||||
}
|
||||
|
||||
/// Calculate position on a circular arc for circle_right
|
||||
fn calculate_circle_right_position(
|
||||
start_pos: Vec2,
|
||||
start_heading: f32,
|
||||
radius: f32,
|
||||
angle_traveled: f32, // How much of the total angle we've traveled (in radians)
|
||||
) -> Vec2 {
|
||||
let geom = CircleGeometry::new(start_pos, start_heading, radius, CircleDirection::Right);
|
||||
let geom = CircleGeometry::new(start_pos, start_heading, radius, direction);
|
||||
geom.position_at_angle(angle_traveled)
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user