PathFlatteningIterator edge case error?

#1

I’m wondering if anyone can confirm this…unexpected behavior.
If I have a quadratic that is basically a straight line, and check if it intersects with a vertical line at X, i get 2 intersection points, because the PathFlatteningIterator (for whatever reason), splits the path into linear segments right at the x of my line.

Here’s the coordinates for testing

    Line<float> line(28.984375, -5.0, 28.984375, 305.0);
    Path path;
    path.startNewSubPath(0.0, 215.0);
    path.quadraticTo(233.9999847412109375, 134.904998779296875, 400.0, 22.0);
    Array<Point<float>> points;

    if( intersectsPath(path, line, points) )
    {
        jassertfalse;
    }

where intersectsPath is:

bool intersectsPath(const Path &p, Line<float> line, Array<Point<float>> &possibleIntersections)
{
    //this is taken from Path::intersectsPath and modified
    PathFlatteningIterator i (p);

    DBG( "checking intersection with line: " << line.getStart().toString() << " " << line.getEnd().toString());
    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());

            }
        }
    }

    if( possibleIntersections.isEmpty() )
        return false;
    //print our line and path coords so we can replicate it.
    if( possibleIntersections.size() > 1 )
    {
        auto pPrint = [](float x) -> String { return String(x, 20); };
        jassertfalse;
        for( auto p : possibleIntersections )
        {
            DBG( "intersection: " << pPrint(p.x) << ", " << pPrint(p.y) );
        }

        Path::Iterator iter(p);
        DBG("");
        DBG( "intersectsPath path info" );
        DBG( "line: Line<float>(" << pPrint(line.getStartX()) << ", " << pPrint(line.getStartY()) << ", " << pPrint(line.getEndX()) << ", " << pPrint(line.getEndY()) << ");" );
        while( iter.next() )
        {
            switch (iter.elementType)
            {
                case juce::Path::Iterator::startNewSubPath:
                    DBG( ".startNewSubPath(" << pPrint(iter.x1) << ", " << pPrint(iter.y1) << ");" );
                    break;
                case juce::Path::Iterator::lineTo:
                    DBG( ".lineTo(" << pPrint(iter.x1) << ", " << pPrint(iter.x2) << ");" );
                    break;
                case juce::Path::Iterator::quadraticTo:
                    DBG( ".quadraticTo(" << pPrint(iter.x1) << ", " << pPrint(iter.y1) << ", " << pPrint(iter.x2) << ", " << pPrint(iter.y2) << ");" );
                    break;
                case juce::Path::Iterator::cubicTo:
                    DBG( ".qubicTo(" << pPrint(iter.x1) << ", " << pPrint(iter.y1) << ", " << pPrint(iter.x2) << ", " << pPrint(iter.y2) << ", " << pPrint(iter.x3) << ", " << pPrint(iter.y3) << ");" );
                    break;
                case juce::Path::Iterator::closePath:
                    DBG( ".closeSubPath()" );
                    break;
            }
        }
    }

    return true;
}

Maybe changing the tolerance for the PathFlatteningIterator is the solution? Or some other Quadratic/Linear intersection solver?

0 Likes