Skip to content

Instantly share code, notes, and snippets.

@kujirahand
Last active May 31, 2024 03:10
Show Gist options
  • Save kujirahand/bcf2363c86e369a5f075806c4f616816 to your computer and use it in GitHub Desktop.
Save kujirahand/bcf2363c86e369a5f075806c4f616816 to your computer and use it in GitHub Desktop.
マンデルブロ集合の画像を連続で書き出しするプログラム
use image::{ImageBuffer, Rgb};
fn main() {
let (sx, sy) = (1280, 720);
let (cx, cy, _zoom) = (0.2713912051561837, 0.005142969158296763, 1.4210854715202004e-14);
let fps = 24;
let image_count = fps * 30;
let mut zoom = 4.0;
for i in 0..image_count {
println!("{:04}/{} - m{:04}.png - zoom*{:.8}", i, image_count, i, zoom);
let fname = format!("m{:04}.png", i);
draw(sx, sy, cx, cy, zoom, &fname);
zoom *= 0.95;
}
}
// マンデルブロ集合の計算
fn mandelbrot(c: (f64, f64), max_iter: u32) -> u32 {
let mut z = (0.0, 0.0);
let mut n = 0;
while n < max_iter {
if z.0 * z.0 + z.1 * z.1 > 4.0 {
break;
}
z = (z.0 * z.0 - z.1 * z.1 + c.0, 2.0 * z.0 * z.1 + c.1);
n += 1;
}
n
}
// imageにマンデルブロ集合を描画してファイルに保存する関数
fn draw(imgx: u32, imgy: u32, cx: f64, cy: f64, zoom: f64, filename: &str) {
let max_iter = 1000;
let left = cx - zoom / 2.0;
let top = cy - zoom / 2.0;
let right = left + zoom;
let bottom = top + zoom;
// マンデルブロ集合のパラメータを指定
let r = imgx as f64 / imgy as f64;
let scale_x = (right - left) / imgx as f64 * r * 0.8;
let scale_y = (bottom - top) / imgy as f64 * 0.8;
// 画像をメモリ上に作成
let mut imgbuf = ImageBuffer::new(imgx, imgy);
// 図形を描画する
for (x, y, pixel) in imgbuf.enumerate_pixels_mut() {
let cx = left + x as f64 * scale_x;
let cy = top + y as f64 * scale_y;
// マンデルブロ集合の計算
let i = mandelbrot((cx as f64, cy as f64), max_iter);
// 色を設定する
*pixel = if i == max_iter {
Rgb([255, 255, 255])
} else {
let cc = i as f64 / max_iter as f64;
Rgb(hsl_to_rgb(cc, 1.0, 0.5).into())
// Rgb(hsl_to_rgb(0.1, 0.5, cc).into()) // ゴールドっぽい
};
}
// Save the image as a PNG file
imgbuf.save(filename).unwrap();
println!("Saved {}", filename);
}
// HSLからRGBに変換する
fn hsl_to_rgb(h: f64, s: f64, l: f64) -> (u8, u8, u8) {
let (mut r, mut g, mut b) = (l, l, l);
if s != 0.0 {
let hue2rgb = |p: f64, q: f64, t: f64| -> f64 {
let mut t = t;
if t < 0.0 { t += 1.0; }
if t > 1.0 { t -= 1.0; }
if t < 1.0 / 6.0 { return p + (q - p) * 6.0 * t; }
if t < 1.0 / 2.0 { return q; }
if t < 2.0 / 3.0 { return p + (q - p) * (2.0 / 3.0 - t) * 6.0; }
p
};
let q = if l < 0.5 { l * (1.0 + s) } else { l + s - l * s };
let p = 2.0 * l - q;
r = hue2rgb(p, q, h + 1.0 / 3.0);
g = hue2rgb(p, q, h);
b = hue2rgb(p, q, h - 1.0 / 3.0);
}
((r * 255.0).round() as u8, (g * 255.0).round() as u8, (b * 255.0).round() as u8)
}
@kujirahand
Copy link
Author

良かったパラメータのメモ
// let (cx, cy, zoom) = (-0.90546875, -0.62873046875, 0.0078125);
// let (cx, cy, zoom) = (0.057809906005859384, 0.6565466308593749, 0.000030517578125);
// let (cx, cy, zoom) = (-1.1557366959459607, -0.2777253744623158, 4.656612873077393e-10);

@kujirahand
Copy link
Author

静止画を描画する場合のメモ
draw(sx, sy, -3.0, -1.5, 4.0, "z0.png");
draw(sx, sy, 0.11, -0.67, 0.06, "z1.png");
draw(sx, sy, 0.11, -0.67, 0.03, "z2.png");
draw(sx, sy, 0.11, -0.67, 0.015, "z3.png");
draw(sx, sy, -0.8278906250000001, -0.1983593749999999, 0.03125, "z4.png");
draw(sx, sy, -0.8137109375, -0.1865917968749999, 0.00390625, "z5.png");

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment