Alexander Hristov

Cartoon flowers are another type of graphic that can be procedurally generated. Many flowers have the same graphical structure : a central part (kernel) and a repeating structure ("petal") that is rotated around this central part.

The petal itself has horizontal symmetry :

This means that in order to generate a random flower, it is enough to generate half of a petal, then construct the other half symmetrically and finally rotate it a number of times around a central location:

We want the petal to vary more or less gently, without sharp edges and without huge variations. To do that, we'll construct it as a series of connected quads. We'll start with several basic parameters:

- The size of the petal (with will be roughly the size of the flower / 2)
- The "aperture", or how far the starting point of the petal path is apart from the axis of symmetry.
- The number of petal segments

With these parameters, the algorithm proceeds as follows:

- We start at the bottom end of the flower, placing the starting point at the predefined ("aperture") distance from the middle of the image.
- We subdivide the available height into a number of equally-spaced segments.
- For each of these segments, we compute two points for making a quad : one lies on the edge of the area (the black dots in the diagram above), while the other one lies in a random location within the area (the red dots above). While doing this, we store the computed points in a pair of arrays.
- When we have reached the final segment (cp2), we compute a "connecting quad". The connecting quad uses a control point (mp) that is placed exactly on the axis of symmetry. The vertical position of this middle point is determined randomly.
- We now proceed downwards, using the stored point locations to compute their horizontal reflections with respect to the axis of symmetry.
- Finally, we close the path and we have our petal ready:

The above method can be implemented in a few lines using the following Java code:

GeneralPath petal = new GeneralPath(); int flowerSize = 128; int upsize=flowerSize/5; int aperture = rnd.nextInt(5)+5; int cp = rnd.nextInt(5)+3; int[] fx = new int[2*cp+3]; int[] fy = new int[2*cp+3]; petal.moveTo(flowerSize/2-aperture,upsize+flowerSize); fx[2*cp+2] = flowerSize/2-aperture; fy[2*cp+2] = upsize+flowerSize; for (int i = cp; i >= 0; i--) { fx[2*i] = rnd.nextInt(flowerSize/2); fy[2*i] = upsize+flowerSize/cp*i; fx[2*i+1] = rnd.nextInt(flowerSize/2); fy[2*i+1] = upsize+fy[2*i]+rnd.nextInt(flowerSize/cp*(i+1)-flowerSize/cp*i); petal.quadTo(fx[2*i+1],fy[2*i+1],fx[2*i],fy[2*i]); } // Connecting quad petal.quadTo(flowerSize/2,upsize+rnd.nextInt(upsize)-2*upsize,flowerSize-fx[0],upsize); // Compute reflected points for (int i = 0; i <= cp; i++) { petal.quadTo(flowerSize-fx[2*i+1],fy[2*i+1],flowerSize-fx[2*i+2],fy[2*i+2]); } petal.closePath();

Once we have this path, we can proceed to make the flower by rotating the filled path around a central point located at (size/2, size). We can parametrize this process by deciding how many petals we want. Since we generally want all petals spread along the full circumferece, the rotation angle for each one will be 360/petals. Also, it helps if we fill each petal not with a solid color but a gradient oriented diagonally.

Here's the part of the code that builds the flower:

int kernelSize = 20; int petals = 10; Color flowerColor = new Color(0x00AAFF); Color kernelColor = new Color(0x00FFFF); BufferedImage flowerImage = new BufferedImage(2*flowerSize,2*flowerSize,BufferedImage.TYPE_INT_ARGB); Graphics2D gFlower = flowerImage.createGraphics(); double angle = 2*Math.PI/petals; gFlower.translate(flowerSize/2,0); // Draw the petals for (int i = 0; i <= petals; i++) { gFlower.setPaint( new GradientPaint(0,0,flowerColor,flowerSize,flowerSize,new Color(0))); gFlower.fill(petal); gFlower.setColor(new Color(0)); gFlower.draw(petal); gFlower.rotate(-angle,flowerSize/2,flowerSize); } // Draw the kernel if (kernelSize != 0) { gFlower = flowerImage.createGraphics(); gFlower.setColor(new Color(0)); gFlower.fillOval( flowerSize-kernelSize,flowerSize-kernelSize, 2*kernelSize,2*kernelSize); gFlower.setColor(kernelColor); gFlower.fillOval( flowerSize-kernelSize+1,flowerSize-kernelSize+1, 2*kernelSize-2,2*kernelSize-2); }

Here are some results that you can obtain with the above two snippets combined:

The FlowerTutorial.java application included contains the above code and is a fully-working application.

FlowerTutorial.java ( 3 Kb ) |