[cu2qu] Fix incosistent approximation when run in pure-python vs cython #3911
+37
−4
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
@cmyr noticed that sometimes with some degenerate cubic curves (e.g. those where control points are on the same line), cu2qu can produce different number of quadratic off-curves depending on whether it is running in compiled cython mode (as one would get when installing from the wheels that we publish to PyPI) vs pure-python mode (e.g. when pip installing fonttools in editable from a local git checkout inside a python environment that doesn't have cython, or without explicitly asking for FONTTOOLS_WITH_CYTHON=1 at built time).
I isolated one of these offending curves (from BilboPro.glyphs) to create the test.
The
calc_intersect
function callsdot
to compute the vector dot product, in this situation this is expected to be 0.0 and trigger a ZeroDivisionError.But for some reasons (implementation details of floating-point and complex math in CPython vs C/Cython) we don't get 0.0 in both modes, but something very close (about 2e-17) to 0.0 in one of the two, whereas the other one gives exactly 0.0. They are both correct within IEEE 754 floating-point precision, but only an exact 0.0 triggers the ZeroDivisionError.
To be safe and get consistent results in either case without relying on particular implementation details, we should just clamp to 0.0 when |result|<1e-15 and go home.