ベジエ曲線のバウンディングボックス

Bézier curve - Wikipedia, the free encyclopedia

B(t) = (1-t)^3 * P0 + 3 * (1-t)^2 * t * P1 + 3 * (1-t) * t^2 * P2 + t^3 * P3
なので
B'(t) = -3 * P0 * (1 - t)^2 + 3 * P1 * (1 - t)^2 - 6 * P1 * (1 - t) * t + 6 * P2 * (1 - t) * t - 3 * P2 * t^2 + 3 * P3 * t^2
の解t = *1(-3 P0+9 P1-9 P2+3 P3!=0)のうち0~1に収まるtの時のB(t)の値を計算して、B(0) = P0、B(1) = P3とあわせて最小値と最大値を求めればいいな。たぶん。後で実装しよう。




あってそう。

(ここにあったコードは全然あっていなかったので削除しました)




こんどこそあってそう。




うひひ。

5次元の空間上に分布しているので切断面を変えると色々変わる。



しばらく動かしてみて特に目立った問題が見つからないので公開。MIT Licenseで、とか書いておくと使いやすいのかな??

    def calc_box(start, curves):
        P0 = start
        bounds = [[P0[0]], [P0[1]]]

        for c in curves:
            P1, P2, P3 = (
                (c[0], c[1]), 
                (c[2], c[3]), 
                (c[4], c[5]))

            bounds[0].append(P3[0])
            bounds[1].append(P3[1])

            for i in [0, 1]:
                f = lambda t: (
                    (1-t)**3 * P0[i] 
                    + 3 * (1-t)**2 * t * P1[i] 
                    + 3 * (1-t) * t**2 * P2[i]
                    + t**3 * P3[i])

                b = float(6 * P0[i] - 12 * P1[i] + 6 * P2[i])
                a = float(-3 * P0[i] + 9 * P1[i] - 9 * P2[i] + 3 * P3[i])
                c = float(3 * P1[i] - 3 * P0[i])

                if a == 0:
                    if b == 0:
                        continue
                    t = -c / b
                    if 0 < t < 1: 
                        bounds[i].append(f(t))
                    continue

                b2ac = b ** 2 - 4 * c * a
                if b2ac < 0: 
                    continue
                t1 = (-b + sqrt(b2ac))/(2 * a)
                if 0 < t1 < 1: bounds[i].append(f(t1))
                t2 = (-b - sqrt(b2ac))/(2 * a)
                if 0 < t2 < 1: bounds[i].append(f(t2))

            P0 = P3

        x = min(bounds[0])
        w = max(bounds[0]) - x
        y = min(bounds[1])
        h = max(bounds[1]) - y
        return (x, y, w, h)

*1:-6 P0+12 P1-6 P2)+-sqrt((6 P0-12 P1+6 P2)^2-4 (3 P1-3 P0) (-3 P0+9 P1-9 P2+3 P3)))/(2 (-3 P0+9 P1-9 P2+3 P3