Reformat with black

This commit is contained in:
Simon Cozens 2020-11-20 10:02:46 +00:00
parent 129e2413a0
commit 08e2a6cdc1

View File

@ -13,209 +13,260 @@ import itertools
class PerContourPen(BasePen):
def __init__(self, Pen, glyphset=None):
BasePen.__init__(self, glyphset)
self._glyphset = glyphset
self._Pen = Pen
self._pen = None
self.value = []
def _moveTo(self, p0):
self._newItem()
self._pen.moveTo(p0)
def _lineTo(self, p1):
self._pen.lineTo(p1)
def _qCurveToOne(self, p1, p2):
self._pen.qCurveTo(p1, p2)
def _curveToOne(self, p1, p2, p3):
self._pen.curveTo(p1, p2, p3)
def _closePath(self):
self._pen.closePath()
self._pen = None
def _endPath(self):
self._pen.endPath()
self._pen = None
def __init__(self, Pen, glyphset=None):
BasePen.__init__(self, glyphset)
self._glyphset = glyphset
self._Pen = Pen
self._pen = None
self.value = []
def _moveTo(self, p0):
self._newItem()
self._pen.moveTo(p0)
def _lineTo(self, p1):
self._pen.lineTo(p1)
def _qCurveToOne(self, p1, p2):
self._pen.qCurveTo(p1, p2)
def _curveToOne(self, p1, p2, p3):
self._pen.curveTo(p1, p2, p3)
def _closePath(self):
self._pen.closePath()
self._pen = None
def _endPath(self):
self._pen.endPath()
self._pen = None
def _newItem(self):
self._pen = pen = self._Pen()
self.value.append(pen)
def _newItem(self):
self._pen = pen = self._Pen()
self.value.append(pen)
class PerContourOrComponentPen(PerContourPen):
def addComponent(self, glyphName, transformation):
self._newItem()
self.value[-1].addComponent(glyphName, transformation)
def addComponent(self, glyphName, transformation):
self._newItem()
self.value[-1].addComponent(glyphName, transformation)
def _vdiff(v0, v1):
return tuple(b-a for a,b in zip(v0,v1))
return tuple(b - a for a, b in zip(v0, v1))
def _vlen(vec):
v = 0
for x in vec:
v += x*x
return v
v = 0
for x in vec:
v += x * x
return v
def _matching_cost(G, matching):
return sum(G[i][j] for i,j in enumerate(matching))
return sum(G[i][j] for i, j in enumerate(matching))
def min_cost_perfect_bipartite_matching(G):
n = len(G)
try:
from scipy.optimize import linear_sum_assignment
rows, cols = linear_sum_assignment(G)
assert (rows == list(range(n))).all()
return list(cols), _matching_cost(G, cols)
except ImportError:
pass
n = len(G)
try:
from scipy.optimize import linear_sum_assignment
try:
from munkres import Munkres
cols = [None] * n
for row,col in Munkres().compute(G):
cols[row] = col
return cols, _matching_cost(G, cols)
except ImportError:
pass
rows, cols = linear_sum_assignment(G)
assert (rows == list(range(n))).all()
return list(cols), _matching_cost(G, cols)
except ImportError:
pass
if n > 6:
raise Exception("Install Python module 'munkres' or 'scipy >= 0.17.0'")
try:
from munkres import Munkres
# Otherwise just brute-force
permutations = itertools.permutations(range(n))
best = list(next(permutations))
best_cost = _matching_cost(G, best)
for p in permutations:
cost = _matching_cost(G, p)
if cost < best_cost:
best, best_cost = list(p), cost
return best, best_cost
cols = [None] * n
for row, col in Munkres().compute(G):
cols[row] = col
return cols, _matching_cost(G, cols)
except ImportError:
pass
if n > 6:
raise Exception("Install Python module 'munkres' or 'scipy >= 0.17.0'")
# Otherwise just brute-force
permutations = itertools.permutations(range(n))
best = list(next(permutations))
best_cost = _matching_cost(G, best)
for p in permutations:
cost = _matching_cost(G, p)
if cost < best_cost:
best, best_cost = list(p), cost
return best, best_cost
def test(glyphsets, glyphs=None, names=None):
if names is None:
names = glyphsets
if glyphs is None:
glyphs = glyphsets[0].keys()
if names is None:
names = glyphsets
if glyphs is None:
glyphs = glyphsets[0].keys()
hist = []
for glyph_name in glyphs:
#print()
#print(glyph_name)
hist = []
for glyph_name in glyphs:
# print()
# print(glyph_name)
try:
allVectors = []
allNodeTypes = []
for glyphset,name in zip(glyphsets, names):
#print('.', end='')
if glyph_name not in glyphset:
print('%s: Glyph cannot be interpolated - does not exist in master %s' % (glyph_name, name))
continue
glyph = glyphset[glyph_name]
try:
allVectors = []
allNodeTypes = []
for glyphset, name in zip(glyphsets, names):
# print('.', end='')
if glyph_name not in glyphset:
print(
"%s: Glyph cannot be interpolated - does not exist in master %s"
% (glyph_name, name)
)
continue
glyph = glyphset[glyph_name]
perContourPen = PerContourOrComponentPen(RecordingPen, glyphset=glyphset)
glyph.draw(perContourPen)
contourPens = perContourPen.value
del perContourPen
perContourPen = PerContourOrComponentPen(
RecordingPen, glyphset=glyphset
)
glyph.draw(perContourPen)
contourPens = perContourPen.value
del perContourPen
contourVectors = []
nodeTypes = []
allNodeTypes.append(nodeTypes)
allVectors.append(contourVectors)
for contour in contourPens:
nodeTypes.append(tuple(instruction[0] for instruction in contour.value))
stats = StatisticsPen(glyphset=glyphset)
try:
contour.replay(stats)
except NotImplementedError as e:
print('%s: Glyph cannot be interpolated - open path!' % glyph_name)
break
size = abs(stats.area) ** .5 * .5
vector = (
int(size),
int(stats.meanX),
int(stats.meanY),
int(stats.stddevX * 2),
int(stats.stddevY * 2),
int(stats.correlation * size),
)
contourVectors.append(vector)
#print(vector)
contourVectors = []
nodeTypes = []
allNodeTypes.append(nodeTypes)
allVectors.append(contourVectors)
for contour in contourPens:
nodeTypes.append(
tuple(instruction[0] for instruction in contour.value)
)
stats = StatisticsPen(glyphset=glyphset)
try:
contour.replay(stats)
except NotImplementedError as e:
print(
"%s: Glyph cannot be interpolated - open path!" % glyph_name
)
break
size = abs(stats.area) ** 0.5 * 0.5
vector = (
int(size),
int(stats.meanX),
int(stats.meanY),
int(stats.stddevX * 2),
int(stats.stddevY * 2),
int(stats.correlation * size),
)
contourVectors.append(vector)
# print(vector)
# Check each master against the next one in the list.
for i, (m0, m1) in enumerate(zip(allNodeTypes[:-1], allNodeTypes[1:])):
if len(m0) != len(m1):
print('%s: %s+%s: Glyphs not compatible (wrong number of paths %i+%i)!!!!!' % (glyph_name, names[i], names[i+1], len(m0), len(m1)))
if m0 == m1:
continue
for pathIx, (nodes1, nodes2) in enumerate(zip(m0, m1)):
if nodes1 == nodes2:
continue
print('%s: %s+%s: Glyphs not compatible at path %i!!!!!' % (glyph_name, names[i], names[i+1], pathIx))
if len(nodes1) != len(nodes2):
print("%s has %i nodes, %s has %i nodes" % (names[i], len(nodes1), names[i+1], len(nodes2)))
continue
for nodeIx, (n1, n2) in enumerate(zip(nodes1, nodes2)):
if n1 != n2:
print("At node %i, %s has %s, %s has %s" % (nodeIx, names[i], n1, names[i+1], n2))
continue
# Check each master against the next one in the list.
for i, (m0, m1) in enumerate(zip(allNodeTypes[:-1], allNodeTypes[1:])):
if len(m0) != len(m1):
print(
"%s: %s+%s: Glyphs not compatible (wrong number of paths %i+%i)!!!!!"
% (glyph_name, names[i], names[i + 1], len(m0), len(m1))
)
if m0 == m1:
continue
for pathIx, (nodes1, nodes2) in enumerate(zip(m0, m1)):
if nodes1 == nodes2:
continue
print(
"%s: %s+%s: Glyphs not compatible at path %i!!!!!"
% (glyph_name, names[i], names[i + 1], pathIx)
)
if len(nodes1) != len(nodes2):
print(
"%s has %i nodes, %s has %i nodes"
% (names[i], len(nodes1), names[i + 1], len(nodes2))
)
continue
for nodeIx, (n1, n2) in enumerate(zip(nodes1, nodes2)):
if n1 != n2:
print(
"At node %i, %s has %s, %s has %s"
% (nodeIx, names[i], n1, names[i + 1], n2)
)
continue
for i,(m0,m1) in enumerate(zip(allVectors[:-1],allVectors[1:])):
if len(m0) != len(m1):
print('%s: %s+%s: Glyphs not compatible!!!!!' % (glyph_name, names[i], names[i+1]))
continue
if not m0:
continue
costs = [[_vlen(_vdiff(v0,v1)) for v1 in m1] for v0 in m0]
matching, matching_cost = min_cost_perfect_bipartite_matching(costs)
if matching != list(range(len(m0))):
print('%s: %s+%s: Glyph has wrong contour/component order: %s' % (glyph_name, names[i], names[i+1], matching)) #, m0, m1)
break
upem = 2048
item_cost = round((matching_cost / len(m0) / len(m0[0])) ** .5 / upem * 100)
hist.append(item_cost)
threshold = 7
if item_cost >= threshold:
print('%s: %s+%s: Glyph has very high cost: %d%%' % (glyph_name, names[i], names[i+1], item_cost))
for i, (m0, m1) in enumerate(zip(allVectors[:-1], allVectors[1:])):
if len(m0) != len(m1):
print(
"%s: %s+%s: Glyphs not compatible!!!!!"
% (glyph_name, names[i], names[i + 1])
)
continue
if not m0:
continue
costs = [[_vlen(_vdiff(v0, v1)) for v1 in m1] for v0 in m0]
matching, matching_cost = min_cost_perfect_bipartite_matching(costs)
if matching != list(range(len(m0))):
print(
"%s: %s+%s: Glyph has wrong contour/component order: %s"
% (glyph_name, names[i], names[i + 1], matching)
) # , m0, m1)
break
upem = 2048
item_cost = round(
(matching_cost / len(m0) / len(m0[0])) ** 0.5 / upem * 100
)
hist.append(item_cost)
threshold = 7
if item_cost >= threshold:
print(
"%s: %s+%s: Glyph has very high cost: %d%%"
% (glyph_name, names[i], names[i + 1], item_cost)
)
except ValueError as e:
print("%s: %s: math error %s; skipping glyph." % (glyph_name, name, e))
print(contour.value)
# raise
# for x in hist:
# print(x)
except ValueError as e:
print('%s: %s: math error %s; skipping glyph.' % (glyph_name, name, e))
print(contour.value)
#raise
#for x in hist:
# print(x)
def main(args=None):
"""Test for interpolatability issues between fonts"""
import argparse
parser = argparse.ArgumentParser(
"fonttools varLib.interpolatable",
description=main.__doc__,
)
parser.add_argument('inputs', metavar='FILE', type=str, nargs='+',
help="Input TTF/UFO files")
"""Test for interpolatability issues between fonts"""
import argparse
args = parser.parse_args(args)
glyphs = None
#glyphs = ['uni08DB', 'uniFD76']
#glyphs = ['uni08DE', 'uni0034']
#glyphs = ['uni08DE', 'uni0034', 'uni0751', 'uni0753', 'uni0754', 'uni08A4', 'uni08A4.fina', 'uni08A5.fina']
parser = argparse.ArgumentParser(
"fonttools varLib.interpolatable",
description=main.__doc__,
)
parser.add_argument(
"inputs", metavar="FILE", type=str, nargs="+", help="Input TTF/UFO files"
)
from os.path import basename
names = [basename(filename).rsplit('.', 1)[0] for filename in args.inputs]
args = parser.parse_args(args)
glyphs = None
# glyphs = ['uni08DB', 'uniFD76']
# glyphs = ['uni08DE', 'uni0034']
# glyphs = ['uni08DE', 'uni0034', 'uni0751', 'uni0753', 'uni0754', 'uni08A4', 'uni08A4.fina', 'uni08A5.fina']
fonts = []
for filename in args.inputs:
if filename.endswith(".ufo"):
from fontTools.ufoLib import UFOReader
fonts.append(UFOReader(filename))
else:
from fontTools.ttLib import TTFont
fonts.append(TTFont(filename))
from os.path import basename
glyphsets = [font.getGlyphSet() for font in fonts]
test(glyphsets, glyphs=glyphs, names=names)
names = [basename(filename).rsplit(".", 1)[0] for filename in args.inputs]
if __name__ == '__main__':
import sys
main()
fonts = []
for filename in args.inputs:
if filename.endswith(".ufo"):
from fontTools.ufoLib import UFOReader
fonts.append(UFOReader(filename))
else:
from fontTools.ttLib import TTFont
fonts.append(TTFont(filename))
glyphsets = [font.getGlyphSet() for font in fonts]
test(glyphsets, glyphs=glyphs, names=names)
if __name__ == "__main__":
import sys
main()