| 1 | /* |
| 2 | Copyright (c) 2012, Broadcom Europe Ltd |
| 3 | All rights reserved. |
| 4 | |
| 5 | Redistribution and use in source and binary forms, with or without |
| 6 | modification, are permitted provided that the following conditions are met: |
| 7 | * Redistributions of source code must retain the above copyright |
| 8 | notice, this list of conditions and the following disclaimer. |
| 9 | * Redistributions in binary form must reproduce the above copyright |
| 10 | notice, this list of conditions and the following disclaimer in the |
| 11 | documentation and/or other materials provided with the distribution. |
| 12 | * Neither the name of the copyright holder nor the |
| 13 | names of its contributors may be used to endorse or promote products |
| 14 | derived from this software without specific prior written permission. |
| 15 | |
| 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND |
| 17 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
| 18 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| 19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY |
| 20 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
| 21 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
| 22 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
| 23 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 24 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
| 25 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 26 | */ |
| 27 | |
| 28 | #include "interface/khronos/common/khrn_int_common.h" |
| 29 | #include "interface/khronos/vg/vg_int_mat3x3.h" |
| 30 | #include "interface/khronos/common/khrn_int_math.h" |
| 31 | #include "interface/khronos/common/khrn_int_util.h" |
| 32 | |
| 33 | /* |
| 34 | Preconditions: |
| 35 | |
| 36 | - |
| 37 | |
| 38 | Postconditions: |
| 39 | |
| 40 | a is the identity matrix. |
| 41 | */ |
| 42 | |
| 43 | void vg_mat3x3_set_identity(VG_MAT3X3_T *a) |
| 44 | { |
| 45 | a->m[0][0] = 1.0f; a->m[0][1] = 0.0f; a->m[0][2] = 0.0f; |
| 46 | a->m[1][0] = 0.0f; a->m[1][1] = 1.0f; a->m[1][2] = 0.0f; |
| 47 | a->m[2][0] = 0.0f; a->m[2][1] = 0.0f; a->m[2][2] = 1.0f; |
| 48 | } |
| 49 | |
| 50 | /* |
| 51 | copies matrix (column-major) into a, "cleaning" the elements (see |
| 52 | clean_float). forces the bottom row of a to (0, 0, 1) if force_affine is |
| 53 | true. |
| 54 | |
| 55 | Preconditions: |
| 56 | |
| 57 | - |
| 58 | |
| 59 | Postconditions: |
| 60 | |
| 61 | no elements of a are nan or infinity. |
| 62 | if force_affine is true, a is affine. |
| 63 | */ |
| 64 | |
| 65 | void vg_mat3x3_set_clean(VG_MAT3X3_T *a, const float *matrix, bool force_affine) |
| 66 | { |
| 67 | a->m[0][0] = clean_float(matrix[0]); |
| 68 | a->m[0][1] = clean_float(matrix[3]); |
| 69 | a->m[0][2] = clean_float(matrix[6]); |
| 70 | |
| 71 | a->m[1][0] = clean_float(matrix[1]); |
| 72 | a->m[1][1] = clean_float(matrix[4]); |
| 73 | a->m[1][2] = clean_float(matrix[7]); |
| 74 | |
| 75 | if (force_affine) { |
| 76 | a->m[2][0] = 0.0f; |
| 77 | a->m[2][1] = 0.0f; |
| 78 | a->m[2][2] = 1.0f; |
| 79 | } else { |
| 80 | a->m[2][0] = clean_float(matrix[2]); |
| 81 | a->m[2][1] = clean_float(matrix[5]); |
| 82 | a->m[2][2] = clean_float(matrix[8]); |
| 83 | } |
| 84 | } |
| 85 | |
| 86 | /* |
| 87 | Preconditions: |
| 88 | |
| 89 | - |
| 90 | |
| 91 | Postconditions: |
| 92 | |
| 93 | matrix (column-major) is set to a. |
| 94 | */ |
| 95 | |
| 96 | void vg_mat3x3_get(const VG_MAT3X3_T *a, float *matrix) |
| 97 | { |
| 98 | matrix[0] = a->m[0][0]; |
| 99 | matrix[3] = a->m[0][1]; |
| 100 | matrix[6] = a->m[0][2]; |
| 101 | |
| 102 | matrix[1] = a->m[1][0]; |
| 103 | matrix[4] = a->m[1][1]; |
| 104 | matrix[7] = a->m[1][2]; |
| 105 | |
| 106 | matrix[2] = a->m[2][0]; |
| 107 | matrix[5] = a->m[2][1]; |
| 108 | matrix[8] = a->m[2][2]; |
| 109 | } |
| 110 | |
| 111 | /* |
| 112 | Preconditions: |
| 113 | |
| 114 | - |
| 115 | |
| 116 | Postconditions: |
| 117 | |
| 118 | returns true iff a and b are bitwise identical. |
| 119 | */ |
| 120 | |
| 121 | bool vg_mat3x3_identical(const VG_MAT3X3_T *a, const VG_MAT3X3_T *b) |
| 122 | { |
| 123 | return floats_identical(a->m[0][0], b->m[0][0]) && floats_identical(a->m[0][1], b->m[0][1]) && floats_identical(a->m[0][2], b->m[0][2]) && |
| 124 | floats_identical(a->m[1][0], b->m[1][0]) && floats_identical(a->m[1][1], b->m[1][1]) && floats_identical(a->m[1][2], b->m[1][2]) && |
| 125 | floats_identical(a->m[2][0], b->m[2][0]) && floats_identical(a->m[2][1], b->m[2][1]) && floats_identical(a->m[2][2], b->m[2][2]); |
| 126 | } |
| 127 | |
| 128 | /* |
| 129 | Preconditions: |
| 130 | |
| 131 | a does not point to the same matrix as b or c. |
| 132 | |
| 133 | Postconditions: |
| 134 | |
| 135 | a is set to b * c. |
| 136 | */ |
| 137 | |
| 138 | void vg_mat3x3_mul(VG_MAT3X3_T *a, const VG_MAT3X3_T *b, const VG_MAT3X3_T *c) |
| 139 | { |
| 140 | uint32_t j, i; |
| 141 | for (j = 0; j != 3; ++j) { |
| 142 | for (i = 0; i != 3; ++i) { |
| 143 | a->m[j][i] = |
| 144 | (b->m[j][0] * c->m[0][i]) + |
| 145 | (b->m[j][1] * c->m[1][i]) + |
| 146 | (b->m[j][2] * c->m[2][i]); |
| 147 | } |
| 148 | } |
| 149 | } |
| 150 | |
| 151 | /* |
| 152 | Preconditions: |
| 153 | |
| 154 | - |
| 155 | |
| 156 | Postconditions: |
| 157 | |
| 158 | a is set to a * translation_matrix(x, y). |
| 159 | */ |
| 160 | |
| 161 | void vg_mat3x3_postmul_translate(VG_MAT3X3_T *a, float x, float y) |
| 162 | { |
| 163 | a->m[0][2] += (a->m[0][0] * x) + (a->m[0][1] * y); |
| 164 | a->m[1][2] += (a->m[1][0] * x) + (a->m[1][1] * y); |
| 165 | a->m[2][2] += (a->m[2][0] * x) + (a->m[2][1] * y); |
| 166 | } |
| 167 | |
| 168 | /* |
| 169 | Preconditions: |
| 170 | |
| 171 | - |
| 172 | |
| 173 | Postconditions: |
| 174 | |
| 175 | a is set to a * scale_matrix(x, y). |
| 176 | */ |
| 177 | |
| 178 | void vg_mat3x3_postmul_scale(VG_MAT3X3_T *a, float x, float y) |
| 179 | { |
| 180 | a->m[0][0] *= x; |
| 181 | a->m[0][1] *= y; |
| 182 | |
| 183 | a->m[1][0] *= x; |
| 184 | a->m[1][1] *= y; |
| 185 | |
| 186 | a->m[2][0] *= x; |
| 187 | a->m[2][1] *= y; |
| 188 | } |
| 189 | |
| 190 | /* |
| 191 | Preconditions: |
| 192 | |
| 193 | - |
| 194 | |
| 195 | Postconditions: |
| 196 | |
| 197 | a is set to a * shear_matrix(x, y). |
| 198 | */ |
| 199 | |
| 200 | void vg_mat3x3_postmul_shear(VG_MAT3X3_T *a, float x, float y) |
| 201 | { |
| 202 | float m00 = a->m[0][0], m10 = a->m[1][0], m20 = a->m[2][0]; |
| 203 | |
| 204 | a->m[0][0] += a->m[0][1] * y; |
| 205 | a->m[0][1] += m00 * x; |
| 206 | |
| 207 | a->m[1][0] += a->m[1][1] * y; |
| 208 | a->m[1][1] += m10 * x; |
| 209 | |
| 210 | a->m[2][0] += a->m[2][1] * y; |
| 211 | a->m[2][1] += m20 * x; |
| 212 | } |
| 213 | |
| 214 | /* |
| 215 | Preconditions: |
| 216 | |
| 217 | angle is in radians. |
| 218 | |
| 219 | Postconditions: |
| 220 | |
| 221 | a is set to a * rotation_matrix(angle). |
| 222 | */ |
| 223 | |
| 224 | void vg_mat3x3_postmul_rotate(VG_MAT3X3_T *a, float angle) |
| 225 | { |
| 226 | float s, c; |
| 227 | sin_cos_(&s, &c, angle); |
| 228 | vg_mat3x3_postmul_rotate_sc(a, s, c); |
| 229 | } |
| 230 | |
| 231 | /* |
| 232 | Preconditions: |
| 233 | |
| 234 | there is some angle such that: |
| 235 | s = sin(angle) |
| 236 | c = cos(angle) |
| 237 | |
| 238 | Postconditions: |
| 239 | |
| 240 | a is set to a * rotation_matrix(angle). |
| 241 | */ |
| 242 | |
| 243 | void vg_mat3x3_postmul_rotate_sc(VG_MAT3X3_T *a, float s, float c) |
| 244 | { |
| 245 | float m00 = a->m[0][0], m10 = a->m[1][0], m20 = a->m[2][0]; |
| 246 | |
| 247 | a->m[0][0] = (m00 * c) + (a->m[0][1] * s); |
| 248 | a->m[0][1] = (a->m[0][1] * c) - (m00 * s); |
| 249 | |
| 250 | a->m[1][0] = (m10 * c) + (a->m[1][1] * s); |
| 251 | a->m[1][1] = (a->m[1][1] * c) - (m10 * s); |
| 252 | |
| 253 | a->m[2][0] = (m20 * c) + (a->m[2][1] * s); |
| 254 | a->m[2][1] = (a->m[2][1] * c) - (m20 * s); |
| 255 | } |
| 256 | |
| 257 | /* |
| 258 | Preconditions: |
| 259 | |
| 260 | - |
| 261 | |
| 262 | Postconditions: |
| 263 | |
| 264 | a is set to translation_matrix(x, y) * a. |
| 265 | */ |
| 266 | |
| 267 | void vg_mat3x3_premul_translate(VG_MAT3X3_T *a, float x, float y) |
| 268 | { |
| 269 | a->m[0][0] += a->m[2][0] * x; |
| 270 | a->m[0][1] += a->m[2][1] * x; |
| 271 | a->m[0][2] += a->m[2][2] * x; |
| 272 | |
| 273 | a->m[1][0] += a->m[2][0] * y; |
| 274 | a->m[1][1] += a->m[2][1] * y; |
| 275 | a->m[1][2] += a->m[2][2] * y; |
| 276 | } |
| 277 | |
| 278 | /* |
| 279 | Preconditions: |
| 280 | |
| 281 | - |
| 282 | |
| 283 | Postconditions: |
| 284 | |
| 285 | a is set to scale_matrix(x, y) * a. |
| 286 | */ |
| 287 | |
| 288 | void vg_mat3x3_premul_scale(VG_MAT3X3_T *a, float x, float y) |
| 289 | { |
| 290 | a->m[0][0] *= x; |
| 291 | a->m[0][1] *= x; |
| 292 | a->m[0][2] *= x; |
| 293 | |
| 294 | a->m[1][0] *= y; |
| 295 | a->m[1][1] *= y; |
| 296 | a->m[1][2] *= y; |
| 297 | } |
| 298 | |
| 299 | /* |
| 300 | Preconditions: |
| 301 | |
| 302 | - |
| 303 | |
| 304 | Postconditions: |
| 305 | |
| 306 | a is set to shear_matrix(x, y) * a. |
| 307 | */ |
| 308 | |
| 309 | void vg_mat3x3_premul_shear(VG_MAT3X3_T *a, float x, float y) |
| 310 | { |
| 311 | float m00 = a->m[0][0], m01 = a->m[0][1], m02 = a->m[0][2]; |
| 312 | |
| 313 | a->m[0][0] += a->m[1][0] * x; |
| 314 | a->m[0][1] += a->m[1][1] * x; |
| 315 | a->m[0][2] += a->m[1][2] * x; |
| 316 | |
| 317 | a->m[1][0] += m00 * y; |
| 318 | a->m[1][1] += m01 * y; |
| 319 | a->m[1][2] += m02 * y; |
| 320 | } |
| 321 | |
| 322 | /* |
| 323 | Preconditions: |
| 324 | |
| 325 | angle is in radians. |
| 326 | |
| 327 | Postconditions: |
| 328 | |
| 329 | a is set to rotation_matrix(angle) * a. |
| 330 | */ |
| 331 | |
| 332 | void vg_mat3x3_premul_rotate(VG_MAT3X3_T *a, float angle) |
| 333 | { |
| 334 | float s, c; |
| 335 | sin_cos_(&s, &c, angle); |
| 336 | vg_mat3x3_premul_rotate_sc(a, s, c); |
| 337 | } |
| 338 | |
| 339 | /* |
| 340 | Preconditions: |
| 341 | |
| 342 | there is some angle such that: |
| 343 | s = sin(angle) |
| 344 | c = cos(angle) |
| 345 | |
| 346 | Postconditions: |
| 347 | |
| 348 | a is set to rotation_matrix(angle) * a. |
| 349 | */ |
| 350 | |
| 351 | void vg_mat3x3_premul_rotate_sc(VG_MAT3X3_T *a, float s, float c) |
| 352 | { |
| 353 | float m00 = a->m[0][0], m01 = a->m[0][1], m02 = a->m[0][2]; |
| 354 | |
| 355 | a->m[0][0] = (m00 * c) - (a->m[1][0] * s); |
| 356 | a->m[0][1] = (m01 * c) - (a->m[1][1] * s); |
| 357 | a->m[0][2] = (m02 * c) - (a->m[1][2] * s); |
| 358 | |
| 359 | a->m[1][0] = (m00 * s) + (a->m[1][0] * c); |
| 360 | a->m[1][1] = (m01 * s) + (a->m[1][1] * c); |
| 361 | a->m[1][2] = (m02 * s) + (a->m[1][2] * c); |
| 362 | } |
| 363 | |
| 364 | /* |
| 365 | Preconditions: |
| 366 | |
| 367 | - |
| 368 | |
| 369 | Postconditions: |
| 370 | |
| 371 | returns true iff a is affine. |
| 372 | */ |
| 373 | |
| 374 | bool vg_mat3x3_is_affine(const VG_MAT3X3_T *a) |
| 375 | { |
| 376 | return (a->m[2][0] == 0.0f) && (a->m[2][1] == 0.0f) && (a->m[2][2] == 1.0f); |
| 377 | } |
| 378 | |
| 379 | /* |
| 380 | Preconditions: |
| 381 | |
| 382 | - |
| 383 | |
| 384 | Postconditions: |
| 385 | |
| 386 | returns true iff a is affine or has nans in the bad elements. |
| 387 | */ |
| 388 | |
| 389 | bool vg_mat3x3_is_affine_or_nans(const VG_MAT3X3_T *a) |
| 390 | { |
| 391 | return !nan_ne_(a->m[2][0], 0.0f) && !nan_ne_(a->m[2][1], 0.0f) && !nan_ne_(a->m[2][2], 1.0f); |
| 392 | } |
| 393 | |
| 394 | /* |
| 395 | Preconditions: |
| 396 | |
| 397 | - |
| 398 | |
| 399 | Postconditions: |
| 400 | |
| 401 | returns the determinant of a. |
| 402 | */ |
| 403 | |
| 404 | float vg_mat3x3_det(const VG_MAT3X3_T *a) |
| 405 | { |
| 406 | return (a->m[0][0] * ((a->m[2][2] * a->m[1][1]) - (a->m[2][1] * a->m[1][2]))) + |
| 407 | (a->m[1][0] * ((a->m[0][2] * a->m[2][1]) - (a->m[0][1] * a->m[2][2]))) + |
| 408 | (a->m[2][0] * ((a->m[1][2] * a->m[0][1]) - (a->m[1][1] * a->m[0][2]))); |
| 409 | } |
| 410 | |
| 411 | /* |
| 412 | Preconditions: |
| 413 | |
| 414 | a must be affine (or have nans in the bad elements). |
| 415 | |
| 416 | Postconditions: |
| 417 | |
| 418 | returns the determinant of a. |
| 419 | */ |
| 420 | |
| 421 | float vg_mat3x3_affine_det(const VG_MAT3X3_T *a) |
| 422 | { |
| 423 | vcos_assert(vg_mat3x3_is_affine_or_nans(a)); |
| 424 | return (a->m[0][0] * a->m[1][1]) - (a->m[1][0] * a->m[0][1]); |
| 425 | } |
| 426 | |
| 427 | /* |
| 428 | Preconditions: |
| 429 | |
| 430 | - |
| 431 | |
| 432 | Postconditions: |
| 433 | |
| 434 | returns false iff a is not invertible (or very close to not being |
| 435 | invertible). |
| 436 | */ |
| 437 | |
| 438 | bool vg_mat3x3_is_invertible(const VG_MAT3X3_T *a) |
| 439 | { |
| 440 | return absf_(vg_mat3x3_det(a)) >= EPS; |
| 441 | } |
| 442 | |
| 443 | /* |
| 444 | Preconditions: |
| 445 | |
| 446 | a must be affine (or have nans in the bad elements). |
| 447 | |
| 448 | Postconditions: |
| 449 | |
| 450 | returns false iff a is not invertible (or very close to not being |
| 451 | invertible). |
| 452 | */ |
| 453 | |
| 454 | bool vg_mat3x3_affine_is_invertible(const VG_MAT3X3_T *a) |
| 455 | { |
| 456 | return absf_(vg_mat3x3_affine_det(a)) >= EPS; |
| 457 | } |
| 458 | |
| 459 | /* |
| 460 | Preconditions: |
| 461 | |
| 462 | a must be invertible, according to vg_mat3x3_is_invertible. |
| 463 | |
| 464 | Postconditions: |
| 465 | |
| 466 | a is inverted. |
| 467 | */ |
| 468 | |
| 469 | void vg_mat3x3_invert(VG_MAT3X3_T *a) |
| 470 | { |
| 471 | float oo_det; |
| 472 | VG_MAT3X3_T b; |
| 473 | |
| 474 | vcos_assert(vg_mat3x3_is_invertible(a)); |
| 475 | |
| 476 | oo_det = recip_(vg_mat3x3_det(a)); |
| 477 | |
| 478 | b.m[0][0] = ((a->m[2][2] * a->m[1][1]) - (a->m[2][1] * a->m[1][2])) * oo_det; |
| 479 | b.m[0][1] = ((a->m[0][2] * a->m[2][1]) - (a->m[0][1] * a->m[2][2])) * oo_det; |
| 480 | b.m[0][2] = ((a->m[1][2] * a->m[0][1]) - (a->m[1][1] * a->m[0][2])) * oo_det; |
| 481 | |
| 482 | b.m[1][0] = ((a->m[2][0] * a->m[1][2]) - (a->m[2][2] * a->m[1][0])) * oo_det; |
| 483 | b.m[1][1] = ((a->m[0][0] * a->m[2][2]) - (a->m[0][2] * a->m[2][0])) * oo_det; |
| 484 | b.m[1][2] = ((a->m[1][0] * a->m[0][2]) - (a->m[1][2] * a->m[0][0])) * oo_det; |
| 485 | |
| 486 | b.m[2][0] = ((a->m[2][1] * a->m[1][0]) - (a->m[2][0] * a->m[1][1])) * oo_det; |
| 487 | b.m[2][1] = ((a->m[0][1] * a->m[2][0]) - (a->m[0][0] * a->m[2][1])) * oo_det; |
| 488 | b.m[2][2] = ((a->m[1][1] * a->m[0][0]) - (a->m[1][0] * a->m[0][1])) * oo_det; |
| 489 | |
| 490 | *a = b; |
| 491 | } |
| 492 | |
| 493 | /* |
| 494 | Preconditions: |
| 495 | |
| 496 | a must be affine (or have nans in the bad elements). |
| 497 | a must be invertible, according to vg_mat3x3_affine_is_invertible. |
| 498 | |
| 499 | Postconditions: |
| 500 | |
| 501 | a is inverted. |
| 502 | */ |
| 503 | |
| 504 | void vg_mat3x3_affine_invert(VG_MAT3X3_T *a) |
| 505 | { |
| 506 | float oo_det; |
| 507 | float m00, m01, m02, m10; |
| 508 | |
| 509 | vcos_assert(vg_mat3x3_affine_is_invertible(a)); |
| 510 | |
| 511 | oo_det = recip_(vg_mat3x3_affine_det(a)); |
| 512 | m00 = a->m[0][0]; |
| 513 | m01 = a->m[0][1]; |
| 514 | m02 = a->m[0][2]; |
| 515 | m10 = a->m[1][0]; |
| 516 | |
| 517 | a->m[0][0] = a->m[1][1] * oo_det; |
| 518 | a->m[0][1] = -m01 * oo_det; |
| 519 | a->m[0][2] = ((a->m[1][2] * m01) - (a->m[1][1] * m02)) * oo_det; |
| 520 | |
| 521 | a->m[1][0] = -m10 * oo_det; |
| 522 | a->m[1][1] = m00 * oo_det; |
| 523 | a->m[1][2] = ((m10 * m02) - (a->m[1][2] * m00)) * oo_det; |
| 524 | |
| 525 | a->m[2][0] = 0.0f; |
| 526 | a->m[2][1] = 0.0f; |
| 527 | a->m[2][2] = 1.0f; |
| 528 | } |
| 529 | |
| 530 | /* |
| 531 | Preconditions: |
| 532 | |
| 533 | - |
| 534 | |
| 535 | Postconditions: |
| 536 | |
| 537 | (x, y, -) is set to a * (x, y, 1). |
| 538 | */ |
| 539 | |
| 540 | void vg_mat3x3_affine_transform(const VG_MAT3X3_T *a, float *x_io, float *y_io) |
| 541 | { |
| 542 | float x = (a->m[0][0] * *x_io) + (a->m[0][1] * *y_io) + a->m[0][2]; |
| 543 | float y = (a->m[1][0] * *x_io) + (a->m[1][1] * *y_io) + a->m[1][2]; |
| 544 | *x_io = x; |
| 545 | *y_io = y; |
| 546 | } |
| 547 | |
| 548 | /* |
| 549 | Preconditions: |
| 550 | |
| 551 | - |
| 552 | |
| 553 | Postconditions: |
| 554 | |
| 555 | (x, y, -) is set to a * (x, y, 0). |
| 556 | */ |
| 557 | |
| 558 | void vg_mat3x3_affine_transform_t(const VG_MAT3X3_T *a, float *x_io, float *y_io) |
| 559 | { |
| 560 | float x = (a->m[0][0] * *x_io) + (a->m[0][1] * *y_io); |
| 561 | float y = (a->m[1][0] * *x_io) + (a->m[1][1] * *y_io); |
| 562 | *x_io = x; |
| 563 | *y_io = y; |
| 564 | } |
| 565 | |
| 566 | /* |
| 567 | the top-left 2x2 submatrix of a is decomposed into (R * S * Q), where R is a |
| 568 | rotation matrix, S is a scale matrix, and Q is a rotation/flip matrix. note |
| 569 | that this decomposition is not unique. |
| 570 | |
| 571 | Preconditions: |
| 572 | |
| 573 | r may be NULL. |
| 574 | s0 may be NULL. |
| 575 | s1 may be NULL. |
| 576 | |
| 577 | Postconditions: |
| 578 | |
| 579 | if r is non-NULL, it is set to the angle of R (so R = rotation_matrix(r)) in |
| 580 | radians. |
| 581 | if s0 is non-NULL, it is set to S[0][0]. |
| 582 | if s1 is non-NULL, it is set to S[1][1]. |
| 583 | so if we set both, S = scale_matrix(s0, s1). |
| 584 | */ |
| 585 | |
| 586 | void vg_mat3x3_rsq(const VG_MAT3X3_T *a, |
| 587 | float *r, float *s0, float *s1) |
| 588 | { |
| 589 | /* |
| 590 | a = R * S * Q (svd, R is rotation, S is scale, Q is rotation/flip) |
| 591 | a^T = Q^T * S * R^T |
| 592 | a * a^T = R * S * Q * Q^T * S * R^T = R * S^2 * R^T |
| 593 | |
| 594 | eigenvalues of a * a^T will give S^2 |
| 595 | eigenvectors of a * a^T will give R |
| 596 | */ |
| 597 | |
| 598 | /* |
| 599 | ( b c ) = a * a^T |
| 600 | ( d e ) |
| 601 | */ |
| 602 | |
| 603 | float b = (a->m[0][0] * a->m[0][0]) + (a->m[0][1] * a->m[0][1]); |
| 604 | float c = (a->m[0][0] * a->m[1][0]) + (a->m[0][1] * a->m[1][1]); |
| 605 | /* d = c */ |
| 606 | float e = (a->m[1][0] * a->m[1][0]) + (a->m[1][1] * a->m[1][1]); |
| 607 | |
| 608 | float bpe = b + e; |
| 609 | float bme = b - e; |
| 610 | |
| 611 | /* |
| 612 | solve: |
| 613 | |
| 614 | bx + cy = sx |
| 615 | dx + ey = sy |
| 616 | |
| 617 | cy * dx = (s - b)x * (s - e)y |
| 618 | c^2 = (s - b) * (s - e) |
| 619 | s^2 - (b + e)s + (be - c^2) = 0 |
| 620 | s = (b + e +/- sqrt((b + e)^2 - 4(be - c^2))) / 2 |
| 621 | s = (b + e +/- sqrt(b^2 + e^2 - 2be + 4c^2)) / 2 |
| 622 | s = (b + e +/- sqrt((b - e)^2 + 4c^2)) / 2 |
| 623 | */ |
| 624 | |
| 625 | float t = sqrt_((bme * bme) + (4.0f * c * c)); |
| 626 | float v = (bpe + t) * 0.5f; /* first eigenvalue */ |
| 627 | if (s0) { |
| 628 | *s0 = sqrt_(v); |
| 629 | } |
| 630 | if (s1) { |
| 631 | *s1 = sqrt_( |
| 632 | /* second eigenvalue */ |
| 633 | _maxf(bpe - t, 0.0f) * 0.5f); |
| 634 | } |
| 635 | |
| 636 | /* |
| 637 | angle of eigenvector corresponds to r |
| 638 | */ |
| 639 | |
| 640 | if (r) { |
| 641 | /* first eigenvector is (c, v - b) / (v - e, c) */ |
| 642 | float x = (v - e) + c; |
| 643 | float y = (v - b) + c; |
| 644 | *r = ((absf_(x) < EPS) && (absf_(y) < EPS)) ? 0.0f : atan2_(y, x); |
| 645 | } |
| 646 | } |
| 647 | |