import java.applet.*;
import java.util.*;
import java.io.*;
import java.net.*;
import java.awt.*;
import java.awt.image.ColorModel;
import java.awt.image.MemoryImageSource;
/* portions of this code were adapted from the DitherTest applet */
/* fractal faulting codes adapted from Usenet and published references
* - Basic faulting on a plane adapted from 'faultmap' by Aurel Balmosan
* (aurel@xylo.owl.de) -- some significant changes made
*/
public class SpectralSynthesisApplet extends Applet implements Runnable
{
/************************************************************
* Boilerplate methods to handle painting and initialization
************************************************************/
private int width = 256;
private int height = 256;
private double scalefactor = 1.0;
private int[][] heightfield;
private Random rgen;
private Image img;
private boolean started;
public boolean handleEvent(Event evt)
{
if (evt.id == Event.WINDOW_DESTROY) System.exit(0);
return super.handleEvent(evt);
}
public boolean action( Event evt, Object arg)
{
return true;
}
String calcString = "Calculating...";
String calcStyle = "planet";
public void paint(Graphics g)
{
int w = size().width;
int h = size().height;
if (img == null) {
super.paint(g);
g.setColor(Color.black);
FontMetrics fm = g.getFontMetrics();
int x = (w - fm.stringWidth(calcString))/2;
int y = h/2;
g.drawString(calcString, x, y);
} else {
g.drawImage(img, 0, 0, w, h, this);
}
}
public void init()
{
int w = Integer.parseInt(getParameter("width"));
if (w<=0 || w>256) w=width;
width=w;
height=w;
scalefactor = 256/width;
rgen = new Random();
initgauss();
started = false;
calcStyle = getParameter("style");
start();
}
synchronized void BuildImage()
{
/* build the image for display -- greyscale */
int pixels[];
int i, j, a, index = 0, min, max;
// calculate range of values in heightfield
min = heightfield[0][0];
max = heightfield[0][0];
for (i=0;i max) max = heightfield[i][j];
}
}
scalefactor = 255.0 / (max-min);
pixels = new int[width * height];
for (i=0;i255) a=255;
/*if (a>255) a=255;*/
pixels[index++] = (255 << 24) | (a << 16) | (a << 8) | a;
}
}
img = createImage(new MemoryImageSource(width, height,
ColorModel.getRGBdefault(),
pixels, 0, width));
repaint();
}
/************************************************************
* Thread methods to handle processing in the background
************************************************************/
Thread kicker;
public /*synchronized*/ void start() {
if (!started) {
started = true;
kicker = new Thread(this);
kicker.start();
} else if ((kicker != null) && (kicker.isAlive()))
kicker.resume();
}
public /*synchronized*/ void stop() {
try {
if ((kicker != null) && (kicker.isAlive())) {
kicker.suspend();
}
} catch (Exception e) {
}
}
public void restart() {
try {
if (kicker != null) {
kicker.stop();
}
} catch (Exception e) {
}
kicker = null;
img = null;
started = false;
start();
}
public void run()
{
Thread me = Thread.currentThread();
me.setPriority(4);
if (calcStyle.equals("planet"))
DoPlanet();
else
DoClouds();
}
/*
Fractal forgery generator for the PPM toolkit
Originally designed and implemented in December of 1989 by
John Walker as a stand-alone program for the Sun and MS-DOS
under Turbo C. Adapted in September of 1991 for use with Jef
Poskanzer's raster toolkit.
References cited in the comments are:
Foley, J. D., and Van Dam, A., Fundamentals of Interactive
Computer Graphics, Reading, Massachusetts: Addison
Wesley, 1984.
Peitgen, H.-O., and Saupe, D. eds., The Science Of Fractal
Images, New York: Springer Verlag, 1988.
Press, W. H., Flannery, B. P., Teukolsky, S. A., Vetterling,
W. T., Numerical Recipes In C, New Rochelle: Cambridge
University Press, 1988.
Author:
John Walker
Autodesk SA
Avenue des Champs-Montants 14b
CH-2074 MARIN
Switzerland
Usenet: kelvin@Autodesk.com
Fax: 038/33 88 15
Voice: 038/33 76 33
Permission to use, copy, modify, and distribute this software and
its documentation for any purpose and without fee is hereby
granted, without any conditions or restrictions. This software is
provided "as is" without express or implied warranty.
PLUGWARE!
If you like this kind of stuff, you may also enjoy "James Gleick's
Chaos--The Software" for MS-DOS, available for $59.95 from your
local software store or directly from Autodesk, Inc., Attn: Science
Series, 2320 Marinship Way, Sausalito, CA 94965, USA. Telephone:
(800) 688-2344 toll-free or, outside the U.S. (415) 332-2344 Ext
4886. Fax: (415) 289-4718. "Chaos--The Software" includes a more
comprehensive fractal forgery generator which creates
three-dimensional landscapes as well as clouds and planets, plus
five more modules which explore other aspects of Chaos. The user
guide of more than 200 pages includes an introduction by James
Gleick and detailed explanations by Rudy Rucker of the mathematics
and algorithms used by each program.
*/
static private final int nrand = 4; /* Gauss() sample count */
private double arand, gaussadd, gaussfac; /* Gaussian random parameters */
private double fracdim; /* Fractal dimension */
private double powscale; /* Power law scaling exponent */
private int meshsize = 128; /* FFT mesh size */
private int rseed; /* Current random seed */
private boolean seedspec = false; /* Did the user specify a seed ? */
private boolean clouds = false; /* Just generate clouds */
private boolean stars = false; /* Just generate stars */
/* FOURN -- Multi-dimensional fast Fourier transform
Called with arguments:
data A one-dimensional array of doubles, indexed from one
(NOTE!!! NOT ZERO!!),
containing pairs of numbers representing the complex
valued samples. The Fourier transformed results are
returned in the same array.
nn An array specifying the edge size in each dimension.
THIS ARRAY IS INDEXED FROM ONE, AND ALL THE EDGE
SIZES MUST BE POWERS OF TWO!!!
ndim Number of dimensions of FFT to perform. Set to 2 for
two dimensional FFT.
isign If 1, a Fourier transform is done; if -1 the inverse
transformation is performed.
This function is essentially as given in Press et al., "Numerical
Recipes In C", Section 12.11, pp. 467-470.
*/
private void fft2d(double[][][] x, int[] nn, int ndim, int isign)
{
// interface to fourn -- copies x to a vector of doubles
double[] a;
int idim, ntot=1, i, j, k, n;
// should raise an exception if not exactly two dimensions
for (idim = 1; idim <= ndim; idim++)
ntot *= nn[idim];
ntot*=2;
a = new double[ntot+1];
n=1;
for (i=0;i= 1; idim--) {
n = nn[idim];
nrem = ntot / (n * nprev);
ip1 = nprev << 1;
ip2 = ip1 * n;
ip3 = ip2 * nrem;
i2rev = 1;
for (i2 = 1; i2 <= ip2; i2 += ip1) {
if (i2 < i2rev) {
for (i1 = i2; i1 <= i2 + ip1 - 2; i1 += 2) {
for (i3 = i1; i3 <= ip3; i3 += ip2) {
i3rev = i2rev + i3 - i2;
tempr=data[i3]; data[i3] = (data[i3rev]); data[i3rev] = tempr;
tempr=data[i3 + 1]; data[i3 + 1] = data[i3rev + 1]; data[i3rev + 1] = tempr;
}
}
}
ibit = ip2 >> 1;
while (ibit >= ip1 && i2rev > ibit) {
i2rev -= ibit;
ibit >>= 1;
}
i2rev += ibit;
}
ifp1 = ip1;
while (ifp1 < ip2) {
ifp2 = ifp1 << 1;
theta = isign * (Math.PI * 2) / (ifp2 / ip1);
wtemp = Math.sin(0.5 * theta);
wpr = -2.0 * wtemp * wtemp;
wpi = Math.sin(theta);
wr = 1.0;
wi = 0.0;
for (i3 = 1; i3 <= ifp1; i3 += ip1) {
for (i1 = i3; i1 <= i3 + ip1 - 2; i1 += 2) {
for (i2 = i1; i2 <= ip3; i2 += ifp2) {
k1 = i2;
k2 = k1 + ifp1;
tempr = wr * data[k2] - wi * data[k2 + 1];
tempi = wr * data[k2 + 1] + wi * data[k2];
data[k2] = data[k1] - tempr;
data[k2 + 1] = data[k1 + 1] - tempi;
data[k1] += tempr;
data[k1 + 1] += tempi;
}
}
wr = (wtemp = wr) * wpr - wi * wpi + wr;
wi = wi * wpr + wtemp * wpi + wi;
}
ifp1 = ifp2;
}
nprev *= n;
}
}
/* INITGAUSS -- Initialise random number generators. As given in
Peitgen & Saupe, page 77. */
private void initgauss()
{
/* Range of random generator */
arand = Math.pow(2.0, 15.0) - 1.0;
gaussadd = Math.sqrt(3.0 * nrand);
gaussfac = 2 * gaussadd / (nrand * arand);
}
/* GAUSS -- Return a Gaussian random number. As given in Peitgen
& Saupe, page 77. */
private double gauss()
{
int i;
double sum = 0.0;
for (i = 1; i <= nrand; i++) {
sum += Math.random();
}
return gaussfac * sum - gaussadd;
}
/* SPECTRALSYNTH -- Spectrally synthesised fractal motion in two
dimensions. This algorithm is given under the
name SpectralSynthesisFM2D on page 108 of
Peitgen & Saupe. */
private void spectralsynth(double[][][] x, int n, double h)
{
int i, j, i0, j0, nsize[];
double rad, phase, rcos, rsin;
nsize = new int[3];
for (i = 0; i <= n / 2; i++) {
for (j = 0; j <= n / 2; j++) {
phase = 2 * Math.PI * Math.random();
if (i != 0 || j != 0) {
rad = Math.pow((double) (i * i + j * j), -(h + 1) / 2) * gauss();
} else {
rad = 0;
}
rcos = rad * Math.cos(phase);
rsin = rad * Math.sin(phase);
x[i][j][0] = rcos;
x[i][j][1] = rsin;
i0 = (i == 0) ? 0 : n - i;
j0 = (j == 0) ? 0 : n - j;
x[i0][j0][0] = rcos;
x[i0][j0][1] = - rsin;
}
}
x[n / 2][0][1] = 0; // imaginary
x[0][n / 2][1] = 0;
x[n / 2][n / 2][1] = 0;
for (i = 1; i <= n / 2 - 1; i++) {
for (j = 1; j <= n / 2 - 1; j++) {
phase = 2 * Math.PI * Math.random();
rad = Math.pow((double) (i * i + j * j), -(h + 1) / 2) * gauss();
rcos = rad * Math.cos(phase);
rsin = rad * Math.sin(phase);
x[i][n - j][0] = rcos;
x[i][n - j][1] = rsin;
x[n - i][j][0] = rcos;
x[n - i][j][1] = - rsin;
}
}
nsize[0] = 0;
nsize[1] = nsize[2] = n; /* Dimension of frequency domain array */
fft2d(x, nsize, 2, -1); /* Take inverse 2D Fourier transform */
}
/* The default fractal dimension and power scale depend upon
whether we're generating a planet or clouds. */
synchronized public void DoClouds()
{
double[][][] x;
int i,j;
fracdim = 2.15;
powscale = 0.75;
x = new double[width][width][2]; // last dimension is real, imag
spectralsynth(x, width, 3.0 - fracdim);
heightfield = new int[width][width];
for (i=0;i