Blender  V2.93
astar.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2014 Blender Foundation.
17  * All rights reserved.
18  */
19 
42 #include <limits.h>
43 
44 #include "MEM_guardedalloc.h"
45 
46 #include "BLI_compiler_attrs.h"
47 #include "BLI_sys_types.h"
48 
49 #include "BLI_heap_simple.h"
50 #include "BLI_listbase.h"
51 #include "BLI_math.h"
52 #include "BLI_memarena.h"
53 
54 #include "BLI_astar.h"
55 
62 void BLI_astar_node_init(BLI_AStarGraph *as_graph, const int node_index, void *custom_data)
63 {
64  as_graph->nodes[node_index].custom_data = custom_data;
65 }
66 
76  const int node1_index,
77  const int node2_index,
78  const float cost,
79  void *custom_data)
80 {
81  MemArena *mem = as_graph->mem;
82  BLI_AStarGNLink *link = BLI_memarena_alloc(mem, sizeof(*link));
83  LinkData *ld = BLI_memarena_alloc(mem, sizeof(*ld) * 2);
84 
85  link->nodes[0] = node1_index;
86  link->nodes[1] = node2_index;
87  link->cost = cost;
88  link->custom_data = custom_data;
89 
90  ld[0].data = ld[1].data = link;
91 
92  BLI_addtail(&(as_graph->nodes[node1_index].neighbor_links), &ld[0]);
93  BLI_addtail(&(as_graph->nodes[node2_index].neighbor_links), &ld[1]);
94 }
95 
100 {
101  return (lnk->nodes[0] == idx) ? lnk->nodes[1] : lnk->nodes[0];
102 }
103 
113  BLI_AStarSolution *as_solution,
114  void *custom_data)
115 {
116  MemArena *mem = as_solution->mem;
117  size_t node_num = (size_t)as_graph->node_num;
118 
119  if (mem == NULL) {
121  as_solution->mem = mem;
122  }
123  /* else memarena should be cleared */
124 
125  as_solution->steps = 0;
126  as_solution->prev_nodes = BLI_memarena_alloc(mem, sizeof(*as_solution->prev_nodes) * node_num);
127  as_solution->prev_links = BLI_memarena_alloc(mem, sizeof(*as_solution->prev_links) * node_num);
128 
129  as_solution->custom_data = custom_data;
130 
131  as_solution->done_nodes = BLI_BITMAP_NEW_MEMARENA(mem, node_num);
132  as_solution->g_costs = BLI_memarena_alloc(mem, sizeof(*as_solution->g_costs) * node_num);
133  as_solution->g_steps = BLI_memarena_alloc(mem, sizeof(*as_solution->g_steps) * node_num);
134 }
135 
143 {
144  if (as_solution->mem) {
145  BLI_memarena_clear(as_solution->mem);
146  }
147 
148  as_solution->steps = 0;
149  as_solution->prev_nodes = NULL;
150  as_solution->prev_links = NULL;
151 
152  as_solution->custom_data = NULL;
153 
154  as_solution->done_nodes = NULL;
155  as_solution->g_costs = NULL;
156  as_solution->g_steps = NULL;
157 }
158 
163 {
164  if (as_solution->mem) {
165  BLI_memarena_free(as_solution->mem);
166  as_solution->mem = NULL;
167  }
168 }
169 
178 void BLI_astar_graph_init(BLI_AStarGraph *as_graph, const int node_num, void *custom_data)
179 {
180  MemArena *mem = as_graph->mem;
181 
182  if (mem == NULL) {
184  as_graph->mem = mem;
185  }
186  /* else memarena should be cleared */
187 
188  as_graph->node_num = node_num;
189  as_graph->nodes = BLI_memarena_calloc(mem, sizeof(*as_graph->nodes) * (size_t)node_num);
190 
191  as_graph->custom_data = custom_data;
192 }
193 
195 {
196  if (as_graph->mem) {
197  BLI_memarena_free(as_graph->mem);
198  as_graph->mem = NULL;
199  }
200 }
201 
211  const int node_index_src,
212  const int node_index_dst,
213  astar_f_cost f_cost_cb,
214  BLI_AStarSolution *r_solution,
215  const int max_steps)
216 {
217  HeapSimple *todo_nodes;
218 
219  BLI_bitmap *done_nodes = r_solution->done_nodes;
220  int *prev_nodes = r_solution->prev_nodes;
221  BLI_AStarGNLink **prev_links = r_solution->prev_links;
222  float *g_costs = r_solution->g_costs;
223  int *g_steps = r_solution->g_steps;
224 
225  r_solution->steps = 0;
226  prev_nodes[node_index_src] = -1;
227  BLI_bitmap_set_all(done_nodes, false, as_graph->node_num);
228  copy_vn_fl(g_costs, as_graph->node_num, FLT_MAX);
229  g_costs[node_index_src] = 0.0f;
230  g_steps[node_index_src] = 0;
231 
232  if (node_index_src == node_index_dst) {
233  return true;
234  }
235 
236  todo_nodes = BLI_heapsimple_new();
237  BLI_heapsimple_insert(todo_nodes,
238  f_cost_cb(as_graph, r_solution, NULL, -1, node_index_src, node_index_dst),
239  POINTER_FROM_INT(node_index_src));
240 
241  while (!BLI_heapsimple_is_empty(todo_nodes)) {
242  const int node_curr_idx = POINTER_AS_INT(BLI_heapsimple_pop_min(todo_nodes));
243  BLI_AStarGNode *node_curr = &as_graph->nodes[node_curr_idx];
244  LinkData *ld;
245 
246  if (BLI_BITMAP_TEST(done_nodes, node_curr_idx)) {
247  /* Might happen, because we always add nodes to heap when evaluating them,
248  * without ever removing them. */
249  continue;
250  }
251 
252  /* If we are limited in amount of steps to find a path, skip if we reached limit. */
253  if (max_steps && g_steps[node_curr_idx] > max_steps) {
254  continue;
255  }
256 
257  if (node_curr_idx == node_index_dst) {
258  /* Success! Path found... */
259  r_solution->steps = g_steps[node_curr_idx] + 1;
260 
261  BLI_heapsimple_free(todo_nodes, NULL);
262  return true;
263  }
264 
265  BLI_BITMAP_ENABLE(done_nodes, node_curr_idx);
266 
267  for (ld = node_curr->neighbor_links.first; ld; ld = ld->next) {
268  BLI_AStarGNLink *link = ld->data;
269  const int node_next_idx = BLI_astar_node_link_other_node(link, node_curr_idx);
270 
271  if (!BLI_BITMAP_TEST(done_nodes, node_next_idx)) {
272  float g_cst = g_costs[node_curr_idx] + link->cost;
273 
274  if (g_cst < g_costs[node_next_idx]) {
275  prev_nodes[node_next_idx] = node_curr_idx;
276  prev_links[node_next_idx] = link;
277  g_costs[node_next_idx] = g_cst;
278  g_steps[node_next_idx] = g_steps[node_curr_idx] + 1;
279  /* We might have this node already in heap, but since this 'instance'
280  * will be evaluated first, no problem. */
282  todo_nodes,
283  f_cost_cb(as_graph, r_solution, link, node_curr_idx, node_next_idx, node_index_dst),
284  POINTER_FROM_INT(node_next_idx));
285  }
286  }
287  }
288  }
289 
290  BLI_heapsimple_free(todo_nodes, NULL);
291  return false;
292 }
An implementation of the A* (AStar) algorithm to solve shortest path problem.
float(* astar_f_cost)(BLI_AStarGraph *as_graph, BLI_AStarSolution *as_solution, BLI_AStarGNLink *link, const int node_idx_curr, const int node_idx_next, const int node_idx_dst)
Definition: BLI_astar.h:104
#define BLI_BITMAP_TEST(_bitmap, _index)
Definition: BLI_bitmap.h:63
#define BLI_BITMAP_ENABLE(_bitmap, _index)
Definition: BLI_bitmap.h:78
#define BLI_BITMAP_NEW_MEMARENA(_mem, _tot)
Definition: BLI_bitmap.h:58
void BLI_bitmap_set_all(BLI_bitmap *bitmap, bool set, size_t bits)
Definition: bitmap.c:33
unsigned int BLI_bitmap
Definition: BLI_bitmap.h:32
A min-heap / priority queue ADT.
void BLI_heapsimple_free(HeapSimple *heap, HeapSimpleFreeFP ptrfreefp) ATTR_NONNULL(1)
HeapSimple * BLI_heapsimple_new(void) ATTR_WARN_UNUSED_RESULT
void * BLI_heapsimple_pop_min(HeapSimple *heap) ATTR_NONNULL(1)
bool BLI_heapsimple_is_empty(const HeapSimple *heap) ATTR_NONNULL(1)
void BLI_heapsimple_insert(HeapSimple *heap, float value, void *ptr) ATTR_NONNULL(1)
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:110
void copy_vn_fl(float *array_tar, const int size, const float val)
Definition: math_vector.c:1410
void BLI_memarena_free(struct MemArena *ma) ATTR_NONNULL(1)
Definition: BLI_memarena.c:109
#define BLI_MEMARENA_STD_BUFSIZE
Definition: BLI_memarena.h:36
void * BLI_memarena_alloc(struct MemArena *ma, size_t size) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1) ATTR_MALLOC ATTR_ALLOC_SIZE(2)
Definition: BLI_memarena.c:131
void BLI_memarena_clear(MemArena *ma) ATTR_NONNULL(1)
Definition: BLI_memarena.c:185
struct MemArena * BLI_memarena_new(const size_t bufsize, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(2) ATTR_MALLOC
Definition: BLI_memarena.c:79
void * BLI_memarena_calloc(struct MemArena *ma, size_t size) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1) ATTR_MALLOC ATTR_ALLOC_SIZE(2)
Definition: BLI_memarena.c:168
#define POINTER_FROM_INT(i)
#define POINTER_AS_INT(i)
Read Guarded memory(de)allocation.
void BLI_astar_graph_init(BLI_AStarGraph *as_graph, const int node_num, void *custom_data)
Definition: astar.c:178
void BLI_astar_solution_clear(BLI_AStarSolution *as_solution)
Definition: astar.c:142
void BLI_astar_node_init(BLI_AStarGraph *as_graph, const int node_index, void *custom_data)
Definition: astar.c:62
void BLI_astar_solution_init(BLI_AStarGraph *as_graph, BLI_AStarSolution *as_solution, void *custom_data)
Definition: astar.c:112
void BLI_astar_node_link_add(BLI_AStarGraph *as_graph, const int node1_index, const int node2_index, const float cost, void *custom_data)
Definition: astar.c:75
bool BLI_astar_graph_solve(BLI_AStarGraph *as_graph, const int node_index_src, const int node_index_dst, astar_f_cost f_cost_cb, BLI_AStarSolution *r_solution, const int max_steps)
Definition: astar.c:210
void BLI_astar_solution_free(BLI_AStarSolution *as_solution)
Definition: astar.c:162
void BLI_astar_graph_free(BLI_AStarGraph *as_graph)
Definition: astar.c:194
int BLI_astar_node_link_other_node(BLI_AStarGNLink *lnk, const int idx)
Definition: astar.c:99
void * custom_data
Definition: BLI_astar.h:47
struct ListBase neighbor_links
Definition: BLI_astar.h:45
BLI_AStarGNode * nodes
Definition: BLI_astar.h:72
void * custom_data
Definition: BLI_astar.h:74
struct MemArena * mem
Definition: BLI_astar.h:76
BLI_AStarGNLink ** prev_links
Definition: BLI_astar.h:58
struct MemArena * mem
Definition: BLI_astar.h:67
float * g_costs
Definition: BLI_astar.h:64
void * custom_data
Definition: BLI_astar.h:60
BLI_bitmap * done_nodes
Definition: BLI_astar.h:63
void * data
Definition: DNA_listBase.h:42
struct LinkData * next
Definition: DNA_listBase.h:41
void * first
Definition: DNA_listBase.h:47