Source Code Cross Referenced for ColorRamp.java in  » GIS » GeoTools-2.4.1 » org » geotools » gui » swing » image » Java Source Code / Java DocumentationJava Source Code and Java Documentation

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 geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » GIS » GeoTools 2.4.1 » org.geotools.gui.swing.image 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         *    GeoTools - OpenSource mapping toolkit
003:         *    http://geotools.org
004:         *    (C) 2003-2006, Geotools Project Managment Committee (PMC)
005:         *    (C) 2000, Institut de Recherche pour le Développement
006:         *    (C) 1999, Pêches et Océans Canada
007:         *
008:         *    This library is free software; you can redistribute it and/or
009:         *    modify it under the terms of the GNU Lesser General Public
010:         *    License as published by the Free Software Foundation; either
011:         *    version 2.1 of the License, or (at your option) any later version.
012:         *
013:         *    This library is distributed in the hope that it will be useful,
014:         *    but WITHOUT ANY WARRANTY; without even the implied warranty of
015:         *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
016:         *    Lesser General Public License for more details.
017:         */
018:        package org.geotools.gui.swing.image;
019:
020:        // Graphical user interface
021:        import javax.swing.JComponent;
022:        import javax.swing.SwingConstants;
023:        import javax.swing.plaf.ComponentUI;
024:
025:        // Graphics
026:        import java.awt.Font;
027:        import java.awt.Color;
028:        import java.awt.Graphics;
029:        import java.awt.Graphics2D;
030:        import java.awt.RenderingHints;
031:        import java.awt.image.BufferedImage;
032:        import java.awt.image.IndexColorModel;
033:        import java.awt.font.FontRenderContext;
034:        import java.awt.font.GlyphVector;
035:
036:        // Geometry
037:        import java.awt.Dimension;
038:        import java.awt.Rectangle;
039:        import java.awt.geom.Rectangle2D;
040:
041:        // Miscellaneous
042:        import java.util.Arrays;
043:        import java.util.logging.Level;
044:        import java.util.logging.Logger;
045:        import java.beans.PropertyChangeEvent;
046:        import java.beans.PropertyChangeListener;
047:        import javax.units.Unit;
048:
049:        // OpenGIS dependencies
050:        import org.opengis.coverage.Coverage;
051:        import org.opengis.coverage.SampleDimension;
052:        import org.opengis.coverage.PaletteInterpretation;
053:        import org.opengis.referencing.operation.MathTransform1D;
054:        import org.opengis.referencing.operation.TransformException;
055:
056:        // Axis
057:        import org.geotools.axis.Graduation;
058:        import org.geotools.axis.TickIterator;
059:        import org.geotools.axis.NumberGraduation;
060:        import org.geotools.axis.AbstractGraduation;
061:        import org.geotools.axis.LogarithmicNumberGraduation;
062:
063:        // Geotools dependencies
064:        import org.geotools.coverage.GridSampleDimension;
065:        import org.geotools.resources.Utilities;
066:        import org.geotools.resources.image.CoverageUtilities;
067:        import org.geotools.resources.i18n.Errors;
068:        import org.geotools.resources.i18n.ErrorKeys;
069:        import org.geotools.resources.i18n.Logging;
070:        import org.geotools.resources.i18n.LoggingKeys;
071:
072:        /**
073:         * A color ramp with a graduation. The colors can be specified with a {@link SampleDimension},
074:         * an array of {@link Color}s or an {@link IndexColorModel} object, and the graduation is
075:         * specified with a {@link Graduation} object. The resulting {@code ColorRamp} object
076:         * is usually painted together with a remote sensing image, for example in a
077:         * {@link org.geotools.gui.swing.MapPane} object.
078:         *
079:         * <p>&nbsp;</p>
080:         * <p align="center"><img src="doc-files/ColorRamp.png"></p>
081:         * <p>&nbsp;</p>
082:         *
083:         * @since 2.3
084:         * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/extension/widgets-swing/src/main/java/org/geotools/gui/swing/image/ColorRamp.java $
085:         * @version $Id: ColorRamp.java 27862 2007-11-12 19:51:19Z desruisseaux $
086:         * @author Martin Desruisseaux
087:         */
088:        public class ColorRamp extends JComponent {
089:            /**
090:             * Margin (in pixel) on each sides: top, left, right and bottom of the color ramp.
091:             */
092:            private static final int MARGIN = 10;
093:
094:            /**
095:             * An empty list of colors.
096:             */
097:            private static final Color[] EMPTY = new Color[0];
098:
099:            /**
100:             * The graduation to write over the color ramp.
101:             */
102:            private Graduation graduation;
103:
104:            /**
105:             * Graduation units. This is constructed from {@link Graduation#getUnit} and cached
106:             * for faster rendering.
107:             */
108:            private String units;
109:
110:            /**
111:             * The colors to paint (never {@code null}).
112:             */
113:            private Color[] colors = EMPTY;
114:
115:            /**
116:             * {@code true} if tick label must be display.
117:             */
118:            private boolean labelVisibles = true;
119:
120:            /**
121:             * {@code true} if tick label can be display with an automatic color. The
122:             * automatic color will be white or black depending the background color.
123:             */
124:            private boolean autoForeground = true;
125:
126:            /**
127:             * {@code true} if the color bar should be drawn horizontally,
128:             * or {@code false} if it should be drawn vertically.
129:             */
130:            private boolean horizontal = true;
131:
132:            /**
133:             * Rendering hints for the graduation. This include the color bar
134:             * length, which is used for the space between ticks.
135:             */
136:            private transient RenderingHints hints;
137:
138:            /**
139:             * The tick iterator used during the last painting. This iterator will be reused as mush
140:             * as possible in order to reduce garbage-collections.
141:             */
142:            private transient TickIterator reuse;
143:
144:            /**
145:             * A temporary buffer for conversions from RGB to HSB
146:             * values. This is used by {@link #getForeground(int)}.
147:             */
148:            private transient float[] HSB;
149:
150:            /**
151:             * The {@link ComponentUI} object for computing preferred
152:             * size, drawn the component and handle some events.
153:             */
154:            private final UI ui = new UI();
155:
156:            /**
157:             * Constructs an initially empty color bar. Colors can be
158:             * set using one of the {@code setColors(...)} methods.
159:             */
160:            public ColorRamp() {
161:                setOpaque(true);
162:                setUI(ui);
163:            }
164:
165:            /**
166:             * Constructs a color bar for the specified coverage.
167:             */
168:            public ColorRamp(final Coverage coverage) {
169:                this ();
170:                setColors(coverage);
171:            }
172:
173:            /**
174:             * Returns the graduation to paint over colors. If the graduation is
175:             * not yet defined, then this method returns {@code null}.
176:             */
177:            public Graduation getGraduation() {
178:                return graduation;
179:            }
180:
181:            /**
182:             * Sets the graduation to paint on top of the color bar. The graduation can be set also
183:             * by a call to {@link #setColors(SampleDimension)} and {@link #setColors(Coverage)}.
184:             * This method will fire a property change event with the {@code "graduation"} name.
185:             * <p>
186:             * The graduation minimum and maximum values should be both inclusive.
187:             *
188:             * @param  graduation The new graduation, or {@code null} if none.
189:             * @return {@code true} if this object changed as a result of this call.
190:             */
191:            public boolean setGraduation(final Graduation graduation) {
192:                final Graduation oldGraduation = this .graduation;
193:                if (graduation != oldGraduation) {
194:                    if (oldGraduation != null) {
195:                        oldGraduation.removePropertyChangeListener(ui);
196:                    }
197:                    if (graduation != null) {
198:                        graduation.addPropertyChangeListener(ui);
199:                    }
200:                    this .graduation = graduation;
201:                    units = null;
202:                    if (graduation != null) {
203:                        final Unit unit = graduation.getUnit();
204:                        if (unit != null) {
205:                            units = unit.toString();
206:                        }
207:                    }
208:                }
209:                final boolean changed = !Utilities.equals(graduation,
210:                        oldGraduation);
211:                if (changed) {
212:                    repaint();
213:                }
214:                firePropertyChange("graduation", oldGraduation, graduation);
215:                return changed;
216:            }
217:
218:            /**
219:             * Returns the colors painted by this {@code ColorRamp}.
220:             *
221:             * @return The colors (never {@code null}).
222:             */
223:            public Color[] getColors() {
224:                return (colors.length != 0) ? (Color[]) colors.clone() : colors;
225:            }
226:
227:            /**
228:             * Sets the colors to paint.
229:             * This method will fire a property change event with the {@code "colors"} name.
230:             *
231:             * @param  colors The colors to paint.
232:             * @return {@code true} if the state of this {@code ColorRamp} changed as a result of this call.
233:             *
234:             * @see #setColors(Coverage)
235:             * @see #setColors(SampleDimension)
236:             * @see #setColors(IndexColorModel)
237:             * @see #getColors()
238:             * @see #getGraduation()
239:             */
240:            public boolean setColors(final Color[] colors) {
241:                final Color[] oldColors = this .colors;
242:                this .colors = (colors != null && colors.length != 0) ? (Color[]) colors
243:                        .clone()
244:                        : EMPTY;
245:                final boolean changed = !Arrays.equals(oldColors, this .colors);
246:                if (changed) {
247:                    repaint();
248:                }
249:                firePropertyChange("colors", oldColors, colors);
250:                return changed;
251:            }
252:
253:            /**
254:             * Sets the colors to paint from an {@link IndexColorModel}. The default implementation
255:             * fetches the colors from the index color model and invokes {@link #setColors(Color[])}.
256:             *
257:             * @param  model The colors to paint.
258:             * @return {@code true} if the state of this {@code ColorRamp} changed as a result of this call.
259:             *
260:             * @see #setColors(Coverage)
261:             * @see #setColors(SampleDimension)
262:             * @see #setColors(Color[])
263:             * @see #getColors()
264:             * @see #getGraduation()
265:             */
266:            public boolean setColors(final IndexColorModel model) {
267:                final Color[] colors;
268:                if (model == null) {
269:                    colors = EMPTY;
270:                } else {
271:                    colors = new Color[model.getMapSize()];
272:                    for (int i = 0; i < colors.length; i++) {
273:                        colors[i] = new Color(model.getRed(i), model
274:                                .getGreen(i), model.getBlue(i), model
275:                                .getAlpha(i));
276:                    }
277:                }
278:                return setColors(colors);
279:            }
280:
281:            /**
282:             * Sets the graduation and the colors from a sample dimension.
283:             * The default implementation fetchs the palette and the minimum and maximum values
284:             * from the supplied band, and then invokes {@link #setColors(Color[]) setColors} and
285:             * {@link #setGraduation setGraduation}.
286:             *
287:             * @param  band The sample dimension, or {@code null}.
288:             * @return {@code true} if the state of this {@code ColorRamp} changed as a result of this call.
289:             *
290:             * @see #setColors(Coverage)
291:             * @see #setColors(SampleDimension)
292:             * @see #setColors(IndexColorModel)
293:             * @see #setColors(Color[])
294:             * @see #getColors()
295:             * @see #getGraduation()
296:             */
297:            public boolean setColors(SampleDimension band) {
298:                Color[] colors = EMPTY;
299:                Graduation graduation = null;
300:                /*
301:                 * Gets the color palette, preferably from the "non-geophysics" view since it is usually
302:                 * the one backed by an IndexColorModel.  We assume that 'palette[i]' gives the color of
303:                 * sample value 'i'. We will search for the largest range of valid sample integer values,
304:                 * ignoring "nodata" values. Those "nodata" values appear usually at the begining or at
305:                 * the end of the whole palette range.
306:                 *
307:                 * Note that the above algorithm works without Category. We try to avoid dependency
308:                 * on categories because some applications don't use them. TODO: should we use this
309:                 * algorithm only as a fallback (i.e. use categories when available)?
310:                 */
311:                if (band != null) {
312:                    if (band instanceof  GridSampleDimension) {
313:                        band = ((GridSampleDimension) band).geophysics(false);
314:                    }
315:                    final int[][] palette = band.getPalette();
316:                    if (palette != null) {
317:                        int lower = 0; // Will be inclusive
318:                        int upper = 0; // Will be exclusive
319:                        final double[] nodata = band.getNoDataValues();
320:                        final double[] sorted = new double[nodata != null ? nodata.length + 2
321:                                : 2];
322:                        sorted[0] = -1;
323:                        sorted[sorted.length - 1] = palette.length;
324:                        if (nodata != null) {
325:                            System.arraycopy(nodata, 0, sorted, 1,
326:                                    nodata.length);
327:                        }
328:                        Arrays.sort(sorted);
329:                        for (int i = 1; i < sorted.length; i++) {
330:                            // Note: Don't cast to integer now, because we
331:                            // want to take NaN and infinity in account.
332:                            final double lo = Math.floor(sorted[i - 1]) + 1; // "Nodata" always excluded
333:                            final double hi = Math.ceil(sorted[i]); // "Nodata" included if integer
334:                            if (lo >= 0 && hi <= palette.length
335:                                    && (hi - lo) > (upper - lower)) {
336:                                lower = (int) lo;
337:                                upper = (int) hi;
338:                            }
339:                        }
340:                        /*
341:                         * We now know the range of values to show on the palette. Creates the colors from
342:                         * the palette. Only palette using RGB colors are understood at this time, but the
343:                         * graduation (after this block) is still created for all kind of palette.
344:                         */
345:                        if (PaletteInterpretation.RGB.equals(band
346:                                .getPaletteInterpretation())) {
347:                            colors = new Color[upper - lower];
348:                            for (int i = 0; i < colors.length; i++) {
349:                                int r = 0, g = 0, b = 0, a = 255;
350:                                final int[] c = palette[i + lower];
351:                                if (c != null)
352:                                    switch (c.length) {
353:                                    default: // Fall through
354:                                    case 4:
355:                                        a = c[3]; // Fall through
356:                                    case 3:
357:                                        b = c[2]; // Fall through
358:                                    case 2:
359:                                        g = c[1]; // Fall through
360:                                    case 1:
361:                                        r = c[0]; // Fall through
362:                                    case 0:
363:                                        break;
364:                                    }
365:                                colors[i] = new Color(r, g, b, a);
366:                            }
367:                        }
368:                        /*
369:                         * Transforms the lower and upper sample values into minimum and maximum geophysics
370:                         * values and creates the graduation. Note that the maximum value will be inclusive,
371:                         * at the difference of upper value which was exclusive prior this point.
372:                         */
373:                        if (upper > lower) {
374:                            upper--; // Make it inclusive.
375:                        }
376:                        double min, max;
377:                        try {
378:                            final MathTransform1D tr = band
379:                                    .getSampleToGeophysics();
380:                            min = tr.transform(lower);
381:                            max = tr.transform(upper);
382:                        } catch (TransformException cause) {
383:                            IllegalArgumentException e = new IllegalArgumentException(
384:                                    Errors.format(
385:                                            ErrorKeys.ILLEGAL_ARGUMENT_$2,
386:                                            "band", band));
387:                            e.initCause(cause);
388:                            throw e;
389:                        }
390:                        if (min > max) {
391:                            // This case occurs typically when displaying a color ramp for
392:                            // sea bathymetry, for which floor level are negative numbers.
393:                            min = -min;
394:                            max = -max;
395:                        }
396:                        if (!(min <= max)) {
397:                            // This case occurs if one or both values is NaN.
398:                            throw new IllegalArgumentException(Errors
399:                                    .format(ErrorKeys.ILLEGAL_ARGUMENT_$2,
400:                                            "band", band));
401:                        }
402:                        graduation = createGraduation(this .graduation, band,
403:                                min, max);
404:                    }
405:                }
406:                return setGraduation(graduation) | setColors(colors); // Realy |, not ||
407:            }
408:
409:            /**
410:             * Sets the graduation and the colors from a coverage.
411:             * The default implementation fetchs the visible sample dimension from the specified coverage,
412:             * and then invokes {@link #setColors(Color[]) setColors} and
413:             * {@link #setGraduation setGraduation}.
414:             *
415:             * @param coverage The coverage, or {@code null}.
416:             * @return {@code true} if the state of this {@code ColorRamp} changed as a result of this call.
417:             *
418:             * @see #setColors(IndexColorModel)
419:             * @see #setColors(SampleDimension)
420:             * @see #getColors()
421:             * @see #getGraduation()
422:             */
423:            public boolean setColors(final Coverage coverage) {
424:                SampleDimension band = null;
425:                if (coverage != null) {
426:                    band = coverage.getSampleDimension(CoverageUtilities
427:                            .getVisibleBand(band));
428:                }
429:                return setColors(band);
430:            }
431:
432:            /**
433:             * Returns the component's orientation (horizontal or vertical).
434:             * It should be one of the following constants:
435:             * ({@link SwingConstants#HORIZONTAL} or {@link SwingConstants#VERTICAL}).
436:             */
437:            public int getOrientation() {
438:                return (horizontal) ? SwingConstants.HORIZONTAL
439:                        : SwingConstants.VERTICAL;
440:            }
441:
442:            /**
443:             * Set the component's orientation (horizontal or vertical).
444:             *
445:             * @param orient {@link SwingConstants#HORIZONTAL} or {@link SwingConstants#VERTICAL}.
446:             */
447:            public void setOrientation(final int orient) {
448:                switch (orient) {
449:                case SwingConstants.HORIZONTAL:
450:                    horizontal = true;
451:                    break;
452:                case SwingConstants.VERTICAL:
453:                    horizontal = false;
454:                    break;
455:                default:
456:                    throw new IllegalArgumentException(String.valueOf(orient));
457:                }
458:            }
459:
460:            /**
461:             * Tests if graduation labels are paint on top of the
462:             * colors ramp. Default value is {@code true}.
463:             */
464:            public boolean isLabelVisibles() {
465:                return labelVisibles;
466:            }
467:
468:            /**
469:             * Sets whatever the graduation labels should be painted on top of the colors ramp.
470:             */
471:            public void setLabelVisibles(final boolean visible) {
472:                labelVisibles = visible;
473:            }
474:
475:            /**
476:             * Sets the label colors. A {@code null} value reset the automatic color.
477:             *
478:             * @see #getForeground
479:             */
480:            public void setForeground(final Color color) {
481:                super .setForeground(color);
482:                autoForeground = (color == null);
483:            }
484:
485:            /**
486:             * Returns a color for label at the specified index. The default color will be
487:             * black or white, depending of the background color at the specified index.
488:             */
489:            private Color getForeground(final int colorIndex) {
490:                final Color color = colors[colorIndex];
491:                HSB = Color.RGBtoHSB(color.getRed(), color.getGreen(), color
492:                        .getBlue(), HSB);
493:                return (HSB[2] >= 0.5f) ? Color.black : Color.white;
494:            }
495:
496:            /**
497:             * Paint the color ramp. This method doesn't need to restore
498:             * {@link Graphics2D} to its initial state once finished.
499:             *
500:             * @param  graphics The graphic context in which to paint.
501:             * @param  bounds   The bounding box where to paint the color ramp.
502:             * @return Bounding box of graduation labels (NOT taking in account the color ramp
503:             *                  behind them), or {@code null} if no label has been painted.
504:             */
505:            private Rectangle2D paint(final Graphics2D graphics,
506:                    final Rectangle bounds) {
507:                final int length = colors.length;
508:                final double dx, dy;
509:                if (length == 0) {
510:                    dx = 0;
511:                    dy = 0;
512:                } else {
513:                    dx = (double) (bounds.width - 2 * MARGIN) / length;
514:                    dy = (double) (bounds.height - 2 * MARGIN) / length;
515:                    int i = 0, lastIndex = 0;
516:                    Color color = colors[i];
517:                    Color nextColor = color;
518:                    int R, G, B;
519:                    int nR = R = color.getRed();
520:                    int nG = G = color.getGreen();
521:                    int nB = B = color.getBlue();
522:                    final int ox = bounds.x + MARGIN;
523:                    final int oy = bounds.y + bounds.height - MARGIN;
524:                    final Rectangle2D.Double rect = new Rectangle2D.Double();
525:                    rect.setRect(bounds);
526:                    while (++i <= length) {
527:                        if (i != length) {
528:                            nextColor = colors[i];
529:                            nR = nextColor.getRed();
530:                            nG = nextColor.getGreen();
531:                            nB = nextColor.getBlue();
532:                            if (R == nR && G == nG && B == nB) {
533:                                continue;
534:                            }
535:                        }
536:                        if (horizontal) {
537:                            rect.x = ox + dx * lastIndex;
538:                            rect.width = dx * (i - lastIndex);
539:                            if (lastIndex == 0) {
540:                                rect.x -= MARGIN;
541:                                rect.width += MARGIN;
542:                            }
543:                            if (i == length) {
544:                                rect.width += MARGIN;
545:                            }
546:                        } else {
547:                            rect.y = oy - dy * i;
548:                            rect.height = dy * (i - lastIndex);
549:                            if (lastIndex == 0) {
550:                                rect.height += MARGIN;
551:                            }
552:                            if (i == length) {
553:                                rect.y -= MARGIN;
554:                                rect.height += MARGIN;
555:                            }
556:                        }
557:                        graphics.setColor(color);
558:                        graphics.fill(rect);
559:                        lastIndex = i;
560:                        color = nextColor;
561:                        R = nR;
562:                        G = nG;
563:                        B = nB;
564:                    }
565:                }
566:                Rectangle2D labelBounds = null;
567:                if (labelVisibles && graduation != null) {
568:                    /*
569:                     * Prepare graduation writting. First, computes the color ramp width in pixels.
570:                     * Then, computes the coefficients for conversion of graduation values to pixel
571:                     * coordinates.
572:                     */
573:                    double x = bounds.getCenterX();
574:                    double y = bounds.getCenterY();
575:                    final double axisRange = graduation.getRange();
576:                    final double axisMinimum = graduation.getMinimum();
577:                    final double visualLength, scale, offset;
578:                    if (horizontal) {
579:                        visualLength = bounds.getWidth() - 2 * MARGIN - dx;
580:                        scale = visualLength / axisRange;
581:                        offset = (bounds.getMinX() + MARGIN + 0.5 * dx) - scale
582:                                * axisMinimum;
583:                    } else {
584:                        visualLength = bounds.getHeight() - 2 * MARGIN - dy;
585:                        scale = -visualLength / axisRange;
586:                        offset = (bounds.getMaxY() - MARGIN - 0.5 * dy) + scale
587:                                * axisMinimum;
588:                    }
589:                    if (hints == null) {
590:                        hints = new RenderingHints(null);
591:                    }
592:                    final double valueToLocation = length / axisRange;
593:                    Font font = getFont();
594:                    if (font == null) {
595:                        font = Font.decode("SansSerif-10");
596:                    }
597:                    final FontRenderContext context = graphics
598:                            .getFontRenderContext();
599:                    hints.put(Graduation.VISUAL_AXIS_LENGTH, new Float(
600:                            (float) visualLength));
601:                    graphics.setColor(getForeground());
602:                    /*
603:                     * Now write the graduation.
604:                     */
605:                    for (final TickIterator ticks = reuse = graduation
606:                            .getTickIterator(hints, reuse); ticks.hasNext(); ticks
607:                            .nextMajor()) {
608:                        if (ticks.isMajorTick()) {
609:                            final GlyphVector glyph = font.createGlyphVector(
610:                                    context, ticks.currentLabel());
611:                            final Rectangle2D rectg = glyph.getVisualBounds();
612:                            final double width = rectg.getWidth();
613:                            final double height = rectg.getHeight();
614:                            final double value = ticks.currentPosition();
615:                            final double position = value * scale + offset;
616:                            final int colorIndex = Math.min(Math.max((int) Math
617:                                    .round((value - axisMinimum)
618:                                            * valueToLocation), 0), length - 1);
619:                            if (horizontal)
620:                                x = position;
621:                            else
622:                                y = position;
623:                            rectg.setRect(x - 0.5 * width, y - 0.5 * height,
624:                                    width, height);
625:                            if (autoForeground) {
626:                                graphics.setColor(getForeground(colorIndex));
627:                            }
628:                            graphics.drawGlyphVector(glyph, (float) rectg
629:                                    .getMinX(), (float) rectg.getMaxY());
630:                            if (labelBounds != null) {
631:                                labelBounds.add(rectg);
632:                            } else {
633:                                labelBounds = rectg;
634:                            }
635:                        }
636:                    }
637:                    /*
638:                     * Writes units.
639:                     */
640:                    if (units != null) {
641:                        final GlyphVector glyph = font.createGlyphVector(
642:                                context, units);
643:                        final Rectangle2D rectg = glyph.getVisualBounds();
644:                        final double width = rectg.getWidth();
645:                        final double height = rectg.getHeight();
646:                        if (horizontal) {
647:                            double left = bounds.getMaxX() - width;
648:                            if (labelBounds != null) {
649:                                final double check = labelBounds.getMaxX() + 4;
650:                                if (check < left) {
651:                                    left = check;
652:                                }
653:                            }
654:                            rectg
655:                                    .setRect(left, y - 0.5 * height, width,
656:                                            height);
657:                        } else {
658:                            rectg.setRect(x - 0.5 * width, bounds.getMinY()
659:                                    + height, width, height);
660:                        }
661:                        if (autoForeground) {
662:                            graphics.setColor(getForeground(length - 1));
663:                        }
664:                        if (labelBounds == null
665:                                || !labelBounds.intersects(rectg)) {
666:                            graphics.drawGlyphVector(glyph, (float) rectg
667:                                    .getMinX(), (float) rectg.getMaxY());
668:                        }
669:                    }
670:                }
671:                return labelBounds;
672:            }
673:
674:            /**
675:             * Returns a graduation for the specified sample dimension, minimum and maximum values. This
676:             * method must returns a graduation of the appropriate class, usually {@link NumberGraduation}
677:             * or {@link LogarithmicNumberGraduation}. If the supplied {@code reuse} object is non-null and
678:             * is of the appropriate class, then this method can returns {@code reuse} without creating a
679:             * new graduation object. This method must set graduations's
680:             * {@linkplain AbstractGraduation#setMinimum minimum},
681:             * {@linkplain AbstractGraduation#setMaximum maximum} and
682:             * {@linkplain AbstractGraduation#setUnit unit} according the values given in arguments.
683:             *
684:             * @param  reuse   The graduation to reuse if possible.
685:             * @param  band    The sample dimension to create graduation for.
686:             * @param  minimum The minimal geophysics value to appears in the graduation.
687:             * @param  maximum The maximal geophysics value to appears in the graduation.
688:             * @return A graduation for the supplied sample dimension.
689:             */
690:            protected Graduation createGraduation(final Graduation reuse,
691:                    final SampleDimension band, final double minimum,
692:                    final double maximum) {
693:                MathTransform1D tr = band.getSampleToGeophysics();
694:                boolean linear = false;
695:                boolean logarithmic = false;
696:                try {
697:                    /*
698:                     * An heuristic approach to determine if the transform is linear or logarithmic.
699:                     * We look at the derivative, which should be constant everywhere for a linear
700:                     * scale and be proportional to the inverse of 'x' for a logarithmic one.
701:                     */
702:                    tr = (MathTransform1D) tr.inverse();
703:                    final double EPS = 1E-6; // For rounding error.
704:                    final double ratio = tr.derivative(minimum)
705:                            / tr.derivative(maximum);
706:                    if (Math.abs(ratio - 1) <= EPS) {
707:                        linear = true;
708:                    }
709:                    if (Math.abs(ratio * (minimum / maximum) - 1) <= EPS) {
710:                        logarithmic = true;
711:                    }
712:                } catch (TransformException exception) {
713:                    // Transformation failed. We don't know if the scale is linear or logarithmic.
714:                    // Continue anyway. A warning will be logged later in this method.
715:                }
716:                final Unit units = band.getUnits();
717:                AbstractGraduation graduation = (reuse instanceof  AbstractGraduation) ? (AbstractGraduation) reuse
718:                        : null;
719:                if (linear) {
720:                    if (graduation == null
721:                            || !graduation.getClass().equals(
722:                                    NumberGraduation.class)) {
723:                        graduation = new NumberGraduation(units);
724:                    }
725:                } else if (logarithmic) {
726:                    if (graduation == null
727:                            || !graduation.getClass().equals(
728:                                    LogarithmicNumberGraduation.class)) {
729:                        graduation = new LogarithmicNumberGraduation(units);
730:                    }
731:                } else {
732:                    org.geotools.util.logging.Logging.getLogger(
733:                            "org.geotools.gui.swing").log(
734:                            Logging.format(Level.WARNING,
735:                                    LoggingKeys.UNRECOGNIZED_SCALE_TYPE_$1,
736:                                    Utilities.getShortClassName(tr)));
737:                    graduation = new NumberGraduation(units);
738:                }
739:                if (graduation == reuse) {
740:                    graduation.setUnit(units);
741:                }
742:                graduation.setMinimum(minimum);
743:                graduation.setMaximum(maximum);
744:                return graduation;
745:            }
746:
747:            /**
748:             * Returns an image representation for this color ramp. The image size will be this
749:             * {@linkplain #getSize widget size}.
750:             */
751:            public BufferedImage toImage() {
752:                final BufferedImage image = new BufferedImage(getWidth(),
753:                        getHeight(), BufferedImage.TYPE_INT_ARGB);
754:                final Graphics2D graphics = image.createGraphics();
755:                paint(graphics, new Rectangle(0, 0, image.getWidth(), image
756:                        .getHeight()));
757:                graphics.dispose();
758:                return image;
759:            }
760:
761:            /**
762:             * Returns a string representation for this color ramp.
763:             */
764:            public String toString() {
765:                int count = 0;
766:                int i = 0;
767:                if (i < colors.length) {
768:                    Color last = colors[i];
769:                    while (++i < colors.length) {
770:                        Color c = colors[i];
771:                        if (!c.equals(last)) {
772:                            last = c;
773:                            count++;
774:                        }
775:                    }
776:                }
777:                return Utilities.getShortClassName(this ) + '[' + count
778:                        + " colors]";
779:            }
780:
781:            /**
782:             * Notifies this component that it now has a parent component. This method
783:             * is invoked by <cite>Swing</cite> and shouldn't be directly used.
784:             */
785:            public void addNotify() {
786:                super .addNotify();
787:                if (graduation != null) {
788:                    graduation.removePropertyChangeListener(ui); // Avoid duplication
789:                    graduation.addPropertyChangeListener(ui);
790:                }
791:            }
792:
793:            /**
794:             * Notifies this component that it no longer has a parent component.
795:             * This method is invoked by <em>Swing</em> and shouldn't be directly used.
796:             */
797:            public void removeNotify() {
798:                if (graduation != null) {
799:                    graduation.removePropertyChangeListener(ui);
800:                }
801:                super .removeNotify();
802:            }
803:
804:            /**
805:             * Classe ayant la charge de dessiner la rampe de couleurs, ainsi que
806:             * de calculer l'espace qu'elle occupe. Cette classe peut aussi réagir
807:             * à certains événements.
808:             *
809:             * @version $Id: ColorRamp.java 27862 2007-11-12 19:51:19Z desruisseaux $
810:             * @author Martin Desruisseaux
811:             */
812:            private final class UI extends ComponentUI implements 
813:                    PropertyChangeListener {
814:                /**
815:                 * Retourne la dimension minimale de cette rampe de couleurs.
816:                 */
817:                public Dimension getMinimumSize(final JComponent c) {
818:                    return (((ColorRamp) c).horizontal) ? new Dimension(
819:                            2 * MARGIN, 16) : new Dimension(16, 2 * MARGIN);
820:                }
821:
822:                /**
823:                 * Retourne la dimension préférée de cette rampe de couleurs.
824:                 */
825:                public Dimension getPreferredSize(final JComponent c) {
826:                    return (((ColorRamp) c).horizontal) ? new Dimension(256, 16)
827:                            : new Dimension(16, 256);
828:                }
829:
830:                /**
831:                 * Dessine la rampe de couleurs vers le graphique spécifié.  Cette méthode a
832:                 * l'avantage d'être appelée automatiquement par <i>Swing</i> avec une copie
833:                 * d'un objet {@link Graphics}, ce qui nous évite d'avoir à le remettre dans
834:                 * son état initial lorsqu'on a terminé le traçage de la rampe de couleurs.
835:                 * On n'a pas cet avantage lorsque l'on ne fait que redéfinir
836:                 * {@link JComponent#paintComponent}.
837:                 */
838:                public void paint(final Graphics graphics,
839:                        final JComponent component) {
840:                    final ColorRamp ramp = (ColorRamp) component;
841:                    if (ramp.colors != null) {
842:                        final Rectangle bounds = ramp.getBounds();
843:                        bounds.x = 0;
844:                        bounds.y = 0;
845:                        ramp.paint((Graphics2D) graphics, bounds);
846:                    }
847:                }
848:
849:                /**
850:                 * Méthode appelée automatiquement chaque fois qu'une propriété de l'axe a changée.
851:                 */
852:                public void propertyChange(final PropertyChangeEvent event) {
853:                    repaint();
854:                }
855:            }
856:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.