Blender V5.0
astar.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2014 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
26
27#include "BLI_sys_types.h"
28
29#include "BLI_heap_simple.h"
30#include "BLI_listbase.h"
31#include "BLI_math_vector.h"
32#include "BLI_memarena.h"
33
34#include "BLI_astar.h"
35
36void BLI_astar_node_init(BLI_AStarGraph *as_graph, const int node_index, void *custom_data)
37{
38 as_graph->nodes[node_index].custom_data = custom_data;
39}
40
42 const int node1_index,
43 const int node2_index,
44 const float cost,
45 void *custom_data)
46{
47 MemArena *mem = as_graph->mem;
50
51 link->nodes[0] = node1_index;
52 link->nodes[1] = node2_index;
53 link->cost = cost;
54 link->custom_data = custom_data;
55
56 ld[0].data = ld[1].data = link;
57
58 BLI_addtail(&(as_graph->nodes[node1_index].neighbor_links), &ld[0]);
59 BLI_addtail(&(as_graph->nodes[node2_index].neighbor_links), &ld[1]);
60}
61
63{
64 return (lnk->nodes[0] == idx) ? lnk->nodes[1] : lnk->nodes[0];
65}
66
68 BLI_AStarSolution *as_solution,
69 void *custom_data)
70{
71 MemArena *mem = as_solution->mem;
72 size_t node_num = size_t(as_graph->node_num);
73
74 if (mem == nullptr) {
76 as_solution->mem = mem;
77 }
78 /* else memarena should be cleared */
79
80 as_solution->steps = 0;
81 as_solution->prev_nodes = BLI_memarena_alloc<int>(mem, node_num);
82 as_solution->prev_links = BLI_memarena_alloc<BLI_AStarGNLink *>(mem, node_num);
83
84 as_solution->custom_data = custom_data;
85
86 as_solution->done_nodes = BLI_BITMAP_NEW_MEMARENA(mem, node_num);
87 as_solution->g_costs = BLI_memarena_alloc<float>(mem, node_num);
88 as_solution->g_steps = BLI_memarena_alloc<int>(mem, node_num);
89}
90
92{
93 if (as_solution->mem) {
94 BLI_memarena_clear(as_solution->mem);
95 }
96
97 as_solution->steps = 0;
98 as_solution->prev_nodes = nullptr;
99 as_solution->prev_links = nullptr;
100
101 as_solution->custom_data = nullptr;
102
103 as_solution->done_nodes = nullptr;
104 as_solution->g_costs = nullptr;
105 as_solution->g_steps = nullptr;
106}
107
109{
110 if (as_solution->mem) {
111 BLI_memarena_free(as_solution->mem);
112 as_solution->mem = nullptr;
113 }
114}
115
116void BLI_astar_graph_init(BLI_AStarGraph *as_graph, const int node_num, void *custom_data)
117{
118 MemArena *mem = as_graph->mem;
119
120 if (mem == nullptr) {
122 as_graph->mem = mem;
123 }
124 /* else memarena should be cleared */
125
126 as_graph->node_num = node_num;
127 as_graph->nodes = BLI_memarena_calloc<BLI_AStarGNode>(mem, size_t(node_num));
128
129 as_graph->custom_data = custom_data;
130}
131
133{
134 if (as_graph->mem) {
135 BLI_memarena_free(as_graph->mem);
136 as_graph->mem = nullptr;
137 }
138}
139
141 const int node_index_src,
142 const int node_index_dst,
143 astar_f_cost f_cost_cb,
144 BLI_AStarSolution *r_solution,
145 const int max_steps)
146{
147 HeapSimple *todo_nodes;
148
149 BLI_bitmap *done_nodes = r_solution->done_nodes;
150 int *prev_nodes = r_solution->prev_nodes;
151 BLI_AStarGNLink **prev_links = r_solution->prev_links;
152 float *g_costs = r_solution->g_costs;
153 int *g_steps = r_solution->g_steps;
154
155 r_solution->steps = 0;
156 prev_nodes[node_index_src] = -1;
157 BLI_bitmap_set_all(done_nodes, false, as_graph->node_num);
158 copy_vn_fl(g_costs, as_graph->node_num, FLT_MAX);
159 g_costs[node_index_src] = 0.0f;
160 g_steps[node_index_src] = 0;
161
162 if (node_index_src == node_index_dst) {
163 return true;
164 }
165
166 todo_nodes = BLI_heapsimple_new();
168 todo_nodes,
169 f_cost_cb(as_graph, r_solution, nullptr, -1, node_index_src, node_index_dst),
170 POINTER_FROM_INT(node_index_src));
171
172 while (!BLI_heapsimple_is_empty(todo_nodes)) {
173 const int node_curr_idx = POINTER_AS_INT(BLI_heapsimple_pop_min(todo_nodes));
174 BLI_AStarGNode *node_curr = &as_graph->nodes[node_curr_idx];
175 LinkData *ld;
176
177 if (BLI_BITMAP_TEST(done_nodes, node_curr_idx)) {
178 /* Might happen, because we always add nodes to heap when evaluating them,
179 * without ever removing them. */
180 continue;
181 }
182
183 /* If we are limited in amount of steps to find a path, skip if we reached limit. */
184 if (max_steps && g_steps[node_curr_idx] > max_steps) {
185 continue;
186 }
187
188 if (node_curr_idx == node_index_dst) {
189 /* Success! Path found... */
190 r_solution->steps = g_steps[node_curr_idx] + 1;
191
192 BLI_heapsimple_free(todo_nodes, nullptr);
193 return true;
194 }
195
196 BLI_BITMAP_ENABLE(done_nodes, node_curr_idx);
197
198 for (ld = static_cast<LinkData *>(node_curr->neighbor_links.first); ld; ld = ld->next) {
199 BLI_AStarGNLink *link = static_cast<BLI_AStarGNLink *>(ld->data);
200 const int node_next_idx = BLI_astar_node_link_other_node(link, node_curr_idx);
201
202 if (!BLI_BITMAP_TEST(done_nodes, node_next_idx)) {
203 float g_cst = g_costs[node_curr_idx] + link->cost;
204
205 if (g_cst < g_costs[node_next_idx]) {
206 prev_nodes[node_next_idx] = node_curr_idx;
207 prev_links[node_next_idx] = link;
208 g_costs[node_next_idx] = g_cst;
209 g_steps[node_next_idx] = g_steps[node_curr_idx] + 1;
210 /* We might have this node already in heap, but since this 'instance'
211 * will be evaluated first, no problem. */
213 todo_nodes,
214 f_cost_cb(as_graph, r_solution, link, node_curr_idx, node_next_idx, node_index_dst),
215 POINTER_FROM_INT(node_next_idx));
216 }
217 }
218 }
219 }
220
221 BLI_heapsimple_free(todo_nodes, nullptr);
222 return false;
223}
An implementation of the A* (AStar) algorithm to solve shortest path problem.
float(*)(BLI_AStarGraph *as_graph, BLI_AStarSolution *as_solution, BLI_AStarGNLink *link, int node_idx_curr, int node_idx_next, int node_idx_dst) astar_f_cost
Definition BLI_astar.h:116
#define BLI_BITMAP_TEST(_bitmap, _index)
Definition BLI_bitmap.h:61
#define BLI_BITMAP_ENABLE(_bitmap, _index)
Definition BLI_bitmap.h:78
#define BLI_BITMAP_NEW_MEMARENA(_mem, _num)
Definition BLI_bitmap.h:49
void BLI_bitmap_set_all(BLI_bitmap *bitmap, bool set, size_t bits)
Definition bitmap.cc:17
unsigned int BLI_bitmap
Definition BLI_bitmap.h:13
A min-heap / priority queue ADT.
HeapSimple * BLI_heapsimple_new(void) ATTR_WARN_UNUSED_RESULT
void BLI_heapsimple_free(HeapSimple *heap, HeapSimpleFreeFP ptrfreefp) ATTR_NONNULL(1)
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(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:111
void copy_vn_fl(float *array_tar, int size, float val)
#define BLI_MEMARENA_STD_BUFSIZE
MemArena * BLI_memarena_new(size_t bufsize, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL ATTR_NONNULL(2) ATTR_MALLOC
void * BLI_memarena_calloc(MemArena *ma, size_t size) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1) ATTR_MALLOC ATTR_ALLOC_SIZE(2)
void BLI_memarena_free(MemArena *ma) ATTR_NONNULL(1)
void * BLI_memarena_alloc(MemArena *ma, size_t size) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1) ATTR_MALLOC ATTR_ALLOC_SIZE(2)
void BLI_memarena_clear(MemArena *ma) ATTR_NONNULL(1)
#define POINTER_FROM_INT(i)
#define POINTER_AS_INT(i)
void BLI_astar_graph_init(BLI_AStarGraph *as_graph, const int node_num, void *custom_data)
Definition astar.cc:116
void BLI_astar_solution_clear(BLI_AStarSolution *as_solution)
Definition astar.cc:91
void BLI_astar_node_init(BLI_AStarGraph *as_graph, const int node_index, void *custom_data)
Definition astar.cc:36
void BLI_astar_solution_init(BLI_AStarGraph *as_graph, BLI_AStarSolution *as_solution, void *custom_data)
Definition astar.cc:67
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.cc:41
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.cc:140
void BLI_astar_solution_free(BLI_AStarSolution *as_solution)
Definition astar.cc:108
void BLI_astar_graph_free(BLI_AStarGraph *as_graph)
Definition astar.cc:132
int BLI_astar_node_link_other_node(BLI_AStarGNLink *lnk, const int idx)
Definition astar.cc:62
#define FLT_MAX
Definition stdcycles.h:14
void * custom_data
Definition BLI_astar.h:28
struct ListBase neighbor_links
Definition BLI_astar.h:26
BLI_AStarGNode * nodes
Definition BLI_astar.h:53
void * custom_data
Definition BLI_astar.h:55
struct MemArena * mem
Definition BLI_astar.h:57
BLI_AStarGNLink ** prev_links
Definition BLI_astar.h:39
struct MemArena * mem
Definition BLI_astar.h:48
BLI_bitmap * done_nodes
Definition BLI_astar.h:44
void * data
struct LinkData * next
void * first