Extrapolate split cubic-bezier to 1,1

I need help with the solution provided here.

Create easy function 40% off set

I need to modify it so that the returned left and rights are extrapolated to 1,1 after splitting. This is because if I don't extrapolate, I can't use the returned split cubic-bezier as a css transition.

So this is the test I did. Please help because real does not match mike way :( I think the issue is I need to extrapolate the result to 1,1. I can't simply double the values though I'm pretty sure.

Code used for getting it the Mike way is this:

var result = split({
    z: .5,
    x: [0, 0.42, 0.58, 1],
    y: [0, 0, 1, 1]
});
alert(result.toSource());

Answers:

Answer

first half is ease-in which is cubic-bezier(.42,0,1,1) and graphically is http://cubic-bezier.com/#.42,0,1,1

Please verify this assumption. (curves original end points are 0,0, and 1,1 in a css timing function) The first half of the bezier curve [0,0, .42,0, .58,1, 1,1] should not be [0,0 .42,0, 1,1, 1,1] The end points are correct (after scaling to 1,1), but you have lost continuity there.

The values returned by Mike's algorithm is correct.

Try this visualisation for an explanation on why your assumption might be wrong.

The algorithm you are using to split is a well known algorithm called de Casteljau algorithm. This method can be geometrically expressed in a very simple manner. Check out the animated visualisations on how this splitting at any arbitrary point is possible https://en.wikipedia.org/wiki/B%C3%A9zier_curve.

However, You may soon hit an issue trying to correctly scale a split portion of a bezier curve to fit in a unit square, with endpoints fixed at 0,0 and 1,1. This probably you can try out quite easily on paper. The easiest way probably is to just linearly scale the control points of the bezier, you will get a squashed curve in most cases though.

Answer

I created a modified version of Mike's split function so it fits it to a unit square :) It uses hkrish's pointers to do coordinate normalization.

Just set parameter fitUnitCell to true. :)

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 easeInOut = {
  xs: [0, .42, .58, 1],
  ys: [0,   0,   1, 1]
};


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

alert(splitRes.toSource())

Tags

Recent Questions

Top Questions

Home Tags Terms of Service Privacy Policy DMCA Contact Us

©2020 All rights reserved.