# Polar Coordinates

In this section we'll learn about polar coordinates: what they are and how to create them in Doodle. We're interested in polar coordinates because they allow us to easily create regular polygons. We'll construct regular polygons in the final part of this section.

## Points in Two Dimensions

A point in two dimensions is most commonly specified using x and y coordinates. These are known as *Cartesian coordinates* after their inventor, René Descartes. We can visualize a Cartesian coordinate as projecting a vertical line from the x-axis and a horizontal line from the y-axis. The intersection of these two lines is the chosen point. The animation below shows this.

An alternate representation is *polar coordinates*. In polar coordinates, a point is specified by a distance from the origin and an angle. The animation below illustrates this.

In Doodle we can construct points using either Cartesian or polar coordinates. To create a Cartesian point we pass the x and y values to the `Point`

constructor.

`val cartesian = Point(3, 4)`

To create a polar point we need a length and an angle. The length is just a number, but in Doodle angles are their own type called `Angle`

. We usually construct angles in terms of degrees. Here's an example.

`val ninety = 90.degrees`

As well as degrees we can also use radians or turns. 2π radians make a full circle. A turn is a proportion of a full circle: 1.0 is a full circle (360 degrees), 0.5 is half a circle, and so on. Here are some examples.

```
val radians = 2.radians
val fullTurn = 1.turns
```

Now we know how to create an `Angle`

we can create a `Point`

using polar coordinates.

`val polar = Point(5, 45.degrees)`

## From Points to Polygons

Drawing polygons is our ultimate goal, and polar coordinates allow us to easily specify the corners, or vertices, of regular polygons. Look at the hexagon below. To specify the vertices in Cartesian coordinates we'd have to do some involved geometry. With polar coordinates, however, it's very simple. Each vertex is the same distance from the center but differs in angle, as the animation shows. In the case of the hexagon, each vertex is a 60 degree rotation from the one before. (This is because a full turn of 360 degrees must visit all vertices, and there are 6 evenly spaced vertices, so each vertex is a turn of 360/60 = 60 degrees.)

We can use this idea to draw circles, or another `Image`

, at the vertices of a regular polygon. Here's an example demonstrating what I mean.

```
val dot = Image.circle(5).fillColor(Color.darkViolet)
val vertices =
dot.at(Point(100, 0.degrees))
.on(dot.at(Point(100, 60.degrees)))
.on(dot.at(Point(100, 120.degrees)))
.on(dot.at(Point(100, 180.degrees)))
.on(dot.at(Point(100, 240.degrees)))
.on(dot.at(Point(100, 300.degrees)))
```

Drawing this gives the output shown below.

### Flexible Layout with `at`

The example above uses a method we haven't seen before: `at`

. This is another tool for laying out images, like `on`

, `beside`

, and `above`

. `at`

changes the position of an image relative to its origin. The understand this, and why we have to place the dots `on`

each other, we need to understand how layout works in Doodle.

Every `Image`

in Doodle has a point called its *origin*, and a *bounding box* which determines the extent of the image. By convention the origin is in the center of the bounding box but this is not required. We can see the origin and bounding box of an `Image`

by calling the `debug`

method.

The example code below uses `debug`

to draw the origin and bounding box for:

- the entire image, consisting of three circles;
- the individual circles after they have been moved with
`at`

; and - the individual circles before shifting them with
`at.`

```
val c = Image.circle(40)
val c1 = c.beside(c.at(10, 10)).beside(c.at(10, -10)).debug
val c2 = c.debug.beside(c.at(10, 10).debug).beside(c.at(10, -10).debug)
val c3 = c.debug.beside(c.debug.at(10, 10)).beside(c.debug.at(10, -10))
val example = c1.above(c2).above(c3)
```

This produces the output shown below.

When we layout `Images`

using `above`

, `beside`

, or `on`

it is the bounding boxes and origins that determine how the individual components are positioned relative to one another. For `on`

the rule is that the origins are placed on top of one another. For `beside`

the rule is that origins are horizontally aligned and placed so that the bounding boxes just touch. The origin of the compound image is placed equidistant from the left and right edges of the compound bounding box on the horizontal line that connects the origins of the component images. The rule for `above`

is the same as `beside`

, but we use vertical alignment instead of horizontal alignment.

Using `at`

moves an `Image`

relative to its origin. So `c.at(10, 10)`

moves the circle 10 units up and to the right relative to its origin.

Taken together these rules explain the results we've seen. When drawing the polygon vertices, we want all the elements to share the same origin, so we use `on`

to combine `Images`

that we have moved using `at`

.

#### Exercise: Get To The Point

Implement a method `polygonPoints`

that produces an `Image`

with circles (or something else of your choice) at the vertices of a regular polygon as shown above. The method should accept two parameters:

- the number of sides of the polygon; and
- the radius (distance of the vertices from the center)

Below shows the output of

```
polygonPoints(3, 50)
.fillColor(Color.crimson)
.beside(polygonPoints(5, 50).fillColor(Color.lawngreen))
.beside(polygonPoints(7, 50).fillColor(Color.dodgerBlue))
```

(I've used color to make it clearer which points belong to which polygon.)

This is a structural recursion over the natural numbers, but we need a helper method to actually do the counting. Here's my implementation. I used turns to specify the angle `turn`

, because I felt was the most natural way to express it.

```
def polygonPoints(sides: Int, radius: Double): Image = {
val turn = (1.0 / sides).turns
def loop(count: Int): Image =
count match {
case 0 => Image.empty
case n =>
Image
.circle(5)
.at(Point(radius, turn * n))
.on(loop(n - 1))
}
loop(sides)
}
```