A fractal shape generated by triangles onto triangles onto triangles...

To begin drawing a Koch snowflake, draw an equilateral triangle.

To continue drawing a Koch snowflake, trisect every line segment of the shape you have, and draw an equilateral triangle on the middle third of every line segment, pointing outward.

To continue drawing a Koch snowflake, trisect every line segment of the shape you have, and draw an equilateral triangle on the middle third of every line segment, pointing outward...

What you'd have, if you kept doing this for an infinite time, is a Koch snowflake. Since the Nth step requires that you draw 3(n-1) triangles, you're likely to get tired well before the heat death of the universe.

But try it for a few steps: first a triangle, then the next step you've drawn a Star of David, then you've drawn something with more points, and then you can see basically what a Koch snowflake looks like.

Yet another recipe for making a fractal at home. This one will require the use of an eraser, or the background colour. (See Sierpinski triangle for other ingredients.) This one, however, will be deterministic.

Take a straight line. Divide it into three equal parts. Draw an equilateral triangle using the central part as the base of the triangle. Erase the base of the triangle. You now have something which looks (roughly) like this: _/\_ Now do what you did to your original line to every straight line in the figure. Iterate.

In L-system and turtle graphics terms, this might be written as a system with {f,l,r} as the alphabet (interpreting `f' as forward, `l' as turning left 60 degrees, `r' as turning right 60 degrees), f -> flfrrflf as the only rule, and `frrfrrfrr' as the initial string.

You can always start with an equilateral triangle in the first place, in which case the second generation of the iterated function system will be a star of David.

The Koch snowflake is an example of a space-filling curve.

This is a Java applet based off of android's C OpenGL implementation of a Koch snowflake (node_id=552873). To use it:

  1. make sure you have a JDK 1.1 or higher-compatible compiler (one source is java.sun.com)
  2. copy the HTML part into a file like kochdemo.html
  3. copy the Java part into a file named KochSnowflake.java
  4. compile the Java applet: javac KochSnowflake.java
  5. view the applet: appletviewer kochdemo.html   or   open kochdemo.html in your Java-enabled web-browser
The Java source should be pretty readable, but feel free to /msg me if you have any questions.


kochdemo.html


<html>
<head><title>Koch Snowflake</title></head>
<body>
Koch Snowflake demo applet<br />
<applet code="KochSnowflake.class" width="500" height="600">
You need Java 1.1.
</applet>
</body>
</html>


KochSnowflake.java

/*KochSnowflake.java
 * Copyright 2000 by Nathan Bronecke
 * This is based off of a program written in C for OpenGL by android.
 * android's version is available at
 * http://www.everything2.com/index.pl?node_id=552873
 * http://www.everything2.com/index.pl?node=
 * Reasons+for+wanting+to+write+a+java+program+that+displays+a+snowflake+made+out+of+triangles
 */
//following is a sample HTML page to use to view this applet
/*
<html><head><title>Koch Snowflake</title></head><body>
Koch Snowflake demo applet<br />
<applet code="KochSnowflake.class" width="500" height="600">You need Java 1.1.</applet>
</body></html>
*/

import java.awt.BorderLayout;
import java.awt.Button;
import java.awt.Checkbox;
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Label;
import java.awt.Panel;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.TextField;

/**
 * Applet implementation of the Koch snowflake.
 * This isn't threaded, so once you start drawing it,
 * you have to wait for it to finish drawing to change the settings.
 * @version created: 2000.06.05.n1; updated: 2000.06.08.n4
 * @author  Nathan Bronecke
 */
public class KochSnowflake
    extends java.applet.Applet
    implements java.awt.event.ActionListener
{

    private final static int DEPTH_DEFAULT = 4;
    private final static int DEPTH_MAX = 12;	//gets pointless over 8

    private final static double cos60 = 0.5;	//value of cos(60 degrees)
    private final static double sin60 = Math.sqrt(3)*0.5;	//value of sin(60 degrees)
    private final static double value2root3over3 = Math.sqrt(3)*2/3;

    private int curDepth = DEPTH_DEFAULT;

    private boolean doLines = true;
    private boolean doDots = false;
    private boolean doBoundingRect = false;

    private final Button bDraw = new Button("Draw");
    private final TextField tfIterations = new TextField("" + DEPTH_DEFAULT,3);
    private final Checkbox cbLines = new Checkbox("Lines",doLines);
    private final Checkbox cbDots = new Checkbox("Dots",doDots);
    private final Checkbox cbBoundingRect = new Checkbox("Bounding Rectangle",doBoundingRect);

    private boolean infoShown = false;

    /** component that displays the snowflake */
    private final Panel pGfx = new Panel() {
        /**
         * @version created: 2000.06.06.n2; updated: 2000.06.06.n2
         */
        public void paint(Graphics g) {
            drawPicture(g,new Rectangle(this.getSize()));
        }
    };

    /**
     * @version created: 2000.06.05.n1; updated: 2000.06.07.n3
     */
    public void init() {
        Panel pControls = new Panel();
            pControls.setLayout(new FlowLayout());
            pControls.add(bDraw);
            pControls.add(new Panel());	//just a spacer
            pControls.add(tfIterations);
            pControls.add(new Label("Iterations"));
            pControls.add(cbLines);
            pControls.add(cbDots);
            pControls.add(cbBoundingRect);

        setLayout(new BorderLayout());
        add(pGfx,BorderLayout.CENTER);
        add(pControls,BorderLayout.SOUTH);

        bDraw.addActionListener(this);
    }


    /**
     * Draws one line segment.
     * @param   depth	current recursion depth; when 0, draws a line and just returns
     * @version created: 2000.06.06.n2; updated: 2000.06.06.n2
     */
    public void drawSegment(Graphics g, Point a, Point b, int depth) {

        //done recursion
        if(depth==0) {
            if(doLines)
                g.drawLine(a.x,a.y, b.x,b.y);
            if(doDots)
                g.drawOval(a.x,a.y, 1,1);

        //compute next line parts
        } else {

            //compute points
            final Point distance = new Point( (b.x-a.x)/3, (b.y-a.y)/3 );
            final Point pa = new Point( a.x+distance.x, a.y+distance.y);
            final Point pb = new Point( b.x-distance.x, b.y-distance.y);
            final Point pTip = new Point(
                pa.x + (int)(distance.x*cos60 + distance.y*sin60),
                pa.y + (int)(distance.y*cos60 - distance.x*sin60)
            );

            //draw line segments
            final int newDepth = depth-1;
            drawSegment(g, a,pa ,newDepth);
            drawSegment(g, pa,pTip ,newDepth);
            drawSegment(g, pTip,pb ,newDepth);
            drawSegment(g, pb,b ,newDepth);
        }

    }

    /**
     * Draws a koch snowflake on the given graphics surface within the given bounds
     * using settings set by widgets. Note that the settings are only updated when
     * the "Draw" button is pressed.
     * @version created: 2000.06.06.n2; updated: 2000.06.08.n4
     */
    public void drawPicture(Graphics g, Rectangle bounds) {

        //fill in background
        g.setColor(Color.white);
        g.fillRect(bounds.x,bounds.y, bounds.width,bounds.height);

        //draw box around edge of drawing area
        if(false) {
            g.setColor(Color.blue);
            g.drawRect(bounds.x,bounds.y, bounds.width-1,bounds.height-1);
        }

        //way too small to show
        if( (bounds.width<2) || (bounds.height<2) )
            return;
        //nothing to show
        if(!doLines && !doDots)
            return;

        //find working width and height
        //
        //	if we're assuming starting triangle is equilateral (if it isn't
        //	equilateral, things look ugly), if this is the original shape:
        //	   _______
        //	   \     /
        //	    \   /
        //	     \ /
        //	      ^
        //	and this is second shape (without the inside lines removed) :
        //	                _
        //	      v          |
        //	   __/_\__       |
        //	   \     /       | height
        //	  /_\   /_\      |
        //	     \ /         |
        //	      ^         -+
        //	 |_________|
        //	    width
        //
        //	then the width is equal to 2 root 3 over 3, that is,
        //	(2 times the square root of 3) divided by 3
        //	(this ratio can be derived using geometry of 30-60-90 triangles)
        //	Using this, this part determines the maximum height and
        //	width to use in a given viewing rectangle.
        //
        //	(this formula stuff by NPB)
        //
        final double w,h;
        if(bounds.height < (int)(bounds.width * value2root3over3)) {
            //height is limiting dimension
            h = bounds.height;
            w = h / value2root3over3;
        } else {
            //width is limiting dimension
            w = bounds.width;
            h = w * value2root3over3;
        }

        //determine starting points
        //
        //	 1 _______ 2
        //	   \     /
        //	    \   /
        //	     \ /
        //	      ^ 3
        //
        //	horizontal and vertical location is also centered within the given viewing rectangle
        //
        final int top = bounds.y + (int)((bounds.height-h)*0.5 + (h*0.25));
        final Point p1 = new Point(bounds.x + (int)((bounds.width-w)*0.5), top);
        final Point p2 = new Point(bounds.x + (int)((bounds.width+w)*0.5), top);
        final Point p3 = new Point(
            bounds.x + (bounds.width>>1),
            bounds.y + (int)((bounds.height+h)*0.5)
        );

        //draw snowflake's bounding box
        //	the right/bottom edges may be off a little bit, due to rounding and/or
        //	the way different JVM implementations deal with java.awt.Graphics
        if(doBoundingRect) {
            g.setColor(Color.gray);
            g.drawRect(
                bounds.x+(int)((bounds.width-w)*0.5),
                bounds.y+(int)((bounds.height-h)*0.5),
                (int)w-1,(int)h-1
            );
        }

        //draw recursive line segments
        g.setColor(Color.black);
        drawSegment(g, p1,p2, curDepth);
        drawSegment(g, p2,p3, curDepth);
        drawSegment(g, p3,p1, curDepth);

    }

    /**
     * @version created: 2000.06.06.n2; updated: 2000.06.07.n3
     */
    public void actionPerformed(java.awt.event.ActionEvent ae) {
        java.lang.Object o = ae.getSource();

        if(o==bDraw) {
            if(!infoShown) {
                infoShown=true;
                System.out.println(
                    "\nKochSnowflake source available at\n" +
                    "http://www.everything2.com/index.pl?node_id=598735\n"
                );
            }
            try {
                curDepth = Integer.parseInt(tfIterations.getText());
            } catch(NumberFormatException e) {
                curDepth = DEPTH_DEFAULT;
            }
            if(curDepth < 0)
                curDepth = 0;
            else if(curDepth > DEPTH_MAX)
                curDepth = DEPTH_MAX;
            tfIterations.setText("" + curDepth);
            doLines = cbLines.getState();
            doDots = cbDots.getState();
            doBoundingRect = cbBoundingRect.getState();
            drawPicture(pGfx.getGraphics(),new Rectangle(pGfx.getSize()));
        }
    }

}

        /\
       /  \
      /    \
     /      \
    /        \
   /          \
  /            \
 /              \
/________________\
Perimeter = 3

        /\
       /  \
______/    \______
\    /      \    /
 \  /        \  /
  \/          \/
  /            \
 /              \
/________________\
      \    /
       \  /
        \/
Perimeter = (4/3)1 * 3

       _/\_
      |/  \|
__/\__/    \__/\__
\ ¯¯ /      \ ¯¯ /
|\  /        \  /|
 ¯\/          \/¯
 _/            \_
|/              \|
/________________\
¯ \/  \    /  \/ ¯
      |\  /|
       ¯\/¯
Perimeter = (4/3)2 * 3
       .xx.
      |/  \|
..xx..x    x..xx..
x ¯¯ /      \ ¯¯ /
x\  /        \  /x
 ¯x/          \x¯
 x/            \x
|/              \|
x________________x
``xx``\    /``xx`¯
      |\  /|
       `xx`
Perimeter = (4/3)n * 3
Where n is the current iteration.

Since fractals iterate infinitly, the perimeter of a koch snowflake is infinite.

Log in or register to write something here or to contact authors.