(x0,y0)... (xn,yn)
私は単調な点の配列を持っており、x
ベジェ曲線を使用してこれらを通して「最良の」曲線を描きたいと思っています。この曲線は、「ぎざぎざ」になりすぎてはならず(たとえば、ドットを結合するのと同じように)、曲がりすぎてはいけません(そして間違いなく「後方に移動」してはなりません)。プロトタイプを作成しましたが、客観的に「最善の解決策」があるかどうか疑問に思います。
すべてのセグメントのコントロールポイントを見つける必要がありますxi,y1 x(i+1)y(i+1)
。セグメントに対する私の現在のアプローチ(エンドポイントを除く)x(i), x(i+1)
は次のとおりです。
- ベクトルを見つけ
x(i-1)...x(i+1)
、正規化し、それをスケーリングしてfactor * len(i,i+1)
、主要な制御点のベクトルを与えます - ベクトルを見つけ
x(i+2)...x(i)
、正規化し、それをスケーリングしてfactor * len(i,i+1)
、後続の制御点のベクトルを与えます。
私はfactor=0.1(ジャギーすぎる)、0.33(曲がりすぎる)、0.20を試しました-ほぼ正しいです。しかし、(たとえば)2次および3次導関数を可能な限りスムーズにするより良いアプローチはありますか。(私はそのようなアルゴリズムがグラフィックパッケージに実装されていると思います)?
要求があれば、擬似/コードを投稿できます。これが3つの画像(0.1 / 0.2 / 0.33)です。コントロールポイントは直線で示されます:黒(末尾)と赤(先頭)
これが現在のコードです。これは、 -ingなしで(単調)Y
に対してプロットすることを目的としています。SVG(推奨出力)を作成するための独自のライブラリを構築しました。このコードは、曲線セグメント(control1、xcontrol2、end)ごとにinのトリプルを作成します。開始は最後の操作(移動または曲線)によって想定されます。これはJavaですが、解釈しやすいはずです(cubicにマップされ、SVGでの完全なパスの文字列表現です)。X
X
close
x,y
coordArray
CurvePrimitive
"d"
List<SVGPathPrimitive> primitiveList = new ArrayList<SVGPathPrimitive>();
primitiveList.add(new MovePrimitive(real2Array.get(0)));
for(int i = 0; i < real2Array.size()-1; i++) {
// create path 12
Real2 p0 = (i == 0) ? null : real2Array.get(i-1);
Real2 p1 = real2Array.get(i);
Real2 p2 = real2Array.get(i+1);
Real2 p3 = (i == real2Array.size()-2) ? null : real2Array.get(i+2);
Real2Array coordArray = plotSegment(factor, p0, p1, p2, p3);
SVGPathPrimitive primitive = new CurvePrimitive(coordArray);
primitiveList.add(primitive);
}
String d = SVGPath.constructDString(primitiveList);
SVGPath path1 = new SVGPath(d);
svg.appendChild(path1);
/**
*
* @param factor to scale control points by
* @param p0 previous point (null at start)
* @param p1 start of segment
* @param p2 end of segment
* @param p3 following point (null at end)
* @return
*/
private Real2Array plotSegment(double factor, Real2 p0, Real2 p1, Real2 p2, Real2 p3) {
// create p1-p2 curve
double len12 = p1.getDistance(p2) * factor;
Vector2 vStart = (p0 == null) ? new Vector2(p2.subtract(p1)) : new Vector2(p2.subtract(p0));
vStart = new Vector2(vStart.getUnitVector().multiplyBy(len12));
Vector2 vEnd = (p3 == null) ? new Vector2(p2.subtract(p1)) : new Vector2(p3.subtract(p1));
vEnd = new Vector2(vEnd.getUnitVector().multiplyBy(len12));
Real2Array coordArray = new Real2Array();
Real2 controlStart = p1.plus(vStart);
coordArray.add(controlStart);
Real2 controlEnd = p2.subtract(vEnd);
coordArray.add(controlEnd);
coordArray.add(p2);
// plot controls
SVGLine line12 = new SVGLine(p1, controlStart);
line12.setStroke("red");
svg.appendChild(line12);
SVGLine line21 = new SVGLine(p2, controlEnd);
svg.appendChild(line21);
return coordArray;
}