// The class Julia implements the construction of a Julia set. You give it the Julia set parameter c, // the region over which to compute, the grid density, and the max number of iterations. Then call compute, // and it will return you a 2d array of the iteration values at each grid point. // Sample usage: // #(0.3, 0.9) => complex c; // #(-1, -1) => complex lower_left; // #(1, 1) => complex upper_right; // 20 => int num_points_x; // 20 => int num_points_y; // 30 => int max_iter; // // Julia j; // j.setC(c); // j.setLowerLeft(lower_left); // j.setUpperRight(upper_right); // j.setNumPointsX(num_points_x); // j.setNumPointsY(num_points_y); // j.setMaxIter(max_iter); // j.compute() @=> int iter_values[][]; // // for(0 => int i; i < num_points_x; i++) { // for(0 => int j; j < num_points_y; j++) { // <<<"Val[", i, "][", j, "]:", iter_values[i][j]>>>; // } // } public class Julia { // c_ is the Julia set parameter that governs which Julia set we are creating. #(0.5, 0.5) => complex c_; // lower_left_ and lower_right_ determine our region in the complex plane. #(-1, -1) => complex lower_left_; #(1, 1) => complex upper_right_; // num_points_x_ and num_points_y_ determine our grid density. 4 => int num_points_x_; 4 => int num_points_y_; // max_iter tells us the largest number of iterations to try before giving up. 100 => int max_iter_; // All the setter functions for our class variables... public void setC(complex c) { c => c_; } public void setLowerLeft(complex lower_left) { lower_left => lower_left_; } public void setUpperRight(complex upper_right) { upper_right => upper_right_; } public void setNumPointsX(int num_points_x) { num_points_x => num_points_x_; } public void setNumPointsY(int num_points_y) { num_points_y => num_points_y_; } public void setMaxIter(int max_iter) { max_iter => max_iter_; } // The Julia set computation works as follows. Fix a number c in the complex plane. // Also specify a rectangular region in the plane, the desired granularity (number of // grid points), and max number of iterations. Then for each grid point (i, j), call it z0, // compute the sequence // z_{n+1} --> z_n^2 + c // and bail out if either n > max_iterations or if |z| > 2. The number of iterations // used for grid point (i, j) is the return value iter_values[i][j]. public int[][]compute() { // Spacing is the size of the dimension divided by the desired number of grid points. (upper_right_.re - lower_left_.re) / num_points_x_ => float x_spacing; (upper_right_.im - lower_left_.im) / num_points_y_ => float y_spacing; // Declare our return value. int iter_values[num_points_x_][num_points_y_]; // Walk through the grid rows... for(0 => int row; row < num_points_x_; row++) { // Set the current point's x value lower_left_.re + (row + 0.5) * x_spacing => float cur_x; // And walk through the grid columns... for(0 => int column; column < num_points_y_; column++) { // Set the current point's y value. lower_left_.im + (column + 0.5) * y_spacing => float cur_y; // Make our complex grid point z_0. #(cur_x, cur_y) => complex z; <<<"Iterating at", z>>>; // After the iteration, we either broke out of the loop early, // or reached the max iteration limit. Either way, set the return value // for this grid point. compute_iteration(z) => iter_values[row][column]; <<<"\tSetting iter[", row, "][", column, "] to: ", iter_values[row][column]>>>; } } // Return our newly-computed values. return iter_values; } // Take a complex point z, and use the class variables c_ and max_iter_. // Iterate on z --> z^2 + c until either we reach the maximum number of iterations, or // the magnitude of z becomes greater than 2.0. private int compute_iteration(complex z) { // Initialize the number of iterations to zero. 0 => int cur_iter; // Iterate at most max_iter times... while (cur_iter < max_iter_) { <<<"\t\titeration", cur_iter, ": |z| =", magnitude(z)>>>; // If the magnitude is greater than two, leave the loop. if(magnitude(z) > 2.0) { break; } // Otherwise, set z_{n+1} = z_n^2 + c and go to the next iteration. z * z + c_ => z; cur_iter++; } // Return the iteration value for this point. return cur_iter; } // Supposedly there is a c.mag, but it doesn't seem to work. private float magnitude(complex c) { return Math.sqrt(c.re * c.re + c.im * c.im); } }