Image for post
Image for post

Drawing Repetitive Images in Elm

Elm, the programming language created by Evan Czaplicki, is a revolutionary tool for building web apps. But it has other uses as well. In this article, we show how it can be used to produce repetitive images like the one above, left. The idea is simple: start with a basic shape, in this case a pentagon, then repeatedly apply a transformation to the original to build up modified copies. Put the original and all the modified copies together to make the final image. (Code is at GitHub).

Transforming Shapes

To implement this strategy, I used the Kwarrtz/render graphics package, which makes it easy to manipulate SVG images (Scalable Vector Graphics images). We begin by defining the notion of a Point and an AbstractShape:

Thus a Point is a pair of numbers (x,y), just as in high school analytic geometry class. A polygon, naturally enough, is just a list of points, with an extra number to give its angle of inclination with respect to the x-axis. In this way, we can define

We will define some operations on AbstractShapes and then at the last moment render them into SVG images using Kwarrtz/render to get the Nautilus image above.

To begin, we need to be able to translate shapes — move them horizontally and vertically with code like this:

Here we “piped” the value square into a function translate 5 3, thereby moving our shape 5 units to the right and 3 units up. To translate shapes, we need to be able to add one point to another, e.g..

The addPoints functon can be defined like this:

Now it is easy to define translate:

Thus translate is a function which takes two numbers and an AbstractShape as arguments, returning an AbstractShape, while translate 5 3 is a function taking an AbstractShape as argument and returning an AbstractShape. Here we use the fact that in Elm, we can apply a function of n arguments to the first k arguments, obtaining a function of n-k arguments as result. This is partial application, aka currying. It makes life easier.

In a similar manner, we define functions to scale and rotate AbstractShapes.

Repeating Shapes

Now comes the fun part: repeatedly transforming the shapes and building up the composite image. This operation is an example of what mathematicians call an orbit of a map. Let f be a function and let a be a gizmo — a number, a shape, whatever. An orbit of a under f is an n-element list like [a, f(a), f(f(a)), f(f(f(a)), … ]. With an expressive language like Elm or Haskell (for example), it is easy to define a function orbit f n a that does just this. See the code on GitHub. For a simple example, we can calculate a list of powers of two like this:

Here \x -> 2*x is the (anonymous) function that multiplies its argument by 2.

With the orbit function, it is easy to create a list of shapes. First, we create a base shape, like diamond. In the Nautilus figure, we used a pentagon. Then we apply orbit to the base shape using the transformation ((rotate -10) >> (scale 0.95 0.95)). That is, we rotate counterclockwise by 10 degrees, then shrink the shape by a factor of 0.95 in both the x and y directions. The orbit: it has 80 transformed copies.

In the code above,f>>g is the composition of the functions f and g. As an example, let f x = x + 1 and let g x = 2*x. Then (f>>g) 1 == 4. First, we applied f to 1, obtaining 2. Then we applied g to the result, obtaining 4. Pop Quiz: what is (g>>f) 1?

After computing the orbit, we “pipe” the result into the translate 300 300 function so that the image is not squished into the upper left corner of the screen at position (0,0). Finally, we pipe it into a render function. See the code in the Nautilus GitHub repository. It is here that we use the Kwarrtz/render package to turn a list of AbstractShapes into a list of SVG images.

The last step is to put the resulting list of SVG images into a single SVG image and display it:

Here group is function in Kwarrtx/render.

Conclusion

One of the beautiful/powerful aspects of Elm is the ease with which one can turn ideas into code. In the discussion above, we saw this in the definition of Point and AbstractShape, then in the functions that transform AbstractShapes. This is a general feature of Elm, not something confined to graphics programming.

Written by

jxxcarlson on elm slack, http://jxxcarlson.github.io

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store