import SpringGUI.*; // This code has been ported back and forth many times and contains so much goo and so many hacks it's not even funny. // Stop shaking your head already! :) SpringGUI gui; int aheight, awidth; int apixels[]; Fractal f; boolean zooming; int x1, x2, y1, y2; int maxI; double x, y; double rLeft; double rRight; double iTop; double iBottom; double newrLeft; double newrRight; double newiTop; double newiBottom; Scope begin, currentScope; boolean calculating; boolean ticker; boolean changed; String exponent; PFont myFont; float exp; boolean first; // first frame after recalc void setup() { first = false; exp = 2; maxI = 200; exponent = "2"; myFont = loadFont("AllstarsSquareCompressed-13.vlw"); calculating = false; ticker = false; changed = true; size(400,330, P3D); gui = new SpringGUI(this); gui.addButton("back", "back", 255, 305, 60, 20); gui.addButton("reset", "zoom out", 320, 305, 60, 20); gui.setAllBackgrounds(0,0,0); gui.setAllForegrounds(255,0,0); awidth = 400; aheight = 300; f = new Fractal(0,0); zooming = false; rLeft = -4; rRight = 4; iTop = -3; iBottom = 3; begin = new Scope(); begin.left = rLeft; begin.right = rRight; begin.top = iTop; begin.bottom = iBottom; currentScope = begin; apixels = new int[height*width]; x = y = 0; //background(255,0,0); calculateImage(); } void handleEvent(String[] parameters) { if (parameters[1].equals("reset") && parameters[2].equals("mouseClicked")) { while (currentScope.parent != null) { currentScope = currentScope.parent; } calculateImage(); } if (parameters[1].equals("back") && parameters[2].equals("mouseClicked")) { if (currentScope.parent != null) { currentScope = currentScope.parent; } calculateImage(); } this.requestFocus(); } void draw() { if (first) { first = false; // background(0,0,0); textFont(myFont); fill(255,255,255); rect(45, 85, 90, 20); fill(192,0,0); text("Calculating!", 50, 100); return; } if (calculating) { double average = 0; int min = 500; rLeft = currentScope.left; rRight = currentScope.right; iTop = currentScope.top; iBottom = currentScope.bottom; System.out.println("\nStarting calculation"); System.out.println("real: "+rLeft+" to "+rRight); System.out.println("imaginary: "+iTop+" to "+iBottom); System.out.println("that is a scope of " + (rRight-rLeft) + ", " + (iBottom - iTop)); f.setMaxIterations(maxI); double rStep = (rRight - rLeft) / ((double) awidth); double iStep = (iBottom - iTop) / ((double) aheight); double currentR = rLeft; double currentI = iTop; int currentPixel = 0; int currentIt; for (int i = 0; i < aheight; i++) { for (int j = 0; j < awidth; j++) { if (!calculating) { ticker = true; changed = true; return; } currentIt = f.probePoint(currentR, currentI); average += currentIt; if (min > currentIt) { min = currentIt; } if (currentIt < maxI) { apixels[currentPixel] = 0xFF000000 | (clip(currentIt) << 16) | (clip(currentIt/4) << 8) | (clip(currentIt/2)); } else apixels[currentPixel] = 0xFFFFFFFF; currentR += rStep; currentPixel++; } currentR = rLeft; currentI += iStep; } System.out.println("all done."); System.out.println("average num of iterations this region:"+ (average/(height*width))); System.out.println("min num of iterations this region:"+ (min)); calculating = false; ticker = true; changed = true; } else if (changed) { loadPixels(); background(0,0,0); for (int i = aheight*awidth-1; i >= 0; i--) { pixels[i] = apixels[i]; } if (zooming) { stroke(255,0,0); line(x1,y1,x2,y1); line(x1,y1,x1,y2); line(x2,y1,x2,y2); line(x1,y2,x2,y2); } changed = false; if (calculating) { ticker = !ticker; } if (ticker) { stroke(64,64,64); line (0,aheight, awidth, aheight); } textFont(myFont); fill(128); text("Exponent: "+exponent, 50, aheight + 20); updatePixels(); } } void keyPressed() { if (exponent.length() < 9) { switch (key) { case '0': if (exponent.equals("0")) {exponent = "0";} else { exponent = exponent + "0"; } changed = true; break; case '1': if (exponent.equals("0")) {exponent = "1";} else { exponent = exponent + "1"; } changed = true; break; case '2': if (exponent.equals("0")) {exponent = "2";} else { exponent = exponent + "2"; } changed = true; break; case '3': if (exponent.equals("0")) {exponent = "3";} else { exponent = exponent + "3"; } changed = true; break; case '4': if (exponent.equals("0")) {exponent = "4";} else { exponent = exponent + "4"; } changed = true; break; case '5': if (exponent.equals("0")) {exponent = "5";} else { exponent = exponent + "5"; } changed = true; break; case '6': if (exponent.equals("0")) {exponent = "6";} else { exponent = exponent + "6"; } changed = true; break; case '7': if (exponent.equals("0")) {exponent = "7";} else { exponent = exponent + "7"; } changed = true; break; case '8': if (exponent.equals("0")) {exponent = "8";} else { exponent = exponent + "8"; } changed = true; break; case '9': if (exponent.equals("0")) {exponent = "9";} else { exponent = exponent + "9"; } changed = true; break; case '.': if (exponent.indexOf(".") == -1) { exponent = exponent + "."; changed = true; } break; } } if (key == '\b') { exponent = exponent.substring(0, exponent.length()-1); if (exponent.length() == 0) {exponent = "0";} changed = true; } if (key == '\n') { // float tmp[] = splitFloats(exponent); exp = float(exponent); while (currentScope.parent != null) { currentScope = currentScope.parent; } calculateImage(); } } void mousePressed() { if (mouseX < awidth && mouseX >= 0 && mouseY < aheight && mouseY >= 0 && !calculating) { changed = true; double rStep = (rRight - rLeft) / awidth; double iStep = (iBottom - iTop) / aheight; newrLeft = rLeft + mouseX*rStep; newiTop = iTop + mouseY*iStep; zooming = true; x1 = x2 = mouseX; y1 = y2 = mouseY; } } void mouseReleased() { if (zooming) { loadPixels(); //background(255,0,0); updatePixels(); changed = true; double rStep = (rRight - rLeft) / awidth; double iStep = (iBottom - iTop) / aheight; newrRight = rLeft + mouseX*rStep; newiBottom = iTop + mouseY*iStep; if (newiBottom != newiTop && newrLeft != newrRight) { if (newiBottom < newiTop) { iBottom = newiTop; iTop = newiBottom; } else { iBottom = newiBottom; iTop = newiTop; } if (newrRight < newrLeft) { rRight = newrLeft; rLeft = newrRight; } else { rRight = newrRight; rLeft = newrLeft; } Scope nS = new Scope(); nS.left = rLeft; nS.right = rRight; nS.top = iTop; nS.bottom = iBottom; nS.parent = currentScope; currentScope.child = nS; currentScope = nS; zooming = false; for (int i = aheight*awidth-1; i >= 0; i--) { apixels[i] = 0x000000; } calculateImage(); } } else { if (mouseX >= 10 && mouseX <= 23 && mouseY >= aheight+8 && mouseY <= aheight+21) { while (currentScope.parent != null) { currentScope = currentScope.parent; } zooming = false; calculateImage(); } if (mouseX >= 30 && mouseX <= 43 && mouseY >= aheight+8 && mouseY <= aheight+21) { if (currentScope.parent != null) { currentScope = currentScope.parent; } zooming = false; calculateImage(); } } } void mouseDragged() { if (mouseX < awidth && mouseX >= 0 && mouseY < aheight && mouseY >= 0 && !calculating) { changed = true; x2 = mouseX; y2 = mouseY; } } void calculateImage() { first = true; calculating = true; } int clip(int i) { if (i>255) {return 255;} else return i; } // -------------------------- ComplexNumber class complexNumber { double real, imaginary; complexNumber() { real = 0; imaginary = 1; } complexNumber(double r, double i) { real = r; imaginary = i; } void multiplyReal(double r) { real *= r; imaginary *= r; } void multiplyComplex(complexNumber c) { double r = (Math.pow(this.real*c.real, exp) - Math.pow(this.imaginary*c.imaginary, exp)); double i = (this.real*c.imaginary + this.imaginary*c.real); this.real = r; this.imaginary = i; } void addComplex(complexNumber c) { double r = this.real + c.real; double i = this.imaginary + c.imaginary; this.real = r; this.imaginary = i; } double abs() { return Math.sqrt(this.real*this.real + this.imaginary*this.imaginary); } double abs2() { return (this.real*this.real + this.imaginary*this.imaginary); } void copyTo(complexNumber c) { c.real = this.real; c.imaginary = this.imaginary; } complexNumber copy() { return new complexNumber(real, imaginary); } } // --------------------- Scope class Scope { Scope parent, child; double left, right, top, bottom; } // --------------------- Fractal class Fractal { complexNumber set; int counter; complexNumber c; complexNumber point; int maxIterations; Fractal() { set = new complexNumber(0,0); c = new complexNumber(0,0); point = new complexNumber(0,0); maxIterations = 1000; counter = 0; } Fractal(double setR, double setI) { set = new complexNumber(setR,setI); c = new complexNumber(0,0); point = new complexNumber(setR,setI); maxIterations = 500; counter = 0; } void setSet(double setR, double setI) { set.real = setR; set.imaginary = setI; } void setMaxIterations(int i) { maxIterations = i; } int probePoint(double r, double i) { counter = 0; c.real = r; c.imaginary = i; set.copyTo(point); while ((point.abs2() <= 4) && (counter < maxIterations)) { point.multiplyComplex(point); point.addComplex(c); counter++; } return counter; } }