001/* 002 * Cylindrical3D -- A 3D cylindrical coordinate of radius, azimuth, and height. 003 * 004 * Copyright (C) 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.SI; 029import javax.measure.unit.Unit; 030import javolution.context.ObjectFactory; 031import javolution.context.StackContext; 032import static javolution.lang.MathLib.*; 033import javolution.xml.XMLFormat; 034import javolution.xml.XMLSerializable; 035import javolution.xml.stream.XMLStreamException; 036import org.jscience.mathematics.vector.*; 037 038/** 039 * This class represents a 3 element {@link Vector vector} of Parameter elements 040 * representing a geometrical cylindrical coordinate with elements radius, azimuth angle 041 * and height. 042 * 043 * <p> Modified by: Joseph A. Huwaldt </p> 044 * 045 * @author Joseph A. Huwaldt, Date: October 29, 2015 046 * @version November 3, 2015 047 * 048 * @param <Q> The Quantity (unit type, such as Length or Volume) of this vector. 049 */ 050public final class Cylindrical3D<Q extends Quantity> extends Coordinate3D<Q> implements XMLSerializable { 051 052 private static final long serialVersionUID = 1L; 053 054 /** 055 * Constant used to identify the radius of in the vector. 056 */ 057 public static final int RADIUS = 0; 058 059 /** 060 * Constant used to identify the azimuth angle of the vector. 061 */ 062 public static final int AZIMUTH = 1; 063 064 /** 065 * Constant used to identify the height or altitude of the vector. 066 */ 067 public static final int HEIGHT = 2; 068 069 /** 070 * The radius of this vector. 071 */ 072 private Parameter<Q> _radius; 073 074 /** 075 * The azimuth angle of this vector. 076 */ 077 private Parameter<Angle> _azimuth; 078 079 /** 080 * The height/altitude of this vector. 081 */ 082 private Parameter<Q> _height; 083 084 /** 085 * Returns a {@link Cylindrical3D} instance holding the specified <code>double</code> 086 * values stated in the specified units. 087 * 088 * @param <Q> the Quantity (unit type, e.g. Length or Volume) of this vector. 089 * @param radius the radius of the vector stated in the specified radius unit. 090 * @param azimuth the vector azimuth angle stated in the specified angle unit. 091 * @param height the vector height/altitude value stated in the specified radius 092 * unit. 093 * @param radiusUnit the unit in which the radius and height is stated. 094 * @param angleUnit the unit in which the azimuth angle is stated. 095 * @return the vector having the specified values. 096 */ 097 public static <Q extends Quantity> Cylindrical3D<Q> valueOf(double radius, double azimuth, double height, 098 Unit<Q> radiusUnit, Unit<Angle> angleUnit) { 099 Cylindrical3D<Q> V = Cylindrical3D.newInstance(); 100 101 V._radius = Parameter.valueOf(radius, radiusUnit); 102 V._azimuth = Parameter.valueOf(azimuth, angleUnit); 103 V._height = Parameter.valueOf(height, radiusUnit); 104 105 return V; 106 } 107 108 /** 109 * Returns a {@link Cylindrical3D} instance holding the specified 110 * <code>Parameter</code> values. 111 * 112 * @param <Q> the Quantity (unit type, e.g. Length or Volume) of this vector. 113 * @param radius the vector radius value. 114 * @param azimuth the vector azimuth angle value. 115 * @param height the vector height/altitude value. 116 * @return the vector having the specified values in the units of magnitude. 117 */ 118 public static <Q extends Quantity> Cylindrical3D<Q> valueOf(Parameter<Q> radius, Parameter<Angle> azimuth, Parameter<Q> height) { 119 Cylindrical3D<Q> V = Cylindrical3D.newInstance(); 120 V._radius = radius; 121 V._azimuth = azimuth; 122 V._height = height.to(radius.getUnit()); 123 124 return V; 125 } 126 127 /** 128 * Returns a {@link Cylindrical3D} instance containing the cylindrical coordinate 129 * representation of the specified {@link Coordinate3D coordinate}. The azimuth 130 * component of the resulting vector will have units of radians. 131 * 132 * @param <Q> the Quantity (unit type, e.g. Length or Volume) of this vector. 133 * @param coordinate the input coordinate. 134 * @return the cylindrical coordinate having the specified values. 135 */ 136 public static <Q extends Quantity> Cylindrical3D<Q> valueOf(Coordinate3D<Q> coordinate) { 137 138 if (coordinate instanceof Cylindrical3D) 139 return (Cylindrical3D)coordinate; 140 141 Vector3D<Q> vector = coordinate.toVector3D(); 142 double x = vector.getValue(Vector3D.X); 143 double y = vector.getValue(Vector3D.Y); 144 145 double rho = Math.sqrt(x * x + y * y); 146 double azim = Math.atan2(y, x); 147 148 Cylindrical3D<Q> V = Cylindrical3D.newInstance(); 149 V._radius = Parameter.valueOf(rho, vector.getUnit()); 150 V._azimuth = Parameter.valueOf(azim, SI.RADIAN); 151 V._height = vector.get(Vector3D.Z); 152 153 return V; 154 } 155 156 /** 157 * Returns a {@link Cylindrical3D} instance containing the cylindrical coordinate 158 * representation of the specified {@link Coordinate3D coordinate}. 159 * 160 * @param <Q> the Quantity (unit type, e.g. Length or Volume) of this vector. 161 * @param coord the coordinate to convert. 162 * @param angleUnit the unit to use for the azimuth component. 163 * @return the cylindrical coordinate vector having the specified values. 164 */ 165 public static <Q extends Quantity> Cylindrical3D<Q> valueOf(Coordinate3D<Q> coord, Unit<Angle> angleUnit) { 166 Cylindrical3D<Q> V = Cylindrical3D.valueOf(coord); 167 V._azimuth = V._azimuth.to(angleUnit); 168 return V; 169 } 170 171 /** 172 * Return the specified {@link Vector3D} object as a <code>Cylindrical3D</code> 173 * instance. 174 * 175 * @param vector The Vector3D object to be converted to a Cylindrical3D. 176 * @return A Cylindrical3D instance that is equivalent to the supplied Vector3D 177 * object. 178 */ 179 @Override 180 public Cylindrical3D<Q> fromVector3D(Vector3D<Q> vector) { 181 return Cylindrical3D.valueOf(vector, _azimuth.getUnit()); 182 } 183 184 /** 185 * Returns the value of a Parameter from this vector. The dimensions are defined as: 186 * radius, azimuth angle, and height or altitude in that order. 187 * 188 * @param i the dimension index (0=radius, 1=azimuth, 2=height/altitude). 189 * @return the value of the parameter at <code>i</code>. 190 * @throws IndexOutOfBoundsException <code>(i < 0) || (i > dimension()-1)</code> 191 */ 192 @Override 193 public Parameter get(int i) { 194 Parameter value = null; 195 switch (i) { 196 case 0: 197 value = _radius; 198 break; 199 case 1: 200 value = _azimuth; 201 break; 202 case 2: 203 value = _height; 204 break; 205 default: 206 throw new IndexOutOfBoundsException( 207 MessageFormat.format(RESOURCES.getString("p3dIndexErr"), i)); 208 } 209 return value; 210 } 211 212 /** 213 * Returns the radius element of this vector as a <code>double</code>, stated in this 214 * vector's {@link #getUnit() unit}. 215 * 216 * @return the radius element of this vector in this vector's units. 217 */ 218 public double getRadiusValue() { 219 return _radius.getValue(); 220 } 221 222 /** 223 * Returns the radius element of this vector as a {@link Parameter}. 224 * 225 * @return the radius element of this vector. 226 */ 227 public Parameter<Q> getRadius() { 228 return _radius.pow(2).times(_height.pow(2)).sqrt(); 229 } 230 231 /** 232 * Returns the azimuth angle of this vector as a {@link Parameter}. 233 * 234 * @return the azimuth angle of this vector. 235 */ 236 public Parameter<Angle> getAzimuth() { 237 return _azimuth; 238 } 239 240 /** 241 * Returns the height or altitude element of this vector as a {@link Parameter}. 242 * 243 * @return the height element of this vector. 244 */ 245 public Parameter<Q> getHeight() { 246 return _height; 247 } 248 249 /** 250 * Returns the Euclidian norm, magnitude, or length of this vector (square root of the 251 * dot product of this vector and itself). 252 * 253 * @return <code>sqrt(this · this)</code>. 254 */ 255 @Override 256 public Parameter<Q> norm() { 257 return _radius.pow(2).times(_height.pow(2)).sqrt(); 258 } 259 260 /** 261 * Returns the {@link #norm() norm}, magnitude, or length value of this vector. 262 * 263 * @return <code>this.norm().getValue()</code>. 264 */ 265 @Override 266 public double normValue() { 267 double rho = _radius.getValue(); 268 double h = _height.getValue(); 269 return Math.sqrt(rho * rho + h * h); 270 } 271 272 /** 273 * Returns the negation of this vector. 274 * 275 * @return <code>-this</code>. 276 */ 277 @Override 278 public Cylindrical3D<Q> opposite() { 279 280 // Convert to cartesian coordinates, negate that, and then convert back to polar. 281 Vector3D<Q> V3D = toVector3D().opposite(); 282 Cylindrical3D<Q> V = fromVector3D(V3D); 283 284 return V; 285 } 286 287 /** 288 * Returns the sum of this vector with the one specified. The units of the output 289 * vector will be the units of this vector. 290 * 291 * @param that the vector to be added. 292 * @return <code>this + that</code>. 293 * @throws DimensionException if vector dimensions are different. 294 */ 295 @Override 296 public Cylindrical3D<Q> plus(Vector<Parameter<Q>> that) { 297 298 // Convert to Cartesian coordinates, add those, then convert back. 299 if (!(that instanceof Coordinate3D)) 300 throw new ClassCastException(RESOURCES.getString("notCoordinate3D")); 301 302 StackContext.enter(); 303 try { 304 Vector3D<Q> T = ((Coordinate3D<Q>)that).toVector3D(); 305 Vector3D<Q> V3D = toVector3D().plus(T); 306 Cylindrical3D<Q> V = fromVector3D(V3D); 307 308 return StackContext.outerCopy(V); 309 } finally { 310 StackContext.exit(); 311 } 312 } 313 314 /** 315 * Returns the sum of this vector with the parameter specified. The unit of the output 316 * vector will be the units of this vector. 317 * 318 * @param that the parameter to be added to this vector. 319 * @return <code>this + that</code>. 320 */ 321 @Override 322 public Cylindrical3D<Q> plus(Parameter<Q> that) { 323 324 StackContext.enter(); 325 try { 326 Vector3D<Q> V3D = toVector3D().plus(that); 327 Cylindrical3D<Q> V = fromVector3D(V3D); 328 329 return StackContext.outerCopy(V); 330 } finally { 331 StackContext.exit(); 332 } 333 334 } 335 336 /** 337 * Returns the difference between this vector and the one specified. 338 * 339 * @param that the vector to be subtracted. 340 * @return <code>this - that</code>. 341 */ 342 @Override 343 public Cylindrical3D<Q> minus(Vector<Parameter<Q>> that) { 344 345 // Convert to Cartesian coordinates, subtract those, then convert back. 346 if (!(that instanceof Coordinate3D)) 347 throw new ClassCastException(RESOURCES.getString("notCoordinate3D")); 348 349 StackContext.enter(); 350 try { 351 Vector3D<Q> T = ((Coordinate3D<Q>)that).toVector3D(); 352 Vector3D<Q> V3D = toVector3D().minus(T); 353 Cylindrical3D<Q> V = fromVector3D(V3D); 354 355 return StackContext.outerCopy(V); 356 } finally { 357 StackContext.exit(); 358 } 359 } 360 361 /** 362 * Subtracts the supplied Parameter from this vector's and returns the result. The 363 * unit of the output vector will be the units of this vector. 364 * 365 * @param that the Parameter to be subtracted from this vector. 366 * @return <code>this - that</code>. 367 */ 368 @Override 369 public Cylindrical3D<Q> minus(Parameter<Q> that) { 370 371 StackContext.enter(); 372 try { 373 Vector3D<Q> V3D = toVector3D().minus(that); 374 Cylindrical3D<Q> V = fromVector3D(V3D); 375 376 return StackContext.outerCopy(V); 377 } finally { 378 StackContext.exit(); 379 } 380 } 381 382 /** 383 * Returns the product of this vector with the specified coefficient. The magnitude of 384 * this vector is scaled by the input coefficient and the direction is left unchanged. 385 * 386 * @param k the coefficient multiplier. 387 * @return <code>this · k</code> 388 */ 389 @Override 390 public Cylindrical3D times(Parameter k) { 391 Cylindrical3D V = Cylindrical3D.newInstance(); 392 V._radius = _radius.times(k); 393 V._azimuth = _azimuth; 394 V._height = _height.times(k); 395 return V; 396 } 397 398 /** 399 * Returns the product of this vector with the specified coefficient. The magnitude of 400 * this vector is scaled by the input coefficient and the direction is left unchanged. 401 * 402 * @param k the coefficient multiplier. 403 * @return <code>this · k</code> 404 */ 405 @Override 406 public Cylindrical3D<Q> times(double k) { 407 Cylindrical3D<Q> V = Cylindrical3D.newInstance(); 408 V._radius = _radius.times(k); 409 V._azimuth = _azimuth; 410 V._height = _height.times(k); 411 return V; 412 } 413 414 /** 415 * Returns the dot product of this vector with the one specified. 416 * 417 * @param that the vector multiplier. 418 * @return <code>this · that</code> 419 * @throws DimensionException if <code>this.dimension() != that.dimension()</code> 420 * @see <a href="http://en.wikipedia.org/wiki/Dot_product"> 421 * Wikipedia: Dot Product</a> 422 */ 423 @Override 424 public Parameter times(Vector that) { 425 426 // Convert to Cartesian coordinates and multiply that. 427 if (!(that instanceof Coordinate3D)) 428 throw new ClassCastException(RESOURCES.getString("notCoordinate3D")); 429 430 StackContext.enter(); 431 try { 432 Vector3D T = ((Coordinate3D)that).toVector3D(); 433 Parameter product = toVector3D().times(T); 434 435 return StackContext.outerCopy(product); 436 } finally { 437 StackContext.exit(); 438 } 439 } 440 441 /** 442 * Returns the result of this vector divided by the specified divisor. The magnitude 443 * of this vector is divided by the input coefficient and the direction is left 444 * unchanged. 445 * 446 * @param that the divisor. 447 * @return <code>this / that</code>. 448 */ 449 public Cylindrical3D<?> divide(Parameter<?> that) { 450 return (Cylindrical3D<?>)times(that.inverse()); 451 } 452 453 /** 454 * Returns the cross product of two 3-dimensional vectors. 455 * 456 * @param that the vector multiplier. 457 * @return <code>this x that</code> 458 * @throws DimensionException if <code>(that.getDimension() != 3)</code> 459 * @see <a href="http://en.wikipedia.org/wiki/Cross_product"> 460 * Wikipedia: Cross Product</a> 461 */ 462 @Override 463 public Cylindrical3D cross(Vector that) { 464 465 // Convert to Cartesian coordinates, multiply those, then convert back. 466 if (!(that instanceof Coordinate3D)) 467 throw new ClassCastException(RESOURCES.getString("notCoordinate3D")); 468 469 StackContext.enter(); 470 try { 471 Vector3D<?> T = ((Coordinate3D<?>)that).toVector3D(); 472 Vector3D<?> V3D = toVector3D().cross(T); 473 Cylindrical3D<?> V = Cylindrical3D.valueOf(V3D, _azimuth.getUnit()); 474 475 return StackContext.outerCopy(V); 476 } finally { 477 StackContext.exit(); 478 } 479 } 480 481 /** 482 * Returns this vector converted to a unit vector with a vector magnitude of 1.0. 483 * 484 * @return this vector converted to a unit vector 485 */ 486 public Cylindrical3D<Dimensionless> toUnitVector() { 487 double magnitude = this.normValue(); 488 if (this.getUnit().equals(Dimensionless.UNIT) && MathTools.isApproxEqual(magnitude, 1.0)) 489 return (Cylindrical3D<Dimensionless>)this; 490 491 Cylindrical3D<Dimensionless> V = Cylindrical3D.newInstance(); 492 V._azimuth = this._azimuth; 493 V._height = (Parameter<Dimensionless>)this._height.divide(magnitude); 494 V._radius = (Parameter<Dimensionless>)this._radius.divide(magnitude); 495 496 return V; 497 } 498 499 /** 500 * Returns a copy of this vector {@link javolution.context.AllocatorContext allocated} 501 * by the calling thread (possibly on the stack). 502 * 503 * @return an identical and independent copy of this vector. 504 */ 505 @Override 506 public Cylindrical3D<Q> copy() { 507 return copyOf(this); 508 } 509 510 /** 511 * Returns the unit in which the radius and height in this vector are stated in. 512 * 513 * @return the unit in which the radius and height in this vector are stated in 514 */ 515 @Override 516 public Unit<Q> getUnit() { 517 return _radius.getUnit(); 518 } 519 520 /** 521 * Returns the unit in which the azimuth angle in this vector is stated in. 522 * 523 * @return the unit in which the azimuth angle in this vector is stated in 524 */ 525 public Unit<Angle> getAngleUnit() { 526 return _azimuth.getUnit(); 527 } 528 529 /** 530 * Returns the equivalent to this vector but with the radius and height stated in the 531 * specified unit. 532 * 533 * @param <R> the Quantity (physical unit) type of the returned vector. 534 * @param unit the unit of the radius and height of the vector to be returned. 535 * @return a vector equivalent to this vector but with the radius and height stated in 536 * the specified unit. 537 * @throws ConversionException if the current model does not allows for conversion to 538 * the specified unit. 539 */ 540 @Override 541 public <R extends Quantity> Cylindrical3D<R> to(Unit<R> unit) throws ConversionException { 542 Unit<?> thisUnit = getUnit(); 543 if ((thisUnit == unit) || thisUnit.equals(unit)) 544 return (Cylindrical3D<R>)this; 545 Cylindrical3D<R> result = Cylindrical3D.newInstance(); 546 result._radius = _radius.to(unit); 547 result._azimuth = _azimuth; 548 result._height = _height.to(unit); 549 return result; 550 } 551 552 /** 553 * Returns the equivalent to this vector but with the azimuth angle stated in the 554 * specified unit. 555 * 556 * @param unit the angle unit of the azimuth of the vector to be returned. 557 * @return a coordinate equivalent to this vector but with the azimuth stated in the 558 * specified unit. 559 * @throws ConversionException if the current model does not allows for conversion to 560 * the specified unit. 561 */ 562 public Cylindrical3D<Q> angleTo(Unit<Angle> unit) { 563 Unit<Angle> thisUnit = _azimuth.getUnit(); 564 if ((thisUnit == unit) || thisUnit.equals(unit)) 565 return this; 566 Cylindrical3D<Q> result = Cylindrical3D.newInstance(); 567 result._radius = _radius; 568 result._azimuth = _azimuth.to(unit); 569 result._height = _height; 570 return result; 571 } 572 573 /** 574 * Casts this Cylindrical3D to a parameterized unit of specified nature or throw a 575 * <code>ClassCastException</code> if the dimension of the specified quantity and this 576 * parameter's unit dimension do not match. 577 * 578 * @param <T> the Quantity (physical unit) type of the returned vector. 579 * @param type the quantity class identifying the nature of the unit. 580 * @return this Cylindrical3D parameterized with the specified type. 581 * @throws ClassCastException if the dimension of this parameter's unit is different 582 * from the specified quantity dimension. 583 * @throws UnsupportedOperationException if the specified quantity class does not have 584 * a public static field named "UNIT" holding the standard unit for the quantity. 585 */ 586 @Override 587 public <T extends Quantity> Cylindrical3D<T> asType(Class<T> type) throws ClassCastException { 588 Unit<T> u = getUnit().asType(type); // If no exception is thrown, the cast is valid. 589 return (Cylindrical3D<T>)this; 590 } 591 592 /** 593 * Returns a Cartesian Vector3D representation of this vector. 594 * <p> 595 * The polar to Cartesian transformation is defined by: 596 * <pre> 597 * |x| | radius*cos(azimuth) | 598 * |y| = | radius*sin(azimuth) | 599 * |z| | height | 600 * </pre></p> 601 * 602 * @return a Cartesian Vector3D representation of this vector 603 */ 604 @Override 605 public Vector3D<Q> toVector3D() { 606 607 double radius = _radius.getValue(); 608 double azim = _azimuth.to(SI.RADIAN).getValue(); 609 double z = _height.getValue(); 610 611 double x = radius * cos(azim); 612 double y = radius * sin(azim); 613 614 Vector3D<Q> V = Vector3D.valueOf(x, y, z, getUnit()); 615 616 return V; 617 } 618 619 /** 620 * Compares this Cylindrical3D against the specified object for strict equality (same 621 * values and same units). 622 * 623 * @param obj the object to compare with. 624 * @return <code>true</code> if this vector is identical to that vector; 625 * <code>false</code> otherwise. 626 */ 627 @Override 628 public boolean equals(Object obj) { 629 if (this == obj) 630 return true; 631 if ((obj == null) || (obj.getClass() != this.getClass())) 632 return false; 633 634 Cylindrical3D<?> that = (Cylindrical3D<?>)obj; 635 if (!this._radius.equals(that._radius)) 636 return false; 637 if (!this._azimuth.equals(that._azimuth)) 638 return false; 639 640 return this._height.equals(that._height); 641 } 642 643 /** 644 * Returns the hash code for this parameter. 645 * 646 * @return the hash code value. 647 */ 648 @Override 649 public int hashCode() { 650 int hash = 7; 651 652 int var_code = _radius.hashCode(); 653 hash = hash * 31 + var_code; 654 655 var_code = _azimuth.hashCode(); 656 hash = hash * 31 + var_code; 657 658 var_code = _height.hashCode(); 659 hash = hash * 31 + var_code; 660 661 return hash; 662 } 663 664 /** 665 * Holds the default XML representation. For example: 666 * <pre> 667 * <Radius value="1.73205080756888" unit="m"/> 668 * <Azimuth value="45.0" unit="°" /> 669 * <Height value="35.2643896827547" unit="m" /> 670 * </pre> 671 */ 672 protected static final XMLFormat<Cylindrical3D> XML = new XMLFormat<Cylindrical3D>(Cylindrical3D.class) { 673 674 @Override 675 public Cylindrical3D<?> newInstance(Class<Cylindrical3D> cls, InputElement xml) throws XMLStreamException { 676 return FACTORY.object(); 677 } 678 679 @Override 680 public void read(InputElement xml, Cylindrical3D V) throws XMLStreamException { 681 V._radius = xml.get("Radius", Parameter.class); 682 V._azimuth = xml.get("Azimuth", Parameter.class); 683 V._height = xml.get("Height", Parameter.class); 684 } 685 686 @Override 687 public void write(Cylindrical3D V, OutputElement xml) throws XMLStreamException { 688 xml.add(V._radius, "Radius", Parameter.class); 689 xml.add(V._azimuth, "Azimuth", Parameter.class); 690 xml.add(V._height, "Height", Parameter.class); 691 } 692 }; 693 694 /////////////////////// 695 // Factory creation. // 696 /////////////////////// 697 private Cylindrical3D() { 698 } 699 700 private static final ObjectFactory<Cylindrical3D<? extends Quantity>> FACTORY = new ObjectFactory<Cylindrical3D<? extends Quantity>>() { 701 @Override 702 protected Cylindrical3D<? extends Quantity> create() { 703 return new Cylindrical3D(); 704 } 705 }; 706 707 private static <Q extends Quantity> Cylindrical3D<Q> newInstance() { 708 Cylindrical3D<Q> measure = (Cylindrical3D<Q>)FACTORY.object(); 709 return measure; 710 } 711 712 private static <Q extends Quantity> Cylindrical3D<Q> copyOf(Cylindrical3D<Q> original) { 713 Cylindrical3D<Q> measure = Cylindrical3D.newInstance(); 714 measure._radius = original._radius.copy(); 715 measure._azimuth = original._azimuth.copy(); 716 measure._height = original._height.copy(); 717 return measure; 718 } 719 720}