# Epicycles

We're now going to see a different example of composition, in creating a type of curve known as an epicycle. An epicycle is produced when we trace a point on a circle rotating on another circle. We can stack circles on top of circles, and change the speed at which they rotate, to produce many different curves. Here's an example using two circles.

The parametric curve that produces this result is

``````val twoWheels: Angle => Point =
(angle: Angle) =>
Point(75, angle * 6) + Point(32, angle * 11).toVec``````

Let's walk through this code. We know that a parametric circle is

``(angle: Angle) => Point(1.0, angle)``

where I've chosen the radius to be 1. So

``(angle: Angle) => Point(75, angle * 6)``

is a parametric circle with radius 75, which is spinning six times faster. By the same reasoning

``(angle: Angle) => Point(32, angle * 11)``

is a parametric circle with radius 32 spinning eleven times faster.

The remaining portion of the code is a conversion from `Point` to `Vec` (the call to `toVec`) and addition of a `Point` and a `Vec`.

``Point(..., ...) + Point(..., ...).toVec``

This moves the center of the smaller circle to the current point on the larger circle. The conversion from `Point` to `Vec` is needed for technical reasons which I'll attempt to briefly explain. A point specifies a location relative to a fixed origin. A vector represents a displacement relative to some arbitrary starting point. Therefore we can add a vector to a point to get a new point that is shifted by the vector. Adding a point to a point, however, is not possible as points are both locations relative to the same origin, not displacements like a vector is. (If this explanation doesn't work for you, there are many online resources that describe vectors.)

This is everything we need to build our own curves based on epicycles. The more circles we add, the more complex the curve we can create. The examples below are created using the following code. It uses three circles with fixed radius, but allows us to change the speed of rotation.

``````def epicycle(a: Int, b: Int, c: Int): Angle => Point =
(angle: Angle) =>
(Point(75, angle * a).toVec + Point(32, angle * b).toVec + Point(15, angle * c).toVec).toPoint``````

The examples are created by choosing the parameters a, b, c, as (1, 6, 14), (7, 13, 25), and (1, 7, -21) respectively. ## Composing Epicycles

Let's return to the theme of this chapter, function composition. Using function composition we can do what we've done before, and break the epicycle curves into small reusuable parts.

The first component we need is a parametric circle that allows us to change the speed of rotation. I called this a `wheel`.

``````def wheel(speed: Int): Angle => Point =
???``````

We can use `scale`, which we've already defined, to change the radius.

The other component we need is a way to position a wheel relative to another wheel. (This is the point / vector addition part.) I called this `on`.

``````def on(wheel1: Angle => Point, wheel2: Angle => Point): Angle => Point =
???``````

#### Exercise: Wheels on Wheels

Implement `wheel` and `on`, described above. Then use them, as well as tools we've created earlier, to draw your own epicycle curves.

`wheel` is a parametric circle that rotates at the given speed.

``````def wheel(speed: Int): Angle => Point =
angle => Point(1.0, angle * speed)``````

`on` implements the point and vector addition we discussed earlier.

``````def on(wheel1: Angle => Point, wheel2: Angle => Point): Angle => Point =
angle => wheel1(angle) + wheel2(angle).toVec``````

With these we can easily construct epicycle curves. The example we started this section with

``````val twoWheels: Angle => Point =
(angle: Angle) =>
Point(75, angle * 6) + Point(32, angle * 11).toVec``````

can be written as

``````val wheel1 = wheel(6).andThen(scale(75))
val wheel2 = wheel(11).andThen(scale(32))

val combined = on(wheel1, wheel2)``````