root/trunk/Lib/robofab/pens/angledMarginPen.py

Revision 85, 3.9 kB (checked in by erik, 2 years ago)

AngledMarginPen? calculates the left and right side-bearings of a glyph, relative to slanted margins. The angle is taken from font.info.italicAngle. Curves are approximated. This also contains 5 convenience functions to set and get individual margins and to center the glyph.

The approximation can be improved upon, perhaps taking the size of the bezier into account and so on. Also the italic offset, as it was used in RoboFog? is missing, and could perhaps be taken into account.

Line 
1 from robofab.world import RFont
2 from fontTools.pens.basePen import BasePen
3 from fontTools.misc.arrayTools import updateBounds, pointInRect, unionRect
4 from fontTools.misc.bezierTools import calcCubicBounds, calcQuadraticBounds
5 from robofab.pens.filterPen import _estimateCubicCurveLength, _getCubicPoint
6 import math
7
8
9
10 __all__ = ["AngledMarginPen", "getAngledMargins",
11         "setAngledLeftMargin", "setAngledRightMargin",
12         "centerAngledMargins"]
13
14
15
16 class AngledMarginPen(BasePen):
17         """
18                 Angled Margin Pen
19
20                 Pen to calculate the margins as if the margin lines were slanted
21                 according to the font.info.italicAngle.
22
23                 Notes:
24                 - this pen works on the on-curve points, and approximates the distance to curves.
25                 - results will be float.
26                 - when used in FontLab, the resulting margins may be slightly
27                         different from the values originally set, due to rounding errors.
28                 - similar to what RoboFog used to do.
29                 - RoboFog had a special attribute for "italicoffset", horizontal
30                 shift of all glyphs. This is missing in Robofab.
31         """
32         def __init__(self, glyphSet, width, italicAngle):
33                 BasePen.__init__(self, glyphSet)
34                 self.width = width
35                 self._angle = math.radians(90+italicAngle)
36                 self.maxSteps = 100
37                 self.margin = None
38                 self._left = None
39                 self._right = None
40                 self._start = None
41                 self.currentPt = None
42        
43         def _getAngled(self, pt):
44                 r = (g.width + (pt[1] / math.tan(self._angle)))-pt[0]
45                 l = pt[0]-((pt[1] / math.tan(self._angle)))
46                 if self._right is None:
47                         self._right = r
48                 else:
49                         self._right = min(self._right, r)
50                 if self._left is None:
51                         self._left = l
52                 else:
53                         self._left = min(self._left, l)
54                 #print pt, l, r
55                 self.margin = self._left, self._right
56                
57         def _moveTo(self, pt):
58                 self._start = self.currentPt = pt
59
60         def _addMoveTo(self):
61                 if self._start is None:
62                         return
63                 self._start = self.currentPt = None
64
65         def _lineTo(self, pt):
66                 self._addMoveTo()
67                 self._getAngled(pt)
68
69         def _curveToOne(self, pt1, pt2, pt3):
70                 step = 1.0/self.maxSteps
71                 factors = range(0, self.maxSteps+1)
72                 for i in factors:
73                         pt = _getCubicPoint(i*step, self.currentPt, pt1, pt2, pt3)
74                         self._getAngled(pt)
75                 self.currentPt = pt3
76                                        
77         def _qCurveToOne(self, bcp, pt):
78                 self._addMoveTo()
79                 # add curve tracing magic here.
80                 self._getAngled(pt)
81                 self.currentPt = pt3
82
83 def getAngledMargins(glyph, font):
84         """Get the angled margins for this glyph."""
85         pen = AngledMarginPen(font, glyph.width, font.info.italicAngle)
86         glyph.draw(pen)
87         return pen.margin
88        
89 def setAngledLeftMargin(glyph, font, value):
90         """Set the left angled margin to value, adjusted for font.info.italicAngle."""
91         pen = AngledMarginPen(font, glyph.width, font.info.italicAngle)
92         g.draw(pen)
93         isLeft, isRight = pen.margin
94         glyph.leftMargin += value-isLeft
95        
96 def setAngledRightMargin(glyph, font, value):
97         """Set the right angled margin to value, adjusted for font.info.italicAngle."""
98         pen = AngledMarginPen(font, glyph.width, font.info.italicAngle)
99         g.draw(pen)
100         isLeft, isRight = pen.margin
101         glyph.rightMargin += value-isRight
102
103 def centerAngledMargins(glyph, font):
104         """Center the glyph on angled margins."""
105         pen = AngledMarginPen(font, glyph.width, font.info.italicAngle)
106         g.draw(pen)
107         isLeft, isRight = pen.margin
108         setAngledLeftMargin(glyph, font, (isLeft+isRight)*.5)
109         setAngledRightMargin(glyph, font, (isLeft+isRight)*.5)
110        
111 def guessItalicOffset(glyph, font):
112         """Guess the italic offset based on the margins of a symetric glyph.
113                 For instance H or I.
114         """
115         l, r = getAngledMargins(glyph, font)
116         return l - (l+r)*.5
117
118
119 if __name__ == "__main__":
120        
121         # example for FontLab, with a glyph open.
122         from robofab.world import CurrentFont, CurrentGlyph
123         g = CurrentGlyph()
124         f = CurrentFont()
125
126         print "margins!", getAngledMargins(g, f)
127         # set the angled margin to a value
128         m = 50
129         setAngledLeftMargin(g, f, m)
130         setAngledRightMargin(g, f, m)
131         g.update()
132
Note: See TracBrowser for help on using the browser.