/*
    Most of this code was ported to Java from 'wvlt', for which
    a disclaimer is posted below.  The Java port was performed
    by Carl Burke, cburke@mitre.org, and is intended primarily
    for experiments with terrain synthesis and procedural textures.
    You may, of course, do what you wish with it.

    wvlt: The UBC Imager Wavelet Package -- Release 2.1
    ---------------------------------------------------
    Disclaimer
    ----------
    
    Bob Lewis produced this package and hereby releases it to the public
    domain.  Neither the author nor the University of British Columbia will be
    held responsible for its use, misuse, or abuse or any damages arising from
    same.
    
    Any comments regarding this package may, nevertheless, be sent to
    "bobl@cs.ubc.ca".
    Any comments regarding the Java port of this package may be sent to
    "cburke@mitre.org".
 */

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;
/*
 *	-----------------------------------------------------------------
 *	Battle-Lemarie filter
 *
 *	Source: Mallat, "A Theory for Multiresolution Signal Decomposition: The
 *	  Wavelet Representation", IEEE PAMI, v. 11, no. 7, 674-693, Table 1
 */

class wfltrBattleLemarie extends WaveletFilter
{
    static final double M_SQRT2     = 1.41421356237309504880168872420969808;
    static final double cHBattleLemarie[] = {
	    M_SQRT2 * -0.002,
	    M_SQRT2 * -0.003,
	    M_SQRT2 *  0.006,
	    M_SQRT2 *  0.006,
	    M_SQRT2 * -0.013,
	    M_SQRT2 * -0.012,
	    M_SQRT2 *  0.030,  /*  5 and 6 sign change from Mallat's paper */
	    M_SQRT2 *  0.023,
	    M_SQRT2 * -0.078,
	    M_SQRT2 * -0.035,
	    M_SQRT2 *  0.307,
	    M_SQRT2 *  0.542,
	    M_SQRT2 *  0.307,
	    M_SQRT2 * -0.035,
	    M_SQRT2 * -0.078,
	    M_SQRT2 *  0.023,
	    M_SQRT2 *  0.030,
	    M_SQRT2 * -0.012,
	    M_SQRT2 * -0.013,
	    M_SQRT2 *  0.006,
	    M_SQRT2 *  0.006,
	    M_SQRT2 * -0.003,
	    M_SQRT2 * -0.002,
	      0.0
    };
    public wfltrBattleLemarie()
    {
	cH = cHBattleLemarie;
	nH = cH.length;
	cHtilde = cHBattleLemarie;
	nHtilde = cH.length;
	offH = 11;
	offG = 11;
	offHtilde = 11;
	offGtilde = 11;
    }
}
/*
 *	-----------------------------------------------------------------
 *	Burt-Adelson filter
 *
 *	Source: TLoW, Table 8.4
 */

class wfltrBurtAdelson extends WaveletFilter
{
    static final double M_SQRT2     = 1.41421356237309504880168872420969808;
    static final double cHBurtAdelson[] = {
	    M_SQRT2 * -1.0 / 20.0,
	    M_SQRT2 *  5.0 / 20.0,
	    M_SQRT2 * 12.0 / 20.0,
	    M_SQRT2 *  5.0 / 20.0,
	    M_SQRT2 * -1.0 / 20.0,
	      0.0
    };
    static final double cHtildeBurtAdelson[] = {
	      0.0,
	    M_SQRT2 *  -3.0 / 280.0,
	    M_SQRT2 * -15.0 / 280.0,
	    M_SQRT2 *  73.0 / 280.0,
	    M_SQRT2 * 170.0 / 280.0,
	    M_SQRT2 *  73.0 / 280.0,
	    M_SQRT2 * -15.0 / 280.0,
	    M_SQRT2 *  -3.0 / 280.0
    };
    public wfltrBurtAdelson()
    {
	cH = cHBurtAdelson;
	nH = cH.length;
	cHtilde = cHtildeBurtAdelson;
	nHtilde = cHtilde.length;
	offH = 2;
	offG = 2;
	offHtilde = 4;
	offGtilde = 2;
    }
}
/*
 *	-----------------------------------------------------------------
 *	Coiflet filters
 *
 *	Source: Beylkin, Coifman, and Rokhlin "Fast Wavelet Transforms and
 *	  Numerical Algorithms I", Comm. Pure Appl. Math, v. 44, Appendix A
 */

class wfltrCoiflet2 extends WaveletFilter
{
    static final double M_SQRT2     = 1.41421356237309504880168872420969808;
    static final double SQRT15 = 3.87298334620741688517927;
    static final double cHCoiflet2[] = {
	    M_SQRT2 * (SQRT15 - 3) / 32.0,
	    M_SQRT2 * (1 - SQRT15) / 32.0,
	    M_SQRT2 * (6 - 2 * SQRT15) / 32.0,
	    M_SQRT2 * (2 * SQRT15 + 6) / 32.0,
	    M_SQRT2 * (SQRT15 + 13) / 32.0,
	    M_SQRT2 * (9 - SQRT15) / 32.0
    };
    public wfltrCoiflet2()
    {
	cH = cHCoiflet2;
	nH = cH.length;
	cHtilde = cHCoiflet2;
	nHtilde = cHtilde.length;
	offH = 3;
	offG = 1;
	offHtilde = 3;
	offGtilde = 1;
    }
}
/*
 *	-----------------------------------------------------------------
 *	Coiflet filters
 *
 *	Source: Beylkin, Coifman, and Rokhlin "Fast Wavelet Transforms and
 *	  Numerical Algorithms I", Comm. Pure Appl. Math, v. 44, Appendix A
 */

class wfltrCoiflet4 extends WaveletFilter
{
    static final double M_SQRT2     = 1.41421356237309504880168872420969808;
    static final double SQRT15 = 3.87298334620741688517927;
    static double cHCoiflet4[] = {
	     0.0011945726958388,
	    -0.01284557955324,
	     0.024804330519353,
	     0.050023519962135,
	    -0.15535722285996,
	    -0.071638282295294,
	     0.57046500145033,
	     0.75033630585287,
	     0.28061165190244,
	    -0.0074103835186718,
	    -0.014611552521451,
	    -0.0013587990591632
    };
    public wfltrCoiflet4()
    {
	cH = cHCoiflet4;
	nH = cH.length;
	cHtilde = cHCoiflet4;
	nHtilde = cHtilde.length;
	offH = 6;
	offG = 4;
	offHtilde = 6;
	offGtilde = 4;
    }
}
/*
 *	-----------------------------------------------------------------
 *	Coiflet filters
 *
 *	Source: Beylkin, Coifman, and Rokhlin "Fast Wavelet Transforms and
 *	  Numerical Algorithms I", Comm. Pure Appl. Math, v. 44, Appendix A
 */

