/** This program generates the von Koch curve as a demonstration to explore a fractal. It uses the Graph2D package by Leigh Brookshaw. The program was written by John Bowen as part of an undergraduate research project in the group of Mark Paul in the Mechanical Engineering Department at Virginia Tech. @author John Bowen @version March 2009 */ import java.awt.*; import java.applet.*; import java.net.URL; import graph.*; import java.awt.event.*; import javax.swing.*; import javax.swing.event.*; import java.text.*; import java.lang.*; public class vonkoch extends Applet implements ActionListener { G2Dint graph; DataSet data1, data2; Axis xaxis; Axis yaxis_left; Axis yaxis_right; URL markerURL; double length, tlength, area, tarea; JPanel stuff, select; JButton advance, restart, biter, breset; int i, j; double d[], x[]; JLabel leng, iteration, ar, bdim; int iter = 0; JRadioButton lengthb, areab, lineb; int bci = 1; //bci used in BoxCount, the number of box divisions public void init() { x = new double[4]; length = 1; tlength = 1; area = 0; tarea = 0; /* ** Get the passed parameters */ String mfile = getParameter("MARKERS"); /* ** Create the Graph instance and modify the default behaviour */ graph = new G2Dint(); graph.drawzero = false; graph.drawgrid = false; graph.borderTop = 50; /* ** Load a file containing Marker definitions */ try { markerURL = new URL(getDocumentBase(),mfile); graph.setMarkers(new Markers(markerURL)); } catch(Exception e) { System.out.println("Failed to create Marker URL!"); } setLayout( new BorderLayout() ); add("Center", graph); /* ** Calculate the first data Set. */ x[0] = 0; x[1] = 0; x[2] = Math.sqrt(12); x[3] = 0; data1 = graph.loadDataSet(x,2); data1.linestyle = 1; data1.linecolor = new Color(0,125,0); xaxis = graph.createXAxis(); xaxis.attachDataSet(data1); xaxis.setTitleText(" "); yaxis_left = graph.createYAxis(); yaxis_left.attachDataSet(data1); yaxis_left.minimum = -.25; yaxis_left.maximum = 1.25; yaxis_left.setTitleText(" "); select = new JPanel(new GridLayout(6,1)); select.add(new JLabel("Plot Select")); ButtonGroup sel = new ButtonGroup(); lineb = new JRadioButton("von Koch curve"); lineb.addActionListener(this); lineb.setSelected(true); sel.add(lineb); select.add(lineb); lengthb = new JRadioButton("Length"); lengthb.addActionListener(this); sel.add(lengthb); select.add(lengthb); areab = new JRadioButton("Area"); areab.addActionListener(this); sel.add(areab); select.add(areab); add("West", select); stuff=new JPanel(new GridLayout(6, 1)); iteration = new JLabel("Iteration 0"); stuff.add(iteration); stuff.add(new JLabel("")); advance = new JButton("Next"); advance.addActionListener(this); stuff.add(advance); restart=new JButton(" Restart "); restart.addActionListener(this); stuff.add(restart); leng = new JLabel("Length = 1"); stuff.add(leng); ar = new JLabel("Area = 0"); stuff.add(ar); biter = new JButton("Box Iteration"); biter.addActionListener(this); stuff.add(biter); breset = new JButton("Box-Count Restart"); breset.addActionListener(this); stuff.add(breset); bdim = new JLabel("D = "); stuff.add(bdim); add("East", stuff); } public void Adv() { iter++; d = new double[6*(x.length/2 - 1) + x.length]; j = 0; area = length*length/6/Math.sqrt(12); // 1/2base(length/3) * height(length/sqrt(12)) length = length/3; for (i = 0; i < (x.length - 2); i+=2, j+=8) { d[j] = x[i]; d[j+1] = x[i+1]; d[j+2] = (x[i+2] - x[i])/3 + x[i]; d[j+3] = (x[i+3] - x[i+1])/3 + x[i+1]; //perpendicular/length to normalize times length/sqrt(12) so length simplifies d[j+4] = -(x[i+3] - x[i+1]) / Math.sqrt(12) + (x[i+2] - x[i])/2 + x[i]; d[j+5] = (x[i+2] - x[i])/Math.sqrt(12) + (x[i+3] - x[i+1])/2 + x[i+1]; d[j+6] = (x[i+2] - x[i])*2/3 + x[i]; d[j+7] = (x[i+3] - x[i+1])*2/3 + x[i+1]; d[j+8] = x[i+2]; d[j+9] = x[i+3]; tlength = tlength + length; tarea = tarea + area; } x = new double[ d.length ]; for (i = 0; i < d.length; i++) { x[i] = d[i]; } leng.setText("Length = "+tlength); iteration.setText("Iteration "+iter); ar.setText("Area = "+tarea); graph.detachDataSets(); data1 = graph.loadDataSet(x, x.length/2); data1.linestyle = 1; data1.linecolor = new Color(0,125,0); yaxis_left.attachDataSet(data1); yaxis_left.setTitleText(" "); yaxis_left.minimum = -.25; yaxis_left.maximum = 1.25; xaxis.attachDataSet(data1); xaxis.setTitleText(" "); graph.repaint(); } public void plotLength() { d = new double[40]; d[0] = 0; d[1] = 1; j = 1; for (i = 2; i < 40; i+=2) { d[i] = j; d[i+1] = Math.pow(4.0/3.0, j); j++; } graph.detachDataSets(); data1 = graph.loadDataSet(d, 20); data1.linestyle = 1; data1.linecolor = new Color(125,0,0); yaxis_left.attachDataSet(data1); yaxis_left.setTitleText("Length"); xaxis.attachDataSet(data1); xaxis.setTitleText("Iteration"); graph.repaint(); } public void plotArea() { d = new double[20]; d[0] = 0; d[1] = 0; j = 1; for (i = 2; i < 20; i+=2){ d[i] = j; d[i+1] = d[i-1] + 1.0/6.0/Math.sqrt(12)*Math.pow(4.0/9.0, j-1); j++; } graph.detachDataSets(); data1 = graph.loadDataSet(d, 10); data1.linestyle = 1; data1.linecolor = new Color(125,0,0); yaxis_left.attachDataSet(data1); yaxis_left.setTitleText("Area"); xaxis.attachDataSet(data1); xaxis.setTitleText("Iteration"); graph.repaint(); } public void restartf() { x = new double[4]; length = 1; tlength = 1; area = 0; tarea = 0; x[0] = 0; x[1] = 0; x[2] = Math.sqrt(12); x[3] = 0; graph.detachDataSets(); data1 = graph.loadDataSet(x, x.length/2); data1.linestyle = 1; data1.linecolor = new Color(0,125,0); yaxis_left.attachDataSet(data1); yaxis_left.minimum = -.25; yaxis_left.maximum = 1.25; yaxis_left.setTitleText(" "); xaxis.attachDataSet(data1); xaxis.setTitleText(" "); graph.repaint(); iter = 0; leng.setText("Length = 1"); ar.setText("Area = 0"); iteration.setText("Iteration 0"); bci = 1; bdim.setText("D = "); } public void boxCount() { boolean box[][] = new boolean[bci][bci]; for (i = 0; i < bci; i++) { //initialize the box array to all false for (j = 0; j < bci; j++) { box[i][j] = false; } } for (int bx = 0; bx < bci/2; bx++ ) { //for each verticle box-edge (x-values of each edge); half because symetric for (i = 0; i < x.length/2; i+= 2) { //for each vertex if ( (bx*3.464101615/bci >= x[i] && bx*3.464101615/bci <= x[i+2]) || (bx*3.464101615/bci <= x[i] && bx*3.464101615/bci >= x[i+2]) ) { //if the line segment formed with this beginning point contains the bx-value double y = (x[i+3] - x[i+1])/(x[i+2] - x[i])*(bx*3.464101615/bci - x[i]) + x[i+1]; //linearly interpolate the y-value of this segment for bx value box[bx][(int)(y/3.464101615*(double)bci)] = true; //mark the box that holds the values box[bci - 1 -bx][(int)(y/3.464101615*(double)bci)] = true; //mark the symetric box } if ( ((bx+1)*3.464101615/bci >= x[i] && (bx+1)*3.464101615/bci <= x[i+2]) || ((bx+1)*3.464101615/bci <= x[i] && (bx+1)*3.464101615/bci >= x[i+2])) { double y = (x[i+3] - x[i+1])/(x[i+2] - x[i])*((bx+1)*3.464101615/bci - x[i]) + x[i+1]; //linearly interpolate the y-value of this segment for bx value box[bx][(int)(y/3.464101615*(double)bci)] = true; //mark the box that holds the values box[bci - 1 -bx][(int)(y/3.464101615*(double)bci)] = true; //mark the symetric box } } } for (int by = 0; by < bci; by++) { //for each horizontal box-edge (y-values) for (i = 1; i < x.length/2; i+= 2) { //for each vertex if ( (by*3.464101615/bci >= x[i] && by*3.464101615/bci <= x[i+2]) || (by*3.464101615/bci <= x[i] && by*3.464101615/bci >= x[i+2]) ) { //if the line segment formed with this beginning point contains the by-value double xt = (x[i+1] - x[i-1])/(x[i+2] - x[i])*(by*3.464101615/bci - x[i]) + x[i-1]; //linearly interpolate the x-value of this segment for the by value box[(int)(xt/3.464101615*(double)bci)][by] = true; //mark the box that holds the values box[bci - 1 -(int)(xt/3.464101615*(double)bci)][by] = true; //mark the symetric box } if ( ((by+1)*3.464101615/bci >= x[i] && (by+1)*3.464101615/bci <= x[i+2]) || ((by+1)*3.464101615/bci <= x[i] && (by+1)*3.464101615/bci >= x[i+2])) { //if the line segment formed with this beginning point contains the by-value double xt = (x[i+1] - x[i-1])/(x[i+2] - x[i])*((by+1)*3.464101615/bci - x[i]) + x[i-1]; //linearly interpolate the x-value of this segment for the by value box[(int)(xt/3.464101615*(double)bci)][by] = true; //mark the box that holds the values box[bci - 1 -(int)(xt/3.464101615*(double)bci)][by] = true; //mark the symetric box } } } int N = 0; for (i = 0; i < bci; i++) { for (j = 0; j < bci; j++) { if (box[i][j]) {N++;} } } bdim.setText("D = " + (Math.log(N)/Math.log(bci))); double bxdisp[] = new double[10]; for (i = 0; i < bci; i++) { for (j = 0; j < bci; j++) { //for each box if (box[i][j]) { //draw a box if the box contains data bxdisp[0] = i*Math.sqrt(12)/(double)bci; //lower left corner bxdisp[1] = j*Math.sqrt(12)/(double)bci; bxdisp[2] = i*Math.sqrt(12)/(double)bci; //upper left corner bxdisp[3] = (j+1)*Math.sqrt(12)/(double)bci; bxdisp[4] = (i+1)*Math.sqrt(12)/(double)bci; //upper right corner bxdisp[5] = (j+1)*Math.sqrt(12)/(double)bci; bxdisp[6] = (i+1)*Math.sqrt(12)/(double)bci; //lower right corner bxdisp[7] = j*Math.sqrt(12)/(double)bci; bxdisp[8] = i*Math.sqrt(12)/(double)bci; //lower left corner bxdisp[9] = j*Math.sqrt(12)/(double)bci; data2 = graph.loadDataSet(bxdisp, 5); data2.linecolor = new Color(255, 0 , 0); xaxis.attachDataSet(data2); yaxis_left.attachDataSet(data2); graph.repaint(); } } } } public void actionPerformed(ActionEvent ev) { if (ev.getSource().equals(advance)) { lineb.setSelected(true); Adv(); bci = 1; bdim.setText("D = "); } else if (ev.getSource().equals(restart)) { lineb.setSelected(true); restartf(); } else if (ev.getSource().equals(lineb)) { restartf(); } else if (ev.getSource().equals(lengthb)) { plotLength(); bdim.setText("D = "); } else if (ev.getSource().equals(areab)) { plotArea(); bdim.setText("D = "); } else if (ev.getSource().equals(biter)) { bci = bci*2; graph.detachDataSets(); boxCount(); data1 = graph.loadDataSet(x, x.length/2); data1.linestyle = 1; data1.linecolor = new Color(0,125,0); yaxis_left.attachDataSet(data1); xaxis.attachDataSet(data1); yaxis_left.setTitleText(" "); yaxis_left.minimum = -.25; yaxis_left.maximum = 1.25; graph.repaint(); } else if (ev.getSource().equals(breset)) { bci = 2; graph.detachDataSets(); boxCount(); data1 = graph.loadDataSet(x, x.length/2); data1.linestyle = 1; data1.linecolor = new Color(0,125,0); yaxis_left.attachDataSet(data1); xaxis.attachDataSet(data1); yaxis_left.setTitleText(" "); yaxis_left.minimum = -.25; yaxis_left.maximum = 1.25; graph.repaint(); } } }