2次ベジェ曲線の制御点を求める
2次ベジェ曲線で円弧を近似します。
円弧は単位円の部分集合とし、円弧の角度を とします。
両端点 は円弧と一致するものとします。
両端点の接線ベクトルは円弧の接線ベクトルと方向が同じものであるとします。
が の接線ベクトル と同じ方向であることから であり、
また、 の接線ベクトル と同じ方向であることから となります。
の 成分を比較して、 を求めます。
式 により、 は にのみ依存することが分かりました。
が求まったので、2次ベジェ曲線の制御点の座標が定まりました。
円弧の中心からの距離が最大となるパラメータの値
円弧の中心からの距離が最大となるパラメータ の値を求めてみます。
円弧の中心は原点なので、距離の2乗は以下のようになります。
式 を で微分して と置きます。
はかなり複雑な式なります。(なので、記載しません(できません)。)
式 を について解いた結果は、以下となります。(この解法については、本記事の下側に記載します。)
式 の は円弧上の点であり、円弧の中心からの距離は極小値(最小値) を取ります。
の時、円弧の中心からの距離は極大値(最大値)を取ります。
度の時の を計算してみます。
角度 | 長さ |
22.5度 | 1.00018821930577 |
45度 | 1.00313586640184 |
67.5度 | 1.01707969308632 |
90度 | 1.06066017177982 |
112.5度 | 1.17776133964622 |
135度 | 1.49790468105892 |
上の表より、2次ベジェ曲線で円弧を近似するときはが45度ぐらいで、区切るのが良さそうです。
グラフは以下になります。
式 (5) のSymPyによる解法
SymPyでは式 は のままだと について解けないようです。(参考サイトによるとmaximaなら多分解けます。)
に適当な値を代入すれば について解くことができます。
import sympy sympy.init_printing() sympy.var("px py p0_x p0_y p1_x p1_y p2_x p2_y t theta kappa alpha") px = (1-t)**2 * p0_x + 2 * (1-t) * t * p1_x + t ** 2 * p2_x py = (1-t)**2 * p0_y + 2 * (1-t) * t * p1_y + t ** 2 * p2_y len2 = px ** 2 + py ** 2 len2 = len2.subs([ (p0_x, sympy.cos(theta)), (p0_y, sympy.sin(theta)), (p1_x, 1), (p1_y, sympy.tan(theta/2)), (p2_x, 1), (p2_y, 0), (theta, sympy.pi * 0.5) # change here ]) len2d = sympy.diff(len2, t) eq = sympy.Eq(len2d, 0) solve = sympy.solve(eq, t) display(solve)
コードの実行結果
式 (8) のSymPyによる解法
import sympy sympy.init_printing() sympy.var("px py p0_x p0_y p1_x p1_y p2_x p2_y t theta kappa alpha") px = (1-t)**2 * p0_x + 2 * (1-t) * t * p1_x + t ** 2 * p2_x py = (1-t)**2 * p0_y + 2 * (1-t) * t * p1_y + t ** 2 * p2_y len2 = px ** 2 + py ** 2 len2 = len2.subs([ (p0_x, sympy.cos(theta)), (p0_y, sympy.sin(theta)), (p1_x, 1), (p1_y, sympy.tan(theta/2)), (p2_x, 1), (p2_y, 0), (t, sympy.Rational(1,2)), #(theta, sympy.pi * 0.5) # change here ]) len = sympy.sqrt(len2) lensub = len.subs([ (theta, sympy.pi * 0.125), # change here ]) print(lensub.evalf()) print("\\begin{eqnarray}") print("&&" + sympy.latex(len2) + "\\\\") print("\\end{eqnarray}")
コードの実行結果
1.00018821930577
\begin{eqnarray}
&&\left(\frac{\sin{\left(\theta \right)}}{4} + \frac{\tan{\left(\frac{\theta}{2} \right)}}{2}\right)^{2} + \left(\frac{\cos{\left(\theta \right)}}{4} + \frac{3}{4}\right)^{2}\\
\end{eqnarray}