2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

CrystalAdvent Calendar 2023

Day 10

Crystalでclifford attractorを描出したった

Last updated at Posted at 2023-12-10

はじめに

アドベントカレンダーですが、ネタがありません。そこで Crystal で Clifford Attractor を描くのをやってみました。Clifford Attractor は簡単にかけて綺麗ですのでこういうネタ切れのときに重宝します。

clifford.png

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

この記事は以上です。

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?