FS#2685 - Ellipse - Line intersection not found
Andrew,
Related to forum topic P48583 .
Probably affects ‘Windows All’, user Chuckk reported this for 3.32.3 on Windows 11pro
Or even ‘All Qt 5 Builds’.
In the attached example (the larger file) using QCAD 3.32.2:
There are no real snappable intersection points returned for a line crossing the ellipse.
It reverts to the ellipse center.
Pointing anywhere near them divides the ellipse at the minor points.
An attempt to use Intersection manual (SY) fails too.
Both methods work well in an earlier version.
At some point RSnapIntersection.snap relies on REntity.getIntersectionPoints(...)
What eventually will be handled on RShape level.
For the topic case:
BreakOut.breakOut calls ShapeAlgorithms.autoSplit(...)
ShapeAlgorithms.autoSplit calls ShapeAlgorithms.getIntersectionPoints(...)
ShapeAlgorithms.getIntersectionPoints relies on RShape.getIntersectionPoints(...)
getIntersectionPoints based on RShapes may fail with shape pointers.
Regards,
CVH
Andrew,
Bug traced back to REllipse::getTangentPoint(RLine) .
⇒ No line that (almost) crosses an ellipse center can be a tangent.
Applies for all recent releases since end of 2023 and all OS.
Also fails for any resource using RShape::getIntersectionPointsLE() in one way or another.
Please refer to the follow up in the topic: P48589
Regards,
CVH
Andrew,
The condition for an endless line with equation y = mx + c to be a tangent to a standard full ellipse x²/a² + y²/a² = 1 is given by c² == a²m² + b².
Excluding a vertical normalized line.
In REllipse::getTangentPoint(RLine) the value of a²m² + b² is already known as parameter A for the quadratic equation.
!! We cannot quantify "almost a tangent" by the degree to which the discriminant of the quadratic equation differs from zero !!
When using floating-point some minute tolerance is indeed required.
This test within +/- 0.001 may also fail when c is (nearly) zero or when the line passes (almost) through the ellipse center.
For "almost a tangent" there will be a nearby parallel that is actually a perfect tangent.
The y-intercept of this parallel is +/- sqrt(a²m² + b²) or +/- sqrt(A) depending the sign of c.
How much c is allowed to deviate depends on the parallel tolerance and the slope:
Allowed Δc is less or equal to sqrt( (1/m)² + tol² ) with a reasonably small tolerance relative to the radii.
Substituting A and eliminating the root: c² +/- ( (1/m)² + tol²) ) == A.
Plugged into the code of REllipse::getTangentPoint(RLine):
Note 1: 'As is' the code does not validate the solution to be on a limited line segment or ellipse arc.
While only used in RShape::getIntersectionPointsLE(...) what validates the final solution(s) to be on a limited ellipse arc and on a limited line segment.
This part is never reached when a valid point of tangency is returned.
Note 2: Tolerances differ ...
- For a vertical line it compares for major points within RS::PointTolerance
- The allowed parallel tolerance is not yet defined in the double tolerance
I tend to propose a size relative tolerance based on the radii.
For example: double tolerance = (a + b) / 2000;
Using the same tolerance as for a vertical would be appropriate.
Perhaps added as parameter to the function ... Reverting to a default.
Regards,
CVH