LineSegment-CubicBezier-Intersection Numerical Non-Deterministic Errors
Intersecting a Line with a CubicBezier does not reliably return correct results.
Code to reproduce the error:
const Geom::Point a{486, 597};
const Geom::Point b{313, 285};
const Geom::LineSegment line{std::vector<Geom::Point>{a, b}};
const Geom::Point c{580.1377046525328, 325.5830744834947};
const Geom::Point d{289.35338528516013, 450.62476639303753};
{
const Geom::CubicBezier curve{std::vector<Geom::Point>{c, c, d, d}};
const auto cuts = curve.intersect(line);
// FAIL! `cuts` is actually empty in this case, but I have observed cases where
// `cuts` contained up to eight elements.
// I expected it to contain exactly one element.
EXPECT_EQ(cuts.size(), 1);
}
{
const Geom::LineSegment curve{std::vector<Geom::Point>{c, d}};
const auto cuts = curve.intersect(line);
EXPECT_EQ(cuts.size(), 1); // works.
}
I found these values in an interactive application because the intersection visualization "flickered" when moving the endpoint of the line with the mouse.
I.e., small deviations make a huge (apparently non-deterministic and erroneous) difference.
In the interactive application, the problem is much less severe (i.e., there's much less flickering, but it's still perceivable) if
- the control points of the
CubicBeziercurve are not collinear - using
CubicBezier-CubicBezierintersection rather thanCubicBezier-LineSegmentintersection (replaced the line (a, b) with aCubicBeziercurve with control points (a, a, b, b))
The problem is symmetric, i.e., curve.intersect(line) is equivalent to line.intersect(curve).
I think that it's some numerical problem since when c is defined as
const Geom::Point c{580.1377046525328, std::nextafter(325.5830744834947, 0.0)};,
the test succeeds.
Edited by Rafał Siejakowski