summaryrefslogtreecommitdiff
path: root/misc/pylib/robofab/pens/reverseContourPointPen.py
diff options
context:
space:
mode:
Diffstat (limited to 'misc/pylib/robofab/pens/reverseContourPointPen.py')
-rwxr-xr-xmisc/pylib/robofab/pens/reverseContourPointPen.py125
1 files changed, 125 insertions, 0 deletions
diff --git a/misc/pylib/robofab/pens/reverseContourPointPen.py b/misc/pylib/robofab/pens/reverseContourPointPen.py
new file mode 100755
index 000000000..8ce001b4d
--- /dev/null
+++ b/misc/pylib/robofab/pens/reverseContourPointPen.py
@@ -0,0 +1,125 @@
+"""PointPen for reversing the winding direction of contours."""
+
+
+__all__ = ["ReverseContourPointPen"]
+
+
+from robofab.pens.pointPen import AbstractPointPen
+
+
+class ReverseContourPointPen(AbstractPointPen):
+
+ """This is a PointPen that passes outline data to another PointPen, but
+ reversing the winding direction of all contours. Components are simply
+ passed through unchanged.
+
+ Closed contours are reversed in such a way that the first point remains
+ the first point.
+ """
+
+ def __init__(self, outputPointPen):
+ self.pen = outputPointPen
+ self.currentContour = None # a place to store the points for the current sub path
+
+ def _flushContour(self):
+ pen = self.pen
+ contour = self.currentContour
+ if not contour:
+ pen.beginPath()
+ pen.endPath()
+ return
+
+ closed = contour[0][1] != "move"
+ if not closed:
+ lastSegmentType = "move"
+ else:
+ # Remove the first point and insert it at the end. When
+ # the list of points gets reversed, this point will then
+ # again be at the start. In other words, the following
+ # will hold:
+ # for N in range(len(originalContour)):
+ # originalContour[N] == reversedContour[-N]
+ contour.append(contour.pop(0))
+ # Find the first on-curve point.
+ firstOnCurve = None
+ for i in range(len(contour)):
+ if contour[i][1] is not None:
+ firstOnCurve = i
+ break
+ if firstOnCurve is None:
+ # There are no on-curve points, be basically have to
+ # do nothing but contour.reverse().
+ lastSegmentType = None
+ else:
+ lastSegmentType = contour[firstOnCurve][1]
+
+ contour.reverse()
+ if not closed:
+ # Open paths must start with a move, so we simply dump
+ # all off-curve points leading up to the first on-curve.
+ while contour[0][1] is None:
+ contour.pop(0)
+ pen.beginPath()
+ for pt, nextSegmentType, smooth, name in contour:
+ if nextSegmentType is not None:
+ segmentType = lastSegmentType
+ lastSegmentType = nextSegmentType
+ else:
+ segmentType = None
+ pen.addPoint(pt, segmentType=segmentType, smooth=smooth, name=name)
+ pen.endPath()
+
+ def beginPath(self):
+ assert self.currentContour is None
+ self.currentContour = []
+ self.onCurve = []
+
+ def endPath(self):
+ assert self.currentContour is not None
+ self._flushContour()
+ self.currentContour = None
+
+ def addPoint(self, pt, segmentType=None, smooth=False, name=None, **kwargs):
+ self.currentContour.append((pt, segmentType, smooth, name))
+
+ def addComponent(self, glyphName, transform):
+ assert self.currentContour is None
+ self.pen.addComponent(glyphName, transform)
+
+
+if __name__ == "__main__":
+ from robofab.pens.pointPen import PrintingPointPen
+ pP = PrintingPointPen()
+ rP = ReverseContourPointPen(pP)
+
+ rP.beginPath()
+ rP.addPoint((339, -8), "curve")
+ rP.addPoint((502, -8))
+ rP.addPoint((635, 65))
+ rP.addPoint((635, 305), "curve")
+ rP.addPoint((635, 545))
+ rP.addPoint((504, 623))
+ rP.addPoint((340, 623), "curve")
+ rP.addPoint((177, 623))
+ rP.addPoint((43, 545))
+ rP.addPoint((43, 305), "curve")
+ rP.addPoint((43, 65))
+ rP.addPoint((176, -8))
+ rP.endPath()
+
+ rP.beginPath()
+ rP.addPoint((100, 100), "move", smooth=False, name='a')
+ rP.addPoint((150, 150))
+ rP.addPoint((200, 200))
+ rP.addPoint((250, 250), "curve", smooth=True, name='b')
+ rP.addPoint((300, 300), "line", smooth=False, name='c')
+ rP.addPoint((350, 350))
+ rP.addPoint((400, 400))
+ rP.addPoint((450, 450))
+ rP.addPoint((500, 500), "curve", smooth=True, name='d')
+ rP.addPoint((550, 550))
+ rP.addPoint((600, 600))
+ rP.addPoint((650, 650))
+ rP.addPoint((700, 700))
+ rP.addPoint((750, 750), "qcurve", smooth=False, name='e')
+ rP.endPath()