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.

angle.cpp 2.9 kB

2 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. #include <cfloat>
  2. #include <cmath>
  3. #include "geo/private/math/angle.h"
  4. namespace ns
  5. {
  6. namespace geo
  7. {
  8. double normalize_angle(double angle)
  9. {
  10. while (angle < 0.0)
  11. {
  12. angle += 360.0;
  13. }
  14. while (angle > 360.0)
  15. {
  16. angle -= 360.0;
  17. }
  18. return angle;
  19. }
  20. double average_angle(double angle1, double angle2, double ratio)
  21. {
  22. double a1 = normalize_angle(angle1);
  23. double a2 = normalize_angle(angle2);
  24. return a1 + ratio * (a2 - a1);
  25. }
  26. double opposite_angle(const double angle)
  27. {
  28. return normalize_angle(angle + 180);
  29. }
  30. double diff_angle(double a1, double a2)
  31. {
  32. double a11 = normalize_angle(a1);
  33. double a22 = normalize_angle(a2);
  34. double d1 = fabs(a11 - a22);
  35. if (d1 > 180)
  36. d1 = 360 - d1;
  37. return d1;
  38. }
  39. double cal_north_angle(PointD pt1, PointD pt2)
  40. {
  41. return cal_north_angle(pt2.x - pt1.x, pt2.y - pt1.y);
  42. }
  43. double cal_north_angle(double dx, double dy)
  44. {
  45. if (fabs(dx) < DBL_EPSILON)
  46. return dy >= 0 ? 0 : 180;
  47. if (fabs(dy) < DBL_EPSILON)
  48. return dx >= 0 ? 90 : 270;
  49. double ratio = std::abs(dy / dx);
  50. /// 第一象限
  51. if (dx > 0 && dy > 0)
  52. return 90 - Radian2Degree(atan(ratio));
  53. /// 第二象限
  54. else if (dx > 0 && dy < 0)
  55. return 90 + Radian2Degree(atan(ratio));
  56. /// 第三象限
  57. else if (dx < 0 && dy < 0)
  58. return 270 - Radian2Degree(atan(ratio));
  59. /// 第四象限
  60. else
  61. return 270 + Radian2Degree(atan(ratio));
  62. }
  63. double cal_east_angle(const PointD& pt1, const PointD& pt2)
  64. {
  65. return normalize_angle(Radian2Degree(atan2((pt2.y - pt1.y), (pt2.x - pt1.x))));
  66. }
  67. double cal_lon_lat_angle(double lat1, double lon1, double lat2, double lon2)
  68. {
  69. double numerator = sin(Degree2Radian(lon2 - lon1)) * cos(Degree2Radian(lat2));
  70. double denominator =
  71. cos(Degree2Radian(lat1)) * sin(Degree2Radian(lat2)) -
  72. sin(Degree2Radian(lat1)) * cos(Degree2Radian(lat2)) * cos(Degree2Radian(lon2 - lon1));
  73. double x = atan2(abs(numerator), abs(denominator));
  74. double result = x;
  75. if (lon2 > lon1) // right quadrant
  76. {
  77. if (lat2 > lat1) // first quadrant
  78. result = x;
  79. else if (lat2 < lat1) // forth quadrant
  80. result = c_pi() - x;
  81. else
  82. result = c_pi_2(); // in positive-x axis
  83. }
  84. else if (lon2 < lon1) // left quadrant
  85. {
  86. if (lat2 > lat1) // second quadrant
  87. result = 2 * c_pi() - x;
  88. else if (lat2 < lat1) // third quadrant
  89. result = c_pi() + x;
  90. else
  91. result = c_pi() * 3 / 2; // in negative-x axis
  92. }
  93. else // same longitude
  94. {
  95. if (lat2 > lat1) // in positive-y axis
  96. result = 0;
  97. else if (lat2 < lat1)
  98. result = c_pi(); // in negative-y axis
  99. else
  100. throw "Shouldn't be same location!";
  101. }
  102. return result * 180 / c_pi();
  103. }
  104. } // namespace geo
  105. } // namespace ns