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

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

  35.     /**
  36.      * Construct a new Speed3D from vector of strongly typed Cartesian coordinates.
  37.      * @param speed SpeedVector; the speeds in 3D (YPR coded)
  38.      * @throws ValueException in case the vector does not have exactly three elements
  39.      */
  40.     public Speed3D(final SpeedVector speed) throws ValueException
  41.     {
  42.         super();
  43.         if (speed.size() != 3)
  44.         {
  45.             throw new ValueException("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 ValueException in case the units are incorrect
  55.      */
  56.     public Speed3D(final Speed x, final Speed y, final Speed z) throws ValueException
  57.     {
  58.         super();
  59.         this.speed = new SpeedVector(new Speed[] { x, y, z }, StorageType.DENSE);
  60.     }

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

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

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

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

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

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

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

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

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

  170. }