diff --git a/README.md b/README.md
index 603deec..45940e6 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
# L-systems in Rust
-Renderings of various L-systems using Rust and Cairo.
+Renderings of various L-systems using Rust and Cairo. Special thanks goes to [Paul Bourke](http://paulbourke.net/fractals/lsys/) and the [L-systems Wikipedia page](https://en.wikipedia.org/wiki/L-system) for the systems below
## Sierpinski Triangle

@@ -13,3 +13,27 @@ Renderings of various L-systems using Rust and Cairo.
## Dragon Curve

+
+## Fractal Plant (Wikipedia)
+
+
+## Moore Curve
+
+
+## Hilbert Curve
+
+
+## Sierpinski Carpet
+
+
+## Koch Snowflake
+
+
+## Hexagonal Gosper
+
+
+## Kolam
+
+
+## Crystal
+
diff --git a/out/arrowhead.svg b/out/arrowhead.svg
index faaf7c0..5e79d1f 100644
--- a/out/arrowhead.svg
+++ b/out/arrowhead.svg
@@ -1,6 +1,6 @@
diff --git a/out/crystal.svg b/out/crystal.svg
new file mode 100644
index 0000000..13960ea
--- /dev/null
+++ b/out/crystal.svg
@@ -0,0 +1,6 @@
+
+
diff --git a/out/dragon.svg b/out/dragon.svg
index 2f824c1..880de08 100644
--- a/out/dragon.svg
+++ b/out/dragon.svg
@@ -1,6 +1,6 @@
diff --git a/out/gosper.svg b/out/gosper.svg
new file mode 100644
index 0000000..84ebcc6
--- /dev/null
+++ b/out/gosper.svg
@@ -0,0 +1,6 @@
+
+
diff --git a/out/hilbert.svg b/out/hilbert.svg
new file mode 100644
index 0000000..0869210
--- /dev/null
+++ b/out/hilbert.svg
@@ -0,0 +1,6 @@
+
+
diff --git a/out/koch.svg b/out/koch.svg
index 2da1c7e..7fbe123 100644
--- a/out/koch.svg
+++ b/out/koch.svg
@@ -1,6 +1,6 @@
diff --git a/out/kolam.svg b/out/kolam.svg
new file mode 100644
index 0000000..de9af84
--- /dev/null
+++ b/out/kolam.svg
@@ -0,0 +1,6 @@
+
+
diff --git a/out/moore.svg b/out/moore.svg
new file mode 100644
index 0000000..5d72be4
--- /dev/null
+++ b/out/moore.svg
@@ -0,0 +1,6 @@
+
+
diff --git a/out/plant.svg b/out/plant.svg
new file mode 100644
index 0000000..ae89372
--- /dev/null
+++ b/out/plant.svg
@@ -0,0 +1,6 @@
+
+
diff --git a/out/sierpinski.svg b/out/sierpinski.svg
index f0ed46e..3ca0101 100644
--- a/out/sierpinski.svg
+++ b/out/sierpinski.svg
@@ -1,6 +1,6 @@
diff --git a/out/sierpinski_carpet.svg b/out/sierpinski_carpet.svg
new file mode 100644
index 0000000..d5e7fa5
--- /dev/null
+++ b/out/sierpinski_carpet.svg
@@ -0,0 +1,6 @@
+
+
diff --git a/out/snowflake.svg b/out/snowflake.svg
new file mode 100644
index 0000000..c33a866
--- /dev/null
+++ b/out/snowflake.svg
@@ -0,0 +1,6 @@
+
+
diff --git a/src/main.rs b/src/main.rs
index 8a1ad64..1232fbe 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -9,10 +9,18 @@ fn main() {
sierpinski();
arrowhead();
dragon();
+ plant();
+ moore();
+ hilbert();
+ sierpinski_carpet();
+ snowflake();
+ gosper();
+ kolam();
+ crystal();
}
fn koch() {
- let mut out = File::create("koch.svg").unwrap();
+ let mut out = File::create("out/koch.svg").unwrap();
run(
"F",
&['F'],
@@ -27,7 +35,7 @@ fn koch() {
}
fn sierpinski() {
- let mut out = File::create("sierpinski.svg").unwrap();
+ let mut out = File::create("out/sierpinski.svg").unwrap();
run(
"F-G-G",
&['F', 'G'],
@@ -43,7 +51,7 @@ fn sierpinski() {
}
fn arrowhead() {
- let mut out = File::create("arrowhead.svg").unwrap();
+ let mut out = File::create("out/arrowhead.svg").unwrap();
run(
"A",
&['A', 'B'],
@@ -53,13 +61,13 @@ fn arrowhead() {
other => vec![other],
},
std::f64::consts::PI * 1. / 3.,
- 4,
+ 6,
&mut out,
);
}
fn dragon() {
- let mut out = File::create("dragon.svg").unwrap();
+ let mut out = File::create("out/dragon.svg").unwrap();
run(
"FX",
&['F'],
@@ -69,13 +77,146 @@ fn dragon() {
other => vec![other],
},
std::f64::consts::PI / 2.,
- 10,
+ 12,
+ &mut out,
+ );
+}
+
+fn plant() {
+ let mut out = File::create("out/plant.svg").unwrap();
+ run(
+ "X",
+ &['F'],
+ |c: char| match c {
+ 'X' => "F-[[X]+X]+F[+FX]-X".chars().collect(),
+ 'F' => "FF".chars().collect(),
+ other => vec![other],
+ },
+ std::f64::consts::PI * 25.0 / 180.0,
+ 5,
+ &mut out,
+ );
+}
+
+fn moore() {
+ let mut out = File::create("out/moore.svg").unwrap();
+ run(
+ "LFL+F+LFL",
+ &['F'],
+ |c: char| match c {
+ 'L' => "-RF+LFL+FR-".chars().collect(),
+ 'R' => "+LF-RFR-FL+".chars().collect(),
+ other => vec![other],
+ },
+ std::f64::consts::PI * 90.0 / 180.0,
+ 5,
&mut out,
);
}
-fn run(axiom: &str, variables: &[char], rules: F, angle: f64, iterations: usize, writer: W)
-where
+fn hilbert() {
+ let mut out = File::create("out/hilbert.svg").unwrap();
+ run(
+ "A",
+ &['F'],
+ |c: char| match c {
+ 'A' => "-BF+AFA+FB-".chars().collect(),
+ 'B' => "+AF-BFB-FA+".chars().collect(),
+ other => vec![other],
+ },
+ std::f64::consts::PI / 2.0,
+ 6,
+ &mut out,
+ );
+}
+
+fn sierpinski_carpet() {
+ let mut out = File::create("out/sierpinski_carpet.svg").unwrap();
+ run(
+ "F+F+F+F",
+ &['F'],
+ |c: char| match c {
+ 'F' => "FF+F+F+F+FF".chars().collect(),
+ other => vec![other],
+ },
+ std::f64::consts::PI / 2.,
+ 4,
+ &mut out,
+ );
+}
+
+fn snowflake() {
+ let mut out = File::create("out/snowflake.svg").unwrap();
+ run(
+ "F++F++F",
+ &['F'],
+ |c: char| match c {
+ 'F' => "F-F++F-F".chars().collect(),
+ other => vec![other],
+ },
+ std::f64::consts::PI / 3.,
+ 4,
+ &mut out,
+ );
+}
+
+fn gosper() {
+ let mut out = File::create("out/gosper.svg").unwrap();
+ run(
+ "XF",
+ &['F'],
+ |c: char| match c {
+ 'X' => "X+YF++YF-FX--FXFX-YF+".chars().collect(),
+ 'Y' => "-FX+YFYF++YF+FX--FX-Y".chars().collect(),
+ other => vec![other],
+ },
+ std::f64::consts::PI / 3.,
+ 4,
+ &mut out,
+ );
+}
+
+fn kolam() {
+ let mut out = File::create("out/kolam.svg").unwrap();
+ run(
+ "-D--D",
+ &['F'],
+ |c: char| match c {
+ 'A' => "F++FFFF--F--FFFF++F++FFFF--F".chars().collect(),
+ 'B' => "F--FFFF++F++FFFF--F--FFFF++F".chars().collect(),
+ 'C' => "BFA--BFA".chars().collect(),
+ 'D' => "CFC--CFC".chars().collect(),
+ other => vec![other],
+ },
+ std::f64::consts::PI / 4.0,
+ 6,
+ &mut out,
+ );
+}
+
+fn crystal() {
+ let mut out = File::create("out/crystal.svg").unwrap();
+ run(
+ "F+F+F+F",
+ &['F'],
+ |c: char| match c {
+ 'F' => "FF+F++F+F".chars().collect(),
+ other => vec![other],
+ },
+ std::f64::consts::PI / 2.,
+ 4,
+ &mut out,
+ );
+}
+
+fn run(
+ axiom: &str,
+ variables_to_draw: &[char],
+ rules: F,
+ angle: f64,
+ iterations: usize,
+ writer: W,
+) where
F: Fn(char) -> Vec + Copy,
W: Write,
{
@@ -94,26 +235,36 @@ where
// let segment_count = state.chars().filter(|c| variables.contains(&c)).count();
-
- ctx.move_to(0.0, 0.5);
+ ctx.move_to(0.5, 0.5);
+ let mut stack: Vec<((f64, f64), f64)> = vec![];
+ let mut curangle = -std::f64::consts::PI / 2.0;
for c in state.chars() {
match c {
'+' => {
- ctx.rotate(-angle);
+ // ctx.rotate(angle);
+ curangle += angle;
}
'-' => {
- ctx.rotate(angle);
+ // ctx.rotate(-angle);
+ curangle -= angle;
+ }
+ '|' => {
+ curangle = -curangle;
+ }
+ '[' => {
+ stack.push((ctx.get_current_point(), curangle));
+ }
+ ']' => {
+ let state = stack.pop().unwrap();
+ ctx.move_to((state.0).0, (state.0).1);
+ curangle = state.1;
}
other => {
- if variables.contains(&other) {
- ctx.rel_line_to(0.01, 0.0);
+ if variables_to_draw.contains(&other) {
+ ctx.rel_line_to(0.005 * f64::cos(curangle), 0.005 * f64::sin(curangle));
}
}
}
}
ctx.stroke();
-
- // let mut fout = File::create("out.png").unwrap();
- // surf.write_all(&mut fout).unwrap();
- // println!("{}", axiom);
}