001/* 002 * Polar3D -- A 3D polar coordinate of azimuth & elevation angle and magnitude. 003 * 004 * Copyright (C) 2008-2015, by Joseph A. Huwaldt. 005 * All rights reserved. 006 * 007 * This library is free software; you can redistribute it and/or 008 * modify it under the terms of the GNU Lesser General Public 009 * License as published by the Free Software Foundation; either 010 * version 2 of the License, or (at your option) any later version. 011 * 012 * This library is distributed in the hope that it will be useful, 013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 015 * Lesser General Public License for more details. 016 * 017 * You should have received a copy of the GNU Lesser General Public License 018 * along with this program; if not, write to the Free Software 019 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 020 * Or visit: http://www.gnu.org/licenses/lgpl.html 021 */ 022package jahuwaldt.js.param; 023 024import jahuwaldt.tools.math.MathTools; 025import java.text.MessageFormat; 026import javax.measure.converter.ConversionException; 027import javax.measure.quantity.*; 028import javax.measure.unit.NonSI; 029import javax.measure.unit.SI; 030import javax.measure.unit.Unit; 031import javolution.context.ObjectFactory; 032import javolution.context.StackContext; 033import static javolution.lang.MathLib.*; 034import javolution.xml.XMLFormat; 035import javolution.xml.XMLSerializable; 036import javolution.xml.stream.XMLStreamException; 037import org.jscience.mathematics.vector.*; 038 039/** 040 * This class represents a 3 element {@link Vector vector} of Parameter elements 041 * representing a geometrical polar coordinate with elements magnitude, azimuth angle and 042 * elevation angle where elevation is measured positive above the reference plane (similar 043 * to latitude). 044 * 045 * <p> Modified by: Joseph A. Huwaldt </p> 046 * 047 * @author Joseph A. Huwaldt, Date: November 21, 2008 048 * @version November 4, 2015 049 * 050 * @param <Q> The Quantity (unit type, such as Length or Volume) of this vector. 051 */ 052public final class Polar3D<Q extends Quantity> extends Coordinate3D<Q> implements XMLSerializable { 053 // Reference: http://mathworld.wolfram.com/SphericalCoordinates.html 054 055 private static final long serialVersionUID = -2077967266275152872L; 056 057 /** 058 * Constant used to identify the magnitude of in the vector. 059 */ 060 public static final int MAGNITUDE = 0; 061 062 /** 063 * Constant used to identify the azimuth angle of the vector. 064 */ 065 public static final int AZIMUTH = 1; 066 067 /** 068 * Constant used to identify the elevation angle of the vector. 069 */ 070 public static final int ELEVATION = 2; 071 072 /** 073 * The magnitude of this vector. 074 */ 075 private Parameter<Q> _mag; 076 077 /** 078 * The azimuth angle of this vector. 079 */ 080 private Parameter<Angle> _azimuth; 081 082 /** 083 * The elevation angle of this vector. 084 */ 085 private Parameter<Angle> _elevation; 086 087 /** 088 * Returns a {@link Polar3D} instance holding the specified <code>double</code> values 089 * stated in the specified units. 090 * 091 * @param <Q> the Quantity (unit type, e.g. Length or Volume) of this vector. 092 * @param magnitude the magnitude (length) of the vector stated in the specified unit. 093 * @param azimuth the vector azimuth angle stated in the specified angle unit. 094 * @param elevation the vector elevation angle value stated in the specified angle 095 * unit. 096 * @param magUnit the unit in which the magnitude is stated. 097 * @param angleUnit the unit in which the azimuth and elevation angles are stated. 098 * @return the vector having the specified values. 099 */ 100 public static <Q extends Quantity> Polar3D<Q> valueOf(double magnitude, double azimuth, double elevation, 101 Unit<Q> magUnit, Unit<Angle> angleUnit) { 102 Polar3D<Q> V = Polar3D.newInstance(); 103 104 V._mag = Parameter.valueOf(magnitude, magUnit); 105 V._azimuth = Parameter.valueOf(azimuth, angleUnit); 106 V._elevation = Parameter.valueOf(elevation, angleUnit); 107 108 return V; 109 } 110 111 /** 112 * Returns a {@link Polar3D} instance holding the specified <code>Parameter</code> 113 * values. All the values are converted to the same units as the x value. 114 * 115 * @param <Q> the Quantity (unit type, e.g. Length or Volume) of this vector. 116 * @param magnitude the vector magnitude (length) value. 117 * @param azimuth the vector azimuth angle value. 118 * @param elevation the vector elevation angle value. 119 * @return the vector having the specified values in the units of magnitude. 120 */ 121 public static <Q extends Quantity> Polar3D<Q> valueOf(Parameter<Q> magnitude, Parameter<Angle> azimuth, Parameter<Angle> elevation) { 122 Polar3D<Q> V = Polar3D.newInstance(); 123 V._mag = magnitude; 124 V._azimuth = azimuth; 125 V._elevation = elevation.to(azimuth.getUnit()); 126 127 return V; 128 } 129 130 /** 131 * Returns a {@link Polar3D} instance containing the polar coordinate representation 132 * of the specified {@link Coordinate3D coordinate}. The azimuth and elevation 133 * components of the resulting vector have units of radians. 134 * <p> 135 * The polar representation of a Cartesian coordinate is given by: 136 * <pre> 137 * magnitude = |V| 138 * azimuth = atan2(Y,X) 139 * elevation = 90° - acos(Z/|V|) = latitude 140 * </pre></p> 141 * 142 * @param <Q> the Quantity (unit type, e.g. Length or Volume) of this vector. 143 * @param coordinate the input coordinate. 144 * @return the polar coordinate having the specified values. 145 */ 146 public static <Q extends Quantity> Polar3D<Q> valueOf(Coordinate3D<Q> coordinate) { 147 148 if (coordinate instanceof Polar3D) 149 return (Polar3D)coordinate; 150 151 Vector3D<Q> vector = coordinate.toVector3D(); 152 double x = vector.getValue(Vector3D.X); 153 double y = vector.getValue(Vector3D.Y); 154 double z = vector.getValue(Vector3D.Z); 155 156 double mag = sqrt(x * x + y * y + z * z); 157 double azim = atan2(y, x); 158 double phi = acos(z/mag); 159 double elev = HALF_PI - phi; 160 161 Polar3D<Q> V = Polar3D.newInstance(); 162 V._mag = Parameter.valueOf(mag, vector.getUnit()); 163 V._azimuth = Parameter.valueOf(azim, SI.RADIAN); 164 V._elevation = Parameter.valueOf(elev, SI.RADIAN); 165 166 return V; 167 } 168 169 /** 170 * Returns a {@link Polar3D} instance containing the polar coordinate representation 171 * of the specified {@link Coordinate3D coordinate}. 172 * <p> 173 * The polar representation of a Cartesian coordinate is given by: 174 * <pre> 175 * magnitude = |V| 176 * azimuth = atan2(Y,X) 177 * elevation = atan2(-Z,sqrt(X^2+Y^2)) 178 * </pre></p> 179 * 180 * @param <Q> the Quantity (unit type, e.g. Length or Volume) of this vector. 181 * @param coord the coordinate to convert. 182 * @param angleUnit the unit to use for the azimuth and elevation components. 183 * @return the polar coordinate vector having the specified values. 184 */ 185 public static <Q extends Quantity> Polar3D<Q> valueOf(Coordinate3D<Q> coord, Unit<Angle> angleUnit) { 186 Polar3D<Q> V = Polar3D.valueOf(coord); 187 V._azimuth = V._azimuth.to(angleUnit); 188 V._elevation = V._elevation.to(angleUnit); 189 return V; 190 } 191 192 /** 193 * Return the specified {@link Vector3D} object as a <code>Polar3D</code> instance. 194 * 195 * @param vector The Vector3D object to be converted to a Polar3D. 196 * @return A Polar3D instance that is equivalent to the supplied Vector3D object. 197 */ 198 @Override 199 public Polar3D<Q> fromVector3D(Vector3D<Q> vector) { 200 return Polar3D.valueOf(vector, _azimuth.getUnit()); 201 } 202 203 /** 204 * Returns the value of a Parameter from this vector. The dimensions are defined as: 205 * magnitude, azimuth angle, and elevation angle in that order. 206 * 207 * @param i the dimension index (0=magnitude, 1=azimuth, 2=elevation). 208 * @return the value of the parameter at <code>i</code>. 209 * @throws IndexOutOfBoundsException <code>(i < 0) || (i > dimension()-1)</code> 210 */ 211 @Override 212 public Parameter get(int i) { 213 Parameter value = null; 214 switch (i) { 215 case 0: 216 value = _mag; 217 break; 218 case 1: 219 value = _azimuth; 220 break; 221 case 2: 222 value = _elevation; 223 break; 224 default: 225 throw new IndexOutOfBoundsException( 226 MessageFormat.format(RESOURCES.getString("p3dIndexErr"), i)); 227 } 228 return value; 229 } 230 231 /** 232 * Returns the magnitude of this vector as a <code>double</code>, stated in this 233 * vector's {@link #getUnit() unit}. 234 * 235 * @return the magnitude of this vector in this vector's units. 236 */ 237 public double getMagnitudeValue() { 238 return _mag.getValue(); 239 } 240 241 /** 242 * Returns the magnitude of this vector as a {@link Parameter}. 243 * 244 * @return the magnitude of this vector. 245 */ 246 public Parameter<Q> getMagnitude() { 247 return _mag; 248 } 249 250 /** 251 * Returns the azimuth angle of this vector as a {@link Parameter}. 252 * 253 * @return the azimuth angle of this vector. 254 */ 255 public Parameter<Angle> getAzimuth() { 256 return _azimuth; 257 } 258 259 /** 260 * Returns the elevation angle of this vector as a {@link Parameter}. 261 * 262 * @return the elevation angle of this vector. 263 */ 264 public Parameter<Angle> getElevation() { 265 return _elevation; 266 } 267 268 /** 269 * Returns the Euclidian norm, magnitude, or length of this vector (square root of the 270 * dot product of this vector and itself). 271 * 272 * @return <code>sqrt(this · this)</code>. 273 */ 274 @Override 275 public Parameter<Q> norm() { 276 return _mag; 277 } 278 279 /** 280 * Returns the {@link #norm() norm}, magnitude, or length value of this vector. 281 * 282 * @return <code>this.norm().getValue()</code>. 283 */ 284 @Override 285 public double normValue() { 286 return _mag.getValue(); 287 } 288 289 /** 290 * Returns the negation of this vector. 291 * 292 * @return <code>-this</code>. 293 */ 294 @Override 295 public Polar3D<Q> opposite() { 296 297 // Convert to cartesian coordinates, negate that, and then convert back to polar. 298 Vector3D<Q> V3D = toVector3D().opposite(); 299 Polar3D<Q> V = fromVector3D(V3D); 300 301 return V; 302 } 303 304 /** 305 * Returns the sum of this vector with the one specified. The unit of the output 306 * vector will be the units of this vector. 307 * 308 * @param that the vector to be added. 309 * @return <code>this + that</code>. 310 * @throws DimensionException if vector dimensions are different. 311 */ 312 @Override 313 public Polar3D<Q> plus(Vector<Parameter<Q>> that) { 314 315 // Convert to Cartesian coordinates, add those, then convert back. 316 if (!(that instanceof Coordinate3D)) 317 throw new ClassCastException(RESOURCES.getString("notCoordinate3D")); 318 319 StackContext.enter(); 320 try { 321 Vector3D<Q> T = ((Coordinate3D<Q>)that).toVector3D(); 322 Vector3D<Q> V3D = toVector3D().plus(T); 323 Polar3D<Q> V = fromVector3D(V3D); 324 325 return StackContext.outerCopy(V); 326 } finally { 327 StackContext.exit(); 328 } 329 } 330 331 /** 332 * Returns the sum of this vector with the parameter specified. The input parameter is 333 * added to the magnitude of this vector; the direction is left unchanged. The unit of 334 * the output vector will be the units of this vector. 335 * 336 * @param that the parameter to be added to the magnitude of this vector. 337 * @return <code>this + that</code>. 338 */ 339 @Override 340 public Polar3D<Q> plus(Parameter<Q> that) { 341 342 StackContext.enter(); 343 try { 344 Polar3D<Q> V = Polar3D.newInstance(); 345 Parameter<Q> mag = _mag.plus(that); 346 V._mag = mag; 347 V._azimuth = _azimuth; 348 V._elevation = _elevation; 349 if (mag.getValue() < 0) { 350 V._mag = mag.opposite(); 351 V = V.opposite(); 352 } 353 354 return StackContext.outerCopy(V); 355 } finally { 356 StackContext.exit(); 357 } 358 } 359 360 /** 361 * Returns the difference between this vector and the one specified. 362 * 363 * @param that the vector to be subtracted. 364 * @return <code>this - that</code>. 365 */ 366 @Override 367 public Polar3D<Q> minus(Vector<Parameter<Q>> that) { 368 369 // Convert to Cartesian coordinates, subtract those, then convert back. 370 if (!(that instanceof Coordinate3D)) 371 throw new ClassCastException(RESOURCES.getString("notCoordinate3D")); 372 373 StackContext.enter(); 374 try { 375 Vector3D<Q> T = ((Coordinate3D<Q>)that).toVector3D(); 376 Vector3D<Q> V3D = toVector3D().minus(T); 377 Polar3D<Q> V = fromVector3D(V3D); 378 379 return StackContext.outerCopy(V); 380 } finally { 381 StackContext.exit(); 382 } 383 } 384 385 /** 386 * Subtracts the supplied Parameter from this vector's magnitude and returns the 387 * result. The direction of the vector is left unchanged. The unit of the output 388 * vector will be the units of this vector. 389 * 390 * @param that the Parameter to be subtracted from the magnitude of this vector. 391 * @return <code>this - that</code>. 392 */ 393 @Override 394 public Polar3D<Q> minus(Parameter<Q> that) { 395 396 StackContext.enter(); 397 try { 398 Polar3D<Q> V = Polar3D.newInstance(); 399 Parameter<Q> mag = _mag.minus(that); 400 V._mag = mag; 401 V._azimuth = _azimuth; 402 V._elevation = _elevation; 403 if (mag.getValue() < 0) { 404 V._mag = mag.opposite(); 405 V = V.opposite(); 406 } 407 408 return StackContext.outerCopy(V); 409 } finally { 410 StackContext.exit(); 411 } 412 } 413 414 /** 415 * Returns the product of this vector with the specified coefficient. The magnitude of 416 * this vector is scaled by the input coefficient and the direction is left unchanged. 417 * 418 * @param k the coefficient multiplier. 419 * @return <code>this · k</code> 420 */ 421 @Override 422 public Polar3D times(Parameter k) { 423 Polar3D V = Polar3D.newInstance(); 424 V._mag = _mag.times(k); 425 V._azimuth = _azimuth; 426 V._elevation = _elevation; 427 return V; 428 } 429 430 /** 431 * Returns the product of this vector with the specified coefficient. The magnitude of 432 * this vector is scaled by the input coefficient and the direction is left unchanged. 433 * 434 * @param k the coefficient multiplier. 435 * @return <code>this · k</code> 436 */ 437 @Override 438 public Polar3D<Q> times(double k) { 439 Polar3D<Q> V = Polar3D.newInstance(); 440 V._mag = _mag.times(k); 441 V._azimuth = _azimuth; 442 V._elevation = _elevation; 443 return V; 444 } 445 446 /** 447 * Returns the dot product of this vector with the one specified. 448 * 449 * @param that the vector multiplier. 450 * @return <code>this · that</code> 451 * @throws DimensionException if <code>this.dimension() != that.dimension()</code> 452 * @see <a href="http://en.wikipedia.org/wiki/Dot_product"> 453 * Wikipedia: Dot Product</a> 454 */ 455 @Override 456 public Parameter times(Vector that) { 457 458 // Convert to Cartesian coordinates and multiply that. 459 if (!(that instanceof Coordinate3D)) 460 throw new ClassCastException(RESOURCES.getString("notCoordinate3D")); 461 462 StackContext.enter(); 463 try { 464 Vector3D T = ((Coordinate3D)that).toVector3D(); 465 Parameter product = toVector3D().times(T); 466 467 return StackContext.outerCopy(product); 468 } finally { 469 StackContext.exit(); 470 } 471 } 472 473 /** 474 * Returns the result of this vector divided by the specified divisor. The magnitude 475 * of this vector is divided by the input coefficient and the direction is left 476 * unchanged. 477 * 478 * @param that the divisor. 479 * @return <code>this / that</code>. 480 */ 481 public Polar3D<?> divide(Parameter<?> that) { 482 return (Polar3D<?>)times(that.inverse()); 483 } 484 485 /** 486 * Returns the cross product of two 3-dimensional vectors. 487 * 488 * @param that the vector multiplier. 489 * @return <code>this x that</code> 490 * @throws DimensionException if <code>(that.getDimension() != 3)</code> 491 * @see <a href="http://en.wikipedia.org/wiki/Cross_product"> 492 * Wikipedia: Cross Product</a> 493 */ 494 @Override 495 public Polar3D cross(Vector that) { 496 497 // Convert to Cartesian coordinates, multiply those, then convert back. 498 if (!(that instanceof Coordinate3D)) 499 throw new ClassCastException(RESOURCES.getString("notCoordinate3D")); 500 501 StackContext.enter(); 502 try { 503 Vector3D<?> T = ((Coordinate3D<?>)that).toVector3D(); 504 Vector3D<?> V3D = toVector3D().cross(T); 505 Polar3D<?> V = Polar3D.valueOf(V3D, _azimuth.getUnit()); 506 507 return StackContext.outerCopy(V); 508 } finally { 509 StackContext.exit(); 510 } 511 } 512 513 /** 514 * Returns this vector converted to a unit vector with a vector magnitude of 1.0. 515 * 516 * @return this vector converted to a unit vector 517 */ 518 public Polar3D<Dimensionless> toUnitVector() { 519 double magnitude = this.normValue(); 520 if (this.getUnit().equals(Dimensionless.UNIT) && MathTools.isApproxEqual(magnitude, 1.0)) 521 return (Polar3D<Dimensionless>)this; 522 523 Polar3D<Dimensionless> V = Polar3D.newInstance(); 524 V._azimuth = this._azimuth; 525 V._elevation = this._elevation; 526 V._mag = Parameter.ONE; 527 528 return V; 529 } 530 531 /** 532 * Returns a copy of this vector {@link javolution.context.AllocatorContext allocated} 533 * by the calling thread (possibly on the stack). 534 * 535 * @return an identical and independent copy of this vector. 536 */ 537 @Override 538 public Polar3D<Q> copy() { 539 return copyOf(this); 540 } 541 542 /** 543 * Returns the unit in which the magnitude in this vector are stated in. 544 * 545 * @return the unit in which the magnitude in this vector are stated in 546 */ 547 @Override 548 public Unit<Q> getUnit() { 549 return _mag.getUnit(); 550 } 551 552 /** 553 * Returns the unit in which the angles in this vector are stated in. 554 * 555 * @return the unit in which the angles in this vector are stated in 556 */ 557 public Unit<Angle> getAnglesUnit() { 558 return _azimuth.getUnit(); 559 } 560 561 /** 562 * Returns the equivalent to this vector but with the magnitude stated in the 563 * specified unit. 564 * 565 * @param <R> the Quantity (unit type, e.g. Length or Volume) of the returned vector. 566 * @param unit the unit of the magnitude of the vector to be returned. 567 * @return a vector equivalent to this vector but with the magnitude stated in the 568 * specified unit. 569 * @throws ConversionException if the current model does not allows for conversion to 570 * the specified unit. 571 */ 572 @Override 573 public <R extends Quantity> Polar3D<R> to(Unit<R> unit) throws ConversionException { 574 Unit<?> thisUnit = getUnit(); 575 if ((thisUnit == unit) || thisUnit.equals(unit)) 576 return (Polar3D<R>)this; 577 Polar3D<R> result = Polar3D.newInstance(); 578 result._mag = _mag.to(unit); 579 result._azimuth = _azimuth; 580 result._elevation = _elevation; 581 return result; 582 } 583 584 /** 585 * Returns the equivalent to this vector but with the angles stated in the specified 586 * unit. 587 * 588 * @param unit the angle unit of the angles of the vector to be returned. 589 * @return a coordinate equivalent to this vector but with the angles stated in the 590 * specified unit. 591 * @throws ConversionException if the current model does not allows for conversion to 592 * the specified unit. 593 */ 594 public Polar3D<Q> anglesTo(Unit<Angle> unit) { 595 Unit<Angle> thisUnit = _azimuth.getUnit(); 596 if ((thisUnit == unit) || thisUnit.equals(unit)) 597 return this; 598 Polar3D<Q> result = Polar3D.newInstance(); 599 result._mag = _mag; 600 result._azimuth = _azimuth.to(unit); 601 result._elevation = _elevation.to(unit); 602 return result; 603 } 604 605 /** 606 * Casts this Polar3D to a parameterized unit of specified nature or throw a 607 * <code>ClassCastException</code> if the dimension of the specified quantity and this 608 * parameter's unit dimension do not match. 609 * 610 * @param <T> the Quantity (unit type, e.g. Length or Volume) of the returned vector. 611 * @param type the quantity class identifying the nature of the unit. 612 * @return this Polar3D parameterized with the specified type. 613 * @throws ClassCastException if the dimension of this parameter's unit is different 614 * from the specified quantity dimension. 615 * @throws UnsupportedOperationException if the specified quantity class does not have 616 * a public static field named "UNIT" holding the standard unit for the quantity. 617 */ 618 @Override 619 public <T extends Quantity> Polar3D<T> asType(Class<T> type) throws ClassCastException { 620 Unit<T> u = getUnit().asType(type); // If no exception is thrown, the cast is valid. 621 return (Polar3D<T>)this; 622 } 623 624 /** 625 * Returns a Cartesian Vector3D representation of this vector. 626 * <p> 627 * The polar to Cartesian transformation is defined by: 628 * <pre> 629 * |x| | cos(elevation)*cos(azimuth) | 630 * |y| = magnitude*| cos(elevation)*sin(azimuth) | 631 * |z| | -sin(elevation) | 632 * </pre></p> 633 * 634 * @return a Cartesian Vector3D representation of this vector 635 */ 636 @Override 637 public Vector3D<Q> toVector3D() { 638 639 double mag = _mag.getValue(); 640 double azim = _azimuth.to(SI.RADIAN).getValue(); 641 double elev = _elevation.to(SI.RADIAN).getValue(); 642 //double phi = HALF_PI - elev; 643 644 double sPhi = cos(elev), cPhi = sin(elev); 645 double x = mag * sPhi * cos(azim); 646 double y = mag * sPhi * sin(azim); 647 double z = -mag * cPhi; 648 649 Vector3D<Q> V = Vector3D.valueOf(x, y, z, getUnit()); 650 651 return V; 652 } 653 654 /** 655 * Compares this Polar3D against the specified object for strict equality (same values 656 * and same units). 657 * 658 * @param obj the object to compare with. 659 * @return <code>true</code> if this vector is identical to that vector; 660 * <code>false</code> otherwise. 661 */ 662 @Override 663 public boolean equals(Object obj) { 664 if (this == obj) 665 return true; 666 if ((obj == null) || (obj.getClass() != this.getClass())) 667 return false; 668 669 Polar3D<?> that = (Polar3D<?>)obj; 670 if (!this._mag.equals(that._mag)) 671 return false; 672 if (!this._azimuth.equals(that._azimuth)) 673 return false; 674 675 return this._elevation.equals(that._elevation); 676 } 677 678 /** 679 * Returns the hash code for this parameter. 680 * 681 * @return the hash code value. 682 */ 683 @Override 684 public int hashCode() { 685 int hash = 7; 686 687 int var_code = _mag.hashCode(); 688 hash = hash * 31 + var_code; 689 690 var_code = _azimuth.hashCode(); 691 hash = hash * 31 + var_code; 692 693 var_code = _elevation.hashCode(); 694 hash = hash * 31 + var_code; 695 696 return hash; 697 } 698 699 /** 700 * Holds the default XML representation. For example: 701 * <pre> 702 * <Magnitude value="1.73205080756888" unit="m"/> 703 * <Azimuth value="45.0" unit="°" /> 704 * <Elevation value="35.2643896827547" unit="°" /> 705 * </pre> 706 */ 707 protected static final XMLFormat<Polar3D> XML = new XMLFormat<Polar3D>(Polar3D.class) { 708 709 @Override 710 public Polar3D<?> newInstance(Class<Polar3D> cls, InputElement xml) throws XMLStreamException { 711 return FACTORY.object(); 712 } 713 714 @Override 715 public void read(InputElement xml, Polar3D V) throws XMLStreamException { 716 V._mag = xml.get("Magnitude", Parameter.class); 717 V._azimuth = xml.get("Azimuth", Parameter.class); 718 V._elevation = xml.get("Elevation", Parameter.class); 719 } 720 721 @Override 722 public void write(Polar3D V, OutputElement xml) throws XMLStreamException { 723 xml.add(V._mag, "Magnitude", Parameter.class); 724 xml.add(V._azimuth, "Azimuth", Parameter.class); 725 xml.add(V._elevation, "Elevation", Parameter.class); 726 } 727 }; 728 729 /////////////////////// 730 // Factory creation. // 731 /////////////////////// 732 private Polar3D() { 733 } 734 735 private static final ObjectFactory<Polar3D<? extends Quantity>> FACTORY = new ObjectFactory<Polar3D<? extends Quantity>>() { 736 @Override 737 protected Polar3D<? extends Quantity> create() { 738 return new Polar3D(); 739 } 740 }; 741 742 private static <Q extends Quantity> Polar3D<Q> newInstance() { 743 Polar3D<Q> measure = (Polar3D<Q>)FACTORY.object(); 744 return measure; 745 } 746 747 private static <Q extends Quantity> Polar3D<Q> copyOf(Polar3D<Q> original) { 748 Polar3D<Q> measure = Polar3D.newInstance(); 749 measure._mag = original._mag.copy(); 750 measure._azimuth = original._azimuth.copy(); 751 measure._elevation = original._elevation.copy(); 752 return measure; 753 } 754 755 /** 756 * Tests the methods in this class. 757 * 758 * @param args Command line arguments (ignored) 759 */ 760 public static void main(String args[]) { 761 System.out.println("Testing Polar3D: test = result [correct result]"); 762 763 Polar3D<Length> v1 = Polar3D.valueOf(1, 20, 30, NonSI.FOOT, NonSI.DEGREE_ANGLE); 764 System.out.println("v1 = " + v1); 765 System.out.println("v1 (as Vector3D) = " + v1.toVector3D()); 766 System.out.println(" converted to m = " + v1.to(SI.METER) + " [{0.3048 m, 20.0 °, 30.0 °}]"); 767 System.out.println(" v1.norm() = " + v1.norm() + " [1.0 ft]"); 768 System.out.println(" v1.opposite() = " + v1.opposite() + " [{1.0 ft, 200.0 °, 330.0 °}]"); 769 770 Parameter<Length> point = Parameter.valueOf(24, NonSI.INCH); 771 System.out.println("point = " + point); 772 System.out.println(" v1 + point = " + v1.plus(point) + " [{3.0 ft, 20.0 °, 30.0 °}]"); 773 System.out.println(" v1 - point = " + v1.minus(point) + " [{1.0 ft, 200.0 °, 330.0 °}]"); 774 System.out.println(" v1 * 2 = " + v1.times(2) + " [{2.0 ft, 20.0 °, 30.0 °}]"); 775 776 Polar3D<?> areaVector = (Polar3D<?>)v1.times(point); 777 System.out.println(" v1 * point = " + areaVector); 778 System.out.println(" converted to ft² = " + areaVector.to(NonSI.SQUARE_FOOT) + " [{2.0 ft², 20.0 °, 30.0 °}]"); 779 780 Vector3D<Length> v2 = Vector3D.valueOf(1, 1, -1, SI.METER); 781 System.out.println("v2 = " + v2); 782 System.out.println("v2 (as Polar3D)= " + Polar3D.valueOf(v2, NonSI.DEGREE_ANGLE) + " [{1.73205080756888 m, 45.0 °, 35.2643896827547 °}]"); 783 System.out.println(" v1 + v2 = " + v1.plus(v2) + " [{6.62238689940225 ft, 41.1401661546401 °, 34.8142656403426 °}]"); 784 System.out.println(" v1 - v2 = " + v1.minus(v2) + " [{4.76733198496641 ft, 230.423579133255 °, 324.316200627242 °}]"); 785 System.out.println(" v1 · v2 = " + v1.times(v2.to(NonSI.FOOT)) + " [5.2821384976227 ft²]"); 786 System.out.println(" v1.cross(v2) = " + v1.cross(v2) + " [{2.09541025626521 ft, 56.9975252490327 °, 305.863065923747 °}]"); 787 System.out.println(" v1.angle(v2) = " + v1.angle(Polar3D.valueOf(v2)).to(NonSI.DEGREE_ANGLE) + " [21.638095609098805 deg]"); 788 789 // Write out XML data. 790 try { 791 System.out.println(); 792 793 // Creates some useful aliases for class names. 794 javolution.xml.XMLBinding binding = new javolution.xml.XMLBinding(); 795 binding.setAlias(org.jscience.mathematics.number.Float64.class, "Float64"); 796 binding.setAlias(org.jscience.mathematics.vector.Float64Matrix.class, "Float64Matrix"); 797 798 javolution.xml.XMLObjectWriter writer = javolution.xml.XMLObjectWriter.newInstance(System.out); 799 writer.setIndentation(" "); 800 writer.setBinding(binding); 801 writer.write(v1, "Polar3D", Polar3D.class); 802 writer.flush(); 803 804 System.out.println(); 805 } catch (Exception e) { 806 e.printStackTrace(); 807 } 808 809 } 810}