@@ -221,27 +221,27 @@ Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p
221
221
222
222
// List of all reachable navigation polys.
223
223
LocalVector<gd::NavigationPoly> navigation_polys;
224
- navigation_polys.reserve (polygons.size () * 0.75 );
224
+ navigation_polys.resize (polygons.size () + link_polygons. size () );
225
225
226
- // Add the start polygon to the reachable navigation polygons .
227
- gd::NavigationPoly begin_navigation_poly = gd::NavigationPoly ( begin_poly) ;
228
- begin_navigation_poly.self_id = 0 ;
226
+ // Initialize the matching navigation polygon .
227
+ gd::NavigationPoly & begin_navigation_poly = navigation_polys[ begin_poly-> id ] ;
228
+ begin_navigation_poly.poly = begin_poly ;
229
229
begin_navigation_poly.entry = begin_point;
230
230
begin_navigation_poly.back_navigation_edge_pathway_start = begin_point;
231
231
begin_navigation_poly.back_navigation_edge_pathway_end = begin_point;
232
- navigation_polys.push_back (begin_navigation_poly);
233
232
234
- // List of polygon IDs to visit.
235
- List<uint32_t > to_visit;
236
- to_visit.push_back (0 );
233
+ // Heap of polygons to travel next.
234
+ gd::Heap<gd::NavigationPoly *, gd::NavPolyTravelCostGreaterThan, gd::NavPolyHeapIndexer>
235
+ traversable_polys;
236
+ traversable_polys.reserve (polygons.size () * 0.25 );
237
237
238
238
// This is an implementation of the A* algorithm.
239
- int least_cost_id = 0 ;
239
+ int least_cost_id = begin_poly-> id ;
240
240
int prev_least_cost_id = -1 ;
241
241
bool found_route = false ;
242
242
243
243
const gd::Polygon *reachable_end = nullptr ;
244
- real_t reachable_d = FLT_MAX;
244
+ real_t distance_to_reachable_end = FLT_MAX;
245
245
bool is_reachable = true ;
246
246
247
247
while (true ) {
@@ -260,51 +260,57 @@ Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p
260
260
real_t poly_enter_cost = 0.0 ;
261
261
real_t poly_travel_cost = least_cost_poly.poly ->owner ->get_travel_cost ();
262
262
263
- if (prev_least_cost_id != -1 && ( navigation_polys[prev_least_cost_id].poly ->owner ->get_self () != least_cost_poly.poly ->owner ->get_self () )) {
263
+ if (prev_least_cost_id != -1 && navigation_polys[prev_least_cost_id].poly ->owner ->get_self () != least_cost_poly.poly ->owner ->get_self ()) {
264
264
poly_enter_cost = least_cost_poly.poly ->owner ->get_enter_cost ();
265
265
}
266
266
prev_least_cost_id = least_cost_id;
267
267
268
268
Vector3 pathway[2 ] = { connection.pathway_start , connection.pathway_end };
269
269
const Vector3 new_entry = Geometry3D::get_closest_point_to_segment (least_cost_poly.entry , pathway);
270
- const real_t new_distance = (least_cost_poly.entry .distance_to (new_entry) * poly_travel_cost) + poly_enter_cost + least_cost_poly.traveled_distance ;
271
-
272
- int64_t already_visited_polygon_index = navigation_polys.find (gd::NavigationPoly (connection.polygon ));
273
-
274
- if (already_visited_polygon_index != -1 ) {
275
- // Polygon already visited, check if we can reduce the travel cost.
276
- gd::NavigationPoly &avp = navigation_polys[already_visited_polygon_index];
277
- if (new_distance < avp.traveled_distance ) {
278
- avp.back_navigation_poly_id = least_cost_id;
279
- avp.back_navigation_edge = connection.edge ;
280
- avp.back_navigation_edge_pathway_start = connection.pathway_start ;
281
- avp.back_navigation_edge_pathway_end = connection.pathway_end ;
282
- avp.traveled_distance = new_distance;
283
- avp.entry = new_entry;
270
+ const real_t new_traveled_distance = least_cost_poly.entry .distance_to (new_entry) * poly_travel_cost + poly_enter_cost + least_cost_poly.traveled_distance ;
271
+
272
+ // Check if the neighbor polygon has already been processed.
273
+ gd::NavigationPoly &neighbor_poly = navigation_polys[connection.polygon ->id ];
274
+ if (neighbor_poly.poly != nullptr ) {
275
+ // If the neighbor polygon hasn't been traversed yet and the new path leading to
276
+ // it is shorter, update the polygon.
277
+ if (neighbor_poly.traversable_poly_index < traversable_polys.size () &&
278
+ new_traveled_distance < neighbor_poly.traveled_distance ) {
279
+ neighbor_poly.back_navigation_poly_id = least_cost_id;
280
+ neighbor_poly.back_navigation_edge = connection.edge ;
281
+ neighbor_poly.back_navigation_edge_pathway_start = connection.pathway_start ;
282
+ neighbor_poly.back_navigation_edge_pathway_end = connection.pathway_end ;
283
+ neighbor_poly.traveled_distance = new_traveled_distance;
284
+ neighbor_poly.distance_to_destination =
285
+ new_entry.distance_to (end_point) *
286
+ neighbor_poly.poly ->owner ->get_travel_cost ();
287
+ neighbor_poly.entry = new_entry;
288
+
289
+ // Update the priority of the polygon in the heap.
290
+ traversable_polys.shift (neighbor_poly.traversable_poly_index );
284
291
}
285
292
} else {
286
- // Add the neighbor polygon to the reachable ones.
287
- gd::NavigationPoly new_navigation_poly = gd::NavigationPoly (connection.polygon );
288
- new_navigation_poly.self_id = navigation_polys.size ();
289
- new_navigation_poly.back_navigation_poly_id = least_cost_id;
290
- new_navigation_poly.back_navigation_edge = connection.edge ;
291
- new_navigation_poly.back_navigation_edge_pathway_start = connection.pathway_start ;
292
- new_navigation_poly.back_navigation_edge_pathway_end = connection.pathway_end ;
293
- new_navigation_poly.traveled_distance = new_distance;
294
- new_navigation_poly.entry = new_entry;
295
- navigation_polys.push_back (new_navigation_poly);
296
-
297
- // Add the neighbor polygon to the polygons to visit.
298
- to_visit.push_back (navigation_polys.size () - 1 );
293
+ // Initialize the matching navigation polygon.
294
+ neighbor_poly.poly = connection.polygon ;
295
+ neighbor_poly.back_navigation_poly_id = least_cost_id;
296
+ neighbor_poly.back_navigation_edge = connection.edge ;
297
+ neighbor_poly.back_navigation_edge_pathway_start = connection.pathway_start ;
298
+ neighbor_poly.back_navigation_edge_pathway_end = connection.pathway_end ;
299
+ neighbor_poly.traveled_distance = new_traveled_distance;
300
+ neighbor_poly.distance_to_destination =
301
+ new_entry.distance_to (end_point) *
302
+ neighbor_poly.poly ->owner ->get_travel_cost ();
303
+ neighbor_poly.entry = new_entry;
304
+
305
+ // Add the polygon to the heap of polygons to traverse next.
306
+ traversable_polys.push (&neighbor_poly);
299
307
}
300
308
}
301
309
}
302
310
303
- // Removes the least cost polygon from the list of polygons to visit so we can advance.
304
- to_visit.erase (least_cost_id);
305
-
306
- // When the list of polygons to visit is empty at this point it means the End Polygon is not reachable
307
- if (to_visit.size () == 0 ) {
311
+ // When the heap of traversable polygons is empty at this point it means the end polygon is
312
+ // unreachable.
313
+ if (traversable_polys.is_empty ()) {
308
314
// Thus use the further reachable polygon
309
315
ERR_BREAK_MSG (is_reachable == false , " It's not expect to not find the most reachable polygons" );
310
316
is_reachable = false ;
@@ -366,40 +372,27 @@ Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p
366
372
return path;
367
373
}
368
374
369
- // Reset open and navigation_polys
370
- gd::NavigationPoly np = navigation_polys[0 ];
371
- navigation_polys.clear ();
372
- navigation_polys.push_back (np);
373
- to_visit.clear ();
374
- to_visit.push_back (0 );
375
- least_cost_id = 0 ;
375
+ for (gd::NavigationPoly &nav_poly : navigation_polys) {
376
+ nav_poly.poly = nullptr ;
377
+ }
378
+ navigation_polys[begin_poly->id ].poly = begin_poly;
379
+
380
+ least_cost_id = begin_poly->id ;
376
381
prev_least_cost_id = -1 ;
377
382
378
383
reachable_end = nullptr ;
379
384
380
385
continue ;
381
386
}
382
387
383
- // Find the polygon with the minimum cost from the list of polygons to visit.
384
- least_cost_id = -1 ;
385
- real_t least_cost = FLT_MAX;
386
- for (List<uint32_t >::Element *element = to_visit.front (); element != nullptr ; element = element->next ()) {
387
- gd::NavigationPoly *np = &navigation_polys[element->get ()];
388
- real_t cost = np->traveled_distance ;
389
- cost += (np->entry .distance_to (end_point) * np->poly ->owner ->get_travel_cost ());
390
- if (cost < least_cost) {
391
- least_cost_id = np->self_id ;
392
- least_cost = cost;
393
- }
394
- }
395
-
396
- ERR_BREAK (least_cost_id == -1 );
388
+ // Pop the polygon with the lowest travel cost from the heap of traversable polygons.
389
+ least_cost_id = traversable_polys.pop ()->poly ->id ;
397
390
398
- // Stores the further reachable end polygon, in case our goal is not reachable.
391
+ // Store the farthest reachable end polygon in case our goal is not reachable.
399
392
if (is_reachable) {
400
- real_t d = navigation_polys[least_cost_id].entry .distance_to (p_destination);
401
- if (reachable_d > d ) {
402
- reachable_d = d ;
393
+ real_t distance = navigation_polys[least_cost_id].entry .distance_to (p_destination);
394
+ if (distance_to_reachable_end > distance ) {
395
+ distance_to_reachable_end = distance ;
403
396
reachable_end = navigation_polys[least_cost_id].poly ;
404
397
}
405
398
}
@@ -943,29 +936,30 @@ void NavMap::sync() {
943
936
}
944
937
945
938
// Resize the polygon count.
946
- int count = 0 ;
939
+ int polygon_count = 0 ;
947
940
for (const NavRegion *region : regions) {
948
941
if (!region->get_enabled ()) {
949
942
continue ;
950
943
}
951
- count += region->get_polygons ().size ();
944
+ polygon_count += region->get_polygons ().size ();
952
945
}
953
- polygons.resize (count );
946
+ polygons.resize (polygon_count );
954
947
955
948
// Copy all region polygons in the map.
956
- count = 0 ;
949
+ polygon_count = 0 ;
957
950
for (const NavRegion *region : regions) {
958
951
if (!region->get_enabled ()) {
959
952
continue ;
960
953
}
961
954
const LocalVector<gd::Polygon> &polygons_source = region->get_polygons ();
962
955
for (uint32_t n = 0 ; n < polygons_source.size (); n++) {
963
- polygons[count + n] = polygons_source[n];
956
+ polygons[polygon_count] = polygons_source[n];
957
+ polygons[polygon_count].id = polygon_count;
958
+ polygon_count++;
964
959
}
965
- count += region->get_polygons ().size ();
966
960
}
967
961
968
- _new_pm_polygon_count = polygons. size () ;
962
+ _new_pm_polygon_count = polygon_count ;
969
963
970
964
// Group all edges per key.
971
965
HashMap<gd::EdgeKey, Vector<gd::Edge::Connection>, gd::EdgeKey> connections;
@@ -1136,6 +1130,7 @@ void NavMap::sync() {
1136
1130
// If we have both a start and end point, then create a synthetic polygon to route through.
1137
1131
if (closest_start_polygon && closest_end_polygon) {
1138
1132
gd::Polygon &new_polygon = link_polygons[link_poly_idx++];
1133
+ new_polygon.id = polygon_count++;
1139
1134
new_polygon.owner = link ;
1140
1135
1141
1136
new_polygon.edges .clear ();
0 commit comments