001: /*
002: * GeoTools - OpenSource mapping toolkit
003: * http://geotools.org
004: * (C) 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; either
009: * version 2.1 of the License, or (at your option) any later version.
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: package org.geotools.coverage.grid;
017:
018: // J2SE and JAI dependencies
019: import java.io.Serializable;
020: import java.awt.image.ColorModel; // For javadoc
021: import java.awt.image.IndexColorModel; // For javadoc
022: import javax.media.jai.JAI; // For javadoc
023: import javax.media.jai.InterpolationNearest; // For javadoc
024: import javax.media.jai.InterpolationBilinear; // For javadoc
025: import javax.media.jai.InterpolationBicubic; // For javadoc
026: import javax.media.jai.operator.ScaleDescriptor; // For javadoc
027:
028: /**
029: * Enumerates different "views" over a given coverage. Coverage views represent the same data
030: * in different ways. Some views are more appropriate than others depending of the kind of work
031: * to be performed. For example numerical computations on meteorological or oceanographical data
032: * should be performed on the {@linkplain #GEOPHYSICS geophysics} view, while renderings are
033: * better performed with the {@linkplain #DISPLAYABLE displayable} view.
034: * <p>
035: * Different views are sometime synonymous for a given coverage. For example the
036: * {@linkplain #NATIVE native} and {@linkplain #DISPLAYABLE displayable} views are identical
037: * when the coverage values are unsigned 8 or 16 bits integers, but distincts if the native
038: * values are <em>signed</em> integers. This is because in the later case, the negative values
039: * can not be processed directly by an {@linkplain IndexColorModel index color model}.
040: *
041: * @since 2.4
042: * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/library/coverage/src/main/java/org/geotools/coverage/grid/ViewType.java $
043: * @version $Id: ViewType.java 23398 2006-12-12 05:57:00Z desruisseaux $
044: * @author Martin Desruisseaux
045: *
046: * @todo Should be an enum when we will be allowed to compile for J2SE 1.5.
047: */
048: public final class ViewType implements Serializable {
049: /**
050: * For cross-version compatibility.
051: */
052: private static final long serialVersionUID = -1926667155583006688L;
053:
054: /**
055: * The name for this enum.
056: */
057: private final String name;
058:
059: /**
060: * {@code true} if interpolations other than {@linkplain InterpolationNearest
061: * nearest neighbor} are allowed.
062: */
063: private final boolean interpolationAllowed;
064:
065: /**
066: * {@code true} if the replacement of {@linkplain IndexColorModel index color model}
067: * is allowed.
068: *
069: * @see JAI#KEY_REPLACE_INDEX_COLOR_MODEL
070: */
071: private final boolean colorSpaceConversionAllowed;
072:
073: /**
074: * Coverage data come directly from some source (typically a file) and are unprocessed.
075: * This view doesn't have any of the restrictions imposed by other views: values may be
076: * integers or floating point values, negative values are allowed, and missing data may
077: * be represented by "pad values" like -9999. This view is generally not suitable for
078: * renderings or numerical computations. However in some special cases, this view may
079: * be identical to an other view (see those other views for a more exhaustive list of
080: * their conditions):
081: * <p>
082: * <ul>
083: * <li>If the values are stored as unsigned integers, then the native view may
084: * be identical to the {@linkplain #DISPLAYABLE displayable} view.</li>
085: * <li>If all missing values are represented by {@linkplain Float#isNaN some kind of
086: * NaN values}, then the native view may be identical to the
087: * {@linkplain #GEOPHYSICS geophysics} view.</li>
088: * </ul>
089: * <p>
090: * Interpolations other than {@linkplain InterpolationNearest nearest neighbor} are
091: * not allowed. Conversions to the RGB color space are not allowed neither, for the
092: * same reasons than the {@linkplain #DISPLAYABLE displayable} view.
093: */
094: public static final ViewType NATIVE = new ViewType("NATIVE", false,
095: false);
096:
097: /**
098: * Coverage data are compatible with common Java2D {@linkplain ColorModel color models}.
099: * This usually imply that values are restricted to unsigned integers. This view is often
100: * identical to the {@linkplain #NATIVE native} view if the values on the originating
101: * device were already unsigned.
102: * <p>
103: * Conversions to the RGB color space are not allowed, because the data are often related
104: * to {@linkplain #GEOPHYSICS geophysics} values in some way. For example the coverage may
105: * contains <cite>Sea Surface Temperature</cite> (SST) data packed as 8 bits integers and
106: * convertible to degrees Celsius using the following formula: <var>temperature</var> =
107: * <var>pixel_value</var> × 0.15 - 3. A conversion to RGB space would lose this
108: * relationship, and any oceanographical calculation accidentaly performed on this space
109: * would produce wrong results.
110: * <p>
111: * Interpolations other than {@linkplain InterpolationNearest nearest neighbor} are not
112: * allowed, because some special values are often used as pad values for missing data. An
113: * interpolation between a "real" value (for example a value convertible to the above-cited
114: * SST) and "pad" value would produce a wrong result.
115: */
116: public static final ViewType DISPLAYABLE = new ViewType(
117: "DISPLAYABLE", false, false);
118:
119: /**
120: * Coverage data are the values of some geophysics phenomenon, for example an elevation
121: * in metres or a temperature in Celsius degrees. Values are typically floating point
122: * numbers ({@code float} or {@code double} primitive type), but this is not mandatory
123: * if there is never fractional parts or missing values in a particular coverage.
124: * <p>
125: * If the coverage contains some "no data" values, then those missing values
126: * <strong>must</strong> be represented by {@link Float#NaN} or {@link Double#NaN}
127: * constant, or any other value in the NaN range as {@linkplain Float#intBitsToFloat
128: * explained there}. Real numbers used as "pad values" like {@code -9999} are
129: * <strong>not</strong> allowed.
130: * <p>
131: * Interpolations ({@linkplain InterpolationBilinear bilinear},
132: * {@linkplain InterpolationBicubic bicubic}, <cite>etc.</cite>) are allowed.
133: * If there is some missing values around the interpolation point, then the
134: * result is a {@code NaN} value.
135: * <p>
136: * Conversions to RGB color space is not allowed. All computations (including
137: * interpolations) must be performed in this geophysics space.
138: */
139: public static final ViewType GEOPHYSICS = new ViewType(
140: "GEOPHYSICS", true, false);
141:
142: /**
143: * Coverage data have no meaning other than visual color. It is not an elevation map for
144: * example (in which case the coverage would rather be described as {@linkplain #GEOPHYSICS
145: * geophysics}).
146: * <p>
147: * Conversions to the RGB color space are allowed. Because the coverage has no geophysics
148: * meaning other than visual color, there is no significant data lose in the replacement
149: * of {@linkplain IndexColorModel index color model}.
150: * <p>
151: * Interpolation are not allowed on indexed values. They must be performed on the RGB
152: * or similar color space instead.
153: */
154: public static final ViewType PHOTOGRAPHIC = new ViewType(
155: "PHOTOGRAPHIC", false, true);
156:
157: /**
158: * Creates a new instance of {@code ViewType}.
159: */
160: private ViewType(final String name,
161: final boolean interpolationAllowed,
162: final boolean colorSpaceConversionAllowed) {
163: this .name = name;
164: this .interpolationAllowed = interpolationAllowed;
165: this .colorSpaceConversionAllowed = colorSpaceConversionAllowed;
166: }
167:
168: /**
169: * Returns {@code true} if interpolations other than {@linkplain InterpolationNearest
170: * nearest neighbor} are allowed. Those interpolations require the following conditions:
171: * <p>
172: * <ul>
173: * <li>Values are either {@linkplain #GEOPHYSICS geophysics} values, or related to
174: * geophysics values through a linear relationship over all the range of possible
175: * values (including "no data" values).</li>
176: * <li>There is no "pad values". Missing values, if any, are represented by some
177: * {@link Float#NaN NaN} values}.</li>
178: * </ul>
179: * <p>
180: * This method may conservatively returns {@code false} if unsure. If interpolations
181: * are wanted but not allowed, then users should try to convert the coverage to the
182: * {@linkplain #GEOPHYSICS geophysics} space, which supports interpolations. If no
183: * geophysics view is available, then users may convert the image to the RGB space
184: * if {@linkplain #isColorSpaceConversionAllowed color space conversion is allowed}.
185: * Interpolations in the RGB space produce nice-looking images, but the pixel values
186: * lose all geophysical meaning. If the color space conversion is not allowed, then
187: * then users should stick with {@linkplain InterpolationNearest nearest neighbor}
188: * interpolation.
189: */
190: public boolean isInterpolationAllowed() {
191: return interpolationAllowed;
192: }
193:
194: /**
195: * Returns {@code true} if the replacement of {@linkplain IndexColorModel index color model}
196: * is allowed. Such replacements may occurs during some operations requirying interpolations,
197: * like {@linkplain ScaleDescriptor scale}, in order to produce images that look nicer.
198: * However such replacements should be attempted only in last resort (interpolations in the
199: * {@linkplain #GEOPHYSICS geophysics} space should be preferred) and only if the coverage
200: * data don't have any meaning other than visual color, as in {@linkplain #PHOTOGRAPHIC
201: * photographic} images.
202: *
203: * @see JAI#KEY_REPLACE_INDEX_COLOR_MODEL
204: */
205: public boolean isColorSpaceConversionAllowed() {
206: return colorSpaceConversionAllowed;
207: }
208:
209: /**
210: * Returns a hash value for this enum.
211: */
212: public int hashCode() {
213: return (int) serialVersionUID ^ name.hashCode();
214: }
215:
216: /**
217: * Compares this enum with the specified object for equality.
218: */
219: public boolean equals(final Object object) {
220: return (object instanceof ViewType)
221: && name.equals(((ViewType) object).name);
222: }
223:
224: /**
225: * Returns a string representation of this enum.
226: */
227: public String toString() {
228: return name;
229: }
230: }
|