001: /*
002: * GeoTools - OpenSource mapping toolkit
003: * http://geotools.org
004: * (C) 2007, GeoTools Project Managment Committee (PMC)
005: * (C) 2007, Geomatys
006: *
007: * This library is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU Lesser General Public
009: * License as published by the Free Software Foundation;
010: * version 2.1 of the License.
011: *
012: * This library is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: */
017: package org.geotools.image.io.metadata;
018:
019: // OpenGIS dependencies
020: import org.opengis.geometry.Envelope; // For javadoc
021: import org.opengis.coverage.grid.GridRange; // For javadoc
022: import org.opengis.metadata.spatial.PixelOrientation; // For javadoc
023:
024: // Geotools dependencies
025: import org.geotools.util.NumberRange;
026: import org.geotools.resources.i18n.ErrorKeys;
027:
028: /**
029: * A {@code <GridGeometry>} element in
030: * {@linkplain GeographicMetadataFormat geographic metadata format}. This class offers similar
031: * service than {@link GridRange} and {@link Envelope}, except that the maximum value for
032: * {@linkplain #getGridRange grid range} and {@linkplain #getCoordinateRange coordinate range}
033: * are inclusives.
034: * <p>
035: * The {@code <GridRange>} child element is typically (but not always) initialized
036: * to the following ranges:
037: * <p>
038: * <li>
039: * <ul>[0 .. {@linkplain java.awt.image.RenderedImage#getWidth image width} - 1]</ul>
040: * <ul>[0 .. {@linkplain java.awt.image.RenderedImage#getHeight image height} - 1]</ul>
041: * </li>
042: * <p>
043: * However <var>n</var>-dimensional grid coverages may contains additional entries.
044: *
045: * @since 2.4
046: * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/unsupported/coverageio/src/main/java/org/geotools/image/io/metadata/ImageGeometry.java $
047: * @version $Id: ImageGeometry.java 26151 2007-07-04 18:54:48Z desruisseaux $
048: * @author Martin Desruisseaux
049: */
050: public class ImageGeometry extends MetadataAccessor {
051: /**
052: * The {@code "GridGeometry/GridRange"} node.
053: */
054: private final MetadataAccessor gridRange;
055:
056: /**
057: * The {@code "GridGeometry/Envelope"} node.
058: */
059: private final MetadataAccessor envelope;
060:
061: /**
062: * Creates a parser for a grid geometry. This constructor should not be invoked
063: * directly; use {@link GeographicMetadata#getGeometry} instead.
064: *
065: * @param metadata The metadata node.
066: */
067: protected ImageGeometry(final GeographicMetadata metadata) {
068: super (metadata, "GridGeometry", null);
069: envelope = new MetadataAccessor(metadata,
070: "GridGeometry/Envelope", "CoordinateValues");
071: gridRange = new MetadataAccessor(metadata,
072: "GridGeometry/GridRange", "IndexRange");
073: }
074:
075: /**
076: * Returns the number of dimensions. If the {@linkplain GridRange grid range} and
077: * {@linkplain Envelope envelope} don't have the same dimension, then a warning
078: * is logged and the smallest dimension is returned.
079: */
080: public int getDimension() {
081: final int dim1 = gridRange.childCount();
082: final int dim2 = envelope.childCount();
083: if (dim1 != dim2) {
084: warning("getDimension", ErrorKeys.MISMATCHED_DIMENSION_$2,
085: new Integer[] { new Integer(dim1),
086: new Integer(dim2) });
087: }
088: return Math.min(dim1, dim2);
089: }
090:
091: /**
092: * Returns the range of grid index along the specified dimension. Note that range
093: * {@linkplain NumberRange#getMinValue minimum value},
094: * {@linkplain NumberRange#getMaxValue maximum value} or both may be null if no
095: * {@code "minimum"} or {@code "maximum"} attribute were found for the
096: * {@code "GridGeometry/GridRange/IndexRange"} element.
097: *
098: * @param dimension The dimension index, from 0 inclusive to {@link #getDimension} exclusive.
099: */
100: public NumberRange getGridRange(final int dimension) {
101: gridRange.selectChild(dimension);
102: final Integer minimum = gridRange.getInteger("minimum");
103: final Integer maximum = gridRange.getInteger("maximum");
104: return new NumberRange(Integer.class, minimum, true, maximum,
105: true);
106: }
107:
108: /**
109: * Set the grid range along the specified dimension.
110: *
111: * @param dimension The dimension to set, from 0 inclusive to {@link #getDimension} exclusive.
112: * @param minimum The minimum value along the specified dimension (inclusive).
113: * @param maximum The maximum value along the specified dimension (<strong>inclusive</strong>).
114: */
115: public void setGridRange(final int dimension, final int minimum,
116: final int maximum) {
117: gridRange.selectChild(dimension);
118: gridRange.setInteger("minimum", minimum);
119: gridRange.setInteger("maximum", maximum);
120: }
121:
122: /**
123: * Returns the range of coordinate values along the specified dimension. Note that range
124: * {@linkplain NumberRange#getMinValue minimum value},
125: * {@linkplain NumberRange#getMaxValue maximum value} or both may be null if no
126: * {@code "minimum"} or {@code "maximum"} attribute were found for the
127: * {@code "GridGeometry/Envelope/CoordinateValues"} element.
128: *
129: * @param dimension The dimension index, from 0 inclusive to {@link #getDimension} exclusive.
130: */
131: public NumberRange getCoordinateRange(final int dimension) {
132: envelope.selectChild(dimension);
133: final Double minimum = envelope.getDouble("minimum");
134: final Double maximum = envelope.getDouble("maximum");
135: return new NumberRange(Double.class, minimum, true, maximum,
136: true);
137: }
138:
139: /**
140: * Set the envelope range along the specified dimension.
141: *
142: * @param dimension The dimension to set, from 0 inclusive to {@link #getDimension} exclusive.
143: * @param minimum The minimum value along the specified dimension (inclusive).
144: * @param maximum The maximum value along the specified dimension (<strong>inclusive</strong>).
145: */
146: public void setCoordinateRange(final int dimension,
147: final double minimum, final double maximum) {
148: envelope.selectChild(dimension);
149: envelope.setDouble("minimum", minimum);
150: envelope.setDouble("maximum", maximum);
151: }
152:
153: /**
154: * Adds the range of values for an envelope along a dimension. Invoking this method
155: * will increase the grid and envelope {@linkplain #getDimension dimension} by one.
156: * The ranges should be added in the same order than
157: * {@linkplain GeographicMetadata#addAxis axis}.
158: *
159: * @param minIndex The minimal index value, inclusive. This is usually 0.
160: * @param maxIndex The maximal index value, <strong>inclusive</strong>.
161: * @param minValue The minimal coordinate value, inclusive.
162: * @param maxValue The maximal coordinate value, <strong>inclusive</strong>.
163: *
164: * @see #addCoordinateValues
165: */
166: public void addCoordinateRange(final int minIndex,
167: final int maxIndex, final double minValue,
168: final double maxValue) {
169: setGridRange(gridRange.appendChild(), minIndex, maxIndex);
170: setCoordinateRange(envelope.appendChild(), minValue, maxValue);
171: }
172:
173: /**
174: * Returns the coordinate values along the specified dimension, or {@code null} if none.
175: * This method returns a non-null values only if an array of was explicitly specified,
176: * for example by a call to {@link #setCoordinateValues}.
177: *
178: * @param dimension The dimension index, from 0 inclusive to {@link #getDimension} exclusive.
179: */
180: public double[] getCoordinateValues(final int dimension) {
181: envelope.selectChild(dimension);
182: return (double[]) envelope.getUserObject();
183: }
184:
185: /**
186: * Set the envelope coordinate values along the specified dimension. The minimum and
187: * maximum coordinates will be determined from the specified array.
188: *
189: * @param dimension The dimension to set, from 0 inclusive to {@link #getDimension} exclusive.
190: * @param values The coordinate values.
191: */
192: public void setCoordinateValues(final int dimension,
193: final double[] values) {
194: double minimum = Double.POSITIVE_INFINITY;
195: double maximum = Double.NEGATIVE_INFINITY;
196: if (values != null) {
197: for (int i = 0; i < values.length; i++) {
198: final double value = values[i];
199: if (value < minimum)
200: minimum = value;
201: if (value > maximum)
202: maximum = value;
203: }
204: }
205: setCoordinateRange(dimension, minimum, maximum);
206: envelope.setUserObject(values);
207: }
208:
209: /**
210: * Adds coordinate values for an envelope along a dimension. Invoking this method
211: * will increase the envelope {@linkplain #getDimension dimension} by one. This method
212: * may be invoked in replacement of {@link #addCoordinateRange} when every cell
213: * coordinates need to be specified explicitly.
214: *
215: * @param minIndex The minimal index value, inclusive. This is usually 0.
216: * @param values The coordinate values.
217: *
218: * @see #addCoordinateRange
219: */
220: public void addCoordinateValues(final int minIndex,
221: final double[] values) {
222: setGridRange(gridRange.appendChild(), minIndex, minIndex
223: + values.length - 1);
224: setCoordinateValues(envelope.appendChild(), values);
225: }
226:
227: /**
228: * Returns the point in a pixel corresponding to the Earth location of the pixel. In the JAI
229: * framework, this is typically the {@linkplain PixelOrientation#UPPER_LEFT upper left} corner.
230: * In some OGC specifications, this is often the pixel {@linkplain PixelOrientation#CENTER center}.
231: *
232: * @param pixelOrientation The pixel orientation (usually {@code "center"},
233: * {@code "lower left"}, {@code "lower right"}, {@code "upper right"}
234: * or {@code "upper left"}), or {@code null} if unknown.
235: *
236: * @see PixelOrientation
237: */
238: public String getPixelOrientation() {
239: return getString("pixelOrientation");
240: }
241:
242: /**
243: * Set the pixel orientation to the specified value. The pixel orientation gives the point
244: * in a pixel corresponding to the Earth location of the pixel. In the JAI framework, this
245: * is typically the {@linkplain PixelOrientation#UPPER_LEFT upper left} corner. In some OGC
246: * specifications, this is often the pixel {@linkplain PixelOrientation#CENTER center}.
247: *
248: * @param pixelOrientation The pixel orientation (usually {@code "center"},
249: * {@code "lower left"}, {@code "lower right"}, {@code "upper right"}
250: * or {@code "upper left"}), or {@code null} if unknown.
251: *
252: * @see PixelOrientation
253: */
254: public void setPixelOrientation(final String pixelOrientation) {
255: setEnum("pixelOrientation", pixelOrientation,
256: GeographicMetadataFormat.PIXEL_ORIENTATIONS);
257: }
258: }
|