The open source OpenXR runtime
at main 994 lines 26 kB view raw
1// Copyright 2019, Collabora, Ltd. 2// SPDX-License-Identifier: BSL-1.0 3/*! 4 * @file 5 * @brief Base implementations for math library. 6 * @author Jakob Bornecrantz <jakob@collabora.com> 7 * @author Rylie Pavlik <rylie.pavlik@collabora.com> 8 * @author Moshi Turner <moshiturner@protonmail.com> 9 * @author Nis Madsen <nima_zero_one@protonmail.com> 10 * @ingroup aux_math 11 */ 12// IWYU pragma: no_include "src/Core/DenseBase.h" 13// IWYU pragma: no_include "src/Core/MatrixBase.h" 14 15#include "math/m_api.h" // IWYU pragma: associated 16 17#include "math/m_eigen_interop.hpp" 18#include "math/m_vec3.h" 19 20#include <Eigen/Core> 21#include <Eigen/Geometry> 22 23#include <assert.h> 24 25using namespace xrt::auxiliary::math; 26 27/* 28 * 29 * Copy helpers. 30 * 31 */ 32 33static inline Eigen::Quaternionf 34copy(const struct xrt_quat &q) 35{ 36 // Eigen constructor order is different from XRT, OpenHMD and OpenXR! 37 // Eigen: `float w, x, y, z`. 38 // OpenXR: `float x, y, z, w`. 39 return Eigen::Quaternionf(q.w, q.x, q.y, q.z); 40} 41 42static inline Eigen::Quaternionf 43copy(const struct xrt_quat *q) 44{ 45 return copy(*q); 46} 47 48XRT_MAYBE_UNUSED static inline Eigen::Quaterniond 49copyd(const struct xrt_quat &q) 50{ 51 // Eigen constructor order is different from XRT, OpenHMD and OpenXR! 52 // Eigen: `float w, x, y, z`. 53 // OpenXR: `float x, y, z, w`. 54 return Eigen::Quaterniond(q.w, q.x, q.y, q.z); 55} 56 57XRT_MAYBE_UNUSED static inline Eigen::Quaterniond 58copyd(const struct xrt_quat *q) 59{ 60 return copyd(*q); 61} 62 63static inline Eigen::Vector3f 64copy(const struct xrt_vec3 &v) 65{ 66 return Eigen::Vector3f(v.x, v.y, v.z); 67} 68 69static inline Eigen::Vector3f 70copy(const struct xrt_vec3 *v) 71{ 72 return copy(*v); 73} 74 75 76static inline Eigen::Vector3d 77copy(const struct xrt_vec3_f64 &v) 78{ 79 return Eigen::Vector3d(v.x, v.y, v.z); 80} 81 82static inline Eigen::Vector3d 83copy(const struct xrt_vec3_f64 *v) 84{ 85 return copy(*v); 86} 87 88XRT_MAYBE_UNUSED static inline Eigen::Vector3d 89copyd(const struct xrt_vec3 &v) 90{ 91 return Eigen::Vector3d(v.x, v.y, v.z); 92} 93 94XRT_MAYBE_UNUSED static inline Eigen::Vector3d 95copyd(const struct xrt_vec3 *v) 96{ 97 return copyd(*v); 98} 99 100static inline Eigen::Matrix3f 101copy(const struct xrt_matrix_3x3 *m) 102{ 103 Eigen::Matrix3f res; 104 // clang-format off 105 res << m->v[0], m->v[3], m->v[6], 106 m->v[1], m->v[4], m->v[7], 107 m->v[2], m->v[5], m->v[8]; 108 // clang-format on 109 return res; 110} 111 112static inline Eigen::Matrix4f 113copy(const struct xrt_matrix_4x4 *m) 114{ 115 Eigen::Matrix4f res; 116 // clang-format off 117 res << m->v[0], m->v[4], m->v[8], m->v[12], 118 m->v[1], m->v[5], m->v[9], m->v[13], 119 m->v[2], m->v[6], m->v[10], m->v[14], 120 m->v[3], m->v[7], m->v[11], m->v[15]; 121 // clang-format on 122 return res; 123} 124 125 126/* 127 * 128 * Exported vector functions. 129 * 130 */ 131 132extern "C" bool 133math_vec3_validate(const struct xrt_vec3 *vec3) 134{ 135 assert(vec3 != NULL); 136 137 return map_vec3(*vec3).allFinite(); 138} 139 140extern "C" void 141math_vec3_accum(const struct xrt_vec3 *additional, struct xrt_vec3 *inAndOut) 142{ 143 assert(additional != NULL); 144 assert(inAndOut != NULL); 145 146 map_vec3(*inAndOut) += map_vec3(*additional); 147} 148 149extern "C" void 150math_vec3_subtract(const struct xrt_vec3 *subtrahend, struct xrt_vec3 *inAndOut) 151{ 152 assert(subtrahend != NULL); 153 assert(inAndOut != NULL); 154 155 map_vec3(*inAndOut) -= map_vec3(*subtrahend); 156} 157 158extern "C" void 159math_vec3_scalar_mul(float scalar, struct xrt_vec3 *inAndOut) 160{ 161 assert(inAndOut != NULL); 162 163 map_vec3(*inAndOut) *= scalar; 164} 165 166extern "C" void 167math_vec3_cross(const struct xrt_vec3 *l, const struct xrt_vec3 *r, struct xrt_vec3 *result) 168{ 169 map_vec3(*result) = map_vec3(*l).cross(map_vec3(*r)); 170} 171 172extern "C" void 173math_vec3_normalize(struct xrt_vec3 *in) 174{ 175 map_vec3(*in) = map_vec3(*in).normalized(); 176} 177 178extern "C" void 179math_vec3_translation_from_isometry(const struct xrt_matrix_4x4 *transform, struct xrt_vec3 *result) 180{ 181 Eigen::Isometry3f isometry{map_matrix_4x4(*transform)}; 182 map_vec3(*result) = isometry.translation(); 183} 184 185 186/* 187 * 188 * Exported 64 bit vector functions. 189 * 190 */ 191 192extern "C" void 193math_vec3_f64_cross(const struct xrt_vec3_f64 *l, const struct xrt_vec3_f64 *r, struct xrt_vec3_f64 *result) 194{ 195 map_vec3_f64(*result) = map_vec3_f64(*l).cross(map_vec3_f64(*r)); 196} 197 198extern "C" void 199math_vec3_f64_normalize(struct xrt_vec3_f64 *in) 200{ 201 map_vec3_f64(*in) = map_vec3_f64(*in).normalized(); 202} 203 204 205/* 206 * 207 * Exported quaternion functions. 208 * 209 */ 210 211extern "C" void 212math_quat_from_angle_vector(float angle_rads, const struct xrt_vec3 *vector, struct xrt_quat *result) 213{ 214 map_quat(*result) = Eigen::AngleAxisf(angle_rads, copy(vector)); 215} 216 217extern "C" void 218math_quat_from_euler_angles(const struct xrt_vec3 *angles, struct xrt_quat *result) 219{ 220 map_quat(*result) = Eigen::AngleAxisf(angles->z, Eigen::Vector3f::UnitZ()) * 221 Eigen::AngleAxisf(angles->y, Eigen::Vector3f::UnitY()) * 222 Eigen::AngleAxisf(angles->x, Eigen::Vector3f::UnitX()); 223} 224 225extern "C" void 226math_quat_to_euler_angles(const struct xrt_quat *quat, struct xrt_vec3 *euler_angles) 227{ 228 Eigen::Quaternionf eigen_quat(quat->w, quat->x, quat->y, quat->z); 229 Eigen::Vector3f eigen_euler = eigen_quat.toRotationMatrix().eulerAngles(2, 1, 0); 230 231 euler_angles->x = eigen_euler.x(); 232 euler_angles->y = eigen_euler.y(); 233 euler_angles->z = eigen_euler.z(); 234} 235 236extern "C" void 237math_quat_from_matrix_3x3(const struct xrt_matrix_3x3 *mat, struct xrt_quat *result) 238{ 239 Eigen::Matrix3f m; 240 m << mat->v[0], mat->v[1], mat->v[2], mat->v[3], mat->v[4], mat->v[5], mat->v[6], mat->v[7], mat->v[8]; 241 242 Eigen::Quaternionf q(m); 243 map_quat(*result) = q; 244} 245 246extern "C" void 247math_quat_from_plus_x_z(const struct xrt_vec3 *plus_x, const struct xrt_vec3 *plus_z, struct xrt_quat *result) 248{ 249 xrt_vec3 plus_y; 250 math_vec3_cross(plus_z, plus_x, &plus_y); 251 252 xrt_matrix_3x3 m = {{ 253 plus_x->x, 254 plus_y.x, 255 plus_z->x, 256 plus_x->y, 257 plus_y.y, 258 plus_z->y, 259 plus_x->z, 260 plus_y.z, 261 plus_z->z, 262 }}; 263 264 math_quat_from_matrix_3x3(&m, result); 265} 266 267extern "C" void 268math_quat_from_vec_a_to_vec_b(const struct xrt_vec3 *vec_a, const struct xrt_vec3 *vec_b, struct xrt_quat *result) 269{ 270 map_quat(*result) = Eigen::Quaternionf::FromTwoVectors(copy(vec_a), copy(vec_b)); 271} 272 273static bool 274quat_validate(const float precision, const struct xrt_quat *quat) 275{ 276 assert(quat != NULL); 277 auto rot = copy(*quat); 278 279 280 /* 281 * This was originally squaredNorm, but that could result in a norm 282 * value that was further from 1.0f then FLOAT_EPSILON (two). 283 * 284 * Our tracking system would produce such orientations and looping those 285 * back into say a quad layer would cause this to fail. And even 286 * normalizing the quat would not fix this as normalizations uses 287 * non-squared "length" which does fall into the range and doesn't 288 * change the elements of the quat. 289 */ 290 auto norm = rot.norm(); 291 if (norm > 1.0f + precision || norm < 1.0f - precision) { 292 return false; 293 } 294 295 // Technically not yet a required check, but easier to stop problems 296 // now than once denormalized numbers pollute the rest of our state. 297 // see https://gitlab.khronos.org/openxr/openxr/issues/922 298 if (!rot.coeffs().allFinite()) { 299 return false; 300 } 301 302 return true; 303} 304 305extern "C" bool 306math_quat_validate(const struct xrt_quat *quat) 307{ 308 const float FLOAT_EPSILON = Eigen::NumTraits<float>::epsilon(); 309 return quat_validate(FLOAT_EPSILON, quat); 310} 311 312extern "C" bool 313math_quat_validate_within_1_percent(const struct xrt_quat *quat) 314{ 315 return quat_validate(0.01f, quat); 316} 317 318extern "C" void 319math_quat_invert(const struct xrt_quat *quat, struct xrt_quat *out_quat) 320{ 321 map_quat(*out_quat) = map_quat(*quat).conjugate(); 322} 323 324extern "C" float 325math_quat_len(const struct xrt_quat *quat) 326{ 327 return map_quat(*quat).norm(); 328} 329 330extern "C" void 331math_quat_normalize(struct xrt_quat *inout) 332{ 333 assert(inout != NULL); 334 map_quat(*inout).normalize(); 335} 336 337extern "C" bool 338math_quat_ensure_normalized(struct xrt_quat *inout) 339{ 340 assert(inout != NULL); 341 342 if (math_quat_validate(inout)) 343 return true; 344 345 const float FLOAT_EPSILON = Eigen::NumTraits<float>::epsilon(); 346 const float TOLERANCE = FLOAT_EPSILON * 5; 347 348 auto rot = copy(*inout); 349 auto norm = rot.norm(); 350 if (norm > 1.0f + TOLERANCE || norm < 1.0f - TOLERANCE) { 351 return false; 352 } 353 354 map_quat(*inout).normalize(); 355 return true; 356} 357 358 359extern "C" void 360math_quat_rotate(const struct xrt_quat *left, const struct xrt_quat *right, struct xrt_quat *result) 361{ 362 assert(left != NULL); 363 assert(right != NULL); 364 assert(result != NULL); 365 366 auto l = copy(left); 367 auto r = copy(right); 368 369 auto q = l * r; 370 371 map_quat(*result) = q; 372} 373 374extern "C" void 375math_quat_unrotate(const struct xrt_quat *left, const struct xrt_quat *right, struct xrt_quat *result) 376{ 377 assert(left != NULL); 378 assert(right != NULL); 379 assert(result != NULL); 380 381 auto l = copy(left); 382 auto r = copy(right); 383 384 auto q = l.inverse() * r; 385 386 map_quat(*result) = q; 387} 388 389extern "C" void 390math_quat_rotate_vec3(const struct xrt_quat *left, const struct xrt_vec3 *right, struct xrt_vec3 *result) 391{ 392 assert(left != NULL); 393 assert(right != NULL); 394 assert(result != NULL); 395 396 auto l = copy(left); 397 auto r = copy(right); 398 399 auto v = l * r; 400 401 map_vec3(*result) = v; 402} 403 404extern "C" void 405math_quat_rotate_derivative(const struct xrt_quat *quat, const struct xrt_vec3 *deriv, struct xrt_vec3 *result) 406{ 407 assert(quat != NULL); 408 assert(deriv != NULL); 409 assert(result != NULL); 410 411 auto l = copy(quat); 412 auto m = Eigen::Quaternionf(0.0f, deriv->x, deriv->y, deriv->z); 413 auto r = l.conjugate(); 414 415 auto v = l * m * r; 416 417 struct xrt_vec3 ret = {v.x(), v.y(), v.z()}; 418 *result = ret; 419} 420 421extern "C" void 422math_quat_slerp(const struct xrt_quat *left, const struct xrt_quat *right, float t, struct xrt_quat *result) 423{ 424 assert(left != NULL); 425 assert(right != NULL); 426 assert(result != NULL); 427 428 auto l = copy(left); 429 auto r = copy(right); 430 431 map_quat(*result) = l.slerp(t, r); 432} 433 434extern "C" void 435math_quat_from_swing(const struct xrt_vec2 *swing, struct xrt_quat *result) 436{ 437 assert(swing != NULL); 438 assert(result != NULL); 439 const float *a0 = &swing->x; 440 const float *a1 = &swing->y; 441 const float theta_squared = *a0 * *a0 + *a1 * *a1; 442 443 if (theta_squared > 0.f) { 444 const float theta = sqrt(theta_squared); 445 const float half_theta = theta * 0.5f; 446 const float k = sin(half_theta) / theta; 447 result->w = cos(half_theta); 448 result->x = *a0 * k; 449 result->y = *a1 * k; 450 result->z = 0.f; 451 } else { 452 // lim(x->0) (sin(x/2)/x) = 0.5, but sin(0)/0 is undefined, so we need to catch this with a conditional. 453 const float k = 0.5f; 454 result->w = 1.0f; 455 result->x = *a0 * k; 456 result->y = *a1 * k; 457 result->z = 0.f; 458 } 459} 460 461// See https://gitlab.freedesktop.org/slitcch/rotation_visualizer/-/blob/main/lm_rotations_story.inl for the derivation 462extern "C" void 463math_quat_from_swing_twist(const struct xrt_vec2 *swing, const float twist, struct xrt_quat *result) 464{ 465 assert(swing != NULL); 466 assert(result != NULL); 467 468 float swing_x = swing->x; 469 float swing_y = swing->y; 470 471 float theta_squared_swing = swing_x * swing_x + swing_y * swing_y; 472 473 if (theta_squared_swing > float(0.0)) { 474 // theta_squared_swing is nonzero, so we the regular derived conversion. 475 476 float theta = sqrt(theta_squared_swing); 477 478 float half_theta = theta * float(0.5); 479 480 // the "other" theta 481 float half_twist = twist * float(0.5); 482 483 float cos_half_theta = cos(half_theta); 484 float cos_half_twist = cos(half_twist); 485 486 float sin_half_theta = sin(half_theta); 487 float sin_half_twist = sin(half_twist); 488 489 float sin_half_theta_over_theta = sin_half_theta / theta; 490 491 result->w = cos_half_theta * cos_half_twist; 492 493 float x_part_1 = (swing_x * cos_half_twist * sin_half_theta_over_theta); 494 float x_part_2 = (swing_y * sin_half_twist * sin_half_theta_over_theta); 495 496 result->x = x_part_1 + x_part_2; 497 498 float y_part_1 = (swing_y * cos_half_twist * sin_half_theta_over_theta); 499 float y_part_2 = (swing_x * sin_half_twist * sin_half_theta_over_theta); 500 501 result->y = y_part_1 - y_part_2; 502 503 result->z = cos_half_theta * sin_half_twist; 504 505 } else { 506 // sin_half_theta/theta would be undefined, but 507 // the limit approaches 0.5, so we do this. 508 // Note the differences w/ lm_rotations.inl - we can skip some things as we're not using this to compute 509 // a jacobian. 510 511 float half_twist = twist * float(0.5); 512 513 float cos_half_twist = cos(half_twist); 514 515 float sin_half_twist = sin(half_twist); 516 517 float sin_half_theta_over_theta = float(0.5); 518 519 // cos(0) is 1 so no cos_half_theta necessary 520 result->w = cos_half_twist; 521 522 float x_part_1 = (swing_x * cos_half_twist * sin_half_theta_over_theta); 523 float x_part_2 = (swing_y * sin_half_twist * sin_half_theta_over_theta); 524 525 result->x = x_part_1 + x_part_2; 526 527 float y_part_1 = (swing_y * cos_half_twist * sin_half_theta_over_theta); 528 float y_part_2 = (swing_x * sin_half_twist * sin_half_theta_over_theta); 529 530 result->y = y_part_1 - y_part_2; 531 532 result->z = sin_half_twist; 533 } 534} 535 536/*! 537 * Converts a quaternion to XY-swing and Z-twist 538 * 539 * @relates xrt_quat 540 * @ingroup aux_math 541 */ 542extern "C" void 543math_quat_to_swing_twist(const struct xrt_quat *in, struct xrt_vec2 *out_swing, float *out_twist) 544{ 545 Eigen::Quaternionf rot = map_quat(*in); 546 547 Eigen::Vector3f our_z = rot * (Eigen::Vector3f::UnitZ()); 548 549 Eigen::Quaternionf swing = Eigen::Quaternionf().setFromTwoVectors(Eigen::Vector3f::UnitZ(), our_z); 550 551 Eigen::Quaternionf twist = swing.inverse() * rot; 552 553 Eigen::AngleAxisf twist_aax = Eigen::AngleAxisf(twist); 554 555 Eigen::AngleAxisf swing_aax = Eigen::AngleAxisf(swing); 556 557 out_swing->x = swing_aax.axis().x() * swing_aax.angle(); 558 out_swing->y = swing_aax.axis().y() * swing_aax.angle(); 559 assert(swing_aax.axis().z() < 0.001); 560 561 *out_twist = twist_aax.axis().z() * twist_aax.angle(); 562} 563 564void 565math_quat_decompose_swing_twist(const struct xrt_quat *in, 566 const struct xrt_vec3 *twist_axis, 567 struct xrt_quat *swing, 568 struct xrt_quat *twist) 569{ 570 struct xrt_quat twist_inv; 571 struct xrt_vec3 orig_axis; 572 float dot; 573 574 orig_axis.x = in->x; 575 orig_axis.y = in->y; 576 orig_axis.z = in->z; 577 578 /* Calculate projection onto the twist axis */ 579 dot = m_vec3_dot(orig_axis, *twist_axis); 580 struct xrt_vec3 projection = *twist_axis; 581 math_vec3_scalar_mul(dot, &projection); 582 583 twist->x = projection.x; 584 twist->y = projection.y; 585 twist->z = projection.z; 586 twist->w = in->w; 587 588 if (math_quat_dot(twist, twist) < FLT_EPSILON) { 589 /* Singularity - 180 degree rotation and perpendicular 590 * decomp axis, so twist is the identity quat */ 591 twist->x = twist->y = twist->z = 0.0; 592 twist->w = 1.0; 593 } else { 594 math_quat_normalize(twist); 595 } 596 597 math_quat_invert(twist, &twist_inv); 598 math_quat_rotate(in, &twist_inv, swing); 599 math_quat_normalize(swing); 600} 601 602/* 603 * 604 * Exported matrix functions. 605 * 606 */ 607 608 609 610extern "C" void 611math_matrix_3x3_identity(struct xrt_matrix_3x3 *mat) 612{ 613 map_matrix_3x3(*mat) = Eigen::Matrix3f::Identity(); 614} 615 616extern "C" void 617math_matrix_3x3_from_quat(const struct xrt_quat *q, struct xrt_matrix_3x3 *result_out) 618{ 619 struct xrt_matrix_3x3 result = {{ 620 1 - 2 * q->y * q->y - 2 * q->z * q->z, 621 2 * q->x * q->y - 2 * q->w * q->z, 622 2 * q->x * q->z + 2 * q->w * q->y, 623 624 2 * q->x * q->y + 2 * q->w * q->z, 625 1 - 2 * q->x * q->x - 2 * q->z * q->z, 626 2 * q->y * q->z - 2 * q->w * q->x, 627 628 2 * q->x * q->z - 2 * q->w * q->y, 629 2 * q->y * q->z + 2 * q->w * q->x, 630 1 - 2 * q->x * q->x - 2 * q->y * q->y, 631 }}; 632 633 *result_out = result; 634} 635 636extern "C" void 637math_matrix_3x3_f64_identity(struct xrt_matrix_3x3_f64 *mat) 638{ 639 map_matrix_3x3_f64(*mat) = Eigen::Matrix3d::Identity(); 640} 641 642extern "C" void 643math_matrix_3x3_f64_transform_vec3_f64(const struct xrt_matrix_3x3_f64 *left, 644 const struct xrt_vec3_f64 *right, 645 struct xrt_vec3_f64 *result_out) 646{ 647 Eigen::Matrix3d m; 648 m << left->v[0], left->v[1], left->v[2], // 1 649 left->v[3], left->v[4], left->v[5], // 2 650 left->v[6], left->v[7], left->v[8]; // 3 651 652 map_vec3_f64(*result_out) = m * copy(right); 653} 654 655extern "C" void 656math_matrix_3x3_f64_from_plus_x_z(const struct xrt_vec3_f64 *plus_x, 657 const struct xrt_vec3_f64 *plus_z, 658 struct xrt_matrix_3x3_f64 *result) 659{ 660 xrt_vec3_f64 plus_y; 661 math_vec3_f64_cross(plus_z, plus_x, &plus_y); 662 663 result->v[0] = plus_x->x; 664 result->v[1] = plus_y.x; 665 result->v[2] = plus_z->x; 666 result->v[3] = plus_x->y; 667 result->v[4] = plus_y.y; 668 result->v[5] = plus_z->y; 669 result->v[6] = plus_x->z; 670 result->v[7] = plus_y.z; 671 result->v[8] = plus_z->z; 672} 673 674extern "C" void 675math_matrix_3x3_rotation_from_isometry(const struct xrt_matrix_4x4 *isometry, struct xrt_matrix_3x3 *result) 676{ 677 Eigen::Isometry3f transform{map_matrix_4x4(*isometry)}; 678 map_matrix_3x3(*result) = transform.linear(); 679} 680 681extern "C" void 682math_matrix_3x3_transform_vec3(const struct xrt_matrix_3x3 *left, 683 const struct xrt_vec3 *right, 684 struct xrt_vec3 *result_out) 685{ 686 Eigen::Matrix3f m; 687 m << left->v[0], left->v[1], left->v[2], // 1 688 left->v[3], left->v[4], left->v[5], // 2 689 left->v[6], left->v[7], left->v[8]; // 3 690 691 map_vec3(*result_out) = m * copy(right); 692} 693 694extern "C" void 695math_matrix_4x4_transform_vec3(const struct xrt_matrix_4x4 *left, 696 const struct xrt_vec3 *right, 697 struct xrt_vec3 *result_out) 698{ 699 Eigen::Matrix4f m = copy(left); 700 701 Eigen::Vector4f v; 702 v << right->x, right->y, right->z, 1.0; 703 704 Eigen::Vector4f res; 705 res = m * v; 706 707 result_out->x = res.x(); 708 result_out->y = res.y(); 709 result_out->z = res.z(); 710} 711 712extern "C" void 713math_matrix_3x3_multiply(const struct xrt_matrix_3x3 *left, 714 const struct xrt_matrix_3x3 *right, 715 struct xrt_matrix_3x3 *result_out) 716{ 717 const struct xrt_matrix_3x3 l = *left; 718 const struct xrt_matrix_3x3 r = *right; 719 720 struct xrt_matrix_3x3 result = {{ 721 l.v[0] * r.v[0] + l.v[1] * r.v[3] + l.v[2] * r.v[6], 722 l.v[0] * r.v[1] + l.v[1] * r.v[4] + l.v[2] * r.v[7], 723 l.v[0] * r.v[2] + l.v[1] * r.v[5] + l.v[2] * r.v[8], 724 l.v[3] * r.v[0] + l.v[4] * r.v[3] + l.v[5] * r.v[6], 725 l.v[3] * r.v[1] + l.v[4] * r.v[4] + l.v[5] * r.v[7], 726 l.v[3] * r.v[2] + l.v[4] * r.v[5] + l.v[5] * r.v[8], 727 l.v[6] * r.v[0] + l.v[7] * r.v[3] + l.v[8] * r.v[6], 728 l.v[6] * r.v[1] + l.v[7] * r.v[4] + l.v[8] * r.v[7], 729 l.v[6] * r.v[2] + l.v[7] * r.v[5] + l.v[8] * r.v[8], 730 }}; 731 732 *result_out = result; 733} 734 735extern "C" void 736math_matrix_3x3_inverse(const struct xrt_matrix_3x3 *in, struct xrt_matrix_3x3 *result) 737{ 738 Eigen::Matrix3f m = copy(in); 739 map_matrix_3x3(*result) = m.inverse(); 740} 741 742extern "C" void 743math_matrix_3x3_transpose(const struct xrt_matrix_3x3 *in, struct xrt_matrix_3x3 *result) 744{ 745 Eigen::Matrix3f m = copy(in); 746 map_matrix_3x3(*result) = m.transpose(); 747} 748 749extern "C" void 750math_matrix_4x4_identity(struct xrt_matrix_4x4 *result) 751{ 752 map_matrix_4x4(*result) = Eigen::Matrix4f::Identity(); 753} 754 755extern "C" void 756math_matrix_4x4_multiply(const struct xrt_matrix_4x4 *left, 757 const struct xrt_matrix_4x4 *right, 758 struct xrt_matrix_4x4 *result) 759{ 760 map_matrix_4x4(*result) = copy(left) * copy(right); 761} 762 763extern "C" void 764math_matrix_4x4_inverse(const struct xrt_matrix_4x4 *in, struct xrt_matrix_4x4 *result) 765{ 766 Eigen::Matrix4f m = copy(in); 767 map_matrix_4x4(*result) = m.inverse(); 768} 769 770extern "C" void 771math_matrix_4x4_transpose(const struct xrt_matrix_4x4 *in, struct xrt_matrix_4x4 *result) 772{ 773 Eigen::Matrix4f m = copy(in); 774 map_matrix_4x4(*result) = m.transpose(); 775} 776 777extern "C" void 778math_matrix_4x4_isometry_inverse(const struct xrt_matrix_4x4 *in, struct xrt_matrix_4x4 *result) 779{ 780 Eigen::Isometry3f m{copy(in)}; 781 map_matrix_4x4(*result) = m.inverse().matrix(); 782} 783 784extern "C" void 785math_matrix_4x4_view_from_pose(const struct xrt_pose *pose, struct xrt_matrix_4x4 *result) 786{ 787 Eigen::Vector3f position = copy(&pose->position); 788 Eigen::Quaternionf orientation = copy(&pose->orientation); 789 790 Eigen::Translation3f translation(position); 791 Eigen::Isometry3f transformation = translation * orientation; 792 793 map_matrix_4x4(*result) = transformation.inverse().matrix(); 794} 795 796extern "C" void 797math_matrix_4x4_isometry_from_rt(const struct xrt_matrix_3x3 *rotation, 798 const struct xrt_vec3 *translation, 799 struct xrt_matrix_4x4 *result) 800{ 801 Eigen::Isometry3f transformation = Eigen::Isometry3f::Identity(); 802 transformation.linear() = map_matrix_3x3(*rotation); 803 transformation.translation() = map_vec3(*translation); 804 map_matrix_4x4(*result) = transformation.matrix(); 805} 806 807extern "C" void 808math_matrix_4x4_isometry_from_pose(const struct xrt_pose *pose, struct xrt_matrix_4x4 *result) 809{ 810 Eigen::Isometry3f transform{Eigen::Translation3f{position(*pose)} * orientation(*pose)}; 811 map_matrix_4x4(*result) = transform.matrix(); 812} 813 814extern "C" void 815math_matrix_4x4_model(const struct xrt_pose *pose, const struct xrt_vec3 *size, struct xrt_matrix_4x4 *result) 816{ 817 Eigen::Vector3f position = copy(&pose->position); 818 Eigen::Quaternionf orientation = copy(&pose->orientation); 819 820 auto scale = Eigen::Scaling(size->x, size->y, size->z); 821 822 Eigen::Translation3f translation(position); 823 Eigen::Affine3f transformation = translation * orientation * scale; 824 825 map_matrix_4x4(*result) = transformation.matrix(); 826} 827 828extern "C" void 829math_matrix_4x4_inverse_view_projection(const struct xrt_matrix_4x4 *view, 830 const struct xrt_matrix_4x4 *projection, 831 struct xrt_matrix_4x4 *result) 832{ 833 Eigen::Matrix4f v = copy(view); 834 Eigen::Matrix4f v3 = Eigen::Matrix4f::Identity(); 835 v3.block<3, 3>(0, 0) = v.block<3, 3>(0, 0); 836 Eigen::Matrix4f vp = copy(projection) * v3; 837 map_matrix_4x4(*result) = vp.inverse(); 838} 839 840 841/* 842 * 843 * Exported Matrix 4x4 functions. 844 * 845 */ 846 847extern "C" void 848m_mat4_f64_identity(struct xrt_matrix_4x4_f64 *result) 849{ 850 map_matrix_4x4_f64(*result) = Eigen::Matrix4d::Identity(); 851} 852 853extern "C" void 854m_mat4_f64_invert(const struct xrt_matrix_4x4_f64 *matrix, struct xrt_matrix_4x4_f64 *result) 855{ 856 Eigen::Matrix4d m = map_matrix_4x4_f64(*matrix); 857 map_matrix_4x4_f64(*result) = m.inverse(); 858} 859 860extern "C" void 861m_mat4_f64_multiply(const struct xrt_matrix_4x4_f64 *left, 862 const struct xrt_matrix_4x4_f64 *right, 863 struct xrt_matrix_4x4_f64 *result) 864{ 865 Eigen::Matrix4d l = map_matrix_4x4_f64(*left); 866 Eigen::Matrix4d r = map_matrix_4x4_f64(*right); 867 868 map_matrix_4x4_f64(*result) = l * r; 869} 870 871extern "C" void 872m_mat4_f64_orientation(const struct xrt_quat *quat, struct xrt_matrix_4x4_f64 *result) 873{ 874 map_matrix_4x4_f64(*result) = Eigen::Affine3d(copyd(*quat)).matrix(); 875} 876 877extern "C" void 878m_mat4_f64_model(const struct xrt_pose *pose, const struct xrt_vec3 *size, struct xrt_matrix_4x4_f64 *result) 879{ 880 Eigen::Vector3d position = copyd(pose->position); 881 Eigen::Quaterniond orientation = copyd(pose->orientation); 882 883 auto scale = Eigen::Scaling(copyd(size)); 884 885 Eigen::Translation3d translation(position); 886 Eigen::Affine3d transformation = translation * orientation * scale; 887 888 map_matrix_4x4_f64(*result) = transformation.matrix(); 889} 890 891extern "C" void 892m_mat4_f64_view(const struct xrt_pose *pose, struct xrt_matrix_4x4_f64 *result) 893{ 894 Eigen::Vector3d position = copyd(pose->position); 895 Eigen::Quaterniond orientation = copyd(pose->orientation); 896 897 Eigen::Translation3d translation(position); 898 Eigen::Isometry3d transformation = translation * orientation; 899 900 map_matrix_4x4_f64(*result) = transformation.inverse().matrix(); 901} 902 903 904/* 905 * 906 * Exported pose functions. 907 * 908 */ 909 910extern "C" bool 911math_pose_validate(const struct xrt_pose *pose) 912{ 913 assert(pose != NULL); 914 915 return math_vec3_validate(&pose->position) && math_quat_validate(&pose->orientation); 916} 917 918extern "C" void 919math_pose_invert(const struct xrt_pose *pose, struct xrt_pose *outPose) 920{ 921 Eigen::Isometry3f transform{Eigen::Translation3f{position(*pose)} * orientation(*pose)}; 922 Eigen::Isometry3f inverse = transform.inverse(); 923 position(*outPose) = inverse.translation(); 924 orientation(*outPose) = inverse.rotation(); 925} 926 927extern "C" void 928math_pose_from_isometry(const struct xrt_matrix_4x4 *transform, struct xrt_pose *result) 929{ 930 Eigen::Isometry3f isometry{map_matrix_4x4(*transform)}; 931 position(*result) = isometry.translation(); 932 orientation(*result) = isometry.rotation(); 933} 934 935extern "C" void 936math_pose_interpolate(const struct xrt_pose *a, const struct xrt_pose *b, float t, struct xrt_pose *outPose) 937{ 938 math_quat_slerp(&a->orientation, &b->orientation, t, &outPose->orientation); 939 outPose->position = m_vec3_lerp(a->position, b->position, t); 940} 941 942extern "C" void 943math_pose_identity(struct xrt_pose *pose) 944{ 945 pose->position.x = 0.0; 946 pose->position.y = 0.0; 947 pose->position.z = 0.0; 948 pose->orientation.x = 0.0; 949 pose->orientation.y = 0.0; 950 pose->orientation.z = 0.0; 951 pose->orientation.w = 1.0; 952} 953 954/*! 955 * Return the result of transforming a point by a pose/transform. 956 */ 957static inline Eigen::Vector3f 958transform_point(const xrt_pose &transform, const xrt_vec3 &point) 959{ 960 return orientation(transform) * map_vec3(point) + position(transform); 961} 962 963/*! 964 * Return the result of transforming a pose by a pose/transform. 965 */ 966static inline xrt_pose 967transform_pose(const xrt_pose &transform, const xrt_pose &pose) 968{ 969 xrt_pose ret; 970 position(ret) = transform_point(transform, pose.position); 971 orientation(ret) = orientation(transform) * orientation(pose); 972 return ret; 973} 974 975extern "C" void 976math_pose_transform(const struct xrt_pose *transform, const struct xrt_pose *pose, struct xrt_pose *outPose) 977{ 978 assert(pose != NULL); 979 assert(transform != NULL); 980 assert(outPose != NULL); 981 982 xrt_pose newPose = transform_pose(*transform, *pose); 983 memcpy(outPose, &newPose, sizeof(xrt_pose)); 984} 985 986extern "C" void 987math_pose_transform_point(const struct xrt_pose *transform, const struct xrt_vec3 *point, struct xrt_vec3 *out_point) 988{ 989 assert(transform != NULL); 990 assert(point != NULL); 991 assert(out_point != NULL); 992 993 map_vec3(*out_point) = transform_point(*transform, *point); 994}