polygon_path_finder.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563
  1. /**************************************************************************/
  2. /* polygon_path_finder.cpp */
  3. /**************************************************************************/
  4. /* This file is part of: */
  5. /* GODOT ENGINE */
  6. /* https://godotengine.org */
  7. /**************************************************************************/
  8. /* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
  9. /* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
  10. /* */
  11. /* Permission is hereby granted, free of charge, to any person obtaining */
  12. /* a copy of this software and associated documentation files (the */
  13. /* "Software"), to deal in the Software without restriction, including */
  14. /* without limitation the rights to use, copy, modify, merge, publish, */
  15. /* distribute, sublicense, and/or sell copies of the Software, and to */
  16. /* permit persons to whom the Software is furnished to do so, subject to */
  17. /* the following conditions: */
  18. /* */
  19. /* The above copyright notice and this permission notice shall be */
  20. /* included in all copies or substantial portions of the Software. */
  21. /* */
  22. /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
  23. /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
  24. /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
  25. /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
  26. /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
  27. /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
  28. /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
  29. /**************************************************************************/
  30. #include "polygon_path_finder.h"
  31. #include "core/math/geometry_2d.h"
  32. bool PolygonPathFinder::_is_point_inside(const Vector2 &p_point) const {
  33. int crosses = 0;
  34. for (const Edge &E : edges) {
  35. const Edge &e = E;
  36. Vector2 a = points[e.points[0]].pos;
  37. Vector2 b = points[e.points[1]].pos;
  38. if (Geometry2D::segment_intersects_segment(a, b, p_point, outside_point, nullptr)) {
  39. crosses++;
  40. }
  41. }
  42. return crosses & 1;
  43. }
  44. void PolygonPathFinder::setup(const Vector<Vector2> &p_points, const Vector<int> &p_connections) {
  45. ERR_FAIL_COND(p_connections.size() & 1);
  46. points.clear();
  47. edges.clear();
  48. //insert points
  49. int point_count = p_points.size();
  50. points.resize(point_count + 2);
  51. bounds = Rect2();
  52. for (int i = 0; i < p_points.size(); i++) {
  53. points.write[i].pos = p_points[i];
  54. points.write[i].penalty = 0;
  55. outside_point = i == 0 ? p_points[0] : p_points[i].max(outside_point);
  56. if (i == 0) {
  57. bounds.position = points[i].pos;
  58. } else {
  59. bounds.expand_to(points[i].pos);
  60. }
  61. }
  62. outside_point.x += 20.451 + Math::randf() * 10.2039;
  63. outside_point.y += 21.193 + Math::randf() * 12.5412;
  64. //insert edges (which are also connections)
  65. for (int i = 0; i < p_connections.size(); i += 2) {
  66. Edge e(p_connections[i], p_connections[i + 1]);
  67. ERR_FAIL_INDEX(e.points[0], point_count);
  68. ERR_FAIL_INDEX(e.points[1], point_count);
  69. points.write[p_connections[i]].connections.insert(p_connections[i + 1]);
  70. points.write[p_connections[i + 1]].connections.insert(p_connections[i]);
  71. edges.insert(e);
  72. }
  73. //fill the remaining connections based on visibility
  74. for (int i = 0; i < point_count; i++) {
  75. for (int j = i + 1; j < point_count; j++) {
  76. if (edges.has(Edge(i, j))) {
  77. continue; //if in edge ignore
  78. }
  79. Vector2 from = points[i].pos;
  80. Vector2 to = points[j].pos;
  81. if (!_is_point_inside(from * 0.5 + to * 0.5)) { //connection between points in inside space
  82. continue;
  83. }
  84. bool valid = true;
  85. for (const Edge &E : edges) {
  86. const Edge &e = E;
  87. if (e.points[0] == i || e.points[1] == i || e.points[0] == j || e.points[1] == j) {
  88. continue;
  89. }
  90. Vector2 a = points[e.points[0]].pos;
  91. Vector2 b = points[e.points[1]].pos;
  92. if (Geometry2D::segment_intersects_segment(a, b, from, to, nullptr)) {
  93. valid = false;
  94. break;
  95. }
  96. }
  97. if (valid) {
  98. points.write[i].connections.insert(j);
  99. points.write[j].connections.insert(i);
  100. }
  101. }
  102. }
  103. }
  104. Vector<Vector2> PolygonPathFinder::find_path(const Vector2 &p_from, const Vector2 &p_to) {
  105. Vector<Vector2> path;
  106. Vector2 from = p_from;
  107. Vector2 to = p_to;
  108. Edge ignore_from_edge(-1, -1);
  109. Edge ignore_to_edge(-1, -1);
  110. if (!_is_point_inside(from)) {
  111. float closest_dist = 1e20f;
  112. Vector2 closest_point;
  113. for (const Edge &E : edges) {
  114. const Edge &e = E;
  115. Vector2 seg[2] = {
  116. points[e.points[0]].pos,
  117. points[e.points[1]].pos
  118. };
  119. Vector2 closest = Geometry2D::get_closest_point_to_segment(from, seg);
  120. float d = from.distance_squared_to(closest);
  121. if (d < closest_dist) {
  122. ignore_from_edge = E;
  123. closest_dist = d;
  124. closest_point = closest;
  125. }
  126. }
  127. from = closest_point;
  128. };
  129. if (!_is_point_inside(to)) {
  130. float closest_dist = 1e20f;
  131. Vector2 closest_point;
  132. for (const Edge &E : edges) {
  133. const Edge &e = E;
  134. Vector2 seg[2] = {
  135. points[e.points[0]].pos,
  136. points[e.points[1]].pos
  137. };
  138. Vector2 closest = Geometry2D::get_closest_point_to_segment(to, seg);
  139. float d = to.distance_squared_to(closest);
  140. if (d < closest_dist) {
  141. ignore_to_edge = E;
  142. closest_dist = d;
  143. closest_point = closest;
  144. }
  145. }
  146. to = closest_point;
  147. };
  148. //test direct connection
  149. {
  150. bool can_see_eachother = true;
  151. for (const Edge &E : edges) {
  152. const Edge &e = E;
  153. if (e.points[0] == ignore_from_edge.points[0] && e.points[1] == ignore_from_edge.points[1]) {
  154. continue;
  155. }
  156. if (e.points[0] == ignore_to_edge.points[0] && e.points[1] == ignore_to_edge.points[1]) {
  157. continue;
  158. }
  159. Vector2 a = points[e.points[0]].pos;
  160. Vector2 b = points[e.points[1]].pos;
  161. if (Geometry2D::segment_intersects_segment(a, b, from, to, nullptr)) {
  162. can_see_eachother = false;
  163. break;
  164. }
  165. }
  166. if (can_see_eachother) {
  167. path.push_back(from);
  168. path.push_back(to);
  169. return path;
  170. }
  171. }
  172. //add to graph
  173. int aidx = points.size() - 2;
  174. int bidx = points.size() - 1;
  175. points.write[aidx].pos = from;
  176. points.write[bidx].pos = to;
  177. points.write[aidx].distance = 0;
  178. points.write[bidx].distance = 0;
  179. points.write[aidx].prev = -1;
  180. points.write[bidx].prev = -1;
  181. points.write[aidx].penalty = 0;
  182. points.write[bidx].penalty = 0;
  183. for (int i = 0; i < points.size() - 2; i++) {
  184. bool valid_a = true;
  185. bool valid_b = true;
  186. points.write[i].prev = -1;
  187. points.write[i].distance = 0;
  188. if (!_is_point_inside(from * 0.5 + points[i].pos * 0.5)) {
  189. valid_a = false;
  190. }
  191. if (!_is_point_inside(to * 0.5 + points[i].pos * 0.5)) {
  192. valid_b = false;
  193. }
  194. for (const Edge &E : edges) {
  195. const Edge &e = E;
  196. if (e.points[0] == i || e.points[1] == i) {
  197. continue;
  198. }
  199. Vector2 a = points[e.points[0]].pos;
  200. Vector2 b = points[e.points[1]].pos;
  201. if (valid_a) {
  202. if (e.points[0] != ignore_from_edge.points[1] &&
  203. e.points[1] != ignore_from_edge.points[1] &&
  204. e.points[0] != ignore_from_edge.points[0] &&
  205. e.points[1] != ignore_from_edge.points[0]) {
  206. if (Geometry2D::segment_intersects_segment(a, b, from, points[i].pos, nullptr)) {
  207. valid_a = false;
  208. }
  209. }
  210. }
  211. if (valid_b) {
  212. if (e.points[0] != ignore_to_edge.points[1] &&
  213. e.points[1] != ignore_to_edge.points[1] &&
  214. e.points[0] != ignore_to_edge.points[0] &&
  215. e.points[1] != ignore_to_edge.points[0]) {
  216. if (Geometry2D::segment_intersects_segment(a, b, to, points[i].pos, nullptr)) {
  217. valid_b = false;
  218. }
  219. }
  220. }
  221. if (!valid_a && !valid_b) {
  222. break;
  223. }
  224. }
  225. if (valid_a) {
  226. points.write[i].connections.insert(aidx);
  227. points.write[aidx].connections.insert(i);
  228. }
  229. if (valid_b) {
  230. points.write[i].connections.insert(bidx);
  231. points.write[bidx].connections.insert(i);
  232. }
  233. }
  234. //solve graph
  235. HashSet<int> open_list;
  236. points.write[aidx].distance = 0;
  237. points.write[aidx].prev = aidx;
  238. for (const int &E : points[aidx].connections) {
  239. open_list.insert(E);
  240. points.write[E].distance = from.distance_to(points[E].pos);
  241. points.write[E].prev = aidx;
  242. }
  243. bool found_route = false;
  244. while (true) {
  245. if (open_list.size() == 0) {
  246. print_verbose("Open list empty.");
  247. break;
  248. }
  249. //check open list
  250. int least_cost_point = -1;
  251. float least_cost = 1e30;
  252. //this could be faster (cache previous results)
  253. for (const int &E : open_list) {
  254. const Point &p = points[E];
  255. float cost = p.distance;
  256. cost += p.pos.distance_to(to);
  257. cost += p.penalty;
  258. if (cost < least_cost) {
  259. least_cost_point = E;
  260. least_cost = cost;
  261. }
  262. }
  263. const Point &np = points[least_cost_point];
  264. //open the neighbors for search
  265. for (const int &E : np.connections) {
  266. Point &p = points.write[E];
  267. float distance = np.pos.distance_to(p.pos) + np.distance;
  268. if (p.prev != -1) {
  269. //oh this was visited already, can we win the cost?
  270. if (p.distance > distance) {
  271. p.prev = least_cost_point; //reassign previous
  272. p.distance = distance;
  273. }
  274. } else {
  275. //add to open neighbors
  276. p.prev = least_cost_point;
  277. p.distance = distance;
  278. open_list.insert(E);
  279. if (E == bidx) {
  280. //oh my reached end! stop algorithm
  281. found_route = true;
  282. break;
  283. }
  284. }
  285. }
  286. if (found_route) {
  287. break;
  288. }
  289. open_list.erase(least_cost_point);
  290. }
  291. if (found_route) {
  292. int at = bidx;
  293. path.push_back(points[at].pos);
  294. do {
  295. at = points[at].prev;
  296. path.push_back(points[at].pos);
  297. } while (at != aidx);
  298. path.reverse();
  299. }
  300. for (int i = 0; i < points.size() - 2; i++) {
  301. points.write[i].connections.erase(aidx);
  302. points.write[i].connections.erase(bidx);
  303. points.write[i].prev = -1;
  304. points.write[i].distance = 0;
  305. }
  306. points.write[aidx].connections.clear();
  307. points.write[aidx].prev = -1;
  308. points.write[aidx].distance = 0;
  309. points.write[bidx].connections.clear();
  310. points.write[bidx].prev = -1;
  311. points.write[bidx].distance = 0;
  312. return path;
  313. }
  314. void PolygonPathFinder::_set_data(const Dictionary &p_data) {
  315. ERR_FAIL_COND(!p_data.has("points"));
  316. ERR_FAIL_COND(!p_data.has("connections"));
  317. ERR_FAIL_COND(!p_data.has("segments"));
  318. ERR_FAIL_COND(!p_data.has("bounds"));
  319. Vector<Vector2> p = p_data["points"];
  320. Array c = p_data["connections"];
  321. ERR_FAIL_COND(c.size() != p.size());
  322. if (c.size()) {
  323. return;
  324. }
  325. int pc = p.size();
  326. points.resize(pc + 2);
  327. const Vector2 *pr = p.ptr();
  328. for (int i = 0; i < pc; i++) {
  329. points.write[i].pos = pr[i];
  330. Vector<int> con = c[i];
  331. const int *cr = con.ptr();
  332. int cc = con.size();
  333. for (int j = 0; j < cc; j++) {
  334. points.write[i].connections.insert(cr[j]);
  335. }
  336. }
  337. if (p_data.has("penalties")) {
  338. Vector<real_t> penalties = p_data["penalties"];
  339. if (penalties.size() == pc) {
  340. const real_t *pr2 = penalties.ptr();
  341. for (int i = 0; i < pc; i++) {
  342. points.write[i].penalty = pr2[i];
  343. }
  344. }
  345. }
  346. Vector<int> segs = p_data["segments"];
  347. int sc = segs.size();
  348. ERR_FAIL_COND(sc & 1);
  349. const int *sr = segs.ptr();
  350. for (int i = 0; i < sc; i += 2) {
  351. Edge e(sr[i], sr[i + 1]);
  352. edges.insert(e);
  353. }
  354. bounds = p_data["bounds"];
  355. }
  356. Dictionary PolygonPathFinder::_get_data() const {
  357. Dictionary d;
  358. Vector<Vector2> p;
  359. Vector<int> ind;
  360. Array path_connections;
  361. p.resize(MAX(0, points.size() - 2));
  362. path_connections.resize(MAX(0, points.size() - 2));
  363. ind.resize(edges.size() * 2);
  364. Vector<real_t> penalties;
  365. penalties.resize(MAX(0, points.size() - 2));
  366. {
  367. Vector2 *wp = p.ptrw();
  368. real_t *pw = penalties.ptrw();
  369. for (int i = 0; i < points.size() - 2; i++) {
  370. wp[i] = points[i].pos;
  371. pw[i] = points[i].penalty;
  372. Vector<int> c;
  373. c.resize(points[i].connections.size());
  374. {
  375. int *cw = c.ptrw();
  376. int idx = 0;
  377. for (const int &E : points[i].connections) {
  378. cw[idx++] = E;
  379. }
  380. }
  381. path_connections[i] = c;
  382. }
  383. }
  384. {
  385. int *iw = ind.ptrw();
  386. int idx = 0;
  387. for (const Edge &E : edges) {
  388. iw[idx++] = E.points[0];
  389. iw[idx++] = E.points[1];
  390. }
  391. }
  392. d["bounds"] = bounds;
  393. d["points"] = p;
  394. d["penalties"] = penalties;
  395. d["connections"] = path_connections;
  396. d["segments"] = ind;
  397. return d;
  398. }
  399. bool PolygonPathFinder::is_point_inside(const Vector2 &p_point) const {
  400. return _is_point_inside(p_point);
  401. }
  402. Vector2 PolygonPathFinder::get_closest_point(const Vector2 &p_point) const {
  403. float closest_dist = 1e20f;
  404. Vector2 closest_point;
  405. for (const Edge &E : edges) {
  406. const Edge &e = E;
  407. Vector2 seg[2] = {
  408. points[e.points[0]].pos,
  409. points[e.points[1]].pos
  410. };
  411. Vector2 closest = Geometry2D::get_closest_point_to_segment(p_point, seg);
  412. float d = p_point.distance_squared_to(closest);
  413. if (d < closest_dist) {
  414. closest_dist = d;
  415. closest_point = closest;
  416. }
  417. }
  418. ERR_FAIL_COND_V(Math::is_equal_approx(closest_dist, 1e20f), Vector2());
  419. return closest_point;
  420. }
  421. Vector<Vector2> PolygonPathFinder::get_intersections(const Vector2 &p_from, const Vector2 &p_to) const {
  422. Vector<Vector2> inters;
  423. for (const Edge &E : edges) {
  424. Vector2 a = points[E.points[0]].pos;
  425. Vector2 b = points[E.points[1]].pos;
  426. Vector2 res;
  427. if (Geometry2D::segment_intersects_segment(a, b, p_from, p_to, &res)) {
  428. inters.push_back(res);
  429. }
  430. }
  431. return inters;
  432. }
  433. Rect2 PolygonPathFinder::get_bounds() const {
  434. return bounds;
  435. }
  436. void PolygonPathFinder::set_point_penalty(int p_point, float p_penalty) {
  437. ERR_FAIL_INDEX(p_point, points.size() - 2);
  438. points.write[p_point].penalty = p_penalty;
  439. }
  440. float PolygonPathFinder::get_point_penalty(int p_point) const {
  441. ERR_FAIL_INDEX_V(p_point, points.size() - 2, 0);
  442. return points[p_point].penalty;
  443. }
  444. void PolygonPathFinder::_bind_methods() {
  445. ClassDB::bind_method(D_METHOD("setup", "points", "connections"), &PolygonPathFinder::setup);
  446. ClassDB::bind_method(D_METHOD("find_path", "from", "to"), &PolygonPathFinder::find_path);
  447. ClassDB::bind_method(D_METHOD("get_intersections", "from", "to"), &PolygonPathFinder::get_intersections);
  448. ClassDB::bind_method(D_METHOD("get_closest_point", "point"), &PolygonPathFinder::get_closest_point);
  449. ClassDB::bind_method(D_METHOD("is_point_inside", "point"), &PolygonPathFinder::is_point_inside);
  450. ClassDB::bind_method(D_METHOD("set_point_penalty", "idx", "penalty"), &PolygonPathFinder::set_point_penalty);
  451. ClassDB::bind_method(D_METHOD("get_point_penalty", "idx"), &PolygonPathFinder::get_point_penalty);
  452. ClassDB::bind_method(D_METHOD("get_bounds"), &PolygonPathFinder::get_bounds);
  453. ClassDB::bind_method(D_METHOD("_set_data", "data"), &PolygonPathFinder::_set_data);
  454. ClassDB::bind_method(D_METHOD("_get_data"), &PolygonPathFinder::_get_data);
  455. ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_data", "_get_data");
  456. }
  457. PolygonPathFinder::PolygonPathFinder() {
  458. }