cairo と Ruby で遊んでみる(2)

水平投射です。



require 'bundler/setup'
require 'cairo'
require './gifanime'
include Math

W = 600; H = 300
V0 = 10.0; A = 0.75; G = 5.0

v = lambda {|n| - A ** n * sqrt(2 * G * H)}
t = lambda do |n|
  if n.zero?
    sqrt(2 * H / G)
  else
    ar = [1]
    n.times {|i| ar << 2 * A ** (i + 1)}
    sqrt(2 * H / G) * ar.inject(:+)
  end
end
y = lambda do |n, t1|
  if n.zero?
    H - G * t1 ** 2 / 2
  else
    t2 = t1 - t.call(n - 1)
    - v.call(n) * t2 - G * t2 ** 2 / 2
  end
end
x = lambda {|t1| V0 * t1}

num = lambda do |tm|
  1000.times {|i| return i if tm <= t.call(i)}
end


#main
Dir.chdir("picture")
Surface = Cairo::ImageSurface.new(Cairo::FORMAT_ARGB32, W, H)
C = Cairo::Context.new(Surface)
C.set_source_rgb(0, 0, 0)
C.rectangle(0, 0, W, H)
C.fill

C.set_source_rgb(1, 0, 0)

for i in 0..W
  tm = i / V0
  x1 = x.call(tm)
  y1 = H - y.call(num[tm], tm)
  C.arc(x1, y1, 2, 0, 2 * PI)
  C.stroke
  Surface.write_to_png("%04d.png" % i)
end

gifanime(3)

V0 は初速度、A は反発係数、G は重力加速度。


※参考
cairo と Ruby で遊んでみる - Camera Obscura
cairo: 索引