advertisement
javaboutique
Search Tips
Articles  |   Tutorials  |   Reviews  |   Tools  |   by Category  |   by Date  |   by Name  |   Submit  |   Source  |   Forums  |  
javaboutique
Browse DevX


Partners & Affiliates











advertisement

Julia


/********************************************************************
*                                                                   *
*   Julia.java    By Mark McClure  -  Feb 1996                      *
*   mmcclure@liberty.uc.wlu.edu                                     *
*   http://liberty.uc.wlu.edu/~mmcclure/java/Julia/                 *
*                                                                   *
*   This applet generates julia sets for the quadratic family of    *
*   functions f(z) = z^2 + c.  The complex parameter c may be       *
*   chosen from am image of the Mandelbrot set or entered into      *
*   a TextField.                                                    *
*                                                                   *
********************************************************************/


// Need some tools.
import java.awt.*;
import java.util.StringTokenizer;



// -------------------> The Julia class  <------------------------
// This is the main class which extends the Applet class and 
// implements the Runnable interface to run smoothly.

public class Julia extends java.applet.Applet implements Runnable{        

	static final int H_SIZE = 600;    // Horizontal size of the applet
	static final int V_SIZE = 330;    // Vertical size of the applet
	static Thread initRunner;         // Initialization Thread
	JuliaCanvas juliaCanvas;          // Place to draw the Julia Set
	MandelCanvas mandelCanvas;        // Place to draw the Madelbrot Set
	ControlPanel p;                   // Holds The controls 
	Image mandel_img;    // The Mandelbrot set displayed by the applet
	                     // is a gif rather than a generated image.

	public void init() {
	
		// Initialization
		resize(H_SIZE, V_SIZE);
		setFont(new Font("TimesRoman", Font.PLAIN, 12));
		setBackground(Color.white);
		setForeground(Color.black);
		setLayout(new BorderLayout());	
						
		// The two main canvases - one for the Julia set and one
		// for the Mandelbrot set.
		juliaCanvas = new JuliaCanvas(H_SIZE/2);
		mandel_img = getImage(getCodeBase(), "mandel.gif");
		mandelCanvas = 
		new MandelCanvas(mandel_img, juliaCanvas, p, H_SIZE/2);

		// A panel to hold the two main canvases.
		Panel innerPanel = new Panel();
		add("Center", innerPanel);
		innerPanel.setLayout(new GridLayout(1, 2, 2, 2));
		innerPanel.add(mandelCanvas);
		innerPanel.add(juliaCanvas);

		// The control panel.
		p = new ControlPanel(juliaCanvas, mandelCanvas);
		p.resize(400, 30);
		add("South", p);

		show();
	} //end init()

	// Applet is computationally intensive.  
	// Definately needs a thread.
	public void start(){
		if(initRunner == null) {
			initRunner = new Thread(this);
			initRunner.setPriority(Thread.MIN_PRIORITY);
			initRunner.start();
		}
	}  //end start()

	// Clean up when applet stops.
	public synchronized void stop() {
		if( juliaCanvas.juliaRunner != null ) {
			juliaCanvas.juliaRunner.stop();
		}
		juliaCanvas.juliaRunner = null;

		if(mandelCanvas.canvasRunner != null ) {
			mandelCanvas.canvasRunner.stop();
		}
		mandelCanvas.canvasRunner = null;
		
		if( initRunner != null ) {
			initRunner.stop();
		}
		initRunner = null;
		
		//destroy();
	} //end stop()
	
	
	// Instantiating each complex number for the Julia Set takes
	// time and happens in this initialization thread.
	public void run() {
		int i;
		
		for(i=0; i<juliaCanvas.num_points; i++) {
			// Set the complex numbers out of the picture
			juliaCanvas.points[i] = new ComplexNumber(5);
		}
	}

}//end Julia class.



// -----------------> The Mandel Canvas class <----------------
// This class holds all the information relevant to the displayed
// Mandelbrot set.

class MandelCanvas extends Canvas {
	
	Image mandel_img;                  // Holds the Mandelbrot gif
	JuliaCanvas juliaCanvas;           // Link to the JuliaCanvas
	ControlPanel p;                    // Link to the ControlPanel
	Thread canvasRunner;               // A thread for the JuliaCanvas
	boolean update_positionQ = true;   // Only want to update the position
	                                   // display until a point is selected.

	// Bounds for the Mandelbrot Set in the complex plane
	static final double z_left = -2;   
	static final double z_right = .6;
	static final double z_top = 1.3;
	static final double z_bot = -1.3;
	
