【问题标题】:Drawing part of a Bézier curve by reusing a basic Bézier-curve-function?通过重用基本的贝塞尔曲线函数来绘制贝塞尔曲线的一部分?
【发布时间】:2009-05-18 17:28:34
【问题描述】:

假设我正在使用一些允许我绘制的图形 API 通过指定 4 个必要点的贝塞尔曲线: 开始、结束、两个控制点

我能否重复使用此功能来绘制“原始”曲线的 x% (通过调整控制点和终点)?

还是不可能?

不必要的信息,如果有人关心的话:

  • 我需要整个东西来绘制原件的每 n%
    贝塞尔曲线 具有不同的颜色和/或线条样式
  • 我正在使用 Java 的 Path2D 绘制贝塞尔曲线:

    Path2D p = new GeneralPath();
    p.moveTo(x1, y1);
    p.curveTo(bx1, by1, bx2, by2, x2, y2);
    g2.draw(p);
    

【问题讨论】:

    标签: math graphics drawing coordinates


    【解决方案1】:

    您需要的是the De Casteljau algorithm。这将允许您将曲线分割成您想要的任何部分。

    但是,由于您只处理三次曲线,因此我想建议一个更易于使用的公式,它可以为您提供从 t0t1 的部分,其中 0 <= t0 <= t1 <= 1。这是一些伪代码:

    u0 = 1.0 - t0
    u1 = 1.0 - t1
    
    qxa =  x1*u0*u0 + bx1*2*t0*u0 + bx2*t0*t0
    qxb =  x1*u1*u1 + bx1*2*t1*u1 + bx2*t1*t1
    qxc = bx1*u0*u0 + bx2*2*t0*u0 +  x2*t0*t0
    qxd = bx1*u1*u1 + bx2*2*t1*u1 +  x2*t1*t1
    
    qya =  y1*u0*u0 + by1*2*t0*u0 + by2*t0*t0
    qyb =  y1*u1*u1 + by1*2*t1*u1 + by2*t1*t1
    qyc = by1*u0*u0 + by2*2*t0*u0 +  y2*t0*t0
    qyd = by1*u1*u1 + by2*2*t1*u1 +  y2*t1*t1
    
    xa = qxa*u0 + qxc*t0
    xb = qxa*u1 + qxc*t1
    xc = qxb*u0 + qxd*t0
    xd = qxb*u1 + qxd*t1
    
    ya = qya*u0 + qyc*t0
    yb = qya*u1 + qyc*t1
    yc = qyb*u0 + qyd*t0
    yd = qyb*u1 + qyd*t1
    

    然后画出由(xa,ya)(xb,yb)(xc,yc)(xd,yd)组成的贝塞尔曲线。

    请注意,t0t1 不完全是曲线距离的百分比,而是曲线参数空间。如果您绝对必须保持距离,那么事情就会变得更加困难。试试这个,看看它是否能满足您的需求。

    编辑: 值得注意的是,如果 t0t1 为 0 或 1(即您只想从一侧修剪),这些方程式会简化很多。

    另外,0 <= t0 <= t1 <= 1 的关系不是严格要求。例如t0 = 1t1 = 0 可用于向后“翻转”曲线,或者t0 = 0t1 = 1.5 可用于将曲线延伸到原始末端之外。但是,如果您尝试将其延伸到 [0,1] 范围之外,曲线看起来可能与您预期的不同。

    Edit2: 在我最初回答 3 年多之后,MvG 指出了我的方程式中的一个错误。我忘记了最后一步(获得最终控制点的额外线性插值)。上述等式已更正。

    【讨论】:

    • +1 一些评论明确指出点 a 和 d 是原始曲线上定义新部分曲线范围的点会有所帮助。此外,点 b 和 c 是新定义的控制点(即,仅与原始控制点松散相关)。
    • @Bob Cross:注意到了。出于好奇,点 b 位于 a 点沿曲线的切线,而点 c 位于 d 点沿曲线的切线。实际上,a=p(t0), b=a+p'(t0)/3, c=d-p'(t1)/3 and d=p(t1), 其中 p(t) 是t 处的曲线,p'(t) 是 t 处曲线的一阶导数。
    • @Naaff,您的曲线仅使用二次多项式,因此无法准确描述三次曲线(即三次贝塞尔曲线)上的点。当another question 尝试在此基础上构建时注意到了这一点。
    • @MvG,你是对的。我无意中遗漏了线性插值步骤(当与二次方程结合时,它相当于三次)。谢谢,我已经在上面解决了这个问题。
    • 对于那些感兴趣的人,这里是对上述方程的几何解释:Qa=(qxa,qya) 和 Qb=(qxb,qyb) 在由前三个三次控制点形成的二次曲线上.类似地,Qc=(qxc,qyc) 和 Qd=(qxd,qyd) 在最后三个三次控制点形成的二次曲线上。 (xa,ya) 和 (xb,yb) 在 Qa 和 Qc 之间的直线上,而 (xc,yc) 和 (xd,yd) 在 Qb 和 Qd 之间的直线上。
    【解决方案2】:

    an answeranother question 中,我只包含了一些计算三次曲线部分控制点的公式。 u = 1 − t,三次贝塞尔曲线描述为

    B(t) = u3P1 + 3u2t P2 + 3ut2P3 + t3P4

    P1是曲线的起点,P4是曲线的终点。 P2P3 是控制点。

    给定两个参数 t0t1 (以及 u 0 = (1 - t0), u1 = (1 - t1)),曲线在区间[t0, t1] 由新的控制点描述

    • Q1 = u0u0u0P1 + (t0u0u0 + u0t0u0 + u0u0t0) P2 + (t0t0u0 + u0t0t0 + t0u0t0) P3 + t0t0t0P4
    • Q2 = u0u0u1P1 + (t0u0u1 + u0t0u1 + u0u0t1) P2 + (t0t0u1 + u0t0t1 + t0u0t1) P3 + t0t0t1P4
    • Q3 = u0u1u1P1 + (t0u1u1 + u0t1u1 + u0u1t1) P2 + (t0t1u1 + u0t1t1 + t0u1t1) P3 + t0t1t1P4
    • Q4 = u1u1u1P1 + (t1u1u1 + u1t1u1 + u1u1t1) P2 + (t1t1u1 + u1t1t1 + t1u1t1) P3 + t1t1t1P4

    请注意,在括号中的表达式中,至少有一些术语是相等的并且可以组合。我没有这样做,因为我相信这里所说的公式会使模式更清晰。您可以简单地为 xy 方向独立执行这些计算来计算新的控制点。

    请注意,t 的参数范围的给定百分比通常不会对应于长度的相同百分比。因此,您很可能必须对曲线进行积分才能将路径长度转换回参数。或者你使用一些近似值。

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-02-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-05
    • 2014-09-29
    • 2017-05-18
    相关资源
    最近更新 更多