Source Code Cross Referenced for RadialGradientPaintContext.java in  » 6.0-JDK-Core » AWT » java » awt » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Home
Java Source Code / Java Documentation
1.6.0 JDK Core
2.6.0 JDK Modules
3.6.0 JDK Modules com.sun
4.6.0 JDK Modules com.sun.java
5.6.0 JDK Modules sun
6.6.0 JDK Platform
7.Ajax
8.Apache Harmony Java SE
9.Aspect oriented
10.Authentication Authorization
11.Blogger System
12.Build
13.Byte Code
14.Cache
15.Chart
16.Chat
17.Code Analyzer
18.Collaboration
19.Content Management System
20.Database Client
21.Database DBMS
22.Database JDBC Connection Pool
23.Database ORM
24.Development
25.EJB Server
26.ERP CRM Financial
27.ESB
28.Forum
29.Game
30.GIS
31.Graphic 3D
32.Graphic Library
33.Groupware
34.HTML Parser
35.IDE
36.IDE Eclipse
37.IDE Netbeans
38.Installer
39.Internationalization Localization
40.Inversion of Control
41.Issue Tracking
42.J2EE
43.J2ME
44.JBoss
45.JMS
46.JMX
47.Library
48.Mail Clients
49.Music
50.Net
51.Parser
52.PDF
53.Portal
54.Profiler
55.Project Management
56.Report
57.RSS RDF
58.Rule Engine
59.Science
60.Scripting
61.Search Engine
62.Security
63.Sevlet Container
64.Source Control
65.Swing Library
66.Template Engine
67.Test Coverage
68.Testing
69.UML
70.Web Crawler
71.Web Framework
72.Web Mail
73.Web Server
74.Web Services
75.Web Services apache cxf 2.2.6
76.Web Services AXIS2
77.Wiki Engine
78.Workflow Engines
79.XML
80.XML UI
Java Source Code / Java Documentation » 6.0 JDK Core » AWT » java.awt 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001        /*
002         * Copyright 2006 Sun Microsystems, Inc.  All Rights Reserved.
003         * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004         *
005         * This code is free software; you can redistribute it and/or modify it
006         * under the terms of the GNU General Public License version 2 only, as
007         * published by the Free Software Foundation.  Sun designates this
008         * particular file as subject to the "Classpath" exception as provided
009         * by Sun in the LICENSE file that accompanied this code.
010         *
011         * This code is distributed in the hope that it will be useful, but WITHOUT
012         * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013         * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
014         * version 2 for more details (a copy is included in the LICENSE file that
015         * accompanied this code).
016         *
017         * You should have received a copy of the GNU General Public License version
018         * 2 along with this work; if not, write to the Free Software Foundation,
019         * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020         *
021         * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022         * CA 95054 USA or visit www.sun.com if you need additional information or
023         * have any questions.
024         */
025
026        package java.awt;
027
028        import java.awt.MultipleGradientPaint.CycleMethod;
029        import java.awt.MultipleGradientPaint.ColorSpaceType;
030        import java.awt.geom.AffineTransform;
031        import java.awt.geom.Rectangle2D;
032        import java.awt.image.ColorModel;
033
034        /**
035         * Provides the actual implementation for the RadialGradientPaint.
036         * This is where the pixel processing is done.  A RadialGradienPaint
037         * only supports circular gradients, but it should be possible to scale
038         * the circle to look approximately elliptical, by means of a
039         * gradient transform passed into the RadialGradientPaint constructor.
040         *
041         * @author Nicholas Talian, Vincent Hardy, Jim Graham, Jerry Evans
042         */
043        final class RadialGradientPaintContext extends
044                MultipleGradientPaintContext {
045
046            /** True when (focus == center).  */
047            private boolean isSimpleFocus = false;
048
049            /** True when (cycleMethod == NO_CYCLE). */
050            private boolean isNonCyclic = false;
051
052            /** Radius of the outermost circle defining the 100% gradient stop. */
053            private float radius;
054
055            /** Variables representing center and focus points. */
056            private float centerX, centerY, focusX, focusY;
057
058            /** Radius of the gradient circle squared. */
059            private float radiusSq;
060
061            /** Constant part of X, Y user space coordinates. */
062            private float constA, constB;
063
064            /** Constant second order delta for simple loop. */
065            private float gDeltaDelta;
066
067            /**
068             * This value represents the solution when focusX == X.  It is called
069             * trivial because it is easier to calculate than the general case.
070             */
071            private float trivial;
072
073            /** Amount for offset when clamping focus. */
074            private static final float SCALEBACK = .99f;
075
076            /** 
077             * Constructor for RadialGradientPaintContext.
078             *
079             * @param paint the {@code RadialGradientPaint} from which this context
080             *              is created
081             * @param cm the {@code ColorModel} that receives
082             *           the {@code Paint} data (this is used only as a hint)
083             * @param deviceBounds the device space bounding box of the 
084             *                     graphics primitive being rendered
085             * @param userBounds the user space bounding box of the 
086             *                   graphics primitive being rendered
087             * @param t the {@code AffineTransform} from user
088             *          space into device space (gradientTransform should be 
089             *          concatenated with this)    
090             * @param hints the hints that the context object uses to choose
091             *              between rendering alternatives
092             * @param cx the center X coordinate in user space of the circle defining 
093             *           the gradient.  The last color of the gradient is mapped to
094             *           the perimeter of this circle.
095             * @param cy the center Y coordinate in user space of the circle defining 
096             *           the gradient.  The last color of the gradient is mapped to
097             *           the perimeter of this circle.
098             * @param r the radius of the circle defining the extents of the 
099             *          color gradient
100             * @param fx the X coordinate in user space to which the first color
101             *           is mapped
102             * @param fy the Y coordinate in user space to which the first color
103             *           is mapped
104             * @param fractions the fractions specifying the gradient distribution
105             * @param colors the gradient colors
106             * @param cycleMethod either NO_CYCLE, REFLECT, or REPEAT
107             * @param colorSpace which colorspace to use for interpolation, 
108             *                   either SRGB or LINEAR_RGB
109             */
110            RadialGradientPaintContext(RadialGradientPaint paint,
111                    ColorModel cm, Rectangle deviceBounds,
112                    Rectangle2D userBounds, AffineTransform t,
113                    RenderingHints hints, float cx, float cy, float r,
114                    float fx, float fy, float[] fractions, Color[] colors,
115                    CycleMethod cycleMethod, ColorSpaceType colorSpace) {
116                super (paint, cm, deviceBounds, userBounds, t, hints, fractions,
117                        colors, cycleMethod, colorSpace);
118
119                // copy some parameters
120                centerX = cx;
121                centerY = cy;
122                focusX = fx;
123                focusY = fy;
124                radius = r;
125
126                this .isSimpleFocus = (focusX == centerX) && (focusY == centerY);
127                this .isNonCyclic = (cycleMethod == CycleMethod.NO_CYCLE);
128
129                // for use in the quadractic equation
130                radiusSq = radius * radius;
131
132                float dX = focusX - centerX;
133                float dY = focusY - centerY;
134
135                double distSq = (dX * dX) + (dY * dY);
136
137                // test if distance from focus to center is greater than the radius
138                if (distSq > radiusSq * SCALEBACK) {
139                    // clamp focus to radius
140                    float scalefactor = (float) Math.sqrt(radiusSq * SCALEBACK
141                            / distSq);
142                    dX = dX * scalefactor;
143                    dY = dY * scalefactor;
144                    focusX = centerX + dX;
145                    focusY = centerY + dY;
146                }
147
148                // calculate the solution to be used in the case where X == focusX
149                // in cyclicCircularGradientFillRaster()
150                trivial = (float) Math.sqrt(radiusSq - (dX * dX));
151
152                // constant parts of X, Y user space coordinates 
153                constA = a02 - centerX;
154                constB = a12 - centerY;
155
156                // constant second order delta for simple loop
157                gDeltaDelta = 2 * (a00 * a00 + a10 * a10) / radiusSq;
158            }
159
160            /**
161             * Return a Raster containing the colors generated for the graphics
162             * operation.
163             *
164             * @param x,y,w,h the area in device space for which colors are
165             * generated.
166             */
167            protected void fillRaster(int pixels[], int off, int adjust, int x,
168                    int y, int w, int h) {
169                if (isSimpleFocus && isNonCyclic && isSimpleLookup) {
170                    simpleNonCyclicFillRaster(pixels, off, adjust, x, y, w, h);
171                } else {
172                    cyclicCircularGradientFillRaster(pixels, off, adjust, x, y,
173                            w, h);
174                }
175            }
176
177            /**
178             * This code works in the simplest of cases, where the focus == center 
179             * point, the gradient is noncyclic, and the gradient lookup method is 
180             * fast (single array index, no conversion necessary).
181             */
182            private void simpleNonCyclicFillRaster(int pixels[], int off,
183                    int adjust, int x, int y, int w, int h) {
184                /* We calculate sqrt(X^2 + Y^2) relative to the radius
185                 * size to get the fraction for the color to use.
186                 *
187                 * Each step along the scanline adds (a00, a10) to (X, Y).
188                 * If we precalculate:
189                 *   gRel = X^2+Y^2
190                 * for the start of the row, then for each step we need to
191                 * calculate:
192                 *   gRel' = (X+a00)^2 + (Y+a10)^2
193                 *         = X^2 + 2*X*a00 + a00^2 + Y^2 + 2*Y*a10 + a10^2
194                 *         = (X^2+Y^2) + 2*(X*a00+Y*a10) + (a00^2+a10^2)
195                 *         = gRel + 2*(X*a00+Y*a10) + (a00^2+a10^2)
196                 *         = gRel + 2*DP + SD
197                 * (where DP = dot product between X,Y and a00,a10
198                 *  and   SD = dot product square of the delta vector)
199                 * For the step after that we get:
200                 *   gRel'' = (X+2*a00)^2 + (Y+2*a10)^2
201                 *          = X^2 + 4*X*a00 + 4*a00^2 + Y^2 + 4*Y*a10 + 4*a10^2
202                 *          = (X^2+Y^2) + 4*(X*a00+Y*a10) + 4*(a00^2+a10^2)
203                 *          = gRel  + 4*DP + 4*SD
204                 *          = gRel' + 2*DP + 3*SD
205                 * The increment changed by:
206                 *     (gRel'' - gRel') - (gRel' - gRel)
207                 *   = (2*DP + 3*SD) - (2*DP + SD)
208                 *   = 2*SD
209                 * Note that this value depends only on the (inverse of the)
210                 * transformation matrix and so is a constant for the loop.
211                 * To make this all relative to the unit circle, we need to
212                 * divide all values as follows:
213                 *   [XY] /= radius
214                 *   gRel /= radiusSq
215                 *   DP   /= radiusSq
216                 *   SD   /= radiusSq
217                 */
218                // coordinates of UL corner in "user space" relative to center
219                float rowX = (a00 * x) + (a01 * y) + constA;
220                float rowY = (a10 * x) + (a11 * y) + constB;
221
222                // second order delta calculated in constructor
223                float gDeltaDelta = this .gDeltaDelta;
224
225                // adjust is (scan-w) of pixels array, we need (scan)
226                adjust += w;
227
228                // rgb of the 1.0 color used when the distance exceeds gradient radius
229                int rgbclip = gradient[fastGradientArraySize];
230
231                for (int j = 0; j < h; j++) {
232                    // these values depend on the coordinates of the start of the row
233                    float gRel = (rowX * rowX + rowY * rowY) / radiusSq;
234                    float gDelta = (2 * (a00 * rowX + a10 * rowY) / radiusSq + gDeltaDelta / 2);
235
236                    /* Use optimized loops for any cases where gRel >= 1.
237                     * We do not need to calculate sqrt(gRel) for these
238                     * values since sqrt(N>=1) == (M>=1).
239                     * Note that gRel follows a parabola which can only be < 1
240                     * for a small region around the center on each scanline. In
241                     * particular:
242                     *   gDeltaDelta is always positive
243                     *   gDelta is <0 until it crosses the midpoint, then >0
244                     * To the left and right of that region, it will always be
245                     * >=1 out to infinity, so we can process the line in 3
246                     * regions:
247                     *   out to the left  - quick fill until gRel < 1, updating gRel
248                     *   in the heart     - slow fraction=sqrt fill while gRel < 1
249                     *   out to the right - quick fill rest of scanline, ignore gRel
250                     */
251                    int i = 0;
252                    // Quick fill for "out to the left"
253                    while (i < w && gRel >= 1.0f) {
254                        pixels[off + i] = rgbclip;
255                        gRel += gDelta;
256                        gDelta += gDeltaDelta;
257                        i++;
258                    }
259                    // Slow fill for "in the heart"
260                    while (i < w && gRel < 1.0f) {
261                        int gIndex;
262
263                        if (gRel <= 0) {
264                            gIndex = 0;
265                        } else {
266                            float fIndex = gRel * SQRT_LUT_SIZE;
267                            int iIndex = (int) (fIndex);
268                            float s0 = sqrtLut[iIndex];
269                            float s1 = sqrtLut[iIndex + 1] - s0;
270                            fIndex = s0 + (fIndex - iIndex) * s1;
271                            gIndex = (int) (fIndex * fastGradientArraySize);
272                        }
273
274                        // store the color at this point
275                        pixels[off + i] = gradient[gIndex];
276
277                        // incremental calculation
278                        gRel += gDelta;
279                        gDelta += gDeltaDelta;
280                        i++;
281                    }
282                    // Quick fill to end of line for "out to the right"
283                    while (i < w) {
284                        pixels[off + i] = rgbclip;
285                        i++;
286                    }
287
288                    off += adjust;
289                    rowX += a01;
290                    rowY += a11;
291                }
292            }
293
294            // SQRT_LUT_SIZE must be a power of 2 for the test above to work.
295            private static final int SQRT_LUT_SIZE = (1 << 11);
296            private static float sqrtLut[] = new float[SQRT_LUT_SIZE + 1];
297            static {
298                for (int i = 0; i < sqrtLut.length; i++) {
299                    sqrtLut[i] = (float) Math.sqrt(i / ((float) SQRT_LUT_SIZE));
300                }
301            }
302
303            /**
304             * Fill the raster, cycling the gradient colors when a point falls outside
305             * of the perimeter of the 100% stop circle.          
306             * 
307             * This calculation first computes the intersection point of the line
308             * from the focus through the current point in the raster, and the
309             * perimeter of the gradient circle.
310             * 
311             * Then it determines the percentage distance of the current point along
312             * that line (focus is 0%, perimeter is 100%). 
313             *
314             * Equation of a circle centered at (a,b) with radius r:
315             *     (x-a)^2 + (y-b)^2 = r^2
316             * Equation of a line with slope m and y-intercept b:
317             *     y = mx + b
318             * Replacing y in the circle equation and solving using the quadratic
319             * formula produces the following set of equations.  Constant factors have
320             * been extracted out of the inner loop.
321             */
322            private void cyclicCircularGradientFillRaster(int pixels[],
323                    int off, int adjust, int x, int y, int w, int h) {
324                // constant part of the C factor of the quadratic equation
325                final double constC = -radiusSq + (centerX * centerX)
326                        + (centerY * centerY);
327
328                // coefficients of the quadratic equation (Ax^2 + Bx + C = 0)
329                double A, B, C;
330
331                // slope and y-intercept of the focus-perimeter line
332                double slope, yintcpt;
333
334                // intersection with circle X,Y coordinate
335                double solutionX, solutionY;
336
337                // constant parts of X, Y coordinates
338                final float constX = (a00 * x) + (a01 * y) + a02;
339                final float constY = (a10 * x) + (a11 * y) + a12;
340
341                // constants in inner loop quadratic formula
342                final float precalc2 = 2 * centerY;
343                final float precalc3 = -2 * centerX;
344
345                // value between 0 and 1 specifying position in the gradient
346                float g;
347
348                // determinant of quadratic formula (should always be > 0)
349                float det;
350
351                // sq distance from the current point to focus
352                float currentToFocusSq;
353
354                // sq distance from the intersect point to focus
355                float intersectToFocusSq;
356
357                // temp variables for change in X,Y squared
358                float deltaXSq, deltaYSq;
359
360                // used to index pixels array
361                int indexer = off;
362
363                // incremental index change for pixels array
364                int pixInc = w + adjust;
365
366                // for every row
367                for (int j = 0; j < h; j++) {
368
369                    // user space point; these are constant from column to column
370                    float X = (a01 * j) + constX;
371                    float Y = (a11 * j) + constY;
372
373                    // for every column (inner loop begins here)
374                    for (int i = 0; i < w; i++) {
375
376                        if (X == focusX) {
377                            // special case to avoid divide by zero
378                            solutionX = focusX;
379                            solutionY = centerY;
380                            solutionY += (Y > focusY) ? trivial : -trivial;
381                        } else {
382                            // slope and y-intercept of the focus-perimeter line
383                            slope = (Y - focusY) / (X - focusX);
384                            yintcpt = Y - (slope * X);
385
386                            // use the quadratic formula to calculate the
387                            // intersection point                  
388                            A = (slope * slope) + 1;
389                            B = precalc3 + (-2 * slope * (centerY - yintcpt));
390                            C = constC + (yintcpt * (yintcpt - precalc2));
391
392                            det = (float) Math.sqrt((B * B) - (4 * A * C));
393                            solutionX = -B;
394
395                            // choose the positive or negative root depending
396                            // on where the X coord lies with respect to the focus
397                            solutionX += (X < focusX) ? -det : det;
398                            solutionX = solutionX / (2 * A); // divisor
399                            solutionY = (slope * solutionX) + yintcpt;
400                        }
401
402                        // Calculate the square of the distance from the current point
403                        // to the focus and the square of the distance from the
404                        // intersection point to the focus. Want the squares so we can
405                        // do 1 square root after division instead of 2 before.
406
407                        deltaXSq = X - focusX;
408                        deltaXSq = deltaXSq * deltaXSq;
409
410                        deltaYSq = Y - focusY;
411                        deltaYSq = deltaYSq * deltaYSq;
412
413                        currentToFocusSq = deltaXSq + deltaYSq;
414
415                        deltaXSq = (float) solutionX - focusX;
416                        deltaXSq = deltaXSq * deltaXSq;
417
418                        deltaYSq = (float) solutionY - focusY;
419                        deltaYSq = deltaYSq * deltaYSq;
420
421                        intersectToFocusSq = deltaXSq + deltaYSq;
422
423                        // get the percentage (0-1) of the current point along the 
424                        // focus-circumference line
425                        g = (float) Math.sqrt(currentToFocusSq
426                                / intersectToFocusSq);
427
428                        // store the color at this point
429                        pixels[indexer + i] = indexIntoGradientsArrays(g);
430
431                        // incremental change in X, Y
432                        X += a00;
433                        Y += a10;
434                    } //end inner loop
435
436                    indexer += pixInc;
437                } //end outer loop
438            }
439        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.