	int pixel_size; // Size of the Mandelbrot image in pixels
	

	// The constructor method
	MandelCanvas(Image mandel_passed, JuliaCanvas juliaCanvas_passed,
	ControlPanel p_passed, int pixel_size_passed) {
				
		// Set these variables to the values passed
		mandel_img = mandel_passed;
		juliaCanvas = juliaCanvas_passed;
		p = p_passed;
		pixel_size = pixel_size_passed;
		
		// Set some stuff
		setBackground(Color.white);
		show();
	}// end constructor method
	
	// Update the postion display when the mouse moves.
	public boolean mouseMove(Event evt, int x, int y) {
		if(update_positionQ) {
			ComplexNumber c = complexConvert(x,y);
			p.update_position(c);
		}
		return true;
	}

	// Clear the postion display when the mouse moves.
	public boolean mouseExit(Event evt, int x, int y) {
		if(update_positionQ) {
			p.positionDisplay.setText("");
		}
		return true;
	}
	
	// The action starts when the user clicks on the Mandelbrot set.
	public boolean mouseUp(Event evt, int x, int y) {
		ComplexNumber c = complexConvert(x,y);   // Need a complex
		                                         // number from (x,y)
		
		// Update the position display for the last time.
		p.update_position(c);
		update_positionQ = false;

		// Set the Julia parameter and begin the computation thread.
		juliaCanvas.c = c;
		if( canvasRunner == null ) {
			canvasRunner = new Thread(juliaCanvas);
			canvasRunner.setPriority(Thread.MIN_PRIORITY);
			canvasRunner.start();
		}
		if( !canvasRunner.isAlive() ) {
			canvasRunner.stop();
			canvasRunner = new Thread(juliaCanvas);
			canvasRunner.setPriority(Thread.MIN_PRIORITY);
			canvasRunner.start();
		}
	
		return true;
	} //end mouseUp()
	
	// Called by mouseUp() to converty (x,y) to a complex number.
	ComplexNumber complexConvert(int x, int y) {
		double a, b;
		a = (double) ( ((z_right - z_left)/pixel_size)*x + z_left );
		b = (double) ( ((z_bot - z_top)/pixel_size)*y + z_top );
	
		return new ComplexNumber(a,b);
	}

	public void paint(Graphics g) {
		g.drawImage(mandel_img, 0, 0, this);
	}
}//end MandelCanvas class



// ------------------> The JuliaCanvas class <-----------------
// This class holds the information needed to draw the Julia Set.
// The set itself is an object of class JuliaSet.
// Implents runnable since drawing is time consuming.

class JuliaCanvas extends Canvas  implements Runnable {
	
	static ComplexNumber c;             // Parameter defining the Julia Set
	static final int num_points = 5000; // Number of points to draw
	static final double z_size = 4.0;   // Size of the set in complex plane
	static int pixel_size;              // Size of the set in pixels
	static Thread juliaRunner;          // Thread to start() theSet in
	JuliaSet theSet;                    // The set itself of class JuliaSet
	
	// An array to hold the complex numbers in the Julia Set
	ComplexNumber points[] = new ComplexNumber[num_points];
	
	// The constructor method
	JuliaCanvas(int pixel_size_passed) {

		// Set these variables to the values passed
		theSet = new JuliaSet(num_points, points, this, getGraphics());
		pixel_size = pixel_size_passed;
		
		// Set some stuff
		setBackground(Color.white);
		setForeground(Color.black);
		setFont(new Font("TimesRoman", Font.PLAIN, 12));
		resize(pixel_size, pixel_size);
		show();
	}// end constructor method
	
	public void run() {
		theSet.c = c;    // Sets the parameter
		startJulia();    // Starts the computation of the Julia Set.
	}

	// Called by run to compute the set.
	void startJulia() {
		if(juliaRunner == null) {
			juliaRunner = new Thread(theSet);
			juliaRunner.setPriority(Thread.MIN_PRIORITY);
			juliaRunner.start();
		}
		if( !juliaRunner.isAlive() ) {
			juliaRunner.stop();
			juliaRunner = new Thread(theSet);
			juliaRunner.setPriority(Thread.MIN_PRIORITY);
			juliaRunner.start();
		}
	}// end startJulia()

	// Called in response to a button press to clear the canvas.
	public void clear() {
		int i;
		
		for(i=0; i<num_points; i++) {
			// Set the complex numbers out of the picture
			points[i] = new ComplexNumber(5);  
		}
		repaint();
	}

