Crate dcc_lsystem[−][src]
Expand description
dcc-lsystem
A crate for working with Lindenmayer systems.
Background
An L-System consists of an alphabet of symbols that can be used to make strings, a collection of production rules that expand each symbol into a larger string of symbols, an initial axiom string from which to begin construction, and a mechanism for transforming the generated strings into geometric structures.
Algae example
Lindenmayer’s original L-System for modelling the growth of Algae had
variables A
and B
, axiom A
, and production rules A -> AB
, B -> A
. Iterating
this system produces the following output:
A
AB
ABA
ABAAB
Basic usage
Put the following in your Cargo.toml
:
dcc-lsystem = "0.6"
LSystemBuilder
An L-system is represented by an instance of LSystem
. To create a barebones LSystem
,
the LSystemBuilder
struct is useful. The following example shows an implementation of
Lindenmayer’s Algae system.
use dcc_lsystem::LSystemBuilder; let mut builder = LSystemBuilder::new(); // Set up the two tokens we use for our system. let a = builder.token("A"); let b = builder.token("B"); // Set up our axiom (i.e. initial state) builder.axiom(vec![a]); // Set the transformation rules builder.transformation_rule(a, vec![a,b]); // A -> AB builder.transformation_rule(b, vec![a]); // B -> A // Build our LSystem, which should have initial state A let mut system = builder.finish(); assert_eq!(system.render(), "A"); // system.step() applies our production rules a single time system.step(); assert_eq!(system.render(), "AB"); system.step(); assert_eq!(system.render(), "ABA"); // system.step_by() applies our production rule a number of times system.step_by(5); assert_eq!(system.render(), "ABAABABAABAABABAABABAABAABABAABAAB");
Rendering L-systems
It is possible to render an L-system into an image or gif. Typically this is done using
a turtle - each token in the L-system’s state is associated with some movement or rotation
(or perhaps something more complicated) of a turtle. The TurtleLSystemBuilder
struct offers
a convenient way of constructing such renderings.
Images
The Koch curve can be generated using an L-system with 3 symbols: F
, +
, and -
,
where F
corresponds to moving forwards, +
denotes a left rotation by 90°,
and -
denotes a right rotation by 90°. The system has axiom F
and transformation
rule F => F+F-F-F+F
. This is implemented in the following example.
use image::Rgb; use dcc_lsystem::turtle::{TurtleLSystemBuilder, TurtleAction}; use dcc_lsystem::renderer::{ImageRendererOptionsBuilder, Renderer}; let mut builder = TurtleLSystemBuilder::new(); builder .token("F", TurtleAction::Forward(30)) // F => go forward 30 units .token("+", TurtleAction::Rotate(90)) // + => rotate left 90° .token("-", TurtleAction::Rotate(-90)) // - => rotate right 90° .axiom("F") .rule("F => F + F - F - F + F"); let (mut system, renderer) = builder.finish(); system.step_by(5); // Iterate our L-system 5 times let options = ImageRendererOptionsBuilder::new() .padding(10) .thickness(4.0) .fill_color(Rgb([255u8, 255u8, 255u8])) .line_color(Rgb([0u8, 0u8, 100u8])) .build(); renderer .render(&system, &options) .save("koch_curve.png") .expect("Failed to save koch_curve.png");
The resulting image is shown in the Examples section below.
GIFs
It is also possible to render a GIF using an L-system. The individual frames of the GIF correspond to partial renderings of the L-system’s state.
use image::Rgb; use dcc_lsystem::renderer::{Renderer, VideoRendererOptionsBuilder}; use dcc_lsystem::turtle::{TurtleAction, TurtleLSystemBuilder}; let mut builder = TurtleLSystemBuilder::new(); builder .token("F", TurtleAction::Forward(30)) .token("+", TurtleAction::Rotate(90)) .token("-", TurtleAction::Rotate(-90)) .axiom("F") .rule("F => F + F - F - F + F"); let (mut system, renderer) = builder.finish(); system.step_by(5); let options = VideoRendererOptionsBuilder::new() .filename("koch_curve.gif") .fps(20) .skip_by(0) .padding(10) .thickness(4.0) .fill_color(Rgb([255u8, 255u8, 255u8])) .line_color(Rgb([0u8, 0u8, 100u8])) .progress_bar(true) .build(); renderer .render(&system, &options);
Turtle actions
Currently the following actions are available:
TurtleAction | Description |
---|---|
Nothing | The turtle does nothing. |
Rotate(i32) | Rotate the turtle through an angle. |
Forward(i32) | Move the turtle forwards. |
Push | Push the turtle’s current heading and location onto the stack. |
Pop | Pop the turtle’s heading and location off the stack. |
StochasticRotate(Box<dyn Distribution>) | Rotate the turtle through an angle specified by some probability distribution. |
StochasticForward(Box<dyn Distribution>) | Move the turtle forwards through a distance specified by some probability distribution. |
The Distribution
trait is given by:
pub trait Distribution: dyn_clone:: DynClone { fn sample(&self) -> i32; }
The Uniform
distribution (using the rand
crate) is implemented as follows:
use rand::Rng; #[derive(Clone)] pub struct Uniform { lower: i32, upper: i32, } impl Uniform { pub fn new(lower: i32, upper: i32) -> Self { Self { lower, upper } } } impl Distribution for Uniform { fn sample(&self) -> i32 { let mut rng = rand::thread_rng(); rng.gen_range(self.lower..=self.upper) } }
Examples
Examples are located in dcc-lsystem/examples
.
Sierpinski Arrowhead
Koch curve
Dragon curve
Fractal plant
License
Licensed under either of
- Apache License, Version 2.0 (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
- MIT license (LICENSE-MIT or http://opensource.org/licenses/MIT)
at your option.
Contribution
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.
Re-exports
pub use arena::Arena; | |
pub use arena::ArenaId; | |
pub use builder::LSystemBuilder; | |
pub use system::LSystem; |
Modules
arena | |
builder | |
image | |
image_renderer | |
renderer | |
system | |
token | |
turtle |