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 }