	// Plots the complex numbers that form the Julia Set.
	void plot(ComplexNumber z) {
		int x,y;
		Graphics g = getGraphics();
		
		x = (int) ( (pixel_size/z_size)*(z.a + z_size/2) );
		y = (int) ( (pixel_size/z_size)*(z_size/2 - z.b) );
		g.drawLine(x,y, x,y);
	}
		
	public void paint(Graphics g) {
		int i;
		
		// Plot the JuliaSet.  Check first to make sure that we
		// need to plot it.  If the first point (theSet.points[1])
		// has real part > 4 this must be because the image has
		// been cleared.
		if( (!juliaRunner.isAlive()) && (juliaRunner != null)
		&& (theSet.points[1].a < 4) ) {
			for(i=0; i < num_points; i++) {
				plot(theSet.points[i]);
			}
		}

	}
}//end JuliaCanvas class



// -------------> The JuliaSet class <----------------
// Holds the information defining the Julia Set itself.

class JuliaSet implements Runnable {
	ComplexNumber c;      // Set by the function JuliaCanvas.run()
	int num_points;              // Number of points to draw
	ComplexNumber points[];      // Points in the JuliaSet
	JuliaCanvas canvas;          // A place to draw the JuliaSet
	Graphics g;                  // Defines the drawing functions
	
	// The constructor method
	JuliaSet(int num_points_passed, ComplexNumber[] points_passed,
	JuliaCanvas canvas_passed, Graphics g_passed) {
		
		// Set these variables to the values passed
		num_points = num_points_passed;
		points = points_passed;
		canvas = canvas_passed;
		g = g_passed;
	}// end constructor method
	
	// This is the main computational loop and is, therfore, run in
	// a thread.
	public void run() {
		int i;
		double a = Math.random();
		double b = Math.random();
		
		points[0] = new ComplexNumber(a, b);
		for(i=0; i < num_points - 1; i++) {
			points[i+1] = fc( (int) (2*Math.random()), points[i]);
			canvas.plot(points[i]);
		}
	}
	
	// Iteration of this function generates the Julia Set.
	ComplexNumber fc(int choice, ComplexNumber z) {
		if(choice == 0) {
			return z.minus(c).sqrt();
		}
		else {
			return z.minus(c).sqrt().ominus();
		}
	}
}//end JuliaSet class



// -----------> The ComplexNumber class <----------------
// The computations above are in terms of complex numbers
// defined here.

class ComplexNumber {
	double a, b;        // The real and imaginary parts
	
	
	// ---> Several constructor Methods <---
	ComplexNumber(double a_passed, double b_passed) {
		a = a_passed;
		b = b_passed;
	}
	
	ComplexNumber(double a_passed) {
		a = a_passed;
		b = 0.0;
	}
	
	ComplexNumber() {
		a = 0.0;
		b = 0.0;
	}// end constructor methods
	
	
	// ---> Several arithmetic methods <---
	ComplexNumber plus(ComplexNumber z) {
		return new ComplexNumber(a + z.a, b + z.b);
	}
		
	ComplexNumber minus(ComplexNumber z) {
		return new ComplexNumber(a - z.a, b - z.b);
	}
	
	ComplexNumber ominus() {
		return new ComplexNumber(-a, -b);
	}
	
	//The only slightly tricky operation
	ComplexNumber sqrt() {
		
		// The polar components of the number
		double theta;
		double r = Math.sqrt(Math.sqrt(a*a + b*b));
		
		// The cartesian components of the square root
		double a_sqrt, b_sqrt;

		// Compute theta
		if(a >= 0) {
			theta = (Math.atan(b/a)/2);
		}
		else {
			if(b >= 0) {
				theta = (Math.atan(b/a) + Math.PI)/2;
			}
			else {
				theta = (Math.atan(b/a) - Math.PI)/2;
			}
		}// end computation of theta

		// Compute the cartesian components of the square root
		a_sqrt = r*(Math.cos(theta));
		b_sqrt = r*(Math.sin(theta));
		
		return new ComplexNumber(a_sqrt, b_sqrt);
	}// end sqrt()
	
	 // end arithmetic methods
	 
}// end ComplexNumber class


// ------------> The ControlPanel class <------------------
//This class defines the ControlPanel and responds to events.

class ControlPanel extends Panel {

	Panel mandelPanel;
	Panel juliaPanel;
	
