1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
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)
|