#l-systems #turtle #system #rules #lindenmayer #production #axiom

dcc-lsystem

一个Lindenmayer系统的实现,附带一些渲染工具

11个不稳定版本

0.6.3 2021年5月17日
0.6.2 2020年2月10日
0.6.1 2019年11月2日

#366 in 算法

33 每月下载次数

MIT/Apache 和可能 AGPL-3.0-or-later

69KB
1K SLoC

dcc-lsystem

Build Status codecov dependency status

一个用于处理Lindenmayer系统的crate。

背景

L-系统由一组可以用来生成字符串的符号组成,一个将每个符号扩展成更大符号字符串的生产规则集合,一个开始构建的初始公理字符串,以及将生成的字符串转换为几何结构的一种机制。

藻类示例

Lindenmayer最初用于模拟藻类生长的L-系统有变量AB,公理A,以及生产规则A -> ABB -> A。迭代这个系统会产生以下输出

  1. A
  2. AB
  3. ABA
  4. ABAAB

基本用法

将以下内容放入您的Cargo.toml

dcc-lsystem = "0.6"

LSystemBuilder

L-系统由LSystem的一个实例表示。要创建一个裸骨LSystem,可以使用LSystemBuilder结构。以下示例显示了Lindenmayer的藻类系统的实现。

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");

渲染L-系统

可以将L-系统渲染成图像或gif。通常这通过海龟来完成 - L-系统状态中的每个标记都与海龟的某种移动或旋转(或者可能是更复杂的东西)相关联。TurtleLSystemBuilder结构提供了一种方便的方式来构建此类渲染。

图像

科赫曲线可以使用包含3个符号的L系统生成:F+-,其中 F 表示向前移动,+ 表示左转90°,- 表示右转90°。该系统具有公理 F 和转换规则 F => F+F-F-F+F。以下是一个示例实现。

use image::Rgb;

use dcc_lsystem::turtle::{TurtleLSystemBuilder, TurtleAction};
use dcc_lsystem::renderer::{ImageRendererOptions, 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");

生成的图像显示在下面的示例部分。

GIFs

还可以使用L系统渲染GIF。GIF的各个帧对应于L系统状态的局部渲染。

use image::Rgb;

use dcc_lsystem::renderer::{Renderer, VideoRendererOptions};
use dcc_lsystem::turtle::{TurtleAction, TurtleLSystemBuilder};

fn main() {
    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);
}

龟行动

目前有以下动作可用

TurtleAction 描述
龟什么也不做。
旋转(i32) 通过一个角度旋转龟。
前进(i32) 使龟向前移动。
推入 将龟的当前朝向和位置推入栈中。
弹出 从栈中弹出龟的朝向和位置。
随机旋转(<动态分布>) 通过某些概率分布指定的角度旋转龟。
随机前进(<动态分布>) 通过某些概率分布指定的距离使龟向前移动。

Distribution 特性如下

pub trait Distribution: dyn_clone::DynClone {
    fn sample(&self) -> i32;
}

一个均匀分布的可能实现(使用 rand 包)如下

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)
    }
}

示例

示例位于 dcc-lsystem/examples

谢宾斯基箭头

Sierpinski Arrowhead

科赫曲线

Koch curve

龙曲线

Dragon curve

分形植物

Fractal plant

许可证

根据您的要求,许可协议可以是以下之一

贡献

除非您明确声明,否则根据 Apache-2.0 许可证定义的,您有意提交以包含在作品中的任何贡献,将根据上述协议双许可,没有任何额外的条款或条件。

依赖关系

~5–20MB
~238K SLoC