diff --git a/HT_LetterSpacer_script.py b/HT_LetterSpacer_script.py index bc4db8d4..9d343e58 100644 --- a/HT_LetterSpacer_script.py +++ b/HT_LetterSpacer_script.py @@ -128,9 +128,57 @@ def triangle(angle, y): #result = round(result) return result +def totalMarginList(layer,overshoot,angle): + y = NSMinY(layer.bounds)-overshoot + listL = [] + listR = [] + + #calculate default depth, otherwise measurement is None + #calculate paralelogram extremes + origin=NSMinX(layer.bounds) + endpointx=NSMaxX(layer.bounds) + endpointy=NSMaxY(layer.bounds) + + #calculate paralelogram top left + xpos=triangle(angle,endpointy)+origin + #paralelogram top side width + slantWidth=(endpointx-xpos) + #default depth + dfltDepth=slantWidth + + #result will be false if all the measured margins are emtpy (no outlines in reference zone) + result=False + + while y <= NSMaxY(layer.bounds)+overshoot: + lpos, rpos = getMargins(layer, y) + + #get the default margin measure at a given y position + slantPosL=origin+triangle(angle,y)+dfltDepth + slantPosR=origin+triangle(angle,y) + + if lpos is not None: + listL.append(NSMakePoint(lpos, y)) + result=True + else: + listL.append(NSMakePoint(slantPosL, y)) + + if rpos is not None: + listR.append(NSMakePoint(rpos, y)) + result=True + else: + listR.append(NSMakePoint(slantPosR, y)) + + y += paramFreq + + #if no measurements are taken, returns false and will abort in main function + if result: + return listL, listR + else: + return False,False + # a list of margins -def marginList(layer,angle): - y = NSMinY(layer.bounds) +def marginList(layer,referenceLayer,overshoot,angle): + y = NSMinY(referenceLayer.bounds)-overshoot listL = [] listR = [] @@ -147,24 +195,35 @@ def marginList(layer,angle): #default depth dfltDepth=slantWidth - while y <= NSMaxY(layer.bounds): + #result will be false if all the measured margins are emtpy (no outlines in reference zone) + result=False + + while y <= NSMaxY(referenceLayer.bounds)+overshoot: lpos, rpos = getMargins(layer, y) #get the default margin measure at a given y position slantPosL=origin+triangle(angle,y)+dfltDepth - slantPosR=origin+triangle(angle,y)+slantWidth-dfltDepth + slantPosR=origin+triangle(angle,y) if lpos is not None: listL.append(NSMakePoint(lpos, y)) + result=True else: listL.append(NSMakePoint(slantPosL, y)) + if rpos is not None: listR.append(NSMakePoint(rpos, y)) + result=True else: listR.append(NSMakePoint(slantPosR, y)) y += paramFreq - return listL, listR + + #if no measurements are taken, returns false and will abort in main function + if result: + return listL, listR + else: + return False,False # get appropriate config file path def getConfigPath(directory, glyphsfile, mastername): @@ -270,27 +329,21 @@ def overshoot(self): return self.xHeight * self.paramOver / 100 def maxPoints(self, points, minY, maxY): - #this function should get the leftmost and rightmost points in the given reference area (typically, between baseline and x-height in a lowercase), to close the contour - # When a glyph have outlines, but none of them is in that area, it fails. - #It should be done in a more efficient way - right = -10000 - righty = None - left = 10000 - lefty = None - for p in points: - if p.y >= minY and p.y <= maxY: - if p.x > right: - right = p.x - righty = p.y - if p.x < left: - left = p.x - lefty = p.y - assert righty is not None, ( - "Please file a bug report with a screenshot of the glyph this script fails on." - ) - assert lefty is not None, ( - "Please file a bug report with a screenshot of the glyph this script fails on." - ) + #this function returns the extremes for a given set of points in a given zone + + #filter those outside the range + # pointsFilteredL = [ x for x in points[0] if x.y>=minY and x.y<=maxY] + # pointsFilteredR = [ x for x in points[0] if x.y>=minY and x.y<=maxY] + + #sort all given points by x + sortPointsByXL = sorted(points[0], key=lambda tup: tup[0]) + sortPointsByXR = sorted(points[1], key=lambda tup: tup[0]) + + + #get the extremes position, first and last in the list + left, lefty = sortPointsByXL[0] + right, righty = sortPointsByXR[-1] + return NSMakePoint(left, lefty), NSMakePoint(right, righty) def processMargins(self, lMargin, rMargin, lExtreme, rExtreme): @@ -386,23 +439,42 @@ def setSpace(self, layer, referenceLayer): self.minYref = NSMinY(referenceLayer.bounds) - overshoot self.maxYref = NSMaxY(referenceLayer.bounds) + overshoot - # bounds - print(self.angle) - lFullMargin, rFullMargin = marginList(layer,self.angle) + self.minY = NSMinY(layer.bounds) + self.maxY = NSMaxY(layer.bounds) + + #get the margins for the full outline + lTotalMargins, rTotalMargins = totalMarginList(layer,overshoot,self.angle) + # get all margins in the zone + lZoneMargins, rZoneMargins = marginList(layer,referenceLayer,overshoot,self.angle) + + + #check there is some overlap with reference zone + if not lZoneMargins and not rZoneMargins: + self.output += 'The glyph outlines are outside the reference layer zone/height. No match with '+referenceLayer.parent.name + return + + #if the font has an angle, we need to deslant if self.angle: - lFullMargin = self.deslant(lFullMargin) - rFullMargin = self.deslant(rFullMargin) + print("Using angle: " + str(self.angle)) + lZoneMargins = self.deslant(lZoneMargins) + rZoneMargins = self.deslant(rZoneMargins) + # get extreme points deitalized - lFullExtreme, rFullExtreme = self.maxPoints(lFullMargin + rFullMargin, NSMinY(layer.bounds), NSMaxY(layer.bounds)) + lTotalMargins = self.deslant(lTotalMargins) + rTotalMargins = self.deslant(rTotalMargins) + - lMargins = [p for p in lFullMargin if self.minYref <= p.y <= self.maxYref] - rMargins = [p for p in rFullMargin if self.minYref <= p.y <= self.maxYref] + #full shape extreme points + lFullExtreme, rFullExtreme = self.maxPoints([lTotalMargins,rTotalMargins], self.minY, self.maxY) # get zone extreme points - lExtreme, rExtreme = self.maxPoints(lMargins + rMargins, self.minYref, self.maxYref) + lExtreme, rExtreme = self.maxPoints([lZoneMargins,rZoneMargins], self.minYref, self.maxYref) + # create a closed polygon - lPolygon, rPolygon = self.processMargins(lMargins, rMargins, lExtreme, rExtreme) + lPolygon, rPolygon = self.processMargins(lZoneMargins, rZoneMargins, lExtreme, rExtreme) + # return + # dif between extremes full and zone distanceL = math.ceil(lExtreme.x - lFullExtreme.x) distanceR = math.ceil(rFullExtreme.x - rExtreme.x) @@ -462,10 +534,16 @@ def spaceMain(self, layer, referenceLayer): # Decompose layer for analysis, as the deeper plumbing assumes to be looking at outlines. layer_decomposed = layer.copyDecomposedLayer() layer_decomposed.parent = layer.parent - lp, rp = self.setSpace(layer_decomposed, referenceLayer) - del layer_decomposed - # store values in a list - setSidebearings(layer, self.newL, self.newR, self.newWidth, color) + + #run the spacing + space = self.setSpace(layer_decomposed, referenceLayer) + + #if it worked + if space: + lp, rp = space + del layer_decomposed + # store values in a list + setSidebearings(layer, self.newL, self.newR, self.newWidth, color) print(self.output) self.output = ''