gpt4 book ai didi

graphics - 使用贝塞尔曲线绘制图形

转载 作者:行者123 更新时间:2023-12-01 02:28:52 25 4
gpt4 key购买 nike

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

我需要找到所有段的控制点 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)。控制点用直线表示:黑色(尾随)和红色(前导)

    using factor=0.1

    using factor=0.2

    using factor=0.33

    这是当前代码。它的目的是绘制 Y反对 X (单调 X )没有 close -ing。我已经建立了自己的用于创建 SVG 的库(首选输出);这段代码创建了 x,y 的三元组在 coordArray对于每个曲线段(control1、xcontrol2、end)。开始由最后一次操作(移动或曲线)假设。它是 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;
    }

    最佳答案

    贝塞尔曲线需要数据点,以及每个点的斜率和曲率。在图形程序中,斜率由控制线的斜率设置,曲率由长度可视化。

    当您没有用户输入此类控制线时,您需要估计每个点的梯度和曲率。维基百科页面http://en.wikipedia.org/wiki/Cubic_Hermite_spline ,特别是“插值数据集”部分有一个直接采用这些值的公式。

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

    我引用的维基百科页面也有其他方案,但大多数其他人介绍了一些其他“免费参数”,您需要找到一种设置方式,因此在没有更多信息来帮助您决定如何设置其他参数的情况下,我' d 选择简单的方案,看看你是否喜欢结果。

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

    需要注意的另一点:您追求的是什么“类型”的贝塞尔插值?大多数图形程序在二维中进行三次贝塞尔曲线(即您可以绘制圆形曲线),但您的示例图像看起来可能是一维函数近似值(因为每个 x 只有一个 y 值)。我引用的页面上并没有真正提到图形程序类型曲线。将斜率和曲率的估计值转换为 http://en.wikipedia.org/wiki/B%C3%A9zier_curve 中所示形式的控制向量所涉及的数学运算(Cubic Bezier) 需要一些锻炼,但这个想法是相似的。

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

    Bezier Interpolation Scheme

    构造一条线 (C1,P1,C2),使得 (P3,P1,C1) 和 (P2,P1,C2) 的角度相等。以类似的方式构建其他深灰色线条。这些深灰色线的交点(标记为 C1、C2 和 C3)成为控制点,与贝塞尔曲线维基百科网站上的图像具有相同的意义。所以每条红色曲线,例如 (P3,P1),都是由点 (P3, C1, P1) 定义的二次贝塞尔曲线。红色曲线的构造与维基百科网站上给出的相同。

    但是,我注意到 Bezier Curve 维基百科页面上的控制向量似乎与您使用的控制向量类型不匹配,因此您可能必须弄清楚如何将这两种方法等同起来。

    关于graphics - 使用贝塞尔曲线绘制图形,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14398178/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com