class wfltrCoiflet6 extends WaveletFilter
{
    static final double M_SQRT2     = 1.41421356237309504880168872420969808;
    static final double SQRT15 = 3.87298334620741688517927;
    static final double cHCoiflet6[] = {
	    -0.0016918510194918,
	    -0.00348787621998426,
	     0.019191160680044,
	     0.021671094636352,
	    -0.098507213321468,
	    -0.056997424478478,
	     0.45678712217269,
	     0.78931940900416,
	     0.38055713085151,
	    -0.070438748794943,
	    -0.056514193868065,
	     0.036409962612716,
	     0.0087601307091635,
	    -0.011194759273835,
	    -0.0019213354141368,
	     0.0020413809772660,
	     0.00044583039753204,
	    -0.00021625727664696
    };
    public wfltrCoiflet6()
    {
	cH = cHCoiflet6;
	nH = cH.length;
	cHtilde = cHCoiflet6;
	nHtilde = cHtilde.length;
	offH = 6;
	offG = 10;
	offHtilde = 6;
	offGtilde = 10;
    }
}
/*
 *	-----------------------------------------------------------------
 *	Daubechies filters
 *
 *	Source: TLoW, Table 6.1
 */

class wfltrDaubechies10 extends WaveletFilter
{
    static final double cHDaubechies10[] = {
	     0.1601023979741929,
	     0.6038292697971895,
	     0.7243085284377726,
	     0.1384281459013203,
	    -0.2422948870663823,
	    -0.0322448695846381,
	     0.0775714938400459,
	    -0.0062414902127983,
	    -0.0125807519990820,
	     0.0033357252854738
    };
    public wfltrDaubechies10()
    {
	cH = cHDaubechies10;
	nH = cH.length;
	cHtilde = cHDaubechies10;
	nHtilde = cHtilde.length;
	offH = 1;
	offG = 7;
	offHtilde = 1;
	offGtilde = 7;
    }
}
/*
 *	-----------------------------------------------------------------
 *	Daubechies filters
 *
 *	Source: TLoW, Table 6.1
 */

class wfltrDaubechies12 extends WaveletFilter
{
    static final double cHDaubechies12[] = {
	     0.1115407433501095,
	     0.4946238903984533,
	     0.7511339080210959,
	     0.3152503517091982,
	    -0.2262646939654400,
	    -0.1297668675672625,
	     0.0975016055873225,
	     0.0275228655303053,
	    -0.0315820393184862,
	     0.0005538422011614,
	     0.0047772575119455,
	    -0.0010773010853085
    };
    public wfltrDaubechies12()
    {
	cH = cHDaubechies12;
	nH = cH.length;
	cHtilde = cHDaubechies12;
	nHtilde = cHtilde.length;
	offH = 1;
	offG = 9;
	offHtilde = 1;
	offGtilde = 9;
    }
}
/*
 *	-----------------------------------------------------------------
 *	Daubechies filters
 *
 *	Source: TLoW, Table 6.1
 */

class wfltrDaubechies20 extends WaveletFilter
{
    static final double cHDaubechies20[] = {
	     0.026670057901,
	     0.188176800078,
	     0.527201188932,
	     0.688459039454,
	     0.281172343661,
	    -0.249846424327,
	    -0.195946274377,
	     0.127369340336,
	     0.093057364604,
	    -0.071394147166,
	    -0.029457536822,
	     0.033212674059,
	     0.003606553567,
	    -0.010733175483,
	     0.001395351747,
	     0.001992405295,
	    -0.000685856695,
	    -0.000116466855,
	     0.000093588670,
	    -0.000013264203
    };
    public wfltrDaubechies20()
    {
	cH = cHDaubechies20;
	nH = cH.length;
	cHtilde = cHDaubechies20;
	nHtilde = cHtilde.length;
	offH = 2;
	offG = 16;
	offHtilde = 2;
	offGtilde = 16;
    }
}
/*
 *	-----------------------------------------------------------------
 *	Daubechies filters
 *
 *	Source: TLoW, Table 6.1
 */

class wfltrDaubechies4 extends WaveletFilter
{
    static final double M_SQRT2     = 1.41421356237309504880168872420969808;
    static final double SQRT3 = 1.73205080756887729352745;
    static final double cHDaubechies4[] = {
	    M_SQRT2 * (1 + SQRT3) / 8.0,
	    M_SQRT2 * (3 + SQRT3) / 8.0,
	    M_SQRT2 * (3 - SQRT3) / 8.0,
	    M_SQRT2 * (1 - SQRT3) / 8.0
    };
    public wfltrDaubechies4()
    {
	cH = cHDaubechies4;
	nH = cH.length;
	cHtilde = cHDaubechies4;
	nHtilde = cHtilde.length;
	offH = 1;
	offG = 1;
	offHtilde = 1;
	offGtilde = 1;
    }
}
/*
 *	-----------------------------------------------------------------
 *	Daubechies filters
 *
 *	Source: TLoW, Table 6.1
 */

class wfltrDaubechies6 extends WaveletFilter
{
    static final double cHDaubechies6[] = {
	     0.332670552950,
	     0.806891509311,
	     0.459877502118,
	    -0.135011020010,
	    -0.085441273882,
	     0.035226291882
    };
    public wfltrDaubechies6()
    {
	cH = cHDaubechies6;
	nH = cH.length;
	cHtilde = cHDaubechies6;
	nHtilde = cHtilde.length;
	offH = 1;
	offG = 3;
	offHtilde = 1;
	offGtilde = 3;
    }
}
/*
 *	-----------------------------------------------------------------
 *	Daubechies filters
 *
 *	Source: TLoW, Table 6.1
 */

class wfltrDaubechies8 extends WaveletFilter
{
    static final double cHDaubechies8[] = {
	     0.230377813309,
	     0.714846570553,
	     0.6308807667930,
	    -0.027983769417,
	    -0.187034811719,
	     0.030841381836,
	     0.032883011667,
	    -0.010597401785
    };
    public wfltrDaubechies8()
    {
	cH = cHDaubechies8;
	nH = cH.length;
	cHtilde = cHDaubechies8;
	nHtilde = cHtilde.length;
	offH = 1;
	offG = 5;
	offHtilde = 1;
	offGtilde = 5;
    }
}
/*
 *	-----------------------------------------------------------------
 *	Haar filter
 *
 *	Source: TLoW, p. 10 (and lots of other places!)
 */

