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