deweese     01/08/01 13:23:20

  Modified:    sources/org/apache/batik/ext/awt/image/rendered
                        TurbulencePatternRed8Bit.java
  Log:
  Updated javadocs and added my deduction of how the Perlin Noise
  function works, in the hope that someone might be able to come up with
  a more efficent means to implement all or part of it...
  
  Revision  Changes    Path
  1.2       +82 -118   
xml-batik/sources/org/apache/batik/ext/awt/image/rendered/TurbulencePatternRed8Bit.java
  
  Index: TurbulencePatternRed8Bit.java
  ===================================================================
  RCS file: 
/home/cvs/xml-batik/sources/org/apache/batik/ext/awt/image/rendered/TurbulencePatternRed8Bit.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- TurbulencePatternRed8Bit.java     2001/08/01 19:46:20     1.1
  +++ TurbulencePatternRed8Bit.java     2001/08/01 20:23:20     1.2
  @@ -23,14 +23,37 @@
   import java.awt.image.DirectColorModel;
   import java.awt.image.ColorModel;
   /**
  - * This class creates a noise pattern conform to the one defined for
  - * the feTurbulence filter of the SVG specification. It can be used by
  - * classes implementing specific interfaces, such as the TurbulenceOp
  - * and TurbulencePaintContext classes.
  + * This class creates a RenderedImage in conformance to the one
  + * defined for the feTurbulence filter of the SVG specification.  What
  + * follows is my high-level description of how the noise is generated.
  + * This is not contained in the SVG spec, just the algorithm for
  + * doing it.  This is provided in the hope that someone will figure
  + * out a clever way to accelerate parts of the function.
    *
  + * gradient contains a long list of random unit vectors.  For each
  + * point we are to generate noise for we do two things.  first we use
  + * the latticeSelector to 'co-mingle' the integer portions of x and y
  + * (this allows us to have a one-dimensional array of gradients that
  + * appears 2 dimensional, by using the co-mingled index).
  + *
  + * We do this for [x,y], [x+1,y], [x,y+1], and [x+1, y+1], this gives
  + * us the four gradient vectors that surround the point (b00, b10, ...)
  + * 
  + * Next we construct the four vectors from the grid points (where the
  + * gradient vectors are defined) [these are rx0, rx1, ry0, ry1].
  + *
  + * We then take the dot product between the gradient vectors and the
  + * grid point vectors (this gives the portion of the grid point vector
  + * that projects along the gradient vector for each grid point).
  + * These four dot projects are then combined with linear interpolation.
  + * The weight factor for the linear combination is the result of applying
  + * the 's' curve function to the fractional part of x and y (rx0, ry0).
  + * The S curve function get's it's name because it looks a bit like as
  + * 'S' from 0->1.
  + *  
    * @author     <a href="mailto:[EMAIL PROTECTED]";>Vincent Hardy</a>
  - * @version $Id: TurbulencePatternRed8Bit.java,v 1.1 2001/08/01 19:46:20 deweese 
Exp $
  - */
  + * @author     <a href="mailto:[EMAIL PROTECTED]";>Thomas DeWeese</a>
  + * @version $Id: TurbulencePatternRed8Bit.java,v 1.2 2001/08/01 20:23:20 deweese 
