Program Listing for File coordinate_conversions.cc

Return to documentation for file (conversions/coordinate_conversions.cc)

#include "lupnt/conversions/coordinate_conversions.h"

#include "lupnt/core/constants.h"
#include "lupnt/numerics/math_utils.h"
#include "lupnt/states/state.h"
namespace lupnt {

  State EastNorthUpToAzElRange(const State& enu) {
    Real e = enu(0), n = enu(1), u = enu(2);
    Real range = enu.norm();
    Real az = atan2(e, n);
    Real el = asin(u / range);
    return AzElRange({az, el, range}, enu.GetFrame());
  }
  VEC_IMP_VECTOR(EastNorthUpToAzElRange, 3);

  State AzElRangeToEastNorthUp(const State& aer) {
    Real az = aer(0), el = aer(1), range = aer(2);
    Real e = range * cos(el) * sin(az);
    Real n = range * cos(el) * cos(az);
    Real u = range * sin(el);
    return Cart3({e, n, u}, aer.GetFrame());
  }
  VEC_IMP_VECTOR(AzElRangeToEastNorthUp, 3);

  State LatLonAltToCart(const State& lla, Real R_body, Real flattening) {
    Real lat = lla(0) * RAD, lon = lla(1) * RAD, alt = lla(2);
    Real e2 = flattening * (2 - flattening);
    Real cos_lat = cos(lat);
    Real sin_lat = sin(lat);
    Real N = R_body / sqrt(1 - e2 * sin_lat * sin_lat);
    Real x = (N + alt) * cos_lat * cos(lon);
    Real y = (N + alt) * cos_lat * sin(lon);
    Real z = ((1 - e2) * N + alt) * sin_lat;
    return Cart3({x, y, z}, lla.GetFrame());
  }
  VEC_IMP_VECTOR_REAL(LatLonAltToCart, 3);

  State CartToLatLonAlt(const State& cart, Real R_body, Real flattening) {
    if (abs(R_body) < EPS) R_body = cart.norm();

    Real x = cart(0), y = cart(1), z = cart(2);
    Real e2 = flattening * (2 - flattening);
    const int max_iterations = 1000;

    Real delta_z = e2 * z;  // Initial guess for Δz
    Real delta_z_ant = delta_z + 1e3 * EPS;
    Real sin_phi, N;
    int it = 0;
    while (it < max_iterations && abs(delta_z_ant - delta_z) >= EPS) {
      delta_z_ant = delta_z;
      sin_phi = (z + delta_z) / sqrt(x * x + y * y + (z + delta_z) * (z + delta_z));
      N = R_body / sqrt(1 - e2 * sin_phi * sin_phi);
      delta_z = N * e2 * sin_phi;
      it++;
    }
    if (it >= max_iterations) {
      LUPNT_CHECK(false, "CartToLatLonAlt did not converge", "CartToLatLonAlt");
    }

    Real lon = atan2(y, x);
    Real lat = atan2(z + delta_z, sqrt(x * x + y * y));
    Real h = sqrt(x * x + y * y + (z + delta_z) * (z + delta_z)) - N;
    return LatLonAlt({lat * DEG, lon * DEG, h}, cart.GetFrame());
  }
  VEC_IMP_VECTOR_REAL(CartToLatLonAlt, 3);

  Mat3 RotEastNorthUpToCart(const State& xyz_ref, Real R_body, Real flattening) {
    return RotCartToEastNorthUp(xyz_ref, R_body, flattening).transpose();
  }

  Mat3 RotCartToEastNorthUp(const State& xyz_ref, Real R_body, Real flattening) {
    Vec3 lla = CartToLatLonAlt(xyz_ref, R_body, flattening);
    Real lat = lla(0) * RAD, lon = lla(1) * RAD;
    Mat3 R_body2enu = RotX(PI_OVER_TWO - lat) * RotZ(PI_OVER_TWO + lon);
    return R_body2enu;
  }

