• WGS84坐标系-地心地固坐标系-东北天坐标系


    目录

    1、前言

    2、转换过程

    3、代码示例

     4、参考资料


    1、前言

    工作中遇见个问题,就是ue4中,使用的坐标描述是使用东北天坐标系,因为如果经纬度只能表达到小数点后6位,这就造成有时间物体摆放位置不准确的问题。解决这个问题,就是把经纬度在转成ue里边能够使用的东北天坐标系。东北天坐标系又叫站心坐标系,这个站心可以是自己定义的。

    2、转换过程

    本文标题:WGS84坐标系-地心地固坐标系-东北天坐标系

    不熟悉地理坐标系的小伙伴可以看着比较晕,可以看下边:

    • WGS84坐标系-地心地固坐标系

    wgs84就是我们经常说的经纬度,那边经纬度只是我们讲地球划线,利用经纬度来确定地球上一个位置,但是当我们要计算地球上物体怎么进行位置变换或者距离计算时,我们需要把wgs84做坐标系转换,转换成适合计算的坐标系。因此,地心地固坐标系就是以笛卡尔坐标建立起来的坐标。并且这时候,地球是当作椭球来处理的。经纬度转笛卡尔坐标系可以看我之前这篇文章

    (5条消息) 经纬度转笛卡尔坐标_谢大旭的博客-CSDN博客

    • 地心地固坐标系-东北天坐标系

    站心坐标系以一个站心点为坐标原点,当把坐标系定义为X轴指东、Y轴指北,Z轴指天,就是ENU(东北天)站心坐标系。这样,从地心地固坐标系转换成的站心坐标系,就会成为一个符合常人对地理位置认知的局部坐标系。同时,只要站心点位置选的合理(通常可选取地理表达区域的中心点),表达的地理坐标都会是很小的值,非常便于空间计算。

    ENU、ECEF之间的转换,一个很明显的图形操作是平移变换,将站心移动到地心或者将地心转换到站心,另外一个需要进行的图形变换是旋转变换,其旋转变换矩阵根据P点所在的经度L和纬度B确定。但是的经纬度不适合计算旋转矩阵,旋转矩阵的计算应该在笛卡尔坐标系下来计算。

    3、代码示例

    1. #include <iostream>
    2. #include <eigen3/Eigen/Eigen>
    3. #include <osgEarth/GeoData>
    4. using namespace std;
    5. const double epsilon = 0.000000000000001;
    6. const double pi = 3.14159265358979323846;
    7. const double d2r = pi / 180;
    8. const double r2d = 180 / pi;
    9. const double a = 6378137.0; //椭球长半轴
    10. const double f_inverse = 298.257223563; //扁率倒数
    11. const double b = a - a / f_inverse;
    12. //const double b = 6356752.314245; //椭球短半轴
    13. const double e = sqrt(a * a - b * b) / a;
    14. void Blh2Xyz(double &x, double &y, double &z)
    15. {
    16. double L = x * d2r;
    17. double B = y * d2r;
    18. double H = z;
    19. double N = a / sqrt(1 - e * e * sin(B) * sin(B));
    20. x = (N + H) * cos(B) * cos(L);
    21. y = (N + H) * cos(B) * sin(L);
    22. z = (N * (1 - e * e) + H) * sin(B);
    23. }
    24. void Xyz2Blh(double &x, double &y, double &z)
    25. {
    26. double tmpX = x;
    27. double temY = y ;
    28. double temZ = z;
    29. double curB = 0;
    30. double N = 0;
    31. double calB = atan2(temZ, sqrt(tmpX * tmpX + temY * temY));
    32. int counter = 0;
    33. while (abs(curB - calB) * r2d > epsilon && counter < 25)
    34. {
    35. curB = calB;
    36. N = a / sqrt(1 - e * e * sin(curB) * sin(curB));
    37. calB = atan2(temZ + N * e * e * sin(curB), sqrt(tmpX * tmpX + temY * temY));
    38. counter++;
    39. }
    40. x = atan2(temY, tmpX) * r2d;
    41. y = curB * r2d;
    42. z = temZ / sin(curB) - N * (1 - e * e);
    43. }
    44. void TestBLH2XYZ()
    45. {
    46. //double x = 113.6;
    47. //double y = 38.8;
    48. //double z = 100;
    49. //
    50. //printf("原大地经纬度坐标:%.10lf %.10lf %.10lf
    51. ", x, y, z);
    52. //Blh2Xyz(x, y, z);
    53. //printf("地心地固直角坐标:%.10lf %.10lf %.10lf
    54. ", x, y, z);
    55. //Xyz2Blh(x, y, z);
    56. //printf("转回大地经纬度坐标:%.10lf %.10lf %.10lf
    57. ", x, y, z);
    58. double x = -2318400.6045575836;
    59. double y = 4562004.801366804;
    60. double z = 3794303.054150639;
    61. //116.9395751953 36.7399177551
    62. printf("地心地固直角坐标:%.10lf %.10lf %.10lf
    63. ", x, y, z);
    64. Xyz2Blh(x, y, z);
    65. printf("转回大地经纬度坐标:%.10lf %.10lf %.10lf
    66. ", x, y, z);
    67. }
    68. void CalEcef2Enu(Eigen::Vector3d& topocentricOrigin, Eigen::Matrix4d& resultMat)
    69. {
    70. double rzAngle = -(topocentricOrigin.x() * d2r + pi / 2);
    71. Eigen::AngleAxisd rzAngleAxis(rzAngle, Eigen::Vector3d(0, 0, 1));
    72. Eigen::Matrix3d rZ = rzAngleAxis.matrix();
    73. double rxAngle = -(pi / 2 - topocentricOrigin.y() * d2r);
    74. Eigen::AngleAxisd rxAngleAxis(rxAngle, Eigen::Vector3d(1, 0, 0));
    75. Eigen::Matrix3d rX = rxAngleAxis.matrix();
    76. Eigen::Matrix4d rotation;
    77. rotation.setIdentity();
    78. rotation.block<3, 3>(0, 0) = (rX * rZ);
    79. //cout << rotation << endl;
    80. double tx = topocentricOrigin.x();
    81. double ty = topocentricOrigin.y();
    82. double tz = topocentricOrigin.z();
    83. Blh2Xyz(tx, ty, tz);
    84. Eigen::Matrix4d translation;
    85. translation.setIdentity();
    86. translation(0, 3) = -tx;
    87. translation(1, 3) = -ty;
    88. translation(2, 3) = -tz;
    89. resultMat = rotation * translation;
    90. }
    91. void CalEnu2Ecef(Eigen::Vector3d& topocentricOrigin, Eigen::Matrix4d& resultMat)
    92. {
    93. double rzAngle = (topocentricOrigin.x() * d2r + pi / 2);
    94. Eigen::AngleAxisd rzAngleAxis(rzAngle, Eigen::Vector3d(0, 0, 1));
    95. Eigen::Matrix3d rZ = rzAngleAxis.matrix();
    96. double rxAngle = (pi / 2 - topocentricOrigin.y() * d2r);
    97. Eigen::AngleAxisd rxAngleAxis(rxAngle, Eigen::Vector3d(1, 0, 0));
    98. Eigen::Matrix3d rX = rxAngleAxis.matrix();
    99. Eigen::Matrix4d rotation;
    100. rotation.setIdentity();
    101. rotation.block<3, 3>(0, 0) = (rZ * rX);
    102. //cout << rotation << endl;
    103. double tx = topocentricOrigin.x();
    104. double ty = topocentricOrigin.y();
    105. double tz = topocentricOrigin.z();
    106. Blh2Xyz(tx, ty, tz);
    107. Eigen::Matrix4d translation;
    108. translation.setIdentity();
    109. translation(0, 3) = tx;
    110. translation(1, 3) = ty;
    111. translation(2, 3) = tz;
    112. resultMat = translation * rotation;
    113. }
    114. void TestXYZ2ENU()
    115. {
    116. double L = 116.9395751953;
    117. double B = 36.7399177551;
    118. double H = 0;
    119. cout << fixed << endl;
    120. Eigen::Vector3d topocentricOrigin(L, B, H);
    121. Eigen::Matrix4d wolrd2localMatrix;
    122. CalEcef2Enu(topocentricOrigin, wolrd2localMatrix);
    123. cout << "地心转站心矩阵:" << endl;
    124. cout << wolrd2localMatrix << endl<<endl;
    125. cout << "站心转地心矩阵:" << endl;
    126. Eigen::Matrix4d local2WolrdMatrix;
    127. CalEnu2Ecef(topocentricOrigin, local2WolrdMatrix);
    128. cout << local2WolrdMatrix << endl;
    129. double x = 117;
    130. double y = 37;
    131. double z = 10.3;
    132. Blh2Xyz(x, y, z);
    133. cout << "ECEF坐标(世界坐标):";
    134. Eigen::Vector4d xyz(x, y, z, 1);
    135. cout << xyz << endl;
    136. cout << "ENU坐标(局部坐标):";
    137. Eigen::Vector4d enu = wolrd2localMatrix * xyz;
    138. cout << enu << endl;
    139. }
    140. void TestOE()
    141. {
    142. double L = 116.9395751953;
    143. double B = 36.7399177551;
    144. double H = 0;
    145. osgEarth::SpatialReference *spatialReference = osgEarth::SpatialReference::create("epsg:4326");
    146. osgEarth::GeoPoint centerPoint(spatialReference, L, B, H);
    147. osg::Matrixd worldToLocal;
    148. centerPoint.createWorldToLocal(worldToLocal);
    149. cout << fixed << endl;
    150. cout << "地心转站心矩阵:" << endl;
    151. for (int i = 0; i < 4; i++)
    152. {
    153. for (int j = 0; j < 4; j++)
    154. {
    155. printf("%lf ", worldToLocal.ptr()[j * 4 + i]);
    156. }
    157. cout << endl;
    158. }
    159. cout << endl;
    160. osg::Matrixd localToWorld;
    161. centerPoint.createLocalToWorld(localToWorld);
    162. cout << "站心转地心矩阵:" << endl;
    163. for (int i = 0; i < 4; i++)
    164. {
    165. for (int j = 0; j < 4; j++)
    166. {
    167. printf("%lf ", localToWorld.ptr()[j * 4 + i]);
    168. }
    169. cout << endl;
    170. }
    171. cout << endl;
    172. double x = 117;
    173. double y = 37;
    174. double z = 10.3;
    175. osgEarth::GeoPoint geoPoint(spatialReference, x, y, z);
    176. cout << "ECEF坐标(世界坐标):";
    177. osg::Vec3d out_world;
    178. geoPoint.toWorld(out_world);
    179. cout << out_world.x() <<' '<< out_world.y() << ' ' << out_world.z() << endl;
    180. cout << "ENU坐标(局部坐标):";
    181. osg::Vec3d localCoord = worldToLocal.preMult(out_world);
    182. cout << localCoord.x() << ' ' << localCoord.y() << ' ' << localCoord.z() << endl;
    183. }
    184. int main()
    185. {
    186. //TestBLH2XYZ();
    187. cout << "使用Eigen进行转换实现:" << endl;
    188. TestXYZ2ENU();
    189. cout <<"---------------------------------------"<< endl;
    190. cout << "通过OsgEarth进行验证:" << endl;
    191. TestOE();
    192. }

     4、参考资料

    本着深入学习的态度,经过一番搜索,又找到一篇博客。直接带我起飞。

    地心地固坐标系(ECEF)与站心坐标系(ENU)的转换 - 走看看 (zoukankan.com)

  • 相关阅读:
    【理解ARM架构】不同方式点灯 | ARM架构简介 | 常见汇编指令 | C与汇编
    线程 转储
    【深度学习】图像分类数据集Fashion-MNIST
    R语言:多值提取到点
    Spring Data JPA 按多个列排序
    spring6-提前编译:AOT
    dedecms tag 伪静态 数字版本
    java进阶之路
    神光秘诀React
    探索互联世界的灯光艺术:FastLED库详细介绍及应用实例
  • 原文地址:https://blog.csdn.net/cangqiongxiaoye/article/details/126559605