Introduction
Graphical resources in the digital world are of two basic types, raster and vector. Raster images are essentially a rectangular array of pixel intensities. Vector graphics, on the other hand, are mathematical representations of shapes.
While there are situations in which raster images are irreplaceable (photos, for example), in other scenarios, vector graphics make capable substitutes. Vector graphics make the task of creating graphical resources for multiple screen resolutions trivial. At the time of writing, there are at least half a dozen screen resolutions to contend with on the iOS platform.
One of the best things about vector graphics is that they can be rendered to any resolution while remaining absolutely crisp and smooth. This is why PostScript and TrueType fonts look sharp at any magnification. Because smartphone and computer displays are raster in nature, ultimately, the vector image does need to be rendered to the display as a raster image at the appropriate resolution. This is usually taken care of by the lowlevel graphics library and the programmer doesn’t need to worry about this.
1. When to Use Vector Graphics?
Let’s take a look at some scenarios where you should consider using vector graphics.
App and Menu Icons, User Interface Elements
A few years ago, Apple eschewed skeuomorphism in the user interface of its apps and iOS itself, in favour of bold and geometrically precise designs. Take a look at the Camera or Photo app icons, for example.
More likely than not, they were designed using vector graphics tools. Developers had to follow suit and most of the popular (nongame) apps underwent a complete metamorphosis in order to conform to this design paradigm.
Games
Games with simple graphics (think Asteroids) or geometric themes (Super Hexagon and Geometry Jump come to mind) can have their sprites rendered from vectors. The same applies to games that have procedurally generated levels.
Images
Images in which you want to inject a small amount of randomness to get multiple versions of the same basic shape.
2. Bezier Curves
What are Bezier curves? Without delving into the mathematical theory, let’s just talk about the features that are of practical use to developers.
Degrees of Freedom
Bezier curves are characterized by how many degrees of freedom they have. The higher this degree, the more variation the curve can incorporate (but also the more mathematically complex it is).
Degree one Beziers are straight line segments. Degree two curves are called quad curves. Degree three curves (cubics) are the ones we’ll focus on, because they offer a good compromise between flexibility and complexity.
Cubic Beziers can represent not only simple smooth curves, but also loops and cusps. Several cubic Bezier segments can be hooked up end to end to form more complicated shapes.
Cubic Beziers
A cubic Bezier is defined by its two end points and two additional control points that determine its shape. In general, a degree n Bezier has (n1) control points, not counting the end points.
An attractive feature of cubic Beziers is that these points have a significant visual intepretation. The line connecting an end point to its adjacent control point acts as a tangent to the curve at the end point. This fact is useful for designing shapes. We’ll exploit this property later in the tutorial.
Geometric Transforms
Because of the mathematical nature of these curves, you can easily apply geometric transforms to them, such as scaling, rotation, and translation, without any loss of fidelity.
The following image shows a sampling of different kinds of shapes that a single cubic Bezier can take. Notice how the green line segments act as tangents to the curve.
3. Core Graphics and the UIBezierPath
Class
On iOS and OS X, vector graphics are implemented using the Cbased Core Graphics library. Built on top of this is UIKit/Cocoa, which adds a veneer of object orientation. The workhorse is the UIBezierPath
class (NSBezierPath
on OS X), an implementation of a mathematical Bezier curve.
The UIBezierPath
class supports Bezier curves of degree one (straight line segments), two (quad curves), and three (cubic curves).
Programmatically, a UIBezierPath
object can be built piecebypiece by appending new components (subpaths) to it. To facilitate this, the UIBezierPath
object keeps track of the currentPoint
property. Every time you append a new path segment, the last point of the appended segment becomes the current point. Any additional drawing you do generally starts at this point. You can explicitly move this point to a desired location.
The class has convenience methods for making commonly used shapes, such as arcs and circles, (rounded) rectangles, etc. Internally, these shapes have been built by connecting several subpaths.
The overall path can be either an open or closed shape. It can even be selfintersecting or have multiple closed components.
4. Getting started
This tutorial is meant to serve as a beyondthebasics look at vector graphics generation. But even if you are an experienced developer who hasn’t used Core Graphics or UIBezierPath
before, you should be able to follow along. If you’re new to this, I recommend skimming through the UIBezierPath
class reference (and the underlying Core Graphics functions) if you’re not already familiar with it. We can only exercise a limited number of features of the API in a single tutorial.
Enough talk. Let’s start coding. In the remainder of this tutorial, I will present two scenarios where vector graphics are the ideal tool to use.
Fire up Xcode, create a new playground, and set the platform to iOS. Incidently, Xcode playgrounds are another reason why working with vector graphics is now fun. You can tweak your code and get instant visual feedback. Note that you should be using the latest stable version of Xcode, which is 7.2 at the time of this writing.
Scenario 1: Making Cloud Shapes
We’d like to generate images of clouds that adhere to a basic cloud shape while having some randomness so that each cloud looks different. The basic design I’ve settled on is a compound shape, defined by several circles of random radii centered along an elliptical path of random size (within appropriate ranges).
To clarify, here’s what the overall object looks like if we stroked the vector path instead of filling it.
If your geometry is a bit rusty, then this Wikipedia image shows what an ellipse looks like.
Some Utility Functions
Let’s start by writing a couple of helper functions.
1 

