polygon_path_finder.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564
  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.h"
  32. bool PolygonPathFinder::_is_point_inside(const Vector2 &p_point) const {
  33. int crosses = 0;
  34. for (Set<Edge>::Element *E = edges.front(); E; E = E->next()) {
  35. const Edge &e = E->get();
  36. Vector2 a = points[e.points[0]].pos;
  37. Vector2 b = points[e.points[1]].pos;
  38. if (Geometry::segment_intersects_segment_2d(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.x = i == 0 ? p_points[0].x : (MAX(p_points[i].x, outside_point.x));
  56. outside_point.y = i == 0 ? p_points[0].y : (MAX(p_points[i].y, outside_point.y));
  57. if (i == 0) {
  58. bounds.position = points[i].pos;
  59. } else {
  60. bounds.expand_to(points[i].pos);
  61. }
  62. }
  63. outside_point.x += 20.451 + Math::randf() * 10.2039;
  64. outside_point.y += 21.193 + Math::randf() * 12.5412;
  65. //insert edges (which are also connetions)
  66. for (int i = 0; i < p_connections.size(); i += 2) {
  67. Edge e(p_connections[i], p_connections[i + 1]);
  68. ERR_FAIL_INDEX(e.points[0], point_count);
  69. ERR_FAIL_INDEX(e.points[1], point_count);
  70. points.write[p_connections[i]].connections.insert(p_connections[i + 1]);
  71. points.write[p_connections[i + 1]].connections.insert(p_connections[i]);
  72. edges.insert(e);
  73. }
  74. //fill the remaining connections based on visibility
  75. for (int i = 0; i < point_count; i++) {
  76. for (int j = i + 1; j < point_count; j++) {
  77. if (edges.has(Edge(i, j))) {
  78. continue; //if in edge ignore
  79. }
  80. Vector2 from = points[i].pos;
  81. Vector2 to = points[j].pos;
  82. if (!_is_point_inside(from * 0.5 + to * 0.5)) { //connection between points in inside space
  83. continue;
  84. }
  85. bool valid = true;
  86. for (Set<Edge>::Element *E = edges.front(); E; E = E->next()) {
  87. const Edge &e = E->get();
  88. if (e.points[0] == i || e.points[1] == i || e.points[0] == j || e.points[1] == j) {
  89. continue;
  90. }
  91. Vector2 a = points[e.points[0]].pos;
  92. Vector2 b = points[e.points[1]].pos;
  93. if (Geometry::segment_intersects_segment_2d(a, b, from, to, nullptr)) {
  94. valid = false;
  95. break;
  96. }
  97. }
  98. if (valid) {
  99. points.write[i].connections.insert(j);
  100. points.write[j].connections.insert(i);
  101. }
  102. }
  103. }
  104. }
  105. Vector<Vector2> PolygonPathFinder::find_path(const Vector2 &p_from, const Vector2 &p_to) {
  106. Vector<Vector2> path;
  107. Vector2 from = p_from;
  108. Vector2 to = p_to;
  109. Edge ignore_from_edge(-1, -1);
  110. Edge ignore_to_edge(-1, -1);
  111. if (!_is_point_inside(from)) {
  112. float closest_dist = 1e20f;
  113. Vector2 closest_point;
  114. for (Set<Edge>::Element *E = edges.front(); E; E = E->next()) {
  115. const Edge &e = E->get();
  116. Vector2 seg[2] = {
  117. points[e.points[0]].pos,
  118. points[e.points[1]].pos
  119. };
  120. Vector2 closest = Geometry::get_closest_point_to_segment_2d(from, seg);
  121. float d = from.distance_squared_to(closest);
  122. if (d < closest_dist) {
  123. ignore_from_edge = E->get();
  124. closest_dist = d;
  125. closest_point = closest;
  126. }
  127. }
  128. from = closest_point;
  129. };
  130. if (!_is_point_inside(to)) {
  131. float closest_dist = 1e20f;
  132. Vector2 closest_point;
  133. for (Set<Edge>::Element *E = edges.front(); E; E = E->next()) {
  134. const Edge &e = E->get();
  135. Vector2 seg[2] = {
  136. points[e.points[0]].pos,
  137. points[e.points[1]].pos
  138. };
  139. Vector2 closest = Geometry::get_closest_point_to_segment_2d(to, seg);
  140. float d = to.distance_squared_to(closest);
  141. if (d < closest_dist) {
  142. ignore_to_edge = E->get();
  143. closest_dist = d;
  144. closest_point = closest;
  145. }
  146. }
  147. to = closest_point;
  148. };
  149. //test direct connection
  150. {
  151. bool can_see_eachother = true;
  152. for (Set<Edge>::Element *E = edges.front(); E; E = E->next()) {
  153. const Edge &e = E->get();
  154. if (e.points[0] == ignore_from_edge.points[0] && e.points[1] == ignore_from_edge.points[1]) {
  155. continue;
  156. }
  157. if (e.points[0] == ignore_to_edge.points[0] && e.points[1] == ignore_to_edge.points[1]) {
  158. continue;
  159. }
  160. Vector2 a = points[e.points[0]].pos;
  161. Vector2 b = points[e.points[1]].pos;
  162. if (Geometry::segment_intersects_segment_2d(a, b, from, to, nullptr)) {
  163. can_see_eachother = false;
  164. break;
  165. }
  166. }
  167. if (can_see_eachother) {
  168. path.push_back(from);
  169. path.push_back(to);
  170. return path;
  171. }
  172. }
  173. //add to graph
  174. int aidx = points.size() - 2;
  175. int bidx = points.size() - 1;
  176. points.write[aidx].pos = from;
  177. points.write[bidx].pos = to;
  178. points.write[aidx].distance = 0;
  179. points.write[bidx].distance = 0;
  180. points.write[aidx].prev = -1;
  181. points.write[bidx].prev = -1;
  182. points.write[aidx].penalty = 0;
  183. points.write[bidx].penalty = 0;
  184. for (int i = 0; i < points.size() - 2; i++) {
  185. bool valid_a = true;
  186. bool valid_b = true;
  187. points.write[i].prev = -1;
  188. points.write[i].distance = 0;
  189. if (!_is_point_inside(from * 0.5 + points[i].pos * 0.5)) {
  190. valid_a = false;
  191. }
  192. if (!_is_point_inside(to * 0.5 + points[i].pos * 0.5)) {
  193. valid_b = false;
  194. }
  195. for (Set<Edge>::Element *E = edges.front(); E; E = E->next()) {
  196. const Edge &e = E->get();
  197. if (e.points[0] == i || e.points[1] == i) {
  198. continue;
  199. }
  200. Vector2 a = points[e.points[0]].pos;
  201. Vector2 b = points[e.points[1]].pos;
  202. if (valid_a) {
  203. if (e.points[0] != ignore_from_edge.points[1] &&
  204. e.points[1] != ignore_from_edge.points[1] &&
  205. e.points[0] != ignore_from_edge.points[0] &&
  206. e.points[1] != ignore_from_edge.points[0]) {
  207. if (Geometry::segment_intersects_segment_2d(a, b, from, points[i].pos, nullptr)) {
  208. valid_a = false;
  209. }
  210. }
  211. }
  212. if (valid_b) {
  213. if (e.points[0] != ignore_to_edge.points[1] &&
  214. e.points[1] != ignore_to_edge.points[1] &&
  215. e.points[0] != ignore_to_edge.points[0] &&
  216. e.points[1] != ignore_to_edge.points[0]) {
  217. if (Geometry::segment_intersects_segment_2d(a, b, to, points[i].pos, nullptr)) {
  218. valid_b = false;
  219. }
  220. }
  221. }
  222. if (!valid_a && !valid_b) {
  223. break;
  224. }
  225. }
  226. if (valid_a) {
  227. points.write[i].connections.insert(aidx);
  228. points.write[aidx].connections.insert(i);
  229. }
  230. if (valid_b) {
  231. points.write[i].connections.insert(bidx);
  232. points.write[bidx].connections.insert(i);
  233. }
  234. }
  235. //solve graph
  236. Set<int> open_list;
  237. points.write[aidx].distance = 0;
  238. points.write[aidx].prev = aidx;
  239. for (Set<int>::Element *E = points[aidx].connections.front(); E; E = E->next()) {
  240. open_list.insert(E->get());
  241. points.write[E->get()].distance = from.distance_to(points[E->get()].pos);
  242. points.write[E->get()].prev = aidx;
  243. }
  244. bool found_route = false;
  245. while (true) {
  246. if (open_list.size() == 0) {
  247. printf("open list empty\n");
  248. break;
  249. }
  250. //check open list
  251. int least_cost_point = -1;
  252. float least_cost = 1e30;
  253. //this could be faster (cache previous results)
  254. for (Set<int>::Element *E = open_list.front(); E; E = E->next()) {
  255. const Point &p = points[E->get()];
  256. float cost = p.distance;
  257. cost += p.pos.distance_to(to);
  258. cost += p.penalty;
  259. if (cost < least_cost) {
  260. least_cost_point = E->get();
  261. least_cost = cost;
  262. }
  263. }
  264. const Point &np = points[least_cost_point];
  265. //open the neighbours for search
  266. for (Set<int>::Element *E = np.connections.front(); E; E = E->next()) {
  267. Point &p = points.write[E->get()];
  268. float distance = np.pos.distance_to(p.pos) + np.distance;
  269. if (p.prev != -1) {
  270. //oh this was visited already, can we win the cost?
  271. if (p.distance > distance) {
  272. p.prev = least_cost_point; //reasign previous
  273. p.distance = distance;
  274. }
  275. } else {
  276. //add to open neighbours
  277. p.prev = least_cost_point;
  278. p.distance = distance;
  279. open_list.insert(E->get());
  280. if (E->get() == bidx) {
  281. //oh my reached end! stop algorithm
  282. found_route = true;
  283. break;
  284. }
  285. }
  286. }
  287. if (found_route) {
  288. break;
  289. }
  290. open_list.erase(least_cost_point);
  291. }
  292. if (found_route) {
  293. int at = bidx;
  294. path.push_back(points[at].pos);
  295. do {
  296. at = points[at].prev;
  297. path.push_back(points[at].pos);
  298. } while (at != aidx);
  299. path.invert();
  300. }
  301. for (int i = 0; i < points.size() - 2; i++) {
  302. points.write[i].connections.erase(aidx);
  303. points.write[i].connections.erase(bidx);
  304. points.write[i].prev = -1;
  305. points.write[i].distance = 0;
  306. }
  307. points.write[aidx].connections.clear();
  308. points.write[aidx].prev = -1;
  309. points.write[aidx].distance = 0;
  310. points.write[bidx].connections.clear();
  311. points.write[bidx].prev = -1;
  312. points.write[bidx].distance = 0;
  313. return path;
  314. }
  315. void PolygonPathFinder::_set_data(const Dictionary &p_data) {
  316. ERR_FAIL_COND(!p_data.has("points"));
  317. ERR_FAIL_COND(!p_data.has("connections"));
  318. ERR_FAIL_COND(!p_data.has("segments"));
  319. ERR_FAIL_COND(!p_data.has("bounds"));
  320. PoolVector<Vector2> p = p_data["points"];
  321. Array c = p_data["connections"];
  322. ERR_FAIL_COND(c.size() != p.size());
  323. if (c.size()) {
  324. return;
  325. }
  326. int pc = p.size();
  327. points.resize(pc + 2);
  328. PoolVector<Vector2>::Read pr = p.read();
  329. for (int i = 0; i < pc; i++) {
  330. points.write[i].pos = pr[i];
  331. PoolVector<int> con = c[i];
  332. PoolVector<int>::Read cr = con.read();
  333. int cc = con.size();
  334. for (int j = 0; j < cc; j++) {
  335. points.write[i].connections.insert(cr[j]);
  336. }
  337. }
  338. if (p_data.has("penalties")) {
  339. PoolVector<float> penalties = p_data["penalties"];
  340. if (penalties.size() == pc) {
  341. PoolVector<float>::Read pr2 = penalties.read();
  342. for (int i = 0; i < pc; i++) {
  343. points.write[i].penalty = pr2[i];
  344. }
  345. }
  346. }
  347. PoolVector<int> segs = p_data["segments"];
  348. int sc = segs.size();
  349. ERR_FAIL_COND(sc & 1);
  350. PoolVector<int>::Read sr = segs.read();
  351. for (int i = 0; i < sc; i += 2) {
  352. Edge e(sr[i], sr[i + 1]);
  353. edges.insert(e);
  354. }
  355. bounds = p_data["bounds"];
  356. }
  357. Dictionary PolygonPathFinder::_get_data() const {
  358. Dictionary d;
  359. PoolVector<Vector2> p;
  360. PoolVector<int> ind;
  361. Array connections;
  362. p.resize(MAX(0, points.size() - 2));
  363. connections.resize(MAX(0, points.size() - 2));
  364. ind.resize(edges.size() * 2);
  365. PoolVector<float> penalties;
  366. penalties.resize(MAX(0, points.size() - 2));
  367. {
  368. PoolVector<Vector2>::Write wp = p.write();
  369. PoolVector<float>::Write pw = penalties.write();
  370. for (int i = 0; i < points.size() - 2; i++) {
  371. wp[i] = points[i].pos;
  372. pw[i] = points[i].penalty;
  373. PoolVector<int> c;
  374. c.resize(points[i].connections.size());
  375. {
  376. PoolVector<int>::Write cw = c.write();
  377. int idx = 0;
  378. for (Set<int>::Element *E = points[i].connections.front(); E; E = E->next()) {
  379. cw[idx++] = E->get();
  380. }
  381. }
  382. connections[i] = c;
  383. }
  384. }
  385. {
  386. PoolVector<int>::Write iw = ind.write();
  387. int idx = 0;
  388. for (Set<Edge>::Element *E = edges.front(); E; E = E->next()) {
  389. iw[idx++] = E->get().points[0];
  390. iw[idx++] = E->get().points[1];
  391. }
  392. }
  393. d["bounds"] = bounds;
  394. d["points"] = p;
  395. d["penalties"] = penalties;
  396. d["connections"] = connections;
  397. d["segments"] = ind;
  398. return d;
  399. }
  400. bool PolygonPathFinder::is_point_inside(const Vector2 &p_point) const {
  401. return _is_point_inside(p_point);
  402. }
  403. Vector2 PolygonPathFinder::get_closest_point(const Vector2 &p_point) const {
  404. float closest_dist = 1e20f;
  405. Vector2 closest_point;
  406. for (Set<Edge>::Element *E = edges.front(); E; E = E->next()) {
  407. const Edge &e = E->get();
  408. Vector2 seg[2] = {
  409. points[e.points[0]].pos,
  410. points[e.points[1]].pos
  411. };
  412. Vector2 closest = Geometry::get_closest_point_to_segment_2d(p_point, seg);
  413. float d = p_point.distance_squared_to(closest);
  414. if (d < closest_dist) {
  415. closest_dist = d;
  416. closest_point = closest;
  417. }
  418. }
  419. ERR_FAIL_COND_V(Math::is_equal_approx(closest_dist, 1e20f), Vector2());
  420. return closest_point;
  421. }
  422. Vector<Vector2> PolygonPathFinder::get_intersections(const Vector2 &p_from, const Vector2 &p_to) const {
  423. Vector<Vector2> inters;
  424. for (Set<Edge>::Element *E = edges.front(); E; E = E->next()) {
  425. Vector2 a = points[E->get().points[0]].pos;
  426. Vector2 b = points[E->get().points[1]].pos;
  427. Vector2 res;
  428. if (Geometry::segment_intersects_segment_2d(a, b, p_from, p_to, &res)) {
  429. inters.push_back(res);
  430. }
  431. }
  432. return inters;
  433. }
  434. Rect2 PolygonPathFinder::get_bounds() const {
  435. return bounds;
  436. }
  437. void PolygonPathFinder::set_point_penalty(int p_point, float p_penalty) {
  438. ERR_FAIL_INDEX(p_point, points.size() - 2);
  439. points.write[p_point].penalty = p_penalty;
  440. }
  441. float PolygonPathFinder::get_point_penalty(int p_point) const {
  442. ERR_FAIL_INDEX_V(p_point, points.size() - 2, 0);
  443. return points[p_point].penalty;
  444. }
  445. void PolygonPathFinder::_bind_methods() {
  446. ClassDB::bind_method(D_METHOD("setup", "points", "connections"), &PolygonPathFinder::setup);
  447. ClassDB::bind_method(D_METHOD("find_path", "from", "to"), &PolygonPathFinder::find_path);
  448. ClassDB::bind_method(D_METHOD("get_intersections", "from", "to"), &PolygonPathFinder::get_intersections);
  449. ClassDB::bind_method(D_METHOD("get_closest_point", "point"), &PolygonPathFinder::get_closest_point);
  450. ClassDB::bind_method(D_METHOD("is_point_inside", "point"), &PolygonPathFinder::is_point_inside);
  451. ClassDB::bind_method(D_METHOD("set_point_penalty", "idx", "penalty"), &PolygonPathFinder::set_point_penalty);
  452. ClassDB::bind_method(D_METHOD("get_point_penalty", "idx"), &PolygonPathFinder::get_point_penalty);
  453. ClassDB::bind_method(D_METHOD("get_bounds"), &PolygonPathFinder::get_bounds);
  454. ClassDB::bind_method(D_METHOD("_set_data"), &PolygonPathFinder::_set_data);
  455. ClassDB::bind_method(D_METHOD("_get_data"), &PolygonPathFinder::_get_data);
  456. ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_data", "_get_data");
  457. }
  458. PolygonPathFinder::PolygonPathFinder() {
  459. }