Can I make a half-bezier from full bezier?

眉间皱痕 提交于 2019-12-03 21:40:46

De Casteljau is indeed the algorithm to go. For a cubic Bezier curve defined by 4 control points P0, P1, P2 and P3, the control points of the sub-Bezier curve (0, u) are P0, Q0, R0 and S0 and the control points of the sub-Bezier curve (u, 1) are S0, R1, Q2 and P3, where

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

Please note that if you want to "extract" a segment (u1, u2) from the original Bezier curve, you will have to apply De Casteljau twice. The first time will split the input Bezier curve C(t) into C1(t) and C2(t) at parameter u1 and the 2nd time you will have to split the curve C2(t) at an adjusted parameter u2* = (u2-u1)/(1-u1).

Noitidart

This is how to do it. You can get the left half or right half with this functin. This function is take thanks to mark from here: https://stackoverflow.com/a/23452618/1828637

I have it modified so it can be fit to a unit cell so we can use it for cubic-bezier in css transitions.

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};
  }
}

Thats the function and now to use it with your parameters.

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
});

This gives you

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

fiddle proving its half, i overlaid it over your original:

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

Yes it is! Have a look at the bezier section here

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

It is not that difficult all in all.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!