2 
import UIKit 
3 

4 
func randomInt(lower lower: Int, upper: Int) > Int { 
5 
assert(lower < upper) 
6 
return lower + Int(arc4random_uniform(UInt32(upper  lower))) 
7 
}

8 

9 
func circle(at center: CGPoint, radius: CGFloat) > UIBezierPath { 
10 
return UIBezierPath(arcCenter: center, radius: radius, startAngle: 0, endAngle: CGFloat(2 * M_PI), clockwise: true) 
11 
}

The random(lower:upper:)
function uses the builtin arc4random_uniform()
function to generate random numbers in the range lower
and (upper1)
. The circle(at:center:)
function generates a Bezier path, representing a circle with a given center
and radius
.
Generating Points and Paths
Let’s now focus on generating the points along the elliptical path. An ellipse centered at the origin of the coordinate system with its axes aligned along the coordinate axes has a particularly simple mathematical form that looks like this.
1 
(r, θ) = (a cos(θ), b sin(θ)) 
We assign random values for the lengths of its major and minor axis so that the shape looks like a cloud, more elongated horizontally than vertically.
We use the stride()
function to generate regularly spaced angles around the circle, and then use map()
to generate regularly spaced points on the ellipse using the above mathematical expression.
1 

2 
let a = Double(randomInt(lower: 70, upper: 100)) 
3 
let b = Double(randomInt(lower: 10, upper: 35)) 
4 
let ndiv = 12 as Double 
5 

6 

7 
let points = (0.0).stride(to: 1.0, by: 1/ndiv).map { CGPoint(x: a * cos(2 * M_PI * $0), y: b * sin(2 * M_PI * $0)) } 
We generate the central “mass” of the cloud by joining the points along the elliptical path. If we don’t, we’ll get a big void at the center.
1 

2 
let path = UIBezierPath() 
3 
path.moveToPoint(points[0]) 
4 

