我有一系列(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 - 差不多。但是有没有更好的方法(比如说)使二阶和三阶导数尽可能平滑。(我假设这样的算法是在图形包中实现的)?
如果需要,我可以发布伪/代码。这是三个图像(0.1/0.2/0.33)。控制点用直线表示:黑色(尾随)和红色(前导)
这是当前代码。它的目的是在没有-ing的情况下Y
针对X
(monotonic X
) 进行绘图。close
我已经建立了自己的用于创建 SVG 的库(首选输出);此代码为每个曲线段(control1、xcontrol2、end)创建三倍的x,y
in 。coordArray
开始由最后一次操作(移动或曲线)假设。它是 Java,但应该易于解释(CurvePrimitive
映射到三次,"d"
是 SVG 中完整路径的字符串表示形式)。
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;
}