はじめに
アドベントカレンダーですが、ネタがありません。そこで Crystal で Clifford Attractor を描くのをやってみました。Clifford Attractor は簡単にかけて綺麗ですのでこういうネタ切れのときに重宝します。
Clifford Attractor生成
n = 2000000
a, b, c, d = -1.3, -1.3, -1.8, -1.9
θ = 0.007
xs, ys = [0.0], [0.0]
n.times do |i|
xs << Math.sin(a * ys.last) + c * Math.cos(a * xs.last) * Math.cos(θ)
ys << Math.sin(b * xs.last) + d * Math.cos(b * ys.last) * Math.cos(θ)
θ += 0.007
end
# p! xs
# p! ys
画像のサイズをスケールする準備
x_min, y_min = xs.min, ys![clifford.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/144608/bc06d4a0-b23b-3345-f5c4-98d01b4be7be.png)
.min
x_max, y_max = xs.max, ys.max
display_size = 4000
offset = 100
area_size = display_size - offset * 2
scale = area_size.to_f / [x_max - x_min, y_max - y_min].max
画像にする配列を作成
# Create black (false) 2d array
image_arr = Array.new(display_size) { Array.new(display_size, false) }
# Draw fractal on array
n.times do |i|
x_pos = ((xs[i] - x_min) * scale + offset).to_i
y_pos = ((ys[i] - y_min) * scale + offset).to_i
image_arr[y_pos][x_pos] = true
end
画像書き出し
今回は単純にPBM形式で書き出すことにしました。高速ですがファイルサイズは大きくなります。ちなみに、PBMを出力する関数は ChatGPT 書いてもらいました。すごいですね。
# Write PBM file
File.open("clifford.pbm", "w") do |f|
f.puts "P1"
f.puts "#{display_size} #{display_size}"
image_arr.each do |row|
row.each do |pixel|
f.print pixel ? "1 " : "0 "
end
f.puts
end
end
全体
全体像は上をつなげてこんな感じです。
n = 10000000
a, b, c, d = -1.3, -1.3, -1.8, -1.9
θ = 0.007
xs, ys = [0.0], [0.0]
n.times do |i|
xs << Math.sin(a * ys[i]) + c * Math.cos(a * xs[i]) * Math.cos(θ)
ys << Math.sin(b * xs[i]) + d * Math.cos(b * ys[i]) * Math.cos(θ)
θ += 0.007
end
x_min, y_min = xs.min, ys.min
x_max, y_max = xs.max, ys.max
display_size = 4000
offset = 100
area_size = display_size - offset * 2
scale = area_size.to_f / [x_max - x_min, y_max - y_min].max
# Create black (false) 2d array
image_arr = Array.new(display_size) { Array.new(display_size, false) }
# Draw fractal on array
n.times do |i|
x_pos = ((xs[i] - x_min) * scale + offset).to_i
y_pos = ((ys[i] - y_min) * scale + offset).to_i
image_arr[y_pos][x_pos] = true
end
# Write PBM file
File.open("clifford.pbm", "w") do |f|
f.puts "P1"
f.puts "#{display_size} #{display_size}"
image_arr.each do |row|
row.each do |pixel|
f.print pixel ? "1 " : "0 "
end
f.puts
end
end
完全に一発芸ですね。できあがった画像は ImageMagick のコマンドを使ってPNGに変換します。まあCrystalのライブラリとか使って頑張ってもいいのですが、素直にコマンド操作した方が楽だと思います。
convert clifford.pbm -resize 1000 clifford.png
この記事は以上です。