UNSOLVED Glyph Compatibility & isCompatible
-
Hello there,
I use the isCompatible command to find out if 2 glyphs match. When Glyph A is a circle and Glyph B is a diamond shape, isCompatible returns True.
font = CurrentFont() print(font['A'].isCompatible(font['B']))
While I understand that this is handy in some cases, I think it is a bit confusing if it tells you that two shapes with same amount of oncurve points, different amount of offcurve points, and different segment types are compatible.Is there something more reliable I should use here?
Is there a chance this could be improved?Thanks for your help!
-
there is a big difference between being compatible for interpolation (aka fontMath) and for variable fonts.
Variable fonts requires (out of my head):
- same amount of point both oncurves as offcurves
- same amount of kerning pairs
- same amount of kerning groups
- same amount of glyphs
-
Also here the documentation mentions that isCompatible is able to distinguish different segment types. But when I run:
The documentation is correct, but could use some more detail. The method does distinguish between different segment types, but in the example you show all of the segments are line or curve.
isCompatible
sees those as the same by design (more on that in a moment). If you compare a move to a line or a qCurve to a curve, it should fail. Make the example paths open and it should give you an error.
I'm not familiar with the variable font compatibility requirements, but I am very familiar with
isCompatible
. It was designed to report on interpolation compatibility. In that use, a line segment is compatible with a curve segment in that the off-curves are implied to be on top of the corresponding off-curve points. In fact, inside of fontMath, there is no such thing as a line segment. When a line segment comes in, it is converted to a curve segment. When the outline is sent back, these are cleaned up and converted back to lines as needed. This is a major use case ofisCompatible
so I don't think changing the default behavior is a good idea.We should, however, modify
isCompatible
to be more flexible about not being flexible about segment types. An optional argument, as @gferreira suggested, is a good idea. It could trigger a different segment comparison algorithm. Something likestrictSegmentTypes=True
sounds good to me.As far as matching starting points goes, that's really hard, if not impossible, to do algorithmically. I've been trying to solve this for 15 years. I recommend that
isCompatible
not try to automatically match start points. That should be left up to the designer and other tools.
-
Thanks for the context.
I understand, but I think it is quite confusing to people who do not know all the history in detail.
Also here the documentation mentions that isCompatible is able to distinguish different segment types. But when I run:
font = CurrentFont() print(font['A'].isCompatible(font['B'])) for i,c in enumerate(font['A'].contours): for j,s in enumerate(c): print(font['A'][i][j].isCompatible(font['B'][i][j]))
This is the output:
(True, [OK] Glyph: "A" + "B") (True, [OK] Segment: [0] + [0]) (True, [OK] Segment: [1] + [1]) (True, [OK] Segment: [2] + [2]) (True, [OK] Segment: [3] + [3])
-
this may be tricky to implement in FontParts: in order to match off-curve points, we need to match starting points… see the discussion in Glyph compatibility checker: differing starting point not caught
cc @benkiel
-
hello @benedikt, that’s a good question.
isCompatible
is older than variable fonts – it was made to prepare glyphs for interpolation tools that did not require the same amount of off-curve points. @erik mentions this here:Note that older interpolation tools may interpolate a straight segment with a curve by assuming there are off-curve points on top of the on-curves. In variable fonts this is not possible, and it is a good design practice to have all the points in the masters.
Batch uses a CompatibleContourPointPen to make off-curve points compatible before generating variable fonts.
I agree it would be nice to improve/update
isCompatible
so it can also check for compatibility between off-curve points. maybe this should be an optional parameter, so we can fall back to the old behavior if needed. (?)