平行曲線を描くだけであれば、2:平行曲線を描く の方法で十分である。 しかし、 この方法で生成した式は複雑で、これまでに考えてきた方法で交点を算出することができない。 もし、ベジエ曲線に平行な曲線を、ベジエ曲線の形式で求めることができれば、これまでの方法を適用することができる。
始点・終点
ベジェ曲線の最初の制御点と最後の制御点は、曲線の端を表しているので、新しい曲線の両端は、もとの曲線の両端から法線方向にずらした場所にする。
第1制御点・第2制御点
始点・終点から、隣り合う制御点を結ぶ直線(P0P1とP3P2)の方向は、始点・終点での接線の方向と等しい。 元曲線の両端P0, P3に対応する平行曲線の両端p0, p3の接線も、元曲線のP0P1, P3P2と同じ方向になっていなければならないので、平行曲線のp1, p2は、p0, p3から引かれる直線上に存在することになる。 パラメータt=0.5 を代入した平行曲線の式の値を、元の曲線のt=0.5の位置からずらした場所Mであると仮定し、平行曲線の第1制御点・第2制御点の中点を仮に求める。
p1とp2の中点が求まることによって、p1からp2が一意に求められるようになる。
矛盾
p1とp2の中点が求まったので、以下のように角を設定し、Oが中点になるようなθ1, θ2を求めることができる。 atan2は数学関係のライブラリの多くに含まれている関数。 a=m2/m1
しかし、Mが中点になるように角度を設定しても、Mの接線と、対応する元曲線の接線が平行にならず、平行な曲線が得られなかった。平行曲線のt=0.5地点は、元の曲線のt=0.5地点であるとは限らないことがわかった。
数値計算
「元の曲線のどの地点から法線方向に太さ分ずらした位置が、平行曲線のt=0.5地点となるか。」を知りたい。 最初はt=0.5地点であると仮定し、0.5地点の線の向きがずれていたら、たとえば0.5+0.1の場所であると仮定して元曲線の0.6と平行曲線の0.5の方向を比較する。ずれが大きくなったら逆方向に少しずつ進むようにする。誤差が少なくなるまで繰り返す。
//数値計算によって正確な平行ベジェ曲線の制御点を算出 public Bezier ParallelBezier2(double w) { double t = 0.5; double delta = 0.01; Bezier result; double rad = 100; double rad_prev; string test = ""; do { result = ParallelBezier(w, t); rad_prev = rad; rad = Math.Acos(Vec2D.inproduct(result.d_val(0.5), d_val(t)) / (result.d_val(0.5).length * d_val(t).length)); if (rad_prev > Math.PI * 2)//初回 { } else { if (Math.Abs(rad) - Math.Abs(rad_prev) > 0) { delta *= -0.5; } } t += delta; test += t + "," + rad + "n"; } while ((rad > Math.PI / 18000) && (Math.Abs(rad-rad_prev)>0.000000001 )); return ParallelBezier(w, t); }
これでも、変な形の曲線では誤差が出てきます。そんな時には曲線を分割すれば良いと思います。とりあえずは。