Center point on html quadratic curve

2019-03-27 12:23发布

问题:

I have a quadratic curve drawn on html canvas using context.quadraticCurveTo(controlX, controlY, endX, endY); .

I have the control-point and the starting and end points, which are not necessarily level with each other horizontally.

How can I find the centre point on the curve using these parameters?

Actually I want to put a div tag on this center point. Is there any equation solving involved in this process?

回答1:

quadraticCurveTo draws a quadratic Bézier curve.

The formulas to calculate the coordinates of a point at any given position (from 0 to 1) on the curve are

x(t) = (1-t)^2 * x1 + 2 * (1-t) * t * x2 + t^2 * x3
y(t) = (1-t)^2 * y1 + 2 * (1-t) * t * y2 + t^2 * y3

where (x1, y1) is the starting point, (x2, y2) is the control point and (x3, y3) is the end point.

So, turning that into JavaScript, we end up with something like

function _getQBezierValue(t, p1, p2, p3) {
    var iT = 1 - t;
    return iT * iT * p1 + 2 * iT * t * p2 + t * t * p3;
}

function getQuadraticCurvePoint(startX, startY, cpX, cpY, endX, endY, position) {
    return {
        x:  _getQBezierValue(position, startX, cpX, endX),
        y:  _getQBezierValue(position, startY, cpY, endY)
    };
}

If you pass the start, end and control points to getQuadraticCurvePoint there, along with 0.5 for the halfway position, you should get an object with the X and Y coordinates.

Disclaimer -- I didn't test the code, so your mileage may vary, but it seems right. ;)

EDIT: I tested the code here in a jsfiddle. http://jsfiddle.net/QA6VG/206/



回答2:

Here's a page describing the quadratic equation and it's solution: wiki page . And here is a good tutorial on the subject, complete with diagrams: tutorial



回答3:

A possible way:

// compute coordinates of the middle point of a quadratic Bezier curve
// need two functions: quadraticBezierCurvePoint and quadraticBezierCurvesMiddle

function quadraticBezierCurvePoint(t, c) {
  // compute relative coordinates of a point on the curve using t and c
  // t is a number between 0 and 1
  // c is an array of 3 points:
  //     the initial point of the curve (always (0,0))
  //     the "handle" point of the curve
  //     the final point of the curve
  var t1, t1_2a, t1_2b, t1_2c;
  t1 = 1 - t;
  t1_2a = t1 * t1;
  t1_2b = (2 * t) * t1;
  t1_2c = t * t;
  return {
    x: (c[0].x * t1_2a) + (t1_2b * c[1].x) + (t1_2c * c[2].x),
    y: (c[0].y * t1_2a) + (t1_2b * c[1].y) + (t1_2c * c[2].y)
  };
}

function quadraticBezierCurvesMiddle(m, c) {
  var k, km = 1000,
    km2 = (km >> 1),
    len = 0,
    len2, x, y, a = new Array(km + 1);
  // compute curve lengths from start point to any point
  // store relative point coordinates and corresponding length in array a
  for (k = 0; k <= km; k++) {
    a[k] = {
      pt: quadraticBezierCurvePoint(k / km, c),
      len: 0
    };
    if (k > 0) {
      x = a[k].pt.x - a[k - 1].pt.x;
      y = a[k].pt.y - a[k - 1].pt.y;
      a[k].len = a[k - 1].len + Math.sqrt(x * x + y * y);
    }
  }
  // retrieve the point which is at a distance of half the whole curve length from start point
  // most of the time, this point is not the one at indice km2 in array a, but it is near it
  len2 = a[km].len / 2;
  if (a[km2].len > len2)
    for (k = km2; k >= 0; k--) {
      if (len2 >= a[k].len) break;
    } else
    for (k = km2; k <= km; k++) {
      if (len2 <= a[k].len) break;
    }
    // return absolute coordinates of the point
  return {
    x: Math.round((a[k].pt.x + m.x) * 100) / 100,
    y: Math.round((a[k].pt.y + m.y) * 100) / 100
  };
}

And the corresponding jsfiddle: jsfiddle.net/pTccL/