MarginPen now has a isHorizontal flag when initialising. Default set to True, the calculations will be horizontal. When False, the measurements will be vertical.

Scripts using MarginPen should continue to work without changes.

git-svn-id: http://svn.robofab.com/trunk@94 b5fa9d6c-a76f-4ffd-b3cb-f825fc41095c
This commit is contained in:
Erik van Blokland 2008-09-20 09:32:33 +00:00
parent 339ce1c71c
commit 65b2d92a9f

View File

@ -7,22 +7,30 @@ from sets import Set
class MarginPen(BasePen): class MarginPen(BasePen):
""" """
Pen to calculate the horizontal margins at a given height. Pen to calculate the margins at a given value.
When isHorizontal is True, the margins at <value> are horizontal.
When isHorizontal is False, the margins at <value> are vertical.
When a glyphset or font is given, MarginPen will also calculate for glyphs with components. When a glyphset or font is given, MarginPen will also calculate for glyphs with components.
pen.getMargins() returns the minimum and maximum intersections of the glyph. pen.getMargins() returns the minimum and maximum intersections of the glyph.
pen.getContourMargins() returns the minimum and maximum intersections for each contour. pen.getContourMargins() returns the minimum and maximum intersections for each contour.
Possible optimisation:
Initialise the pen object with a list of points we want to measure,
then draw the glyph once, but do the splitLine() math for all measure points.
""" """
def __init__(self, glyphSet, height): def __init__(self, glyphSet, value, isHorizontal=True):
BasePen.__init__(self, glyphSet) BasePen.__init__(self, glyphSet)
self.height = height self.value = value
self.hits = {} self.hits = {}
self.filterDoubles = True self.filterDoubles = True
self.contourIndex = None self.contourIndex = None
self.startPt = None self.startPt = None
self.isHorizontal = isHorizontal
def _moveTo(self, pt): def _moveTo(self, pt):
self.currentPt = pt self.currentPt = pt
@ -36,7 +44,7 @@ class MarginPen(BasePen):
if self.filterDoubles: if self.filterDoubles:
if pt == self.currentPt: if pt == self.currentPt:
return return
hits = splitLine(self.currentPt, pt, self.height, True) hits = splitLine(self.currentPt, pt, self.value, self.isHorizontal)
if len(hits)>1: if len(hits)>1:
# result will be 2 tuples of 2 coordinates # result will be 2 tuples of 2 coordinates
# first two points: start to intersect # first two points: start to intersect
@ -45,27 +53,43 @@ class MarginPen(BasePen):
# then, the first coordinate of that point is the x. # then, the first coordinate of that point is the x.
if not self.contourIndex in self.hits: if not self.contourIndex in self.hits:
self.hits[self.contourIndex] = [] self.hits[self.contourIndex] = []
self.hits[self.contourIndex].append(round(hits[0][-1][0], 4)) if self.isHorizontal:
if pt[1] == self.height: self.hits[self.contourIndex].append(round(hits[0][-1][0], 4))
else:
self.hits[self.contourIndex].append(round(hits[0][-1][1], 4))
if self.isHorizontal and pt[1] == self.value:
# it could happen # it could happen
if not self.contourIndex in self.hits: if not self.contourIndex in self.hits:
self.hits[self.contourIndex] = [] self.hits[self.contourIndex] = []
self.hits[self.contourIndex].append(pt[0]) self.hits[self.contourIndex].append(pt[0])
elif (not self.isHorizontal) and (pt[0] == self.value):
# it could happen
if not self.contourIndex in self.hits:
self.hits[self.contourIndex] = []
self.hits[self.contourIndex].append(pt[1])
self.currentPt = pt self.currentPt = pt
def _curveToOne(self, pt1, pt2, pt3): def _curveToOne(self, pt1, pt2, pt3):
hits = splitCubic(self.currentPt, pt1, pt2, pt3, self.height, True) hits = splitCubic(self.currentPt, pt1, pt2, pt3, self.value, self.isHorizontal)
for i in range(len(hits)-1): for i in range(len(hits)-1):
# a number of intersections is possible. Just take the # a number of intersections is possible. Just take the
# last point of each segment. # last point of each segment.
if not self.contourIndex in self.hits: if not self.contourIndex in self.hits:
self.hits[self.contourIndex] = [] self.hits[self.contourIndex] = []
self.hits[self.contourIndex].append(round(hits[i][-1][0], 4)) if self.isHorizontal:
if pt3[1] == self.height: self.hits[self.contourIndex].append(round(hits[i][-1][0], 4))
else:
self.hits[self.contourIndex].append(round(hits[i][-1][1], 4))
if self.isHorizontal and pt3[1] == self.value:
# it could happen # it could happen
if not self.contourIndex in self.hits: if not self.contourIndex in self.hits:
self.hits[self.contourIndex] = [] self.hits[self.contourIndex] = []
self.hits[self.contourIndex].append(pt3[0]) self.hits[self.contourIndex].append(pt3[0])
if (not self.isHorizontal) and (pt3[0] == self.value):
# it could happen
if not self.contourIndex in self.hits:
self.hits[self.contourIndex] = []
self.hits[self.contourIndex].append(pt3[1])
self.currentPt = pt3 self.currentPt = pt3
def _closePath(self): def _closePath(self):
@ -77,14 +101,12 @@ class MarginPen(BasePen):
self.currentPt = None self.currentPt = None
def addComponent(self, baseGlyph, transformation): def addComponent(self, baseGlyph, transformation):
from fontTools.pens.transformPen import TransformPen
if self.glyphSet is None: if self.glyphSet is None:
return return
if baseGlyph in self.glyphSet: if baseGlyph in self.glyphSet:
glyph = self.glyphSet[baseGlyph] glyph = self.glyphSet[baseGlyph]
if glyph is not None: if glyph is not None:
tPen = TransformPen(self, transformation) glyph.draw(self)
glyph.draw(tPen)
def getMargins(self): def getMargins(self):
"""Get the horizontal margins for all contours combined, i.e. the whole glyph.""" """Get the horizontal margins for all contours combined, i.e. the whole glyph."""
@ -122,10 +144,9 @@ if __name__ == "__main__":
g = CurrentGlyph() g = CurrentGlyph()
pt = (74, 216) pt = (74, 216)
if f is not None and g is not None:
pen = MarginPen(f, pt[1]) pen = MarginPen(f, pt[1], isHorizontal=False)
g.draw(pen) g.draw(pen)
print 'glyph margins', pen.getMargins() print 'glyph Y margins', pen.getMargins()
print pen.getContourMargins() print pen.getContourMargins()
else:
print "no font or glyph"