/* Newton Fractal Explorations Program Coded in full by Ben McIlwain Completed January 23rd, 2002 A.D. Designed for Graphics Pd. 4, taught by Ms. Collins README: This program implements the graphics program specified in the modified requirements with a few notable exceptions. This program utilizes a thread for drawing, and is drawing continuously in cycles. If a change is made to any of the parameters and the start button is depressed (except for at the very first press), the program will continue to draw where the thread specifies so, but in the modified scheme. Thus, do not be alarmed if the fractal seems disjointed upon change of parameters - in time the loop will once again cover all squares and make everything seem normal. Here is a step-by-step description of the text fields: n - The power fractal that is used. The specs say numbers between 3 and 7; my program will accept pretty much anything (with varying results). a - The offset constant in the fractal equation. Any double value can be entered. Tolerance - How many iterations to run before confirming divergence. A larger value makes for a larger color scale, but also slower program execution. Bounds - This should be a small number. Basically, any two numbers that only differ by this much are "equivalent." Make the number bigger to increase program speed. Do not overflow the bounds of a double though, the program will display incorrectly. Color (RGB) - Input values between 0 and 1 for each of the three fields corresponding to red, green, and blue. This affects what overall color is used in the gradient. Run Button - Click this to make the program accept the new values and start using them. */ //Import statements import java.awt.*; import java.*; import java.awt.event.*; import java.awt.BorderLayout; import java.awt.Dimension; import java.util.Vector; public class Fractals extends java.applet.Applet implements Runnable { int n, tol; double bound, a, red, green, blue; //Interface declarations private Label nL, aL, tolerance, bounds, color; private TextField nT, aT, tolD, boundsD, Rgb, rGb, rgB; private Button go; Graphics g; Dimension d; Thread animator; //Init function ... declares all of the interface items. public void init() { g = getGraphics(); nL = new Label("n:"); add(nL); nT = new TextField("5", 2); add(nT); aL = new Label("a:"); add(aL); aT = new TextField("1", 2); add(aT); tolerance = new Label("Tolerance:"); add(tolerance); tolD = new TextField("100", 4); add(tolD); bounds = new Label("Bounds:"); add(bounds); boundsD = new TextField(".000000000001", 11); add(boundsD); color = new Label("Color (RGB):"); add(color); Rgb = new TextField("0",7); add(Rgb); rGb = new TextField(".5",7); add(rGb); rgB = new TextField("1",7); add(rgB); go = new Button("Run"); go.addActionListener(new ButtonHandler()); add(go); } //Upon thread start ... public void start() { animator = new Thread(this); animator.start(); animator.suspend(); } //Upon thread stop ... public void stop() { animator = null; } //What to do while the thread is running ... public void run() { //Initializations. int mainX, mainY; d = size(); //While the thread is running. while (Thread.currentThread() == animator) { for (mainX = 0; mainX < d.width; mainX += d.width/10) { for (mainY = 0; mainY < d.height; mainY += d.height/10) { drawIt(mainX, mainY); try { Thread.sleep(10); } catch (InterruptedException e) { break; } } } } } public void update(Graphics g) { //This space intentionally left blank. //Overloaded so screen is not unintentionally cleared. } //What do to when the Run button is pressed. class ButtonHandler implements ActionListener { public void actionPerformed(ActionEvent e) { Integer intObj; Double dblObj; //Gets all parameters from text fields. intObj = new Integer(nT.getText()); n = intObj.intValue(); intObj = new Integer(tolD.getText()); tol = intObj.intValue(); dblObj = new Double(aT.getText()); a = dblObj.doubleValue(); dblObj = new Double(boundsD.getText()); bound = dblObj.doubleValue(); dblObj = new Double(Rgb.getText()); red = dblObj.doubleValue(); if (red > 1) red = 1; dblObj = new Double(rGb.getText()); green = dblObj.doubleValue(); if (green > 1) green = 1; dblObj = new Double(rgB.getText()); blue = dblObj.doubleValue(); if (blue > 1) blue = 1; animator.resume(); } } public void paint(Graphics g) { //This space intentionally left blank. //All drawing is done by thread and by drawIt(); this is overloaded to prevent //default functioning. } //Draws each "square" on the screen. public void drawIt(int mainX, int mainY) { d = size(); Complex temp, temp2, temp3; int count; float color; //Loops through the points. for (int x = -d.width/2 + mainX; x < -d.width/2 + mainX + d.width/10; x++) { for (int y = -d.height/2 + mainY; y < -d.height/2 + mainY + d.height/10; y++) { temp = new Complex(x, y).add(new Complex(a,0)); temp2 = new Complex(); count = 0; //Iterates until equality. while (!temp.equals(temp2) && count < tol) { temp2 = temp; temp3 = temp.power(n).add(new Complex(a,0)).divideComplex((temp.power(n - 1)).multiplyDouble(n)); temp = temp.subtract(temp3); count++; } //Sets color gradient and draws the point. color = (float)count / (float)tol; g.setColor(new Color(color * (float)red, color * (float)green, color * (float)blue)); g.drawLine(x + d.width/2, y + d.height/2, x + d.width/2, y + d.height/2); } } } //Complex class ... everything is self-evident ... no commenting required. class Complex { double real, imaginary; public Complex() { real = 0; imaginary = 0; } public Complex(double real1, double imaginary1) { real = real1; imaginary = imaginary1; } public Complex add(Complex temp) { return new Complex(real + temp.real, imaginary + temp.imaginary); } public Complex subtract(Complex temp) { return new Complex(real - temp.real, imaginary - temp.imaginary); } public Complex multiplyDouble(double temp) { return new Complex(real * temp, imaginary * temp); } public Complex multiplyComplex(Complex temp) { return new Complex(real*temp.real - imaginary * temp.imaginary, imaginary * temp.real + real * temp.imaginary); } public Complex divideDouble(double temp) { return new Complex(real / temp, imaginary / temp); } public Complex divideComplex(Complex temp) { return new Complex((real * temp.real + imaginary * temp.imaginary)/ (temp.real * temp.real + temp.imaginary * temp.imaginary), (temp.real * imaginary - real * temp.imaginary)/(temp.real * temp.real + temp.imaginary * temp.imaginary)); } public boolean equals(Complex temp) { if (Math.abs(temp.real - real) <= bound && Math.abs(temp.imaginary - imaginary) <= bound) return true; else return false; } public Complex power(int temp) { double tempR, tempI, finalR = real, finalI = imaginary; for (int i = 1; i < temp; i++) { tempR = finalR * real - finalI * imaginary; tempI = finalR * imaginary + real * finalI; finalR = tempR; finalI = tempI; } return new Complex(finalR, finalI); } public double getReal() { return real; } public double getImaginary() { return imaginary; } } }