Ruby と rcairo でベジェ曲線を描いてみる
ベジェ曲線(Wikipedia)は滑らかな曲線を描くために使われるものです。いくつかの「制御点」を指定して描きます。計算はそんなにむずかしくなくて、上の Wikipedia の記事で充分わかりますし、ネット上にわかりやすい記事がたくさんあるので検索してみて下さい。
Ruby と 'rcairo' で描いてみた例です。
青い線が制御点を結んだ折れ線で、赤い曲線がベジェ曲線です。
Ruby コード。
bezier_curve.rb
require 'cairo' require 'matrix' class BezierCurve def initialize(points, step = 0.01) @points = points.map {|a| a.class == Array ? Vector[*a] : a} @step = step end def calc n = @points.size - 1 Enumerator.new do |y| c = [1] + (1..n).map {|k| (n - k + 1..n).inject(&:*) / (1..k).inject(&:*)} 0.0.step(1.0, @step) do |t| j = ->(i) { c[i] * t ** i * (1 - t) ** (n - i) } y << @points.map.with_index {|b, i| b * j.(i)}.inject(&:+) end y << @points.last end end end if __FILE__ == $0 #画像の大きさ W = 300 #cairoの初期設定 surface = Cairo::ImageSurface.new(W, W) context = Cairo::Context.new(surface) #背景 context.set_source_color(Cairo::Color.parse("#F1F389")) context.rectangle(0, 0, W, W) context.fill #制御点を与える points = [[20.0, 280.0], [60.0, 100.0], [200.0, 120.0], [290.0, 230.0]] #制御点を結ぶ青い線 context.set_source_color(Cairo::Color::BLUE) context.set_line_width(2) context.move_to(*points.first) points.drop(1).each {|r| context.line_to(*r)} context.stroke #ベジェ曲線(赤色)の描画 context.set_source_color(Cairo::Color::RED) context.move_to(*points.first) BezierCurve.new(points).calc.each do |r| context.line_to(*r.to_a) end context.stroke #png画像として出力 surface.write_to_png("bezier_curve.png") end
使い方としては、配列 points に制御点を入れて(制御点は配列あるいは Vector クラスで表現します)、BezierCurve.new(points, step).calc
で折れ線(step を細かくすればベジェ曲線に見えるわけです)の頂点(Vector クラスで表現されています)を順に与える Enumerator を返します。step は省略されれば 0.01 がデフォルトになります。曲線は t = 0 が開始で t = 1 が終了なので、step は一回に進む t の値を指定します。step = 0.01 ならば曲線が 100分割されるということです。
なお、なめらかな曲線としては「スプライン曲線」というのもあります。下の記事で扱っています。
obelisk.hatenablog.com