fonttools/Lib/fontTools/varLib/interpolatableTestStartingPoint.py
Behdad Esfahbod 90a84d25ca [interpolatableTestStartingPoint] Try to rationalize the extended case
Breaks all kinds of things. Going to revert. I have no idea why
the existing code works so well but any touching it to make it more
reasonable regresses the results :(.
2023-12-06 09:03:40 -07:00

61 lines
2.4 KiB
Python

from .interpolatableHelpers import *
def test_starting_point(glyph0, glyph1, ix, tolerance, matching):
if matching is None:
matching = list(range(len(glyph0.isomorphisms)))
contour0 = glyph0.isomorphisms[ix]
contour1 = glyph1.isomorphisms[matching[ix]]
m0Vectors = glyph0.greenVectors
m1Vectors = [glyph1.greenVectors[i] for i in matching]
c0 = contour0[0]
# Next few lines duplicated below.
costs = [vdiff_hypot2_complex(c0[0], c1[0]) for c1 in contour1]
min_cost_idx, min_cost = min(enumerate(costs), key=lambda x: x[1])
first_cost = costs[0]
proposed_point = contour1[min_cost_idx][1]
reverse = contour1[min_cost_idx][2]
this_tolerance = min_cost / first_cost if first_cost else 1
if min_cost < first_cost * tolerance:
# c0 is the first isomorphism of the m0 master
# contour1 is list of all isomorphisms of the m1 master
#
# If the two shapes are both circle-ish and slightly
# rotated, we detect wrong start point. This is for
# example the case hundreds of times in
# RobotoSerif-Italic[GRAD,opsz,wdth,wght].ttf
#
# If the proposed point is only one off from the first
# point (and not reversed), try harder:
#
# Find the major eigenvector of the covariance matrix,
# and rotate the contours by that angle. Then find the
# closest point again. If it matches this time, let it
# pass.
num_points = len(glyph1.points[ix])
leeway = num_points // 4
if proposed_point <= leeway or proposed_point >= num_points - leeway:
# Try harder
contour0 = glyph0.isomorphismsNormalized[ix]
contour1 = glyph1.isomorphismsNormalized[matching[ix]]
c0 = contour0[0]
costs = [vdiff_hypot2_complex(c0[0], c1[0]) for c1 in contour1]
new_min_cost_idx, new_min_cost = min(enumerate(costs), key=lambda x: x[1])
new_first_cost = costs[0]
new_this_tolerance = new_min_cost / new_first_cost if new_first_cost else 1
if new_this_tolerance > this_tolerance:
proposed_point = contour1[new_min_cost_idx][1]
reverse = contour1[new_min_cost_idx][2]
this_tolerance = new_this_tolerance
log.debug(
"test-starting-point: tolerance %g",
this_tolerance,
)
return this_tolerance, proposed_point, reverse