Blender V4.3
bmo_connect_pair.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
11#include "MEM_guardedalloc.h"
12
13#include "BLI_heap_simple.h"
14#include "BLI_math_matrix.h"
15#include "BLI_math_vector.h"
16#include "BLI_utildefines.h"
17
18#include "bmesh.hh"
19
20#include "intern/bmesh_operators_private.hh" /* own include */
21
22#include "BLI_mempool.h"
23
43#define CONNECT_EPS 0.0001f
44#define VERT_OUT 1
45#define VERT_EXCLUDE 2
46
47/* typically hidden faces */
48#define FACE_EXCLUDE 2
49
50/* any element we've walked over (only do it once!) */
51#define ELE_TOUCHED 4
52
53#define FACE_WALK_TEST(f) \
54 (CHECK_TYPE_INLINE(f, BMFace *), BMO_face_flag_test(pc->bm_bmoflag, f, FACE_EXCLUDE) == 0)
55#define VERT_WALK_TEST(v) \
56 (CHECK_TYPE_INLINE(v, BMVert *), BMO_vert_flag_test(pc->bm_bmoflag, v, VERT_EXCLUDE) == 0)
57
58#if 0
59# define ELE_TOUCH_TEST(e) \
60 (CHECK_TYPE_ANY(e, BMVert *, BMEdge *, BMElem *, BMElemF *), \
61 BMO_elem_flag_test(pc->bm_bmoflag, (BMElemF *)e, ELE_TOUCHED))
62#endif
63#define ELE_TOUCH_MARK(e) \
64 { \
65 CHECK_TYPE_ANY(e, BMVert *, BMEdge *, BMElem *, BMElemF *); \
66 BMO_elem_flag_enable(pc->bm_bmoflag, (BMElemF *)e, ELE_TOUCHED); \
67 } \
68 ((void)0)
69
70#define ELE_TOUCH_TEST_VERT(v) BMO_vert_flag_test(pc->bm_bmoflag, v, ELE_TOUCHED)
71// #define ELE_TOUCH_MARK_VERT(v) BMO_vert_flag_enable(pc->bm_bmoflag, (BMElemF *)v, ELE_TOUCHED)
72
73#define ELE_TOUCH_TEST_EDGE(e) BMO_edge_flag_test(pc->bm_bmoflag, e, ELE_TOUCHED)
74// #define ELE_TOUCH_MARK_EDGE(e) BMO_edge_flag_enable(pc->bm_bmoflag, (BMElemF *)e, ELE_TOUCHED)
75
76// #define ELE_TOUCH_TEST_FACE(f) BMO_face_flag_test(pc->bm_bmoflag, f, ELE_TOUCHED)
77// #define ELE_TOUCH_MARK_FACE(f) BMO_face_flag_enable(pc->bm_bmoflag, (BMElemF *)f, ELE_TOUCHED)
78
79// #define DEBUG_PRINT
80
83 float matrix[3][3];
84 float axis_sep;
85
86 /* only to access BMO flags */
88
90
92};
93
97struct PathLink {
99 BMElem *ele; /* edge or vert */
100 BMElem *ele_from; /* edge or face we came from (not 'next->ele') */
101};
102
104 /* chain of links */
106
107 /* length along links */
108 float dist;
109 float co_prev[3];
110};
111
112/* -------------------------------------------------------------------- */
127 /* distance in both directions (FLT_MAX == uninitialized) */
128 float dist_min[2];
129 /* direction of the first intersection found */
130 float dir[3];
131};
132
133#define MIN_DIST_DIR_INIT \
134 { \
135 { \
136 FLT_MAX, FLT_MAX \
137 } \
138 }
139
140static int min_dist_dir_test(MinDistDir *mddir, const float dist_dir[3], const float dist_sq)
141{
142
143 if (mddir->dist_min[0] == FLT_MAX) {
144 return 0;
145 }
146 if (dot_v3v3(dist_dir, mddir->dir) > 0.0f) {
147 if (dist_sq < mddir->dist_min[0]) {
148 return 0;
149 }
150 }
151 else {
152 if (dist_sq < mddir->dist_min[1]) {
153 return 1;
154 }
155 }
156
157 return -1;
158}
159
160static void min_dist_dir_update(MinDistDir *dist, const float dist_dir[3])
161{
162 if (dist->dist_min[0] == FLT_MAX) {
163 copy_v3_v3(dist->dir, dist_dir);
164 }
165}
166
169static int state_isect_co_pair(const PathContext *pc, const float co_a[3], const float co_b[3])
170{
171 const float diff_a = dot_m3_v3_row_x(pc->matrix, co_a) - pc->axis_sep;
172 const float diff_b = dot_m3_v3_row_x(pc->matrix, co_b) - pc->axis_sep;
173
174 const int test_a = (fabsf(diff_a) < CONNECT_EPS) ? 0 : (diff_a < 0.0f) ? -1 : 1;
175 const int test_b = (fabsf(diff_b) < CONNECT_EPS) ? 0 : (diff_b < 0.0f) ? -1 : 1;
176
177 if ((test_a && test_b) && (test_a != test_b)) {
178 return 1; /* on either side */
179 }
180 return 0;
181}
182
183static int state_isect_co_exact(const PathContext *pc, const float co[3])
184{
185 const float diff = dot_m3_v3_row_x(pc->matrix, co) - pc->axis_sep;
186 return (fabsf(diff) <= CONNECT_EPS);
187}
188
189static float state_calc_co_pair_fac(const PathContext *pc,
190 const float co_a[3],
191 const float co_b[3])
192{
193 float diff_a, diff_b, diff_tot;
194
195 diff_a = fabsf(dot_m3_v3_row_x(pc->matrix, co_a) - pc->axis_sep);
196 diff_b = fabsf(dot_m3_v3_row_x(pc->matrix, co_b) - pc->axis_sep);
197 diff_tot = (diff_a + diff_b);
198 return (diff_tot > FLT_EPSILON) ? (diff_a / diff_tot) : 0.5f;
199}
200
201static void state_calc_co_pair(const PathContext *pc,
202 const float co_a[3],
203 const float co_b[3],
204 float r_co[3])
205{
206 const float fac = state_calc_co_pair_fac(pc, co_a, co_b);
207 interp_v3_v3v3(r_co, co_a, co_b, fac);
208}
209
210#ifndef NDEBUG
215static bool state_link_find(const PathLinkState *state, BMElem *ele)
216{
217 PathLink *link = state->link_last;
219 if (link) {
220 do {
221 if (link->ele == ele) {
222 return true;
223 }
224 } while ((link = link->next));
225 }
226 return false;
227}
228#endif
229
230static void state_link_add(PathContext *pc, PathLinkState *state, BMElem *ele, BMElem *ele_from)
231{
232 PathLink *step_new = static_cast<PathLink *>(BLI_mempool_alloc(pc->link_pool));
233 BLI_assert(ele != ele_from);
234 BLI_assert(state_link_find(state, ele) == false);
235
236 /* never walk onto this again */
237 ELE_TOUCH_MARK(ele);
238
239#ifdef DEBUG_PRINT
240 printf("%s: adding to state %p, %.4f - ", __func__, state, state->dist);
241 if (ele->head.htype == BM_VERT) {
242 printf("vert %d, ", BM_elem_index_get(ele));
243 }
244 else if (ele->head.htype == BM_EDGE) {
245 printf("edge %d, ", BM_elem_index_get(ele));
246 }
247 else {
248 BLI_assert(0);
249 }
250
251 if (ele_from == nullptr) {
252 printf("from nullptr\n");
253 }
254 else if (ele_from->head.htype == BM_EDGE) {
255 printf("from edge %d\n", BM_elem_index_get(ele_from));
256 }
257 else if (ele_from->head.htype == BM_FACE) {
258 printf("from face %d\n", BM_elem_index_get(ele_from));
259 }
260 else {
261 BLI_assert(0);
262 }
263#endif
264
265 /* track distance */
266 {
267 float co[3];
268 if (ele->head.htype == BM_VERT) {
269 copy_v3_v3(co, ((BMVert *)ele)->co);
270 }
271 else if (ele->head.htype == BM_EDGE) {
272 state_calc_co_pair(pc, ((BMEdge *)ele)->v1->co, ((BMEdge *)ele)->v2->co, co);
273 }
274 else {
275 BLI_assert(0);
276 }
277
278 /* tally distance */
279 if (ele_from) {
280 state->dist += len_v3v3(state->co_prev, co);
281 }
282 copy_v3_v3(state->co_prev, co);
283 }
284
285 step_new->ele = ele;
286 step_new->ele_from = ele_from;
287 step_new->next = state->link_last;
288 state->link_last = step_new;
289}
290
292{
293 state = static_cast<PathLinkState *>(MEM_mallocN(sizeof(*state), __func__));
294 *state = *state_orig;
295 return state;
296}
297
300 const PathLinkState *state_orig,
301 BMElem *ele,
302 BMElem *ele_from)
303{
304 const bool is_new = (state_orig->link_last != state->link_last);
305 if (is_new) {
306 state = state_dupe_add(state, state_orig);
307 }
308
309 state_link_add(pc, state, ele, ele_from);
310
311 /* after adding a link so we use the updated 'state->dist' */
312 if (is_new) {
314 }
315
316 return state;
317}
318
319/* walk around the face edges */
322 const PathLinkState *state_orig,
323 BMLoop *l_iter,
324 BMLoop *l_last,
325 MinDistDir *mddir)
326{
327
328 BMLoop *l_iter_best[2] = {nullptr, nullptr};
329 int i;
330
331 do {
332 if (state_isect_co_pair(pc, l_iter->v->co, l_iter->next->v->co)) {
333 float dist_test;
334 float co_isect[3];
335 float dist_dir[3];
336 int index;
337
338 state_calc_co_pair(pc, l_iter->v->co, l_iter->next->v->co, co_isect);
339
340 sub_v3_v3v3(dist_dir, co_isect, state_orig->co_prev);
341 dist_test = len_squared_v3(dist_dir);
342 if ((index = min_dist_dir_test(mddir, dist_dir, dist_test)) != -1) {
343 BMElem *ele_next = (BMElem *)l_iter->e;
344 BMElem *ele_next_from = (BMElem *)l_iter->f;
345
346 if (FACE_WALK_TEST((BMFace *)ele_next_from) &&
347 (ELE_TOUCH_TEST_EDGE((BMEdge *)ele_next) == false))
348 {
349 min_dist_dir_update(mddir, dist_dir);
350 mddir->dist_min[index] = dist_test;
351 l_iter_best[index] = l_iter;
352 }
353 }
354 }
355 } while ((l_iter = l_iter->next) != l_last);
356
357 for (i = 0; i < 2; i++) {
358 if ((l_iter = l_iter_best[i])) {
359 BMElem *ele_next = (BMElem *)l_iter->e;
360 BMElem *ele_next_from = (BMElem *)l_iter->f;
361 state = state_link_add_test(pc, state, state_orig, ele_next, ele_next_from);
362 }
363 }
364
365 return state;
366}
367
368/* walk around the face verts */
371 const PathLinkState *state_orig,
372 BMLoop *l_iter,
373 BMLoop *l_last,
374 MinDistDir *mddir)
375{
376 BMLoop *l_iter_best[2] = {nullptr, nullptr};
377 int i;
378
379 do {
380 if (state_isect_co_exact(pc, l_iter->v->co)) {
381 float dist_test;
382 const float *co_isect = l_iter->v->co;
383 float dist_dir[3];
384 int index;
385
386 sub_v3_v3v3(dist_dir, co_isect, state_orig->co_prev);
387 dist_test = len_squared_v3(dist_dir);
388 if ((index = min_dist_dir_test(mddir, dist_dir, dist_test)) != -1) {
389 BMElem *ele_next = (BMElem *)l_iter->v;
390 BMElem *ele_next_from = (BMElem *)l_iter->f;
391
392 if (FACE_WALK_TEST((BMFace *)ele_next_from) &&
393 (ELE_TOUCH_TEST_VERT((BMVert *)ele_next) == false))
394 {
395 min_dist_dir_update(mddir, dist_dir);
396 mddir->dist_min[index] = dist_test;
397 l_iter_best[index] = l_iter;
398 }
399 }
400 }
401 } while ((l_iter = l_iter->next) != l_last);
402
403 for (i = 0; i < 2; i++) {
404 if ((l_iter = l_iter_best[i])) {
405 BMElem *ele_next = (BMElem *)l_iter->v;
406 BMElem *ele_next_from = (BMElem *)l_iter->f;
407 state = state_link_add_test(pc, state, state_orig, ele_next, ele_next_from);
408 }
409 }
410
411 return state;
412}
413
415{
416 PathLinkState state_orig = *state;
417 BMElem *ele = state->link_last->ele;
418 const void *ele_from = state->link_last->ele_from;
419
420 if (ele->head.htype == BM_EDGE) {
421 BMEdge *e = (BMEdge *)ele;
422
423 BMIter liter;
424 BMLoop *l_start;
425
426 BM_ITER_ELEM (l_start, &liter, e, BM_LOOPS_OF_EDGE) {
427 if ((l_start->f != ele_from) && FACE_WALK_TEST(l_start->f)) {
429 /* Very similar to block below. */
430 state = state_step__face_edges(pc, state, &state_orig, l_start->next, l_start, &mddir);
432 pc, state, &state_orig, l_start->next->next, l_start, &mddir);
433 }
434 }
435 }
436 else if (ele->head.htype == BM_VERT) {
437 BMVert *v = (BMVert *)ele;
438
439 /* Vert loops. */
440 {
441 BMIter liter;
442 BMLoop *l_start;
443
444 BM_ITER_ELEM (l_start, &liter, v, BM_LOOPS_OF_VERT) {
445 if ((l_start->f != ele_from) && FACE_WALK_TEST(l_start->f)) {
447 /* Very similar to block above. */
449 pc, state, &state_orig, l_start->next, l_start->prev, &mddir);
450 if (l_start->f->len > 3) {
451 /* Adjacent verts are handled in #state_step__vert_edges. */
453 pc, state, &state_orig, l_start->next->next, l_start->prev, &mddir);
454 }
455 }
456 }
457 }
458
459 /* Vert edges. */
460 {
461 BMIter eiter;
462 BMEdge *e;
463 BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
464 BMVert *v_other = BM_edge_other_vert(e, v);
465 if (((BMElem *)e != ele_from) && VERT_WALK_TEST(v_other)) {
466 if (state_isect_co_exact(pc, v_other->co)) {
467 BMElem *ele_next = (BMElem *)v_other;
468 BMElem *ele_next_from = (BMElem *)e;
469 if (ELE_TOUCH_TEST_VERT((BMVert *)ele_next) == false) {
470 state = state_link_add_test(pc, state, &state_orig, ele_next, ele_next_from);
471 }
472 }
473 }
474 }
475 }
476 }
477 else {
478 BLI_assert(0);
479 }
480 return (state_orig.link_last != state->link_last);
481}
482
486static void bm_vert_pair_to_matrix(BMVert *v_pair[2], float r_unit_mat[3][3])
487{
488 const float eps = 1e-8f;
489
490 float basis_dir[3];
491 float basis_tmp[3];
492 float basis_nor[3];
493
494 sub_v3_v3v3(basis_dir, v_pair[0]->co, v_pair[1]->co);
495 normalize_v3(basis_dir);
496
497#if 0
498 add_v3_v3v3(basis_nor, v_pair[0]->no, v_pair[1]->no);
499 cross_v3_v3v3(basis_tmp, basis_nor, basis_dir);
500 cross_v3_v3v3(basis_nor, basis_tmp, basis_dir);
501#else
502 /* align both normals to the directions before combining */
503 {
504 float basis_nor_a[3];
505 float basis_nor_b[3];
506
507 /* align normal to direction */
508 project_plane_normalized_v3_v3v3(basis_nor_a, v_pair[0]->no, basis_dir);
509 project_plane_normalized_v3_v3v3(basis_nor_b, v_pair[1]->no, basis_dir);
510
511 /* Don't normalize before combining so as normals approach the direction,
512 * they have less effect (#46784). */
513
514 /* combine the normals */
515 /* for flipped faces */
516 if (dot_v3v3(basis_nor_a, basis_nor_b) < 0.0f) {
517 negate_v3(basis_nor_b);
518 }
519 add_v3_v3v3(basis_nor, basis_nor_a, basis_nor_b);
520 }
521#endif
522
523 /* get third axis */
524 normalize_v3(basis_nor);
525 cross_v3_v3v3(basis_tmp, basis_dir, basis_nor);
526
527 /* Try get the axis from surrounding faces, fallback to 'ortho_v3_v3' */
528 if (UNLIKELY(normalize_v3(basis_tmp) < eps)) {
529 /* vertex normals are directly opposite */
530
531 /* find the loop with the lowest angle */
532 struct {
533 float nor[3];
534 float angle_cos;
535 } axis_pair[2];
536 int i;
537
538 for (i = 0; i < 2; i++) {
539 BMIter liter;
540 BMLoop *l;
541
542 zero_v2(axis_pair[i].nor);
543 axis_pair[i].angle_cos = -FLT_MAX;
544
545 BM_ITER_ELEM (l, &liter, v_pair[i], BM_LOOPS_OF_VERT) {
546 float basis_dir_proj[3];
547 float angle_cos_test;
548
549 /* project basis dir onto the normal to find its closest angle */
550 project_plane_normalized_v3_v3v3(basis_dir_proj, basis_dir, l->f->no);
551
552 if (normalize_v3(basis_dir_proj) > eps) {
553 angle_cos_test = dot_v3v3(basis_dir_proj, basis_dir);
554
555 if (angle_cos_test > axis_pair[i].angle_cos) {
556 axis_pair[i].angle_cos = angle_cos_test;
557 copy_v3_v3(axis_pair[i].nor, basis_dir_proj);
558 }
559 }
560 }
561 }
562
563 /* create a new 'basis_nor' from the best direction.
564 * NOTE: we could add the directions,
565 * but this more often gives 45d rotated matrix, so just use the best one. */
566 copy_v3_v3(basis_nor, axis_pair[axis_pair[0].angle_cos < axis_pair[1].angle_cos].nor);
567 project_plane_normalized_v3_v3v3(basis_nor, basis_nor, basis_dir);
568
569 cross_v3_v3v3(basis_tmp, basis_dir, basis_nor);
570
571 /* last resort, pick _any_ ortho axis */
572 if (UNLIKELY(normalize_v3(basis_tmp) < eps)) {
573 ortho_v3_v3(basis_nor, basis_dir);
574 normalize_v3(basis_nor);
575 cross_v3_v3v3(basis_tmp, basis_dir, basis_nor);
576 normalize_v3(basis_tmp);
577 }
578 }
579
580 copy_v3_v3(r_unit_mat[0], basis_tmp);
581 copy_v3_v3(r_unit_mat[1], basis_dir);
582 copy_v3_v3(r_unit_mat[2], basis_nor);
583 if (invert_m3(r_unit_mat) == false) {
584 unit_m3(r_unit_mat);
585 }
586}
587
589{
590 BMOpSlot *op_verts_slot = BMO_slot_get(op->slots_in, "verts");
591
592 PathContext pc;
593 PathLinkState state_best = {nullptr};
594
595 if (op_verts_slot->len != 2) {
596 /* fail! */
597 return;
598 }
599
600 pc.bm_bmoflag = bm;
601 pc.v_pair[0] = ((BMVert **)op_verts_slot->data.p)[0];
602 pc.v_pair[1] = ((BMVert **)op_verts_slot->data.p)[1];
603
604 /* fail! */
605 if (!(pc.v_pair[0] && pc.v_pair[1])) {
606 return;
607 }
608
609#ifdef DEBUG_PRINT
610 printf("%s: v_pair[0]: %d\n", __func__, BM_elem_index_get(pc.v_pair[0]));
611 printf("%s: v_pair[1]: %d\n", __func__, BM_elem_index_get(pc.v_pair[1]));
612#endif
613
614 /* tag so we won't touch ever (typically hidden faces) */
617
618 /* setup context */
619 {
622 }
623
624 /* calculate matrix */
625 {
627 pc.axis_sep = dot_m3_v3_row_x(pc.matrix, pc.v_pair[0]->co);
628 }
629
630 /* add first vertex */
631 {
633 state = static_cast<PathLinkState *>(MEM_callocN(sizeof(*state), __func__));
634 state_link_add(&pc, state, (BMElem *)pc.v_pair[0], nullptr);
636 }
637
638 while (!BLI_heapsimple_is_empty(pc.states)) {
639
640#ifdef DEBUG_PRINT
641 printf("\n%s: stepping %u\n", __func__, BLI_heapsimple_len(pc.states));
642#endif
643
644 while (!BLI_heapsimple_is_empty(pc.states)) {
646
647 /* either we insert this into 'pc.states' or its freed */
648 bool continue_search;
649
650 if (state->link_last->ele == (BMElem *)pc.v_pair[1]) {
651/* pass, wait until all are found */
652#ifdef DEBUG_PRINT
653 printf("%s: state %p loop found %.4f\n", __func__, state, state->dist);
654#endif
655 state_best = *state;
656
657 /* we're done, exit all loops */
659 continue_search = false;
660 }
661 else if (state_step(&pc, state)) {
662 continue_search = true;
663 }
664 else {
665 /* didn't reach the end, remove it,
666 * links are shared between states so just free the link_pool at the end */
667
668#ifdef DEBUG_PRINT
669 printf("%s: state %p removed\n", __func__, state);
670#endif
671 continue_search = false;
672 }
673
674 if (continue_search) {
676 }
677 else {
679 }
680 }
681 }
682
683 if (state_best.link_last) {
684 PathLink *link;
685
686 /* find the best state */
687 link = state_best.link_last;
688 do {
689 if (link->ele->head.htype == BM_EDGE) {
690 BMEdge *e = (BMEdge *)link->ele;
691 BMVert *v_new;
692 float e_fac = state_calc_co_pair_fac(&pc, e->v1->co, e->v2->co);
693 v_new = BM_edge_split(bm, e, e->v1, nullptr, e_fac);
695 }
696 else if (link->ele->head.htype == BM_VERT) {
697 BMVert *v = (BMVert *)link->ele;
699 }
700 else {
701 BLI_assert(0);
702 }
703 } while ((link = link->next));
704 }
705
708
710
712
713#if 1
714 if (state_best.link_last) {
717 &op_sub,
718 0,
719 "connect_verts verts=%fv faces_exclude=%s check_degenerate=%b",
720 VERT_OUT,
721 op,
722 "faces_exclude",
723 true);
725 BMO_slot_copy(&op_sub, slots_out, "edges.out", op, slots_out, "edges.out");
727 }
728#endif
729}
#define BLI_assert(a)
Definition BLI_assert.h:50
A min-heap / priority queue ADT.
HeapSimple * BLI_heapsimple_new(void) ATTR_WARN_UNUSED_RESULT
void BLI_heapsimple_clear(HeapSimple *heap, HeapSimpleFreeFP ptrfreefp) ATTR_NONNULL(1)
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)
uint BLI_heapsimple_len(const HeapSimple *heap) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
void BLI_heapsimple_insert(HeapSimple *heap, float value, void *ptr) ATTR_NONNULL(1)
void unit_m3(float m[3][3])
bool invert_m3(float mat[3][3])
MINLINE float len_squared_v3(const float v[3]) ATTR_WARN_UNUSED_RESULT
MINLINE float len_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE float dot_m3_v3_row_x(const float M[3][3], const float a[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void copy_v3_v3(float r[3], const float a[3])
void project_plane_normalized_v3_v3v3(float out[3], const float p[3], const float v_plane[3])
MINLINE float dot_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
void interp_v3_v3v3(float r[3], const float a[3], const float b[3], float t)
Definition math_vector.c:36
MINLINE void add_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void cross_v3_v3v3(float r[3], const float a[3], const float b[3])
void ortho_v3_v3(float out[3], const float v[3])
MINLINE void negate_v3(float r[3])
MINLINE void zero_v2(float r[2])
MINLINE float normalize_v3(float n[3])
void * BLI_mempool_alloc(BLI_mempool *pool) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL ATTR_NONNULL(1)
BLI_mempool * BLI_mempool_create(unsigned int esize, unsigned int elem_num, unsigned int pchunk, unsigned int flag) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL
@ BLI_MEMPOOL_NOP
Definition BLI_mempool.h:86
void BLI_mempool_destroy(BLI_mempool *pool) ATTR_NONNULL(1)
#define UNLIKELY(x)
#define ELEM(...)
Read Guarded memory(de)allocation.
#define BM_elem_index_get(ele)
#define BM_ITER_ELEM(ele, iter, data, itype)
@ BM_LOOPS_OF_VERT
@ BM_LOOPS_OF_EDGE
@ BM_EDGES_OF_VERT
ATTR_WARN_UNUSED_RESULT BMesh * bm
BMVert * BM_edge_split(BMesh *bm, BMEdge *e, BMVert *v, BMEdge **r_e, float fac)
Edge Split.
#define BM_FACE
#define BM_EDGE
#define BM_VERT
void BMO_slot_buffer_flag_enable(BMesh *bm, BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, char htype, short oflag)
BMO_FLAG_BUFFER.
#define BMO_vert_flag_enable(bm, e, oflag)
BMOpSlot * BMO_slot_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *identifier)
BMESH OPSTACK GET SLOT.
void BMO_op_exec(BMesh *bm, BMOperator *op)
BMESH OPSTACK EXEC OP.
#define BMO_slot_copy(op_src, slots_src, slot_name_src, op_dst, slots_dst, slot_name_dst)
bool BMO_op_initf(BMesh *bm, BMOperator *op, int flag, const char *fmt,...)
void BMO_op_finish(BMesh *bm, BMOperator *op)
BMESH OPSTACK FINISH OP.
BLI_INLINE BMVert * BM_edge_other_vert(BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
ATTR_WARN_UNUSED_RESULT const BMLoop * l
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
ATTR_WARN_UNUSED_RESULT const BMVert * v
#define ELE_TOUCH_TEST_VERT(v)
static int state_isect_co_exact(const PathContext *pc, const float co[3])
#define CONNECT_EPS
#define VERT_EXCLUDE
#define FACE_WALK_TEST(f)
static int min_dist_dir_test(MinDistDir *mddir, const float dist_dir[3], const float dist_sq)
#define VERT_OUT
#define VERT_WALK_TEST(v)
#define FACE_EXCLUDE
static bool state_step(PathContext *pc, PathLinkState *state)
void bmo_connect_vert_pair_exec(BMesh *bm, BMOperator *op)
static PathLinkState * state_step__face_edges(PathContext *pc, PathLinkState *state, const PathLinkState *state_orig, BMLoop *l_iter, BMLoop *l_last, MinDistDir *mddir)
static float state_calc_co_pair_fac(const PathContext *pc, const float co_a[3], const float co_b[3])
static void min_dist_dir_update(MinDistDir *dist, const float dist_dir[3])
static PathLinkState * state_dupe_add(PathLinkState *state, const PathLinkState *state_orig)
static bool state_link_find(const PathLinkState *state, BMElem *ele)
#define ELE_TOUCH_MARK(e)
#define ELE_TOUCH_TEST_EDGE(e)
static int state_isect_co_pair(const PathContext *pc, const float co_a[3], const float co_b[3])
static PathLinkState * state_step__face_verts(PathContext *pc, PathLinkState *state, const PathLinkState *state_orig, BMLoop *l_iter, BMLoop *l_last, MinDistDir *mddir)
static void state_link_add(PathContext *pc, PathLinkState *state, BMElem *ele, BMElem *ele_from)
static void bm_vert_pair_to_matrix(BMVert *v_pair[2], float r_unit_mat[3][3])
static PathLinkState * state_link_add_test(PathContext *pc, PathLinkState *state, const PathLinkState *state_orig, BMElem *ele, BMElem *ele_from)
#define MIN_DIST_DIR_INIT
static void state_calc_co_pair(const PathContext *pc, const float co_a[3], const float co_b[3], float r_co[3])
#define printf
#define fabsf(x)
static double op_sub(double a, double b)
IMETHOD Vector diff(const Vector &a, const Vector &b, double dt)
Definition frames.inl:1166
void *(* MEM_mallocN)(size_t len, const char *str)
Definition mallocn.cc:44
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
void *(* MEM_callocN)(size_t len, const char *str)
Definition mallocn.cc:42
static ulong state[N]
Frequency::GEOMETRY nor[]
const btScalar eps
Definition poly34.cpp:11
#define FLT_MAX
Definition stdcycles.h:14
BMHeader head
float no[3]
struct BMVert * v
struct BMEdge * e
struct BMLoop * prev
struct BMFace * f
struct BMLoop * next
union BMOpSlot::@139 data
struct BMOpSlot slots_in[BMO_OP_MAX_SLOTS]
float co[3]
BLI_mempool * link_pool
float matrix[3][3]
HeapSimple * states
BMVert * v_pair[2]