pub struct LSystem { /* private fields */ }Expand description
An L-system.
§Basic Usage
The suggested method for constructing an LSystem is to use a LSystemBuilder, as shown in our implementation
of Lindenmayer’s system below.
use dcc_lsystem::LSystemBuilder;
let mut builder = LSystemBuilder::new();
// Set up our two tokens
let a = builder.token("A");
let b = builder.token("B");
// Set the axiom
builder.axiom(vec![a]);
// Set the transformation rules
builder.transformation_rule(a, vec![a, b]);
builder.transformation_rule(b, vec![a]);
// Build our L-system
let mut system = builder.finish();Once the LSystem has been built, you can use the step() and step_by() methods
to iterate the system.
use dcc_lsystem::LSystemBuilder;
let mut builder = LSystemBuilder::new();
/* <---- snip ----> */
let mut system = builder.finish();
// The initial state of our system
assert_eq!(system.render(), "A");
system.step();
assert_eq!(system.render(), "AB");
system.step();
assert_eq!(system.render(), "ABA");
system.step_by(5);
// The state after 7 iterations
assert_eq!(system.render(), "ABAABABAABAABABAABABAABAABABAABAAB");Implementations§
Source§impl LSystem
impl LSystem
Sourcepub fn new(
arena: Arena<Token>,
axiom: Vec<ArenaId>,
rules_map: HashMap<ArenaId, Vec<ArenaId>>,
) -> Self
pub fn new( arena: Arena<Token>, axiom: Vec<ArenaId>, rules_map: HashMap<ArenaId, Vec<ArenaId>>, ) -> Self
Create a new instance of LSystem. In general you should avoid using this
and use an LSystemBuilder instead.
Sourcepub fn reset(&mut self)
pub fn reset(&mut self)
Reset the system to its initial state.
§Example
use dcc_lsystem::LSystemBuilder;
let mut builder = LSystemBuilder::new();
// Create a simple L-System with one variable `A` and production rule `A -> AA`
let a = builder.token("A");
builder.axiom(vec![a]);
builder.transformation_rule(a, vec![a, a]);
let mut system = builder.finish();
// Do some work with the system
system.step_by(3);
assert_eq!(system.render(), "AAAAAAAA");
// Reset the system back to its axiom
system.reset();
assert_eq!(system.render(), "A");Sourcepub fn step(&mut self)
pub fn step(&mut self)
Iterate the system a single step.
Examples found in repository?
examples/cantor_set.rs (line 45)
6fn main() {
7 let mut builder = LSystemBuilder::new();
8
9 let a = builder.token("A");
10 let b = builder.token("B");
11
12 builder.axiom(vec![a]);
13 builder.transformation_rule(a, vec![a, b, a]);
14 builder.transformation_rule(b, vec![b, b, b]);
15
16 let mut system = builder.finish();
17
18 // the total number of states (including the initial state!) to render
19 let step_limit = 6;
20
21 // At state number `step_limit`, our diagram has 3^(step_limit - 1) bars,
22 // so we make the width of our image an integer multiple of this number.
23 let width = 3_u32.pow(step_limit - 1) * 2;
24
25 // the vertical spacing between each bar in the render
26 let vertical_spacing = 5;
27
28 let mut lines = Vec::new();
29
30 for index in 0..step_limit {
31 let state = system.get_state();
32 let bar_width: u32 = width / state.len() as u32;
33
34 let mut x: u32 = 0;
35 let y = vertical_spacing * index;
36
37 for token in state {
38 if *token == a {
39 // draw a line
40 lines.push((x, y, x + bar_width, y));
41 }
42 x += bar_width;
43 }
44
45 system.step();
46 }
47
48 let padding: u32 = 5;
49 let render_width = 2 * padding + width as u32;
50 let render_height = 2 * padding + vertical_spacing * (step_limit - 1);
51
52 let mut buffer = ImageBuffer::new(render_width, render_height);
53
54 // Make the buffer entirely white
55 fill_mut(&mut buffer, Rgb([255u8, 255u8, 255u8]));
56
57 // Draw the lines
58 for (x1, y1, x2, y2) in lines.into_iter() {
59 for x in x1..=x2 {
60 for y in y1..=y2 {
61 let pixel = buffer.get_pixel_mut(x + padding, y + padding);
62 *pixel = Rgb([0u8, 0u8, 0u8]);
63 }
64 }
65 }
66
67 buffer
68 .save("cantor_set.png")
69 .expect("Failed to save to cantor_set.png");
70}Sourcepub fn step_by(&mut self, n: usize)
pub fn step_by(&mut self, n: usize)
Iterate the system by n steps.
Examples found in repository?
examples/dragon_curve_data.rs (line 19)
5fn main() {
6 let mut builder = TurtleLSystemBuilder::new();
7
8 builder
9 .token("X", TurtleAction::Nothing)
10 .token("Y", TurtleAction::Nothing)
11 .token("F", TurtleAction::Forward(30))
12 .token("+", TurtleAction::Rotate(-90))
13 .token("-", TurtleAction::Rotate(90))
14 .axiom("F X")
15 .rule("X => X + Y F +")
16 .rule("Y => - F X - Y");
17
18 let (mut system, renderer) = builder.finish();
19 system.step_by(15);
20
21 let rv = renderer.render(&system, &DataRendererOptions::default());
22 println!("Dragon curve builder generated {} lines", rv.len());
23}More examples
examples/koch_curve.rs (line 17)
6fn main() {
7 let mut builder = TurtleLSystemBuilder::new();
8
9 builder
10 .token("F", TurtleAction::Forward(30))
11 .token("+", TurtleAction::Rotate(90))
12 .token("-", TurtleAction::Rotate(-90))
13 .axiom("F")
14 .rule("F => F + F - F - F + F");
15
16 let (mut system, renderer) = builder.finish();
17 system.step_by(7);
18
19 let options = ImageRendererOptionsBuilder::new()
20 .padding(10)
21 .thickness(4.0)
22 .fill_color(Rgb([255u8, 255u8, 255u8]))
23 .line_color(Rgb([0u8, 0u8, 100u8]))
24 .build();
25
26 renderer
27 .render(&system, &options)
28 .save("koch_curve.png")
29 .expect("Failed to save koch_curve.png");
30}examples/koch_curve_video.rs (line 17)
6fn main() {
7 let mut builder = TurtleLSystemBuilder::new();
8
9 builder
10 .token("F", TurtleAction::Forward(30))
11 .token("+", TurtleAction::Rotate(90))
12 .token("-", TurtleAction::Rotate(-90))
13 .axiom("F")
14 .rule("F => F + F - F - F + F");
15
16 let (mut system, renderer) = builder.finish();
17 system.step_by(4);
18
19 let options = VideoRendererOptionsBuilder::new()
20 .filename("koch_curve.gif")
21 .fps(20)
22 .skip_by(5)
23 .padding(10)
24 .thickness(4.0)
25 .fill_color(Rgb([255u8, 255u8, 255u8]))
26 .line_color(Rgb([0u8, 0u8, 100u8]))
27 .progress_bar(true)
28 .build();
29
30 renderer.render(&system, &options);
31}examples/sierpinski_arrowhead.rs (line 19)
6fn main() {
7 let mut builder = TurtleLSystemBuilder::new();
8
9 builder
10 .token("A", TurtleAction::Forward(200))
11 .token("B", TurtleAction::Forward(200))
12 .token("+", TurtleAction::Rotate(60))
13 .token("-", TurtleAction::Rotate(-60))
14 .axiom("A")
15 .rule("A => B - A - B")
16 .rule("B => A + B + A");
17
18 let (mut system, renderer) = builder.finish();
19 system.step_by(7);
20
21 let options = ImageRendererOptionsBuilder::new()
22 .padding(20)
23 .thickness(15.0)
24 .fill_color(Rgb([255u8, 255u8, 255u8]))
25 .line_color(Rgb([0u8, 100u8, 0u8]))
26 .build();
27
28 renderer
29 .render(&system, &options)
30 .save("sierpinski_arrowhead.png")
31 .expect("Failed to save to sierpinski_arrowhead.png");
32}examples/sierpinski_triangle.rs (line 19)
6fn main() {
7 let mut builder = TurtleLSystemBuilder::new();
8
9 builder
10 .token("F", TurtleAction::Forward(200))
11 .token("G", TurtleAction::Forward(200))
12 .token("+", TurtleAction::Rotate(120))
13 .token("-", TurtleAction::Rotate(-120))
14 .axiom("F - G - G")
15 .rule("F => F - G + F + G - F")
16 .rule("G => G G");
17
18 let (mut system, renderer) = builder.finish();
19 system.step_by(7);
20
21 let options = ImageRendererOptionsBuilder::new()
22 .padding(20)
23 .thickness(8.0)
24 .fill_color(Rgb([255u8, 255u8, 255u8]))
25 .line_color(Rgb([0u8, 100u8, 0u8]))
26 .build();
27
28 renderer
29 .render(&system, &options)
30 .save("sierpinski_triangle.png")
31 .expect("Failed to save to sierpinski_triangle.png");
32}examples/dragon_curve.rs (line 21)
7fn main() {
8 let mut builder = TurtleLSystemBuilder::new();
9
10 builder
11 .token("X", TurtleAction::Nothing)
12 .token("Y", TurtleAction::Nothing)
13 .token("F", TurtleAction::Forward(30))
14 .token("+", TurtleAction::Rotate(-90))
15 .token("-", TurtleAction::Rotate(90))
16 .axiom("F X")
17 .rule("X => X + Y F +")
18 .rule("Y => - F X - Y");
19
20 let (mut system, renderer) = builder.finish();
21 system.step_by(15);
22
23 let options = ImageRendererOptionsBuilder::new()
24 .padding(10)
25 .thickness(8.0)
26 .fill_color(Rgb([255u8, 255u8, 255u8]))
27 .line_color(Rgb([100u8, 0u8, 0u8]))
28 .build();
29
30 renderer
31 .render(&system, &options)
32 .save("dragon_curve.png")
33 .expect("Failed to save to dragon_curve.png");
34}Additional examples can be found in:
Sourcepub fn get_state(&self) -> &[ArenaId]
pub fn get_state(&self) -> &[ArenaId]
Returns the current state of the system.
Examples found in repository?
examples/cantor_set.rs (line 31)
6fn main() {
7 let mut builder = LSystemBuilder::new();
8
9 let a = builder.token("A");
10 let b = builder.token("B");
11
12 builder.axiom(vec![a]);
13 builder.transformation_rule(a, vec![a, b, a]);
14 builder.transformation_rule(b, vec![b, b, b]);
15
16 let mut system = builder.finish();
17
18 // the total number of states (including the initial state!) to render
19 let step_limit = 6;
20
21 // At state number `step_limit`, our diagram has 3^(step_limit - 1) bars,
22 // so we make the width of our image an integer multiple of this number.
23 let width = 3_u32.pow(step_limit - 1) * 2;
24
25 // the vertical spacing between each bar in the render
26 let vertical_spacing = 5;
27
28 let mut lines = Vec::new();
29
30 for index in 0..step_limit {
31 let state = system.get_state();
32 let bar_width: u32 = width / state.len() as u32;
33
34 let mut x: u32 = 0;
35 let y = vertical_spacing * index;
36
37 for token in state {
38 if *token == a {
39 // draw a line
40 lines.push((x, y, x + bar_width, y));
41 }
42 x += bar_width;
43 }
44
45 system.step();
46 }
47
48 let padding: u32 = 5;
49 let render_width = 2 * padding + width as u32;
50 let render_height = 2 * padding + vertical_spacing * (step_limit - 1);
51
52 let mut buffer = ImageBuffer::new(render_width, render_height);
53
54 // Make the buffer entirely white
55 fill_mut(&mut buffer, Rgb([255u8, 255u8, 255u8]));
56
57 // Draw the lines
58 for (x1, y1, x2, y2) in lines.into_iter() {
59 for x in x1..=x2 {
60 for y in y1..=y2 {
61 let pixel = buffer.get_pixel_mut(x + padding, y + padding);
62 *pixel = Rgb([0u8, 0u8, 0u8]);
63 }
64 }
65 }
66
67 buffer
68 .save("cantor_set.png")
69 .expect("Failed to save to cantor_set.png");
70}Trait Implementations§
Auto Trait Implementations§
impl Freeze for LSystem
impl RefUnwindSafe for LSystem
impl Send for LSystem
impl Sync for LSystem
impl Unpin for LSystem
impl UnwindSafe for LSystem
Blanket Implementations§
Source§impl<Src, Scheme> ApproxFrom<Src, Scheme> for Srcwhere
Scheme: ApproxScheme,
impl<Src, Scheme> ApproxFrom<Src, Scheme> for Srcwhere
Scheme: ApproxScheme,
Source§fn approx_from(src: Src) -> Result<Src, <Src as ApproxFrom<Src, Scheme>>::Err>
fn approx_from(src: Src) -> Result<Src, <Src as ApproxFrom<Src, Scheme>>::Err>
Convert the given value into an approximately equivalent representation.
Source§impl<Dst, Src, Scheme> ApproxInto<Dst, Scheme> for Srcwhere
Dst: ApproxFrom<Src, Scheme>,
Scheme: ApproxScheme,
impl<Dst, Src, Scheme> ApproxInto<Dst, Scheme> for Srcwhere
Dst: ApproxFrom<Src, Scheme>,
Scheme: ApproxScheme,
Source§type Err = <Dst as ApproxFrom<Src, Scheme>>::Err
type Err = <Dst as ApproxFrom<Src, Scheme>>::Err
The error type produced by a failed conversion.
Source§fn approx_into(self) -> Result<Dst, <Src as ApproxInto<Dst, Scheme>>::Err>
fn approx_into(self) -> Result<Dst, <Src as ApproxInto<Dst, Scheme>>::Err>
Convert the subject into an approximately equivalent representation.
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T, Dst> ConvAsUtil<Dst> for T
impl<T, Dst> ConvAsUtil<Dst> for T
Source§impl<T> ConvUtil for T
impl<T> ConvUtil for T
Source§fn approx_as<Dst>(self) -> Result<Dst, Self::Err>where
Self: Sized + ApproxInto<Dst>,
fn approx_as<Dst>(self) -> Result<Dst, Self::Err>where
Self: Sized + ApproxInto<Dst>,
Approximate the subject to a given type with the default scheme.
Source§fn approx_as_by<Dst, Scheme>(self) -> Result<Dst, Self::Err>
fn approx_as_by<Dst, Scheme>(self) -> Result<Dst, Self::Err>
Approximate the subject to a given type with a specific scheme.
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
Converts
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
Converts
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more