├── Font ├── Copy anchors from italic.py ├── Copy layer from italic.py └── Replace glyphs with ss01.py ├── Italic ├── Move selection down 100u at italic angle.py ├── Move selection down 10u at italic angle.py ├── Move selection up 100u at italic angle.py └── Move selection up 10u at italic angle.py ├── Metrics └── Copy sidebearings to all layers in master.py ├── Nodes ├── Convert to Lines.py ├── Convert to Offcurves.py └── Split Selected Nodes.py ├── Paths └── Add Handles to path segment.py ├── README.md ├── Subdivision ├── Add Midpoint.py ├── Catmull-Clark.py └── Subdivide to curves.py └── Window └── Update preview.py /Font/Copy anchors from italic.py: -------------------------------------------------------------------------------- 1 | #MenuTitle: Copy Anchors from Italic 2 | # -*- coding: utf-8 -*- 3 | __doc__ = """ 4 | Quickly copies anchors from either the italic or the upright counterpart. 5 | Mostly from @mekkablue 6 | """ 7 | 8 | # most of the code taken from 9 | # https://github.com/mekkablue/ShowItalic/blob/master/ShowItalic.glyphsReporter/Contents/Resources/ShowItalic.py 10 | # and 11 | # https://github.com/mekkablue/Glyphs-Scripts/blob/master/Masters/Copy%20Layer%20to%20Layer.py 12 | 13 | def masterHasItalicAngle(thisMaster): 14 | try: 15 | if thisMaster.italicAngle == 0.0: 16 | return False 17 | else: 18 | return True 19 | except Exception as e: 20 | print( "masterHasItalicAngle: %s" % str(e) ) 21 | 22 | def italicFontForFont(thisFont): 23 | try: 24 | if thisFont: 25 | familyName = thisFont.familyName 26 | listOfPossibleFamilyMembers = [ f for f in Glyphs.fonts if f.familyName == familyName and f != thisFont ] 27 | if len(listOfPossibleFamilyMembers) == 1: 28 | return listOfPossibleFamilyMembers[0] 29 | else: 30 | thisFontIsItalic = masterHasItalicAngle(thisFont.masters[0]) 31 | listOfItalicFamilyMembers = [f for f in listOfPossibleFamilyMembers if masterHasItalicAngle(f.masters[0]) is not thisFontIsItalic] 32 | if len(listOfItalicFamilyMembers) == 1: 33 | return listOfItalicFamilyMembers[0] 34 | return None 35 | except Exception as e: 36 | print( "italicFontForFont: %s" % str(e) ) 37 | 38 | def copyAnchorsFromLayerToLayer( sourceLayer, targetLayer ): 39 | """Copies all anchors from sourceLayer to targetLayer.""" 40 | numberOfAnchorsInSource = len( sourceLayer.anchors ) 41 | numberOfAnchorsInTarget = len( targetLayer.anchors ) 42 | 43 | if numberOfAnchorsInTarget != 0: 44 | print "- Deleting %i anchors in target layer" % numberOfAnchorsInTarget 45 | targetLayer.setAnchors_(None) 46 | 47 | if numberOfAnchorsInSource > 0: 48 | print "- Copying anchors from source layer:" 49 | for thisAnchor in sourceLayer.anchors: 50 | newAnchor = thisAnchor.copy() 51 | targetLayer.anchors.append( newAnchor ) 52 | print " %s (%i, %i)" % ( thisAnchor.name, thisAnchor.position.x, thisAnchor.position.y ) 53 | 54 | italicFont = italicFontForFont(Layer.parent.parent) 55 | for glyph in [ x.parent for x in Font.selectedLayers ]: 56 | glyphName = glyph.name 57 | 58 | uprightMasterID = Layer.associatedMasterId 59 | uprightMasterName = italicFont.masters[uprightMasterID].name.replace("Italic","").strip() 60 | 61 | italicGlyph = italicFont.glyphs[glyphName] 62 | italicMasters = [m for m in italicFont.masters if m.name.startswith(uprightMasterName)] 63 | 64 | targetlayer = glyph.layers[uprightMasterID] 65 | sourcelayer = italicGlyph.layers[uprightMasterID] 66 | 67 | copyAnchorsFromLayerToLayer( sourcelayer, targetlayer ) 68 | -------------------------------------------------------------------------------- /Font/Copy layer from italic.py: -------------------------------------------------------------------------------- 1 | #MenuTitle: Copy Layer from Italic 2 | # -*- coding: utf-8 -*- 3 | __doc__ = """ 4 | Quickly copies layer from either the italic or the upright counterpart. 5 | Mostly from @mekkablue 6 | """ 7 | 8 | # most of the code taken from 9 | # https://github.com/mekkablue/ShowItalic/blob/master/ShowItalic.glyphsReporter/Contents/Resources/ShowItalic.py 10 | # and 11 | # https://github.com/mekkablue/Glyphs-Scripts/blob/master/Masters/Copy%20Layer%20to%20Layer.py 12 | 13 | def masterHasItalicAngle(thisMaster): 14 | try: 15 | if thisMaster.italicAngle == 0.0: 16 | return False 17 | else: 18 | return True 19 | except Exception as e: 20 | print( "masterHasItalicAngle: %s" % str(e) ) 21 | 22 | def italicFontForFont(thisFont): 23 | try: 24 | if thisFont: 25 | familyName = thisFont.familyName 26 | listOfPossibleFamilyMembers = [ f for f in Glyphs.fonts if f.familyName == familyName and f != thisFont ] 27 | if len(listOfPossibleFamilyMembers) == 1: 28 | return listOfPossibleFamilyMembers[0] 29 | else: 30 | thisFontIsItalic = masterHasItalicAngle(thisFont.masters[0]) 31 | listOfItalicFamilyMembers = [f for f in listOfPossibleFamilyMembers if masterHasItalicAngle(f.masters[0]) is not thisFontIsItalic] 32 | if len(listOfItalicFamilyMembers) == 1: 33 | return listOfItalicFamilyMembers[0] 34 | return None 35 | except Exception as e: 36 | print( "italicFontForFont: %s" % str(e) ) 37 | 38 | def copyPathsFromLayerToLayer( sourceLayer, targetLayer ): 39 | """Copies all paths from sourceLayer to targetLayer""" 40 | numberOfPathsInSource = len( sourceLayer.paths ) 41 | numberOfPathsInTarget = len( targetLayer.paths ) 42 | 43 | if numberOfPathsInTarget != 0: 44 | print "- Deleting %i paths in target layer" % numberOfPathsInTarget 45 | targetLayer.paths = [] 46 | 47 | if numberOfPathsInSource > 0: 48 | print "- Copying paths" 49 | for thisPath in sourceLayer.paths: 50 | newPath = thisPath.copy() 51 | targetLayer.paths.append( newPath ) 52 | 53 | def copyComponentsFromLayerToLayer( sourceLayer, targetLayer ): 54 | """Copies all components from sourceLayer to targetLayer.""" 55 | numberOfComponentsInSource = len( sourceLayer.components ) 56 | numberOfComponentsInTarget = len( targetLayer.components ) 57 | 58 | if numberOfComponentsInTarget != 0: 59 | print "- Deleting %i components in target layer" % numberOfComponentsInTarget 60 | targetLayer.components = [] 61 | 62 | if numberOfComponentsInSource > 0: 63 | print "- Copying components:" 64 | for thisComp in sourceLayer.components: 65 | newComp = thisComp.copy() 66 | print " Component: %s" % ( thisComp.componentName ) 67 | targetLayer.components.append( newComp ) 68 | 69 | def copyAnchorsFromLayerToLayer( sourceLayer, targetLayer ): 70 | """Copies all anchors from sourceLayer to targetLayer.""" 71 | numberOfAnchorsInSource = len( sourceLayer.anchors ) 72 | numberOfAnchorsInTarget = len( targetLayer.anchors ) 73 | 74 | if numberOfAnchorsInTarget != 0: 75 | print "- Deleting %i anchors in target layer" % numberOfAnchorsInTarget 76 | targetLayer.setAnchors_(None) 77 | 78 | if numberOfAnchorsInSource > 0: 79 | print "- Copying anchors from source layer:" 80 | for thisAnchor in sourceLayer.anchors: 81 | newAnchor = thisAnchor.copy() 82 | targetLayer.anchors.append( newAnchor ) 83 | print " %s (%i, %i)" % ( thisAnchor.name, thisAnchor.position.x, thisAnchor.position.y ) 84 | 85 | def copyMetricsFromLayerToLayer( sourceLayer, targetLayer ): 86 | """Copies width of sourceLayer to targetLayer.""" 87 | sourceWidth = sourceLayer.width 88 | if targetLayer.width != sourceWidth: 89 | targetLayer.width = sourceWidth 90 | print "- Copying width (%.1f)" % sourceWidth 91 | else: 92 | print "- Width not changed (already was %.1f)" % sourceWidth 93 | 94 | italicFont = italicFontForFont(Layer.parent.parent) 95 | for glyph in [ x.parent for x in Font.selectedLayers ]: 96 | glyphName = glyph.name 97 | 98 | uprightMasterID = Layer.associatedMasterId 99 | uprightMasterName = italicFont.masters[uprightMasterID].name.replace("Italic","").strip() 100 | 101 | italicGlyph = italicFont.glyphs[glyphName] 102 | italicMasters = [m for m in italicFont.masters if m.name.startswith(uprightMasterName)] 103 | 104 | targetlayer = glyph.layers[uprightMasterID] 105 | sourcelayer = italicGlyph.layers[uprightMasterID] 106 | 107 | copyPathsFromLayerToLayer( sourcelayer, targetlayer ) 108 | copyComponentsFromLayerToLayer( sourcelayer, targetlayer ) 109 | copyAnchorsFromLayerToLayer( sourcelayer, targetlayer ) 110 | copyMetricsFromLayerToLayer( sourcelayer, targetlayer ) 111 | -------------------------------------------------------------------------------- /Font/Replace glyphs with ss01.py: -------------------------------------------------------------------------------- 1 | #MenuTitle: Replace primary glyphs with ss01 2 | # -*- coding: utf-8 -*- 3 | __doc__ = """ 4 | Replaces primary glyph with ss01 variant (if it exists) 5 | """ 6 | 7 | glyphsToRename = [] 8 | stringToMatch = ".ss01" 9 | 10 | for glyph in Font.glyphs: 11 | if stringToMatch in glyph.name: 12 | glyphsToRename.append(glyph) 13 | 14 | for glyph in glyphsToRename: 15 | mainGlyphName = glyph.name.replace(stringToMatch, "") 16 | mainGlyph = Font.glyphForName_(mainGlyphName) 17 | 18 | # remove main glyph 19 | Font.removeGlyph_(mainGlyph) 20 | 21 | # rename ss01 22 | glyph.setName_changeName_(mainGlyphName, True) 23 | -------------------------------------------------------------------------------- /Italic/Move selection down 100u at italic angle.py: -------------------------------------------------------------------------------- 1 | #MenuTitle: Move Selection Down 100 Units at Italic Angle 2 | # -*- coding: utf-8 -*- 3 | __doc__ = """ 4 | Moves selection in the direction of the italic angle 5 | """ 6 | 7 | import math 8 | import Cocoa 9 | 10 | globalHeight = -100 11 | 12 | 13 | def getWidth(italicAngle, height): 14 | # subtract from 90 since 90º is upright 15 | angle = math.radians(90 - master.italicAngle) 16 | width = height / math.tan(angle) 17 | return width 18 | 19 | for master in Font.masters: 20 | if master.name == Layer.name: 21 | globalWidth = getWidth(master.italicAngle, globalHeight) 22 | 23 | for node in Layer.selection: 24 | newPoint = Cocoa.NSMakePoint(node.position.x + globalWidth, node.position.y + globalHeight) 25 | node.setPosition_(newPoint) 26 | -------------------------------------------------------------------------------- /Italic/Move selection down 10u at italic angle.py: -------------------------------------------------------------------------------- 1 | #MenuTitle: Move Selection Down 10 Units at Italic Angle 2 | # -*- coding: utf-8 -*- 3 | __doc__ = """ 4 | Moves selection in the direction of the italic angle 5 | """ 6 | 7 | import math 8 | import Cocoa 9 | 10 | globalHeight = -10 11 | 12 | 13 | def getWidth(italicAngle, height): 14 | # subtract from 90 since 90º is upright 15 | angle = math.radians(90 - master.italicAngle) 16 | width = height / math.tan(angle) 17 | return width 18 | 19 | for master in Font.masters: 20 | if master.name == Layer.name: 21 | globalWidth = getWidth(master.italicAngle, globalHeight) 22 | 23 | for node in Layer.selection: 24 | newPoint = Cocoa.NSMakePoint(node.position.x + globalWidth, node.position.y + globalHeight) 25 | node.setPosition_(newPoint) 26 | -------------------------------------------------------------------------------- /Italic/Move selection up 100u at italic angle.py: -------------------------------------------------------------------------------- 1 | #MenuTitle: Move Selection Up 100 Units at Italic Angle 2 | # -*- coding: utf-8 -*- 3 | __doc__ = """ 4 | Moves selection in the direction of the italic angle 5 | """ 6 | 7 | import math 8 | import Cocoa 9 | 10 | globalHeight = 100 11 | 12 | 13 | def getWidth(italicAngle, height): 14 | # subtract from 90 since 90º is upright 15 | angle = math.radians(90 - master.italicAngle) 16 | width = height / math.tan(angle) 17 | return width 18 | 19 | for master in Font.masters: 20 | if master.name == Layer.name: 21 | globalWidth = getWidth(master.italicAngle, globalHeight) 22 | 23 | for node in Layer.selection: 24 | newPoint = Cocoa.NSMakePoint(node.position.x + globalWidth, node.position.y + globalHeight) 25 | node.setPosition_(newPoint) 26 | -------------------------------------------------------------------------------- /Italic/Move selection up 10u at italic angle.py: -------------------------------------------------------------------------------- 1 | #MenuTitle: Move Selection Up 10 Units at Italic Angle 2 | # -*- coding: utf-8 -*- 3 | __doc__ = """ 4 | Moves selection in the direction of the italic angle 5 | """ 6 | 7 | import math 8 | import Cocoa 9 | 10 | globalHeight = 10 11 | 12 | 13 | def getWidth(italicAngle, height): 14 | # subtract from 90 since 90º is upright 15 | angle = math.radians(90 - master.italicAngle) 16 | width = height / math.tan(angle) 17 | return width 18 | 19 | for master in Font.masters: 20 | if master.name == Layer.name: 21 | globalWidth = getWidth(master.italicAngle, globalHeight) 22 | 23 | for node in Layer.selection: 24 | newPoint = Cocoa.NSMakePoint(node.position.x + globalWidth, node.position.y + globalHeight) 25 | node.setPosition_(newPoint) 26 | -------------------------------------------------------------------------------- /Metrics/Copy sidebearings to all layers in master.py: -------------------------------------------------------------------------------- 1 | #MenuTitle: Copy sidebearings to all layers in master 2 | # -*- coding: utf-8 -*- 3 | __doc__ = """ 4 | Copies the sidebearings of the current layer to all other layers that share the same master (helpful for smart components) 5 | """ 6 | 7 | from GlyphsApp import Glyphs 8 | 9 | font = Glyphs.font 10 | currentLayer = font.selectedLayers[0] 11 | 12 | # Get the metrics of the current layer 13 | currentMetrics = (currentLayer.LSB, currentLayer.RSB) 14 | 15 | # Iterate over all glyphs in the font 16 | for glyph in font.glyphs: 17 | # Iterate over all layers of the glyph 18 | for layer in glyph.layers: 19 | # If the layer shares the same master as the current layer 20 | if layer.associatedMasterId == currentLayer.associatedMasterId: 21 | # Copy the metrics to the layer 22 | layer.LSB, layer.RSB = currentMetrics -------------------------------------------------------------------------------- /Nodes/Convert to Lines.py: -------------------------------------------------------------------------------- 1 | #MenuTitle: Convert Selected Nodes to Lines 2 | # -*- coding: utf-8 -*- 3 | __doc__ = """ 4 | If you're selecting off-curves, select ALL off-curve nodes in a path segment. 5 | """ 6 | 7 | for node in Layer.selection: 8 | node.type = "line" 9 | node.nextNode.type = "line" 10 | -------------------------------------------------------------------------------- /Nodes/Convert to Offcurves.py: -------------------------------------------------------------------------------- 1 | #MenuTitle: Convert Selected Nodes to Offcurves 2 | # -*- coding: utf-8 -*- 3 | __doc__ = """ 4 | This is a rather dangerous operation. 5 | Usually used on all nodes of a path to make a closed quad curve. 6 | """ 7 | 8 | for node in Layer.selection: 9 | node.type = "offcurve" 10 | if len(Layer.selection) == 1: 11 | node.nextNode.type = "qcurve" 12 | elif node.nextNode.type != "offcurve": 13 | node.nextNode.type = "curve" 14 | -------------------------------------------------------------------------------- /Nodes/Split Selected Nodes.py: -------------------------------------------------------------------------------- 1 | #MenuTitle: Split Selected Nodes (Make Inktraps) 2 | # -*- coding: utf-8 -*- 3 | __doc__ = """ 4 | Splits nodes into two and separates them by 2 units at 90°-snapped angle. 5 | Great for making inktraps fast. 6 | """ 7 | 8 | import Cocoa 9 | import math 10 | import copy 11 | 12 | def translateNode(node, distance): 13 | path = node.parent 14 | angleFloat = path.tangentAngleAtNode_direction_(node, path.direction) + (90 * path.direction) 15 | angleSnapped = round(angleFloat / 90) * 90 16 | # always make corners LESS acute and separate away from vertex 17 | direction = -1 if angleFloat < angleSnapped else 1 18 | # convert to radians for translation 19 | angleSnappedRadians = angleSnapped * (math.pi/180) 20 | 21 | x = node.x + distance * direction * math.cos(angleSnappedRadians) 22 | y = node.y + distance * direction * math.sin(angleSnappedRadians) 23 | newPoint = Cocoa.NSMakePoint(x, y) 24 | return newPoint 25 | 26 | for node in Layer.selection: 27 | path = node.parent 28 | cloneNode = node.copy() 29 | 30 | # make sure nodes don't go in the same direction 31 | originPosition = translateNode(node, 1) 32 | clonePosition = translateNode(node, -1) 33 | 34 | path.insertNode_atIndex_(cloneNode, node.index) 35 | 36 | # make joining path segment a line 37 | if node.type == "curve": 38 | node.type = "line" 39 | 40 | # separate nodes from origin 41 | node.setPosition_(originPosition) 42 | cloneNode.setPosition_(clonePosition) 43 | -------------------------------------------------------------------------------- /Paths/Add Handles to path segment.py: -------------------------------------------------------------------------------- 1 | #MenuTitle: Add handles to selected segments 2 | # -*- coding: utf-8 -*- 3 | __doc__ = """ 4 | Adds offcurve points to selected straight line path segments. 5 | """ 6 | 7 | for node in Layer.selection: 8 | path = node.parent 9 | if node.nextNode.selected and node.type != 'offcurve' and node.nextNode.type != 'offcurve': 10 | if not (not path.closed and node.index == len(path.nodes) - 1): 11 | offcurve1 = path.insertNodeWithPathTime_(node.index + 1.6667) 12 | offcurve2 = path.insertNodeWithPathTime_(node.index + 1.5) 13 | offcurve1.type = 'offcurve' 14 | offcurve2.type = 'offcurve' 15 | node.nextNode.nextNode.nextNode.type = 'curve' 16 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | This document is separated by group. Within each folder you'll find scripts for different occasions. 2 | 3 | ## Font 4 | 5 | ##### Replace glyphs with ss01 6 | You may find this helpful if your roman font has upright italics in ss01 (for say, `a`, `g`, and `y`). Save a new font and run this to replace your default letters with their ss01 set counterparts. 7 | 8 | ##### Copy layer from italic 9 | Mostly taken from mekkablue's [Copy Layer to Layer script](https://github.com/mekkablue/Glyphs-Scripts/blob/master/Masters/Copy Layer to Layer.py), this copies the entire layer of a glyph from an italic counterpart. Useful for quickly syncing changes between roman and oblique. 10 | 11 | ##### Copy anchors from italic 12 | Same as Copy layer from italic but only copies anchors 13 | 14 | ## Italic 15 | 16 | ##### Move Selection Down 10 Units at Italic Angle 17 | ##### Move Selection Down 100 Units at Italic Angle 18 | ##### Move Selection Up 10 Units at Italic Angle 19 | ##### Move Selection Up 100 Units at Italic Angle 20 | Translates nodes up or down either 10 or 100 units, then shifts left or right to move at the same angle as the master's italic angle. 21 | 22 | ## Nodes 23 | 24 | ##### Convert Selected Nodes to Lines 25 | Converts selected nodes to `line`-type nodes. Make sure you know how path segments (especially curves) are calculated in Glyphs, as this can create some odd results. 26 | 27 | ##### Convert Selected Nodes to Offcurves 28 | Converts selected nodes to `offcurve` (handles). If you select two nodes, they'll be converted and the following node will become a curve. 29 | 30 | If you execute this on an entire path, you'll get some quadratic curve cages (**experimental**). 31 | 32 | ##### Split Selected Nodes (Make Inktraps) 33 | Duplicates selected node(s) and separates them away from origin at a 0° or 90° angle. Great for quickly setting up ink traps. 34 | 35 | ## Paths 36 | 37 | ##### Add handles to selected segments 38 | For all selected line segments, adds bezier handles at 1/3 and 2/3 of the segment length. Equivocal to alt-clicking on a line segment, but useful if adding handles to many different segments. 39 | 40 | ## Subdivision 41 | 42 | ##### Subdivide Lines to Curves (Catmull-Clark) 43 | Similar to b-spline cages (like very similar), you can draw out line nodes and run this script to convert them to smooth cubic bézier curves. The result after one execution should be identical in shape to the Subdivide Lines (Catmull-Clark) script after three executions, but this will use far fewer nodes. 44 | 45 | ![](https://pbs.twimg.com/media/CvM1vXrWgAETVor.jpg) 46 | 47 | You can also use [Subdivide Filter](https://github.com/danielgamage/Subdivide) to get this functionality in a nondestructive way. 48 | 49 | ##### Subdivide Lines (Catmull-Clark) 50 | Subdivides path using Catmull-Clark algorithm. With more subdivision, paths will smooth out, but node count will get unwieldy. 51 | 52 | ##### Subdivide Selection (Add Midpoint) 53 | Adds midpoints to all selected path segments. For line segments, this is akin to faceted subdivision. 54 | 55 | ## Selection 56 | 57 | This repository previously contained scripts to Continue Selection, Grow Selection, Shrink Selection, and Undo Selection. These functions have been moved to their own plugin and extended at [SelectionPalette](https://github.com/danielgamage/SelectionPalette/). 58 | -------------------------------------------------------------------------------- /Subdivision/Add Midpoint.py: -------------------------------------------------------------------------------- 1 | #MenuTitle: Subdivide Selection (Add Midpoint) 2 | # -*- coding: utf-8 -*- 3 | __doc__ = """ 4 | Adds a midpoint between selected nodes. 5 | """ 6 | 7 | for node in Layer.selection: 8 | if (node.nextNode.selected): 9 | path = node.parent 10 | nodeIndex = path.indexOfNode_(node) 11 | path.insertNodeWithPathTime_(nodeIndex + 1.5) 12 | -------------------------------------------------------------------------------- /Subdivision/Catmull-Clark.py: -------------------------------------------------------------------------------- 1 | #MenuTitle: Subdivide Lines (Catmull-Clark) 2 | # -*- coding: utf-8 -*- 3 | __doc__ = """ 4 | Subdivides entire paths using Catmull-Clark smoothing subdivision. 5 | """ 6 | 7 | import Cocoa 8 | 9 | for path in Layer.paths: 10 | # store static node count 11 | nodeCount = len(path.nodes) 12 | 13 | corners = list(path.nodes) 14 | vertexPoints = [] 15 | 16 | for i in range(0, nodeCount): 17 | # midpoints between edgePoints and their vertex neighbors 18 | midpointOne = path.pointAtPathTime_(i - 0.25) if i != 0 else path.pointAtPathTime_(nodeCount - 0.25) 19 | midpointTwo = path.pointAtPathTime_(i + 0.25) 20 | x = (midpointOne.x + midpointTwo.x) / 2 21 | y = (midpointOne.y + midpointTwo.y) / 2 22 | vertexPoints.append(Cocoa.NSMakePoint(x, y)) 23 | 24 | # add edge points 25 | for x in range(0, nodeCount): 26 | path.insertNodeWithPathTime_(nodeCount - x + 0.5) 27 | 28 | # translate corners 29 | for n in range(0, nodeCount): 30 | index = (n * 2 - 2) if n > 0 else len(path) - 2 31 | path.nodes[index].position = vertexPoints[n] 32 | -------------------------------------------------------------------------------- /Subdivision/Subdivide to curves.py: -------------------------------------------------------------------------------- 1 | #MenuTitle: Subdivide Lines to Curves (Catmull-Clark) 2 | # -*- coding: utf-8 -*- 3 | __doc__ = """ 4 | Draw lines as a cubic b-spline cage and convert them to cubic bézier curves. 5 | """ 6 | 7 | import Cocoa 8 | 9 | ONE_THIRD = 0.333333 10 | 11 | for path in Layer.paths: 12 | # store static node count 13 | nodeCount = len(path.nodes) 14 | 15 | for i in xrange(nodeCount, 0, -1): 16 | # insert nodes backwards 17 | p1 = path.insertNodeWithPathTime_(i + ONE_THIRD) if i == nodeCount else path.insertNodeWithPathTime_(i + 0.5) 18 | p2 = path.insertNodeWithPathTime_(i - ONE_THIRD) if i > 1 else path.insertNodeWithPathTime_(i - 0.5) 19 | 20 | # find midpoints 21 | midpointX = (p1.x + p2.x) / 2 22 | midpointY = (p1.y + p2.y) / 2 23 | midpoint = Cocoa.NSMakePoint(midpointX, midpointY) 24 | 25 | node = path.nodes[i] 26 | node.setPosition_(midpoint) 27 | 28 | for i in xrange(0, nodeCount): 29 | oncurveNode = path.nodes[i * 3].nextNode 30 | oncurveNode.type = "curve" 31 | oncurveNode.connection = "smooth" 32 | oncurveNode.prevNode.type = "offcurve" 33 | oncurveNode.nextNode.type = "offcurve" 34 | -------------------------------------------------------------------------------- /Window/Update preview.py: -------------------------------------------------------------------------------- 1 | #MenuTitle: Refresh Preview 2 | # -*- coding: utf-8 -*- 3 | __doc__ = """ 4 | Manually updates the preview window. 5 | Useful for actions that don't automatically update the preview 6 | like changing the interpolation settings of an instance. 7 | """ 8 | 9 | Glyphs.currentDocument.windowController().activeEditViewController().updatePreview() 10 | --------------------------------------------------------------------------------