summaryrefslogtreecommitdiff
path: root/misc/pylib/robofab/pens/mathPens.py
diff options
context:
space:
mode:
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)
+