googlefonts / googlefonts/fontc

subtle cu2qu rounding issue

Open
#1,981 1 comment 0 reactions 0 assignees View on GitHub
crater
Dominant language
Rust
Stars
193
Forks
21
Avg merge
1d 20h
Merged PRs (30d)
60

Description

this is ultimately meaningless, but wanted to open an issue to at least track.

## cu2qu epsilon causes extra point for near-degenerate cubics

### Summary

fontc produces 1 fewer point than fontmake for the glyph `ordmasculine` in RubikGlitchPop. The difference comes from cubic-to-quadratic conversion of a nearly degenerate cubic where all four control points are within ~0.05 design units and round to the same integer coordinate.

### Reproduction

```bash
python3 -m ttx_diff 'https://github.com/NaN-xyz/Rubik-Filtered?1126980434#glitchpop/sources/RubikGlitchPop.glyphs'
```

Only the `glyf` table differs: `ordmasculine` has 423 points (fontc) vs 424 points (fontmake).

### The source curve

The cubic in question has four nearly-identical control points:

```
p0 = (234.740, 471.556)
p1 = (234.742, 471.574)
p2 = (234.744, 471.592)
p3 = (234.746, 471.610)
```

All round to `(235, 472)`. The lines p0-p1 and p2-p3 are nearly parallel, producing a cross product of ~5e-16.

### What happens

cu2qu's `dot()` function clamps values with `abs() < 1e-15` to zero ([cu2qu.py:58-59](https://github.com/fonttools/fonttools/blob/main/Lib/fontTools/cu2qu/cu2qu.py#L58-L59)). This was added to ensure consistent results between pure Python and Cython runtimes, where IEEE-754 rounding can differ slightly for perpendicular vectors.

For this curve, the ~5e-16 cross product gets clamped to zero, causing a `ZeroDivisionError` in the crossing-point calculation. The n=1 quadratic approximation fails and falls through to n=2, producing 2 quadratic segments (an extra off-curve point) instead of 1.

kurbo (used by fontc) has no such epsilon — the ~5e-16 cross product is treated as non-zero, a valid crossing point is found, and 1 quadratic segment is produced.

### Impact

The difference is purely cosmetic. Both outputs render identically — all points are at the same integer coordinate `(235, 472)`. fontc's output is marginally better (1 fewer point).

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.