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