Skip to content

Commit

Permalink
Merge pull request #3377 from fonttools/interpolatable-refactor3
Browse files Browse the repository at this point in the history
Interpolatable refactor3
  • Loading branch information
behdad committed Dec 6, 2023
2 parents 8728789 + 930047d commit 39f6142
Show file tree
Hide file tree
Showing 4 changed files with 121 additions and 54 deletions.
55 changes: 32 additions & 23 deletions Lib/fontTools/varLib/interpolatable.py
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,11 @@ def grand_parent(i, glyphname):
if not ignore_missing:
yield (
glyph_name,
{"type": "missing", "master": name, "master_idx": master_idx},
{
"type": InterpolatableProblem.MISSING,
"master": name,
"master_idx": master_idx,
},
)
continue

Expand All @@ -198,10 +202,10 @@ def grand_parent(i, glyphname):
yield (
glyph_name,
{
"type": InterpolatableProblem.OPEN_PATH,
"master": name,
"master_idx": master_idx,
"contour": ix,
"type": "open_path",
},
)
if has_open:
Expand Down Expand Up @@ -230,7 +234,7 @@ def grand_parent(i, glyphname):
yield (
glyph_name,
{
"type": "path_count",
"type": InterpolatableProblem.PATH_COUNT,
"master_1": names[m0idx],
"master_2": names[m1idx],
"master_1_idx": m0idx,
Expand All @@ -249,7 +253,7 @@ def grand_parent(i, glyphname):
yield (
glyph_name,
{
"type": "node_count",
"type": InterpolatableProblem.NODE_COUNT,
"path": pathIx,
"master_1": names[m0idx],
"master_2": names[m1idx],
Expand All @@ -265,7 +269,7 @@ def grand_parent(i, glyphname):
yield (
glyph_name,
{
"type": "node_incompatibility",
"type": InterpolatableProblem.NODE_INCOMPATIBILITY,
"path": pathIx,
"node": nodeIx,
"master_1": names[m0idx],
Expand All @@ -279,15 +283,15 @@ def grand_parent(i, glyphname):
continue

#
# "contour_order" check
# InterpolatableProblem.CONTOUR_ORDER check
#

this_tolerance, matching = test_contour_order(glyph0, glyph1)
if this_tolerance < tolerance:
yield (
glyph_name,
{
"type": "contour_order",
"type": InterpolatableProblem.CONTOUR_ORDER,
"master_1": names[m0idx],
"master_2": names[m1idx],
"master_1_idx": m0idx,
Expand All @@ -300,7 +304,7 @@ def grand_parent(i, glyphname):
matchings[m1idx] = matching

#
# "wrong_start_point" / weight check
# wrong-start-point / weight check
#

m0Isomorphisms = glyph0.isomorphisms
Expand Down Expand Up @@ -354,7 +358,7 @@ def grand_parent(i, glyphname):
yield (
glyph_name,
{
"type": "wrong_start_point",
"type": InterpolatableProblem.WRONG_START_POINT,
"contour": ix,
"master_1": names[m0idx],
"master_2": names[m1idx],
Expand Down Expand Up @@ -400,7 +404,10 @@ def grand_parent(i, glyphname):
t = tolerance**power

for overweight, problem_type in enumerate(
("underweight", "overweight")
(
InterpolatableProblem.UNDERWEIGHT,
InterpolatableProblem.OVERWEIGHT,
)
):
if overweight:
expectedSize = sqrt(size0 * size1)
Expand Down Expand Up @@ -579,7 +586,7 @@ def grand_parent(i, glyphname):
yield (
glyph_name,
{
"type": "kink",
"type": InterpolatableProblem.KINK,
"contour": ix,
"master_1": names[m0idx],
"master_2": names[m1idx],
Expand All @@ -598,7 +605,7 @@ def grand_parent(i, glyphname):
yield (
glyph_name,
{
"type": "nothing",
"type": InterpolatableProblem.NOTHING,
"master_1": names[m0idx],
"master_2": names[m1idx],
"master_1_idx": m0idx,
Expand Down Expand Up @@ -947,16 +954,16 @@ def main(args=None):
print(f" Masters: %s:" % ", ".join(master_names), file=f)
last_master_idxs = master_idxs

if p["type"] == "missing":
if p["type"] == InterpolatableProblem.MISSING:
print(
" Glyph was missing in master %s" % p["master"], file=f
)
elif p["type"] == "open_path":
elif p["type"] == InterpolatableProblem.OPEN_PATH:
print(
" Glyph has an open path in master %s" % p["master"],
file=f,
)
elif p["type"] == "path_count":
elif p["type"] == InterpolatableProblem.PATH_COUNT:
print(
" Path count differs: %i in %s, %i in %s"
% (
Expand All @@ -967,7 +974,7 @@ def main(args=None):
),
file=f,
)
elif p["type"] == "node_count":
elif p["type"] == InterpolatableProblem.NODE_COUNT:
print(
" Node count differs in path %i: %i in %s, %i in %s"
% (
Expand All @@ -979,7 +986,7 @@ def main(args=None):
),
file=f,
)
elif p["type"] == "node_incompatibility":
elif p["type"] == InterpolatableProblem.NODE_INCOMPATIBILITY:
print(
" Node %o incompatible in path %i: %s in %s, %s in %s"
% (
Expand All @@ -992,7 +999,7 @@ def main(args=None):
),
file=f,
)
elif p["type"] == "contour_order":
elif p["type"] == InterpolatableProblem.CONTOUR_ORDER:
print(
" Contour order differs: %s in %s, %s in %s"
% (
Expand All @@ -1003,7 +1010,7 @@ def main(args=None):
),
file=f,
)
elif p["type"] == "wrong_start_point":
elif p["type"] == InterpolatableProblem.WRONG_START_POINT:
print(
" Contour %d start point differs: %s in %s, %s in %s; reversed: %s"
% (
Expand All @@ -1016,7 +1023,7 @@ def main(args=None):
),
file=f,
)
elif p["type"] == "underweight":
elif p["type"] == InterpolatableProblem.UNDERWEIGHT:
print(
" Contour %d interpolation is underweight: %s, %s"
% (
Expand All @@ -1026,7 +1033,7 @@ def main(args=None):
),
file=f,
)
elif p["type"] == "overweight":
elif p["type"] == InterpolatableProblem.OVERWEIGHT:
print(
" Contour %d interpolation is overweight: %s, %s"
% (
Expand All @@ -1036,7 +1043,7 @@ def main(args=None):
),
file=f,
)
elif p["type"] == "kink":
elif p["type"] == InterpolatableProblem.KINK:
print(
" Contour %d has a kink at %s: %s, %s"
% (
Expand All @@ -1047,7 +1054,7 @@ def main(args=None):
),
file=f,
)
elif p["type"] == "nothing":
elif p["type"] == InterpolatableProblem.NOTHING:
print(
" Showing %s and %s"
% (
Expand All @@ -1060,6 +1067,8 @@ def main(args=None):
for glyphname, problem in problems_gen:
problems[glyphname].append(problem)

problems = sort_problems(problems)

if args.pdf:
log.info("Writing PDF to %s", args.pdf)
from .interpolatablePlot import InterpolatablePDF
Expand Down
48 changes: 48 additions & 0 deletions Lib/fontTools/varLib/interpolatableHelpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,61 @@
from fontTools.misc.transform import Transform
from collections import defaultdict, deque
from math import sqrt, copysign, atan2, pi
from enum import Enum
import itertools

import logging

log = logging.getLogger("fontTools.varLib.interpolatable")


class InterpolatableProblem:
NOTHING = "nothing"
MISSING = "missing"
OPEN_PATH = "open_path"
PATH_COUNT = "path_count"
NODE_COUNT = "node_count"
NODE_INCOMPATIBILITY = "node_incompatibility"
CONTOUR_ORDER = "contour_order"
WRONG_START_POINT = "wrong_start_point"
KINK = "kink"
UNDERWEIGHT = "underweight"
OVERWEIGHT = "overweight"

severity = {
MISSING: 1,
OPEN_PATH: 2,
PATH_COUNT: 3,
NODE_COUNT: 4,
NODE_INCOMPATIBILITY: 5,
CONTOUR_ORDER: 6,
WRONG_START_POINT: 7,
KINK: 8,
UNDERWEIGHT: 9,
OVERWEIGHT: 10,
NOTHING: 11,
}


def sort_problems(problems):
"""Sort problems by severity, then by glyph name, then by problem message."""
return dict(
sorted(
problems.items(),
key=lambda _: -min(
(
InterpolatableProblem.severity[p["type"]]
for p in _[1]
if InterpolatableProblem.severity[p["type"]]
!= InterpolatableProblem.severity[InterpolatableProblem.NOTHING]
),
default=InterpolatableProblem.severity[InterpolatableProblem.NOTHING],
),
reverse=True,
)
)


def rot_list(l, k):
"""Rotate list by k items forward. Ie. item at position 0 will be
at position k in returned list. Negative k is allowed."""
Expand Down

0 comments on commit 39f6142

Please sign in to comment.