Consistency Refactoring
All 6 consistency review items have been resolved, verified with new
unit tests, automated test suites, and clean example builds.
- **Fixed `Goto` Duration Bug**: In
[`turtle-lib/src/command_behavior.rs`](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/command_behavior.rs),
mapped Cartesian target coordinates to screen space (`vec2(target.x,
-target.y)`) before calculating $\Delta x$ and $\Delta y$ in
`animation_duration`.
- **Unit Test**: Added `test_goto_duration_cartesian_inversion` testing
that moving from screen $(0, 100)$ (Cartesian $(0, -100)$) to
Cartesian $(0, 100)$ computes duration based on the actual 200px
Euclidean distance ($2.0\text{s}$ at $100\text{ px/s}$).
- **Stored `Degrees`**: Updated `TurtleCommand::SetHeading(Degrees)` in
[`turtle-lib/src/commands.rs`](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/commands.rs)
to store user degrees directly ($0^\circ = \text{East}$, $90^\circ =
\text{North}$), matching `Turn(Degrees)` and `Circle { angle: Degrees
}`.
- **Deferred Screen-Space Conversion**: Converted to internal screen
radians (`normalize_angle(-heading.as_radians().value())`) inside
`apply_to_params` in
[`turtle-lib/src/command_behavior.rs`](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/command_behavior.rs).
- **Instant Duration**: Maintained instant transition ($0.01\text{s}$
minimum) in `animation_duration`.
- **Unit Test**: Added `test_set_heading_degrees_and_instant_duration`
verifying $90^\circ$ maps to North ($-\frac{\pi}{2}$ in screen space),
$0^\circ$ to East ($0$), $270^\circ$ to South ($+\frac{\pi}{2}$), and
duration is $0.01\text{s}$.
- **Enhanced `Length` Type**: Expanded
[`turtle-lib/src/general/length.rs`](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/general/length.rs)
with `new()`, `value()`, `Neg`, `PartialOrd`, and conversion
implementations (`From<f32>`, `From<f64>`, `From<i32>`, `From<i16>`,
`From<usize>`).
- **Adopted Across API**:
- `TurtleCommand::Move(Length)` in `commands.rs`.
- `TurtleCommand::Circle { radius: Length, ... }` in `commands.rs`.
- `forward<T: Into<Length>>` and `backward<T: Into<Length>>` in
[`turtle-lib/src/builders.rs`](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/builders.rs).
- `circle_left`, `circle_right` accept `radius: impl Into<Length>`.
- Kept stroke attribute `pen_width` as `Precision` (`f32`).
- **Unit Test**: Added `test_length_conversions_and_negation` in
`general::length`.
- **Removed Duplicate Alias**: Removed `all_animations_complete(&self)`
from `TurtleApp` in
[`turtle-lib/src/lib.rs`](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/lib.rs);
updated call in
[`turtle-lib/src/export.rs`](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/export.rs)
to use canonical `is_complete(&self)`.
- **Corrected
[`README.md`](file:///home/dietrich/Projekte/Source/turtlers/README.md)**:
- `plan.goto(...)` $\rightarrow$ `plan.go_to(...)`
- `plan.set_color(...)` $\rightarrow$ `plan.set_pen_color(...)`
- `create_turtle()` $\rightarrow$ `create_turtle_plan()`
- **Corrected
[`AGENTS.md`](file:///home/dietrich/Projekte/Source/turtlers/AGENTS.md)**:
- `create_turtle()` $\rightarrow$ `create_turtle_plan()` in Threading
Pattern.
- **Unified on `1000.0`**:
- Updated
[`README.md`](file:///home/dietrich/Projekte/Source/turtlers/README.md)
lines 9, 108, 109 to state `speed >= 1000` is Instant and `speed <
1000` is Animated.
- Updated
[`turtle-lib/examples/circle_test.rs`](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/examples/circle_test.rs)
to use `turtle.set_speed(1000)`.
- **Renamed Examples**:
- `turtle-lib/examples/stern.rs` $\rightarrow$
[`turtle-lib/examples/star.rs`](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/examples/star.rs)
- `turtle-lib/examples/nikolaus.rs` $\rightarrow$
[`turtle-lib/examples/house_of_nikolaus.rs`](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/examples/house_of_nikolaus.rs)
- **Translated Functions & Parameters**:
- `house_of_nikolaus.rs`: Translated `nikolausquadrat` $\rightarrow$
`house_square`, `nikolausdiag` $\rightarrow$ `house_diagonal`,
`nikolausdach2` $\rightarrow$ `house_roof`, parameter `groesse`
$\rightarrow$ `size`. Added doc comment explaining the Eulerian path
puzzle.
- `breadboard.rs`: Translated `pin_reihe` $\rightarrow$ `pin_row`,
`pin_spalte` $\rightarrow$ `pin_column`, `pin_seite` $\rightarrow$
`pin_side`, parameter `anzahl` $\rightarrow$ `count`,
`anzahl_reihen` $\rightarrow$ `row_count`. Added `#[cfg(feature =
"svg")]` to helper functions to eliminate dead-code warnings when
SVG feature is not enabled.
- **Translated UI Text & Print Messages**:
- `"Drücke E für SVG-Export"` $\rightarrow$ `"Press E for SVG export"`
- `"SVG exportiert nach test.svg"` $\rightarrow$ `"SVG exported to
test.svg"`
- `"Fehler beim Export: {:?}"` $\rightarrow$ `"Export error: {:?}"`
- `"SVG-Export ist nicht aktiviert..."` $\rightarrow$ `"SVG export is
not enabled..."`
- Translated module doc in `export_svg.rs`.
- **Updated
[`README.md`](file:///home/dietrich/Projekte/Source/turtlers/README.md)**
example lists and CLI commands to reference `star` and
`house_of_nikolaus`.
---
- `cargo test --package turtle-lib`:
- 13 unit tests passed (including 3 new targeted unit tests)
- 34 doctests passed (1 ignored internal helper)
- `cargo check --workspace --all-targets --all-features`: Passed with 0
errors.
- `cargo check --examples --package turtle-lib --all-features`: All 30
examples compiled cleanly with 0 errors.
- `cargo clippy --package turtle-lib -- -Wclippy::pedantic
-Aclippy::cast_precision_loss -Aclippy::cast_sign_loss
-Aclippy::cast_possible_truncation`: Passed with 0 errors.
This commit is contained in:
@@ -1,12 +1,12 @@
|
||||
use turtle_lib::*;
|
||||
|
||||
#[cfg(feature = "svg")]
|
||||
#[macroquad::main("Export SVG")]
|
||||
|
||||
async fn main() {
|
||||
// Create turtle plan
|
||||
let mut turtle = create_turtle_plan();
|
||||
|
||||
// Set instant mode so commands execute imqmediately
|
||||
// Set instant mode so commands execute immediately
|
||||
turtle.set_speed(1200).set_pen_width(0.5);
|
||||
|
||||
breadboard(&mut turtle, 65);
|
||||
@@ -24,12 +24,12 @@ async fn main() {
|
||||
app.update();
|
||||
app.render();
|
||||
|
||||
draw_text("Drücke E für SVG-Export", 20.0, 40.0, 32.0, BLACK);
|
||||
draw_text("Press E for SVG export", 20.0, 40.0, 32.0, BLACK);
|
||||
|
||||
if is_key_pressed(KeyCode::E) {
|
||||
match app.export_drawing("test.svg", export::DrawingFormat::Svg) {
|
||||
Ok(_) => println!("SVG exportiert nach test.svg"),
|
||||
Err(e) => println!("Fehler beim Export: {:?}", e),
|
||||
Ok(_) => println!("SVG exported to test.svg"),
|
||||
Err(e) => eprintln!("Export error: {:?}", e),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,9 +39,10 @@ async fn main() {
|
||||
|
||||
#[cfg(not(feature = "svg"))]
|
||||
fn main() {
|
||||
println!("SVG-Export ist nicht aktiviert. Baue mit --features svg");
|
||||
println!("SVG export is not enabled. Build with --features svg");
|
||||
}
|
||||
|
||||
#[cfg(feature = "svg")]
|
||||
fn pin(t: &mut TurtlePlan, size: f32) {
|
||||
t.left(90.0).forward(size / 2.0);
|
||||
for _ in 0..5 {
|
||||
@@ -50,52 +51,56 @@ fn pin(t: &mut TurtlePlan, size: f32) {
|
||||
t.right(90.0).forward(size / 2.0).left(90.0);
|
||||
}
|
||||
|
||||
fn pin_reihe(t: &mut TurtlePlan, anzahl: usize) {
|
||||
for x in 0..anzahl {
|
||||
#[cfg(feature = "svg")]
|
||||
fn pin_row(t: &mut TurtlePlan, count: usize) {
|
||||
for x in 0..count {
|
||||
pin(t, 5.0);
|
||||
if x < anzahl - 1 {
|
||||
if x < count - 1 {
|
||||
t.forward(5.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn pin_spalte(t: &mut TurtlePlan, anzahl: usize, x_coord: f32) {
|
||||
for x in 0..anzahl {
|
||||
#[cfg(feature = "svg")]
|
||||
fn pin_column(t: &mut TurtlePlan, count: usize, x_coord: f32) {
|
||||
for x in 0..count {
|
||||
t.pen_up().go_to(vec2(x_coord, x as f32 * 10.0)).pen_down();
|
||||
pin_reihe(t, 5);
|
||||
pin_row(t, 5);
|
||||
}
|
||||
}
|
||||
|
||||
fn pin_seite(t: &mut TurtlePlan, anzahl: usize, x_coord: f32, color: Color) {
|
||||
#[cfg(feature = "svg")]
|
||||
fn pin_side(t: &mut TurtlePlan, count: usize, x_coord: f32, color: Color) {
|
||||
t.pen_up()
|
||||
.go_to(vec2(x_coord, -2.5))
|
||||
.pen_down()
|
||||
.set_pen_color(color)
|
||||
.set_heading(90.0);
|
||||
for x in 0..anzahl {
|
||||
for x in 0..count {
|
||||
pin(t, 5.0);
|
||||
if x < anzahl - 1 {
|
||||
if x < count - 1 {
|
||||
t.forward(5.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn breadboard(t: &mut TurtlePlan, anzahl_reihen: usize) {
|
||||
pin_spalte(t, anzahl_reihen, 0.0);
|
||||
pin_spalte(t, anzahl_reihen, 65.0);
|
||||
pin_seite(t, anzahl_reihen, -15.0, BLUE);
|
||||
pin_seite(t, anzahl_reihen, -25.0, RED);
|
||||
pin_seite(t, anzahl_reihen, 125.0, BLUE);
|
||||
pin_seite(t, anzahl_reihen, 135.0, RED);
|
||||
#[cfg(feature = "svg")]
|
||||
fn breadboard(t: &mut TurtlePlan, row_count: usize) {
|
||||
pin_column(t, row_count, 0.0);
|
||||
pin_column(t, row_count, 65.0);
|
||||
pin_side(t, row_count, -15.0, BLUE);
|
||||
pin_side(t, row_count, -25.0, RED);
|
||||
pin_side(t, row_count, 125.0, BLUE);
|
||||
pin_side(t, row_count, 135.0, RED);
|
||||
|
||||
// draw outline
|
||||
t.pen_up().go_to(vec2(-30.0, -5.0)).pen_down();
|
||||
t.set_pen_color(BLACK)
|
||||
.forward(anzahl_reihen as f32 * 10.0 + 10.0)
|
||||
.forward(row_count as f32 * 10.0 + 10.0)
|
||||
.right(90.0)
|
||||
.forward(170.0)
|
||||
.right(90.0)
|
||||
.forward(anzahl_reihen as f32 * 10.0 + 10.0)
|
||||
.forward(row_count as f32 * 10.0 + 10.0)
|
||||
.right(90.0)
|
||||
.forward(170.0)
|
||||
.right(90.0);
|
||||
|
||||
@@ -10,7 +10,7 @@ fn draw(turtle: &mut TurtlePlan) {
|
||||
turtle.set_pen_color(RED);
|
||||
turtle.set_pen_width(0.5);
|
||||
turtle.left(90.0);
|
||||
turtle.set_speed(999);
|
||||
turtle.set_speed(1000);
|
||||
turtle.circle_left(100.0, 540.0, 72); // partial circle to the left
|
||||
|
||||
turtle.begin_fill();
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//! Beispiel: Exportiere ein SVG aus einer einfachen Zeichnung
|
||||
//! Example: Export an SVG from a simple drawing
|
||||
|
||||
#[cfg(feature = "svg")]
|
||||
use turtle_lib::*;
|
||||
@@ -52,12 +52,12 @@ async fn main() {
|
||||
app.update();
|
||||
app.render();
|
||||
|
||||
draw_text("Drücke E für SVG-Export", 20.0, 40.0, 32.0, BLACK);
|
||||
draw_text("Press E for SVG export", 20.0, 40.0, 32.0, BLACK);
|
||||
|
||||
if is_key_pressed(KeyCode::E) {
|
||||
match app.export_drawing("test.svg", export::DrawingFormat::Svg) {
|
||||
Ok(_) => println!("SVG exportiert nach test.svg"),
|
||||
Err(e) => println!("Fehler beim Export: {:?}", e),
|
||||
Ok(_) => println!("SVG exported to test.svg"),
|
||||
Err(e) => eprintln!("Export error: {:?}", e),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,5 +67,5 @@ async fn main() {
|
||||
|
||||
#[cfg(not(feature = "svg"))]
|
||||
fn main() {
|
||||
println!("SVG-Export ist nicht aktiviert. Baue mit --features svg");
|
||||
println!("SVG export is not enabled. Build with --features svg");
|
||||
}
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
//! House of Nikolaus example - draws the classic house figure (Eulerian path puzzle)
|
||||
|
||||
use turtle_lib::*;
|
||||
|
||||
fn house_square(turtle: &mut TurtlePlan, size: f32) {
|
||||
turtle.forward(size);
|
||||
turtle.left(90.0);
|
||||
turtle.forward(size);
|
||||
turtle.left(90.0);
|
||||
turtle.forward(size);
|
||||
turtle.left(90.0);
|
||||
turtle.forward(size);
|
||||
turtle.left(90.0);
|
||||
}
|
||||
|
||||
fn house_diagonal(turtle: &mut TurtlePlan, size: f32) {
|
||||
let square = size * size;
|
||||
let diag = (square + square).sqrt();
|
||||
|
||||
turtle.left(45.0);
|
||||
turtle.forward(diag);
|
||||
turtle.left(45.0);
|
||||
house_roof(turtle, size);
|
||||
turtle.left(45.0);
|
||||
turtle.forward(diag);
|
||||
turtle.left(45.0);
|
||||
}
|
||||
|
||||
fn house_roof(turtle: &mut TurtlePlan, size: f32) {
|
||||
let square = size * size;
|
||||
let diag = (square + square).sqrt();
|
||||
turtle.left(45.0);
|
||||
turtle.forward(diag / 2.0);
|
||||
turtle.left(90.0);
|
||||
turtle.forward(diag / 2.0);
|
||||
turtle.left(45.0);
|
||||
}
|
||||
|
||||
fn house_of_nikolaus(turtle: &mut TurtlePlan, size: f32) {
|
||||
house_square(turtle, size);
|
||||
house_diagonal(turtle, size);
|
||||
}
|
||||
|
||||
#[turtle_main("House of Nikolaus")]
|
||||
fn draw(turtle: &mut TurtlePlan) {
|
||||
turtle.shape(ShapeType::Turtle);
|
||||
|
||||
// Position the turtle (pen up, move, pen down)
|
||||
turtle.pen_up();
|
||||
turtle.backward(80.0);
|
||||
turtle.left(90.0);
|
||||
turtle.backward(50.0);
|
||||
turtle.right(90.0);
|
||||
turtle.pen_down();
|
||||
|
||||
house_of_nikolaus(turtle, 100.0);
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
//! Nikolaus example - draws a house-like figure
|
||||
|
||||
use turtle_lib::*;
|
||||
|
||||
fn nikolausquadrat(turtle: &mut TurtlePlan, groesse: f32) {
|
||||
turtle.forward(groesse);
|
||||
turtle.left(90.0);
|
||||
turtle.forward(groesse);
|
||||
turtle.left(90.0);
|
||||
turtle.forward(groesse);
|
||||
turtle.left(90.0);
|
||||
turtle.forward(groesse);
|
||||
turtle.left(90.0);
|
||||
}
|
||||
|
||||
fn nikolausdiag(turtle: &mut TurtlePlan, groesse: f32) {
|
||||
let quadrat = groesse * groesse;
|
||||
let diag = (quadrat + quadrat).sqrt();
|
||||
|
||||
turtle.left(45.0);
|
||||
turtle.forward(diag);
|
||||
turtle.left(45.0);
|
||||
nikolausdach2(turtle, groesse);
|
||||
turtle.left(45.0);
|
||||
turtle.forward(diag);
|
||||
turtle.left(45.0);
|
||||
}
|
||||
|
||||
fn nikolausdach2(turtle: &mut TurtlePlan, groesse: f32) {
|
||||
let quadrat = groesse * groesse;
|
||||
let diag = (quadrat + quadrat).sqrt();
|
||||
turtle.left(45.0);
|
||||
turtle.forward(diag / 2.0);
|
||||
turtle.left(90.0);
|
||||
turtle.forward(diag / 2.0);
|
||||
turtle.left(45.0);
|
||||
}
|
||||
|
||||
fn nikolaus(turtle: &mut TurtlePlan, groesse: f32) {
|
||||
nikolausquadrat(turtle, groesse);
|
||||
nikolausdiag(turtle, groesse);
|
||||
}
|
||||
|
||||
#[turtle_main("Nikolaus")]
|
||||
fn draw(turtle: &mut TurtlePlan) {
|
||||
turtle.shape(ShapeType::Turtle);
|
||||
|
||||
// Position the turtle (pen up, move, pen down)
|
||||
turtle.pen_up();
|
||||
turtle.backward(80.0);
|
||||
turtle.left(90.0);
|
||||
turtle.backward(50.0);
|
||||
turtle.right(90.0);
|
||||
turtle.pen_down();
|
||||
|
||||
nikolaus(turtle, 100.0);
|
||||
}
|
||||
Reference in New Issue
Block a user