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