Speed up perimeterPen

It's still too slow, but an improvement.

Also, remove duplicate copy from symfont.
This commit is contained in:
Behdad Esfahbod 2016-06-13 18:47:43 -04:00
parent 71fb49962a
commit 56c27f45c9
2 changed files with 16 additions and 31 deletions

View File

@ -3,7 +3,7 @@
from __future__ import print_function, division, absolute_import from __future__ import print_function, division, absolute_import
from fontTools.misc.py23 import * from fontTools.misc.py23 import *
from fontTools.pens.basePen import BasePen from fontTools.pens.basePen import BasePen
from fontTools.misc.bezierTools import splitCubicAtT from fontTools.misc.bezierTools import splitQuadraticAtT, splitCubicAtT
import math import math
@ -16,7 +16,7 @@ class PerimeterPen(BasePen):
def __init__(self, glyphset=None, tolerance=0.005): def __init__(self, glyphset=None, tolerance=0.005):
BasePen.__init__(self, glyphset) BasePen.__init__(self, glyphset)
self.value = 0 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): def _moveTo(self, p0):
self.__startPoint = p0 self.__startPoint = p0
@ -25,15 +25,26 @@ class PerimeterPen(BasePen):
p0 = self._getCurrentPoint() p0 = self._getCurrentPoint()
self.value += distance(p0, p1) 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): def _addCubic(self, p0, p1, p2, p3):
arch = distance(p0, p3) arch = distance(p0, p3)
box = distance(p0, p1) + distance(p1, p2) + distance(p2, p3) box = distance(p0, p1) + distance(p1, p2) + distance(p2, p3)
if arch * self._mult >= box: if arch * self._mult >= box:
self.value += (arch + box) * .5 self.value += (arch + box) * .5
else: 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) self._addCubic(*c)
def _qCurveToOne(self, p1, p2):
p0 = self._getCurrentPoint()
self._addQuadratic(p0, p1, p2)
def _curveToOne(self, p1, p2, p3): def _curveToOne(self, p1, p2, p3):
p0 = self._getCurrentPoint() p0 = self._getCurrentPoint()
self._addCubic(p0, p1, p2, p3) self._addCubic(p0, p1, p2, p3)

View File

@ -14,8 +14,9 @@ import sympy as sp
import math import math
from fontTools.pens.basePen import BasePen from fontTools.pens.basePen import BasePen
from fontTools.pens.transformPen import TransformPen from fontTools.pens.transformPen import TransformPen
from fontTools.pens.perimeterPen import PerimeterPen
from fontTools.misc.transform import Scale from fontTools.misc.transform import Scale
from fontTools.misc.bezierTools import splitCubicAtT from fontTools.misc.bezierTools import splitQuadraticAtT, splitCubicAtT
from functools import partial from functools import partial
n = 3 # Max Bezier degree; 3 for cubic, 2 for quadratic 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): def distance(p0, p1):
return math.hypot(p0[0] - p1[0], p0[1] - p1[1]) 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): class GlyphStatistics(object):
def __init__(self, glyph, transform=None, glyphset=None): def __init__(self, glyph, transform=None, glyphset=None):