# How to Draw a Circle

## 02 October, 2021

Lately I've been studying some Linear Algebra and felt like dipping my toes back into some generative art.

It seems, whenever I start doing something like this my first step is to draw a circle by radiating spokes from the origin. I always have to sort of rediscover the math from first principles, so I felt like writing a quick post about it. I'm going to walk through how I was thinking about this from scratch.

I'm using p5.js for these pictures.

First let's define our canvas:

```
DIM = [500,500];
ORIGIN = DIM.map((el)=>el/2);
```

This is obvious enough. Now, p5.js has two main functions: `setup`

and `draw`

which are pretty obvious.

```
function setup() {
createCanvas(...DIM);
background(255);
}
```

Color functions take a variety of arguments. In this case, we're
using one argument to define intensity of RGB I guess, 255 is `#FFFFFF`

, or all
full RGB or white.

I'm going to do this with only three drawing functions: `line`

, which takes an
origin and end point, `strokeWeight`

, which defines the line's width, and
`stroke`

which defines the line's color.

Let's just get something on screen.

```
function draw() {
line(...ORIGIN, ...DIM);
}
```

This just draws a line from the center to the bottom right (coordinates are
defined with `(0,0)`

at the top left and increasing right and down, as with most
systems).

Okay, now let's try looping over 360 degrees:

```
function draw() {
for (let i = 0; i <= 360; i++) {
line(...ORIGIN, i, i);
}
}
```

This will be hideously wrong, but I start naive. Always.

Okay, we know, obviously, that we're drawing a lot of lines from (0,0,250,250)
to (360,360,250,250) which is pretty meaningless, it's obviously a diagonal line
because `i=i`

. Let's try some trigonometry.

We know that every point on the unit circle can be described as a vertex on a right triangle. Since this triangle is right, getting coordinates with some trig shouldn't be too hard.

This is a classic Unit Circle (sourced from Wikipedia). Every point on the unit circle can be represented as $(\cos{\theta}, \sin{\theta})$. But $\theta$ is a radian, so let's do that right.

We know that $360° = 2 \pi$, so translating a degree to a radian as easy:

```
rad = 360 / (2 * Math.PI);
```

Now, let's draw a circle:

```
function draw() {
rad = 360 / (2 * Math.PI);
for (let i = 0; i <= 360; i++) {
line(...ORIGIN,
Math.cos(i*rad),
Math.sin(i*rad)
);
}
}
```

Well that's not doing it. Let's think about this.

We're definitely converting our $\theta$ from degrees to radians. But now that I
think of it, the output of each of `Math.sin`

and `Math.cos`

has got to be
${\alpha : -1 \leq \alpha \leq 1}$, so we're just drawing a lot of lines from
the origin to a circle around the pixels in the top left corner. Really it's
just a square because it's the top circling around the top pixel and 3 pixels
outside the frame.

So let's recenter to the origin.

```
function draw() {
rad = 360 / (2 * Math.PI);
for (let i = 0; i <= 360; i++) {
line(...ORIGIN,
ORIGIN[0] + Math.cos(i*rad),
ORIGIN[0] + Math.sin(i*rad)
);
}
}
```

Beautiful, we have a dot. Our radius is 1 pixel, so it's a 2x2 pixel square around the origin. Let's adjust the radius.

```
function draw() {
radius = 250;
rad = 360 / (2 * Math.PI);
for (let i = 0; i <= 360; i++) {
line(...ORIGIN,
ORIGIN[0] + Math.cos(i*rad)*radius,
ORIGIN[0] + Math.sin(i*rad)*radius
);
}
}
```

Hey, we got a circle! Nice.

Technically this is all we needed. But let's try giving it some varied color.
We've got a nice variable `i`

right there that describes a circle in 360
degrees. We could use the same sin wave we've already got to give our 3 colors
different degrees. Remember, the outputs of sine and cosine are always between
-1 and 1, so since our color scale is from 0 to 255 we'd basically have just
black lines if we don't normalize our scale to 255.

Since -1*255 is -255, we should move our color scale up to [0,2] by adding 1 to the output of sine and cosine.

```
s = 1 + Math.sin(i);
c = 1 + Math.cos(i);
```

Then we should scale to 255. We can't just multiply by 255, though, because when either sine or cosine equal 1, s and c = 2, so $s \cdot 255 = 510$. Let's instead scale by half of 255, so 127.5.

```
s = (1 + Math.sin(i)) * 127.5;
c = (1 + Math.cos(i)) * 127.5;
```

```
function draw() {
radius = 250;
rad = 360 / (2 * Math.PI);
for (let i = 0; i <= 360; i++) {
line(...ORIGIN,
ORIGIN[0] + Math.cos(i*rad)*radius,
ORIGIN[0] + Math.sin(i*rad)*radius
);
s = (1 + Math.sin(i)) * 127.5;
c = (1 + Math.cos(i)) * 127.5;
stroke(s, s, c);
}
}
```

So right here I wanted to start experimenting with size and got a happy accident
I'd like to checkpoint as I was troubleshooting gain. If you just change `DIM`

to `[1920,1080]`

you get this:

I'm not fully sure what's going on with that, but I like it. I'm going to troubleshoot this point.

Fixed:

```
function draw() {
radius = 250;
rad = 360 / (2 * Math.PI);
for (let i = 0; i <= 360; i++) {
line(...ORIGIN,
ORIGIN[0] + Math.cos(i*rad)*radius,
ORIGIN[1] + Math.sin(i*rad)*radius
);
s = (1 + Math.sin(i)) * 127.5;
c = (1 + Math.cos(i)) * 127.5;
stroke(s, s, c);
}
}
```

I was actually centering the Y origin on the X origin, which means my origin was offcentered vertically by $(x/2)-(y/2)$. Good to remember for future experimentation.

In the meantime, let's mess with some stroke width. First I'm going to refactor for some clarity (I'm trying to reproduce an effect I got earlier).

Ah, fascinating, I just found a bug: the line defining `rad`

is backward. I'm
blowing up the definition of rad. It should read `rad = Math.PI/180;`

.

Let's rewrite a bit, and get rid of my bad Python habits:

```
function draw() {
const radius = 250;
const rad = Math.PI / 180;
for (let i = 0; i <= 360; i+=2) {
let rads = i * rad;
let xOffset = Math.cos(rads)*radius;
let yOffset = Math.sin(rads)*radius;
line(...ORIGIN,
ORIGIN[0] + xOffset,
ORIGIN[1] + yOffset
);
let s = (1 + Math.sin(i)) * 127.5;
let c = (1 + Math.cos(i)) * 127.5;
strokeWeight(i);
stroke(s, s, c);
}
}
```

`Math.PI / 180`

is the equivalent of $\frac{2 \pi}{360}$.

Well that's a fascinating result. Let's scale it back up to 1920x1080.

Fascinating.

Well, that's it. I just wanted to work through some of the math of programming a circle.