1 /** 2 * Quaternion of 4 double-precision doubles which can represent rotation and uniform scaling. 3 * 4 * @author Richard Greenlees 5 * @author Kai Burjack 6 */ 7 module doml.quaternion_d; 8 9 import Math = doml.math; 10 11 import doml.axis_angle_4d; 12 import doml.matrix_3d; 13 import doml.matrix_4d; 14 import doml.matrix_4x3d; 15 import doml.vector_3d; 16 import doml.vector_4d; 17 18 /* 19 * The MIT License 20 * 21 * Copyright (c) 2015-2021 Richard Greenlees 22 * 23 * Permission is hereby granted, free of charge, to any person obtaining a copy 24 * of this software and associated documentation files (the "Software"), to deal 25 * in the Software without restriction, including without limitation the rights 26 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 27 * copies of the Software, and to permit persons to whom the Software is 28 * furnished to do so, subject to the following conditions: 29 * 30 * The above copyright notice and this permission notice shall be included in 31 * all copies or substantial portions of the Software. 32 * 33 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 34 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 35 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 36 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 37 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 38 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 39 * THE SOFTWARE. 40 */ 41 42 /** 43 * Quaternion of 4 double-precision doubles which can represent rotation and uniform scaling. 44 * 45 * @author Richard Greenlees 46 * @author Kai Burjack 47 */ 48 struct Quaterniond { 49 50 /** 51 * The first component of the vector part. 52 */ 53 public double x = 0.0; 54 /** 55 * The second component of the vector part. 56 */ 57 public double y = 0.0; 58 /** 59 * The third component of the vector part. 60 */ 61 public double z = 0.0; 62 /** 63 * The real/scalar part of the quaternion. 64 */ 65 public double w = 1.0; 66 67 /** 68 * Create a new {@link Quaterniond} and initialize its components to the given values. 69 * 70 * @param x 71 * the first component of the imaginary part 72 * @param y 73 * the second component of the imaginary part 74 * @param z 75 * the third component of the imaginary part 76 * @param w 77 * the real part 78 */ 79 this(double x, double y, double z, double w) { 80 this.x = x; 81 this.y = y; 82 this.z = z; 83 this.w = w; 84 } 85 86 /** 87 * Create a new {@link Quaterniond} and initialize its components to the same values as the given {@link Quaterniond}. 88 * 89 * @param source 90 * the {@link Quaterniond} to take the component values from 91 */ 92 this(Quaterniond source) { 93 x = source.x; 94 y = source.y; 95 z = source.z; 96 w = source.w; 97 } 98 99 /** 100 * Create a new {@link Quaterniond} and initialize it to represent the same rotation as the given {@link AxisAngle4d}. 101 * 102 * @param axisAngle 103 * the axis-angle to initialize this quaternion with 104 */ 105 this(AxisAngle4d axisAngle) { 106 double s = Math.sin(axisAngle.angle * 0.5); 107 x = axisAngle.x * s; 108 y = axisAngle.y * s; 109 z = axisAngle.z * s; 110 w = Math.cosFromSin(s, axisAngle.angle * 0.5); 111 } 112 113 /** 114 * Normalize this quaternion. 115 * 116 * @return this 117 */ 118 ref public Quaterniond normalize() return { 119 double invNorm = Math.invsqrt(lengthSquared()); 120 x *= invNorm; 121 y *= invNorm; 122 z *= invNorm; 123 w *= invNorm; 124 return this; 125 } 126 127 public Quaterniond normalize(ref Quaterniond dest) { 128 double invNorm = Math.invsqrt(lengthSquared()); 129 dest.x = x * invNorm; 130 dest.y = y * invNorm; 131 dest.z = z * invNorm; 132 dest.w = w * invNorm; 133 return dest; 134 } 135 136 /** 137 * Add the quaternion <code>(x, y, z, w)</code> to this quaternion. 138 * 139 * @param x 140 * the x component of the vector part 141 * @param y 142 * the y component of the vector part 143 * @param z 144 * the z component of the vector part 145 * @param w 146 * the real/scalar component 147 * @return this 148 */ 149 ref public Quaterniond add(double x, double y, double z, double w) return { 150 add(x, y, z, w, this); 151 return this; 152 } 153 154 public Quaterniond add(double x, double y, double z, double w, ref Quaterniond dest) { 155 dest.x = this.x + x; 156 dest.y = this.y + y; 157 dest.z = this.z + z; 158 dest.w = this.w + w; 159 return dest; 160 } 161 162 /** 163 * Add <code>q2</code> to this quaternion. 164 * 165 * @param q2 166 * the quaternion to add to this 167 * @return this 168 */ 169 ref public Quaterniond add(Quaterniond q2) return { 170 x += q2.x; 171 y += q2.y; 172 z += q2.z; 173 w += q2.w; 174 return this; 175 } 176 177 public Quaterniond add(Quaterniond q2, ref Quaterniond dest) { 178 dest.x = x + q2.x; 179 dest.y = y + q2.y; 180 dest.z = z + q2.z; 181 dest.w = w + q2.w; 182 return dest; 183 } 184 185 public double dot(Quaterniond otherQuat) { 186 return this.x * otherQuat.x + this.y * otherQuat.y + this.z * otherQuat.z + this.w * otherQuat.w; 187 } 188 189 public double angle() { 190 return 2.0 * Math.safeAcos(w); 191 } 192 193 public Matrix3d get(ref Matrix3d dest) { 194 return dest.set(this); 195 } 196 197 198 public Matrix4d get(ref Matrix4d dest) { 199 return dest.set(this); 200 } 201 202 public AxisAngle4d get(AxisAngle4d dest) { 203 double x = this.x; 204 double y = this.y; 205 double z = this.z; 206 double w = this.w; 207 if (w > 1.0) { 208 double invNorm = Math.invsqrt(lengthSquared()); 209 x *= invNorm; 210 y *= invNorm; 211 z *= invNorm; 212 w *= invNorm; 213 } 214 dest.angle = 2.0 * Math.acos(w); 215 double s = Math.sqrt(1.0 - w * w); 216 if (s < 0.001) { 217 dest.x = x; 218 dest.y = y; 219 dest.z = z; 220 } else { 221 s = 1.0 / s; 222 dest.x = x * s; 223 dest.y = y * s; 224 dest.z = z * s; 225 } 226 return dest; 227 } 228 229 /** 230 * Set the given {@link Quaterniond} to the values of <code>this</code>. 231 * 232 * @see #set(Quaterniond) 233 * 234 * @param dest 235 * the {@link Quaterniond} to set 236 * @return the passed in destination 237 */ 238 public Quaterniond get(ref Quaterniond dest) { 239 return dest.set(this); 240 } 241 242 243 /** 244 * Set this quaternion to the new values. 245 * 246 * @param x 247 * the new value of x 248 * @param y 249 * the new value of y 250 * @param z 251 * the new value of z 252 * @param w 253 * the new value of w 254 * @return this 255 */ 256 ref public Quaterniond set(double x, double y, double z, double w) return { 257 this.x = x; 258 this.y = y; 259 this.z = z; 260 this.w = w; 261 return this; 262 } 263 264 /** 265 * Set this quaternion to be a copy of q. 266 * 267 * @param q 268 * the {@link Quaterniond} to copy 269 * @return this 270 */ 271 ref public Quaterniond set(Quaterniond q) return { 272 x = q.x; 273 y = q.y; 274 z = q.z; 275 w = q.w; 276 return this; 277 } 278 279 /** 280 * Set this {@link Quaterniond} to be equivalent to the given 281 * {@link AxisAngle4d}. 282 * 283 * @param axisAngle 284 * the {@link AxisAngle4d} 285 * @return this 286 */ 287 ref public Quaterniond set(AxisAngle4d axisAngle) return { 288 return setAngleAxis(axisAngle.angle, axisAngle.x, axisAngle.y, axisAngle.z); 289 } 290 291 /** 292 * Set this quaternion to a rotation equivalent to the supplied axis and 293 * angle (in radians). 294 * <p> 295 * This method assumes that the given rotation axis <code>(x, y, z)</code> is already normalized 296 * 297 * @param angle 298 * the angle in radians 299 * @param x 300 * the x-component of the normalized rotation axis 301 * @param y 302 * the y-component of the normalized rotation axis 303 * @param z 304 * the z-component of the normalized rotation axis 305 * @return this 306 */ 307 ref public Quaterniond setAngleAxis(double angle, double x, double y, double z) return { 308 double s = Math.sin(angle * 0.5); 309 this.x = x * s; 310 this.y = y * s; 311 this.z = z * s; 312 this.w = Math.cosFromSin(s, angle * 0.5); 313 return this; 314 } 315 316 /** 317 * Set this quaternion to be a representation of the supplied axis and 318 * angle (in radians). 319 * 320 * @param angle 321 * the angle in radians 322 * @param axis 323 * the rotation axis 324 * @return this 325 */ 326 ref public Quaterniond setAngleAxis(double angle, Vector3d axis) return { 327 return setAngleAxis(angle, axis.x, axis.y, axis.z); 328 } 329 330 private void setFromUnnormalized(double m00, double m01, double m02, double m10, double m11, double m12, double m20, double m21, double m22) { 331 double nm00 = m00, nm01 = m01, nm02 = m02; 332 double nm10 = m10, nm11 = m11, nm12 = m12; 333 double nm20 = m20, nm21 = m21, nm22 = m22; 334 double lenX = Math.invsqrt(m00 * m00 + m01 * m01 + m02 * m02); 335 double lenY = Math.invsqrt(m10 * m10 + m11 * m11 + m12 * m12); 336 double lenZ = Math.invsqrt(m20 * m20 + m21 * m21 + m22 * m22); 337 nm00 *= lenX; nm01 *= lenX; nm02 *= lenX; 338 nm10 *= lenY; nm11 *= lenY; nm12 *= lenY; 339 nm20 *= lenZ; nm21 *= lenZ; nm22 *= lenZ; 340 setFromNormalized(nm00, nm01, nm02, nm10, nm11, nm12, nm20, nm21, nm22); 341 } 342 343 private void setFromNormalized(double m00, double m01, double m02, double m10, double m11, double m12, double m20, double m21, double m22) { 344 double t; 345 double tr = m00 + m11 + m22; 346 if (tr >= 0.0) { 347 t = Math.sqrt(tr + 1.0); 348 w = t * 0.5; 349 t = 0.5 / t; 350 x = (m12 - m21) * t; 351 y = (m20 - m02) * t; 352 z = (m01 - m10) * t; 353 } else { 354 if (m00 >= m11 && m00 >= m22) { 355 t = Math.sqrt(m00 - (m11 + m22) + 1.0); 356 x = t * 0.5; 357 t = 0.5 / t; 358 y = (m10 + m01) * t; 359 z = (m02 + m20) * t; 360 w = (m12 - m21) * t; 361 } else if (m11 > m22) { 362 t = Math.sqrt(m11 - (m22 + m00) + 1.0); 363 y = t * 0.5; 364 t = 0.5 / t; 365 z = (m21 + m12) * t; 366 x = (m10 + m01) * t; 367 w = (m20 - m02) * t; 368 } else { 369 t = Math.sqrt(m22 - (m00 + m11) + 1.0); 370 z = t * 0.5; 371 t = 0.5 / t; 372 x = (m02 + m20) * t; 373 y = (m21 + m12) * t; 374 w = (m01 - m10) * t; 375 } 376 } 377 } 378 379 380 /** 381 * Set this quaternion to be a representation of the rotational component of the given matrix. 382 * <p> 383 * This method assumes that the first three columns of the upper left 3x3 submatrix are no unit vectors. 384 * 385 * @param mat 386 * the matrix whose rotational component is used to set this quaternion 387 * @return this 388 */ 389 ref public Quaterniond setFromUnnormalized(Matrix4x3d mat) return { 390 setFromUnnormalized(mat.m00, mat.m01, mat.m02, mat.m10, mat.m11, mat.m12, mat.m20, mat.m21, mat.m22); 391 return this; 392 } 393 394 395 /** 396 * Set this quaternion to be a representation of the rotational component of the given matrix. 397 * <p> 398 * This method assumes that the first three columns of the upper left 3x3 submatrix are unit vectors. 399 * 400 * @param mat 401 * the matrix whose rotational component is used to set this quaternion 402 * @return this 403 */ 404 ref public Quaterniond setFromNormalized(Matrix4x3d mat) return { 405 setFromNormalized(mat.m00, mat.m01, mat.m02, mat.m10, mat.m11, mat.m12, mat.m20, mat.m21, mat.m22); 406 return this; 407 } 408 409 /** 410 * Set this quaternion to be a representation of the rotational component of the given matrix. 411 * <p> 412 * This method assumes that the first three columns of the upper left 3x3 submatrix are no unit vectors. 413 * 414 * @param mat 415 * the matrix whose rotational component is used to set this quaternion 416 * @return this 417 */ 418 ref public Quaterniond setFromUnnormalized(Matrix4d mat) return { 419 setFromUnnormalized(mat.m00, mat.m01, mat.m02, mat.m10, mat.m11, mat.m12, mat.m20, mat.m21, mat.m22); 420 return this; 421 } 422 423 /** 424 * Set this quaternion to be a representation of the rotational component of the given matrix. 425 * <p> 426 * This method assumes that the first three columns of the upper left 3x3 submatrix are unit vectors. 427 * 428 * @param mat 429 * the matrix whose rotational component is used to set this quaternion 430 * @return this 431 */ 432 ref public Quaterniond setFromNormalized(Matrix4d mat) return { 433 setFromNormalized(mat.m00, mat.m01, mat.m02, mat.m10, mat.m11, mat.m12, mat.m20, mat.m21, mat.m22); 434 return this; 435 } 436 437 438 439 /** 440 * Set this quaternion to be a representation of the rotational component of the given matrix. 441 * <p> 442 * This method assumes that the first three columns of the upper left 3x3 submatrix are no unit vectors. 443 * 444 * @param mat 445 * the matrix whose rotational component is used to set this quaternion 446 * @return this 447 */ 448 ref public Quaterniond setFromUnnormalized(Matrix3d mat) return { 449 setFromUnnormalized(mat.m00, mat.m01, mat.m02, mat.m10, mat.m11, mat.m12, mat.m20, mat.m21, mat.m22); 450 return this; 451 } 452 453 /** 454 * Set this quaternion to be a representation of the rotational component of the given matrix. 455 * 456 * @param mat 457 * the matrix whose rotational component is used to set this quaternion 458 * @return this 459 */ 460 ref public Quaterniond setFromNormalized(Matrix3d mat) return { 461 setFromNormalized(mat.m00, mat.m01, mat.m02, mat.m10, mat.m11, mat.m12, mat.m20, mat.m21, mat.m22); 462 return this; 463 } 464 465 /** 466 * Set this quaternion to be a representation of the supplied axis and 467 * angle (in radians). 468 * 469 * @param axis 470 * the rotation axis 471 * @param angle 472 * the angle in radians 473 * @return this 474 */ 475 ref public Quaterniond fromAxisAngleRad(Vector3d axis, double angle) return { 476 return fromAxisAngleRad(axis.x, axis.y, axis.z, angle); 477 } 478 479 /** 480 * Set this quaternion to be a representation of the supplied axis and 481 * angle (in radians). 482 * 483 * @param axisX 484 * the x component of the rotation axis 485 * @param axisY 486 * the y component of the rotation axis 487 * @param axisZ 488 * the z component of the rotation axis 489 * @param angle 490 * the angle in radians 491 * @return this 492 */ 493 ref public Quaterniond fromAxisAngleRad(double axisX, double axisY, double axisZ, double angle) return { 494 double hangle = angle / 2.0; 495 double sinAngle = Math.sin(hangle); 496 double vLength = Math.sqrt(axisX * axisX + axisY * axisY + axisZ * axisZ); 497 x = axisX / vLength * sinAngle; 498 y = axisY / vLength * sinAngle; 499 z = axisZ / vLength * sinAngle; 500 w = Math.cosFromSin(sinAngle, hangle); 501 return this; 502 } 503 504 /** 505 * Set this quaternion to be a representation of the supplied axis and 506 * angle (in degrees). 507 * 508 * @param axis 509 * the rotation axis 510 * @param angle 511 * the angle in degrees 512 * @return this 513 */ 514 ref public Quaterniond fromAxisAngleDeg(Vector3d axis, double angle) return { 515 return fromAxisAngleRad(axis.x, axis.y, axis.z, Math.toRadians(angle)); 516 } 517 518 /** 519 * Set this quaternion to be a representation of the supplied axis and 520 * angle (in degrees). 521 * 522 * @param axisX 523 * the x component of the rotation axis 524 * @param axisY 525 * the y component of the rotation axis 526 * @param axisZ 527 * the z component of the rotation axis 528 * @param angle 529 * the angle in radians 530 * @return this 531 */ 532 ref public Quaterniond fromAxisAngleDeg(double axisX, double axisY, double axisZ, double angle) return { 533 return fromAxisAngleRad(axisX, axisY, axisZ, Math.toRadians(angle)); 534 } 535 536 /** 537 * Multiply this quaternion by <code>q</code>. 538 * <p> 539 * If <code>T</code> is <code>this</code> and <code>Q</code> is the given 540 * quaternion, then the resulting quaternion <code>R</code> is: 541 * <p> 542 * <code>R = T * Q</code> 543 * <p> 544 * So, this method uses post-multiplication like the matrix classes, resulting in a 545 * vector to be transformed by <code>Q</code> first, and then by <code>T</code>. 546 * 547 * @param q 548 * the quaternion to multiply <code>this</code> by 549 * @return this 550 */ 551 ref public Quaterniond mul(Quaterniond q) return { 552 mul(q, this); 553 return this; 554 } 555 556 public Quaterniond mul(Quaterniond q, ref Quaterniond dest) { 557 return mul(q.x, q.y, q.z, q.w, dest); 558 } 559 560 /** 561 * Multiply this quaternion by the quaternion represented via <code>(qx, qy, qz, qw)</code>. 562 * <p> 563 * If <code>T</code> is <code>this</code> and <code>Q</code> is the given 564 * quaternion, then the resulting quaternion <code>R</code> is: 565 * <p> 566 * <code>R = T * Q</code> 567 * <p> 568 * So, this method uses post-multiplication like the matrix classes, resulting in a 569 * vector to be transformed by <code>Q</code> first, and then by <code>T</code>. 570 * 571 * @param qx 572 * the x component of the quaternion to multiply <code>this</code> by 573 * @param qy 574 * the y component of the quaternion to multiply <code>this</code> by 575 * @param qz 576 * the z component of the quaternion to multiply <code>this</code> by 577 * @param qw 578 * the w component of the quaternion to multiply <code>this</code> by 579 * @return this 580 */ 581 ref public Quaterniond mul(double qx, double qy, double qz, double qw) return { 582 mul(qx, qy, qz, qw, this); 583 return this; 584 } 585 586 public Quaterniond mul(double qx, double qy, double qz, double qw, ref Quaterniond dest) { 587 return dest.set(Math.fma(w, qx, Math.fma(x, qw, Math.fma(y, qz, -z * qy))), 588 Math.fma(w, qy, Math.fma(-x, qz, Math.fma(y, qw, z * qx))), 589 Math.fma(w, qz, Math.fma(x, qy, Math.fma(-y, qx, z * qw))), 590 Math.fma(w, qw, Math.fma(-x, qx, Math.fma(-y, qy, -z * qz)))); 591 } 592 593 /** 594 * Pre-multiply this quaternion by <code>q</code>. 595 * <p> 596 * If <code>T</code> is <code>this</code> and <code>Q</code> is the given quaternion, then the resulting quaternion <code>R</code> is: 597 * <p> 598 * <code>R = Q * T</code> 599 * <p> 600 * So, this method uses pre-multiplication, resulting in a vector to be transformed by <code>T</code> first, and then by <code>Q</code>. 601 * 602 * @param q 603 * the quaternion to pre-multiply <code>this</code> by 604 * @return this 605 */ 606 ref public Quaterniond premul(Quaterniond q) return { 607 premul(q, this); 608 return this; 609 } 610 611 public Quaterniond premul(Quaterniond q, ref Quaterniond dest) { 612 return premul(q.x, q.y, q.z, q.w, dest); 613 } 614 615 /** 616 * Pre-multiply this quaternion by the quaternion represented via <code>(qx, qy, qz, qw)</code>. 617 * <p> 618 * If <code>T</code> is <code>this</code> and <code>Q</code> is the given quaternion, then the resulting quaternion <code>R</code> is: 619 * <p> 620 * <code>R = Q * T</code> 621 * <p> 622 * So, this method uses pre-multiplication, resulting in a vector to be transformed by <code>T</code> first, and then by <code>Q</code>. 623 * 624 * @param qx 625 * the x component of the quaternion to multiply <code>this</code> by 626 * @param qy 627 * the y component of the quaternion to multiply <code>this</code> by 628 * @param qz 629 * the z component of the quaternion to multiply <code>this</code> by 630 * @param qw 631 * the w component of the quaternion to multiply <code>this</code> by 632 * @return this 633 */ 634 ref public Quaterniond premul(double qx, double qy, double qz, double qw) return { 635 premul(qx, qy, qz, qw, this); 636 return this; 637 } 638 639 public Quaterniond premul(double qx, double qy, double qz, double qw, ref Quaterniond dest) { 640 return dest.set(Math.fma(qw, x, Math.fma(qx, w, Math.fma(qy, z, -qz * y))), 641 Math.fma(qw, y, Math.fma(-qx, z, Math.fma(qy, w, qz * x))), 642 Math.fma(qw, z, Math.fma(qx, y, Math.fma(-qy, x, qz * w))), 643 Math.fma(qw, w, Math.fma(-qx, x, Math.fma(-qy, y, -qz * z)))); 644 } 645 646 public Vector3d transform(Vector3d vec){ 647 return transform(vec.x, vec.y, vec.z, vec); 648 } 649 650 public Vector3d transformInverse(Vector3d vec){ 651 return transformInverse(vec.x, vec.y, vec.z, vec); 652 } 653 654 public Vector3d transformUnit(Vector3d vec){ 655 return transformUnit(vec.x, vec.y, vec.z, vec); 656 } 657 658 public Vector3d transformInverseUnit(Vector3d vec){ 659 return transformInverseUnit(vec.x, vec.y, vec.z, vec); 660 } 661 662 public Vector3d transformPositiveX(ref Vector3d dest) { 663 double ww = w * w; 664 double xx = x * x; 665 double yy = y * y; 666 double zz = z * z; 667 double zw = z * w; 668 double xy = x * y; 669 double xz = x * z; 670 double yw = y * w; 671 dest.x = ww + xx - zz - yy; 672 dest.y = xy + zw + zw + xy; 673 dest.z = xz - yw + xz - yw; 674 return dest; 675 } 676 677 public Vector4d transformPositiveX(ref Vector4d dest) { 678 double ww = w * w; 679 double xx = x * x; 680 double yy = y * y; 681 double zz = z * z; 682 double zw = z * w; 683 double xy = x * y; 684 double xz = x * z; 685 double yw = y * w; 686 dest.x = ww + xx - zz - yy; 687 dest.y = xy + zw + zw + xy; 688 dest.z = xz - yw + xz - yw; 689 return dest; 690 } 691 692 public Vector3d transformUnitPositiveX(ref Vector3d dest) { 693 double yy = y * y; 694 double zz = z * z; 695 double xy = x * y; 696 double xz = x * z; 697 double yw = y * w; 698 double zw = z * w; 699 dest.x = 1.0 - yy - yy - zz - zz; 700 dest.y = xy + zw + xy + zw; 701 dest.z = xz - yw + xz - yw; 702 return dest; 703 } 704 705 public Vector4d transformUnitPositiveX(ref Vector4d dest) { 706 double yy = y * y; 707 double zz = z * z; 708 double xy = x * y; 709 double xz = x * z; 710 double yw = y * w; 711 double zw = z * w; 712 dest.x = 1.0 - yy - yy - zz - zz; 713 dest.y = xy + zw + xy + zw; 714 dest.z = xz - yw + xz - yw; 715 return dest; 716 } 717 718 public Vector3d transformPositiveY(ref Vector3d dest) { 719 double ww = w * w; 720 double xx = x * x; 721 double yy = y * y; 722 double zz = z * z; 723 double zw = z * w; 724 double xy = x * y; 725 double yz = y * z; 726 double xw = x * w; 727 dest.x = -zw + xy - zw + xy; 728 dest.y = yy - zz + ww - xx; 729 dest.z = yz + yz + xw + xw; 730 return dest; 731 } 732 733 public Vector4d transformPositiveY(ref Vector4d dest) { 734 double ww = w * w; 735 double xx = x * x; 736 double yy = y * y; 737 double zz = z * z; 738 double zw = z * w; 739 double xy = x * y; 740 double yz = y * z; 741 double xw = x * w; 742 dest.x = -zw + xy - zw + xy; 743 dest.y = yy - zz + ww - xx; 744 dest.z = yz + yz + xw + xw; 745 return dest; 746 } 747 748 public Vector4d transformUnitPositiveY(ref Vector4d dest) { 749 double xx = x * x; 750 double zz = z * z; 751 double xy = x * y; 752 double yz = y * z; 753 double xw = x * w; 754 double zw = z * w; 755 dest.x = xy - zw + xy - zw; 756 dest.y = 1.0 - xx - xx - zz - zz; 757 dest.z = yz + yz + xw + xw; 758 return dest; 759 } 760 761 public Vector3d transformUnitPositiveY(ref Vector3d dest) { 762 double xx = x * x; 763 double zz = z * z; 764 double xy = x * y; 765 double yz = y * z; 766 double xw = x * w; 767 double zw = z * w; 768 dest.x = xy - zw + xy - zw; 769 dest.y = 1.0 - xx - xx - zz - zz; 770 dest.z = yz + yz + xw + xw; 771 return dest; 772 } 773 774 public Vector3d transformPositiveZ(ref Vector3d dest) { 775 double ww = w * w; 776 double xx = x * x; 777 double yy = y * y; 778 double zz = z * z; 779 double xz = x * z; 780 double yw = y * w; 781 double yz = y * z; 782 double xw = x * w; 783 dest.x = yw + xz + xz + yw; 784 dest.y = yz + yz - xw - xw; 785 dest.z = zz - yy - xx + ww; 786 return dest; 787 } 788 789 public Vector4d transformPositiveZ(ref Vector4d dest) { 790 double ww = w * w; 791 double xx = x * x; 792 double yy = y * y; 793 double zz = z * z; 794 double xz = x * z; 795 double yw = y * w; 796 double yz = y * z; 797 double xw = x * w; 798 dest.x = yw + xz + xz + yw; 799 dest.y = yz + yz - xw - xw; 800 dest.z = zz - yy - xx + ww; 801 return dest; 802 } 803 804 public Vector4d transformUnitPositiveZ(ref Vector4d dest) { 805 double xx = x * x; 806 double yy = y * y; 807 double xz = x * z; 808 double yz = y * z; 809 double xw = x * w; 810 double yw = y * w; 811 dest.x = xz + yw + xz + yw; 812 dest.y = yz + yz - xw - xw; 813 dest.z = 1.0 - xx - xx - yy - yy; 814 return dest; 815 } 816 817 public Vector3d transformUnitPositiveZ(ref Vector3d dest) { 818 double xx = x * x; 819 double yy = y * y; 820 double xz = x * z; 821 double yz = y * z; 822 double xw = x * w; 823 double yw = y * w; 824 dest.x = xz + yw + xz + yw; 825 dest.y = yz + yz - xw - xw; 826 dest.z = 1.0 - xx - xx - yy - yy; 827 return dest; 828 } 829 830 public Vector4d transform(Vector4d vec){ 831 return transform(vec, vec); 832 } 833 834 public Vector4d transformInverse(Vector4d vec){ 835 return transformInverse(vec, vec); 836 } 837 838 public Vector3d transform(Vector3d vec, ref Vector3d dest) { 839 return transform(vec.x, vec.y, vec.z, dest); 840 } 841 842 public Vector3d transformInverse(Vector3d vec, ref Vector3d dest) { 843 return transformInverse(vec.x, vec.y, vec.z, dest); 844 } 845 846 public Vector3d transform(double x, double y, double z, ref Vector3d dest) { 847 double xx = this.x * this.x, yy = this.y * this.y, zz = this.z * this.z, ww = this.w * this.w; 848 double xy = this.x * this.y, xz = this.x * this.z, yz = this.y * this.z, xw = this.x * this.w; 849 double zw = this.z * this.w, yw = this.y * this.w, k = 1 / (xx + yy + zz + ww); 850 return dest.set(Math.fma((xx - yy - zz + ww) * k, x, Math.fma(2 * (xy - zw) * k, y, (2 * (xz + yw) * k) * z)), 851 Math.fma(2 * (xy + zw) * k, x, Math.fma((yy - xx - zz + ww) * k, y, (2 * (yz - xw) * k) * z)), 852 Math.fma(2 * (xz - yw) * k, x, Math.fma(2 * (yz + xw) * k, y, ((zz - xx - yy + ww) * k) * z))); 853 } 854 855 public Vector3d transformInverse(double x, double y, double z, ref Vector3d dest) { 856 double n = 1.0 / Math.fma(this.x, this.x, Math.fma(this.y, this.y, Math.fma(this.z, this.z, this.w * this.w))); 857 double qx = this.x * n, qy = this.y * n, qz = this.z * n, qw = this.w * n; 858 double xx = qx * qx, yy = qy * qy, zz = qz * qz, ww = qw * qw; 859 double xy = qx * qy, xz = qx * qz, yz = qy * qz, xw = qx * qw; 860 double zw = qz * qw, yw = qy * qw, k = 1 / (xx + yy + zz + ww); 861 return dest.set(Math.fma((xx - yy - zz + ww) * k, x, Math.fma(2 * (xy + zw) * k, y, (2 * (xz - yw) * k) * z)), 862 Math.fma(2 * (xy - zw) * k, x, Math.fma((yy - xx - zz + ww) * k, y, (2 * (yz + xw) * k) * z)), 863 Math.fma(2 * (xz + yw) * k, x, Math.fma(2 * (yz - xw) * k, y, ((zz - xx - yy + ww) * k) * z))); 864 } 865 866 public Vector4d transform(Vector4d vec, ref Vector4d dest) { 867 return transform(vec.x, vec.y, vec.z, dest); 868 } 869 870 public Vector4d transformInverse(Vector4d vec, ref Vector4d dest) { 871 return transformInverse(vec.x, vec.y, vec.z, dest); 872 } 873 874 public Vector4d transform(double x, double y, double z, ref Vector4d dest) { 875 double xx = this.x * this.x, yy = this.y * this.y, zz = this.z * this.z, ww = this.w * this.w; 876 double xy = this.x * this.y, xz = this.x * this.z, yz = this.y * this.z, xw = this.x * this.w; 877 double zw = this.z * this.w, yw = this.y * this.w, k = 1 / (xx + yy + zz + ww); 878 return dest.set(Math.fma((xx - yy - zz + ww) * k, x, Math.fma(2 * (xy - zw) * k, y, (2 * (xz + yw) * k) * z)), 879 Math.fma(2 * (xy + zw) * k, x, Math.fma((yy - xx - zz + ww) * k, y, (2 * (yz - xw) * k) * z)), 880 Math.fma(2 * (xz - yw) * k, x, Math.fma(2 * (yz + xw) * k, y, ((zz - xx - yy + ww) * k) * z)), dest.w); 881 } 882 883 public Vector4d transformInverse(double x, double y, double z, ref Vector4d dest) { 884 double n = 1.0 / Math.fma(this.x, this.x, Math.fma(this.y, this.y, Math.fma(this.z, this.z, this.w * this.w))); 885 double qx = this.x * n, qy = this.y * n, qz = this.z * n, qw = this.w * n; 886 double xx = qx * qx, yy = qy * qy, zz = qz * qz, ww = qw * qw; 887 double xy = qx * qy, xz = qx * qz, yz = qy * qz, xw = qx * qw; 888 double zw = qz * qw, yw = qy * qw, k = 1 / (xx + yy + zz + ww); 889 return dest.set(Math.fma((xx - yy - zz + ww) * k, x, Math.fma(2 * (xy + zw) * k, y, (2 * (xz - yw) * k) * z)), 890 Math.fma(2 * (xy - zw) * k, x, Math.fma((yy - xx - zz + ww) * k, y, (2 * (yz + xw) * k) * z)), 891 Math.fma(2 * (xz + yw) * k, x, Math.fma(2 * (yz - xw) * k, y, ((zz - xx - yy + ww) * k) * z))); 892 } 893 894 public Vector4d transformUnit(Vector4d vec){ 895 return transformUnit(vec, vec); 896 } 897 898 public Vector4d transformInverseUnit(Vector4d vec){ 899 return transformInverseUnit(vec, vec); 900 } 901 902 public Vector3d transformUnit(Vector3d vec, ref Vector3d dest) { 903 return transformUnit(vec.x, vec.y, vec.z, dest); 904 } 905 906 public Vector3d transformInverseUnit(Vector3d vec, ref Vector3d dest) { 907 return transformInverseUnit(vec.x, vec.y, vec.z, dest); 908 } 909 910 public Vector3d transformUnit(double x, double y, double z, ref Vector3d dest) { 911 double xx = this.x * this.x, xy = this.x * this.y, xz = this.x * this.z; 912 double xw = this.x * this.w, yy = this.y * this.y, yz = this.y * this.z; 913 double yw = this.y * this.w, zz = this.z * this.z, zw = this.z * this.w; 914 return dest.set(Math.fma(Math.fma(-2, yy + zz, 1), x, Math.fma(2 * (xy - zw), y, (2 * (xz + yw)) * z)), 915 Math.fma(2 * (xy + zw), x, Math.fma(Math.fma(-2, xx + zz, 1), y, (2 * (yz - xw)) * z)), 916 Math.fma(2 * (xz - yw), x, Math.fma(2 * (yz + xw), y, Math.fma(-2, xx + yy, 1) * z))); 917 } 918 919 public Vector3d transformInverseUnit(double x, double y, double z, ref Vector3d dest) { 920 double xx = this.x * this.x, xy = this.x * this.y, xz = this.x * this.z; 921 double xw = this.x * this.w, yy = this.y * this.y, yz = this.y * this.z; 922 double yw = this.y * this.w, zz = this.z * this.z, zw = this.z * this.w; 923 return dest.set(Math.fma(Math.fma(-2, yy + zz, 1), x, Math.fma(2 * (xy + zw), y, (2 * (xz - yw)) * z)), 924 Math.fma(2 * (xy - zw), x, Math.fma(Math.fma(-2, xx + zz, 1), y, (2 * (yz + xw)) * z)), 925 Math.fma(2 * (xz + yw), x, Math.fma(2 * (yz - xw), y, Math.fma(-2, xx + yy, 1) * z))); 926 } 927 928 public Vector4d transformUnit(Vector4d vec, ref Vector4d dest) { 929 return transformUnit(vec.x, vec.y, vec.z, dest); 930 } 931 932 public Vector4d transformInverseUnit(Vector4d vec, ref Vector4d dest) { 933 return transformInverseUnit(vec.x, vec.y, vec.z, dest); 934 } 935 936 public Vector4d transformUnit(double x, double y, double z, ref Vector4d dest) { 937 double xx = this.x * this.x, xy = this.x * this.y, xz = this.x * this.z; 938 double xw = this.x * this.w, yy = this.y * this.y, yz = this.y * this.z; 939 double yw = this.y * this.w, zz = this.z * this.z, zw = this.z * this.w; 940 return dest.set(Math.fma(Math.fma(-2, yy + zz, 1), x, Math.fma(2 * (xy - zw), y, (2 * (xz + yw)) * z)), 941 Math.fma(2 * (xy + zw), x, Math.fma(Math.fma(-2, xx + zz, 1), y, (2 * (yz - xw)) * z)), 942 Math.fma(2 * (xz - yw), x, Math.fma(2 * (yz + xw), y, Math.fma(-2, xx + yy, 1) * z)), 943 dest.w); 944 } 945 946 public Vector4d transformInverseUnit(double x, double y, double z, ref Vector4d dest) { 947 double xx = this.x * this.x, xy = this.x * this.y, xz = this.x * this.z; 948 double xw = this.x * this.w, yy = this.y * this.y, yz = this.y * this.z; 949 double yw = this.y * this.w, zz = this.z * this.z, zw = this.z * this.w; 950 return dest.set(Math.fma(Math.fma(-2, yy + zz, 1), x, Math.fma(2 * (xy + zw), y, (2 * (xz - yw)) * z)), 951 Math.fma(2 * (xy - zw), x, Math.fma(Math.fma(-2, xx + zz, 1), y, (2 * (yz + xw)) * z)), 952 Math.fma(2 * (xz + yw), x, Math.fma(2 * (yz - xw), y, Math.fma(-2, xx + yy, 1) * z)), 953 dest.w); 954 } 955 956 957 public Quaterniond invert(ref Quaterniond dest) { 958 double invNorm = 1.0 / lengthSquared(); 959 dest.x = -x * invNorm; 960 dest.y = -y * invNorm; 961 dest.z = -z * invNorm; 962 dest.w = w * invNorm; 963 return dest; 964 } 965 966 /** 967 * Invert this quaternion and {@link #normalize() normalize} it. 968 * <p> 969 * If this quaternion is already normalized, then {@link #conjugate()} should be used instead. 970 * 971 * @see #conjugate() 972 * 973 * @return this 974 */ 975 ref public Quaterniond invert() return { 976 invert(this); 977 return this; 978 } 979 980 public Quaterniond div(Quaterniond b, ref Quaterniond dest) { 981 double invNorm = 1.0 / Math.fma(b.x, b.x, Math.fma(b.y, b.y, Math.fma(b.z, b.z, b.w * b.w))); 982 double x = -b.x * invNorm; 983 double y = -b.y * invNorm; 984 double z = -b.z * invNorm; 985 double w = b.w * invNorm; 986 return dest.set(Math.fma(this.w, x, Math.fma(this.x, w, Math.fma(this.y, z, -this.z * y))), 987 Math.fma(this.w, y, Math.fma(-this.x, z, Math.fma(this.y, w, this.z * x))), 988 Math.fma(this.w, z, Math.fma(this.x, y, Math.fma(-this.y, x, this.z * w))), 989 Math.fma(this.w, w, Math.fma(-this.x, x, Math.fma(-this.y, y, -this.z * z)))); 990 } 991 992 /** 993 * Divide <code>this</code> quaternion by <code>b</code>. 994 * <p> 995 * The division expressed using the inverse is performed in the following way: 996 * <p> 997 * <code>this = this * b^-1</code>, where <code>b^-1</code> is the inverse of <code>b</code>. 998 * 999 * @param b 1000 * the {@link Quaterniond} to divide this by 1001 * @return this 1002 */ 1003 ref public Quaterniond div(Quaterniond b) return { 1004 div(b, this); 1005 return this; 1006 } 1007 1008 /** 1009 * Conjugate this quaternion. 1010 * 1011 * @return this 1012 */ 1013 ref public Quaterniond conjugate() return { 1014 x = -x; 1015 y = -y; 1016 z = -z; 1017 return this; 1018 } 1019 1020 public Quaterniond conjugate(ref Quaterniond dest) { 1021 dest.x = -x; 1022 dest.y = -y; 1023 dest.z = -z; 1024 dest.w = w; 1025 return dest; 1026 } 1027 1028 /** 1029 * Set this quaternion to the identity. 1030 * 1031 * @return this 1032 */ 1033 ref public Quaterniond identity() return { 1034 x = 0.0; 1035 y = 0.0; 1036 z = 0.0; 1037 w = 1.0; 1038 return this; 1039 } 1040 1041 public double lengthSquared() { 1042 return Math.fma(x, x, Math.fma(y, y, Math.fma(z, z, w * w))); 1043 } 1044 1045 /** 1046 * Set this quaternion from the supplied euler angles (in radians) with rotation order XYZ. 1047 * <p> 1048 * This method is equivalent to calling: <code>rotationX(angleX).rotateY(angleY).rotateZ(angleZ)</code> 1049 * <p> 1050 * Reference: <a href="http://gamedev.stackexchange.com/questions/13436/glm-euler-angles-to-quaternion#answer-13446">this stackexchange answer</a> 1051 * 1052 * @param angleX 1053 * the angle in radians to rotate about x 1054 * @param angleY 1055 * the angle in radians to rotate about y 1056 * @param angleZ 1057 * the angle in radians to rotate about z 1058 * @return this 1059 */ 1060 ref public Quaterniond rotationXYZ(double angleX, double angleY, double angleZ) return { 1061 double sx = Math.sin(angleX * 0.5); 1062 double cx = Math.cosFromSin(sx, angleX * 0.5); 1063 double sy = Math.sin(angleY * 0.5); 1064 double cy = Math.cosFromSin(sy, angleY * 0.5); 1065 double sz = Math.sin(angleZ * 0.5); 1066 double cz = Math.cosFromSin(sz, angleZ * 0.5); 1067 1068 double cycz = cy * cz; 1069 double sysz = sy * sz; 1070 double sycz = sy * cz; 1071 double cysz = cy * sz; 1072 w = cx*cycz - sx*sysz; 1073 x = sx*cycz + cx*sysz; 1074 y = cx*sycz - sx*cysz; 1075 z = cx*cysz + sx*sycz; 1076 1077 return this; 1078 } 1079 1080 /** 1081 * Set this quaternion from the supplied euler angles (in radians) with rotation order ZYX. 1082 * <p> 1083 * This method is equivalent to calling: <code>rotationZ(angleZ).rotateY(angleY).rotateX(angleX)</code> 1084 * <p> 1085 * Reference: <a href="http://gamedev.stackexchange.com/questions/13436/glm-euler-angles-to-quaternion#answer-13446">this stackexchange answer</a> 1086 * 1087 * @param angleX 1088 * the angle in radians to rotate about x 1089 * @param angleY 1090 * the angle in radians to rotate about y 1091 * @param angleZ 1092 * the angle in radians to rotate about z 1093 * @return this 1094 */ 1095 ref public Quaterniond rotationZYX(double angleZ, double angleY, double angleX) return { 1096 double sx = Math.sin(angleX * 0.5); 1097 double cx = Math.cosFromSin(sx, angleX * 0.5); 1098 double sy = Math.sin(angleY * 0.5); 1099 double cy = Math.cosFromSin(sy, angleY * 0.5); 1100 double sz = Math.sin(angleZ * 0.5); 1101 double cz = Math.cosFromSin(sz, angleZ * 0.5); 1102 1103 double cycz = cy * cz; 1104 double sysz = sy * sz; 1105 double sycz = sy * cz; 1106 double cysz = cy * sz; 1107 w = cx*cycz + sx*sysz; 1108 x = sx*cycz - cx*sysz; 1109 y = cx*sycz + sx*cysz; 1110 z = cx*cysz - sx*sycz; 1111 1112 return this; 1113 } 1114 1115 /** 1116 * Set this quaternion from the supplied euler angles (in radians) with rotation order YXZ. 1117 * <p> 1118 * This method is equivalent to calling: <code>rotationY(angleY).rotateX(angleX).rotateZ(angleZ)</code> 1119 * <p> 1120 * Reference: <a href="https://en.wikipedia.org/wiki/Conversion_between_quaternions_and_Euler_angles">https://en.wikipedia.org</a> 1121 * 1122 * @param angleY 1123 * the angle in radians to rotate about y 1124 * @param angleX 1125 * the angle in radians to rotate about x 1126 * @param angleZ 1127 * the angle in radians to rotate about z 1128 * @return this 1129 */ 1130 ref public Quaterniond rotationYXZ(double angleY, double angleX, double angleZ) return { 1131 double sx = Math.sin(angleX * 0.5); 1132 double cx = Math.cosFromSin(sx, angleX * 0.5); 1133 double sy = Math.sin(angleY * 0.5); 1134 double cy = Math.cosFromSin(sy, angleY * 0.5); 1135 double sz = Math.sin(angleZ * 0.5); 1136 double cz = Math.cosFromSin(sz, angleZ * 0.5); 1137 1138 double x = cy * sx; 1139 double y = sy * cx; 1140 double z = sy * sx; 1141 double w = cy * cx; 1142 this.x = x * cz + y * sz; 1143 this.y = y * cz - x * sz; 1144 this.z = w * sz - z * cz; 1145 this.w = w * cz + z * sz; 1146 1147 return this; 1148 } 1149 1150 /** 1151 * Interpolate between <code>this</code> {@link #normalize() unit} quaternion and the specified 1152 * <code>target</code> {@link #normalize() unit} quaternion using spherical linear interpolation using the specified interpolation factor <code>alpha</code>. 1153 * <p> 1154 * This method resorts to non-spherical linear interpolation when the absolute dot product between <code>this</code> and <code>target</code> is 1155 * below <code>1E-6</code>. 1156 * 1157 * @param target 1158 * the target of the interpolation, which should be reached with <code>alpha = 1.0</code> 1159 * @param alpha 1160 * the interpolation factor, within <code>[0..1]</code> 1161 * @return this 1162 */ 1163 ref public Quaterniond slerp(Quaterniond target, double alpha) return { 1164 slerp(target, alpha, this); 1165 return this; 1166 } 1167 1168 public Quaterniond slerp(Quaterniond target, double alpha, ref Quaterniond dest) { 1169 double cosom = Math.fma(x, target.x, Math.fma(y, target.y, Math.fma(z, target.z, w * target.w))); 1170 double absCosom = Math.abs(cosom); 1171 double scale0, scale1; 1172 if (1.0 - absCosom > 1E-6) { 1173 double sinSqr = 1.0 - absCosom * absCosom; 1174 double sinom = Math.invsqrt(sinSqr); 1175 double omega = Math.atan2(sinSqr * sinom, absCosom); 1176 scale0 = Math.sin((1.0 - alpha) * omega) * sinom; 1177 scale1 = Math.sin(alpha * omega) * sinom; 1178 } else { 1179 scale0 = 1.0 - alpha; 1180 scale1 = alpha; 1181 } 1182 scale1 = cosom >= 0.0 ? scale1 : -scale1; 1183 dest.x = Math.fma(scale0, x, scale1 * target.x); 1184 dest.y = Math.fma(scale0, y, scale1 * target.y); 1185 dest.z = Math.fma(scale0, z, scale1 * target.z); 1186 dest.w = Math.fma(scale0, w, scale1 * target.w); 1187 return dest; 1188 } 1189 1190 /** 1191 * Interpolate between all of the quaternions given in <code>qs</code> via spherical linear interpolation using the specified interpolation factors <code>weights</code>, 1192 * and store the result in <code>dest</code>. 1193 * <p> 1194 * This method will interpolate between each two successive quaternions via {@link #slerp(Quaterniond, double)} using their relative interpolation weights. 1195 * <p> 1196 * This method resorts to non-spherical linear interpolation when the absolute dot product of any two interpolated quaternions is below <code>1E-6f</code>. 1197 * <p> 1198 * Reference: <a href="http://gamedev.stackexchange.com/questions/62354/method-for-interpolation-between-3-quaternions#answer-62356">http://gamedev.stackexchange.com/</a> 1199 * 1200 * @param qs 1201 * the quaternions to interpolate over 1202 * @param weights 1203 * the weights of each individual quaternion in <code>qs</code> 1204 * @param dest 1205 * will hold the result 1206 * @return dest 1207 */ 1208 public static Quaterniond slerp(Quaterniond[] qs, double[] weights, ref Quaterniond dest) { 1209 dest.set(qs[0]); 1210 double w = weights[0]; 1211 for (int i = 1; i < qs.length; i++) { 1212 double w0 = w; 1213 double w1 = weights[i]; 1214 double rw1 = w1 / (w0 + w1); 1215 w += w1; 1216 dest.slerp(qs[i], rw1); 1217 } 1218 return dest; 1219 } 1220 1221 /** 1222 * Apply scaling to this quaternion, which results in any vector transformed by this quaternion to change 1223 * its length by the given <code>factor</code>. 1224 * 1225 * @param factor 1226 * the scaling factor 1227 * @return this 1228 */ 1229 ref public Quaterniond scale(double factor) return { 1230 scale(factor, this); 1231 return this; 1232 } 1233 1234 public Quaterniond scale(double factor, ref Quaterniond dest) { 1235 double sqrt = Math.sqrt(factor); 1236 dest.x = sqrt * x; 1237 dest.y = sqrt * y; 1238 dest.z = sqrt * z; 1239 dest.w = sqrt * w; 1240 return dest; 1241 } 1242 1243 /** 1244 * Set this quaternion to represent scaling, which results in a transformed vector to change 1245 * its length by the given <code>factor</code>. 1246 * 1247 * @param factor 1248 * the scaling factor 1249 * @return this 1250 */ 1251 ref public Quaterniond scaling(double factor) return { 1252 double sqrt = Math.sqrt(factor); 1253 this.x = 0.0; 1254 this.y = 0.0; 1255 this.z = 0.0; 1256 this.w = sqrt; 1257 return this; 1258 } 1259 1260 /** 1261 * Integrate the rotation given by the angular velocity <code>(vx, vy, vz)</code> around the x, y and z axis, respectively, 1262 * with respect to the given elapsed time delta <code>dt</code> and add the differentiate rotation to the rotation represented by this quaternion. 1263 * <p> 1264 * This method pre-multiplies the rotation given by <code>dt</code> and <code>(vx, vy, vz)</code> by <code>this</code>, so 1265 * the angular velocities are always relative to the local coordinate system of the rotation represented by <code>this</code> quaternion. 1266 * <p> 1267 * This method is equivalent to calling: <code>rotateLocal(dt * vx, dt * vy, dt * vz)</code> 1268 * <p> 1269 * Reference: <a href="http://physicsforgames.blogspot.de/2010/02/quaternions.html">http://physicsforgames.blogspot.de/</a> 1270 * 1271 * @param dt 1272 * the delta time 1273 * @param vx 1274 * the angular velocity around the x axis 1275 * @param vy 1276 * the angular velocity around the y axis 1277 * @param vz 1278 * the angular velocity around the z axis 1279 * @return this 1280 */ 1281 ref public Quaterniond integrate(double dt, double vx, double vy, double vz) return { 1282 integrate(dt, vx, vy, vz, this); 1283 return this; 1284 } 1285 1286 public Quaterniond integrate(double dt, double vx, double vy, double vz, ref Quaterniond dest) { 1287 double thetaX = dt * vx * 0.5; 1288 double thetaY = dt * vy * 0.5; 1289 double thetaZ = dt * vz * 0.5; 1290 double thetaMagSq = thetaX * thetaX + thetaY * thetaY + thetaZ * thetaZ; 1291 double s; 1292 double dqX, dqY, dqZ, dqW; 1293 if (thetaMagSq * thetaMagSq / 24.0 < 1E-8) { 1294 dqW = 1.0 - thetaMagSq * 0.5; 1295 s = 1.0 - thetaMagSq / 6.0; 1296 } else { 1297 double thetaMag = Math.sqrt(thetaMagSq); 1298 double sin = Math.sin(thetaMag); 1299 s = sin / thetaMag; 1300 dqW = Math.cosFromSin(sin, thetaMag); 1301 } 1302 dqX = thetaX * s; 1303 dqY = thetaY * s; 1304 dqZ = thetaZ * s; 1305 /* Pre-multiplication */ 1306 return dest.set(Math.fma(dqW, x, Math.fma(dqX, w, Math.fma(dqY, z, -dqZ * y))), 1307 Math.fma(dqW, y, Math.fma(-dqX, z, Math.fma(dqY, w, dqZ * x))), 1308 Math.fma(dqW, z, Math.fma(dqX, y, Math.fma(-dqY, x, dqZ * w))), 1309 Math.fma(dqW, w, Math.fma(-dqX, x, Math.fma(-dqY, y, -dqZ * z)))); 1310 } 1311 1312 /** 1313 * Compute a linear (non-spherical) interpolation of <code>this</code> and the given quaternion <code>q</code> 1314 * and store the result in <code>this</code>. 1315 * 1316 * @param q 1317 * the other quaternion 1318 * @param factor 1319 * the interpolation factor. It is between 0.0 and 1.0 1320 * @return this 1321 */ 1322 ref public Quaterniond nlerp(Quaterniond q, double factor) return { 1323 nlerp(q, factor, this); 1324 return this; 1325 } 1326 1327 public Quaterniond nlerp(Quaterniond q, double factor, ref Quaterniond dest) { 1328 double cosom = Math.fma(x, q.x, Math.fma(y, q.y, Math.fma(z, q.z, w * q.w))); 1329 double scale0 = 1.0 - factor; 1330 double scale1 = (cosom >= 0.0) ? factor : -factor; 1331 dest.x = Math.fma(scale0, x, scale1 * q.x); 1332 dest.y = Math.fma(scale0, y, scale1 * q.y); 1333 dest.z = Math.fma(scale0, z, scale1 * q.z); 1334 dest.w = Math.fma(scale0, w, scale1 * q.w); 1335 double s = Math.invsqrt(Math.fma(dest.x, dest.x, Math.fma(dest.y, dest.y, Math.fma(dest.z, dest.z, dest.w * dest.w)))); 1336 dest.x *= s; 1337 dest.y *= s; 1338 dest.z *= s; 1339 dest.w *= s; 1340 return dest; 1341 } 1342 1343 /** 1344 * Interpolate between all of the quaternions given in <code>qs</code> via non-spherical linear interpolation using the 1345 * specified interpolation factors <code>weights</code>, and store the result in <code>dest</code>. 1346 * <p> 1347 * This method will interpolate between each two successive quaternions via {@link #nlerp(Quaterniond, double)} 1348 * using their relative interpolation weights. 1349 * <p> 1350 * Reference: <a href="http://gamedev.stackexchange.com/questions/62354/method-for-interpolation-between-3-quaternions#answer-62356">http://gamedev.stackexchange.com/</a> 1351 * 1352 * @param qs 1353 * the quaternions to interpolate over 1354 * @param weights 1355 * the weights of each individual quaternion in <code>qs</code> 1356 * @param dest 1357 * will hold the result 1358 * @return dest 1359 */ 1360 public static Quaterniond nlerp(Quaterniond[] qs, double[] weights, ref Quaterniond dest) { 1361 dest.set(qs[0]); 1362 double w = weights[0]; 1363 for (int i = 1; i < qs.length; i++) { 1364 double w0 = w; 1365 double w1 = weights[i]; 1366 double rw1 = w1 / (w0 + w1); 1367 w += w1; 1368 dest.nlerp(qs[i], rw1); 1369 } 1370 return dest; 1371 } 1372 1373 public Quaterniond nlerpIterative(Quaterniond q, double alpha, double dotThreshold, ref Quaterniond dest) { 1374 double q1x = x, q1y = y, q1z = z, q1w = w; 1375 double q2x = q.x, q2y = q.y, q2z = q.z, q2w = q.w; 1376 double dot = Math.fma(q1x, q2x, Math.fma(q1y, q2y, Math.fma(q1z, q2z, q1w * q2w))); 1377 double absDot = Math.abs(dot); 1378 if (1.0 - 1E-6 < absDot) { 1379 return dest.set(this); 1380 } 1381 double alphaN = alpha; 1382 while (absDot < dotThreshold) { 1383 double scale0 = 0.5; 1384 double scale1 = dot >= 0.0 ? 0.5 : -0.5; 1385 if (alphaN < 0.5) { 1386 q2x = Math.fma(scale0, q2x, scale1 * q1x); 1387 q2y = Math.fma(scale0, q2y, scale1 * q1y); 1388 q2z = Math.fma(scale0, q2z, scale1 * q1z); 1389 q2w = Math.fma(scale0, q2w, scale1 * q1w); 1390 double s = cast(double) Math.invsqrt(Math.fma(q2x, q2x, Math.fma(q2y, q2y, Math.fma(q2z, q2z, q2w * q2w)))); 1391 q2x *= s; 1392 q2y *= s; 1393 q2z *= s; 1394 q2w *= s; 1395 alphaN = alphaN + alphaN; 1396 } else { 1397 q1x = Math.fma(scale0, q1x, scale1 * q2x); 1398 q1y = Math.fma(scale0, q1y, scale1 * q2y); 1399 q1z = Math.fma(scale0, q1z, scale1 * q2z); 1400 q1w = Math.fma(scale0, q1w, scale1 * q2w); 1401 double s = cast(double) Math.invsqrt(Math.fma(q1x, q1x, Math.fma(q1y, q1y, Math.fma(q1z, q1z, q1w * q1w)))); 1402 q1x *= s; 1403 q1y *= s; 1404 q1z *= s; 1405 q1w *= s; 1406 alphaN = alphaN + alphaN - 1.0; 1407 } 1408 dot = Math.fma(q1x, q2x, Math.fma(q1y, q2y, Math.fma(q1z, q2z, q1w * q2w))); 1409 absDot = Math.abs(dot); 1410 } 1411 double scale0 = 1.0 - alphaN; 1412 double scale1 = dot >= 0.0 ? alphaN : -alphaN; 1413 double resX = Math.fma(scale0, q1x, scale1 * q2x); 1414 double resY = Math.fma(scale0, q1y, scale1 * q2y); 1415 double resZ = Math.fma(scale0, q1z, scale1 * q2z); 1416 double resW = Math.fma(scale0, q1w, scale1 * q2w); 1417 double s = Math.invsqrt(Math.fma(resX, resX, Math.fma(resY, resY, Math.fma(resZ, resZ, resW * resW)))); 1418 dest.x = resX * s; 1419 dest.y = resY * s; 1420 dest.z = resZ * s; 1421 dest.w = resW * s; 1422 return dest; 1423 } 1424 1425 /** 1426 * Compute linear (non-spherical) interpolations of <code>this</code> and the given quaternion <code>q</code> 1427 * iteratively and store the result in <code>this</code>. 1428 * <p> 1429 * This method performs a series of small-step nlerp interpolations to avoid doing a costly spherical linear interpolation, like 1430 * {@link #slerp(Quaterniond, double, Quaterniond) slerp}, 1431 * by subdividing the rotation arc between <code>this</code> and <code>q</code> via non-spherical linear interpolations as long as 1432 * the absolute dot product of <code>this</code> and <code>q</code> is greater than the given <code>dotThreshold</code> parameter. 1433 * <p> 1434 * Thanks to <code>@theagentd</code> at <a href="http://www.java-gaming.org/">http://www.java-gaming.org/</a> for providing the code. 1435 * 1436 * @param q 1437 * the other quaternion 1438 * @param alpha 1439 * the interpolation factor, between 0.0 and 1.0 1440 * @param dotThreshold 1441 * the threshold for the dot product of <code>this</code> and <code>q</code> above which this method performs another iteration 1442 * of a small-step linear interpolation 1443 * @return this 1444 */ 1445 ref public Quaterniond nlerpIterative(Quaterniond q, double alpha, double dotThreshold) return { 1446 nlerpIterative(q, alpha, dotThreshold, this); 1447 return this; 1448 } 1449 1450 /** 1451 * Interpolate between all of the quaternions given in <code>qs</code> via iterative non-spherical linear interpolation using the 1452 * specified interpolation factors <code>weights</code>, and store the result in <code>dest</code>. 1453 * <p> 1454 * This method will interpolate between each two successive quaternions via {@link #nlerpIterative(Quaterniond, double, double)} 1455 * using their relative interpolation weights. 1456 * <p> 1457 * Reference: <a href="http://gamedev.stackexchange.com/questions/62354/method-for-interpolation-between-3-quaternions#answer-62356">http://gamedev.stackexchange.com/</a> 1458 * 1459 * @param qs 1460 * the quaternions to interpolate over 1461 * @param weights 1462 * the weights of each individual quaternion in <code>qs</code> 1463 * @param dotThreshold 1464 * the threshold for the dot product of each two interpolated quaternions above which {@link #nlerpIterative(Quaterniond, double, double)} performs another iteration 1465 * of a small-step linear interpolation 1466 * @param dest 1467 * will hold the result 1468 * @return dest 1469 */ 1470 public static Quaterniond nlerpIterative(Quaterniond[] qs, double[] weights, double dotThreshold, ref Quaterniond dest) { 1471 dest.set(qs[0]); 1472 double w = weights[0]; 1473 for (int i = 1; i < qs.length; i++) { 1474 double w0 = w; 1475 double w1 = weights[i]; 1476 double rw1 = w1 / (w0 + w1); 1477 w += w1; 1478 dest.nlerpIterative(qs[i], rw1, dotThreshold); 1479 } 1480 return dest; 1481 } 1482 1483 /** 1484 * Apply a rotation to this quaternion that maps the given direction to the positive Z axis. 1485 * <p> 1486 * Because there are multiple possibilities for such a rotation, this method will choose the one that ensures the given up direction to remain 1487 * parallel to the plane spanned by the <code>up</code> and <code>dir</code> vectors. 1488 * <p> 1489 * If <code>Q</code> is <code>this</code> quaternion and <code>R</code> the quaternion representing the 1490 * specified rotation, then the new quaternion will be <code>Q * R</code>. So when transforming a 1491 * vector <code>v</code> with the new quaternion by using <code>Q * R * v</code>, the 1492 * rotation added by this method will be applied first! 1493 * <p> 1494 * Reference: <a href="http://answers.unity3d.com/questions/467614/what-is-the-source-code-of-quaternionlookrotation.html">http://answers.unity3d.com</a> 1495 * 1496 * @see #lookAlong(double, double, double, double, double, double, Quaterniond) 1497 * 1498 * @param dir 1499 * the direction to map to the positive Z axis 1500 * @param up 1501 * the vector which will be mapped to a vector parallel to the plane 1502 * spanned by the given <code>dir</code> and <code>up</code> 1503 * @return this 1504 */ 1505 ref public Quaterniond lookAlong(Vector3d dir, Vector3d up) return { 1506 lookAlong(dir.x, dir.y, dir.z, up.x, up.y, up.z, this); 1507 return this; 1508 } 1509 1510 public Quaterniond lookAlong(Vector3d dir, Vector3d up, ref Quaterniond dest) { 1511 return lookAlong(dir.x, dir.y, dir.z, up.x, up.y, up.z, dest); 1512 } 1513 1514 /** 1515 * Apply a rotation to this quaternion that maps the given direction to the positive Z axis. 1516 * <p> 1517 * Because there are multiple possibilities for such a rotation, this method will choose the one that ensures the given up direction to remain 1518 * parallel to the plane spanned by the <code>up</code> and <code>dir</code> vectors. 1519 * <p> 1520 * If <code>Q</code> is <code>this</code> quaternion and <code>R</code> the quaternion representing the 1521 * specified rotation, then the new quaternion will be <code>Q * R</code>. So when transforming a 1522 * vector <code>v</code> with the new quaternion by using <code>Q * R * v</code>, the 1523 * rotation added by this method will be applied first! 1524 * <p> 1525 * Reference: <a href="http://answers.unity3d.com/questions/467614/what-is-the-source-code-of-quaternionlookrotation.html">http://answers.unity3d.com</a> 1526 * 1527 * @see #lookAlong(double, double, double, double, double, double, Quaterniond) 1528 * 1529 * @param dirX 1530 * the x-coordinate of the direction to look along 1531 * @param dirY 1532 * the y-coordinate of the direction to look along 1533 * @param dirZ 1534 * the z-coordinate of the direction to look along 1535 * @param upX 1536 * the x-coordinate of the up vector 1537 * @param upY 1538 * the y-coordinate of the up vector 1539 * @param upZ 1540 * the z-coordinate of the up vector 1541 * @return this 1542 */ 1543 ref public Quaterniond lookAlong(double dirX, double dirY, double dirZ, double upX, double upY, double upZ) return { 1544 lookAlong(dirX, dirY, dirZ, upX, upY, upZ, this); 1545 return this; 1546 } 1547 1548 public Quaterniond lookAlong(double dirX, double dirY, double dirZ, double upX, double upY, double upZ, ref Quaterniond dest) { 1549 // Normalize direction 1550 double invDirLength = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ); 1551 double dirnX = -dirX * invDirLength; 1552 double dirnY = -dirY * invDirLength; 1553 double dirnZ = -dirZ * invDirLength; 1554 // left = up x dir 1555 double leftX, leftY, leftZ; 1556 leftX = upY * dirnZ - upZ * dirnY; 1557 leftY = upZ * dirnX - upX * dirnZ; 1558 leftZ = upX * dirnY - upY * dirnX; 1559 // normalize left 1560 double invLeftLength = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ); 1561 leftX *= invLeftLength; 1562 leftY *= invLeftLength; 1563 leftZ *= invLeftLength; 1564 // up = direction x left 1565 double upnX = dirnY * leftZ - dirnZ * leftY; 1566 double upnY = dirnZ * leftX - dirnX * leftZ; 1567 double upnZ = dirnX * leftY - dirnY * leftX; 1568 1569 /* Convert orthonormal basis vectors to quaternion */ 1570 double x, y, z, w; 1571 double t; 1572 double tr = leftX + upnY + dirnZ; 1573 if (tr >= 0.0) { 1574 t = Math.sqrt(tr + 1.0); 1575 w = t * 0.5; 1576 t = 0.5 / t; 1577 x = (dirnY - upnZ) * t; 1578 y = (leftZ - dirnX) * t; 1579 z = (upnX - leftY) * t; 1580 } else { 1581 if (leftX > upnY && leftX > dirnZ) { 1582 t = Math.sqrt(1.0 + leftX - upnY - dirnZ); 1583 x = t * 0.5; 1584 t = 0.5 / t; 1585 y = (leftY + upnX) * t; 1586 z = (dirnX + leftZ) * t; 1587 w = (dirnY - upnZ) * t; 1588 } else if (upnY > dirnZ) { 1589 t = Math.sqrt(1.0 + upnY - leftX - dirnZ); 1590 y = t * 0.5; 1591 t = 0.5 / t; 1592 x = (leftY + upnX) * t; 1593 z = (upnZ + dirnY) * t; 1594 w = (leftZ - dirnX) * t; 1595 } else { 1596 t = Math.sqrt(1.0 + dirnZ - leftX - upnY); 1597 z = t * 0.5; 1598 t = 0.5 / t; 1599 x = (dirnX + leftZ) * t; 1600 y = (upnZ + dirnY) * t; 1601 w = (upnX - leftY) * t; 1602 } 1603 } 1604 /* Multiply */ 1605 return dest.set(Math.fma(this.w, x, Math.fma(this.x, w, Math.fma(this.y, z, -this.z * y))), 1606 Math.fma(this.w, y, Math.fma(-this.x, z, Math.fma(this.y, w, this.z * x))), 1607 Math.fma(this.w, z, Math.fma(this.x, y, Math.fma(-this.y, x, this.z * w))), 1608 Math.fma(this.w, w, Math.fma(-this.x, x, Math.fma(-this.y, y, -this.z * z)))); 1609 } 1610 1611 public int hashCode() { 1612 immutable int prime = 31; 1613 int result = 1; 1614 long temp; 1615 temp = Math.doubleToLongBits(w); 1616 result = prime * result + cast(int) (temp ^ (temp >>> 32)); 1617 temp = Math.doubleToLongBits(x); 1618 result = prime * result + cast(int) (temp ^ (temp >>> 32)); 1619 temp = Math.doubleToLongBits(y); 1620 result = prime * result + cast(int) (temp ^ (temp >>> 32)); 1621 temp = Math.doubleToLongBits(z); 1622 result = prime * result + cast(int) (temp ^ (temp >>> 32)); 1623 return result; 1624 } 1625 1626 public bool equals(Quaterniond other) { 1627 if (this == other) 1628 return true; 1629 if (Math.doubleToLongBits(w) != Math.doubleToLongBits(other.w)) 1630 return false; 1631 if (Math.doubleToLongBits(x) != Math.doubleToLongBits(other.x)) 1632 return false; 1633 if (Math.doubleToLongBits(y) != Math.doubleToLongBits(other.y)) 1634 return false; 1635 if (Math.doubleToLongBits(z) != Math.doubleToLongBits(other.z)) 1636 return false; 1637 return true; 1638 } 1639 1640 /** 1641 * Compute the difference between <code>this</code> and the <code>other</code> quaternion 1642 * and store the result in <code>this</code>. 1643 * <p> 1644 * The difference is the rotation that has to be applied to get from 1645 * <code>this</code> rotation to <code>other</code>. If <code>T</code> is <code>this</code>, <code>Q</code> 1646 * is <code>other</code> and <code>D</code> is the computed difference, then the following equation holds: 1647 * <p> 1648 * <code>T * D = Q</code> 1649 * <p> 1650 * It is defined as: <code>D = T^-1 * Q</code>, where <code>T^-1</code> denotes the {@link #invert() inverse} of <code>T</code>. 1651 * 1652 * @param other 1653 * the other quaternion 1654 * @return this 1655 */ 1656 ref public Quaterniond difference(Quaterniond other) return { 1657 difference(other, this); 1658 return this; 1659 } 1660 1661 public Quaterniond difference(Quaterniond other, ref Quaterniond dest) { 1662 double invNorm = 1.0 / lengthSquared(); 1663 double x = -this.x * invNorm; 1664 double y = -this.y * invNorm; 1665 double z = -this.z * invNorm; 1666 double w = this.w * invNorm; 1667 dest.set(Math.fma(w, other.x, Math.fma(x, other.w, Math.fma(y, other.z, -z * other.y))), 1668 Math.fma(w, other.y, Math.fma(-x, other.z, Math.fma(y, other.w, z * other.x))), 1669 Math.fma(w, other.z, Math.fma(x, other.y, Math.fma(-y, other.x, z * other.w))), 1670 Math.fma(w, other.w, Math.fma(-x, other.x, Math.fma(-y, other.y, -z * other.z)))); 1671 return dest; 1672 } 1673 1674 /** 1675 * Set <code>this</code> quaternion to a rotation that rotates the <code>fromDir</code> vector to point along <code>toDir</code>. 1676 * <p> 1677 * Since there can be multiple possible rotations, this method chooses the one with the shortest arc. 1678 * <p> 1679 * Reference: <a href="http://stackoverflow.com/questions/1171849/finding-quaternion-representing-the-rotation-from-one-vector-to-another#answer-1171995">stackoverflow.com</a> 1680 * 1681 * @param fromDirX 1682 * the x-coordinate of the direction to rotate into the destination direction 1683 * @param fromDirY 1684 * the y-coordinate of the direction to rotate into the destination direction 1685 * @param fromDirZ 1686 * the z-coordinate of the direction to rotate into the destination direction 1687 * @param toDirX 1688 * the x-coordinate of the direction to rotate to 1689 * @param toDirY 1690 * the y-coordinate of the direction to rotate to 1691 * @param toDirZ 1692 * the z-coordinate of the direction to rotate to 1693 * @return this 1694 */ 1695 ref public Quaterniond rotationTo(double fromDirX, double fromDirY, double fromDirZ, double toDirX, double toDirY, double toDirZ) return { 1696 double fn = Math.invsqrt(Math.fma(fromDirX, fromDirX, Math.fma(fromDirY, fromDirY, fromDirZ * fromDirZ))); 1697 double tn = Math.invsqrt(Math.fma(toDirX, toDirX, Math.fma(toDirY, toDirY, toDirZ * toDirZ))); 1698 double fx = fromDirX * fn, fy = fromDirY * fn, fz = fromDirZ * fn; 1699 double tx = toDirX * tn, ty = toDirY * tn, tz = toDirZ * tn; 1700 double dot = fx * tx + fy * ty + fz * tz; 1701 double x, y, z, w; 1702 if (dot < -1.0 + 1E-6) { 1703 x = fy; 1704 y = -fx; 1705 z = 0.0; 1706 w = 0.0; 1707 if (x * x + y * y == 0.0) { 1708 x = 0.0; 1709 y = fz; 1710 z = -fy; 1711 w = 0.0; 1712 } 1713 this.x = x; 1714 this.y = y; 1715 this.z = z; 1716 this.w = 0; 1717 } else { 1718 double sd2 = Math.sqrt((1.0 + dot) * 2.0); 1719 double isd2 = 1.0 / sd2; 1720 double cx = fy * tz - fz * ty; 1721 double cy = fz * tx - fx * tz; 1722 double cz = fx * ty - fy * tx; 1723 x = cx * isd2; 1724 y = cy * isd2; 1725 z = cz * isd2; 1726 w = sd2 * 0.5; 1727 double n2 = Math.invsqrt(Math.fma(x, x, Math.fma(y, y, Math.fma(z, z, w * w)))); 1728 this.x = x * n2; 1729 this.y = y * n2; 1730 this.z = z * n2; 1731 this.w = w * n2; 1732 } 1733 return this; 1734 } 1735 1736 /** 1737 * Set <code>this</code> quaternion to a rotation that rotates the <code>fromDir</code> vector to point along <code>toDir</code>. 1738 * <p> 1739 * Because there can be multiple possible rotations, this method chooses the one with the shortest arc. 1740 * 1741 * @see #rotationTo(double, double, double, double, double, double) 1742 * 1743 * @param fromDir 1744 * the starting direction 1745 * @param toDir 1746 * the destination direction 1747 * @return this 1748 */ 1749 ref public Quaterniond rotationTo(Vector3d fromDir, Vector3d toDir) return { 1750 return rotationTo(fromDir.x, fromDir.y, fromDir.z, toDir.x, toDir.y, toDir.z); 1751 } 1752 1753 public Quaterniond rotateTo(double fromDirX, double fromDirY, double fromDirZ, 1754 double toDirX, double toDirY, double toDirZ, ref Quaterniond dest) { 1755 double fn = Math.invsqrt(Math.fma(fromDirX, fromDirX, Math.fma(fromDirY, fromDirY, fromDirZ * fromDirZ))); 1756 double tn = Math.invsqrt(Math.fma(toDirX, toDirX, Math.fma(toDirY, toDirY, toDirZ * toDirZ))); 1757 double fx = fromDirX * fn, fy = fromDirY * fn, fz = fromDirZ * fn; 1758 double tx = toDirX * tn, ty = toDirY * tn, tz = toDirZ * tn; 1759 double dot = fx * tx + fy * ty + fz * tz; 1760 double x, y, z, w; 1761 if (dot < -1.0 + 1E-6) { 1762 x = fy; 1763 y = -fx; 1764 z = 0.0; 1765 w = 0.0; 1766 if (x * x + y * y == 0.0) { 1767 x = 0.0; 1768 y = fz; 1769 z = -fy; 1770 w = 0.0; 1771 } 1772 } else { 1773 double sd2 = Math.sqrt((1.0 + dot) * 2.0); 1774 double isd2 = 1.0 / sd2; 1775 double cx = fy * tz - fz * ty; 1776 double cy = fz * tx - fx * tz; 1777 double cz = fx * ty - fy * tx; 1778 x = cx * isd2; 1779 y = cy * isd2; 1780 z = cz * isd2; 1781 w = sd2 * 0.5; 1782 double n2 = Math.invsqrt(Math.fma(x, x, Math.fma(y, y, Math.fma(z, z, w * w)))); 1783 x *= n2; 1784 y *= n2; 1785 z *= n2; 1786 w *= n2; 1787 } 1788 /* Multiply */ 1789 return dest.set(Math.fma(this.w, x, Math.fma(this.x, w, Math.fma(this.y, z, -this.z * y))), 1790 Math.fma(this.w, y, Math.fma(-this.x, z, Math.fma(this.y, w, this.z * x))), 1791 Math.fma(this.w, z, Math.fma(this.x, y, Math.fma(-this.y, x, this.z * w))), 1792 Math.fma(this.w, w, Math.fma(-this.x, x, Math.fma(-this.y, y, -this.z * z)))); 1793 } 1794 1795 /** 1796 * Set this quaternion to a rotation of the given angle in radians about the supplied axis. 1797 * 1798 * @param angle 1799 * the rotation angle in radians 1800 * @param axisX 1801 * the x-coordinate of the rotation axis 1802 * @param axisY 1803 * the y-coordinate of the rotation axis 1804 * @param axisZ 1805 * the z-coordinate of the rotation axis 1806 * @return this 1807 */ 1808 ref public Quaterniond rotationAxis(double angle, double axisX, double axisY, double axisZ) return { 1809 double hangle = angle / 2.0; 1810 double sinAngle = Math.sin(hangle); 1811 double invVLength = Math.invsqrt(axisX * axisX + axisY * axisY + axisZ * axisZ); 1812 return set(axisX * invVLength * sinAngle, 1813 axisY * invVLength * sinAngle, 1814 axisZ * invVLength * sinAngle, 1815 Math.cosFromSin(sinAngle, hangle)); 1816 } 1817 1818 /** 1819 * Set this quaternion to represent a rotation of the given radians about the x axis. 1820 * 1821 * @param angle 1822 * the angle in radians to rotate about the x axis 1823 * @return this 1824 */ 1825 ref public Quaterniond rotationX(double angle) return { 1826 double sin = Math.sin(angle * 0.5); 1827 double cos = Math.cosFromSin(sin, angle * 0.5); 1828 return set(sin, 0, cos, 0); 1829 } 1830 1831 /** 1832 * Set this quaternion to represent a rotation of the given radians about the y axis. 1833 * 1834 * @param angle 1835 * the angle in radians to rotate about the y axis 1836 * @return this 1837 */ 1838 ref public Quaterniond rotationY(double angle) return { 1839 double sin = Math.sin(angle * 0.5); 1840 double cos = Math.cosFromSin(sin, angle * 0.5); 1841 return set(0, sin, 0, cos); 1842 } 1843 1844 /** 1845 * Set this quaternion to represent a rotation of the given radians about the z axis. 1846 * 1847 * @param angle 1848 * the angle in radians to rotate about the z axis 1849 * @return this 1850 */ 1851 ref public Quaterniond rotationZ(double angle) return { 1852 double sin = Math.sin(angle * 0.5); 1853 double cos = Math.cosFromSin(sin, angle * 0.5); 1854 return set(0, 0, sin, cos); 1855 } 1856 1857 /** 1858 * Apply a rotation to <code>this</code> that rotates the <code>fromDir</code> vector to point along <code>toDir</code>. 1859 * <p> 1860 * Since there can be multiple possible rotations, this method chooses the one with the shortest arc. 1861 * <p> 1862 * If <code>Q</code> is <code>this</code> quaternion and <code>R</code> the quaternion representing the 1863 * specified rotation, then the new quaternion will be <code>Q * R</code>. So when transforming a 1864 * vector <code>v</code> with the new quaternion by using <code>Q * R * v</code>, the 1865 * rotation added by this method will be applied first! 1866 * 1867 * @see #rotateTo(double, double, double, double, double, double, Quaterniond) 1868 * 1869 * @param fromDirX 1870 * the x-coordinate of the direction to rotate into the destination direction 1871 * @param fromDirY 1872 * the y-coordinate of the direction to rotate into the destination direction 1873 * @param fromDirZ 1874 * the z-coordinate of the direction to rotate into the destination direction 1875 * @param toDirX 1876 * the x-coordinate of the direction to rotate to 1877 * @param toDirY 1878 * the y-coordinate of the direction to rotate to 1879 * @param toDirZ 1880 * the z-coordinate of the direction to rotate to 1881 * @return this 1882 */ 1883 ref public Quaterniond rotateTo(double fromDirX, double fromDirY, double fromDirZ, double toDirX, double toDirY, double toDirZ) return { 1884 rotateTo(fromDirX, fromDirY, fromDirZ, toDirX, toDirY, toDirZ, this); 1885 return this; 1886 } 1887 1888 public Quaterniond rotateTo(Vector3d fromDir, Vector3d toDir, ref Quaterniond dest) { 1889 return rotateTo(fromDir.x, fromDir.y, fromDir.z, toDir.x, toDir.y, toDir.z, dest); 1890 } 1891 1892 /** 1893 * Apply a rotation to <code>this</code> that rotates the <code>fromDir</code> vector to point along <code>toDir</code>. 1894 * <p> 1895 * Because there can be multiple possible rotations, this method chooses the one with the shortest arc. 1896 * <p> 1897 * If <code>Q</code> is <code>this</code> quaternion and <code>R</code> the quaternion representing the 1898 * specified rotation, then the new quaternion will be <code>Q * R</code>. So when transforming a 1899 * vector <code>v</code> with the new quaternion by using <code>Q * R * v</code>, the 1900 * rotation added by this method will be applied first! 1901 * 1902 * @see #rotateTo(double, double, double, double, double, double, Quaterniond) 1903 * 1904 * @param fromDir 1905 * the starting direction 1906 * @param toDir 1907 * the destination direction 1908 * @return this 1909 */ 1910 ref public Quaterniond rotateTo(Vector3d fromDir, Vector3d toDir) return { 1911 rotateTo(fromDir.x, fromDir.y, fromDir.z, toDir.x, toDir.y, toDir.z, this); 1912 return this; 1913 } 1914 1915 /** 1916 * Apply a rotation to <code>this</code> quaternion rotating the given radians about the x axis. 1917 * <p> 1918 * If <code>Q</code> is <code>this</code> quaternion and <code>R</code> the quaternion representing the 1919 * specified rotation, then the new quaternion will be <code>Q * R</code>. So when transforming a 1920 * vector <code>v</code> with the new quaternion by using <code>Q * R * v</code>, the 1921 * rotation added by this method will be applied first! 1922 * 1923 * @param angle 1924 * the angle in radians to rotate about the x axis 1925 * @return this 1926 */ 1927 ref public Quaterniond rotateX(double angle) return { 1928 rotateX(angle, this); 1929 return this; 1930 } 1931 1932 public Quaterniond rotateX(double angle, ref Quaterniond dest) { 1933 double sin = Math.sin(angle * 0.5); 1934 double cos = Math.cosFromSin(sin, angle * 0.5); 1935 return dest.set(w * sin + x * cos, 1936 y * cos + z * sin, 1937 z * cos - y * sin, 1938 w * cos - x * sin); 1939 } 1940 1941 /** 1942 * Apply a rotation to <code>this</code> quaternion rotating the given radians about the y axis. 1943 * <p> 1944 * If <code>Q</code> is <code>this</code> quaternion and <code>R</code> the quaternion representing the 1945 * specified rotation, then the new quaternion will be <code>Q * R</code>. So when transforming a 1946 * vector <code>v</code> with the new quaternion by using <code>Q * R * v</code>, the 1947 * rotation added by this method will be applied first! 1948 * 1949 * @param angle 1950 * the angle in radians to rotate about the y axis 1951 * @return this 1952 */ 1953 ref public Quaterniond rotateY(double angle) return { 1954 rotateY(angle, this); 1955 return this; 1956 } 1957 1958 public Quaterniond rotateY(double angle, ref Quaterniond dest) { 1959 double sin = Math.sin(angle * 0.5); 1960 double cos = Math.cosFromSin(sin, angle * 0.5); 1961 return dest.set(x * cos - z * sin, 1962 w * sin + y * cos, 1963 x * sin + z * cos, 1964 w * cos - y * sin); 1965 } 1966 1967 /** 1968 * Apply a rotation to <code>this</code> quaternion rotating the given radians about the z axis. 1969 * <p> 1970 * If <code>Q</code> is <code>this</code> quaternion and <code>R</code> the quaternion representing the 1971 * specified rotation, then the new quaternion will be <code>Q * R</code>. So when transforming a 1972 * vector <code>v</code> with the new quaternion by using <code>Q * R * v</code>, the 1973 * rotation added by this method will be applied first! 1974 * 1975 * @param angle 1976 * the angle in radians to rotate about the z axis 1977 * @return this 1978 */ 1979 ref public Quaterniond rotateZ(double angle) return { 1980 rotateZ(angle, this); 1981 return this; 1982 } 1983 1984 public Quaterniond rotateZ(double angle, ref Quaterniond dest) { 1985 double sin = Math.sin(angle * 0.5); 1986 double cos = Math.cosFromSin(sin, angle * 0.5); 1987 return dest.set(x * cos + y * sin, 1988 y * cos - x * sin, 1989 w * sin + z * cos, 1990 w * cos - z * sin); 1991 } 1992 1993 /** 1994 * Apply a rotation to <code>this</code> quaternion rotating the given radians about the local x axis. 1995 * <p> 1996 * If <code>Q</code> is <code>this</code> quaternion and <code>R</code> the quaternion representing the 1997 * specified rotation, then the new quaternion will be <code>R * Q</code>. So when transforming a 1998 * vector <code>v</code> with the new quaternion by using <code>R * Q * v</code>, the 1999 * rotation represented by <code>this</code> will be applied first! 2000 * 2001 * @param angle 2002 * the angle in radians to rotate about the local x axis 2003 * @return this 2004 */ 2005 ref public Quaterniond rotateLocalX(double angle) return { 2006 rotateLocalX(angle, this); 2007 return this; 2008 } 2009 2010 public Quaterniond rotateLocalX(double angle, ref Quaterniond dest) { 2011 double hangle = angle * 0.5; 2012 double s = Math.sin(hangle); 2013 double c = Math.cosFromSin(s, hangle); 2014 dest.set(c * x + s * w, 2015 c * y - s * z, 2016 c * z + s * y, 2017 c * w - s * x); 2018 return dest; 2019 } 2020 2021 /** 2022 * Apply a rotation to <code>this</code> quaternion rotating the given radians about the local y axis. 2023 * <p> 2024 * If <code>Q</code> is <code>this</code> quaternion and <code>R</code> the quaternion representing the 2025 * specified rotation, then the new quaternion will be <code>R * Q</code>. So when transforming a 2026 * vector <code>v</code> with the new quaternion by using <code>R * Q * v</code>, the 2027 * rotation represented by <code>this</code> will be applied first! 2028 * 2029 * @param angle 2030 * the angle in radians to rotate about the local y axis 2031 * @return this 2032 */ 2033 ref public Quaterniond rotateLocalY(double angle) return { 2034 rotateLocalY(angle, this); 2035 return this; 2036 } 2037 2038 public Quaterniond rotateLocalY(double angle, ref Quaterniond dest) { 2039 double hangle = angle * 0.5; 2040 double s = Math.sin(hangle); 2041 double c = Math.cosFromSin(s, hangle); 2042 dest.set(c * x + s * z, 2043 c * y + s * w, 2044 c * z - s * x, 2045 c * w - s * y); 2046 return dest; 2047 } 2048 2049 /** 2050 * Apply a rotation to <code>this</code> quaternion rotating the given radians about the local z axis. 2051 * <p> 2052 * If <code>Q</code> is <code>this</code> quaternion and <code>R</code> the quaternion representing the 2053 * specified rotation, then the new quaternion will be <code>R * Q</code>. So when transforming a 2054 * vector <code>v</code> with the new quaternion by using <code>R * Q * v</code>, the 2055 * rotation represented by <code>this</code> will be applied first! 2056 * 2057 * @param angle 2058 * the angle in radians to rotate about the local z axis 2059 * @return this 2060 */ 2061 ref public Quaterniond rotateLocalZ(double angle) return { 2062 rotateLocalZ(angle, this); 2063 return this; 2064 } 2065 2066 public Quaterniond rotateLocalZ(double angle, ref Quaterniond dest) { 2067 double hangle = angle * 0.5; 2068 double s = Math.sin(hangle); 2069 double c = Math.cosFromSin(s, hangle); 2070 dest.set(c * x - s * y, 2071 c * y + s * x, 2072 c * z + s * w, 2073 c * w - s * z); 2074 return dest; 2075 } 2076 2077 /** 2078 * Apply a rotation to <code>this</code> quaternion rotating the given radians about the cartesian base unit axes, 2079 * called the euler angles using rotation sequence <code>XYZ</code>. 2080 * <p> 2081 * This method is equivalent to calling: <code>rotateX(angleX).rotateY(angleY).rotateZ(angleZ)</code> 2082 * <p> 2083 * If <code>Q</code> is <code>this</code> quaternion and <code>R</code> the quaternion representing the 2084 * specified rotation, then the new quaternion will be <code>Q * R</code>. So when transforming a 2085 * vector <code>v</code> with the new quaternion by using <code>Q * R * v</code>, the 2086 * rotation added by this method will be applied first! 2087 * 2088 * @param angleX 2089 * the angle in radians to rotate about the x axis 2090 * @param angleY 2091 * the angle in radians to rotate about the y axis 2092 * @param angleZ 2093 * the angle in radians to rotate about the z axis 2094 * @return this 2095 */ 2096 ref public Quaterniond rotateXYZ(double angleX, double angleY, double angleZ) return { 2097 rotateXYZ(angleX, angleY, angleZ, this); 2098 return this; 2099 } 2100 2101 public Quaterniond rotateXYZ(double angleX, double angleY, double angleZ, ref Quaterniond dest) { 2102 double sx = Math.sin(angleX * 0.5); 2103 double cx = Math.cosFromSin(sx, angleX * 0.5); 2104 double sy = Math.sin(angleY * 0.5); 2105 double cy = Math.cosFromSin(sy, angleY * 0.5); 2106 double sz = Math.sin(angleZ * 0.5); 2107 double cz = Math.cosFromSin(sz, angleZ * 0.5); 2108 2109 double cycz = cy * cz; 2110 double sysz = sy * sz; 2111 double sycz = sy * cz; 2112 double cysz = cy * sz; 2113 double w = cx*cycz - sx*sysz; 2114 double x = sx*cycz + cx*sysz; 2115 double y = cx*sycz - sx*cysz; 2116 double z = cx*cysz + sx*sycz; 2117 // right-multiply 2118 return dest.set(Math.fma(this.w, x, Math.fma(this.x, w, Math.fma(this.y, z, -this.z * y))), 2119 Math.fma(this.w, y, Math.fma(-this.x, z, Math.fma(this.y, w, this.z * x))), 2120 Math.fma(this.w, z, Math.fma(this.x, y, Math.fma(-this.y, x, this.z * w))), 2121 Math.fma(this.w, w, Math.fma(-this.x, x, Math.fma(-this.y, y, -this.z * z)))); 2122 } 2123 2124 /** 2125 * Apply a rotation to <code>this</code> quaternion rotating the given radians about the cartesian base unit axes, 2126 * called the euler angles, using the rotation sequence <code>ZYX</code>. 2127 * <p> 2128 * This method is equivalent to calling: <code>rotateZ(angleZ).rotateY(angleY).rotateX(angleX)</code> 2129 * <p> 2130 * If <code>Q</code> is <code>this</code> quaternion and <code>R</code> the quaternion representing the 2131 * specified rotation, then the new quaternion will be <code>Q * R</code>. So when transforming a 2132 * vector <code>v</code> with the new quaternion by using <code>Q * R * v</code>, the 2133 * rotation added by this method will be applied first! 2134 * 2135 * @param angleZ 2136 * the angle in radians to rotate about the z axis 2137 * @param angleY 2138 * the angle in radians to rotate about the y axis 2139 * @param angleX 2140 * the angle in radians to rotate about the x axis 2141 * @return this 2142 */ 2143 ref public Quaterniond rotateZYX(double angleZ, double angleY, double angleX) return { 2144 rotateZYX(angleZ, angleY, angleX, this); 2145 return this; 2146 } 2147 2148 public Quaterniond rotateZYX(double angleZ, double angleY, double angleX, ref Quaterniond dest) { 2149 double sx = Math.sin(angleX * 0.5); 2150 double cx = Math.cosFromSin(sx, angleX * 0.5); 2151 double sy = Math.sin(angleY * 0.5); 2152 double cy = Math.cosFromSin(sy, angleY * 0.5); 2153 double sz = Math.sin(angleZ * 0.5); 2154 double cz = Math.cosFromSin(sz, angleZ * 0.5); 2155 2156 double cycz = cy * cz; 2157 double sysz = sy * sz; 2158 double sycz = sy * cz; 2159 double cysz = cy * sz; 2160 double w = cx*cycz + sx*sysz; 2161 double x = sx*cycz - cx*sysz; 2162 double y = cx*sycz + sx*cysz; 2163 double z = cx*cysz - sx*sycz; 2164 // right-multiply 2165 return dest.set(Math.fma(this.w, x, Math.fma(this.x, w, Math.fma(this.y, z, -this.z * y))), 2166 Math.fma(this.w, y, Math.fma(-this.x, z, Math.fma(this.y, w, this.z * x))), 2167 Math.fma(this.w, z, Math.fma(this.x, y, Math.fma(-this.y, x, this.z * w))), 2168 Math.fma(this.w, w, Math.fma(-this.x, x, Math.fma(-this.y, y, -this.z * z)))); 2169 } 2170 2171 /** 2172 * Apply a rotation to <code>this</code> quaternion rotating the given radians about the cartesian base unit axes, 2173 * called the euler angles, using the rotation sequence <code>YXZ</code>. 2174 * <p> 2175 * This method is equivalent to calling: <code>rotateY(angleY).rotateX(angleX).rotateZ(angleZ)</code> 2176 * <p> 2177 * If <code>Q</code> is <code>this</code> quaternion and <code>R</code> the quaternion representing the 2178 * specified rotation, then the new quaternion will be <code>Q * R</code>. So when transforming a 2179 * vector <code>v</code> with the new quaternion by using <code>Q * R * v</code>, the 2180 * rotation added by this method will be applied first! 2181 * 2182 * @param angleY 2183 * the angle in radians to rotate about the y axis 2184 * @param angleX 2185 * the angle in radians to rotate about the x axis 2186 * @param angleZ 2187 * the angle in radians to rotate about the z axis 2188 * @return this 2189 */ 2190 ref public Quaterniond rotateYXZ(double angleY, double angleX, double angleZ) return { 2191 rotateYXZ(angleY, angleX, angleZ, this); 2192 return this; 2193 } 2194 2195 public Quaterniond rotateYXZ(double angleY, double angleX, double angleZ, ref Quaterniond dest) { 2196 double sx = Math.sin(angleX * 0.5); 2197 double cx = Math.cosFromSin(sx, angleX * 0.5); 2198 double sy = Math.sin(angleY * 0.5); 2199 double cy = Math.cosFromSin(sy, angleY * 0.5); 2200 double sz = Math.sin(angleZ * 0.5); 2201 double cz = Math.cosFromSin(sz, angleZ * 0.5); 2202 2203 double yx = cy * sx; 2204 double yy = sy * cx; 2205 double yz = sy * sx; 2206 double yw = cy * cx; 2207 double x = yx * cz + yy * sz; 2208 double y = yy * cz - yx * sz; 2209 double z = yw * sz - yz * cz; 2210 double w = yw * cz + yz * sz; 2211 // right-multiply 2212 return dest.set(Math.fma(this.w, x, Math.fma(this.x, w, Math.fma(this.y, z, -this.z * y))), 2213 Math.fma(this.w, y, Math.fma(-this.x, z, Math.fma(this.y, w, this.z * x))), 2214 Math.fma(this.w, z, Math.fma(this.x, y, Math.fma(-this.y, x, this.z * w))), 2215 Math.fma(this.w, w, Math.fma(-this.x, x, Math.fma(-this.y, y, -this.z * z)))); 2216 } 2217 2218 public Vector3d getEulerAnglesXYZ(Vector3d eulerAngles) { 2219 eulerAngles.x = Math.atan2(x * w - y * z, 0.5 - x * x - y * y); 2220 eulerAngles.y = Math.safeAsin(2.0 * (x * z + y * w)); 2221 eulerAngles.z = Math.atan2(z * w - x * y, 0.5 - y * y - z * z); 2222 return eulerAngles; 2223 } 2224 2225 public Vector3d getEulerAnglesZYX(Vector3d eulerAngles) { 2226 eulerAngles.x = Math.atan2(y * z + w * x, 0.5 - x * x + y * y); 2227 eulerAngles.y = Math.safeAsin(-2.0 * (x * z - w * y)); 2228 eulerAngles.z = Math.atan2(x * y + w * z, 0.5 - y * y - z * z); 2229 return eulerAngles; 2230 } 2231 2232 public Vector3d getEulerAnglesZXY(Vector3d eulerAngles) { 2233 eulerAngles.x = Math.safeAsin(2.0 * (w * x + y * z)); 2234 eulerAngles.y = Math.atan2(w * y - x * z, 0.5 - y * y - x * x); 2235 eulerAngles.z = Math.atan2(w * z - x * y, 0.5 - z * z - x * x); 2236 return eulerAngles; 2237 } 2238 2239 public Vector3d getEulerAnglesYXZ(Vector3d eulerAngles) { 2240 eulerAngles.x = Math.safeAsin(-2.0 * (y * z - w * x)); 2241 eulerAngles.y = Math.atan2(x * z + y * w, 0.5 - y * y - x * x); 2242 eulerAngles.z = Math.atan2(y * x + w * z, 0.5 - x * x - z * z); 2243 return eulerAngles; 2244 } 2245 2246 public Quaterniond rotateAxis(double angle, double axisX, double axisY, double axisZ, ref Quaterniond dest) { 2247 double hangle = angle / 2.0; 2248 double sinAngle = Math.sin(hangle); 2249 double invVLength = Math.invsqrt(Math.fma(axisX, axisX, Math.fma(axisY, axisY, axisZ * axisZ))); 2250 double rx = axisX * invVLength * sinAngle; 2251 double ry = axisY * invVLength * sinAngle; 2252 double rz = axisZ * invVLength * sinAngle; 2253 double rw = Math.cosFromSin(sinAngle, hangle); 2254 return dest.set(Math.fma(this.w, rx, Math.fma(this.x, rw, Math.fma(this.y, rz, -this.z * ry))), 2255 Math.fma(this.w, ry, Math.fma(-this.x, rz, Math.fma(this.y, rw, this.z * rx))), 2256 Math.fma(this.w, rz, Math.fma(this.x, ry, Math.fma(-this.y, rx, this.z * rw))), 2257 Math.fma(this.w, rw, Math.fma(-this.x, rx, Math.fma(-this.y, ry, -this.z * rz)))); 2258 } 2259 2260 public Quaterniond rotateAxis(double angle, Vector3d axis, ref Quaterniond dest) { 2261 return rotateAxis(angle, axis.x, axis.y, axis.z, dest); 2262 } 2263 2264 /** 2265 * Apply a rotation to <code>this</code> quaternion rotating the given radians about the specified axis. 2266 * <p> 2267 * If <code>Q</code> is <code>this</code> quaternion and <code>R</code> the quaternion representing the 2268 * specified rotation, then the new quaternion will be <code>Q * R</code>. So when transforming a 2269 * vector <code>v</code> with the new quaternion by using <code>Q * R * v</code>, the 2270 * rotation added by this method will be applied first! 2271 * 2272 * @see #rotateAxis(double, double, double, double, Quaterniond) 2273 * 2274 * @param angle 2275 * the angle in radians to rotate about the specified axis 2276 * @param axis 2277 * the rotation axis 2278 * @return this 2279 */ 2280 ref public Quaterniond rotateAxis(double angle, Vector3d axis) return { 2281 rotateAxis(angle, axis.x, axis.y, axis.z, this); 2282 return this; 2283 } 2284 2285 /** 2286 * Apply a rotation to <code>this</code> quaternion rotating the given radians about the specified axis. 2287 * <p> 2288 * If <code>Q</code> is <code>this</code> quaternion and <code>R</code> the quaternion representing the 2289 * specified rotation, then the new quaternion will be <code>Q * R</code>. So when transforming a 2290 * vector <code>v</code> with the new quaternion by using <code>Q * R * v</code>, the 2291 * rotation added by this method will be applied first! 2292 * 2293 * @see #rotateAxis(double, double, double, double, Quaterniond) 2294 * 2295 * @param angle 2296 * the angle in radians to rotate about the specified axis 2297 * @param axisX 2298 * the x coordinate of the rotation axis 2299 * @param axisY 2300 * the y coordinate of the rotation axis 2301 * @param axisZ 2302 * the z coordinate of the rotation axis 2303 * @return this 2304 */ 2305 ref public Quaterniond rotateAxis(double angle, double axisX, double axisY, double axisZ) return { 2306 rotateAxis(angle, axisX, axisY, axisZ, this); 2307 return this; 2308 } 2309 2310 public Vector3d positiveX(Vector3d dir) { 2311 double invNorm = 1.0 / lengthSquared(); 2312 double nx = -x * invNorm; 2313 double ny = -y * invNorm; 2314 double nz = -z * invNorm; 2315 double nw = w * invNorm; 2316 double dy = ny + ny; 2317 double dz = nz + nz; 2318 dir.x = -ny * dy - nz * dz + 1.0; 2319 dir.y = nx * dy + nw * dz; 2320 dir.z = nx * dz - nw * dy; 2321 return dir; 2322 } 2323 2324 public Vector3d normalizedPositiveX(Vector3d dir) { 2325 double dy = y + y; 2326 double dz = z + z; 2327 dir.x = -y * dy - z * dz + 1.0; 2328 dir.y = x * dy - w * dz; 2329 dir.z = x * dz + w * dy; 2330 return dir; 2331 } 2332 2333 public Vector3d positiveY(Vector3d dir) { 2334 double invNorm = 1.0 / lengthSquared(); 2335 double nx = -x * invNorm; 2336 double ny = -y * invNorm; 2337 double nz = -z * invNorm; 2338 double nw = w * invNorm; 2339 double dx = nx + nx; 2340 double dy = ny + ny; 2341 double dz = nz + nz; 2342 dir.x = nx * dy - nw * dz; 2343 dir.y = -nx * dx - nz * dz + 1.0; 2344 dir.z = ny * dz + nw * dx; 2345 return dir; 2346 } 2347 2348 public Vector3d normalizedPositiveY(Vector3d dir) { 2349 double dx = x + x; 2350 double dy = y + y; 2351 double dz = z + z; 2352 dir.x = x * dy + w * dz; 2353 dir.y = -x * dx - z * dz + 1.0; 2354 dir.z = y * dz - w * dx; 2355 return dir; 2356 } 2357 2358 public Vector3d positiveZ(Vector3d dir) { 2359 double invNorm = 1.0 / lengthSquared(); 2360 double nx = -x * invNorm; 2361 double ny = -y * invNorm; 2362 double nz = -z * invNorm; 2363 double nw = w * invNorm; 2364 double dx = nx + nx; 2365 double dy = ny + ny; 2366 double dz = nz + nz; 2367 dir.x = nx * dz + nw * dy; 2368 dir.y = ny * dz - nw * dx; 2369 dir.z = -nx * dx - ny * dy + 1.0; 2370 return dir; 2371 } 2372 2373 public Vector3d normalizedPositiveZ(Vector3d dir) { 2374 double dx = x + x; 2375 double dy = y + y; 2376 double dz = z + z; 2377 dir.x = x * dz - w * dy; 2378 dir.y = y * dz + w * dx; 2379 dir.z = -x * dx - y * dy + 1.0; 2380 return dir; 2381 } 2382 2383 /** 2384 * Conjugate <code>this</code> by the given quaternion <code>q</code> by computing <code>q * this * q^-1</code>. 2385 * 2386 * @param q 2387 * the {@link Quaterniond} to conjugate <code>this</code> by 2388 * @return this 2389 */ 2390 ref public Quaterniond conjugateBy(Quaterniond q) return { 2391 conjugateBy(q, this); 2392 return this; 2393 } 2394 2395 /** 2396 * Conjugate <code>this</code> by the given quaternion <code>q</code> by computing <code>q * this * q^-1</code> 2397 * and store the result into <code>dest</code>. 2398 * 2399 * @param q 2400 * the {@link Quaterniond} to conjugate <code>this</code> by 2401 * @param dest 2402 * will hold the result 2403 * @return dest 2404 */ 2405 public Quaterniond conjugateBy(Quaterniond q, ref Quaterniond dest) { 2406 double invNorm = 1.0 / q.lengthSquared(); 2407 double qix = -q.x * invNorm, qiy = -q.y * invNorm, qiz = -q.z * invNorm, qiw = q.w * invNorm; 2408 double qpx = Math.fma(q.w, x, Math.fma(q.x, w, Math.fma(q.y, z, -q.z * y))); 2409 double qpy = Math.fma(q.w, y, Math.fma(-q.x, z, Math.fma(q.y, w, q.z * x))); 2410 double qpz = Math.fma(q.w, z, Math.fma(q.x, y, Math.fma(-q.y, x, q.z * w))); 2411 double qpw = Math.fma(q.w, w, Math.fma(-q.x, x, Math.fma(-q.y, y, -q.z * z))); 2412 return dest.set(Math.fma(qpw, qix, Math.fma(qpx, qiw, Math.fma(qpy, qiz, -qpz * qiy))), 2413 Math.fma(qpw, qiy, Math.fma(-qpx, qiz, Math.fma(qpy, qiw, qpz * qix))), 2414 Math.fma(qpw, qiz, Math.fma(qpx, qiy, Math.fma(-qpy, qix, qpz * qiw))), 2415 Math.fma(qpw, qiw, Math.fma(-qpx, qix, Math.fma(-qpy, qiy, -qpz * qiz)))); 2416 } 2417 2418 public bool isFinite() { 2419 return Math.isFinite(x) && Math.isFinite(y) && Math.isFinite(z) && Math.isFinite(w); 2420 } 2421 2422 public bool equals(Quaterniond q, double delta) { 2423 if (this == q) 2424 return true; 2425 if (!Math.equals(x, q.x, delta)) 2426 return false; 2427 if (!Math.equals(y, q.y, delta)) 2428 return false; 2429 if (!Math.equals(z, q.z, delta)) 2430 return false; 2431 if (!Math.equals(w, q.w, delta)) 2432 return false; 2433 return true; 2434 } 2435 2436 public bool equals(double x, double y, double z, double w) { 2437 if (Math.doubleToLongBits(this.x) != Math.doubleToLongBits(x)) 2438 return false; 2439 if (Math.doubleToLongBits(this.y) != Math.doubleToLongBits(y)) 2440 return false; 2441 if (Math.doubleToLongBits(this.z) != Math.doubleToLongBits(z)) 2442 return false; 2443 if (Math.doubleToLongBits(this.w) != Math.doubleToLongBits(w)) 2444 return false; 2445 return true; 2446 } 2447 2448 }