You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

distance.cpp 6.6 kB

2 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. /****************************************************************************
  2. * Copyright (C) 2020 by Simulation Team, NavInfo Ltd. *
  3. * *
  4. * This file is part of Simulation Core Software Stack. *
  5. * *
  6. * Simulation Core is a commercial autonomous driving simulation solution.*
  7. * *
  8. * You should have received a copy of the NavInfo EULA License along with *
  9. * the software. If not, please contact us, <simulation@navinfo.com>. *
  10. ****************************************************************************/
  11. #include "geo/private/base/constant.h"
  12. #include "geo/private/math/angle.h"
  13. #include "geo/private/math/distance.h"
  14. #include "geo/private/math/trigonometric.h"
  15. namespace ns
  16. {
  17. namespace geo
  18. {
  19. double flat_distance(const PointD& p1, const PointD& p2)
  20. {
  21. const double dx = p1.x - p2.x;
  22. const double dy = p1.y - p2.y;
  23. return std::sqrt(dx * dx + dy * dy);
  24. }
  25. /*
  26. * 计算pos点到由p1、p2组成的直线的距离,以及直线上距离pos最近的点foot
  27. */
  28. double pointSegmentDistance(const PointD& p, const PointD& p1,
  29. const PointD& p2, PointD& foot, CalDistanceFunc func)
  30. {
  31. double deltaX = p2.x - p1.x;
  32. double deltaY = p2.y - p1.y;
  33. double d1 = deltaX * (p.x - p1.x) + deltaY * (p.y - p1.y);
  34. if (d1 <= 0)
  35. {
  36. foot = p1;
  37. return func(p, p1);
  38. }
  39. double d2 = deltaX * deltaX + deltaY * deltaY;
  40. if (d1 >= d2)
  41. {
  42. foot = p2;
  43. return func(p, p2);
  44. }
  45. double r = d1 / d2;
  46. foot.x = p1.x + deltaX * r;
  47. foot.y = p1.y + deltaY * r;
  48. foot.z = p1.z + (p2.z - p1.z) * r;
  49. return func(p, foot);
  50. }
  51. double calcPt2SegmentLonlat(const PointD& pos, const PointD& p1,
  52. const PointD& p2, CalDistanceFunc func)
  53. {
  54. double a = func(p1, p2); //经纬坐标系中求两点的距离公式
  55. double b = func(p2, pos); //经纬坐标系中求两点的距离公式
  56. double c = func(p1, pos); //经纬坐标系中求两点的距离公式
  57. if (b * b >= c * c + a * a)
  58. return c;
  59. if (c * c >= b * b + a * a)
  60. return b;
  61. double l = (a + b + c) / 2; //周长的一半
  62. double s = sqrt(std::abs(l * (l - a) * (l - b) * (l - c))); //海伦公式求面积
  63. return 2 * s / a;
  64. }
  65. // 美团采用的计算方法,在一个小范围内,例如北京市里面,把地球的经线和纬线当成是垂直的,直接采用勾股定理计算出距离
  66. const double calDistanceSimple(const PointD& p1, const PointD& p2)
  67. {
  68. double dx = Degree2Radian(p1.x - p2.x); // 经度差值
  69. double dy = Degree2Radian(p1.y - p2.y); // 纬度差值
  70. double cosb1 = ns_cos_round((p1.y + p2.y) * 0.5);
  71. double lx = dx * EARTH_EQUATOR_RADIUS * cosb1; // 东西距离
  72. // double b = Degree2Radian((p1.y + p2.y) * 0.5); // 平均纬度
  73. // double lx = dx * EARTH_EQUATOR_RADIUS * cos(b); // 东西距离
  74. double ly = dy * EARTH_EQUATOR_RADIUS; // 南北距离
  75. return sqrt(lx * lx + ly * ly);
  76. }
  77. // 已知两个经纬度坐标点,求两个经纬度之间的距离
  78. const double calDistanceHaversine(const PointD& p1, const PointD& p2)
  79. {
  80. // 所有的角度转化为弧度进行计算
  81. double dLat = Degree2Radian(p2.y - p1.y);
  82. double dLon = Degree2Radian(p2.x - p1.x);
  83. double tmpLat1 = Degree2Radian(p1.y);
  84. double tmpLat2 = Degree2Radian(p2.y);
  85. // 代入计算地球距离的Haversine公式中
  86. double a = pow(sin(dLat * 0.5), 2) + pow(sin(dLon * 0.5), 2) * cos(tmpLat1) * cos(tmpLat2);
  87. double c = 2 * asin(sqrt(a)); // 和2 * atan2(sqrt(a), sqrt(1-a));一样
  88. // double c = 2 * atan2(sqrt(a), sqrt(1-a));
  89. return EARTH_EQUATOR_RADIUS * c;
  90. }
  91. // 根据Vincenty的公式计算地球上两点间的距离,把地球当成椭圆形进行计算
  92. const double calDistanceVincenty(const PointD& p1, const PointD& p2)
  93. {
  94. static double a = EARTH_EQUATOR_RADIUS; // 椭球长轴半径
  95. static double f = 1 / 298.257223563; // 椭球体变平
  96. static double b = (1 - f) * a; // 椭球短轴半径
  97. double U1 = atan((1 - f) * tan(Degree2Radian(p1.y))); //降低纬度处理
  98. double U2 = atan((1 - f) * tan(Degree2Radian(p2.y))); //同时把经纬度转化为弧度
  99. double sinU1 = sin(U1), cosU1 = cos(U1);
  100. double sinU2 = sin(U2), cosU2 = cos(U2);
  101. double L = Degree2Radian(p2.x - p1.x); // 两点经度差
  102. double sinLambda;
  103. double cosLambda;
  104. double sinSigma;
  105. double cosSigma;
  106. double sigma;
  107. double cosSqAlpha;
  108. double cos2SigmaM;
  109. double lambda = L;
  110. double prevLambda;
  111. int iterationLimit = 100; // 迭代公式次数限制
  112. do
  113. {
  114. sinLambda = sin(lambda);
  115. cosLambda = cos(lambda);
  116. sinSigma =
  117. sqrt(pow(cosU2 * sinLambda, 2) + pow(cosU1 * sinU2 - sinU1 * cosU2 * cosLambda, 2));
  118. if (sinSigma == 0) // 判断是否为重合点
  119. return 0;
  120. cosSigma = sinU1 * sinU2 + cosU1 * cosU2 * cosLambda;
  121. sigma = atan(sinSigma / cosSigma);
  122. double sinAlpha = cosU1 * cosU2 * sinLambda / sinSigma;
  123. cosSqAlpha = 1 - pow(sinAlpha, 2);
  124. if (cosSqAlpha == 0)
  125. {
  126. cos2SigmaM = 0;
  127. }
  128. else
  129. {
  130. cos2SigmaM = cosSigma - 2 * sinU1 * sinU2 / cosSqAlpha;
  131. }
  132. double C = f / 16 * cosSqAlpha * (4 + f * (4 - 3 * cosSqAlpha));
  133. prevLambda = lambda;
  134. lambda = L + (1 - C) * f * sinAlpha *
  135. (sigma + C * sinSigma *
  136. (cos2SigmaM + C * cosSigma * (-1 + 2 * pow(cos2SigmaM, 2))));
  137. } while (std::abs(lambda - prevLambda) > 1e-12 && --iterationLimit > 0);
  138. if (iterationLimit == 0)
  139. return 0;
  140. double uSq = cosSqAlpha * (pow(a, 2) - pow(b, 2)) / pow(b, 2);
  141. double A = 1 + uSq / 16384 * (4096 + uSq * (-768 + uSq * (320 - 175 * uSq)));
  142. double B = uSq / 1024 * (256 + uSq * (-128 + uSq * (74 - 47 * uSq)));
  143. double deltaSigma = B * sinSigma *
  144. (cos2SigmaM + B / 4 *
  145. (cosSigma * (-1 + 2 * pow(cos2SigmaM, 2)) -
  146. B / 6 * cos2SigmaM * (-3 + 4 * pow(sinSigma, 2)) *
  147. (-3 + 4 * pow(cos2SigmaM, 2))));
  148. double s = b * A * (sigma - deltaSigma);
  149. return s;
  150. }
  151. } // namespace geo
  152. } // namespace ns