๐Ÿ”ฎ :: Colorful Dots HashpMap

BamgasiJMยท2025๋…„ 11์›” 2์ผ

Nannou <Generative Art>

๋ชฉ๋ก ๋ณด๊ธฐ
51/55
post-thumbnail

๐Ÿ“ Rust Code

use nannou::prelude::*;
use rand::{Rng, SeedableRng};
use std::collections::HashMap;

//
// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ ์ƒ์ˆ˜ ์ •์˜ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
//
const WIN_W: u32 = 1000;
const WIN_H: u32 = 1000;
const GRID_COLS: i32 = 40;
const GRID_ROWS: i32 = 40;
const COLOR_SAT_RANGE: (f32, f32) = (0.5, 1.0);
const COLOR_VAL_RANGE: (f32, f32) = (0.4, 1.0);
const RADIUS_JITTER_RANGE: (f32, f32) = (0.2, 1.0);

//
// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ ์ž๋ฃŒ ๊ตฌ์กฐ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
//

#[derive(Clone)]
struct Cell {
    x: f32,
    y: f32,
    radius: f32,
    color: Rgb<f32>,
    id: usize,
}

struct Model {
    cols: i32,
    rows: i32,
    cell_w: f32,
    cell_h: f32,
    grid: HashMap<(i32, i32), Cell>,
    rng: rand::rngs::SmallRng,
    t: f32,
}

//
// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ ๋ฉ”์ธ ํ•จ์ˆ˜ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
//

fn main() {
    nannou::app(model).update(update).run();
}

//
// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ ์ดˆ๊ธฐํ™” โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
//

fn model(app: &App) -> Model {
    app.new_window()
        .size(WIN_W, WIN_H)
        .title("HashMap Grid Artwork (Refactored)")
        .view(view)
        .key_released(key_released)
        .build()
        .unwrap();

    let seed = 42u64;
    let rng = rand::rngs::SmallRng::seed_from_u64(seed);

    let win = app.window_rect();
    let cell_w = win.w() / GRID_COLS as f32;
    let cell_h = win.h() / GRID_ROWS as f32;

    let grid = create_grid(&win, GRID_COLS, GRID_ROWS, cell_w, cell_h, rng.clone());

    Model {
        cols: GRID_COLS,
        rows: GRID_ROWS,
        cell_w,
        cell_h,
        grid,
        rng,
        t: 0.0,
    }
}

//
// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ ๊ทธ๋ฆฌ๋“œ ์ƒ์„ฑ ํ•จ์ˆ˜ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
//

fn create_grid(
    win: &Rect,
    cols: i32,
    rows: i32,
    cell_w: f32,
    cell_h: f32,
    mut rng: rand::rngs::SmallRng,
) -> HashMap<(i32, i32), Cell> {
    let mut grid = HashMap::new();
    let mut id_counter = 0usize;

    for row in 0..rows {
        for col in 0..cols {
            let x = map_range(
                col as f32 + 0.5,
                0.0,
                cols as f32,
                -win.w() / 2.0,
                win.w() / 2.0,
            );
            let y = map_range(
                row as f32 + 0.5,
                0.0,
                rows as f32,
                -win.h() / 2.0,
                win.h() / 2.0,
            );

            let color = random_color(&mut rng);
            let base_radius = (cell_w.min(cell_h) * 0.45).abs();
            let radius_jitter = rng.gen_range(RADIUS_JITTER_RANGE.0..RADIUS_JITTER_RANGE.1);
            let radius = base_radius * radius_jitter;

            grid.insert(
                (col, row),
                Cell {
                    x,
                    y,
                    radius,
                    color,
                    id: id_counter,
                },
            );

            id_counter += 1;
        }
    }

    grid
}

//
// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ ๋žœ๋ค ์ƒ‰์ƒ ์ƒ์„ฑ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
//

fn random_color(rng: &mut rand::rngs::SmallRng) -> Rgb<f32> {
    let hue = rng.gen_range(0.0..1.0);
    let sat = rng.gen_range(COLOR_SAT_RANGE.0..COLOR_SAT_RANGE.1);
    let val = rng.gen_range(COLOR_VAL_RANGE.0..COLOR_VAL_RANGE.1);
    hsv_to_rgb(hue, sat, val)
}

//
// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ ์—…๋ฐ์ดํŠธ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
//

fn update(_app: &App, model: &mut Model, update: Update) {
    model.t += update.since_last.as_secs_f32();

    for cell in model.grid.values_mut() {
        let phase = (cell.id as f32 * 0.13).sin();
        let hue = ((model.t * 0.05) + phase).fract().abs();
        let sat = 0.7;
        let val = 0.7 + 0.2 * (model.t * 0.2 + phase).sin();

        cell.color = hsv_to_rgb(hue, sat, val);

        cell.radius *= 0.9999;
        if cell.radius < 2.0 {
            cell.radius *= 1.05;
        }
    }
}

//
// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ ํ‚ค ์ž…๋ ฅ (์ŠคํŽ˜์ด์Šค๋ฐ” โ†’ ๋ฆฌ์…‹) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
//

fn key_released(app: &App, model: &mut Model, key: Key) {
    if key == Key::Space {
        model.rng = rand::rngs::SmallRng::from_entropy();
        let win = app.window_rect();
        model.grid = create_grid(
            &win,
            model.cols,
            model.rows,
            model.cell_w,
            model.cell_h,
            model.rng.clone(),
        );
    }
}

//
// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ ๊ทธ๋ฆฌ๊ธฐ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
//

fn view(app: &App, model: &Model, frame: Frame) {
    let draw = app.draw();
    draw.background().color(srgb(0.08, 0.08, 0.12));

    for cell in model.grid.values() {
        let r = cell.color.red;
        let g = cell.color.green;
        let b = cell.color.blue;

        draw.ellipse()
            .x_y(cell.x, cell.y)
            .w_h(cell.radius * 2.0, cell.radius * 2.0)
            .color(srgb(r, g, b));

        draw.ellipse()
            .x_y(cell.x, cell.y)
            .w_h(cell.radius * 2.1, cell.radius * 2.1)
            .no_fill()
            .stroke_weight(1.2)
            .stroke(srgb(
                (r * 0.9).min(1.0),
                (g * 0.9).min(1.0),
                (b * 0.9).min(1.0),
            ));
    }

    draw.to_frame(app, &frame).unwrap();
}

//
// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ ์œ ํ‹ธ๋ฆฌํ‹ฐ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
//

fn hsv_to_rgb(h: f32, s: f32, v: f32) -> Rgb<f32> {
    let i = (h * 6.0).floor() as i32;
    let f = h * 6.0 - i as f32;
    let p = v * (1.0 - s);
    let q = v * (1.0 - f * s);
    let t = v * (1.0 - (1.0 - f) * s);

    let (r, g, b) = match i.rem_euclid(6) {
        0 => (v, t, p),
        1 => (q, v, p),
        2 => (p, v, t),
        3 => (p, q, v),
        4 => (t, p, v),
        5 => (v, p, q),
        _ => (1.0, 0.0, 0.0),
    };

    srgb(r, g, b)
}

profile
Coding Art with Blender / oF / Processing / p5.js / nannou

0๊ฐœ์˜ ๋Œ“๊ธ€