Hello friends,
I’ve been trying to find the Y coordinates of a Bezier Curve given X. I’ve been fairly successful getting approximate values by putting in an array lots of x values corresponding to “t” using the bezierPoint. Then obtaining the closest x values to my requested x values. But that’s only an approximation that requires iterating through at least 4000 values to be reasonably close.
Then I searched the forums for a way to do it mathematically solving cubic roots and the maths is way, way beyond me. There are some solutions out there to be found, but they are mainly written in javascript.
Then I found this equations written by prince_polka that almost do what I want, but unfortunately it all fails at some point because they weren’t really meant to do what I want to do, as illustrated bellow. Please drag the bottom control point to the right, pass the middle point, and you will see that the “t” coordinates suddenly disappear, the ellipse vanishes. I think it’s almost there though, but prince_polka doesn’t seem to be in the forum for me to ask him and use his clever brain:).
Could some kind person who has managed to solve XY mathematically help me with a solution to use with Processing please?
Link to original code:
https://forum.processing.org/two/discussion/23333/using-a-bezier-curve-as-a-boundary
//=======================================
PVector p1= new PVector(50, 200);//bottom anchor
PVector c1= new PVector(200, 340);//bottom control
PVector c2= new PVector(600, 130);//top control
PVector p2= new PVector(750, 200);//top anchor
float x;
float y;
void setup() {
size(800, 450);
noFill();
}
void draw() {
background(255);
stroke(1);
noFill();
rect(50, 50, 700, 330);
double[] sol = bezierTime(p1.x, c1.x, c2.x, p2.x, mouseX);
noFill();
stroke(1);
bezier(p1.x, p1.y, c1.x, c1.y, c2.x, c2.y, p2.x, p2.y);
x = bezierPoint(p1.x, c1.x, c2.x, p2.x, (float)sol[1]);
y = bezierPoint(p1.y, c1.y, c2.y, p2.y, (float)sol[1]);
fill(1);
text("t: "+sol[1], 80, 80);
text("x: "+x, 290, 400);
text("y: "+y, 420, 400);
noStroke();
fill(255, 0, 0);
ellipse(x, y, 10, 10);
stroke(1);
line(400, 50, 400, 80);
float distance1 = dist(mouseX, mouseY, c1.x, c1.y);
if (mousePressed) {
if (distance1<25) {
c1.x=mouseX;
c1.y=mouseY;
}
}
float distance2 = dist(mouseX, mouseY, c2.x, c2.y);
if (mousePressed) {
if (distance2<25) {
c2.x=mouseX;
c2.y=mouseY;
}
}
noStroke();
fill(0, 0, 250);
ellipse(c1.x, c1.y, 10, 10);
ellipse(c2.x, c2.y, 10, 10);
}// end draw
//=====FORMULAS===VVVVV=== as calculated by prince_polka and posted in the Processing forum September 2017
double[] bezierTime( double A, double B, double C, double D, double E ) {
double[] T = new double[3];
double F, G, H, J, FG, s, r, n, multr;
final double U, HALF_PI, TWO_PI, SIXTH_PI;
H = 3*(C-B) + A-D;
F = 27*((B-C-C)*(B*(B+B+C)-C*(A*3+C))+D*(A*(A+D-3*(B+C))+B*(6*B-3*C))-(H*H*E));
G = 9 * ( A*(C-D) + B*(D+C-B) - C*C );
J = ( A + C - B - B )/H;
U = 1.5874010519681994747517056392723; //2^2/3
HALF_PI = 1.5707963267948966192313216916397;
TWO_PI = 6.28318530717958647692528676655;
SIXTH_PI = 0.5235987755982988730771072305465;
FG = F*F+4*G*G*G;
s = Math.sqrt(Math.abs(FG));
if (FG>=0) {
r = Math.cbrt(Math.abs(F+s));
n = ( Math.atan2(0, F+s) + TWO_PI )/3;
} else {
r = Math.cbrt(Math.abs(F)+s);
n = ( Math.atan2(s, F) + TWO_PI )/3;
}
multr = (4*G - r*r *U*U)/(6*H*r*U);
T[0] = Math.sin( -n - HALF_PI ) * multr + J;
T[1] = Math.sin( n + SIXTH_PI ) * multr + J;
T[2] = Math.sin( -n + SIXTH_PI ) * multr + J;
return T;
}