class wfltrHaar extends WaveletFilter
{
    static final double M_SQRT2     = 1.41421356237309504880168872420969808;
    static final double cHHaar[] = {
	    M_SQRT2 * 1.0 / 2.0,
	    M_SQRT2 * 1.0 / 2.0
    };
    public wfltrHaar()
    {
	cH = cHHaar;
	nH = cH.length;
	cHtilde = cHHaar;
	nHtilde = cHtilde.length;
	offH = 0;
	offG = 0;
	offHtilde = 0;
	offGtilde = 0;
    }
}
/*
 *	-----------------------------------------------------------------
 *	Pseudocoiflet filter
 *	Source: Reissell, "Multiresolution Geometric Algorithms Using Wavelets I:
 *	  Representation for Parametric Curves and Surfaces", UBC TR 93-17, p. 33
 */

class wfltrPseudocoiflet4 extends WaveletFilter
{
    static final double M_SQRT2     = 1.41421356237309504880168872420969808;
    static final double cHPseudocoiflet4[] = {
	    M_SQRT2 *  -1.0 / 512.0,
	      0.0,
	    M_SQRT2 *  18.0 / 512.0,
	    M_SQRT2 * -16.0 / 512.0,
	    M_SQRT2 * -63.0 / 512.0,
	    M_SQRT2 * 144.0 / 512.0,
	    M_SQRT2 * 348.0 / 512.0,
	    M_SQRT2 * 144.0 / 512.0,
	    M_SQRT2 * -63.0 / 512.0,
	    M_SQRT2 * -16.0 / 512.0,
	    M_SQRT2 *  18.0 / 512.0,
	      0.0,
	    M_SQRT2 *  -1.0 / 512.0,
	  0.0
    };
    static final double cHtildePseudocoiflet4[] = {
	      0.0,
	    M_SQRT2 *  -1.0 / 32.0,
	      0.0,
	    M_SQRT2 *   9.0 / 32.0,
	    M_SQRT2 *  16.0 / 32.0,
	    M_SQRT2 *   9.0 / 32.0,
	      0.0,
	    M_SQRT2 *  -1.0 / 32.0
    };
    public wfltrPseudocoiflet4()
    {
	cH = cHPseudocoiflet4;
	nH = cH.length;
	cHtilde = cHtildePseudocoiflet4;
	nHtilde = cHtilde.length;
	offH = 6;
	offG = 2;
	offHtilde = 4;
	offGtilde = 6;
    }
}
/*
 *	-----------------------------------------------------------------
 *	Spline filters
 *
 *	Source: TLoW, Table 8.2 (corrected)
 */

class wfltrSpline_2_2 extends WaveletFilter
{
    static final double M_SQRT2     = 1.41421356237309504880168872420969808;
    static final double cHSpline_2[] = {
	    M_SQRT2 * -0.125,
	    M_SQRT2 *  0.25,
	    M_SQRT2 *  0.75,
	    M_SQRT2 *  0.25,
	    M_SQRT2 * -0.125,
	      0.0
    };
    static final double cHSpline_3[] = {
	    M_SQRT2 * 1.0 / 8.0,
	    M_SQRT2 * 3.0 / 8.0,
	    M_SQRT2 * 3.0 / 8.0,
	    M_SQRT2 * 1.0 / 8.0
    };
    static final double cHSpline_4[] = {
	    M_SQRT2 *   3.0 / 128.0,
	    M_SQRT2 *  -6.0 / 128.0,
	    M_SQRT2 * -16.0 / 128.0,
	    M_SQRT2 *  38.0 / 128.0,
	    M_SQRT2 *  90.0 / 128.0,
	    M_SQRT2 *  38.0 / 128.0,
	    M_SQRT2 * -16.0 / 128.0,
	    M_SQRT2 *  -6.0 / 128.0,
	    M_SQRT2 *   3.0 / 128.0,
	       0.0
    };
    static final double cHtildeSpline_2[] = {
	       0.0,
	    M_SQRT2 * 1.0 / 4.0,
	    M_SQRT2 * 2.0 / 4.0,
	    M_SQRT2 * 1.0 / 4.0
    };
    static final double cHtildeSpline_3[] = {
	    M_SQRT2 *  3.0 / 64.0,
	    M_SQRT2 * -9.0 / 64.0,
	    M_SQRT2 * -7.0 / 64.0,
	    M_SQRT2 * 45.0 / 64.0,
	    M_SQRT2 * 45.0 / 64.0,
	    M_SQRT2 * -7.0 / 64.0,
	    M_SQRT2 * -9.0 / 64.0,
	    M_SQRT2 *  3.0 / 64.0
    };
    static final double cHtildeSpline_7[] = {
	    M_SQRT2 *   -35.0 / 16384.0,
	    M_SQRT2 *  -105.0 / 16384.0,
	    M_SQRT2 *  -195.0 / 16384.0,
	    M_SQRT2 *   865.0 / 16384.0,
	    M_SQRT2 *   363.0 / 16384.0,	/* corrected ("363" was "336") in text) */
	    M_SQRT2 * -3489.0 / 16384.0,
	    M_SQRT2 *  -307.0 / 16384.0,
	    M_SQRT2 * 11025.0 / 16384.0,
	    M_SQRT2 * 11025.0 / 16384.0,
	    M_SQRT2 *  -307.0 / 16384.0,
	    M_SQRT2 * -3489.0 / 16384.0,
	    M_SQRT2 *   363.0 / 16384.0,	/* corrected ("363" was "336") in text) */
	    M_SQRT2 *   865.0 / 16384.0,
	    M_SQRT2 *  -195.0 / 16384.0,
	    M_SQRT2 *  -105.0 / 16384.0,
	    M_SQRT2 *   -35.0 / 16384.0
    };
    public wfltrSpline_2_2()
    {
	cH = cHSpline_2;
	nH = cH.length;
	cHtilde = cHtildeSpline_2;
	nHtilde = cHtilde.length;
	offH = 2;
	offG = 0;
	offHtilde = 2;
	offGtilde = 2;
    }
}
/*
 *	-----------------------------------------------------------------
 *	Spline filters
 *
 *	Source: TLoW, Table 8.2 (corrected)
 */

