KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > batik > ext > awt > image > rendered > TurbulencePatternRed


1 /*
2
3    Copyright 1999-2003 The Apache Software Foundation
4
5    Licensed under the Apache License, Version 2.0 (the "License");
6    you may not use this file except in compliance with the License.
7    You may obtain a copy of the License at
8
9        http://www.apache.org/licenses/LICENSE-2.0
10
11    Unless required by applicable law or agreed to in writing, software
12    distributed under the License is distributed on an "AS IS" BASIS,
13    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14    See the License for the specific language governing permissions and
15    limitations under the License.
16
17 */

18
19 package org.apache.batik.ext.awt.image.rendered;
20
21 import java.awt.Rectangle JavaDoc;
22 import java.awt.color.ColorSpace JavaDoc;
23 import java.awt.geom.AffineTransform JavaDoc;
24 import java.awt.geom.Rectangle2D JavaDoc;
25 import java.awt.image.ColorModel JavaDoc;
26 import java.awt.image.DataBuffer JavaDoc;
27 import java.awt.image.DataBufferInt JavaDoc;
28 import java.awt.image.DirectColorModel JavaDoc;
29 import java.awt.image.SinglePixelPackedSampleModel JavaDoc;
30 import java.awt.image.WritableRaster JavaDoc;
31 /**
32  * This class creates a RenderedImage in conformance to the one
33  * defined for the feTurbulence filter of the SVG specification. What
34  * follows is my high-level description of how the noise is generated.
35  * This is not contained in the SVG spec, just the algorithm for
36  * doing it. This is provided in the hope that someone will figure
37  * out a clever way to accelerate parts of the function.
38  *
39  * gradient contains a long list of random unit vectors. For each
40  * point we are to generate noise for we do two things. first we use
41  * the latticeSelector to 'co-mingle' the integer portions of x and y
42  * (this allows us to have a one-dimensional array of gradients that
43  * appears 2 dimensional, by using the co-mingled index).
44  *
45  * We do this for [x,y], [x+1,y], [x,y+1], and [x+1, y+1], this gives
46  * us the four gradient vectors that surround the point (b00, b10, ...)
47  *
48  * Next we construct the four vectors from the grid points (where the
49  * gradient vectors are defined) [these are rx0, rx1, ry0, ry1].
50  *
51  * We then take the dot product between the gradient vectors and the
52  * grid point vectors (this gives the portion of the grid point vector
53  * that projects along the gradient vector for each grid point).
54  * These four dot projects are then combined with linear interpolation.
55  * The weight factor for the linear combination is the result of applying
56  * the 's' curve function to the fractional part of x and y (rx0, ry0).
57  * The S curve function get's it's name because it looks a bit like as
58  * 'S' from 0->1.
59  *
60  * @author <a HREF="mailto:vincent.hardy@eng.sun.com">Vincent Hardy</a>
61  * @author <a HREF="mailto:DeWeese@apache.org">Thomas DeWeese</a>
62  * @version $Id: TurbulencePatternRed.java,v 1.4 2004/10/30 18:38:05 deweese Exp $ */

