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`.
57 lines
1.5 KiB
Rust
57 lines
1.5 KiB
Rust
//! Cubic Bézier curve example
|
|
//! <https://en.wikipedia.org/wiki/B%C3%A9zier_curve>
|
|
|
|
use turtle_lib::*;
|
|
|
|
struct CubicBezier {
|
|
point0: (f32, f32),
|
|
point1: (f32, f32),
|
|
point2: (f32, f32),
|
|
point3: (f32, f32),
|
|
}
|
|
|
|
impl CubicBezier {
|
|
/// Returns the value of this curve at the given parameter t (0.0 to 1.0)
|
|
pub fn at(&self, t: f64) -> (f32, f32) {
|
|
let t = t as f32;
|
|
let mt = 1.0 - t; // (1 - t)
|
|
|
|
// Cubic Bézier formula from Wikipedia
|
|
let p0_weight = mt.powi(3);
|
|
let p1_weight = 3.0 * mt.powi(2) * t;
|
|
let p2_weight = 3.0 * mt * t.powi(2);
|
|
let p3_weight = t.powi(3);
|
|
|
|
(
|
|
self.point0.0 * p0_weight
|
|
+ self.point1.0 * p1_weight
|
|
+ self.point2.0 * p2_weight
|
|
+ self.point3.0 * p3_weight,
|
|
self.point0.1 * p0_weight
|
|
+ self.point1.1 * p1_weight
|
|
+ self.point2.1 * p2_weight
|
|
+ self.point3.1 * p3_weight,
|
|
)
|
|
}
|
|
}
|
|
|
|
#[turtle_main("Bézier Curve")]
|
|
fn draw(turtle: &mut TurtlePlan) {
|
|
let curve = CubicBezier {
|
|
point0: (-200.0, -100.0),
|
|
point1: (-100.0, 400.0),
|
|
point2: (100.0, -500.0),
|
|
point3: (300.0, 200.0),
|
|
};
|
|
|
|
let start = curve.at(0.0);
|
|
turtle.pen_up().go_to(vec2(start.0, start.1)).pen_down();
|
|
|
|
let samples = 100;
|
|
for i in 0..samples {
|
|
let t = f64::from(i) / f64::from(samples);
|
|
let point = curve.at(t);
|
|
turtle.go_to(vec2(point.0, point.1));
|
|
}
|
|
}
|