2016-11-07 01:16:18 +01:00
/*************************************************************************/
2017-01-16 08:04:19 +01:00
/* a_star.cpp */
2016-11-07 01:16:18 +01:00
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
2017-08-27 14:16:55 +02:00
/* https://godotengine.org */
2016-11-07 01:16:18 +01:00
/*************************************************************************/
2019-01-01 12:53:14 +01:00
/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
2016-11-07 01:16:18 +01: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
2016-09-13 23:17:18 +02:00
# include "a_star.h"
2018-09-11 18:13:45 +02:00
# include "core/math/geometry.h"
# include "core/script_language.h"
2017-03-25 10:44:41 +01:00
# include "scene/scene_string_names.h"
2016-09-13 23:17:18 +02:00
int AStar : : get_available_point_id ( ) const {
if ( points . empty ( ) ) {
return 1 ;
}
2019-08-16 00:22:52 +02:00
// calculate our new next available point id if bigger than before or next id already contained in set of points.
if ( points . has ( last_free_id ) ) {
int cur_new_id = last_free_id ;
while ( points . has ( cur_new_id ) ) {
cur_new_id + + ;
}
int & non_const = const_cast < int & > ( last_free_id ) ;
non_const = cur_new_id ;
}
return last_free_id ;
2016-09-13 23:17:18 +02:00
}
2017-01-14 21:35:39 +01:00
void AStar : : add_point ( int p_id , const Vector3 & p_pos , real_t p_weight_scale ) {
2017-10-27 19:19:01 +02:00
2017-03-05 16:44:50 +01:00
ERR_FAIL_COND ( p_id < 0 ) ;
2017-05-21 21:55:21 +02:00
ERR_FAIL_COND ( p_weight_scale < 1 ) ;
2017-10-27 19:19:01 +02:00
2019-08-16 00:22:52 +02:00
Point * found_pt ;
bool p_exists = points . lookup ( p_id , found_pt ) ;
if ( ! p_exists ) {
2017-03-05 16:44:50 +01:00
Point * pt = memnew ( Point ) ;
pt - > id = p_id ;
pt - > pos = p_pos ;
pt - > weight_scale = p_weight_scale ;
pt - > prev_point = NULL ;
2019-05-16 20:09:47 +02:00
pt - > open_pass = 0 ;
pt - > closed_pass = 0 ;
2019-03-29 09:10:57 +01:00
pt - > enabled = true ;
2019-08-16 00:22:52 +02:00
points . set ( p_id , pt ) ;
2016-09-13 23:17:18 +02:00
} else {
2019-08-16 00:22:52 +02:00
found_pt - > pos = p_pos ;
found_pt - > weight_scale = p_weight_scale ;
2016-09-13 23:17:18 +02:00
}
}
2017-09-10 15:37:49 +02:00
Vector3 AStar : : get_point_position ( int p_id ) const {
2016-09-13 23:17:18 +02:00
2019-08-16 00:22:52 +02:00
Point * p ;
bool p_exists = points . lookup ( p_id , p ) ;
ERR_FAIL_COND_V ( ! p_exists , Vector3 ( ) ) ;
2016-09-13 23:17:18 +02:00
2019-08-16 00:22:52 +02:00
return p - > pos ;
2016-09-13 23:17:18 +02:00
}
2017-10-27 19:19:01 +02:00
void AStar : : set_point_position ( int p_id , const Vector3 & p_pos ) {
2019-08-16 00:22:52 +02:00
Point * p ;
bool p_exists = points . lookup ( p_id , p ) ;
ERR_FAIL_COND ( ! p_exists ) ;
2017-10-27 19:19:01 +02:00
2019-08-16 00:22:52 +02:00
p - > pos = p_pos ;
2017-10-27 19:19:01 +02:00
}
2017-03-05 16:44:50 +01:00
real_t AStar : : get_point_weight_scale ( int p_id ) const {
2016-09-13 23:17:18 +02:00
2019-08-16 00:22:52 +02:00
Point * p ;
bool p_exists = points . lookup ( p_id , p ) ;
ERR_FAIL_COND_V ( ! p_exists , 0 ) ;
2016-09-13 23:17:18 +02:00
2019-08-16 00:22:52 +02:00
return p - > weight_scale ;
2016-09-13 23:17:18 +02:00
}
2017-10-27 19:19:01 +02:00
void AStar : : set_point_weight_scale ( int p_id , real_t p_weight_scale ) {
2019-08-16 00:22:52 +02:00
Point * p ;
bool p_exists = points . lookup ( p_id , p ) ;
ERR_FAIL_COND ( ! p_exists ) ;
2017-10-27 19:19:01 +02:00
ERR_FAIL_COND ( p_weight_scale < 1 ) ;
2019-08-16 00:22:52 +02:00
p - > weight_scale = p_weight_scale ;
2017-10-27 19:19:01 +02:00
}
2017-03-05 16:44:50 +01:00
void AStar : : remove_point ( int p_id ) {
2016-09-13 23:17:18 +02:00
2019-08-16 00:22:52 +02:00
Point * p ;
bool p_exists = points . lookup ( p_id , p ) ;
ERR_FAIL_COND ( ! p_exists ) ;
2016-09-13 23:17:18 +02:00
2019-08-16 00:22:52 +02:00
for ( OAHashMap < int , Point * > : : Iterator it = p - > neighbours . iter ( ) ; it . valid ; it = p - > neighbours . next_iter ( it ) ) {
2019-06-04 21:39:37 +02:00
2019-08-16 00:22:52 +02:00
Segment s ( p_id , ( * it . key ) ) ;
2019-06-04 21:39:37 +02:00
segments . erase ( s ) ;
2019-08-16 00:22:52 +02:00
( * it . value ) - > neighbours . remove ( p - > id ) ;
( * it . value ) - > unlinked_neighbours . remove ( p - > id ) ;
2019-06-04 21:39:37 +02:00
}
2019-08-16 00:22:52 +02:00
for ( OAHashMap < int , Point * > : : Iterator it = p - > unlinked_neighbours . iter ( ) ; it . valid ; it = p - > unlinked_neighbours . next_iter ( it ) ) {
2019-06-04 21:39:37 +02:00
2019-08-16 00:22:52 +02:00
Segment s ( p_id , ( * it . key ) ) ;
2019-06-04 21:39:37 +02:00
segments . erase ( s ) ;
2019-08-16 00:22:52 +02:00
( * it . value ) - > neighbours . remove ( p - > id ) ;
( * it . value ) - > unlinked_neighbours . remove ( p - > id ) ;
2016-09-13 23:17:18 +02:00
}
memdelete ( p ) ;
2019-08-16 00:22:52 +02:00
points . remove ( p_id ) ;
last_free_id = p_id ;
2016-09-13 23:17:18 +02:00
}
2017-05-19 13:16:45 +02:00
void AStar : : connect_points ( int p_id , int p_with_id , bool bidirectional ) {
2016-09-13 23:17:18 +02:00
2017-03-05 16:44:50 +01:00
ERR_FAIL_COND ( p_id = = p_with_id ) ;
2016-09-13 23:17:18 +02:00
2019-08-16 00:22:52 +02:00
Point * a ;
bool from_exists = points . lookup ( p_id , a ) ;
ERR_FAIL_COND ( ! from_exists ) ;
2017-05-19 13:16:45 +02:00
2019-08-16 00:22:52 +02:00
Point * b ;
bool to_exists = points . lookup ( p_with_id , b ) ;
ERR_FAIL_COND ( ! to_exists ) ;
a - > neighbours . set ( b - > id , b ) ;
if ( bidirectional ) {
b - > neighbours . set ( a - > id , a ) ;
} else {
b - > unlinked_neighbours . set ( a - > id , a ) ;
}
2016-09-13 23:17:18 +02:00
2017-03-05 16:44:50 +01:00
Segment s ( p_id , p_with_id ) ;
2019-07-15 19:01:50 +02:00
if ( bidirectional ) s . direction = Segment : : BIDIRECTIONAL ;
Set < Segment > : : Element * element = segments . find ( s ) ;
if ( element ! = NULL ) {
s . direction | = element - > get ( ) . direction ;
if ( s . direction = = Segment : : BIDIRECTIONAL ) {
// Both are neighbours of each other now
a - > unlinked_neighbours . remove ( b - > id ) ;
b - > unlinked_neighbours . remove ( a - > id ) ;
}
segments . erase ( element ) ;
2016-09-13 23:17:18 +02:00
}
segments . insert ( s ) ;
}
2019-08-16 00:22:52 +02:00
2019-07-13 05:22:12 +02:00
void AStar : : disconnect_points ( int p_id , int p_with_id , bool bidirectional ) {
2016-09-13 23:17:18 +02:00
2019-08-16 00:22:52 +02:00
Point * a ;
bool a_exists = points . lookup ( p_id , a ) ;
CRASH_COND ( ! a_exists ) ;
Point * b ;
bool b_exists = points . lookup ( p_with_id , b ) ;
CRASH_COND ( ! b_exists ) ;
2019-07-15 19:01:50 +02:00
Segment s ( p_id , p_with_id ) ;
int remove_direction = bidirectional ? ( int ) Segment : : BIDIRECTIONAL : s . direction ;
Set < Segment > : : Element * element = segments . find ( s ) ;
if ( element ! = NULL ) {
// s is the new segment
// Erase the directions to be removed
s . direction = ( element - > get ( ) . direction & ~ remove_direction ) ;
2019-07-13 05:22:12 +02:00
a - > neighbours . remove ( b - > id ) ;
2019-07-15 19:01:50 +02:00
if ( bidirectional ) {
b - > neighbours . remove ( a - > id ) ;
if ( element - > get ( ) . direction ! = Segment : : BIDIRECTIONAL ) {
a - > unlinked_neighbours . remove ( b - > id ) ;
b - > unlinked_neighbours . remove ( a - > id ) ;
}
} else {
if ( s . direction = = Segment : : NONE )
b - > unlinked_neighbours . remove ( a - > id ) ;
else
a - > unlinked_neighbours . set ( b - > id , b ) ;
}
2019-07-13 05:22:12 +02:00
2019-07-15 19:01:50 +02:00
segments . erase ( element ) ;
if ( s . direction ! = Segment : : NONE )
segments . insert ( s ) ;
2019-07-13 05:22:12 +02:00
}
2016-09-13 23:17:18 +02:00
}
2017-07-11 16:04:41 +02:00
bool AStar : : has_point ( int p_id ) const {
return points . has ( p_id ) ;
}
2017-09-07 16:11:48 +02:00
Array AStar : : get_points ( ) {
2017-10-27 19:19:01 +02:00
2017-09-07 16:11:48 +02:00
Array point_list ;
2019-08-16 00:22:52 +02:00
for ( OAHashMap < int , Point * > : : Iterator it = points . iter ( ) ; it . valid ; it = points . next_iter ( it ) ) {
point_list . push_back ( * ( it . key ) ) ;
2017-09-07 16:11:48 +02:00
}
return point_list ;
}
2017-11-02 20:42:58 +01:00
PoolVector < int > AStar : : get_point_connections ( int p_id ) {
2019-08-16 00:22:52 +02:00
Point * p ;
bool p_exists = points . lookup ( p_id , p ) ;
ERR_FAIL_COND_V ( ! p_exists , PoolVector < int > ( ) ) ;
2017-11-02 20:42:58 +01:00
PoolVector < int > point_list ;
2019-08-16 00:22:52 +02:00
for ( OAHashMap < int , Point * > : : Iterator it = p - > neighbours . iter ( ) ; it . valid ; it = p - > neighbours . next_iter ( it ) ) {
point_list . push_back ( ( * it . key ) ) ;
2017-11-02 20:42:58 +01:00
}
return point_list ;
}
2019-07-13 05:22:12 +02:00
bool AStar : : are_points_connected ( int p_id , int p_with_id , bool bidirectional ) const {
2016-09-13 23:17:18 +02:00
2017-03-05 16:44:50 +01:00
Segment s ( p_id , p_with_id ) ;
2019-07-15 19:01:50 +02:00
const Set < Segment > : : Element * element = segments . find ( s ) ;
return element ! = NULL & &
( bidirectional | | ( element - > get ( ) . direction & s . direction ) = = s . direction ) ;
2016-09-13 23:17:18 +02:00
}
2017-03-05 16:44:50 +01:00
void AStar : : clear ( ) {
2016-09-13 23:17:18 +02:00
2019-08-16 00:22:52 +02:00
last_free_id = 0 ;
for ( OAHashMap < int , Point * > : : Iterator it = points . iter ( ) ; it . valid ; it = points . next_iter ( it ) ) {
memdelete ( * ( it . value ) ) ;
2016-09-13 23:17:18 +02:00
}
segments . clear ( ) ;
points . clear ( ) ;
}
2019-08-25 21:30:52 +02:00
int AStar : : get_point_count ( ) const {
return points . get_num_elements ( ) ;
}
int AStar : : get_point_capacity ( ) const {
return points . get_capacity ( ) ;
}
void AStar : : reserve_space ( int p_num_nodes ) {
ERR_FAIL_COND_MSG ( p_num_nodes < = 0 , " New capacity must be greater than 0, was: " + itos ( p_num_nodes ) + " . " ) ;
ERR_FAIL_COND_MSG ( ( uint32_t ) p_num_nodes < points . get_capacity ( ) , " New capacity must be greater than current capacity: " + itos ( points . get_capacity ( ) ) + " , new was: " + itos ( p_num_nodes ) + " . " ) ;
points . reserve ( p_num_nodes ) ;
}
2019-09-04 19:04:48 +02:00
int AStar : : get_closest_point ( const Vector3 & p_point , bool p_include_disabled ) const {
2016-09-13 23:17:18 +02:00
2017-03-05 16:44:50 +01:00
int closest_id = - 1 ;
real_t closest_dist = 1e20 ;
2016-09-13 23:17:18 +02:00
2019-08-16 00:22:52 +02:00
for ( OAHashMap < int , Point * > : : Iterator it = points . iter ( ) ; it . valid ; it = points . next_iter ( it ) ) {
2019-09-04 19:04:48 +02:00
if ( ! p_include_disabled & & ! ( * it . value ) - > enabled ) continue ; // Disabled points should not be considered.
2016-09-13 23:17:18 +02:00
2019-08-16 00:22:52 +02:00
real_t d = p_point . distance_squared_to ( ( * it . value ) - > pos ) ;
2017-03-05 16:44:50 +01:00
if ( closest_id < 0 | | d < closest_dist ) {
closest_dist = d ;
2019-08-16 00:22:52 +02:00
closest_id = * ( it . key ) ;
2016-09-13 23:17:18 +02:00
}
}
return closest_id ;
}
2017-10-27 19:19:01 +02:00
2017-09-10 15:37:49 +02:00
Vector3 AStar : : get_closest_position_in_segment ( const Vector3 & p_point ) const {
2016-09-13 23:17:18 +02:00
2017-03-05 16:44:50 +01:00
bool found = false ;
2019-08-16 00:22:52 +02:00
real_t closest_dist = 1e20 ;
2016-09-13 23:17:18 +02:00
Vector3 closest_point ;
2017-03-05 16:44:50 +01:00
for ( const Set < Segment > : : Element * E = segments . front ( ) ; E ; E = E - > next ( ) ) {
2016-09-13 23:17:18 +02:00
2019-07-15 19:01:50 +02:00
Point * from_point = nullptr , * to_point = nullptr ;
points . lookup ( E - > get ( ) . u , from_point ) ;
points . lookup ( E - > get ( ) . v , to_point ) ;
if ( ! ( from_point - > enabled & & to_point - > enabled ) ) {
2019-06-27 05:19:52 +02:00
continue ;
}
2017-03-05 16:44:50 +01:00
Vector3 segment [ 2 ] = {
2019-07-15 19:01:50 +02:00
from_point - > pos ,
to_point - > pos ,
2016-09-13 23:17:18 +02:00
} ;
2017-03-05 16:44:50 +01:00
Vector3 p = Geometry : : get_closest_point_to_segment ( p_point , segment ) ;
2017-01-14 21:35:39 +01:00
real_t d = p_point . distance_squared_to ( p ) ;
2017-03-05 16:44:50 +01:00
if ( ! found | | d < closest_dist ) {
2016-09-13 23:17:18 +02:00
2017-03-05 16:44:50 +01:00
closest_point = p ;
closest_dist = d ;
found = true ;
2016-09-13 23:17:18 +02:00
}
}
return closest_point ;
}
2017-03-05 16:44:50 +01:00
bool AStar : : _solve ( Point * begin_point , Point * end_point ) {
2016-09-13 23:17:18 +02:00
pass + + ;
2019-08-16 00:22:52 +02:00
if ( ! end_point - > enabled ) return false ;
2019-03-29 09:10:57 +01:00
2017-03-05 16:44:50 +01:00
bool found_route = false ;
2016-09-13 23:17:18 +02:00
2019-05-16 20:09:47 +02:00
Vector < Point * > open_list ;
SortArray < Point * , SortPoints > sorter ;
2019-03-29 09:10:57 +01:00
2019-05-16 20:09:47 +02:00
begin_point - > g_score = 0 ;
begin_point - > f_score = _estimate_cost ( begin_point - > id , end_point - > id ) ;
open_list . push_back ( begin_point ) ;
2016-09-13 23:17:18 +02:00
2019-08-16 00:22:52 +02:00
while ( ! open_list . empty ( ) ) {
2016-09-13 23:17:18 +02:00
2019-05-16 20:09:47 +02:00
Point * p = open_list [ 0 ] ; // The currently processed point
2016-09-13 23:17:18 +02:00
2018-08-27 18:58:22 +02:00
if ( p = = end_point ) {
found_route = true ;
break ;
}
2016-09-13 23:17:18 +02:00
2019-05-16 20:09:47 +02:00
sorter . pop_heap ( 0 , open_list . size ( ) , open_list . ptrw ( ) ) ; // Remove the current point from the open list
open_list . remove ( open_list . size ( ) - 1 ) ;
p - > closed_pass = pass ; // Mark the point as closed
2019-08-16 00:22:52 +02:00
for ( OAHashMap < int , Point * > : : Iterator it = p - > neighbours . iter ( ) ; it . valid ; it = p - > neighbours . next_iter ( it ) ) {
2016-09-13 23:17:18 +02:00
2019-08-16 00:22:52 +02:00
Point * e = * ( it . value ) ; // The neighbour point
2016-09-13 23:17:18 +02:00
2019-08-16 00:22:52 +02:00
if ( ! e - > enabled | | e - > closed_pass = = pass ) {
2019-03-29 09:10:57 +01:00
continue ;
2019-08-16 00:22:52 +02:00
}
2019-03-29 09:10:57 +01:00
2019-05-16 20:09:47 +02:00
real_t tentative_g_score = p - > g_score + _compute_cost ( p - > id , e - > id ) * e - > weight_scale ;
bool new_point = false ;
2016-09-13 23:17:18 +02:00
2019-08-16 00:22:52 +02:00
if ( e - > open_pass ! = pass ) { // The point wasn't inside the open list.
2019-05-16 20:09:47 +02:00
e - > open_pass = pass ;
open_list . push_back ( e ) ;
new_point = true ;
2019-08-16 00:22:52 +02:00
} else if ( tentative_g_score > = e - > g_score ) { // The new path is worse than the previous.
2019-05-16 20:09:47 +02:00
continue ;
2016-09-13 23:17:18 +02:00
}
2019-05-16 20:09:47 +02:00
e - > prev_point = p ;
e - > g_score = tentative_g_score ;
e - > f_score = e - > g_score + _estimate_cost ( e - > id , end_point - > id ) ;
2016-09-13 23:17:18 +02:00
2019-08-16 00:22:52 +02:00
if ( new_point ) { // The position of the new points is already known.
2019-05-16 20:09:47 +02:00
sorter . push_heap ( 0 , open_list . size ( ) - 1 , 0 , e , open_list . ptrw ( ) ) ;
2019-08-16 00:22:52 +02:00
} else {
2019-05-16 20:09:47 +02:00
sorter . push_heap ( 0 , open_list . find ( e ) , 0 , e , open_list . ptrw ( ) ) ;
2019-08-16 00:22:52 +02:00
}
2019-05-16 20:09:47 +02:00
}
2016-09-13 23:17:18 +02:00
}
return found_route ;
}
2017-03-25 10:44:41 +01:00
float AStar : : _estimate_cost ( int p_from_id , int p_to_id ) {
2017-10-27 19:19:01 +02:00
2017-03-25 10:44:41 +01:00
if ( get_script_instance ( ) & & get_script_instance ( ) - > has_method ( SceneStringNames : : get_singleton ( ) - > _estimate_cost ) )
return get_script_instance ( ) - > call ( SceneStringNames : : get_singleton ( ) - > _estimate_cost , p_from_id , p_to_id ) ;
2019-08-16 00:22:52 +02:00
Point * from_point ;
bool from_exists = points . lookup ( p_from_id , from_point ) ;
CRASH_COND ( ! from_exists ) ;
Point * to_point ;
bool to_exists = points . lookup ( p_to_id , to_point ) ;
CRASH_COND ( ! to_exists ) ;
return from_point - > pos . distance_to ( to_point - > pos ) ;
2017-03-25 10:44:41 +01:00
}
float AStar : : _compute_cost ( int p_from_id , int p_to_id ) {
2017-10-27 19:19:01 +02:00
2017-03-25 10:44:41 +01:00
if ( get_script_instance ( ) & & get_script_instance ( ) - > has_method ( SceneStringNames : : get_singleton ( ) - > _compute_cost ) )
return get_script_instance ( ) - > call ( SceneStringNames : : get_singleton ( ) - > _compute_cost , p_from_id , p_to_id ) ;
2019-08-16 00:22:52 +02:00
Point * from_point ;
bool from_exists = points . lookup ( p_from_id , from_point ) ;
CRASH_COND ( ! from_exists ) ;
Point * to_point ;
bool to_exists = points . lookup ( p_to_id , to_point ) ;
CRASH_COND ( ! to_exists ) ;
return from_point - > pos . distance_to ( to_point - > pos ) ;
2017-03-25 10:44:41 +01:00
}
2017-01-07 22:25:37 +01:00
PoolVector < Vector3 > AStar : : get_point_path ( int p_from_id , int p_to_id ) {
2016-09-13 23:17:18 +02:00
2019-08-16 00:22:52 +02:00
Point * a ;
bool from_exists = points . lookup ( p_from_id , a ) ;
ERR_FAIL_COND_V ( ! from_exists , PoolVector < Vector3 > ( ) ) ;
2016-09-13 23:17:18 +02:00
2019-08-16 00:22:52 +02:00
Point * b ;
bool to_exists = points . lookup ( p_to_id , b ) ;
ERR_FAIL_COND_V ( ! to_exists , PoolVector < Vector3 > ( ) ) ;
2016-09-13 23:17:18 +02:00
2017-03-05 16:44:50 +01:00
if ( a = = b ) {
2017-01-07 22:25:37 +01:00
PoolVector < Vector3 > ret ;
2016-09-13 23:17:18 +02:00
ret . push_back ( a - > pos ) ;
return ret ;
}
2017-03-05 16:44:50 +01:00
Point * begin_point = a ;
Point * end_point = b ;
2016-09-13 23:17:18 +02:00
2017-03-05 16:44:50 +01:00
bool found_route = _solve ( begin_point , end_point ) ;
2019-08-16 00:22:52 +02:00
if ( ! found_route ) return PoolVector < Vector3 > ( ) ;
2016-09-13 23:17:18 +02:00
2017-03-05 16:44:50 +01:00
Point * p = end_point ;
2017-10-27 19:19:01 +02:00
int pc = 1 ; // Begin point
2017-03-05 16:44:50 +01:00
while ( p ! = begin_point ) {
2016-09-13 23:17:18 +02:00
pc + + ;
2017-03-05 16:44:50 +01:00
p = p - > prev_point ;
2016-09-13 23:17:18 +02:00
}
2017-01-07 22:25:37 +01:00
PoolVector < Vector3 > path ;
2016-09-13 23:17:18 +02:00
path . resize ( pc ) ;
{
2017-01-07 22:25:37 +01:00
PoolVector < Vector3 > : : Write w = path . write ( ) ;
2016-09-13 23:17:18 +02:00
2019-02-12 21:10:08 +01:00
Point * p2 = end_point ;
2017-03-05 16:44:50 +01:00
int idx = pc - 1 ;
2019-02-12 21:10:08 +01:00
while ( p2 ! = begin_point ) {
w [ idx - - ] = p2 - > pos ;
p2 = p2 - > prev_point ;
2016-09-13 23:17:18 +02:00
}
2019-02-12 21:10:08 +01:00
w [ 0 ] = p2 - > pos ; // Assign first
2016-09-13 23:17:18 +02:00
}
return path ;
}
2017-01-07 22:25:37 +01:00
PoolVector < int > AStar : : get_id_path ( int p_from_id , int p_to_id ) {
2016-09-13 23:17:18 +02:00
2019-08-16 00:22:52 +02:00
Point * a ;
bool from_exists = points . lookup ( p_from_id , a ) ;
ERR_FAIL_COND_V ( ! from_exists , PoolVector < int > ( ) ) ;
2016-09-13 23:17:18 +02:00
2019-08-16 00:22:52 +02:00
Point * b ;
bool to_exists = points . lookup ( p_to_id , b ) ;
ERR_FAIL_COND_V ( ! to_exists , PoolVector < int > ( ) ) ;
2016-09-13 23:17:18 +02:00
2017-03-05 16:44:50 +01:00
if ( a = = b ) {
2017-01-07 22:25:37 +01:00
PoolVector < int > ret ;
2016-09-13 23:17:18 +02:00
ret . push_back ( a - > id ) ;
return ret ;
}
2017-03-05 16:44:50 +01:00
Point * begin_point = a ;
Point * end_point = b ;
2016-09-13 23:17:18 +02:00
2017-03-05 16:44:50 +01:00
bool found_route = _solve ( begin_point , end_point ) ;
2019-08-16 00:22:52 +02:00
if ( ! found_route ) return PoolVector < int > ( ) ;
2016-09-13 23:17:18 +02:00
2017-03-05 16:44:50 +01:00
Point * p = end_point ;
2017-10-27 19:19:01 +02:00
int pc = 1 ; // Begin point
2017-03-05 16:44:50 +01:00
while ( p ! = begin_point ) {
2016-09-13 23:17:18 +02:00
pc + + ;
2017-03-05 16:44:50 +01:00
p = p - > prev_point ;
2016-09-13 23:17:18 +02:00
}
2017-01-07 22:25:37 +01:00
PoolVector < int > path ;
2016-09-13 23:17:18 +02:00
path . resize ( pc ) ;
{
2017-01-07 22:25:37 +01:00
PoolVector < int > : : Write w = path . write ( ) ;
2016-09-13 23:17:18 +02:00
2017-03-05 16:44:50 +01:00
p = end_point ;
int idx = pc - 1 ;
while ( p ! = begin_point ) {
w [ idx - - ] = p - > id ;
p = p - > prev_point ;
2016-09-13 23:17:18 +02:00
}
2017-10-27 19:19:01 +02:00
w [ 0 ] = p - > id ; // Assign first
2016-09-13 23:17:18 +02:00
}
return path ;
}
2019-03-29 09:10:57 +01:00
void AStar : : set_point_disabled ( int p_id , bool p_disabled ) {
2019-06-18 06:53:41 +02:00
2019-08-16 00:22:52 +02:00
Point * p ;
bool p_exists = points . lookup ( p_id , p ) ;
ERR_FAIL_COND ( ! p_exists ) ;
2019-06-18 06:53:41 +02:00
2019-08-16 00:22:52 +02:00
p - > enabled = ! p_disabled ;
2019-03-29 09:10:57 +01:00
}
bool AStar : : is_point_disabled ( int p_id ) const {
2019-06-18 06:53:41 +02:00
2019-08-16 00:22:52 +02:00
Point * p ;
bool p_exists = points . lookup ( p_id , p ) ;
ERR_FAIL_COND_V ( ! p_exists , false ) ;
2019-06-18 06:53:41 +02:00
2019-08-16 00:22:52 +02:00
return ! p - > enabled ;
2019-03-29 09:10:57 +01:00
}
2016-09-13 23:17:18 +02:00
void AStar : : _bind_methods ( ) {
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( D_METHOD ( " get_available_point_id " ) , & AStar : : get_available_point_id ) ;
2017-09-10 15:37:49 +02:00
ClassDB : : bind_method ( D_METHOD ( " add_point " , " id " , " position " , " weight_scale " ) , & AStar : : add_point , DEFVAL ( 1.0 ) ) ;
ClassDB : : bind_method ( D_METHOD ( " get_point_position " , " id " ) , & AStar : : get_point_position ) ;
2017-10-27 19:19:01 +02:00
ClassDB : : bind_method ( D_METHOD ( " set_point_position " , " id " , " position " ) , & AStar : : set_point_position ) ;
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( D_METHOD ( " get_point_weight_scale " , " id " ) , & AStar : : get_point_weight_scale ) ;
2017-10-27 19:19:01 +02:00
ClassDB : : bind_method ( D_METHOD ( " set_point_weight_scale " , " id " , " weight_scale " ) , & AStar : : set_point_weight_scale ) ;
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( D_METHOD ( " remove_point " , " id " ) , & AStar : : remove_point ) ;
2017-07-11 16:04:41 +02:00
ClassDB : : bind_method ( D_METHOD ( " has_point " , " id " ) , & AStar : : has_point ) ;
2019-03-19 17:15:59 +01:00
ClassDB : : bind_method ( D_METHOD ( " get_point_connections " , " id " ) , & AStar : : get_point_connections ) ;
2017-09-07 16:11:48 +02:00
ClassDB : : bind_method ( D_METHOD ( " get_points " ) , & AStar : : get_points ) ;
2016-09-13 23:17:18 +02:00
2019-03-29 09:10:57 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_point_disabled " , " id " , " disabled " ) , & AStar : : set_point_disabled , DEFVAL ( true ) ) ;
ClassDB : : bind_method ( D_METHOD ( " is_point_disabled " , " id " ) , & AStar : : is_point_disabled ) ;
2017-06-15 18:49:40 +02:00
ClassDB : : bind_method ( D_METHOD ( " connect_points " , " id " , " to_id " , " bidirectional " ) , & AStar : : connect_points , DEFVAL ( true ) ) ;
2019-07-13 05:22:12 +02:00
ClassDB : : bind_method ( D_METHOD ( " disconnect_points " , " id " , " to_id " , " bidirectional " ) , & AStar : : disconnect_points , DEFVAL ( true ) ) ;
ClassDB : : bind_method ( D_METHOD ( " are_points_connected " , " id " , " to_id " , " bidirectional " ) , & AStar : : are_points_connected , DEFVAL ( true ) ) ;
2016-09-13 23:17:18 +02:00
2019-08-25 21:30:52 +02:00
ClassDB : : bind_method ( D_METHOD ( " get_point_count " ) , & AStar : : get_point_count ) ;
ClassDB : : bind_method ( D_METHOD ( " get_point_capacity " ) , & AStar : : get_point_capacity ) ;
ClassDB : : bind_method ( D_METHOD ( " reserve_space " , " num_nodes " ) , & AStar : : reserve_space ) ;
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( D_METHOD ( " clear " ) , & AStar : : clear ) ;
2016-09-13 23:17:18 +02:00
2019-09-04 19:04:48 +02:00
ClassDB : : bind_method ( D_METHOD ( " get_closest_point " , " to_position " , " include_disabled " ) , & AStar : : get_closest_point , DEFVAL ( false ) ) ;
2017-09-10 15:37:49 +02:00
ClassDB : : bind_method ( D_METHOD ( " get_closest_position_in_segment " , " to_position " ) , & AStar : : get_closest_position_in_segment ) ;
2016-09-13 23:17:18 +02:00
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( D_METHOD ( " get_point_path " , " from_id " , " to_id " ) , & AStar : : get_point_path ) ;
ClassDB : : bind_method ( D_METHOD ( " get_id_path " , " from_id " , " to_id " ) , & AStar : : get_id_path ) ;
2017-03-25 10:44:41 +01:00
2017-12-10 15:10:54 +01:00
BIND_VMETHOD ( MethodInfo ( Variant : : REAL , " _estimate_cost " , PropertyInfo ( Variant : : INT , " from_id " ) , PropertyInfo ( Variant : : INT , " to_id " ) ) ) ;
BIND_VMETHOD ( MethodInfo ( Variant : : REAL , " _compute_cost " , PropertyInfo ( Variant : : INT , " from_id " ) , PropertyInfo ( Variant : : INT , " to_id " ) ) ) ;
2016-09-13 23:17:18 +02:00
}
AStar : : AStar ( ) {
2019-08-16 00:22:52 +02:00
last_free_id = 0 ;
2017-03-05 16:44:50 +01:00
pass = 1 ;
2016-09-13 23:17:18 +02:00
}
AStar : : ~ AStar ( ) {
2017-10-23 00:37:02 +02:00
clear ( ) ;
2016-09-13 23:17:18 +02:00
}
2019-03-19 17:15:59 +01:00
/////////////////////////////////////////////////////////////
int AStar2D : : get_available_point_id ( ) const {
return astar . get_available_point_id ( ) ;
}
void AStar2D : : add_point ( int p_id , const Vector2 & p_pos , real_t p_weight_scale ) {
astar . add_point ( p_id , Vector3 ( p_pos . x , p_pos . y , 0 ) , p_weight_scale ) ;
}
Vector2 AStar2D : : get_point_position ( int p_id ) const {
Vector3 p = astar . get_point_position ( p_id ) ;
return Vector2 ( p . x , p . y ) ;
}
void AStar2D : : set_point_position ( int p_id , const Vector2 & p_pos ) {
astar . set_point_position ( p_id , Vector3 ( p_pos . x , p_pos . y , 0 ) ) ;
}
real_t AStar2D : : get_point_weight_scale ( int p_id ) const {
return astar . get_point_weight_scale ( p_id ) ;
}
void AStar2D : : set_point_weight_scale ( int p_id , real_t p_weight_scale ) {
astar . set_point_weight_scale ( p_id , p_weight_scale ) ;
}
void AStar2D : : remove_point ( int p_id ) {
astar . remove_point ( p_id ) ;
}
bool AStar2D : : has_point ( int p_id ) const {
return astar . has_point ( p_id ) ;
}
PoolVector < int > AStar2D : : get_point_connections ( int p_id ) {
return astar . get_point_connections ( p_id ) ;
}
Array AStar2D : : get_points ( ) {
return astar . get_points ( ) ;
}
void AStar2D : : set_point_disabled ( int p_id , bool p_disabled ) {
astar . set_point_disabled ( p_id , p_disabled ) ;
}
bool AStar2D : : is_point_disabled ( int p_id ) const {
return astar . is_point_disabled ( p_id ) ;
}
void AStar2D : : connect_points ( int p_id , int p_with_id , bool p_bidirectional ) {
astar . connect_points ( p_id , p_with_id , p_bidirectional ) ;
}
void AStar2D : : disconnect_points ( int p_id , int p_with_id ) {
astar . disconnect_points ( p_id , p_with_id ) ;
}
bool AStar2D : : are_points_connected ( int p_id , int p_with_id ) const {
return astar . are_points_connected ( p_id , p_with_id ) ;
}
2019-08-25 21:30:52 +02:00
int AStar2D : : get_point_count ( ) const {
return astar . get_point_count ( ) ;
}
int AStar2D : : get_point_capacity ( ) const {
return astar . get_point_capacity ( ) ;
}
2019-03-19 17:15:59 +01:00
void AStar2D : : clear ( ) {
astar . clear ( ) ;
}
2019-08-25 21:30:52 +02:00
void AStar2D : : reserve_space ( int p_num_nodes ) {
astar . reserve_space ( p_num_nodes ) ;
}
2019-09-04 19:04:48 +02:00
int AStar2D : : get_closest_point ( const Vector2 & p_point , bool p_include_disabled ) const {
return astar . get_closest_point ( Vector3 ( p_point . x , p_point . y , 0 ) , p_include_disabled ) ;
2019-03-19 17:15:59 +01:00
}
Vector2 AStar2D : : get_closest_position_in_segment ( const Vector2 & p_point ) const {
Vector3 p = astar . get_closest_position_in_segment ( Vector3 ( p_point . x , p_point . y , 0 ) ) ;
return Vector2 ( p . x , p . y ) ;
}
PoolVector < Vector2 > AStar2D : : get_point_path ( int p_from_id , int p_to_id ) {
PoolVector3Array pv = astar . get_point_path ( p_from_id , p_to_id ) ;
int size = pv . size ( ) ;
PoolVector2Array path ;
path . resize ( size ) ;
{
PoolVector < Vector3 > : : Read r = pv . read ( ) ;
PoolVector < Vector2 > : : Write w = path . write ( ) ;
for ( int i = 0 ; i < size ; i + + ) {
Vector3 p = r [ i ] ;
w [ i ] = Vector2 ( p . x , p . y ) ;
}
}
return path ;
}
PoolVector < int > AStar2D : : get_id_path ( int p_from_id , int p_to_id ) {
return astar . get_id_path ( p_from_id , p_to_id ) ;
}
void AStar2D : : _bind_methods ( ) {
ClassDB : : bind_method ( D_METHOD ( " get_available_point_id " ) , & AStar2D : : get_available_point_id ) ;
ClassDB : : bind_method ( D_METHOD ( " add_point " , " id " , " position " , " weight_scale " ) , & AStar2D : : add_point , DEFVAL ( 1.0 ) ) ;
ClassDB : : bind_method ( D_METHOD ( " get_point_position " , " id " ) , & AStar2D : : get_point_position ) ;
ClassDB : : bind_method ( D_METHOD ( " set_point_position " , " id " , " position " ) , & AStar2D : : set_point_position ) ;
ClassDB : : bind_method ( D_METHOD ( " get_point_weight_scale " , " id " ) , & AStar2D : : get_point_weight_scale ) ;
ClassDB : : bind_method ( D_METHOD ( " set_point_weight_scale " , " id " , " weight_scale " ) , & AStar2D : : set_point_weight_scale ) ;
ClassDB : : bind_method ( D_METHOD ( " remove_point " , " id " ) , & AStar2D : : remove_point ) ;
ClassDB : : bind_method ( D_METHOD ( " has_point " , " id " ) , & AStar2D : : has_point ) ;
ClassDB : : bind_method ( D_METHOD ( " get_point_connections " , " id " ) , & AStar2D : : get_point_connections ) ;
ClassDB : : bind_method ( D_METHOD ( " get_points " ) , & AStar2D : : get_points ) ;
ClassDB : : bind_method ( D_METHOD ( " set_point_disabled " , " id " , " disabled " ) , & AStar2D : : set_point_disabled , DEFVAL ( true ) ) ;
ClassDB : : bind_method ( D_METHOD ( " is_point_disabled " , " id " ) , & AStar2D : : is_point_disabled ) ;
ClassDB : : bind_method ( D_METHOD ( " connect_points " , " id " , " to_id " , " bidirectional " ) , & AStar2D : : connect_points , DEFVAL ( true ) ) ;
ClassDB : : bind_method ( D_METHOD ( " disconnect_points " , " id " , " to_id " ) , & AStar2D : : disconnect_points ) ;
ClassDB : : bind_method ( D_METHOD ( " are_points_connected " , " id " , " to_id " ) , & AStar2D : : are_points_connected ) ;
2019-08-25 21:30:52 +02:00
ClassDB : : bind_method ( D_METHOD ( " get_point_count " ) , & AStar2D : : get_point_count ) ;
ClassDB : : bind_method ( D_METHOD ( " get_point_capacity " ) , & AStar2D : : get_point_capacity ) ;
ClassDB : : bind_method ( D_METHOD ( " reserve_space " , " num_nodes " ) , & AStar2D : : reserve_space ) ;
2019-03-19 17:15:59 +01:00
ClassDB : : bind_method ( D_METHOD ( " clear " ) , & AStar2D : : clear ) ;
2019-09-04 19:04:48 +02:00
ClassDB : : bind_method ( D_METHOD ( " get_closest_point " , " to_position " , " include_disabled " ) , & AStar2D : : get_closest_point , DEFVAL ( false ) ) ;
2019-03-19 17:15:59 +01:00
ClassDB : : bind_method ( D_METHOD ( " get_closest_position_in_segment " , " to_position " ) , & AStar2D : : get_closest_position_in_segment ) ;
ClassDB : : bind_method ( D_METHOD ( " get_point_path " , " from_id " , " to_id " ) , & AStar2D : : get_point_path ) ;
ClassDB : : bind_method ( D_METHOD ( " get_id_path " , " from_id " , " to_id " ) , & AStar2D : : get_id_path ) ;
}
AStar2D : : AStar2D ( ) {
}
AStar2D : : ~ AStar2D ( ) {
}