class wfltrSpline_2_4 extends WaveletFilter
{
    static final double M_SQRT2     = 1.41421356237309504880168872420969808;
    static final double cHSpline_2[] = {
	    M_SQRT2 * -0.125,
	    M_SQRT2 *  0.25,
	    M_SQRT2 *  0.75,
	    M_SQRT2 *  0.25,
	    M_SQRT2 * -0.125,
	      0.0
    };
    static final double cHSpline_3[] = {
	    M_SQRT2 * 1.0 / 8.0,
	    M_SQRT2 * 3.0 / 8.0,
	    M_SQRT2 * 3.0 / 8.0,
	    M_SQRT2 * 1.0 / 8.0
    };
    static final double cHSpline_4[] = {
	    M_SQRT2 *   3.0 / 128.0,
	    M_SQRT2 *  -6.0 / 128.0,
	    M_SQRT2 * -16.0 / 128.0,
	    M_SQRT2 *  38.0 / 128.0,
	    M_SQRT2 *  90.0 / 128.0,
	    M_SQRT2 *  38.0 / 128.0,
	    M_SQRT2 * -16.0 / 128.0,
	    M_SQRT2 *  -6.0 / 128.0,
	    M_SQRT2 *   3.0 / 128.0,
	       0.0
    };
    static final double cHtildeSpline_2[] = {
	       0.0,
	    M_SQRT2 * 1.0 / 4.0,
	    M_SQRT2 * 2.0 / 4.0,
	    M_SQRT2 * 1.0 / 4.0
    };
    static final double cHtildeSpline_3[] = {
	    M_SQRT2 *  3.0 / 64.0,
	    M_SQRT2 * -9.0 / 64.0,
	    M_SQRT2 * -7.0 / 64.0,
	    M_SQRT2 * 45.0 / 64.0,
	    M_SQRT2 * 45.0 / 64.0,
	    M_SQRT2 * -7.0 / 64.0,
	    M_SQRT2 * -9.0 / 64.0,
	    M_SQRT2 *  3.0 / 64.0
    };
    static final double cHtildeSpline_7[] = {
	    M_SQRT2 *   -35.0 / 16384.0,
	    M_SQRT2 *  -105.0 / 16384.0,
	    M_SQRT2 *  -195.0 / 16384.0,
	    M_SQRT2 *   865.0 / 16384.0,
	    M_SQRT2 *   363.0 / 16384.0,	/* corrected ("363" was "336") in text) */
	    M_SQRT2 * -3489.0 / 16384.0,
	    M_SQRT2 *  -307.0 / 16384.0,
	    M_SQRT2 * 11025.0 / 16384.0,
	    M_SQRT2 * 11025.0 / 16384.0,
	    M_SQRT2 *  -307.0 / 16384.0,
	    M_SQRT2 * -3489.0 / 16384.0,
	    M_SQRT2 *   363.0 / 16384.0,	/* corrected ("363" was "336") in text) */
	    M_SQRT2 *   865.0 / 16384.0,
	    M_SQRT2 *  -195.0 / 16384.0,
	    M_SQRT2 *  -105.0 / 16384.0,
	    M_SQRT2 *   -35.0 / 16384.0
    };
    public wfltrSpline_2_4()
    {
	cH = cHSpline_4;
	nH = cH.length;
	cHtilde = cHtildeSpline_2;
	nHtilde = cHtilde.length;
	offH = 4;
	offG = 0;
	offHtilde = 2;
	offGtilde = 4;
    }
}
/*
 *	-----------------------------------------------------------------
 *	Spline filters
 *
 *	Source: TLoW, Table 8.2 (corrected)
 */

class wfltrSpline_3_3 extends WaveletFilter
{
    static final double M_SQRT2     = 1.41421356237309504880168872420969808;
    static final double cHSpline_2[] = {
	    M_SQRT2 * -0.125,
	    M_SQRT2 *  0.25,
	    M_SQRT2 *  0.75,
	    M_SQRT2 *  0.25,
	    M_SQRT2 * -0.125,
	      0.0
    };
    static final double cHSpline_3[] = {
	    M_SQRT2 * 1.0 / 8.0,
	    M_SQRT2 * 3.0 / 8.0,
	    M_SQRT2 * 3.0 / 8.0,
	    M_SQRT2 * 1.0 / 8.0
    };
    static final double cHSpline_4[] = {
	    M_SQRT2 *   3.0 / 128.0,
	    M_SQRT2 *  -6.0 / 128.0,
	    M_SQRT2 * -16.0 / 128.0,
	    M_SQRT2 *  38.0 / 128.0,
	    M_SQRT2 *  90.0 / 128.0,
	    M_SQRT2 *  38.0 / 128.0,
	    M_SQRT2 * -16.0 / 128.0,
	    M_SQRT2 *  -6.0 / 128.0,
	    M_SQRT2 *   3.0 / 128.0,
	       0.0
    };
    static final double cHtildeSpline_2[] = {
	       0.0,
	    M_SQRT2 * 1.0 / 4.0,
	    M_SQRT2 * 2.0 / 4.0,
	    M_SQRT2 * 1.0 / 4.0
    };
    static final double cHtildeSpline_3[] = {
	    M_SQRT2 *  3.0 / 64.0,
	    M_SQRT2 * -9.0 / 64.0,
	    M_SQRT2 * -7.0 / 64.0,
	    M_SQRT2 * 45.0 / 64.0,
	    M_SQRT2 * 45.0 / 64.0,
	    M_SQRT2 * -7.0 / 64.0,
	    M_SQRT2 * -9.0 / 64.0,
	    M_SQRT2 *  3.0 / 64.0
    };
    static final double cHtildeSpline_7[] = {
	    M_SQRT2 *   -35.0 / 16384.0,
	    M_SQRT2 *  -105.0 / 16384.0,
	    M_SQRT2 *  -195.0 / 16384.0,
	    M_SQRT2 *   865.0 / 16384.0,
	    M_SQRT2 *   363.0 / 16384.0,	/* corrected ("363" was "336") in text) */
	    M_SQRT2 * -3489.0 / 16384.0,
	    M_SQRT2 *  -307.0 / 16384.0,
	    M_SQRT2 * 11025.0 / 16384.0,
	    M_SQRT2 * 11025.0 / 16384.0,
	    M_SQRT2 *  -307.0 / 16384.0,
	    M_SQRT2 * -3489.0 / 16384.0,
	    M_SQRT2 *   363.0 / 16384.0,	/* corrected ("363" was "336") in text) */
	    M_SQRT2 *   865.0 / 16384.0,
	    M_SQRT2 *  -195.0 / 16384.0,
	    M_SQRT2 *  -105.0 / 16384.0,
	    M_SQRT2 *   -35.0 / 16384.0
    };
    public wfltrSpline_3_3()
    {
	cH = cHSpline_3;
	nH = cH.length;
	cHtilde = cHtildeSpline_3;
	nHtilde = cHtilde.length;
	offH = 1;
	offG = 3;
	offHtilde = 3;
	offGtilde = 1;
    }
}
/*
 *	-----------------------------------------------------------------
 *	Spline filters
 *
 *	Source: TLoW, Table 8.2 (corrected)
 */

