View Javadoc

1   /*
2    * Trip Tracker, a real-time position tracking system for the Internet.
3    * Copyright (C) 2006  Team Trip Tracker
4    *
5    * This program is free software; you can redistribute it and/or modify it
6    * under the terms of the GNU General Public License as published by the
7    * Free Software Foundation; either version 2 of the License, or (at your
8    * option) any later version.
9    *
10   * This program is distributed in the hope that it will be useful, but
11   * WITHOUT ANY WARRANTY; without even the implied warranty of
12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13   * General Public License for more details.
14   *
15   * You should have received a copy of the GNU General Public License along
16   * with this program; if not, write to the Free Software Foundation, Inc.,
17   * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
18   */
19  
20  package triptracker.client.map.core;
21  
22  import java.util.Arrays;
23  
24  public class SimpleMatrixOps {
25  	// TODO Attempt to convert the list of basic matrices into an enum.  
26  	
27  //public enum MatrixOps {
28  //IDENTITY3X3 ( new double[][] { { 1, 0, 0 }, { 0, 1, 0 }, { 0, 0, 1 } } ),
29  //ROTATE90D3X3 ( new double[][] { { 0, -1, 0 }, { 1, 0, 0 }, { 0, 0, 1 } } ),
30  //ROTATE180d3X3 ( new double[][] { { -1, 0, 0 }, { 0, -1, 0 }, { 0, 0, 1 } } ),
31  //ROTATE180d3X3 ( new double[][] { { -1, 0, 0 }, { 0, -1, 0 }, { 0, 0, 1 } } ),
32  //ROTATE180d3X3 ( new double[][] { { -1, 0, 0 }, { 0, -1, 0 }, { 0, 0, 1 } } ),
33  //ROTATE180d3X3 ( new double[][] { { -1, 0, 0 }, { 0, -1, 0 }, { 0, 0, 1 } } ),
34  //ROTATE180d3X3 ( new double[][] { { -1, 0, 0 }, { 0, -1, 0 }, { 0, 0, 1 } } ),
35  //ROTATE180d3X3 ( new double[][] { { -1, 0, 0 }, { 0, -1, 0 }, { 0, 0, 1 } } ),
36  //ROTATE180d3X3 ( new double[][] { { -1, 0, 0 }, { 0, -1, 0 }, { 0, 0, 1 } } ),
37  //ROTATE180d3X3 ( new double[][] { { -1, 0, 0 }, { 0, -1, 0 }, { 0, 0, 1 } } ),
38  //ROTATE180d3X3 ( new double[][] { { -1, 0, 0 }, { 0, -1, 0 }, { 0, 0, 1 } } ),
39  //ROTATE180d3X3 ( new double[][] { { -1, 0, 0 }, { 0, -1, 0 }, { 0, 0, 1 } } ),
40  //ROTATE180d3X3 ( new double[][] { { -1, 0, 0 }, { 0, -1, 0 }, { 0, 0, 1 } } );
41  //		
42  //		
43  //		private final double[][] mat;
44  //		
45  //		MatrixOps(double[][] mat) {
46  //			this.mat = mat;
47  //		}
48  //		
49  //		public double[][] matrix() {
50  //			return mat;
51  //		}
52  //	}
53  	
54  	/*** 3x3 identity matrix.  */
55      public static final double[][] identity3x3 = {
56      	{  1,  0,  0 },
57      	{  0,  1,  0 },
58      	{  0,  0,  1 }
59      };
60      
61      /*** 90 degrees (anti-clockwise?) rotation matrix. */
62      public static final double[][] rotate90d3x3 = {
63      	{  0, -1,  0 },
64      	{  1,  0,  0 },
65      	{  0,  0,  1 }
66      };
67      
68      /*** 180 degrees rotation matrix. */
69      public static final double[][] rotate180d3x3 = {
70      	{ -1,  0,  0 },
71      	{  0, -1,  0 },
72      	{  0,  0,  1 }
73      };
74      
75      /*** 270 degrees (anti-clockwise?) rotation matrix */
76      public static final double[][] rotate270d3x3 = {
77      	{  0,  1,  0 },
78      	{ -1,  0,  0 },
79      	{  0,  0,  1 }
80      };
81      
82      /*** X-axis scaling matrix. */
83      public static final double[][] scalex3x3 = {
84      	{  1,  0,  0 },
85      	{  0,  0,  0 },
86      	{  0,  0,  0 }
87      };
88      
89      /*** Y-axis scaling matrix. */
90      public static final double[][] scaley3x3 = {
91      	{  0,  0,  0 },
92      	{  0,  1,  0 },
93      	{  0,  0,  0 }
94      };
95  
96      /*** X-axis translation matrix. */
97      public static final double[][] translatex3x3 = {
98      	{  0,  0,  1 },
99      	{  0,  0,  0 },
100     	{  0,  0,  0 }
101     };
102     
103     /*** Y-axis translation matrix. */
104     public static final double[][] translatey3x3 = {
105     	{  0,  0,  0 },
106     	{  0,  0,  1 },
107     	{  0,  0,  0 }
108     };
109     
110     /*** Flip matrix. Scale -1 about the y-axis (invert all x values) */
111     public static final double[][] flip3x3 =
112     	add(multiply(-1, scalex3x3), identity3x3);
113 
114     /*** Mirror matrix. Scale -1 about the x-axis (invert all y values) */
115     public static final double[][] mirror3x3 =
116     	add(multiply(-1, scaley3x3), identity3x3);
117     
118     
119     /*** All rotation matrices. */
120     public static final double[][][] rotate3x3 = {
121     	identity3x3,
122     	rotate90d3x3,
123     	rotate180d3x3,
124     	rotate270d3x3
125     };
126 
127     /*** Both scaling matrices. */
128     public static final double[][][] scale3x3 = {
129     	scalex3x3,
130     	scaley3x3
131     };
132     
133     /*** Both translation matrices. */
134     public static final double[][][] translate3x3 = {
135     	translatex3x3,
136     	translatey3x3
137     };
138 
139     /***
140      * Perform a matrix multiplication operation. In matrix multiplication the
141      * order of the matrices is essential to the final result.
142      * 
143      * @param mat1 the first matrix
144      * @param mat2 the second matrix
145      * @return resulting multiplied matrix
146      * @throws IllegalArgumentException if not all matrices are the same size
147      */
148     public static double[][] multiply(double[][] mat1, double[][] mat2) {
149         double[][] result = new double[mat1.length][mat2[0].length];
150 
151         // Check for 
152         if (mat1[0].length != mat2.length)
153             throw new IllegalArgumentException("incompatible dimensions");
154 
155         for (int row = 0; row < result.length; row++) {
156             for (int col = 0; col < result[0].length; col++) {
157                 int val = 0;
158                 for (int i = 0; i < result.length; i++) {
159                     val += mat1[row][i] * mat2[i][col];
160                 }
161                 result[row][col] = val;
162             }
163         }
164 
165         return result;
166     }
167 
168     /***
169      * Multiply a matrix by a factor. 
170      * 
171      * @param factor
172      * @param matrix 
173      * @return matrix with elements multiplied by the factor
174      */
175     public static double[][] multiply(double factor, double[][] matrix) {
176         double[][] result = new double[matrix.length][matrix[0].length];
177 
178         for (int i = 0; i < matrix.length; i++) {
179             for (int j = 0; j < matrix[0].length; j++) {
180                 result[i][j] = factor * matrix[i][j];
181             }
182         }
183 
184         return result;
185     }
186 
187 //     public static double[][] add(double[][] mat1, double[][] mat2) {
188 //        double[][] result = new double[mat1.length][mat1[0].length];
189 //
190 //        if (mat1.length != mat2.length || mat1[0].length != mat2[0].length)
191 //            throw new IllegalArgumentException("incompatible dimensions");
192 //
193 //        for (int i = 0; i < result.length; i++) {
194 //            for (int j = 0; j < result[0].length; j++) {
195 //                result[i][j] = mat1[i][j] + mat2[i][j];
196 //            }
197 //        }
198 //
199 //        return result;
200 //    }
201 
202     /***
203      * Perform a matrix addition operation on an abitrary number of matrices.
204      * 
205      * @param matrices matrices to perform the addition operation on
206      * @return matrix with all the elements added
207      * @throws IllegalArgumentException if matrix dimensions are incompatible
208      */
209     public static double[][] add(double[][]... matrices) {
210         double[][] result
211         		= new double[matrices[0].length][matrices[0][0].length];
212 
213         // For each matrix to add.
214         for (int mat = 0; mat < matrices.length; mat++) {
215             // Compare the input matrix size to the result matrix.
216             if (result.length != matrices[mat].length 
217             		|| result[0].length != matrices[mat][0].length)
218                 throw new IllegalArgumentException("incompatible dimensions");
219 
220             // Add values to result matrix.
221             for (int i = 0; i < result.length; i++) {
222                 for (int j = 0; j < result[0].length; j++) {
223                     result[i][j] += matrices[mat][i][j];
224                 }
225             }
226         }
227 
228         return result;
229     }
230 
231     // XXX Proof of concept method to apply generics with the Matrix2D class
232     // TODO Maybe move these operations directly into the Matrix2D class
233     // TODO Use the new Matrix2D MatrixIterator to perform the operation. 
234     public static Matrix2D<? extends Number> add(
235     		Matrix2D<? extends Number>... matrices) {
236         Matrix2D<Number> result = new Matrix2D<Number>(
237         		new Number[matrices[0].getLength(0)][matrices[0].getLength(1)]);
238 
239         // For each matrix to add.
240         for (int mat = 0; mat < matrices.length; mat++) {
241             // Compare the input matrix size to the result matrix.
242             if (result.getLength(0) != matrices[mat].getLength(0)
243                     || result.getLength(1) != matrices[mat].getLength(1))
244                 throw new IllegalArgumentException("incompatible dimensions");
245 
246             // Add values to result matrix.
247 //           for (Number num : result) {
248 //            	num = num.doubleValue()
249 //            			+ matrices[mat].get(num. i, j).doubleValue();
250 //			}
251             
252         }
253 
254         return result;
255     }
256     
257     // TODO Convert to double/Number processing.
258    /***
259      * Expand a matrix until it becomes square. The extra rows or columns added,
260      * to give the matrix an equal amount of rows and columns, will be filled
261      * with the value false.
262      * 
263      * @param layout matrix
264      * @return squared matrix
265      */
266     public static boolean[][] expandToSquare(boolean[][] layout) {
267         int length = (layout.length > layout[0].length ? layout.length
268                 : layout[0].length);
269         boolean[][] matrix = new boolean[length][length];
270 
271         Arrays.fill(matrix, false); // Fill array with false for safety.
272 
273         // Fill array with values from layout.
274         for (int i = 0; i < layout.length; i++) {
275             for (int j = 0; j < layout[0].length; j++) {
276                 matrix[i][j] = layout[i][j];
277             }
278         }
279 
280         return matrix;
281     }
282     
283     // XXX Finish this.
284     public static Matrix2D<Number> expandToSquares(Matrix2D<Number> mat,
285     		Number defaultValue) {
286         int length = (mat.getLength(0) > mat.getLength(1) ? mat.getLength(0)
287                 : mat.getLength(1));
288         Matrix2D<Number> mat2d = new Matrix2D<Number>();
289         Number[][] matrix = new Number[length][length];
290 
291         Arrays.fill(matrix, defaultValue); // Fill array with default value.
292 
293         // Fill array with values from input matrix.
294 //        mat.getMatrix()
295 //        for (int i = 0; i < mat.length; i++) {
296 //            for (int j = 0; j < mat[0].length; j++) {
297 //                matrix[i][j] = mat[i][j];
298 //            }
299 //        }
300         
301         mat2d.setMatrix(matrix);
302 
303         return new Matrix2D<Number>();
304 //        return matrix;
305     }
306    
307     
308     
309 
310     // TODO Convert to double/Number processing.
311     /***
312      * Minimize the matrix by removing rows and columns from either of the four
313      * sides where all the elements are false. 
314      */
315     public static boolean[][] minimize(boolean[][] layout) {
316         boolean[][] minimized;
317         int x1 = 0, x2 = 0;
318         int y1 = 0, y2 = 0;
319 
320         // TODO Could use 90 degree rotation matrix operations.
321 
322         // Find the top edge.
323         outer: for (int i = 0; i < layout.length; i++) {
324             y1 = i;
325             for (int j = 0; j < layout[0].length; j++) {
326                 if (layout[i][j])
327                     break outer;
328             }
329         }
330 
331         // Find the bottom edge.
332         outer: for (int i = layout.length - 1; i >= 0; i--) {
333             y2 = i;
334             for (int j = 0; j < layout[0].length; j++) {
335                 if (layout[i][j])
336                     break outer;
337             }
338         }
339 
340         // Find the left edge.
341         outer: for (int j = 0; j < layout[0].length; j++) {
342             x1 = j;
343             for (int i = 0; i < layout.length; i++) {
344                 if (layout[i][j])
345                     break outer;
346             }
347         }
348 
349         // Find the right edge.
350         outer: for (int j = layout[0].length - 1; j >= 0; j--) {
351             x2 = j;
352             for (int i = 0; i < layout.length; i++) {
353                 if (layout[i][j])
354                     break outer;
355             }
356         }
357 
358         // TODO Examine if System.arraycopy() could do the job instead.
359         // Build the minimized layout from the edge coordinates.
360         minimized = new boolean[y2 - y1 + 1][x2 - x1 + 1];
361         
362         for (int i = y1; i <= y2; i++) {
363             for (int j = x1; j <= x2; j++) {
364                 minimized[i - y1][j - x1] = layout[i][j];
365             }
366         }
367 
368         return minimized;
369     }
370 
371 }