[Snippets/symfont] Add glyph perimeter to GlyphStatistics

This commit is contained in:
Behdad Esfahbod 2016-03-28 15:47:19 -07:00
parent f70d264ef0
commit 6bfe6989de

View File

@ -13,6 +13,9 @@ from fontTools.misc.py23 import *
import sympy as sp
import math
from fontTools.pens.basePen import BasePen
from fontTools.pens.transformPen import TransformPen
from fontTools.misc.transform import Scale
from fontTools.misc.bezierTools import splitCubicAtT
from functools import partial
n = 3 # Max Bezier degree; 3 for cubic, 2 for quadratic
@ -71,15 +74,12 @@ def getGreenBezierFuncs(func):
class GreenPen(BasePen):
def __init__(self, glyphset, func, scale=1):
def __init__(self, func, glyphset=None):
BasePen.__init__(self, glyphset)
self._funcs = getGreenBezierFuncs(func)
self._scale = scale
self.value = 0
def _segment(self, *P):
scale = self._scale
P = tuple((x/scale,y/scale) for x,y in P)
self.value += self._funcs[len(P) - 1](P)
def _moveTo(self, p0):
@ -97,7 +97,6 @@ class GreenPen(BasePen):
p0 = self._getCurrentPoint()
self._segment(p0,p1,p2,p3)
AreaPen = partial(GreenPen, func=1)
Moment1XPen = partial(GreenPen, func=x)
Moment1YPen = partial(GreenPen, func=y)
@ -105,23 +104,56 @@ Moment2XXPen = partial(GreenPen, func=x*x)
Moment2YYPen = partial(GreenPen, func=y*y)
Moment2XYPen = partial(GreenPen, func=x*y)
def distance(p0, p1):
return math.hypot(p0[0] - p1[0], p0[1] - p1[1])
class PerimeterPen(BasePen):
def __init__(self, tolerance=0.005, glyphset=None):
BasePen.__init__(self, glyphset)
self.value = 0
self._mult = 1.+tolerance
def _moveTo(self, p0):
pass
def _lineTo(self, p1):
p0 = self._getCurrentPoint()
self.value += distance(p0, p1)
def _addCubic(self, p0, p1, p2, p3):
arch = distance(p0, p3)
box = distance(p0, p1) + distance(p1, p2) + distance(p2, p3)
if arch * self._mult >= box:
self.value += (arch + box) * .5
else:
for c in splitCubicAtT(p0,p1,p2,p3,.5):
self._addCubic(*c)
def _curveToOne(self, p1, p2, p3):
p0 = self._getCurrentPoint()
self._addCubic(p0, p1, p2, p3)
class GlyphStatistics(object):
def __init__(self, glyph, glyphset=None, scale=1):
def __init__(self, glyph, transform=None, glyphset=None):
self._glyph = glyph
self._glyphset = glyphset
self._scale = scale
self._transform = transform
def _penAttr(self, attr):
internalName = '_'+attr
if internalName not in self.__dict__:
Pen = globals()[attr+'Pen']
pen = Pen(self._glyphset, scale=self._scale)
self._glyph.draw(pen)
pen = transformer = Pen(glyphset=self._glyphset)
if self._transform:
transformer = TransformPen(pen, self._transform)
self._glyph.draw(transformer)
self.__dict__[internalName] = pen.value
return self.__dict__[internalName]
Area = property(partial(_penAttr, attr='Area'))
Perimeter = property(partial(_penAttr, attr='Perimeter'))
Moment1X = property(partial(_penAttr, attr='Moment1X'))
Moment1Y = property(partial(_penAttr, attr='Moment1Y'))
Moment2XX = property(partial(_penAttr, attr='Moment2XX'))
@ -196,7 +228,7 @@ def test(glyphset, upem, glyphs):
print()
print("glyph:", glyph_name)
glyph = glyphset[glyph_name]
stats = GlyphStatistics(glyph, glyphset, scale=upem)
stats = GlyphStatistics(glyph, transform=Scale(1./upem), glyphset=glyphset)
for item in dir(stats):
if item[0] == '_': continue
print ("%s: %g" % (item, getattr(stats, item)))