🥦
【フラクタル図形】樹木曲線の書き方
class Broccoli < Base
def call
depth = 10 # 複雑度
v0 = wh * V[0.5, 1.0] # 根元
angle = 270.deg_to_rad # 方向
draw(v0, angle, depth)
end
def draw(v0, angle, depth)
if depth <= 0
return
end
stem_size = 9.0 * depth # 幹の長さ (depth を掛けることでだんだん幹が小さくなる)
v1 = v0 + V.from_angle(angle) * stem_size
line(v0, v1)
snapshot
draw(v1, angle - 20.deg_to_rad, depth - 1) # 左に伸びる幹
draw(v1, angle + 20.deg_to_rad, depth - 1) # 右に伸びる幹
end
end
アルゴリズム
- v0 から angle の方向に幹を描く
- その幹の先から二股に angle をずらして再度幹を描く
パラメータ次第でいろんな木ができる。たとえば、 angle をわずかに右方向にだけ向けるとすすきのようになる。
共通コード
require "#{__dir__}/../../物理/ベクトル/vec2"
require "rmagick"
include Magick
class Base
include Math
def call
end
def write(path)
layer.write(path)
puts path
open path
end
def animation_write(path, delay: 2)
av = image_list.optimize_layers(Magick::OptimizeLayer)
av.delay = 100.0 / 60 * delay
av.write(path)
puts path
open path
end
private
def canvas_wh
V[800, (800 / 1.618033988749895).to_i]
end
def wh
canvas_wh
end
def title
self.class.name.underscore
end
def snapshot
image_list << layer.dup
end
def snapshot_counter
@snapshot_counter ||= 0
@snapshot_counter += 1
end
def open(path)
system "open -a 'Google Chrome' #{path}"
end
def layer
@layer ||= Image.new(*canvas_wh) do |e|
e.background_color = background_color
end
end
def image_list
@image_list ||= ImageList.new
end
def background_color
"white"
end
def foreground_color
"grey30"
end
def line_width
2
end
def color_from(iter)
r = iter % 32 * 8
b = iter % 8 * 32
g = iter % 16 * 16
"#%02x%02x%02x" % [r, g, b]
end
def draw_context
g = Draw.new
yield g
g.draw(layer)
end
def line(v0, v1)
draw_context do |g|
g.stroke_width(line_width)
g.stroke(foreground_color)
g.line(*v0, *v1)
end
end
def triangle(v0, v1, v2)
draw_context do |g|
g.fill("transparent")
g.stroke_width(line_width)
g.stroke(foreground_color)
g.polygon(*v0, *v1, *v2)
end
end
def pixel(v0, color)
draw_context do |g|
g.fill(color)
g.rectangle(*v0, *v0)
end
end
def rectangle(v0, v1, color: foreground_color)
draw_context do |g|
g.fill(color)
g.rectangle(*v0, *v1)
end
end
def rectangle_border(v0, v1)
draw_context do |g|
g.fill("transparent")
g.stroke_width(1)
g.stroke(foreground_color)
g.rectangle(*v0, *v1)
end
end
end
if $0 == __FILE__
require "rspec/autorun"
RSpec.configure do |config|
config.expect_with :test_unit
end
describe do
it "works" do
end
end
end
# >> .
# >>
# >> Finished in 0.00282 seconds (files took 0.08633 seconds to load)
# >> 1 example, 0 failures
# >>
Discussion