I’ve been trying to implement a function that does a flip transformation of a component inside of a glyph. The only idea I could come up with is trying to access the component’s bounds.size.height
and bounds.size.width
and inverting their values. But as bounds
and its properties are read only, the transformation doesn’t apply even though my code doesn’t generate any errors.
The function takes the glyph name, the index of the component in layers[0].components
and a transformation keyword as parameters:
def flipComponent(glyphName, componentIndex, transformation):
componentWidth = font.glyphs[glyphName].layers[0].components[componentIndex].bounds.size.width
componentHeight = font.glyphs[glyphName].layers[0].components[componentIndex].bounds.size.height
if transformation == 'horizontal':
componentWidth = -(componentWidth)
if transformation == 'vertical':
componentHeight = -(componentHeight)
Is it possible to make the above code work, or is there another, perhaps simpler, way to implement this (if at all)?
A component has a property called transform
which you can set to any NSAffineTransform
.
Here is a method for applying an existing transformation to a component:
def transformComponent( myComponent, myTransform ):
compTransform = NSAffineTransform.transform()
compTransform.setTransformStruct_( myComponent.transform )
compTransform.appendTransform_( myTransform )
myComponent.transform = compTransform.transformStruct()
And as an example, a function that produces a rotation transformation:
def rotationTransform( angle=180.0, xOrigin=0.0, yOrigin=0.0 ):
"""Returns a TransformStruct for rotating."""
RotationTransform = NSAffineTransform.transform()
RotationTransform.translateXBy_yBy_( xOrigin, yOrigin )
RotationTransform.rotateByDegrees_( angle )
RotationTransform.translateXBy_yBy_( -xOrigin, -yOrigin )
return RotationTransform
For what you want to do, you will more likely need Scale and Translate , which looks like this:
def scaleAndTranslateTransform( scaleX, scaleY, moveX, moveY, xOrigin=0.0, yOrigin=0.0 ):
ScaleAndMoveTransform = NSAffineTransform.transform()
ScaleAndMoveTransform.translateXBy_yBy_( xOrigin, yOrigin )
ScaleAndMoveTransform.scaleXBy_yBy_( scaleX, scaleY )
ScaleAndMoveTransform.translateXBy_yBy_( -xOrigin, -yOrigin )
ScaleAndMoveTransform.translateXBy_yBy_( moveX, moveY )
return ScaleAndMoveTransform
1 Like
Tosche
July 7, 2015, 2:11am
#3
How about this? This flips a component horizontally.
component.setScaleX_scaleY_rotation_(-1, 1, 0)
Positioning adjustment has to follow, but it shouldn’t be complicated.
def flipComponentVertically(c):
bounds = c.bounds
print bounds
t = c.transform
print t
newY = t[5]
if t[3] < 0:
newY = newY - bounds.size.height
else:
newY = newY + bounds.size.height
t = (t[0], t[1], t[2], -t[3], t[4], newY )
print t
c.transform = t
c = font.selectedLayers[0].components[0]
flipComponentVertically(c)
1 Like
Any way of applying the transform without accessing selectedLayers
? The idea I’m working on generates the components, draws them, generates a glyph, adds the applicable components and then applies transformations to them, all via function calls in the script.
I tried to mix @GeorgSeifert ’s idea with my previous code, accessing the chosen component with font.glyphs[glyphName].layers[0].components[componentIndex]
, and the tuple values remain unchanged. The following is my source code (sorry for the verbosity):
#MenuTitle: Flip Component (test)
# -*- coding: utf-8 -*-
font = Glyphs.font
font.glyphs.append(GSGlyph('cornerComponent'))
font.glyphs['cornerComponent'].layers[0].paths.append(GSPath())
cornerComponent = font.glyphs['cornerComponent'].layers[0].paths[0]
cornerComponent.nodes.append(GSNode([0, 0], GSLINE))
cornerComponent.nodes.append(GSNode([0, 100], GSLINE))
cornerComponent.nodes.append(GSNode([100, 100], GSLINE))
cornerComponent.closed = True
def addComponent(glyphName, componentName, x, y):
components = font.glyphs[glyphName].layers[0].components
components.append(GSComponent(componentName, [x,y]))
def flipComponent(glyphName, componentIndex, transformation):
component = font.glyphs[glyphName].layers[0].components[componentIndex]
transform = component.transform
if transformation == 'horizontal':
newX = component.transform[4]
if transform[0] < 0:
newX -= component.bounds.size.width
else:
newX += component.bounds.size.width
transform = (-transform[0], transform[1], transform[2], transform[3], newX, transform[5])
if transformation == 'vertical':
newY = transform[5]
if transform[3] < 0:
newY -= component.bounds.size.height
else:
newY += component.bounds.size.height
transform = (transform[0], transform[1], transform[2], -transform[3], transform[4], newY)
addComponent('a', 'cornerComponent', 0,0)
print font.glyphs['a'].layers[0].components[0].transform
flipComponent('a', 0, 'vertical')
print font.glyphs['a'].layers[0].components[0].transform
I would reorder the first part a bit:
cornerComponent = GSGlyph('cornerComponent')
cornerPath = GSPath()
cornerPath.nodes.append(GSNode([0, 0], GSLINE))
cornerPath.nodes.append(GSNode([0, 100], GSLINE))
cornerPath.nodes.append(GSNode([100, 100], GSLINE))
cornerPath.closed = True
cornerComponent.layers[0].paths.append(GSPath())
font.glyphs.append(cornerComponent)
The rest seems to be fine. Only to access the glyphs and components by name and index is not very elegant. Why not use the component itself as an argument.
component = font.glyphs['a'].layers[0].components[0]
flipComponent(component, 'vertical')
print component.transform
1 Like