class wfltrSpline_3_7 extends WaveletFilter
{
    static final double M_SQRT2     = 1.41421356237309504880168872420969808;
    static final double cHSpline_2[] = {
	    M_SQRT2 * -0.125,
	    M_SQRT2 *  0.25,
	    M_SQRT2 *  0.75,
	    M_SQRT2 *  0.25,
	    M_SQRT2 * -0.125,
	      0.0
    };
    static final double cHSpline_3[] = {
	    M_SQRT2 * 1.0 / 8.0,
	    M_SQRT2 * 3.0 / 8.0,
	    M_SQRT2 * 3.0 / 8.0,
	    M_SQRT2 * 1.0 / 8.0
    };
    static final double cHSpline_4[] = {
	    M_SQRT2 *   3.0 / 128.0,
	    M_SQRT2 *  -6.0 / 128.0,
	    M_SQRT2 * -16.0 / 128.0,
	    M_SQRT2 *  38.0 / 128.0,
	    M_SQRT2 *  90.0 / 128.0,
	    M_SQRT2 *  38.0 / 128.0,
	    M_SQRT2 * -16.0 / 128.0,
	    M_SQRT2 *  -6.0 / 128.0,
	    M_SQRT2 *   3.0 / 128.0,
	       0.0
    };
    static final double cHtildeSpline_2[] = {
	       0.0,
	    M_SQRT2 * 1.0 / 4.0,
	    M_SQRT2 * 2.0 / 4.0,
	    M_SQRT2 * 1.0 / 4.0
    };
    static final double cHtildeSpline_3[] = {
	    M_SQRT2 *  3.0 / 64.0,
	    M_SQRT2 * -9.0 / 64.0,
	    M_SQRT2 * -7.0 / 64.0,
	    M_SQRT2 * 45.0 / 64.0,
	    M_SQRT2 * 45.0 / 64.0,
	    M_SQRT2 * -7.0 / 64.0,
	    M_SQRT2 * -9.0 / 64.0,
	    M_SQRT2 *  3.0 / 64.0
    };
    static final double cHtildeSpline_7[] = {
	    M_SQRT2 *   -35.0 / 16384.0,
	    M_SQRT2 *  -105.0 / 16384.0,
	    M_SQRT2 *  -195.0 / 16384.0,
	    M_SQRT2 *   865.0 / 16384.0,
	    M_SQRT2 *   363.0 / 16384.0,	/* corrected ("363" was "336") in text) */
	    M_SQRT2 * -3489.0 / 16384.0,
	    M_SQRT2 *  -307.0 / 16384.0,
	    M_SQRT2 * 11025.0 / 16384.0,
	    M_SQRT2 * 11025.0 / 16384.0,
	    M_SQRT2 *  -307.0 / 16384.0,
	    M_SQRT2 * -3489.0 / 16384.0,
	    M_SQRT2 *   363.0 / 16384.0,	/* corrected ("363" was "336") in text) */
	    M_SQRT2 *   865.0 / 16384.0,
	    M_SQRT2 *  -195.0 / 16384.0,
	    M_SQRT2 *  -105.0 / 16384.0,
	    M_SQRT2 *   -35.0 / 16384.0
    };
    public wfltrSpline_3_7()
    {
	cH = cHSpline_3;
	nH = cH.length;
	cHtilde = cHtildeSpline_7;
	nHtilde = cHtilde.length;
	offH = 1;
	offG = 7;
	offHtilde = 7;
	offGtilde = 1;
    }
}
class WaveletFilter
{
    double cH[];
    int nH;
    double cHtilde[];
    int nHtilde;
    int offH;
    int offG;
    int offHtilde;
    int offGtilde;
    boolean swapped;
    public WaveletFilter()
    {
	cH = null;
	cHtilde = null;
	nH = 0;
	nHtilde = 0;
	offH = 0;
	offG = 0;
	offHtilde = 0;
	offGtilde = 0;
	swapped = false;
    }

    /*
     *	'exchange' is only relevant for biorthogonal filters.  Orthogonal
     *	filters are unchanged.
     */

    public void exchange()
    {
	int iSwap;
	double pDSwap[];

	swapped = !swapped;

	iSwap = offH;
	offH = offHtilde;
	offHtilde = iSwap;

	iSwap = offG;
	offG = offGtilde;
	offGtilde = iSwap;

	iSwap = nH;
	nH = nHtilde;
	nHtilde = iSwap;

	pDSwap = cH;
	cH = cHtilde;
	cHtilde = pDSwap; 
    }

    /*
     * Utility functions
     */

    private int MOD(int i, int j)
    {
	return ((i) >= 0 ? (i) % (j) : ((j) - ((-(i)) % (j))) % (j));
    }

    /*
     *  Forward and backward wavelet transforms
     */

    /* this is the minimum-order wavelet filter allowed */
    static final int MIN_ORDER = 2;
    
    /* multidimensional transforms support a maximum of this many dimensions */
    static final int MXN_D = 32;
    
    /*
     *	To avoid lots of unnecessary malloc/free calls, especially in
     *	multidimensional transforms, we use a "static global" buffer that, at the
     *	highest level, will be allocated once to the maximum possible size and
     *	freed when done.
     */
    double aTmp1D[] = null;
    
