1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 package org.apache.pdfbox.util; 18 19 import java.awt.geom.AffineTransform; 20 21 /** 22 * This class will be used for matrix manipulation. 23 * 24 * @author <a href="mailto:ben@benlitchfield.com">Ben Litchfield</a> 25 * @version $Revision: 1.14 $ 26 */ 27 public class Matrix implements Cloneable 28 { 29 private float[] single = 30 { 31 1,0,0, 32 0,1,0, 33 0,0,1 34 }; 35 36 /** 37 * Constructor. 38 */ 39 public Matrix() 40 { 41 //default constructor 42 } 43 44 /** 45 * Create an affine transform from this matrix's values. 46 * 47 * @return An affine transform with this matrix's values. 48 */ 49 public AffineTransform createAffineTransform() 50 { 51 AffineTransform retval = new AffineTransform( 52 single[0], single[1], 53 single[3], single[4], 54 single[6], single[7] ); 55 return retval; 56 } 57 58 /** 59 * Set the values of the matrix from the AffineTransform. 60 * 61 * @param af The transform to get the values from. 62 */ 63 public void setFromAffineTransform( AffineTransform af ) 64 { 65 single[0] = (float)af.getScaleX(); 66 single[1] = (float)af.getShearY(); 67 single[3] = (float)af.getShearX(); 68 single[4] = (float)af.getScaleY(); 69 single[6] = (float)af.getTranslateX(); 70 single[7] = (float)af.getTranslateY(); 71 } 72 73 /** 74 * This will get a matrix value at some point. 75 * 76 * @param row The row to get the value from. 77 * @param column The column to get the value from. 78 * 79 * @return The value at the row/column position. 80 */ 81 public float getValue( int row, int column ) 82 { 83 return single[row*3+column]; 84 } 85 86 /** 87 * This will set a value at a position. 88 * 89 * @param row The row to set the value at. 90 * @param column the column to set the value at. 91 * @param value The value to set at the position. 92 */ 93 public void setValue( int row, int column, float value ) 94 { 95 single[row*3+column] = value; 96 } 97 98 /** 99 * Return a single dimension array of all values in the matrix. 100 * 101 * @return The values ot this matrix. 102 */ 103 public float[][] getValues() 104 { 105 float[][] retval = new float[3][3]; 106 retval[0][0] = single[0]; 107 retval[0][1] = single[1]; 108 retval[0][2] = single[2]; 109 retval[1][0] = single[3]; 110 retval[1][1] = single[4]; 111 retval[1][2] = single[5]; 112 retval[2][0] = single[6]; 113 retval[2][1] = single[7]; 114 retval[2][2] = single[8]; 115 return retval; 116 } 117 118 /** 119 * Return a single dimension array of all values in the matrix. 120 * 121 * @return The values ot this matrix. 122 */ 123 public double[][] getValuesAsDouble() 124 { 125 double[][] retval = new double[3][3]; 126 retval[0][0] = single[0]; 127 retval[0][1] = single[1]; 128 retval[0][2] = single[2]; 129 retval[1][0] = single[3]; 130 retval[1][1] = single[4]; 131 retval[1][2] = single[5]; 132 retval[2][0] = single[6]; 133 retval[2][1] = single[7]; 134 retval[2][2] = single[8]; 135 return retval; 136 } 137 138 /** 139 * This will take the current matrix and multipy it with a matrix that is passed in. 140 * 141 * @param b The matrix to multiply by. 142 * 143 * @return The result of the two multiplied matrices. 144 */ 145 public Matrix multiply( Matrix b ) 146 { 147 Matrix result = new Matrix(); 148 149 if (b != null && b.single != null) 150 { 151 float[] bMatrix = b.single; 152 float[] resultMatrix = result.single; 153 resultMatrix[0] = single[0] * bMatrix[0] + single[1] * bMatrix[3] + single[2] * bMatrix[6]; 154 resultMatrix[1] = single[0] * bMatrix[1] + single[1] * bMatrix[4] + single[2] * bMatrix[7]; 155 resultMatrix[2] = single[0] * bMatrix[2] + single[1] * bMatrix[5] + single[2] * bMatrix[8]; 156 resultMatrix[3] = single[3] * bMatrix[0] + single[4] * bMatrix[3] + single[5] * bMatrix[6]; 157 resultMatrix[4] = single[3] * bMatrix[1] + single[4] * bMatrix[4] + single[5] * bMatrix[7]; 158 resultMatrix[5] = single[3] * bMatrix[2] + single[4] * bMatrix[5] + single[5] * bMatrix[8]; 159 resultMatrix[6] = single[6] * bMatrix[0] + single[7] * bMatrix[3] + single[8] * bMatrix[6]; 160 resultMatrix[7] = single[6] * bMatrix[1] + single[7] * bMatrix[4] + single[8] * bMatrix[7]; 161 resultMatrix[8] = single[6] * bMatrix[2] + single[7] * bMatrix[5] + single[8] * bMatrix[8]; 162 } 163 return result; 164 } 165 166 /** 167 * Create a new matrix with just the scaling operators. 168 * 169 * @return A new matrix with just the scaling operators. 170 */ 171 public Matrix extractScaling() 172 { 173 Matrix retval = new Matrix(); 174 175 retval.single[0] = this.single[0]; 176 retval.single[4] = this.single[4]; 177 178 return retval; 179 } 180 181 /** 182 * Convenience method to create a scaled instance. 183 * 184 * @param x The xscale operator. 185 * @param y The yscale operator. 186 * @return A new matrix with just the x/y scaling 187 */ 188 public static Matrix getScaleInstance( float x, float y) 189 { 190 Matrix retval = new Matrix(); 191 192 retval.single[0] = x; 193 retval.single[4] = y; 194 195 return retval; 196 } 197 198 /** 199 * Create a new matrix with just the translating operators. 200 * 201 * @return A new matrix with just the translating operators. 202 */ 203 public Matrix extractTranslating() 204 { 205 Matrix retval = new Matrix(); 206 207 retval.single[6] = this.single[6]; 208 retval.single[7] = this.single[7]; 209 210 return retval; 211 } 212 213 /** 214 * Convenience method to create a translating instance. 215 * 216 * @param x The x translating operator. 217 * @param y The y translating operator. 218 * @return A new matrix with just the x/y translating. 219 */ 220 public static Matrix getTranslatingInstance( float x, float y) 221 { 222 Matrix retval = new Matrix(); 223 224 retval.single[6] = x; 225 retval.single[7] = y; 226 227 return retval; 228 } 229 230 /** 231 * Clones this object. 232 * @return cloned matrix as an object. 233 */ 234 public Object clone() 235 { 236 Matrix clone = new Matrix(); 237 System.arraycopy( single, 0, clone.single, 0, 9 ); 238 return clone; 239 } 240 241 /** 242 * This will copy the text matrix data. 243 * 244 * @return a matrix that matches this one. 245 */ 246 public Matrix copy() 247 { 248 return (Matrix) clone(); 249 } 250 251 /** 252 * This will return a string representation of the matrix. 253 * 254 * @return The matrix as a string. 255 */ 256 public String toString() 257 { 258 StringBuffer result = new StringBuffer( "" ); 259 result.append( "[[" ); 260 result.append( single[0] + "," ); 261 result.append( single[1] + "," ); 262 result.append( single[2] + "]["); 263 result.append( single[3] + "," ); 264 result.append( single[4] + "," ); 265 result.append( single[5] + "]["); 266 result.append( single[6] + "," ); 267 result.append( single[7] + "," ); 268 result.append( single[8] + "]]"); 269 270 return result.toString(); 271 } 272 273 /** 274 * Get the xscaling factor of this matrix. 275 * @return The x-scale. 276 */ 277 public float getXScale() 278 { 279 float xScale = single[0]; 280 281 /** 282 * BM: if the trm is rotated, the calculation is a little more complicated 283 * 284 * The rotation matrix multiplied with the scaling matrix is: 285 * ( x 0 0) ( cos sin 0) ( x*cos x*sin 0) 286 * ( 0 y 0) * (-sin cos 0) = (-y*sin y*cos 0) 287 * ( 0 0 1) ( 0 0 1) ( 0 0 1) 288 * 289 * So, if you want to deduce x from the matrix you take 290 * M(0,0) = x*cos and M(0,1) = x*sin and use the theorem of Pythagoras 291 * 292 * sqrt(M(0,0)^2+M(0,1)^2) = 293 * sqrt(x2*cos2+x2*sin2) = 294 * sqrt(x2*(cos2+sin2)) = <- here is the trick cos2+sin2 is one 295 * sqrt(x2) = 296 * abs(x) 297 */ 298 if( !(single[1]==0.0f && single[3]==0.0f) ) 299 { 300 xScale = (float)Math.sqrt(Math.pow(single[0], 2)+ 301 Math.pow(single[1], 2)); 302 } 303 return xScale; 304 } 305 306 /** 307 * Get the y scaling factor of this matrix. 308 * @return The y-scale factor. 309 */ 310 public float getYScale() 311 { 312 float yScale = single[4]; 313 if( !(single[1]==0.0f && single[3]==0.0f) ) 314 { 315 yScale = (float)Math.sqrt(Math.pow(single[3], 2)+ 316 Math.pow(single[4], 2)); 317 } 318 return yScale; 319 } 320 321 /** 322 * Get the x position in the matrix. 323 * @return The x-position. 324 */ 325 public float getXPosition() 326 { 327 return single[6]; 328 } 329 330 /** 331 * Get the y position. 332 * @return The y position. 333 */ 334 public float getYPosition() 335 { 336 return single[7]; 337 } 338 }