001: /*
002: * GeoTools - OpenSource mapping toolkit
003: * http://geotools.org
004: * (C) 2002-2006, GeoTools Project Managment Committee (PMC)
005: *
006: * This library is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation;
009: * version 2.1 of the License.
010: *
011: * This library is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * Lesser General Public License for more details.
015: *
016: * Created on 13 November 2002, 13:47
017: */
018: package org.geotools.styling;
019:
020: import org.geotools.event.AbstractGTComponent;
021: import org.geotools.factory.CommonFactoryFinder;
022: import org.geotools.factory.GeoTools;
023: import org.opengis.filter.FilterFactory;
024: import org.opengis.filter.expression.Expression;
025:
026: /**
027: * DOCUMENT ME!
028: *
029: * @author iant
030: * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/library/main/src/main/java/org/geotools/styling/RasterSymbolizerImpl.java $
031: */
032: public class RasterSymbolizerImpl extends AbstractGTComponent implements
033: RasterSymbolizer {
034: // TODO: make container ready
035: private FilterFactory filterFactory;
036: private ChannelSelection channelSelection = new ChannelSelectionImpl();
037: private ColorMap colorMap = new ColorMapImpl();
038: private ContrastEnhancement contrastEnhancement = new ContrastEnhancementImpl();
039: private ShadedRelief shadedRelief = new ShadedReliefImpl();
040: private String geometryName = "raster";
041: private Symbolizer symbolizer;
042: private Expression opacity;
043: private Expression overlap;
044:
045: public RasterSymbolizerImpl() {
046: this (CommonFactoryFinder.getFilterFactory(GeoTools
047: .getDefaultHints()));
048: }
049:
050: public RasterSymbolizerImpl(FilterFactory factory) {
051: filterFactory = factory;
052: opacity = filterFactory.literal(1.0);
053: overlap = filterFactory.literal("Random");
054: }
055:
056: public int hashcode() {
057: int key = 0;
058: key = channelSelection.hashCode();
059: key = (key * 13) + colorMap.hashCode();
060: key = (key * 13) + contrastEnhancement.hashCode();
061: key = (key * 13) + shadedRelief.hashCode();
062: key = (key * 13) + opacity.hashCode();
063: key = (key * 13) + overlap.hashCode();
064: key = (key * 13) + geometryName.hashCode();
065:
066: return key;
067: }
068:
069: /**
070: * The ChannelSelection element specifies the false-color channel selection
071: * for a multi-spectral raster source (such as a multi-band
072: * satellite-imagery source). Either a channel may be selected to display
073: * in each of red, green, and blue, or a single channel may be selected to
074: * display in grayscale. (The spelling ?gray? is used since it seems to
075: * be more common on the Web than ?grey? by a ratio of about 3:1.)
076: * Contrast enhancement may be applied to each channel in isolation.
077: * Channels are identified by a system and data-dependent character
078: * identifier. Commonly, channels will be labelled as ?1?, ?2?, etc.
079: *
080: * @return the ChannelSelection object set or null if none is available.
081: */
082: public ChannelSelection getChannelSelection() {
083: return channelSelection;
084: }
085:
086: /**
087: * The ColorMap element defines either the colors of a palette-type raster
088: * source or the mapping of fixed-numeric pixel values to colors. For
089: * example, a DEM raster giving elevations in meters above sea level can
090: * be translated to a colored image with a ColorMap. The quantity
091: * attributes of a color-map are used for translating between numeric
092: * matrixes and color rasters and the ColorMap entries should be in order
093: * of increasing numeric quantity so that intermediate numeric values can
094: * be matched to a color (or be interpolated between two colors). Labels
095: * may be used for legends or may be used in the future to match character
096: * values. Not all systems can support opacity in colormaps. The default
097: * opacity is 1.0 (fully opaque). Defaults for quantity and label are
098: * system-dependent.
099: *
100: * @return the ColorMap for the raster
101: */
102: public ColorMap getColorMap() {
103: return colorMap;
104: }
105:
106: /**
107: * The ContrastEnhancement element defines contrast enhancement for a
108: * channel of a false-color image or for a color image. In the case of a
109: * color image, the relative grayscale brightness of a pixel color is
110: * used. ?Normalize? means to stretch the contrast so that the dimmest
111: * color is stretched to black and the brightest color is stretched to
112: * white, with all colors in between stretched out linearly. ?Histogram?
113: * means to stretch the contrast based on a histogram of how many colors
114: * are at each brightness level on input, with the goal of producing equal
115: * number of pixels in the image at each brightness level on output. This
116: * has the effect of revealing many subtle ground features. A ?GammaValue?
117: * tells how much to brighten (value greater than 1.0) or dim (value less
118: * than 1.0) an image. The default GammaValue is 1.0 (no change). If none
119: * of Normalize, Histogram, or GammaValue are selected in a
120: * ContrastEnhancement, then no enhancement is performed.
121: *
122: * @return the ContrastEnhancement
123: */
124: public ContrastEnhancement getContrastEnhancement() {
125: return contrastEnhancement;
126: }
127:
128: /**
129: * The interpretation of Geometry is system-dependent, as raster data may
130: * be organized differently from feature data, though omitting this
131: * element selects the default raster-data source. Geometry-type
132: * transformations are also system-dependent and it is assumed that this
133: * capability will be little used.
134: *
135: * @return the name of the geometry
136: */
137: public String getGeometryPropertyName() {
138: return geometryName;
139: }
140:
141: /**
142: * The ImageOutline element specifies that individual source rasters in a
143: * multi-raster set (such as a set of satellite-image scenes) should be
144: * outlined with either a LineStringSymbol or PolygonSymbol. It is defined
145: * as:
146: * <pre>
147: * <xs:element name="ImageOutline">
148: * <xs:complexType>
149: * <xs:choice>
150: * <xs:element ref="sld:LineSymbolizer"/>
151: * <xs:element ref="sld:PolygonSymbolizer"/>
152: * </xs:choice>
153: * </xs:complexType>
154: * </xs:element>
155: * </pre>
156: * An Opacity of 0.0 can be selected for the main raster to avoid rendering
157: * the main-raster pixels, or an opacity can be used for a
158: * PolygonSymbolizer Fill to allow the main-raster data be visible through
159: * the fill.
160: *
161: * @return The relevent symbolizer
162: */
163: public Symbolizer getImageOutline() {
164: return symbolizer;
165: }
166:
167: /**
168: * fetch the expresion which evaluates to the opacity fo rthis coverage
169: *
170: * @return The expression
171: */
172: public Expression getOpacity() {
173: return opacity;
174: }
175:
176: /**
177: * The OverlapBehavior element tells a system how to behave when multiple
178: * raster images in a layer overlap each other, for example with
179: * satellite-image scenes. LATEST_ON_TOP and EARLIEST_ON_TOP refer to the
180: * time the scene was captured. AVERAGE means to average multiple scenes
181: * together. This can produce blurry results if the source images are not
182: * perfectly aligned in their geo-referencing. RANDOM means to select an
183: * image (or piece thereof) randomly and place it on top. This can
184: * produce crisper results than AVERAGE potentially more efficiently than
185: * LATEST_ON_TOP or EARLIEST_ON_TOP. The default behaviour is
186: * system-dependent.
187: *
188: * @return The expression which evaluates to LATEST_ON_TOP,
189: * EARLIEST_ON_TOP, AVERAGE or RANDOM
190: */
191: public Expression getOverlap() {
192: return overlap;
193: }
194:
195: /**
196: * The ShadedRelief element selects the application of relief shading (or
197: * ?hill shading?) to an image for a three-dimensional visual effect. It
198: * is defined as: Exact parameters of the shading are system-dependent
199: * (for now). If the BrightnessOnly flag is ?0? (false, default), the
200: * shading is applied to the layer being rendered as the current
201: * RasterSymbol. If BrightnessOnly is ?1? (true), the shading is applied
202: * to the brightness of the colors in the rendering canvas generated so
203: * far by other layers, with the effect of relief-shading these other
204: * layers. The default for BrightnessOnly is ?0? (false). The
205: * ReliefFactor gives the amount of exaggeration to use for the height of
206: * the ?hills.? A value of around 55 (times) gives reasonable results for
207: * Earth-based DEMs. The default value is system-dependent.
208: *
209: * @return the shadedrelief object
210: */
211: public ShadedRelief getShadedRelief() {
212: return shadedRelief;
213: }
214:
215: /**
216: * The ChannelSelection element specifies the false-color channel selection
217: * for a multi-spectral raster source (such as a multi-band
218: * satellite-imagery source). Either a channel may be selected to display
219: * in each of red, green, and blue, or a single channel may be selected to
220: * display in grayscale. (The spelling ?gray? is used since it seems to
221: * be more common on the Web than ?grey? by a ratio of about 3:1.)
222: * Contrast enhancement may be applied to each channel in isolation.
223: * Channels are identified by a system and data-dependent character
224: * identifier. Commonly, channels will be labelled as ?1?, ?2?, etc.
225: *
226: * @param channel the channel selected
227: */
228: public void setChannelSelection(ChannelSelection channel) {
229: if (this .channelSelection == channel) {
230: return;
231: }
232:
233: ChannelSelection old = this .channelSelection;
234: this .channelSelection = channel;
235: fireChildChanged("channelSelection", channel, old);
236: }
237:
238: /**
239: * The ColorMap element defines either the colors of a palette-type raster
240: * source or the mapping of fixed-numeric pixel values to colors. For
241: * example, a DEM raster giving elevations in meters above sea level can
242: * be translated to a colored image with a ColorMap. The quantity
243: * attributes of a color-map are used for translating between numeric
244: * matrixes and color rasters and the ColorMap entries should be in order
245: * of increasing numeric quantity so that intermediate numeric values can
246: * be matched to a color (or be interpolated between two colors). Labels
247: * may be used for legends or may be used in the future to match character
248: * values. Not all systems can support opacity in colormaps. The default
249: * opacity is 1.0 (fully opaque). Defaults for quantity and label are
250: * system-dependent.
251: *
252: * @param colorMap the ColorMap for the raster
253: */
254: public void setColorMap(ColorMap colorMap) {
255: if (this .colorMap == colorMap) {
256: return;
257: }
258:
259: ColorMap old = colorMap;
260: this .colorMap = colorMap;
261: fireChildChanged("colorMap", colorMap, old);
262: }
263:
264: /**
265: * The ContrastEnhancement element defines contrast enhancement for a
266: * channel of a false-color image or for a color image. In the case of a
267: * color image, the relative grayscale brightness of a pixel color is
268: * used. ?Normalize? means to stretch the contrast so that the dimmest
269: * color is stretched to black and the brightest color is stretched to
270: * white, with all colors in between stretched out linearly. ?Histogram?
271: * means to stretch the contrast based on a histogram of how many colors
272: * are at each brightness level on input, with the goal of producing equal
273: * number of pixels in the image at each brightness level on output. This
274: * has the effect of revealing many subtle ground features. A ?GammaValue?
275: * tells how much to brighten (value greater than 1.0) or dim (value less
276: * than 1.0) an image. The default GammaValue is 1.0 (no change). If none
277: * of Normalize, Histogram, or GammaValue are selected in a
278: * ContrastEnhancement, then no enhancement is performed.
279: *
280: * @param contrastEnhancement the contrastEnhancement
281: */
282: public void setContrastEnhancement(
283: ContrastEnhancement contrastEnhancement) {
284: if (this .contrastEnhancement == contrastEnhancement) {
285: return;
286: }
287:
288: ContrastEnhancement old = this .contrastEnhancement;
289: this .contrastEnhancement = contrastEnhancement;
290: fireChildChanged("contrastEnhancement", contrastEnhancement,
291: old);
292: }
293:
294: /**
295: * The interpretation of Geometry is system-dependent, as raster data may
296: * be organized differently from feature data, though omitting this
297: * element selects the default raster-data source. Geometry-type
298: * transformations are also system-dependent and it is assumed that this
299: * capability will be little used.
300: *
301: * @param geometryName the name of the Geometry
302: */
303: public void setGeometryPropertyName(String geometryName) {
304: if (this .geometryName == geometryName) {
305: return;
306: }
307:
308: String old = this .geometryName;
309: this .geometryName = geometryName;
310: fireChildChanged("geometryName", geometryName, old);
311: }
312:
313: /**
314: * The ImageOutline element specifies that individual source rasters in a
315: * multi-raster set (such as a set of satellite-image scenes) should be
316: * outlined with either a LineStringSymbol or PolygonSymbol. It is defined
317: * as:
318: * <pre>
319: * <xs:element name="ImageOutline">
320: * <xs:complexType>
321: * <xs:choice>
322: * <xs:element ref="sld:LineSymbolizer"/>
323: * <xs:element ref="sld:PolygonSymbolizer"/>
324: * </xs:choice>
325: * </xs:complexType>
326: * </xs:element>
327: * </pre>
328: * An Opacity of 0.0 can be selected for the main raster to avoid rendering
329: * the main-raster pixels, or an opacity can be used for a
330: * PolygonSymbolizer Fill to allow the main-raster data be visible through
331: * the fill.
332: *
333: * @param symbolizer the symbolizer to be used. If this is <B>not</B> a
334: * polygon or a line symbolizer an unexpected argument exception
335: * may be thrown by an implementing class.
336: *
337: * @throws IllegalArgumentException DOCUMENT ME!
338: */
339: public void setImageOutline(Symbolizer symbolizer) {
340: if (symbolizer instanceof LineSymbolizer
341: || symbolizer instanceof PolygonSymbolizer) {
342: if (this .symbolizer == symbolizer) {
343: return;
344: }
345:
346: Symbolizer old = this .symbolizer;
347: this .symbolizer = symbolizer;
348: fireChildChanged("symbolizer", symbolizer, old);
349: } else {
350: throw new IllegalArgumentException(
351: "Only a line or polygon symbolizer may be used to outline a raster");
352: }
353: }
354:
355: /**
356: * sets the opacity for the coverage, it has the usual meaning.
357: *
358: * @param opacity An expression which evaluates to the the opacity (0-1)
359: */
360: public void setOpacity(Expression opacity) {
361: if (this .opacity == opacity) {
362: return;
363: }
364:
365: Expression old = this .opacity;
366: this .opacity = opacity;
367: fireChildChanged("opacity", opacity, old);
368: }
369:
370: /**
371: * The OverlapBehavior element tells a system how to behave when multiple
372: * raster images in a layer overlap each other, for example with
373: * satellite-image scenes. LATEST_ON_TOP and EARLIEST_ON_TOP refer to the
374: * time the scene was captured. AVERAGE means to average multiple scenes
375: * together. This can produce blurry results if the source images are not
376: * perfectly aligned in their geo-referencing. RANDOM means to select an
377: * image (or piece thereof) randomly and place it on top. This can
378: * produce crisper results than AVERAGE potentially more efficiently than
379: * LATEST_ON_TOP or EARLIEST_ON_TOP. The default behaviour is
380: * system-dependent.
381: *
382: * @param overlap the expression which evaluates to LATEST_ON_TOP,
383: * EARLIEST_ON_TOP, AVERAGE or RANDOM
384: */
385: public void setOverlap(Expression overlap) {
386: if (this .overlap == overlap) {
387: return;
388: }
389:
390: Expression old = this .overlap;
391: this .overlap = overlap;
392: fireChildChanged("overlap", overlap, old);
393: }
394:
395: /**
396: * The ShadedRelief element selects the application of relief shading (or
397: * ?hill shading?) to an image for a three-dimensional visual effect. It
398: * is defined as: Exact parameters of the shading are system-dependent
399: * (for now). If the BrightnessOnly flag is ?0? (false, default), the
400: * shading is applied to the layer being rendered as the current
401: * RasterSymbol. If BrightnessOnly is ?1? (true), the shading is applied
402: * to the brightness of the colors in the rendering canvas generated so
403: * far by other layers, with the effect of relief-shading these other
404: * layers. The default for BrightnessOnly is ?0? (false). The
405: * ReliefFactor gives the amount of exaggeration to use for the height of
406: * the ?hills.? A value of around 55 (times) gives reasonable results for
407: * Earth-based DEMs. The default value is system-dependent.
408: *
409: * @param shadedRelief the shadedrelief object
410: */
411: public void setShadedRelief(ShadedRelief shadedRelief) {
412: if (this .shadedRelief == shadedRelief) {
413: return;
414: }
415:
416: ShadedRelief old = this .shadedRelief;
417: this .shadedRelief = shadedRelief;
418: fireChildChanged("shadedRelief", shadedRelief, old);
419: }
420:
421: public void accept(StyleVisitor visitor) {
422: visitor.visit(this );
423: }
424:
425: /**
426: * Creates a deep copy clone. TODO: Need to complete the deep copy,
427: * currently only shallow copy.
428: *
429: * @return The deep copy clone.
430: *
431: * @throws RuntimeException DOCUMENT ME!
432: */
433: public Object clone() {
434: Object clone;
435:
436: try {
437: clone = super .clone();
438: } catch (CloneNotSupportedException e) {
439: throw new RuntimeException(e); // this should never happen.
440: }
441:
442: return clone;
443: }
444: }
|