This repository has been archived on 2025-10-02. You can view files and clone it, but you cannot make any changes to it's state, such as pushing and creating new issues, pull requests or comments.
inter-font/misc/pylib/robofab/pens/mathPens.py
Rasmus Andersson 8234b62ab7 Speeds up font compilation by around 200%
Cython is used to compile some hot paths into native Python extensions.
These hot paths were identified through running ufocompile with the hotshot
profiler and then converting file by file to Cython, starting with the "hottest"
paths and continuing until returns were deminishing. This means that only a few
Python files were converted to Cython.

Closes #23
Closes #20 (really this time)
2017-09-04 11:12:34 -04:00

185 lines
5.5 KiB
Python
Executable file

"""Some pens that are needed during glyph math"""
from robofab.pens.pointPen import BasePointToSegmentPen, AbstractPointPen
class GetMathDataPointPen(AbstractPointPen):
"""
Point pen that converts all "line" segments into
curve segments containing two off curve points.
"""
def __init__(self):
self.contours = []
self.components = []
self.anchors = []
self._points = []
def _flushContour(self):
points = self._points
if len(points) == 1:
segmentType, pt, smooth, name = points[0]
self.anchors.append((pt, name))
else:
self.contours.append([])
prevOnCurve = None
offCurves = []
# deal with the first point
segmentType, pt, smooth, name = points[0]
# if it is an offcurve, add it to the offcurve list
if segmentType is None:
offCurves.append((segmentType, pt, smooth, name))
# if it is a line, change the type to curve and add it to the contour
# create offcurves corresponding with the last oncurve and
# this point and add them to the points list
elif segmentType == "line":
prevOnCurve = pt
self.contours[-1].append(("curve", pt, False, name))
lastPoint = points[-1][1]
points.append((None, lastPoint, False, None))
points.append((None, pt, False, None))
# a move, curve or qcurve. simple append the data.
else:
self.contours[-1].append((segmentType, pt, smooth, name))
prevOnCurve = pt
# now go through the rest of the points
for segmentType, pt, smooth, name in points[1:]:
# store the off curves
if segmentType is None:
offCurves.append((segmentType, pt, smooth, name))
continue
# make off curve corresponding the the previous
# on curve an dthis point
if segmentType == "line":
segmentType = "curve"
offCurves.append((None, prevOnCurve, False, None))
offCurves.append((None, pt, False, None))
# add the offcurves to the contour
for offCurve in offCurves:
self.contours[-1].append(offCurve)
# add the oncurve to the contour
self.contours[-1].append((segmentType, pt, smooth, name))
# reset the stored data
prevOnCurve = pt
offCurves = []
# catch offcurves that belong to the first
if len(offCurves) != 0:
self.contours[-1].extend(offCurves)
def beginPath(self):
self._points = []
def addPoint(self, pt, segmentType=None, smooth=False, name=None, **kwargs):
self._points.append((segmentType, pt, smooth, name))
def endPath(self):
self._flushContour()
def addComponent(self, baseGlyphName, transformation):
self.components.append((baseGlyphName, transformation))
def getData(self):
return {
'contours':list(self.contours),
'components':list(self.components),
'anchors':list(self.anchors)
}
class CurveSegmentFilterPointPen(AbstractPointPen):
"""
Point pen that turns curve segments that contain
unnecessary anchor points into line segments.
"""
# XXX it would be great if this also checked to see if the
# off curves are on the segment and therefre unneeded
def __init__(self, anotherPointPen):
self._pen = anotherPointPen
self._points = []
def _flushContour(self):
points = self._points
# an anchor
if len(points) == 1:
pt, segmentType, smooth, name = points[0]
self._pen.addPoint(pt, segmentType, smooth, name)
else:
prevOnCurve = None
offCurves = []
pointsToDraw = []
# deal with the first point
pt, segmentType, smooth, name = points[0]
# if it is an offcurve, add it to the offcurve list
if segmentType is None:
offCurves.append((pt, segmentType, smooth, name))
else:
# potential redundancy
if segmentType == "curve":
# gather preceding off curves
testOffCurves = []
lastPoint = None
for i in xrange(len(points)):
i = -i - 1
testPoint = points[i]
testSegmentType = testPoint[1]
if testSegmentType is not None:
lastPoint = testPoint[0]
break
testOffCurves.append(testPoint[0])
# if two offcurves exist we can test for redundancy
if len(testOffCurves) == 2:
if testOffCurves[1] == lastPoint and testOffCurves[0] == pt:
segmentType = "line"
# remove the last two points
points = points[:-2]
# add the point to the contour
pointsToDraw.append((pt, segmentType, smooth, name))
prevOnCurve = pt
for pt, segmentType, smooth, name in points[1:]:
# store offcurves
if segmentType is None:
offCurves.append((pt, segmentType, smooth, name))
continue
# curves are a potential redundancy
elif segmentType == "curve":
if len(offCurves) == 2:
# test for redundancy
if offCurves[0][0] == prevOnCurve and offCurves[1][0] == pt:
offCurves = []
segmentType = "line"
# add all offcurves
for offCurve in offCurves:
pointsToDraw.append(offCurve)
# add the on curve
pointsToDraw.append((pt, segmentType, smooth, name))
# reset the stored data
prevOnCurve = pt
offCurves = []
# catch any remaining offcurves
if len(offCurves) != 0:
for offCurve in offCurves:
pointsToDraw.append(offCurve)
# draw to the pen
for pt, segmentType, smooth, name in pointsToDraw:
self._pen.addPoint(pt, segmentType, smooth, name)
def beginPath(self):
self._points = []
self._pen.beginPath()
def addPoint(self, pt, segmentType=None, smooth=False, name=None, **kwargs):
self._points.append((pt, segmentType, smooth, name))
def endPath(self):
self._flushContour()
self._pen.endPath()
def addComponent(self, baseGlyphName, transformation):
self._pen.addComponent(baseGlyphName, transformation)