I'm trying to follow the matrix equation solution presented here: Convert quadratic bezier curve to parabola by @robjohn
I'm assuming his solution can be used for any quadratic coordinates. My goal is to be able to pass in the coordinates defining a quadratic bezier curve, an x
within the bounds of the curve, and get a y
value out of it.
here's the python that I came up with:
a_x, a_y, b_x, b_y, c_x, c_y, x, y = symbols('a_x a_y b_x b_y c_x c_y x y')
u = Matrix([[b_y - c_y],[c_x - b_x],[b_x*c_y - b_y*c_x]])
v = Matrix([[c_y - a_y],[a_x - c_x],[c_x*a_y - c_y*a_x]])
w = Matrix([[a_y - b_y],[b_x - a_x],[a_x*b_y - c_y*a_x]])
expr = 2*(u*w.T + w*u.T) - v*v.T
lh = Matrix([[x,y,1]])
rh = Matrix([x,y,1])
My next steps were to run collectExpr = collect(lh * expr * rh, y)
and then collectExpr
, which gave me an extremely long expression following the format Ax^2 + Bx + C = 0
, which I was then able to convert into the quadratic equation form.
Executing collectExpr
at the python prompt will show the A, B, and C. it's very long, so I'm leaving it out.
the problem I'm running into is when I solve for y
and then compare that y
against other solvers, the values aren't the same. For example, I've got the following juce::Path
drawing a quadratic:
juce::Path path;
path.startNewSubPath(0.0, 215.0);
path.quadraticTo(233.9999847412109375, 134.904998779296875, 400.0, 22.0);
there are member functions in the Path class to compute the intersection point with a line:
Line<float> line(28.984375, -5.0, 28.984375, 305.0);
When I check via the juce::Path member functions, I get an intersection point with a y = 204.859955
, which I can visually confirm in my window as correct.
When I run those same values through the solver that computes the y
for a Quadratic's control points and an x
within those bounds, I get a different value. https://coliru.stacked-crooked.com/a/9c7556d1da7f7b0e
I've triple checked my C++ implementation against the resulting python from @robjohn's math via collectExpr
output, and it's accurate. But I can't figure out why I'm not getting the same y values as the juce::Path::intersectsLine
functions to satisfy the equation. Does anyone have any idea if that matrix solution is correct or usable?
the juce::Path::intersectsLine()
looks similar to this:
bool CurveTableAudioProcessorEditor::intersectsPath(const Path &p, Line<float> line, Array<Point<float>> &possibleIntersections)
{
//this is taken from Path::intersectsPath and modified
//to store intersections in the array
PathFlatteningIterator i (p);
Point<float> intersectionPoint;
while (i.next())
{
if (line.intersects (Line<float> (i.x1, i.y1, i.x2, i.y2), intersectionPoint))
{
DBG( " intersection: " << intersectionPoint.toString() );
if( !possibleIntersections.addIfNotAlreadyThere( intersectionPoint ) )
{
DBG( "**** intersected point found twice! " << intersectionPoint.toString() << " for line: " << line.getStart().toString() << " " << line.getEnd().toString());
}
}
}