    /* wfltr_convolve -- perform one convolution of a (general) wavelet transform */
    private void wfltr_convolve(
	    boolean isFwd,			/* in: true <=> forward transform */
	    double aIn[],	/* in: input data */
	    int aInBase,
	    int incA,			/* in: spacing of elements in aIn[] and aXf[] */
	    int n,				/* in: size of aIn and aXf */
	    double aXf[],	/* out: output data (OK if == aIn) */
	    int aXfBase)
    {
	int nDiv2 = n / 2;
	int iA, iHtilde, iGtilde, j, jH, jG, i;
	double sum;
	boolean flip;
    
	/*
	 *	According to Daubechies:
	 *
	 *	H is the analyzing smoothing filter.
	 *	G is the analyzing detail filter.
	 *	Htilde is the reconstruction smoothing filter.
	 *	Gtilde is the reconstruction detail filter.
	 */
    
	/* the reconstruction detail filter is the mirror of the analysis smoothing filter */
	int nGtilde = nH;
    
	/* the analysis detail filter is the mirror of the reconstruction smoothing filter */
	int nG = nHtilde;
    
	if (isFwd)
	{
	    /*
	     *	A single step of the analysis is summarized by:
	     *		aTmp1D[0..n/2-1] = H * a (smooth component)
	     *		aTmp1D[n/2..n-1] = G * a (detail component)
	     */
	    for (i = 0; i < nDiv2; i++)
	    {
		/*
		 *	aTmp1D[0..nDiv2-1] contains the smooth components.
		 */
		sum = 0.0;
		for (jH = 0; jH < nH; jH++)
		{
		    /*
		     *	Each row of H is offset by 2 from the previous one.
		     *
		     *	We assume our data is periodic, so we wrap the aIn[] values
		     *	if necessary.  If we have more samples than we have H
		     *	coefficients, we also wrap the H coefficients.
		     */
		    iA = MOD(2 * i + jH - offH, n);
		    sum += cH[jH] * aIn[aInBase + incA * iA];
		}
		aTmp1D[i] = sum;
    
		/*
		 *	aTmp1D[nDiv2..n-1] contains the detail components.
		 */
		sum = 0.0;
		flip = true;
		for (jG = 0; jG < nG; jG++)
		{
		    /*
		     *	We construct the G coefficients on-the-fly from the
		     *	Htilde coefficients.
		     *
		     *	Like H, each row of G is offset by 2 from the previous
		     *	one.  As with H, we also allow the coefficents of G to
		     *	wrap.
		     *
		     *	Again as before, the aIn[] values may wrap.
		     */
		    iA = MOD(2 * i + jG - offG, n);
		    if (flip)
			sum -= cHtilde[nG - 1 - jG] * aIn[aInBase + incA * iA];
		    else
			sum += cHtilde[nG - 1 - jG] * aIn[aInBase + incA * iA];
		    flip = !flip;
		}
		aTmp1D[nDiv2 + i] = sum;
	    }
	}
	else
	{
	    /*
	     *	The inverse transform is a little trickier to do efficiently.
	     *	A single step of the reconstruction is summarized by:
	     *
	     *		aTmp1D = Htilde^t * aIn[incA * (0..n/2-1)]
	     *				+ Gtilde^t * aIn[incA * (n/2..n-1)]
	     *
	     *	where x^t is the transpose of x.
	     */
	    for (i = 0; i < n; i++)
		aTmp1D[i] = 0.0;	/* necessary */
	    for (j = 0; j < nDiv2; j++)
	    {
		for (iHtilde = 0; iHtilde < nHtilde; iHtilde++)
		{
		    /*
		     *	Each row of Htilde is offset by 2 from the previous one.
		     */
		    iA = MOD(2 * j + iHtilde - offHtilde, n);
		    aTmp1D[iA] += cHtilde[iHtilde] * aIn[aInBase + incA * j];
		}
		flip = true;
		for (iGtilde = 0; iGtilde < nGtilde; iGtilde++)
		{
		    /*
		     *	As with Htilde, we also allow the coefficents of Gtilde,
		     *	which is the mirror of H, to wrap.
		     *
		     *	We assume our data is periodic, so we wrap the aIn[] values
		     *	if necessary.  If we have more samples than we have Gtilde
		     *	coefficients, we also wrap the Gtilde coefficients.
		     */
		    iA = MOD(2 * j + iGtilde - offGtilde, n);
		    if (flip)
		    {
			aTmp1D[iA] -= cH[nGtilde - 1 - iGtilde]
					* aIn[aInBase + incA * (j + nDiv2)];
		    }
		    else
		    {
			aTmp1D[iA] += cH[nGtilde - 1 - iGtilde]
					* aIn[aInBase + incA * (j + nDiv2)];
		    }
		    flip = !flip;
		}
	    }
	}
	for (i = 0; i < n; i++)
	    aXf[aXfBase + incA * i] = aTmp1D[i];
    }

    /* wxfrm_1d_varstep -- 1-dimensional discrete wavelet transform with variable step size */
    private void wxfrm_1d_varstep(
	    double aIn[],	/* in: original array */
	    int aInBase,		/* base index in array aIn */
	    int incA,		/* in: spacing of elements in aIn[] and aXf[] */
	    int nA,			/* in: size of a (must be power of 2) */
	    boolean isFwd,		/* in: true <=> forward transform */
	    double aXf[],		/* out: transformed array */
	    int aXfBase)		/* base index in array aXf */
    {
	int iA;
    
	if (nA < MIN_ORDER) return;
    
	if (isFwd)
	{
	    /*
	     *	Start at largest hierarchy, work towards smallest.
	     */
	    wfltr_convolve(isFwd, aIn, aInBase, incA, nA, aXf, aXfBase);
	    for (iA = nA / 2; iA >= MIN_ORDER; iA /= 2)
		    wfltr_convolve(isFwd, aXf, aXfBase, incA, iA, aXf, aXfBase);
	} else {
	    /*
	     *	Start at smallest hierarchy, work towards largest.
	     */
	    if (aXf != aIn)
	    {
		/* required for inverse */
		for (iA = 0; iA < nA; iA++)
		    aXf[aXfBase + incA * iA] = aIn[aInBase + incA * iA];
	    }
	    for (iA = MIN_ORDER; iA <= nA; iA *= 2)
		wfltr_convolve(isFwd, aXf, aXfBase, incA, iA, aXf, aXfBase);
	}
    }

    /* 1-dimensional discrete wavelet transform */
    public void wxfrm_da1d(
	    double a[],		/* in: original array */
	    boolean isFwd,			/* in: true <=> forward transform */
	    double aXf[])	/* out: transformed array */
    {
	aTmp1D = new double[a.length];
	wxfrm_1d_varstep(a, 0, 1, a.length, isFwd, aXf, 0);
	aTmp1D = null;
    }

