Skip to content

Latest commit

 

History

History
276 lines (216 loc) · 8.83 KB

README_cn.md

File metadata and controls

276 lines (216 loc) · 8.83 KB

Rsille 🎨

GitHub License Crates.io Version Crates.io Total Downloads docs.rs

English中文

📚 目录


👀 尝试一下

所有 readme 中使用的图片都可以在example,中找到无需编程直接运行!

git clone https://github.com/nidhoggfgg/rsille.git
cd rsille
cargo run --example cube

这会产生一个旋转的正方体。 关于更多例子或者想自己尝试生成那些有趣的图案,可以尝试使用 cargo run --example,你会找到所有的可执行的例子而无需编程。

当然,还有更多的例子,比如 bad-apple 等。 下方的使用指南会教你如何使用这个库。

🔧 安装

这是一个 rust 库,所以你只需要将如下代码添加到你的 Cargo.toml 中即可使用

[dependencies]
rsille = "2.1.0"

🚀使用方法

限于篇幅,此处给出的是比较常用的 api 以及一般的使用方法。 关于详细的 api,可以去往 doc.rs 查看

基础

最基础的就是 set

use rsille::Canvas;
fn main() {
    let mut c = Canvas::new();
    for x in -360..360 {
        let x = x as f64;
        c.set(x / 10.0, x.to_radians().sin() * 10.0);
    }
    c.print();
}

basic-sin

关于为什么是 (x / 10.0, x.to_radians().sin() * 10.0) 而不是 (x, x.sin())。 这一点你可以自己尝试加减乘除来更改绘制的坐标,有一个小提示 包含 8 个点。 如果你真的不理解或者想知道为什么,可以查看 内部解析。 稍后我可能会写一遍文章关于 braille code。


set 相反的是 unset,作用就是将 set 过的点擦,这里就不给出具体的例子了。


还有一个有用的方法就是 toggle,它会将已经 set 过的点 unset,而 setset 的点

use rsille::Canvas;
fn main() {
    let mut c = Canvas::new();
    for x in (0..360).step_by(4) {
        let x = x as f64;
        c.set(x / 4.0, x.to_radians().sin() * 30.0);
    }

    for x in 0..=30 {
        for y in 0..=30 {
            c.toggle(x, y);
            c.toggle(x + 30, y - 30);
            c.toggle(x + 60, y);
        }
    }
    c.print();
}

toggle-sin

这个例子稍微有点长,先来解释一下其中的代码。

  • (0..360).step_by(4) 是在 [0, π) 上遍历 x,而 step_by(4) 是为了降采样,使线条更细(太低会导致不精确)
  • 第一个 for 就是为了画出 f(x) = sin(x) 的图像,为了更好看,这里对 xy 有一定的缩放
  • 第二个 for 中就是为了产生那几个 toggle 块,它们的大小都是 31x31

toggle 中并没有使用浮点数,这是因为所有的方法都是有泛型支持的,可以传入各种数值! 不过仍然强烈建议使用 f64 来实现更高的精度。

Turtle

在 python 中,有个很有趣的库就是 turtle。 它可以使初次使用 python 的初学者也能体会编程的乐趣。 在这个库中也实现了 turtle 中大部分的方法。

use rsille::{extra::Turtle, Canvas};
fn main() {
    let mut canvas = Canvas::new();
    let mut t = Turtle::new();
    for _ in 0..5 {
        t.forward(50);
        t.right(144);
    }
    canvas.paint(&t, 0, 0).unwrap();
    canvas.print();
}

turtle-star

paint 方法中的两个 0 并不是固定的,而是将目标绘制在 (0, 0)。 这是任意的,但是对于单个物体,总是绘制在 (0, 0) 是不错的。

turtle 就不过多介绍了,可以直接粘贴 python 的代码稍加修改即可使用。

3D Object

这个库也对三维物体提供了支持,还有内部方便的直接构造物体的方法

use rsille::{extra::Object3D, Animation};

fn main() {
    let mut anime = Animation::new();
    let cube = Object3D::cube(30);
    anime.push(
        cube,
        |cube| {
            cube.rotate((1.0, 2.0, 3.0));
            false
        },
        (0, 0),
    );
    anime.run();
}

cube

这里使用了 Animation 来产生动画,这也是内部支持的,可以点开 动画 查看详细信息

