001 //$HeadURL: svn+ssh://jwilden@svn.wald.intevation.org/deegree/base/branches/2.5_testing/src/org/deegree/crs/utilities/Matrix.java $ 002 /*---------------------------------------------------------------------------- 003 This file is part of deegree, http://deegree.org/ 004 Copyright (C) 2001-2009 by: 005 Department of Geography, University of Bonn 006 and 007 lat/lon GmbH 008 009 This library is free software; you can redistribute it and/or modify it under 010 the terms of the GNU Lesser General Public License as published by the Free 011 Software Foundation; either version 2.1 of the License, or (at your option) 012 any later version. 013 This library is distributed in the hope that it will be useful, but WITHOUT 014 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 015 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 016 details. 017 You should have received a copy of the GNU Lesser General Public License 018 along with this library; if not, write to the Free Software Foundation, Inc., 019 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 020 021 Contact information: 022 023 lat/lon GmbH 024 Aennchenstr. 19, 53177 Bonn 025 Germany 026 http://lat-lon.de/ 027 028 Department of Geography, University of Bonn 029 Prof. Dr. Klaus Greve 030 Postfach 1147, 53001 Bonn 031 Germany 032 http://www.geographie.uni-bonn.de/deegree/ 033 034 e-mail: info@deegree.org 035 ----------------------------------------------------------------------------*/ 036 package org.deegree.crs.utilities; 037 038 import static org.deegree.crs.projections.ProjectionUtils.EPS11; 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 047 /** 048 * The <code>Matrix</code> class TODO add documentation here 049 * 050 * @author <a href="mailto:bezema@lat-lon.de">Rutger Bezema</a> 051 * 052 * @author last edited by: $Author: mschneider $ 053 * 054 * @version $Revision: 18195 $, $Date: 2009-06-18 17:55:39 +0200 (Do, 18 Jun 2009) $ 055 * 056 */ 057 058 public class Matrix extends GMatrix { 059 /** 060 * Serial number for interoperability with different versions. 061 */ 062 private static final long serialVersionUID = 3778102551617232269L; 063 064 /** 065 * Construct a square identity matrix of size <code>size</code> × <code>size</code>. 066 * 067 * @param size 068 */ 069 public Matrix( final int size ) { 070 super( size, size ); 071 } 072 073 /** 074 * Construct a matrix of size <code>numRow</code> × <code>numCol</code>. Elements on the 075 * diagonal <var>j==i</var> are set to 1. 076 * 077 * @param numRow 078 * @param numCol 079 */ 080 public Matrix( final int numRow, final int numCol ) { 081 super( numRow, numCol ); 082 } 083 084 /** 085 * Constructs a <code>numRow</code> × <code>numCol</code> matrix initialized to the values in 086 * the <code>matrix</code> array. The array values are copied in one row at a time in row major fashion. The array 087 * should be exactly <code>numRow*numCol</code> in length. Note that because row and column numbering begins with 088 * zero, <code>row</code> and <code>numCol</code> will be one larger than the maximum possible matrix index 089 * values. 090 * 091 * @param numRow 092 * @param numCol 093 * @param matrix 094 */ 095 public Matrix( final int numRow, final int numCol, final double[] matrix ) { 096 super( numRow, numCol, matrix ); 097 if ( numRow * numCol != matrix.length ) { 098 throw new IllegalArgumentException( String.valueOf( matrix.length ) ); 099 } 100 } 101 102 /** 103 * Constructs a new matrix from a two-dimensional array of doubles. 104 * 105 * @param matrix 106 * Array of rows. Each row must have the same length. 107 * @throws IllegalArgumentException 108 * if the specified matrix is not regular (i.e. if all rows doesn't have the same length). 109 */ 110 public Matrix( final double[][] matrix ) throws IllegalArgumentException { 111 super( matrix.length, ( matrix.length != 0 ) ? matrix[0].length : 0 ); 112 final int numRow = getNumRow(); 113 final int numCol = getNumCol(); 114 for ( int j = 0; j < numRow; j++ ) { 115 if ( matrix[j].length != numCol ) { 116 throw new IllegalArgumentException( "Not a regular Matrix (given rows have different lengths)" ); 117 } 118 setRow( j, matrix[j] ); 119 } 120 } 121 122 /** 123 * Constructs a new matrix and copies the initial values from the parameter matrix. 124 * 125 * @param matrix 126 */ 127 public Matrix( final GMatrix matrix ) { 128 super( matrix ); 129 } 130 131 /** 132 * Construct a 3×3 matrix from the specified affine transform. 133 * 134 * @param transform 135 */ 136 public Matrix( final AffineTransform transform ) { 137 super( 3, 3, new double[] { transform.getScaleX(), transform.getShearX(), transform.getTranslateX(), 138 transform.getShearY(), transform.getScaleY(), transform.getTranslateY(), 0, 0, 1 } ); 139 } 140 141 /** 142 * Construct an affine transform changing axis order. The resulting affine transform will convert incoming 143 * coordinates into the given destination Axis. For example if source axis are given with (NORTH,WEST) and 144 * destination axis as (EAST,NORTH) assuming the axis use the same units, the resulted matrix will look like:<br/><code> 145 * 0, 1, 0<br/> 146 * -1, 0, 0<br/> 147 * 0, 0, 1<br/> 148 * </code> 149 * Axis orientation can be inverted only. Rotating axis (e.g. from NORTH,WEST, to NORTH,DOWN, ) is not supported. 150 * 151 * @param srcAxis 152 * The set of axis orientation for source coordinate system. 153 * @param dstAxis 154 * The set of axis orientation for destination coordinate system. 155 * @throws IllegalArgumentException 156 * if the affine transform can't be created for some other reason. 157 */ 158 public Matrix( final Axis[] srcAxis, final Axis[] dstAxis ) { 159 this( srcAxis.length + 1 ); 160 final int dimension = srcAxis.length; 161 if ( dstAxis.length != dimension ) { 162 throw new IllegalArgumentException( "Given dimensions are of differnt length." ); 163 } 164 /* 165 * Map source axis to destination axis. If no axis is moved (for example if the user want to transform 166 * (NORTH,EAST) to (SOUTH,EAST)), then source and destination index will be equal. If some axis are moved (for 167 * example if the user want to transform (NORTH,EAST) to (EAST,NORTH)), then ordinates at index <code>srcIndex</code> 168 * will have to be moved at index <code>dstIndex</code>. 169 */ 170 setZero(); 171 for ( int srcIndex = 0; srcIndex < dimension; srcIndex++ ) { 172 boolean hasFound = false; 173 final int srcAxe = srcAxis[srcIndex].getOrientation(); 174 final int sourceAxisDirection = Math.abs( srcAxe ); 175 for ( int dstIndex = 0; dstIndex < dimension; dstIndex++ ) { 176 final int dstAxeDirection = dstAxis[dstIndex].getOrientation(); 177 if ( sourceAxisDirection == Math.abs( dstAxeDirection ) ) { 178 if ( hasFound ) { 179 throw new IllegalArgumentException( "Following axis are colinear: " 180 + srcAxis[srcIndex].getName() + " dstAxe: " 181 + dstAxis[dstIndex].getName() ); 182 } 183 hasFound = true; 184 // row, column, value 185 setElement( dstIndex, srcIndex, ( srcAxe == dstAxeDirection ) ? 1 : -1 ); 186 } 187 } 188 if ( !hasFound ) { 189 throw new IllegalArgumentException( "No appropriate transformation axis found for srcAxis: " 190 + srcAxis[srcIndex].getName() ); 191 } 192 } 193 setElement( dimension, dimension, 1 ); 194 195 } 196 197 /** 198 * Returns <code>true</code> if this matrix is an affine transform. A transform is affine if the matrix is square 199 * and last row contains only zeros, except in the last column which contains 1. 200 * 201 * @return <code>true</code> if this matrix is an affine transform. 202 */ 203 public final boolean isAffine() { 204 int dimension = getNumRow(); 205 if ( dimension != getNumCol() ) { 206 return false; 207 } 208 209 dimension--; 210 for ( int i = 0; i <= dimension; i++ ) { 211 if ( Math.abs( getElement( dimension, i ) - ( i == dimension ? 1 : 0 ) ) > EPS11 ) { 212 return false; 213 } 214 } 215 return true; 216 } 217 218 /** 219 * Copies the first 2x3 values into an affine transform object. If not enough values are available, an identity 220 * transform is returned. 221 * 222 * @return an affine transform for this matrix. or an identity if this matrix has not sufficient values. 223 * 224 */ 225 public final Matrix3d toAffineTransform() { 226 if ( getNumCol() < 3 || getNumRow() < 2 ) { 227 return new Matrix3d(); 228 } 229 return new Matrix3d( getElement( 0, 0 ), getElement( 0, 1 ), getElement( 0, 2 ), getElement( 1, 0 ), 230 getElement( 1, 1 ), getElement( 1, 2 ), 0, 0, 1 ); 231 } 232 233 /** 234 * Returns <code>true</code> if this matrix is an identity matrix. 235 * 236 * @return <code>true</code> if this matrix is an identity matrix. 237 */ 238 public final boolean isIdentity() { 239 final int numRow = getNumRow(); 240 final int numCol = getNumCol(); 241 if ( numRow != numCol ) { 242 return false; 243 } 244 for ( int j = 0; j < numRow; j++ ) 245 for ( int i = 0; i < numCol; i++ ) { 246 if ( Math.abs( getElement( j, i ) - ( i == j ? 1 : 0 ) ) > EPS11 ) { 247 return false; 248 } 249 } 250 return true; 251 } 252 }