Click on the two screenshots to see the drawings generated in real time (subsequent clicks on the canvas will cause the image to be regenerated). Then read below for another demonstration and more information on the fractal subdivision process used to create the human touch.
The complete code (containing three examples) can be downloaded here:
About the code
Drawing an imperfect circle can be done in more than one way. The basic idea is to use a little trigonometry to sketch out the circle in very small line segments which traverse around a center point, by changing an angle in small steps. A perfect circle is obtained by fixing a radius; imperfection can be added by allowing this radius to vary randomly. Different randomization methods will produce different effects.
But drawing a circle presents a specific problem: we want the circle to end at the same point where we began. If we simply add randomized values to the radius as we draw the curve, after going through 360 degrees we may end up at a different radius than where we began.
So what we would like is a randomized function which has the same value at the beginning and end. We will use this function to determine the varying radius of our imperfect circle as we draw through 0 to 360 degrees. such a function could be constructed in many ways, but an elegant soution is to use a classic fractal-subdivision algorithm.
We start by fixing the beginning and ending y-values of our function to a common value – in the algorithm here I set these to the value 1, but this is an aribtrary value that will be changed at the end after some rescaling. The next step is to put a new point at the middle x-value between these two points, at a randomized y-value. We continually subdivide the curve by repeating this process, adding new points in between existing points. The method is illustrated below, where the first three iterates are shown.
At each step of this process, we allow the curve to change by randomized amounts which are scaled down according to the size of the interval which is being subdivided. This controlling of scale is what gives us a final curve which is randomized, but not wildly fluctuating.
Click on the screenshot below to see an interactive demonstration of this effect, where randomized curves are created with 10 iterations, producing a function with 1024 randomized points.
It’s not completely random
The fractal curve created with this method is generated with random points, but the probability distribution of points is not uniform. To see what I mean, have a look at this image which shows about 2500 of these random curves drawn on top of each other (isn’t this a nice picture in and of itself?). Click on the image to see a larger version. You can see that certain points are favored over others by this method. In particular, the point halfway between the two endpoints is frequently at the maximum or minimum value. We will be mindful of this when drawing our imperfect circles.
Using the fractal function
In the code for these demonstrations, the fractal function created with the method described above is scaled so that the x ranges from 0 to 1, and the output values also range from 0 to 1. The points which define the function are stored as a linked list. A linked list is particularly nice for generating the points: at every iterative step we add new points between existing points, and reset the links between points.
Using the function to create some randomness is fairly straightforward. For example, to vary the radius of an imperfect circle as we traverse through 0 to 360 degrees, we use the points in the linked list to scale the radius in a linear way between a given maximum and minimum radius. Have a look inside the code to see how this is accomplished.
We also have to be mindful of the non-uniform probability distribution of points as described above. To avoid any effect that this might have on our circles, we simply add a randomized phase amount to the drawing angle, so that the beginning angle of a given circle will be different from the beginning angle of a different circle. this ensures that all of the circles we draw in the canvas will be truly random.
There are certainly many other uses for a randomized function of this type. Have fun and add a little randomness to the drawing of some simple shapes. I know I will certainly be playing around with this some more!
Some inspiration for the “wrong way” to draw a circle came from a very nice book by Matt Pearson, entitled Generative Art. I am using a fractal subdivision process here, but Pearson also illustrates the use of random number generators and sinusoids to create variability. Experienced coders will find some of the introduction to programming in this book to be elementary, but the text progresses into more complex ideas and you are likely to learn a new trick or two. The overall focus is on art and it’s a very pleasant read and full of some beautiful pictures.