5 
for point in points[1.. 
6 

7 
Note that the exact path doesn't matter, because we'll be filling the path, not stroking it. This means that it won't be distinguishable from the circles. 
8 

9 
To generate the circles, we first heuristically choose a range for the random circle radii. The fact that we're developing this in a playground helped me play with the values until I got a result I was satisfied with. 
10 

11 

12 
let minRadius = (Int)(M_PI * a/ndiv) 
13 
let maxRadius = minRadius + 25 
14 

15 
for point in points[0..<points.count let randomradius="CGFloat(randomInt(lower:" minradius upper: maxradius circ="circle(at:" point radius: path.appendpath path> 
16 

17 
### Previewing the Result 
18 

19 
You can view the result by clicking the "eye" icon in the results panel on the right, on the same line as the "path" statement. 
20 

21 
![Quick look](https://cmsassets.tutsplus.com/uploads/users/1211/posts/25367/attachment/rsz_qlook.png) 
22 

23 
### Final Touches 
24 

25 
How do we rasterize this to get the final result? We need what's known as a "graphical context" in which to draw the paths. In our case, we'll be drawing into an image (a `UIImage` instance). It is at this point that you need to set several parameters that specify what the final path will be rendered as, such as colors and stroke widths. Finally, you stroke or fill your path (or both). In our case, we want our clouds to be white, and we only want to fill them. 
26 

27 
Let's package this code into a function so we can generate as many clouds as we wish. And while we're at it, we'll write some code to draw a few random clouds on a blue background (representing the sky) and to draw all this into the playground live view. 
28 

29 
Here's the final code: 
30 

31 

32 
import UIKit 
33 
import XCPlayground 
34 

35 
func generateRandomCloud() > UIImage { 
36 

37 
func randomInt(lower lower: Int, upper: Int) > Int { 
38 
assert(lower < upper) 
39 
return lower + Int(arc4random_uniform(UInt32(upper  lower))) 
40 
}

41 

42 
func circle(at center: CGPoint, radius: CGFloat) > UIBezierPath { 
43 
return UIBezierPath(arcCenter: center, radius: radius, startAngle: 0, endAngle: CGFloat(2 * M_PI), clockwise: true) 
44 
}

45 

46 
let a = Double(randomInt(lower: 70, upper: 100)) 
47 
let b = Double(randomInt(lower: 10, upper: 35)) 
48 
let ndiv = 12 as Double 
49 

50 

51 
let points = (0.0).stride(to: 1.0, by: 1/ndiv).map { CGPoint(x: a * cos(2 * M_PI * $0), y: b * sin(2 * M_PI * $0)) } 
52 

53 
let path = UIBezierPath() 
54 
path.moveToPoint(points[0]) 
55 
for point in points[1..<points.count path.addlinetopoint path.closepath let minradius="(Int)(M_PI" a maxradius="minRadius" for point in points randomradius="CGFloat(randomInt(lower:" upper: circ="circle(at:" radius: path.appendpath path height path.bounds.height margin="CGFloat(20)" uigraphicsbeginimagecontext uicolor.whitecolor path.applytransform path.fill im="UIGraphicsGetImageFromCurrentImageContext()" return class view: uiview override func drawrect cgrect ctx="UIGraphicsGetCurrentContext()" uicolor.bluecolor cgcontextfillrect rect cloud1="generateRandomCloud().CGImage" cloud2="generateRandomCloud().CGImage" cloud3="generateRandomCloud().CGImage" cgcontextdrawimage y: width: cgimagegetwidth height: cgimagegetheight xcplaygroundpage.currentpage.liveview="View(frame:" cgrectmake> 
56 

57 
And this is what the final result looks like: 
58 

59 
![Final clouds image](https://cmsassets.tutsplus.com/uploads/users/1211/posts/25367/attachment/rsz_clouds_final.png) 
60 

61 
The silhouttes of the clouds appear a bit blurred in the above image, but this is simply a resizing artefact. The true output image is sharp. 
62 

63 
To view it in your own Playground, make sure the **Assistant Editor** is open. Select **Show Assitant Editor** from the **View** menu. 
64 

65 
## Scenario 2: Generating Jigsaw Puzzle Pieces 
66 

67 
Jigsaw puzzle pieces usually have a square "frame", with each edge being either flat, having a rounded tab protruding outwards, or a slot of the same shape to tesellate with a tab from an adjacent piece. Here's a section of a typical jigsaw puzzle. 
68 

69 
![Jigsaw piece puzzle prototype](https://cmsassets.tutsplus.com/uploads/users/1211/posts/25367/attachment/rsz_puzzle.png)

70 

71 
### Accomodating Variations With Vector Graphics

72 

73 
If you were developing a jigsaw puzzle app, you'd want to use a puzzle pieceshaped mask to segment the image representing the puzzle. You could go for pregenerated raster masks that you shipped with the app, but you'd need to include several variations to accomodate all possible shape variations of the four edges. 
74 

75 
With vector graphics, you can generate the mask for any kind of piece on the fly. Plus, it would be easier to accomodate other variations, such as if you wanted rectangular or oblique pieces (instead of square pieces).

76 

77 
### Designing the Jigsaw Piece Boundary

78 

79 
How do we actually design the puzzle piece, which is to say, how do we figure out how to place our control points to generate a bezier path that looks like the curved tab?

80 

81 
Recall the useful tangency property of cubic Beziers I mentioned earlier. You can begin by drawing an approximation to the desired shape, breaking it up into segments by estimating how many cubic segments you'll need (knowing the kinds of shapes a single cubic segment can accomodate) and then drawing tangents to these segments to figure out where you might place your control points. Here's a diagram explaining what I'm talking about. 
82 

83 
![Bezier path for outward tab](https://cmsassets.tutsplus.com/uploads/users/1211/posts/25367/attachment/rsz_outie.png) 
84 

85 
### Relating the Shape to the Bezier Curve Control Points 
86 

87 
I determined that to represent the tab shape, four Bezier segments would do nicely: 
88 

89 
 two representing the straight line segments at either end of the shape 
90 
 two representing the Sshaped segments representing the tab at the center 
91 

92 
Notice the green and yellow dashed line segments acting as tangents to the Sshaped segments, which helped me estimate where to place the control points. Note also that I visualized the piece as having a length of one unit, which is why all the coordinates are fractions of one. I could easily have made my curve to be, say, 100 points long (scaling the control points by a factor of 100). The resolution independence of vector graphics means this is a nonissue. 
93 

94 
Lastly, I used cubic Beziers even for the straight line segments purely for convenience, so that the code could be written more concisely and uniformly. 
95 

96 
I skipped drawing the control points of the straight segments in the diagram to avoid clutter. Of course, a cubic Bezier representing a line simply has the end points and control points all lying along the line itself. 
97 

98 
The fact that you're developing this in a playground means that you can easily "rejig" the control point values to find a shape that pleases you and get instant feedback. 
99 

100 
### Getting Started

101 

102 
Let's get started. You can use the same playground as before by adding a new page to it. Choose **New > Playground Page** from the **File** menu or create a new playground if you prefer. 
103 

104 
Replace any code on the new page with the following: 
105 

106 

107 
import UIKit 
108 

109 
let outie_coords: [(x: CGFloat, y: CGFloat)] = [(1.0/9, 0), (2.0/9, 0), (1.0/3, 0), (37.0/60, 0), (1.0/6, 1.0/3), (1.0/2, 1.0/3), (5.0/6, 1.0/3), (23.0/60, 0), (2.0/3, 0), (7.0/9, 0), (8.0/9, 0), (1.0, 0)] 
110 

111 
let size: CGFloat = 100 
112 
let outie_points = outie_coords.map { CGPointApplyAffineTransform(CGPointMake($0.x, $0.y), CGAffineTransformMakeScale(size, size)) } 
113 

114 

115 
let path = UIBezierPath() 
116 
path.moveToPoint(CGPointZero) 
117 

118 
for i in 0.stride(through: outie_points.count  3, by: 3) { 
119 
path.addCurveToPoint(outie_points[i+2], controlPoint1: outie_points[i], controlPoint2: outie_points[i+1]) 
120 
}

121 

122 
path

123 

124 

125 
### Generating All Four Sides Using Geometric Transforms 
126 

127 
Note that we decided to make our path 100 points long by applying a scaling transform to the points. 
128 

129 
We see the following result using the "Quick Look" feature: 
130 

131 
![Quick Look](https://cmsassets.tutsplus.com/uploads/users/1211/posts/25367/attachment/rsz_outie_ql.png) 
132 

133 
So far, so good. How do we generate four sides of the jigsaw piece? The answer is (as you can guess), using geometric transformations. By applying a 90 degrees rotation followed by an appropriate translation to `path` above, we can easily generate the rest of the sides. 
134 

135 
### Caveat: A Problem With Interior Filling 
136 

137 
There's a caveat here, unfortunately. The transformation won't automatically join individual segments together. Even though our jigsaw piece's silhouette looks fine, its interior won't be filled and we'll face problems using it as a mask. We can observe this in the playground. Add the following code: 
138 

139 

140 
let transform = CGAffineTransformTranslate(CGAffineTransformMakeRotation(CGFloat(M_PI/2)), 0, size)

141 

142 
let temppath = path.copy() as! UIBezierPath

143 

144 
let foursided = UIBezierPath()

145 
for i in 0...3 {

146 
temppath.applyTransform(transform)

147 
foursided.appendPath(temppath)

148 

149 
}

150 

151 
foursided

152 

153 

154 
Quick Look shows us the following:

155 

156 
![Improperlyfilled jigsaw piece](https://cmsassets.tutsplus.com/uploads/users/1211/posts/25367/attachment/rsz_foursided.png)

157 

158 
Notice how the interior of the piece isn't shaded, indicating it hasn't been filled. 
159 

160 
*You can find out the drawing commands used to construct a complex `UIBezierPath` by examining its `debugDescription` property in the playground.*

161 

162 
### Resolving the Filling Problem

163 

164 
Geometric transforms on `UIBezierPath` work quite well for the common use case, that is, when you've already got a closed shape or the shape you're transforming is intrinsically open, and you want to generate geometrically transformed versions of them. Our use case is different. The path acts as a subpath in a larger shape that we're building and whose interior we intend to fill. This is a bit trickier. 
165 

166 
One approach would be to mess with the internals of the path (using the `CGPathApply()` function from the Core Graphics API) and manually join the segments together to end up with a single, closed and properlyfilled shape. 
167 

168 
But that option feels a bit hackish and that's why I opted for a different approach. We apply the geometric transforms to the points themselves first, via the `CGPointApplyAffineTransform()` function, applying the exact same transform we attempted to use a moment ago. We then use the transformed points to create the subpath, that is appended to the overall shape. At the end of the tutorial, we'll see an example where we can correctly apply a geometric transform to the Bezier path. 
169 

170 
### Generating the Piece Edge Variations 
171 

172 
How do we generate the "innie" tab? We could apply a geometric transform again, with a negative scaling factor in the ydirection (inverting its shape), but I opted to do it manually by simply inverting the ycoordinates of the points in `outie_points`. 
173 

174 
As for the flatedged tab, while I could've simply used a straight line segment to represent it, in order to avoid having to specialize the code for distinct cases, I simply set the ycoordinate of each point in `outie_points` to zero. This gives us: 
175 

176 

177 
let innie_points = outie_points.map { CGPointMake($0.x, $0.y) }

178 
let flat_points = outie_points.map { CGPointMake($0.x, 0) }

179 

180 

181 
As an exercise, you might generate Bezier curves out of these edges and view them using Quick Look.

182 

183 
You now know enough for me to blitz you with the entire code, which ties everything together in a single function.

184 

185 
Replace all the content of the playground page with the following:

186 

187 

188 
import UIKit

189 
import XCPlayground

190 

191 

192 
enum Edge {

193 
case Outie

194 
case Innie

195 
case Flat

196 
}

197 

198 
func jigsawPieceMaker(size size: CGFloat, edges: [Edge]) > UIBezierPath {

199 

200 
func incrementalPathBuilder(firstPoint: CGPoint) > ([CGPoint]) > UIBezierPath {

201 
let path = UIBezierPath()

202 
path.moveToPoint(firstPoint)

203 
return {

204 
points in

205 
assert(points.count % 3 == 0)

206 
for i in 0.stride(through: points.count  3, by: 3) {

207 
path.addCurveToPoint(points[i+2], controlPoint1: points[i], controlPoint2: points[i+1])

208 
}

209 

210 
return path

211 
}

212 
}

213 

214 

215 
let outie_coords: [(x: CGFloat, y: CGFloat)] = [/*(0, 0), */ (1.0/9, 0), (2.0/9, 0), (1.0/3, 0), (37.0/60, 0), (1.0/6, 1.0/3), (1.0/2, 1.0/3), (5.0/6, 1.0/3), (23.0/60, 0), (2.0/3, 0), (7.0/9, 0), (8.0/9, 0), (1.0, 0)]

216 

217 
let outie_points = outie_coords.map { CGPointApplyAffineTransform(CGPointMake($0.x, $0.y), CGAffineTransformMakeScale(size, size)) }

218 
let innie_points = outie_points.map { CGPointMake($0.x, $0.y) }

219 
let flat_points = outie_points.map { CGPointMake($0.x, 0) }

220 

221 
var shapeDict: [Edge: [CGPoint]] = [.Outie: outie_points, .Innie: innie_points, .Flat: flat_points]

222 

223 

224 
let transform = CGAffineTransformTranslate(CGAffineTransformMakeRotation(CGFloat(M_PI/2)), 0, size)

225 
let path_builder = incrementalPathBuilder(CGPointZero)

226 
var path: UIBezierPath!

227 
for edge in edges {

228 
path = path_builder(shapeDict[edge]!)

229 

230 
for (e, pts) in shapeDict {

231 
let tr_pts = pts.map { CGPointApplyAffineTransform($0, transform) }

232 
shapeDict[e] = tr_pts

233 
}

234 
}

235 

236 
path.closePath()

237 
return path

238 
}

239 

240 

241 
let piece1 = jigsawPieceMaker(size: 100, edges: [.Innie, .Outie, .Flat, .Innie])

242 

243 
let piece2 = jigsawPieceMaker(size: 100, edges: [.Innie, .Innie, .Innie, .Innie])

244 
piece2.applyTransform(CGAffineTransformMakeRotation(CGFloat(M_PI/3)))

245 

246 

247 

248 
There are only a few more interesting things in the code that I'd like to clarify: 
249 

250 
 We use an `enum` to define the different edge shapes. We store the points in a dictionary that uses the enumeration values as keys. 
251 
 We piece together the subpaths (consisting of each edge of the foursided jigsaw piece shape) in the `incrementalPathBuilder(_)` function, defined internally to the `jigsawPieceMaker(size:edges:)` function. 
252 
 Now that the jigsaw piece is filled properly, as we can see in the Quick Look output, we can safely use the `applyTransform(_:)` method to apply a geometric transform to the shape. As an example, I've applied a 60 degrees rotation to the second piece. 
253 

254 
![Examples of jigsaw puzzle pieces](https://cmsassets.tutsplus.com/uploads/users/1211/posts/25367/attachment/rsz_jigsawpieces.png)

255 

256 
## Conclusion

257 

258 
I hope to have convinced you that the ability to programmatically generate vector graphics can be a useful skill to have in your arsenal. Hopefully, you'll be inspired to think of (and code up) other interesting applications for vector graphics that you can incorporate in your own apps.</points.count></points.count> 