【问题标题】:Trying to find length of a bezier curve with 4 points试图找到 4 个点的贝塞尔曲线的长度
【发布时间】:2016-11-15 18:23:14
【问题描述】:

我已经找到了大约 1000 个关于这个问题的答案,但没有一个我可以使用,因为我的曲线使用了 4 个控制点。

也就是说,我偶然发现了这个人here

double BezierArcLength(point2d p1, point2d p2, point2d p3, point2d p4)
{
    point2d k1, k2, k3, k4;

    k1 = -p1 + 3*(p2 - p3) + p4;
    k2 = 3*(p1 + p3) - 6*p2;
    k3 = 3*(p2 - p1);
    k4 = p1;

    q1 = 9.0*(sqr(k1.x) + sqr(k1.y));
    q2 = 12.0*(k1.x*k2.x + k1.y*k2.y);
    q3 = 3.0*(k1.x*k3.x + k1.y*k3.y) + 4.0*(sqr(k2.x) + sqr(k2.y));
    q4 = 4.0*(k2.x*k3.x + k2.y*k3.y);
    q5 = sqr(k3.x) + sqr(k3.y);

    double result = Simpson(balf, 0, 1, 1024, 0.001);
    return result;
}

看起来这将是一个完美的解决方案,但开始的部分让我完全困惑:

k1 = -p1 + 3*(p2 - p3) + p4;
k2 = 3*(p1 + p3) - 6*p2;
k3 = 3*(p2 - p1);
k4 = p1;

我到底应该如何对二维对象进行加法、减法和乘法之类的操作(我假设 point2d 是像 {x: 0, y: 0} 这样的对象结构)?我觉得自己很愚蠢,但这是唯一让我无法真正实现这个怪物的事情。

FWIW,我正在使用这个方程来标准化实体在游戏中穿越曲线时的速度。如果您完全知道这样做的更好方法,我会全力以赴。

【问题讨论】:

  • 问题:我到底应该如何对二维对象进行加、减、乘之类的操作?答案:您一次在一个坐标(x 或 y)上执行它们。

标签: javascript math canvas bezier


【解决方案1】:

以下是匀速遍历三次贝塞尔曲线的方法

没有一个简单的公式可以沿三次贝塞尔曲线获得偶数长度段(即偶数弧长段)。所涉及的是计算沿曲线的许多点,然后使用插值将每个点“微调”为大致等距。

我可以让你接近那里,而无需获得数学博士学位。

首先使用通用公式计算曲线上从 t=0 到 t=1 的 x/y 点,其中 t=0 表示曲线的起点,t=1 表示曲线的终点。这是常用的公式:

// calc the x/y point at t interval
// t=0 at startPt, t=1 at endPt
var x=CubicN(t,startPt.x,controlPt1.x,controlPt2.x,endPt.x);
var y=CubicN(t,startPt.y,controlPt1.y,controlPt2.y,endPt.y);

// cubic helper formula at t interval
function CubicN(t, a,b,c,d) {
    var t2 = t * t;
    var t3 = t2 * t;
    return a + (-a * 3 + t * (3 * a - a * t)) * t
    + (3 * b + t * (-6 * b + b * 3 * t)) * t
    + (c * 3 - c * 3 * t) * t2
    + d * t3;
}

如果您计算出足够多的间隔,例如 100 个间隔(每个循环 t += .01),那么您将获得非常好的曲线近似值。

这意味着如果你用线连接这 100 个点,结果看起来很像三次贝塞尔曲线。

但你还没有完成!

上面计算的一系列x/y点彼此的弧距不均匀。

一些相邻点靠得很近,一些相邻点相距较远。

计算均匀分布的点:

  1. 用线连接所有点(创建折线)。
  2. 计算该折线的总距离 (T)。
  3. 将 (T) 除以所需的统一段数,得到统一段长度 (SL)
  4. 最后,从头到尾遍历折线,计算每个点与前一点的 (SL) 距离。

结果:您可以使用这些等距点来遍历您的曲线。

额外细化:这应该会导致您的贝塞尔路径在视觉上平滑移动。但是,如果您想要更多的平滑度,只需计算 100 多个点——更多点 == 更多平滑度。

【讨论】:

  • 只是为了尝试将第 4 点扩展到其他(像我一样)与之斗争的人。在我的例子中,我采集了 10 个不同区间的样本(在上面的例子中表示为“t”)。一旦我得到“SL”,我不是将每个样本除以 10,而是将它除以它的间隔平均长度的结果。方程类似于single sample from interval (t) / (length of interval / average length of all intervals)。您可能还需要调整您的 10 次方,但我不确定这是肯定的还是仅对我而言。
【解决方案2】:

二维对象或 Point2D 只是一个向量,Vector Arithmetic 在数学中是明确定义的。例如:

          k*(x,y) = (k*x, k*y)
           -(x,y) = (-1)*(x,y)
(x1,y1) + (x2,y2) = (x1+x2, y1+y2)

这些是计算k1k2k3k4 所需的所有公式

【讨论】:

  • 这不是 TS 要求的。
  • 嗯,这是他的问题的一部分,“我到底应该如何对二维对象进行加、减和乘之类的操作?”
猜你喜欢
  • 2011-03-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多