【问题标题】:Can I make a half-bezier from full bezier?我可以从全贝塞尔曲线制作半贝塞尔曲线吗?
【发布时间】:2014-11-01 13:54:36
【问题描述】:

以 JavaScript 绘制的典型三次贝塞尔曲线(这个例子我用谷歌搜索...) http://jsfiddle.net/atsanche/K38kM/

具体来说,这两行:

context.moveTo(188, 130);
context.bezierCurveTo(170, 10, 350, 10, 388, 170);

我们有一个三次贝塞尔曲线,它从 188, 130 开始,在 388, 170 结束,并具有控制点 a:170, 10 和 b:350, 10

我的问题是,是否可以通过数学方式调整终点和控制点以制作另一条曲线,它只是原始曲线的一部分?

理想的结果是能够从一开始就提取贝塞尔曲线的百分比切片,其中 0.5 将仅绘制一半贝塞尔曲线,0.75 将绘制大部分贝塞尔曲线(依此类推)

我已经开始使用 De Castelau 的一些实现,它们允许我在 [0...1] 之间追踪贝塞尔曲线的轮廓,但这并没有提供一种在数学上重新计算结束点和控制点的方法的贝塞尔曲线来制作子贝塞尔曲线......

提前致谢

【问题讨论】:

  • 有可能吗?是的。与卡斯泰尔约?是的。但是如何?...by proceeding in this way。只说 Casteljau 是必要的还不够。正确且更难的答案是如何使用Casteljau...

标签: javascript canvas bezier


【解决方案1】:

是的!看看这里的贝塞尔曲线部分

http://en.m.wikipedia.org/wiki/De_Casteljau's_algorithm

总的来说,这并不难。

【讨论】:

  • 实际上我发现你引用的例子中的数学非常高级,并没有清楚地解释细分贝塞尔曲线。但是,使用您链接中的图表,我拼凑了我需要的事实:终点在 [0...1] 处完全遵循曲线,并且控制点从其原始位置接近先前的点 [0. ..1]。我不愿意将此标记为正确答案,因为现在我很想发布一个脚本示例,但同时你帮助我对我的问题得出结论,所以谢谢你的回答。
  • 好吧,几何解释很简单,而数学以外的东西则不然。贝塞尔曲线本质上并不是那么简单,但在这种情况下,运气就在你身边。 N.b.:我可以推荐 paper.js 一个不错的画布矢量曲线库...
【解决方案2】:

De Casteljau 确实是要采用的算法。对于由 4 个控制点 P0、P1、P2 和 P3 定义的三次贝塞尔曲线,子贝塞尔曲线 (0, u) 的控制点为 P0、Q0、R0 和 S0 以及子贝塞尔曲线的控制点(u, 1) 是 S0、R1、Q2 和 P3,其中

Q0 = (1-u)*P0 + u*P1
Q1 = (1-u)*P1 + u*P2
Q2 = (1-u)*P2 + u*P3
R0 = (1-u)*Q0 + u*Q1
R1 = (1-u)*Q1 + u*Q2
S0 = (1-u)*R0 + u*R1

请注意,如果您想从原始贝塞尔曲线中“提取”一段(u1,u2),则必须应用 De Casteljau 两次。第一次将输入贝塞尔曲线 C(t) 在参数 u1 处拆分为 C1(t) 和 C2(t),第二次您将必须在调整后的参数处拆分曲线 C2(t) u2* = (u2 -u1)/(1-u1)。

【讨论】:

  • 刚刚实施了您的解决方案。工作完美!公平地说,这是对我的问题的更准确的答案。谢谢芳!对不起菲利普
  • 太棒了!我很高兴知道我的回答有帮助。
【解决方案3】:

这是怎么做的。您可以使用此功能获得左半部分或右半部分。此功能感谢此处的标记:https://stackoverflow.com/a/23452618/1828637

我对其进行了修改,使其可以适应单元格,因此我们可以在 css 转换中将其用于cubic-bezier

function splitCubicBezier(options) {
  var z = options.z,
      cz = z-1,
      z2 = z*z,
      cz2 = cz*cz,
      z3 = z2*z,
      cz3 = cz2*cz,
      x = options.x,
      y = options.y;

  var left = [
    x[0],
    y[0],
    z*x[1] - cz*x[0], 
    z*y[1] - cz*y[0], 
    z2*x[2] - 2*z*cz*x[1] + cz2*x[0],
    z2*y[2] - 2*z*cz*y[1] + cz2*y[0],
    z3*x[3] - 3*z2*cz*x[2] + 3*z*cz2*x[1] - cz3*x[0],
    z3*y[3] - 3*z2*cz*y[2] + 3*z*cz2*y[1] - cz3*y[0]];

  var right = [
    z3*x[3] - 3*z2*cz*x[2] + 3*z*cz2*x[1] - cz3*x[0],
    z3*y[3] - 3*z2*cz*y[2] + 3*z*cz2*y[1] - cz3*y[0],
                    z2*x[3] - 2*z*cz*x[2] + cz2*x[1],
                    z2*y[3] - 2*z*cz*y[2] + cz2*y[1],
                                    z*x[3] - cz*x[2], 
                                    z*y[3] - cz*y[2], 
                                                x[3],
                                                y[3]];

  if (options.fitUnitSquare) {
    return {
      left: left.map(function(el, i) {
        if (i % 2 == 0) {
          //return el * (1 / left[6])
          var Xmin = left[0];
          var Xmax = left[6]; //should be 1
          var Sx = 1 / (Xmax - Xmin);
          return (el - Xmin) * Sx;
        } else {
          //return el * (1 / left[7])
          var Ymin = left[1];
          var Ymax = left[7]; //should be 1
          var Sy = 1 / (Ymax - Ymin);
          return (el - Ymin) * Sy;
        }
      }),
      right: right.map(function(el, i) {
        if (i % 2 == 0) {
          //xval
          var Xmin = right[0]; //should be 0
          var Xmax = right[6];
          var Sx = 1 / (Xmax - Xmin);
          return (el - Xmin) * Sx;
        } else {
          //yval
          var Ymin = right[1]; //should be 0
          var Ymax = right[7];
          var Sy = 1 / (Ymax - Ymin);
          return (el - Ymin) * Sy;
        }
      })
    }
  } else {
   return { left: left, right: right};
  }
}

这就是函数,现在将它与您的参数一起使用。

var myBezier = {
  xs: [188, 170, 350, 388],
  ys: [130, 10, 10, 170]
};

var splitRes = splitCubicBezier({
  z: .5, //percent
  x: myBezier.xs,
  y: myBezier.ys,
  fitUnitSquare: false
});

这给了你

({
    left: [188, 130, 179, 70, 219.5, 40, 267, 45],
    right: [267, 45, 314.5, 50, 369, 90, 388, 170]
})

小提琴证明了它的一半,我把它覆盖在你原来的上面:

http://jsfiddle.net/K38kM/8/

【讨论】:

  • 一个很好的答案,真正的完美实现。现在第三次更改我选择的答案是否正确?这似乎是某种剥削。实际上,我自己也根据我打算发布的先前选择的答案自己做了一个类似的实现。不过还是感谢您的帮助!
  • 不要担心接受它,如果他们搜索这个,我只是分享以帮助其他人。 :) 如果您也可以分享您的方法,那就太棒了:)
猜你喜欢
  • 2014-09-29
  • 2011-03-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多