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 &lt; 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     *    &lt;Radius value="1.73205080756888" unit="m"/&gt;
668     *    &lt;Azimuth value="45.0" unit="°" /&gt;
669     *    &lt;Height value="35.2643896827547" unit="m" /&gt;
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}