/[schmitzm]/trunk/src/skrueger/geotools/StyledMapUtil.java
ViewVC logotype

Contents of /trunk/src/skrueger/geotools/StyledMapUtil.java

Parent Directory Parent Directory | Revision Log Revision Log


Revision 52 - (show annotations)
Fri Apr 17 13:57:14 2009 UTC (15 years, 10 months ago) by mojays
File size: 29194 byte(s)


1 package skrueger.geotools;
2
3 import java.text.DecimalFormat;
4 import java.util.Map;
5 import java.util.HashMap;
6 import java.util.List;
7 import java.util.SortedMap;
8 import java.util.TreeMap;
9 import java.net.URL;
10
11 import org.geotools.feature.FeatureCollection;
12 import org.geotools.map.MapLayer;
13 import org.geotools.map.DefaultMapLayer;
14 import org.geotools.coverage.grid.GridCoverage2D;
15 import org.geotools.coverage.grid.io.AbstractGridCoverage2DReader;
16 import org.geotools.data.FeatureSource;
17 import org.geotools.styling.ColorMap;
18 import org.geotools.styling.ColorMapEntry;
19 import org.geotools.styling.Style;
20
21 import org.apache.log4j.Logger;
22
23 import org.jdom.Element;
24 import org.jdom.Document;
25 import org.jdom.input.SAXBuilder;
26 import org.jdom.output.XMLOutputter;
27
28 import schmitzm.geotools.styling.StylingUtil;
29 import skrueger.AttributeMetaData;
30 import skrueger.RasterLegendData;
31 import skrueger.i8n.Translation;
32 import schmitzm.io.IOUtil;
33 import java.io.File;
34 import java.io.FileNotFoundException;
35 import schmitzm.lang.LangUtil;
36 import schmitzm.swing.SwingUtil;
37
38 import java.io.FileWriter;
39
40 /**
41 * This class provides static helper methods for dealing with
42 * {@link StyledMapInterface} stuff.
43 * @author <a href="mailto:[email protected]">Martin Schmitz</a> (University of Bonn/Germany)
44 * @version 1.0
45 */
46 public class StyledMapUtil {
47 private static final Logger LOGGER = Logger.getLogger(StyledMapUtil.class.getName());
48 private static final SAXBuilder SAX_BUILDER = new SAXBuilder();
49 private static final XMLOutputter XML_OUTPUTTER = new XMLOutputter();
50
51 /** URL for Atlas XML schema */
52 public static final String AMLURI = "http://www.wikisquare.de/AtlasML";
53 /** Name of the XML Element for the attribute meta data map */
54 public static final String ELEM_NAME_AMD = "attributeMetaData";
55 /** Name of the XML Element for the raster legend data */
56 public static final String ELEM_NAME_RLD = "rasterLegendData";
57 /** Name of the XML Element for an attribute meta data map entry */
58 public static final String ELEM_NAME_ATTRIBUTE = "dataAttribute";
59 /** Name of the XML Element for an raster legend data entry */
60 public static final String ELEM_NAME_RASTERLEGEND = "rasterLegendItem";
61 /** Name of the XML Element for a translation */
62 public static final String ELEM_NAME_TRANSLATION = "translation";
63
64 /**
65 * Creates a Geotools {@link MapLayer} from an object. If the object is a
66 * {@link StyledMapInterface} then its sytle is used. In case of direct
67 * Geotools objects ({@link GridCoverage2D}, {@link AbstractGridCoverage2DReader},
68 * {@link FeatureCollection}) a default style is generated.
69 * @param object an Object
70 * @exception Exception if {@code null} is given as object or an error occurs during layer creation
71 */
72 public static MapLayer createMapLayer(Object object) throws Exception {
73 return createMapLayer(object,null);
74 }
75
76 /**
77 * Creates a Geotools {@link MapLayer} from an object. If the object is a
78 * {@link StyledMapInterface} then its sytle is used. In case of direct
79 * Geotools objects ({@link GridCoverage2D}, {@link AbstractGridCoverage2DReader},
80 * {@link FeatureCollection}) a default style is generated.
81 * @param object an Object
82 * @param forcedStyle (SLD-)Style to force for the object
83 * @exception Exception if {@code null} is given as object or an error occurs during layer creation
84 */
85 public static MapLayer createMapLayer(Object object, Style forcedStyle) throws Exception {
86 MapLayer layer = null;
87 Style style = null;
88 if ( object instanceof StyledMapInterface ) {
89 style = ((StyledMapInterface<?>)object).getStyle();
90 object = ((StyledMapInterface<?>)object).getGeoObject();
91 }
92 if ( forcedStyle != null )
93 style = forcedStyle;
94 if ( style == null )
95 style = StylingUtil.createDefaultStyle(object);
96
97 if (object instanceof GridCoverage2D)
98 layer = new DefaultMapLayer( (GridCoverage2D) object, style);
99 if (object instanceof AbstractGridCoverage2DReader)
100 layer = new DefaultMapLayer( (AbstractGridCoverage2DReader) object, style);
101 if (object instanceof FeatureCollection)
102 layer = new DefaultMapLayer( (FeatureCollection) object, style);
103
104 if ( layer == null )
105 throw new Exception("Can not create MapLayer from "+(object == null ? "null" : object.getClass()));
106
107 return layer;
108 }
109
110 /**
111 * Creates an default instance of {@link StyledMapInterface} for a Geotools
112 * object ({@link GridCoverage2D}, {@link FeatureCollection}) with a default
113 * style.
114 * @param object an Object
115 * @param title title for the object
116 * @exception UnsupportedOperationException if {@code null} is given as object or an error occurs during creation
117 */
118 public static StyledMapInterface<?> createStyledMap(Object object, String title) {
119 return createStyledMap(object, title, null);
120 }
121
122 /**
123 * Creates an default instance of {@link StyledMapInterface} for a Geotools
124 * object ({@link GridCoverage2D}, {@link FeatureCollection}) with a given
125 * style.
126 * @param object an Object
127 * @param title title for the object
128 * @param style style and meta data for the object
129 * @exception UnsupportedOperationException if {@code null} is given as object or an error occurs during creation
130 */
131 public static StyledMapInterface<?> createStyledMap(Object object, String title, StyledMapStyle style) {
132 StyledMapInterface<?> styledObject = null;
133
134 String id = (title != null) ? title : "defaultID";
135
136 if ( object instanceof GridCoverage2D )
137 styledObject = new StyledGridCoverage(
138 (GridCoverage2D)object,
139 id,
140 title,
141 style
142 );
143 else if ( object instanceof AbstractGridCoverage2DReader )
144 styledObject = new StyledGridCoverageReader(
145 (AbstractGridCoverage2DReader)object,
146 id,
147 title,
148 style
149 );
150 else if ( object instanceof FeatureCollection )
151 styledObject = new StyledFeatureCollection(
152 (FeatureCollection)object,
153 id,
154 title,
155 style
156 );
157
158 if ( styledObject == null )
159 throw new UnsupportedOperationException("Can not create StyledMapInterface object from "+(object == null ? "null" : object.getClass()));
160
161 return styledObject;
162 }
163
164 /**
165 * Return only the visible or invisible entries of an AttributeMetaData-Map.
166 * @param amdMap AttributeMetaData-Map
167 * @param visible indicated whether the visible or invisible entries are
168 * returned
169 */
170 public static Map<Integer,AttributeMetaData> getVisibleAttributeMetaData(Map<Integer,AttributeMetaData> amdMap, boolean visible) {
171 SortedMap<Integer,AttributeMetaData> filteredMap = new TreeMap<Integer,AttributeMetaData>();
172 for (AttributeMetaData amd : amdMap.values())
173 if ( amd.isVisible() )
174 filteredMap.put(amd.getColIdx(), amd);
175
176 return filteredMap;
177 }
178
179
180 /**
181 * Parses a {@link AttributeMetaData} object from an JDOM-{@link Element}.
182 * This method works like {@link AMLImport#parseDataAttribute(org.w3c.dom.Node},
183 * but for JDOM.
184 * @param element {@link Element} to parse
185 */
186 public static AttributeMetaData parseAttributeMetaData(final Element element) {
187 final Integer col = Integer.valueOf(element.getAttributeValue("col"));
188 final Boolean visible = Boolean.valueOf(element.getAttributeValue("visible"));
189 final String unit = element.getAttributeValue("unit");
190
191 Translation name = new Translation();
192 Translation desc = new Translation();
193 for (final Element childElement : (List<Element>)element.getChildren()) {
194 if (childElement.getName() == null)
195 continue;
196
197 if (childElement.getName().equals("name"))
198 name = parseTranslation(childElement);
199 else if (childElement.getName().equals("desc"))
200 desc = parseTranslation(childElement);
201 }
202 return new AttributeMetaData(col, visible, name, desc, unit);
203 }
204
205 /**
206 * Parses a {@link AttributeMetaData} map from an JDOM-{@link Element}
207 * with {@code <attribute>}-childs.
208 * @param element {@link Element} to parse
209 */
210 public static Map<Integer,AttributeMetaData> parseAttributeMetaDataMap(final Element element) {
211 HashMap<Integer,AttributeMetaData> metaData = new HashMap<Integer,AttributeMetaData>();
212 List<Element> attributesElements = element.getChildren( ELEM_NAME_ATTRIBUTE );
213 for (Element attibuteElement : attributesElements)
214 {
215 AttributeMetaData attrMetaData = parseAttributeMetaData( attibuteElement );
216 metaData.put( attrMetaData.getColIdx(), attrMetaData );
217 }
218 return metaData;
219 }
220
221 /**
222 * Loads a {@link AttributeMetaData} object from an URL.
223 * @param documentUrl {@link URL} to parse
224 * @see #parseAttributeMetaData(Element)
225 */
226 public static Map<Integer,AttributeMetaData> loadAttributeMetaDataMap(final URL documentUrl) throws Exception {
227 Document document = SAX_BUILDER.build(documentUrl);
228 return parseAttributeMetaDataMap( document.getRootElement() );
229 }
230
231 /**
232 * Creates an JDOM {@link Element} for the given {@link AttributeMetaData}
233 * object.
234 * @param amd meta data for one attribute
235 */
236 public static Element createAttributeMetaDataElement(final AttributeMetaData amd) {
237 final Element element = new Element( ELEM_NAME_ATTRIBUTE , AMLURI);
238 element.setAttribute("col", String.valueOf( amd.getColIdx() ) );
239 element.setAttribute("visible", String.valueOf( amd.isVisible() ) );
240 element.setAttribute("unit", amd.getUnit() );
241 // Creating a aml:name tag...
242 element.addContent( createTranslationElement("name", amd.getTitle()) );
243 // Creating a aml:desc tag...
244 element.addContent( createTranslationElement("desc", amd.getDesc()) );
245 return element;
246 }
247
248 /**
249 * Creates an JDOM {@link Element} for the given {@link AttributeMetaData}
250 * map.
251 * @param amdMap map of attribute meta data
252 */
253 public static Element createAttributeMetaDataMapElement(final Map<Integer,AttributeMetaData> amdMap) {
254 final Element element = new Element( ELEM_NAME_AMD , AMLURI);
255 for (AttributeMetaData amd : amdMap.values())
256 element.addContent( createAttributeMetaDataElement( amd ) );
257 return element;
258 }
259
260 /**
261 * Saves a {@link AttributeMetaData AttributeMetaData-Map} to an URL.
262 * @param amdMap map of {@link AttributeMetaData}
263 * @param documentUrl {@link URL} to store the XML
264 */
265 public static void saveAttributeMetaDataMap(final Map<Integer,AttributeMetaData> amdMap, final URL documentUrl) throws Exception {
266 // Create XML-Document
267 final FileWriter out = new FileWriter( new File(documentUrl.toURI()) );
268 XML_OUTPUTTER.output(
269 createAttributeMetaDataMapElement(amdMap),
270 out
271 );
272 out.flush();
273 out.close();
274 }
275
276
277
278 /**
279 * Parses a {@link RasterLegendData} object from an JDOM-{@link Element}.
280 * This method works like {@link AMLImport#parseRasterLegendData(org.w3c.dom.Node},
281 * but for JDOM.
282 * @param element {@link Element} to parse
283 */
284 public static RasterLegendData parseRasterLegendData(Element element) {
285
286 final boolean paintGaps = Boolean.valueOf( element.getAttributeValue("paintGaps") );
287
288 RasterLegendData rld = new RasterLegendData(paintGaps);
289
290 for ( Element childElement : (List<Element>)element.getChildren() ) {
291 final String name = childElement.getName();
292 // Cancel if it's an attribute
293 if ( childElement.getChildren().size() == 0 )
294 continue;
295
296 if (name.equals( ELEM_NAME_RASTERLEGEND )) {
297 final String valueAttr = childElement.getAttributeValue("value");
298 if ( valueAttr == null )
299 throw new UnsupportedOperationException("Attribute 'value' missing for definition of <"+ELEM_NAME_RASTERLEGEND+">");
300 final double value = Double.valueOf(valueAttr);
301
302 // first and only item should be the label
303 final Element labelElement = childElement.getChild("label");
304 // id label element is missing, the translation is searched directly
305 // as childs of the rasterLegendItem element
306 Translation label = parseTranslation( labelElement != null ? labelElement : childElement );
307 rld.put(value, label);
308 }
309 }
310
311 return rld;
312 }
313
314 /**
315 * Loads a {@link RasterLegendData} object from an URL.
316 * @param documentUrl {@link URL} to parse
317 * @see #parseAttributeMetaData(Element)
318 */
319 public static RasterLegendData loadRasterLegendData(final URL documentUrl) throws Exception {
320 Document document = SAX_BUILDER.build(documentUrl);
321 return parseRasterLegendData( document.getRootElement() );
322 }
323
324 /**
325 * Creates an JDOM {@link Element} for the given {@link RasterLegendData}
326 * map.
327 * @param rld raster legend data
328 */
329 public static Element createRasterLegendDataElement(final RasterLegendData rld) {
330 final Element element = new Element( ELEM_NAME_RLD , AMLURI);
331 element.setAttribute("paintGaps", rld.isPaintGaps().toString());
332 for (Double key : rld.getSortedKeys()) {
333 Element item = new Element( ELEM_NAME_RASTERLEGEND, AMLURI);
334 item.setAttribute("value", key.toString());
335 item.addContent( createTranslationElement("label", rld.get(key)) );
336 element.addContent(item);
337 }
338 return element;
339 }
340
341 /**
342 * Creates {@link RasterLegendData} from a {@link ColorMap}.
343 * @param colorMap a color map
344 * @param paintGaps indicated whether gaps are painted between the legend items
345 * @param digits number of digits the grid value classes (and legend) are
346 * rounded to (null means no round; >= 0 means digits after comma;
347 * < 0 means digits before comma) */
348 public static RasterLegendData generateRasterLegendData(ColorMap colorMap, boolean paintGaps, Integer digits) {
349 DecimalFormat decFormat = digits != null ? new DecimalFormat( SwingUtil.getNumberFormatPattern(digits) ) : null;
350 RasterLegendData rld = new RasterLegendData(paintGaps);
351 for (ColorMapEntry cme : colorMap.getColorMapEntries())
352 {
353 double value = StylingUtil.getQuantityFromColorMapEntry(cme);
354 String label = cme.getLabel();
355 // if no label is set (e.g. quantitative style),
356 // use the value as label
357 if ( label == null || label.equals("") )
358 if ( digits == null )
359 label = String.valueOf(value);
360 else
361 label = decFormat.format( LangUtil.round(value, digits) );
362 rld.put( value, new Translation(" "+label) );
363 }
364 return rld;
365 }
366
367 /**
368 * Creates {@link RasterLegendData} from the {@link ColorMap} of a style.
369 * @param style a raster style (must contain a {@link RasterSymbolizer})
370 * @param paintGaps indicated whether gaps are painted between the legend items
371 * @param digits number of digits the grid value classes (and legend) are
372 * rounded to (null means no round; >= 0 means digits after comma;
373 * < 0 means digits before comma) */
374 public static RasterLegendData generateRasterLegendData(Style style, boolean paintGaps, Integer digits) {
375 ColorMap colorMap = StylingUtil.getColorMapFromStyle(style);
376 if ( colorMap == null)
377 throw new IllegalArgumentException("Color map can not be determined from style!");
378 return generateRasterLegendData(colorMap, paintGaps, digits);
379 }
380
381 /**
382 * Saves a {@link RasterLegendData} to an URL.
383 * @param rld raster legend data
384 * @param documentUrl {@link URL} to store the XML
385 */
386 public static void saveRasterLegendData(final RasterLegendData rld, final URL documentUrl) throws Exception {
387 // Create XML-Document
388 final FileWriter out = new FileWriter( new File(documentUrl.toURI()) );
389 XML_OUTPUTTER.output(
390 createRasterLegendDataElement(rld),
391 out
392 );
393 out.flush();
394 out.close();
395 }
396
397 /**
398 * Parses a {@link Translation} object from an JDOM-{@link Element}.
399 * This method works like {@link AMLImport#parseTranslation(org.w3c.dom.Node},
400 * but for JDOM.
401 * @param element {@link Element} to parse
402 */
403 public final static Translation parseTranslation(final Element element) {
404 Translation trans = new Translation();
405
406 if (element == null)
407 return trans;
408
409 for (final Element translationElement : (List<Element>)element.getChildren()) {
410 final String name = translationElement.getName();
411 if (name == null)
412 continue;
413
414 // lang attribute
415 String lang = translationElement.getAttributeValue("lang");
416 // set the default, if no language code is set
417 if ( lang == null )
418 lang = Translation.DEFAULT_KEY;
419
420 final String translationText = translationElement.getValue();
421 if (translationText == null)
422 trans.put(lang, "");
423 else
424 trans.put(lang, translationText);
425 }
426
427 // if no <translation> is given, the value of the node should
428 // be used as a default translation
429 if (trans.size() == 0)
430 trans.put( Translation.DEFAULT_KEY, element.getValue() );
431 // trans = new Translation( ((List<Element>)element.getChildren()).get(0).getValue() );
432
433 return trans;
434 }
435
436 /**
437 * Creates an JDOM {@link Element} for the given {@link Translation}.
438 * @param tagname Name of the Element
439 * @param translation Translation to store in the Element
440 */
441 public final static Element createTranslationElement(String tagname, Translation translation) {
442 Element element = new Element(tagname, AMLURI);
443 if ( translation == null )
444 throw new UnsupportedOperationException("Translation element can not be created from null!");
445
446 // If only a default translation is set, the <translation lang="..">..</tranlation>
447 // part is not used
448 if (translation.keySet().size() == 1 && translation.get(Translation.DEFAULT_KEY) != null) {
449 element.addContent( translation.get(Translation.DEFAULT_KEY) );
450 return element;
451 }
452
453 // add a <translation lang="..">..</tranlation> part to the element for
454 // all languages
455 for (String lang : translation.keySet()) {
456 Element translationElement = new Element( ELEM_NAME_TRANSLATION , AMLURI);
457 translationElement.setAttribute("lang", lang);
458 String translationString = translation.get(lang);
459 if (translationString == null)
460 translationString = "";
461 translationElement.addContent( translationString );
462 element.addContent(translationElement);
463 }
464
465 return element;
466 }
467
468
469 /**
470 * Sets a style to {@link StyledMapInterface}.
471 * @param styledObject a styled object
472 * @param style a Style
473 */
474 public static void setStyledMapStyle(StyledMapInterface styledObject, StyledMapStyle<?> style) {
475 // set SLD style
476 styledObject.setStyle( style.getGeoObjectStyle() );
477 // set meta data
478 if ( styledObject instanceof StyledGridCoverageInterface &&
479 (style.getMetaData() instanceof RasterLegendData || style.getMetaData() == null) ) {
480 RasterLegendData sourceRld = (RasterLegendData)style.getMetaData();
481 RasterLegendData destRld = ((StyledGridCoverageInterface)styledObject).getLegendMetaData();
482 if ( destRld != null && sourceRld != null ) {
483 destRld.setPaintGaps(sourceRld.isPaintGaps());
484 destRld.clear();
485 destRld.putAll( sourceRld );
486 }
487 return;
488 }
489 if ( styledObject instanceof StyledFeatureCollectionInterface &&
490 (style.getMetaData() instanceof Map || style.getMetaData() == null) ) {
491 Map<Integer, AttributeMetaData> sourceAmd = (Map<Integer, AttributeMetaData>)style.getMetaData();
492 Map<Integer, AttributeMetaData> destAmd = ((StyledFeatureCollectionInterface)styledObject).getAttributeMetaDataMap();
493 if ( destAmd != null && sourceAmd != null ) {
494 destAmd.clear();
495 destAmd.putAll( sourceAmd );
496 }
497 return;
498 }
499
500 throw new UnsupportedOperationException("Style is not compatible to object: " +
501 (style.getMetaData() == null ? null : style.getMetaData().getClass().getSimpleName()) +
502 " <-> " +
503 (styledObject == null ? null : styledObject.getClass().getSimpleName()));
504 }
505
506 /**
507 * Returns the style a {@link StyledMapInterface} as a {@link StyledMapStyle}.
508 * @param styledObject a styled object
509 * @return {@code StyledMapStyle<RasterLegendData>} for {@link StyledGridCoverageInterface}
510 * or {@code StyledMapStyle<Map<Integer,AttributeMetaData>>} for
511 * {@link StyledFeatureCollectionInterface}
512 */
513 public static StyledMapStyle<?> getStyledMapStyle(StyledMapInterface styledObject) {
514 if ( styledObject instanceof StyledGridCoverageInterface )
515 return getStyledMapStyle( (StyledGridCoverageInterface)styledObject );
516 if ( styledObject instanceof StyledFeatureCollectionInterface )
517 return getStyledMapStyle( (StyledFeatureCollectionInterface)styledObject );
518 throw new UnsupportedOperationException("Unknown type of StyledMapInterface: "+(styledObject == null ? null : styledObject.getClass().getSimpleName()));
519 }
520
521 /**
522 * Returns the style and raster meta data of a {@link StyledGridCoverageInterface}
523 * as a {@link StyledMapStyle}.
524 * @param styledGC a styled grid coverage
525 */
526 public static StyledMapStyle<RasterLegendData> getStyledMapStyle(StyledGridCoverageInterface styledGC) {
527 return new StyledMapStyle<RasterLegendData>(
528 styledGC.getStyle(),
529 styledGC.getLegendMetaData()
530 );
531 }
532
533 /**
534 * Returns the style and attribute meta data of a {@link StyledFeatureCollectionInterface}
535 * as a {@link StyledMapStyle}.
536 * @param styledFC a styled feature collection
537 */
538 public static StyledMapStyle<Map<Integer,AttributeMetaData>> getStyledMapStyle(StyledFeatureCollectionInterface styledFC) {
539 return new StyledMapStyle<Map<Integer,AttributeMetaData>>(
540 styledFC.getStyle(),
541 styledFC.getAttributeMetaDataMap()
542 );
543 }
544
545 /**
546 * Loads a {@linkplain Style SLD-Style} and {@linkplain RasterLegendData Raster-LegendData}
547 * for a given geo-object (raster) source. The SLD file must be present. A missing
548 * raster legend-data file is tolerated.
549 * @param geoObjectURL URL of the (already read) raster object
550 * @param sldExt file extention for the SLD file
551 * @param rldExt file extention for the raster legend-data file
552 * @return {@code null} in case of any error
553 */
554 public static StyledMapStyle<RasterLegendData> loadStyledRasterStyle(URL geoObjectURL, String sldExt, String rldExt) {
555 RasterLegendData metaData = null;
556 Style sldStyle = null;
557 try {
558 Style[] styles = StylingUtil.loadSLD(IOUtil.changeUrlExt(geoObjectURL, sldExt));
559 // SLD must be present
560 if ( styles == null || styles.length == 0 )
561 return null;
562 sldStyle = styles[0];
563 }
564 catch (Exception err) {
565 // SLD must be present
566 LangUtil.logDebugError(LOGGER,err);
567 return null;
568 }
569
570 try {
571 metaData = StyledMapUtil.loadRasterLegendData( IOUtil.changeUrlExt(geoObjectURL,rldExt) );
572 } catch (FileNotFoundException err) {
573 // ignore missing raster legend data
574 } catch (Exception err) {
575 // any other error during legend data creation leads to error
576 LangUtil.logDebugError(LOGGER,err);
577 return null;
578 }
579 return new StyledMapStyle<RasterLegendData>(sldStyle, metaData);
580 }
581
582 /**
583 * Loads a {@linkplain Style SLD-Style} from a {@code .sld} file and
584 * {@linkplain RasterLegendData Raster-LegendData} from a {@code .rld} file
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 StyledMapStyle<RasterLegendData> loadStyledRasterStyle(URL geoObjectURL) {
593 return loadStyledRasterStyle(geoObjectURL, "sld", "rld");
594 }
595
596 /**
597 * Loads a {@linkplain Style SLD-Style} and a {@linkplain AttributeMetaData AttributeMetaData-Map}
598 * for a given geo-object (feature) source. The SLD file must be present. A missing
599 * attribute meta-data file is tolerated.
600 * @param geoObjectURL URL of the (already read) feature object
601 * @param sldExt file extention for the SLD file
602 * @param rldExt file extention for the raster legend-data file
603 * @return {@code null} in case of any error
604 */
605 public static StyledMapStyle<Map<Integer,AttributeMetaData>> loadStyledFeatureStyle(URL geoObjectURL, String sldExt, String rldExt) {
606 Map<Integer,AttributeMetaData> metaData = null;
607 Style sldStyle = null;
608 try {
609 Style[] styles = StylingUtil.loadSLD(IOUtil.changeUrlExt(geoObjectURL, sldExt));
610 // SLD must be present
611 if ( styles == null || styles.length == 0 )
612 return null;
613 sldStyle = styles[0];
614 } catch (Exception err) {
615 // SLD must be present
616 LangUtil.logDebugError(LOGGER,err);
617 return null;
618 }
619
620 try {
621 metaData = StyledMapUtil.loadAttributeMetaDataMap( IOUtil.changeUrlExt(geoObjectURL,rldExt) );
622 } catch (FileNotFoundException err) {
623 // ignore missing attribute meta data
624 } catch (Exception err) {
625 // any other error during meta data creation leads to error
626 LangUtil.logDebugError(LOGGER,err);
627 return null;
628 }
629
630 return new StyledMapStyle<Map<Integer,AttributeMetaData>>(sldStyle, metaData);
631 }
632
633 /**
634 * Loads a {@linkplain Style SLD-Style} from a {@code .sld} file and
635 * {@linkplain AttributeMetaData AttributeMetaData-Map} from a {@code .amd} file
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 StyledMapStyle<Map<Integer,AttributeMetaData>> loadStyledFeatureStyle(URL geoObjectURL) {
644 return loadStyledFeatureStyle(geoObjectURL, "sld", "amd");
645 }
646
647 /**
648 * Stores a {@linkplain Style SLD-Style} and {@linkplain RasterLegendData Raster-LegendData}
649 * for a given geo-object (raster) source.
650 * @param style style to save
651 * @param geoObjectURL URL of the raster object
652 * @param sldExt file extention for the SLD file
653 * @param mdExt file extention for the meta-data file
654 */
655 public static <T> void saveStyledMapStyle(StyledMapStyle<T> style, URL geoObjectURL, String sldExt, String mdExt) throws Exception {
656 // Store the SLD
657 Style sldStyle = style.getGeoObjectStyle();
658 if ( sldStyle != null ) {
659 StylingUtil.saveStyleToSLD(
660 sldStyle,
661 IOUtil.changeFileExt(
662 new File(geoObjectURL.toURI()),
663 sldExt
664 )
665 );
666 }
667
668 // Store the meta data
669 T metaData = style.getMetaData();
670 if ( metaData != null ) {
671 if ( metaData instanceof RasterLegendData ) {
672 saveRasterLegendData(
673 (RasterLegendData)metaData,
674 IOUtil.changeUrlExt(geoObjectURL,mdExt)
675 );
676 // } else if ( metaData instanceof Map<Integer,AttributeMetaData> ) { // LEIDER NICHT KOMPILIERBAR!!
677 } else if ( metaData instanceof Map ) {
678 saveAttributeMetaDataMap(
679 (Map<Integer,AttributeMetaData>)metaData,
680 IOUtil.changeUrlExt(geoObjectURL,mdExt)
681 );
682 } else
683 throw new UnsupportedOperationException("Export for meta data not yet supported: "+metaData.getClass().getSimpleName());
684 }
685 }
686
687 /**
688 * Stores the {@linkplain Style SLD-Style} to a {@code .sld} file and
689 * the meta data ({@link RasterLegendData} or {@link AttributeMetaData})
690 * to a {@code .rld} or {@code .amd} file.
691 * for a given geo-object source.
692 * @param style style to save
693 * @param geoObjectURL URL of the (already read) raster object
694 */
695 public static void saveStyledMapStyle(StyledMapStyle<?> style, URL geoObjectURL) throws Exception {
696 if ( style.getMetaData() instanceof RasterLegendData )
697 saveStyledMapStyle(style,geoObjectURL, "sld", "rld");
698 else
699 saveStyledMapStyle(style,geoObjectURL, "sld", "amd");
700 }
701
702 }

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26