Object3D 主要有两个有用的方法,一个是 rotate 用于旋转物体,另一个则是 zoom 用于缩放物体。

生命游戏

生命游戏非常有意思,所以也作为了库的一部分

use rsille::{extra::LifeGame, Animation};

fn main() {
    let mut anime = Animation::new();
    let lg = LifeGame::from(r#"
x = 47, y = 47, rule = B3/S23
18bo$18b3o$21bo$20b2o$$32b2o$32b2o$26bobo$28bo$$22b3o$15b2o5bo2bo$15b
2o5bo3bo$5b2o19bo$5b2o15bo3bo$22bo2bo8b2o$22b3o9b2o$$7b2o36b2o$45bo$7b
o4b3o28bobo$11bo3bo27b2o$10bo5bo13b3ob3o$10bo5bo13bo5bo$10b3ob3o13bo5b
o$2b2o27bo3bo$bobo28b3o4bo$bo$2o36b2o$$11b2o9b3o$11b2o8bo2bo$20bo3bo
15b2o$20bo19b2o$20bo3bo5b2o$21bo2bo5b2o$22b3o$$18bo$18bobo$13b2o$13b2o
$$25b2o$25bo$26b3o$28bo!
"#).unwrap();
    anime.push(
        lg,
        |lg| lg.update(),
        (0, 0),
    );
    anime.run();
}

lifegame

这里仍然是使用 Animation,同时解析 lifegame 的 rle 文件。 在 Lifegame 内部已经编写了解析 rle 文件所需的一切,没有添加任何依赖,而且解析的代码是非常轻量化的。

图片

使用 braille code 来绘制图片也是非常不错的选择。 但是由于解析图片使用的 image 库有点大,默认是不启用的。 想要使用则请将 Cargo.toml 添加如下内容

[dependencies]
rsille = { version = "2.1.0", features = ["img"] }

这是一个使用的案例。注意:请填上图片的文件路径!

use rsille::{extra::Imgille, Canvas};

fn main() {
    let mut canvas = Canvas::new();
    let img = Imgille::new("path/to/img").unwrap();
    canvas.paint(&img, 0, 0).unwrap();
    canvas.print();
}

lena xkcd xkcd-invert

默认是使用颜色,而使用颜色的情况下对灰度图或者黑白图(比如来自 xkcd)等非常不友好,还会降低清晰度!

所以对于它们可以一定要调用 color(false) ! 同时还支持反色,比如上方两张 xckd 的图片,黑色为主的是未反色的,白色为主的是反色的,调用 invert(true) 即可反色。 而对于彩色图片,不使用颜色一样是不错的选择,比如:

lena-gray

另外,图片的大小会随着终端自动缩放,无论是长的终端还是宽的终端,它总是能正确地缩放至合适大小!

动画

生成一些物体,然后绘制到 Canvas上,接着更新物体,重新绘制。 还要设置帧数,处理用户输入等。 每次自己写代码利用基础的 Canvas 绘制一个动画都是如此麻烦! 更别提还有合适地擦除屏幕以及防止闪烁等问题。

所以这个库将这些麻烦事都包装了起来,使用它来产生动画只需要 3 行代码即可!

  1. 新建一个动画 let mut anime = Animation::new()
  2. 装载一个可以绘制的目标以及更新函数 anime.push()
  3. 运行 anime.run()

简直简单到了极点!

use rsille::{extra::Object3D, Animation};

fn main() {
    let cube = Object3D::cube(30);
    let mut anime = Animation::new();
    anime.push(cube, |cube| { cube.rotate((1.0, 2.0, 3.0)); false }, (0, 0));
    anime.run();
}

push 方法的参数如下:

  1. 目标,直接传入即可
  2. 闭包,一个返回值为 bool 的更新函数。每一帧都会运行一次该闭包,当闭包返回值为 true 时该目标停止更新,也不会再执行更新函数,但仍然会绘制在画布上。当所有的目标都已经结束更新,动画停止。
  3. (x, y),放置目标所在的位置,一般只有多个目标时使用

对于用户输入的处理,目前只有 ctrl+cesc 退出, 之后应该会开放自定义。

📌 TODO

  • 优化 Animation 中多线程
  • Animation 添加更多功能
  • 添加更多可绘制的对象
  • Lifegame 添加有边界的版本
  • 更多的例子

📝 许可

MIT