/**
   * Defines an elliptical orbit around a point.
   *
   * @param focalPoint Point which the {@link ATransformable3D} orbits around.
   * @param periapsis Point which the object passes closest to the focal point.
   * @param normal Normal to the orbital plane. This defines the orbital inclination.
   * @param eccentricity Eccentricity of the orbit. Zero value results in a circular orbit.
   * @param angle Degrees to rotate.
   */
  public EllipticalOrbitAnimation3D(
      Vector3 focalPoint, Vector3 periapsis, Vector3 normal, double eccentricity, double angle) {
    super();
    mFocalPoint = focalPoint;
    mPeriapsis = periapsis;
    mNormal = normal.clone();
    mEccentricity = eccentricity;
    mAngle = angle;

    mDirection = (mAngle < 0) ? OrbitDirection.CLOCKWISE : OrbitDirection.COUNTERCLOCKWISE;
    mAngle = Math.abs(mAngle);
  }
 /**
  * Defines an elliptical orbit around a point.
  *
  * @param focalPoint Point which the {@link ATransformable3D} orbits around.
  * @param periapsis Point which the object passes closest to the focal point.
  * @param normal Normal to the orbital plane. This defines the orbital inclination.
  * @param eccentricity Eccentricity of the orbit. Zero value results in a circular orbit.
  * @param direction Direction of the orbit.
  */
 public EllipticalOrbitAnimation3D(
     Vector3 focalPoint,
     Vector3 periapsis,
     Vector3 normal,
     double eccentricity,
     OrbitDirection direction) {
   super();
   mFocalPoint = focalPoint;
   mPeriapsis = periapsis;
   mNormal = normal.clone();
   mEccentricity = eccentricity;
   mDirection = direction;
   mAngle = 360.0;
 }
  @Override
  protected void applyTransformation() {
    // Everything here is stored in double precision because single precision floating point causes
    // a major
    // overflow. Number3D still stores internally in single precision so all the calculation will be
    // done in here
    // until Number3D is completely overhauled. Theory behind math in this method can be looked up
    // easily on
    // Wikipedia.

    // Angle in radians (interpolated time from 0 to 1 results in radian angle 0 to 2PI)
    double angle =
        (mDirection == OrbitDirection.CLOCKWISE ? -1 : 1) * mAngle * mInterpolatedTime * PI_DIV_180;

    // Calculate the distances of periapsis and apoapsis to the focal point.
    double periapsisRadius = mPeriapsis.distanceTo(mFocalPoint);
    double apoapsisRadius = periapsisRadius * (1 + mEccentricity) / (1 - mEccentricity);

    // Get the apoapsis point which will be needed to calculate the center point of the ellipse.
    // NOTE: Discard least significant digits after 8th decimal places to lower the computational
    // error epsilon.
    double uAx = (Math.round(mFocalPoint.x * 1e8) - Math.round(mPeriapsis.x * 1e8)) / 1e8;
    double uAy = (Math.round(mFocalPoint.y * 1e8) - Math.round(mPeriapsis.y * 1e8)) / 1e8;
    double uAz = (Math.round(mFocalPoint.z * 1e8) - Math.round(mPeriapsis.z * 1e8)) / 1e8;
    double mod = Math.sqrt(uAx * uAx + uAy * uAy + uAz * uAz);
    if (mod != 0 && mod != 1) {
      mod = 1 / mod;
      uAx *= mod;
      uAy *= mod;
      uAz *= mod;
    }
    double apoapsisDir_x = Math.round(uAx * apoapsisRadius * 1e8) / 1e8;
    double apoapsisDir_y = Math.round(uAy * apoapsisRadius * 1e8) / 1e8;
    double apoapsisDir_z = Math.round(uAz * apoapsisRadius * 1e8) / 1e8;
    double apoapsisPos_x = Math.round((apoapsisDir_x + mFocalPoint.x) * 1e8) / 1e8;
    double apoapsisPos_y = Math.round((apoapsisDir_y + mFocalPoint.y) * 1e8) / 1e8;
    double apoapsisPos_z = Math.round((apoapsisDir_z + mFocalPoint.z) * 1e8) / 1e8;

    // Midpoint between apoapsis and periapsis is the center of the ellipse.
    double center_x = Math.round(((mPeriapsis.x + apoapsisPos_x) / 2) * 1e8) / 1e8;
    double center_y = Math.round(((mPeriapsis.y + apoapsisPos_y) / 2) * 1e8) / 1e8;
    double center_z = Math.round(((mPeriapsis.z + apoapsisPos_z) / 2) * 1e8) / 1e8;

    // Calculate semiminor axis length.
    double b = Math.sqrt(periapsisRadius * apoapsisRadius);

    // Direction vector to periapsis from the center point and ascending node from the center point
    double semimajorAxis_x = Math.round((mPeriapsis.x - center_x) * 1e8) / 1e8;
    double semimajorAxis_y = Math.round((mPeriapsis.y - center_y) * 1e8) / 1e8;
    double semimajorAxis_z = Math.round((mPeriapsis.z - center_z) * 1e8) / 1e8;
    double unitSemiMajorAxis_x = semimajorAxis_x;
    double unitSemiMajorAxis_y = semimajorAxis_y;
    double unitSemiMajorAxis_z = semimajorAxis_z;
    mod =
        Math.sqrt(
            semimajorAxis_x * semimajorAxis_x
                + semimajorAxis_y * semimajorAxis_y
                + semimajorAxis_z * semimajorAxis_z);
    if (mod != 0 && mod != 1) {
      mod = 1 / mod;
      unitSemiMajorAxis_x *= mod;
      unitSemiMajorAxis_y *= mod;
      unitSemiMajorAxis_z *= mod;
    }

    // Translate normal vector to the center point.
    Vector3 unitNormal = mNormal.clone();
    unitNormal.normalize();
    double uNx = Math.round(unitNormal.x * 1e8) / 1e8;
    double uNy = Math.round(unitNormal.y * 1e8) / 1e8;
    double uNz = Math.round(unitNormal.z * 1e8) / 1e8;
    double normalCenter_x = center_x + uNx;
    double normalCenter_y = center_y + uNy;
    double normalCenter_z = center_z + uNz;
    mod =
        Math.sqrt(
            normalCenter_x * normalCenter_x
                + normalCenter_y * normalCenter_y
                + normalCenter_z * normalCenter_z);
    if (mod != 0 && mod != 1) {
      mod = 1 / mod;
      normalCenter_x *= mod;
      normalCenter_y *= mod;
      normalCenter_z *= mod;
    }

    // We can calculate the semiminor axis from unit vector of cross product of semimajor axis and
    // the normal.
    Vector3 unitSemiminorAxis =
        Vector3.crossAndCreate(
            new Vector3(unitSemiMajorAxis_x, unitSemiMajorAxis_y, unitSemiMajorAxis_z),
            new Vector3(normalCenter_x, normalCenter_y, normalCenter_z));
    Vector3 semiminorAxis = Vector3.scaleAndCreate(unitSemiminorAxis, (float) b);

    // Parametric equation for ellipse in 3D space.
    double x = center_x + (Math.cos(angle) * semimajorAxis_x) + (Math.sin(angle) * semiminorAxis.x);
    double y = center_y + (Math.cos(angle) * semimajorAxis_y) + (Math.sin(angle) * semiminorAxis.y);
    double z = center_z + (Math.cos(angle) * semimajorAxis_z) + (Math.sin(angle) * semiminorAxis.z);
    mTransformable3D.setPosition((float) x, (float) y, (float) z);
  }