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
17 /** \file
18 * \ingroup bmesh
19 *
20 * Find a path between 2 elements.
21 *
22 * \note All 3 functions are similar, changes to one most likely apply to another.
23 */
24
25 #include "MEM_guardedalloc.h"
26
27 #include "BLI_heap_simple.h"
28 #include "BLI_linklist.h"
29 #include "BLI_math.h"
30
31 #include "bmesh.h"
32 #include "bmesh_path.h" /* own include */
33
34 #define COST_INIT_MAX FLT_MAX
35
36 /* -------------------------------------------------------------------- */
37 /** \name Generic Helpers
38 * \{ */
39
40 /**
41 * Use skip options when we want to start measuring from a boundary.
42 */
step_cost_3_v3_ex(const float v1[3],const float v2[3],const float v3[3],bool skip_12,bool skip_23)43 static float step_cost_3_v3_ex(
44 const float v1[3], const float v2[3], const float v3[3], bool skip_12, bool skip_23)
45 {
46 float d1[3], d2[3];
47
48 /* The cost is based on the simple sum of the length of the two edges. */
49 sub_v3_v3v3(d1, v2, v1);
50 sub_v3_v3v3(d2, v3, v2);
51 const float cost_12 = normalize_v3(d1);
52 const float cost_23 = normalize_v3(d2);
53 const float cost = ((skip_12 ? 0.0f : cost_12) + (skip_23 ? 0.0f : cost_23));
54
55 /* But is biased to give higher values to sharp turns, so that it will take paths with
56 * fewer "turns" when selecting between equal-weighted paths between the two edges. */
57 return cost * (1.0f + 0.5f * (2.0f - sqrtf(fabsf(dot_v3v3(d1, d2)))));
58 }
59
step_cost_3_v3(const float v1[3],const float v2[3],const float v3[3])60 static float step_cost_3_v3(const float v1[3], const float v2[3], const float v3[3])
61 {
62 return step_cost_3_v3_ex(v1, v2, v3, false, false);
63 }
64
65 /** \} */
66
67 /* -------------------------------------------------------------------- */
68 /** \name BM_mesh_calc_path_vert
69 * \{ */
70
verttag_add_adjacent(HeapSimple * heap,BMVert * v_a,BMVert ** verts_prev,float * cost,const struct BMCalcPathParams * params)71 static void verttag_add_adjacent(HeapSimple *heap,
72 BMVert *v_a,
73 BMVert **verts_prev,
74 float *cost,
75 const struct BMCalcPathParams *params)
76 {
77 const int v_a_index = BM_elem_index_get(v_a);
78
79 {
80 BMIter eiter;
81 BMEdge *e;
82 /* Loop over faces of face, but do so by first looping over loops. */
83 BM_ITER_ELEM (e, &eiter, v_a, BM_EDGES_OF_VERT) {
84 BMVert *v_b = BM_edge_other_vert(e, v_a);
85 if (!BM_elem_flag_test(v_b, BM_ELEM_TAG)) {
86 /* We know 'v_b' is not visited, check it out! */
87 const int v_b_index = BM_elem_index_get(v_b);
88 const float cost_cut = params->use_topology_distance ? 1.0f : len_v3v3(v_a->co, v_b->co);
89 const float cost_new = cost[v_a_index] + cost_cut;
90
91 if (cost[v_b_index] > cost_new) {
92 cost[v_b_index] = cost_new;
93 verts_prev[v_b_index] = v_a;
94 BLI_heapsimple_insert(heap, cost_new, v_b);
95 }
96 }
97 }
98 }
99
100 if (params->use_step_face) {
101 BMIter liter;
102 BMLoop *l;
103 /* Loop over faces of face, but do so by first looping over loops. */
104 BM_ITER_ELEM (l, &liter, v_a, BM_LOOPS_OF_VERT) {
105 if (l->f->len > 3) {
106 /* Skip loops on adjacent edges. */
107 BMLoop *l_iter = l->next->next;
108 do {
109 BMVert *v_b = l_iter->v;
110 if (!BM_elem_flag_test(v_b, BM_ELEM_TAG)) {
111 /* We know 'v_b' is not visited, check it out! */
112 const int v_b_index = BM_elem_index_get(v_b);
113 const float cost_cut = params->use_topology_distance ? 1.0f :
114 len_v3v3(v_a->co, v_b->co);
115 const float cost_new = cost[v_a_index] + cost_cut;
116
117 if (cost[v_b_index] > cost_new) {
118 cost[v_b_index] = cost_new;
119 verts_prev[v_b_index] = v_a;
120 BLI_heapsimple_insert(heap, cost_new, v_b);
121 }
122 }
123 } while ((l_iter = l_iter->next) != l->prev);
124 }
125 }
126 }
127 }
128
BM_mesh_calc_path_vert(BMesh * bm,BMVert * v_src,BMVert * v_dst,const struct BMCalcPathParams * params,bool (* filter_fn)(BMVert *,void * user_data),void * user_data)129 LinkNode *BM_mesh_calc_path_vert(BMesh *bm,
130 BMVert *v_src,
131 BMVert *v_dst,
132 const struct BMCalcPathParams *params,
133 bool (*filter_fn)(BMVert *, void *user_data),
134 void *user_data)
135 {
136 LinkNode *path = NULL;
137 /* #BM_ELEM_TAG flag is used to store visited edges. */
138 BMVert *v;
139 BMIter viter;
140 HeapSimple *heap;
141 float *cost;
142 BMVert **verts_prev;
143 int i, totvert;
144
145 /* Note, would pass #BM_EDGE except we are looping over all faces anyway. */
146 // BM_mesh_elem_index_ensure(bm, BM_VERT /* | BM_EDGE */); // NOT NEEDED FOR FACETAG
147
148 BM_ITER_MESH_INDEX (v, &viter, bm, BM_VERTS_OF_MESH, i) {
149 BM_elem_flag_set(v, BM_ELEM_TAG, !filter_fn(v, user_data));
150 BM_elem_index_set(v, i); /* set_inline */
151 }
152 bm->elem_index_dirty &= ~BM_VERT;
153
154 /* Allocate. */
155 totvert = bm->totvert;
156 verts_prev = MEM_callocN(sizeof(*verts_prev) * totvert, __func__);
157 cost = MEM_mallocN(sizeof(*cost) * totvert, __func__);
158
159 copy_vn_fl(cost, totvert, COST_INIT_MAX);
160
161 /*
162 * Arrays are now filled as follows:
163 *
164 * As the search continues, `verts_prev[n]` will be the previous verts on the shortest
165 * path found so far to face `n`. #BM_ELEM_TAG is used to tag elements we have visited,
166 * `cost[n]` will contain the length of the shortest
167 * path to face n found so far, Finally, heap is a priority heap which is built on the
168 * the same data as the cost array, but inverted: it is a work-list of faces prioritized
169 * by the shortest path found so far to the face.
170 */
171
172 /* Regular dijkstra shortest path, but over faces instead of vertices. */
173 heap = BLI_heapsimple_new();
174 BLI_heapsimple_insert(heap, 0.0f, v_src);
175 cost[BM_elem_index_get(v_src)] = 0.0f;
176
177 while (!BLI_heapsimple_is_empty(heap)) {
178 v = BLI_heapsimple_pop_min(heap);
179
180 if (v == v_dst) {
181 break;
182 }
183
184 if (!BM_elem_flag_test(v, BM_ELEM_TAG)) {
185 BM_elem_flag_enable(v, BM_ELEM_TAG);
186 verttag_add_adjacent(heap, v, verts_prev, cost, params);
187 }
188 }
189
190 if (v == v_dst) {
191 do {
192 BLI_linklist_prepend(&path, v);
193 } while ((v = verts_prev[BM_elem_index_get(v)]));
194 }
195
196 MEM_freeN(verts_prev);
197 MEM_freeN(cost);
198 BLI_heapsimple_free(heap, NULL);
199
200 return path;
201 }
202
203 /** \} */
204
205 /* -------------------------------------------------------------------- */
206 /** \name BM_mesh_calc_path_edge
207 * \{ */
208
edgetag_cut_cost_vert(BMEdge * e_a,BMEdge * e_b,BMVert * v)209 static float edgetag_cut_cost_vert(BMEdge *e_a, BMEdge *e_b, BMVert *v)
210 {
211 BMVert *v1 = BM_edge_other_vert(e_a, v);
212 BMVert *v2 = BM_edge_other_vert(e_b, v);
213 return step_cost_3_v3(v1->co, v->co, v2->co);
214 }
215
edgetag_cut_cost_face(BMEdge * e_a,BMEdge * e_b,BMFace * f)216 static float edgetag_cut_cost_face(BMEdge *e_a, BMEdge *e_b, BMFace *f)
217 {
218 float e_a_cent[3], e_b_cent[3], f_cent[3];
219
220 mid_v3_v3v3(e_a_cent, e_a->v1->co, e_a->v1->co);
221 mid_v3_v3v3(e_b_cent, e_b->v1->co, e_b->v1->co);
222
223 BM_face_calc_center_median_weighted(f, f_cent);
224
225 return step_cost_3_v3(e_a_cent, e_b_cent, f_cent);
226 }
227
edgetag_add_adjacent(HeapSimple * heap,BMEdge * e_a,BMEdge ** edges_prev,float * cost,const struct BMCalcPathParams * params)228 static void edgetag_add_adjacent(HeapSimple *heap,
229 BMEdge *e_a,
230 BMEdge **edges_prev,
231 float *cost,
232 const struct BMCalcPathParams *params)
233 {
234 const int e_a_index = BM_elem_index_get(e_a);
235
236 /* Unlike vert/face, stepping faces disables scanning connected edges
237 * and only steps over faces (selecting a ring of edges instead of a loop). */
238 if (params->use_step_face == false || e_a->l == NULL) {
239 BMIter viter;
240 BMVert *v;
241
242 BMIter eiter;
243 BMEdge *e_b;
244
245 BM_ITER_ELEM (v, &viter, e_a, BM_VERTS_OF_EDGE) {
246
247 /* Don't walk over previous vertex. */
248 if ((edges_prev[e_a_index]) && (BM_vert_in_edge(edges_prev[e_a_index], v))) {
249 continue;
250 }
251
252 BM_ITER_ELEM (e_b, &eiter, v, BM_EDGES_OF_VERT) {
253 if (!BM_elem_flag_test(e_b, BM_ELEM_TAG)) {
254 /* We know 'e_b' is not visited, check it out! */
255 const int e_b_index = BM_elem_index_get(e_b);
256 const float cost_cut = params->use_topology_distance ?
257 1.0f :
258 edgetag_cut_cost_vert(e_a, e_b, v);
259 const float cost_new = cost[e_a_index] + cost_cut;
260
261 if (cost[e_b_index] > cost_new) {
262 cost[e_b_index] = cost_new;
263 edges_prev[e_b_index] = e_a;
264 BLI_heapsimple_insert(heap, cost_new, e_b);
265 }
266 }
267 }
268 }
269 }
270 else {
271 BMLoop *l_first, *l_iter;
272
273 l_iter = l_first = e_a->l;
274 do {
275 BMLoop *l_cycle_iter, *l_cycle_end;
276
277 l_cycle_iter = l_iter->next;
278 l_cycle_end = l_iter;
279
280 /* Good, but we need to allow this otherwise paths may fail to connect at all. */
281 #if 0
282 if (l_iter->f->len > 3) {
283 l_cycle_iter = l_cycle_iter->next;
284 l_cycle_end = l_cycle_end->prev;
285 }
286 #endif
287
288 do {
289 BMEdge *e_b = l_cycle_iter->e;
290 if (!BM_elem_flag_test(e_b, BM_ELEM_TAG)) {
291 /* We know 'e_b' is not visited, check it out! */
292 const int e_b_index = BM_elem_index_get(e_b);
293 const float cost_cut = params->use_topology_distance ?
294 1.0f :
295 edgetag_cut_cost_face(e_a, e_b, l_iter->f);
296 const float cost_new = cost[e_a_index] + cost_cut;
297
298 if (cost[e_b_index] > cost_new) {
299 cost[e_b_index] = cost_new;
300 edges_prev[e_b_index] = e_a;
301 BLI_heapsimple_insert(heap, cost_new, e_b);
302 }
303 }
304 } while ((l_cycle_iter = l_cycle_iter->next) != l_cycle_end);
305 } while ((l_iter = l_iter->radial_next) != l_first);
306 }
307 }
308
BM_mesh_calc_path_edge(BMesh * bm,BMEdge * e_src,BMEdge * e_dst,const struct BMCalcPathParams * params,bool (* filter_fn)(BMEdge *,void * user_data),void * user_data)309 LinkNode *BM_mesh_calc_path_edge(BMesh *bm,
310 BMEdge *e_src,
311 BMEdge *e_dst,
312 const struct BMCalcPathParams *params,
313 bool (*filter_fn)(BMEdge *, void *user_data),
314 void *user_data)
315 {
316 LinkNode *path = NULL;
317 /* #BM_ELEM_TAG flag is used to store visited edges. */
318 BMEdge *e;
319 BMIter eiter;
320 HeapSimple *heap;
321 float *cost;
322 BMEdge **edges_prev;
323 int i, totedge;
324
325 /* Note, would pass #BM_EDGE except we are looping over all edges anyway. */
326 BM_mesh_elem_index_ensure(bm, BM_VERT /* | BM_EDGE */);
327
328 BM_ITER_MESH_INDEX (e, &eiter, bm, BM_EDGES_OF_MESH, i) {
329 BM_elem_flag_set(e, BM_ELEM_TAG, !filter_fn(e, user_data));
330 BM_elem_index_set(e, i); /* set_inline */
331 }
332 bm->elem_index_dirty &= ~BM_EDGE;
333
334 /* Allocate. */
335 totedge = bm->totedge;
336 edges_prev = MEM_callocN(sizeof(*edges_prev) * totedge, __func__);
337 cost = MEM_mallocN(sizeof(*cost) * totedge, __func__);
338
339 copy_vn_fl(cost, totedge, COST_INIT_MAX);
340
341 /*
342 * Arrays are now filled as follows:
343 *
344 * As the search continues, `edges_prev[n]` will be the previous edge on the shortest
345 * path found so far to edge `n`. #BM_ELEM_TAG is used to tag elements we have visited,
346 * `cost[n]` will contain the length of the shortest
347 * path to edge n found so far, Finally, heap is a priority heap which is built on the
348 * the same data as the cost array, but inverted: it is a work-list of edges prioritized
349 * by the shortest path found so far to the edge.
350 */
351
352 /* Regular dijkstra shortest path, but over edges instead of vertices. */
353 heap = BLI_heapsimple_new();
354 BLI_heapsimple_insert(heap, 0.0f, e_src);
355 cost[BM_elem_index_get(e_src)] = 0.0f;
356
357 while (!BLI_heapsimple_is_empty(heap)) {
358 e = BLI_heapsimple_pop_min(heap);
359
360 if (e == e_dst) {
361 break;
362 }
363
364 if (!BM_elem_flag_test(e, BM_ELEM_TAG)) {
365 BM_elem_flag_enable(e, BM_ELEM_TAG);
366 edgetag_add_adjacent(heap, e, edges_prev, cost, params);
367 }
368 }
369
370 if (e == e_dst) {
371 do {
372 BLI_linklist_prepend(&path, e);
373 } while ((e = edges_prev[BM_elem_index_get(e)]));
374 }
375
376 MEM_freeN(edges_prev);
377 MEM_freeN(cost);
378 BLI_heapsimple_free(heap, NULL);
379
380 return path;
381 }
382
383 /** \} */
384
385 /* -------------------------------------------------------------------- */
386 /** \name BM_mesh_calc_path_face
387 * \{ */
388
facetag_cut_cost_edge(BMFace * f_a,BMFace * f_b,BMEdge * e,const void * const f_endpoints[2])389 static float facetag_cut_cost_edge(BMFace *f_a,
390 BMFace *f_b,
391 BMEdge *e,
392 const void *const f_endpoints[2])
393 {
394 float f_a_cent[3];
395 float f_b_cent[3];
396 float e_cent[3];
397
398 BM_face_calc_center_median_weighted(f_a, f_a_cent);
399 BM_face_calc_center_median_weighted(f_b, f_b_cent);
400 #if 0
401 mid_v3_v3v3(e_cent, e->v1->co, e->v2->co);
402 #else
403 /* For triangle fans it gives better results to pick a point on the edge. */
404 {
405 float ix_e[3], ix_f[3];
406 isect_line_line_v3(e->v1->co, e->v2->co, f_a_cent, f_b_cent, ix_e, ix_f);
407 const float factor = line_point_factor_v3(ix_e, e->v1->co, e->v2->co);
408 if (factor < 0.0f) {
409 copy_v3_v3(e_cent, e->v1->co);
410 }
411 else if (factor > 1.0f) {
412 copy_v3_v3(e_cent, e->v2->co);
413 }
414 else {
415 copy_v3_v3(e_cent, ix_e);
416 }
417 }
418 #endif
419
420 return step_cost_3_v3_ex(
421 f_a_cent, e_cent, f_b_cent, (f_a == f_endpoints[0]), (f_b == f_endpoints[1]));
422 }
423
facetag_cut_cost_vert(BMFace * f_a,BMFace * f_b,BMVert * v,const void * const f_endpoints[2])424 static float facetag_cut_cost_vert(BMFace *f_a,
425 BMFace *f_b,
426 BMVert *v,
427 const void *const f_endpoints[2])
428 {
429 float f_a_cent[3];
430 float f_b_cent[3];
431
432 BM_face_calc_center_median_weighted(f_a, f_a_cent);
433 BM_face_calc_center_median_weighted(f_b, f_b_cent);
434
435 return step_cost_3_v3_ex(
436 f_a_cent, v->co, f_b_cent, (f_a == f_endpoints[0]), (f_b == f_endpoints[1]));
437 }
438
facetag_add_adjacent(HeapSimple * heap,BMFace * f_a,BMFace ** faces_prev,float * cost,const void * const f_endpoints[2],const struct BMCalcPathParams * params)439 static void facetag_add_adjacent(HeapSimple *heap,
440 BMFace *f_a,
441 BMFace **faces_prev,
442 float *cost,
443 const void *const f_endpoints[2],
444 const struct BMCalcPathParams *params)
445 {
446 const int f_a_index = BM_elem_index_get(f_a);
447
448 /* Loop over faces of face, but do so by first looping over loops. */
449 {
450 BMIter liter;
451 BMLoop *l_a;
452
453 BM_ITER_ELEM (l_a, &liter, f_a, BM_LOOPS_OF_FACE) {
454 BMLoop *l_first, *l_iter;
455
456 l_iter = l_first = l_a;
457 do {
458 BMFace *f_b = l_iter->f;
459 if (!BM_elem_flag_test(f_b, BM_ELEM_TAG)) {
460 /* We know 'f_b' is not visited, check it out! */
461 const int f_b_index = BM_elem_index_get(f_b);
462 const float cost_cut = params->use_topology_distance ?
463 1.0f :
464 facetag_cut_cost_edge(f_a, f_b, l_iter->e, f_endpoints);
465 const float cost_new = cost[f_a_index] + cost_cut;
466
467 if (cost[f_b_index] > cost_new) {
468 cost[f_b_index] = cost_new;
469 faces_prev[f_b_index] = f_a;
470 BLI_heapsimple_insert(heap, cost_new, f_b);
471 }
472 }
473 } while ((l_iter = l_iter->radial_next) != l_first);
474 }
475 }
476
477 if (params->use_step_face) {
478 BMIter liter;
479 BMLoop *l_a;
480
481 BM_ITER_ELEM (l_a, &liter, f_a, BM_LOOPS_OF_FACE) {
482 BMIter litersub;
483 BMLoop *l_b;
484 BM_ITER_ELEM (l_b, &litersub, l_a->v, BM_LOOPS_OF_VERT) {
485 if ((l_a != l_b) && !BM_loop_share_edge_check(l_a, l_b)) {
486 BMFace *f_b = l_b->f;
487 if (!BM_elem_flag_test(f_b, BM_ELEM_TAG)) {
488 /* We know 'f_b' is not visited, check it out! */
489 const int f_b_index = BM_elem_index_get(f_b);
490 const float cost_cut = params->use_topology_distance ?
491 1.0f :
492 facetag_cut_cost_vert(f_a, f_b, l_a->v, f_endpoints);
493 const float cost_new = cost[f_a_index] + cost_cut;
494
495 if (cost[f_b_index] > cost_new) {
496 cost[f_b_index] = cost_new;
497 faces_prev[f_b_index] = f_a;
498 BLI_heapsimple_insert(heap, cost_new, f_b);
499 }
500 }
501 }
502 }
503 }
504 }
505 }
506
BM_mesh_calc_path_face(BMesh * bm,BMFace * f_src,BMFace * f_dst,const struct BMCalcPathParams * params,bool (* filter_fn)(BMFace *,void * user_data),void * user_data)507 LinkNode *BM_mesh_calc_path_face(BMesh *bm,
508 BMFace *f_src,
509 BMFace *f_dst,
510 const struct BMCalcPathParams *params,
511 bool (*filter_fn)(BMFace *, void *user_data),
512 void *user_data)
513 {
514 LinkNode *path = NULL;
515 /* #BM_ELEM_TAG flag is used to store visited edges. */
516 BMFace *f;
517 BMIter fiter;
518 HeapSimple *heap;
519 float *cost;
520 BMFace **faces_prev;
521 int i, totface;
522
523 /* Start measuring face path at the face edges, ignoring their centers. */
524 const void *const f_endpoints[2] = {f_src, f_dst};
525
526 /* Note, would pass #BM_EDGE except we are looping over all faces anyway. */
527 // BM_mesh_elem_index_ensure(bm, BM_VERT /* | BM_EDGE */); // NOT NEEDED FOR FACETAG
528
529 BM_ITER_MESH_INDEX (f, &fiter, bm, BM_FACES_OF_MESH, i) {
530 BM_elem_flag_set(f, BM_ELEM_TAG, !filter_fn(f, user_data));
531 BM_elem_index_set(f, i); /* set_inline */
532 }
533 bm->elem_index_dirty &= ~BM_FACE;
534
535 /* Allocate. */
536 totface = bm->totface;
537 faces_prev = MEM_callocN(sizeof(*faces_prev) * totface, __func__);
538 cost = MEM_mallocN(sizeof(*cost) * totface, __func__);
539
540 copy_vn_fl(cost, totface, COST_INIT_MAX);
541
542 /*
543 * Arrays are now filled as follows:
544 *
545 * As the search continues, `faces_prev[n]` will be the previous face on the shortest
546 * path found so far to face `n`. #BM_ELEM_TAG is used to tag elements we have visited,
547 * `cost[n]` will contain the length of the shortest
548 * path to face n found so far, Finally, heap is a priority heap which is built on the
549 * the same data as the cost array, but inverted: it is a work-list of faces prioritized
550 * by the shortest path found so far to the face.
551 */
552
553 /* Regular dijkstra shortest path, but over faces instead of vertices. */
554 heap = BLI_heapsimple_new();
555 BLI_heapsimple_insert(heap, 0.0f, f_src);
556 cost[BM_elem_index_get(f_src)] = 0.0f;
557
558 while (!BLI_heapsimple_is_empty(heap)) {
559 f = BLI_heapsimple_pop_min(heap);
560
561 if (f == f_dst) {
562 break;
563 }
564
565 if (!BM_elem_flag_test(f, BM_ELEM_TAG)) {
566 BM_elem_flag_enable(f, BM_ELEM_TAG);
567 facetag_add_adjacent(heap, f, faces_prev, cost, f_endpoints, params);
568 }
569 }
570
571 if (f == f_dst) {
572 do {
573 BLI_linklist_prepend(&path, f);
574 } while ((f = faces_prev[BM_elem_index_get(f)]));
575 }
576
577 MEM_freeN(faces_prev);
578 MEM_freeN(cost);
579 BLI_heapsimple_free(heap, NULL);
580
581 return path;
582 }
583 /** \} */
584