1 package JSci.maths; 2 3 import JSci.GlobalSettings; 4 import JSci.maths.matrices.AbstractDoubleSquareMatrix; 5 import JSci.maths.matrices.DoubleSquareMatrix; 6 import JSci.maths.matrices.MatrixDimensionException; 7 import JSci.maths.vectors.Double3Vector; 8 import JSci.maths.groups.AbelianGroup; 9 import JSci.maths.fields.*; 10 import JSci.maths.algebras.*; 11 12 20 public final class Quaternion implements Field.Member, CStarAlgebra.Member { 21 private static final long serialVersionUID = 1605315490425547301L; 22 23 private double re; 24 private double imi, imj, imk; 25 26 public static final Quaternion ONE=new Quaternion(1.0, 0.0, 0.0, 0.0); 27 public static final Quaternion I=new Quaternion(0.0, 1.0, 0.0, 0.0); 28 public static final Quaternion J=new Quaternion(0.0, 0.0, 1.0, 0.0); 29 public static final Quaternion K=new Quaternion(0.0, 0.0, 0.0, 1.0); 30 33 public Quaternion(final double real,final Double3Vector imag) { 34 re=real; 35 imi=imag.getComponent(0); 36 imj=imag.getComponent(1); 37 imk=imag.getComponent(2); 38 } 39 42 public Quaternion(final double q0,final double q1,final double q2,final double q3) { 43 re=q0; 44 imi=q1; 45 imj=q2; 46 imk=q3; 47 } 48 55 public static Quaternion rotation(AbstractDoubleSquareMatrix m) { 56 if(m.rows() != 3 && m.columns() != 3) 57 throw new MatrixDimensionException("The matrix is not 3-dimensional."); 58 double re, imi, imj, imk; 59 double wSqr = ( 1.0 + m.trace() ) / 4.0; 60 if(wSqr > GlobalSettings.ZERO_TOL) { 61 re = Math.sqrt( wSqr ); 62 imi = ( m.getElement(2,1) - m.getElement(1,2) ) / ( re * 4.0 ); 63 imj = ( m.getElement(0,2) - m.getElement(2,0) ) / ( re * 4.0 ); 64 imk = ( m.getElement(1,0) - m.getElement(0,1) ) / ( re * 4.0 ); 65 } else { 66 double xSqr = -( m.getElement(1,1) + m.getElement(2,2) ) / 2.0; 67 re = 0.0; 68 if(xSqr > GlobalSettings.ZERO_TOL) { 69 imi = Math.sqrt( xSqr ); 70 imj = m.getElement(1,0) / ( 2.0 * imi ); 71 imk = m.getElement(2,0) / ( 2.0 * imi ); 72 } else { 73 double ySqr = ( 1.0 - m.getElement(2,2) ) / 2.0; 74 imi = 0.0; 75 if(ySqr > GlobalSettings.ZERO_TOL) { 76 imj = Math.sqrt( ySqr ); 77 imk = m.getElement(2,1) / ( 2.0 * imj ); 78 } else { 79 imj = 0.0; 80 imk = 1.0; 81 } 82 } 83 } 84 return new Quaternion(re, imi, imj, imk); 85 } 86 91 public AbstractDoubleSquareMatrix toRotationMatrix() { 92 final double[][] array = new double[3][3]; 93 94 array[0][0] = 1.0 - 2.0 * ( imj * imj + imk * imk ); 95 array[0][1] = 2.0 * ( imi * imj - re * imk ); 96 array[0][2] = 2.0 * ( imi * imk + re * imj ); 97 98 array[1][0] = 2.0 * ( imi * imj + re * imk ); 99 array[1][1] = 1.0 - 2.0 * ( imi * imi + imk * imk ); 100 array[1][2] = 2.0 * ( imj * imk - re * imi ); 101 102 array[2][0] = 2.0 * ( imi * imk - re * imj ); 103 array[2][1] = 2.0 * ( imj * imk + re * imi ); 104 array[2][2] = 1.0 - 2.0 * ( imi * imi + imj * imj ); 105 106 return new DoubleSquareMatrix( array ); 107 } 108 112 public boolean equals(Object obj) { 113 if(obj instanceof Quaternion) { 114 final Quaternion q = (Quaternion)obj; 115 return this.subtract(q).norm() <= GlobalSettings.ZERO_TOL; 116 } else 117 return false; 118 } 119 122 public String toString() { 123 final StringBuffer buf=new StringBuffer (40); 124 buf.append(re); 125 if(imi>=0.0) 126 buf.append("+"); 127 buf.append(imi); 128 buf.append("i"); 129 if(imj>=0.0) 130 buf.append("+"); 131 buf.append(imj); 132 buf.append("j"); 133 if(imk>=0.0) 134 buf.append("+"); 135 buf.append(imk); 136 buf.append("k"); 137 return buf.toString(); 138 } 139 142 public int hashCode() { 143 return (int)(Math.exp(norm())); 144 } 145 148 public boolean isNaN() { 149 return (re==Double.NaN) || (imi==Double.NaN) || 150 (imj==Double.NaN) || (imk==Double.NaN); 151 } 152 155 public boolean isInfinite() { 156 return (re==Double.POSITIVE_INFINITY) || (re==Double.NEGATIVE_INFINITY) 157 || (imi==Double.POSITIVE_INFINITY) || (imi==Double.NEGATIVE_INFINITY) 158 || (imj==Double.POSITIVE_INFINITY) || (imj==Double.NEGATIVE_INFINITY) 159 || (imk==Double.POSITIVE_INFINITY) || (imk==Double.NEGATIVE_INFINITY); 160 } 161 164 public double real() { 165 return re; 166 } 167 170 public Double3Vector imag() { 171 return new Double3Vector(imi, imj, imk); 172 } 173 public Object getSet() { 174 throw new RuntimeException ("Not yet implemented: please file bug report"); 175 } 176 180 public double norm() { 181 return Math.sqrt(sumSquares()); 182 } 183 186 public double sumSquares() { 187 return re*re+imi*imi+imj*imj+imk*imk; 188 } 189 190 194 197 public AbelianGroup.Member negate() { 198 return new Quaternion(-re, -imi, -imj, -imk); 199 } 200 203 public Field.Member inverse() { 204 final double sumSqr=sumSquares(); 205 return new Quaternion(re/sumSqr, -imi/sumSqr, -imj/sumSqr, -imk/sumSqr); 206 } 207 210 public CStarAlgebra.Member involution() { 211 return conjugate(); 212 } 213 216 public Quaternion conjugate() { 217 return new Quaternion(re, -imi, -imj, -imk); 218 } 219 220 222 225 public AbelianGroup.Member add(final AbelianGroup.Member x) { 226 if(x instanceof Quaternion) 227 return add((Quaternion)x); 228 else if(x instanceof MathDouble) 229 return addReal(((MathDouble)x).value()); 230 else if(x instanceof MathInteger) 231 return addReal(((MathInteger)x).value()); 232 else 233 throw new IllegalArgumentException ("Member class not recognised by this method."); 234 } 235 239 public Quaternion add(final Quaternion q) { 240 return new Quaternion(re+q.re, imi+q.imi, imj+q.imj, imk+q.imk); 241 } 242 246 public Quaternion addReal(final double real) { 247 return new Quaternion(re+real, imi, imj, imk); 248 } 249 253 public Quaternion addImag(final Double3Vector imag) { 254 return new Quaternion(re, imi+imag.getComponent(0), imj+imag.getComponent(1), imk+imag.getComponent(2)); 255 } 256 257 259 262 public AbelianGroup.Member subtract(final AbelianGroup.Member x) { 263 if(x instanceof Quaternion) 264 return subtract((Quaternion)x); 265 else if(x instanceof MathDouble) 266 return subtractReal(((MathDouble)x).value()); 267 else if(x instanceof MathInteger) 268 return subtractReal(((MathInteger)x).value()); 269 else 270 throw new IllegalArgumentException ("Member class not recognised by this method."); 271 } 272 276 public Quaternion subtract(final Quaternion q) { 277 return new Quaternion(re-q.re, imi-q.imi, imj-q.imj, imk-q.imk); 278 } 279 283 public Quaternion subtractReal(final double real) { 284 return new Quaternion(re-real, imi, imj, imk); 285 } 286 290 public Quaternion subtractImag(final Double3Vector imag) { 291 return new Quaternion(re, imi-imag.getComponent(0), imj-imag.getComponent(1), imk-imag.getComponent(2)); 292 } 293 294 296 299 public Module.Member scalarMultiply(final Ring.Member x) { 300 if(x instanceof MathDouble) 301 return multiply(((MathDouble)x).value()); 302 else if(x instanceof MathInteger) 303 return multiply(((MathInteger)x).value()); 304 else 305 throw new IllegalArgumentException ("Member class not recognised by this method."); 306 } 307 310 public Ring.Member multiply(final Ring.Member x) { 311 if(x instanceof Quaternion) 312 return multiply((Quaternion)x); 313 else if(x instanceof MathDouble) 314 return multiply(((MathDouble)x).value()); 315 else if(x instanceof MathInteger) 316 return multiply(((MathInteger)x).value()); 317 else 318 throw new IllegalArgumentException ("Member class not recognised by this method."); 319 } 320 324 public Quaternion multiply(final Quaternion q) { 325 return new Quaternion( 326 re*q.re-imi*q.imi-imj*q.imj-imk*q.imk, 327 re*q.imi+q.re*imi+(imj*q.imk-q.imj*imk), 328 re*q.imj+q.re*imj+(imk*q.imi-q.imk*imi), 329 re*q.imk+q.re*imk+(imi*q.imj-q.imi*imj) 330 ); 331 } 332 336 public Quaternion multiply(final double x) { 337 return new Quaternion(x*re, x*imi, x*imj, x*imk); 338 } 339 340 342 345 public VectorSpace.Member scalarDivide(final Field.Member x) { 346 if(x instanceof MathDouble) 347 return divide(((MathDouble)x).value()); 348 else 349 throw new IllegalArgumentException ("Member class not recognised by this method."); 350 } 351 354 public Field.Member divide(final Field.Member x) { 355 if(x instanceof Quaternion) 356 return divide((Quaternion)x); 357 else if(x instanceof MathDouble) 358 return divide(((MathDouble)x).value()); 359 else 360 throw new IllegalArgumentException ("Member class not recognised by this method."); 361 } 362 367 public Quaternion divide(final Quaternion q) { 368 final double qSumSqr=q.sumSquares(); 369 return new Quaternion( 370 (re*q.re+imi*q.imi+imj*q.imj+imk*q.imk)/qSumSqr, 371 (q.re*imi-re*q.imi-(imj*q.imk-q.imj*imk))/qSumSqr, 372 (q.re*imj-re*q.imj-(imk*q.imi-q.imk*imi))/qSumSqr, 373 (q.re*imk-re*q.imk-(imi*q.imj-q.imi*imj))/qSumSqr 374 ); 375 } 376 381 public Quaternion divide(final double x) { 382 return new Quaternion(re/x, imi/x, imj/x, imk/x); 383 } 384 public Quaternion normalize() { 385 return this.divide(norm()); 386 } 387 388 392 public static Quaternion exp(Quaternion q) { 393 final double k = Math.exp(q.re); 394 Double3Vector imag = q.imag(); 395 final double imagNorm = imag.norm(); 396 return new Quaternion(k*Math.cos(imagNorm), (Double3Vector) imag.normalize().scalarMultiply(k*Math.sin(imagNorm))); 397 } 398 public static Quaternion log(Quaternion q) { 399 final double norm = q.norm(); 400 return new Quaternion(Math.log(norm), (Double3Vector) q.imag().normalize().scalarMultiply(Math.acos(q.re/norm))); 401 } 402 public static Quaternion sin(Quaternion q) { 403 Double3Vector imag = q.imag(); 404 final double imagNorm = imag.norm(); 405 return new Quaternion(Math.sin(q.re)*ExtraMath.cosh(imagNorm), (Double3Vector) imag.normalize().scalarMultiply(Math.cos(q.re)*ExtraMath.sinh(imagNorm))); 406 } 407 public static Quaternion cos(Quaternion q) { 408 Double3Vector imag = q.imag(); 409 final double imagNorm = imag.norm(); 410 return new Quaternion(Math.cos(q.re)*ExtraMath.cosh(imagNorm), (Double3Vector) imag.normalize().scalarMultiply(-Math.sin(q.re)*ExtraMath.sinh(imagNorm))); 411 } 412 public static Quaternion tan(Quaternion q) { 413 return sin(q).divide(cos(q)); 414 } 415 public static Quaternion sinh(Quaternion q) { 416 Double3Vector imag = q.imag(); 417 final double imagNorm = imag.norm(); 418 return new Quaternion(ExtraMath.sinh(q.re)*Math.cos(imagNorm), (Double3Vector) imag.normalize().scalarMultiply(ExtraMath.cosh(q.re)*Math.sin(imagNorm))); 419 } 420 public static Quaternion cosh(Quaternion q) { 421 Double3Vector imag = q.imag(); 422 final double imagNorm = imag.norm(); 423 return new Quaternion(ExtraMath.cosh(q.re)*Math.cos(imagNorm), (Double3Vector) imag.normalize().scalarMultiply(ExtraMath.sinh(q.re)*Math.sin(imagNorm))); 424 } 425 public static Quaternion tanh(Quaternion q) { 426 return sinh(q).divide(cosh(q)); 427 } 428 } 429 430 | Popular Tags |