SimsWorld/StandardGlobe/standardglobe.cpp

185 lines
5.1 KiB
C++

#include "standardglobe.h"
#include <cmath>
#include <QVector3D>
double StandardGlobe::_radius_m = 6500000;
StandardGlobe::StandardGlobe()
{
}
ECEFv3d StandardGlobe::llaToEcef(const LonLatAlt& v)
{
// 计算距离球心距离
auto axis_r_g = v._alt_m + _radius_m;
// ecef-z坐标
auto axis_z = axis_r_g * sin(deg2a(v._lat_deg));
// 纬度圈半径
auto axis_r_lat = axis_r_g * cos(deg2a(v._lat_deg));
// ecef-x
auto axis_x = axis_r_lat * cos(deg2a(v._lon_deg));
// ecef-y
auto axis_y = axis_r_lat * sin(deg2a(v._lon_deg));
return ECEFv3d{ axis_x, axis_y, axis_z };
}
LonLatAlt StandardGlobe::ecefToLLA(const ECEFv3d& v)
{
auto r2 = std::sqrt(v._x_pos * v._x_pos + v._y_pos * v._y_pos);
auto rad_lon = acos(v._x_pos / r2);
if (v._y_pos < 0)
rad_lon *= -1;
auto rx = std::sqrt(v._x_pos * v._x_pos + v._y_pos * v._y_pos + v._z_pos * v._z_pos);
auto rad_lat = asin(v._z_pos / rx);
if(v._z_pos < 0)
rad_lat *= -1;
LonLatAlt ret;
ret._lon_deg = rad2d(rad_lon);
ret._lat_deg = rad2d(rad_lat);
ret._alt_m = rx - _radius_m;
return ret;
}
void StandardGlobe::getDistanceWithLLA(const LonLatAlt& base, const LonLatAlt& target, double& dist, double& azi)
{
// ecef矢量
auto vec_base = llaToEcef(base).getVec3();
auto vec_target = llaToEcef(target).getVec3();
auto vec_bn = vec_base.normalized();
auto vec_tn = vec_target.normalized();
// 两点之间的矢量夹角
auto cos_between = QVector3D::dotProduct(vec_bn, vec_tn);
// 两点之间最短球面弧线长度
dist = acos(cos_between) * _radius_m;
// 目标平面法线矢量
auto vec_vn = QVector3D::crossProduct(vec_bn, vec_tn).normalized();
// 目标平面切线矢量
auto vec_hn = QVector3D::crossProduct(vec_vn, vec_bn).normalized();
// 初始夹角cos值
auto cos_angle = QVector3D::dotProduct(vec_hn, QVector3D(0, 0, 1));
auto angle = acos(cos_angle);
// 180°校验
auto flag_vec = QVector3D::crossProduct(vec_hn, QVector3D(0, 0, 1)).normalized();
if (vec_bn.z() * flag_vec.z() < 0)
angle = 2 * PI - angle;
// 返回方位角
azi = rad2d(angle);
}
#include <qquaternion.h>
void StandardGlobe::getLLAWithDistance(const LonLatAlt& base, double dist, double azi, LonLatAlt& target)
{
auto ecef_basevec = llaToEcef(base).getVec3().normalized();
QQuaternion u0 = QQuaternion::fromAxisAndAngle(ecef_basevec, -azi);
// 获取切线方向矢量
auto vec_hv = u0.rotatedVector(QVector3D(0, 0, 1)).normalized();
// 获取法线方向矢量
auto vec_bv = QVector3D::crossProduct(ecef_basevec, vec_hv).normalized();
auto rad_between = dist / _radius_m;
QQuaternion u1 = QQuaternion::fromAxisAndAngle(vec_bv, rad2d(rad_between));
auto ecef_t = u1.rotatedVector(llaToEcef(base).getVec3());
ECEFv3d sv;
sv._x_pos = ecef_t.x();
sv._y_pos = ecef_t.y();
sv._z_pos = ecef_t.z();
target = ecefToLLA(sv);
}
PolarPos StandardGlobe::getPolarWithLLA(const LonLatAlt& base, const LonLatAlt& target)
{
// ecef矢量
auto vec_base = llaToEcef(base).getVec3();
auto vec_target = llaToEcef(target).getVec3();
auto vec_bn = vec_base.normalized();
auto vec_tn = vec_target.normalized();
// 目标平面法线矢量
auto vec_vn = QVector3D::crossProduct(vec_bn, vec_tn).normalized();
// 目标平面切线矢量
auto vec_hn = QVector3D::crossProduct(vec_vn, vec_bn).normalized();
// 初始方位角cos值
auto cos_angle = QVector3D::dotProduct(vec_hn, QVector3D(0, 0, 1));
auto angle = acos(cos_angle);
// 180°校验
auto flag_vec = QVector3D::crossProduct(vec_hn, QVector3D(0, 0, 1)).normalized();
if (flag_vec.z() < 0)
angle = 2 * PI - angle;
// 返回方位角
auto azi_deg = rad2d(angle);
// 视线矢量
auto vec_bt = vec_target - vec_base;
auto vec_btn = vec_bt.normalized();
auto cos_pitch = QVector3D::dotProduct(vec_hn, vec_btn);
auto pit_deg = rad2d(acos(cos_pitch));
auto axis_x = QVector3D::crossProduct(vec_hn, vec_btn).normalized();
auto axis_flag = QVector3D::crossProduct(axis_x, vec_hn);
if (QVector3D::dotProduct(axis_flag, vec_bn) < 0) {
pit_deg *= -1;
}
PolarPos p;
p._azimuth_deg = azi_deg;
p._pitch_deg = pit_deg;
p._dist_m = vec_bt.length();
return p;
}
LonLatAlt StandardGlobe::getLLAWithPolar(const LonLatAlt& base, const PolarPos& target)
{
auto ecef_bvec = llaToEcef(base).getVec3();
auto u_azi = QQuaternion::fromAxisAndAngle(ecef_bvec.normalized(),-target._azimuth_deg);
auto vec_ts = u_azi.rotatedVector(QVector3D(0, 0, 1)).normalized();
auto axis_pitch = QVector3D::crossProduct(vec_ts, ecef_bvec.normalized());
auto u_pit = QQuaternion::fromAxisAndAngle(axis_pitch, target._pitch_deg);
auto ts_appv = u_pit.rotatedVector(vec_ts).normalized() * target._dist_m;
auto ecef_target = ecef_bvec + ts_appv;
ECEFv3d tt = ECEFv3d::fromVec3(ecef_target);
return ecefToLLA(tt);
}
QVector3D ECEFv3d::getVec3() const
{
return QVector3D(_x_pos, _y_pos, _z_pos);
}
ECEFv3d ECEFv3d::fromVec3(const QVector3D& p) {
ECEFv3d o;
o._x_pos = p.x();
o._y_pos = p.y();
o._z_pos = p.z();
return o;
}
LonLatAlt::LonLatAlt(const LonLatPos& plain_pos)
: _lon_deg(plain_pos._lon_deg),
_lat_deg(plain_pos._lat_deg),
_alt_m(0) {
}
LonLatAlt::LonLatAlt(double lon, double lat, double alt)
:_lon_deg(lon), _lat_deg(lat), _alt_m(alt) {
}
LonLatPos LonLatAlt::toLonLatPos() const
{
return LonLatPos{ _lon_deg, _lat_deg };
}