001: /*
002: * GeoTools - OpenSource mapping toolkit
003: * http://geotools.org
004: * (C) 2005-2006, Geotools Project Managment Committee (PMC)
005: * (C) 2005, Institut de Recherche pour le Développement
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; either
010: * version 2.1 of the License, or (at your option) any later version.
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.coverage;
018:
019: // J2SE and JAI dependencies
020: import javax.media.jai.PropertySource;
021:
022: // OpenGIS dependencies
023: import org.opengis.coverage.Coverage;
024: import org.opengis.coverage.SampleDimension;
025: import org.opengis.coverage.CannotEvaluateException;
026: import org.opengis.geometry.Envelope;
027: import org.opengis.geometry.DirectPosition;
028: import org.opengis.referencing.FactoryException;
029: import org.opengis.referencing.crs.CoordinateReferenceSystem;
030: import org.opengis.referencing.operation.MathTransform;
031: import org.opengis.referencing.operation.TransformException;
032:
033: // Geotools dependencies
034: import org.geotools.factory.Hints;
035: import org.geotools.referencing.CRS;
036: import org.geotools.referencing.ReferencingFactoryFinder;
037: import org.geotools.geometry.GeneralDirectPosition;
038: import org.geotools.geometry.GeneralEnvelope;
039:
040: /**
041: * A coverage wrapping an other one with a different coordinate reference system. The coordinate
042: * transformation is applied on the fly every time an {@code evaluate} method is invoked. It may
043: * be efficient if few points are queried, but become ineficient if a large amount of points is
044: * queried. In the later case, consider reprojecting the whole grid coverage instead.
045: * <br><br>
046: * <strong>Note:</strong> This class is not thread safe for performance reasons. If desired,
047: * users should create one instance of {@code TransformedCoverage} for each thread.
048: *
049: * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/library/coverage/src/main/java/org/geotools/coverage/TransformedCoverage.java $
050: * @version $Id: TransformedCoverage.java 25050 2007-04-06 00:41:49Z jgarnett $
051: * @author Martin Desruisseaux
052: *
053: * @since 2.1
054: */
055: public class TransformedCoverage extends AbstractCoverage {
056: /**
057: * The hints for the creation of coordinate operation.
058: * The default coordinate operation factory should be suffisient.
059: */
060: private static final Hints HINTS = null;
061:
062: /**
063: * The wrapped coverage.
064: */
065: protected final Coverage coverage;
066:
067: /**
068: * The transform from this coverage CRS to the wrapped coverage CRS.
069: */
070: private final MathTransform toWrapped;
071:
072: /**
073: * The projected point.
074: */
075: private final GeneralDirectPosition position;
076:
077: /**
078: * Creates a new coverage wrapping the specified one.
079: *
080: * @param name The name for this new coverage.
081: * @param crs The crs for this coverage.
082: * @param coverage The coverage to wraps.
083: * @throws FactoryException if no transformation can be found from the coverage CRS to the
084: * specified CRS.
085: */
086: protected TransformedCoverage(final CharSequence name,
087: final CoordinateReferenceSystem crs, final Coverage coverage)
088: throws FactoryException {
089: super (
090: name,
091: crs,
092: (coverage instanceof PropertySource) ? ((PropertySource) coverage)
093: : null, null);
094: this .coverage = coverage;
095: position = new GeneralDirectPosition(crs.getCoordinateSystem()
096: .getDimension());
097: toWrapped = ReferencingFactoryFinder
098: .getCoordinateOperationFactory(HINTS).createOperation(
099: crs, coverage.getCoordinateReferenceSystem())
100: .getMathTransform();
101: }
102:
103: /**
104: * Creates a new coverage wrapping the specified one with a different CRS.
105: * If the specified coverage already uses the specified CRS (or an equivalent one),
106: * it is returned unchanged.
107: *
108: * @param name The name for this new coverage.
109: * @param crs The crs for this coverage.
110: * @param coverage The coverage to wraps.
111: * @return A coverage using the specified CRS.
112: * @throws FactoryException if no transformation can be found from the coverage CRS to the
113: * specified CRS.
114: */
115: public static Coverage reproject(final CharSequence name,
116: final CoordinateReferenceSystem crs, Coverage coverage)
117: throws FactoryException {
118: while (true) {
119: if (CRS.equalsIgnoreMetadata(coverage
120: .getCoordinateReferenceSystem(), crs)) {
121: return coverage;
122: }
123: if (TransformedCoverage.class.equals(coverage.getClass())) {
124: coverage = ((TransformedCoverage) coverage).coverage;
125: continue;
126: }
127: break;
128: }
129: return new TransformedCoverage(name, crs, coverage);
130: }
131:
132: /**
133: * The number of sample dimensions in the coverage.
134: * For grid coverages, a sample dimension is a band.
135: *
136: * @return The number of sample dimensions in the coverage.
137: */
138: public int getNumSampleDimensions() {
139: return coverage.getNumSampleDimensions();
140: }
141:
142: /**
143: * Retrieve sample dimension information for the coverage.
144: *
145: * @param index Index for sample dimension to retrieve. Indices are numbered 0 to
146: * (<var>{@linkplain #getNumSampleDimensions n}</var>-1).
147: * @return Sample dimension information for the coverage.
148: * @throws IndexOutOfBoundsException if {@code index} is out of bounds.
149: */
150: public SampleDimension getSampleDimension(final int index)
151: throws IndexOutOfBoundsException {
152: return coverage.getSampleDimension(index);
153: }
154:
155: /**
156: * Wraps the checked exception into an unchecked one.
157: *
158: * @todo Provides a localized message.
159: */
160: private final CannotEvaluateException transformationFailed(
161: final TransformException cause) {
162: return new CannotEvaluateException("Transformation failed",
163: cause);
164: }
165:
166: /**
167: * Returns the envelope.
168: */
169: public Envelope getEnvelope() {
170: final GeneralEnvelope envelope;
171: try {
172: envelope = CRS.transform(toWrapped.inverse(), coverage
173: .getEnvelope());
174: } catch (TransformException exception) {
175: throw transformationFailed(exception);
176: }
177: envelope.setCoordinateReferenceSystem(crs);
178: return envelope;
179: }
180:
181: /**
182: * Returns the value vector for a given point in the coverage.
183: *
184: * @param coord The coordinate point where to evaluate.
185: * @throws PointOutsideCoverageException if {@code coord} is outside coverage.
186: * @throws CannotEvaluateException if the computation failed for some other reason.
187: */
188: public final Object evaluate(final DirectPosition coord)
189: throws CannotEvaluateException {
190: try {
191: return coverage.evaluate(toWrapped.transform(coord,
192: position));
193: } catch (TransformException exception) {
194: throw transformationFailed(exception);
195: }
196: }
197:
198: /**
199: * Returns a sequence of boolean values for a given point in the coverage.
200: */
201: public final boolean[] evaluate(final DirectPosition coord,
202: boolean[] dest) throws CannotEvaluateException {
203: try {
204: return coverage.evaluate(toWrapped.transform(coord,
205: position), dest);
206: } catch (TransformException exception) {
207: throw transformationFailed(exception);
208: }
209: }
210:
211: /**
212: * Returns a sequence of byte values for a given point in the coverage.
213: */
214: public final byte[] evaluate(final DirectPosition coord, byte[] dest)
215: throws CannotEvaluateException {
216: try {
217: return coverage.evaluate(toWrapped.transform(coord,
218: position), dest);
219: } catch (TransformException exception) {
220: throw transformationFailed(exception);
221: }
222: }
223:
224: /**
225: * Returns a sequence of integer values for a given point in the coverage.
226: */
227: public final int[] evaluate(final DirectPosition coord, int[] dest)
228: throws CannotEvaluateException {
229: try {
230: return coverage.evaluate(toWrapped.transform(coord,
231: position), dest);
232: } catch (TransformException exception) {
233: throw transformationFailed(exception);
234: }
235: }
236:
237: /**
238: * Returns a sequence of float values for a given point in the coverage.
239: */
240: public final float[] evaluate(final DirectPosition coord,
241: float[] dest) throws CannotEvaluateException {
242: try {
243: return coverage.evaluate(toWrapped.transform(coord,
244: position), dest);
245: } catch (TransformException exception) {
246: throw transformationFailed(exception);
247: }
248: }
249:
250: /**
251: * Returns a sequence of double values for a given point in the coverage.
252: */
253: public final double[] evaluate(final DirectPosition coord,
254: final double[] dest) throws CannotEvaluateException {
255: try {
256: return coverage.evaluate(toWrapped.transform(coord,
257: position), dest);
258: } catch (TransformException exception) {
259: throw transformationFailed(exception);
260: }
261: }
262: }
|