From 56c27f45c9534a96fe291a10965185578472e8fc Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Mon, 13 Jun 2016 18:47:43 -0400 Subject: [PATCH] Speed up perimeterPen It's still too slow, but an improvement. Also, remove duplicate copy from symfont. --- Lib/fontTools/pens/perimeterPen.py | 17 ++++++++++++++--- Snippets/symfont.py | 30 ++---------------------------- 2 files changed, 16 insertions(+), 31 deletions(-) diff --git a/Lib/fontTools/pens/perimeterPen.py b/Lib/fontTools/pens/perimeterPen.py index 254d9ef54..8d0893f94 100644 --- a/Lib/fontTools/pens/perimeterPen.py +++ b/Lib/fontTools/pens/perimeterPen.py @@ -3,7 +3,7 @@ from __future__ import print_function, division, absolute_import from fontTools.misc.py23 import * from fontTools.pens.basePen import BasePen -from fontTools.misc.bezierTools import splitCubicAtT +from fontTools.misc.bezierTools import splitQuadraticAtT, splitCubicAtT import math @@ -16,7 +16,7 @@ class PerimeterPen(BasePen): def __init__(self, glyphset=None, tolerance=0.005): BasePen.__init__(self, glyphset) self.value = 0 - self._mult = 1. + tolerance + self._mult = 1.+1.5*tolerance # The 1.5 is a empirical hack; no math def _moveTo(self, p0): self.__startPoint = p0 @@ -25,15 +25,26 @@ class PerimeterPen(BasePen): p0 = self._getCurrentPoint() self.value += distance(p0, p1) + def _addQuadratic(self, p0, p1, p2): + arch = distance(p0, p2) + box = distance(p0, p1) + distance(p1, p2) + if arch * self._mult >= box: + self.value += (arch + box) * .5 + else: + for c in splitQuadraticAtT(p0,p1,p2,.25,.5,.75): + self._addQuadratic(*c) 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): + for c in splitCubicAtT(p0,p1,p2,p3,.2,.4,.6,.8): self._addCubic(*c) + def _qCurveToOne(self, p1, p2): + p0 = self._getCurrentPoint() + self._addQuadratic(p0, p1, p2) def _curveToOne(self, p1, p2, p3): p0 = self._getCurrentPoint() self._addCubic(p0, p1, p2, p3) diff --git a/Snippets/symfont.py b/Snippets/symfont.py index 3919cdadd..8d1e66df1 100755 --- a/Snippets/symfont.py +++ b/Snippets/symfont.py @@ -14,8 +14,9 @@ import sympy as sp import math from fontTools.pens.basePen import BasePen from fontTools.pens.transformPen import TransformPen +from fontTools.pens.perimeterPen import PerimeterPen from fontTools.misc.transform import Scale -from fontTools.misc.bezierTools import splitCubicAtT +from fontTools.misc.bezierTools import splitQuadraticAtT, splitCubicAtT from functools import partial n = 3 # Max Bezier degree; 3 for cubic, 2 for quadratic @@ -109,33 +110,6 @@ 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, transform=None, glyphset=None):