-
Notifications
You must be signed in to change notification settings - Fork 448
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[interpolatable] Move another test to its own file
- Loading branch information
Showing
2 changed files
with
112 additions
and
103 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
100 changes: 100 additions & 0 deletions
100
Lib/fontTools/varLib/interpolatableTestStartingPoint.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
from .interpolatableHelpers import * | ||
|
||
|
||
def test_starting_point(glyph0, glyph1, ix, tolerance): | ||
contour0 = glyph0.isomorphisms[ix] | ||
contour1 = glyph1.isomorphisms[ix] | ||
m0Vectors = glyph0.greenVectors | ||
m1Vectors = glyph1.greenVectors | ||
|
||
starting_point = 0 | ||
reverse = False | ||
min_cost = first_cost = 1 | ||
|
||
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] | ||
|
||
if min_cost < first_cost * tolerance: | ||
this_tolerance = min_cost / first_cost | ||
# 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. | ||
|
||
proposed_point = contour1[min_cost_idx][1] | ||
reverse = contour1[min_cost_idx][2] | ||
num_points = len(glyph1.points[ix]) | ||
leeway = 3 | ||
if not reverse and ( | ||
proposed_point <= leeway or proposed_point >= num_points - leeway | ||
): | ||
# Try harder | ||
|
||
# Recover the covariance matrix from the GreenVectors. | ||
# This is a 2x2 matrix. | ||
transforms = [] | ||
for vector in (m0Vectors[ix], m1Vectors[ix]): | ||
meanX = vector[1] | ||
meanY = vector[2] | ||
stddevX = vector[3] * 0.5 | ||
stddevY = vector[4] * 0.5 | ||
correlation = vector[5] / abs(vector[0]) | ||
|
||
# https://cookierobotics.com/007/ | ||
a = stddevX * stddevX # VarianceX | ||
c = stddevY * stddevY # VarianceY | ||
b = correlation * stddevX * stddevY # Covariance | ||
|
||
delta = (((a - c) * 0.5) ** 2 + b * b) ** 0.5 | ||
lambda1 = (a + c) * 0.5 + delta # Major eigenvalue | ||
lambda2 = (a + c) * 0.5 - delta # Minor eigenvalue | ||
theta = atan2(lambda1 - a, b) if b != 0 else (pi * 0.5 if a < c else 0) | ||
trans = Transform() | ||
# Don't translate here. We are working on the complex-vector | ||
# that includes more than just the points. It's horrible what | ||
# we are doing anyway... | ||
# trans = trans.translate(meanX, meanY) | ||
trans = trans.rotate(theta) | ||
trans = trans.scale(sqrt(lambda1), sqrt(lambda2)) | ||
transforms.append(trans) | ||
|
||
trans = transforms[0] | ||
new_c0 = ( | ||
[complex(*trans.transformPoint((pt.real, pt.imag))) for pt in c0[0]], | ||
) + c0[1:] | ||
trans = transforms[1] | ||
new_contour1 = [] | ||
for c1 in contour1: | ||
new_c1 = ( | ||
[ | ||
complex(*trans.transformPoint((pt.real, pt.imag))) | ||
for pt in c1[0] | ||
], | ||
) + c1[1:] | ||
new_contour1.append(new_c1) | ||
|
||
# Next few lines duplicate from above. | ||
costs = [ | ||
vdiff_hypot2_complex(new_c0[0], new_c1[0]) for new_c1 in new_contour1 | ||
] | ||
min_cost_idx, min_cost = min(enumerate(costs), key=lambda x: x[1]) | ||
first_cost = costs[0] | ||
if min_cost < first_cost * tolerance: | ||
this_tolerance = min_cost / first_cost | ||
proposed_point = new_contour1[min_cost_idx][1] | ||
|
||
return starting_point, reverse, min_cost, first_cost |