/********************************************************* * * * Fractal Generating Applet * * * *********************************************************/ /* DiBiano, Robert J. * Fractal Generating Applet * 11/8/2002 * * Purpose: graphically show what root complex numbers converge to with Newton's method. * * The applet can recive non default varibale values from the calling web page through * the use of the param command as shown in this sample applet call: * * * * * * Valid Parameters: * - width and height are in pixels, name and value are strings, quotes are optional though * - polynomial is the polynomial * - xMin,xMax,yMin,yMax are bounds of graph * - lowIter: if it converges in this many or less will look a shade darker * - highIter: if it takes this many or more to converge, graph will be a shade lighter * * * Changes Log: * * 11/08/2002 - changes log started * 11/21/2002 - formula for yStepSize was wrong (was same as for xStepSize) so I fixed it. * 12/17/2003 - was displaying upside down(fixed I tihnk), added interface for end user to * type in the function to use and various other data. No error checking right now. * * * Known Issues: The program is still in it's early stages, so error checking may not exist * for everything. * - not sure it can handle negative height and width input * - polynomial can only be in standard form (Ax^B + Cx^D + ...) and only integer coefficients * - class polynomial is a hunk of junk; string input has to be redone minimally (so floats * work), internal representation (and therefore derivative method) could stand to be * totally re worked, it would also be nice to handle stuff in factored form or functions * other than simple powers. * - xMin, xMax, yMin, yMax also can only be integers if brought from outside b/c we use * parseInt to parse them, browsers don't support the java version that that has * parseDouble yet. * - Our test for convergence does not actually work in some cases it seems. Things like x^5 * show up as having many different roots b/c roots are badly calculated after a false * convergence detection flag is raised. There may be other problems obscured by this * one. * - only the first 10 roots get unique colors, eventually want to generate random colors * beyond this. * */ import java.applet.*; import java.awt.*; import java.lang.Math; public class atractor extends Applet { String polyString="x^3-1"; // polynomial to do Newton's method on polynomial equation; // wrapper class for polynomial polynomial derivative; // d(polynomial)/dx int width=100, height=100; // image width and height in pixels double xMin=-1, xMax=1, yMin=-1, yMax=1; // graph bounds double xStepSize=(xMax-xMin)/(width-1); // x step size between pixels double yStepSize=(yMax-yMin)/(height-1); // y step size between pixels double error=Math.min(xStepSize,yStepSize)/100; // max error for several things int lowIter=0, highIter=0; Font font=new Font("Courier", Font.PLAIN, 20); Font bigFont=new Font("Courier", Font.BOLD, 25); boolean fractalDrawn=false; // is fractal drawn once yet? int maxRoots=10; // max number of individual roots displayable complex roots[]=new complex[maxRoots]; // roots of our equation Color colors[]=new Color[maxRoots+1]; // colors for each root Image offScrImage; // an offscreen scratch pad to hold the image Graphics offScrGC; // the graphics context used to draw on the pad Button b1; TextField tPolynomial,tXMin,tXMax,tYMin,tYMax,tLowIter,tHighIter; public void init() { String parameter; // holds external data fed into applet for (int x=0; x=highIter) temp=temp.brighter(); } offScrGC.setColor(temp); // set to correct color g.setColor(temp); offScrGC.drawLine(xPixel,yPixel,xPixel,yPixel); // plot the point g.drawLine(xPixel,yPixel,xPixel,yPixel); } // End of if (converged) } } // End of 2 loops to iterate through every pixel fractalDrawn=true; } // End of draw fractal else { // stick our prefabricated fractal onto the applets graphics context, // this way we dont need to re-generate the fractal in order to re display it g.drawImage(offScrImage,0,0,width,height,this); } } // END of paint }// END of class atractor //---------------------------------------------------------------------------------------------- class complex // implements complex numbers, needs java.lang.Math { private double realPart; private double imaginaryPart; public complex(double realPart, double imaginaryPart) // constructor { this.realPart=realPart; this.imaginaryPart=imaginaryPart; } public complex() // constructor { this.realPart=0; this.imaginaryPart=0; } void setEqual(complex other) // = operator { this.realPart=other.realPart; this.imaginaryPart=other.imaginaryPart; } void setEqual(double realPart, double imaginaryPart) // = operator { this.realPart=realPart; this.imaginaryPart=imaginaryPart; } complex add(complex other) // + operator { complex answer=new complex(); answer.realPart=this.realPart+other.realPart; answer.imaginaryPart=this.imaginaryPart+other.imaginaryPart; return answer; } complex add(double other) // + operator { complex answer=new complex(); answer.realPart=this.realPart+other; answer.imaginaryPart=this.imaginaryPart; return answer; } complex subtract(complex other) // - operator { complex answer=new complex(); answer.realPart=this.realPart-other.realPart; answer.imaginaryPart=this.imaginaryPart-other.imaginaryPart; return answer; } complex subtract(double other) // - operator { complex answer=new complex(); answer.realPart=this.realPart-other; answer.imaginaryPart=this.imaginaryPart; return answer; } complex multiply(complex other) // * operator { complex answer=new complex(); answer.realPart=this.realPart*other.realPart-this.imaginaryPart*other.imaginaryPart; answer.imaginaryPart=this.realPart*other.imaginaryPart+this.imaginaryPart*other.realPart; return answer; } complex multiply(double other) // * operator { complex answer=new complex(); answer.realPart=this.realPart*other; answer.imaginaryPart=this.imaginaryPart*other; return answer; } complex divide(complex other) // / operator { complex answer=new complex(); answer.realPart=(this.realPart*other.realPart+this.imaginaryPart*other.imaginaryPart)/ (other.realPart*other.realPart+other.imaginaryPart*other.imaginaryPart); answer.imaginaryPart=(this.imaginaryPart*other.realPart-this.realPart*other.imaginaryPart)/ (other.realPart*other.realPart+other.imaginaryPart*other.imaginaryPart); return answer; } complex divide(double other) // / operator { complex answer=new complex(); answer.realPart=this.realPart/other; answer.imaginaryPart=this.imaginaryPart/other; return answer; } complex pow(int n) // raises to the nth power { if (n>1) return this.multiply(this.pow(n-1)); if (n==1) return this; complex one = new complex(1,0); if (n==0) return one; return one.divide(this.pow(-n)); } public String toString() // automatic string conversion { String s; s = realPart + "+" + imaginaryPart + "i"; return s; } public boolean isNear(double range, complex other) //true if #'s are within range of each other { double distance=Math.sqrt((this.realPart-other.realPart)*(this.realPart-other.realPart)+ (this.imaginaryPart-other.imaginaryPart)*(this.imaginaryPart-other.imaginaryPart)); if (distance<=range) return true; return false; } public boolean isNear(double range, double other) // true if #'s are within range of each other { double distance=Math.sqrt((this.realPart-other)*(this.realPart-other)+ this.imaginaryPart*this.imaginaryPart); if (distance<=range) return true; return false; } } // End of class complex //---------------------------------------------------------------------------------------------- class polynomial // class to hold a polynomial in standard form only, NOT especially robust { private int maxTerms=10; private String equation; private int terms; private int multipliers[]=new int[maxTerms]; private int coefficients[]=new int[maxTerms]; private boolean isANumber(char c) { return c>='0' && c<='9'; } private boolean isValid(char c) { return isANumber(c) || c=='x' || c=='X' || c=='^' || c=='+' || c=='-'; } public polynomial(String s) // constructor { int x,length; char c; boolean working; // are we working on a term? equation=s; equation.trim(); equation.toLowerCase(); equation+=' '; length=equation.length(); terms=0; // # of terms and location of unfinished term working=false; for (x=0;x=0) multipliers[terms]+=(int)equation.charAt(x)-48; else multipliers[terms]-=(int)equation.charAt(x)-48; x+=1; } if (equation.charAt(x)=='x' || equation.charAt(x)=='X') // stuff past a 'x' { x+=1; coefficients[terms]=1; if (equation.charAt(x)=='^') // stuff past a '^' { x+=1; while (equation.charAt(x)=='+' || equation.charAt(x)=='-') { if (equation.charAt(x)=='-') coefficients[terms]=-coefficients[terms]; x+=1; } if (isANumber(equation.charAt(x))) { coefficients[terms]*=(int)equation.charAt(x)-48; x+=1; } while (isANumber(equation.charAt(x))) { coefficients[terms]*=10; if (coefficients[terms]>=0) coefficients[terms]+=(int)equation.charAt(x)-48; else coefficients[terms]-=(int)equation.charAt(x)-48; x+=1; } } // End of stuff past a '^' } // End of stuff past a 'x' terms+=1; // term finished x-=1; // go back on char b/c loop will advance by one } // End of valid term } // End of traverse valid chars } // End of traverse eqation } // End of constructor public String toString() // automatic string conversion { int x; String s=""; for (x=0;x