1 /* 2 SPDX-FileCopyrightText: 2011 See AUTHORS file. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package org.kde.kstars.math; 8 9 /** from libgdx: https://github.com/libgdx/libgdx */ 10 import java.io.Serializable; 11 12 /** A 3x3 <a href="http://en.wikipedia.org/wiki/Row-major_order">column major</a> matrix; useful for 2D transforms. 13 * 14 * @author mzechner */ 15 public class Matrix3 implements Serializable { 16 private static final long serialVersionUID = 7907569533774959788L; 17 private final static float DEGREE_TO_RAD = (float)Math.PI / 180; 18 public static final int M00 = 0; 19 public static final int M01 = 3; 20 public static final int M02 = 6; 21 public static final int M10 = 1; 22 public static final int M11 = 4; 23 public static final int M12 = 7; 24 public static final int M20 = 2; 25 public static final int M21 = 5; 26 public static final int M22 = 8; 27 public float[] val = new float[9]; 28 private float[] tmp = new float[9]; 29 Matrix3()30 public Matrix3 () { 31 idt(); 32 } 33 Matrix3(Matrix3 matrix)34 public Matrix3 (Matrix3 matrix) { 35 set(matrix); 36 } 37 38 /** Sets this matrix to the identity matrix 39 * @return This matrix for the purpose of chaining operations. */ idt()40 public Matrix3 idt () { 41 val[M00] = 1; 42 val[M10] = 0; 43 val[M20] = 0; 44 val[M01] = 0; 45 val[M11] = 1; 46 val[M21] = 0; 47 val[M02] = 0; 48 val[M12] = 0; 49 val[M22] = 1; 50 return this; 51 } 52 53 /** Multiplies this matrix with the provided matrix and stores the result in this matrix. For example: 54 * 55 * <pre> 56 * A.mul(B) results in A := AB 57 * </pre> 58 * @param m Matrix to multiply by. 59 * @return This matrix for the purpose of chaining operations together. */ mul(Matrix3 m)60 public Matrix3 mul (Matrix3 m) { 61 float v00 = val[M00] * m.val[M00] + val[M01] * m.val[M10] + val[M02] * m.val[M20]; 62 float v01 = val[M00] * m.val[M01] + val[M01] * m.val[M11] + val[M02] * m.val[M21]; 63 float v02 = val[M00] * m.val[M02] + val[M01] * m.val[M12] + val[M02] * m.val[M22]; 64 65 float v10 = val[M10] * m.val[M00] + val[M11] * m.val[M10] + val[M12] * m.val[M20]; 66 float v11 = val[M10] * m.val[M01] + val[M11] * m.val[M11] + val[M12] * m.val[M21]; 67 float v12 = val[M10] * m.val[M02] + val[M11] * m.val[M12] + val[M12] * m.val[M22]; 68 69 float v20 = val[M20] * m.val[M00] + val[M21] * m.val[M10] + val[M22] * m.val[M20]; 70 float v21 = val[M20] * m.val[M01] + val[M21] * m.val[M11] + val[M22] * m.val[M21]; 71 float v22 = val[M20] * m.val[M02] + val[M21] * m.val[M12] + val[M22] * m.val[M22]; 72 73 val[M00] = v00; 74 val[M10] = v10; 75 val[M20] = v20; 76 val[M01] = v01; 77 val[M11] = v11; 78 val[M21] = v21; 79 val[M02] = v02; 80 val[M12] = v12; 81 val[M22] = v22; 82 83 return this; 84 } 85 86 /** Sets this matrix to a rotation matrix that will rotate any vector in counter-clockwise order around the z-axis. 87 * @param degrees the angle in degrees. 88 * @return This matrix for the purpose of chaining operations. */ setToRotation(float degrees)89 public Matrix3 setToRotation (float degrees) { 90 float angle = DEGREE_TO_RAD * degrees; 91 float cos = (float)Math.cos(angle); 92 float sin = (float)Math.sin(angle); 93 94 this.val[M00] = cos; 95 this.val[M10] = sin; 96 this.val[M20] = 0; 97 98 this.val[M01] = -sin; 99 this.val[M11] = cos; 100 this.val[M21] = 0; 101 102 this.val[M02] = 0; 103 this.val[M12] = 0; 104 this.val[M22] = 1; 105 106 return this; 107 } 108 109 /** Sets this matrix to a translation matrix. 110 * @param x the translation in x 111 * @param y the translation in y 112 * @return This matrix for the purpose of chaining operations. */ setToTranslation(float x, float y)113 public Matrix3 setToTranslation (float x, float y) { 114 this.val[M00] = 1; 115 this.val[M10] = 0; 116 this.val[M20] = 0; 117 118 this.val[M01] = 0; 119 this.val[M11] = 1; 120 this.val[M21] = 0; 121 122 this.val[M02] = x; 123 this.val[M12] = y; 124 this.val[M22] = 1; 125 126 return this; 127 } 128 129 /** Sets this matrix to a translation matrix. 130 * @param translation The translation vector. 131 * @return This matrix for the purpose of chaining operations. */ setToTranslation(Vector2 translation)132 public Matrix3 setToTranslation (Vector2 translation) { 133 this.val[M00] = 1; 134 this.val[M10] = 0; 135 this.val[M20] = 0; 136 137 this.val[M01] = 0; 138 this.val[M11] = 1; 139 this.val[M21] = 0; 140 141 this.val[M02] = translation.x; 142 this.val[M12] = translation.y; 143 this.val[M22] = 1; 144 145 return this; 146 } 147 148 /** Sets this matrix to a scaling matrix. 149 * 150 * @param scaleX the scale in x 151 * @param scaleY the scale in y 152 * @return This matrix for the purpose of chaining operations. */ setToScaling(float scaleX, float scaleY)153 public Matrix3 setToScaling (float scaleX, float scaleY) { 154 val[M00] = scaleX; 155 val[M10] = 0; 156 val[M20] = 0; 157 val[M01] = 0; 158 val[M11] = scaleY; 159 val[M21] = 0; 160 val[M02] = 0; 161 val[M12] = 0; 162 val[M22] = 1; 163 return this; 164 } 165 toString()166 public String toString () { 167 return "[" + val[0] + "|" + val[3] + "|" + val[6] + "]\n" + "[" + val[1] + "|" + val[4] + "|" + val[7] + "]\n" + "[" 168 + val[2] + "|" + val[5] + "|" + val[8] + "]"; 169 } 170 171 /** @return The determinant of this matrix */ det()172 public float det () { 173 return val[M00] * val[M11] * val[M22] + val[M01] * val[M12] * val[M20] + val[M02] * val[M10] * val[M21] - val[M00] 174 * val[M12] * val[M21] - val[M01] * val[M10] * val[M22] - val[M02] * val[M11] * val[M20]; 175 } 176 177 /** Inverts this matrix given that the determinant is != 0. 178 * @return This matrix for the purpose of chaining operations. */ inv()179 public Matrix3 inv () { 180 float det = det(); 181 if (det == 0) throw new Error("Can't invert a singular matrix"); // changed to error from GdxRuntimeException 182 183 float inv_det = 1.0f / det; 184 185 tmp[M00] = val[M11] * val[M22] - val[M21] * val[M12]; 186 tmp[M10] = val[M20] * val[M12] - val[M10] * val[M22]; 187 tmp[M20] = val[M10] * val[M21] - val[M20] * val[M11]; 188 tmp[M01] = val[M21] * val[M02] - val[M01] * val[M22]; 189 tmp[M11] = val[M00] * val[M22] - val[M20] * val[M02]; 190 tmp[M21] = val[M20] * val[M01] - val[M00] * val[M21]; 191 tmp[M02] = val[M01] * val[M12] - val[M11] * val[M02]; 192 tmp[M12] = val[M10] * val[M02] - val[M00] * val[M12]; 193 tmp[M22] = val[M00] * val[M11] - val[M10] * val[M01]; 194 195 val[M00] = inv_det * tmp[M00]; 196 val[M10] = inv_det * tmp[M10]; 197 val[M20] = inv_det * tmp[M20]; 198 val[M01] = inv_det * tmp[M01]; 199 val[M11] = inv_det * tmp[M11]; 200 val[M21] = inv_det * tmp[M21]; 201 val[M02] = inv_det * tmp[M02]; 202 val[M12] = inv_det * tmp[M12]; 203 val[M22] = inv_det * tmp[M22]; 204 205 return this; 206 } 207 208 /** Copies the values from the provided matrix to this matrix. 209 * @param mat The matrix to copy. 210 * @return This matrix for the purposes of chaining. */ set(Matrix3 mat)211 public Matrix3 set (Matrix3 mat) { 212 System.arraycopy(mat.val, 0, val, 0, val.length); 213 return this; 214 } 215 216 /** Sets this 3x3 matrix to the top left 3x3 corner of the provided 4x4 matrix. 217 * @param mat The matrix whose top left corner will be copied. This matrix will not be modified. 218 * @return This matrix for the purpose of chaining operations. */ set(Matrix4 mat)219 public Matrix3 set (Matrix4 mat) { 220 val[M00] = mat.val[Matrix4.M00]; 221 val[M10] = mat.val[Matrix4.M10]; 222 val[M20] = mat.val[Matrix4.M20]; 223 val[M01] = mat.val[Matrix4.M01]; 224 val[M11] = mat.val[Matrix4.M11]; 225 val[M21] = mat.val[Matrix4.M21]; 226 val[M02] = mat.val[Matrix4.M02]; 227 val[M12] = mat.val[Matrix4.M12]; 228 val[M22] = mat.val[Matrix4.M22]; 229 return this; 230 } 231 232 /** Adds a translational component to the matrix in the 3rd column. The other columns are untouched. 233 * @param vector The translation vector. 234 * @return This matrix for the purpose of chaining. */ trn(Vector2 vector)235 public Matrix3 trn (Vector2 vector) { 236 val[M02] += vector.x; 237 val[M12] += vector.y; 238 return this; 239 } 240 241 /** Adds a translational component to the matrix in the 3rd column. The other columns are untouched. 242 * @param x The x-component of the translation vector. 243 * @param y The y-component of the translation vector. 244 * @return This matrix for the purpose of chaining. */ trn(float x, float y)245 public Matrix3 trn (float x, float y) { 246 val[M02] += x; 247 val[M12] += y; 248 return this; 249 } 250 251 /** Adds a translational component to the matrix in the 3rd column. The other columns are untouched. 252 * @param vector The translation vector. (The z-component of the vector is ignored because this is a 3x3 matrix) 253 * @return This matrix for the purpose of chaining. */ trn(Vector3 vector)254 public Matrix3 trn (Vector3 vector) { 255 val[M02] += vector.x; 256 val[M12] += vector.y; 257 return this; 258 } 259 260 /** Postmultiplies this matrix by a translation matrix. Postmultiplication is also used by OpenGL ES' 1.x 261 * glTranslate/glRotate/glScale. 262 * @param x The x-component of the translation vector. 263 * @param y The y-component of the translation vector. 264 * @return This matrix for the purpose of chaining. */ translate(float x, float y)265 public Matrix3 translate (float x, float y) { 266 tmp[M00] = 1; 267 tmp[M10] = 0; 268 tmp[M20] = 0; 269 270 tmp[M01] = 0; 271 tmp[M11] = 1; 272 tmp[M21] = 0; 273 274 tmp[M02] = x; 275 tmp[M12] = y; 276 tmp[M22] = 1; 277 mul(val, tmp); 278 return this; 279 } 280 281 /** Postmultiplies this matrix by a translation matrix. Postmultiplication is also used by OpenGL ES' 1.x 282 * glTranslate/glRotate/glScale. 283 * @param translation The translation vector. 284 * @return This matrix for the purpose of chaining. */ translate(Vector2 translation)285 public Matrix3 translate (Vector2 translation) { 286 tmp[M00] = 1; 287 tmp[M10] = 0; 288 tmp[M20] = 0; 289 290 tmp[M01] = 0; 291 tmp[M11] = 1; 292 tmp[M21] = 0; 293 294 tmp[M02] = translation.x; 295 tmp[M12] = translation.y; 296 tmp[M22] = 1; 297 mul(val, tmp); 298 return this; 299 } 300 301 /** Postmultiplies this matrix with a (counter-clockwise) rotation matrix. Postmultiplication is also used by OpenGL ES' 1.x 302 * glTranslate/glRotate/glScale. 303 * @param angle The angle in degrees 304 * @return This matrix for the purpose of chaining. */ rotate(float angle)305 public Matrix3 rotate (float angle) { 306 if (angle == 0) return this; 307 angle = DEGREE_TO_RAD * angle; 308 float cos = (float)Math.cos(angle); 309 float sin = (float)Math.sin(angle); 310 311 tmp[M00] = cos; 312 tmp[M10] = sin; 313 tmp[M20] = 0; 314 315 tmp[M01] = -sin; 316 tmp[M11] = cos; 317 tmp[M21] = 0; 318 319 tmp[M02] = 0; 320 tmp[M12] = 0; 321 tmp[M22] = 1; 322 mul(val, tmp); 323 return this; 324 } 325 326 /** Postmultiplies this matrix with a scale matrix. Postmultiplication is also used by OpenGL ES' 1.x 327 * glTranslate/glRotate/glScale. 328 * @param scaleX The scale in the x-axis. 329 * @param scaleY The scale in the y-axis. 330 * @return This matrix for the purpose of chaining. */ scale(float scaleX, float scaleY)331 public Matrix3 scale (float scaleX, float scaleY) { 332 tmp[M00] = scaleX; 333 tmp[M10] = 0; 334 tmp[M20] = 0; 335 tmp[M01] = 0; 336 tmp[M11] = scaleY; 337 tmp[M21] = 0; 338 tmp[M02] = 0; 339 tmp[M12] = 0; 340 tmp[M22] = 1; 341 mul(val, tmp); 342 return this; 343 } 344 345 /** Postmultiplies this matrix with a scale matrix. Postmultiplication is also used by OpenGL ES' 1.x 346 * glTranslate/glRotate/glScale. 347 * @param scale The vector to scale the matrix by. 348 * @return This matrix for the purpose of chaining. */ scale(Vector2 scale)349 public Matrix3 scale (Vector2 scale) { 350 tmp[M00] = scale.x; 351 tmp[M10] = 0; 352 tmp[M20] = 0; 353 tmp[M01] = 0; 354 tmp[M11] = scale.y; 355 tmp[M21] = 0; 356 tmp[M02] = 0; 357 tmp[M12] = 0; 358 tmp[M22] = 1; 359 mul(val, tmp); 360 return this; 361 } 362 363 /** Get the values in this matrix. 364 * @return The float values that make up this matrix in column-major order. */ getValues()365 public float[] getValues () { 366 return val; 367 } 368 369 /** Scale the matrix in the both the x and y components by the scalar value. 370 * @param scale The single value that will be used to scale both the x and y components. 371 * @return This matrix for the purpose of chaining methods together. */ scl(float scale)372 public Matrix3 scl (float scale) { 373 val[M00] *= scale; 374 val[M11] *= scale; 375 return this; 376 } 377 378 /** Scale this matrix using the x and y components of the vector but leave the rest of the matrix alone. 379 * @param scale The {@link Vector3} to use to scale this matrix. 380 * @return This matrix for the purpose of chaining methods together. */ scl(Vector2 scale)381 public Matrix3 scl (Vector2 scale) { 382 val[M00] *= scale.x; 383 val[M11] *= scale.y; 384 return this; 385 } 386 387 /** Scale this matrix using the x and y components of the vector but leave the rest of the matrix alone. 388 * @param scale The {@link Vector3} to use to scale this matrix. The z component will be ignored. 389 * @return This matrix for the purpose of chaining methods together. */ scl(Vector3 scale)390 public Matrix3 scl (Vector3 scale) { 391 val[M00] *= scale.x; 392 val[M11] *= scale.y; 393 return this; 394 } 395 396 /** Transposes the current matrix. 397 * @return This matrix for the purpose of chaining methods together. */ transpose()398 public Matrix3 transpose () { 399 // Where MXY you do not have to change MXX 400 float v01 = val[M10]; 401 float v02 = val[M20]; 402 float v10 = val[M01]; 403 float v12 = val[M21]; 404 float v20 = val[M02]; 405 float v21 = val[M12]; 406 val[M01] = v01; 407 val[M02] = v02; 408 val[M10] = v10; 409 val[M12] = v12; 410 val[M20] = v20; 411 val[M21] = v21; 412 return this; 413 } 414 415 /** Multiplies matrix a with matrix b in the following manner: 416 * 417 * <pre> 418 * mul(A, B) => A := AB 419 * </pre> 420 * @param mata The float array representing the first matrix. Must have at least 9 elements. 421 * @param matb The float array representing the second matrix. Must have at least 9 elements. */ mul(float[] mata, float[] matb)422 private static void mul (float[] mata, float[] matb) { 423 float v00 = mata[M00] * matb[M00] + mata[M01] * matb[M10] + mata[M02] * matb[M20]; 424 float v01 = mata[M00] * matb[M01] + mata[M01] * matb[M11] + mata[M02] * matb[M21]; 425 float v02 = mata[M00] * matb[M02] + mata[M01] * matb[M12] + mata[M02] * matb[M22]; 426 427 float v10 = mata[M10] * matb[M00] + mata[M11] * matb[M10] + mata[M12] * matb[M20]; 428 float v11 = mata[M10] * matb[M01] + mata[M11] * matb[M11] + mata[M12] * matb[M21]; 429 float v12 = mata[M10] * matb[M02] + mata[M11] * matb[M12] + mata[M12] * matb[M22]; 430 431 float v20 = mata[M20] * matb[M00] + mata[M21] * matb[M10] + mata[M22] * matb[M20]; 432 float v21 = mata[M20] * matb[M01] + mata[M21] * matb[M11] + mata[M22] * matb[M21]; 433 float v22 = mata[M20] * matb[M02] + mata[M21] * matb[M12] + mata[M22] * matb[M22]; 434 435 mata[M00] = v00; 436 mata[M10] = v10; 437 mata[M20] = v20; 438 mata[M01] = v01; 439 mata[M11] = v11; 440 mata[M21] = v21; 441 mata[M02] = v02; 442 mata[M12] = v12; 443 mata[M22] = v22; 444 } 445 } 446