Exp $ */
   public final class TurbulencePatternRed8Bit extends AbstractRed {
       /**
        * Inner class to store tile stitching info.
  @@ -268,74 +291,15 @@
       private static final double lerp(double t, double a, double b) {
           return ( a + t * (b - a) );
       }
  -
  -    private final void noise2_4(final double noise[], 
  -                                double vec0, 
  -                                double vec1){
  -        int b0, b1;
  -        final int i, j, b00, b10, b01, b11;
  -        final double rx0, rx1, ry0, ry1, sx, sy;
  -        vec0 += PerlinN;
  -        b0 = (int)vec0;
  -
  -        i = latticeSelector[b0 & BM];
  -        j = latticeSelector[(b0+1) & BM];
   
  -        rx0 = vec0 - (int)vec0;
  -        rx1 = rx0 - 1.0;
  -        sx  = s_curve(rx0);
  -
  -        vec1 += PerlinN;
  -        b0 = ((int)vec1) & BM;
  -        b1 = (b0+1) & BM;
  -
  -        b00 = latticeSelector[i + b0]<<3;
  -        b10 = latticeSelector[j + b0]<<3;
  -        b01 = latticeSelector[i + b1]<<3;
  -        b11 = latticeSelector[j + b1]<<3;
  -
  -        ry0 = vec1 - (int)vec1;
  -        ry1 = ry0 - 1.0;
  -        sy = s_curve(ry0);
  -
  -        noise[0] = 
  -            lerp(sy, 
  -                 lerp(sx, 
  -                      rx0*gradient[b00+0] + ry0*gradient[b00+1],
  -                      rx1*gradient[b10+0] + ry0*gradient[b10+1]),
  -                 lerp(sx, 
  -                      rx0*gradient[b01+0] + ry1*gradient[b01+1],
  -                      rx1*gradient[b11+0] + ry1*gradient[b11+1]));
  -
  -        noise[1] = 
  -            lerp(sy, 
  -                 lerp(sx, 
  -                      rx0*gradient[b00+2] + ry0*gradient[b00+3],
  -                      rx1*gradient[b10+2] + ry0*gradient[b10+3]),
  -                 lerp(sx, 
  -                      rx0*gradient[b01+2] + ry1*gradient[b01+3],
  -                      rx1*gradient[b11+2] + ry1*gradient[b11+3]));
  -
  -        noise[2] = 
  -            lerp(sy, 
  -                 lerp(sx, 
  -                      rx0*gradient[b00+4] + ry0*gradient[b00+5],
  -                      rx1*gradient[b10+4] + ry0*gradient[b10+5]),
  -                 lerp(sx, 
  -                      rx0*gradient[b01+4] + ry1*gradient[b01+5],
  -                      rx1*gradient[b11+4] + ry1*gradient[b11+5]));
  -
  -        noise[3] = 
  -            lerp(sy, 
  -                 lerp(sx, 
  -                      rx0*gradient[b00+6] + ry0*gradient[b00+7],
  -                      rx1*gradient[b10+6] + ry0*gradient[b10+7]),
  -                 lerp(sx, 
  -                      rx0*gradient[b01+6] + ry1*gradient[b01+7],
  -                      rx1*gradient[b11+6] + ry1*gradient[b11+7]));
  -
  -    }
  -
  +    /**
  +     * Generate a pixel of noise corresponding to the point vec0,vec1.
  +     * See class description for a high level discussion of method.
  +     * This handles cases where channels <= 4.  
  +     * @param noise The place to put the generated noise.
  +     * @param vec0  The X coordiate to generate noise for
  +     * @param vec1  The Y coordiate to generate noise for
  +     */
       private final void noise2(final double noise[], double vec0, double vec1) {
           int b0, b1;
           final int i, j, b00, b10, b01, b11;
  @@ -410,6 +374,10 @@
        * If any of the lattice is on the right or bottom edge, the
        * function uses the the latice on the other side of the
        * tile, i.e., the left or right edge.
  +     * @param noise The place to put the generated noise.
  +     * @param vec0  The X coordiate to generate noise for
  +     * @param vec1  The Y coordiate to generate noise for
  +     * @param stitchInfo The stitching information for the noise function.
        */
       private final void noise2Stitch(final double noise[],
                                       final double vec0, final double vec1,
  @@ -506,12 +474,12 @@
   
       /**
        * This is the heart of the turbulence calculation. It returns
  -     * 'turbFunctionResult', as defined in the spec.
  -     * @param rgb array for the four color components
  +     * 'turbFunctionResult', as defined in the spec.  This is
  +     * special case for 4 bands of output.
  +     *
        * @param point x and y coordinates of the point to process.
        * @param fSum array used to avoid reallocating double array for each pixel
  -     * @param noise array used to avoid reallocating double array for
  -     *        each pixel
  +     * @return The ARGB pixel value.
        */
       private final int turbulence_4(double pointX, 
                                      double pointY,
  @@ -637,7 +605,7 @@
           switch (channels.length) {
           case 4:
               for(int nOctave = 0; nOctave < numOctaves; nOctave++){
  -                noise2_4(noise, pointX, pointY);
  +                noise2(noise, pointX, pointY);
   
                   if (noise[0]<0) fSum[0] -= (noise[0] * ratio);
                   else            fSum[0] += (noise[0] * ratio);
  @@ -728,13 +696,14 @@
       }
   
       /**
  -     * This is the heart of the turbulence calculation. It returns 
'turbFunctionResult', as
  -     * defined in the spec.
  +     * This is the heart of the turbulence calculation. It returns
  +     * 'turbFunctionResult', as defined in the spec.
        * @param rgb array for the four color components
        * @param point x and y coordinates of the point to process.
        * @param fSum array used to avoid reallocating double array for each pixel
  -     * @param noise array used to avoid reallocating double array for each pixel
  -     * @param channels channels for which values should be computed
  +     * @param noise array used to avoid reallocating double array for
  +     * each pixel
  +     * @param stitchInfo The stitching information for the noise function
        */
       private final void turbulenceStitch(final int rgb[], 
                                           double pointX, double pointY,
  @@ -749,6 +718,7 @@
           case 4:
               for(int nOctave = 0; nOctave < numOctaves; nOctave++){
                   noise2Stitch(noise, pointX, pointY, stitchInfo);
  +
                   if (noise[3]<0) fSum[3] -= (noise[3] * ratio);
                   else            fSum[3] += (noise[3] * ratio);
                   if (noise[2]<0) fSum[2] -= (noise[2] * ratio);
  @@ -840,15 +810,12 @@
       }
   
       /**
  -     * This is the heart of the turbulence calculation. It returns 
'turbFunctionResult', as
  -     * defined in the spec.
  -     * @param rgb array for the four color components
  +     * This is the heart of the turbulence calculation. It returns
  +     * 'turbFunctionResult', as defined in the spec.  This handles the
  +     * case where we are generating 4 channels of noise.
        * @param point x and y coordinates of the point to process.
        * @param fSum array used to avoid reallocating double array for each pixel
  -     * @param noise array used to avoid reallocating double array for each pixel
  -     * @param numOctaves number of octaves (may be limited so that spatial 
frequency below
  -     *        half a pixel are not processed).
  -     * @param channels channels for which values should be computed
  +     * @return The ARGB pixel
        */
       private final int turbulenceFractal_4( double pointX, 
                                              double pointY,
  @@ -940,15 +907,13 @@
       }
   
       /**
  -     * This is the heart of the turbulence calculation. It returns 
'turbFunctionResult', as
  -     * defined in the spec.
  +     * This is the heart of the turbulence calculation. It returns
  +     * 'turbFunctionResult', as defined in the spec.
        * @param rgb array for the four color components
        * @param point x and y coordinates of the point to process.
        * @param fSum array used to avoid reallocating double array for each pixel
  -     * @param noise array used to avoid reallocating double array for each pixel
  -     * @param numOctaves number of octaves (may be limited so that spatial 
frequency below
  -     *        half a pixel are not processed).
  -     * @param channels channels for which values should be computed
  +     * @param noise array used to avoid reallocating double array for
  +     * each pixel 
        */
       private final void turbulenceFractal(final int rgb[], 
                                            double pointX, 
  @@ -1000,15 +965,14 @@
       }
   
       /**
  -     * This is the heart of the turbulence calculation. It returns 
'turbFunctionResult', as
  -     * defined in the spec.
  +     * This is the heart of the turbulence calculation. It returns
  +     * 'turbFunctionResult', as defined in the spec.
        * @param rgb array for the four color components
        * @param point x and y coordinates of the point to process.
        * @param fSum array used to avoid reallocating double array for each pixel
  -     * @param noise array used to avoid reallocating double array for each pixel
  -     * @param numOctaves number of octaves (may be limited so that spatial 
frequency below
  -     *        half a pixel are not processed).
  -     * @param channels channels for which values should be computed
  +     * @param noise array used to avoid reallocating double array for
  +     * each pixel
  +     * @param stitchInfo The stitching information for the noise function
        */
       private final void turbulenceFractalStitch(final int rgb[], 
                                                  double pointX,
  @@ -1063,10 +1027,7 @@
   
       /**
        * Generates a Perlin noise pattern into dest Raster.
  -     *
  -     * @param txf image space to noise space transform. The 'noise space' is the
  -     *        space where the spatial characteristics of the noise are defined.
  -     * @param des Raster where the pattern should be generated.
  +     * @param dest Raster to fill with the pattern.
        */
       public WritableRaster copyData(WritableRaster dest) {
           //
  @@ -1076,18 +1037,6 @@
               throw new IllegalArgumentException
                   ("Cannot generate a noise pattern into a null raster");
   
  -        //
  -        // Now, limit the number of octaves so that we do not get frequencies
  -        // below half a pixel.
  -        //
  -        // If d is the distance between to pixels in user space, then,
  -        // numOctavesMax = -(log2(d) + log2(bf))
  -        // along one axis.
  -        //
  -        // The maximum distance along each axis is processed by computing the
  -        // inverse transform of 'maximum' vectors from device space to the filter 
space
  -        // and determining the maximum component along each axis.
  -        //
   
           int w = dest.getWidth();
           int h = dest.getHeight();
  @@ -1289,6 +1238,19 @@
           txf.deltaTransform(vecX, 0, vecX, 0, 1);
           txf.deltaTransform(vecY, 0, vecY, 0, 1);
   
  +        //
  +        // Now, limit the number of octaves so that we do not get frequencies
  +        // below half a pixel.
  +        //
  +        // If d is the distance between to pixels in user space, then,
  +        // numOctavesMax = -(log2(d) + log2(bf))
  +        // along one axis.
  +        //
  +        // The maximum distance along each axis is processed by
  +        // computing the inverse transform of 'maximum' vectors from
  +        // device space to the filter space and determining the
  +        // maximum component along each axis.
  +
           double dx = Math.max(Math.abs(vecX[0]), Math.abs(vecY[0]));
           int maxX = -(int)Math.round((Math.log(dx) + Math.log(baseFrequencyX))/
                                       Math.log(2));
  @@ -1305,7 +1267,9 @@
   
           if (this.numOctaves > 8)
               // beyond 8 octaves there is no significant contribution
  -            // to the output pixel.
  +            // to the output pixel (contribution is halved for each
  +            // octave so after 8 we are contributing less than half a
  +            // code value _at_best_).
               this.numOctaves = 8;  
   
           if (tile != null) {
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to