Newsletter sign-up
View all newsletters

Enterprise Java Newsletter
Stay up to date on the latest tutorials and Java community news posted on JavaWorld

Sponsored Links

Optimize with a SATA RAID Storage Solution
Range of capacities as low as $1250 per TB. Ideal if you currently rely on servers/disks/JBODs

Java Fun and Games: Explore the geometry of nature

Journey into the realm of fractals

  • Print
  • Feedback

Page 4 of 7

Use this equilateral triangle to visualize the calculations for the Koch snowflake.

Figure 3. Use this equilateral triangle to visualize the calculations for the Koch snowflake.

After studying Figure 3, you should be able to understand a.x = A.x-(A.x-B.x)/3 (equivalent to double x4 = x1*2/3+x2*1/3;), a.y = A.y-(A.y-B.y)/3 (equivalent to double y4 = y1*2/3+y2*1/3;), b.x = A.x-2*(A.x-B.x)/3 (equivalent to double x5 = x1*1/3+x2*2/3;), and b.y = A.y-2*(A.y-B.y)/3 (equivalent to double y5 = y1*1/3+y2*2/3;).

For double x6 = (x4+x5)/2+(y4-y5)*SIN60; and double y6 = (y4+y5)/2+(x5-x4)*SIN60;, (x4+x5)/2 and (y4+y5)/2 identify the removed middle line segment's midpoint, and (y4-y5)*SIN60 and (x5-x4)*SIN60 move the midpoint along an imaginary line perpendicular to the midpoint. Note that the SIN60 multiplication scales the line to prevent an exaggerated size in the resulting equilateral triangle.

Sierpinski triangle

In 1915, Polish mathematician Waclaw Sierpinski described a fractal that is an example of a self-similar set. This fractal is known as the Sierpinski triangle, but is also referred to as the Sierpinski gasket. The algorithm below recursively generates the Sierpinski triangle:

  1. Start with an equilateral triangle whose base is parallel to the horizontal axis. (In practice, any triangle with any orientation will work.)
  2. Shrink the triangle by 50%, make three copies, and translate the copies so that each triangle touches the other two triangles at a corner.
  3. Assume that each shrunken copy is the original equilateral triangle and apply the previous steps to each copy.

As you recursively repeat the above steps, the equilateral triangle morphs into a set of nested triangles. Figure 4 reveals the original equilateral triangle on the left, the fractal after a single iteration in the middle, and the fractal after two iterations on the right.

The area of the Sierpinski triangle tends to zero as the iterations tend to infinity -- the triangular area between the three triangles is not part of the Sierpinski triangle's area.

Figure 4. The area of the Sierpinski triangle tends to zero as the iterations tend to infinity -- the triangular area between the three triangles (see the algorithm's second step) is not part of the Sierpinski triangle's area. Click the thumbnail to view a full-sized image.

The Sierpinski triangle generator algorithm is described by an STFractalGenerator class. Listing 5 is an excerpt of the class. (See the Resources section for the Sierpinski Triangle applet, ST.java and ST.html.)

Listing 5. The STFractalGenerator class

 
class STFractalGenerator implements FractalGenerator {
     private final static int MAX_DEPTH = 5;

     private final static int OFFSET = 10;

     private Line2D line = new Line2D.Double (0.0, 0.0, 0.0, 0.0);

     private Stroke stroke = new BasicStroke (2.0f, BasicStroke.CAP_ROUND,
                                              BasicStroke.JOIN_ROUND);

     public void generate (Graphics2D g, int depth, int width, int
height)
     {
        st (width/2, OFFSET, OFFSET, height-1-OFFSET, width-1-OFFSET,
            height-1-OFFSET, depth, g);
     }

     public int maxDepth ()
     {
        return MAX_DEPTH;
     }

     private void st (int x1, int y1, int x2, int y2, int x3, int y3, int depth,
                      Graphics2D g)
     {
        if (depth <= 0)
        {
            g.setStroke (stroke);
            line.setLine (x1, y1, x2, y2);
            g.draw (line);
            line.setLine (x2, y2, x3, y3);
            g.draw (line);
            line.setLine (x3, y3, x1, y1);
            g.draw (line);
        }
        else
        {
            int x4 = (x1+x2)/2;
            int y4 = (y1+y2)/2;
            int x5 = (x2+x3)/2;
            int y5 = (y2+y3)/2;
            int x6 = (x1+x3)/2;
            int y6 = (y1+y3)/2;

            st (x1, y1, x4, y4, x6, y6, depth-1, g);
            st (x4, y4, x2, y2, x5, y5, depth-1, g);
            st (x6, y6, x5, y5, x3, y3, depth-1, g);
        }
     }
}

The generate() method chooses the original triangle's endpoints so that the triangle occupies the entire display area except for a small border. It makes a single call to the private st() method, to calculate the midpoint of each triangle line segment. The coordinates of these midpoints are combined with st()'s coordinate arguments to form three new triangles.

  • Print
  • Feedback

Resources