Context Transforms

Transforms allow you to draw things rotated, moved, or scaled differently than you specified. You can use this technique to reuse drawing operations where they only differ by some small factor (like drawing lines on a graph), to tilt things like text, or to correct issues where the drawn element is upside down or sideways. In this episode, Sam shares a helpful technique of drawing a grid with a highlighted "origin square" to make it obvious what the transforms are doing.

Links

Drawing a Grid to Help Visualize Transformations

This utility function is a helpful way of visualizing where your drawing is happening. Not the use of the saveGState and restoreGState to keep this function self contained (in other words, no drawing state will leak out of this method and cause other operations to draw incorrectly).

funcdrawGrid(_context:CGContext){context.saveGState()letcolorSpace=CGColorSpaceCreateDeviceRGB()letcolor=CGColor(colorSpace:colorSpace,components:[0,0,0,0.2])!context.setStrokeColor(color)context.setLineWidth(2)// Stroke the bordercontext.stroke(bounds)// Draw a line every 20pxletincrement:CGFloat=20forxin1..<Int(bounds.height/increment){// Vertical linecontext.move(to:CGPoint(x:CGFloat(x)*increment,y:0))context.addLine(to:CGPoint(x:CGFloat(x)*increment,y:bounds.height))foryin1..<Int(bounds.width/increment){// Horizontal linecontext.move(to:CGPoint(x:0,y:CGFloat(y)*increment))context.addLine(to:CGPoint(x:bounds.width,y:CGFloat(y)*increment))}}// Stroke gridcontext.strokePath()// Draw top left red squarecontext.setFillColor(CGColor(colorSpace:colorSpace,components:[1,0,0,0.5])!)context.fill(CGRect(x:0,y:0,width:increment,height:increment))context.restoreGState()}

Zooming Out

Zooming out can help you figure out issues where your drawing is happening outside the frame. This is a common situation you might find yourself in when drawing with transforms. For instance if you rotate around the origin 180°, your entire drawing will happen outside the visible rect.

When performing transformations like zoom, it is important to remember that it happens at the anchor point, or origin of the context. In order to zoom out from the center, we'll first have to translate so that the anchor point is at the center of the view:

context.translateBy(x:bounds.midX,y:bounds.midY)

Then we can apply our scale transformation:

context.scaleBy(x:0.5,y:0.5)

And then we just need to jump back to where we were:

context.translateBy(x:-bounds.midX,y:-bounds.midY)

Flipping Horizontally

This is a common thing you might do when showing an image of someone through the camera. Since most people are accustomed to looking at themselves in a mirror, you can simulate this effect by horizontally flipping the image.