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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 397 - (hide annotations)
Mon Sep 14 11:40:17 2009 UTC (15 years, 5 months ago) by alfonx
File size: 34416 byte(s)
* Moving towards a better raster legend
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     package skrueger.geotools;
31    
32 alfonx 397 import java.awt.Color;
33     import java.awt.Dimension;
34     import java.awt.Graphics;
35     import java.awt.image.BufferedImage;
36 alfonx 244 import java.io.File;
37     import java.io.FileNotFoundException;
38     import java.io.FileWriter;
39     import java.net.URL;
40     import java.text.DecimalFormat;
41     import java.util.HashMap;
42     import java.util.List;
43     import java.util.Map;
44     import java.util.SortedMap;
45     import java.util.TreeMap;
46    
47 alfonx 397 import javax.swing.Box;
48     import javax.swing.BoxLayout;
49     import javax.swing.ImageIcon;
50     import javax.swing.JLabel;
51    
52 alfonx 244 import org.apache.log4j.Logger;
53     import org.geotools.coverage.grid.GridCoverage2D;
54     import org.geotools.coverage.grid.io.AbstractGridCoverage2DReader;
55     import org.geotools.feature.FeatureCollection;
56     import org.geotools.map.DefaultMapLayer;
57     import org.geotools.map.MapLayer;
58     import org.geotools.styling.ColorMap;
59     import org.geotools.styling.ColorMapEntry;
60 alfonx 397 import org.geotools.styling.FeatureTypeStyle;
61 alfonx 244 import org.geotools.styling.RasterSymbolizer;
62 alfonx 397 import org.geotools.styling.Rule;
63 alfonx 244 import org.geotools.styling.Style;
64     import org.jdom.Document;
65     import org.jdom.Element;
66     import org.jdom.input.SAXBuilder;
67     import org.jdom.output.XMLOutputter;
68 alfonx 397 import org.opengis.feature.simple.SimpleFeatureType;
69 alfonx 244
70     import schmitzm.geotools.styling.StylingUtil;
71     import schmitzm.io.IOUtil;
72     import schmitzm.lang.LangUtil;
73     import schmitzm.swing.SwingUtil;
74     import skrueger.AttributeMetaData;
75     import skrueger.RasterLegendData;
76     import skrueger.i8n.Translation;
77    
78     /**
79     * This class provides static helper methods for dealing with
80     * {@link StyledLayerInterface} stuff.
81     * @author <a href="mailto:[email protected]">Martin Schmitz</a> (University of Bonn/Germany)
82     * @version 1.0
83     */
84     public class StyledLayerUtil {
85     private static final Logger LOGGER = Logger.getLogger(StyledLayerUtil.class.getName());
86     private static final SAXBuilder SAX_BUILDER = new SAXBuilder();
87     private static final XMLOutputter XML_OUTPUTTER = new XMLOutputter();
88    
89     /** URL for Atlas XML schema */
90     public static final String AMLURI = "http://www.wikisquare.de/AtlasML";
91     /** Name of the XML Element for the attribute meta data map */
92     public static final String ELEM_NAME_AMD = "attributeMetaData";
93     /** Name of the XML Element for the raster legend data */
94     public static final String ELEM_NAME_RLD = "rasterLegendData";
95     /** Name of the XML Element for an attribute meta data map entry */
96     public static final String ELEM_NAME_ATTRIBUTE = "dataAttribute";
97     /** Name of the XML Element for an raster legend data entry */
98     public static final String ELEM_NAME_RASTERLEGEND = "rasterLegendItem";
99     /** Name of the XML Element for a translation */
100     public static final String ELEM_NAME_TRANSLATION = "translation";
101    
102     /**
103     * Creates a Geotools {@link MapLayer} from an object. If the object is a
104     * {@link StyledLayerInterface} then its sytle is used. In case of direct
105     * Geotools objects ({@link GridCoverage2D}, {@link AbstractGridCoverage2DReader},
106     * {@link FeatureCollection}) a default style is generated.
107     * @param object an Object
108     * @exception Exception if {@code null} is given as object or an error occurs during layer creation
109     */
110     public static MapLayer createMapLayer(Object object) throws Exception {
111     return createMapLayer(object,null);
112     }
113    
114     /**
115     * Creates a Geotools {@link MapLayer} from an object. If the object is a
116     * {@link StyledLayerInterface} then its sytle is used. In case of direct
117     * Geotools objects ({@link GridCoverage2D}, {@link AbstractGridCoverage2DReader},
118     * {@link FeatureCollection}) a default style is generated.
119     * @param object an Object
120     * @param forcedStyle (SLD-)Style to force for the object
121     * @exception Exception if {@code null} is given as object or an error occurs during layer creation
122     */
123     public static MapLayer createMapLayer(Object object, Style forcedStyle) throws Exception {
124     MapLayer layer = null;
125     Style style = null;
126     if ( object instanceof StyledLayerInterface ) {
127     style = ((StyledLayerInterface<?>)object).getStyle();
128     object = ((StyledLayerInterface<?>)object).getGeoObject();
129     }
130     if ( forcedStyle != null )
131     style = forcedStyle;
132     if ( style == null )
133     style = StylingUtil.createDefaultStyle(object);
134    
135     if (object instanceof GridCoverage2D)
136     layer = new DefaultMapLayer( (GridCoverage2D) object, style);
137     if (object instanceof AbstractGridCoverage2DReader)
138     layer = new DefaultMapLayer( (AbstractGridCoverage2DReader) object, style);
139     if (object instanceof FeatureCollection)
140     layer = new DefaultMapLayer( (FeatureCollection) object, style);
141    
142     if ( layer == null )
143     throw new Exception("Can not create MapLayer from "+(object == null ? "null" : object.getClass()));
144    
145     return layer;
146     }
147    
148     /**
149     * Creates an default instance of {@link StyledLayerInterface} for a Geotools
150     * object ({@link GridCoverage2D}, {@link FeatureCollection}) with a default
151     * style.
152     * @param object an Object
153     * @param title title for the object
154     * @exception UnsupportedOperationException if {@code null} is given as object or an error occurs during creation
155     */
156     public static StyledLayerInterface<?> createStyledLayer(Object object, String title) {
157     return createStyledLayer(object, title, null);
158     }
159    
160     /**
161     * Creates an default instance of {@link StyledLayerInterface} for a Geotools
162     * object ({@link GridCoverage2D}, {@link FeatureCollection}) with a given
163     * style.
164     * @param object an Object
165     * @param title title for the object
166     * @param style style and meta data for the object
167     * @exception UnsupportedOperationException if {@code null} is given as object or an error occurs during creation
168     */
169     public static StyledLayerInterface<?> createStyledLayer(Object object, String title, StyledLayerStyle style) {
170     StyledLayerInterface<?> styledLayer = null;
171    
172     String id = (title != null) ? title : "defaultID";
173    
174     if ( object instanceof GridCoverage2D )
175     styledLayer = new StyledGridCoverage(
176     (GridCoverage2D)object,
177     id,
178     title,
179     style
180     );
181     else if ( object instanceof AbstractGridCoverage2DReader )
182     styledLayer = new StyledGridCoverageReader(
183     (AbstractGridCoverage2DReader)object,
184     id,
185     title,
186     style
187     );
188     else if ( object instanceof FeatureCollection )
189     styledLayer = new StyledFeatureCollection(
190     (FeatureCollection)object,
191     id,
192     title,
193     style
194     );
195    
196     if ( styledLayer == null )
197     throw new UnsupportedOperationException("Can not create StyledLayerInterface object from "+(object == null ? "null" : object.getClass()));
198    
199     return styledLayer;
200     }
201    
202     /**
203     * Return only the visible or invisible entries of an AttributeMetaData-Map.
204     * @param amdMap AttributeMetaData-Map
205     * @param visible indicated whether the visible or invisible entries are
206     * returned
207     */
208     public static SortedMap<Integer,AttributeMetaData> getVisibleAttributeMetaData(Map<Integer,AttributeMetaData> amdMap, boolean visible) {
209     SortedMap<Integer,AttributeMetaData> filteredMap = new TreeMap<Integer,AttributeMetaData>();
210     for (AttributeMetaData amd : amdMap.values())
211     if ( amd.isVisible() )
212     filteredMap.put(amd.getColIdx(), amd);
213    
214     return filteredMap;
215     }
216    
217    
218     /**
219     * Parses a {@link AttributeMetaData} object from an JDOM-{@link Element}.
220     * This method works like {@link AMLImport#parseDataAttribute(org.w3c.dom.Node},
221     * but for JDOM.
222     * @param element {@link Element} to parse
223     */
224     public static AttributeMetaData parseAttributeMetaData(final Element element) {
225     final Integer col = Integer.valueOf(element.getAttributeValue("col"));
226     final Boolean visible = Boolean.valueOf(element.getAttributeValue("visible"));
227     final String unit = element.getAttributeValue("unit");
228    
229     Translation name = new Translation();
230     Translation desc = new Translation();
231     for (final Element childElement : (List<Element>)element.getChildren()) {
232     if (childElement.getName() == null)
233     continue;
234    
235     if (childElement.getName().equals("name"))
236     name = parseTranslation(childElement);
237     else if (childElement.getName().equals("desc"))
238     desc = parseTranslation(childElement);
239     }
240     return new AttributeMetaData(col, visible, name, desc, unit);
241     }
242    
243     /**
244     * Parses a {@link AttributeMetaData} map from an JDOM-{@link Element}
245     * with {@code <attribute>}-childs.
246     * @param element {@link Element} to parse
247     */
248     public static Map<Integer,AttributeMetaData> parseAttributeMetaDataMap(final Element element) {
249     HashMap<Integer,AttributeMetaData> metaData = new HashMap<Integer,AttributeMetaData>();
250     List<Element> attributesElements = element.getChildren( ELEM_NAME_ATTRIBUTE );
251     for (Element attibuteElement : attributesElements)
252     {
253     AttributeMetaData attrMetaData = parseAttributeMetaData( attibuteElement );
254     metaData.put( attrMetaData.getColIdx(), attrMetaData );
255     }
256     return metaData;
257     }
258    
259     /**
260     * Loads a {@link AttributeMetaData} object from an URL.
261     * @param documentUrl {@link URL} to parse
262     * @see #parseAttributeMetaData(Element)
263     */
264     public static Map<Integer,AttributeMetaData> loadAttributeMetaDataMap(final URL documentUrl) throws Exception {
265     Document document = SAX_BUILDER.build(documentUrl);
266     return parseAttributeMetaDataMap( document.getRootElement() );
267     }
268    
269     /**
270     * Creates an JDOM {@link Element} for the given {@link AttributeMetaData}
271     * object.
272     * @param amd meta data for one attribute
273     */
274     public static Element createAttributeMetaDataElement(final AttributeMetaData amd) {
275     final Element element = new Element( ELEM_NAME_ATTRIBUTE , AMLURI);
276     element.setAttribute("col", String.valueOf( amd.getColIdx() ) );
277     element.setAttribute("visible", String.valueOf( amd.isVisible() ) );
278     element.setAttribute("unit", amd.getUnit() );
279     // Creating a aml:name tag...
280     element.addContent( createTranslationElement("name", amd.getTitle()) );
281     // Creating a aml:desc tag...
282     element.addContent( createTranslationElement("desc", amd.getDesc()) );
283     return element;
284     }
285    
286     /**
287     * Creates an JDOM {@link Element} for the given {@link AttributeMetaData}
288     * map.
289     * @param amdMap map of attribute meta data
290     */
291     public static Element createAttributeMetaDataMapElement(final Map<Integer,AttributeMetaData> amdMap) {
292     final Element element = new Element( ELEM_NAME_AMD , AMLURI);
293     for (AttributeMetaData amd : amdMap.values())
294     element.addContent( createAttributeMetaDataElement( amd ) );
295     return element;
296     }
297    
298     /**
299     * Saves a {@link AttributeMetaData AttributeMetaData-Map} to an URL.
300     * @param amdMap map of {@link AttributeMetaData}
301     * @param documentUrl {@link URL} to store the XML
302     */
303     public static void saveAttributeMetaDataMap(final Map<Integer,AttributeMetaData> amdMap, final URL documentUrl) throws Exception {
304     // Create XML-Document
305     final FileWriter out = new FileWriter( new File(documentUrl.toURI()) );
306     XML_OUTPUTTER.output(
307     createAttributeMetaDataMapElement(amdMap),
308     out
309     );
310     out.flush();
311     out.close();
312     }
313    
314    
315    
316     /**
317     * Parses a {@link RasterLegendData} object from an JDOM-{@link Element}.
318     * This method works like {@link AMLImport#parseRasterLegendData(org.w3c.dom.Node},
319     * but for JDOM.
320     * @param element {@link Element} to parse
321     */
322     public static RasterLegendData parseRasterLegendData(Element element) {
323    
324     final boolean paintGaps = Boolean.valueOf( element.getAttributeValue("paintGaps") );
325    
326     RasterLegendData rld = new RasterLegendData(paintGaps);
327    
328     for ( Element childElement : (List<Element>)element.getChildren() ) {
329     final String name = childElement.getName();
330     // Cancel if it's an attribute
331     if ( childElement.getChildren().size() == 0 )
332     continue;
333    
334     if (name.equals( ELEM_NAME_RASTERLEGEND )) {
335     final String valueAttr = childElement.getAttributeValue("value");
336     if ( valueAttr == null )
337     throw new UnsupportedOperationException("Attribute 'value' missing for definition of <"+ELEM_NAME_RASTERLEGEND+">");
338     final double value = Double.valueOf(valueAttr);
339    
340     // first and only item should be the label
341     final Element labelElement = childElement.getChild("label");
342     // id label element is missing, the translation is searched directly
343     // as childs of the rasterLegendItem element
344     Translation label = parseTranslation( labelElement != null ? labelElement : childElement );
345     rld.put(value, label);
346     }
347     }
348    
349     return rld;
350     }
351    
352     /**
353     * Loads a {@link RasterLegendData} object from an URL.
354     * @param documentUrl {@link URL} to parse
355     * @see #parseAttributeMetaData(Element)
356     */
357     public static RasterLegendData loadRasterLegendData(final URL documentUrl) throws Exception {
358     Document document = SAX_BUILDER.build(documentUrl);
359     return parseRasterLegendData( document.getRootElement() );
360     }
361    
362     /**
363     * Creates an JDOM {@link Element} for the given {@link RasterLegendData}
364     * map.
365     * @param rld raster legend data
366     */
367     public static Element createRasterLegendDataElement(final RasterLegendData rld) {
368     final Element element = new Element( ELEM_NAME_RLD , AMLURI);
369     element.setAttribute("paintGaps", rld.isPaintGaps().toString());
370     for (Double key : rld.getSortedKeys()) {
371     Element item = new Element( ELEM_NAME_RASTERLEGEND, AMLURI);
372     item.setAttribute("value", key.toString());
373     item.addContent( createTranslationElement("label", rld.get(key)) );
374     element.addContent(item);
375     }
376     return element;
377     }
378    
379     /**
380     * Creates {@link RasterLegendData} from a {@link ColorMap}.
381     * @param colorMap a color map
382     * @param paintGaps indicated whether gaps are painted between the legend items
383     * @param digits number of digits the grid value classes (and legend) are
384     * rounded to (null means no round; >= 0 means digits after comma;
385     * < 0 means digits before comma) */
386     public static RasterLegendData generateRasterLegendData(ColorMap colorMap, boolean paintGaps, Integer digits) {
387     DecimalFormat decFormat = digits != null ? new DecimalFormat( SwingUtil.getNumberFormatPattern(digits) ) : null;
388     RasterLegendData rld = new RasterLegendData(paintGaps);
389     for (ColorMapEntry cme : colorMap.getColorMapEntries())
390     {
391     double value = StylingUtil.getQuantityFromColorMapEntry(cme);
392     String label = cme.getLabel();
393     // if no label is set (e.g. quantitative style),
394     // use the value as label
395     if ( label == null || label.equals("") )
396     if ( digits == null )
397     label = String.valueOf(value);
398     else
399     label = decFormat.format( LangUtil.round(value, digits) );
400     rld.put( value, new Translation(" "+label) );
401     }
402     return rld;
403     }
404    
405     /**
406     * Creates {@link RasterLegendData} from the {@link ColorMap} of a style.
407     * @param style a raster style (must contain a {@link RasterSymbolizer})
408     * @param paintGaps indicated whether gaps are painted between the legend items
409     * @param digits number of digits the grid value classes (and legend) are
410     * rounded to (null means no round; >= 0 means digits after comma;
411     * < 0 means digits before comma) */
412     public static RasterLegendData generateRasterLegendData(Style style, boolean paintGaps, Integer digits) {
413     ColorMap colorMap = StylingUtil.getColorMapFromStyle(style);
414     if ( colorMap == null)
415     throw new IllegalArgumentException("Color map can not be determined from style!");
416     return generateRasterLegendData(colorMap, paintGaps, digits);
417     }
418    
419     /**
420     * Saves a {@link RasterLegendData} to an URL.
421     * @param rld raster legend data
422     * @param documentUrl {@link URL} to store the XML
423     */
424     public static void saveRasterLegendData(final RasterLegendData rld, final URL documentUrl) throws Exception {
425     // Create XML-Document
426     final FileWriter out = new FileWriter( new File(documentUrl.toURI()) );
427     XML_OUTPUTTER.output(
428     createRasterLegendDataElement(rld),
429     out
430     );
431     out.flush();
432     out.close();
433     }
434    
435     /**
436     * Parses a {@link Translation} object from an JDOM-{@link Element}.
437     * This method works like {@link AMLImport#parseTranslation(org.w3c.dom.Node},
438     * but for JDOM.
439     * @param element {@link Element} to parse
440     */
441     public final static Translation parseTranslation(final Element element) {
442     Translation trans = new Translation();
443    
444     if (element == null)
445     return trans;
446    
447     for (final Element translationElement : (List<Element>)element.getChildren()) {
448     final String name = translationElement.getName();
449     if (name == null)
450     continue;
451    
452     // lang attribute
453     String lang = translationElement.getAttributeValue("lang");
454     // set the default, if no language code is set
455     if ( lang == null )
456     lang = Translation.DEFAULT_KEY;
457    
458     final String translationText = translationElement.getValue();
459     if (translationText == null)
460     trans.put(lang, "");
461     else
462     trans.put(lang, translationText);
463     }
464    
465     // if no <translation> is given, the value of the node should
466     // be used as a default translation
467     if (trans.size() == 0)
468     trans.put( Translation.DEFAULT_KEY, element.getValue() );
469     // trans = new Translation( ((List<Element>)element.getChildren()).get(0).getValue() );
470    
471     return trans;
472     }
473    
474     /**
475     * Creates an JDOM {@link Element} for the given {@link Translation}.
476     * @param tagname Name of the Element
477     * @param translation Translation to store in the Element
478     */
479     public final static Element createTranslationElement(String tagname, Translation translation) {
480     Element element = new Element(tagname, AMLURI);
481     if ( translation == null )
482     throw new UnsupportedOperationException("Translation element can not be created from null!");
483    
484     // If only a default translation is set, the <translation lang="..">..</tranlation>
485     // part is not used
486     if (translation.keySet().size() == 1 && translation.get(Translation.DEFAULT_KEY) != null) {
487     element.addContent( translation.get(Translation.DEFAULT_KEY) );
488     return element;
489     }
490    
491     // add a <translation lang="..">..</tranlation> part to the element for
492     // all languages
493     for (String lang : translation.keySet()) {
494     Element translationElement = new Element( ELEM_NAME_TRANSLATION , AMLURI);
495     translationElement.setAttribute("lang", lang);
496     String translationString = translation.get(lang);
497     if (translationString == null)
498     translationString = "";
499     translationElement.addContent( translationString );
500     element.addContent(translationElement);
501     }
502    
503     return element;
504     }
505    
506    
507     /**
508     * Sets a style to {@link StyledLayerInterface}.
509     * @param styledObject a styled object
510     * @param style a Style
511     */
512     public static void setStyledLayerStyle(StyledLayerInterface styledObject, StyledLayerStyle<?> style) {
513     // set SLD style
514     styledObject.setStyle( style.getGeoObjectStyle() );
515     // set meta data
516     if ( styledObject instanceof StyledGridCoverageInterface &&
517     (style.getMetaData() instanceof RasterLegendData || style.getMetaData() == null) ) {
518     RasterLegendData sourceRld = (RasterLegendData)style.getMetaData();
519     RasterLegendData destRld = ((StyledGridCoverageInterface)styledObject).getLegendMetaData();
520     if ( destRld != null && sourceRld != null ) {
521     destRld.setPaintGaps(sourceRld.isPaintGaps());
522     destRld.clear();
523     destRld.putAll( sourceRld );
524     }
525     return;
526     }
527     if ( styledObject instanceof StyledFeatureCollectionInterface &&
528     (style.getMetaData() instanceof Map || style.getMetaData() == null) ) {
529     Map<Integer, AttributeMetaData> sourceAmd = (Map<Integer, AttributeMetaData>)style.getMetaData();
530     Map<Integer, AttributeMetaData> destAmd = ((StyledFeatureCollectionInterface)styledObject).getAttributeMetaDataMap();
531     if ( destAmd != null && sourceAmd != null ) {
532     destAmd.clear();
533     destAmd.putAll( sourceAmd );
534     }
535     return;
536     }
537    
538     throw new UnsupportedOperationException("Style is not compatible to object: " +
539     (style.getMetaData() == null ? null : style.getMetaData().getClass().getSimpleName()) +
540     " <-> " +
541     (styledObject == null ? null : styledObject.getClass().getSimpleName()));
542     }
543    
544     /**
545     * Returns the style a {@link StyledLayerInterface} as a {@link StyledLayerStyle}.
546     * @param styledObject a styled object
547     * @return {@code StyledLayerStyle<RasterLegendData>} for {@link StyledGridCoverageInterface}
548     * or {@code StyledLayerStyle<Map<Integer,AttributeMetaData>>} for
549     * {@link StyledFeatureCollectionInterface}
550     */
551     public static StyledLayerStyle<?> getStyledLayerStyle(StyledLayerInterface styledObject) {
552     if ( styledObject instanceof StyledGridCoverageInterface )
553     return getStyledLayerStyle( (StyledGridCoverageInterface)styledObject );
554     if ( styledObject instanceof StyledFeatureCollectionInterface )
555     return getStyledLayerStyle( (StyledFeatureCollectionInterface)styledObject );
556     throw new UnsupportedOperationException("Unknown type of StyledLayerInterface: "+(styledObject == null ? null : styledObject.getClass().getSimpleName()));
557     }
558    
559     /**
560     * Returns the style and raster meta data of a {@link StyledGridCoverageInterface}
561     * as a {@link StyledLayerStyle}.
562     * @param styledGC a styled grid coverage
563     */
564     public static StyledLayerStyle<RasterLegendData> getStyledLayerStyle(StyledGridCoverageInterface styledGC) {
565     return new StyledLayerStyle<RasterLegendData>(
566     styledGC.getStyle(),
567     styledGC.getLegendMetaData()
568     );
569     }
570    
571     /**
572     * Returns the style and attribute meta data of a {@link StyledFeatureCollectionInterface}
573     * as a {@link StyledLayerStyle}.
574     * @param styledFC a styled feature collection
575     */
576     public static StyledLayerStyle<Map<Integer,AttributeMetaData>> getStyledLayerStyle(StyledFeatureCollectionInterface styledFC) {
577     return new StyledLayerStyle<Map<Integer,AttributeMetaData>>(
578     styledFC.getStyle(),
579     styledFC.getAttributeMetaDataMap()
580     );
581     }
582    
583     /**
584     * Loads a {@linkplain Style SLD-Style} and {@linkplain RasterLegendData Raster-LegendData}
585     * for a given geo-object (raster) source. The SLD file must be present. A missing
586     * raster legend-data file is tolerated.
587     * @param geoObjectURL URL of the (already read) raster object
588     * @param sldExt file extention for the SLD file
589     * @param rldExt file extention for the raster legend-data file
590     * @return {@code null} in case of any error
591     */
592     public static StyledLayerStyle<RasterLegendData> loadStyledRasterStyle(URL geoObjectURL, String sldExt, String rldExt) {
593     RasterLegendData metaData = null;
594     Style sldStyle = null;
595     try {
596     Style[] styles = StylingUtil.loadSLD(IOUtil.changeUrlExt(geoObjectURL, sldExt));
597     // SLD must be present
598     if ( styles == null || styles.length == 0 )
599     return null;
600     sldStyle = styles[0];
601     }
602     catch (Exception err) {
603     // SLD must be present
604     LangUtil.logDebugError(LOGGER,err);
605     return null;
606     }
607    
608     try {
609     metaData = StyledLayerUtil.loadRasterLegendData( IOUtil.changeUrlExt(geoObjectURL,rldExt) );
610     } catch (FileNotFoundException err) {
611     // ignore missing raster legend data
612     } catch (Exception err) {
613     // any other error during legend data creation leads to error
614     LangUtil.logDebugError(LOGGER,err);
615     return null;
616     }
617     return new StyledLayerStyle<RasterLegendData>(sldStyle, metaData);
618     }
619    
620     /**
621     * Loads a {@linkplain Style SLD-Style} from a {@code .sld} file and
622     * {@linkplain RasterLegendData Raster-LegendData} from a {@code .rld} file
623     * for a given geo-object (raster) source. The SLD file must be present. A missing
624     * raster legend-data file is tolerated.
625     * @param geoObjectURL URL of the (already read) raster object
626     * @param sldExt file extention for the SLD file
627     * @param rldExt file extention for the raster legend-data file
628     * @return {@code null} in case of any error
629     */
630     public static StyledLayerStyle<RasterLegendData> loadStyledRasterStyle(URL geoObjectURL) {
631     return loadStyledRasterStyle(geoObjectURL, "sld", "rld");
632     }
633    
634     /**
635     * Loads a {@linkplain Style SLD-Style} and a {@linkplain AttributeMetaData AttributeMetaData-Map}
636     * for a given geo-object (feature) source. The SLD file must be present. A missing
637     * attribute meta-data file is tolerated.
638     * @param geoObjectURL URL of the (already read) feature object
639     * @param sldExt file extention for the SLD file
640     * @param rldExt file extention for the raster legend-data file
641     * @return {@code null} in case of any error
642     */
643     public static StyledLayerStyle<Map<Integer,AttributeMetaData>> loadStyledFeatureStyle(URL geoObjectURL, String sldExt, String rldExt) {
644     Map<Integer,AttributeMetaData> metaData = null;
645     Style sldStyle = null;
646     try {
647     Style[] styles = StylingUtil.loadSLD(IOUtil.changeUrlExt(geoObjectURL, sldExt));
648     // SLD must be present
649     if ( styles == null || styles.length == 0 )
650     return null;
651     sldStyle = styles[0];
652     } catch (Exception err) {
653     // SLD must be present
654     LangUtil.logDebugError(LOGGER,err);
655     return null;
656     }
657    
658     try {
659     metaData = StyledLayerUtil.loadAttributeMetaDataMap( IOUtil.changeUrlExt(geoObjectURL,rldExt) );
660     } catch (FileNotFoundException err) {
661     // ignore missing attribute meta data
662     } catch (Exception err) {
663     // any other error during meta data creation leads to error
664     LangUtil.logDebugError(LOGGER,err);
665     return null;
666     }
667    
668     return new StyledLayerStyle<Map<Integer,AttributeMetaData>>(sldStyle, metaData);
669     }
670    
671     /**
672     * Loads a {@linkplain Style SLD-Style} from a {@code .sld} file and
673     * {@linkplain AttributeMetaData AttributeMetaData-Map} from a {@code .amd} file
674     * for a given geo-object (feature) source. The SLD file must be present. A missing
675     * attribute meta-data file is tolerated.
676     * @param geoObjectURL URL of the (already read) feature object
677     * @param sldExt file extention for the SLD file
678     * @param rldExt file extention for the raster legend-data file
679     * @return {@code null} in case of any error
680     */
681     public static StyledLayerStyle<Map<Integer,AttributeMetaData>> loadStyledFeatureStyle(URL geoObjectURL) {
682     return loadStyledFeatureStyle(geoObjectURL, "sld", "amd");
683     }
684    
685     /**
686     * Stores a {@linkplain Style SLD-Style} and {@linkplain RasterLegendData Raster-LegendData}
687     * for a given geo-object (raster) source.
688     * @param style style to save
689     * @param geoObjectURL URL of the raster object
690     * @param sldExt file extention for the SLD file
691     * @param mdExt file extention for the meta-data file
692     */
693     public static <T> void saveStyledLayerStyle(StyledLayerStyle<T> style, URL geoObjectURL, String sldExt, String mdExt) throws Exception {
694     // Store the SLD
695     Style sldStyle = style.getGeoObjectStyle();
696     if ( sldStyle != null ) {
697     StylingUtil.saveStyleToSLD(
698     sldStyle,
699     IOUtil.changeFileExt(
700     new File(geoObjectURL.toURI()),
701     sldExt
702     )
703     );
704     }
705    
706     // Store the meta data
707     T metaData = style.getMetaData();
708     if ( metaData != null ) {
709     if ( metaData instanceof RasterLegendData ) {
710     saveRasterLegendData(
711     (RasterLegendData)metaData,
712     IOUtil.changeUrlExt(geoObjectURL,mdExt)
713     );
714     // } else if ( metaData instanceof Map<Integer,AttributeMetaData> ) { // LEIDER NICHT KOMPILIERBAR!!
715     } else if ( metaData instanceof Map ) {
716     saveAttributeMetaDataMap(
717     (Map<Integer,AttributeMetaData>)metaData,
718     IOUtil.changeUrlExt(geoObjectURL,mdExt)
719     );
720     } else
721     throw new UnsupportedOperationException("Export for meta data not yet supported: "+metaData.getClass().getSimpleName());
722     }
723     }
724    
725     /**
726     * Stores the {@linkplain Style SLD-Style} to a {@code .sld} file and
727     * the meta data ({@link RasterLegendData} or {@link AttributeMetaData})
728     * to a {@code .rld} or {@code .amd} file.
729     * for a given geo-object source.
730     * @param style style to save
731     * @param geoObjectURL URL of the (already read) raster object
732     */
733     public static void saveStyledLayerStyle(StyledLayerStyle<?> style, URL geoObjectURL) throws Exception {
734     if ( style.getMetaData() instanceof RasterLegendData )
735     saveStyledLayerStyle(style,geoObjectURL, "sld", "rld");
736     else
737     saveStyledLayerStyle(style,geoObjectURL, "sld", "amd");
738     }
739 alfonx 397
740    
741 alfonx 244
742 alfonx 397 /**
743     * Creates a {@link Box} that shows a legend for a list of
744     * {@link FeatureTypeStyle}s and a targeted featureType
745     *
746     * @param featureType
747     * If this a legend for Point, Polygon or Line?
748     * @param list
749     * The Styles to presented in this legend
750     *
751     * @author <a href="mailto:[email protected]">Stefan Alfons
752     * Kr&uuml;ger</a>
753     */
754     public static Box createLegendPanel(List<FeatureTypeStyle> list,
755     SimpleFeatureType featureType, int iconWidth, int iconHeight) {
756    
757     Box box = new Box(BoxLayout.Y_AXIS) {
758    
759     /**
760     * Nuetzlich wenn die Componente gedruckt (z.B. wenn ein Screenshot
761     * gemacht wird) wird. Dann werden wird der Hintergrund auf WEISS
762     * gesetzt.
763     *
764     * @author <a href="mailto:[email protected]">Stefan Alfons
765     * Kr&uuml;ger</a>
766     */
767     @Override
768     public void print(Graphics g) {
769     final Color orig = getBackground();
770     setBackground(Color.WHITE);
771     // wrap in try/finally so that we always restore the state
772     try {
773     super.print(g);
774     } finally {
775     setBackground(orig);
776     }
777     }
778     };
779    
780     for (FeatureTypeStyle ftStyle : list) {
781    
782     // One child-node for every rule
783     List<Rule> rules = ftStyle.rules();
784     for (Rule rule : rules) {
785    
786     /**
787     * Let's not create a hbox for Rules that only contain
788     * TextSymbolizers
789     */
790     if (StylingUtil.getTextSymbolizers(rule.getSymbolizers())
791     .size() == rule.getSymbolizers().length)
792     continue;
793    
794     Box hbox = new Box(BoxLayout.X_AXIS) {
795    
796     /**
797     * Nuetzlich wenn die Componente gedruckt (z.B. wenn ein
798     * Screenshot gemacht wird) wird. Dann werden wird der
799     * Hintergrund auf WEISS gesetzt.
800     *
801     * @author <a href="mailto:[email protected]">Stefan
802     * Alfons Kr&uuml;ger</a>
803     */
804     @Override
805     public void print(Graphics g) {
806     final Color orig = getBackground();
807     setBackground(Color.WHITE);
808     // wrap in try/finally so that we always restore the
809     // state
810     try {
811     super.print(g);
812     } finally {
813     setBackground(orig);
814     }
815     }
816     };
817    
818     /**
819     * The size of the legend Symbol is dependent on the size of the
820     * font.
821     */
822     final int fontHeight = new JLabel().getFontMetrics(
823     new JLabel().getFont()).getHeight();
824    
825     final Dimension ICON_SIZE = new Dimension(iconWidth,
826     fontHeight > 5 ? fontHeight : iconHeight);
827    
828     // ****************************************************************************
829     // Create the actual icon
830     // ****************************************************************************
831     final BufferedImage imageForRule = LegendIconFeatureRenderer
832     .getInstance().createImageForRule(rule, featureType,
833     ICON_SIZE);
834    
835     // LOGGER.debug("Creating a new Legend Image for RUle name =
836     // "+rule.getName());
837    
838     ImageIcon legendIcon = new ImageIcon(imageForRule);
839    
840     final JLabel iconLabel = new JLabel(legendIcon);
841     hbox.setAlignmentX(0f);
842     hbox.add(iconLabel);
843     hbox.add(Box.createHorizontalStrut(3));
844    
845     // ****************************************************************************
846     // The labeltext is read from the SLD. Its either the title
847     // directly, or interpreted as OneLine Code
848     // ****************************************************************************
849     // final String rawText =
850     // rule.getDescription().getTitle().toString();
851     final String rawText = rule.getDescription().getTitle().toString();
852    
853     Translation labelT = new Translation();
854     labelT.fromOneLine(rawText);
855    
856     final JLabel classTitleLabel = new JLabel(labelT.toString());
857     hbox.add(classTitleLabel);
858     classTitleLabel.setLabelFor(iconLabel);
859    
860     box.add(hbox);
861    
862     }
863     }
864    
865     return box;
866     }
867    
868    
869     /**
870     * Creates a
871     * @param styledGrid
872     * @param iconHeight
873     * @param iconWidth
874     * @return
875     */
876     public static Box createLegendPanel(StyledRasterInterface<?> styledGrid, int iconWidth, int iconHeight) {
877     throw new RuntimeException("Not yet...");
878     }
879    
880    
881 alfonx 244 }

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26