63 public final class TurbulencePatternRed extends AbstractRed {
64     /**
65      * Inner class to store tile stitching info.
66      * #see
67      */

68     static final class StitchInfo {
69         /**
70          * Width of the integer lattice tile
71          */

72         int width;
73
74         /**
75          * Height of the integer lattice tile
76          */

77         int height;
78
79         /**
80          * Value beyond which values are wrapped on
81          * the x-axis.
82          * @see #noise2Stitch
83          */

84         int wrapX;
85
86         /**
87          * Value beyond which values are wrapped on
88          * the y-axis.
89          * @see #noise2Stitch
90          */

91         int wrapY;
92
93         /**
94          * Default constructor
95          */

96         StitchInfo(){
97         }
98
99         /**
100          * Copy constructor
101          */

102         StitchInfo(StitchInfo stitchInfo){
103             this.width = stitchInfo.width;
104             this.height = stitchInfo.height;
105             this.wrapX = stitchInfo.wrapX;
106             this.wrapY = stitchInfo.wrapY;
107         }
108
109         final void assign(StitchInfo stitchInfo) {
110             this.width = stitchInfo.width;
111             this.height = stitchInfo.height;
112             this.wrapX = stitchInfo.wrapX;
113             this.wrapY = stitchInfo.wrapY;
114         }
115
116         /*
117          * Adjustst the StitchInfo for when the frequency has been
118          * doubled.
119          *
120          * width = tileWidth*baseFrequencyX
121          * height = tileHeight*baseFrequencyY
122          * minY = tileY*baseFrequencyY + PerlinN
123          * wrapX = tileX*baseFrequencyX + PerlinN + width
124          * wrapY = tileY*baseFrequencyY + PerlinN + height
125          *
126          */

127         final void doubleFrequency(){
128             width *= 2;
129             height *= 2;
130             wrapX *= 2;
131             wrapY *= 2;
132             wrapX -= PerlinN;
133             wrapY -= PerlinN;
134         }
135     }
136
137     /**
138      * Used when stitching is on
139      */

140     private StitchInfo stitchInfo = null;
141
142     /**
143      * Identity transform, default used when null input in generatePattern
144      * @see #generatePattern
145      */

146     private static final AffineTransform JavaDoc IDENTITY = new AffineTransform JavaDoc();
147
148     /**
149      * x-axis base frequency for the noise function along the x-axis
150      */

151     private double baseFrequencyX;
152
153     /**
154      * y-axis base frequency for the noise function along the y-axis
155      */

156     private double baseFrequencyY;
157
158     /**
159      * Number of octaves in the noise function
160      */

161     private int numOctaves;
162
163     /**
164      * Starting number for the pseudo random number generator
165      */

166     private int seed;
167
168     /**
169      * Defines the tile for the turbulence function, if non-null turns
170      * on stitching, so frequencies are adjusted to avoid
171      * discontinuities in case frequencies do not match tile
172      * boundaries.
173      */

174     private Rectangle2D JavaDoc tile;
175
176     /**
177      * Defines the tile for the turbulence function
178      */

179     private AffineTransform JavaDoc txf;
180
181     /**
182      * Defines whether the filter performs a fractal noise or a turbulence function
183      */

184     private boolean isFractalNoise;
185
186     /**
187      * List of channels that the generator produces.
188      */

189     private int channels[];
190
191     // To avoid doing an inverse transform on each pixel, transform
192
// the image space unit vectors and process how much of a delta
193
// this is in filter space.
194
double tx[] = {1, 0};
195     double ty[] = {0, 1};
196
197     /**
198      * Produces results in the range [1, 2**31 - 2].
199      * Algorithm is: r = (a * r) mod m
200      * where a = 16807 and m = 2**31 - 1 = 2147483647
201      * See [Park & Miller], CACM vol. 31 no. 10 p. 1195, Oct. 1988
202      * To test: the algorithm should produce the result 1043618065
203      * as the 10,000th generated number if the original seed is 1.
204      */

205     private static final int RAND_m = 2147483647; /* 2**31 - 1 */
206     private static final int RAND_a = 16807; /* 7**5; primitive root of m */
207     private static final int RAND_q = 127773; /* m / a */
208     private static final int RAND_r = 2836; /* m % a */
209
210     private static final int BSize = 0x100;
211     private static final int BM = 0xff;
212     private static final double PerlinN = 0x1000;
213     private static final int NP = 12 /* 2^PerlinN */;
214     private static final int NM = 0xfff;
215     private final int latticeSelector[] = new int[BSize + 1];
216     private final double gradient[] = new double[(BSize+1)*8];
217
218     public double getBaseFrequencyX(){
219         return baseFrequencyX;
220     }
221
222     public double getBaseFrequencyY(){
223         return baseFrequencyY;
224     }
225
226     public int getNumOctaves(){
227         return numOctaves;
228     }
229
230     public int getSeed(){
231         return seed;
232     }
233
234     public Rectangle2D JavaDoc getTile(){
235         return (Rectangle2D JavaDoc)tile.clone();
236     }
237
238     public boolean isFractalNoise(){
239         return isFractalNoise;
240     }
241
242     public boolean[] getChannels(){
243         boolean channels[] = new boolean[4];
244         for(int i=0; i<this.channels.length; i++)
245             channels[this.channels[i]] = true;
246
247         return channels;
248     }
249
250     public final int setupSeed(int seed) {
251         if (seed <= 0) seed = -(seed % (RAND_m - 1)) + 1;
252         if (seed > RAND_m - 1) seed = RAND_m - 1;
253         return seed;
254     }
255
256     public final int random(int seed) {
257       int result = RAND_a * (seed % RAND_q) - RAND_r * (seed / RAND_q);
258         if (result <= 0) result += RAND_m;
259         return result;
260     }
261
262     private void initLattice(int seed) {
263         double u, v, s;
264         int i, j, k, s1, s2;
265         seed = setupSeed(seed);
266
267         for(k = 0; k < 4; k++){
268             for(i = 0; i < BSize; i++){
269                 u = (((seed = random(seed)) % (BSize + BSize)) - BSize);
270                 v = (((seed = random(seed)) % (BSize + BSize)) - BSize);
271                 
272                 s = 1/Math.sqrt(u*u + v*v);
273                 gradient[i*8 + k*2 ] = u*s;
274                 gradient[i*8 + k*2 + 1] = v*s;
275             }
276         }
277
278         for(i = 0; i < BSize; i++)
279             latticeSelector[i] = i;
280
281         while(--i > 0){
282             k = latticeSelector[i];
283             j = (seed = random(seed)) % BSize;
284             latticeSelector[i] = latticeSelector[j];
285             latticeSelector[j] = k;
286             
287             // Now we apply the lattice to the gradient array, this
288
// lets us avoid one of the lattice lookups.
289
s1 = i<<3;
290             s2 = j<<3;
291             for (j=0; j<8; j++) {
292                 s = gradient[s1+j];
293                 gradient[s1+j] = gradient[s2+j];
294                 gradient[s2+j] = s;
295             }
296         }
297         latticeSelector[BSize] = latticeSelector[0];
298         for (j=0; j<8; j++)
299             gradient[(BSize*8)+j] = gradient[j];
300     }
301
302
303     private static final double s_curve(final double t) {
304         return (t * t * (3 - 2 * t) );
305     }
306
307     private static final double lerp(double t, double a, double b) {
308         return ( a + t * (b - a) );
309     }
310
311     /**
312      * Generate a pixel of noise corresponding to the point vec0,vec1.
313      * See class description for a high level discussion of method.
314      * This handles cases where channels <= 4.
315      * @param noise The place to put the generated noise.
316      * @param vec0 The X coordiate to generate noise for
317      * @param vec1 The Y coordiate to generate noise for
318      */

319     private final void noise2(final double noise[], double vec0, double vec1) {
320         int b0, b1;
321         final int i, j;
322         final double rx0, rx1, ry0, ry1, sx, sy;
323
324         vec0 += PerlinN;
325         b0 = ((int)vec0)&BM;
326
327         i = latticeSelector[b0];
328         j = latticeSelector[b0+1];
329
330         rx0 = vec0 - (int)vec0;
331         rx1 = rx0 - 1.0;
332         sx = s_curve(rx0);
333
334         vec1 += PerlinN;
335         b0 = (int)vec1;
336
337         // The gradient array already has the latticeSelector applied
338
// to it, So we can avoid doing the last lookup.
339
b1 = ((j + b0)&BM)<<3;
340         b0 = ((i + b0)&BM)<<3;
341
342         ry0 = vec1 - (int)vec1;
343         ry1 = ry0 - 1.0;
344         sy = s_curve(ry0);
345
346         switch (channels.length) {
347             // Intentionally use 'fall through' in switch statement.
348
case 4:
349             noise[3] =
350                 lerp(sy,
351                      lerp(sx,
352                           rx0*gradient[b0+6] + ry0*gradient[b0+7],
353                           rx1*gradient[b1+6] + ry0*gradient[b1+7]),
354                      lerp(sx,
355                           rx0*gradient[b0+8+6] + ry1*gradient[b0+8+7],
356                           rx1*gradient[b1+8+6] + ry1*gradient[b1+8+7]));
357         case 3:
358             noise[2] =
359                 lerp(sy,
360                      lerp(sx,
361                           rx0*gradient[b0+4] + ry0*gradient[b0+5],
362                           rx1*gradient[b1+4] + ry0*gradient[b1+5]),
363                      lerp(sx,
364                           rx0*gradient[b0+8+4] + ry1*gradient[b0+8+5],
365                           rx1*gradient[b1+8+4] + ry1*gradient[b1+8+5]));
366         case 2:
367             noise[1] =
368                 lerp(sy,
369                      lerp(sx,
370                           rx0*gradient[b0+2] + ry0*gradient[b0+3],
371                           rx1*gradient[b1+2] + ry0*gradient[b1+3]),
372                      lerp(sx,
373                           rx0*gradient[b0+8+2] + ry1*gradient[b0+8+3],
374                           rx1*gradient[b1+8+2] + ry1*gradient[b1+8+3]));
375         case 1:
376             noise[0] =
377                 lerp(sy,
378                      lerp(sx,
379                           rx0*gradient[b0+0] + ry0*gradient[b0+1],
380                           rx1*gradient[b1+0] + ry0*gradient[b1+1]),
381                      lerp(sx,
382                           rx0*gradient[b0+8+0] + ry1*gradient[b0+8+1],
383                           rx1*gradient[b1+8+0] + ry1*gradient[b1+8+1]));
384         }
385     }
386
387     /**
388      * This version of the noise function implements stitching.
389      * If any of the lattice is on the right or bottom edge, the
390      * function uses the the latice on the other side of the
391      * tile, i.e., the left or right edge.
392      * @param noise The place to put the generated noise.
393      * @param vec0 The X coordiate to generate noise for
394      * @param vec1 The Y coordiate to generate noise for
395      * @param stitchInfo The stitching information for the noise function.
396      */

397     private final void noise2Stitch(final double noise[],
398                                     final double vec0, final double vec1,
399                                     final StitchInfo stitchInfo){
400         int b0, b1;
401         final int i, j, b00, b10, b01, b11;
402         double t;
403         final double rx0, rx1, ry0, ry1, sx, sy;
404
405         t = vec0 + PerlinN;
406         b0 = ((int)t);
407         b1 = b0+1;
408         // Stitch lattice tile x coordinates
409
if (b1 >= stitchInfo.wrapX) {
410             if (b0 >= stitchInfo.wrapX) {
411                 b0 -= stitchInfo.width;
412                 b1 -= stitchInfo.width;
413             } else {
414                 b1 -= stitchInfo.width;
415             }
416         }
417         i = latticeSelector[b0&BM];
418         j = latticeSelector[b1&BM];
419
420         rx0 = t - (int)t;
421         rx1 = rx0 - 1.0;
422         sx = s_curve(rx0);
423
424         t = vec1 + PerlinN;
425         b0 = ((int)t);
426         b1 = b0+1;
427         // Stitch lattice tile y coordinates
428
if (b1 >= stitchInfo.wrapY) {
429             if (b0 >= stitchInfo.wrapY) {
430                 b0 -= stitchInfo.height;
431                 b1 -= stitchInfo.height;
432             } else {
433                 b1 -= stitchInfo.height;
434             }
435         }
436         // In this case we still need to keep all four indexes since
437
// we may have split y across the stitch boundry, in which
438
// case b0 and b1 do not have a fixed offset from one another.
439
// We still avoid a latticeSelector lookup for each index though...
440
b00 = ((i + b0)&BM)<<3;
441         b10 = ((j + b0)&BM)<<3;
442         b01 = ((i + b1)&BM)<<3;
443         b11 = ((j + b1)&BM)<<3;
444
445         ry0 = t - (int)t;
446         ry1 = ry0 - 1.0;
447         sy = s_curve(ry0);
448
449         switch (channels.length) {
450             // Intentionally use 'fall through' in switch statement.
451
case 4:
452             noise[3] =
453                 lerp(sy,
454                      lerp(sx,
455                           rx0*gradient[b00+6] + ry0*gradient[b00+7],
456                           rx1*gradient[b10+6] + ry0*gradient[b10+7]),
457                      lerp(sx,
458                           rx0*gradient[b01+6] + ry1*gradient[b01+7],
459                           rx1*gradient[b11+6] + ry1*gradient[b11+7]));
460         case 3:
461             noise[2] =
462                 lerp(sy,
463                      lerp(sx,
464                           rx0*gradient[b00+4] + ry0*gradient[b00+5],
465                           rx1*gradient[b10+4] + ry0*gradient[b10+5]),
466                      lerp(sx,
467                           rx0*gradient[b01+4] + ry1*gradient[b01+5],
468                           rx1*gradient[b11+4] + ry1*gradient[b11+5]));
469         case 2:
470             noise[1] =
471                 lerp(sy,
472                      lerp(sx,
473                           rx0*gradient[b00+2] + ry0*gradient[b00+3],
474                           rx1*gradient[b10+2] + ry0*gradient[b10+3]),
475                      lerp(sx,
476                           rx0*gradient[b01+2] + ry1*gradient[b01+3],
477                           rx1*gradient[b11+2] + ry1*gradient[b11+3]));
478         case 1:
479             noise[0] =
480                 lerp(sy,
481                      lerp(sx,
482                           rx0*gradient[b00+0] + ry0*gradient[b00+1],
483                           rx1*gradient[b10+0] + ry0*gradient[b10+1]),
484                      lerp(sx,
485                           rx0*gradient[b01+0] + ry1*gradient[b01+1],
486                           rx1*gradient[b11+0] + ry1*gradient[b11+1]));
487         }
488     }
489
490     /**
491      * This is the heart of the turbulence calculation. It returns
492      * 'turbFunctionResult', as defined in the spec. This is
493      * special case for 4 bands of output.
494      *
495      * @param point x and y coordinates of the point to process.
496      * @param fSum array used to avoid reallocating double array for each pixel
497      * @return The ARGB pixel value.
498      */

499     private final int turbulence_4(double pointX,
500                                    double pointY,
501                                    final double fSum[]) {
502         double n, ratio = 255;
503         int i, j, b0, b1, nOctave;
504         double px, py, rx0, rx1, ry0, ry1, sx, sy;
505
506         pointX *= baseFrequencyX;
507         pointY *= baseFrequencyY;
508         fSum[0] = fSum[1] = fSum[2] = fSum[3] = 0;
509
510         for (nOctave = numOctaves; nOctave > 0; nOctave--){
511             px = pointX+PerlinN;
512
513             b0 = ((int)px)&BM;
514             i = latticeSelector[b0 ];
515             j = latticeSelector[b0+1];
516
517             rx0 = px - (int)px;
518             rx1 = rx0 - 1.0;
519             sx = s_curve(rx0);
520
521             py = pointY+PerlinN;
522             b0 = ((int)py) & BM;
523             b1 = (b0+1) & BM;
524
525             b1 = ((j + b0)&BM)<<3;
526             b0 = ((i + b0)&BM)<<3;
527
528             ry0 = py - (int)py;
529             ry1 = ry0 - 1.0;
530             sy = s_curve(ry0);
531
532             n = lerp(sy,
533                      lerp(sx,
534                           rx0*gradient[b0+0] + ry0*gradient[b0+1],
535                           rx1*gradient[b1+0] + ry0*gradient[b1+1]),
536                      lerp(sx,
537                           rx0*gradient[b0+8+0] + ry1*gradient[b0+8+1],
538                           rx1*gradient[b1+8+0] + ry1*gradient[b1+8+1]));
539
540             if (n<0) fSum[0] -= (n * ratio);
541             else fSum[0] += (n * ratio);
542
543             n = lerp(sy,
544                      lerp(sx,
545                           rx0*gradient[b0+2] + ry0*gradient[b0+3],
546                           rx1*gradient[b1+2] + ry0*gradient[b1+3]),
547                      lerp(sx,
548                           rx0*gradient[b0+8+2] + ry1*gradient[b0+8+3],
549                           rx1*gradient[b1+8+2] + ry1*gradient[b1+8+3]));
550
551             if (n<0) fSum[1] -= (n * ratio);
552             else fSum[1] += (n * ratio);
553
554             n = lerp(sy,
555                      lerp(sx,
556                           rx0*gradient[b0+4] + ry0*gradient[b0+5],
557                           rx1*gradient[b1+4] + ry0*gradient[b1+5]),
558                      lerp(sx,
559                           rx0*gradient[b0+8+4] + ry1*gradient[b0+8+5],
560                           rx1*gradient[b1+8+4] + ry1*gradient[b1+8+5]));
561
562             if (n<0) fSum[2] -= (n * ratio);
563             else fSum[2] += (n * ratio);
564
565             n = lerp(sy,
566                      lerp(sx,
567                           rx0*gradient[b0+6] + ry0*gradient[b0+7],
568                           rx1*gradient[b1+6] + ry0*gradient[b1+7]),
569                      lerp(sx,
570                           rx0*gradient[b0+8+6] + ry1*gradient[b0+8+7],
571                           rx1*gradient[b1+8+6] + ry1*gradient[b1+8+7]));
572             if (n<0) fSum[3] -= (n * ratio);
573             else fSum[3] += (n * ratio);
574
575             ratio *= .5;
576             pointX *= 2;
577             pointY *= 2;
578         }
579
580         i = (int)fSum[0];
581         if ((i & 0xFFFFFF00) == 0) j = i<<16;
582         else j = ((i & 0x80000000) != 0)?0:0xFF0000;
583
584         i = (int)fSum[1];
585         if ((i & 0xFFFFFF00) == 0) j |= i<<8;
586         else j |= ((i & 0x80000000) != 0)?0:0xFF00;
587
588         i = (int)fSum[2];
589         if ((i & 0xFFFFFF00) == 0) j |= i;
590         else j |= ((i & 0x80000000) != 0)?0:0xFF;
591
592         i = (int)fSum[3];
593         if ((i & 0xFFFFFF00) == 0) j |= i<<24;
594         else j |= ((i & 0x80000000) != 0)?0:0xFF000000;
595         return j;
596     }
597
598
599     /**
600      * This is the heart of the turbulence calculation. It returns
601      * 'turbFunctionResult', as defined in the spec.
602      * @param rgb array for the four color components
603      * @param point x and y coordinates of the point to process.
604      * @param fSum array used to avoid reallocating double array for each pixel
605      * @param noise array used to avoid reallocating double array for
606      * each pixel
607      */

608     private final void turbulence(final int rgb[],
609                                   double pointX,
610                                   double pointY,
611                                   final double fSum[],
612                                   final double noise[]) {
613         fSum[0] = fSum[1] = fSum[2] = fSum[3] = 0;
614         double ratio = 255;
615         pointX *= baseFrequencyX;
616         pointY *= baseFrequencyY;
617         switch (channels.length) {
618         case 4:
619             for(int nOctave = 0; nOctave < numOctaves; nOctave++){
620                 noise2(noise, pointX, pointY);
621
622                 if (noise[0]<0) fSum[0] -= (noise[0] * ratio);
623                 else fSum[0] += (noise[0] * ratio);
624                 if (noise[1]<0) fSum[1] -= (noise[1] * ratio);
625                 else fSum[1] += (noise[1] * ratio);
626                 if (noise[2]<0) fSum[2] -= (noise[2] * ratio);
627                 else fSum[2] += (noise[2] * ratio);
628                 if (noise[3]<0) fSum[3] -= (noise[3] * ratio);
629                 else fSum[3] += (noise[3] * ratio);
630                 ratio *= .5;
631                 pointX *= 2;
632                 pointY *= 2;
633             }
634
635             rgb[0] = (int)fSum[0];
636             if ((rgb[0] & 0xFFFFFF00) != 0)
637                 rgb[0] = ((rgb[0] & 0x80000000) != 0)?0:255;
638             rgb[1] = (int)fSum[1];
639             if ((rgb[1] & 0xFFFFFF00) != 0)
640                 rgb[1] = ((rgb[1] & 0x80000000) != 0)?0:255;
641             rgb[2] = (int)fSum[2];
642             if ((rgb[2] & 0xFFFFFF00) != 0)
643                 rgb[2] = ((rgb[2] & 0x80000000) != 0)?0:255;
644             rgb[3] = (int)fSum[3];
645             if ((rgb[3] & 0xFFFFFF00) != 0)
646                 rgb[3] = ((rgb[3] & 0x80000000) != 0)?0:255;
647             break;
648         case 3:
649             for(int nOctave = 0; nOctave < numOctaves; nOctave++){
650                 noise2(noise, pointX, pointY);
651
652                 if (noise[2]<0) fSum[2] -= (noise[2] * ratio);
653                 else fSum[2] += (noise[2] * ratio);
654                 if (noise[1]<0) fSum[1] -= (noise[1] * ratio);
655                 else fSum[1] += (noise[1] * ratio);
656                 if (noise[0]<0) fSum[0] -= (noise[0] * ratio);
657                 else fSum[0] += (noise[0] * ratio);
658                 ratio *= .5;
659                 pointX *= 2;
660                 pointY *= 2;
661             }
662             rgb[2] = (int)fSum[2];
663             if ((rgb[2] & 0xFFFFFF00) != 0)
664                 rgb[2] = ((rgb[2] & 0x80000000) != 0)?0:255;
665             rgb[1] = (int)fSum[1];
666             if ((rgb[1] & 0xFFFFFF00) != 0)
667                 rgb[1] = ((rgb[1] & 0x80000000) != 0)?0:255;
668             rgb[0] = (int)fSum[0];
669             if ((rgb[0] & 0xFFFFFF00) != 0)
670                 rgb[0] = ((rgb[0] & 0x80000000) != 0)?0:255;
671             break;
672         case 2:
673             for(int nOctave = 0; nOctave < numOctaves; nOctave++){
674                 noise2(noise, pointX, pointY);
675
676                 if (noise[1]<0) fSum[1] -= (noise[1] * ratio);
677                 else fSum[1] += (noise[1] * ratio);
678                 if (noise[0]<0) fSum[0] -= (noise[0] * ratio);
679                 else fSum[0] += (noise[0] * ratio);
680                 ratio *= .5;
681                 pointX *= 2;
682                 pointY *= 2;
683             }
684
685             rgb[1] = (int)fSum[1];
686             if ((rgb[1] & 0xFFFFFF00) != 0)
687                 rgb[1] = ((rgb[1] & 0x80000000) != 0)?0:255;
688             rgb[0] = (int)fSum[0];
689             if ((rgb[0] & 0xFFFFFF00) != 0)
690                 rgb[0] = ((rgb[0] & 0x80000000) != 0)?0:255;
691             break;
692         case 1:
693             for(int nOctave = 0; nOctave < numOctaves; nOctave++){
694                 noise2(noise, pointX, pointY);
695
696                 if (noise[0]<0) fSum[0] -= (noise[0] * ratio);
697                 else fSum[0] += (noise[0] * ratio);
698                 ratio *= .5;
699                 pointX *= 2;
700                 pointY *= 2;
701             }
702
703             rgb[0] = (int)fSum[0];
704             if ((rgb[0] & 0xFFFFFF00) != 0)
705                 rgb[0] = ((rgb[0] & 0x80000000) != 0)?0:255;
706             break;
707         }
708     }
709
710     /**
711      * This is the heart of the turbulence calculation. It returns
712      * 'turbFunctionResult', as defined in the spec.
713      * @param rgb array for the four color components
714      * @param point x and y coordinates of the point to process.
715      * @param fSum array used to avoid reallocating double array for each pixel
716      * @param noise array used to avoid reallocating double array for
717      * each pixel
718      * @param stitchInfo The stitching information for the noise function
719      */

720     private final void turbulenceStitch(final int rgb[],
721                                         double pointX, double pointY,
722                                         final double fSum[],
723                                         final double noise[],
724                                         StitchInfo stitchInfo){
725         double ratio = 1;
726         pointX *= baseFrequencyX;
727         pointY *= baseFrequencyY;
728         fSum[0] = fSum[1] = fSum[2] = fSum[3] = 0;
729         switch (channels.length) {
730         case 4:
731             for(int nOctave = 0; nOctave < numOctaves; nOctave++){
732                 noise2Stitch(noise, pointX, pointY, stitchInfo);
733
734                 if (noise[3]<0) fSum[3] -= (noise[3] * ratio);
735                 else fSum[3] += (noise[3] * ratio);
736                 if (noise[2]<0) fSum[2] -= (noise[2] * ratio);
737                 else fSum[2] += (noise[2] * ratio);
738                 if (noise[1]<0) fSum[1] -= (noise[1] * ratio);
739                 else fSum[1] += (noise[1] * ratio);
740                 if (noise[0]<0) fSum[0] -= (noise[0] * ratio);
741                 else fSum[0] += (noise[0] * ratio);
742                 ratio *= .5;
743                 pointX *= 2;
744                 pointY *= 2;
745
746                 stitchInfo.doubleFrequency();
747             }
748             rgb[3] = (int)(fSum[3] * 255);
749             if ((rgb[3] & 0xFFFFFF00) != 0)
750                 rgb[3] = ((rgb[3] & 0x80000000) != 0)?0:255;
751             rgb[2] = (int)(fSum[2] * 255);
752             if ((rgb[2] & 0xFFFFFF00) != 0)
753                 rgb[2] = ((rgb[2] & 0x80000000) != 0)?0:255;
754             rgb[1] = (int)(fSum[1] * 255);
755             if ((rgb[1] & 0xFFFFFF00) != 0)
756                 rgb[1] = ((rgb[1] & 0x80000000) != 0)?0:255;
757             rgb[0] = (int)(fSum[0] * 255);
758             if ((rgb[0] & 0xFFFFFF00) != 0)
759                 rgb[0] = ((rgb[0] & 0x80000000) != 0)?0:255;
760             break;
761         case 3:
762             for(int nOctave = 0; nOctave < numOctaves; nOctave++){
763                 noise2Stitch(noise, pointX, pointY, stitchInfo);
764                 if (noise[2]<0) fSum[2] -= (noise[2] * ratio);
765                 else fSum[2] += (noise[2] * ratio);
766                 if (noise[1]<0) fSum[1] -= (noise[1] * ratio);
767                 else fSum[1] += (noise[1] * ratio);
768                 if (noise[0]<0) fSum[0] -= (noise[0] * ratio);
769                 else fSum[0] += (noise[0] * ratio);
770                 ratio *= .5;
771                 pointX *= 2;
772                 pointY *= 2;
773
774                 stitchInfo.doubleFrequency();
775             }
776             rgb[2] = (int)(fSum[2] * 255);
777             if ((rgb[2] & 0xFFFFFF00) != 0)
778                 rgb[2] = ((rgb[2] & 0x80000000) != 0)?0:255;
779             rgb[1] = (int)(fSum[1] * 255);
780             if ((rgb[1] & 0xFFFFFF00) != 0)
781                 rgb[1] = ((rgb[1] & 0x80000000) != 0)?0:255;
782             rgb[0] = (int)(fSum[0] * 255);
783             if ((rgb[0] & 0xFFFFFF00) != 0)
784                 rgb[0] = ((rgb[0] & 0x80000000) != 0)?0:255;
785             break;
786         case 2:
787             for(int nOctave = 0; nOctave < numOctaves; nOctave++){
788                 noise2Stitch(noise, pointX, pointY, stitchInfo);
789                 if (noise[1]<0) fSum[1] -= (noise[1] * ratio);
790                 else fSum[1] += (noise[1] * ratio);
791                 if (noise[0]<0) fSum[0] -= (noise[0] * ratio);
792                 else fSum[0] += (noise[0] * ratio);
793                 ratio *= .5;
794                 pointX *= 2;
795                 pointY *= 2;
796
797                 stitchInfo.doubleFrequency();
798             }
799             rgb[1] = (int)(fSum[1] * 255);
800             if ((rgb[1] & 0xFFFFFF00) != 0)
801                 rgb[1] = ((rgb[1] & 0x80000000) != 0)?0:255;
802             rgb[0] = (int)(fSum[0] * 255);
803             if ((rgb[0] & 0xFFFFFF00) != 0)
804                 rgb[0] = ((rgb[0] & 0x80000000) != 0)?0:255;
805             break;
806         case 1:
807             for(int nOctave = 0; nOctave < numOctaves; nOctave++){
808                 noise2Stitch(noise, pointX, pointY, stitchInfo);
809                 if (noise[0]<0) fSum[0] -= (noise[0] * ratio);
810                 else fSum[0] += (noise[0] * ratio);
811                 ratio *= .5;
812                 pointX *= 2;
813                 pointY *= 2;
814
815                 stitchInfo.doubleFrequency();
816             }
817             rgb[0] = (int)(fSum[0] * 255);
818             if ((rgb[0] & 0xFFFFFF00) != 0)
819                 rgb[0] = ((rgb[0] & 0x80000000) != 0)?0:255;
820             break;
821         }
822     }
823
824     /**
825      * This is the heart of the turbulence calculation. It returns
826      * 'turbFunctionResult', as defined in the spec. This handles the
827      * case where we are generating 4 channels of noise.
828      * @param point x and y coordinates of the point to process.
829      * @param fSum array used to avoid reallocating double array for each pixel
830      * @return The ARGB pixel
831      */

832     private final int turbulenceFractal_4( double pointX,
833                                            double pointY,
834                                            final double fSum[]) {
835         int b0, b1, nOctave, i, j;
836         double px, py, rx0, rx1, ry0, ry1, sx, sy, ratio = 127.5;
837
838         pointX *= baseFrequencyX;
839         pointY *= baseFrequencyY;
840         fSum[0] = fSum[1] = fSum[2] = fSum[3] = 127.5;
841
842         for (nOctave = numOctaves; nOctave > 0; nOctave--){
843             px = pointX+PerlinN;
844
845             b0 = ((int)px)&BM;
846             i = latticeSelector[b0 ];
847             j = latticeSelector[b0+1];
848
849             rx0 = px - (int)px;
850             rx1 = rx0 - 1.0;
851             sx = s_curve(rx0);
852
853             py = pointY+PerlinN;
854             b0 = ((int)py) & BM;
855             b1 = (b0+1) & BM;
856
857             b1 = ((j + b0)&BM)<<3;
858             b0 = ((i + b0)&BM)<<3;
859
860             ry0 = py - (int)py;
861             ry1 = ry0 - 1.0;
862             sy = s_curve(ry0);
863
864             fSum[0] += lerp(sy,
865                      lerp(sx,
866                           rx0*gradient[b0+0] + ry0*gradient[b0+1],
867                           rx1*gradient[b1+0] + ry0*gradient[b1+1]),
868                      lerp(sx,
869                           rx0*gradient[b0+8+0] + ry1*gradient[b0+8+1],
870                           rx1*gradient[b1+8+0] + ry1*gradient[b1+8+1]))*ratio;
871
872             fSum[1] += lerp(sy,
873                      lerp(sx,
874                           rx0*gradient[b0+2] + ry0*gradient[b0+3],
875                           rx1*gradient[b1+2] + ry0*gradient[b1+3]),
876                      lerp(sx,
877                           rx0*gradient[b0+8+2] + ry1*gradient[b0+8+3],
878                           rx1*gradient[b1+8+2] + ry1*gradient[b1+8+3]))*ratio;
879
880             fSum[2] += lerp(sy,
881                      lerp(sx,
882                           rx0*gradient[b0+4] + ry0*gradient[b0+5],
883                           rx1*gradient[b1+4] + ry0*gradient[b1+5]),
884                      lerp(sx,
885                           rx0*gradient[b0+8+4] + ry1*gradient[b0+8+5],
886                           rx1*gradient[b1+8+4] + ry1*gradient[b1+8+5]))*ratio;
887
888             fSum[3] += lerp(sy,
889                      lerp(sx,
890                           rx0*gradient[b0+6] + ry0*gradient[b0+7],
891                           rx1*gradient[b1+6] + ry0*gradient[b1+7]),
892                      lerp(sx,
893                           rx0*gradient[b0+8+6] + ry1*gradient[b0+8+7],
894                           rx1*gradient[b1+8+6] + ry1*gradient[b1+8+7]))*ratio;
895
896             ratio *= .5;
897             pointX *= 2;
898             pointY *= 2;
899         }
900
901         i = (int)fSum[0];
902         if ((i & 0xFFFFFF00) == 0) j = i<<16;
903         else j = ((i & 0x80000000) != 0)?0:0xFF0000;
904
905         i = (int)fSum[1];
906         if ((i & 0xFFFFFF00) == 0) j |= i<<8;
907         else j |= ((i & 0x80000000) != 0)?0:0xFF00;
908
909         i = (int)fSum[2];
910         if ((i & 0xFFFFFF00) == 0) j |= i;
911         else j |= ((i & 0x80000000) != 0)?0:0xFF;
912
913         i = (int)fSum[3];
914         if ((i & 0xFFFFFF00) == 0) j |= i<<24;
915         else j |= ((i & 0x80000000) != 0)?0:0xFF000000;
916         return j;
917     }
918
919     /**
920      * This is the heart of the turbulence calculation. It returns
921      * 'turbFunctionResult', as defined in the spec.
922      * @param rgb array for the four color components
923      * @param point x and y coordinates of the point to process.
924      * @param fSum array used to avoid reallocating double array for each pixel
925      * @param noise array used to avoid reallocating double array for
926      * each pixel
927      */

928     private final void turbulenceFractal(final int rgb[],
929                                          double pointX,
930                                          double pointY,
931                                          final double fSum[],
932                                          final double noise[]){
933         double ratio = 127.5;
934         int nOctave;
935         fSum[0] = fSum[1] = fSum[2] = fSum[3] = 127.5;
936         pointX *= baseFrequencyX;
937         pointY *= baseFrequencyY;
938         for(nOctave = numOctaves; nOctave > 0; nOctave--){
939             noise2(noise, pointX, pointY);
940
941             switch (channels.length) {
942             case 4:
943                 fSum[3] += (noise[3] * ratio);
944             case 3:
945                 fSum[2] += (noise[2] * ratio);
946             case 2:
947                 fSum[1] += (noise[1] * ratio);
948             case 1:
949                 fSum[0] += (noise[0] * ratio);
950             }
951
952             ratio *= .5;
953             pointX *= 2;
954             pointY *= 2;
955         }
956
957         switch (channels.length) {
958         case 4:
959             rgb[3] = (int)fSum[3];
960             if ((rgb[3] & 0xFFFFFF00) != 0)
961                 rgb[3] = ((rgb[3] & 0x80000000) != 0)?0:255;
962         case 3:
963             rgb[2] = (int)fSum[2];
964             if ((rgb[2] & 0xFFFFFF00) != 0)
965                 rgb[2] = ((rgb[2] & 0x80000000) != 0)?0:255;
966         case 2:
967             rgb[1] = (int)fSum[1];
968             if ((rgb[1] & 0xFFFFFF00) != 0)
969                 rgb[1] = ((rgb[1] & 0x80000000) != 0)?0:255;
970         case 1:
971             rgb[0] = (int)fSum[0];
972             if ((rgb[0] & 0xFFFFFF00) != 0)
973                 rgb[0] = ((rgb[0] & 0x80000000) != 0)?0:255;
974         }
975     }
976
977     /**
978      * This is the heart of the turbulence calculation. It returns
979      * 'turbFunctionResult', as defined in the spec.
980      * @param rgb array for the four color components
981      * @param point x and y coordinates of the point to process.
982      * @param fSum array used to avoid reallocating double array for each pixel
983      * @param noise array used to avoid reallocating double array for
984      * each pixel
985      * @param stitchInfo The stitching information for the noise function
986      */

987     private final void turbulenceFractalStitch(final int rgb[],
988                                                double pointX,
989                                                double pointY,
990                                                final double fSum[],
991                                                final double noise[],
992                                                StitchInfo stitchInfo){
993         double ratio = 127.5;
994         int nOctave;
995         fSum[0] = fSum[1] = fSum[2] = fSum[3] = 127.5;
996         pointX *= baseFrequencyX;
997         pointY *= baseFrequencyY;
998         for(nOctave = numOctaves; nOctave > 0; nOctave--){
999             noise2Stitch(noise, pointX, pointY, stitchInfo);
1000
1001            switch (channels.length) {
1002            case 4:
1003                fSum[3] += (noise[3] * ratio);
1004            case 3:
1005                fSum[2] += (noise[2] * ratio);
1006            case 2:
1007                fSum[1] += (noise[1] * ratio);
1008            case 1:
1009                fSum[0] += (noise[0] * ratio);
1010            }
1011
1012            ratio *= .5;
1013            pointX *= 2;
1014            pointY *= 2;
1015            stitchInfo.doubleFrequency();
1016        }
1017
1018        switch (channels.length) {
1019        case 4:
1020            rgb[3] = (int)fSum[3];
1021            if ((rgb[3] & 0xFFFFFF00) != 0)
1022                rgb[3] = ((rgb[3] & 0x80000000) != 0)?0:255;
1023        case 3:
1024            rgb[2] = (int)fSum[2];
1025            if ((rgb[2] & 0xFFFFFF00) != 0)
1026                rgb[2] = ((rgb[2] & 0x80000000) != 0)?0:255;
1027        case 2:
1028            rgb[1] = (int)fSum[1];
1029            if ((rgb[1] & 0xFFFFFF00) != 0)
1030                rgb[1] = ((rgb[1] & 0x80000000) != 0)?0:255;
1031        case 1:
1032            rgb[0] = (int)fSum[0];
1033            if ((rgb[0] & 0xFFFFFF00) != 0)
1034                rgb[0] = ((rgb[0] & 0x80000000) != 0)?0:255;
1035        }
1036    }
1037
1038    /**
1039     * Generates a Perlin noise pattern into dest Raster.
1040     * @param dest Raster to fill with the pattern.
1041     */

1042    public WritableRaster JavaDoc copyData(WritableRaster JavaDoc dest) {
1043        //
1044
// First, check input arguments
1045
//
1046
if(dest==null)
1047            throw new IllegalArgumentException JavaDoc
1048                ("Cannot generate a noise pattern into a null raster");
1049
1050
1051        int w = dest.getWidth();
1052        int h = dest.getHeight();
1053
1054        // Access the integer buffer for the destination Raster
1055
DataBufferInt JavaDoc dstDB = (DataBufferInt JavaDoc)dest.getDataBuffer();
1056        SinglePixelPackedSampleModel JavaDoc sppsm;
1057        int minX = dest.getMinX();
1058        int minY = dest.getMinY();
1059        sppsm = (SinglePixelPackedSampleModel JavaDoc)dest.getSampleModel();
1060        int dstOff = dstDB.getOffset() +
1061            sppsm.getOffset(minX - dest.getSampleModelTranslateX(),
1062                            minY - dest.getSampleModelTranslateY());
1063
1064        final int destPixels[] = dstDB.getBankData()[0];
1065        int dstAdjust = sppsm.getScanlineStride() - w;
1066
1067        // Generate pixel pattern now
1068
int i, end, dp=dstOff;
1069        final int rgb[] = new int[4];
1070        final double fSum[] = {0, 0, 0, 0};
1071        final double noise[] = {0, 0, 0, 0};
1072
1073        final double tx0, tx1, ty0, ty1;
1074        tx0 = tx[0];
1075        tx1 = tx[1];
1076        // Update for y step, (note we substract all the stuff we
1077
// added while going across the scan line).
1078
ty0 = ty[0]-(w*tx0);
1079        ty1 = ty[1]-(w*tx1);
1080
1081        double p[] = {minX, minY};
1082        txf.transform(p, 0, p, 0, 1);
1083        double point_0 = p[0];
1084        double point_1 = p[1];
1085
1086        if(isFractalNoise){
1087            if(stitchInfo == null){
1088                if (channels.length == 4) {
1089                    for(i=0; i<h; i++){
1090                        for(end=dp+w; dp<end; dp++) {
1091                            destPixels[dp] = turbulenceFractal_4
1092                                (point_0, point_1, fSum);
1093                            point_0 += tx0;
1094                            point_1 += tx1;
1095                        }
1096                        point_0 += ty0;
1097                        point_1 += ty1;
1098                        dp += dstAdjust;
1099                    }
1100                } else {
1101                    for(i=0; i<h; i++){
1102                        for(end=dp+w; dp<end; dp++){
1103                            turbulenceFractal(rgb, point_0, point_1, fSum, noise);
1104
1105                            // Write RGB value.
1106
destPixels[dp] = ((rgb[3]<<24) |
1107                                              (rgb[0]<<16) |
1108                                              (rgb[1]<<8) |
1109                                              (rgb[2] ));
1110                            point_0 += tx0;
1111                            point_1 += tx1;
1112                        }
1113                        point_0 += ty0;
1114                        point_1 += ty1;
1115                        dp += dstAdjust;
1116                    }
1117                }
1118            }
1119            else{
1120                StitchInfo si = new StitchInfo();
1121                for(i=0; i<h; i++){
1122                    for(end=dp+w; dp<end; dp++){
1123                        si.assign(this.stitchInfo);
1124                        turbulenceFractalStitch(rgb, point_0, point_1,
1125                                                fSum, noise, si);
1126
1127                        // Write RGB value.
1128
destPixels[dp] = ((rgb[3]<<24) |
1129                                          (rgb[0]<<16) |
1130                                          (rgb[1]<<8) |
1131                                          (rgb[2] ));
1132                        point_0 += tx0;
1133                        point_1 += tx1;
1134                    }
1135                    point_0 += ty0;
1136                    point_1 += ty1;
1137                    dp += dstAdjust;
1138                }
1139            }
1140        }
1141        else{ // Loop for turbulence noise
1142
if(stitchInfo == null){
1143                if (channels.length == 4) {
1144                    for(i=0; i<h; i++){
1145                        for(end=dp+w; dp<end; dp++){
1146                            destPixels[dp] = turbulence_4
1147                                (point_0, point_1, fSum);
1148
1149                            point_0 += tx0;
1150                            point_1 += tx1;
1151                        }
1152                        point_0 += ty0;
1153                        point_1 += ty1;
1154                        dp += dstAdjust;
1155                    }
1156                } else {
1157                    for(i=0; i<h; i++){
1158                        for(end=dp+w; dp<end; dp++){
1159                            turbulence(rgb, point_0, point_1, fSum, noise);
1160
1161                            // Write RGB value.
1162
destPixels[dp] = ((rgb[3]<<24) |
1163                                              (rgb[0]<<16) |
1164                                              (rgb[1]<<8) |
1165                                              (rgb[2] ));
1166                            point_0 += tx0;
1167                            point_1 += tx1;
1168                        }
1169                        point_0 += ty0;
1170                        point_1 += ty1;
1171                        dp += dstAdjust;
1172                    }
1173                }
1174            }
1175            else{
1176                StitchInfo si = new StitchInfo();
1177                for(i=0; i<h; i++){
1178                    for(end=dp+w; dp<end; dp++){
1179                        si.assign(this.stitchInfo);
1180                        turbulenceStitch(rgb, point_0, point_1,
1181                                         fSum, noise, si);
1182
1183                        // Write RGB value.
1184
destPixels[dp] = ((rgb[3]<<24) |
1185                                          (rgb[0]<<16) |
1186                                          (rgb[1]<<8) |
1187                                          (rgb[2] ));
1188                        point_0 += tx0;
1189                        point_1 += tx1;
1190                    }
1191                    point_0 += ty0;
1192                    point_1 += ty1;
1193                    dp += dstAdjust;
1194                }
1195            }
1196        }
1197
1198        return dest;
1199    }
1200
1201    /**
1202     * @param baseFrequencyX x-axis base frequency for the noise
1203     * function along the x-axis
1204     * @param baseFrequencyY y-axis base frequency for the noise
1205     * function along the x-axis
1206     * @param numOctaves number of octaves in the noise
1207     * function. Positive integral value.
1208     * @param seed starting number for the pseudo random number generator
1209     * @param isFractalNoise defines whether the filter performs a
1210     * fractal noise or a turbulence function.
1211     * @param tile defines the tile size. May be null if stitchTiles
1212     * is false. Otherwise, should not be null.
1213     * @param txf The affine transform from device to user space.
1214     * @param cs The Colorspace to output.
1215     * @param alpha True if the data should have an alpha channel.
1216     */

1217    public TurbulencePatternRed(double baseFrequencyX,
1218                                double baseFrequencyY,
1219                                int numOctaves,
1220                                int seed,
1221                                boolean isFractalNoise,
1222                                Rectangle2D JavaDoc tile,
1223                                AffineTransform JavaDoc txf,
1224                                Rectangle JavaDoc devRect,
1225                                ColorSpace JavaDoc cs,
1226                                boolean alpha) {
1227        this.baseFrequencyX = baseFrequencyX;
1228        this.baseFrequencyY = baseFrequencyY;
1229        this.seed = seed;
1230        this.isFractalNoise = isFractalNoise;
1231        this.tile = tile;
1232        this.txf = txf;
1233
1234        if(this.txf == null)
1235            this.txf = IDENTITY;
1236
1237        int nChannels = cs.getNumComponents();
1238        if (alpha) nChannels++;
1239        channels = new int[nChannels];
1240        for(int i=0; i<channels.length; i++)
1241            channels[i] = i;
1242
1243        txf.deltaTransform(tx, 0, tx, 0, 1);
1244        txf.deltaTransform(ty, 0, ty, 0, 1);
1245
1246        double vecX[] = {.5, 0};
1247        double vecY[] = {0, .5};
1248        txf.deltaTransform(vecX, 0, vecX, 0, 1);
1249        txf.deltaTransform(vecY, 0, vecY, 0, 1);
1250
1251        //
1252
// Now, limit the number of octaves so that we do not get frequencies
1253
// below half a pixel.
1254
//
1255
// If d is the distance between to pixels in user space, then,
1256
// numOctavesMax = -(log2(d) + log2(bf))
1257
// along one axis.
1258
//
1259
// The maximum distance along each axis is processed by
1260
// computing the inverse transform of 'maximum' vectors from
1261
// device space to the filter space and determining the
1262
// maximum component along each axis.
1263

1264        double dx = Math.max(Math.abs(vecX[0]), Math.abs(vecY[0]));
1265        int maxX = -(int)Math.round((Math.log(dx) + Math.log(baseFrequencyX))/
1266                                    Math.log(2));
1267
1268        double dy = Math.max(Math.abs(vecX[1]), Math.abs(vecY[1]));
1269        int maxY = -(int)Math.round((Math.log(dy) + Math.log(baseFrequencyY))/
1270                                    Math.log(2));
1271
1272        this.numOctaves = numOctaves > maxX? maxX : numOctaves;
1273        this.numOctaves = this.numOctaves > maxY? maxY : this.numOctaves;
1274
1275        if(this.numOctaves < 1 && numOctaves > 1)
1276            this.numOctaves = 1;
1277
1278        if (this.numOctaves > 8)
1279            // beyond 8 octaves there is no significant contribution
1280
// to the output pixel (contribution is halved for each
1281
// octave so after 8 we are contributing less than half a
1282
// code value _at_best_).
1283
this.numOctaves = 8;
1284
1285        if (tile != null) {
1286            //
1287
// Adjust frequencies to the tile size
1288
//
1289
double lowFreq = Math.floor(tile.getWidth()*baseFrequencyX)/tile.getWidth();
1290            double highFreq = Math.ceil(tile.getWidth()*baseFrequencyX)/tile.getWidth();
1291            if(baseFrequencyX/lowFreq < highFreq/baseFrequencyX)
1292                this.baseFrequencyX = lowFreq;
1293            else
1294                this.baseFrequencyX = highFreq;
1295
1296            lowFreq = Math.floor(tile.getHeight()*baseFrequencyY)/tile.getHeight();
1297            highFreq = Math.ceil(tile.getHeight()*baseFrequencyY)/tile.getHeight();
1298            if(baseFrequencyY/lowFreq < highFreq/baseFrequencyY)
1299                this.baseFrequencyY = lowFreq;
1300            else
1301                this.baseFrequencyY = highFreq;
1302
1303            //
1304
// Now, process the initial latice grid size to compute the minimum
1305
// and maximum latice values on each axis.
1306
//
1307
stitchInfo = new StitchInfo();
1308            stitchInfo.width = ((int)(tile.getWidth()*this.baseFrequencyX));
1309            stitchInfo.height = ((int)(tile.getHeight()*this.baseFrequencyY));
1310            stitchInfo.wrapX = ((int)(tile.getX()*this.baseFrequencyX +
1311                                      PerlinN + stitchInfo.width));
1312            stitchInfo.wrapY = ((int)(tile.getY()*this.baseFrequencyY +
1313                                      PerlinN + stitchInfo.height));
1314
1315            // Protect agains zero frequencies. Setting values to 1
1316
// will not affect the result of the computations.
1317
if(stitchInfo.width == 0) stitchInfo.width = 1;
1318            if(stitchInfo.height == 0) stitchInfo.height = 1;
1319
1320            // System.out.println( "minLatticeX = " + minLatticeX +
1321
// " minLatticeY = " + minLatticeY +
1322
// " maxLatticeX = " + maxLatticeX +
1323
// " maxLatticeY = " + maxLatticeY);
1324
}
1325
1326        initLattice(seed);
1327
1328        ColorModel JavaDoc cm;
1329        if (alpha)
1330            cm = new DirectColorModel JavaDoc
1331                (cs, 32, 0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000,
1332                 false, DataBuffer.TYPE_INT);
1333        else
1334            cm = new DirectColorModel JavaDoc
1335                (cs, 24, 0x00FF0000, 0x0000FF00, 0x000000FF, 0x0,
1336                 false, DataBuffer.TYPE_INT);
1337
1338        int tileSize = AbstractTiledRed.getDefaultTileSize();
1339        init((CachableRed)null, devRect, cm,
1340             cm.createCompatibleSampleModel(tileSize, tileSize),
1341             0, 0, null);
1342    }
1343
1344}
1345
Popular Tags