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?
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/
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
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/