	Button stop_button;                  // The stop button
	Button clear_button;                 // The clear button
	JuliaCanvas juliaCanvas;             // Linked to the JuliaCanvas
	MandelCanvas mandelCanvas;           // Linked to the MandelCanvas
	static TextField positionDisplay;    // Displays the Julia parameter
	
	Thread juliaTextRunner;              // The user may start the 
	                                     // computation by entering a
	                                     // value in the TextField.  So
	                                     // we need a thread for that 
	                                     // computation

	// The constructor method.
	ControlPanel(JuliaCanvas juliaCanvas_passed,
	MandelCanvas mandelCanvas_passed) {
	
		// Set the layout
		try{ 
			setLayout(new GridLayout(1, 2, 0, 0)); 
		}
		catch(IllegalArgumentException e){/* Ignore exception */}
		                                  // I'm not even sure why this
		                                  // exception exists.
		
		// Place a panel below the Mandelbrot image and the Julia image. 
		mandelPanel = new Panel();
		juliaPanel  = new Panel();
		add(mandelPanel);
		add(juliaPanel);
		
		// Create and add the position display to the mandelPanel.
		positionDisplay = new TextField(25);
		positionDisplay.setEditable(true);
		mandelPanel.add(positionDisplay);
		
		// Create and add the buttons to the juliaPanel.
		stop_button = new Button("Stop");
		clear_button = new Button("Clear");
		juliaPanel.add(stop_button);
		juliaPanel.add(clear_button);
		
		// Set the canvases to the values passed.
		juliaCanvas = juliaCanvas_passed;
		mandelCanvas = mandelCanvas_passed;
		
		// Set the background color
		setBackground(Color.gray);
	}// end constructor method
	
	//The event handler.
	public boolean action(Event evt, Object arg) {
	
		// Figure out which Button is pressed.
		if (evt.target instanceof Button) {
			choose( (String) arg);
		}
		
		// Start computation if user hits return in the TextField
		if( (evt.target instanceof TextField) 
		&& (evt.id == Event.ACTION_EVENT) ) {
		
			// Seems that I should have to check to see if this works.
			juliaCanvas.c = parseInput(positionDisplay.getText());
			
			if( juliaTextRunner == null ) {
				juliaTextRunner = new Thread(juliaCanvas);
				juliaTextRunner.setPriority(Thread.MIN_PRIORITY);
				juliaTextRunner.start();
			}
			if( !juliaTextRunner.isAlive() ) {
				juliaTextRunner.stop();
				juliaTextRunner = new Thread(juliaCanvas);
				juliaTextRunner.setPriority(Thread.MIN_PRIORITY);
				juliaTextRunner.start();
			}
		}// end if	
		return true;
	}// end action()

	//Called by action in response to the Button press event.
	void choose(String button_name) {
		if(button_name.equals("Stop"))
			juliaCanvas.juliaRunner.stop();
		else {
			mandelCanvas.update_positionQ = true;
			juliaCanvas.juliaRunner.stop();
			juliaCanvas.clear();
			juliaCanvas.repaint();
		}
	}// end choose

	// Called by MandelCanvas.mouseEvents to update the postion.
	public static void update_position(ComplexNumber c) {
		String x = new Double(c.a).toString();
		if(c.b >= 0) {
			String y = new Double(c.b).toString();
			positionDisplay.setText("c = " + x + " + " + y + " i");
		}
		else {
			String y = new Double(-c.b).toString();
			positionDisplay.setText("c = " + x + " - " + y + " i");
		}
	}// end choose
	
	
	// When user presses return in the TextField, we want to compute the
	// JuliaSet.  So we need to parse the TextField to get the complex
	// Juliaset parameter.  The user **must** enter text in the format
	// "c = a + b i" or "c = a - b i"  where 'a' and 'b' are non-negative
	// numbers.
	ComplexNumber parseInput(String str) {
	
		// Use the StringTokenizer to pares the TextField.
		StringTokenizer string_toke = new StringTokenizer(str, " ");
		int num_tokes = string_toke.countTokens();
		
		// User may enter "c = a + b i" or "c = a - b i".  
		// plus_or_minus tells which one it was.
		String plus_or_minus;
		
		// -------> Hopefully I can delete this soon <-----------
		// There's a wierd Netscape bug (PowerMac only) which won't let
		// the user type capital letters (or + which is -shift- =) into 
		// a text field.  wierd_bugQ helps deal with this.
		boolean wierd_bugQ = false;
		
		double a = 0, b = 0;    // The real and imaginary parts
		int i;
		
		// Check to make sure the text was entered correctly
		if( num_tokes != 6 ) {
			inputError();
		}
		if( !string_toke.nextToken().equalsIgnoreCase("c") ) {
			inputError();
		}
		if( !string_toke.nextToken().equals("=") ) {
			inputError();
		}
		
		// Get the real part.
		try {
			a = new Double(string_toke.nextToken()).doubleValue();
		}
		catch(NumberFormatException e) {
			inputError();
		}
		
		// Get the imaginary part. Check whether it's positve or
		// negative first.
		plus_or_minus = new String(string_toke.nextToken());
		if( !( plus_or_minus.equals("+") || plus_or_minus.equals("-") ) ) {
		
			// ---------> Hopefully this goes away soon <--------
			if( plus_or_minus.equals("=") ) {
				wierd_bugQ = true;
			}
			else {
				inputError();  // would need to keep this
			}
		}
		try {
			b = new Double(string_toke.nextToken()).doubleValue();
		}
		catch(NumberFormatException e) {
			inputError();
		}
		if(plus_or_minus.equals("-")) {
			b = -b;
		}
		
		// Check for the 'i'.
		if( !string_toke.nextToken().equalsIgnoreCase("i") ) {
			inputError();
		}
		
		// The wierd bug occurs if the user tried to type + on 
		// a PowerMac.  This resets the display correctly.
		if( wierd_bugQ == true ) {
			positionDisplay.setText("c = "+a+" + "+b+" i");
		}
		
		// Return the ComplexNumber.
		return new ComplexNumber(a,b);
	}// end parseInput()
	
