Apply flip transformation in component inside of glyph

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

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

@Tosche and @mekkablue, didn’t check the new documentation page :wink:

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