summaryrefslogtreecommitdiff
path: root/misc/pylib/robofab/pens/mathPens.py
diff options
context:
space:
mode:
authorRasmus Andersson <rasmus@notion.se>2017-09-04 06:03:17 +0300
committerRasmus Andersson <rasmus@notion.se>2017-09-04 18:12:34 +0300
commit8234b62ab762637ef24c3398b4204a8ce8db31a7 (patch)
tree1c8df547021cdb58951630a015e4101ede46dbf1 /misc/pylib/robofab/pens/mathPens.py
parent31ae014e0c827dd76696fdab7e4ca3fed9f6402b (diff)
downloadinter-8234b62ab762637ef24c3398b4204a8ce8db31a7.tar.xz
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)
Diffstat (limited to 'misc/pylib/robofab/pens/mathPens.py')
-rwxr-xr-xmisc/pylib/robofab/pens/mathPens.py185
1 files changed, 185 insertions, 0 deletions
diff --git a/misc/pylib/robofab/pens/mathPens.py b/misc/pylib/robofab/pens/mathPens.py
new file mode 100755
index 000000000..1fe1026e1
--- /dev/null
+++ b/misc/pylib/robofab/pens/mathPens.py
@@ -0,0 +1,185 @@
+"""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)
+