001: package org.cougaar.demo.mandelbrot.util;
002:
003: /**
004: * Fractal math routines.
005: */
006: public final class FractalMath {
007:
008: private FractalMath() {
009: }
010:
011: /** @see #compute(double,double,double,double) */
012: public static byte mandelbrot(double x0, double y0) {
013: return compute(x0, y0, x0, y0);
014: }
015:
016: /** @see #compute(double,double,double,double) */
017: public static byte julia(double x0, double y0, double cx, double cy) {
018: return compute(x0, y0, cx, cy);
019: }
020:
021: /**
022: * Compute a single pixel for either the Mandelbrot or Julia Set.
023: *
024: * @param x0 the initial x value
025: * @param y0 the initial y value
026: * @param cx for the Mandlebrot Set use x0, otherwise for the Julia Set
027: * use a constant (e.g. -0.70176)
028: * @param cy for the Mandlebrot Set use y0, otherwise for the Julia Set
029: * use a constant (e.g. -0.3842)
030: */
031: public static byte compute(double x0, double y0, double cx,
032: double cy) {
033: double x = x0;
034: double y = y0;
035: int i;
036: for (i = 0; i < 255; i++) {
037: double x2 = x * x;
038: double y2 = y * y;
039: if ((x2 + y2) > 4.0) {
040: break;
041: }
042: double tmp = x * y;
043: tmp += tmp; // tmp *= 2.0
044: x = x2 - y2 + cx;
045: y = tmp + cy;
046: }
047: return (byte) i;
048: }
049:
050: /** @see #compute(double,double,double,double,boolean,double,double) */
051: public static byte[] mandelbrot(int width, int height,
052: double x_min, double x_max, double y_min, double y_max) {
053: return compute(width, height, x_min, x_max, y_min, y_max,
054: false, 0, 0);
055: }
056:
057: /** @see #compute(double,double,double,double,boolean,double,double) */
058: public static byte[] julia(int width, int height, double x_min,
059: double x_max, double y_min, double y_max, double cx,
060: double cy) {
061: return compute(width, height, x_min, x_max, y_min, y_max, true,
062: cx, cy);
063: }
064:
065: /**
066: * Compute all pixel values within the given range.
067: *
068: * @param isJulia if true then use the "cx" and "cy" values to compute the
069: * Julia Set, otherwise ignore the "cx" and "cy" values and compute the
070: * MandelbrotSet
071: * @param cx only used if isJulia is true
072: * @param cy only used if isJulia is true
073: *
074: * @return an array of size (width*height).
075: */
076: public static byte[] compute(int width, int height, double x_min,
077: double x_max, double y_min, double y_max, boolean isJulia,
078: double cx, double cy) {
079:
080: validateRange(width, height);
081:
082: int data_length = (height * width);
083: byte[] data = new byte[data_length];
084:
085: compute(width, height, x_min, x_max, y_min, y_max, isJulia, cx,
086: cy, data);
087:
088: return data;
089: }
090:
091: /** @see #compute(double,double,double,double,boolean,double,double,byte[]) */
092: public static void mandelbrot(int width, int height, double x_min,
093: double x_max, double y_min, double y_max, byte[] data) {
094: compute(width, height, x_min, x_max, y_min, y_max, false, 0, 0,
095: data);
096: }
097:
098: /** @see #compute(double,double,double,double,boolean,double,double,byte[]) */
099: public static void julia(int width, int height, double x_min,
100: double x_max, double y_min, double y_max, double cx,
101: double cy, byte[] data) {
102: compute(width, height, x_min, x_max, y_min, y_max, true, cx,
103: cy, data);
104: }
105:
106: /**
107: * @see #compute(int,int,double,double,double,double,boolean,double,double)
108: * Same as the other "compute", except pass in the byte[] instead of
109: * allocating and returning one.
110: */
111: public static void compute(int width, int height, double x_min,
112: double x_max, double y_min, double y_max, boolean julia,
113: double cx, double cy, byte[] data) {
114:
115: // validate
116: validateRange(width, height);
117: int data_length = (height * width);
118: if (data == null || data.length < data_length) {
119: throw new IllegalArgumentException("Given "
120: + (data == null ? "null" : "small byte["
121: + data.length + "]")
122: + " data array, expecting a byte[(" + width + "*"
123: + height + ")]");
124: }
125:
126: // compute step size
127: double x_step = (x_max - x_min) / width;
128: double y_step = (y_max - y_min) / height;
129:
130: // compute data
131: //
132: // note that we use
133: // v += v_step
134: // instead of
135: // v = min_v + (i * v_step)
136: // the "+=" is faster but introduces (negligible) rounding errors.
137: int data_index = 0;
138: double y = y_min;
139: for (int row = 0; row < height; row++) {
140: double x = x_min;
141: for (int col = 0; col < width; col++) {
142: byte b = compute(x, y, (julia ? cx : x), (julia ? cy
143: : y));
144: data[data_index++] = b;
145: x += x_step;
146: }
147: y += y_step;
148: }
149: }
150:
151: private static void validateRange(int width, int height) {
152: if (width <= 0) {
153: throw new IllegalArgumentException("Invalid width: "
154: + width);
155: }
156: if (height <= 0) {
157: throw new IllegalArgumentException("Invalid height: "
158: + height);
159: }
160: }
161: }
|