/[schmitzm]/branches/1.0-gt2-2.6/src/skrueger/geotools/LegendIconFeatureRenderer.java
ViewVC logotype

Annotation of /branches/1.0-gt2-2.6/src/skrueger/geotools/LegendIconFeatureRenderer.java

Parent Directory Parent Directory | Revision Log Revision Log


Revision 372 - (hide annotations)
Thu Sep 3 18:41:50 2009 UTC (15 years, 5 months ago) by alfonx
File size: 19420 byte(s)
* Renamed the folder with the GT JARs from 'gt-2.6' to 'gt'
* Extended the build.xml to write the correct version into the .jnlp files
* Many many small adaptations to GT2.6 .. AtlasStyler is working again.
* Changed all the clone?() methods in StylingUtil to use the DuplicatingStyleVisitor

1 alfonx 244 /*******************************************************************************
2     * Copyright (c) 2009 Martin O. J. Schmitz.
3     *
4     * This file is part of the SCHMITZM library - a collection of utility
5 alfonx 256 * classes based on Java 1.6, focusing (not only) on Java Swing
6 alfonx 244 * and the Geotools library.
7     *
8     * The SCHMITZM project is hosted at:
9     * http://wald.intevation.org/projects/schmitzm/
10     *
11     * This program is free software; you can redistribute it and/or
12     * modify it under the terms of the GNU Lesser General Public License
13     * as published by the Free Software Foundation; either version 3
14     * of the License, or (at your option) any later version.
15     *
16     * This program is distributed in the hope that it will be useful,
17     * but WITHOUT ANY WARRANTY; without even the implied warranty of
18     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19     * GNU General Public License for more details.
20     *
21     * You should have received a copy of the GNU Lesser General Public License (license.txt)
22     * along with this program; if not, write to the Free Software
23     * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
24     * or try this link: http://www.gnu.org/licenses/lgpl.html
25     *
26     * Contributors:
27     * Martin O. J. Schmitz - initial API and implementation
28     * Stefan A. Krüger - additional utility classes
29     ******************************************************************************/
30 alfonx 154 /**
31     Copyright 2008 Stefan Alfons Krüger and parts from some Geotools code
32    
33     atlas-framework - This file is part of the Atlas Framework
34    
35     This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
36     This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
37     You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
38    
39     Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
40     Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
41     Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
42     **/
43     package skrueger.geotools;
44    
45     import java.awt.Canvas;
46     import java.awt.Color;
47     import java.awt.Dimension;
48     import java.awt.Graphics2D;
49     import java.awt.RenderingHints;
50     import java.awt.image.BufferedImage;
51     import java.awt.image.ImageObserver;
52    
53     import javax.swing.tree.DefaultTreeCellRenderer;
54    
55     import org.apache.log4j.Logger;
56     import org.geotools.factory.GeoTools;
57     import org.geotools.factory.Hints;
58     import org.geotools.feature.IllegalAttributeException;
59     import org.geotools.geometry.jts.LiteShape2;
60     import org.geotools.renderer.lite.StyledShapePainter;
61     import org.geotools.renderer.style.SLDStyleFactory;
62     import org.geotools.renderer.style.Style2D;
63     import org.geotools.styling.LineSymbolizer;
64     import org.geotools.styling.PointSymbolizer;
65     import org.geotools.styling.PolygonSymbolizer;
66     import org.geotools.styling.RasterSymbolizer;
67     import org.geotools.styling.Rule;
68     import org.geotools.styling.Style;
69     import org.geotools.styling.Symbolizer;
70     import org.geotools.styling.TextSymbolizer;
71     import org.geotools.util.NumberRange;
72 mojays 325 import org.opengis.feature.simple.SimpleFeature;
73     import org.opengis.feature.simple.SimpleFeatureType;
74 alfonx 332 import org.opengis.feature.type.AttributeDescriptor;
75 alfonx 154
76     import schmitzm.geotools.feature.FeatureUtil;
77    
78     import com.vividsolutions.jts.geom.Coordinate;
79     import com.vividsolutions.jts.geom.GeometryFactory;
80     import com.vividsolutions.jts.geom.LineString;
81     import com.vividsolutions.jts.geom.LinearRing;
82     import com.vividsolutions.jts.geom.Polygon;
83    
84     /**
85     * Based on geoserver!
86     * <hr>
87     * <b>Changes by <a href="mailto:[email protected]">Martin Schmitz</a></b>
88     * <br>
89     * <ul>
90     * <li>07.02.2008:<br>
91 alfonx 318 * Determining the default values of a {@link SimpleFeatureType} by
92     * {@link FeatureUtil#getDefaultAttributeValues(SimpleFeatureType)} instead of using
93 alfonx 332 * {@link AttributeDescriptor#createDefaultValue()} directly, because the latter
94 alfonx 154 * returns {@code null} even though the attribut is not nillable.</li>
95     * </ul>
96     *
97     * @author Stefan Alfons Krüger
98     */
99     public class LegendIconFeatureRenderer extends DefaultTreeCellRenderer {
100     private static final Dimension SIZE = new Dimension(30,20);
101    
102     Logger LOGGER = Logger.getLogger(LegendIconFeatureRenderer.class);
103    
104     /**
105     * This is a static class
106     */
107     private LegendIconFeatureRenderer() {
108     }
109    
110     final static LegendIconFeatureRenderer instance = new LegendIconFeatureRenderer();
111    
112     public static LegendIconFeatureRenderer getInstance() {
113     // In GT 2.4.5 it we have to create a new one all the time!
114     return new LegendIconFeatureRenderer();
115     // return instance;
116     }
117    
118     /** The image produced at <code>produceLegendGraphic</code> */
119     private BufferedImage legendGraphic;
120    
121     /**
122     * used to create sample point shapes with LiteShape (not lines nor
123     * polygons)
124     */
125     private static final GeometryFactory geomFac = new GeometryFactory();
126    
127     /** padding percentage factor at both sides of the legend. */
128     private static final float hpaddingFactor = 0.11f; // was 0.15
129    
130     /** top & bottom padding percentage factor for the legend */
131     private static final float vpaddingFactor = 0.08f; // was 0.15
132    
133     /**
134     * Image observer to help in creating the stack like legend graphic from the
135     * images created for each rule
136     */
137     private static final ImageObserver imgObs = new Canvas();
138    
139     /**
140     * Just a holder to avoid creating many polygon shapes from inside
141     * <code>getSampleShape()</code>
142     */
143     private LiteShape2 sampleRect;
144    
145     /**
146     * Just a holder to avoid creating many line shapes from inside
147     * <code>getSampleShape()</code>
148     */
149     private LiteShape2 sampleLine;
150    
151     /**
152     * Just a holder to avoid creating many point shapes from inside
153     * <code>getSampleShape()</code>
154     */
155     private LiteShape2 samplePoint;
156    
157     private Hints hints;
158    
159     /**
160     * Returns a <code>java.awt.Shape</code> appropiate to render a legend
161     * graphic given the symbolizer type and the legend dimensions.
162     *
163     * @param symbolizer
164     * the Symbolizer for whose type a sample shape will be created
165     * @param legendWidth
166     * the requested width, in output units, of the legend graphic
167     * @param legendHeight
168     * the requested height, in output units, of the legend graphic
169     *
170     * @return an appropiate Line2D, Rectangle2D or LiteShape(Point) for the
171     * symbolizer, wether it is a LineSymbolizer, a PolygonSymbolizer,
172     * or a Point ot Text Symbolizer
173     *
174     * @throws IllegalArgumentException
175     * if an unknown symbolizer impl was passed in.
176     */
177     private LiteShape2 getSampleShape(Symbolizer symbolizer, int legendWidth,
178     int legendHeight) {
179     LiteShape2 sampleShape;
180     final float hpad = (legendWidth * hpaddingFactor);
181     final float vpad = (legendHeight * vpaddingFactor);
182    
183     if (symbolizer instanceof LineSymbolizer) {
184     if (this.sampleLine == null) {
185     Coordinate[] coords = {
186     new Coordinate(hpad, legendHeight - vpad),
187     new Coordinate(legendWidth - hpad, vpad) };
188     LineString geom = geomFac.createLineString(coords);
189    
190     try {
191     this.sampleLine = new LiteShape2(geom, null, null, false);
192     } catch (Exception e) {
193     this.sampleLine = null;
194     }
195     }
196    
197     sampleShape = this.sampleLine;
198     } else if ((symbolizer instanceof PolygonSymbolizer)
199     || (symbolizer instanceof RasterSymbolizer)) {
200     if (this.sampleRect == null) {
201     final float w = legendWidth - (2 * hpad);
202     final float h = legendHeight - (2 * vpad);
203    
204     Coordinate[] coords = { new Coordinate(hpad, vpad),
205     new Coordinate(hpad, vpad + h),
206     new Coordinate(hpad + w, vpad + h),
207     new Coordinate(hpad + w, vpad),
208     new Coordinate(hpad, vpad) };
209     LinearRing shell = geomFac.createLinearRing(coords);
210     Polygon geom = geomFac.createPolygon(shell, null);
211    
212     try {
213     this.sampleRect = new LiteShape2(geom, null, null, false);
214     } catch (Exception e) {
215     this.sampleRect = null;
216     }
217     }
218    
219     sampleShape = this.sampleRect;
220     } else if (symbolizer instanceof PointSymbolizer
221     || symbolizer instanceof TextSymbolizer) {
222     if (this.samplePoint == null) {
223     Coordinate coord = new Coordinate(legendWidth / 2,
224     legendHeight / 2);
225    
226     try {
227     this.samplePoint = new LiteShape2(geomFac
228     .createPoint(coord), null, null, false);
229     } catch (Exception e) {
230     this.samplePoint = null;
231     }
232     }
233    
234     sampleShape = this.samplePoint;
235     } else {
236     throw new IllegalArgumentException("Unknown symbolizer: "
237     + symbolizer);
238     }
239    
240     return sampleShape;
241     }
242 alfonx 361 //
243     // /**
244     // * Puts a BufferedImage into this.legendGraphic
245     // */
246     // public void produceLegendGraphic(SimpleFeatureType featureType, Style gt2Style,
247     // Rule[] applicableRules) {
248     //
249     // // final FeatureTypeStyle[] ftStyles = gt2Style.getFeatureTypeStyles();
250     //
251     // // if (request.getRule() != null) {
252     // // applicableRules = new Rule[] { request.getRule() };
253     // // } else {
254     // // applicableRules = getApplicableRules(ftStyles, scaleDenominator);
255     // // }
256     //
257     // final int ruleCount = applicableRules.length;
258     //
259     // /**
260     // * A legend graphic is produced for each applicable rule. They're being
261     // * holded here until the process is done and then painted on a "stack"
262     // * like legend.
263     // */
264     // final List<BufferedImage> legendsStack = new ArrayList<BufferedImage>(
265     // ruleCount);
266     //
267     // for (int i = 0; i < ruleCount; i++) {
268     // BufferedImage image = createImageForRule(applicableRules[i],
269     // featureType, SIZE);
270     // legendsStack.add(image);
271     // }
272     //
273     // // this.legendGraphic =
274     // // scaleImage(mergeLegends(legendsStack,applicableRules), request);
275     // this.legendGraphic = mergeLegends(legendsStack, applicableRules);
276     // }
277     //
278     // /**
279     // * Recieves a list of <code>BufferedImages</code> and produces a new one
280     // * which holds all the images in <code>imageStack</code> one above the
281     // * other.
282     // *
283     // * @param imageStack
284     // * the list of BufferedImages, one for each applicable Rule
285     // * @param rules
286     // * The applicable rules, one for each image in the stack
287     // * @param request
288     // * The request.
289     // *
290     // * @return the stack image with all the images on the argument list.
291     // *
292     // * @throws IllegalArgumentException
293     // * if the list is empty
294     // */
295     // private static BufferedImage mergeLegends(List<BufferedImage> imageStack,
296     // Rule[] rules) {
297     // if (imageStack.size() == 0) {
298     // throw new IllegalArgumentException("No legend graphics passed");
299     // }
300     //
301     // BufferedImage finalLegend = null;
302     //
303     // if (imageStack.size() == 1) {
304     // finalLegend = (BufferedImage) imageStack.get(0);
305     // } else {
306     // final int imgCount = imageStack.size();
307     // final String[] labels = new String[imgCount];
308     //
309     // BufferedImage img = ((BufferedImage) imageStack.get(0));
310     // FontMetrics fontMetrics = img.getGraphics().getFontMetrics();
311     //
312     // final int rowHeight = Math.max(fontMetrics.getHeight(), img
313     // .getHeight());
314     //
315     // // calculate the total dimensions of the image
316     // int totalHeight = rowHeight * imgCount;
317     // int totalWidth = 0;
318     //
319     // for (int i = 0; i < imgCount; i++) {
320     // img = (BufferedImage) imageStack.get(i);
321     //
322     // Rule rule = rules[i];
323     //
324     // // does this rule have a label
325     // labels[i] = rule.getTitle();
326     //
327     // if (labels[i] == null) {
328     // labels[i] = rule.getName();
329     // }
330     //
331     // int w = img.getWidth();
332     //
333     // if (labels[i] != null) {
334     // Graphics g = img.getGraphics();
335     // w += g.getFontMetrics().stringWidth(labels[i]);
336     // }
337     //
338     // totalWidth = Math.max(w, totalWidth);
339     // }
340     //
341     // // create the final image
342     // finalLegend = new BufferedImage(totalWidth, totalHeight,
343     // BufferedImage.TYPE_INT_ARGB);
344     //
345     // Graphics2D finalGraphics = finalLegend.createGraphics();
346     //
347     // finalGraphics.setColor(Color.white);
348     // finalGraphics.fillRect(0, 0, totalWidth, totalHeight);
349     //
350     // int h = 0;
351     //
352     // for (int i = 0; i < imgCount; i++) {
353     // img = (BufferedImage) imageStack.get(i);
354     //
355     // // draw the image
356     // int y = h;
357     //
358     // if (img.getHeight() < rowHeight) {
359     // // move the image to the center of the row
360     // y += (int) ((rowHeight - img.getHeight()) / 2d);
361     // }
362     //
363     // finalGraphics.drawImage(img, 0, y, imgObs);
364     //
365     // // draw the label
366     // if (labels[i] != null) {
367     // finalGraphics.setColor(Color.BLACK);
368     //
369     // y = (h + rowHeight) - fontMetrics.getDescent();
370     //
371     // if (fontMetrics.getHeight() < rowHeight) {
372     // // move the baseline to the center of the row
373     // y -= (int) ((rowHeight - fontMetrics.getHeight()) / 2d);
374     // }
375     //
376     // finalGraphics.drawString(labels[i], img.getWidth(), y);
377     // }
378     //
379     // h += rowHeight;
380     // }
381     // }
382     //
383     // return finalLegend;
384     // }
385     //
386     // /**
387     // * DOCUMENT ME!
388     // *
389     // * @return
390     // *
391     // * @throws IllegalStateException
392     // * DOCUMENT ME!
393     // */
394     // public BufferedImage getLegendGraphic() {
395     // if (this.legendGraphic == null) {
396     // throw new IllegalStateException();
397     // }
398     // return this.legendGraphic;
399     // }
400 alfonx 154
401     // /**
402     // * Paints a little rectangle in the color defined by the
403     // * {@link ColorMapEntry}
404     // *
405     // * unused
406     // *
407     // * @param cme
408     // * {@link ColorMapEntry}
409     // * @param cm
410     // * {@link ColorMap} to determine type (VALUES, INTERVALL )
411     // * @param iconWidth
412     // * Size of the rectangle
413     // * @param iconHeight
414     // * Size of the rectangle
415     // * @return {@link ImageIcon} of that color, maybe with a white border
416     // * @author Stefan Alfons Krüger
417     // */
418     // public static ImageIcon createImageForColorMapEntry(ColorMapEntry cme,
419     // ColorMap cm, Integer iconWidth, Integer iconHeight) {
420     //
421     // BufferedImage imageForRule = new BufferedImage(iconWidth, iconHeight,
422     // BufferedImage.TYPE_INT_ARGB);
423     //
424     // final Color color = StylingUtil.getColorFromColorMapEntry(cme);
425     //
426     // // Paint a block
427     // for (int x = 0; x < iconWidth; x++) {
428     // for (int y = 0; y < iconHeight; y++) {
429     // int rgb = color.getRGB();
430     // int rand = 2;
431     //
432     // // Paint a white border if the type is VALUES
433     // if ((x < rand) || (x > iconWidth - rand) || (y < rand)
434     // || (y > iconHeight - rand)) {
435     // if (cm.getType() == ColorMap.TYPE_VALUES) {
436     // rgb = Color.white.getRGB();
437     // }
438     // }
439     // imageForRule.setRGB(x, y, rgb);
440     // }
441     // }
442     // return new ImageIcon(imageForRule);
443     // }
444    
445     /**
446     * Creates a little BufferedImage that presents the Style/Symbols used by
447 alfonx 318 * the {@link MapLegend} to show a legend for the {@link SimpleFeatureType}
448 alfonx 154 *
449     * @param rule
450     * {@link Rule} that provides the text and the style to present
451     * @param featureType
452 alfonx 318 * Schema that describes the kind of the sample {@link SimpleFeature}
453 alfonx 154 * that will be rendered with the {@link Style}
454     * @param bg
455     * Background {@link Color} or <code>null</code>
456     *
457     * @throws IllegalAttributeException
458     */
459 alfonx 318 public BufferedImage createImageForRule(Rule rule, SimpleFeatureType featureType,
460 alfonx 154 Dimension size, Color bg) {
461    
462     Symbolizer[] symbolizers = rule.getSymbolizers();
463    
464     BufferedImage buffImage = new BufferedImage(size.width, size.height,
465     BufferedImage.TYPE_INT_ARGB);
466     Graphics2D graphics = buffImage.createGraphics();
467    
468     if (bg != null) {
469     // ****************************************************************************
470     // The following lines define the backgroup color for the rendered
471     // images
472     // ****************************************************************************
473     graphics.setBackground(bg);
474     graphics.setColor(bg);
475     graphics.fillRect(0, 0, size.width, size.height);
476     }
477    
478     // Enable anti-aliasing for the legend symbols
479     graphics.setRenderingHints(getHints());
480    
481     // TODO scaleDenominator = 100000000000000000000000000000d; Was ist das
482     // fuer ein Quatsch?
483     final double scaleDenominator = 100000000000000000000000000000d;
484     final NumberRange scaleRange = new NumberRange(scaleDenominator,
485     scaleDenominator);
486    
487     try {
488    
489     for (int sIdx = 0; sIdx < symbolizers.length; sIdx++) {
490     Symbolizer symbolizer = symbolizers[sIdx];
491    
492     if (symbolizer instanceof TextSymbolizer) {
493     LOGGER
494     .warn("createImageForRule for a TextSymbolizer. Sure we want that?");
495     continue;
496     }
497    
498     // if (symbolizer instanceof RasterSymbolizer) {
499     // log.warn("createImageForRule method can't be used for
500     // RasterSymbolizers..");
501     // }
502     // else
503 alfonx 318 final SimpleFeature sampleFeature = FeatureUtil.createSampleFeature(featureType);
504 alfonx 154
505     // The SLDStyleFactory has to be recreated, as it seams to cache
506     // some stuff.
507     SLDStyleFactory sldStyleFactory = new SLDStyleFactory();
508     Style2D style2d = sldStyleFactory.createStyle(sampleFeature,
509     symbolizer, scaleRange);
510    
511     LiteShape2 shape = getSampleShape(symbolizer, size.width,
512     size.height);
513    
514     if (style2d != null) {
515     new StyledShapePainter(null).paint(graphics, shape,
516     style2d, scaleDenominator);
517     }
518     }
519     } catch (Exception e) {
520     LOGGER
521     .error(
522     "Error during createImageForRule, returning empty Image",
523     e);
524     }
525     return buffImage;
526     }
527    
528     /**
529     * Define Java2D and other Hints
530     *
531     * @param hints
532     * @author <a href="mailto:[email protected]">Stefan Alfons
533     * Kr&uuml;ger</a>
534     */
535     public void setHints(Hints hints) {
536     getHints().add(hints);
537     }
538    
539     private Hints getHints() {
540     if (hints == null) {
541     hints = GeoTools.getDefaultHints();
542     hints.put(RenderingHints.KEY_ANTIALIASING,
543     RenderingHints.VALUE_ANTIALIAS_ON);
544     hints.put(RenderingHints.KEY_TEXT_ANTIALIASING,
545     RenderingHints.VALUE_TEXT_ANTIALIAS_GASP);
546     hints.put(RenderingHints.KEY_ALPHA_INTERPOLATION,
547     RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
548     hints.put(RenderingHints.KEY_RENDERING,
549     RenderingHints.VALUE_RENDER_QUALITY);
550     hints.put(RenderingHints.KEY_COLOR_RENDERING,
551     RenderingHints.VALUE_COLOR_RENDER_QUALITY);
552     }
553     return hints;
554     }
555    
556     /**
557     * Creates a little BufferedImage that presents the Style/Symbols used by
558 alfonx 318 * the {@link MapLegend} to show a legend for the {@link SimpleFeatureType}
559 alfonx 154 *
560     * @param rule
561     * {@link Rule} that provides the text and the style to present
562     * @param featureType
563 alfonx 318 * Schema that describes the kind of the sample {@link SimpleFeature}
564 alfonx 154 * that will be rendered with the {@link Style}
565     *
566     * @throws IllegalAttributeException
567     */
568     public BufferedImage createImageForRule(final Rule rule,
569 alfonx 318 final SimpleFeatureType featureType, final Dimension size) {
570 alfonx 154 return createImageForRule(rule, featureType, size, null);
571     }
572    
573     }

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26