001: //$HeadURL: svn+ssh://rbezema@svn.wald.intevation.org/deegree/base/trunk/src/org/deegree/model/csct/ct/MatrixTransform.java $
002: /*---------------- FILE HEADER ------------------------------------------
003: This file is part of deegree.
004: Copyright (C) 2001-2008 by:
005: Department of Geography, University of Bonn
006: http://www.giub.uni-bonn.de/deegree/
007: lat/lon GmbH
008: http://www.lat-lon.de
009:
010: This library is free software; you can redistribute it and/or
011: modify it under the terms of the GNU Lesser General Public
012: License as published by the Free Software Foundation; either
013: version 2.1 of the License, or (at your option) any later version.
014: This library is distributed in the hope that it will be useful,
015: but WITHOUT ANY WARRANTY; without even the implied warranty of
016: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
017: Lesser General Public License for more details.
018: You should have received a copy of the GNU Lesser General Public
019: License along with this library; if not, write to the Free Software
020: Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
021: Contact:
022:
023: Andreas Poth
024: lat/lon GmbH
025: Aennchenstr. 19
026: 53177 Bonn
027: Germany
028: E-Mail: poth@lat-lon.de
029:
030: Prof. Dr. Klaus Greve
031: Department of Geography
032: University of Bonn
033: Meckenheimer Allee 166
034: 53115 Bonn
035: Germany
036: E-Mail: greve@giub.uni-bonn.de
037: ---------------------------------------------------------------------------*/
038: package org.deegree.crs.transformations;
039:
040: // Geometry
041: import java.util.ArrayList;
042: import java.util.List;
043:
044: import javax.media.jai.PerspectiveTransform;
045: import javax.vecmath.GMatrix;
046: import javax.vecmath.Matrix3d;
047: import javax.vecmath.Matrix4d;
048: import javax.vecmath.Point3d;
049:
050: import org.deegree.crs.coordinatesystems.CoordinateSystem;
051: import org.deegree.crs.projections.ProjectionUtils;
052: import org.deegree.crs.utilities.Matrix;
053:
054: /**
055: *
056: * The <code>MatrixTransform</code> class allows transformations using matrices. Although technically n × m
057: * matrices are possible, at the moment only 2 × 2, 3 × 3 and 4 × 4 matrices are supported.
058: *
059: * @author <a href="mailto:bezema@lat-lon.de">Rutger Bezema</a>
060: *
061: * @author last edited by: $Author:$
062: *
063: * @version $Revision:$, $Date:$
064: *
065: */
066: public class MatrixTransform extends CRSTransformation {
067: /**
068: * Serial number for interoperability with different versions.
069: */
070: private static final long serialVersionUID = -2104496465933824935L;
071:
072: /**
073: * the number of rows.
074: */
075: private final int numRow;
076:
077: /**
078: * the number of columns.
079: */
080: private final int numCol;
081:
082: private GMatrix matrix = null;
083:
084: private GMatrix invertMatrix = null;
085:
086: private Matrix3d matrix3D = null;
087:
088: private Matrix3d invertMatrix3D = null;
089:
090: private Matrix4d matrix4D = null;
091:
092: private Matrix4d invertMatrix4D = null;
093:
094: private String transformationName = "Matrix-Transform";
095:
096: /**
097: * Set super values and numRow,numCol.
098: *
099: * @param source
100: * @param target
101: * @param numRow
102: * @param numCol
103: */
104: private MatrixTransform(CoordinateSystem source,
105: CoordinateSystem target, int numRow, int numCol) {
106: super (source, target);
107: this .numCol = numCol;
108: this .numRow = numRow;
109: }
110:
111: /**
112: * Construct a transform.
113: *
114: * @param source
115: * the source coordinate system
116: * @param target
117: * the target coordinate system.
118: *
119: * @param matrix
120: */
121: public MatrixTransform(CoordinateSystem source,
122: CoordinateSystem target, final GMatrix matrix) {
123: this (source, target, matrix.getNumRow(), matrix.getNumCol());
124: this .matrix = new GMatrix(matrix);
125: invertMatrix = new GMatrix(matrix);
126: invertMatrix.invert();
127: }
128:
129: /**
130: * Construct a 3d transform.
131: *
132: * @param source
133: * the source coordinate system
134: * @param target
135: * the target coordinate system.
136: *
137: * @param matrix
138: */
139: public MatrixTransform(CoordinateSystem source,
140: CoordinateSystem target, final Matrix3d matrix) {
141: this (source, target, 3, 3);
142: this .matrix3D = new Matrix3d(matrix);
143: invertMatrix3D = new Matrix3d();
144: invertMatrix3D.invert(matrix3D);
145: }
146:
147: /**
148: * Construct a 4d transform.
149: *
150: * @param source
151: * the source coordinate system
152: * @param target
153: * the target coordinate system.
154: *
155: * @param matrix
156: */
157: public MatrixTransform(CoordinateSystem source,
158: CoordinateSystem target, Matrix4d matrix) {
159: this (source, target, 4, 4);
160: matrix4D = new Matrix4d(matrix);
161: invertMatrix4D = new Matrix4d();
162: invertMatrix4D.invert(matrix4D);
163: }
164:
165: /**
166: * Construct a 4d transform.
167: *
168: * @param source
169: * the source coordinate system
170: * @param target
171: * the target coordinate system.
172: *
173: * @param matrix
174: * @param transformationName
175: * the 'optional' name of the transformation, which is useful to specify the 'helmert' transformation.
176: */
177: public MatrixTransform(CoordinateSystem source,
178: CoordinateSystem target, Matrix4d matrix,
179: String transformationName) {
180: this (source, target, matrix);
181: if (transformationName != null) {
182: this .transformationName = transformationName;
183: }
184: }
185:
186: @Override
187: public List<Point3d> doTransform(List<Point3d> srcPts) {
188: if (isIdentity()) {
189: return srcPts;
190: }
191: List<Point3d> results = new ArrayList<Point3d>(srcPts);
192: if (isInverseTransform()) {
193: if (matrix3D != null) {
194: transform(invertMatrix3D, results);
195: } else if (matrix4D != null) {
196: transform(invertMatrix4D, results);
197: } else {
198: transform(invertMatrix, results);
199: }
200: } else {
201: if (matrix3D != null) {
202: transform(matrix3D, results);
203: } else if (matrix4D != null) {
204: transform(matrix4D, results);
205: } else {
206: transform(matrix, results);
207: }
208: }
209: return results;
210: }
211:
212: /**
213: * @return the dimension of input points.
214: */
215: public int getDimSource() {
216: return numCol - 1;
217: }
218:
219: /**
220: * @return the dimension of output points.
221: */
222: public int getDimTarget() {
223: return numRow - 1;
224: }
225:
226: /**
227: * @return true if this transformation holds an identity matrix (e.g. doesn't transform at all).
228: */
229: @Override
230: public boolean isIdentity() {
231: if (numRow != numCol) {
232: return false;
233: }
234: for (int row = 0; row < numRow; row++)
235: for (int col = 0; col < numCol; col++) {
236: double value = (matrix3D != null) ? matrix3D
237: .getElement(row, col)
238: : ((matrix4D != null) ? matrix4D.getElement(
239: row, col) : matrix.getElement(row, col));
240: if (Math.abs(value - (col == row ? 1 : 0)) > ProjectionUtils.EPS11) {
241: return false;
242: }
243: }
244: return true;
245: // return true;
246: }
247:
248: @Override
249: public boolean equals(final Object object) {
250: if (object == this ) {
251: return true; // Slight optimization
252: }
253: if (object != null && super .equals(object)) {
254: return matrix.equals(((MatrixTransform) object).matrix);
255: }
256: return false;
257: }
258:
259: /**
260: * Transforms an array of floating point coordinates by this matrix. Point coordinates must have a dimension equals
261: * to <code>{@link Matrix#getNumCol()}-1</code>. For example, for square matrix of size 4×4, coordinate
262: * points are three-dimensional and stored in the arrays starting at the specified offset (<code>srcOff</code>)
263: * in the order <code>[x<sub>0</sub>, y<sub>0</sub>, z<sub>0</sub>,
264: * x<sub>1</sub>, y<sub>1</sub>, z<sub>1</sub>...,
265: * x<sub>n</sub>, y<sub>n</sub>, z<sub>n</sub>]</code>.
266: *
267: * The transformed points <code>(x',y',z')</code> are computed as below (note that this computation is similar to
268: * {@link PerspectiveTransform}):
269: *
270: * <blockquote> <code>
271: * <pre>
272: * [ u ] [ m<sub>00</sub> m<sub>01</sub> m<sub>02</sub> m<sub>03</sub> ] [ x ]
273: * [ v ] = [ m<sub>10</sub> m<sub>11</sub> m<sub>12</sub> m<sub>13</sub> ] [ y ]
274: * [ w ] [ m<sub>20</sub> m<sub>21</sub> m<sub>22</sub> m<sub>23</sub> ] [ z ]
275: * [ t ] [ m<sub>30</sub> m<sub>31</sub> m<sub>32</sub> m<sub>33</sub> ] [ 1 ]
276: *
277: * x' = u/t
278: * y' = v/t
279: * w' = w/t
280: * </pre>
281: * </code> </blockquote>
282: *
283: * @param srcPts
284: * The array containing the source point coordinates.
285: */
286: private void transform(@SuppressWarnings("unused")
287: GMatrix gm, List<Point3d> srcPts) {
288: throw new UnsupportedOperationException("not yet implemented");
289: // final int inputDimension = numCol - 1; // The last value will be assumed equals to 1.
290: // final int outputDimension = numRow - 1;
291: // final double[] buffer = new double[numRow];
292: // while ( --numPts >= 0 ) {
293: // int mix = 0;
294: // for ( int j = 0; j < numRow; j++ ) {
295: // // double sum = elt[mix + inputDimension];
296: // // for ( int i = 0; i < inputDimension; i++ ) {
297: // // sum += srcPts[srcOff + i] * elt[mix++];
298: // // }
299: // // buffer[j] = sum;
300: // mix++;
301: // }
302: // final double w = buffer[outputDimension];
303: // for ( int j = 0; j < outputDimension; j++ ) {
304: // // 'w' is equals to 1 if the transform is affine.
305: // dstPts[dstOff++] = buffer[j] / w;
306: // }
307: // srcOff += inputDimension;
308: // }
309:
310: }
311:
312: /**
313: * Use the given GMatrix to transform the given points inplace.
314: *
315: * @param m4d
316: * the matrix to use (e.g. the inverse matrix or the forward matrix.
317: * @param srcPts
318: * The array containing the source point coordinates.
319: */
320: private void transform(Matrix4d m4d, List<Point3d> srcPts) {
321: for (Point3d p : srcPts) {
322: m4d.transform(p);
323: }
324: }
325:
326: /**
327: * Use the given GMatrix to transform the given points in-place.
328: *
329: * @param m3d
330: * the matrix to use (e.g. the inverse matrix or the forward matrix).
331: * @param srcPts
332: * The array containing the source point coordinates.
333: */
334: private void transform(Matrix3d m3d, List<Point3d> srcPts) {
335: for (Point3d p : srcPts) {
336: boolean zIsNaN = Double.isNaN(p.z);
337: if (zIsNaN) {
338: p.z = 0;
339: }
340: m3d.transform(p);
341: if (zIsNaN) {
342: p.z = Double.NaN;
343: }
344: }
345: }
346:
347: /**
348: * @return the matrix.
349: */
350: public final GMatrix getMatrix() {
351: if (matrix != null) {
352: return isInverse ? invertMatrix : matrix;
353: }
354: GMatrix result = new GMatrix(numRow, numCol);
355: if (matrix3D != null) {
356: if (isInverse) {
357: result.set(invertMatrix3D);
358: } else {
359: result.set(matrix3D);
360: }
361: }
362: if (matrix4D != null) {
363: if (isInverse) {
364: result.set(invertMatrix4D);
365: } else {
366: result.set(matrix4D);
367: }
368: }
369: return result;
370: }
371:
372: @Override
373: public String getName() {
374: return transformationName;
375: }
376:
377: }
|