    /* n-dimensional discrete wavelet transform */
    public void wxfrm_dand(
	    double aIn[],	/* in: original data */
	    int nA[],			/* in: size of each dimension of a (must be powers of 2) */
	    int nD,				/* in: number of dimensions (size of nA[]) */
	    boolean isFwd,			/* in: true <=> forward transform */
	    boolean isStd,			/* in: true <=> standard basis */
	    double aXf[])	/* out: transformed data (ok if == a) */
    {
	int k, d, nDMax, nATot;
	int lg2nA;
    
	if (nD < 1 || MXN_D < nD)
	{
	    System.err.println("number of dimensions must be between 1 and "+MXN_D+" -- exiting\n");
	    System.exit(1);
	}
    
	for (d = 0; d < nD; d++)
	{
	    for (lg2nA = 0; (1 << lg2nA) < nA[d]; lg2nA++)
		continue;
	    if ((1 << lg2nA) != nA[d])
	    {
		System.err.println("size of dimension #"+d+" (= "+nA[d]+") is not a power of 2 -- exiting\n");
		System.exit(1);
	    }
	}
    
	nDMax = 1;
	nATot = 1;
	for (d = 0; d < nD; d++)
	{
	    if (nA[d] > nDMax)
		nDMax = nA[d];
	    nATot *= nA[d];
	}
    
	/*
	 *	Make the "private global" temp array aTmp1D, big enough to hold the
	 *	longest dimension.
	 */
	aTmp1D = new double[nDMax];
    
	/*
	 *	aXf[] starts out equal to aIn[] and gets modified in-place.
	 *	(If they're the same array, we don't need to copy aIn[] to aXf[].)
	 */
	if (aIn != aXf)
	{
	    for (k = 0; k < nATot; k++) aXf[k] = aIn[k];
	}
    
	if (isStd)
	    wxfrm_nd_std(aXf, nA, nD, isFwd);
	else
	    wxfrm_nd_nonstd(aXf, nA, nD, isFwd);
    
	aTmp1D = null;
    }

    /* wxfrm_nd_nonstd -- perform a nonstandard n-dimensional wavelet transform */
    private void wxfrm_nd_nonstd(
	    double a[],	/* in: original/final data (modified in-place) */
	    int nA[],		/* in: size of each dimension of a (must be powers of 2) */
	    int nD,			/* in: number of dimensions (size of nA[]) */
	    boolean isFwd)		/* in: true <=> forward transform */
    {
	int d, d0, dMax, nConv, iConv, iConvDecoded;
	int iA, nATot, nBTot;
	int nARev[], nB[], incA[];
	boolean stretchOk[];

	nARev = new int[MXN_D];
	nB = new int[MXN_D];
	incA = new int[MXN_D];
	stretchOk = new boolean[MXN_D];
    
	/*
	 *	In C, a matrix a declared
	 *
	 *		double a[n][m];
	 *
	 *	has nA declared
	 *
	 *		int nA[] = { n, m };
	 *
	 *	but it is convenient for us to refer to nA[] in reversed form as
	 *	nARev[], so that nARev[0] is the "fastest varying" index in the
	 *	multidimensional mapping a[].
	 */
	for (d = 0; d < nD; d++)
	    nARev[d] = nA[nD - 1 - d];
    
	/*
	 *	A[] is the original matrix.  B[] is the A[]'s submatrix whose
	 *	transform we are computing at any given time.
	 */
	nATot = 1;
	for (d = 0; d < nD; d++)
	{
	    incA[d] = nATot;
	    nATot *= nARev[d];
	}
    
	nBTot = nATot;
	if (isFwd)
	{
	    /* initially, B is equivalent to A */
	    for (d = 0; d < nD; d++)
		nB[d] = nARev[d];
	    /*
	     *	main loop is in descending scale
	     */
	    while (nBTot > 1)
	    {
		for (d0 = 0; d0 < nD; d0++)
		{
		    if (nB[d0] <= 1) continue;
		    nConv = nBTot / nB[d0];	/* # of convolutions to perform */
		    /*
		     *	The idea is to enumerate the nConv convolutions we need to
		     *	do in direction d0 and pull apart the enumeration index,
		     *	reforming it into the index iA of the original matrix.
		     */
		    for (iConv = 0; iConv < nConv; iConv++)
		    {
			iA = 0;
			iConvDecoded = iConv;
			for (d = 0; d < nD; d++)
			{
			    if (d != d0)
			    {
				iA += incA[d] * (iConvDecoded % nB[d]);
				iConvDecoded /= nB[d];
			    }
			}
			wfltr_convolve(true, a, iA, incA[d0], nB[d0], a, iA);
		    }
		}
		nBTot = 1;
		for (d = 0; d < nD; d++)
		{
		    if (nB[d] > 1)
		    {
			nB[d] /= 2;
			nBTot *= nB[d];
		    }
		}
	    }
	} else {
	    /* initially, B is a 1x1x..x1 submatrix */
	    for (d = 0; d < nD; d++)
		nB[d] = 1;
	    nBTot = 1;
	    /*
	     *	main loop is in ascending scale
	     */
	    while (nBTot < nATot)
	    {
		/*
		 *	We have to be careful about non-hypercubic grids.  In order to
		 *	duplicate what we've done above for the forward transform, if
		 *	nB[d0] is 1, we only stretch dimension d0 if
		 *
		 *		nARev[d0] / nB[d0] == max( nARev[d] / nB[d] ) for all d
		 *
		 *	The elements of stretchOk will reflect this.  dMax is the
		 *	dimension that has the largest stretch.
		 */
		dMax = 0;
		for (d = 1; d < nD; d++)
		{
		    if (nARev[d] * nB[dMax] >= nARev[dMax] * nB[d])
			    dMax = d;
		}
		for (d = 0; d < nD; d++)
		    stretchOk[d] = (nB[d] > 1 || (nARev[d] * nB[dMax] >= nARev[dMax] * nB[d]));
    
		for (d0 = nD - 1; d0 >= 0; d0--)
		{
		    if (!stretchOk[d0])
			    continue;
		    nB[d0] *= 2;
		    nBTot *= 2;
		}
    
		for (d0 = nD - 1; d0 >= 0; d0--)
		{
		    if (!stretchOk[d0])
			    continue;
		    nConv = nBTot / nB[d0];
		    /*
		     *	As with the forward transform, the idea is to enumerate the
		     *	nConv convolutions we need to do in direction d0 and pull
		     *	apart the enumeration index, reforming it into the index iA
		     *	of the original matrix.
		     */
		    for (iConv = 0; iConv < nConv; iConv++)
		    {
			iA = 0;
			iConvDecoded = iConv;
			for (d = 0; d < nD; d++)
			{
			    /*
			     *	Non-stretched directions don't count in nConv, so
			     *	they don't count in the index computation, either.
			     *	Neither does d0, obviously.
			     */
			    if (d != d0 && stretchOk[d])
			    {
				iA += incA[d] * (iConvDecoded % nB[d]);
				iConvDecoded /= nB[d];
			    }
			}
			wfltr_convolve(false, a, iA, incA[d0], nB[d0], a, iA);
		    }
		}
	    }
	}
    }

