Graphics 使用Bezier曲线绘制图形

Graphics 使用Bezier曲线绘制图形,graphics,plot,bezier,Graphics,Plot,Bezier,我有一个点数组(x0,y0)。。。(xn,yn)在x中单调,并希望通过使用贝塞尔曲线绘制“最佳”曲线。该曲线不应太“锯齿状”(例如,类似于连接点),也不应太曲折(绝对不应“向后”)。我已经创建了一个原型,但不知道是否有一个客观的“最佳解决方案” 我需要找到所有分段的控制点xi,y1 x(I+1)y(I+1)。我目前对x(i),x(i+1)段的方法(端点除外)是: 找到向量x(i-1)…x(i+1),对其进行规格化,并按因子*len(i,i+1)对其进行缩放,以给出领先控制点的向量 找到向量x(

我有一个点数组
(x0,y0)。。。(xn,yn)
x
中单调,并希望通过使用贝塞尔曲线绘制“最佳”曲线。该曲线不应太“锯齿状”(例如,类似于连接点),也不应太曲折(绝对不应“向后”)。我已经创建了一个原型,但不知道是否有一个客观的“最佳解决方案”

我需要找到所有分段的控制点
xi,y1 x(I+1)y(I+1)
。我目前对
x(i),x(i+1)
段的方法(端点除外)是:

  • 找到向量
    x(i-1)…x(i+1)
    ,对其进行规格化,并按
    因子*len(i,i+1)
    对其进行缩放,以给出领先控制点的向量
  • 找到向量
    x(i+2)…x(i)
    ,标准化,并按
    因子*len(i,i+1)
    对其进行缩放,以给出跟踪控制点的向量
我试过系数=0.1(太粗糙),0.33(太弯曲)和0.20-大约右边。但是否有更好的方法(比如)使第二和第三导数尽可能平滑。(我假设这样的算法是在图形包中实现的)

如果需要,我可以发布伪代码。以下是三个图像(0.1/0.2/0.33)。控制点以直线显示:黑色(尾随)和红色(前导)

这是当前的代码。它旨在绘制
Y
X
(单调
X
)的对比图,而无需
关闭
。我建立了自己的库来创建SVG(首选输出);此代码在
coordArray
中为每个曲线段(control1、xcontrol2、end)创建三个
x,y
。由最后一个操作(移动或曲线)假定开始。它是Java,但应该易于解释(
CurvePrimitive
映射到cubic,
“d”
是SVG中完整路径的字符串表示)

List primitiveList=new ArrayList();
add(newmoveprimitive(real2Array.get(0));
对于(int i=0;i
贝塞尔曲线需要数据点,以及每个点的斜率和曲率。在图形程序中,坡度由控制线的坡度设置,曲率由长度显示

当用户没有输入这样的控制线时,需要估计每个点的梯度和曲率。wikipedia页面,特别是“插入数据集”部分有一个直接获取这些值的公式

通常,从点估算这些值是使用有限差分法完成的,因此您可以使用任意一侧的点的值来帮助估算。这里唯一的选择是如何处理只有一个相邻点的端点:可以将曲率设置为零,或者如果曲线是周期性的,则可以“环绕”并使用最后一个点的值

我引用的wikipedia页面也有其他方案,但大多数方案都会引入一些其他“自由参数”,您需要找到一种设置方法,因此在没有更多信息帮助您决定如何设置其他参数的情况下,我会选择简单的方案,看看您是否喜欢结果

如果维基百科的文章不够清晰,请告诉我,我会编一些代码

还有一点需要注意:你想要什么样的贝塞尔插值?大多数图形程序都在二维中使用三次贝塞尔(即,您可以绘制一条类似于圆的曲线),但您的示例图像看起来可能是1d函数近似值(因为对于每个x,只有一个y值)。图形程序类型曲线在我引用的页面上没有真正提到。将斜率和曲率的估计值转换为(三次贝塞尔)所示形式的控制向量所涉及的数学需要一些计算,但其思想是相似的

下面是可能方案的图片和算法,假设您的唯一输入是三个点P1、P2、P3

构造一条直线(C1,P1,C2),使角度(P3,P1,C1)和(P2,P1,C2)相等。以类似的方式构造其他深灰色线条。这些深灰色线(标记为C1、C2和C3)的交点成为控制点,如图所示
        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;
}
function lagrange(points) { //points is  [ [x1,y1], [x2,y2], ... ]
//  See: http://www.codecogs.com/library/maths/approximation/interpolation/lagrange.php
  var j,n = points.length;
  var p = [];
  for (j=0;j<n;j++) {
    p[j] = function (x,j) { //have to pass j cos JS is lame at currying
      var k, res = 1;
      for (k=0;k<n;k++)
        res*=( k==j ? points[j][1] : ((x-points[k][0])/(points[j][0]-points[k][0])) );
      return res; 
    }
  }
  return function(x) {
    var i, res = 0;
    for (i=0;i<n;i++)
      res += p[i](x,i);
    return res;
  }
}