1 /* 2 * Copyright (c) 2009-2010 jMonkeyEngine 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: 8 * 9 * * Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 12 * * Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * * Neither the name of 'jMonkeyEngine' nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 24 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 25 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 26 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 27 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 28 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 29 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 30 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 package com.jme3.math; 33 34 import com.jme3.export.*; 35 import com.jme3.util.TempVars; 36 import java.io.Externalizable; 37 import java.io.IOException; 38 import java.io.ObjectInput; 39 import java.io.ObjectOutput; 40 import java.util.logging.Logger; 41 42 /** 43 * <code>Quaternion</code> defines a single example of a more general class of 44 * hypercomplex numbers. Quaternions extends a rotation in three dimensions to a 45 * rotation in four dimensions. This avoids "gimbal lock" and allows for smooth 46 * continuous rotation. 47 * 48 * <code>Quaternion</code> is defined by four floating point numbers: {x y z 49 * w}. 50 * 51 * @author Mark Powell 52 * @author Joshua Slack 53 */ 54 public final class Quaternion implements Savable, Cloneable, java.io.Serializable { 55 56 static final long serialVersionUID = 1; 57 58 private static final Logger logger = Logger.getLogger(Quaternion.class.getName()); 59 /** 60 * Represents the identity quaternion rotation (0, 0, 0, 1). 61 */ 62 public static final Quaternion IDENTITY = new Quaternion(); 63 public static final Quaternion DIRECTION_Z = new Quaternion(); 64 public static final Quaternion ZERO = new Quaternion(0, 0, 0, 0); 65 66 static { 67 DIRECTION_Z.fromAxes(Vector3f.UNIT_X, Vector3f.UNIT_Y, Vector3f.UNIT_Z); 68 } 69 protected float x, y, z, w; 70 71 /** 72 * Constructor instantiates a new <code>Quaternion</code> object 73 * initializing all values to zero, except w which is initialized to 1. 74 * 75 */ 76 public Quaternion() { 77 x = 0; 78 y = 0; 79 z = 0; 80 w = 1; 81 } 82 83 /** 84 * Constructor instantiates a new <code>Quaternion</code> object from the 85 * given list of parameters. 86 * 87 * @param x 88 * the x value of the quaternion. 89 * @param y 90 * the y value of the quaternion. 91 * @param z 92 * the z value of the quaternion. 93 * @param w 94 * the w value of the quaternion. 95 */ 96 public Quaternion(float x, float y, float z, float w) { 97 this.x = x; 98 this.y = y; 99 this.z = z; 100 this.w = w; 101 } 102 103 public float getX() { 104 return x; 105 } 106 107 public float getY() { 108 return y; 109 } 110 111 public float getZ() { 112 return z; 113 } 114 115 public float getW() { 116 return w; 117 } 118 119 /** 120 * sets the data in a <code>Quaternion</code> object from the given list 121 * of parameters. 122 * 123 * @param x 124 * the x value of the quaternion. 125 * @param y 126 * the y value of the quaternion. 127 * @param z 128 * the z value of the quaternion. 129 * @param w 130 * the w value of the quaternion. 131 * @return this 132 */ 133 public Quaternion set(float x, float y, float z, float w) { 134 this.x = x; 135 this.y = y; 136 this.z = z; 137 this.w = w; 138 return this; 139 } 140 141 /** 142 * Sets the data in this <code>Quaternion</code> object to be equal to the 143 * passed <code>Quaternion</code> object. The values are copied producing 144 * a new object. 145 * 146 * @param q 147 * The Quaternion to copy values from. 148 * @return this 149 */ 150 public Quaternion set(Quaternion q) { 151 this.x = q.x; 152 this.y = q.y; 153 this.z = q.z; 154 this.w = q.w; 155 return this; 156 } 157 158 /** 159 * Constructor instantiates a new <code>Quaternion</code> object from a 160 * collection of rotation angles. 161 * 162 * @param angles 163 * the angles of rotation (x, y, z) that will define the 164 * <code>Quaternion</code>. 165 */ 166 public Quaternion(float[] angles) { 167 fromAngles(angles); 168 } 169 170 /** 171 * Constructor instantiates a new <code>Quaternion</code> object from an 172 * interpolation between two other quaternions. 173 * 174 * @param q1 175 * the first quaternion. 176 * @param q2 177 * the second quaternion. 178 * @param interp 179 * the amount to interpolate between the two quaternions. 180 */ 181 public Quaternion(Quaternion q1, Quaternion q2, float interp) { 182 slerp(q1, q2, interp); 183 } 184 185 /** 186 * Constructor instantiates a new <code>Quaternion</code> object from an 187 * existing quaternion, creating a copy. 188 * 189 * @param q 190 * the quaternion to copy. 191 */ 192 public Quaternion(Quaternion q) { 193 this.x = q.x; 194 this.y = q.y; 195 this.z = q.z; 196 this.w = q.w; 197 } 198 199 /** 200 * Sets this Quaternion to {0, 0, 0, 1}. Same as calling set(0,0,0,1). 201 */ 202 public void loadIdentity() { 203 x = y = z = 0; 204 w = 1; 205 } 206 207 /** 208 * @return true if this Quaternion is {0,0,0,1} 209 */ 210 public boolean isIdentity() { 211 if (x == 0 && y == 0 && z == 0 && w == 1) { 212 return true; 213 } else { 214 return false; 215 } 216 } 217 218 /** 219 * <code>fromAngles</code> builds a quaternion from the Euler rotation 220 * angles (y,r,p). 221 * 222 * @param angles 223 * the Euler angles of rotation (in radians). 224 */ 225 public Quaternion fromAngles(float[] angles) { 226 if (angles.length != 3) { 227 throw new IllegalArgumentException( 228 "Angles array must have three elements"); 229 } 230 231 return fromAngles(angles[0], angles[1], angles[2]); 232 } 233 234 /** 235 * <code>fromAngles</code> builds a Quaternion from the Euler rotation 236 * angles (y,r,p). Note that we are applying in order: roll, pitch, yaw but 237 * we've ordered them in x, y, and z for convenience. 238 * @see <a href="http://www.euclideanspace.com/maths/geometry/rotations/conversions/eulerToQuaternion/index.htm">http://www.euclideanspace.com/maths/geometry/rotations/conversions/eulerToQuaternion/index.htm</a> 239 * 240 * @param yaw 241 * the Euler yaw of rotation (in radians). (aka Bank, often rot 242 * around x) 243 * @param roll 244 * the Euler roll of rotation (in radians). (aka Heading, often 245 * rot around y) 246 * @param pitch 247 * the Euler pitch of rotation (in radians). (aka Attitude, often 248 * rot around z) 249 */ 250 public Quaternion fromAngles(float yaw, float roll, float pitch) { 251 float angle; 252 float sinRoll, sinPitch, sinYaw, cosRoll, cosPitch, cosYaw; 253 angle = pitch * 0.5f; 254 sinPitch = FastMath.sin(angle); 255 cosPitch = FastMath.cos(angle); 256 angle = roll * 0.5f; 257 sinRoll = FastMath.sin(angle); 258 cosRoll = FastMath.cos(angle); 259 angle = yaw * 0.5f; 260 sinYaw = FastMath.sin(angle); 261 cosYaw = FastMath.cos(angle); 262 263 // variables used to reduce multiplication calls. 264 float cosRollXcosPitch = cosRoll * cosPitch; 265 float sinRollXsinPitch = sinRoll * sinPitch; 266 float cosRollXsinPitch = cosRoll * sinPitch; 267 float sinRollXcosPitch = sinRoll * cosPitch; 268 269 w = (cosRollXcosPitch * cosYaw - sinRollXsinPitch * sinYaw); 270 x = (cosRollXcosPitch * sinYaw + sinRollXsinPitch * cosYaw); 271 y = (sinRollXcosPitch * cosYaw + cosRollXsinPitch * sinYaw); 272 z = (cosRollXsinPitch * cosYaw - sinRollXcosPitch * sinYaw); 273 274 normalize(); 275 return this; 276 } 277 278 /** 279 * <code>toAngles</code> returns this quaternion converted to Euler 280 * rotation angles (yaw,roll,pitch).<br/> 281 * @see <a href="http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToEuler/index.htm">http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToEuler/index.htm</a> 282 * 283 * @param angles 284 * the float[] in which the angles should be stored, or null if 285 * you want a new float[] to be created 286 * @return the float[] in which the angles are stored. 287 */ 288 public float[] toAngles(float[] angles) { 289 if (angles == null) { 290 angles = new float[3]; 291 } else if (angles.length != 3) { 292 throw new IllegalArgumentException("Angles array must have three elements"); 293 } 294 295 float sqw = w * w; 296 float sqx = x * x; 297 float sqy = y * y; 298 float sqz = z * z; 299 float unit = sqx + sqy + sqz + sqw; // if normalized is one, otherwise 300 // is correction factor 301 float test = x * y + z * w; 302 if (test > 0.499 * unit) { // singularity at north pole 303 angles[1] = 2 * FastMath.atan2(x, w); 304 angles[2] = FastMath.HALF_PI; 305 angles[0] = 0; 306 } else if (test < -0.499 * unit) { // singularity at south pole 307 angles[1] = -2 * FastMath.atan2(x, w); 308 angles[2] = -FastMath.HALF_PI; 309 angles[0] = 0; 310 } else { 311 angles[1] = FastMath.atan2(2 * y * w - 2 * x * z, sqx - sqy - sqz + sqw); // roll or heading 312 angles[2] = FastMath.asin(2 * test / unit); // pitch or attitude 313 angles[0] = FastMath.atan2(2 * x * w - 2 * y * z, -sqx + sqy - sqz + sqw); // yaw or bank 314 } 315 return angles; 316 } 317 318 /** 319 * 320 * <code>fromRotationMatrix</code> generates a quaternion from a supplied 321 * matrix. This matrix is assumed to be a rotational matrix. 322 * 323 * @param matrix 324 * the matrix that defines the rotation. 325 */ 326 public Quaternion fromRotationMatrix(Matrix3f matrix) { 327 return fromRotationMatrix(matrix.m00, matrix.m01, matrix.m02, matrix.m10, 328 matrix.m11, matrix.m12, matrix.m20, matrix.m21, matrix.m22); 329 } 330 331 public Quaternion fromRotationMatrix(float m00, float m01, float m02, 332 float m10, float m11, float m12, 333 float m20, float m21, float m22) { 334 // Use the Graphics Gems code, from 335 // ftp://ftp.cis.upenn.edu/pub/graphics/shoemake/quatut.ps.Z 336 // *NOT* the "Matrix and Quaternions FAQ", which has errors! 337 338 // the trace is the sum of the diagonal elements; see 339 // http://mathworld.wolfram.com/MatrixTrace.html 340 float t = m00 + m11 + m22; 341 342 // we protect the division by s by ensuring that s>=1 343 if (t >= 0) { // |w| >= .5 344 float s = FastMath.sqrt(t + 1); // |s|>=1 ... 345 w = 0.5f * s; 346 s = 0.5f / s; // so this division isn't bad 347 x = (m21 - m12) * s; 348 y = (m02 - m20) * s; 349 z = (m10 - m01) * s; 350 } else if ((m00 > m11) && (m00 > m22)) { 351 float s = FastMath.sqrt(1.0f + m00 - m11 - m22); // |s|>=1 352 x = s * 0.5f; // |x| >= .5 353 s = 0.5f / s; 354 y = (m10 + m01) * s; 355 z = (m02 + m20) * s; 356 w = (m21 - m12) * s; 357 } else if (m11 > m22) { 358 float s = FastMath.sqrt(1.0f + m11 - m00 - m22); // |s|>=1 359 y = s * 0.5f; // |y| >= .5 360 s = 0.5f / s; 361 x = (m10 + m01) * s; 362 z = (m21 + m12) * s; 363 w = (m02 - m20) * s; 364 } else { 365 float s = FastMath.sqrt(1.0f + m22 - m00 - m11); // |s|>=1 366 z = s * 0.5f; // |z| >= .5 367 s = 0.5f / s; 368 x = (m02 + m20) * s; 369 y = (m21 + m12) * s; 370 w = (m10 - m01) * s; 371 } 372 373 return this; 374 } 375 376 /** 377 * <code>toRotationMatrix</code> converts this quaternion to a rotational 378 * matrix. Note: the result is created from a normalized version of this quat. 379 * 380 * @return the rotation matrix representation of this quaternion. 381 */ 382 public Matrix3f toRotationMatrix() { 383 Matrix3f matrix = new Matrix3f(); 384 return toRotationMatrix(matrix); 385 } 386 387 /** 388 * <code>toRotationMatrix</code> converts this quaternion to a rotational 389 * matrix. The result is stored in result. 390 * 391 * @param result 392 * The Matrix3f to store the result in. 393 * @return the rotation matrix representation of this quaternion. 394 */ 395 public Matrix3f toRotationMatrix(Matrix3f result) { 396 397 float norm = norm(); 398 // we explicitly test norm against one here, saving a division 399 // at the cost of a test and branch. Is it worth it? 400 float s = (norm == 1f) ? 2f : (norm > 0f) ? 2f / norm : 0; 401 402 // compute xs/ys/zs first to save 6 multiplications, since xs/ys/zs 403 // will be used 2-4 times each. 404 float xs = x * s; 405 float ys = y * s; 406 float zs = z * s; 407 float xx = x * xs; 408 float xy = x * ys; 409 float xz = x * zs; 410 float xw = w * xs; 411 float yy = y * ys; 412 float yz = y * zs; 413 float yw = w * ys; 414 float zz = z * zs; 415 float zw = w * zs; 416 417 // using s=2/norm (instead of 1/norm) saves 9 multiplications by 2 here 418 result.m00 = 1 - (yy + zz); 419 result.m01 = (xy - zw); 420 result.m02 = (xz + yw); 421 result.m10 = (xy + zw); 422 result.m11 = 1 - (xx + zz); 423 result.m12 = (yz - xw); 424 result.m20 = (xz - yw); 425 result.m21 = (yz + xw); 426 result.m22 = 1 - (xx + yy); 427 428 return result; 429 } 430 431 /** 432 * <code>toRotationMatrix</code> converts this quaternion to a rotational 433 * matrix. The result is stored in result. 4th row and 4th column values are 434 * untouched. Note: the result is created from a normalized version of this quat. 435 * 436 * @param result 437 * The Matrix4f to store the result in. 438 * @return the rotation matrix representation of this quaternion. 439 */ 440 public Matrix4f toRotationMatrix(Matrix4f result) { 441 442 float norm = norm(); 443 // we explicitly test norm against one here, saving a division 444 // at the cost of a test and branch. Is it worth it? 445 float s = (norm == 1f) ? 2f : (norm > 0f) ? 2f / norm : 0; 446 447 // compute xs/ys/zs first to save 6 multiplications, since xs/ys/zs 448 // will be used 2-4 times each. 449 float xs = x * s; 450 float ys = y * s; 451 float zs = z * s; 452 float xx = x * xs; 453 float xy = x * ys; 454 float xz = x * zs; 455 float xw = w * xs; 456 float yy = y * ys; 457 float yz = y * zs; 458 float yw = w * ys; 459 float zz = z * zs; 460 float zw = w * zs; 461 462 // using s=2/norm (instead of 1/norm) saves 9 multiplications by 2 here 463 result.m00 = 1 - (yy + zz); 464 result.m01 = (xy - zw); 465 result.m02 = (xz + yw); 466 result.m10 = (xy + zw); 467 result.m11 = 1 - (xx + zz); 468 result.m12 = (yz - xw); 469 result.m20 = (xz - yw); 470 result.m21 = (yz + xw); 471 result.m22 = 1 - (xx + yy); 472 473 return result; 474 } 475 476 /** 477 * <code>getRotationColumn</code> returns one of three columns specified 478 * by the parameter. This column is returned as a <code>Vector3f</code> 479 * object. 480 * 481 * @param i 482 * the column to retrieve. Must be between 0 and 2. 483 * @return the column specified by the index. 484 */ 485 public Vector3f getRotationColumn(int i) { 486 return getRotationColumn(i, null); 487 } 488 489 /** 490 * <code>getRotationColumn</code> returns one of three columns specified 491 * by the parameter. This column is returned as a <code>Vector3f</code> 492 * object. The value is retrieved as if this quaternion was first normalized. 493 * 494 * @param i 495 * the column to retrieve. Must be between 0 and 2. 496 * @param store 497 * the vector object to store the result in. if null, a new one 498 * is created. 499 * @return the column specified by the index. 500 */ 501 public Vector3f getRotationColumn(int i, Vector3f store) { 502 if (store == null) { 503 store = new Vector3f(); 504 } 505 506 float norm = norm(); 507 if (norm != 1.0f) { 508 norm = FastMath.invSqrt(norm); 509 } 510 511 float xx = x * x * norm; 512 float xy = x * y * norm; 513 float xz = x * z * norm; 514 float xw = x * w * norm; 515 float yy = y * y * norm; 516 float yz = y * z * norm; 517 float yw = y * w * norm; 518 float zz = z * z * norm; 519 float zw = z * w * norm; 520 521 switch (i) { 522 case 0: 523 store.x = 1 - 2 * (yy + zz); 524 store.y = 2 * (xy + zw); 525 store.z = 2 * (xz - yw); 526 break; 527 case 1: 528 store.x = 2 * (xy - zw); 529 store.y = 1 - 2 * (xx + zz); 530 store.z = 2 * (yz + xw); 531 break; 532 case 2: 533 store.x = 2 * (xz + yw); 534 store.y = 2 * (yz - xw); 535 store.z = 1 - 2 * (xx + yy); 536 break; 537 default: 538 logger.warning("Invalid column index."); 539 throw new IllegalArgumentException("Invalid column index. " + i); 540 } 541 542 return store; 543 } 544 545 /** 546 * <code>fromAngleAxis</code> sets this quaternion to the values specified 547 * by an angle and an axis of rotation. This method creates an object, so 548 * use fromAngleNormalAxis if your axis is already normalized. 549 * 550 * @param angle 551 * the angle to rotate (in radians). 552 * @param axis 553 * the axis of rotation. 554 * @return this quaternion 555 */ 556 public Quaternion fromAngleAxis(float angle, Vector3f axis) { 557 Vector3f normAxis = axis.normalize(); 558 fromAngleNormalAxis(angle, normAxis); 559 return this; 560 } 561 562 /** 563 * <code>fromAngleNormalAxis</code> sets this quaternion to the values 564 * specified by an angle and a normalized axis of rotation. 565 * 566 * @param angle 567 * the angle to rotate (in radians). 568 * @param axis 569 * the axis of rotation (already normalized). 570 */ 571 public Quaternion fromAngleNormalAxis(float angle, Vector3f axis) { 572 if (axis.x == 0 && axis.y == 0 && axis.z == 0) { 573 loadIdentity(); 574 } else { 575 float halfAngle = 0.5f * angle; 576 float sin = FastMath.sin(halfAngle); 577 w = FastMath.cos(halfAngle); 578 x = sin * axis.x; 579 y = sin * axis.y; 580 z = sin * axis.z; 581 } 582 return this; 583 } 584 585 /** 586 * <code>toAngleAxis</code> sets a given angle and axis to that 587 * represented by the current quaternion. The values are stored as 588 * following: The axis is provided as a parameter and built by the method, 589 * the angle is returned as a float. 590 * 591 * @param axisStore 592 * the object we'll store the computed axis in. 593 * @return the angle of rotation in radians. 594 */ 595 public float toAngleAxis(Vector3f axisStore) { 596 float sqrLength = x * x + y * y + z * z; 597 float angle; 598 if (sqrLength == 0.0f) { 599 angle = 0.0f; 600 if (axisStore != null) { 601 axisStore.x = 1.0f; 602 axisStore.y = 0.0f; 603 axisStore.z = 0.0f; 604 } 605 } else { 606 angle = (2.0f * FastMath.acos(w)); 607 if (axisStore != null) { 608 float invLength = (1.0f / FastMath.sqrt(sqrLength)); 609 axisStore.x = x * invLength; 610 axisStore.y = y * invLength; 611 axisStore.z = z * invLength; 612 } 613 } 614 615 return angle; 616 } 617 618 /** 619 * <code>slerp</code> sets this quaternion's value as an interpolation 620 * between two other quaternions. 621 * 622 * @param q1 623 * the first quaternion. 624 * @param q2 625 * the second quaternion. 626 * @param t 627 * the amount to interpolate between the two quaternions. 628 */ 629 public Quaternion slerp(Quaternion q1, Quaternion q2, float t) { 630 // Create a local quaternion to store the interpolated quaternion 631 if (q1.x == q2.x && q1.y == q2.y && q1.z == q2.z && q1.w == q2.w) { 632 this.set(q1); 633 return this; 634 } 635 636 float result = (q1.x * q2.x) + (q1.y * q2.y) + (q1.z * q2.z) 637 + (q1.w * q2.w); 638 639 if (result < 0.0f) { 640 // Negate the second quaternion and the result of the dot product 641 q2.x = -q2.x; 642 q2.y = -q2.y; 643 q2.z = -q2.z; 644 q2.w = -q2.w; 645 result = -result; 646 } 647 648 // Set the first and second scale for the interpolation 649 float scale0 = 1 - t; 650 float scale1 = t; 651 652 // Check if the angle between the 2 quaternions was big enough to 653 // warrant such calculations 654 if ((1 - result) > 0.1f) {// Get the angle between the 2 quaternions, 655 // and then store the sin() of that angle 656 float theta = FastMath.acos(result); 657 float invSinTheta = 1f / FastMath.sin(theta); 658 659 // Calculate the scale for q1 and q2, according to the angle and 660 // it's sine value 661 scale0 = FastMath.sin((1 - t) * theta) * invSinTheta; 662 scale1 = FastMath.sin((t * theta)) * invSinTheta; 663 } 664 665 // Calculate the x, y, z and w values for the quaternion by using a 666 // special 667 // form of linear interpolation for quaternions. 668 this.x = (scale0 * q1.x) + (scale1 * q2.x); 669 this.y = (scale0 * q1.y) + (scale1 * q2.y); 670 this.z = (scale0 * q1.z) + (scale1 * q2.z); 671 this.w = (scale0 * q1.w) + (scale1 * q2.w); 672 673 // Return the interpolated quaternion 674 return this; 675 } 676 677 /** 678 * Sets the values of this quaternion to the slerp from itself to q2 by 679 * changeAmnt 680 * 681 * @param q2 682 * Final interpolation value 683 * @param changeAmnt 684 * The amount diffrence 685 */ 686 public void slerp(Quaternion q2, float changeAmnt) { 687 if (this.x == q2.x && this.y == q2.y && this.z == q2.z 688 && this.w == q2.w) { 689 return; 690 } 691 692 float result = (this.x * q2.x) + (this.y * q2.y) + (this.z * q2.z) 693 + (this.w * q2.w); 694 695 if (result < 0.0f) { 696 // Negate the second quaternion and the result of the dot product 697 q2.x = -q2.x; 698 q2.y = -q2.y; 699 q2.z = -q2.z; 700 q2.w = -q2.w; 701 result = -result; 702 } 703 704 // Set the first and second scale for the interpolation 705 float scale0 = 1 - changeAmnt; 706 float scale1 = changeAmnt; 707 708 // Check if the angle between the 2 quaternions was big enough to 709 // warrant such calculations 710 if ((1 - result) > 0.1f) { 711 // Get the angle between the 2 quaternions, and then store the sin() 712 // of that angle 713 float theta = FastMath.acos(result); 714 float invSinTheta = 1f / FastMath.sin(theta); 715 716 // Calculate the scale for q1 and q2, according to the angle and 717 // it's sine value 718 scale0 = FastMath.sin((1 - changeAmnt) * theta) * invSinTheta; 719 scale1 = FastMath.sin((changeAmnt * theta)) * invSinTheta; 720 } 721 722 // Calculate the x, y, z and w values for the quaternion by using a 723 // special 724 // form of linear interpolation for quaternions. 725 this.x = (scale0 * this.x) + (scale1 * q2.x); 726 this.y = (scale0 * this.y) + (scale1 * q2.y); 727 this.z = (scale0 * this.z) + (scale1 * q2.z); 728 this.w = (scale0 * this.w) + (scale1 * q2.w); 729 } 730 731 /** 732 * Sets the values of this quaternion to the nlerp from itself to q2 by blend. 733 * @param q2 734 * @param blend 735 */ 736 public void nlerp(Quaternion q2, float blend) { 737 float dot = dot(q2); 738 float blendI = 1.0f - blend; 739 if (dot < 0.0f) { 740 x = blendI * x - blend * q2.x; 741 y = blendI * y - blend * q2.y; 742 z = blendI * z - blend * q2.z; 743 w = blendI * w - blend * q2.w; 744 } else { 745 x = blendI * x + blend * q2.x; 746 y = blendI * y + blend * q2.y; 747 z = blendI * z + blend * q2.z; 748 w = blendI * w + blend * q2.w; 749 } 750 normalizeLocal(); 751 } 752 753 /** 754 * <code>add</code> adds the values of this quaternion to those of the 755 * parameter quaternion. The result is returned as a new quaternion. 756 * 757 * @param q 758 * the quaternion to add to this. 759 * @return the new quaternion. 760 */ 761 public Quaternion add(Quaternion q) { 762 return new Quaternion(x + q.x, y + q.y, z + q.z, w + q.w); 763 } 764 765 /** 766 * <code>add</code> adds the values of this quaternion to those of the 767 * parameter quaternion. The result is stored in this Quaternion. 768 * 769 * @param q 770 * the quaternion to add to this. 771 * @return This Quaternion after addition. 772 */ 773 public Quaternion addLocal(Quaternion q) { 774 this.x += q.x; 775 this.y += q.y; 776 this.z += q.z; 777 this.w += q.w; 778 return this; 779 } 780 781 /** 782 * <code>subtract</code> subtracts the values of the parameter quaternion 783 * from those of this quaternion. The result is returned as a new 784 * quaternion. 785 * 786 * @param q 787 * the quaternion to subtract from this. 788 * @return the new quaternion. 789 */ 790 public Quaternion subtract(Quaternion q) { 791 return new Quaternion(x - q.x, y - q.y, z - q.z, w - q.w); 792 } 793 794 /** 795 * <code>subtract</code> subtracts the values of the parameter quaternion 796 * from those of this quaternion. The result is stored in this Quaternion. 797 * 798 * @param q 799 * the quaternion to subtract from this. 800 * @return This Quaternion after subtraction. 801 */ 802 public Quaternion subtractLocal(Quaternion q) { 803 this.x -= q.x; 804 this.y -= q.y; 805 this.z -= q.z; 806 this.w -= q.w; 807 return this; 808 } 809 810 /** 811 * <code>mult</code> multiplies this quaternion by a parameter quaternion. 812 * The result is returned as a new quaternion. It should be noted that 813 * quaternion multiplication is not commutative so q * p != p * q. 814 * 815 * @param q 816 * the quaternion to multiply this quaternion by. 817 * @return the new quaternion. 818 */ 819 public Quaternion mult(Quaternion q) { 820 return mult(q, null); 821 } 822 823 /** 824 * <code>mult</code> multiplies this quaternion by a parameter quaternion. 825 * The result is returned as a new quaternion. It should be noted that 826 * quaternion multiplication is not commutative so q * p != p * q. 827 * 828 * It IS safe for q and res to be the same object. 829 * It IS safe for this and res to be the same object. 830 * 831 * @param q 832 * the quaternion to multiply this quaternion by. 833 * @param res 834 * the quaternion to store the result in. 835 * @return the new quaternion. 836 */ 837 public Quaternion mult(Quaternion q, Quaternion res) { 838 if (res == null) { 839 res = new Quaternion(); 840 } 841 float qw = q.w, qx = q.x, qy = q.y, qz = q.z; 842 res.x = x * qw + y * qz - z * qy + w * qx; 843 res.y = -x * qz + y * qw + z * qx + w * qy; 844 res.z = x * qy - y * qx + z * qw + w * qz; 845 res.w = -x * qx - y * qy - z * qz + w * qw; 846 return res; 847 } 848 849 /** 850 * <code>apply</code> multiplies this quaternion by a parameter matrix 851 * internally. 852 * 853 * @param matrix 854 * the matrix to apply to this quaternion. 855 */ 856 public void apply(Matrix3f matrix) { 857 float oldX = x, oldY = y, oldZ = z, oldW = w; 858 fromRotationMatrix(matrix); 859 float tempX = x, tempY = y, tempZ = z, tempW = w; 860 861 x = oldX * tempW + oldY * tempZ - oldZ * tempY + oldW * tempX; 862 y = -oldX * tempZ + oldY * tempW + oldZ * tempX + oldW * tempY; 863 z = oldX * tempY - oldY * tempX + oldZ * tempW + oldW * tempZ; 864 w = -oldX * tempX - oldY * tempY - oldZ * tempZ + oldW * tempW; 865 } 866 867 /** 868 * 869 * <code>fromAxes</code> creates a <code>Quaternion</code> that 870 * represents the coordinate system defined by three axes. These axes are 871 * assumed to be orthogonal and no error checking is applied. Thus, the user 872 * must insure that the three axes being provided indeed represents a proper 873 * right handed coordinate system. 874 * 875 * @param axis 876 * the array containing the three vectors representing the 877 * coordinate system. 878 */ 879 public Quaternion fromAxes(Vector3f[] axis) { 880 if (axis.length != 3) { 881 throw new IllegalArgumentException( 882 "Axis array must have three elements"); 883 } 884 return fromAxes(axis[0], axis[1], axis[2]); 885 } 886 887 /** 888 * 889 * <code>fromAxes</code> creates a <code>Quaternion</code> that 890 * represents the coordinate system defined by three axes. These axes are 891 * assumed to be orthogonal and no error checking is applied. Thus, the user 892 * must insure that the three axes being provided indeed represents a proper 893 * right handed coordinate system. 894 * 895 * @param xAxis vector representing the x-axis of the coordinate system. 896 * @param yAxis vector representing the y-axis of the coordinate system. 897 * @param zAxis vector representing the z-axis of the coordinate system. 898 */ 899 public Quaternion fromAxes(Vector3f xAxis, Vector3f yAxis, Vector3f zAxis) { 900 return fromRotationMatrix(xAxis.x, yAxis.x, zAxis.x, xAxis.y, yAxis.y, 901 zAxis.y, xAxis.z, yAxis.z, zAxis.z); 902 } 903 904 /** 905 * 906 * <code>toAxes</code> takes in an array of three vectors. Each vector 907 * corresponds to an axis of the coordinate system defined by the quaternion 908 * rotation. 909 * 910 * @param axis 911 * the array of vectors to be filled. 912 */ 913 public void toAxes(Vector3f axis[]) { 914 Matrix3f tempMat = toRotationMatrix(); 915 axis[0] = tempMat.getColumn(0, axis[0]); 916 axis[1] = tempMat.getColumn(1, axis[1]); 917 axis[2] = tempMat.getColumn(2, axis[2]); 918 } 919 920 /** 921 * <code>mult</code> multiplies this quaternion by a parameter vector. The 922 * result is returned as a new vector. 923 * 924 * @param v 925 * the vector to multiply this quaternion by. 926 * @return the new vector. 927 */ 928 public Vector3f mult(Vector3f v) { 929 return mult(v, null); 930 } 931 932 /** 933 * <code>mult</code> multiplies this quaternion by a parameter vector. The 934 * result is stored in the supplied vector 935 * 936 * @param v 937 * the vector to multiply this quaternion by. 938 * @return v 939 */ 940 public Vector3f multLocal(Vector3f v) { 941 float tempX, tempY; 942 tempX = w * w * v.x + 2 * y * w * v.z - 2 * z * w * v.y + x * x * v.x 943 + 2 * y * x * v.y + 2 * z * x * v.z - z * z * v.x - y * y * v.x; 944 tempY = 2 * x * y * v.x + y * y * v.y + 2 * z * y * v.z + 2 * w * z 945 * v.x - z * z * v.y + w * w * v.y - 2 * x * w * v.z - x * x 946 * v.y; 947 v.z = 2 * x * z * v.x + 2 * y * z * v.y + z * z * v.z - 2 * w * y * v.x 948 - y * y * v.z + 2 * w * x * v.y - x * x * v.z + w * w * v.z; 949 v.x = tempX; 950 v.y = tempY; 951 return v; 952 } 953 954 /** 955 * Multiplies this Quaternion by the supplied quaternion. The result is 956 * stored in this Quaternion, which is also returned for chaining. Similar 957 * to this *= q. 958 * 959 * @param q 960 * The Quaternion to multiply this one by. 961 * @return This Quaternion, after multiplication. 962 */ 963 public Quaternion multLocal(Quaternion q) { 964 float x1 = x * q.w + y * q.z - z * q.y + w * q.x; 965 float y1 = -x * q.z + y * q.w + z * q.x + w * q.y; 966 float z1 = x * q.y - y * q.x + z * q.w + w * q.z; 967 w = -x * q.x - y * q.y - z * q.z + w * q.w; 968 x = x1; 969 y = y1; 970 z = z1; 971 return this; 972 } 973 974 /** 975 * Multiplies this Quaternion by the supplied quaternion. The result is 976 * stored in this Quaternion, which is also returned for chaining. Similar 977 * to this *= q. 978 * 979 * @param qx - 980 * quat x value 981 * @param qy - 982 * quat y value 983 * @param qz - 984 * quat z value 985 * @param qw - 986 * quat w value 987 * 988 * @return This Quaternion, after multiplication. 989 */ 990 public Quaternion multLocal(float qx, float qy, float qz, float qw) { 991 float x1 = x * qw + y * qz - z * qy + w * qx; 992 float y1 = -x * qz + y * qw + z * qx + w * qy; 993 float z1 = x * qy - y * qx + z * qw + w * qz; 994 w = -x * qx - y * qy - z * qz + w * qw; 995 x = x1; 996 y = y1; 997 z = z1; 998 return this; 999 } 1000 1001 /** 1002 * <code>mult</code> multiplies this quaternion by a parameter vector. The 1003 * result is returned as a new vector. 1004 * 1005 * @param v 1006 * the vector to multiply this quaternion by. 1007 * @param store 1008 * the vector to store the result in. It IS safe for v and store 1009 * to be the same object. 1010 * @return the result vector. 1011 */ 1012 public Vector3f mult(Vector3f v, Vector3f store) { 1013 if (store == null) { 1014 store = new Vector3f(); 1015 } 1016 if (v.x == 0 && v.y == 0 && v.z == 0) { 1017 store.set(0, 0, 0); 1018 } else { 1019 float vx = v.x, vy = v.y, vz = v.z; 1020 store.x = w * w * vx + 2 * y * w * vz - 2 * z * w * vy + x * x 1021 * vx + 2 * y * x * vy + 2 * z * x * vz - z * z * vx - y 1022 * y * vx; 1023 store.y = 2 * x * y * vx + y * y * vy + 2 * z * y * vz + 2 * w 1024 * z * vx - z * z * vy + w * w * vy - 2 * x * w * vz - x 1025 * x * vy; 1026 store.z = 2 * x * z * vx + 2 * y * z * vy + z * z * vz - 2 * w 1027 * y * vx - y * y * vz + 2 * w * x * vy - x * x * vz + w 1028 * w * vz; 1029 } 1030 return store; 1031 } 1032 1033 /** 1034 * <code>mult</code> multiplies this quaternion by a parameter scalar. The 1035 * result is returned as a new quaternion. 1036 * 1037 * @param scalar 1038 * the quaternion to multiply this quaternion by. 1039 * @return the new quaternion. 1040 */ 1041 public Quaternion mult(float scalar) { 1042 return new Quaternion(scalar * x, scalar * y, scalar * z, scalar * w); 1043 } 1044 1045 /** 1046 * <code>mult</code> multiplies this quaternion by a parameter scalar. The 1047 * result is stored locally. 1048 * 1049 * @param scalar 1050 * the quaternion to multiply this quaternion by. 1051 * @return this. 1052 */ 1053 public Quaternion multLocal(float scalar) { 1054 w *= scalar; 1055 x *= scalar; 1056 y *= scalar; 1057 z *= scalar; 1058 return this; 1059 } 1060 1061 /** 1062 * <code>dot</code> calculates and returns the dot product of this 1063 * quaternion with that of the parameter quaternion. 1064 * 1065 * @param q 1066 * the quaternion to calculate the dot product of. 1067 * @return the dot product of this and the parameter quaternion. 1068 */ 1069 public float dot(Quaternion q) { 1070 return w * q.w + x * q.x + y * q.y + z * q.z; 1071 } 1072 1073 /** 1074 * <code>norm</code> returns the norm of this quaternion. This is the dot 1075 * product of this quaternion with itself. 1076 * 1077 * @return the norm of the quaternion. 1078 */ 1079 public float norm() { 1080 return w * w + x * x + y * y + z * z; 1081 } 1082 1083 /** 1084 * <code>normalize</code> normalizes the current <code>Quaternion</code> 1085 * @deprecated The naming of this method doesn't follow convention. 1086 * Please use {@link Quaternion#normalizeLocal() } instead. 1087 */ 1088 @Deprecated 1089 public void normalize() { 1090 float n = FastMath.invSqrt(norm()); 1091 x *= n; 1092 y *= n; 1093 z *= n; 1094 w *= n; 1095 } 1096 1097 /** 1098 * <code>normalize</code> normalizes the current <code>Quaternion</code> 1099 */ 1100 public void normalizeLocal() { 1101 float n = FastMath.invSqrt(norm()); 1102 x *= n; 1103 y *= n; 1104 z *= n; 1105 w *= n; 1106 } 1107 1108 /** 1109 * <code>inverse</code> returns the inverse of this quaternion as a new 1110 * quaternion. If this quaternion does not have an inverse (if its normal is 1111 * 0 or less), then null is returned. 1112 * 1113 * @return the inverse of this quaternion or null if the inverse does not 1114 * exist. 1115 */ 1116 public Quaternion inverse() { 1117 float norm = norm(); 1118 if (norm > 0.0) { 1119 float invNorm = 1.0f / norm; 1120 return new Quaternion(-x * invNorm, -y * invNorm, -z * invNorm, w 1121 * invNorm); 1122 } 1123 // return an invalid result to flag the error 1124 return null; 1125 } 1126 1127 /** 1128 * <code>inverse</code> calculates the inverse of this quaternion and 1129 * returns this quaternion after it is calculated. If this quaternion does 1130 * not have an inverse (if it's norma is 0 or less), nothing happens 1131 * 1132 * @return the inverse of this quaternion 1133 */ 1134 public Quaternion inverseLocal() { 1135 float norm = norm(); 1136 if (norm > 0.0) { 1137 float invNorm = 1.0f / norm; 1138 x *= -invNorm; 1139 y *= -invNorm; 1140 z *= -invNorm; 1141 w *= invNorm; 1142 } 1143 return this; 1144 } 1145 1146 /** 1147 * <code>negate</code> inverts the values of the quaternion. 1148 * 1149 */ 1150 public void negate() { 1151 x *= -1; 1152 y *= -1; 1153 z *= -1; 1154 w *= -1; 1155 } 1156 1157 /** 1158 * 1159 * <code>toString</code> creates the string representation of this 1160 * <code>Quaternion</code>. The values of the quaternion are displace (x, 1161 * y, z, w), in the following manner: <br> 1162 * (x, y, z, w) 1163 * 1164 * @return the string representation of this object. 1165 * @see java.lang.Object#toString() 1166 */ 1167 @Override 1168 public String toString() { 1169 return "(" + x + ", " + y + ", " + z + ", " + w + ")"; 1170 } 1171 1172 /** 1173 * <code>equals</code> determines if two quaternions are logically equal, 1174 * that is, if the values of (x, y, z, w) are the same for both quaternions. 1175 * 1176 * @param o 1177 * the object to compare for equality 1178 * @return true if they are equal, false otherwise. 1179 */ 1180 @Override 1181 public boolean equals(Object o) { 1182 if (!(o instanceof Quaternion)) { 1183 return false; 1184 } 1185 1186 if (this == o) { 1187 return true; 1188 } 1189 1190 Quaternion comp = (Quaternion) o; 1191 if (Float.compare(x, comp.x) != 0) { 1192 return false; 1193 } 1194 if (Float.compare(y, comp.y) != 0) { 1195 return false; 1196 } 1197 if (Float.compare(z, comp.z) != 0) { 1198 return false; 1199 } 1200 if (Float.compare(w, comp.w) != 0) { 1201 return false; 1202 } 1203 return true; 1204 } 1205 1206 /** 1207 * 1208 * <code>hashCode</code> returns the hash code value as an integer and is 1209 * supported for the benefit of hashing based collection classes such as 1210 * Hashtable, HashMap, HashSet etc. 1211 * 1212 * @return the hashcode for this instance of Quaternion. 1213 * @see java.lang.Object#hashCode() 1214 */ 1215 @Override 1216 public int hashCode() { 1217 int hash = 37; 1218 hash = 37 * hash + Float.floatToIntBits(x); 1219 hash = 37 * hash + Float.floatToIntBits(y); 1220 hash = 37 * hash + Float.floatToIntBits(z); 1221 hash = 37 * hash + Float.floatToIntBits(w); 1222 return hash; 1223 1224 } 1225 1226 /** 1227 * <code>readExternal</code> builds a quaternion from an 1228 * <code>ObjectInput</code> object. <br> 1229 * NOTE: Used with serialization. Not to be called manually. 1230 * 1231 * @param in 1232 * the ObjectInput value to read from. 1233 * @throws IOException 1234 * if the ObjectInput value has problems reading a float. 1235 * @see java.io.Externalizable 1236 */ 1237 public void readExternal(ObjectInput in) throws IOException { 1238 x = in.readFloat(); 1239 y = in.readFloat(); 1240 z = in.readFloat(); 1241 w = in.readFloat(); 1242 } 1243 1244 /** 1245 * <code>writeExternal</code> writes this quaternion out to a 1246 * <code>ObjectOutput</code> object. NOTE: Used with serialization. Not to 1247 * be called manually. 1248 * 1249 * @param out 1250 * the object to write to. 1251 * @throws IOException 1252 * if writing to the ObjectOutput fails. 1253 * @see java.io.Externalizable 1254 */ 1255 public void writeExternal(ObjectOutput out) throws IOException { 1256 out.writeFloat(x); 1257 out.writeFloat(y); 1258 out.writeFloat(z); 1259 out.writeFloat(w); 1260 } 1261 1262 /** 1263 * <code>lookAt</code> is a convienence method for auto-setting the 1264 * quaternion based on a direction and an up vector. It computes 1265 * the rotation to transform the z-axis to point into 'direction' 1266 * and the y-axis to 'up'. 1267 * 1268 * @param direction 1269 * where to look at in terms of local coordinates 1270 * @param up 1271 * a vector indicating the local up direction. 1272 * (typically {0, 1, 0} in jME.) 1273 */ 1274 public void lookAt(Vector3f direction, Vector3f up) { 1275 TempVars vars = TempVars.get(); 1276 vars.vect3.set(direction).normalizeLocal(); 1277 vars.vect1.set(up).crossLocal(direction).normalizeLocal(); 1278 vars.vect2.set(direction).crossLocal(vars.vect1).normalizeLocal(); 1279 fromAxes(vars.vect1, vars.vect2, vars.vect3); 1280 vars.release(); 1281 } 1282 1283 public void write(JmeExporter e) throws IOException { 1284 OutputCapsule cap = e.getCapsule(this); 1285 cap.write(x, "x", 0); 1286 cap.write(y, "y", 0); 1287 cap.write(z, "z", 0); 1288 cap.write(w, "w", 1); 1289 } 1290 1291 public void read(JmeImporter e) throws IOException { 1292 InputCapsule cap = e.getCapsule(this); 1293 x = cap.readFloat("x", 0); 1294 y = cap.readFloat("y", 0); 1295 z = cap.readFloat("z", 0); 1296 w = cap.readFloat("w", 1); 1297 } 1298 1299 /** 1300 * @return A new quaternion that describes a rotation that would point you 1301 * in the exact opposite direction of this Quaternion. 1302 */ 1303 public Quaternion opposite() { 1304 return opposite(null); 1305 } 1306 1307 /** 1308 * FIXME: This seems to have singularity type issues with angle == 0, possibly others such as PI. 1309 * @param store 1310 * A Quaternion to store our result in. If null, a new one is 1311 * created. 1312 * @return The store quaternion (or a new Quaterion, if store is null) that 1313 * describes a rotation that would point you in the exact opposite 1314 * direction of this Quaternion. 1315 */ 1316 public Quaternion opposite(Quaternion store) { 1317 if (store == null) { 1318 store = new Quaternion(); 1319 } 1320 1321 Vector3f axis = new Vector3f(); 1322 float angle = toAngleAxis(axis); 1323 1324 store.fromAngleAxis(FastMath.PI + angle, axis); 1325 return store; 1326 } 1327 1328 /** 1329 * @return This Quaternion, altered to describe a rotation that would point 1330 * you in the exact opposite direction of where it is pointing 1331 * currently. 1332 */ 1333 public Quaternion oppositeLocal() { 1334 return opposite(this); 1335 } 1336 1337 @Override 1338 public Quaternion clone() { 1339 try { 1340 return (Quaternion) super.clone(); 1341 } catch (CloneNotSupportedException e) { 1342 throw new AssertionError(); // can not happen 1343 } 1344 } 1345 } 1346