Chapter 6
Astrological Sign Provider

Estimated Time


We’re going to create an object that will hold all the data (positions, shapes, etc.) for the astrological signs. It will also define an AstrologicalSign structure that will hold, for a single sign, information about the shape of its icon, the position of its small and big stars, as well as the location of each of the lines we’ll draw to highlight the shape.

But, before we begin, we need to look at the design files to get a sense of what it is we need to build.

Logic

The menu and background both make reference to icons that reference each of the twelve astrological signs.

From looking at these design specs we can tell two things. Also, from talking things over with Jake I figure out a third.

  1. The signs need to be used from two different objects (i.e. the menu and the background)
  2. The signs need to be rendered at different scales
  3. I need to be able to animate a single icon from a point to its full shape

These three points help me figure out the following:

  1. I don’t want to hard code the same shape data two separate objects, so I’ll need a single object to provide me with the shape data when I need it.
  2. I can’t use images because I need to animate over the shapes
  3. The shapes need to be beziers (i.e. made up of a series of lines and curves) so that I can easily scale and animate them

This is why we’re going to build an AstrologicalSignProvider.

But, before we begin we need to get the shapes of the signs in code.

Icon Shapes

There’s two ways to go about getting the shapes of the signs. We could add an image to a new C4 project, then painstakingly add points and curves to the project, guessing the position of control points and lines until we build each of the signs from scratch. However, between all of the icons there’s something like 200 different points… Guessing all of this would take a week of effort.1

Instead of wasting our lives by doing things the hard way, it’s way easier to use PaintCode, a super easy program that will let us create the icons using simple controls and then will spit out a bunch of Objective-C code that we can use in our app.

Minutes instead of days.

While I’m testing out drawing a shape, Jake uses PaintCode to trace all these icons:

And, when he’s done he hits export and I get a file made up of 12 different methods that look something like this:

1
2
3
4
5
6
7
//// Libra
UIBezierPath* bezier30Path = UIBezierPath.bezierPath;
[bezier30Path moveToPoint: CGPointMake(272.9, 181.68)];
[bezier30Path addLineToPoint: CGPointMake(265.4, 181.68)];
[bezier30Path addCurveToPoint: CGPointMake(254.1, 170.38) controlPoint1: CGPointMake(265.4, 175.48) controlPoint2: CGPointMake(260.3, 170.38)];
[bezier30Path addCurveToPoint: CGPointMake(242.8, 181.68) controlPoint1: CGPointMake(247.9, 170.38) controlPoint2: CGPointMake(242.8, 175.48)];
[bezier30Path addLineToPoint: CGPointMake(235.4, 181.68)];

This is great. But, since we’re working in C4 I take the time to translate this code to our own style:

1
2
3
4
5
6
7
8
bezier.moveToPoint(Point(37.5, 11.3))
bezier.addLineToPoint(Point(30, 11.3))
bezier.addCurveToPoint(Point(18.7, 0), control1:Point(30, 5.1), control2:Point(24.9, 0))
bezier.addCurveToPoint(Point(7.4, 11.3), control1:Point(12.5, 0), control2:Point(7.4, 5.1))
bezier.addLineToPoint(Point(0, 11.3))

bezier.moveToPoint(Point(0, 20.2))
bezier.addLineToPoint(Point(37.5, 20.2))

Cleaner. More readable. Ultimately, we’re now able to use C4 to create, scale and animate our shapes.2

Star Positions

On top of shapes, we need to know where the positions of stars should lie. The process for defining them again starts with Jake tracing images and figuring out the positions of stars relative to one another using:

Since we’re basing our design on this image it’s clear that each AstrologicalSign will need 3 sets of data: small stars, big stars, lines.

To get the positions Jake uses Sketch 3 to position the small and big stars relative to a canvas the same size as an iPhone 4, scaled so that the orientation looks good on the 5 and 6 as well. Each of the positions will be relative to the center of the screen, and we’ll offset those positions to their specific coordinates based on a signs position in the set of 12.

Show {0,0} and relative positions

Each sign will have an array of big and small points… The sets of data for Aries (the simplest of the signs) looks like this:

1
2
3
4
5
6
7
8
9
let big = [
Point(58.0,-57.7),
Point(125.5,-17.7)]
sign.big = big

let small = [
Point(-134.5,-95.2),
Point(137.0,11.3)]
sign.small = small

Notice how some of the points are negative? For example, the first big point is to the right and up from the center of the screen. Figuring out the center of each star (or image) in Sketch is easy, but calculating its position based on the center isn’t so straightforward… Unless you use Numbers. I create a spreadsheet that takes the values from Sketch and converts them to retina coordinates based on the size of the image being rendered, from which I am then able to subtract those values from the position of the center of the canvas.

For example:

  1. Sketch measures the top-left coordinate of a 17x17 image to be {585.5, 582}
  2. Based on 17x17 the center in retina coordinates becomes {297.00, 295.3}
  3. Which is then subtracted by {160, 284}, the center of an iPhone 5 canvas (the size in Sketch that Jake is designing into)
  4. The final point becomes {125.5, -17.7}

The lines between the stars are arbitrary, so I come up with a pattern that relies on the star position. Jake takes that pattern and fills in the positions by numbering the big and small stars, then writing out their positions based on their order, like so:

1
2
3
4
5
let lines = [
[big[0],small[0]],
[big[1],big[0]],
[big[1],small[1]]]
sign.lines = lines

The entry for Aries in Jake’s final Numbers file looks like this:

Ready to build.

Now that we know what we need to do, it’s time to build the provider. The guts of the class are really small ~40 lines of code. The methods for each sign take up a lot more space but there’s no logic in them, so they’re pretty straightforward.

Allons-y.

  1. With a bunch of breaks, stops for beer, and moments of extreme boredom of course 

  2. I could have written a script, but I took the time to copy/paste all the points because I could and because I wanted to simply “read” or “know” all the points I was going to work with.