001/** 002 * Vector3D -- A three element vector of Parameter objects that may represent a Cartesian 003 * coordinate. 004 * 005 * Copyright (C) 2008-2025, 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 February 23, 2025 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 @SuppressWarnings("null") 260 public static <Q extends Quantity> Vector3D<Q> valueOf(Vector<Parameter<Q>> vector) { 261 if (vector instanceof Vector3D) 262 return (Vector3D<Q>)vector; 263 264 if (vector.getDimension() != 3) 265 throw new DimensionException(RESOURCES.getString("v3dBadDimErr")); 266 267 return Vector3D.valueOf(vector.get(X), vector.get(Y), vector.get(Z)); 268 } 269 270 /** 271 * Return the specified {@link Vector3D} object as a <code>Vector3D</code> instance. 272 * 273 * @param vector The <code>Vector3D</code> object to be converted to a 274 * <code>Vector3D</code>. 275 * @return The input object is simply returned. 276 */ 277 @Override 278 public Vector3D<Q> fromVector3D(Vector3D<Q> vector) { 279 return vector; 280 } 281 282 /** 283 * Returns the value of a Parameter from this vector. 284 * 285 * @param i the dimension index. 286 * @return the value of the parameter at <code>i</code>. 287 * @throws IndexOutOfBoundsException <code>(i < 0) || (i > dimension()-1)</code> 288 */ 289 @Override 290 public Parameter<Q> get(int i) { 291 return Parameter.valueOf(getValue(i), getUnit()); 292 } 293 294 /** 295 * Returns the value of the Parameter in this vector as a <code>double</code>, stated 296 * in this vector's {@link #getUnit unit}. 297 * 298 * @param i the dimension index. 299 * @return the value of the Parameter at <code>i</code>. 300 * @throws IndexOutOfBoundsException <code>(i < 0) || (i > dimension()-1)</code> 301 */ 302 @Override 303 public double getValue(int i) { 304 return _data.getValue(i); 305 } 306 307 /** 308 * Returns the {@link #norm}, magnitude, or length value of this vector. 309 * 310 * @return <code>this.norm().doubleValue()</code>. 311 */ 312 @Override 313 public double normValue() { 314 return _data.normValue(); 315 } 316 317 /** 318 * Returns the negation of this vector. 319 * 320 * @return <code>-this</code>. 321 */ 322 @Override 323 public Vector3D<Q> opposite() { 324 Vector3D<Q> V = Vector3D.newInstance(this._unit); 325 V._data = this._data.opposite(); 326 return V; 327 } 328 329 /** 330 * Returns the sum of this vector with the one specified. The unit of the output 331 * vector will be the units of this vector. 332 * 333 * @param that the vector to be added. 334 * @return <code>this + that</code>. 335 * @throws DimensionException if vector dimensions are different. 336 */ 337 @Override 338 public Vector3D<Q> plus(Vector<Parameter<Q>> that) { 339 340 // Convert input vector to a Float64Vector (with unit conversion if necessary). 341 Float64Vector thatData = toFloat64Vector(that, this._unit); 342 343 Vector3D<Q> V = Vector3D.newInstance(this._unit); 344 V._data = this._data.plus(thatData); 345 346 return V; 347 } 348 349 /** 350 * Returns the sum of this vector with the parameter specified. The input parameter is 351 * added to each component of this vector. The unit of the output vector will be the 352 * units of this vector. 353 * 354 * @param that the parameter to be added to each element of this vector. 355 * @return <code>this + that</code>. 356 */ 357 @Override 358 public Vector3D<Q> plus(Parameter<Q> that) { 359 Vector3D<Q> V = Vector3D.newInstance(this._unit); 360 361 // Convert input parameter to the units of this vector. 362 double thatValue = that.getValue(this._unit); 363 double x = this._data.getValue(X) + thatValue; 364 double y = this._data.getValue(Y) + thatValue; 365 double z = this._data.getValue(Z) + thatValue; 366 V._data = Float64Vector.valueOf(x, y, z); 367 368 return V; 369 } 370 371 /** 372 * Returns the difference between this vector and the one specified. The unit of the 373 * output vector will be the units of this vector. 374 * 375 * @param that the vector to be subtracted. 376 * @return <code>this - that</code>. 377 */ 378 @Override 379 public Vector3D<Q> minus(Vector<Parameter<Q>> that) { 380 381 // Convert input vector to a Float64Vector (with unit conversion if necessary). 382 Float64Vector thatData = toFloat64Vector(that, this._unit); 383 384 Vector3D<Q> V = Vector3D.newInstance(this._unit); 385 V._data = this._data.minus(thatData); 386 387 return V; 388 } 389 390 /** 391 * Subtracts the supplied Parameter from each element of this vector and returns the 392 * result. The unit of the output vector will be the units of this vector. 393 * 394 * @param that the Parameter to be subtracted from each element of this vector. 395 * @return <code>this - that</code>. 396 */ 397 @Override 398 public Vector3D<Q> minus(Parameter<Q> that) { 399 Vector3D<Q> V = Vector3D.newInstance(this._unit); 400 401 // Convert input parameter to the units of this vector. 402 double thatValue = that.getValue(this._unit); 403 double x = this._data.getValue(X) - thatValue; 404 double y = this._data.getValue(Y) - thatValue; 405 double z = this._data.getValue(Z) - thatValue; 406 V._data = Float64Vector.valueOf(x, y, z); 407 408 return V; 409 } 410 411 /** 412 * Returns the product of this vector with the specified coefficient. 413 * 414 * @param k the coefficient multiplier. 415 * @return <code>this · k</code> 416 */ 417 @Override 418 public Vector3D times(Parameter k) { 419 420 Unit unit = Parameter.productOf(this.getUnit(), k.getUnit()); 421 Vector3D<?> V = Vector3D.newInstance(unit); 422 V._data = this._data.times(k.getValue()); 423 424 return V; 425 } 426 427 /** 428 * Returns the product of this vector with the specified coefficient. 429 * 430 * @param k the coefficient multiplier. 431 * @return <code>this · k</code> 432 */ 433 @Override 434 public Vector3D<Q> times(double k) { 435 Vector3D<Q> V = Vector3D.newInstance(this._unit); 436 V._data = _data.times(k); 437 return V; 438 } 439 440 /** 441 * Returns the dot product of this vector with the one specified. 442 * 443 * @param that the vector multiplier. 444 * @return <code>this · that</code> 445 * @throws DimensionException if <code>this.dimension() != that.dimension()</code> 446 * @see <a href="http://en.wikipedia.org/wiki/Dot_product"> 447 * Wikipedia: Dot Product</a> 448 */ 449 @Override 450 public Parameter times(Vector that) { 451 452 // Convert input vector to a Float64Vector. 453 Float64Vector thatData = toFloat64Vector(that, null); 454 455 Float64 f = this._data.times(thatData); 456 Unit<?> unit = Parameter.productOf(this.getUnit(), ((Parameter)that.get(X)).getUnit()); 457 458 return Parameter.valueOf(f.doubleValue(), unit); 459 } 460 461 /** 462 * Returns the element-by-element product of this vector with the one specified. 463 * 464 * @param that the vector multiplier. 465 * @return <code>this .* that</code> 466 * @throws DimensionException if <code>this.dimension() != that.dimension()</code> 467 */ 468 public Vector3D timesEBE(Vector that) { 469 470 // Convert input vector to a Float64Vector. 471 Float64Vector thatData = toFloat64Vector(that, null); 472 473 Unit<?> unit = Parameter.productOf(this.getUnit(), ((Parameter)that.get(X)).getUnit()); 474 475 // Carry out the multiplication. 476 double x = this._data.getValue(X) * thatData.getValue(X); 477 double y = this._data.getValue(Y) * thatData.getValue(Y); 478 double z = this._data.getValue(Z) * thatData.getValue(Z); 479 480 return Vector3D.valueOf(x, y, z, unit); 481 } 482 483 /** 484 * Returns this vector with each element divided by the specified divisor 485 * (dimensionless). 486 * 487 * @param divisor the divisor. 488 * @return <code>this / divisor</code>. 489 */ 490 @Override 491 public Vector3D<Q> divide(double divisor) { 492 return times(1. / divisor); 493 } 494 495 /** 496 * Returns the cross product of two 3-dimensional vectors. 497 * 498 * @param that the vector multiplier. 499 * @return <code>this x that</code> 500 * @throws DimensionException if <code>(that.getDimension() != 3)</code> 501 * @see <a href="http://en.wikipedia.org/wiki/Cross_product"> 502 * Wikipedia: Cross Product</a> 503 */ 504 @Override 505 public Vector3D cross(Vector that) { 506 507 // Convert input vector to a Float64Vector. 508 Float64Vector thatData = toFloat64Vector(that, null); 509 510 Unit unit = Parameter.productOf(this.getUnit(), ((Parameter)that.get(X)).getUnit()); 511 512 Vector3D V = Vector3D.newInstance(unit); 513 V._data = this._data.cross(thatData); 514 515 return V; 516 } 517 518 /** 519 * Returns this vector with each element divided by the specified divisor. 520 * 521 * @param that the divisor. 522 * @return <code>this / that</code>. 523 */ 524 public Vector3D<?> divide(Parameter<?> that) { 525 return (Vector3D<?>)times(that.inverse()); 526 } 527 528 /** 529 * Returns this vector converted to a unit vector by dividing all the vector's 530 * elements by the length ({@link #norm}) of this vector. 531 * 532 * @return this vector converted to a unit vector 533 */ 534 @Override 535 public Vector3D<Dimensionless> toUnitVector() { 536 double magnitude = this.normValue(); 537 if (this.getUnit().equals(Dimensionless.UNIT) && MathLib.abs(magnitude - 1) <= Parameter.EPS) 538 return (Vector3D<Dimensionless>)this; 539 540 Vector3D<Dimensionless> V = Vector3D.newInstance(Dimensionless.UNIT); 541 V._data = this._data.times(1.0 / magnitude); 542 return V; 543 } 544 545 /** 546 * Returns a copy of this vector {@link javolution.context.AllocatorContext allocated} 547 * by the calling thread (possibly on the stack). 548 * 549 * @return an identical and independent copy of this vector. 550 */ 551 @Override 552 public Vector3D<Q> copy() { 553 return copyOf(this); 554 } 555 556 /** 557 * Returns the unit in which the {@link #getValue values} in this vector are stated 558 * in. 559 * 560 * @return the unit in which the values in this vector are stated 561 */ 562 @Override 563 public Unit<Q> getUnit() { 564 return _unit; 565 } 566 567 /** 568 * Returns the equivalent to this vector but stated in the specified unit. 569 * 570 * @param <R> the Quantity (unit type, e.g. Length or Volume) of the returned vector. 571 * @param unit the unit of the vector to be returned. 572 * @return a vector equivalent to this vector but stated in the specified unit. 573 * @throws ConversionException if the current model does not allows for conversion to 574 * the specified unit. 575 */ 576 @Override 577 public <R extends Quantity> Vector3D<R> to(Unit<R> unit) throws ConversionException { 578 if ((_unit == unit) || this._unit.equals(unit)) 579 return (Vector3D<R>)this; 580 581 UnitConverter cvtr = Parameter.converterOf(_unit, unit); 582 if (cvtr == UnitConverter.IDENTITY) { // No conversion necessary. 583 Vector3D<R> result = (Vector3D<R>)Vector3D.copyOf(this); 584 result._unit = unit; 585 return result; 586 } 587 Vector3D<R> result = Vector3D.newInstance(unit); 588 double x = cvtr.convert(_data.getValue(X)); 589 double y = cvtr.convert(_data.getValue(Y)); 590 double z = cvtr.convert(_data.getValue(Z)); 591 result._data = Float64Vector.valueOf(x, y, z); 592 593 return result; 594 } 595 596 /** 597 * Casts this Vector3D to a parameterized unit of specified nature or throw a 598 * <code>ClassCastException</code> if the dimension of the specified quantity and this 599 * parameter's unit dimension do not match. 600 * 601 * @param <T> the Quantity (unit type, e.g. Length or Volume) of the returned vector. 602 * @param type the quantity class identifying the nature of the unit. 603 * @return this Vector3D parameterized with the specified type. 604 * @throws ClassCastException if the dimension of this parameter's unit is different 605 * from the specified quantity dimension. 606 * @throws UnsupportedOperationException if the specified quantity class does not have 607 * a public static field named "UNIT" holding the standard unit for the quantity. 608 */ 609 @Override 610 public <T extends Quantity> Vector3D<T> asType(Class<T> type) throws ClassCastException { 611 _unit.asType(type); // If no exception is thrown, the cast is valid. 612 return (Vector3D<T>)this; 613 } 614 615 /** 616 * Returns a Cartesian Vector3D representation of this vector. 617 * 618 * @return a Cartesian Vector3D representation of this vector 619 */ 620 @Override 621 public Vector3D<Q> toVector3D() { 622 return this; 623 } 624 625 /** 626 * Returns double the values stored in this vector, stated in this vector's 627 * {@link #getUnit unit}, as a Float64Vector. 628 * 629 * @return the values stored in this vector as a Float64Vector 630 */ 631 public Float64Vector toFloat64Vector() { 632 return _data; 633 } 634 635 /** 636 * Returns a 3x3 skew-symmetric matrix representation of the values in this vector 637 * stated in this vector's {@link #getUnit unit}. 638 * <p> 639 * A skew symmetric representation of a vector is defined by: 640 * <pre> 641 * | 0 -c b| |a| 642 * | c 0 -a| <-- |b| 643 * |-b a 0| |c| 644 * </pre></p> 645 * 646 * @return a 3x3 skew-symmetric matrix representation of the values in this vector 647 */ 648 public Matrix3D<Q> toSkewSymmetric() { 649 return makeSkewSymmetric(_data.getValue(X), _data.getValue(Y), _data.getValue(Z), _unit); 650 } 651 652 /** 653 * Returns a 3x3 skew-symmetric matrix representation of the values in the input 3D 654 * vector stated in the specified units. 655 * <p> 656 * A skew symmetric representation of a vector is defined by: 657 * <pre> 658 * | 0 -c b| |a| 659 * | c 0 -a| <-- |b| 660 * |-b a 0| |c| 661 * </pre></p> 662 * 663 * <p> 664 * This is a more efficient convenience method equivalent to: 665 * <code>Vector3D.valueOf(a, b, c, Dimensionless.UNIT).toSkewSymmetric();</code></p> 666 * 667 * @param <R> the Quantity (unit type, e.g. Length or Volume) of the returned matrix. 668 * @param a The 1st element of the 3D vector 669 * @param b The 2nd element of the 3D vector 670 * @param c The 3rd element of the 3D vector 671 * @param unit The unit that the elements are stated in. 672 * @return a 3x3 skew-symmetric matrix representation of the values in the input 3D 673 * vector. 674 */ 675 public static <R extends Quantity> Matrix3D<R> makeSkewSymmetric(double a, double b, double c, Unit<R> unit) { 676 Float64Vector row1 = Float64Vector.valueOf(0, -c, b); 677 Float64Vector row2 = Float64Vector.valueOf(c, 0, -a); 678 Float64Vector row3 = Float64Vector.valueOf(-b, a, 0); 679 680 return Matrix3D.valueOf(row1, row2, row3, unit); 681 } 682 683 /** 684 * Compares this Vector3D against the specified object for strict equality (same 685 * values and same units). 686 * 687 * @param obj the object to compare with. 688 * @return <code>true</code> if this vector is identical to that vector; 689 * <code>false</code> otherwise. 690 */ 691 @Override 692 public boolean equals(Object obj) { 693 if (this == obj) 694 return true; 695 if ((obj == null) || (obj.getClass() != this.getClass())) 696 return false; 697 698 Vector3D<?> that = (Vector3D<?>)obj; 699 if (!this._data.equals(that._data)) 700 return false; 701 702 return this._unit.equals(that._unit); 703 } 704 705 /** 706 * Returns the hash code for this parameter. 707 * 708 * @return the hash code value. 709 */ 710 @Override 711 public int hashCode() { 712 int hash = 7; 713 714 int var_code = _unit.hashCode(); 715 hash = hash * 31 + var_code; 716 717 var_code = _data.hashCode(); 718 hash = hash * 31 + var_code; 719 720 return hash; 721 } 722 723 /** 724 * Convert a vector of Parameter objects to a Float64Vector stated in the specified 725 * units. If the units are null, no conversion occurs. 726 */ 727 private <Q extends Quantity> Float64Vector toFloat64Vector(Vector<Parameter<Q>> that, Unit<Q> unit) { 728 729 // Make sure input is a Vector3D instance. 730 if (!(that instanceof Coordinate3D)) 731 throw new ClassCastException(RESOURCES.getString("notCoordinate3D")); 732 733 Vector3D<Q> T = ((Coordinate3D<Q>)that).toVector3D(); // Convert to a Vector3D. 734 735 // Convert that vector's units to the specified units if necessary. 736 Float64Vector thatData = T._data; 737 if (unit != null) { 738 if ((unit != T._unit) && !unit.equals(T._unit)) { 739 UnitConverter cvtr = Parameter.converterOf(T._unit, unit); 740 if (cvtr != UnitConverter.IDENTITY) { 741 double x = cvtr.convert(thatData.getValue(X)); 742 double y = cvtr.convert(thatData.getValue(Y)); 743 double z = cvtr.convert(thatData.getValue(Z)); 744 thatData = Float64Vector.valueOf(x, y, z); 745 } 746 } 747 } 748 749 return thatData; 750 } 751 752 /** 753 * During serialization, this will write out the Float64Vector as a simple series of 754 * <code>double</code> values. This method is ONLY called by the Java Serialization 755 * mechanism and should not otherwise be used. 756 * 757 * @param out The output stream to serialized this object to. 758 * @throws java.io.IOException if the output stream could not be written to. 759 */ 760 private void writeObject(java.io.ObjectOutputStream out) throws java.io.IOException { 761 762 // Call the default write object method. 763 out.defaultWriteObject(); 764 765 // Write out the three coordinate values. 766 out.writeDouble(_data.getValue(X)); 767 out.writeDouble(_data.getValue(Y)); 768 out.writeDouble(_data.getValue(Z)); 769 770 } 771 772 /** 773 * During de-serialization, this will handle the reconstruction of the Float64Vector. 774 * This method is ONLY called by the Java Serialization mechanism and should not 775 * otherwise be used. 776 * 777 * @param in The input stream to be de-serialized 778 * @throws java.io.IOException if there is a problem reading from the input stream. 779 * @throws ClassNotFoundException if the class could not be constructed. 780 */ 781 private void readObject(java.io.ObjectInputStream in) throws java.io.IOException, ClassNotFoundException { 782 783 // Call the default read object method. 784 in.defaultReadObject(); 785 786 // Read in the three coordinate values. 787 double x = in.readDouble(); 788 double y = in.readDouble(); 789 double z = in.readDouble(); 790 791 _data = Float64Vector.valueOf(x, y, z); 792 793 } 794 795 /** 796 * Holds the default XML representation. For example: 797 * <pre> 798 * <Vector3D unit = "m"> 799 * <X value="1.0" /> 800 * <Y value="0.0" /> 801 * <Z value="2.0" /> 802 * </Vector3D> 803 * </pre> 804 */ 805 protected static final XMLFormat<Vector3D> XML = new XMLFormat<Vector3D>(Vector3D.class) { 806 807 @Override 808 public Vector3D<?> newInstance(Class<Vector3D> cls, InputElement xml) throws XMLStreamException { 809 return FACTORY.object(); 810 } 811 812 @Override 813 public void read(InputElement xml, Vector3D V) throws XMLStreamException { 814 815 V._unit = Unit.valueOf(xml.getAttribute("unit")); 816 Float64 x = xml.get("X", Float64.class); 817 Float64 y = xml.get("Y", Float64.class); 818 Float64 z = xml.get("Z", Float64.class); 819 V._data = Float64Vector.valueOf(x.doubleValue(), y.doubleValue(), z.doubleValue()); 820 821 if (xml.hasNext()) 822 throw new XMLStreamException(RESOURCES.getString("toManyXMLElementsErr")); 823 } 824 825 @Override 826 public void write(Vector3D V, OutputElement xml) throws XMLStreamException { 827 828 xml.setAttribute("unit", V._unit.toString()); 829 xml.add(V._data.get(X), "X", Float64.class); 830 xml.add(V._data.get(Y), "Y", Float64.class); 831 xml.add(V._data.get(Z), "Z", Float64.class); 832 833 } 834 }; 835 836 /** 837 * Tests the methods in this class. 838 * 839 * @param args Command line arguments (ignored). 840 */ 841 public static void main(String args[]) { 842 System.out.println("Testing Vector3D: test = result [correct result]"); 843 844 Vector3D<Length> v1 = Vector3D.valueOf(1, 2, 3, NonSI.FOOT); 845 System.out.println("v1 = " + v1); 846 System.out.println(" converted to m = " + v1.to(SI.METER) + " [{0.3048 m, 0.6096 m, 0.9144 m}]"); 847 System.out.println(" v1.norm() = " + v1.norm() + " [3.74165738677394 ft]"); 848 System.out.println(" v1.opposite() = " + v1.opposite() + " [{-1.0 ft, -2.0 ft, -3.0 ft}]"); 849 System.out.println(" v1.toUnitVector() = " + v1.toUnitVector() + " [{0.267261241912424 , 0.534522483824849 , 0.801783725737273 }]"); 850 System.out.println(" v1.toSkewSymmetric() = \n" + v1.toSkewSymmetric()); 851 852 Parameter<Length> point = Parameter.valueOf(24, NonSI.INCH); 853 System.out.println("point = " + point); 854 System.out.println(" v1 + point = " + v1.plus(point) + " [{3.0 ft, 4.0 ft, 5.0 ft}]"); 855 System.out.println(" v1 - point = " + v1.minus(point) + " [{-1.0 ft, 0.0 ft, 1.0 ft}]"); 856 System.out.println(" v1 * 2 = " + v1.times(2) + " [{2.0 ft, 4.0 ft, 6.0 ft}]"); 857 858 Vector3D<?> areaVector = (Vector3D<?>)v1.times(point); 859 System.out.println(" v1 * point = " + areaVector); 860 System.out.println(" converted to ft² = " + areaVector.to(NonSI.SQUARE_FOOT) + " [{2.0 ft², 4.0 ft², 6.0 ft²}]"); 861 862 Vector3D<Length> v2 = Vector3D.valueOf(1, 1, 1, SI.METER); 863 Vector3D<?> v1xv2 = (Vector3D<?>)v1.cross(v2); 864 System.out.println("v2 = " + v2); 865 System.out.println(" v1 + v2 = " + v1.plus(v2) + " [{4.28083989501312 ft, 5.28083989501312 ft, 6.28083989501312 ft}]"); 866 System.out.println(" v1 - v2 = " + v1.minus(v2) + " [{-2.28083989501312 ft, -1.28083989501312 ft, -0.280839895013123 ft}]"); 867 System.out.println(" v1 · v2 = " + v1.times(v2.to(NonSI.FOOT)) + " [19.6850393700787 ft²]"); 868 System.out.println(" v1.cross(v2) = " + v1xv2.to(NonSI.FOOT.pow(2)) + " [{-3.28083989501312 ft^2, 6.56167979002625 ft^2, -3.28083989501312 ft^2}]"); 869 System.out.println(" v1.angle(v2) = " + v1.angle(v2).to(NonSI.DEGREE_ANGLE) + " [73.6090476746643 deg]"); 870 871 // Write out XML data. 872 try { 873 System.out.println(); 874 875 // Creates some useful aliases for class names. 876 javolution.xml.XMLBinding binding = new javolution.xml.XMLBinding(); 877 binding.setAlias(org.jscience.mathematics.number.Float64.class, "Float64"); 878 binding.setAlias(org.jscience.mathematics.vector.Float64Matrix.class, "Float64Matrix"); 879 880 javolution.xml.XMLObjectWriter writer = javolution.xml.XMLObjectWriter.newInstance(System.out); 881 writer.setIndentation(" "); 882 writer.setBinding(binding); 883 writer.write(v1, "Vector3D", Vector3D.class); 884 writer.flush(); 885 886 System.out.println(); 887 } catch (Exception e) { 888 e.printStackTrace(); 889 } 890 891 } 892}