# How To Create Vector Graphics on iOS

## 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 low-level 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 (non-game) 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 (n-1) 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 C-based 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 piece-by-piece 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 self-intersecting or have multiple closed components.

## 4. Getting started

This tutorial is meant to serve as a beyond-the-basics 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 built-in arc4random_uniform() function to generate random numbers in the range lower and (upper-1). 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..  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://cms-assets.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..  56 57 And this is what the final result looks like:  58 59 ![Final clouds image](https://cms-assets.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://cms-assets.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 piece-shaped 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://cms-assets.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 S-shaped segments representing the tab at the center  91 92 Notice the green and yellow dashed line segments acting as tangents to the S-shaped 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 non-issue.  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://cms-assets.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 ![Improperly-filled jigsaw piece](https://cms-assets.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 properly-filled 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 y-direction (inverting its shape), but I opted to do it manually by simply inverting the y-coordinates of the points in outie_points.  173 174 As for the flat-edged 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 y-coordinate 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 four-sided 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://cms-assets.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.