  State EastNorthUpToCart(const State& enu, const State& xyz_ref, Real R_body, Real flattening) {
    Mat3 R_enu2body = RotEastNorthUpToCart(xyz_ref, R_body, flattening);
    Vec3 r = R_enu2body * enu + xyz_ref;
    if (enu.size() == 6) {
      Vec3 v = R_enu2body * enu.tail(3);
      return Cart6(r, v, enu.GetFrame());
    } else {
      return Cart3(r, enu.GetFrame());
    }
  }
  VEC_IMP_VECTOR_VECTOR(EastNorthUpToCart, 3);

  State CartToEastNorthUp(const State& xyz, const State& xyz_ref, Real R_body, Real flattening) {
    Mat3 R_body2enu = RotCartToEastNorthUp(xyz_ref, R_body, flattening);
    Vec3 r_enu = R_body2enu * (xyz - xyz_ref);
    if (xyz.size() == 6) {
      Vec3 v_enu = R_body2enu * xyz.tail(3);
      return Cart6(r_enu, v_enu, xyz.GetFrame());
    } else {
      return Cart3(r_enu, xyz.GetFrame());
    }
  }
  VEC_IMP_VECTOR_VECTOR(CartToEastNorthUp, 3);

  State CartToAzElRange(const State& xyz, const State& xyz_ref, Real R_body, Real flattening) {
    State enu = CartToEastNorthUp(xyz, xyz_ref, R_body, flattening);
    State aer = EastNorthUpToAzElRange(enu);
    return AzElRange(aer, xyz.GetFrame());
  }
  VEC_IMP_VECTOR_VECTOR(CartToAzElRange, 3);

  State AzElRangeToCart(const State& aer, const State& xyz_ref, Real R_body, Real flattening) {
    State enu = AzElRangeToEastNorthUp(aer);
    State xyz = EastNorthUpToCart(enu, xyz_ref, R_body, flattening);
    return Cart3(xyz, aer.GetFrame());
  }
  VEC_IMP_VECTOR_VECTOR(AzElRangeToCart, 3);

  State LatLonAltToStereographic(const State& lla, Real R_body) {
    LatLonAlt lla_tmp({lla(0), lla(1), 0}, lla.GetFrame());
    Cart3 xyz_cart = LatLonAltToCart(lla_tmp, R_body, 0);
    Real x = xyz_cart(0), y = xyz_cart(1), z = xyz_cart(2);

    Real xs = 2 * R_body / (R_body - z) * x;
    Real ys = 2 * R_body / (R_body - z) * y;
    Real alt = lla(2);
    return Cart3({xs, ys, alt}, lla.GetFrame());
  }
  VEC_IMP_VECTOR_REAL(LatLonAltToStereographic, 3);

  State StereographicToLatLonAlt(const State& xya, Real R_body) {
    Real xs = xya(0), ys = xya(1), alt = xya(2);
    Real denom = xs * xs + ys * ys + 4 * R_body * R_body;
    Real num = xs * xs + ys * ys - 4 * R_body * R_body;
    Real x = 4 * R_body * R_body * xs / denom;
    Real y = 4 * R_body * R_body * ys / denom;
    Real z = (num * R_body) / denom;

    LatLonAlt lla = CartToLatLonAlt(Cart3({x, y, z}, xya.GetFrame()), R_body, 0);
    lla(2) = alt;
    return lla;
  }
  VEC_IMP_VECTOR_REAL(StereographicToLatLonAlt, 3);

  State StereographicToCart(const State& xya, Real R_body) {
    LatLonAlt lla = StereographicToLatLonAlt(xya, R_body);
    return LatLonAltToCart(lla, R_body, 0);
  }
  VEC_IMP_VECTOR_REAL(StereographicToCart, 3);

  State CartToStereographic(const State& xyz, Real R_body) {
    LatLonAlt lla = CartToLatLonAlt(xyz, R_body, 0);
    return LatLonAltToStereographic(lla, R_body);
  }
  VEC_IMP_VECTOR_REAL(CartToStereographic, 3);

}  // namespace lupnt