I'm building a simple 3d framework and have come across an issue when applying my projection matrix to a vector.
This is the code I am using the calculate my perspective project:
var t = near * Math.tan(fov * Math.PI / 180);
var n = far - near;
// width height near far
this.setValues( near / (t * aspect), 0, 0, 0,
0, near / t, 0, 0,
0, 0, -(far + near) / n, -(2 * far * near) / n,
0, 0, -1, 1 );
And then applying my projection to my vector like so:
var w = 1 / ( x * e[3] ) + ( y * e[7] ) + ( z * e[11] ) + e[15];
this.x = (x * e[0] + y * e[4] + z * e[8] + e[12]) * w;
this.y = (x * e[1] + y * e[5] + z * e[9] + e[13]) * w;
this.z = (x * e[2] + y * e[6] + z * e[10] + e[14]) * w;
The problem is the vector will always become [ X: NaN Y: NaN Z: -Infinity ].
I can't understand why its not returning a numerical value? This is what the calculated projection matrix looks like below.
-----------------
| 0.5570236439499305, 0, 0, 0 |
| 0, 1.0000000000000002, 0, 0 |
| 0, 0, -1.0618556701030928, -61.855670103092784 |
| 0, 0, -1, 1 |
-----------------
You're getting NaNs and Infinitys -- check all of your variables and make sure you're not getting any non numbers there. Dividing by 0 (with a negative number) will return -Infinity, so some of your values are resulting in that.
I manage to fix this issue by changing the vector projection code to the following:
var w = ( x * e[3] ) + ( y * e[7] ) + ( z * e[11] ) + e[15];
this.x = (x * e[0] + y * e[4] + z * e[8] + e[12]) / w;
this.y = (x * e[1] + y * e[5] + z * e[9] + e[13]) / w;
this.z = (x * e[2] + y * e[6] + z * e[10] + e[14]) / w;
It seems removing the / 1 from the w calculation fixed the issue.
Related
I am attempting to make a function that can rotate a given 3D point around a 3D origin using transformation matrices.
I do not have experience with linear Algebra, so this is purely based on research.
I saw various other questions on the same topic, but I could not find a clear response.
This is based on the QNA from: https://stackoverflow.com/a/34052492/10448256
My thought was to get the XYZ point and subtract the origin.
From here, multiply the XYZ point by the Rx matrix, take those points and multiply by Ry, and then Rz. Return the point + origin.
This led to the following program:
function rotatePointXYZ(point, origin, rad) {
let ox = origin[0];
let oy = origin[1];
let oz = origin[2];
let px = point[0] - ox;
let py = point[1] - oy;
let pz = point[2] - oz;
let tx = rad[0];
let ty = rad[1];
let tz = rad[2];
let rx = [1, 0, 0, 0, Math.cos(tx), -Math.sin(tx), 0, Math.sin(tx), Math.cos(tx)];
let ry = [Math.cos(ty), 0, Math.sin(ty), 0, 1, 0, -Math.sin(ty), 0, Math.cos(ty)];
let rz = [Math.cos(tz), -Math.sin(tz), 0, Math.sin(tz), Math.cos(tz), 0, 0, 0, 1];
let rotatedX = [(rx[0] * px + rx[1] * py + rx[2] * pz), (rx[3] * px + rx[4] * py + rx[5] * pz), (rx[6] * px + rx[7] * py + rx[8] * pz)];
px = rotatedX[0];
py = rotatedX[1];
pz = rotatedX[2];
let rotatedY = [(ry[0] * px + ry[1] * py + ry[2] * pz), (ry[3] * px + ry[4] * py + ry[5] * pz), (ry[6] * px + ry[7] * py + ry[8] * pz)];
px = rotatedY[0];
py = rotatedY[1];
pz = rotatedY[2];
let rotatedZ = [(rz[0] * px + rz[1] * py + rz[2] * pz), (rz[3] * px + rz[4] * py + rz[5] * pz), (rz[6] * px + rz[7] * py + rz[8] * pz)];
px = rotatedZ[0];
py = rotatedZ[1];
pz = rotatedZ[2];
return [px + ox, py + oy, pz + oz]
}
console.log(rotatePointXYZ([1, 1, 1], [0, 0, 0], [Math.PI / 2, Math.PI / 2, 0]))
The issue is that this function is also rotating the coordinate within the z-axis despite the angle of rotation being zero radians.
Red is the origin, Orange is pre-rotation, and yellow is post-rotation.
It seems to rotate on the XY plain correctly.
But is also rotating on the z-axis when it should not:
This may be more of a mathematics problem, but maybe there is a simple javascript solution that I am missing.
I want to plot an ellipse on html canvas from user input of a center point, radius of the major (longest) axis, and 2 points will fall on the ellipse.
This should potentially create 2 possible ellipse paths, both of which will center around the center point, and cross through the 2 points.
So for example, if the center = [2, 1] major axis radius a = 10, point 1 u = [4, 2] and point 2 v = [5, 6], what is the minor axis radius b and angle of rotation theta?
So far I have tried to implement an equation that I found from https://math.stackexchange.com/questions/3210414/find-the-angle-of-rotation-and-minor-axis-length-of-ellipse-from-major-axis-leng,
but it does not return valid values. My javascript code looks like this:
function getEllipseFrom2Points(center, u, v, a) {
function getSlope(plusOrMinus) {
return Math.sqrt(((uy * vx - ux * vy) ** 2) / (-ux * uy * (a * (v2x + v2y) - 1) + vx * vy * (a * (u2x + u2y) - 1) - plusOrMinus * (uy * vx - ux * vy) * q) / (u2x * (1 - a * v2y) + v2x * (a * u2y - 1)));
}
function getMinorAxis(plusOrMinus) {
return (u2x + u2y + v2x + v2y - a * (2 * u2x * v2x + 2 * u2y * v2y + 2 * ux * uy * vx * vy + u2y * v2x + u2x * v2y) + plusOrMinus * 2 * (ux * vx + uy * vy) * q);
}
var vx = v[0],
vy = v[1],
ux = u[0],
uy = u[1],
v2x = vx ** 2,
v2y = vy ** 2,
u2x = ux ** 2,
u2y = uy ** 2,
q = Math.sqrt((1 - a * (u2x + u2y)) * (1 - a * (v2x + v2y))),
ellipse1 = { rx: a, ry: getMinorAxis(1), origin: center, rotation: getSlope(1) },
ellipse2 = { rx: a, ry: getMinorAxis(-1), origin: center, rotation: getSlope(-1) };
}
Either the equation that I am following is wrong, or I have implemented it wrong
In case anyone is interested, here is my solution to the problem, which isn't really "the" solution. If anyone can solve this I would still be happy to know.
Since I can't solve for both slope of the major axis and length of the minor axis, I just take a guess at slope and then test how close it is, and then refine the result by trying in a smaller and smaller region. Since the final ellipse that gets drawn is actually an estimation constructed from bezier curves, I can get close enough in a reasonable amount of time.
function getEllipseFrom2Points (center, u, v, a) {
function getSemiMinorAxis([x, y], a, t) {
// equation for rotated ellipse
// b = a(ycos(t) - xsin(t)) / sqrt(a^2 - x^2cos^2(t) - 2xysin(t)cos(t) - y^2sin^2(t)) and
// b = a(xsin(t) - ycos(t)) / sqrt(a^2 - x^2cos^2(t) - 2xysin(t)cos(t) - y^2sin^2(t))
// where a^2 !== (xcos(t) + ysin(t))^2
// and aycos(t) !== axsin(t)
if (a ** 2 !== (x * Math.cos(t) + y * Math.sin(t)) ** 2 &&
a * y * Math.cos(t) !== a * x * Math.sin(t)) {
var b = [],
q = (Math.sqrt(a ** 2 - x ** 2 * (Math.cos(t)) ** 2 - 2 * x * y * Math.sin(t) * Math.cos(t) - y ** 2 * (Math.sin(t)) ** 2));
b[0] = (a * (y * Math.cos(t) - x * Math.sin(t))) / q;
b[1] = (a * (x * Math.sin(t) - y * Math.cos(t))) / q;
return b;
}
}
function getAngle_radians(point1, point2){
return Math.atan2(point2[1] - point1[1], point2[0] - point1[0]);
}
function getDistance(point1, point2) {
return Math.sqrt((point2[0] - point1[0]) ** 2 + (point2[1] - point1[1]) ** 2);
}
function rotatePoint(point, center, radians) {
var x = (point[0] - center[0]) * Math.cos(radians) - (point[1] - center[1]) * Math.sin(radians) + center[0];
var y = (point[1] - center[1]) * Math.cos(radians) + (point[0] - center[0]) * Math.sin(radians) + center[1];
return [x, y];
}
function measure(ellipseRotation, pointOnEllipse, minorAxisLength) {
var d = getDistance(point, pointOnEllipse);
if (d < bestDistanceBetweenPointAndEllipse) {
bestDistanceBetweenPointAndEllipse = d;
bestEstimationOfB = minorAxisLength;
bestEstimationOfR = ellipseRotation;
}
}
function getBestEstimate(min, max) {
var testIncrement = (max - min) / 10;
for (let r = min; r < max; r = r + testIncrement) {
if (radPoint1 < r && radPoint2 < r || radPoint1 > r && radPoint2 > r) {//points both on same side of ellipse
semiMinorAxis = getSemiMinorAxis(v, a, r);
if (semiMinorAxis) {
for (let t = 0; t < circle; t = t + degree) {
ellipsePoint1 = [a * Math.cos(t), semiMinorAxis[0] * Math.sin(t)];
ellipsePoint2 = [a * Math.cos(t), semiMinorAxis[1] * Math.sin(t)];
point = rotatePoint(u, [0, 0], -r);
measure(r, ellipsePoint1, semiMinorAxis[0]);
measure(r, ellipsePoint2, semiMinorAxis[1]);
}
}
}
}
count++;
if (new Date().getTime() - startTime < 200 && count < 10) //refine estimate
getBestEstimate(bestEstimationOfR - testIncrement, bestEstimationOfR + testIncrement);
}
if (center instanceof Array &&
typeof center[0] === "number" &&
typeof center[1] === "number" &&
u instanceof Array &&
typeof u[0] === "number" &&
typeof u[1] === "number" &&
v instanceof Array &&
typeof v[0] === "number" &&
typeof v[1] === "number" &&
typeof a === "number") {
// translate points
u = [u[0] - center[0], u[1] - center[1]];
v = [v[0] - center[0], v[1] - center[1]];
var bestDistanceBetweenPointAndEllipse = a,
point,
semiMinorAxis,
ellipsePoint1,
ellipsePoint2,
bestEstimationOfB,
bestEstimationOfR,
radPoint1 = getAngle_radians([0, 0], v),
radPoint2 = getAngle_radians([0, 0], u),
circle = 2 * Math.PI,
degree = circle / 360,
startTime = new Date().getTime(),
count = 0;
getBestEstimate(0, circle);
var ellipseModel = MakerJs.$(new MakerJs.models.Ellipse(a, bestEstimationOfB))
.rotate(MakerJs.angle.toDegrees(bestEstimationOfR), [0, 0])
.move(center)
.originate([0, 0])
.$result;
return ellipseModel;
}
So I have a solution to solving for location (point of intersection) of someone based on landmark angles (312.27) and (19.65) degrees and grid coordinates (1,5) and (9,7) of those landmarks. So the issue I'm having is how can I convert these formulas into something that I can dynamically plugin angles and grid coordinates and return the x and y intersection point for location?
Equations of the Lines based on land marks:
P1: y = cot(312.27)*x + 5 - cot(312.27)*1 ⇒ y = -0.91x + 5.91
P2: y = cot(19.65)*x + 7 - cot(19.65) * 9 ⇒ y = 2.80x - 18.21
solve point of intersection:
P1 = P2
-0.91x + 5.91 = 2.80x - 18.21
5.91 + 18.21 = 2.80x + 0.91x
24.12 = 3.71x
6.5 = x
y = -0.91(6.5) + 5.91
y = 0
Your position is (6.5,0).
So I'm looking at creating a function like:
function getLocation(angle1, angle2, coord1, coord2){}
but I just am having trouble trying to figure out how I can convert this solution into something that would output x and y. As I would have to pass around x or y which is unknown.
Any ideas would be appreciated.
note: angles are converted to radians.
You need to solve the system of equations in terms of the angles and the x,y coordinates:
// let phi1 be the first angle and phi2 be the second angle thus
// let P1 be the first point and P2 be the second point
y = x * cot(phi1) + P1.y - P1.x * cot(phi1)
Similarly
y = x * cot(phi2) + P2.y - P2.x * cot(phi2)
Equating both sides:
x * cot(phi1) + P1.y - P1.x * cot(phi1) = x * cot(phi2) + P2.y - P2.x * cot(phi2)
Solving for x
x * (cot(phi1) - cot(phi2)) = P2.y - P2.x * cot(phi2) - P1.y + P1.x * cot(phi1)
Thus:
x = (P2.y - P2.x * cot(phi2) - P1.y + P1.x * cot(phi1)) / (cot(phi1) - cot(phi2))
Once you get x you can plug x in any of the equations for y:
y = x * cot(phi1) + P1.y - P1.x * cot(phi1)
So to get x and y:
function getLocation(angle1, angle2, coord1, coord2) {
let num = coord2.y - coord2.x * cot(angle2) - coord1.y + coord1.x * cot(angle1)
let den = cot(angle1) - cot(angle2)
let x = num / den
let y = x * cot(angle1) + P1.y - P1.x * cot(angle1)
// do something awesome with x and y
}
Given a point outside of an arc, how can one find the point on the arc which extends to that point?
For example, the radius of the circle (R) is 10cm, it's center point is [0,0].
The origin (o) of the line (8) is at [-3, 10]
How can we find the point (p) (p8) were the tangent at that point continues to the origin of the line?
A brute force solution would not be acceptable.
Let point coordinates are px, py, and circle center is at (0,0) (if not - subtract center cx, cy from all coordinates to simplify equations, add them back at the end).
You can write two equations for unknown x,y. Circle equation and perpendicularity one - tangent is perpendicular to radius-vector, their dot product is zero.
(x - px) * x + (y - py) * y = 0
x^2 + y^2 = r^2
x^2 - px * x + y^2 - py * y = 0
r^2 - px * x = py * y
y = (r^2 - px * x) / py
y^2 = r^4 / py ^2 - x * 2 * r^2 * px / py^2 + x^2 * px^2 / py^2
x^2 * (1 + px^2 / py^2) - x * 2 * r^2 * px / py^2 + (r^4 / py^2 - r^2) = 0
x^2 * (py^2 + px^2) - x * 2 * r^2 * px + (r^4 - r^2 * py^2) = 0
Solve the last quadratic equation for x, then calculate y.
Delphi function for reference (note: py=0 case is treated separately)
function GetTangentPts(px, py, r: Double): TArray<Double>;
var
px2, py2, pxpy, r2, Dis, x, y: Double;
begin
px2 := px * px;
py2 := py * py;
r2 := r * r;
pxpy := px2 + py2;
Dis := pxpy - r2;
if Dis < 0 then //point is inside
Exit(nil)
else if Dis = 0 then begin //point is at circumference
SetLength(Result, 2);
if py = 0 then begin
x := px;
y := 0;
end else begin
x := px * r2 / pxpy;
y := (r2 - px * x) / py;
end;
Result[0] := x;
Result[1] := y;
end else begin //general case, two tangents
SetLength(Result, 4);
if py = 0 then begin
y := - r * Sqrt(Dis) / px;
x := px / Abs(px) * r * Sqrt(1 - Dis/px2);
Result[0] := x;
Result[1] := y;
y := r * Sqrt(Dis) / px;
Result[2] := x;
Result[3] := y;
end else begin
x := (px * r2 - r * Sqrt(py2 * Dis)) / pxpy;
y := (r2 - px * x) / py;
Result[0] := x;
Result[1] := y;
x := (px * r2 + r * Sqrt(py2 * Dis)) / pxpy;
y := (r2 - px * x) / py;
Result[2] := x;
Result[3] := y;
end;
end;
end;
some results:
10.00 10.00 10.00 //two perpendicular tangents
0.00
10.00
10.00
0.00
-10.00 10.00 10.00
-10.00
0.00
0.00
10.00
1.00 1.00 10.00
//inside
0.00 10.00 10.00 //horizontal tangent
0.00
10.00
10.00 0.00 10.00 //vertical tangent
10.00
0.00
-14.14 0.00 10.00 //two tangents from OX-axis
-7.07
7.07
-7.07
-7.07
WLOG the circle is centered at the origin. We express that a point on the circle, let (u, v), forms a right angle with the lines to the center and to the target point (x, y):
u (x - u) + v (y - v) = 0
or
u x + v y = r².
We rewrite and square to obtain
(r² - u²) y² = (r² - u x)²,
a quadratic equation in u. From this, v = √(r² - u²) follows and you have the tangency point.
Edit:
This first preferred method is a js version very much based on the method of #MBo Fixes a couple of bugs there.
function tangentLines(centerX, centerY, radius, pX, pY) {
var horizontalAdjustment, verticalAdjustment, pX_Squared, pY_Squared,
pXY_Squared, radiusSquared, delta, x, y, result, onSameY, temp
// Center the circle at [0,0] to simplify things
onSameY = pY === centerY
horizontalAdjustment = centerX
verticalAdjustment = centerY
pX -= horizontalAdjustment
pY -= verticalAdjustment
centerX = centerY = 0
// If pY is on the same vertical as centerY then temporarily swap pX and pY
// to avoid bug caused by division of 0
if(onSameY){
temp = pY
pY = pX
pX = temp
}
pX_Squared = pX * pX
pY_Squared = pY * pY
radiusSquared = radius * radius
pXY_Squared = pX_Squared + pY_Squared
delta = pY_Squared * (pXY_Squared - radiusSquared)
// Point is inside i.e. no tangent
if (delta < 0 || pXY_Squared < radiusSquared) {
return false
}
// Point is on circumference only one tangent point
if (delta === 0) {
x = (pX * radiusSquared)
if (pXY_Squared) { x /= pXY_Squared }
y = (radiusSquared - pX * x)
if (pY) { y /= pY }
x += horizontalAdjustment
y += verticalAdjustment
return onSameY ? [y,x] : [x, y]
}
// Regular case point is outside of tangent there are 2 tangent points
x = (pX * radiusSquared - radius * Math.sqrt(delta))
if (pXY_Squared) { x /= pXY_Squared }
y = (radiusSquared - pX * x)
if (pY) { y /= pY }
x += horizontalAdjustment
y += verticalAdjustment
result = [
onSameY ? [y, x] : [x, y],
[]
]
x = (pX * radiusSquared + radius * Math.sqrt(delta))
if (pXY_Squared) { x /= pXY_Squared }
y = (radiusSquared - pX * x)
if (pY) { y /= pY }
x += horizontalAdjustment
y += verticalAdjustment
result[1] = onSameY ? [y, x] : [x, y]
return result
}
new Vue({
el: '#app',
template: `
<div>
<div>
centerX: <input v-model="centerX" #input="intersectionPoints">
centerY: <input v-model="centerY" #input="intersectionPoints">
<div>radius: <input v-model="radius" #input="intersectionPoints"></div>
</div>
<div>
pointX: <input v-model="pointX" #input="intersectionPoints">
pointY: <input v-model="pointY" #input="intersectionPoints">
</div>
<div v-if=result>
<div>Insect points: {{result}}</div>
</div>
<div v-if=!result>No intersections :-(</div>
</div>
`,
data: function() {
return {
centerX: 200,
centerY: 200,
radius: 100,
pointX: 160,
pointY: 100,
result: null
};
},
methods: {
intersectionPoints() {
this.result = tangentLines(
+this.centerX,
+this.centerY,
+this.radius,
+this.pointX,
+this.pointY
);
}
},
mounted: function() {
this.intersectionPoints();
}
});
// Without Vue just use something like
// tangentLines(200, 200, 100, 160, 100);
div {
margin: .5em;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app"></div>
Here's the original code I came up with.
Based on #Aretino answer https://math.stackexchange.com/questions/3541795/given-a-point-outside-of-an-arc-how-can-one-find-the-point-on-the-arc-which-ext/3541928#3541928
Make a circle with a radius half the distance between o and p, originate it at the midpoint of the line op.
Calculate the intersection point of the original circle and the newly made circle.
// Function to find tangent intersection points to a point outside of the circle
// Credits
// https://math.stackexchange.com/questions/3541795/given-a-point-outside-of-an-arc-how-can-one-find-the-point-on-the-arc-which-ext/3541928#3541928
// https://stackoverflow.com/questions/60156373/given-a-point-outside-of-an-arc-how-can-one-find-the-point-on-the-arc-which-ext
/**
*
*
* #param {number} centerX1 Center of circle 1 X
* #param {number} centerY1 Center of circle 1 Y
* #param {number} radius1 Radius of circle 1
* #param {number} centerX2 Center of circle 2 X
* #param {number} centerY2 Center of circle 2 Y
* #param {number} radius2 Radius of circle 2
* #returns {object | boolean} The to intersect points { point1: [x1, y1], point2: [x2, y2] } or false
* #credit Math based on https://www.analyzemath.com/CircleEq/circle_intersection_calcu.html
*/
var circleIntersections = function(
centerX1,
centerY1,
radius1,
centerX2,
centerY2,
radius2
) {
var a, b, c, A, B, C, delta, x1, x2, y1, y2;
a = -(centerY1 - centerY2) / (centerX1 - centerX2);
b = 2 * (centerX1 - centerX2);
c =
(-radius1 * radius1 +
radius2 * radius2 +
centerX1 * centerX1 -
centerX2 * centerX2 +
centerY1 * centerY1 -
centerY2 * centerY2) /
b;
A = a * a + 1;
B = 2 * a * c - 2 * centerX1 * a - 2 * centerY1;
C =
c * c +
centerX1 * centerX1 -
2 * centerX1 * c +
centerY1 * centerY1 -
radius1 * radius1;
delta = B * B - 4 * A * C;
if (delta < 0) {
return false;
}
y1 = (-B + Math.sqrt(delta)) / (2 * A);
x1 = a * y1 + c;
y2 = (-B - Math.sqrt(delta)) / (2 * A);
x2 = a * y2 + c;
return {
point1: [x1, y1],
point2: [x2, y2]
};
};
/**
*
*
* #param {number} centerX Center of circle X
* #param {number} centerY Center of circle Y
* #param {number} radius Radius of circle
* #param {number} pointX Point to tangent to X
* #param {number} pointY Point to tangent to Y
* #returns {object | boolean} The to intersect points { point1: [x1, y1], point2: [x2, y2] } or false
*/
var tangentLines = function(centerX, centerY, radius, pointX, pointY) {
var centerX2, centerY2, radius2, dX, dY;
centerX2 = centerX - (centerX - pointX) / 2;
centerY2 = centerY - (centerY - pointY) / 2;
dX = centerX2 - centerX;
dY = centerY2 - centerY;
radius2 = Math.sqrt(dX * dX + dY * dY);
return circleIntersections(
centerX,
centerY,
radius,
centerX2,
centerY2,
radius2
);
};
new Vue({
el: '#app',
template: `
<div>
<div>
centerX: <input v-model="centerX" #input="intersectionPoints">
centerY: <input v-model="centerY" #input="intersectionPoints">
<div>radius: <input v-model="radius" #input="intersectionPoints"></div>
</div>
<div>
pointX: <input v-model="pointX" #input="intersectionPoints">
pointY: <input v-model="pointY" #input="intersectionPoints">
</div>
<div v-if=result>
<div>point1: {{result.point1}}</div>
<div>point2: {{result.point2}}</div>
</div>
<div v-if=!result>No intersections :-(</div>
</div>
`,
data: function() {
return {
centerX: 200,
centerY: 200,
radius: 100,
pointX: 160,
pointY: 100,
result: null
};
},
methods: {
intersectionPoints() {
this.result = tangentLines(
this.centerX,
this.centerY,
this.radius,
this.pointX,
this.pointY
);
}
},
mounted: function() {
this.intersectionPoints();
}
});
// Without Vue just use something like
// tangentLines(200, 200, 100, 160, 100);
div {
margin:5px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id=app></div>
I am working on an animation library and have a variable that is incrementing from 0 to 1 (X axis in the graphic) while a timer is running. I now want to apply easing to my function in a similar fashion as the CSS function cubic-bezier.
My goal is that the y value doesn't increment linearly but instead is converted by the easing function. The function should look something like this:
function cubic-bezier(x, p0x, p0y, p1x, p1y){
// Any suggestions for a formula or algorithm?
return y;
};
I am not using any libraries and can't use any third party libraries on this project.
Thanks!
EDIT: This is the code I came up with. It is an adaption of this code jsfiddle.net/fQYsU.
var p1 = {0.5, 0.5};
var p2 = {0.5, 0.5};
cubic-bezier(t, p1, p2){
var cX = 3 * (p1.x),
bX = 3 * (p2.x - p1.x) - cX,
aX = 1 - cX - bX;
var cY = 3 * (p1.y - 1),
bY = 3 * (p2.y - p1.y) - cY,
aY = -1 - cY - bY;
var x = (aX * Math.pow(t, 3)) + (bX * Math.pow(t, 2)) + (cX * t);
var y = (aY * Math.pow(t, 3)) + (bY * Math.pow(t, 2)) + (cY * t) + 1;
return {x: x, y: y};
}
var y = cubic-bezier(progress, p1, p2).y;
But the value it returns corresponds to x which might not be t. So I still don't know how to get the value at the correct position.