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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2 - (show annotations)
Tue Feb 24 22:43:52 2009 UTC (16 years ago) by mojays
Original Path: trunk/src/skrueger/geotools/StyledMapUtil.java
File size: 28445 byte(s)
First Commit, corresponds to Revision 1008 of Wikisquare-SVN
includes:
- schmitzm.* (except schmitzm.test)
- org.geotools.* (all overridden classes)
- skrueger.geotools
- skrueger.i8n
- skrueger.swing
- appl.data.LateLoadable (dependency in SCHMITZM)
- appl.data.LoadingException (dependency in SCHMITZM)
- appl.util.RasterMetaData (dependency in SCHMITZM)

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26