diff --git a/Lib/fontTools/varLib/interpolatable.py b/Lib/fontTools/varLib/interpolatable.py index f03e94620..ae2de2a19 100644 --- a/Lib/fontTools/varLib/interpolatable.py +++ b/Lib/fontTools/varLib/interpolatable.py @@ -282,14 +282,8 @@ def test_gen( # "contour_order" check # - matching, matching_cost, identity_cost = test_contour_order(glyph0, glyph1) - if matching_cost < identity_cost * tolerance: - log.debug( - "matching_ratio %g", - matching_cost / identity_cost, - ) - this_tolerance = matching_cost / identity_cost - log.debug("tolerance: %g", this_tolerance) + this_tolerance, matching = test_contour_order(glyph0, glyph1) + if this_tolerance < tolerance: yield ( glyph_name, { @@ -352,119 +346,109 @@ def test_gen( # after reordering above. continue - proposed_point, reverse, min_cost, first_cost = test_starting_point( + this_tolerance, proposed_point, reverse = test_starting_point( glyph0, glyph1, ix, tolerance, matching ) - if proposed_point or reverse: - this_tolerance = min_cost / first_cost - log.debug("tolerance: %g", this_tolerance) - if min_cost < first_cost * tolerance: - yield ( - glyph_name, - { - "type": "wrong_start_point", - "contour": ix, - "master_1": names[m0idx], - "master_2": names[m1idx], - "master_1_idx": m0idx, - "master_2_idx": m1idx, - "value_1": 0, - "value_2": proposed_point, - "reversed": reverse, - "tolerance": this_tolerance, - }, - ) - else: - # Weight check. - # - # If contour could be mid-interpolated, and the two - # contours have the same area sign, proceeed. - # - # The sign difference can happen if it's a werido - # self-intersecting contour; ignore it. - contour = midRecording[ix] + if this_tolerance < tolerance: + yield ( + glyph_name, + { + "type": "wrong_start_point", + "contour": ix, + "master_1": names[m0idx], + "master_2": names[m1idx], + "master_1_idx": m0idx, + "master_2_idx": m1idx, + "value_1": 0, + "value_2": proposed_point, + "reversed": reverse, + "tolerance": this_tolerance, + }, + ) - normalized = False - if contour and (m0Vectors[ix][0] < 0) == (m1Vectors[ix][0] < 0): - if normalized: - midStats = StatisticsPen(glyphset=None) - tpen = TransformPen( - midStats, transform_from_stats(midStats, inverse=True) - ) - contour.replay(tpen) + # Weight check. + # + # If contour could be mid-interpolated, and the two + # contours have the same area sign, proceeed. + # + # The sign difference can happen if it's a weirdo + # self-intersecting contour; ignore it. + contour = midRecording[ix] + + normalized = False + if contour and (m0Vectors[ix][0] < 0) == (m1Vectors[ix][0] < 0): + if normalized: + midStats = StatisticsPen(glyphset=None) + tpen = TransformPen( + midStats, transform_from_stats(midStats, inverse=True) + ) + contour.replay(tpen) + else: + midStats = StatisticsPen(glyphset=None) + contour.replay(midStats) + + midVector = contour_vector_from_stats(midStats) + + m0Vec = m0Vectors[ix] if not normalized else m0VectorsNormalized[ix] + m1Vec = m1Vectors[ix] if not normalized else m1VectorsNormalized[ix] + size0 = m0Vec[0] * m0Vec[0] + size1 = m1Vec[0] * m1Vec[0] + midSize = midVector[0] * midVector[0] + + power = 1 + t = tolerance**power + + for overweight, problem_type in enumerate( + ("underweight", "overweight") + ): + if overweight: + expectedSize = sqrt(size0 * size1) + expectedSize = (size0 + size1) - expectedSize + expectedSize = size1 + (midSize - size1) + continue else: - midStats = StatisticsPen(glyphset=None) - contour.replay(midStats) + expectedSize = sqrt(size0 * size1) - midVector = contour_vector_from_stats(midStats) - - m0Vec = ( - m0Vectors[ix] if not normalized else m0VectorsNormalized[ix] + log.debug( + "%s: actual size %g; threshold size %g, master sizes: %g, %g", + problem_type, + midSize, + expectedSize, + size0, + size1, ) - m1Vec = ( - m1Vectors[ix] if not normalized else m1VectorsNormalized[ix] - ) - size0 = m0Vec[0] * m0Vec[0] - size1 = m1Vec[0] * m1Vec[0] - midSize = midVector[0] * midVector[0] - power = 1 - t = tolerance**power + size0, size1 = sorted((size0, size1)) - for overweight, problem_type in enumerate( - ("underweight", "overweight") - ): - if overweight: - expectedSize = sqrt(size0 * size1) - expectedSize = (size0 + size1) - expectedSize - expectedSize = size1 + (midSize - size1) - continue - else: - expectedSize = sqrt(size0 * size1) - - log.debug( - "%s: actual size %g; threshold size %g, master sizes: %g, %g", - problem_type, - midSize, - expectedSize, - size0, - size1, + if ( + not overweight and expectedSize * tolerance > midSize + 1e-5 + ) or (overweight and 1e-5 + expectedSize / tolerance < midSize): + try: + if overweight: + this_tolerance = (expectedSize / midSize) ** ( + 1 / power + ) + else: + this_tolerance = (midSize / expectedSize) ** ( + 1 / power + ) + except ZeroDivisionError: + this_tolerance = 0 + log.debug("tolerance %g", this_tolerance) + yield ( + glyph_name, + { + "type": problem_type, + "contour": ix, + "master_1": names[m0idx], + "master_2": names[m1idx], + "master_1_idx": m0idx, + "master_2_idx": m1idx, + "tolerance": this_tolerance, + }, ) - size0, size1 = sorted((size0, size1)) - - if ( - not overweight - and expectedSize * tolerance > midSize + 1e-5 - ) or ( - overweight and 1e-5 + expectedSize / tolerance < midSize - ): - try: - if overweight: - this_tolerance = (expectedSize / midSize) ** ( - 1 / power - ) - else: - this_tolerance = (midSize / expectedSize) ** ( - 1 / power - ) - except ZeroDivisionError: - this_tolerance = 0 - log.debug("tolerance %g", this_tolerance) - yield ( - glyph_name, - { - "type": problem_type, - "contour": ix, - "master_1": names[m0idx], - "master_2": names[m1idx], - "master_1_idx": m0idx, - "master_2_idx": m1idx, - "tolerance": this_tolerance, - }, - ) - # # "kink" detector # diff --git a/Lib/fontTools/varLib/interpolatableTestContourOrder.py b/Lib/fontTools/varLib/interpolatableTestContourOrder.py index d089e4357..9edb1afcb 100644 --- a/Lib/fontTools/varLib/interpolatableTestContourOrder.py +++ b/Lib/fontTools/varLib/interpolatableTestContourOrder.py @@ -1,4 +1,7 @@ from .interpolatableHelpers import * +import logging + +log = logging.getLogger("fontTools.varLib.interpolatable") def test_contour_order(glyph0, glyph1): @@ -71,4 +74,9 @@ def test_contour_order(glyph0, glyph1): matching_cost = matching_cost_green identity_cost = identity_cost_green - return matching, matching_cost, identity_cost + this_tolerance = matching_cost / identity_cost if identity_cost else 1 + log.debug( + "test-contour-order: tolerance %g", + this_tolerance, + ) + return this_tolerance, matching diff --git a/Lib/fontTools/varLib/interpolatableTestStartingPoint.py b/Lib/fontTools/varLib/interpolatableTestStartingPoint.py index 9f742a14f..a84a65184 100644 --- a/Lib/fontTools/varLib/interpolatableTestStartingPoint.py +++ b/Lib/fontTools/varLib/interpolatableTestStartingPoint.py @@ -19,8 +19,10 @@ def test_starting_point(glyph0, glyph1, ix, tolerance, matching): 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] + 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 # @@ -37,8 +39,6 @@ def test_starting_point(glyph0, glyph1, ix, tolerance, matching): # 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 ( @@ -102,4 +102,9 @@ def test_starting_point(glyph0, glyph1, ix, tolerance, matching): # proposed_point = 0 # new_contour1[min_cost_idx][1] pass - return proposed_point, reverse, min_cost, first_cost + this_tolerance = min_cost / first_cost if first_cost else 1 + log.debug( + "test-starting-point: tolerance %g", + this_tolerance, + ) + return this_tolerance, proposed_point, reverse