001/** 002 * Vector3D -- A three element vector of Parameter objects that may represent a Cartesian 003 * coordinate. 004 * 005 * Copyright (C) 2008-2015, by Joseph A. Huwaldt. All rights reserved. 006 * 007 * This library is free software; you can redistribute it and/or modify it under the terms 008 * of the GNU Lesser General Public License as published by the Free Software Foundation; 009 * either version 2 of the License, or (at your option) any later version. 010 * 011 * This library is distributed in the hope that it will be useful, but WITHOUT ANY 012 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 013 * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. 014 * 015 * You should have received a copy of the GNU Lesser General Public License along with 016 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - 017 * Suite 330, Boston, MA 02111-1307, USA. Or visit: http://www.gnu.org/licenses/lgpl.html 018 */ 019package jahuwaldt.js.param; 020 021import javax.measure.converter.ConversionException; 022import javax.measure.converter.UnitConverter; 023import javax.measure.quantity.*; 024import javax.measure.unit.NonSI; 025import javax.measure.unit.SI; 026import javax.measure.unit.Unit; 027import javolution.context.ImmortalContext; 028import javolution.context.ObjectFactory; 029import javolution.lang.MathLib; 030import javolution.xml.XMLFormat; 031import javolution.xml.XMLSerializable; 032import javolution.xml.stream.XMLStreamException; 033import org.jscience.mathematics.number.Float64; 034import org.jscience.mathematics.vector.*; 035 036/** 037 * This class represents a 3 element {@link Vector vector} of Parameter elements sharing 038 * the same units. In geometrical terms, this vector represents a set of 3 Cartesian 039 * coordinates. 040 * 041 * <p> Modified by: Joseph A. Huwaldt </p> 042 * 043 * @author Joseph A. Huwaldt, Date: November 15, 2008 044 * @version October 30, 2015 045 * 046 * @param <Q> The Quantity (unit type, such as Length or Volume) of this vector. 047 */ 048public final class Vector3D<Q extends Quantity> extends Coordinate3D<Q> implements XMLSerializable { 049 050 private static final long serialVersionUID = -306965157071885706L; 051 052 /** 053 * Constant used to identify the X coordinate in the vector. 054 */ 055 public static final int X = 0; 056 057 /** 058 * Constant used to identify the Y coordinate in the vector. 059 */ 060 public static final int Y = 1; 061 062 /** 063 * Constant used to identify the Z coordinate in the vector. 064 */ 065 public static final int Z = 2; 066 067 /////////////////////// 068 // Factory creation. // 069 /////////////////////// 070 private Vector3D() { 071 } 072 073 private static final ObjectFactory<Vector3D> FACTORY = new ObjectFactory<Vector3D>() { 074 @Override 075 protected Vector3D create() { 076 return new Vector3D(); 077 } 078 }; 079 080 private static <Q extends Quantity> Vector3D<Q> newInstance(Unit<Q> unit) { 081 if (unit == null) 082 throw new NullPointerException("Unit can not be null."); 083 Vector3D<Q> measure = FACTORY.object(); 084 measure._unit = unit; 085 return measure; 086 } 087 088 private static <Q extends Quantity> Vector3D<Q> copyOf(Vector3D<Q> original) { 089 Vector3D<Q> measure = Vector3D.newInstance(original._unit); 090 measure._data = original._data.copy(); 091 return measure; 092 } 093 094 /** 095 * A Float64Vector with all the elements set to zero. 096 */ 097 private static final Float64Vector ZERO_F64VECTOR; 098 099 /** 100 * A dimensionless vector with all the elements set to zero. 101 */ 102 public static final Vector3D<Dimensionless> ZERO; 103 104 /** 105 * A position or length vector with all the elements set to zero. 106 */ 107 public static final Vector3D<Length> ZERO_POSITION; 108 109 /** 110 * A velocity vector with all the elements set to zero. 111 */ 112 public static final Vector3D<Velocity> ZERO_VELOCITY; 113 114 /** 115 * An acceleration vector with all the elements set to zero. 116 */ 117 public static final Vector3D<Acceleration> ZERO_ACCELERATION; 118 119 /** 120 * A force vector with all the elements set to zero. 121 */ 122 public static final Vector3D<Force> ZERO_FORCE; 123 124 /** 125 * A angle vector with all the elements set to zero. 126 */ 127 public static final Vector3D<Angle> ZERO_ANGLE; 128 129 /** 130 * A unit vector in the X axis direction. 131 */ 132 public static final Vector3D<Dimensionless> UNIT_X; 133 134 /** 135 * A unit vector in the Y axis direction. 136 */ 137 public static final Vector3D<Dimensionless> UNIT_Y; 138 139 /** 140 * A unit vector in the Z axis direction. 141 */ 142 public static final Vector3D<Dimensionless> UNIT_Z; 143 144 static { 145 // Forces constants to ImmortalMemory. 146 ImmortalContext.enter(); 147 try { 148 ZERO_F64VECTOR = Float64Vector.valueOf(0, 0, 0); 149 150 ZERO = Vector3D.newInstance(Dimensionless.UNIT); 151 ZERO._data = ZERO_F64VECTOR; 152 153 ZERO_POSITION = Vector3D.newInstance(Length.UNIT); 154 ZERO_POSITION._data = ZERO_F64VECTOR; 155 156 ZERO_VELOCITY = Vector3D.newInstance(Velocity.UNIT); 157 ZERO_VELOCITY._data = ZERO_F64VECTOR; 158 159 ZERO_ACCELERATION = Vector3D.newInstance(Acceleration.UNIT); 160 ZERO_ACCELERATION._data = ZERO_F64VECTOR; 161 162 ZERO_FORCE = Vector3D.newInstance(Force.UNIT); 163 ZERO_FORCE._data = ZERO_F64VECTOR; 164 165 ZERO_ANGLE = Vector3D.newInstance(Angle.UNIT); 166 ZERO_ANGLE._data = ZERO_F64VECTOR; 167 168 UNIT_X = Vector3D.newInstance(Dimensionless.UNIT); 169 UNIT_X._data = Float64Vector.valueOf(1, 0, 0); 170 171 UNIT_Y = Vector3D.newInstance(Dimensionless.UNIT); 172 UNIT_Y._data = Float64Vector.valueOf(0, 1, 0); 173 174 UNIT_Z = Vector3D.newInstance(Dimensionless.UNIT); 175 UNIT_Z._data = Float64Vector.valueOf(0, 0, 1); 176 177 } finally { 178 ImmortalContext.exit(); 179 } 180 } 181 182 /** 183 * The coordinates are stored in this vector. Serialization is handled by this class 184 * since Float64Vector is not Serializable. 185 */ 186 private transient Float64Vector _data; 187 188 /** 189 * Holds the unit of the coordinates. 190 */ 191 private Unit<Q> _unit; 192 193 /** 194 * Returns a {@link Vector3D} instance holding the specified <code>double</code> 195 * values stated in the specified units. 196 * 197 * @param <Q> the Quantity (unit type, e.g. Length or Volume) of this vector. 198 * @param x the x value stated in the specified unit. 199 * @param y the y value stated in the specified unit. 200 * @param z the z value stated in the specified unit. 201 * @param unit the unit in which the coordinates are stated. 202 * @return the vector having the specified values. 203 */ 204 public static <Q extends Quantity> Vector3D<Q> valueOf(double x, double y, double z, Unit<Q> unit) { 205 Vector3D<Q> V = Vector3D.newInstance(unit); 206 V._data = Float64Vector.valueOf(x, y, z); 207 208 return V; 209 } 210 211 /** 212 * Returns a {@link Vector3D} instance holding the specified <code>Parameter</code> 213 * values. All the values are converted to the same units as the x value. 214 * 215 * @param <Q> the Quantity (unit type, e.g. Length or Volume) of this vector. 216 * @param x the x value. 217 * @param y the y value. 218 * @param z the z value. 219 * @return the vector having the specified values in the units of x. 220 */ 221 public static <Q extends Quantity> Vector3D<Q> valueOf(Parameter<Q> x, Parameter<Q> y, Parameter<Q> z) { 222 223 Unit<Q> unit = x.getUnit(); 224 Vector3D<Q> V = Vector3D.newInstance(unit); 225 V._data = Float64Vector.valueOf(x.getValue(), y.getValue(unit), z.getValue(unit)); 226 227 return V; 228 } 229 230 /** 231 * Returns a {@link Vector3D} instance containing the specified vector of Float64 232 * values stated in the specified units. The vector must have only 3 elements. 233 * 234 * @param <Q> the Quantity (unit type, e.g. Length or Volume) of this vector. 235 * @param vector the vector of Float64 values stated in the specified unit (must have 236 * dimension of 3). 237 * @param unit the unit in which the coordinates are stated. 238 * @return the vector having the specified values. 239 */ 240 public static <Q extends Quantity> Vector3D<Q> valueOf(Vector<Float64> vector, Unit<Q> unit) { 241 if (vector.getDimension() != 3) 242 throw new DimensionException(RESOURCES.getString("v3dBadDimErr")); 243 244 Vector3D<Q> V = Vector3D.newInstance(unit); 245 V._data = Float64Vector.valueOf(vector); 246 247 return V; 248 } 249 250 /** 251 * Returns a {@link Vector3D} instance containing the specified vector of Parameter 252 * values with compatible units. The vector must have only 3 elements. All the values 253 * are converted to the same units as the 1st value. 254 * 255 * @param <Q> the Quantity (unit type, e.g. Length or Volume) of this vector. 256 * @param vector the vector of Parameter values (must have dimension of 3). 257 * @return the vector having the specified values. 258 */ 259 public static <Q extends Quantity> Vector3D<Q> valueOf(Vector<Parameter<Q>> vector) { 260 if (vector instanceof Vector3D) 261 return (Vector3D<Q>)vector; 262 263 if (vector.getDimension() != 3) 264 throw new DimensionException(RESOURCES.getString("v3dBadDimErr")); 265 266 return Vector3D.valueOf(vector.get(X), vector.get(Y), vector.get(Z)); 267 } 268 269 /** 270 * Return the specified {@link Vector3D} object as a <code>Vector3D</code> instance. 271 * 272 * @param vector The <code>Vector3D</code> object to be converted to a 273 * <code>Vector3D</code>. 274 * @return The input object is simply returned. 275 */ 276 @Override 277 public Vector3D<Q> fromVector3D(Vector3D<Q> vector) { 278 return vector; 279 } 280 281 /** 282 * Returns the value of a Parameter from this vector. 283 * 284 * @param i the dimension index. 285 * @return the value of the parameter at <code>i</code>. 286 * @throws IndexOutOfBoundsException <code>(i < 0) || (i > dimension()-1)</code> 287 */ 288 @Override 289 public Parameter<Q> get(int i) { 290 return Parameter.valueOf(getValue(i), getUnit()); 291 } 292 293 /** 294 * Returns the value of the Parameter in this vector as a <code>double</code>, stated 295 * in this vector's {@link #getUnit unit}. 296 * 297 * @param i the dimension index. 298 * @return the value of the Parameter at <code>i</code>. 299 * @throws IndexOutOfBoundsException <code>(i < 0) || (i > dimension()-1)</code> 300 */ 301 @Override 302 public double getValue(int i) { 303 return _data.getValue(i); 304 } 305 306 /** 307 * Returns the {@link #norm}, magnitude, or length value of this vector. 308 * 309 * @return <code>this.norm().doubleValue()</code>. 310 */ 311 @Override 312 public double normValue() { 313 return _data.normValue(); 314 } 315 316 /** 317 * Returns the negation of this vector. 318 * 319 * @return <code>-this</code>. 320 */ 321 @Override 322 public Vector3D<Q> opposite() { 323 Vector3D<Q> V = Vector3D.newInstance(this._unit); 324 V._data = this._data.opposite(); 325 return V; 326 } 327 328 /** 329 * Returns the sum of this vector with the one specified. The unit of the output 330 * vector will be the units of this vector. 331 * 332 * @param that the vector to be added. 333 * @return <code>this + that</code>. 334 * @throws DimensionException if vector dimensions are different. 335 */ 336 @Override 337 public Vector3D<Q> plus(Vector<Parameter<Q>> that) { 338 339 // Convert input vector to a Float64Vector (with unit conversion if necessary). 340 Float64Vector thatData = toFloat64Vector(that, this._unit); 341 342 Vector3D<Q> V = Vector3D.newInstance(this._unit); 343 V._data = this._data.plus(thatData); 344 345 return V; 346 } 347 348 /** 349 * Returns the sum of this vector with the parameter specified. The input parameter is 350 * added to each component of this vector. The unit of the output vector will be the 351 * units of this vector. 352 * 353 * @param that the parameter to be added to each element of this vector. 354 * @return <code>this + that</code>. 355 */ 356 @Override 357 public Vector3D<Q> plus(Parameter<Q> that) { 358 Vector3D<Q> V = Vector3D.newInstance(this._unit); 359 360 // Convert input parameter to the units of this vector. 361 double thatValue = that.getValue(this._unit); 362 double x = this._data.getValue(X) + thatValue; 363 double y = this._data.getValue(Y) + thatValue; 364 double z = this._data.getValue(Z) + thatValue; 365 V._data = Float64Vector.valueOf(x, y, z); 366 367 return V; 368 } 369 370 /** 371 * Returns the difference between this vector and the one specified. The unit of the 372 * output vector will be the units of this vector. 373 * 374 * @param that the vector to be subtracted. 375 * @return <code>this - that</code>. 376 */ 377 @Override 378 public Vector3D<Q> minus(Vector<Parameter<Q>> that) { 379 380 // Convert input vector to a Float64Vector (with unit conversion if necessary). 381 Float64Vector thatData = toFloat64Vector(that, this._unit); 382 383 Vector3D<Q> V = Vector3D.newInstance(this._unit); 384 V._data = this._data.minus(thatData); 385 386 return V; 387 } 388 389 /** 390 * Subtracts the supplied Parameter from each element of this vector and returns the 391 * result. The unit of the output vector will be the units of this vector. 392 * 393 * @param that the Parameter to be subtracted from each element of this vector. 394 * @return <code>this - that</code>. 395 */ 396 @Override 397 public Vector3D<Q> minus(Parameter<Q> that) { 398 Vector3D<Q> V = Vector3D.newInstance(this._unit); 399 400 // Convert input parameter to the units of this vector. 401 double thatValue = that.getValue(this._unit); 402 double x = this._data.getValue(X) - thatValue; 403 double y = this._data.getValue(Y) - thatValue; 404 double z = this._data.getValue(Z) - thatValue; 405 V._data = Float64Vector.valueOf(x, y, z); 406 407 return V; 408 } 409 410 /** 411 * Returns the product of this vector with the specified coefficient. 412 * 413 * @param k the coefficient multiplier. 414 * @return <code>this · k</code> 415 */ 416 @Override 417 public Vector3D times(Parameter k) { 418 419 Unit unit = Parameter.productOf(this.getUnit(), k.getUnit()); 420 Vector3D<?> V = Vector3D.newInstance(unit); 421 V._data = this._data.times(k.getValue()); 422 423 return V; 424 } 425 426 /** 427 * Returns the product of this vector with the specified coefficient. 428 * 429 * @param k the coefficient multiplier. 430 * @return <code>this · k</code> 431 */ 432 @Override 433 public Vector3D<Q> times(double k) { 434 Vector3D<Q> V = Vector3D.newInstance(this._unit); 435 V._data = _data.times(k); 436 return V; 437 } 438 439 /** 440 * Returns the dot product of this vector with the one specified. 441 * 442 * @param that the vector multiplier. 443 * @return <code>this · that</code> 444 * @throws DimensionException if <code>this.dimension() != that.dimension()</code> 445 * @see <a href="http://en.wikipedia.org/wiki/Dot_product"> 446 * Wikipedia: Dot Product</a> 447 */ 448 @Override 449 public Parameter times(Vector that) { 450 451 // Convert input vector to a Float64Vector. 452 Float64Vector thatData = toFloat64Vector(that, null); 453 454 Float64 f = this._data.times(thatData); 455 Unit<?> unit = Parameter.productOf(this.getUnit(), ((Parameter)that.get(X)).getUnit()); 456 457 return Parameter.valueOf(f.doubleValue(), unit); 458 } 459 460 /** 461 * Returns the element-by-element product of this vector with the one specified. 462 * 463 * @param that the vector multiplier. 464 * @return <code>this .* that</code> 465 * @throws DimensionException if <code>this.dimension() != that.dimension()</code> 466 */ 467 public Vector3D timesEBE(Vector that) { 468 469 // Convert input vector to a Float64Vector. 470 Float64Vector thatData = toFloat64Vector(that, null); 471 472 Unit<?> unit = Parameter.productOf(this.getUnit(), ((Parameter)that.get(X)).getUnit()); 473 474 // Carry out the multiplication. 475 double x = this._data.getValue(X) * thatData.getValue(X); 476 double y = this._data.getValue(Y) * thatData.getValue(Y); 477 double z = this._data.getValue(Z) * thatData.getValue(Z); 478 479 return Vector3D.valueOf(x, y, z, unit); 480 } 481 482 /** 483 * Returns this vector with each element divided by the specified divisor 484 * (dimensionless). 485 * 486 * @param divisor the divisor. 487 * @return <code>this / divisor</code>. 488 */ 489 @Override 490 public Vector3D<Q> divide(double divisor) { 491 return times(1. / divisor); 492 } 493 494 /** 495 * Returns the cross product of two 3-dimensional vectors. 496 * 497 * @param that the vector multiplier. 498 * @return <code>this x that</code> 499 * @throws DimensionException if <code>(that.getDimension() != 3)</code> 500 * @see <a href="http://en.wikipedia.org/wiki/Cross_product"> 501 * Wikipedia: Cross Product</a> 502 */ 503 @Override 504 public Vector3D cross(Vector that) { 505 506 // Convert input vector to a Float64Vector. 507 Float64Vector thatData = toFloat64Vector(that, null); 508 509 Unit unit = Parameter.productOf(this.getUnit(), ((Parameter)that.get(X)).getUnit()); 510 511 Vector3D V = Vector3D.newInstance(unit); 512 V._data = this._data.cross(thatData); 513 514 return V; 515 } 516 517 /** 518 * Returns this vector with each element divided by the specified divisor. 519 * 520 * @param that the divisor. 521 * @return <code>this / that</code>. 522 */ 523 public Vector3D<?> divide(Parameter<?> that) { 524 return (Vector3D<?>)times(that.inverse()); 525 } 526 527 /** 528 * Returns this vector converted to a unit vector by dividing all the vector's 529 * elements by the length ({@link #norm}) of this vector. 530 * 531 * @return this vector converted to a unit vector 532 */ 533 public Vector3D<Dimensionless> toUnitVector() { 534 double magnitude = this.normValue(); 535 if (this.getUnit().equals(Dimensionless.UNIT) && MathLib.abs(magnitude - 1) <= Parameter.EPS) 536 return (Vector3D<Dimensionless>)this; 537 538 Vector3D<Dimensionless> V = Vector3D.newInstance(Dimensionless.UNIT); 539 V._data = this._data.times(1.0 / magnitude); 540 return V; 541 } 542 543 /** 544 * Returns a copy of this vector {@link javolution.context.AllocatorContext allocated} 545 * by the calling thread (possibly on the stack). 546 * 547 * @return an identical and independent copy of this vector. 548 */ 549 @Override 550 public Vector3D<Q> copy() { 551 return copyOf(this); 552 } 553 554 /** 555 * Returns the unit in which the {@link #getValue values} in this vector are stated 556 * in. 557 * 558 * @return the unit in which the values in this vector are stated 559 */ 560 @Override 561 public Unit<Q> getUnit() { 562 return _unit; 563 } 564 565 /** 566 * Returns the equivalent to this vector but stated in the specified unit. 567 * 568 * @param <R> the Quantity (unit type, e.g. Length or Volume) of the returned vector. 569 * @param unit the unit of the vector to be returned. 570 * @return a vector equivalent to this vector but stated in the specified unit. 571 * @throws ConversionException if the current model does not allows for conversion to 572 * the specified unit. 573 */ 574 @Override 575 public <R extends Quantity> Vector3D<R> to(Unit<R> unit) throws ConversionException { 576 if ((_unit == unit) || this._unit.equals(unit)) 577 return (Vector3D<R>)this; 578 579 UnitConverter cvtr = Parameter.converterOf(_unit, unit); 580 if (cvtr == UnitConverter.IDENTITY) { // No conversion necessary. 581 Vector3D<R> result = (Vector3D<R>)Vector3D.copyOf(this); 582 result._unit = unit; 583 return result; 584 } 585 Vector3D<R> result = Vector3D.newInstance(unit); 586 double x = cvtr.convert(_data.getValue(X)); 587 double y = cvtr.convert(_data.getValue(Y)); 588 double z = cvtr.convert(_data.getValue(Z)); 589 result._data = Float64Vector.valueOf(x, y, z); 590 591 return result; 592 } 593 594 /** 595 * Casts this Vector3D to a parameterized unit of specified nature or throw a 596 * <code>ClassCastException</code> if the dimension of the specified quantity and this 597 * parameter's unit dimension do not match. 598 * 599 * @param <T> the Quantity (unit type, e.g. Length or Volume) of the returned vector. 600 * @param type the quantity class identifying the nature of the unit. 601 * @return this Vector3D parameterized with the specified type. 602 * @throws ClassCastException if the dimension of this parameter's unit is different 603 * from the specified quantity dimension. 604 * @throws UnsupportedOperationException if the specified quantity class does not have 605 * a public static field named "UNIT" holding the standard unit for the quantity. 606 */ 607 @Override 608 public <T extends Quantity> Vector3D<T> asType(Class<T> type) throws ClassCastException { 609 Unit<T> u = _unit.asType(type); // If no exception is thrown, the cast is valid. 610 return (Vector3D<T>)this; 611 } 612 613 /** 614 * Returns a Cartesian Vector3D representation of this vector. 615 * 616 * @return a Cartesian Vector3D representation of this vector 617 */ 618 @Override 619 public Vector3D<Q> toVector3D() { 620 return this; 621 } 622 623 /** 624 * Returns double the values stored in this vector, stated in this vector's 625 * {@link #getUnit unit}, as a Float64Vector. 626 * 627 * @return the values stored in this vector as a Float64Vector 628 */ 629 public Float64Vector toFloat64Vector() { 630 return _data; 631 } 632 633 /** 634 * Returns a 3x3 skew-symmetric matrix representation of the values in this vector 635 * stated in this vector's {@link #getUnit unit}. 636 * <p> 637 * A skew symmetric representation of a vector is defined by: 638 * <pre> 639 * | 0 -c b| |a| 640 * | c 0 -a| <-- |b| 641 * |-b a 0| |c| 642 * </pre></p> 643 * 644 * @return a 3x3 skew-symmetric matrix representation of the values in this vector 645 */ 646 public Matrix3D<Q> toSkewSymmetric() { 647 return makeSkewSymmetric(_data.getValue(X), _data.getValue(Y), _data.getValue(Z), _unit); 648 } 649 650 /** 651 * Returns a 3x3 skew-symmetric matrix representation of the values in the input 3D 652 * vector stated in the specified units. 653 * <p> 654 * A skew symmetric representation of a vector is defined by: 655 * <pre> 656 * | 0 -c b| |a| 657 * | c 0 -a| <-- |b| 658 * |-b a 0| |c| 659 * </pre></p> 660 * 661 * <p> 662 * This is a more efficient convenience method equivalent to: 663 * <code>Vector3D.valueOf(a, b, c, Dimensionless.UNIT).toSkewSymmetric();</code></p> 664 * 665 * @param <R> the Quantity (unit type, e.g. Length or Volume) of the returned matrix. 666 * @param a The 1st element of the 3D vector 667 * @param b The 2nd element of the 3D vector 668 * @param c The 3rd element of the 3D vector 669 * @param unit The unit that the elements are stated in. 670 * @return a 3x3 skew-symmetric matrix representation of the values in the input 3D 671 * vector. 672 */ 673 public static <R extends Quantity> Matrix3D<R> makeSkewSymmetric(double a, double b, double c, Unit<R> unit) { 674 Float64Vector row1 = Float64Vector.valueOf(0, -c, b); 675 Float64Vector row2 = Float64Vector.valueOf(c, 0, -a); 676 Float64Vector row3 = Float64Vector.valueOf(-b, a, 0); 677 678 return Matrix3D.valueOf(row1, row2, row3, unit); 679 } 680 681 /** 682 * Compares this Vector3D against the specified object for strict equality (same 683 * values and same units). 684 * 685 * @param obj the object to compare with. 686 * @return <code>true</code> if this vector is identical to that vector; 687 * <code>false</code> otherwise. 688 */ 689 @Override 690 public boolean equals(Object obj) { 691 if (this == obj) 692 return true; 693 if ((obj == null) || (obj.getClass() != this.getClass())) 694 return false; 695 696 Vector3D<?> that = (Vector3D<?>)obj; 697 if (!this._data.equals(that._data)) 698 return false; 699 700 return this._unit.equals(that._unit); 701 } 702 703 /** 704 * Returns the hash code for this parameter. 705 * 706 * @return the hash code value. 707 */ 708 @Override 709 public int hashCode() { 710 int hash = 7; 711 712 int var_code = _unit.hashCode(); 713 hash = hash * 31 + var_code; 714 715 var_code = _data.hashCode(); 716 hash = hash * 31 + var_code; 717 718 return hash; 719 } 720 721 /** 722 * Convert a vector of Parameter objects to a Float64Vector stated in the specified 723 * units. If the units are null, no conversion occurs. 724 */ 725 private <Q extends Quantity> Float64Vector toFloat64Vector(Vector<Parameter<Q>> that, Unit<Q> unit) { 726 727 // Make sure input is a Vector3D instance. 728 if (!(that instanceof Coordinate3D)) 729 throw new ClassCastException(RESOURCES.getString("notCoordinate3D")); 730 731 Vector3D<Q> T = ((Coordinate3D<Q>)that).toVector3D(); // Convert to a Vector3D. 732 733 // Convert that vector's units to the specified units if necessary. 734 Float64Vector thatData = T._data; 735 if (unit != null) { 736 if ((unit != T._unit) && !unit.equals(T._unit)) { 737 UnitConverter cvtr = Parameter.converterOf(T._unit, unit); 738 if (cvtr != UnitConverter.IDENTITY) { 739 double x = cvtr.convert(thatData.getValue(X)); 740 double y = cvtr.convert(thatData.getValue(Y)); 741 double z = cvtr.convert(thatData.getValue(Z)); 742 thatData = Float64Vector.valueOf(x, y, z); 743 } 744 } 745 } 746 747 return thatData; 748 } 749 750 /** 751 * During serialization, this will write out the Float64Vector as a simple series of 752 * <code>double</code> values. This method is ONLY called by the Java Serialization 753 * mechanism and should not otherwise be used. 754 */ 755 private void writeObject(java.io.ObjectOutputStream out) throws java.io.IOException { 756 757 // Call the default write object method. 758 out.defaultWriteObject(); 759 760 // Write out the three coordinate values. 761 out.writeDouble(_data.getValue(X)); 762 out.writeDouble(_data.getValue(Y)); 763 out.writeDouble(_data.getValue(Z)); 764 765 } 766 767 /** 768 * During de-serialization, this will handle the reconstruction of the Float64Vector. 769 * This method is ONLY called by the Java Serialization mechanism and should not 770 * otherwise be used. 771 */ 772 private void readObject(java.io.ObjectInputStream in) throws java.io.IOException, ClassNotFoundException { 773 774 // Call the default read object method. 775 in.defaultReadObject(); 776 777 // Read in the three coordinate values. 778 double x = in.readDouble(); 779 double y = in.readDouble(); 780 double z = in.readDouble(); 781 782 _data = Float64Vector.valueOf(x, y, z); 783 784 } 785 786 /** 787 * Holds the default XML representation. For example: 788 * <pre> 789 * <Vector3D unit = "m"> 790 * <X value="1.0" /> 791 * <Y value="0.0" /> 792 * <Z value="2.0" /> 793 * </Vector3D> 794 * </pre> 795 */ 796 protected static final XMLFormat<Vector3D> XML = new XMLFormat<Vector3D>(Vector3D.class) { 797 798 @Override 799 public Vector3D<?> newInstance(Class<Vector3D> cls, InputElement xml) throws XMLStreamException { 800 return FACTORY.object(); 801 } 802 803 @Override 804 public void read(InputElement xml, Vector3D V) throws XMLStreamException { 805 806 V._unit = Unit.valueOf(xml.getAttribute("unit")); 807 Float64 x = xml.get("X", Float64.class); 808 Float64 y = xml.get("Y", Float64.class); 809 Float64 z = xml.get("Z", Float64.class); 810 V._data = Float64Vector.valueOf(x.doubleValue(), y.doubleValue(), z.doubleValue()); 811 812 if (xml.hasNext()) 813 throw new XMLStreamException(RESOURCES.getString("toManyXMLElementsErr")); 814 } 815 816 @Override 817 public void write(Vector3D V, OutputElement xml) throws XMLStreamException { 818 819 xml.setAttribute("unit", V._unit.toString()); 820 xml.add(V._data.get(X), "X", Float64.class); 821 xml.add(V._data.get(Y), "Y", Float64.class); 822 xml.add(V._data.get(Z), "Z", Float64.class); 823 824 } 825 }; 826 827 /** 828 * Tests the methods in this class. 829 * 830 * @param args Command line arguments (ignored). 831 */ 832 public static void main(String args[]) { 833 System.out.println("Testing Vector3D: test = result [correct result]"); 834 835 Vector3D<Length> v1 = Vector3D.valueOf(1, 2, 3, NonSI.FOOT); 836 System.out.println("v1 = " + v1); 837 System.out.println(" converted to m = " + v1.to(SI.METER) + " [{0.3048 m, 0.6096 m, 0.9144 m}]"); 838 System.out.println(" v1.norm() = " + v1.norm() + " [3.74165738677394 ft]"); 839 System.out.println(" v1.opposite() = " + v1.opposite() + " [{-1.0 ft, -2.0 ft, -3.0 ft}]"); 840 System.out.println(" v1.toUnitVector() = " + v1.toUnitVector() + " [{0.267261241912424 , 0.534522483824849 , 0.801783725737273 }]"); 841 System.out.println(" v1.toSkewSymmetric() = \n" + v1.toSkewSymmetric()); 842 843 Parameter<Length> point = Parameter.valueOf(24, NonSI.INCH); 844 System.out.println("point = " + point); 845 System.out.println(" v1 + point = " + v1.plus(point) + " [{3.0 ft, 4.0 ft, 5.0 ft}]"); 846 System.out.println(" v1 - point = " + v1.minus(point) + " [{-1.0 ft, 0.0 ft, 1.0 ft}]"); 847 System.out.println(" v1 * 2 = " + v1.times(2) + " [{2.0 ft, 4.0 ft, 6.0 ft}]"); 848 849 Vector3D<?> areaVector = (Vector3D<?>)v1.times(point); 850 System.out.println(" v1 * point = " + areaVector); 851 System.out.println(" converted to ft² = " + areaVector.to(NonSI.SQUARE_FOOT) + " [{2.0 ft², 4.0 ft², 6.0 ft²}]"); 852 853 Vector3D<Length> v2 = Vector3D.valueOf(1, 1, 1, SI.METER); 854 Vector3D<?> v1xv2 = (Vector3D<?>)v1.cross(v2); 855 System.out.println("v2 = " + v2); 856 System.out.println(" v1 + v2 = " + v1.plus(v2) + " [{4.28083989501312 ft, 5.28083989501312 ft, 6.28083989501312 ft}]"); 857 System.out.println(" v1 - v2 = " + v1.minus(v2) + " [{-2.28083989501312 ft, -1.28083989501312 ft, -0.280839895013123 ft}]"); 858 System.out.println(" v1 · v2 = " + v1.times(v2.to(NonSI.FOOT)) + " [19.6850393700787 ft²]"); 859 System.out.println(" v1.cross(v2) = " + v1xv2.to(NonSI.FOOT.pow(2)) + " [{-3.28083989501312 ft^2, 6.56167979002625 ft^2, -3.28083989501312 ft^2}]"); 860 System.out.println(" v1.angle(v2) = " + v1.angle(v2).to(NonSI.DEGREE_ANGLE) + " [73.6090476746643 deg]"); 861 862 // Write out XML data. 863 try { 864 System.out.println(); 865 866 // Creates some useful aliases for class names. 867 javolution.xml.XMLBinding binding = new javolution.xml.XMLBinding(); 868 binding.setAlias(org.jscience.mathematics.number.Float64.class, "Float64"); 869 binding.setAlias(org.jscience.mathematics.vector.Float64Matrix.class, "Float64Matrix"); 870 871 javolution.xml.XMLObjectWriter writer = javolution.xml.XMLObjectWriter.newInstance(System.out); 872 writer.setIndentation(" "); 873 writer.setBinding(binding); 874 writer.write(v1, "Vector3D", Vector3D.class); 875 writer.flush(); 876 877 System.out.println(); 878 } catch (Exception e) { 879 e.printStackTrace(); 880 } 881 882 } 883}