-
-
Save fenjalien/bc9fa8ca765470308ea311ea68fb499a to your computer and use it in GitHub Desktop.
Generates an SVG file of a Sierpinski triangle when the mouse is pressed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use std::path::PathBuf; | |
use nannou::{ | |
draw::renderer::svg::render_and_save, | |
geom::Tri, | |
prelude::*, | |
rand::{prelude::SliceRandom, thread_rng}, | |
}; | |
fn main() { | |
nannou::app(model).update(update).run(); | |
} | |
struct Model { | |
svg_render_frame: u64, | |
tri: Tri<Vec2>, | |
points: Vec<Point2>, | |
} | |
fn model(app: &App) -> Model { | |
app.new_window() | |
.mouse_pressed(mouse_pressed) | |
.view(view) | |
.build() | |
.unwrap(); | |
let win_rect = app.window_rect(); | |
Model { | |
svg_render_frame: 0, | |
tri: Tri([ | |
win_rect.mid_top(), | |
win_rect.bottom_right(), | |
win_rect.bottom_left(), | |
]), | |
points: vec![Point2::ZERO], | |
} | |
} | |
fn mouse_pressed(app: &App, model: &mut Model, button: MouseButton) { | |
if let MouseButton::Left = button { | |
model.svg_render_frame = app.elapsed_frames() + 1; | |
} | |
} | |
fn captured_frame_path(app: &App) -> PathBuf { | |
PathBuf::from(env!("CARGO_MANIFEST_DIR")).join(format!("out_{:03}.svg", app.elapsed_frames())) | |
} | |
fn update(_app: &App, model: &mut Model, _update: Update) { | |
// Calculate and save the next point | |
model.points.push( | |
model | |
.points | |
.last() | |
.unwrap() | |
.lerp(*model.tri.choose(&mut thread_rng()).unwrap(), 0.5), | |
); | |
} | |
fn view(app: &App, model: &Model, frame: Frame) { | |
let draw = app.draw(); | |
// We only need to draw the background and bounding triangle once. | |
if app.elapsed_frames() == 1 { | |
draw.background().color(WHITE); | |
draw_tri(&draw, model.tri); | |
} | |
// Draw the latest calculated point | |
// We don't need to draw all of them as the previous are kept on the frame | |
draw.ellipse() | |
.color(BLACK) | |
.radius(1.0) | |
.xy(*model.points.last().unwrap()); | |
if model.svg_render_frame == app.elapsed_frames() { | |
// Redraw bounding triangle and all points as they don't exist in the draw struct | |
draw_tri(&draw, model.tri); | |
for point in &model.points { | |
draw.ellipse().color(BLACK).radius(1.0).xy(*point); | |
} | |
render_and_save(app.window_rect(), &draw.clone(), captured_frame_path(app)); | |
} else { | |
draw.to_frame(app, &frame).unwrap(); | |
} | |
} | |
fn draw_tri(draw: &Draw, tri: Tri<Vec2>) { | |
let points: (Vec2, Vec2, Vec2) = Into::into(tri); | |
draw.tri() | |
.no_fill() | |
.stroke(RED) | |
.stroke_weight(1.0) | |
.points(points.0, points.1, points.2); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment