| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | #include "base/gps.h" |
| |
|
| | #include "util/math.h" |
| |
|
| | namespace colmap { |
| |
|
| | GPSTransform::GPSTransform(const int ellipsoid) { |
| | switch (ellipsoid) { |
| | case GRS80: |
| | a_ = 6378137.0; |
| | f_ = 1.0 / 298.257222100882711243162837; |
| | b_ = (1.0 - f_) * a_; |
| | break; |
| | case WGS84: |
| | a_ = 6378137.0; |
| | f_ = 1.0 / 298.257223563; |
| | b_ = (1.0 - f_) * a_; |
| | break; |
| | default: |
| | a_ = std::numeric_limits<double>::quiet_NaN(); |
| | b_ = std::numeric_limits<double>::quiet_NaN(); |
| | f_ = std::numeric_limits<double>::quiet_NaN(); |
| | throw std::invalid_argument("Ellipsoid not defined"); |
| | } |
| | e2_ = f_ * (2.0 - f_); |
| | } |
| |
|
| | std::vector<Eigen::Vector3d> GPSTransform::EllToXYZ( |
| | const std::vector<Eigen::Vector3d>& ell) const { |
| | std::vector<Eigen::Vector3d> xyz(ell.size()); |
| |
|
| | for (size_t i = 0; i < ell.size(); ++i) { |
| | const double lat = DegToRad(ell[i](0)); |
| | const double lon = DegToRad(ell[i](1)); |
| | const double alt = ell[i](2); |
| |
|
| | const double sin_lat = sin(lat); |
| | const double sin_lon = sin(lon); |
| | const double cos_lat = cos(lat); |
| | const double cos_lon = cos(lon); |
| |
|
| | |
| | const double N = a_ / sqrt(1 - e2_ * sin_lat * sin_lat); |
| |
|
| | xyz[i](0) = (N + alt) * cos_lat * cos_lon; |
| | xyz[i](1) = (N + alt) * cos_lat * sin_lon; |
| | xyz[i](2) = (N * (1 - e2_) + alt) * sin_lat; |
| | } |
| |
|
| | return xyz; |
| | } |
| |
|
| | std::vector<Eigen::Vector3d> GPSTransform::XYZToEll( |
| | const std::vector<Eigen::Vector3d>& xyz) const { |
| | std::vector<Eigen::Vector3d> ell(xyz.size()); |
| |
|
| | for (size_t i = 0; i < ell.size(); ++i) { |
| | const double x = xyz[i](0); |
| | const double y = xyz[i](1); |
| | const double z = xyz[i](2); |
| |
|
| | const double radius_xy = std::sqrt(x * x + y * y); |
| | const double kEps = 1e-12; |
| |
|
| | |
| | double lat = atan2(z, radius_xy); |
| | double alt; |
| |
|
| | for (size_t j = 0; j < 100; ++j) { |
| | const double sin_lat0 = sin(lat); |
| | const double N = a_ / sqrt(1 - e2_ * sin_lat0 * sin_lat0); |
| | const double prev_alt = alt; |
| | alt = radius_xy / cos(lat) - N; |
| | const double prev_lat = lat; |
| | lat = std::atan((z / radius_xy) * 1 / (1 - e2_ * N / (N + alt))); |
| |
|
| | if (std::abs(prev_lat - lat) < kEps && std::abs(prev_alt - alt) < kEps) { |
| | break; |
| | } |
| | } |
| |
|
| | ell[i](0) = RadToDeg(lat); |
| |
|
| | |
| | ell[i](1) = RadToDeg(atan2(y, x)); |
| | |
| | ell[i](2) = alt; |
| | } |
| |
|
| | return ell; |
| | } |
| |
|
| | std::vector<Eigen::Vector3d> GPSTransform::EllToENU( |
| | const std::vector<Eigen::Vector3d>& ell, const double lat0, |
| | const double lon0) const { |
| | |
| | std::vector<Eigen::Vector3d> xyz = EllToXYZ(ell); |
| |
|
| | return XYZToENU(xyz, lat0, lon0); |
| | } |
| |
|
| | std::vector<Eigen::Vector3d> GPSTransform::XYZToENU( |
| | const std::vector<Eigen::Vector3d>& xyz, const double lat0, |
| | const double lon0) const { |
| | std::vector<Eigen::Vector3d> enu(xyz.size()); |
| |
|
| | |
| |
|
| | |
| | const double cos_lat0 = std::cos(DegToRad(lat0)); |
| | const double sin_lat0 = std::sin(DegToRad(lat0)); |
| |
|
| | const double cos_lon0 = std::cos(DegToRad(lon0)); |
| | const double sin_lon0 = std::sin(DegToRad(lon0)); |
| |
|
| | Eigen::Matrix3d R; |
| | R << -sin_lon0, cos_lon0, 0., -sin_lat0 * cos_lon0, -sin_lat0 * sin_lon0, |
| | cos_lat0, cos_lat0 * cos_lon0, cos_lat0 * sin_lon0, sin_lat0; |
| |
|
| | |
| | for (size_t i = 0; i < xyz.size(); ++i) { |
| | enu[i] = R * (xyz[i] - xyz[0]); |
| | } |
| |
|
| | return enu; |
| | } |
| |
|
| | std::vector<Eigen::Vector3d> GPSTransform::ENUToEll( |
| | const std::vector<Eigen::Vector3d>& enu, const double lat0, |
| | const double lon0, const double alt0) const { |
| | return XYZToEll(ENUToXYZ(enu, lat0, lon0, alt0)); |
| | } |
| |
|
| | std::vector<Eigen::Vector3d> GPSTransform::ENUToXYZ( |
| | const std::vector<Eigen::Vector3d>& enu, const double lat0, |
| | const double lon0, const double alt0) const { |
| | std::vector<Eigen::Vector3d> xyz(enu.size()); |
| |
|
| | |
| | const Eigen::Vector3d xyz_ref = |
| | EllToXYZ({Eigen::Vector3d(lat0, lon0, alt0)})[0]; |
| |
|
| | |
| | const double cos_lat0 = std::cos(DegToRad(lat0)); |
| | const double sin_lat0 = std::sin(DegToRad(lat0)); |
| |
|
| | const double cos_lon0 = std::cos(DegToRad(lon0)); |
| | const double sin_lon0 = std::sin(DegToRad(lon0)); |
| |
|
| | Eigen::Matrix3d R; |
| | R << -sin_lon0, cos_lon0, 0., -sin_lat0 * cos_lon0, -sin_lat0 * sin_lon0, |
| | cos_lat0, cos_lat0 * cos_lon0, cos_lat0 * sin_lon0, sin_lat0; |
| |
|
| | |
| | R.transposeInPlace(); |
| |
|
| | |
| | for (size_t i = 0; i < enu.size(); ++i) { |
| | xyz[i] = (R * enu[i]) + xyz_ref; |
| | } |
| |
|
| | return xyz; |
| | } |
| |
|
| | } |
| |
|