/** * Bifurcation Map Generator for x = x**2 + c * @author Robert J Morton YE572246C * @version 4 November 1997 */ import java.awt.*; public class bifmap2 extends java.applet.Applet implements Runnable { int X, Y, // dimensions of display window (in pixels) Xb, Yb, // co-ords of 'real' origin (in pixels) x, y, // co-ords of resultant plot (in pixels) I, // number of iterations of x = x * x + c i; // current iteration number of the above long TF = 60, // inter-plot time frame (milliseconds) T; // future system time at which a new plot is due to begin double r, // the 'real' variable c, // the 'real' constant Scale = 100; // pixels per unit 'real' (100 pixels = 1.00) boolean finished = false; // indicates when the map has been completed String Sp[] = {"", " ", " ", " ", " "}; // spacer for axis numbering Image buffer = null; // reference for an off-screen image buffer Graphics gc = null; // graphics context for the off-screen image Color bg, tc, ac; // background colour, trace colour, attractor colour Color A[][]; // pixel array to minimise calls to drawLine() Thread Bif; // thread reference variable for this program // DISPLAY A NUMERIC VALUE FOR A FIELD void ShowNum(Graphics g, double a, int x, int y) { String sign = "+"; // means number to be displayed is positive // if number is negative, reverse it and make sign a minus if(a < 0) { sign = "-"; a = -a; } String s = String.valueOf(a); // convert the integer to a string // compute number of leading zeros needed then display the string i = 3 - s.length(); if(i < 0) i = 0; g.drawString(Sp[i] + sign + s, x, y); } public void init() { // NORMAL APPLET INITIALISER METHOD int j, k; // utility loop variables bg = Color.black; // set background colour ac = new Color( 0, 160, 96); // create the trace colour tc = new Color( 0, 255, 128); // create the attractor colour /* Deprecated code: Dimension d = size(); // get size of window as given in HTML applet tag X = d.width; Y = d.height; // establish window width and height */ X = 250; Y = 400; // applet window: width=250 height=400 buffer = createImage(X, Y); // create the off-screen image buffer A = new Color[X][Y]; // create a pixel array for pixels /* Set all pixels to light grey. The pixels are plotted in here so they can be checked to avoid having to call drawLine() unnecessarily. */ for(j = 0 ; j < X ; j++) for(k = 0 ; k < Y ; k++) A[j][k] = bg; x = X - 1; // set to start map from right-hand edge Xb = 210; // set horizontal 'real' origin (pixel bias) Yb = Y >> 1; // set vertical 'real' origin (pixel bias) /* Get the graphics context reference for the off-screen image, set the background colour for the off-screen image and the off- screen image with the background colour. */ gc = buffer.getGraphics(); gc.setColor(Color.black); gc.fillRect(0, 0, X, Y); /* Set the colour for the scale lines then draw the vertical and horizontal scales. */ gc.setColor(Color.gray); gc.drawLine(Xb, Yb - 200, Xb, Yb + 200); for(i = 50 - Yb, j = Xb - 5, k = Xb + 5 ; i < Yb; i += 50) gc.drawLine(j, Yb + i, k, Yb + i); gc.drawLine(Xb - Xb, Yb, Xb + 150, Yb); for(i = 10 - Xb, j = Yb - 5, k = Yb + 5 ; i < 150; i += 50) gc.drawLine(Xb + i, j, Xb + i, k); /* Create and set the font for writing on the applet pane, then number the vertical and horizontal axes. */ Font font = new Font("Dialog", Font.PLAIN, 12); gc.setFont(font); ShowNum(gc, +1.5, 180, 50); ShowNum(gc, +1.0, 180, 100); ShowNum(gc, +0.5, 180, 150); ShowNum(gc, -0.5, 218, 250); ShowNum(gc, -1.0, 218, 300); ShowNum(gc, -1.5, 218, 350); ShowNum(gc, -0.5, 150, 191); ShowNum(gc, -1.0, 100, 191); // Label the vertical and horizontal axes in black. gc.setColor(Color.black); gc.drawString( "x", 202, 13); gc.drawString( "c", 240, 196); T = System.currentTimeMillis() + TF; // end of first plot's time frame } // PAINT THE PICTURE SO FAR by drawing from the off-screen image public void paint(Graphics g) { g.drawImage(buffer, 0, 0, null); } // RE-PAINT THE PICTURE SO FAR by redrawing from the off-screen image public void update(Graphics g) { g.drawImage(buffer, 0, 0, null); } public void newPlot() { // called in response a request for a repaint() Color C = tc; // set current colour to aura trace colour /* If not yet reached left side of window, compute the real 'c' value corresponding to current x-pixel and reset 'r' for a new iteration.*/ if(x > 0) { c = (double)(x - Xb) / Scale; r = 0; for(i = 0; i < 10000; i++) { // for a I (further) iterations // Change the trace colour when 'r' has had time to settle. if(i > 100) C = ac; /* Iterate the appropriate non-linear difference equation and bail out if 'r' goes off-screen. */ r = r * r + c; if(r > 2 || r < -1.99) break; /* Compute the y-pixel position corresponding to the new value of 'r' and set the appropriate colour for this pixel. */ y = Yb - (int)(r * Scale); Color K = A[x][y]; /* If the pixel needs to be drawn, set the appropriate trace colour for the final stretch of the current line and draw the line from the current dot to the previous dot. */ if(K == bg || C == ac && K == tc) { A[x][y] = C; gc.setColor(C); gc.drawLine(x, y, x, y); } } x--; // advance left one pixel repaint(); // get graphics context and call update() } else finished = true; // Else, we've completed the attractor, } // so the map is finished. public void run() { // run the bifurcation map painting thread while(true) { // permanent loop /* If plotting has not yet finished, paint the next vertical line of plots on the off-screen IMAGE. */ if(!finished) newPlot(); /* Get the time left in this plot's time frame, ensur- ing that it is at least 5 milliseconds, then put the thread to sleep for this remaining time. */ long s = T - System.currentTimeMillis(); if(s < 5) s = 5; try { Thread.currentThread().sleep(s); } /* Catch any exceptions that may occur during the above sleep loop but do nothing about them because they are not errors. Then set 'T' to the system time at which the next time frame is due to finish. */ catch (InterruptedException e) { } T = System.currentTimeMillis() + TF; } } /* Start the program thread by creating the thread object and starting it running by requesting a call to run(). */ public void start() { Bif = new Thread(this); Bif.start(); } public void stop() { Bif=null; } // Stop this program thread }