001 //$HeadURL: svn+ssh://rbezema@svn.wald.intevation.org/deegree/base/tags/2.1/src/org/deegree/model/csct/ct/PassThroughTransform.java $
002 /*---------------- FILE HEADER ------------------------------------------
003
004 This file is part of deegree.
005 Copyright (C) 2001 by:
006 EXSE, Department of Geography, University of Bonn
007 http://www.giub.uni-bonn.de/exse/
008 lat/lon GmbH
009 http://www.lat-lon.de
010
011 It has been implemented within SEAGIS - An OpenSource implementation of OpenGIS specification
012 (C) 2001, Institut de Recherche pour le D�veloppement (http://sourceforge.net/projects/seagis/)
013 SEAGIS Contacts: Surveillance de l'Environnement Assist�e par Satellite
014 Institut de Recherche pour le D�veloppement / US-Espace
015 mailto:seasnet@teledetection.fr
016
017
018 This library is free software; you can redistribute it and/or
019 modify it under the terms of the GNU Lesser General Public
020 License as published by the Free Software Foundation; either
021 version 2.1 of the License, or (at your option) any later version.
022
023 This library is distributed in the hope that it will be useful,
024 but WITHOUT ANY WARRANTY; without even the implied warranty of
025 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
026 Lesser General Public License for more details.
027
028 You should have received a copy of the GNU Lesser General Public
029 License along with this library; if not, write to the Free Software
030 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
031
032 Contact:
033
034 Andreas Poth
035 lat/lon GmbH
036 Aennchenstr. 19
037 53115 Bonn
038 Germany
039 E-Mail: poth@lat-lon.de
040
041 Klaus Greve
042 Department of Geography
043 University of Bonn
044 Meckenheimer Allee 166
045 53115 Bonn
046 Germany
047 E-Mail: klaus.greve@uni-bonn.de
048
049
050 ---------------------------------------------------------------------------*/
051 package org.deegree.model.csct.ct;
052
053 // OpenGIS dependencies (SEAGIS)
054 import java.io.Serializable;
055
056 import org.deegree.model.csct.pt.CoordinatePoint;
057 import org.deegree.model.csct.pt.Matrix;
058 import org.deegree.model.csct.pt.MismatchedDimensionException;
059 import org.deegree.model.csct.resources.Utilities;
060
061
062 /**
063 * Transform which passes through a subset of ordinates to another transform.
064 * This allows transforms to operate on a subset of ordinates. For example,
065 * if you have (<var>latitude</var>,<var>longitude</var>,<var>height</var>)
066 * coordinates, then you may wish to convert the height values from feet to
067 * meters without affecting the latitude and longitude values.
068 *
069 * @version 1.00
070 * @author OpenGIS (www.opengis.org)
071 * @author Martin Desruisseaux
072 */
073 final class PassThroughTransform extends AbstractMathTransform implements Serializable
074 {
075 /**
076 * Serial number for interoperability with different versions.
077 */
078 private static final long serialVersionUID = -1673997634240223449L;
079
080 /**
081 * Index of the first affected ordinate.
082 */
083 protected final int firstAffectedOrdinate;
084
085 /**
086 * Number of unaffected ordinates after the affected ones.
087 * Always 0 when used through the strict OpenGIS API.
088 */
089 protected final int numTrailingOrdinates;
090
091 /**
092 * The sub transform.
093 */
094 protected final MathTransform transform;
095
096 /**
097 * The inverse transform. This field
098 * will be computed only when needed.
099 */
100 private transient PassThroughTransform inverse;
101
102 /**
103 * Create a pass through transform.
104 *
105 * @param firstAffectedOrdinate Index of the first affected ordinate.
106 * @param transform The sub transform.
107 * @param numTrailingOrdinates Number of trailing ordinates to pass through.
108 * Affected ordinates will range from <code>firstAffectedOrdinate</code>
109 * inclusive to <code>dimTarget-numTrailingOrdinates</code> exclusive.
110 */
111 public PassThroughTransform(final int firstAffectedOrdinate, final MathTransform transform, final int numTrailingOrdinates)
112 {
113 if (transform instanceof PassThroughTransform)
114 {
115 final PassThroughTransform passThrough = (PassThroughTransform) transform;
116 this.firstAffectedOrdinate = passThrough.firstAffectedOrdinate + firstAffectedOrdinate;
117 this.numTrailingOrdinates = passThrough.numTrailingOrdinates + numTrailingOrdinates;
118 this.transform = passThrough.transform;
119 }
120 else
121 {
122 this.firstAffectedOrdinate = firstAffectedOrdinate;
123 this.numTrailingOrdinates = numTrailingOrdinates;
124 this.transform = transform;
125 }
126 }
127
128 /**
129 * Gets the dimension of input points.
130 */
131 public int getDimSource()
132 {return firstAffectedOrdinate + transform.getDimSource() + numTrailingOrdinates;}
133
134 /**
135 * Gets the dimension of output points.
136 */
137 public int getDimTarget()
138 {return firstAffectedOrdinate + transform.getDimTarget() + numTrailingOrdinates;}
139
140 /**
141 * Tests whether this transform does not move any points.
142 */
143 public boolean isIdentity()
144 {return transform.isIdentity();}
145
146 /**
147 * Transforms a list of coordinate point ordinal values.
148 */
149 public void transform(final float[] srcPts, int srcOff, final float[] dstPts, int dstOff, int numPts) throws TransformException
150 {
151 final int subDimSource = transform.getDimSource();
152 final int subDimTarget = transform.getDimTarget();
153 int srcStep = numTrailingOrdinates;
154 int dstStep = numTrailingOrdinates;
155 if (srcPts==dstPts && srcOff<dstOff)
156 {
157 final int dimSource = getDimSource();
158 final int dimTarget = getDimTarget();
159 srcOff += numPts * dimSource;
160 dstOff += numPts * dimTarget;
161 srcStep -= 2*dimSource;
162 dstStep -= 2*dimTarget;
163 }
164 while (--numPts >= 0)
165 {
166 System.arraycopy (srcPts, srcOff, dstPts, dstOff, firstAffectedOrdinate);
167 transform.transform(srcPts, srcOff+=firstAffectedOrdinate, dstPts, dstOff+=firstAffectedOrdinate, 1);
168 System.arraycopy (srcPts, srcOff+=subDimSource, dstPts, dstOff+=subDimTarget, numTrailingOrdinates);
169 srcOff += srcStep;
170 dstOff += dstStep;
171 }
172 }
173
174 /**
175 * Transforms a list of coordinate point ordinal values.
176 */
177 public void transform(final double[] srcPts, int srcOff, final double[] dstPts, int dstOff, int numPts) throws TransformException
178 {
179 final int subDimSource = transform.getDimSource();
180 final int subDimTarget = transform.getDimTarget();
181 int srcStep = numTrailingOrdinates;
182 int dstStep = numTrailingOrdinates;
183 if (srcPts==dstPts && srcOff<dstOff)
184 {
185 final int dimSource = getDimSource();
186 final int dimTarget = getDimTarget();
187 srcOff += numPts * dimSource;
188 dstOff += numPts * dimTarget;
189 srcStep -= 2*dimSource;
190 dstStep -= 2*dimTarget;
191 }
192 while (--numPts >= 0)
193 {
194 System.arraycopy (srcPts, srcOff, dstPts, dstOff, firstAffectedOrdinate);
195 transform.transform(srcPts, srcOff+=firstAffectedOrdinate, dstPts, dstOff+=firstAffectedOrdinate, 1);
196 System.arraycopy (srcPts, srcOff+=subDimSource, dstPts, dstOff+=subDimTarget, numTrailingOrdinates);
197 srcOff += srcStep;
198 dstOff += dstStep;
199 }
200 }
201
202 /**
203 * Gets the derivative of this transform at a point.
204 */
205 public Matrix derivative(final CoordinatePoint point) throws TransformException
206 {
207 final int nSkipped = firstAffectedOrdinate + numTrailingOrdinates;
208 final int transDim = transform.getDimSource();
209 final int pointDim = point.getDimension();
210 if (pointDim != transDim+nSkipped)
211 {
212 throw new MismatchedDimensionException(pointDim, transDim+nSkipped);
213 }
214 final CoordinatePoint subPoint = new CoordinatePoint(transDim);
215 System.arraycopy(point.ord, firstAffectedOrdinate, subPoint.ord, 0, transDim);
216 final Matrix subMatrix = transform.derivative(subPoint);
217 final int numRow = subMatrix.getNumRow();
218 final int numCol = subMatrix.getNumCol();
219 final Matrix matrix = new Matrix(nSkipped+numRow, nSkipped+numCol);
220 matrix.setZero();
221
222 // Set UL part to 1: [ 1 0 ]
223 // [ 0 1 ]
224 // [ ]
225 // [ ]
226 // [ ]
227 for (int j=0; j<firstAffectedOrdinate; j++)
228 matrix.setElement(j,j,1);
229
230 // Set central part: [ 1 0 0 0 0 0 ]
231 // [ 0 1 0 0 0 0 ]
232 // [ 0 0 ? ? ? 0 ]
233 // [ 0 0 ? ? ? 0 ]
234 // [ ]
235 subMatrix.copySubMatrix(0,0,numRow,numCol,firstAffectedOrdinate,firstAffectedOrdinate, matrix);
236
237 // Set LR part to 1: [ 1 0 0 0 0 0 ]
238 // [ 0 1 0 0 0 0 ]
239 // [ 0 0 ? ? ? 0 ]
240 // [ 0 0 ? ? ? 0 ]
241 // [ 0 0 0 0 0 1 ]
242 final int offset = numCol-numRow;
243 for (int j=pointDim-numTrailingOrdinates; j<pointDim; j++)
244 matrix.setElement(j, j+offset, 1);
245
246 return matrix;
247 }
248
249 /**
250 * Creates the inverse transform of this object.
251 */
252 public synchronized MathTransform inverse() throws NoninvertibleTransformException
253 {
254 if (inverse==null)
255 {
256 inverse = new PassThroughTransform(firstAffectedOrdinate, transform.inverse(), numTrailingOrdinates);
257 inverse.inverse = this;
258 }
259 return inverse;
260 }
261
262 /**
263 * Compares the specified object with
264 * this math transform for equality.
265 */
266 public boolean equals(final Object object)
267 {
268 if (object==this) return true;
269 if (super.equals(object))
270 {
271 final PassThroughTransform that = (PassThroughTransform) object;
272 return this.firstAffectedOrdinate == that.firstAffectedOrdinate &&
273 this.numTrailingOrdinates == that.numTrailingOrdinates &&
274 Utilities.equals(this.transform, that.transform);
275 }
276 return false;
277 }
278
279 /**
280 * Returns the WKT for this math transform.
281 */
282 public String toString()
283 {
284 final StringBuffer buffer = new StringBuffer("PASSTHROUGH_MT[");
285 buffer.append(firstAffectedOrdinate);
286 buffer.append(',');
287 if (numTrailingOrdinates!=0)
288 {
289 // TODO: This parameter is not part of OpenGIS specification!
290 // We should returns a more complex WKT here, using an
291 // affine transform to change the coordinates order.
292 buffer.append(numTrailingOrdinates);
293 buffer.append(',');
294 }
295 buffer.append(transform);
296 buffer.append(']');
297 return buffer.toString();
298 }
299 }