1

我已经阅读了我可以在这里找到的关于这个主题的所有内容,但我没有设法将部分代码翻译成我能理解的简单 python。

我得到了这个,基于对de Casteljau 算法的非常好的解释:

def divideCurve(p0, cp0, cp1, p1, t):
    # p0 and p1 are the start/end points of the bezier curve,
    # cp0 and cp1 are the control points
    # all points are tuples of their coordinates: p0 = (10, 15)

    Ax = ( (1 - t) * p0[0] ) + (t * cp0[0])
    Ay = ( (1 - t) * p0[1] ) + (t * cp0[1])
    Bx = ( (1 - t) * cp0[0] ) + (t * cp1[0])
    By = ( (1 - t) * cp0[1] ) + (t * cp1[1])
    Cx = ( (1 - t) * cp1[0] ) + (t * p1[0])
    Cy = ( (1 - t) * cp1[1] ) + (t * p1[1])

    Dx = ( (1 - t) * Ax ) + (t * Bx)
    Dy = ( (1 - t) * Ay ) + (t * By)
    Ex = ( (1 - t) * Bx ) + (t * Cx)
    Ey = ( (1 - t) * By ) + (t * Cy)

    Px = ( (1 - t) * Dx ) + (t * Ex)
    Py = ( (1 - t) * Dy ) + (t * Ey)

    print Px, Py

for T in range(0, 11, 1):
    t = T*0.1
    divideCurve(p0, cp0, cp1, p1, t)

但这会使曲线上的点分布不均。

我认为是一个可能的解决方案,但我完全不理解弧长函数的逆代码或如何将其转换为 python。我在这里找到了另一种方法,我认为它采用了不同的方法,但我对在 python 中实现的理解还不够。

如果有人愿意将这一点澄清为简单的python,那就太好了。

4

1 回答 1

3

首先:这是一个没有符号解决方案的问题,即您不能将“length-for-t”函数(在t值 ...,曲线的长度为 X)用于贝塞尔曲线并将其反转你得到“t-for-length”(如果我的长度是……总长度 X 的百分比,我在哪个t值)。因此,您将为此找到的所有实现都是主题的变体

  1. 确定完整的曲线长度,
  2. 确定沿曲线的各种t值的参考长度,以及
  3. 对于与参考值不完全匹配的值,找到它附近的两个t值,然后进行插值。

一些实现会为此使曲线变平(将贝塞尔曲线变成一系列直线),另一些实现会构建一个 distance-for-t Lookup Table (LUT)。一些实现将在已知参考值之间进行线性插值(有效地模拟扁平曲线),其他实现将使用弧插值,将两个已知值之间的每个段近似为(圆形)弧的一部分。对于所有这些实现,底线是您的里程将根据所做的选择而有所不同,但所有这些都接近“真实”结果,您使连续t值之间的距离越小。

最简单,通常也是最快的方法是在连续t值之间构建一个具有“足够小”步长的 LUT,然后甚至不用插值,而是选择最接近实际长度的t点。只要步长导致 1px 或以下的段长度,出于显示目的,您不需要比这更好的东西,因为更高的分辨率实际上不会导致“更好”的点,它们甚至会在同一个像素上如果您使距离参考点更精确。

我在http://pomax.github.io/bezierinfo/#tracing上有一个关于这个的描述,带有代码,它是在 Javascript 中,而不是 python,但是考虑到算法描述,它应该相对简单直接写出来Python 基于您已有的代码。

于 2013-04-28T14:29:15.217 回答