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.

ns_geom_math.cpp 10 kB

2 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362
  1. #include "basic/basic.h"
  2. #include "geo/private/math/math.h"
  3. #include "geo/private/math/angle.h"
  4. #include "geo/private/math/distance.h"
  5. #include "geo/private/math/ns_geom_math.h"
  6. #ifdef OS_WINDOWS
  7. #include <time.h>
  8. #elif defined(OS_LINUX)
  9. #include <sys/time.h>
  10. #endif
  11. #include <cfloat>
  12. #include <cmath>
  13. #include <cstdint>
  14. #include <ctime>
  15. #include <limits>
  16. #include <string>
  17. using namespace std;
  18. namespace ns
  19. {
  20. namespace geo
  21. {
  22. static double g_maxLon = 180.0;
  23. static double g_minLon = -180.0;
  24. static double g_maxLat = 90.0;
  25. static double g_minLat = -90.0;
  26. double clipLongitude(double lon)
  27. {
  28. return max(g_minLon, min(g_maxLon, lon));
  29. }
  30. double clipLatitude(double lat)
  31. {
  32. return max(g_minLat, min(g_maxLat, lat));
  33. }
  34. bool segmentIntersection(const PointD& p1, const PointD& p2, const PointD& q1,
  35. const PointD& q2)
  36. {
  37. if (max(p1.x, p2.x) < min(q1.x, q2.x) || max(q1.x, q2.x) < min(p1.x, p2.x) ||
  38. max(p1.y, p2.y) < min(q1.y, q2.y) || max(q1.y, q2.y) < min(p1.y, p2.y))
  39. return false;
  40. double res1 = (p1.x - p2.x) * (q1.y - p2.y) - (p1.y - p2.y) * (q1.x - p2.x);
  41. double res2 = (p1.x - p2.x) * (q2.y - p2.y) - (p1.y - p2.y) * (q2.x - p2.x);
  42. double res3 = (q1.x - q2.x) * (p1.y - q2.y) - (q1.y - q2.y) * (p1.x - q2.x);
  43. double res4 = (q1.x - q2.x) * (p2.y - q2.y) - (q1.y - q2.y) * (p2.x - q2.x);
  44. return res1 * res2 <= 0 && res3 * res4 <= 0;
  45. }
  46. bool segmentIntersectionWithRect(const PointD& p1, const PointD& p2, const RectD& rct)
  47. {
  48. if (rct.contain(p1) || rct.contain(p2))
  49. return true;
  50. PointD q1(rct.minX, rct.minY);
  51. PointD q2(rct.minX, rct.maxY);
  52. PointD q3(rct.maxX, rct.maxY);
  53. PointD q4(rct.maxX, rct.minY);
  54. return segmentIntersection(p1, p2, q1, q2) || segmentIntersection(p1, p2, q2, q3) ||
  55. segmentIntersection(p1, p2, q3, q4) || segmentIntersection(p1, p2, q4, q1);
  56. }
  57. int judgeShapePointDirectionBothEnds(const std::vector<PointD>& line1,
  58. const std::vector<PointD>& line2)
  59. {
  60. if (line1.size() >= 2 && line2.size() >= 2)
  61. {
  62. const PointD& p1 = line1[0];
  63. const PointD& p2 = line1[1];
  64. const PointD& p3 = line1[line1.size() - 2];
  65. const PointD& p4 = line1[line1.size() - 1];
  66. const PointD& q1 = line2[0];
  67. const PointD& q2 = line2[1];
  68. const PointD& q3 = line2[line2.size() - 2];
  69. const PointD& q4 = line2[line2.size() - 1];
  70. // head two points
  71. double hAngle1 = cal_east_angle(p1, p2);
  72. double hAngle2 = cal_east_angle(q1, q2);
  73. double hDiff = diff_angle(hAngle1, hAngle2);
  74. // tail two points
  75. double tAngle1 = cal_east_angle(p3, p4);
  76. double tAngle2 = cal_east_angle(q3, q4);
  77. double tDiff = diff_angle(tAngle1, tAngle2);
  78. // 开始的方向和结尾的角度相差小于90度,方向就认为是相同的
  79. if (hDiff < 90 && tDiff < 90)
  80. {
  81. return 1;
  82. }
  83. // first and last points
  84. double angle1 = cal_east_angle(p1, p4);
  85. double angle2 = cal_east_angle(q1, q4);
  86. double diff = diff_angle(angle1, angle2);
  87. // 或者两条线的第一个点与最后一个点的连线角度小于90,方向就认为是相同的
  88. return diff < 90 ? 1 : -1;
  89. }
  90. return 0;
  91. }
  92. double calProj2Vector(const PointD& pos, const PointD& p1, const PointD& p2,
  93. PointD& proj, int& inVector)
  94. {
  95. double n_x = p2.x - p1.x;
  96. double n_y = p2.y - p1.y;
  97. double x_x = pos.x - p1.x;
  98. double x_y = pos.y - p1.y;
  99. if (p1 == p2)
  100. {
  101. proj = p1;
  102. inVector = 0;
  103. return pos.distance(proj);
  104. }
  105. double proj_norm = (x_x * n_x + x_y * n_y) / (n_x * n_x + n_y * n_y);
  106. double proj_x = proj_norm * n_x;
  107. double proj_y = proj_norm * n_y;
  108. proj.x = p1.x + proj_x;
  109. proj.y = p1.y + proj_y;
  110. inVector = proj_norm >= 0 && proj_norm <= 1;
  111. double dis = std::sqrt((proj_x - x_x) * (proj_x - x_x) + (proj_y - x_y) * (proj_y - x_y));
  112. int32_t side = JudgeSideness(p1, p2, pos);
  113. if (side < 0)
  114. {
  115. dis *= -1;
  116. }
  117. return dis;
  118. }
  119. bool projInVector(const PointD& pos, const PointD& p1, const PointD& p2)
  120. {
  121. double n_x = p2.x - p1.x;
  122. double n_y = p2.y - p1.y;
  123. double x_x = pos.x - p1.x;
  124. double x_y = pos.y - p1.y;
  125. double proj_norm = (x_x * n_x + x_y * n_y);
  126. double length = (n_x * n_x + n_y * n_y);
  127. return proj_norm >= 0 && proj_norm <= length;
  128. }
  129. PointD pointInSegment(const PointD& p1, const PointD& p2, double s,
  130. double length)
  131. {
  132. PointD pos;
  133. double len;
  134. if (length > 0)
  135. len = length;
  136. else
  137. len = sqrt((p2.x - p1.x) * (p2.x - p1.x) + (p2.y - p1.y) * (p2.y - p1.y));
  138. if (len > 0 && s >= 0 && s <= len)
  139. {
  140. double ratio = s / len;
  141. pos.x = p1.x + ratio * (p2.x - p1.x);
  142. pos.y = p1.y + ratio * (p2.y - p1.y);
  143. pos.z = p1.z + ratio * (p2.z - p1.z);
  144. }
  145. return pos;
  146. }
  147. bool pointInPolygon(const PointD& p, const std::vector<PointD>& pts)
  148. {
  149. double x = p.x;
  150. double y = p.y;
  151. int polySides = static_cast<int>(pts.size());
  152. int i, j = polySides - 1;
  153. bool oddNodes = false;
  154. for (i = 0; i < polySides; i++)
  155. {
  156. // 只针对平面比较是否在polygon中, 没有对z值作比较
  157. // if (pts[i] == p)
  158. if (are_equal(pts[i].x, p.x) && are_equal(pts[i].y, p.y))
  159. return true;
  160. if (pts[i].x <= x || pts[j].x <= x)
  161. {
  162. // if已经保证下面的除数不会为0
  163. if ((pts[i].y < y && pts[j].y >= y) ||
  164. (pts[j].y < y && pts[i].y >= y)) // y大于等于都认为大于
  165. {
  166. oddNodes ^=
  167. (pts[i].x + (y - pts[i].y) / (pts[j].y - pts[i].y) * (pts[j].x - pts[i].x) < x);
  168. }
  169. }
  170. j = i;
  171. }
  172. return oddNodes;
  173. }
  174. static PointD _HadMath_getRelatedPoint(const PointD* p, double distance, double angle)
  175. {
  176. PointD dst;
  177. // Point64_invalidate(&dst);
  178. static const double Ea = 6378137; // 赤道半径
  179. static const double Eb = 6356725; // 极半径
  180. double lon = p->x;
  181. double lat = p->y;
  182. //正北朝上
  183. double dx = distance * sin(angle * c_pi() / 180.0);
  184. double dy = distance * cos(angle * c_pi() / 180.0);
  185. ////正东朝上
  186. // double dx = distance * cos(angle * c_pi() / 180.0);
  187. // double dy = distance * sin(angle * c_pi() / 180.0);
  188. // double ec = 6356725 + 21412 * (90.0 - GLAT) / 90.0;
  189. // 21412 是赤道半径与极半径的差
  190. // ec:修正因为纬度不断变化的球半径长度,ed:lat所在纬度的纬度圈的半径
  191. double ec = Eb + (Ea - Eb) * (90.0 - lat) / 90.0;
  192. double ed = ec * cos(lat * c_pi() / 180);
  193. double dstLon = (dx / ed + lon * c_pi() / 180.0) * 180.0 / c_pi();
  194. double dstLat = (dy / ec + lat * c_pi() / 180.0) * 180.0 / c_pi();
  195. dst.x = dstLon;
  196. dst.y = dstLat;
  197. return dst;
  198. }
  199. bool calcCircleCenter(double curvature, double heading, const PointD* position,
  200. PointD* center)
  201. {
  202. if ((position == NULL) || (center == NULL))
  203. {
  204. return false;
  205. }
  206. if (curvature == 0.0)
  207. {
  208. return false;
  209. }
  210. if (curvature < 0)
  211. {
  212. heading += 90;
  213. }
  214. else
  215. {
  216. heading -= 90;
  217. }
  218. *center = _HadMath_getRelatedPoint(position, std::abs(1.0 / curvature), heading);
  219. return true;
  220. }
  221. PointD getPointInTangentLine(double heading, const PointD* pt, double dis)
  222. {
  223. double arc = heading * c_pi() / 180;
  224. return PointD(pt->x + dis * cos(arc), pt->y + dis * sin(arc));
  225. }
  226. namespace
  227. {
  228. // 不对外接口,写到这个命名空间里面
  229. bool genCenterLine(const std::vector<PointDST>& l, const std::vector<PointDST>& r,
  230. std::vector<PointD>& c)
  231. {
  232. auto getXYByS = [&](const std::vector<PointDST>& position, double s) -> PointDST {
  233. // 获取position上s值对应点处的xy笛卡尔坐标
  234. PointDST pp;
  235. if (!position.empty())
  236. {
  237. double length = position[position.size() - 1].s;
  238. if (s >= 0 && s <= length)
  239. {
  240. for (size_t i = 1; i < position.size(); i++)
  241. {
  242. if (s <= position[i].s)
  243. {
  244. pp.p =
  245. pointInSegment(position[i - 1].p, position[i].p, s - position[i - 1].s,
  246. position[i].s - position[i - 1].s);
  247. pp.s = s;
  248. pp.t = 0;
  249. break;
  250. }
  251. }
  252. }
  253. }
  254. return pp;
  255. };
  256. c.clear();
  257. if (l.size() >= 2 && r.size() >= 2)
  258. {
  259. double len1 = l[l.size() - 1].s;
  260. double len2 = r[r.size() - 1].s;
  261. if (len1 > 0 && len2 > 0)
  262. {
  263. for (auto& p : l)
  264. {
  265. double len = p.s / len1 * len2;
  266. auto q = getXYByS(r, len);
  267. PointD cp((p.p.x + q.p.x) / 2.0, (p.p.y + q.p.y) / 2.0,
  268. (p.p.z + q.p.z) / 2.0);
  269. c.emplace_back(cp);
  270. }
  271. }
  272. return true;
  273. }
  274. return false;
  275. }
  276. } // namespace
  277. bool genCenterLine(const std::vector<PointD>& l, const std::vector<PointD>& r,
  278. std::vector<PointD>& c)
  279. {
  280. auto computeS = [&](const std::vector<PointD>& pts,
  281. std::vector<PointDST>& position) -> double {
  282. PointDST pos;
  283. pos.p = pts[0];
  284. pos.t = pos.s = 0;
  285. position.emplace_back(pos);
  286. for (size_t i = 1; i < pts.size(); i++)
  287. {
  288. pos.p = pts[i];
  289. pos.t = 0;
  290. PointD pre = position[i - 1].p;
  291. PointD cur = pos.p;
  292. pos.s = cur.distance(pre) + position[i - 1].s;
  293. position.emplace_back(pos);
  294. }
  295. return position[position.size() - 1].s;
  296. };
  297. if (l.size() >= 2 && r.size() >= 2)
  298. {
  299. std::vector<PointDST> position1, position2;
  300. computeS(l, position1);
  301. computeS(r, position2);
  302. position1.size() > position2.size() ? genCenterLine(position1, position2, c)
  303. : genCenterLine(position2, position1, c);
  304. return true;
  305. }
  306. return false;
  307. }
  308. } // namespace geo
  309. } // namespace ns