	// Display message if input is incorrectly formatted.
	static void inputError() {
		positionDisplay.setText("Input Error");
	}	
	
}//end ControlPanel class.

//end file


Back to the Julia applet page

How to Add Java Applets to Your Site

New on the Java Boutique:

New Review:

Time Management Made Easy with the Quartz Enterprise Job Scheduler
Why not just use the Java timer API? This open source scheduling API boasts simplicity, ease-of-integration, a well-rounded feature set, and it's free!

New Applet:

Reverse Complement
Reverse Complement is a simple applet that converts DNA or RNA sequences into three useful formats.

Elsewhere on internet.com:

WebDeveloper Java
Lots of Java information on webdeveloper.com

WDVL Java
Thorough Java resource at the Web Developer's Virtual Library.

ScriptSearch Java
Hundreds of free Java code files to download.

jGuru: Your View of the Java Universe
Customizable portal with online training, FAQs, regular news updates, and tutorials.

 Internet.com eBook Library
 IBM Software Construction Toolbox
 Microsoft RIA Development Center
 Destination .NET
XML error: not well-formed (invalid token) at line 38
advertisement
Receive Articles via our XML/RSS feed
Receive Articles via our XML/RSS feed

JavaBytes
Internet Cyclone
This powerful, easy-to-use, internet optimizer is for Windows 95, 98, ME, NT, 2000 and XP. It's designed to automatically optimize your Windows settings, boosting your Internet connection up to 200%.

Microsoft's Novell Investment Tops $340M
Fedora 10 Takes Shape
IBM Gives a Mobile Voice to Developers
Inadequate Tools Send Software Down the Drain
USB 3.0 One Step Closer to Reality
Would-Be Linux Contributors May Get a Leg Up
SAP, Oracle Holding Out on Ubuntu?
GIPS Technology to Voice-Enable iPhone Apps
Citrix CTO Eyes the Future of Virtualization
The Pitfalls of Open Source Litigation

DevXtra Editors' Blog: Executives Avoiding Cloud Computing in Droves
Q&A with James Reinders on the Intel Parallel Studio Beta Program
The Pros and Cons of Outsourcing Enterprise Emails
Hosting Options: Shared or Dedicated Server
Movin' On Up: How to Hop to a New Host
Simplifying Composite Applications with Service Component Architecture
The Guide to E-Mail Archiving and Management
Making XQuery Control Structures Work for You
Overview: C++ Gets an Overhaul
Sharpening Your Axis with Visual Basic 9

Advertising Info  |   Member Services  |   Contact Us  |   Help  |   Feedback  |   Site Map  |   Network Map  |   About



JupiterOnlineMedia

internet.comearthweb.comDevx.commediabistro.comGraphics.com

Search:

Jupitermedia Corporation has two divisions: Jupiterimages and JupiterOnlineMedia

Jupitermedia Corporate Info


Legal Notices, Licensing, Reprints, & Permissions, Privacy Policy.

Advertise | Newsletters | Tech Jobs | Shopping | E-mail Offers