JavaScript: Epicycloid Negentropy

Radu B. Gaspar
4 min readMay 8, 2019

--

…order from randomness

You might have heard of an epicycloid before and if you haven’t, you’ve surely seen one at some point in your life… regardless I’ll spare you a Google search:

Epicycloid — a curve traced by a point on the circumference of a circle rolling on the exterior of another circle.

You’ll usually find them in conjunction with Fourier series or transforms but we’re not going to talk about that.

The definition is simple enough… let’s build a system which can handle the following requirements:

  • allow chaining of multiple epicycles
  • allow multiple simultaneous tracers (let’s think of them as coloring crayons on a piece of paper)
  • generate epicycles by tweaking a handful of variables with random values within a given range
  • add ability to save and restore any generated system
  • use the previous ability to create a few presets and finally,
  • add ability to hide the tracer — just to see the resulting drawing a bit better

Since your time is precious, I think it’s easier to let you see the finished product… you’ll find the logic behind the building process below.

I wanted to see the shape being generated as well as the intricacies of the entire mechanism as an animation so using the canvas and requestAnimationFrame was the logical choice.

We’ll use a vector to represent our tracer and there are two ways we could represent it:

  • by providing a starting point and an end point
  • by providing a starting point, the magnitude (size) of the vector and an angle

We’ll go with the second version, because we can easily control the rotation with the angle and that’s what we need.

Vector2D representation

In the image above we have:

  • s — the starting point
  • the green line represents the angle in degrees
  • the black line represents the vector magnitude rotated by the angle
  • the red line represents the magnitude with angle = 0
  • e — the end point — it will be calculated every time we change the angle as it will serve as the starting point of the next vector in the chain.

With that we can build our Vector2D class as follows:

We can also add some additional properties on this class, like:

  • isPencil — a boolean to indicate if the end point of this vector should be traced on the canvas
  • color — the color used to draw the end point if isPencil === true
  • rotationStep — indicates the amount by which the angle will change on every cycle

Please notice the rotation setter; it’s needed to convert the provided angle value (which is in degrees) to radians and also ensures that the angle, stored on the instance, never exceeds 360 degrees.

Mechanism initialization

Now that we have the main class, we’ll need a way to initialize the entire mechanism. This method will either use a provided array of Vector2D instances or generate a random set of instances.

You’ll see above that we’re storing a clone of each vector in the initState array. We’re doing this so we can retrieve that data later and save it as a preset if the mechanism generates a shape we like. That preset can be then passed back into the handleInit function in order to redraw that shape.

The rest of the code is pretty much self-explanatory, the data.map() will either use the provided arr or an array with vectorCount empty slots.

How do we draw?

We’ll have 2 canvases for this:

  • one will have our tracing mechanism — we’ll clear this one on every cycle as we want to see a snapshot of the mechanism’s position on every frame
  • the other will have the drawing — we’ll fade this one out by a really small amount on every cycle as we want to see the full drawing

In actuality, only the first vector in the mechanism has a start point, all others are automatically placed at the end point of the previous vector.

Combine that with the fact that each vector has a random size (magnitude), starting angle and rotation step and you’ll have quite an interesting drawing apparatus.

A preset like the following:

[{"sx":450,"sy":400,"size":64,"rotationStep":-2},{"size":37,"color":"#d233c9","isPencil":true,"rotationStep":5}]

Will produce a shape like this:

Want to generate a random mechanism with n vectors? Nothing simpler, just call handleInit([...Array(n)]) where n > 0 . Pretty cool wouldn’t you say?

You can review the full code here. I encourage you to tweak it: change the ranges, add random starting angles, play with positioning, make all of the vectors pencils and see what crazy shapes you get.

A few improvements that could be made:

  • preset optimization — they currently contain a lot of unnecessary data
  • adjust canvas scale to fit large drawings — if you go wild with the ranges, you’ll draw outside the canvas
  • perhaps an export as SVG since some of them are so symmetrical they could be used as icons or logos

Happy coding!

How many claps does this article deserve?

If you’ve enjoyed this article, feel free to hit that clap button until it gets tired or share with a friend (you know you want to!).

--

--