You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
120 lines
2.6 KiB
120 lines
2.6 KiB
extern crate cairo;
|
|
|
|
use cairo::{svg, Context};
|
|
use std::fs::File;
|
|
use std::io::Write;
|
|
|
|
fn main() {
|
|
koch();
|
|
sierpinski();
|
|
arrowhead();
|
|
dragon();
|
|
}
|
|
|
|
fn koch() {
|
|
let mut out = File::create("koch.svg").unwrap();
|
|
run(
|
|
"F",
|
|
&['F'],
|
|
|c: char| match c {
|
|
'F' => "F+F-F-F+F".chars().collect(),
|
|
other => vec![other],
|
|
},
|
|
std::f64::consts::PI / 2.,
|
|
4,
|
|
&mut out,
|
|
);
|
|
}
|
|
|
|
fn sierpinski() {
|
|
let mut out = File::create("sierpinski.svg").unwrap();
|
|
run(
|
|
"F-G-G",
|
|
&['F', 'G'],
|
|
|c: char| match c {
|
|
'F' => "F-G+F+G-F".chars().collect(),
|
|
'G' => "GG".chars().collect(),
|
|
other => vec![other],
|
|
},
|
|
std::f64::consts::PI * 2. / 3.,
|
|
4,
|
|
&mut out,
|
|
);
|
|
}
|
|
|
|
fn arrowhead() {
|
|
let mut out = File::create("arrowhead.svg").unwrap();
|
|
run(
|
|
"A",
|
|
&['A', 'B'],
|
|
|c: char| match c {
|
|
'A' => "B-A-B".chars().collect(),
|
|
'B' => "A+B+A".chars().collect(),
|
|
other => vec![other],
|
|
},
|
|
std::f64::consts::PI * 1. / 3.,
|
|
4,
|
|
&mut out,
|
|
);
|
|
}
|
|
|
|
fn dragon() {
|
|
let mut out = File::create("dragon.svg").unwrap();
|
|
run(
|
|
"FX",
|
|
&['F'],
|
|
|c: char| match c {
|
|
'X' => "X+YF+".chars().collect(),
|
|
'Y' => "-FX-Y".chars().collect(),
|
|
other => vec![other],
|
|
},
|
|
std::f64::consts::PI / 2.,
|
|
10,
|
|
&mut out,
|
|
);
|
|
}
|
|
|
|
fn run<F, W>(axiom: &str, variables: &[char], rules: F, angle: f64, iterations: usize, writer: W)
|
|
where
|
|
F: Fn(char) -> Vec<char> + Copy,
|
|
W: Write,
|
|
{
|
|
let surf = svg::Writer::new(1024.0, 1024.0, writer);
|
|
let ctx = Context::new(&surf);
|
|
ctx.scale(1024., 1024.);
|
|
|
|
ctx.set_line_width(0.001);
|
|
ctx.set_source_rgb(0., 0., 0.);
|
|
|
|
let mut state = axiom.to_string();
|
|
|
|
for _ in 0..iterations {
|
|
state = state.chars().map(rules).flatten().collect();
|
|
}
|
|
|
|
// let segment_count = state.chars().filter(|c| variables.contains(&c)).count();
|
|
|
|
|
|
ctx.move_to(0.0, 0.5);
|
|
for c in state.chars() {
|
|
match c {
|
|
'+' => {
|
|
ctx.rotate(-angle);
|
|
}
|
|
'-' => {
|
|
ctx.rotate(angle);
|
|
}
|
|
other => {
|
|
if variables.contains(&other) {
|
|
ctx.rel_line_to(0.01, 0.0);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
ctx.stroke();
|
|
|
|
// let mut fout = File::create("out.png").unwrap();
|
|
// surf.write_all(&mut fout).unwrap();
|
|
// println!("{}", axiom);
|
|
}
|