Files
turtle/README.md
T
dietrich 68593ba64d Builder Pattern Trait Hierarchy Refactoring
We refactored the builder pattern in
[`turtle-lib`](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib)
to eliminate inherent method asymmetry and organize all turtle
capabilities into six cohesive traits.

[`builders.rs`](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/builders.rs)

The legacy traits (`DirectionalMovement`, `Turnable`, `CurvedMovement`)
and orphaned inherent methods have been reorganized into six
domain-focused traits:

-
  **[`Movement`](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/builders.rs#L14)**:
  - `forward()`
  - `backward()`
  - `go_to()`
  - `circle_left()`
  - `circle_right()`
-
  **[`Rotation`](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/builders.rs#L191)**:
  - `left()`
  - `right()`
  - `set_heading()`
-
  **[`Pen`](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/builders.rs#L279)**:
  - `pen_up()`
  - `pen_down()`
  - `set_pen_color()`
  - `set_pen_width()`
-
  **[`Fill`](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/builders.rs#L393)**:
  - `begin_fill()`
  - `end_fill()`
  - `set_fill_color()`
-
  **[`Cursor`](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/builders.rs#L481)**:
  - `hide()`
  - `show()`
  - `shape()`
  - `set_shape()`
  - `set_speed()`
  - `reset()`
-
  **[`Text`](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/builders.rs#L646)**:
  - `write_text()`

[`TurtlePlan`](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/builders.rs#L688)

`TurtlePlan`'s inherent methods are now strictly builder lifecycle
controls:
- `new() -> Self`
- `build(self) -> CommandQueue`

`TurtlePlan` implements `WithCommands`, `Movement`, `Rotation`, `Pen`,
`Fill`, `Cursor`, and `Text`.

-
  **[`lib.rs`](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/src/lib.rs#L62-L65)**:
  Re-exports `Cursor`, `Fill`, `Movement`, `Pen`, `Rotation`, `Text`,
  `TurtlePlan`, `WithCommands`.
- **Examples**: Updated
  [`clock.rs`](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/examples/clock.rs#L8),
  [`clock_threaded.rs`](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/examples/clock_threaded.rs#L9),
  [`dashed_circle.rs`](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/examples/dashed_circle.rs#L4),
  and
  [`bezier.rs`](file:///home/dietrich/Projekte/Source/turtlers/turtle-lib/examples/bezier.rs#L4)
  to use `use turtle_lib::*;`.
-
  **[`README.md`](file:///home/dietrich/Projekte/Source/turtlers/README.md#L344)**:
  Updated trait references in the architecture outline.

---

- **Unit & Doc Tests**:
  ```bash
  cargo test --package turtle-lib
  ```
  Result: 17 unit tests passed; 34 doc-tests passed (0 failed).
- **All Examples**:
  ```bash
  cargo check --package turtle-lib --examples
  ```
  Result: Successfully compiled all 30 examples.
- **Clippy**:
  ```bash
  cargo clippy --package turtle-lib -- -Wclippy::pedantic \
  -Aclippy::cast_precision_loss -Aclippy::cast_sign_loss
  -Aclippy::cast_possible_truncation
  ```
  Result: 0 warnings in `builders.rs`.
2026-09-19 11:45:57 +02:00

417 lines
11 KiB
Markdown

# Turtle Graphics Library
A modern turtle graphics library for Rust built on [Macroquad](https://macroquad.rs/) with [Lyon](https://github.com/nical/lyon) for high-quality GPU-accelerated rendering.
## Features
- 🎨 **Simple Builder API**: Chain commands like `forward(100).right(90)`
- ⚡ **Smooth Animations**: Tweening support with easing functions and live fill preview
- 🚀 **Instant Mode**: Execute commands immediately without animation (speed ≥ 1000)
- 🎯 **High-Quality Rendering**: Complete Lyon tessellation pipeline with GPU acceleration
- 🫟 **Multi-Contour Fills**: Automatic hole detection with EvenOdd fill rule - draw cheese with holes!
- 📐 **Self-Intersecting Paths**: Stars, complex shapes - all handled correctly
- 🐢 **Multiple Turtle Shapes**: Triangle, classic turtle, circle, square, arrow, and custom shapes
- 🔍 **Structured Logging**: Optional `tracing` integration for debugging (zero overhead when disabled)
- 💨 **Lightweight**: Fast compilation and runtime
- 📤 **SVG Export**: Export drawings to SVG format with viewBox and padding (feature-gated)
## Quick Start
The simplest example to draw a square:
```rust
//! Minimal turtle example - just 10 lines!
//!
//! This is the simplest possible turtle program using the macro.
use turtle_lib::*;
#[turtle_main]
fn hello() {
turtle.set_pen_color(BLUE);
for _ in 0..4 {
turtle.forward(100.0);
turtle.right(90.0);
}
}
```
The turtle starts at the center of the window, facing right (0 degrees). The above code draws a blue square.
The `turtle_main` macro sets up the Macroquad window, turtle initialization, and main loop for you. It expands to code similar to this:
```rust
use macroquad::prelude::*;
use turtle_lib::*;
#[macroquad::main("Turtle")]
async fn main() {
// Create a turtle plan
let mut plan = create_turtle_plan();
// Set speed (part of the plan)
plan.set_speed(100);
// Draw a square
for _ in 0..4 {
plan.forward(100).right(90);
}
// Create app (speed is managed by commands)
let mut app = TurtleApp::new().with_commands(plan.build());
loop {
clear_background(WHITE);
app.update();
app.render();
next_frame().await
}
}
```
## API Overview
### Creating Plans
```rust
let mut plan = create_turtle_plan();
// Movement
plan.forward(100);
plan.backward(50);
// Rotation
plan.left(90); // degrees
plan.right(45);
// Circular arcs
plan.circle_left(50.0, 180.0, 36); // radius, angle (degrees), segments
plan.circle_right(50.0, 180.0, 36); // draws arc to the right
// Pen control
plan.pen_up();
plan.pen_down();
// Filling (with automatic hole detection)
plan.set_fill_color(BLUE);
plan.begin_fill();
// ... draw shape ...
plan.end_fill(); // Auto-closes and applies fill
// Appearance
plan.set_pen_color(RED);
plan.set_pen_width(5.0);
plan.hide();
plan.show();
// Speed control (dynamic)
plan.set_speed(100); // Animated mode (< 1000)
plan.set_speed(1000); // Instant mode (>= 1000)
// Turtle shapes
plan.shape(ShapeType::Triangle);
plan.shape(ShapeType::Turtle); // Classic turtle shape
plan.shape(ShapeType::Circle);
plan.shape(ShapeType::Square);
plan.shape(ShapeType::Arrow);
// Custom shapes
let custom = TurtleShape::new(
vec![vec2(10.0, 0.0), vec2(-5.0, 5.0), vec2(-5.0, -5.0)],
true // filled
);
plan.set_shape(custom);
// Method chaining
plan.forward(100).right(90).forward(50);
```
### Execution Modes
Speed controlled via commands, allowing dynamic switching during execution:
```rust
let mut plan = create_turtle_plan();
// Fast initial positioning (instant mode)
plan.set_speed(1000);
plan.pen_up();
plan.go_to(vec2(-100.0, -100.0));
// Slow animated drawing
plan.set_speed(50);
plan.pen_down();
plan.forward(200);
plan.right(90);
// Create app
let app = TurtleApp::new().with_commands(plan.build());
```
**Speed Modes:**
- **Speed < 1000**: Animated mode with smooth tweening
- **Speed >= 1000**: Instant mode (no animation) the bigger the number the more segments will be added per frame.
- Default speed is 100.0 if not specified
## Debugging and Logging
The library uses [`tracing`](https://docs.rs/tracing) for structured diagnostic logging. This is completely optional - if you don't set up a subscriber, there's zero overhead.
### Enable Logging
```rust
// Add to your Cargo.toml:
// tracing-subscriber = { version = "0.3", features = ["env-filter", "fmt"] }
tracing_subscriber::fmt()
.with_env_filter(tracing_subscriber::EnvFilter::from_default_env())
.init();
```
Control verbosity with the `RUST_LOG` environment variable:
```bash
# Show debug output
RUST_LOG=turtle_lib=debug cargo run
# Very verbose trace output
RUST_LOG=turtle_lib=trace cargo run
```
**See the complete example**: [`examples/logging_example.rs`](turtle-lib/examples/logging_example.rs) demonstrates initialization, log levels, filtering, and example output.
## SVG Export
Export your turtle drawings to SVG format for use in web applications, vector graphics editors, or further processing.
### Enabling SVG Export
Add the `svg` feature to enable SVG export functionality:
```bash
cargo run --example export_svg --features svg
```
### Command-Line SVG Export
When using the `turtle_main` macro with the `svg` feature enabled, you can export drawings directly to SVG files using the `--export-svg` command-line parameter:
```bash
# Export any example to SVG without showing the window
cargo run --example macro_demo --features svg -- --export-svg output.svg
# Works with all turtle_main-based examples
cargo run --example hello_turtle --features svg -- --export-svg square.svg
```
This will:
- Execute all drawing commands instantly (no animation)
- Export the result to an SVG file
- Exit immediately without opening a window
### Programmatic SVG Export
You can also export SVG programmatically from your code:
```rust
use turtle_lib::*;
// Create your drawing
let mut plan = create_turtle_plan();
plan.forward(100).right(90).forward(100);
// Create app
let mut app = TurtleApp::new().with_commands(plan.build());
// Export to SVG
app.export_drawing("drawing.svg", export::DrawingFormat::Svg)?;
```
### Features
- **Complete Primitive Support**: Lines, circles, arcs, polygons, and fills
- **Automatic viewBox**: Includes 20px padding around the entire drawing
- **Color and Styling**: Preserves colors, pen width, and fill colors
- **Multi-Contour Fills**: Exports complex fills with holes using SVG paths
- **Text Support**: Exports text elements with positioning
### Example
See [`examples/export_svg.rs`](turtle-lib/examples/export_svg.rs) for a complete example that draws various shapes and exports them to SVG.
The exported SVG can be opened in any web browser or vector graphics application.
## Examples
Run examples with:
```bash
cargo run --example square
cargo run --example koch
cargo run --example shapes
cargo run --example yinyang
cargo run --example star
cargo run --example house_of_nikolaus
# SVG export example (requires --features svg)
cargo run --example export_svg --features svg
# Export any example to SVG using CLI parameter (requires --features svg)
cargo run --example macro_demo --features svg -- --export-svg output.svg
cargo run --example hello_turtle --features svg -- --export-svg square.svg
# Logging example - shows how to enable debug output
cargo run --example logging_example
RUST_LOG=turtle_lib=debug cargo run --example logging_example
```
### Available Examples
#### Basic Drawing
- **square.rs**: Basic square drawing
- **koch.rs**: Koch snowflake fractal
- **shapes.rs**: Demonstrates different turtle shapes
- **star.rs**: Star pattern drawing
- **house_of_nikolaus.rs**: House of Nikolaus (Eulerian path puzzle)
#### Fill Examples
- **yinyang.rs**: Yin-yang symbol with automatic hole detection
- **fill_demo.rs**: Donut shape with hole
- **fill_requirements.rs**: Circle with red fill
- **fill_advanced.rs**: Complex shapes (star, swiss cheese, multiple holes)
- **fill_circle_test.rs**: Circle fills with different angles
- **fill_instant_test.rs**: Quick fill test in instant mode
#### Export
- **export_svg.rs**: Demonstrates SVG export functionality (requires `--features svg`)
#### Debugging
- **logging_example.rs**: Demonstrates how to enable and use tracing/logging output
### Basic Fill
```rust
let mut plan = create_turtle_plan();
plan.set_fill_color(RED);
plan.begin_fill();
// Draw shape
for _ in 0..4 {
plan.forward(100);
plan.right(90);
}
plan.end_fill(); // Auto-closes and fills
```
### Fill with Holes (Multi-Contour)
```rust
plan.set_fill_color(BLUE);
plan.begin_fill();
// Outer circle (first contour)
plan.circle_left(90.0, 360.0, 72);
// pen_up() closes current contour
plan.pen_up();
plan.go_to(vec2(0.0, -30.0));
// pen_down() starts new contour
plan.pen_down();
// Inner circle (becomes a hole automatically with EvenOdd rule!)
plan.circle_left(30.0, 360.0, 36);
plan.end_fill(); // Auto-detects holes and fills correctly
```
## Architecture
### Module Structure
```
turtle-lib/src/
├── lib.rs - Public API and TurtleApp
├── state.rs - TurtleState and TurtleWorld
├── commands.rs - TurtleCommand enum (consolidated commands)
├── builders.rs - Builder traits (Movement, Rotation, Pen, Fill, Cursor, Text)
├── execution.rs - Command execution with fill support
├── tweening.rs - Animation/tweening controller with dynamic speed
├── drawing.rs - Rendering with Lyon tessellation
├── shapes.rs - Turtle shape definitions
├── tessellation.rs - Lyon tessellation utilities
├── circle_geometry.rs - Circle arc calculations
└── general/ - Type definitions (Angle, Length, etc.)
```
## Workspace Structure
```
turtlers/
├── turtle-lib/ - Main library (Macroquad + Lyon)
└── turtle-lib-macros/ - Procedural macros (turtle_main)
```
## Building and Running
```bash
# Check all packages
cargo check
# Run specific example
cargo run --example yinyang
# Run SVG export example (requires svg feature)
cargo run --example export_svg --features svg
# Build release version
cargo build --release
# Build with SVG support
cargo build --features svg
```
### Optional: Faster Linker Setup
For significantly faster incremental build and linking times during development on Linux, you can optionally configure `mold` or `lld` in your user-level Cargo configuration (`~/.cargo/config.toml`):
```toml
[target.x86_64-unknown-linux-gnu]
linker = "clang"
rustflags = ["-C", "link-arg=-fuse-ld=mold"]
```
## Development Status
### ✅ Completed
- **Turtle movement** and rotation (consolidated Move/Turn commands)
- **Pen control** (up/down) with contour management
- **Color** and **pen width**
- **Circle arcs** (left/right with unified Circle command)
- **Dynamic speed control** via SetSpeed commands
- **Instant mode** (speed ≥ 1000) and **animated mode** (speed < 1000)
- **Multi-contour fill** system with automatic hole detection
- **Lyon integration** for all drawing primitives
- **Multiple turtle shapes** with custom shape support
- **Tweening** system with easing functions
- **EvenOdd fill rule** for complex self-intersecting paths
- **Live fill preview** during animation with progressive rendering
- **Multi-contour support** - pen_up/pen_down manage contours
- **SVG Export** - Export drawings to SVG with viewBox and padding (feature-gated)
## License
MIT OR Apache-2.0
## Contributing
Contributions are welcome! The library now has a stable foundation with complete Lyon integration and multi-contour fill support.