001: //$HeadURL: https://sushibar/svn/deegree/base/trunk/src/org/deegree/model/csct/pt/Matrix.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.utilities;
039:
040: import java.awt.geom.AffineTransform;
041:
042: import javax.vecmath.GMatrix;
043: import javax.vecmath.Matrix3d;
044:
045: import org.deegree.crs.components.Axis;
046: import org.deegree.crs.projections.ProjectionUtils;
047:
048: /**
049: * The <code>Matrix</code> class TODO add documentation here
050: *
051: * @author <a href="mailto:bezema@lat-lon.de">Rutger Bezema</a>
052: *
053: * @author last edited by: $Author:$
054: *
055: * @version $Revision:$, $Date:$
056: *
057: */
058:
059: public class Matrix extends GMatrix {
060: /**
061: * Serial number for interoperability with different versions.
062: */
063: private static final long serialVersionUID = 3778102551617232269L;
064:
065: /**
066: * Construct a square identity matrix of size <code>size</code> × <code>size</code>.
067: *
068: * @param size
069: */
070: public Matrix(final int size) {
071: super (size, size);
072: }
073:
074: /**
075: * Construct a matrix of size <code>numRow</code> × <code>numCol</code>. Elements on the
076: * diagonal <var>j==i</var> are set to 1.
077: *
078: * @param numRow
079: * @param numCol
080: */
081: public Matrix(final int numRow, final int numCol) {
082: super (numRow, numCol);
083: }
084:
085: /**
086: * Constructs a <code>numRow</code> × <code>numCol</code> matrix initialized to the values in
087: * the <code>matrix</code> array. The array values are copied in one row at a time in row major fashion. The array
088: * should be exactly <code>numRow*numCol</code> in length. Note that because row and column numbering begins with
089: * zero, <code>row</code> and <code>numCol</code> will be one larger than the maximum possible matrix index
090: * values.
091: *
092: * @param numRow
093: * @param numCol
094: * @param matrix
095: */
096: public Matrix(final int numRow, final int numCol,
097: final double[] matrix) {
098: super (numRow, numCol, matrix);
099: if (numRow * numCol != matrix.length) {
100: throw new IllegalArgumentException(String
101: .valueOf(matrix.length));
102: }
103: }
104:
105: /**
106: * Constructs a new matrix from a two-dimensional array of doubles.
107: *
108: * @param matrix
109: * Array of rows. Each row must have the same length.
110: * @throws IllegalArgumentException
111: * if the specified matrix is not regular (i.e. if all rows doesn't have the same length).
112: */
113: public Matrix(final double[][] matrix)
114: throws IllegalArgumentException {
115: super (matrix.length, (matrix.length != 0) ? matrix[0].length
116: : 0);
117: final int numRow = getNumRow();
118: final int numCol = getNumCol();
119: for (int j = 0; j < numRow; j++) {
120: if (matrix[j].length != numCol) {
121: throw new IllegalArgumentException(
122: "Not a regular Matrix (given rows have different lengths)");
123: }
124: setRow(j, matrix[j]);
125: }
126: }
127:
128: /**
129: * Constructs a new matrix and copies the initial values from the parameter matrix.
130: *
131: * @param matrix
132: */
133: public Matrix(final GMatrix matrix) {
134: super (matrix);
135: }
136:
137: /**
138: * Construct a 3×3 matrix from the specified affine transform.
139: *
140: * @param transform
141: */
142: public Matrix(final AffineTransform transform) {
143: super (3, 3, new double[] { transform.getScaleX(),
144: transform.getShearX(), transform.getTranslateX(),
145: transform.getShearY(), transform.getScaleY(),
146: transform.getTranslateY(), 0, 0, 1 });
147: }
148:
149: /**
150: * Construct an affine transform changing axis order. The resulting affine transform will convert incoming
151: * coordinates into the given destination Axis. For example if source axis are given with (NORTH,WEST) and
152: * destination axis as (EAST,NORTH) assuming the axis use the same units, the resulted matrix will look like:<br/><code>
153: * 0, 1, 0<br/>
154: * -1, 0, 0<br/>
155: * 0, 0, 1<br/>
156: * </code>
157: * Axis orientation can be inverted only. Rotating axis (e.g. from NORTH,WEST, to NORTH,DOWN, ) is not supported.
158: *
159: * @param srcAxis
160: * The set of axis orientation for source coordinate system.
161: * @param dstAxis
162: * The set of axis orientation for destination coordinate system.
163: * @throws IllegalArgumentException
164: * if the affine transform can't be created for some other reason.
165: */
166: public Matrix(final Axis[] srcAxis, final Axis[] dstAxis) {
167: this (srcAxis.length + 1);
168: final int dimension = srcAxis.length;
169: if (dstAxis.length != dimension) {
170: throw new IllegalArgumentException(
171: "Given dimensions are of differnt length.");
172: }
173: /*
174: * Map source axis to destination axis. If no axis is moved (for example if the user want to transform
175: * (NORTH,EAST) to (SOUTH,EAST)), then source and destination index will be equal. If some axis are moved (for
176: * example if the user want to transform (NORTH,EAST) to (EAST,NORTH)), then ordinates at index <code>srcIndex</code>
177: * will have to be moved at index <code>dstIndex</code>.
178: */
179: setZero();
180: for (int srcIndex = 0; srcIndex < dimension; srcIndex++) {
181: boolean hasFound = false;
182: final int srcAxe = srcAxis[srcIndex].getOrientation();
183: final int sourceAxisDirection = Math.abs(srcAxe);
184: for (int dstIndex = 0; dstIndex < dimension; dstIndex++) {
185: final int dstAxeDirection = dstAxis[dstIndex]
186: .getOrientation();
187: if (sourceAxisDirection == Math.abs(dstAxeDirection)) {
188: if (hasFound) {
189: throw new IllegalArgumentException(
190: "Following axis are colinear: "
191: + srcAxis[srcIndex].getName()
192: + " dstAxe: "
193: + dstAxis[dstIndex].getName());
194: }
195: hasFound = true;
196: // row, column, value
197: setElement(dstIndex, srcIndex,
198: (srcAxe == dstAxeDirection) ? 1 : -1);
199: }
200: }
201: if (!hasFound) {
202: throw new IllegalArgumentException(
203: "No appropriate transformation axis found for srcAxis: "
204: + srcAxis[srcIndex].getName());
205: }
206: }
207: setElement(dimension, dimension, 1);
208:
209: }
210:
211: /**
212: * Returns <code>true</code> if this matrix is an affine transform. A transform is affine if the matrix is square
213: * and last row contains only zeros, except in the last column which contains 1.
214: *
215: * @return <code>true</code> if this matrix is an affine transform.
216: */
217: public final boolean isAffine() {
218: int dimension = getNumRow();
219: if (dimension != getNumCol()) {
220: return false;
221: }
222:
223: dimension--;
224: for (int i = 0; i <= dimension; i++) {
225: if (Math.abs(getElement(dimension, i)
226: - (i == dimension ? 1 : 0)) > ProjectionUtils.EPS11) {
227: return false;
228: }
229: }
230: return true;
231: }
232:
233: /**
234: * Copies the first 2x3 values into an affine transform object. If not enough values are available, an identity
235: * transform is returned.
236: *
237: * @return an affine transform for this matrix. or an identity if this matrix has not sufficient values.
238: *
239: */
240: public final Matrix3d toAffineTransform() {
241: if (getNumCol() < 3 || getNumRow() < 2) {
242: return new Matrix3d();
243: }
244: return new Matrix3d(getElement(0, 0), getElement(0, 1),
245: getElement(0, 2), getElement(1, 0), getElement(1, 1),
246: getElement(1, 2), 0, 0, 1);
247: }
248:
249: /**
250: * Returns <code>true</code> if this matrix is an identity matrix.
251: *
252: * @return <code>true</code> if this matrix is an identity matrix.
253: */
254: public final boolean isIdentity() {
255: final int numRow = getNumRow();
256: final int numCol = getNumCol();
257: if (numRow != numCol) {
258: return false;
259: }
260: for (int j = 0; j < numRow; j++)
261: for (int i = 0; i < numCol; i++) {
262: if (Math.abs(getElement(j, i) - (i == j ? 1 : 0)) > ProjectionUtils.EPS11) {
263: return false;
264: }
265: }
266: return true;
267: }
268: }
|