Fix Timing Clocks Divergence
Fixed the timing clock divergence between [tweening.rs](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/tweening.rs) and [drawing.rs](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/drawing.rs) by delegating animation progress evaluation exclusively to `TweenController`. `current_time()` in `tweening.rs` was using a monotonic `Instant` epoch (to support headless execution and unit tests without panicking on missing Macroquad context), while `drawing.rs` was measuring progress via `macroquad::time::get_time() - tween.start_time`. Because these two clocks operate on completely different epochs, subtracting them caused negative elapsed times, premature clamping, jitter, or animation lockup. In [`turtle-lib/src/tweening.rs`](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/tweening.rs): - Added `pub(crate) progress: f32` to [`CommandTween`](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/tweening.rs#L55-L68) to track the current evaluated, eased progress in `[0.0, 1.0]`. - Made `start_time: f64` and `duration: f64` private to `tweening.rs` so outside modules cannot accidentally perform desynchronized clock arithmetic. - Initialized `progress: 0.0` when constructing a new `CommandTween`. - In `TweenController::update`, evaluated and clamped `tween.progress = tween.heading_tweener.move_to(elapsed).clamp(0.0, 1.0)`. In [`turtle-lib/src/drawing.rs`](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/drawing.rs): - Removed `use tween::CubicInOut;` and duplicate easing calculations. - Replaced `get_time() - tween.start_time` and `CubicInOut.tween(...)` in in-flight fill preview with `tween.progress`. - Replaced `get_time() - tween.start_time` and `CubicInOut.tween(...)` in `draw_tween_arc` with `tween.progress`. - Ensured `drawing.rs` has zero clock queries and strictly renders the state provided by `TweenController`. In [`turtle-lib/src/tweening.rs`](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/tweening.rs#L540-L579): - Updated `test_animated_mode_pops_to_current_tween` to assert that `progress` initializes to `0.0`. - Added `test_animated_mode_progress_advances_and_clamps` to verify that `progress` advances monotonically across frames and stays within `[0.0, 1.0]`. --- ```bash cargo test --package turtle-lib --features svg ``` Output: ```text running 17 tests test circle_geometry::tests::test_circle_left_geometry ... ok test circle_geometry::tests::test_circle_right_geometry ... ok test command_behavior::tests::test_goto_duration_cartesian_inversion ... ok test command_behavior::tests::test_set_heading_degrees_and_instant_duration ... ok test execution::tests::test_forward_left_forward ... ok test general::angle::tests::degrees_to_radians_roundtrip ... ok test general::angle::tests::from_f64 ... ok test general::angle::tests::from_integer ... ok test general::angle::tests::negation ... ok test general::fontsize::tests::font_size_conversions ... ok test general::length::tests::test_length_conversions_and_negation ... ok test general::tests::animation_speed_conversions ... ok test tweening::tests::test_animated_mode_pops_to_current_tween ... ok test tweening::tests::test_instant_mode_drains_queue ... ok test tweening::tests::test_instant_mode_respects_batch_limit_and_retains_pending ... ok test tweening::tests::test_streaming_append_commands_does_not_accumulate ... ok test tweening::tests::test_animated_mode_progress_advances_and_clamps ... ok test result: ok. 17 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.02s Doc-tests turtle_lib: 34 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 0.26s ``` ```bash cargo clippy --package turtle-lib --features svg -- -Wclippy::pedantic \ -Aclippy::cast_precision_loss -Aclippy::cast_sign_loss -Aclippy::cast_possible_truncation ``` Output: ```text Finished `dev` profile [optimized + debuginfo] target(s) in 0.82s ``` **0 warnings.** ```bash cargo run --example yinyang --features svg -- --export-svg /tmp/yinyang_test.svg ``` Output: ```text SVG exported successfully to: /tmp/yinyang_test.svg ``` ```bash cargo build --package turtle-lib --examples ``` Output: ```text Finished `dev` profile [optimized + debuginfo] target(s) in 6.74s ``` **All 30 examples compiled cleanly with 0 errors and 0 warnings.**
This commit is contained in:
@@ -5,12 +5,7 @@ use crate::state::{DrawCommand, TurtleParams, TurtleWorld};
|
||||
use crate::tessellation;
|
||||
use macroquad::prelude::*;
|
||||
|
||||
// Import the easing function from the tween crate
|
||||
// To change the easing, change both this import and the usage in the draw_tween_arc function below
|
||||
// Available options: Linear, SineInOut, QuadInOut, CubicInOut, QuartInOut, QuintInOut,
|
||||
// ExpoInOut, CircInOut, BackInOut, ElasticInOut, BounceInOut, etc.
|
||||
// See https://easings.net/ for visual demonstrations
|
||||
use tween::CubicInOut;
|
||||
|
||||
|
||||
/// Render the turtle world with active tween visualization.
|
||||
#[allow(clippy::too_many_lines)]
|
||||
@@ -136,15 +131,11 @@ pub(crate) fn render_world_with_tweens(world: &TurtleWorld, zoom_level: f32) {
|
||||
radius.value(),
|
||||
*direction,
|
||||
);
|
||||
let elapsed = get_time() - tween.start_time;
|
||||
let progress = (elapsed / tween.duration).min(1.0);
|
||||
let eased_progress = CubicInOut.tween(1.0, progress as f32);
|
||||
|
||||
// Delegate to the shared arc_points function — same sampling
|
||||
// strategy as tessellate_arc, eliminating the divergence.
|
||||
// strategy as tessellate_arc, using tween.progress directly.
|
||||
let samples_to_draw =
|
||||
(((*steps).max(1) as f32 * eased_progress) as usize).max(1);
|
||||
let sweep_so_far = angle.as_radians().value() * eased_progress;
|
||||
(((*steps).max(1) as f32 * tween.progress) as usize).max(1);
|
||||
let sweep_so_far = angle.as_radians().value() * tween.progress;
|
||||
for pt in arc_points(
|
||||
geom.center,
|
||||
radius.value(),
|
||||
@@ -309,21 +300,15 @@ fn draw_tween_arc(
|
||||
draw_mesh(&mesh);
|
||||
}
|
||||
|
||||
// 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;
|
||||
let t = (elapsed / tween.duration).min(1.0);
|
||||
let progress = CubicInOut.tween(1.0, t as f32); // tween from 0 to 1
|
||||
|
||||
// Use Lyon to tessellate and draw the partial arc
|
||||
// Draw the partial arc traveled based on tween progress
|
||||
if let Ok(mesh) = crate::tessellation::tessellate_arc(
|
||||
geom.center,
|
||||
radius,
|
||||
geom.start_angle_from_center.to_degrees(),
|
||||
total_angle.value() * progress,
|
||||
total_angle.value() * tween.progress,
|
||||
tween.start_params.color,
|
||||
tween.start_params.pen_width,
|
||||
((steps as f32 * progress).ceil() as usize).max(1),
|
||||
((steps as f32 * tween.progress).ceil() as usize).max(1),
|
||||
direction,
|
||||
) {
|
||||
draw_mesh(&mesh);
|
||||
|
||||
Reference in New Issue
Block a user