らんだむな記憶

blogというものを体験してみようか!的なー

rubyとBézierと

rubyでBézierの計算をしようと思って、まずは雰囲気だけ書いた。(主に演算子の優先順位について。いちいち調べたくないから動かして観察する!)
演算子式 (Ruby 1.9.3)を見られるのは優秀なやつだけ!

排他的論理和(XOR)のために ^ が使われているから、冪乗の計算にハットを使えないのが不便だゎ~。

#! /usr/bin/ruby -Ku

class Point
    attr_reader :x, :y

    def initialize(x, y)
        @x = x; @y = y
    end
end

class Bezier
    def initialize(p0, p1, p2, p3)
        @p0 = p0; @p1 = p1; @p2 = p2; @p3 = p3
    end

    def pos(t)
        x = (1-t)**3 * @p0.x + 3 * (1-t)**2 * t * @p1.x + 3 * (1-t) * t**2 * @p2.x + t**3 * @p3.x
        y = (1-t)**3 * @p0.y + 3 * (1-t)**2 * t * @p1.y + 3 * (1-t) * t**2 * @p2.y + t**3 * @p3.y

        return x, y
    end
end


################################################################################

b = Bezier.new(Point.new(1, -1), Point.new(1, 0), Point.new(1, 0), Point.new(1, 1))

0.upto(10) do |i|
    p b.pos(0.1 * i)
end

はぁ... しっかりと丸め誤差が出よるゎ...。
(1, -1)→(1, 1)のstraight curveのつもりだし、数式上はx成分は恒等的に1のはずなんだがね。

$ ruby bezier_test.rb
[1.0, -1.0]
[1.0, -0.7280000000000001]
[1.0000000000000002, -0.5040000000000001]
[1.0, -0.3159999999999999]
[1.0, -0.15199999999999997]
[1.0, 0.0]
[0.9999999999999999, 0.15200000000000014]
[1.0, 0.3160000000000001]
[1.0, 0.5040000000000001]
[1.0, 0.7280000000000001]
[1.0, 1.0]

ま、

        return x, y

のとこを

        return x.round(10), y.round(10)

にでもすれば、上記の場合はなんか綺麗になるけど、丸め誤差を適当な決め打ちの桁で四捨五入するのもますます制御が難しくなりそうだね!ご利用は計画的に!だね!