Speed3D.java

  1. package org.opentrafficsim.core.math;

  2. import java.io.Serializable;
  3. import java.util.Locale;

  4. import org.djunits.unit.DirectionUnit;
  5. import org.djunits.unit.SpeedUnit;
  6. import org.djunits.value.ValueRuntimeException;
  7. import org.djunits.value.storage.StorageType;
  8. import org.djunits.value.vdouble.scalar.Direction;
  9. import org.djunits.value.vdouble.scalar.Speed;
  10. import org.djunits.value.vdouble.vector.SpeedVector;
  11. import org.djunits.value.vdouble.vector.base.DoubleVector;

  12. /**
  13.  * A 3D speed vector, decomposed in X, Y, and Z-speed with easy conversion from and to a spherical coordinate system. <br>
  14.  * <a href="https://en.wikipedia.org/wiki/Spherical_coordinate_system">Physicists and mathematicians <strong>do not</strong>
  15.  * agree on the meaning of theta and phi.</a> In this class the convention in the physics domain is used:
  16.  * <ul>
  17.  * <li>theta is the angle from the z direction.</li>
  18.  * <li>phi is the projected angle in the xy-plane from the x direction.</li>
  19.  * </ul>
  20.  * N.B. In the geography domain yet another convention is used. <br>
  21.  * <p>
  22.  * Copyright (c) 2013-2022 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
  23.  * BSD-style license. See <a href="http://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
  24.  * </p>
  25.  * $LastChangedDate: 2015-07-24 02:58:59 +0200 (Fri, 24 Jul 2015) $, @version $Revision: 1147 $, by $Author: averbraeck $,
  26.  * initial version Dec 10, 2015 <br>
  27.  * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
  28.  * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
  29.  */
  30. public class Speed3D implements Serializable
  31. {
  32.     /** */
  33.     private static final long serialVersionUID = 20160000L;

  34.     /** The speed in 3D (XYZ coded). */
  35.     private final SpeedVector speed;

  36.     /**
  37.      * Construct a new Speed3D from vector of strongly typed Cartesian coordinates.
  38.      * @param speed SpeedVector; the speeds in 3D (YPR coded)
  39.      * @throws ValueRuntimeException in case the vector does not have exactly three elements
  40.      */
  41.     public Speed3D(final SpeedVector speed) throws ValueRuntimeException
  42.     {
  43.         if (speed.size() != 3)
  44.         {
  45.             throw new ValueRuntimeException("Size of an RPY-speed vector should be exactly 3. Got: " + speed);
  46.         }
  47.         this.speed = speed;
  48.     }

  49.     /**
  50.      * Construct a new Speed3D from three strongly typed Cartesian coordinates.
  51.      * @param x Speed; the speed in the x-direction
  52.      * @param y Speed; the speed in the y-direction
  53.      * @param z Speed; the speed in the z-direction
  54.      * @throws ValueRuntimeException in case the units are incorrect
  55.      */
  56.     public Speed3D(final Speed x, final Speed y, final Speed z) throws ValueRuntimeException
  57.     {
  58.         this.speed = DoubleVector.instantiate(new Speed[] {x, y, z}, x.getDisplayUnit(), StorageType.DENSE);
  59.     }

  60.     /**
  61.      * Construct a new Speed3D from three double Cartesian coordinates and a speed unit.
  62.      * @param x double; the speed in the x-direction
  63.      * @param y double; the speed in the y-direction
  64.      * @param z double; the speed in the z-direction
  65.      * @param unit SpeedUnit; the unit of the xyz parameters
  66.      * @throws ValueRuntimeException in case the units are incorrect
  67.      */
  68.     public Speed3D(final double x, final double y, final double z, final SpeedUnit unit) throws ValueRuntimeException
  69.     {
  70.         this.speed = DoubleVector.instantiate(new double[] {x, y, z}, unit, StorageType.DENSE);
  71.     }

  72.     /**
  73.      * Construct a new Speed3D from a strongly typed speed and polar coordinates.
  74.      * @param speed Speed; the speed in the direction of the angle along the vector
  75.      * @param theta Direction; the angle from the z direction
  76.      * @param phi Direction; the projected angle in the xy-plane from the x direction
  77.      * @throws ValueRuntimeException in case the vector does not have exactly three elements
  78.      */
  79.     public Speed3D(final Speed speed, final Direction theta, final Direction phi) throws ValueRuntimeException
  80.     {
  81.         double[] xyz = Scalar3D.polarToCartesian(speed.getInUnit(), theta.si, phi.si);
  82.         this.speed = DoubleVector.instantiate(xyz, speed.getDisplayUnit(), StorageType.DENSE);
  83.     }

  84.     /**
  85.      * Retrieve the x-component of this Speed3D.
  86.      * @return the speed in the x-direction.
  87.      */
  88.     public final Speed getX()
  89.     {
  90.         try
  91.         {
  92.             return this.speed.get(0);
  93.         }
  94.         catch (ValueRuntimeException exception)
  95.         {
  96.             // should be impossible as we constructed the vector always with three elements
  97.             throw new RuntimeException(
  98.                     "getX() gave an exception; apparently vector " + this.speed + " was not constructed right", exception);
  99.         }
  100.     }

  101.     /**
  102.      * Retrieve the y-component of this Speed3D.
  103.      * @return the speed in the y-direction.
  104.      */
  105.     public final Speed getY()
  106.     {
  107.         try
  108.         {
  109.             return this.speed.get(1);
  110.         }
  111.         catch (ValueRuntimeException exception)
  112.         {
  113.             // should be impossible as we constructed the vector always with three elements
  114.             throw new RuntimeException(
  115.                     "getY() gave an exception; apparently vector " + this.speed + " was not constructed right", exception);
  116.         }
  117.     }

  118.     /**
  119.      * Retrieve the z-component of this Speed3D.
  120.      * @return the speed in the z-direction.
  121.      */
  122.     public final Speed getZ()
  123.     {
  124.         try
  125.         {
  126.             return this.speed.get(2);
  127.         }
  128.         catch (ValueRuntimeException exception)
  129.         {
  130.             // should be impossible as we constructed the vector always with three elements
  131.             throw new RuntimeException(
  132.                     "getZ() gave an exception; apparently vector " + this.speed + " was not constructed right", exception);
  133.         }
  134.     }

  135.     /**
  136.      * Retrieve the theta of this Speed3D.
  137.      * @return the angle of direction perpendicular to the xy-plane
  138.      */
  139.     public final Direction getTheta()
  140.     {
  141.         return Scalar3D.cartesianToTheta(getX().si, getY().si, getZ().si);
  142.     }

  143.     /**
  144.      * Retrieve the phi of this Speed3D.
  145.      * @return the projected angle of direction in the xy-plane
  146.      */
  147.     public final Direction getPhi()
  148.     {
  149.         return Scalar3D.cartesianToPhi(getX().si, getY().si);
  150.     }

  151.     /**
  152.      * Retrieve the norm of this Speed3D.
  153.      * @return the combined speed in the direction of the angle
  154.      */
  155.     public final Speed getSpeed()
  156.     {
  157.         return new Speed(Scalar3D.cartesianToRadius(getX().si, getY().si, getZ().si), SpeedUnit.SI);
  158.     }

  159.     /** {@inheritDoc} */
  160.     @Override
  161.     public final String toString()
  162.     {
  163.         return String.format(Locale.US, "Speed3D %s (%s, theta %s, phi %s)", this.speed, getSpeed(),
  164.                 new Direction(getTheta().getInUnit(DirectionUnit.EAST_DEGREE), DirectionUnit.EAST_DEGREE),
  165.                 new Direction(getPhi().getInUnit(DirectionUnit.EAST_DEGREE), DirectionUnit.EAST_DEGREE));
  166.     }

  167. }