- ๐ฎ :: Connecting Dots ver.2์ ๋ฆฌํฉํ ๋ง
- ์ ์ฌ์ด์ ๋ฐ๋ผ์ ์ ์ ์ํ๊ฐ์ด ๋ฌ๋ผ์ง๋ ๋ก์ง ์ถ๊ฐ
use nannou::prelude::*;
use std::path::Path;
const WINDOW_SIZE: u32 = 1200;
const HALF_WINDOW: f32 = (WINDOW_SIZE / 2) as f32;
const POINT_COLOR: (f32, f32, f32) = (1.0, 1.0, 1.0);
const LINE_COLOR: (f32, f32, f32, f32) = (1.0, 1.0, 1.0, 0.1);
const LINE_DISTANCE_THRESHOLD: f32 = 70.0;
const LINE_WEIGHT: f32 = 0.4;
const POINT_SPEED: f32 = 0.3;
const NUM_POINTS: usize = 3000;
struct Point {
position: Vec2,
velocity: Vec2,
}
struct Model {
points: Vec<Point>,
counter: u32,
}
fn main() {
nannou::app(model).update(update).event(event).run();
}
fn model(app: &App) -> Model {
app.new_window()
.size(WINDOW_SIZE, WINDOW_SIZE)
.view(view)
.build()
.unwrap();
let points = (0..NUM_POINTS)
.map(|_| Point {
position: pt2(
random_range(-HALF_WINDOW, HALF_WINDOW),
random_range(-HALF_WINDOW, HALF_WINDOW),
),
velocity: pt2(
random_range(-POINT_SPEED, POINT_SPEED),
random_range(-POINT_SPEED, POINT_SPEED),
),
})
.collect();
Model { points, counter: 1 }
}
fn update(_app: &App, model: &mut Model, _update: Update) {
for point in &mut model.points {
point.position += point.velocity;
if point.position.x.abs() > HALF_WINDOW {
point.velocity.x = -point.velocity.x;
point.position.x = point.position.x.clamp(-HALF_WINDOW, HALF_WINDOW);
}
if point.position.y.abs() > HALF_WINDOW {
point.velocity.y = -point.velocity.y;
point.position.y = point.position.y.clamp(-HALF_WINDOW, HALF_WINDOW);
}
}
}
fn event(app: &App, model: &mut Model, event: Event) {
if let Event::WindowEvent {
simple: Some(WindowEvent::KeyPressed(key)),
..
} = event
{
match key {
Key::P => save_frame(app, model, "png"),
Key::J => save_frame(app, model, "jpg"),
_ => {}
}
}
}
fn view(app: &App, model: &Model, frame: Frame) {
let draw = app.draw();
draw.background().rgb(0.05, 0.05, 0.05);
for point in &model.points {
draw.ellipse().xy(point.position).radius(1.0).rgb(
POINT_COLOR.0,
POINT_COLOR.1,
POINT_COLOR.2,
);
}
let threshold_sq = LINE_DISTANCE_THRESHOLD * LINE_DISTANCE_THRESHOLD;
for i in 0..model.points.len() {
for j in i + 1..model.points.len() {
let p1 = &model.points[i];
let p2 = &model.points[j];
let dx = p2.position.x - p1.position.x;
let dy = p2.position.y - p1.position.y;
let distance_sq = dx * dx + dy * dy;
if distance_sq < threshold_sq {
let distance = distance_sq.sqrt();
let alpha = (1.0 - distance / LINE_DISTANCE_THRESHOLD) * LINE_COLOR.3;
draw.line()
.start(p1.position)
.end(p2.position)
.weight(LINE_WEIGHT)
.rgba(LINE_COLOR.0, LINE_COLOR.1, LINE_COLOR.2, alpha);
}
}
}
draw.to_frame(app, &frame).unwrap();
}
fn save_frame(app: &App, model: &mut Model, format: &str) {
let filename = format!("output_{:04}.{}", model.counter, format);
let path = Path::new(&filename);
app.main_window().capture_frame(path);
println!("Frame saved as {}", filename);
model.counter += 1;
}