The inspiration for this investigation comes from the book Creating Symmetry: the Artful Mathematics of Wallpaper Patterns, in particular implementing functions that create "rosette" symmetry - that is there is a central point around which there is an n-fold rotational symmetry.
I am also following an extension of the ideas behind the images generated from cyclic motions. I want to combine technique to ultimately make images that are somewhat different from those in Dr Farris's book.
The basis of the cyclic motion algorithms were closed curves constructed using epicycles: imagine a small wheel rolling around the circumference of a larger wheel, and that is rolling round the circumference of an even larger wheel etc..
We allow the contact point on the largest circle to make a complete circuit (that is, the rotation angle, θ, goes from 0 to 2*π - remember because we are doing proper maths we always measure angles in radians rather than degrees). From our basic trigonometry we know that we can now work out X and Y coordinates of every point on the circumference using X= R*cos(θ) and Y=R*sin(θ), where R is the radius of the circle.
While we are doing this rotation the smaller wheels are rotating at multiples of this basic rotation rate, and our program calculated the curve by increasing θ in small steps and adding up all the sines and cosines using formulas that were equivalent to:
X = R1*cos(θ + P1) + R2*cos(2(θ+P2)) + R3*cos(3(θ+P3)) .....
Y = R1*sin(θ + P1) + R2*sin(2(θ+P2)) + R3*sin(3(θ+P3)) .....
Here, the Rs are the different radii of the wheels, and the Ps (P1, P2, P3 etc.) are phases which allow us to start each of the different wheels already rotated by a certain amount. In fact we can allow ourselves to be even a bit more general and add in sines and cosine where the value of θ is multiplied by negative integers, which just means that the wheel rotates in the anticlockwise rather than clockwise.
That is all stuff that we have already done. Now think about the curve we have drawn. If we wanted to we could mark each point on that curve with a value of θ between 0 and 2*π. In fact, we could take that curve unbend it and lay it out in a straight line. A mathematician says that have created a mapping from the range 0 to 2*π (which we could think of as the points on a straight line starting at 0 and ending at 2*π) to every point on the curve in our canvas. (Mapping in this context really does just mean that we make a connection between all the points in one place out to points in another place. You could imagine drawing faint lines between points on a straight line and corresponding points on our curve. A mathematician says that all the points on our straight line and all the points on the curve are elements of sets and we can create a one-to-one mapping. The idea of a Set is one of the most fundamental concepts in mathematics, including being the basis of counting.)
Now fasten your safety belts, because we are about to put our foot on the accelerator (but you can close your eyes if you wish). The great mathematician Euler showed that we are allowed to write:
eiθ = cos(θ) + i.sin(θ)
where i is the square root of -1 (an imaginary number), so eiθ is a complex number which has real and imaginary parts. (If you know a bit of calculus you would also know that this equations comes as a real surprise, with a bit of wonder - see my Beautiful Maths page.)
We are now going to identify the value of the real part with the X direction in our drawing plane and the imaginary part with the Y direction. If we allow θ to vary from 0 to 2*π it makes eiθ draw out a circle when we separate out the real and imaginary parts and interpret them as X and Y coordinates.
Our epicyclic curve can now be expressed as:
R1*exp(i(θ + P1) )+ R2*exp(2i(θ+P2)) + R3*exp(3i(θ+P3)) ....
So far, nothing has changed apart from the notation. The equation looks simpler (though it carries more meaning) and in fact if we program this summation we have to write exactly the same algorithm as before because computers don't do imaginary numbers, we always have to separate the real and imaginary parts first and treat them separately. (In some computer languages there are built-in types which can hide this stuff behind the scenes for us - but it is still there!) And, let us remember, θ, stands for a real number (its value runs through the respectable range 0 to 2*π). What we are actually doing with this formula is mapping a line running along the Y axis to a closed curve in the X-Y complex plane.
Suppose now we ask what happens if we replace iθ (a completely imaginary number) by a complex number which has real and imaginary parts. Traditionally we use the symbol z for a complex number (which we usually choose to write it as ix+iy with suitable values of x and y). The expression ez then turns out to have a perfectly good mathematical interpretation. Take the next bit on trust if you cannot follow the maths, but this is very standard stuff for maths students (at about the end of high-school maths).
ez = e(x+iy) = ex.eiy = ex.(cos(y) + i.sin(y))
Equations over! What we now have is a generalisation from the previous mapping of a straight line into a curve into a mapping of any point on a 2D surface into points on another 2D surface.
What is so wonderful about that! Nothing really, except that because we are using expressions that can be written as equations using complex numbers (technically they also have to be analytic - but that terminology is really for the maths buffs among you) it turns out they have some very nice properties for creating visual images. (For example, any lines crossing at right angles in the plane we are transforming from will still cross at right angle in the plane we a transforming to. This is what we mean by a conformal map. It is not all: a vast amount of interesting, important and extremely useful 19th century mathematics grew out of complex analysis - but that is university stuff and a different story.)
It can also be interesting to produce non-conformal maps by using complex conjugates of z - that is replace (x+iy) by (x-iy). We loose the property of preserving angles in the transformation, but can gain freedom from some extreme behaviours (such as going off to infinity).
All we need to know now is that we can take our program for creating epicyclic curves and with relatively minor modifications and a re-interpretation of what the numbers it calculates actually mean we can make something completely different and perhaps more exciting. The reason that I have spent so much time explaining this is to demonstrate that in order to understand what a program is trying to do (and how it does it) you must grasp the intentions in the mind of the person who designed the software. Two programs that were constructed against quite different intentions may in fact differ less than might be expected in the algorithms employed: they are distinguished by the meanings to associated with the data going in and the data coming out. That is why it can be very difficult to read a program's source code and work out what it is supposed to be doing.
I also wanted to show why understanding the mathematics behind a program can be important. We used the abstract idea of epicycles to build one program and then used to connections between abstract mathematical ideas such as trigonometry and complex numbers to find a different way of extending the original software in the confident knowledge that the maths guarantees some interesting properties.
As it happens, the modified version of the epicycles program will not look particularly similar to the earlier version, though the algorithms will be essentially similar. I have decided that it is time to introduce some object-oriented programming techniques to simplify the structure of the software and make it align more obviously with the design ideas. It is a great mistake to believe that one saves time by never rewriting what has already been done. In my (very extensive!) experience, the first attempt to get a program running may more-or-less work but usually turns out to be overly complicated and a bit fragile. You only really understand how to do the job properly having struggled with the prototype. Too many programmers stay with this - and spend the next ten years (or someone does) applying sticking plaster to keep it from falling apart. Throw the prototype away! Build the production version to production standards! I find that this is still good advice even when working with no one to satisfy but myself. I get less frustrated and move faster by securing the foundations before building up.
Here it is: the algorithm I initially implemented was not the one I originally intended to write. It is doing something related but different. I had assumed I had understood the problem and understood how it should be translated into a program. I did not take enough time and my assumptions were incorrect! (I include the cautionary tale because this type of problem is one of the most common reasons why companies waste time and money building software that never works properly. I should know by now! But having left my nuclear engineering hat behind I relaxed my previously rigorous processes a little too much.) OK, I realised that I had gone wrong before I had wasted much time. In fact, although I had taken a wrong track, I thought it would be interesting to see where it would actually come out, and I was not entirely displeased with the results. This is something that never happened when I was using computer to do physics: if I got the algorithm wrong the software would simulate un-physical events, and that is of no use to anyone. In this case, I was looking for a transformation that would produce an interesting visual effect, and I certainly got that.
Let me see if I can explain my mistake and why it was easy to make. What I wanted to do was to take a position (and individual pixel) on the target plane (my final image) and apply my mapping formula to identify a pixel on the source plane which I would use to define the colour. What I actually started to do was to take a position on the source plane, identify its colour, and then apply my mapping formula to identify a position on the target plane to which I applied that colour.
This turned out to be a many-to-one mapping, in the sense that some pixels in the target plane were left uncoloured and others had their colour set several times. This was the point where I realised I had gone wrong.
My diversion from the original intention at this point was to see if there was a simple method of filling in the unset pixels. I just wanted to see what happened! Hence I just drew a line from the last pixel to the set to the current pixel using the current colour. That is what you see in the images on the previous page and in those to the right. (These represent two different stages of development of the mapping program.)
The images in the top image slider to the right show some of the results based on a source image constructed as a simple grid of primary colours and black lines. (I chose the constructed source partly to provide a method of checking that the algorithms were working. It is much easier to test a program when you know what you should expect at the output. One of the well-known properties of a "conformal map" is that lines that cross at right angles in the original will still cross at right angles in the transformed results.)
The bottom image slider starts with the same source image and follows something closer to the original intention. In fact, my "correct" implementation of my intended transformation does not, in my opinion, produce nearly such interesting effects when applied to these simple patterns, which come out as too predicable and ordered. In contrast, when I use an original photograph as the source the "correct" approach generates the better results. I increasingly think that good art emerges from a fine balance between order and chaos. In one case too much order in the source requires less order in the transformation in order to create visual interest; in the other case, the less ordered original photograph needs to have some symmetry imposed to introduce visual interest.
My original intentions will be fully explored below, but this image Gallery shows some of the results from exposing simple ordered source images to my "disordering" algorithm.
Transformation of Original Photographs
My original inspiration was indeed at attempt to follow some of the methods (using "rosette" functions) outlined in early chapters of Creating Symmetry: the Artful Mathematics of Wallpaper Patterns and now we are ready to actually do the job.
The transformation formula used in this case is based on a polynomial expression, simple in terms of its complexity, complex in the technical sense of being a polynomial employing complex numbers. I have programmed an expression of the form:
z' = .... A-2/z2 + A-1/z + A0 + A1z + A2 z2 + A3z3......
where the .... dots mean "it goes on and on for as far as you like". In practice "as far as I like" involves no more than about 10 terms, and at any one time I would choose to make only at most three or four of the "An" values non-zero. This polynomial expression is analytic (except where it goes to infinity) so the transformation has some nice properties. How do we use this? We iterate over the pixels in what is to be our output image and treat each pixel coordinate as the value of a complex number in the Argand plane. Now feed this number into the express above and use the output value of z to find a pixel in the original source photograph.
What do we do if the output of our transformation function goes outside the boundary of the source image? Frank Farris sets the pixel to black, which produces some striking results, throwing the generated "rosette" into the visual foreground. I set up my program to explore some alternative options. Most of the images on this web site extend the source image plane to infinity by repeated reflection the image in its boundary line. When we combine this with use of the 1/z powers can produce results in which the inside and the outside of the image are swapped over. (On the other hand, an artist friend of mine prefers some of the unpredictable linear patterns which are generated when I use the nearest boundary pixel.)
Warning! More advanced skippable maths stuff! It can be shown (this is mathematician-speak for "I can't be bothered to explain just now - but it's true.") that the right choices of the Ans can either create certain predictable over-riding symmetries in the output pattern, or not according to one's desires. (See "Creating Symmetry" for the mathematical details if you wish - but the "n" values all have to reduce to the same number when expressed as modulus-m, where m will define the symmetry observed in the final results). All that will not mean much to you unless you understand the mathematical terms, but as I have previously pointed out pattern and symmetry are built into maths at a very fundamental level sometimes in ways that are not easy to discuss in purely visual terms, so mathematicians have invented much more abstract ways of handling it. We can give visual interpretations to some of these ideas, but the abstract foundation is still there.
Because the strict conformal properties are not absolutely essential to what I produce (as they are when one uses conformal maps to solve complex physics problems!) I have also experimented in variations of the expression (for example by dividing or multiplying the whole expression by |z|p where p is some value with which I can experiment). These variations can produce useful modifications where transformation of parts of the image would otherwise become excessively large or small too quickly. Apologies to the mathematical purists - but I am motivated by the images which result rather than attempts to illustrate mathematical principles.
From a purely artistic viewpoint, I find that I like to create a symmetrical image - and then do something else to break the visual symmetry, which I find becomes someone tedious if over-done. It is a matter of trying to tread that fine line between order and chaos. My transformation functions therefore allow a bit of the original source image to be added to the mix (by this I mean that Ao in the polynomial expression above may be non-zero.)
Some of the results are shown in the gallery "Complex Mapping Using Photographs as Sources" or some in the image slider below.
This link will let you view and download a program that performs similar photographic manipulations. (It differs from the program used to produce some of the Gallery images in that instead of powers of (1/z) it uses powers of the complex conjugate of z. This is slightly better behaved than 1/z functions because there are no outrageous infinities to deal with, though it does create somewhat different effects when the conjugates are added into the mix. Nor do these functions strictly preserve the "conformal" property - but whatever produces and interesting image is OK by me. (You can take is as an exercise for the reader to go back to using 1/z. It is a two-line change. You will have to read and understand the program to do this - which is the point of the whole exercise.) I choose to include this version of the program because it includes a number of useful features to provide more control over the transformation that go beyond those in the earlier strictly conformal transformations.
One of the new features save a "csv" file describing the parameters used to generate the image. This file can be "replayed" to regenerate exactly the same image - which you might choose to compute at a higher resolution having found something that particularly pleases. The new program version can also automatically play through a sequence of transformations in which control parameters vary slightly through time. I have experimented with using several hundred such images to produce a video. (The open source utility ffmpeg will stitch still images into a video.) See my description of producing video clips.
So far, I have just used one "rosette" centre to transform the image.
It is natural to wonder what would happen if instead of just one power series expanding from the centre of the image, we create our mapping function using more than one expansion centre.
In a further modification to my software, I have given it the option to calculate the sum of either four or six separate series. (In the case of the fourfold expansions, the centres can be positioned either as a rectangle or a diamond, with the overall size controlled by a mouse click. A mouse click can also be used to rotate the orientation of the six-fold centres.)
Note that the overriding symmetry created by use of this option can have interesting interactions with the choice of underlying rosette symmetries. (For example, one might expect that an underlying four-fold rosette symmetry would work with the four-centre overlying symmetry, but a five-fold rotation would break some overt aspects of the overall symmetric appearance.)
As I have noted previously, I generally find subtle symmetries and slightly broken symmetries give more visual interest than strict symmetry. As a further twist, I allow a progressive phase shift to be introduced to each rosette centre, providing more opportunities to break the symmetry in non-obvious ways.