    /* wxfrm_nd_std -- perform a standard n-dimensional wavelet transform */
    private void wxfrm_nd_std(
	    double a[],		/* in: original/final data (modified in-place) */
	    int nA[],		/* in: size of each dimension of a (must be powers of 2) */
	    int nD,			/* in: number of dimensions (size of nA[]) */
	    boolean isFwd)			/* in: true <=> forward transform */
    {
	int incA = 1;
	int incNext, d, i1, i2, nATot;
	int nARev[] = new int[MXN_D];
	
	/*
	 *	In C, a matrix "a" declared
	 *
	 *		double a[n][m];
	 *
	 *	has "nA" declared
	 *
	 *		int nA[] = { n, m };
	 *
	 *	but it is convenient for us to refer to nA[] in reversed form as
	 *	nARev[], so that nARev[0] is the "fastest varying" index in the
	 *	multidimensional mapping a[].
	 */
	for (d = 0; d < nD; d++)
	    nARev[d] = nA[nD - 1 - d];
	
	nATot = 1;
	for (d = 0; d < nD; d++)
	    nATot *= nARev[d];
	
	/*
	 *	main loop is over the dimensions
	 */
	for (d = 0; d < nD; d++)
	{
	    incNext = nARev[d] * incA;
	    if (nARev[d] >= MIN_ORDER)
	    {
		for (i2 = 0; i2 < nATot; i2 += incNext)
		{
		    for (i1 = 0; i1 < incA; i1++)
		    {
			/*
			 *	Use a variable step size (incA) and pointers to
			 *	perform the one-dimensional wavelet transform in-place.
			 */
			wxfrm_1d_varstep(a, (i1 + i2), incA, nARev[d], isFwd,
					a, (i1 + i2));
		    }
		}
	    }
	    incA = incNext;
	}
    }
}

/* portions of this code were adapted from the DitherTest applet */

public class WaveletSynthesisApplet 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 calcRandom = "uniform";
    String calcWavelet = "Haar";
    double calcDecay = 2.0;
    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"));
	double d;
	String waveletType = getParameter("wavelet");
	String randomType = getParameter("random");
	if (w<=0 || w>256) w=width;
	width=w;
	height=w;
	scalefactor = 256/width;
	try
	{
	    d = Double.valueOf(getParameter("decay")).doubleValue();
	}
	catch (NumberFormatException nfe)
	{
	    d = 0.0;
	}
	if (d > 0.0) calcDecay = d;
	if (waveletType != null) calcWavelet = waveletType;
	if (randomType != null) calcRandom = randomType;
        rgen = new Random();
	started = false;
	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 (calcWavelet.equalsIgnoreCase("haar"))
	    DoWavelet(calcDecay, new wfltrHaar());
	else if (calcWavelet.equalsIgnoreCase("battlelemarie"))
	    DoWavelet(calcDecay, new wfltrBattleLemarie());
	else if (calcWavelet.equalsIgnoreCase("burtadelson"))
	    DoWavelet(calcDecay, new wfltrBurtAdelson());
	else if (calcWavelet.equalsIgnoreCase("coiflet2"))
	    DoWavelet(calcDecay, new wfltrCoiflet2());
	else if (calcWavelet.equalsIgnoreCase("coiflet4"))
	    DoWavelet(calcDecay, new wfltrCoiflet4());
	else if (calcWavelet.equalsIgnoreCase("coiflet6"))
	    DoWavelet(calcDecay, new wfltrCoiflet6());
	else if (calcWavelet.equalsIgnoreCase("daubechies10"))
	    DoWavelet(calcDecay, new wfltrDaubechies10());
	else if (calcWavelet.equalsIgnoreCase("daubechies12"))
	    DoWavelet(calcDecay, new wfltrDaubechies12());
	else if (calcWavelet.equalsIgnoreCase("daubechies20"))
	    DoWavelet(calcDecay, new wfltrDaubechies20());
	else if (calcWavelet.equalsIgnoreCase("daubechies4"))
	    DoWavelet(calcDecay, new wfltrDaubechies4());
	else if (calcWavelet.equalsIgnoreCase("daubechies6"))
	    DoWavelet(calcDecay, new wfltrDaubechies6());
	else if (calcWavelet.equalsIgnoreCase("daubechies8"))
	    DoWavelet(calcDecay, new wfltrDaubechies8());
	else if (calcWavelet.equalsIgnoreCase("pseudocoiflet4"))
	    DoWavelet(calcDecay, new wfltrPseudocoiflet4());
	else if (calcWavelet.equalsIgnoreCase("spline2,2"))
	    DoWavelet(calcDecay, new wfltrSpline_2_2());
	else if (calcWavelet.equalsIgnoreCase("spline2,4"))
	    DoWavelet(calcDecay, new wfltrSpline_2_4());
	else if (calcWavelet.equalsIgnoreCase("spline3,3"))
	    DoWavelet(calcDecay, new wfltrSpline_3_3());
	else if (calcWavelet.equalsIgnoreCase("spline3,7"))
	    DoWavelet(calcDecay, new wfltrSpline_3_7());
	else
	    DoWavelet(calcDecay, new wfltrHaar());  // make this the default
    }

    /************************************************************
     * Method to perform simple wavelet terrain synthesis
     ************************************************************/

    synchronized public void DoWavelet(double decay, WaveletFilter wfltr)
    {
	int i,j,dist;
	double buffer[] = new double[width*width];
	double min, max;
	double scale[], maxScale;
	int dim[] = new int[2];
	boolean useGaussian = calcRandom.equals("gaussian");

	heightfield = new int[width][width];
	scale = new double[width];
	for (maxScale=1.0,dist=1,i=0;i=dist)
	    {
		dist *= 2;
		maxScale /= (decay*decay);
	    }
	    scale[i] = maxScale;
	}
	for (i=0;i buffer[i+j*width]) min = buffer[i+j*width];
	    if (max < buffer[i+j*width]) min = buffer[i+j*width];
	}
	for (i=0;i



1