///|
/// Turtle state used to turn production rules into botanical and geometric paths.
pub(all) struct TurtleState {
mut position : Vec2
mut heading : Double
step : Double
turn : Double
} derive(Eq, Debug, ToJson)
///|
pub fn TurtleState::new(
x : Double,
y : Double,
step : Double,
turn : Double,
) -> TurtleState {
{ position: Vec2::new(x, y), heading: 0.0, step, turn }
}
///|
pub(all) struct LSystem {
axiom : String
rules : Map[String, String]
} derive(Debug)
///|
pub fn LSystem::new(axiom : String) -> LSystem {
{ axiom, rules: {} }
}
///|
pub fn LSystem::rule(
self : LSystem,
symbol : String,
replacement : String,
) -> LSystem {
self.rules[symbol] = replacement
self
}
///|
pub fn LSystem::expand(
self : LSystem,
iterations : Int,
max_symbols? : Int = 200000,
) -> String {
let mut current = self.axiom
let limit = max_symbols
for _ in 0.. next.write_string(value)
None => next.write_string(key)
}
if next.to_string().length() >= limit {
break
}
}
current = next.to_string()
if current.length() >= limit {
break
}
}
if current.length() > limit {
current[:limit].to_owned()
} else {
current
}
}
///|
/// Interprets F/f as forward, +/- as turns, and [] as a branch stack.
pub fn turtle_render(program : String, state : TurtleState) -> Path {
let path = Path::new()
let stack = []
let mut current = state
for symbol in program.to_array() {
match symbol {
'F' | 'f' => {
let next = current.position.add({
x: @math.cos(current.heading) * current.step,
y: @math.sin(current.heading) * current.step,
})
let _ = path.line_to(next.x, next.y)
current.position = next
}
'+' => current.heading += current.turn
'-' => current.heading -= current.turn
'[' => stack.push(current)
']' =>
match stack.pop() {
Some(saved) => {
current = saved
let _ = path.move_to(saved.position.x, saved.position.y)
}
None => ()
}
_ => ()
}
}
path
}
///|
pub fn fern_lsystem(iterations : Int) -> String {
LSystem::new("X")
.rule("X", "F+[[X]-X]-F[-FX]+X")
.rule("F", "FF")
.expand(iterations)
}
///|
pub fn koch_lsystem(iterations : Int) -> String {
LSystem::new("F").rule("F", "F+F-F-F+F").expand(iterations)
}
///|
pub fn dragon_lsystem(iterations : Int) -> String {
LSystem::new("FX").rule("X", "X+YF+").rule("Y", "-FX-Y").expand(iterations)
}