| 
									
										
										
										
											2016-06-18 14:46:12 +02:00
										 |  |  | /*************************************************************************/ | 
					
						
							|  |  |  | /*  navigation.cpp                                                       */ | 
					
						
							|  |  |  | /*************************************************************************/ | 
					
						
							|  |  |  | /*                       This file is part of:                           */ | 
					
						
							|  |  |  | /*                           GODOT ENGINE                                */ | 
					
						
							| 
									
										
										
										
											2017-08-27 14:16:55 +02:00
										 |  |  | /*                      https://godotengine.org                          */ | 
					
						
							| 
									
										
										
										
											2016-06-18 14:46:12 +02:00
										 |  |  | /*************************************************************************/ | 
					
						
							| 
									
										
										
										
											2021-01-01 20:13:46 +01:00
										 |  |  | /* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */ | 
					
						
							|  |  |  | /* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */ | 
					
						
							| 
									
										
										
										
											2016-06-18 14:46:12 +02:00
										 |  |  | /*                                                                       */ | 
					
						
							|  |  |  | /* Permission is hereby granted, free of charge, to any person obtaining */ | 
					
						
							|  |  |  | /* a copy of this software and associated documentation files (the       */ | 
					
						
							|  |  |  | /* "Software"), to deal in the Software without restriction, including   */ | 
					
						
							|  |  |  | /* without limitation the rights to use, copy, modify, merge, publish,   */ | 
					
						
							|  |  |  | /* distribute, sublicense, and/or sell copies of the Software, and to    */ | 
					
						
							|  |  |  | /* permit persons to whom the Software is furnished to do so, subject to */ | 
					
						
							|  |  |  | /* the following conditions:                                             */ | 
					
						
							|  |  |  | /*                                                                       */ | 
					
						
							|  |  |  | /* The above copyright notice and this permission notice shall be        */ | 
					
						
							|  |  |  | /* included in all copies or substantial portions of the Software.       */ | 
					
						
							|  |  |  | /*                                                                       */ | 
					
						
							|  |  |  | /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */ | 
					
						
							|  |  |  | /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */ | 
					
						
							|  |  |  | /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ | 
					
						
							|  |  |  | /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */ | 
					
						
							|  |  |  | /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */ | 
					
						
							|  |  |  | /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */ | 
					
						
							|  |  |  | /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */ | 
					
						
							|  |  |  | /*************************************************************************/ | 
					
						
							| 
									
										
										
										
											2018-01-05 00:50:27 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-08-01 22:10:38 -03:00
										 |  |  | #include "navigation.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-13 21:11:33 +02:00
										 |  |  | #define USE_ENTRY_POINT
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-08-01 22:10:38 -03:00
										 |  |  | void Navigation::_navmesh_link(int p_id) { | 
					
						
							|  |  |  | 	ERR_FAIL_COND(!navmesh_map.has(p_id)); | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	NavMesh &nm = navmesh_map[p_id]; | 
					
						
							| 
									
										
										
										
											2014-08-01 22:10:38 -03:00
										 |  |  | 	ERR_FAIL_COND(nm.linked); | 
					
						
							| 
									
										
										
										
											2018-03-02 09:37:32 +01:00
										 |  |  | 	ERR_FAIL_COND(nm.navmesh.is_null()); | 
					
						
							| 
									
										
										
										
											2014-08-01 22:10:38 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	PoolVector<Vector3> vertices = nm.navmesh->get_vertices(); | 
					
						
							| 
									
										
										
										
											2014-08-01 22:10:38 -03:00
										 |  |  | 	int len = vertices.size(); | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	if (len == 0) | 
					
						
							| 
									
										
										
										
											2014-08-01 22:10:38 -03:00
										 |  |  | 		return; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	PoolVector<Vector3>::Read r = vertices.read(); | 
					
						
							| 
									
										
										
										
											2014-08-01 22:10:38 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	for (int i = 0; i < nm.navmesh->get_polygon_count(); i++) { | 
					
						
							| 
									
										
										
										
											2014-08-01 22:10:38 -03:00
										 |  |  | 		//build
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 		List<Polygon>::Element *P = nm.polygons.push_back(Polygon()); | 
					
						
							|  |  |  | 		Polygon &p = P->get(); | 
					
						
							|  |  |  | 		p.owner = &nm; | 
					
						
							| 
									
										
										
										
											2014-08-01 22:10:38 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		Vector<int> poly = nm.navmesh->get_polygon(i); | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 		int plen = poly.size(); | 
					
						
							|  |  |  | 		const int *indices = poly.ptr(); | 
					
						
							|  |  |  | 		bool valid = true; | 
					
						
							| 
									
										
										
										
											2014-08-01 22:10:38 -03:00
										 |  |  | 		p.edges.resize(plen); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		Vector3 center; | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 		float sum = 0; | 
					
						
							| 
									
										
										
										
											2014-08-01 22:10:38 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 		for (int j = 0; j < plen; j++) { | 
					
						
							| 
									
										
										
										
											2014-08-01 22:10:38 -03:00
										 |  |  | 			int idx = indices[j]; | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 			if (idx < 0 || idx >= len) { | 
					
						
							|  |  |  | 				valid = false; | 
					
						
							| 
									
										
										
										
											2014-08-01 22:10:38 -03:00
										 |  |  | 				break; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			Polygon::Edge e; | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 			Vector3 ep = nm.xform.xform(r[idx]); | 
					
						
							|  |  |  | 			center += ep; | 
					
						
							|  |  |  | 			e.point = _get_point(ep); | 
					
						
							| 
									
										
										
										
											2018-07-25 03:11:03 +02:00
										 |  |  | 			p.edges.write[j] = e; | 
					
						
							| 
									
										
										
										
											2015-05-02 17:39:29 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 			if (j >= 2) { | 
					
						
							|  |  |  | 				Vector3 epa = nm.xform.xform(r[indices[j - 2]]); | 
					
						
							|  |  |  | 				Vector3 epb = nm.xform.xform(r[indices[j - 1]]); | 
					
						
							| 
									
										
										
										
											2015-05-02 17:39:29 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 				sum += up.dot((epb - epa).cross(ep - epa)); | 
					
						
							| 
									
										
										
										
											2015-05-02 17:39:29 -03:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2014-08-01 22:10:38 -03:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 		p.clockwise = sum > 0; | 
					
						
							| 
									
										
										
										
											2015-05-02 17:39:29 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-08-01 22:10:38 -03:00
										 |  |  | 		if (!valid) { | 
					
						
							|  |  |  | 			nm.polygons.pop_back(); | 
					
						
							|  |  |  | 			ERR_CONTINUE(!valid); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-01 00:08:33 +01:00
										 |  |  | 		p.center = center; | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 		if (plen != 0) { | 
					
						
							| 
									
										
										
										
											2016-03-01 00:08:33 +01:00
										 |  |  | 			p.center /= plen; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-08-01 22:10:38 -03:00
										 |  |  | 		//connect
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 		for (int j = 0; j < plen; j++) { | 
					
						
							|  |  |  | 			int next = (j + 1) % plen; | 
					
						
							|  |  |  | 			EdgeKey ek(p.edges[j].point, p.edges[next].point); | 
					
						
							| 
									
										
										
										
											2014-08-01 22:10:38 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 			Map<EdgeKey, Connection>::Element *C = connections.find(ek); | 
					
						
							| 
									
										
										
										
											2014-08-01 22:10:38 -03:00
										 |  |  | 			if (!C) { | 
					
						
							|  |  |  | 				Connection c; | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 				c.A = &p; | 
					
						
							|  |  |  | 				c.A_edge = j; | 
					
						
							| 
									
										
										
										
											2021-05-04 16:00:45 +02:00
										 |  |  | 				c.B = nullptr; | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 				c.B_edge = -1; | 
					
						
							|  |  |  | 				connections[ek] = c; | 
					
						
							| 
									
										
										
										
											2014-08-01 22:10:38 -03:00
										 |  |  | 			} else { | 
					
						
							| 
									
										
										
										
											2021-05-04 16:00:45 +02:00
										 |  |  | 				if (C->get().B != nullptr) { | 
					
						
							| 
									
										
										
										
											2015-06-01 19:42:34 -03:00
										 |  |  | 					ConnectionPending pending; | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 					pending.polygon = &p; | 
					
						
							|  |  |  | 					pending.edge = j; | 
					
						
							| 
									
										
										
										
											2018-07-25 03:11:03 +02:00
										 |  |  | 					p.edges.write[j].P = C->get().pending.push_back(pending); | 
					
						
							| 
									
										
										
										
											2015-06-01 19:42:34 -03:00
										 |  |  | 					continue; | 
					
						
							| 
									
										
										
										
											2014-08-01 22:10:38 -03:00
										 |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 				C->get().B = &p; | 
					
						
							|  |  |  | 				C->get().B_edge = j; | 
					
						
							| 
									
										
										
										
											2018-07-25 03:11:03 +02:00
										 |  |  | 				C->get().A->edges.write[C->get().A_edge].C = &p; | 
					
						
							|  |  |  | 				C->get().A->edges.write[C->get().A_edge].C_edge = j; | 
					
						
							|  |  |  | 				p.edges.write[j].C = C->get().A; | 
					
						
							|  |  |  | 				p.edges.write[j].C_edge = C->get().A_edge; | 
					
						
							| 
									
										
										
										
											2014-08-01 22:10:38 -03:00
										 |  |  | 				//connection successful.
 | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	nm.linked = true; | 
					
						
							| 
									
										
										
										
											2014-08-01 22:10:38 -03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void Navigation::_navmesh_unlink(int p_id) { | 
					
						
							|  |  |  | 	ERR_FAIL_COND(!navmesh_map.has(p_id)); | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	NavMesh &nm = navmesh_map[p_id]; | 
					
						
							| 
									
										
										
										
											2014-08-01 22:10:38 -03:00
										 |  |  | 	ERR_FAIL_COND(!nm.linked); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	for (List<Polygon>::Element *E = nm.polygons.front(); E; E = E->next()) { | 
					
						
							|  |  |  | 		Polygon &p = E->get(); | 
					
						
							| 
									
										
										
										
											2014-08-01 22:10:38 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-20 12:32:35 +01:00
										 |  |  | 		int edge_count = p.edges.size(); | 
					
						
							| 
									
										
										
										
											2017-11-25 00:07:54 -03:00
										 |  |  | 		Polygon::Edge *edges = p.edges.ptrw(); | 
					
						
							| 
									
										
										
										
											2014-08-01 22:10:38 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-20 12:32:35 +01:00
										 |  |  | 		for (int i = 0; i < edge_count; i++) { | 
					
						
							|  |  |  | 			int next = (i + 1) % edge_count; | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 			EdgeKey ek(edges[i].point, edges[next].point); | 
					
						
							|  |  |  | 			Map<EdgeKey, Connection>::Element *C = connections.find(ek); | 
					
						
							| 
									
										
										
										
											2015-06-01 19:42:34 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-08-01 22:10:38 -03:00
										 |  |  | 			ERR_CONTINUE(!C); | 
					
						
							| 
									
										
										
										
											2015-06-01 19:42:34 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			if (edges[i].P) { | 
					
						
							|  |  |  | 				C->get().pending.erase(edges[i].P); | 
					
						
							| 
									
										
										
										
											2021-05-04 16:00:45 +02:00
										 |  |  | 				edges[i].P = nullptr; | 
					
						
							| 
									
										
										
										
											2015-06-01 19:42:34 -03:00
										 |  |  | 			} else if (C->get().B) { | 
					
						
							| 
									
										
										
										
											2014-08-01 22:10:38 -03:00
										 |  |  | 				//disconnect
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-04 16:00:45 +02:00
										 |  |  | 				C->get().B->edges.write[C->get().B_edge].C = nullptr; | 
					
						
							| 
									
										
										
										
											2018-07-25 03:11:03 +02:00
										 |  |  | 				C->get().B->edges.write[C->get().B_edge].C_edge = -1; | 
					
						
							| 
									
										
										
										
											2021-05-04 16:00:45 +02:00
										 |  |  | 				C->get().A->edges.write[C->get().A_edge].C = nullptr; | 
					
						
							| 
									
										
										
										
											2018-07-25 03:11:03 +02:00
										 |  |  | 				C->get().A->edges.write[C->get().A_edge].C_edge = -1; | 
					
						
							| 
									
										
										
										
											2014-08-01 22:10:38 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 				if (C->get().A == &E->get()) { | 
					
						
							|  |  |  | 					C->get().A = C->get().B; | 
					
						
							|  |  |  | 					C->get().A_edge = C->get().B_edge; | 
					
						
							| 
									
										
										
										
											2014-08-01 22:10:38 -03:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2021-05-04 16:00:45 +02:00
										 |  |  | 				C->get().B = nullptr; | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 				C->get().B_edge = -1; | 
					
						
							| 
									
										
										
										
											2014-08-01 22:10:38 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-01 19:42:34 -03:00
										 |  |  | 				if (C->get().pending.size()) { | 
					
						
							|  |  |  | 					//reconnect if something is pending
 | 
					
						
							|  |  |  | 					ConnectionPending cp = C->get().pending.front()->get(); | 
					
						
							|  |  |  | 					C->get().pending.pop_front(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 					C->get().B = cp.polygon; | 
					
						
							|  |  |  | 					C->get().B_edge = cp.edge; | 
					
						
							| 
									
										
										
										
											2018-07-25 03:11:03 +02:00
										 |  |  | 					C->get().A->edges.write[C->get().A_edge].C = cp.polygon; | 
					
						
							|  |  |  | 					C->get().A->edges.write[C->get().A_edge].C_edge = cp.edge; | 
					
						
							|  |  |  | 					cp.polygon->edges.write[cp.edge].C = C->get().A; | 
					
						
							|  |  |  | 					cp.polygon->edges.write[cp.edge].C_edge = C->get().A_edge; | 
					
						
							| 
									
										
										
										
											2021-05-04 16:00:45 +02:00
										 |  |  | 					cp.polygon->edges.write[cp.edge].P = nullptr; | 
					
						
							| 
									
										
										
										
											2015-06-01 19:42:34 -03:00
										 |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-08-01 22:10:38 -03:00
										 |  |  | 			} else { | 
					
						
							|  |  |  | 				connections.erase(C); | 
					
						
							|  |  |  | 				//erase
 | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	nm.polygons.clear(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	nm.linked = false; | 
					
						
							| 
									
										
										
										
											2014-08-01 22:10:38 -03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-15 15:09:06 -05:00
										 |  |  | int Navigation::navmesh_add(const Ref<NavigationMesh> &p_mesh, const Transform &p_xform, Object *p_owner) { | 
					
						
							| 
									
										
										
										
											2014-08-01 22:10:38 -03:00
										 |  |  | 	int id = last_id++; | 
					
						
							|  |  |  | 	NavMesh nm; | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	nm.linked = false; | 
					
						
							|  |  |  | 	nm.navmesh = p_mesh; | 
					
						
							|  |  |  | 	nm.xform = p_xform; | 
					
						
							|  |  |  | 	nm.owner = p_owner; | 
					
						
							|  |  |  | 	navmesh_map[id] = nm; | 
					
						
							| 
									
										
										
										
											2014-08-01 22:10:38 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	_navmesh_link(id); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return id; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | void Navigation::navmesh_set_transform(int p_id, const Transform &p_xform) { | 
					
						
							| 
									
										
										
										
											2014-08-01 22:10:38 -03:00
										 |  |  | 	ERR_FAIL_COND(!navmesh_map.has(p_id)); | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	NavMesh &nm = navmesh_map[p_id]; | 
					
						
							|  |  |  | 	if (nm.xform == p_xform) | 
					
						
							| 
									
										
										
										
											2014-08-01 22:10:38 -03:00
										 |  |  | 		return; //bleh
 | 
					
						
							|  |  |  | 	_navmesh_unlink(p_id); | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	nm.xform = p_xform; | 
					
						
							| 
									
										
										
										
											2014-08-01 22:10:38 -03:00
										 |  |  | 	_navmesh_link(p_id); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | void Navigation::navmesh_remove(int p_id) { | 
					
						
							| 
									
										
										
										
											2019-09-25 10:28:50 +02:00
										 |  |  | 	ERR_FAIL_COND_MSG(!navmesh_map.has(p_id), "Trying to remove nonexisting navmesh with id: " + itos(p_id)); | 
					
						
							| 
									
										
										
										
											2014-08-01 22:10:38 -03:00
										 |  |  | 	_navmesh_unlink(p_id); | 
					
						
							|  |  |  | 	navmesh_map.erase(p_id); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | void Navigation::_clip_path(Vector<Vector3> &path, Polygon *from_poly, const Vector3 &p_to_point, Polygon *p_to_poly) { | 
					
						
							|  |  |  | 	Vector3 from = path[path.size() - 1]; | 
					
						
							| 
									
										
										
										
											2014-11-17 07:46:11 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	if (from.distance_to(p_to_point) < CMP_EPSILON) | 
					
						
							| 
									
										
										
										
											2014-11-17 07:46:11 -03:00
										 |  |  | 		return; | 
					
						
							|  |  |  | 	Plane cut_plane; | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	cut_plane.normal = (from - p_to_point).cross(up); | 
					
						
							|  |  |  | 	if (cut_plane.normal == Vector3()) | 
					
						
							| 
									
										
										
										
											2014-11-17 07:46:11 -03:00
										 |  |  | 		return; | 
					
						
							|  |  |  | 	cut_plane.normal.normalize(); | 
					
						
							|  |  |  | 	cut_plane.d = cut_plane.normal.dot(from); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	while (from_poly != p_to_poly) { | 
					
						
							| 
									
										
										
										
											2020-05-20 12:32:35 +01:00
										 |  |  | 		int edge_count = from_poly->edges.size(); | 
					
						
							|  |  |  | 		ERR_FAIL_COND_MSG(edge_count == 0, "Polygon has no edges."); | 
					
						
							| 
									
										
										
										
											2014-11-17 07:46:11 -03:00
										 |  |  | 		int pe = from_poly->prev_edge; | 
					
						
							| 
									
										
										
										
											2020-05-20 12:32:35 +01:00
										 |  |  | 		int next = (pe + 1) % edge_count; | 
					
						
							| 
									
										
										
										
											2014-11-17 07:46:11 -03:00
										 |  |  | 		Vector3 a = _get_vertex(from_poly->edges[pe].point); | 
					
						
							| 
									
										
										
										
											2020-05-20 12:32:35 +01:00
										 |  |  | 		Vector3 b = _get_vertex(from_poly->edges[next].point); | 
					
						
							| 
									
										
										
										
											2014-11-17 07:46:11 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 		from_poly = from_poly->edges[pe].C; | 
					
						
							| 
									
										
										
										
											2014-11-17 07:46:11 -03:00
										 |  |  | 		ERR_FAIL_COND(!from_poly); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 		if (a.distance_to(b) > CMP_EPSILON) { | 
					
						
							| 
									
										
										
										
											2014-11-17 07:46:11 -03:00
										 |  |  | 			Vector3 inters; | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 			if (cut_plane.intersects_segment(a, b, &inters)) { | 
					
						
							| 
									
										
										
										
											2020-05-20 12:32:35 +01:00
										 |  |  | 				if (inters.distance_to(p_to_point) > CMP_EPSILON && inters.distance_to(path[path.size() - 1]) > CMP_EPSILON) { | 
					
						
							| 
									
										
										
										
											2014-11-17 07:46:11 -03:00
										 |  |  | 					path.push_back(inters); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | Vector<Vector3> Navigation::get_simple_path(const Vector3 &p_start, const Vector3 &p_end, bool p_optimize) { | 
					
						
							| 
									
										
										
										
											2021-05-04 16:00:45 +02:00
										 |  |  | 	Polygon *begin_poly = nullptr; | 
					
						
							|  |  |  | 	Polygon *end_poly = nullptr; | 
					
						
							| 
									
										
										
										
											2014-08-01 22:10:38 -03:00
										 |  |  | 	Vector3 begin_point; | 
					
						
							|  |  |  | 	Vector3 end_point; | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	float begin_d = 1e20; | 
					
						
							|  |  |  | 	float end_d = 1e20; | 
					
						
							| 
									
										
										
										
											2014-08-01 22:10:38 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	for (Map<int, NavMesh>::Element *E = navmesh_map.front(); E; E = E->next()) { | 
					
						
							| 
									
										
										
										
											2014-08-01 22:10:38 -03:00
										 |  |  | 		if (!E->get().linked) | 
					
						
							|  |  |  | 			continue; | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 		for (List<Polygon>::Element *F = E->get().polygons.front(); F; F = F->next()) { | 
					
						
							|  |  |  | 			Polygon &p = F->get(); | 
					
						
							|  |  |  | 			for (int i = 2; i < p.edges.size(); i++) { | 
					
						
							|  |  |  | 				Face3 f(_get_vertex(p.edges[0].point), _get_vertex(p.edges[i - 1].point), _get_vertex(p.edges[i].point)); | 
					
						
							| 
									
										
										
										
											2014-08-01 22:10:38 -03:00
										 |  |  | 				Vector3 spoint = f.get_closest_point_to(p_start); | 
					
						
							|  |  |  | 				float dpoint = spoint.distance_to(p_start); | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 				if (dpoint < begin_d) { | 
					
						
							|  |  |  | 					begin_d = dpoint; | 
					
						
							|  |  |  | 					begin_poly = &p; | 
					
						
							|  |  |  | 					begin_point = spoint; | 
					
						
							| 
									
										
										
										
											2014-08-01 22:10:38 -03:00
										 |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				spoint = f.get_closest_point_to(p_end); | 
					
						
							|  |  |  | 				dpoint = spoint.distance_to(p_end); | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 				if (dpoint < end_d) { | 
					
						
							|  |  |  | 					end_d = dpoint; | 
					
						
							|  |  |  | 					end_poly = &p; | 
					
						
							|  |  |  | 					end_point = spoint; | 
					
						
							| 
									
										
										
										
											2014-08-01 22:10:38 -03:00
										 |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 			p.prev_edge = -1; | 
					
						
							| 
									
										
										
										
											2014-08-01 22:10:38 -03:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!begin_poly || !end_poly) { | 
					
						
							|  |  |  | 		return Vector<Vector3>(); //no path
 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	if (begin_poly == end_poly) { | 
					
						
							| 
									
										
										
										
											2014-08-01 22:10:38 -03:00
										 |  |  | 		Vector<Vector3> path; | 
					
						
							|  |  |  | 		path.resize(2); | 
					
						
							| 
									
										
										
										
											2018-07-25 03:11:03 +02:00
										 |  |  | 		path.write[0] = begin_point; | 
					
						
							|  |  |  | 		path.write[1] = end_point; | 
					
						
							| 
									
										
										
										
											2014-08-01 22:10:38 -03:00
										 |  |  | 		return path; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	bool found_route = false; | 
					
						
							| 
									
										
										
										
											2014-08-01 22:10:38 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	List<Polygon *> open_list; | 
					
						
							| 
									
										
										
										
											2020-05-20 12:32:35 +01:00
										 |  |  | 	int begin_edge_count = begin_poly->edges.size(); | 
					
						
							| 
									
										
										
										
											2014-08-01 22:10:38 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-20 12:32:35 +01:00
										 |  |  | 	for (int i = 0; i < begin_edge_count; i++) { | 
					
						
							| 
									
										
										
										
											2014-08-01 22:10:38 -03:00
										 |  |  | 		if (begin_poly->edges[i].C) { | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 			begin_poly->edges[i].C->prev_edge = begin_poly->edges[i].C_edge; | 
					
						
							| 
									
										
										
										
											2018-09-13 21:11:33 +02:00
										 |  |  | #ifdef USE_ENTRY_POINT
 | 
					
						
							| 
									
										
										
										
											2020-05-20 12:32:35 +01:00
										 |  |  | 			int next = (i + 1) % begin_edge_count; | 
					
						
							| 
									
										
										
										
											2018-09-13 21:11:33 +02:00
										 |  |  | 			Vector3 edge[2] = { | 
					
						
							|  |  |  | 				_get_vertex(begin_poly->edges[i].point), | 
					
						
							| 
									
										
										
										
											2020-05-20 12:32:35 +01:00
										 |  |  | 				_get_vertex(begin_poly->edges[next].point) | 
					
						
							| 
									
										
										
										
											2018-09-13 21:11:33 +02:00
										 |  |  | 			}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			Vector3 entry = Geometry::get_closest_point_to_segment(begin_poly->entry, edge); | 
					
						
							| 
									
										
										
										
											2019-05-03 10:50:26 +03:00
										 |  |  | 			begin_poly->edges[i].C->distance = begin_point.distance_to(entry); | 
					
						
							| 
									
										
										
										
											2018-09-13 21:11:33 +02:00
										 |  |  | 			begin_poly->edges[i].C->entry = entry; | 
					
						
							|  |  |  | #else
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 			begin_poly->edges[i].C->distance = begin_poly->center.distance_to(begin_poly->edges[i].C->center); | 
					
						
							| 
									
										
										
										
											2018-09-13 21:11:33 +02:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2014-08-01 22:10:38 -03:00
										 |  |  | 			open_list.push_back(begin_poly->edges[i].C); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	while (!found_route) { | 
					
						
							|  |  |  | 		if (open_list.size() == 0) { | 
					
						
							| 
									
										
										
										
											2014-08-01 22:10:38 -03:00
										 |  |  | 			break; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		//check open list
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-04 16:00:45 +02:00
										 |  |  | 		List<Polygon *>::Element *least_cost_poly = nullptr; | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 		float least_cost = 1e30; | 
					
						
							| 
									
										
										
										
											2014-08-01 22:10:38 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		//this could be faster (cache previous results)
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 		for (List<Polygon *>::Element *E = open_list.front(); E; E = E->next()) { | 
					
						
							|  |  |  | 			Polygon *p = E->get(); | 
					
						
							| 
									
										
										
										
											2014-08-01 22:10:38 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 			float cost = p->distance; | 
					
						
							| 
									
										
										
										
											2018-09-13 21:11:33 +02:00
										 |  |  | #ifdef USE_ENTRY_POINT
 | 
					
						
							| 
									
										
										
										
											2019-05-03 10:50:26 +03:00
										 |  |  | 			cost += p->entry.distance_to(end_point); | 
					
						
							| 
									
										
										
										
											2018-09-13 21:11:33 +02:00
										 |  |  | #else
 | 
					
						
							|  |  |  | 			cost += p->center.distance_to(end_point); | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 			if (cost < least_cost) { | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 				least_cost_poly = E; | 
					
						
							|  |  |  | 				least_cost = cost; | 
					
						
							| 
									
										
										
										
											2014-08-01 22:10:38 -03:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 		Polygon *p = least_cost_poly->get(); | 
					
						
							| 
									
										
										
										
											2014-08-01 22:10:38 -03:00
										 |  |  | 		//open the neighbours for search
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-03 10:50:26 +03:00
										 |  |  | 		if (p == end_poly) { | 
					
						
							|  |  |  | 			//oh my reached end! stop algorithm
 | 
					
						
							|  |  |  | 			found_route = true; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-20 12:32:35 +01:00
										 |  |  | 		int edge_count = p->edges.size(); | 
					
						
							|  |  |  | 		for (int i = 0; i < edge_count; i++) { | 
					
						
							| 
									
										
										
										
											2018-07-25 03:11:03 +02:00
										 |  |  | 			Polygon::Edge &e = p->edges.write[i]; | 
					
						
							| 
									
										
										
										
											2014-08-01 22:10:38 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			if (!e.C) | 
					
						
							|  |  |  | 				continue; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-03 10:50:26 +03:00
										 |  |  | #ifdef USE_ENTRY_POINT
 | 
					
						
							| 
									
										
										
										
											2020-05-20 12:32:35 +01:00
										 |  |  | 			int next = (i + 1) % edge_count; | 
					
						
							| 
									
										
										
										
											2019-05-03 10:50:26 +03:00
										 |  |  | 			Vector3 edge[2] = { | 
					
						
							|  |  |  | 				_get_vertex(p->edges[i].point), | 
					
						
							| 
									
										
										
										
											2020-05-20 12:32:35 +01:00
										 |  |  | 				_get_vertex(p->edges[next].point) | 
					
						
							| 
									
										
										
										
											2019-05-03 10:50:26 +03:00
										 |  |  | 			}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			Vector3 entry = Geometry::get_closest_point_to_segment(p->entry, edge); | 
					
						
							|  |  |  | 			float distance = p->entry.distance_to(entry) + p->distance; | 
					
						
							|  |  |  | #else
 | 
					
						
							| 
									
										
										
										
											2014-08-01 22:10:38 -03:00
										 |  |  | 			float distance = p->center.distance_to(e.C->center) + p->distance; | 
					
						
							| 
									
										
										
										
											2019-05-03 10:50:26 +03:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2014-08-01 22:10:38 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 			if (e.C->prev_edge != -1) { | 
					
						
							| 
									
										
										
										
											2014-08-01 22:10:38 -03:00
										 |  |  | 				//oh this was visited already, can we win the cost?
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 				if (e.C->distance > distance) { | 
					
						
							|  |  |  | 					e.C->prev_edge = e.C_edge; | 
					
						
							|  |  |  | 					e.C->distance = distance; | 
					
						
							| 
									
										
										
										
											2019-05-03 10:50:26 +03:00
										 |  |  | #ifdef USE_ENTRY_POINT
 | 
					
						
							|  |  |  | 					e.C->entry = entry; | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2014-08-01 22:10:38 -03:00
										 |  |  | 				} | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				//add to open neighbours
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 				e.C->prev_edge = e.C_edge; | 
					
						
							|  |  |  | 				e.C->distance = distance; | 
					
						
							| 
									
										
										
										
											2019-05-03 10:50:26 +03:00
										 |  |  | #ifdef USE_ENTRY_POINT
 | 
					
						
							|  |  |  | 				e.C->entry = entry; | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2014-08-01 22:10:38 -03:00
										 |  |  | 				open_list.push_back(e.C); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		open_list.erase(least_cost_poly); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (found_route) { | 
					
						
							|  |  |  | 		Vector<Vector3> path; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-08-14 10:31:38 -03:00
										 |  |  | 		if (p_optimize) { | 
					
						
							|  |  |  | 			//string pulling
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 			Polygon *apex_poly = end_poly; | 
					
						
							|  |  |  | 			Vector3 apex_point = end_point; | 
					
						
							|  |  |  | 			Vector3 portal_left = apex_point; | 
					
						
							|  |  |  | 			Vector3 portal_right = apex_point; | 
					
						
							|  |  |  | 			Polygon *left_poly = end_poly; | 
					
						
							|  |  |  | 			Polygon *right_poly = end_poly; | 
					
						
							|  |  |  | 			Polygon *p = end_poly; | 
					
						
							| 
									
										
										
										
											2014-08-14 10:31:38 -03:00
										 |  |  | 			path.push_back(end_point); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 			while (p) { | 
					
						
							| 
									
										
										
										
											2014-08-14 10:31:38 -03:00
										 |  |  | 				Vector3 left; | 
					
						
							|  |  |  | 				Vector3 right; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | #define CLOCK_TANGENT(m_a, m_b, m_c) (((m_a) - (m_c)).cross((m_a) - (m_b)))
 | 
					
						
							| 
									
										
										
										
											2014-08-14 10:31:38 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 				if (p == begin_poly) { | 
					
						
							|  |  |  | 					left = begin_point; | 
					
						
							|  |  |  | 					right = begin_point; | 
					
						
							| 
									
										
										
										
											2014-08-14 10:31:38 -03:00
										 |  |  | 				} else { | 
					
						
							| 
									
										
										
										
											2020-05-20 12:32:35 +01:00
										 |  |  | 					int edge_count = p->edges.size(); | 
					
						
							|  |  |  | 					ERR_FAIL_COND_V_MSG(edge_count == 0, Vector<Vector3>(), "Polygon has no edges."); | 
					
						
							| 
									
										
										
										
											2014-08-14 10:31:38 -03:00
										 |  |  | 					int prev = p->prev_edge; | 
					
						
							| 
									
										
										
										
											2020-05-20 12:32:35 +01:00
										 |  |  | 					int prev_n = (p->prev_edge + 1) % edge_count; | 
					
						
							| 
									
										
										
										
											2014-08-14 10:31:38 -03:00
										 |  |  | 					left = _get_vertex(p->edges[prev].point); | 
					
						
							|  |  |  | 					right = _get_vertex(p->edges[prev_n].point); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-02 17:39:29 -03:00
										 |  |  | 					//if (CLOCK_TANGENT(apex_point,left,(left+right)*0.5).dot(up) < 0){
 | 
					
						
							|  |  |  | 					if (p->clockwise) { | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 						SWAP(left, right); | 
					
						
							| 
									
										
										
										
											2014-08-14 10:31:38 -03:00
										 |  |  | 					} | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 				bool skip = false; | 
					
						
							| 
									
										
										
										
											2014-08-14 10:31:38 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 				if (CLOCK_TANGENT(apex_point, portal_left, left).dot(up) >= 0) { | 
					
						
							| 
									
										
										
										
											2014-08-14 10:31:38 -03:00
										 |  |  | 					//process
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 					if (portal_left == apex_point || CLOCK_TANGENT(apex_point, left, portal_right).dot(up) > 0) { | 
					
						
							|  |  |  | 						left_poly = p; | 
					
						
							|  |  |  | 						portal_left = left; | 
					
						
							| 
									
										
										
										
											2014-08-14 10:31:38 -03:00
										 |  |  | 					} else { | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 						_clip_path(path, apex_poly, portal_right, right_poly); | 
					
						
							| 
									
										
										
										
											2014-11-17 07:46:11 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 						apex_point = portal_right; | 
					
						
							|  |  |  | 						p = right_poly; | 
					
						
							|  |  |  | 						left_poly = p; | 
					
						
							|  |  |  | 						apex_poly = p; | 
					
						
							|  |  |  | 						portal_left = apex_point; | 
					
						
							|  |  |  | 						portal_right = apex_point; | 
					
						
							| 
									
										
										
										
											2014-08-14 10:31:38 -03:00
										 |  |  | 						path.push_back(apex_point); | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 						skip = true; | 
					
						
							| 
									
										
										
										
											2014-08-14 10:31:38 -03:00
										 |  |  | 					} | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 				if (!skip && CLOCK_TANGENT(apex_point, portal_right, right).dot(up) <= 0) { | 
					
						
							| 
									
										
										
										
											2014-08-14 10:31:38 -03:00
										 |  |  | 					//process
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 					if (portal_right == apex_point || CLOCK_TANGENT(apex_point, right, portal_left).dot(up) < 0) { | 
					
						
							|  |  |  | 						right_poly = p; | 
					
						
							|  |  |  | 						portal_right = right; | 
					
						
							| 
									
										
										
										
											2014-08-14 10:31:38 -03:00
										 |  |  | 					} else { | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 						_clip_path(path, apex_poly, portal_left, left_poly); | 
					
						
							| 
									
										
										
										
											2014-11-17 07:46:11 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 						apex_point = portal_left; | 
					
						
							|  |  |  | 						p = left_poly; | 
					
						
							|  |  |  | 						right_poly = p; | 
					
						
							|  |  |  | 						apex_poly = p; | 
					
						
							|  |  |  | 						portal_right = apex_point; | 
					
						
							|  |  |  | 						portal_left = apex_point; | 
					
						
							| 
									
										
										
										
											2014-08-14 10:31:38 -03:00
										 |  |  | 						path.push_back(apex_point); | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 				if (p != begin_poly) | 
					
						
							|  |  |  | 					p = p->edges[p->prev_edge].C; | 
					
						
							| 
									
										
										
										
											2014-08-14 10:31:38 -03:00
										 |  |  | 				else | 
					
						
							| 
									
										
										
										
											2021-05-04 16:00:45 +02:00
										 |  |  | 					p = nullptr; | 
					
						
							| 
									
										
										
										
											2014-08-14 10:31:38 -03:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2014-08-01 22:10:38 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 			if (path[path.size() - 1] != begin_point) | 
					
						
							| 
									
										
										
										
											2014-08-14 10:31:38 -03:00
										 |  |  | 				path.push_back(begin_point); | 
					
						
							| 
									
										
										
										
											2014-08-01 22:10:38 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-08-14 10:31:38 -03:00
										 |  |  | 			path.invert(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			//midpoints
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 			Polygon *p = end_poly; | 
					
						
							| 
									
										
										
										
											2014-08-14 10:31:38 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			path.push_back(end_point); | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 			while (true) { | 
					
						
							| 
									
										
										
										
											2014-08-14 10:31:38 -03:00
										 |  |  | 				int prev = p->prev_edge; | 
					
						
							| 
									
										
										
										
											2019-05-03 10:50:26 +03:00
										 |  |  | #ifdef USE_ENTRY_POINT
 | 
					
						
							|  |  |  | 				Vector3 point = p->entry; | 
					
						
							|  |  |  | #else
 | 
					
						
							| 
									
										
										
										
											2020-05-20 12:32:35 +01:00
										 |  |  | 				int edge_count = p->edges.size(); | 
					
						
							|  |  |  | 				ERR_FAIL_COND_V_MSG(edge_count == 0, Vector<Vector3>(), "Polygon has no edges."); | 
					
						
							|  |  |  | 				int prev_n = (p->prev_edge + 1) % edge_count; | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 				Vector3 point = (_get_vertex(p->edges[prev].point) + _get_vertex(p->edges[prev_n].point)) * 0.5; | 
					
						
							| 
									
										
										
										
											2019-05-03 10:50:26 +03:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2014-08-14 10:31:38 -03:00
										 |  |  | 				path.push_back(point); | 
					
						
							|  |  |  | 				p = p->edges[prev].C; | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 				if (p == begin_poly) | 
					
						
							| 
									
										
										
										
											2014-08-14 10:31:38 -03:00
										 |  |  | 					break; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			path.push_back(begin_point); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-14 18:03:38 +01:00
										 |  |  | 			path.invert(); | 
					
						
							| 
									
										
										
										
											2014-08-14 10:31:38 -03:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2014-08-01 22:10:38 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		return path; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return Vector<Vector3>(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | Vector3 Navigation::get_closest_point_to_segment(const Vector3 &p_from, const Vector3 &p_to, const bool &p_use_collision) { | 
					
						
							|  |  |  | 	bool use_collision = p_use_collision; | 
					
						
							| 
									
										
										
										
											2014-08-01 22:10:38 -03:00
										 |  |  | 	Vector3 closest_point; | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	float closest_point_d = 1e20; | 
					
						
							| 
									
										
										
										
											2014-08-01 22:10:38 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	for (Map<int, NavMesh>::Element *E = navmesh_map.front(); E; E = E->next()) { | 
					
						
							| 
									
										
										
										
											2014-08-01 22:10:38 -03:00
										 |  |  | 		if (!E->get().linked) | 
					
						
							|  |  |  | 			continue; | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 		for (List<Polygon>::Element *F = E->get().polygons.front(); F; F = F->next()) { | 
					
						
							|  |  |  | 			Polygon &p = F->get(); | 
					
						
							|  |  |  | 			for (int i = 2; i < p.edges.size(); i++) { | 
					
						
							|  |  |  | 				Face3 f(_get_vertex(p.edges[0].point), _get_vertex(p.edges[i - 1].point), _get_vertex(p.edges[i].point)); | 
					
						
							| 
									
										
										
										
											2014-08-01 22:10:38 -03:00
										 |  |  | 				Vector3 inters; | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 				if (f.intersects_segment(p_from, p_to, &inters)) { | 
					
						
							| 
									
										
										
										
											2014-08-01 22:10:38 -03:00
										 |  |  | 					if (!use_collision) { | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 						closest_point = inters; | 
					
						
							|  |  |  | 						use_collision = true; | 
					
						
							|  |  |  | 						closest_point_d = p_from.distance_to(inters); | 
					
						
							|  |  |  | 					} else if (closest_point_d > inters.distance_to(p_from)) { | 
					
						
							|  |  |  | 						closest_point = inters; | 
					
						
							|  |  |  | 						closest_point_d = p_from.distance_to(inters); | 
					
						
							| 
									
										
										
										
											2014-08-01 22:10:38 -03:00
										 |  |  | 					} | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if (!use_collision) { | 
					
						
							| 
									
										
										
										
											2020-05-20 12:32:35 +01:00
										 |  |  | 				int edge_count = p.edges.size(); | 
					
						
							|  |  |  | 				for (int i = 0; i < edge_count; i++) { | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 					Vector3 a, b; | 
					
						
							| 
									
										
										
										
											2020-05-20 12:32:35 +01:00
										 |  |  | 					int next = (i + 1) % edge_count; | 
					
						
							|  |  |  | 					Geometry::get_closest_points_between_segments(p_from, p_to, _get_vertex(p.edges[i].point), _get_vertex(p.edges[next].point), a, b); | 
					
						
							| 
									
										
										
										
											2014-08-01 22:10:38 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 					float d = a.distance_to(b); | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 					if (d < closest_point_d) { | 
					
						
							|  |  |  | 						closest_point_d = d; | 
					
						
							|  |  |  | 						closest_point = b; | 
					
						
							| 
									
										
										
										
											2014-08-01 22:10:38 -03:00
										 |  |  | 					} | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return closest_point; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | Vector3 Navigation::get_closest_point(const Vector3 &p_point) { | 
					
						
							| 
									
										
										
										
											2014-08-01 22:10:38 -03:00
										 |  |  | 	Vector3 closest_point; | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	float closest_point_d = 1e20; | 
					
						
							| 
									
										
										
										
											2014-08-01 22:10:38 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	for (Map<int, NavMesh>::Element *E = navmesh_map.front(); E; E = E->next()) { | 
					
						
							| 
									
										
										
										
											2014-08-01 22:10:38 -03:00
										 |  |  | 		if (!E->get().linked) | 
					
						
							|  |  |  | 			continue; | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 		for (List<Polygon>::Element *F = E->get().polygons.front(); F; F = F->next()) { | 
					
						
							|  |  |  | 			Polygon &p = F->get(); | 
					
						
							|  |  |  | 			for (int i = 2; i < p.edges.size(); i++) { | 
					
						
							|  |  |  | 				Face3 f(_get_vertex(p.edges[0].point), _get_vertex(p.edges[i - 1].point), _get_vertex(p.edges[i].point)); | 
					
						
							| 
									
										
										
										
											2014-08-01 22:10:38 -03:00
										 |  |  | 				Vector3 inters = f.get_closest_point_to(p_point); | 
					
						
							|  |  |  | 				float d = inters.distance_to(p_point); | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 				if (d < closest_point_d) { | 
					
						
							|  |  |  | 					closest_point = inters; | 
					
						
							|  |  |  | 					closest_point_d = d; | 
					
						
							| 
									
										
										
										
											2014-08-01 22:10:38 -03:00
										 |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return closest_point; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | Vector3 Navigation::get_closest_point_normal(const Vector3 &p_point) { | 
					
						
							| 
									
										
										
										
											2014-08-01 22:10:38 -03:00
										 |  |  | 	Vector3 closest_point; | 
					
						
							|  |  |  | 	Vector3 closest_normal; | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	float closest_point_d = 1e20; | 
					
						
							| 
									
										
										
										
											2014-08-01 22:10:38 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	for (Map<int, NavMesh>::Element *E = navmesh_map.front(); E; E = E->next()) { | 
					
						
							| 
									
										
										
										
											2014-08-01 22:10:38 -03:00
										 |  |  | 		if (!E->get().linked) | 
					
						
							|  |  |  | 			continue; | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 		for (List<Polygon>::Element *F = E->get().polygons.front(); F; F = F->next()) { | 
					
						
							|  |  |  | 			Polygon &p = F->get(); | 
					
						
							|  |  |  | 			for (int i = 2; i < p.edges.size(); i++) { | 
					
						
							|  |  |  | 				Face3 f(_get_vertex(p.edges[0].point), _get_vertex(p.edges[i - 1].point), _get_vertex(p.edges[i].point)); | 
					
						
							| 
									
										
										
										
											2014-08-01 22:10:38 -03:00
										 |  |  | 				Vector3 inters = f.get_closest_point_to(p_point); | 
					
						
							|  |  |  | 				float d = inters.distance_to(p_point); | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 				if (d < closest_point_d) { | 
					
						
							|  |  |  | 					closest_point = inters; | 
					
						
							|  |  |  | 					closest_point_d = d; | 
					
						
							|  |  |  | 					closest_normal = f.get_plane().normal; | 
					
						
							| 
									
										
										
										
											2014-08-01 22:10:38 -03:00
										 |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return closest_normal; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | Object *Navigation::get_closest_point_owner(const Vector3 &p_point) { | 
					
						
							| 
									
										
										
										
											2015-04-21 16:47:49 -03:00
										 |  |  | 	Vector3 closest_point; | 
					
						
							| 
									
										
										
										
											2021-05-04 16:00:45 +02:00
										 |  |  | 	Object *owner = nullptr; | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	float closest_point_d = 1e20; | 
					
						
							| 
									
										
										
										
											2015-04-21 16:47:49 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	for (Map<int, NavMesh>::Element *E = navmesh_map.front(); E; E = E->next()) { | 
					
						
							| 
									
										
										
										
											2015-04-21 16:47:49 -03:00
										 |  |  | 		if (!E->get().linked) | 
					
						
							|  |  |  | 			continue; | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 		for (List<Polygon>::Element *F = E->get().polygons.front(); F; F = F->next()) { | 
					
						
							|  |  |  | 			Polygon &p = F->get(); | 
					
						
							|  |  |  | 			for (int i = 2; i < p.edges.size(); i++) { | 
					
						
							|  |  |  | 				Face3 f(_get_vertex(p.edges[0].point), _get_vertex(p.edges[i - 1].point), _get_vertex(p.edges[i].point)); | 
					
						
							| 
									
										
										
										
											2015-04-21 16:47:49 -03:00
										 |  |  | 				Vector3 inters = f.get_closest_point_to(p_point); | 
					
						
							|  |  |  | 				float d = inters.distance_to(p_point); | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 				if (d < closest_point_d) { | 
					
						
							|  |  |  | 					closest_point = inters; | 
					
						
							|  |  |  | 					closest_point_d = d; | 
					
						
							|  |  |  | 					owner = E->get().owner; | 
					
						
							| 
									
										
										
										
											2015-04-21 16:47:49 -03:00
										 |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return owner; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | void Navigation::set_up_vector(const Vector3 &p_up) { | 
					
						
							|  |  |  | 	up = p_up; | 
					
						
							| 
									
										
										
										
											2014-08-14 10:31:38 -03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | Vector3 Navigation::get_up_vector() const { | 
					
						
							| 
									
										
										
										
											2014-08-14 10:31:38 -03:00
										 |  |  | 	return up; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-08-01 22:10:38 -03:00
										 |  |  | void Navigation::_bind_methods() { | 
					
						
							| 
									
										
										
										
											2017-12-15 15:09:06 -05:00
										 |  |  | 	ClassDB::bind_method(D_METHOD("navmesh_add", "mesh", "xform", "owner"), &Navigation::navmesh_add, DEFVAL(Variant())); | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	ClassDB::bind_method(D_METHOD("navmesh_set_transform", "id", "xform"), &Navigation::navmesh_set_transform); | 
					
						
							|  |  |  | 	ClassDB::bind_method(D_METHOD("navmesh_remove", "id"), &Navigation::navmesh_remove); | 
					
						
							| 
									
										
										
										
											2017-02-13 12:47:24 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	ClassDB::bind_method(D_METHOD("get_simple_path", "start", "end", "optimize"), &Navigation::get_simple_path, DEFVAL(true)); | 
					
						
							|  |  |  | 	ClassDB::bind_method(D_METHOD("get_closest_point_to_segment", "start", "end", "use_collision"), &Navigation::get_closest_point_to_segment, DEFVAL(false)); | 
					
						
							|  |  |  | 	ClassDB::bind_method(D_METHOD("get_closest_point", "to_point"), &Navigation::get_closest_point); | 
					
						
							|  |  |  | 	ClassDB::bind_method(D_METHOD("get_closest_point_normal", "to_point"), &Navigation::get_closest_point_normal); | 
					
						
							|  |  |  | 	ClassDB::bind_method(D_METHOD("get_closest_point_owner", "to_point"), &Navigation::get_closest_point_owner); | 
					
						
							| 
									
										
										
										
											2017-02-13 12:47:24 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	ClassDB::bind_method(D_METHOD("set_up_vector", "up"), &Navigation::set_up_vector); | 
					
						
							|  |  |  | 	ClassDB::bind_method(D_METHOD("get_up_vector"), &Navigation::get_up_vector); | 
					
						
							| 
									
										
										
										
											2014-08-14 10:31:38 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "up_vector"), "set_up_vector", "get_up_vector"); | 
					
						
							| 
									
										
										
										
											2014-08-01 22:10:38 -03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Navigation::Navigation() { | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	ERR_FAIL_COND(sizeof(Point) != 8); | 
					
						
							|  |  |  | 	cell_size = 0.01; //one centimeter
 | 
					
						
							|  |  |  | 	last_id = 1; | 
					
						
							|  |  |  | 	up = Vector3(0, 1, 0); | 
					
						
							| 
									
										
										
										
											2014-08-01 22:10:38 -03:00
										 |  |  | } |