Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCampbell Barton <ideasman42@gmail.com>2019-04-17 07:17:24 +0300
committerCampbell Barton <ideasman42@gmail.com>2019-04-17 07:21:24 +0300
commite12c08e8d170b7ca40f204a5b0423c23a9fbc2c1 (patch)
tree8cf3453d12edb177a218ef8009357518ec6cab6a /source/blender/bmesh/tools
parentb3dabc200a4b0399ec6b81f2ff2730d07b44fcaa (diff)
ClangFormat: apply to source, most of intern
Apply clang format as proposed in T53211. For details on usage and instructions for migrating branches without conflicts, see: https://wiki.blender.org/wiki/Tools/ClangFormat
Diffstat (limited to 'source/blender/bmesh/tools')
-rw-r--r--source/blender/bmesh/tools/bmesh_beautify.c645
-rw-r--r--source/blender/bmesh/tools/bmesh_beautify.h23
-rw-r--r--source/blender/bmesh/tools/bmesh_bevel.c10981
-rw-r--r--source/blender/bmesh/tools/bmesh_bevel.h27
-rw-r--r--source/blender/bmesh/tools/bmesh_bisect_plane.c784
-rw-r--r--source/blender/bmesh/tools/bmesh_bisect_plane.h11
-rw-r--r--source/blender/bmesh/tools/bmesh_decimate.h34
-rw-r--r--source/blender/bmesh/tools/bmesh_decimate_collapse.c2397
-rw-r--r--source/blender/bmesh/tools/bmesh_decimate_dissolve.c887
-rw-r--r--source/blender/bmesh/tools/bmesh_decimate_unsubdivide.c541
-rw-r--r--source/blender/bmesh/tools/bmesh_edgenet.c707
-rw-r--r--source/blender/bmesh/tools/bmesh_edgenet.h4
-rw-r--r--source/blender/bmesh/tools/bmesh_edgesplit.c195
-rw-r--r--source/blender/bmesh/tools/bmesh_edgesplit.h8
-rw-r--r--source/blender/bmesh/tools/bmesh_intersect.c2670
-rw-r--r--source/blender/bmesh/tools/bmesh_intersect.h30
-rw-r--r--source/blender/bmesh/tools/bmesh_path.c932
-rw-r--r--source/blender/bmesh/tools/bmesh_path.h37
-rw-r--r--source/blender/bmesh/tools/bmesh_path_region.c733
-rw-r--r--source/blender/bmesh/tools/bmesh_path_region.h30
-rw-r--r--source/blender/bmesh/tools/bmesh_region_match.c2183
-rw-r--r--source/blender/bmesh/tools/bmesh_region_match.h8
-rw-r--r--source/blender/bmesh/tools/bmesh_separate.c177
-rw-r--r--source/blender/bmesh/tools/bmesh_separate.h4
-rw-r--r--source/blender/bmesh/tools/bmesh_triangulate.c224
-rw-r--r--source/blender/bmesh/tools/bmesh_triangulate.h14
-rw-r--r--source/blender/bmesh/tools/bmesh_wireframe.c1078
-rw-r--r--source/blender/bmesh/tools/bmesh_wireframe.h33
28 files changed, 12749 insertions, 12648 deletions
diff --git a/source/blender/bmesh/tools/bmesh_beautify.c b/source/blender/bmesh/tools/bmesh_beautify.c
index aa484a2ef8b..e8a49c895ab 100644
--- a/source/blender/bmesh/tools/bmesh_beautify.c
+++ b/source/blender/bmesh/tools/bmesh_beautify.c
@@ -36,8 +36,7 @@
#include "MEM_guardedalloc.h"
#include "bmesh.h"
-#include "bmesh_beautify.h" /* own include */
-
+#include "bmesh_beautify.h" /* own include */
// #define DEBUG_TIME
@@ -50,169 +49,169 @@
/* GSet for edge rotation */
typedef struct EdRotState {
- int v1, v2; /* edge vert, small -> large */
- int f1, f2; /* face vert, small -> large */
+ int v1, v2; /* edge vert, small -> large */
+ int f1, f2; /* face vert, small -> large */
} EdRotState;
#if 0
/* use BLI_ghashutil_inthash_v4 direct */
static uint erot_gsetutil_hash(const void *ptr)
{
- const EdRotState *e_state = (const EdRotState *)ptr;
- return BLI_ghashutil_inthash_v4(&e_state->v1);
+ const EdRotState *e_state = (const EdRotState *)ptr;
+ return BLI_ghashutil_inthash_v4(&e_state->v1);
}
#endif
#if 0
static int erot_gsetutil_cmp(const void *a, const void *b)
{
- const EdRotState *e_state_a = (const EdRotState *)a;
- const EdRotState *e_state_b = (const EdRotState *)b;
- if (e_state_a->v1 < e_state_b->v1) return -1;
- else if (e_state_a->v1 > e_state_b->v1) return 1;
- else if (e_state_a->v2 < e_state_b->v2) return -1;
- else if (e_state_a->v2 > e_state_b->v2) return 1;
- else if (e_state_a->f1 < e_state_b->f1) return -1;
- else if (e_state_a->f1 > e_state_b->f1) return 1;
- else if (e_state_a->f2 < e_state_b->f2) return -1;
- else if (e_state_a->f2 > e_state_b->f2) return 1;
- else return 0;
+ const EdRotState *e_state_a = (const EdRotState *)a;
+ const EdRotState *e_state_b = (const EdRotState *)b;
+ if (e_state_a->v1 < e_state_b->v1) return -1;
+ else if (e_state_a->v1 > e_state_b->v1) return 1;
+ else if (e_state_a->v2 < e_state_b->v2) return -1;
+ else if (e_state_a->v2 > e_state_b->v2) return 1;
+ else if (e_state_a->f1 < e_state_b->f1) return -1;
+ else if (e_state_a->f1 > e_state_b->f1) return 1;
+ else if (e_state_a->f2 < e_state_b->f2) return -1;
+ else if (e_state_a->f2 > e_state_b->f2) return 1;
+ else return 0;
}
#endif
static GSet *erot_gset_new(void)
{
- return BLI_gset_new(BLI_ghashutil_inthash_v4_p, BLI_ghashutil_inthash_v4_cmp, __func__);
+ return BLI_gset_new(BLI_ghashutil_inthash_v4_p, BLI_ghashutil_inthash_v4_cmp, __func__);
}
/* ensure v0 is smaller */
-#define EDGE_ORD(v0, v1) \
- if (v0 > v1) { \
- SWAP(int, v0, v1); \
- } (void)0
+#define EDGE_ORD(v0, v1) \
+ if (v0 > v1) { \
+ SWAP(int, v0, v1); \
+ } \
+ (void)0
static void erot_state_ex(const BMEdge *e, int v_index[2], int f_index[2])
{
- BLI_assert(BM_edge_is_manifold(e));
- BLI_assert(BM_vert_in_edge(e, e->l->prev->v) == false);
- BLI_assert(BM_vert_in_edge(e, e->l->radial_next->prev->v) == false);
-
- /* verts of the edge */
- v_index[0] = BM_elem_index_get(e->v1);
- v_index[1] = BM_elem_index_get(e->v2);
- EDGE_ORD(v_index[0], v_index[1]);
-
- /* verts of each of the 2 faces attached to this edge
- * (that are not apart of this edge) */
- f_index[0] = BM_elem_index_get(e->l->prev->v);
- f_index[1] = BM_elem_index_get(e->l->radial_next->prev->v);
- EDGE_ORD(f_index[0], f_index[1]);
+ BLI_assert(BM_edge_is_manifold(e));
+ BLI_assert(BM_vert_in_edge(e, e->l->prev->v) == false);
+ BLI_assert(BM_vert_in_edge(e, e->l->radial_next->prev->v) == false);
+
+ /* verts of the edge */
+ v_index[0] = BM_elem_index_get(e->v1);
+ v_index[1] = BM_elem_index_get(e->v2);
+ EDGE_ORD(v_index[0], v_index[1]);
+
+ /* verts of each of the 2 faces attached to this edge
+ * (that are not apart of this edge) */
+ f_index[0] = BM_elem_index_get(e->l->prev->v);
+ f_index[1] = BM_elem_index_get(e->l->radial_next->prev->v);
+ EDGE_ORD(f_index[0], f_index[1]);
}
static void erot_state_current(const BMEdge *e, EdRotState *e_state)
{
- erot_state_ex(e, &e_state->v1, &e_state->f1);
+ erot_state_ex(e, &e_state->v1, &e_state->f1);
}
static void erot_state_alternate(const BMEdge *e, EdRotState *e_state)
{
- erot_state_ex(e, &e_state->f1, &e_state->v1);
+ erot_state_ex(e, &e_state->f1, &e_state->v1);
}
/* -------------------------------------------------------------------- */
/* Calculate the improvement of rotating the edge */
-static float bm_edge_calc_rotate_beauty__area(
- const float v1[3], const float v2[3], const float v3[3], const float v4[3])
+static float bm_edge_calc_rotate_beauty__area(const float v1[3],
+ const float v2[3],
+ const float v3[3],
+ const float v4[3])
{
- /* not a loop (only to be able to break out) */
- do {
- float v1_xy[2], v2_xy[2], v3_xy[2], v4_xy[2];
-
- /* first get the 2d values */
- {
- const float eps = 1e-5;
- float no_a[3], no_b[3];
- float no[3];
- float axis_mat[3][3];
- float no_scale;
- cross_tri_v3(no_a, v2, v3, v4);
- cross_tri_v3(no_b, v2, v4, v1);
-
- // printf("%p %p %p %p - %p %p\n", v1, v2, v3, v4, e->l->f, e->l->radial_next->f);
- BLI_assert((ELEM(v1, v2, v3, v4) == false) &&
- (ELEM(v2, v1, v3, v4) == false) &&
- (ELEM(v3, v1, v2, v4) == false) &&
- (ELEM(v4, v1, v2, v3) == false));
-
- add_v3_v3v3(no, no_a, no_b);
- if (UNLIKELY((no_scale = normalize_v3(no)) == 0.0f)) {
- break;
- }
-
- axis_dominant_v3_to_m3(axis_mat, no);
- mul_v2_m3v3(v1_xy, axis_mat, v1);
- mul_v2_m3v3(v2_xy, axis_mat, v2);
- mul_v2_m3v3(v3_xy, axis_mat, v3);
- mul_v2_m3v3(v4_xy, axis_mat, v4);
-
- /**
- * Check if input faces are already flipped.
- * Logic for 'signum_i' addition is:
- *
- * Accept:
- * - (1, 1) or (-1, -1): same side (common case).
- * - (-1/1, 0): one degenerate, OK since we may rotate into a valid state.
- *
- * Ignore:
- * - (-1, 1): opposite winding, ignore.
- * - ( 0, 0): both degenerate, ignore.
- *
- * \note The cross product is divided by 'no_scale'
- * so the rotation calculation is scale independent.
- */
- if (!(signum_i_ex(cross_tri_v2(v2_xy, v3_xy, v4_xy) / no_scale, eps) +
- signum_i_ex(cross_tri_v2(v2_xy, v4_xy, v1_xy) / no_scale, eps)))
- {
- break;
- }
- }
-
- /**
- * Important to lock degenerate here,
- * since the triangle pars will be projected into different 2D spaces.
- * Allowing to rotate out of a degenerate state can flip the faces (when performed iteratively).
- */
- return BLI_polyfill_beautify_quad_rotate_calc_ex(v1_xy, v2_xy, v3_xy, v4_xy, true);
- } while (false);
-
- return FLT_MAX;
+ /* not a loop (only to be able to break out) */
+ do {
+ float v1_xy[2], v2_xy[2], v3_xy[2], v4_xy[2];
+
+ /* first get the 2d values */
+ {
+ const float eps = 1e-5;
+ float no_a[3], no_b[3];
+ float no[3];
+ float axis_mat[3][3];
+ float no_scale;
+ cross_tri_v3(no_a, v2, v3, v4);
+ cross_tri_v3(no_b, v2, v4, v1);
+
+ // printf("%p %p %p %p - %p %p\n", v1, v2, v3, v4, e->l->f, e->l->radial_next->f);
+ BLI_assert((ELEM(v1, v2, v3, v4) == false) && (ELEM(v2, v1, v3, v4) == false) &&
+ (ELEM(v3, v1, v2, v4) == false) && (ELEM(v4, v1, v2, v3) == false));
+
+ add_v3_v3v3(no, no_a, no_b);
+ if (UNLIKELY((no_scale = normalize_v3(no)) == 0.0f)) {
+ break;
+ }
+
+ axis_dominant_v3_to_m3(axis_mat, no);
+ mul_v2_m3v3(v1_xy, axis_mat, v1);
+ mul_v2_m3v3(v2_xy, axis_mat, v2);
+ mul_v2_m3v3(v3_xy, axis_mat, v3);
+ mul_v2_m3v3(v4_xy, axis_mat, v4);
+
+ /**
+ * Check if input faces are already flipped.
+ * Logic for 'signum_i' addition is:
+ *
+ * Accept:
+ * - (1, 1) or (-1, -1): same side (common case).
+ * - (-1/1, 0): one degenerate, OK since we may rotate into a valid state.
+ *
+ * Ignore:
+ * - (-1, 1): opposite winding, ignore.
+ * - ( 0, 0): both degenerate, ignore.
+ *
+ * \note The cross product is divided by 'no_scale'
+ * so the rotation calculation is scale independent.
+ */
+ if (!(signum_i_ex(cross_tri_v2(v2_xy, v3_xy, v4_xy) / no_scale, eps) +
+ signum_i_ex(cross_tri_v2(v2_xy, v4_xy, v1_xy) / no_scale, eps))) {
+ break;
+ }
+ }
+
+ /**
+ * Important to lock degenerate here,
+ * since the triangle pars will be projected into different 2D spaces.
+ * Allowing to rotate out of a degenerate state can flip the faces (when performed iteratively).
+ */
+ return BLI_polyfill_beautify_quad_rotate_calc_ex(v1_xy, v2_xy, v3_xy, v4_xy, true);
+ } while (false);
+
+ return FLT_MAX;
}
-static float bm_edge_calc_rotate_beauty__angle(
- const float v1[3], const float v2[3], const float v3[3], const float v4[3])
+static float bm_edge_calc_rotate_beauty__angle(const float v1[3],
+ const float v2[3],
+ const float v3[3],
+ const float v4[3])
{
- /* not a loop (only to be able to break out) */
- do {
- float no_a[3], no_b[3];
- float angle_24, angle_13;
-
- /* edge (2-4), current state */
- normal_tri_v3(no_a, v2, v3, v4);
- normal_tri_v3(no_b, v2, v4, v1);
- angle_24 = angle_normalized_v3v3(no_a, no_b);
-
- /* edge (1-3), new state */
- /* only check new state for degenerate outcome */
- if ((normal_tri_v3(no_a, v1, v2, v3) == 0.0f) ||
- (normal_tri_v3(no_b, v1, v3, v4) == 0.0f))
- {
- break;
- }
- angle_13 = angle_normalized_v3v3(no_a, no_b);
-
- return angle_13 - angle_24;
- } while (false);
-
- return FLT_MAX;
+ /* not a loop (only to be able to break out) */
+ do {
+ float no_a[3], no_b[3];
+ float angle_24, angle_13;
+
+ /* edge (2-4), current state */
+ normal_tri_v3(no_a, v2, v3, v4);
+ normal_tri_v3(no_b, v2, v4, v1);
+ angle_24 = angle_normalized_v3v3(no_a, no_b);
+
+ /* edge (1-3), new state */
+ /* only check new state for degenerate outcome */
+ if ((normal_tri_v3(no_a, v1, v2, v3) == 0.0f) || (normal_tri_v3(no_b, v1, v3, v4) == 0.0f)) {
+ break;
+ }
+ angle_13 = angle_normalized_v3v3(no_a, no_b);
+
+ return angle_13 - angle_24;
+ } while (false);
+
+ return FLT_MAX;
}
/**
@@ -221,44 +220,47 @@ static float bm_edge_calc_rotate_beauty__angle(
*
* \return (negative number means the edge can be rotated, lager == better).
*/
-float BM_verts_calc_rotate_beauty(
- const BMVert *v1, const BMVert *v2, const BMVert *v3, const BMVert *v4,
- const short flag, const short method)
+float BM_verts_calc_rotate_beauty(const BMVert *v1,
+ const BMVert *v2,
+ const BMVert *v3,
+ const BMVert *v4,
+ const short flag,
+ const short method)
{
- /* not a loop (only to be able to break out) */
- do {
- if (flag & VERT_RESTRICT_TAG) {
- const BMVert *v_a = v1, *v_b = v3;
- if (BM_elem_flag_test(v_a, BM_ELEM_TAG) == BM_elem_flag_test(v_b, BM_ELEM_TAG)) {
- break;
- }
- }
-
- if (UNLIKELY(v1 == v3)) {
- // printf("This should never happen, but does sometimes!\n");
- break;
- }
-
- switch (method) {
- case 0:
- return bm_edge_calc_rotate_beauty__area(v1->co, v2->co, v3->co, v4->co);
- default:
- return bm_edge_calc_rotate_beauty__angle(v1->co, v2->co, v3->co, v4->co);
- }
- } while (false);
-
- return FLT_MAX;
+ /* not a loop (only to be able to break out) */
+ do {
+ if (flag & VERT_RESTRICT_TAG) {
+ const BMVert *v_a = v1, *v_b = v3;
+ if (BM_elem_flag_test(v_a, BM_ELEM_TAG) == BM_elem_flag_test(v_b, BM_ELEM_TAG)) {
+ break;
+ }
+ }
+
+ if (UNLIKELY(v1 == v3)) {
+ // printf("This should never happen, but does sometimes!\n");
+ break;
+ }
+
+ switch (method) {
+ case 0:
+ return bm_edge_calc_rotate_beauty__area(v1->co, v2->co, v3->co, v4->co);
+ default:
+ return bm_edge_calc_rotate_beauty__angle(v1->co, v2->co, v3->co, v4->co);
+ }
+ } while (false);
+
+ return FLT_MAX;
}
static float bm_edge_calc_rotate_beauty(const BMEdge *e, const short flag, const short method)
{
- const BMVert *v1, *v2, *v3, *v4;
- v1 = e->l->prev->v; /* first vert co */
- v2 = e->l->v; /* e->v1 or e->v2*/
- v3 = e->l->radial_next->prev->v; /* second vert co */
- v4 = e->l->next->v; /* e->v1 or e->v2*/
+ const BMVert *v1, *v2, *v3, *v4;
+ v1 = e->l->prev->v; /* first vert co */
+ v2 = e->l->v; /* e->v1 or e->v2*/
+ v3 = e->l->radial_next->prev->v; /* second vert co */
+ v4 = e->l->next->v; /* e->v1 or e->v2*/
- return BM_verts_calc_rotate_beauty(v1, v2, v3, v4, flag, method);
+ return BM_verts_calc_rotate_beauty(v1, v2, v3, v4, flag, method);
}
/* -------------------------------------------------------------------- */
@@ -266,83 +268,85 @@ static float bm_edge_calc_rotate_beauty(const BMEdge *e, const short flag, const
BLI_INLINE bool edge_in_array(const BMEdge *e, const BMEdge **edge_array, const int edge_array_len)
{
- const int index = BM_elem_index_get(e);
- return ((index >= 0) &&
- (index < edge_array_len) &&
- (e == edge_array[index]));
+ const int index = BM_elem_index_get(e);
+ return ((index >= 0) && (index < edge_array_len) && (e == edge_array[index]));
}
/* recalc an edge in the heap (surrounding geometry has changed) */
-static void bm_edge_update_beauty_cost_single(
- BMEdge *e, Heap *eheap, HeapNode **eheap_table, GSet **edge_state_arr,
- /* only for testing the edge is in the array */
- const BMEdge **edge_array, const int edge_array_len,
-
- const short flag, const short method)
+static void bm_edge_update_beauty_cost_single(BMEdge *e,
+ Heap *eheap,
+ HeapNode **eheap_table,
+ GSet **edge_state_arr,
+ /* only for testing the edge is in the array */
+ const BMEdge **edge_array,
+ const int edge_array_len,
+
+ const short flag,
+ const short method)
{
- if (edge_in_array(e, edge_array, edge_array_len)) {
- const int i = BM_elem_index_get(e);
- GSet *e_state_set = edge_state_arr[i];
-
- if (eheap_table[i]) {
- BLI_heap_remove(eheap, eheap_table[i]);
- eheap_table[i] = NULL;
- }
-
- /* check if we can add it back */
- BLI_assert(BM_edge_is_manifold(e) == true);
-
- /* check we're not moving back into a state we have been in before */
- if (e_state_set != NULL) {
- EdRotState e_state_alt;
- erot_state_alternate(e, &e_state_alt);
- if (BLI_gset_haskey(e_state_set, (void *)&e_state_alt)) {
- // printf(" skipping, we already have this state\n");
- return;
- }
- }
-
- {
- /* recalculate edge */
- const float cost = bm_edge_calc_rotate_beauty(e, flag, method);
- if (cost < 0.0f) {
- eheap_table[i] = BLI_heap_insert(eheap, cost, e);
- }
- else {
- eheap_table[i] = NULL;
- }
- }
- }
+ if (edge_in_array(e, edge_array, edge_array_len)) {
+ const int i = BM_elem_index_get(e);
+ GSet *e_state_set = edge_state_arr[i];
+
+ if (eheap_table[i]) {
+ BLI_heap_remove(eheap, eheap_table[i]);
+ eheap_table[i] = NULL;
+ }
+
+ /* check if we can add it back */
+ BLI_assert(BM_edge_is_manifold(e) == true);
+
+ /* check we're not moving back into a state we have been in before */
+ if (e_state_set != NULL) {
+ EdRotState e_state_alt;
+ erot_state_alternate(e, &e_state_alt);
+ if (BLI_gset_haskey(e_state_set, (void *)&e_state_alt)) {
+ // printf(" skipping, we already have this state\n");
+ return;
+ }
+ }
+
+ {
+ /* recalculate edge */
+ const float cost = bm_edge_calc_rotate_beauty(e, flag, method);
+ if (cost < 0.0f) {
+ eheap_table[i] = BLI_heap_insert(eheap, cost, e);
+ }
+ else {
+ eheap_table[i] = NULL;
+ }
+ }
+ }
}
/* we have rotated an edge, tag other edges and clear this one */
-static void bm_edge_update_beauty_cost(
- BMEdge *e, Heap *eheap, HeapNode **eheap_table, GSet **edge_state_arr,
- const BMEdge **edge_array, const int edge_array_len,
- /* only for testing the edge is in the array */
- const short flag, const short method)
+static void bm_edge_update_beauty_cost(BMEdge *e,
+ Heap *eheap,
+ HeapNode **eheap_table,
+ GSet **edge_state_arr,
+ const BMEdge **edge_array,
+ const int edge_array_len,
+ /* only for testing the edge is in the array */
+ const short flag,
+ const short method)
{
- int i;
-
- BMEdge *e_arr[4] = {
- e->l->next->e,
- e->l->prev->e,
- e->l->radial_next->next->e,
- e->l->radial_next->prev->e,
- };
-
- BLI_assert(e->l->f->len == 3 &&
- e->l->radial_next->f->len == 3);
-
- BLI_assert(BM_edge_face_count_is_equal(e, 2));
-
- for (i = 0; i < 4; i++) {
- bm_edge_update_beauty_cost_single(
- e_arr[i],
- eheap, eheap_table, edge_state_arr,
- edge_array, edge_array_len,
- flag, method);
- }
+ int i;
+
+ BMEdge *e_arr[4] = {
+ e->l->next->e,
+ e->l->prev->e,
+ e->l->radial_next->next->e,
+ e->l->radial_next->prev->e,
+ };
+
+ BLI_assert(e->l->f->len == 3 && e->l->radial_next->f->len == 3);
+
+ BLI_assert(BM_edge_face_count_is_equal(e, 2));
+
+ for (i = 0; i < 4; i++) {
+ bm_edge_update_beauty_cost_single(
+ e_arr[i], eheap, eheap_table, edge_state_arr, edge_array, edge_array_len, flag, method);
+ }
}
/* -------------------------------------------------------------------- */
@@ -351,102 +355,109 @@ static void bm_edge_update_beauty_cost(
/**
* \note This function sets the edge indices to invalid values.
*/
-void BM_mesh_beautify_fill(
- BMesh *bm, BMEdge **edge_array, const int edge_array_len,
- const short flag, const short method,
- const short oflag_edge, const short oflag_face)
+void BM_mesh_beautify_fill(BMesh *bm,
+ BMEdge **edge_array,
+ const int edge_array_len,
+ const short flag,
+ const short method,
+ const short oflag_edge,
+ const short oflag_face)
{
- Heap *eheap; /* edge heap */
- HeapNode **eheap_table; /* edge index aligned table pointing to the eheap */
+ Heap *eheap; /* edge heap */
+ HeapNode **eheap_table; /* edge index aligned table pointing to the eheap */
- GSet **edge_state_arr = MEM_callocN((size_t)edge_array_len * sizeof(GSet *), __func__);
- BLI_mempool *edge_state_pool = BLI_mempool_create(sizeof(EdRotState), 0, 512, BLI_MEMPOOL_NOP);
- int i;
+ GSet **edge_state_arr = MEM_callocN((size_t)edge_array_len * sizeof(GSet *), __func__);
+ BLI_mempool *edge_state_pool = BLI_mempool_create(sizeof(EdRotState), 0, 512, BLI_MEMPOOL_NOP);
+ int i;
#ifdef DEBUG_TIME
- TIMEIT_START(beautify_fill);
+ TIMEIT_START(beautify_fill);
#endif
- eheap = BLI_heap_new_ex((uint)edge_array_len);
- eheap_table = MEM_mallocN(sizeof(HeapNode *) * (size_t)edge_array_len, __func__);
-
- /* build heap */
- for (i = 0; i < edge_array_len; i++) {
- BMEdge *e = edge_array[i];
- const float cost = bm_edge_calc_rotate_beauty(e, flag, method);
- if (cost < 0.0f) {
- eheap_table[i] = BLI_heap_insert(eheap, cost, e);
- }
- else {
- eheap_table[i] = NULL;
- }
-
- BM_elem_index_set(e, i); /* set_dirty */
- }
- bm->elem_index_dirty |= BM_EDGE;
-
- while (BLI_heap_is_empty(eheap) == false) {
- BMEdge *e = BLI_heap_pop_min(eheap);
- i = BM_elem_index_get(e);
- eheap_table[i] = NULL;
-
- BLI_assert(BM_edge_face_count_is_equal(e, 2));
-
- e = BM_edge_rotate(bm, e, false, BM_EDGEROT_CHECK_EXISTS);
-
- BLI_assert(e == NULL || BM_edge_face_count_is_equal(e, 2));
-
- if (LIKELY(e)) {
- GSet *e_state_set = edge_state_arr[i];
-
- /* add the new state into the set so we don't move into this state again
- * note: we could add the previous state too but this isn't essential)
- * for avoiding eternal loops */
- EdRotState *e_state = BLI_mempool_alloc(edge_state_pool);
- erot_state_current(e, e_state);
- if (UNLIKELY(e_state_set == NULL)) {
- edge_state_arr[i] = e_state_set = erot_gset_new(); /* store previous state */
- }
- BLI_assert(BLI_gset_haskey(e_state_set, (void *)e_state) == false);
- BLI_gset_insert(e_state_set, e_state);
-
-
- // printf(" %d -> %d, %d\n", i, BM_elem_index_get(e->v1), BM_elem_index_get(e->v2));
-
- /* maintain the index array */
- edge_array[i] = e;
- BM_elem_index_set(e, i);
-
- /* recalculate faces connected on the heap */
- bm_edge_update_beauty_cost(e, eheap, eheap_table, edge_state_arr,
- (const BMEdge **)edge_array, edge_array_len,
- flag, method);
-
- /* update flags */
- if (oflag_edge) {
- BMO_edge_flag_enable(bm, e, oflag_edge);
- }
-
- if (oflag_face) {
- BMO_face_flag_enable(bm, e->l->f, oflag_face);
- BMO_face_flag_enable(bm, e->l->radial_next->f, oflag_face);
- }
- }
- }
-
- BLI_heap_free(eheap, NULL);
- MEM_freeN(eheap_table);
-
- for (i = 0; i < edge_array_len; i++) {
- if (edge_state_arr[i]) {
- BLI_gset_free(edge_state_arr[i], NULL);
- }
- }
-
- MEM_freeN(edge_state_arr);
- BLI_mempool_destroy(edge_state_pool);
+ eheap = BLI_heap_new_ex((uint)edge_array_len);
+ eheap_table = MEM_mallocN(sizeof(HeapNode *) * (size_t)edge_array_len, __func__);
+
+ /* build heap */
+ for (i = 0; i < edge_array_len; i++) {
+ BMEdge *e = edge_array[i];
+ const float cost = bm_edge_calc_rotate_beauty(e, flag, method);
+ if (cost < 0.0f) {
+ eheap_table[i] = BLI_heap_insert(eheap, cost, e);
+ }
+ else {
+ eheap_table[i] = NULL;
+ }
+
+ BM_elem_index_set(e, i); /* set_dirty */
+ }
+ bm->elem_index_dirty |= BM_EDGE;
+
+ while (BLI_heap_is_empty(eheap) == false) {
+ BMEdge *e = BLI_heap_pop_min(eheap);
+ i = BM_elem_index_get(e);
+ eheap_table[i] = NULL;
+
+ BLI_assert(BM_edge_face_count_is_equal(e, 2));
+
+ e = BM_edge_rotate(bm, e, false, BM_EDGEROT_CHECK_EXISTS);
+
+ BLI_assert(e == NULL || BM_edge_face_count_is_equal(e, 2));
+
+ if (LIKELY(e)) {
+ GSet *e_state_set = edge_state_arr[i];
+
+ /* add the new state into the set so we don't move into this state again
+ * note: we could add the previous state too but this isn't essential)
+ * for avoiding eternal loops */
+ EdRotState *e_state = BLI_mempool_alloc(edge_state_pool);
+ erot_state_current(e, e_state);
+ if (UNLIKELY(e_state_set == NULL)) {
+ edge_state_arr[i] = e_state_set = erot_gset_new(); /* store previous state */
+ }
+ BLI_assert(BLI_gset_haskey(e_state_set, (void *)e_state) == false);
+ BLI_gset_insert(e_state_set, e_state);
+
+ // printf(" %d -> %d, %d\n", i, BM_elem_index_get(e->v1), BM_elem_index_get(e->v2));
+
+ /* maintain the index array */
+ edge_array[i] = e;
+ BM_elem_index_set(e, i);
+
+ /* recalculate faces connected on the heap */
+ bm_edge_update_beauty_cost(e,
+ eheap,
+ eheap_table,
+ edge_state_arr,
+ (const BMEdge **)edge_array,
+ edge_array_len,
+ flag,
+ method);
+
+ /* update flags */
+ if (oflag_edge) {
+ BMO_edge_flag_enable(bm, e, oflag_edge);
+ }
+
+ if (oflag_face) {
+ BMO_face_flag_enable(bm, e->l->f, oflag_face);
+ BMO_face_flag_enable(bm, e->l->radial_next->f, oflag_face);
+ }
+ }
+ }
+
+ BLI_heap_free(eheap, NULL);
+ MEM_freeN(eheap_table);
+
+ for (i = 0; i < edge_array_len; i++) {
+ if (edge_state_arr[i]) {
+ BLI_gset_free(edge_state_arr[i], NULL);
+ }
+ }
+
+ MEM_freeN(edge_state_arr);
+ BLI_mempool_destroy(edge_state_pool);
#ifdef DEBUG_TIME
- TIMEIT_END(beautify_fill);
+ TIMEIT_END(beautify_fill);
#endif
}
diff --git a/source/blender/bmesh/tools/bmesh_beautify.h b/source/blender/bmesh/tools/bmesh_beautify.h
index f967af2bfe7..f957f0d3560 100644
--- a/source/blender/bmesh/tools/bmesh_beautify.h
+++ b/source/blender/bmesh/tools/bmesh_beautify.h
@@ -22,17 +22,22 @@
*/
enum {
- VERT_RESTRICT_TAG = (1 << 0),
+ VERT_RESTRICT_TAG = (1 << 0),
};
-void BM_mesh_beautify_fill(
- BMesh *bm, BMEdge **edge_array, const int edge_array_len,
- const short flag, const short method,
- const short oflag_edge, const short oflag_face);
+void BM_mesh_beautify_fill(BMesh *bm,
+ BMEdge **edge_array,
+ const int edge_array_len,
+ const short flag,
+ const short method,
+ const short oflag_edge,
+ const short oflag_face);
-float BM_verts_calc_rotate_beauty(
- const BMVert *v1, const BMVert *v2,
- const BMVert *v3, const BMVert *v4,
- const short flag, const short method);
+float BM_verts_calc_rotate_beauty(const BMVert *v1,
+ const BMVert *v2,
+ const BMVert *v3,
+ const BMVert *v4,
+ const short flag,
+ const short method);
#endif /* __BMESH_BEAUTIFY_H__ */
diff --git a/source/blender/bmesh/tools/bmesh_bevel.c b/source/blender/bmesh/tools/bmesh_bevel.c
index 1c77220c03c..2c304d790df 100644
--- a/source/blender/bmesh/tools/bmesh_bevel.c
+++ b/source/blender/bmesh/tools/bmesh_bevel.c
@@ -39,12 +39,12 @@
#include "eigen_capi.h"
#include "bmesh.h"
-#include "bmesh_bevel.h" /* own include */
+#include "bmesh_bevel.h" /* own include */
#include "./intern/bmesh_private.h"
-#define BEVEL_EPSILON_D 1e-6
-#define BEVEL_EPSILON 1e-6f
+#define BEVEL_EPSILON_D 1e-6
+#define BEVEL_EPSILON 1e-6f
#define BEVEL_EPSILON_SQ 1e-12f
#define BEVEL_EPSILON_BIG 1e-4f
#define BEVEL_EPSILON_BIG_SQ 1e-8f
@@ -62,31 +62,31 @@
/* Constructed vertex, sometimes later instantiated as BMVert */
typedef struct NewVert {
- BMVert *v;
- float co[3];
-// int _pad;
+ BMVert *v;
+ float co[3];
+ // int _pad;
} NewVert;
struct BoundVert;
/* Data for one end of an edge involved in a bevel */
typedef struct EdgeHalf {
- struct EdgeHalf *next, *prev; /* in CCW order */
- BMEdge *e; /* original mesh edge */
- BMFace *fprev; /* face between this edge and previous, if any */
- BMFace *fnext; /* face between this edge and next, if any */
- struct BoundVert *leftv; /* left boundary vert (looking along edge to end) */
- struct BoundVert *rightv; /* right boundary vert, if beveled */
- int profile_index; /* offset into profile to attach non-beveled edge */
- int seg; /* how many segments for the bevel */
- float offset_l; /* offset for this edge, on left side */
- float offset_r; /* offset for this edge, on right side */
- float offset_l_spec; /* user specification for offset_l */
- float offset_r_spec; /* user specification for offset_r */
- bool is_bev; /* is this edge beveled? */
- bool is_rev; /* is e->v2 the vertex at this end? */
- bool is_seam; /* is e a seam for custom loopdata (e.g., UVs)? */
-// int _pad;
+ struct EdgeHalf *next, *prev; /* in CCW order */
+ BMEdge *e; /* original mesh edge */
+ BMFace *fprev; /* face between this edge and previous, if any */
+ BMFace *fnext; /* face between this edge and next, if any */
+ struct BoundVert *leftv; /* left boundary vert (looking along edge to end) */
+ struct BoundVert *rightv; /* right boundary vert, if beveled */
+ int profile_index; /* offset into profile to attach non-beveled edge */
+ int seg; /* how many segments for the bevel */
+ float offset_l; /* offset for this edge, on left side */
+ float offset_r; /* offset for this edge, on right side */
+ float offset_l_spec; /* user specification for offset_l */
+ float offset_r_spec; /* user specification for offset_r */
+ bool is_bev; /* is this edge beveled? */
+ bool is_rev; /* is e->v2 the vertex at this end? */
+ bool is_seam; /* is e a seam for custom loopdata (e.g., UVs)? */
+ // int _pad;
} EdgeHalf;
/* Profile specification.
@@ -103,15 +103,15 @@ typedef struct EdgeHalf {
* in prof_co_2.
*/
typedef struct Profile {
- float super_r; /* superellipse r parameter */
- float coa[3]; /* start control point for profile */
- float midco[3]; /* mid control point for profile */
- float cob[3]; /* end control point for profile */
- float plane_no[3]; /* normal of plane to project to */
- float plane_co[3]; /* coordinate on plane to project to */
- float proj_dir[3]; /* direction of projection line */
- float *prof_co; /* seg+1 profile coordinates (triples of floats) */
- float *prof_co_2; /* like prof_co, but for seg power of 2 >= seg */
+ float super_r; /* superellipse r parameter */
+ float coa[3]; /* start control point for profile */
+ float midco[3]; /* mid control point for profile */
+ float cob[3]; /* end control point for profile */
+ float plane_no[3]; /* normal of plane to project to */
+ float plane_co[3]; /* coordinate on plane to project to */
+ float proj_dir[3]; /* direction of projection line */
+ float *prof_co; /* seg+1 profile coordinates (triples of floats) */
+ float *prof_co_2; /* like prof_co, but for seg power of 2 >= seg */
} Profile;
#define PRO_SQUARE_R 1e4f
#define PRO_CIRCLE_R 2.0f
@@ -122,102 +122,103 @@ typedef struct Profile {
* get even spacing on superellipse for current BevelParams seg
* and pro_super_r. */
typedef struct ProfileSpacing {
- double *xvals; /* seg+1 x values */
- double *xvals_2; /* seg_2+1 x values, seg_2 = power of 2 >= seg */
- double *yvals; /* seg+1 y values */
- double *yvals_2; /* seg_2+1 y values, seg_2 = power of 2 >= seg */
- int seg_2; /* the seg_2 value */
+ double *xvals; /* seg+1 x values */
+ double *xvals_2; /* seg_2+1 x values, seg_2 = power of 2 >= seg */
+ double *yvals; /* seg+1 y values */
+ double *yvals_2; /* seg_2+1 y values, seg_2 = power of 2 >= seg */
+ int seg_2; /* the seg_2 value */
} ProfileSpacing;
/* An element in a cyclic boundary of a Vertex Mesh (VMesh) */
typedef struct BoundVert {
- struct BoundVert *next, *prev; /* in CCW order */
- NewVert nv;
- EdgeHalf *efirst; /* first of edges attached here: in CCW order */
- EdgeHalf *elast;
- EdgeHalf *eon; /* the "edge between" that this is on, in offset_on_edge_between case */
- EdgeHalf *ebev; /* beveled edge whose left side is attached here, if any */
- int index; /* used for vmesh indexing */
- float sinratio; /* when eon set, ratio of sines of angles to eon edge */
- struct BoundVert *adjchain; /* adjustment chain or cycle link pointer */
- Profile profile; /* edge profile between this and next BoundVert */
- bool any_seam; /* are any of the edges attached here seams? */
- bool visited; /* used during delta adjust pass */
- bool is_arc_start; /* this boundvert begins an arc profile */
- bool is_patch_start; /* this boundvert begins a patch profile */
- int seam_len; /* length of seam starting from current boundvert to next boundvert with ccw ordering */
- int sharp_len; /* Same as seam_len but defines length of sharp edges */
-// int _pad;
+ struct BoundVert *next, *prev; /* in CCW order */
+ NewVert nv;
+ EdgeHalf *efirst; /* first of edges attached here: in CCW order */
+ EdgeHalf *elast;
+ EdgeHalf *eon; /* the "edge between" that this is on, in offset_on_edge_between case */
+ EdgeHalf *ebev; /* beveled edge whose left side is attached here, if any */
+ int index; /* used for vmesh indexing */
+ float sinratio; /* when eon set, ratio of sines of angles to eon edge */
+ struct BoundVert *adjchain; /* adjustment chain or cycle link pointer */
+ Profile profile; /* edge profile between this and next BoundVert */
+ bool any_seam; /* are any of the edges attached here seams? */
+ bool visited; /* used during delta adjust pass */
+ bool is_arc_start; /* this boundvert begins an arc profile */
+ bool is_patch_start; /* this boundvert begins a patch profile */
+ int seam_len; /* length of seam starting from current boundvert to next boundvert with ccw ordering */
+ int sharp_len; /* Same as seam_len but defines length of sharp edges */
+ // int _pad;
} BoundVert;
/* Mesh structure replacing a vertex */
typedef struct VMesh {
- NewVert *mesh; /* allocated array - size and structure depends on kind */
- BoundVert *boundstart; /* start of boundary double-linked list */
- int count; /* number of vertices in the boundary */
- int seg; /* common # of segments for segmented edges */
- enum {
- M_NONE, /* no polygon mesh needed */
- M_POLY, /* a simple polygon */
- M_ADJ, /* "adjacent edges" mesh pattern */
- M_TRI_FAN, /* a simple polygon - fan filled */
- } mesh_kind;
-// int _pad;
+ NewVert *mesh; /* allocated array - size and structure depends on kind */
+ BoundVert *boundstart; /* start of boundary double-linked list */
+ int count; /* number of vertices in the boundary */
+ int seg; /* common # of segments for segmented edges */
+ enum {
+ M_NONE, /* no polygon mesh needed */
+ M_POLY, /* a simple polygon */
+ M_ADJ, /* "adjacent edges" mesh pattern */
+ M_TRI_FAN, /* a simple polygon - fan filled */
+ } mesh_kind;
+ // int _pad;
} VMesh;
/* Data for a vertex involved in a bevel */
typedef struct BevVert {
- BMVert *v; /* original mesh vertex */
- int edgecount; /* total number of edges around the vertex (excluding wire edges if edge beveling) */
- int selcount; /* number of selected edges around the vertex */
- int wirecount; /* count of wire edges */
- float offset; /* offset for this vertex, if vertex_only bevel */
- bool any_seam; /* any seams on attached edges? */
- bool visited; /* used in graph traversal */
- EdgeHalf *edges; /* array of size edgecount; CCW order from vertex normal side */
- BMEdge **wire_edges; /* array of size wirecount of wire edges */
- VMesh *vmesh; /* mesh structure for replacing vertex */
+ BMVert *v; /* original mesh vertex */
+ int edgecount; /* total number of edges around the vertex (excluding wire edges if edge beveling) */
+ int selcount; /* number of selected edges around the vertex */
+ int wirecount; /* count of wire edges */
+ float offset; /* offset for this vertex, if vertex_only bevel */
+ bool any_seam; /* any seams on attached edges? */
+ bool visited; /* used in graph traversal */
+ EdgeHalf *edges; /* array of size edgecount; CCW order from vertex normal side */
+ BMEdge **wire_edges; /* array of size wirecount of wire edges */
+ VMesh *vmesh; /* mesh structure for replacing vertex */
} BevVert;
/* face classification: note depend on F_RECON > F_EDGE > F_VERT */
typedef enum {
- F_NONE, /* used when there is no face at all */
- F_ORIG, /* original face, not touched */
- F_VERT, /* face for construction aroun a vert */
- F_EDGE, /* face for a beveled edge */
- F_RECON, /* reconstructed original face with some new verts */
+ F_NONE, /* used when there is no face at all */
+ F_ORIG, /* original face, not touched */
+ F_VERT, /* face for construction aroun a vert */
+ F_EDGE, /* face for a beveled edge */
+ F_RECON, /* reconstructed original face with some new verts */
} FKind;
// static const char* fkind_names[] = {"F_NONE", "F_ORIG", "F_VERT", "F_EDGE", "F_RECON"}; /* DEBUG */
/* Bevel parameters and state */
typedef struct BevelParams {
- GHash *vert_hash; /* records BevVerts made: key BMVert*, value BevVert* */
- GHash *face_hash; /* records new faces: key BMFace*, value one of {VERT/EDGE/RECON}_POLY */
- MemArena *mem_arena; /* use for all allocs while bevel runs, if we need to free we can switch to mempool */
- ProfileSpacing pro_spacing; /* parameter values for evenly spaced profiles */
-
- float offset; /* blender units to offset each side of a beveled edge */
- int offset_type; /* how offset is measured; enum defined in bmesh_operators.h */
- int seg; /* number of segments in beveled edge profile */
- float profile; /* user profile setting */
- float pro_super_r; /* superellipse parameter for edge profile */
- bool vertex_only; /* bevel vertices only */
- bool use_weights; /* bevel amount affected by weights on edges or verts */
- bool loop_slide; /* should bevel prefer to slide along edges rather than keep widths spec? */
- bool limit_offset; /* should offsets be limited by collisions? */
- bool offset_adjust; /* should offsets be adjusted to try to get even widths? */
- bool mark_seam; /* should we propagate seam edge markings? */
- bool mark_sharp; /* should we propagate sharp edge markings? */
- bool harden_normals; /* should we harden normals? */
- const struct MDeformVert *dvert; /* vertex group array, maybe set if vertex_only */
- int vertex_group; /* vertex group index, maybe set if vertex_only */
- int mat_nr; /* if >= 0, material number for bevel; else material comes from adjacent faces */
- int face_strength_mode; /* setting face strength if > 0 */
- int miter_outer; /* what kind of miter pattern to use on reflex angles */
- int miter_inner; /* what kind of miter pattern to use on non-reflex angles */
- float spread; /* amount to spread when doing inside miter */
- float smoothresh; /* mesh's smoothresh, used if hardening */
+ GHash *vert_hash; /* records BevVerts made: key BMVert*, value BevVert* */
+ GHash *face_hash; /* records new faces: key BMFace*, value one of {VERT/EDGE/RECON}_POLY */
+ MemArena *
+ mem_arena; /* use for all allocs while bevel runs, if we need to free we can switch to mempool */
+ ProfileSpacing pro_spacing; /* parameter values for evenly spaced profiles */
+
+ float offset; /* blender units to offset each side of a beveled edge */
+ int offset_type; /* how offset is measured; enum defined in bmesh_operators.h */
+ int seg; /* number of segments in beveled edge profile */
+ float profile; /* user profile setting */
+ float pro_super_r; /* superellipse parameter for edge profile */
+ bool vertex_only; /* bevel vertices only */
+ bool use_weights; /* bevel amount affected by weights on edges or verts */
+ bool loop_slide; /* should bevel prefer to slide along edges rather than keep widths spec? */
+ bool limit_offset; /* should offsets be limited by collisions? */
+ bool offset_adjust; /* should offsets be adjusted to try to get even widths? */
+ bool mark_seam; /* should we propagate seam edge markings? */
+ bool mark_sharp; /* should we propagate sharp edge markings? */
+ bool harden_normals; /* should we harden normals? */
+ const struct MDeformVert *dvert; /* vertex group array, maybe set if vertex_only */
+ int vertex_group; /* vertex group index, maybe set if vertex_only */
+ int mat_nr; /* if >= 0, material number for bevel; else material comes from adjacent faces */
+ int face_strength_mode; /* setting face strength if > 0 */
+ int miter_outer; /* what kind of miter pattern to use on reflex angles */
+ int miter_inner; /* what kind of miter pattern to use on non-reflex angles */
+ float spread; /* amount to spread when doing inside miter */
+ float smoothresh; /* mesh's smoothresh, used if hardening */
} BevelParams;
// #pragma GCC diagnostic ignored "-Wpadded"
@@ -231,7 +232,7 @@ static int bev_debug_flags = 0;
#define DEBUG_OLD_FLAT_MID (bev_debug_flags & 4)
/* use the unused _BM_ELEM_TAG_ALT flag to flag the 'long' loops (parallel to beveled edge) of edge-polygons */
-#define BM_ELEM_LONG_TAG (1<<6)
+#define BM_ELEM_LONG_TAG (1 << 6)
/* these flag values will get set on geom we want to return in 'out' slots for edges and verts */
#define EDGE_OUT 4
@@ -240,81 +241,81 @@ static int bev_debug_flags = 0;
/* If we're called from the modifier, tool flags aren't available, but don't need output geometry */
static void flag_out_edge(BMesh *bm, BMEdge *bme)
{
- if (bm->use_toolflags) {
- BMO_edge_flag_enable(bm, bme, EDGE_OUT);
- }
+ if (bm->use_toolflags) {
+ BMO_edge_flag_enable(bm, bme, EDGE_OUT);
+ }
}
static void flag_out_vert(BMesh *bm, BMVert *bmv)
{
- if (bm->use_toolflags) {
- BMO_vert_flag_enable(bm, bmv, VERT_OUT);
- }
+ if (bm->use_toolflags) {
+ BMO_vert_flag_enable(bm, bmv, VERT_OUT);
+ }
}
static void disable_flag_out_edge(BMesh *bm, BMEdge *bme)
{
- if (bm->use_toolflags) {
- BMO_edge_flag_disable(bm, bme, EDGE_OUT);
- }
+ if (bm->use_toolflags) {
+ BMO_edge_flag_disable(bm, bme, EDGE_OUT);
+ }
}
static void record_face_kind(BevelParams *bp, BMFace *f, FKind fkind)
{
- if (bp->face_hash) {
- BLI_ghash_insert(bp->face_hash, f, POINTER_FROM_INT(fkind));
- }
+ if (bp->face_hash) {
+ BLI_ghash_insert(bp->face_hash, f, POINTER_FROM_INT(fkind));
+ }
}
static FKind get_face_kind(BevelParams *bp, BMFace *f)
{
- void *val = BLI_ghash_lookup(bp->face_hash, f);
- return val ? (FKind)POINTER_AS_INT(val) : F_ORIG;
+ void *val = BLI_ghash_lookup(bp->face_hash, f);
+ return val ? (FKind)POINTER_AS_INT(val) : F_ORIG;
}
/* Are d1 and d2 parallel or nearly so? */
static bool nearly_parallel(const float d1[3], const float d2[3])
{
- float ang;
+ float ang;
- ang = angle_v3v3(d1, d2);
- return (fabsf(ang) < BEVEL_EPSILON_ANG) || (fabsf(ang - (float)M_PI) < BEVEL_EPSILON_ANG);
+ ang = angle_v3v3(d1, d2);
+ return (fabsf(ang) < BEVEL_EPSILON_ANG) || (fabsf(ang - (float)M_PI) < BEVEL_EPSILON_ANG);
}
/* Make a new BoundVert of the given kind, insert it at the end of the circular linked
* list with entry point bv->boundstart, and return it. */
static BoundVert *add_new_bound_vert(MemArena *mem_arena, VMesh *vm, const float co[3])
{
- BoundVert *ans = (BoundVert *)BLI_memarena_alloc(mem_arena, sizeof(BoundVert));
-
- copy_v3_v3(ans->nv.co, co);
- if (!vm->boundstart) {
- ans->index = 0;
- vm->boundstart = ans;
- ans->next = ans->prev = ans;
- }
- else {
- BoundVert *tail = vm->boundstart->prev;
- ans->index = tail->index + 1;
- ans->prev = tail;
- ans->next = vm->boundstart;
- tail->next = ans;
- vm->boundstart->prev = ans;
- }
- ans->profile.super_r = PRO_LINE_R;
- ans->adjchain = NULL;
- ans->sinratio = 1.0f;
- ans->visited = false;
- ans->any_seam = false;
- ans->is_arc_start = false;
- ans->is_patch_start = false;
- vm->count++;
- return ans;
+ BoundVert *ans = (BoundVert *)BLI_memarena_alloc(mem_arena, sizeof(BoundVert));
+
+ copy_v3_v3(ans->nv.co, co);
+ if (!vm->boundstart) {
+ ans->index = 0;
+ vm->boundstart = ans;
+ ans->next = ans->prev = ans;
+ }
+ else {
+ BoundVert *tail = vm->boundstart->prev;
+ ans->index = tail->index + 1;
+ ans->prev = tail;
+ ans->next = vm->boundstart;
+ tail->next = ans;
+ vm->boundstart->prev = ans;
+ }
+ ans->profile.super_r = PRO_LINE_R;
+ ans->adjchain = NULL;
+ ans->sinratio = 1.0f;
+ ans->visited = false;
+ ans->any_seam = false;
+ ans->is_arc_start = false;
+ ans->is_patch_start = false;
+ vm->count++;
+ return ans;
}
BLI_INLINE void adjust_bound_vert(BoundVert *bv, const float co[3])
{
- copy_v3_v3(bv->nv.co, co);
+ copy_v3_v3(bv->nv.co, co);
}
/* Mesh verts are indexed (i, j, k) where
@@ -324,49 +325,47 @@ BLI_INLINE void adjust_bound_vert(BoundVert *bv, const float co[3])
* Not all of these are used, and some will share BMVerts */
static NewVert *mesh_vert(VMesh *vm, int i, int j, int k)
{
- int nj = (vm->seg / 2) + 1;
- int nk = vm->seg + 1;
+ int nj = (vm->seg / 2) + 1;
+ int nk = vm->seg + 1;
- return &vm->mesh[i * nk * nj + j * nk + k];
+ return &vm->mesh[i * nk * nj + j * nk + k];
}
static void create_mesh_bmvert(BMesh *bm, VMesh *vm, int i, int j, int k, BMVert *eg)
{
- NewVert *nv = mesh_vert(vm, i, j, k);
- nv->v = BM_vert_create(bm, nv->co, eg, BM_CREATE_NOP);
- BM_elem_flag_disable(nv->v, BM_ELEM_TAG);
- flag_out_vert(bm, nv->v);
+ NewVert *nv = mesh_vert(vm, i, j, k);
+ nv->v = BM_vert_create(bm, nv->co, eg, BM_CREATE_NOP);
+ BM_elem_flag_disable(nv->v, BM_ELEM_TAG);
+ flag_out_vert(bm, nv->v);
}
-static void copy_mesh_vert(
- VMesh *vm, int ito, int jto, int kto,
- int ifrom, int jfrom, int kfrom)
+static void copy_mesh_vert(VMesh *vm, int ito, int jto, int kto, int ifrom, int jfrom, int kfrom)
{
- NewVert *nvto, *nvfrom;
+ NewVert *nvto, *nvfrom;
- nvto = mesh_vert(vm, ito, jto, kto);
- nvfrom = mesh_vert(vm, ifrom, jfrom, kfrom);
- nvto->v = nvfrom->v;
- copy_v3_v3(nvto->co, nvfrom->co);
+ nvto = mesh_vert(vm, ito, jto, kto);
+ nvfrom = mesh_vert(vm, ifrom, jfrom, kfrom);
+ nvto->v = nvfrom->v;
+ copy_v3_v3(nvto->co, nvfrom->co);
}
/* find the EdgeHalf in bv's array that has edge bme */
static EdgeHalf *find_edge_half(BevVert *bv, BMEdge *bme)
{
- int i;
-
- for (i = 0; i < bv->edgecount; i++) {
- if (bv->edges[i].e == bme) {
- return &bv->edges[i];
- }
- }
- return NULL;
+ int i;
+
+ for (i = 0; i < bv->edgecount; i++) {
+ if (bv->edges[i].e == bme) {
+ return &bv->edges[i];
+ }
+ }
+ return NULL;
}
/* find the BevVert corresponding to BMVert bmv */
static BevVert *find_bevvert(BevelParams *bp, BMVert *bmv)
{
- return BLI_ghash_lookup(bp->vert_hash, bmv);
+ return BLI_ghash_lookup(bp->vert_hash, bmv);
}
/* Find the EdgeHalf representing the other end of e->e.
@@ -374,56 +373,56 @@ static BevVert *find_bevvert(BevelParams *bp, BMVert *bmv)
* That may not have been constructed yet, in which case return NULL. */
static EdgeHalf *find_other_end_edge_half(BevelParams *bp, EdgeHalf *e, BevVert **r_bvother)
{
- BevVert *bvo;
- EdgeHalf *eother;
-
- bvo = find_bevvert(bp, e->is_rev ? e->e->v1 : e->e->v2);
- if (bvo) {
- if (r_bvother) {
- *r_bvother = bvo;
- }
- eother = find_edge_half(bvo, e->e);
- BLI_assert(eother != NULL);
- return eother;
- }
- else if (r_bvother) {
- *r_bvother = NULL;
- }
- return NULL;
+ BevVert *bvo;
+ EdgeHalf *eother;
+
+ bvo = find_bevvert(bp, e->is_rev ? e->e->v1 : e->e->v2);
+ if (bvo) {
+ if (r_bvother) {
+ *r_bvother = bvo;
+ }
+ eother = find_edge_half(bvo, e->e);
+ BLI_assert(eother != NULL);
+ return eother;
+ }
+ else if (r_bvother) {
+ *r_bvother = NULL;
+ }
+ return NULL;
}
/* Return the next EdgeHalf after from_e that is beveled.
* If from_e is NULL, find the first beveled edge. */
static EdgeHalf *next_bev(BevVert *bv, EdgeHalf *from_e)
{
- EdgeHalf *e;
-
- if (from_e == NULL) {
- from_e = &bv->edges[bv->edgecount - 1];
- }
- e = from_e;
- do {
- if (e->is_bev) {
- return e;
- }
- } while ((e = e->next) != from_e);
- return NULL;
+ EdgeHalf *e;
+
+ if (from_e == NULL) {
+ from_e = &bv->edges[bv->edgecount - 1];
+ }
+ e = from_e;
+ do {
+ if (e->is_bev) {
+ return e;
+ }
+ } while ((e = e->next) != from_e);
+ return NULL;
}
/* return count of edges between e1 and e2 when going around bv CCW */
static int count_ccw_edges_between(EdgeHalf *e1, EdgeHalf *e2)
{
- int cnt = 0;
- EdgeHalf *e = e1;
-
- do {
- if (e == e2) {
- break;
- }
- e = e->next;
- cnt++;
- } while (e != e1);
- return cnt;
+ int cnt = 0;
+ EdgeHalf *e = e1;
+
+ do {
+ if (e == e2) {
+ break;
+ }
+ e = e->next;
+ cnt++;
+ } while (e != e1);
+ return cnt;
}
/* Assume bme1 and bme2 both share some vert. Do they share a face?
@@ -431,15 +430,15 @@ static int count_ccw_edges_between(EdgeHalf *e1, EdgeHalf *e2)
* where the next or previous edge in the face must be bme2. */
static bool edges_face_connected_at_vert(BMEdge *bme1, BMEdge *bme2)
{
- BMLoop *l;
- BMIter iter;
-
- BM_ITER_ELEM(l, &iter, bme1, BM_LOOPS_OF_EDGE) {
- if (l->prev->e == bme2 || l->next->e == bme2) {
- return true;
- }
- }
- return false;
+ BMLoop *l;
+ BMIter iter;
+
+ BM_ITER_ELEM (l, &iter, bme1, BM_LOOPS_OF_EDGE) {
+ if (l->prev->e == bme2 || l->next->e == bme2) {
+ return true;
+ }
+ }
+ return false;
}
/* Return a good representative face (for materials, etc.) for faces
@@ -449,56 +448,56 @@ static bool edges_face_connected_at_vert(BMEdge *bme1, BMEdge *bme2)
* possible frep, return the other one in that parameter. */
static BMFace *boundvert_rep_face(BoundVert *v, BMFace **r_fother)
{
- BMFace *frep, *frep2;
-
- frep2 = NULL;
- if (v->ebev) {
- frep = v->ebev->fprev;
- if (v->efirst->fprev != frep) {
- frep2 = v->efirst->fprev;
- }
- }
- else if (v->efirst) {
- frep = v->efirst->fprev;
- if (frep) {
- if (v->elast->fnext != frep) {
- frep2 = v->elast->fnext;
- }
- else if (v->efirst->fnext != frep) {
- frep2 = v->efirst->fnext;
- }
- else if (v->elast->fprev != frep) {
- frep2 = v->efirst->fprev;
- }
- }
- else if (v->efirst->fnext) {
- frep = v->efirst->fnext;
- if (v->elast->fnext != frep) {
- frep2 = v->elast->fnext;
- }
- }
- else if (v->elast->fprev) {
- frep = v->elast->fprev;
- }
- }
- else if (v->prev->elast) {
- frep = v->prev->elast->fnext;
- if (v->next->efirst) {
- if (frep) {
- frep2 = v->next->efirst->fprev;
- }
- else {
- frep = v->next->efirst->fprev;
- }
- }
- }
- else {
- frep = NULL;
- }
- if (r_fother) {
- *r_fother = frep2;
- }
- return frep;
+ BMFace *frep, *frep2;
+
+ frep2 = NULL;
+ if (v->ebev) {
+ frep = v->ebev->fprev;
+ if (v->efirst->fprev != frep) {
+ frep2 = v->efirst->fprev;
+ }
+ }
+ else if (v->efirst) {
+ frep = v->efirst->fprev;
+ if (frep) {
+ if (v->elast->fnext != frep) {
+ frep2 = v->elast->fnext;
+ }
+ else if (v->efirst->fnext != frep) {
+ frep2 = v->efirst->fnext;
+ }
+ else if (v->elast->fprev != frep) {
+ frep2 = v->efirst->fprev;
+ }
+ }
+ else if (v->efirst->fnext) {
+ frep = v->efirst->fnext;
+ if (v->elast->fnext != frep) {
+ frep2 = v->elast->fnext;
+ }
+ }
+ else if (v->elast->fprev) {
+ frep = v->elast->fprev;
+ }
+ }
+ else if (v->prev->elast) {
+ frep = v->prev->elast->fnext;
+ if (v->next->efirst) {
+ if (frep) {
+ frep2 = v->next->efirst->fprev;
+ }
+ else {
+ frep = v->next->efirst->fprev;
+ }
+ }
+ }
+ else {
+ frep = NULL;
+ }
+ if (r_fother) {
+ *r_fother = frep2;
+ }
+ return frep;
}
/**
@@ -511,303 +510,318 @@ static BMFace *boundvert_rep_face(BoundVert *v, BMFace **r_fother)
*
* \note ALL face creation goes through this function, this is important to keep!
*/
-static BMFace *bev_create_ngon(
- BMesh *bm, BMVert **vert_arr, const int totv,
- BMFace **face_arr, BMFace *facerep, BMEdge **edge_arr,
- int mat_nr, bool do_interp)
+static BMFace *bev_create_ngon(BMesh *bm,
+ BMVert **vert_arr,
+ const int totv,
+ BMFace **face_arr,
+ BMFace *facerep,
+ BMEdge **edge_arr,
+ int mat_nr,
+ bool do_interp)
{
- BMIter iter;
- BMLoop *l;
- BMFace *f, *interp_f;
- BMEdge *bme;
- float save_co[3];
- int i;
-
- f = BM_face_create_verts(bm, vert_arr, totv, facerep, BM_CREATE_NOP, true);
-
- if ((facerep || (face_arr && face_arr[0])) && f) {
- BM_elem_attrs_copy(bm, bm, facerep ? facerep : face_arr[0], f);
- if (do_interp) {
- i = 0;
- BM_ITER_ELEM (l, &iter, f, BM_LOOPS_OF_FACE) {
- if (face_arr) {
- /* assume loops of created face are in same order as verts */
- BLI_assert(l->v == vert_arr[i]);
- interp_f = face_arr[i];
- }
- else {
- interp_f = facerep;
- }
- if (interp_f) {
- bme = NULL;
- if (edge_arr) {
- bme = edge_arr[i];
- }
- if (bme) {
- copy_v3_v3(save_co, l->v->co);
- closest_to_line_segment_v3(l->v->co, save_co, bme->v1->co, bme->v2->co);
- }
- BM_loop_interp_from_face(bm, l, interp_f, true, true);
- if (bme) {
- copy_v3_v3(l->v->co, save_co);
- }
- }
- i++;
- }
- }
- }
-
- /* not essential for bevels own internal logic,
- * this is done so the operator can select newly created geometry */
- if (f) {
- BM_elem_flag_enable(f, BM_ELEM_TAG);
- BM_ITER_ELEM(bme, &iter, f, BM_EDGES_OF_FACE) {
- flag_out_edge(bm, bme);
- }
- }
-
- if (mat_nr >= 0) {
- f->mat_nr = mat_nr;
- }
- return f;
+ BMIter iter;
+ BMLoop *l;
+ BMFace *f, *interp_f;
+ BMEdge *bme;
+ float save_co[3];
+ int i;
+
+ f = BM_face_create_verts(bm, vert_arr, totv, facerep, BM_CREATE_NOP, true);
+
+ if ((facerep || (face_arr && face_arr[0])) && f) {
+ BM_elem_attrs_copy(bm, bm, facerep ? facerep : face_arr[0], f);
+ if (do_interp) {
+ i = 0;
+ BM_ITER_ELEM (l, &iter, f, BM_LOOPS_OF_FACE) {
+ if (face_arr) {
+ /* assume loops of created face are in same order as verts */
+ BLI_assert(l->v == vert_arr[i]);
+ interp_f = face_arr[i];
+ }
+ else {
+ interp_f = facerep;
+ }
+ if (interp_f) {
+ bme = NULL;
+ if (edge_arr) {
+ bme = edge_arr[i];
+ }
+ if (bme) {
+ copy_v3_v3(save_co, l->v->co);
+ closest_to_line_segment_v3(l->v->co, save_co, bme->v1->co, bme->v2->co);
+ }
+ BM_loop_interp_from_face(bm, l, interp_f, true, true);
+ if (bme) {
+ copy_v3_v3(l->v->co, save_co);
+ }
+ }
+ i++;
+ }
+ }
+ }
+
+ /* not essential for bevels own internal logic,
+ * this is done so the operator can select newly created geometry */
+ if (f) {
+ BM_elem_flag_enable(f, BM_ELEM_TAG);
+ BM_ITER_ELEM (bme, &iter, f, BM_EDGES_OF_FACE) {
+ flag_out_edge(bm, bme);
+ }
+ }
+
+ if (mat_nr >= 0) {
+ f->mat_nr = mat_nr;
+ }
+ return f;
}
-static BMFace *bev_create_quad(
- BMesh *bm, BMVert *v1, BMVert *v2, BMVert *v3, BMVert *v4,
- BMFace *f1, BMFace *f2, BMFace *f3, BMFace *f4,
- int mat_nr)
+static BMFace *bev_create_quad(BMesh *bm,
+ BMVert *v1,
+ BMVert *v2,
+ BMVert *v3,
+ BMVert *v4,
+ BMFace *f1,
+ BMFace *f2,
+ BMFace *f3,
+ BMFace *f4,
+ int mat_nr)
{
- BMVert *varr[4] = {v1, v2, v3, v4};
- BMFace *farr[4] = {f1, f2, f3, f4};
- return bev_create_ngon(bm, varr, 4, farr, f1, NULL, mat_nr, true);
+ BMVert *varr[4] = {v1, v2, v3, v4};
+ BMFace *farr[4] = {f1, f2, f3, f4};
+ return bev_create_ngon(bm, varr, 4, farr, f1, NULL, mat_nr, true);
}
-static BMFace *bev_create_quad_ex(
- BMesh *bm, BMVert *v1, BMVert *v2, BMVert *v3, BMVert *v4,
- BMFace *f1, BMFace *f2, BMFace *f3, BMFace *f4,
- BMEdge *e1, BMEdge *e2, BMEdge *e3, BMEdge *e4,
- int mat_nr)
+static BMFace *bev_create_quad_ex(BMesh *bm,
+ BMVert *v1,
+ BMVert *v2,
+ BMVert *v3,
+ BMVert *v4,
+ BMFace *f1,
+ BMFace *f2,
+ BMFace *f3,
+ BMFace *f4,
+ BMEdge *e1,
+ BMEdge *e2,
+ BMEdge *e3,
+ BMEdge *e4,
+ int mat_nr)
{
- BMVert *varr[4] = {v1, v2, v3, v4};
- BMFace *farr[4] = {f1, f2, f3, f4};
- BMEdge *earr[4] = {e1, e2, e3, e4};
- return bev_create_ngon(bm, varr, 4, farr, f1, earr, mat_nr, true);
+ BMVert *varr[4] = {v1, v2, v3, v4};
+ BMFace *farr[4] = {f1, f2, f3, f4};
+ BMEdge *earr[4] = {e1, e2, e3, e4};
+ return bev_create_ngon(bm, varr, 4, farr, f1, earr, mat_nr, true);
}
/* Is Loop layer layer_index contiguous across shared vertex of l1 and l2? */
-static bool contig_ldata_across_loops(
- BMesh *bm, BMLoop *l1, BMLoop *l2,
- int layer_index)
+static bool contig_ldata_across_loops(BMesh *bm, BMLoop *l1, BMLoop *l2, int layer_index)
{
- const int offset = bm->ldata.layers[layer_index].offset;
- const int type = bm->ldata.layers[layer_index].type;
+ const int offset = bm->ldata.layers[layer_index].offset;
+ const int type = bm->ldata.layers[layer_index].type;
- return CustomData_data_equals(type,
- (char *)l1->head.data + offset,
- (char *)l2->head.data + offset);
+ return CustomData_data_equals(
+ type, (char *)l1->head.data + offset, (char *)l2->head.data + offset);
}
/* Are all loop layers with have math (e.g., UVs) contiguous from face f1 to face f2 across edge e? */
static bool contig_ldata_across_edge(BMesh *bm, BMEdge *e, BMFace *f1, BMFace *f2)
{
- BMLoop *lef1, *lef2;
- BMLoop *lv1f1, *lv1f2, *lv2f1, *lv2f2;
- BMVert *v1, *v2;
- int i;
-
- if (bm->ldata.totlayer == 0) {
- return true;
- }
-
- v1 = e->v1;
- v2 = e->v2;
- if (!BM_edge_loop_pair(e, &lef1, &lef2)) {
- return false;
- }
- if (lef1->f == f2) {
- SWAP(BMLoop *, lef1, lef2);
- }
-
- if (lef1->v == v1) {
- lv1f1 = lef1;
- lv2f1 = BM_face_other_edge_loop(f1, e, v2);
- }
- else {
- lv2f1 = lef1;
- lv1f1 = BM_face_other_edge_loop(f1, e, v1);
- }
-
- if (lef2->v == v1) {
- lv1f2 = lef2;
- lv2f2 = BM_face_other_edge_loop(f2, e, v2);
- }
- else {
- lv2f2 = lef2;
- lv1f2 = BM_face_other_edge_loop(f2, e, v1);
- }
-
- for (i = 0; i < bm->ldata.totlayer; i++) {
- if (CustomData_layer_has_math(&bm->ldata, i) &&
- (!contig_ldata_across_loops(bm, lv1f1, lv1f2, i) ||
- !contig_ldata_across_loops(bm, lv2f1, lv2f2, i)))
- {
- return false;
- }
- }
- return true;
+ BMLoop *lef1, *lef2;
+ BMLoop *lv1f1, *lv1f2, *lv2f1, *lv2f2;
+ BMVert *v1, *v2;
+ int i;
+
+ if (bm->ldata.totlayer == 0) {
+ return true;
+ }
+
+ v1 = e->v1;
+ v2 = e->v2;
+ if (!BM_edge_loop_pair(e, &lef1, &lef2)) {
+ return false;
+ }
+ if (lef1->f == f2) {
+ SWAP(BMLoop *, lef1, lef2);
+ }
+
+ if (lef1->v == v1) {
+ lv1f1 = lef1;
+ lv2f1 = BM_face_other_edge_loop(f1, e, v2);
+ }
+ else {
+ lv2f1 = lef1;
+ lv1f1 = BM_face_other_edge_loop(f1, e, v1);
+ }
+
+ if (lef2->v == v1) {
+ lv1f2 = lef2;
+ lv2f2 = BM_face_other_edge_loop(f2, e, v2);
+ }
+ else {
+ lv2f2 = lef2;
+ lv1f2 = BM_face_other_edge_loop(f2, e, v1);
+ }
+
+ for (i = 0; i < bm->ldata.totlayer; i++) {
+ if (CustomData_layer_has_math(&bm->ldata, i) &&
+ (!contig_ldata_across_loops(bm, lv1f1, lv1f2, i) ||
+ !contig_ldata_across_loops(bm, lv2f1, lv2f2, i))) {
+ return false;
+ }
+ }
+ return true;
}
/* Merge (using average) all the UV values for loops of v's faces.
* Caller should ensure that no seams are violated by doing this. */
static void bev_merge_uvs(BMesh *bm, BMVert *v)
{
- BMIter iter;
- MLoopUV *luv;
- BMLoop *l;
- float uv[2];
- int n;
- int num_of_uv_layers = CustomData_number_of_layers(&bm->ldata, CD_MLOOPUV);
- int i;
-
- for (i = 0; i < num_of_uv_layers; i++) {
- int cd_loop_uv_offset = CustomData_get_n_offset(&bm->ldata, CD_MLOOPUV, i);
-
- if (cd_loop_uv_offset == -1) {
- return;
- }
-
- n = 0;
- zero_v2(uv);
- BM_ITER_ELEM (l, &iter, v, BM_LOOPS_OF_VERT) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- add_v2_v2(uv, luv->uv);
- n++;
- }
- if (n > 1) {
- mul_v2_fl(uv, 1.0f / (float)n);
- BM_ITER_ELEM (l, &iter, v, BM_LOOPS_OF_VERT) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- copy_v2_v2(luv->uv, uv);
- }
- }
- }
+ BMIter iter;
+ MLoopUV *luv;
+ BMLoop *l;
+ float uv[2];
+ int n;
+ int num_of_uv_layers = CustomData_number_of_layers(&bm->ldata, CD_MLOOPUV);
+ int i;
+
+ for (i = 0; i < num_of_uv_layers; i++) {
+ int cd_loop_uv_offset = CustomData_get_n_offset(&bm->ldata, CD_MLOOPUV, i);
+
+ if (cd_loop_uv_offset == -1) {
+ return;
+ }
+
+ n = 0;
+ zero_v2(uv);
+ BM_ITER_ELEM (l, &iter, v, BM_LOOPS_OF_VERT) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ add_v2_v2(uv, luv->uv);
+ n++;
+ }
+ if (n > 1) {
+ mul_v2_fl(uv, 1.0f / (float)n);
+ BM_ITER_ELEM (l, &iter, v, BM_LOOPS_OF_VERT) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ copy_v2_v2(luv->uv, uv);
+ }
+ }
+ }
}
/* Merge (using average) the UV values for two specific loops of v: those for faces containing v,
* and part of faces that share edge bme */
static void bev_merge_edge_uvs(BMesh *bm, BMEdge *bme, BMVert *v)
{
- BMIter iter;
- MLoopUV *luv;
- BMLoop *l, *l1, *l2;
- float uv[2];
- int num_of_uv_layers = CustomData_number_of_layers(&bm->ldata, CD_MLOOPUV);
- int i;
-
- l1 = NULL;
- l2 = NULL;
- BM_ITER_ELEM (l, &iter, v, BM_LOOPS_OF_VERT) {
- if (l->e == bme) {
- l1 = l;
- }
- else if (l->prev->e == bme) {
- l2 = l;
- }
- }
- if (l1 == NULL || l2 == NULL) {
- return;
- }
-
- for (i = 0; i < num_of_uv_layers; i++) {
- int cd_loop_uv_offset = CustomData_get_n_offset(&bm->ldata, CD_MLOOPUV, i);
-
- if (cd_loop_uv_offset == -1) {
- return;
- }
-
- zero_v2(uv);
- luv = BM_ELEM_CD_GET_VOID_P(l1, cd_loop_uv_offset);
- add_v2_v2(uv, luv->uv);
- luv = BM_ELEM_CD_GET_VOID_P(l2, cd_loop_uv_offset);
- add_v2_v2(uv, luv->uv);
- mul_v2_fl(uv, 0.5f);
- luv = BM_ELEM_CD_GET_VOID_P(l1, cd_loop_uv_offset);
- copy_v2_v2(luv->uv, uv);
- luv = BM_ELEM_CD_GET_VOID_P(l2, cd_loop_uv_offset);
- copy_v2_v2(luv->uv, uv);
- }
+ BMIter iter;
+ MLoopUV *luv;
+ BMLoop *l, *l1, *l2;
+ float uv[2];
+ int num_of_uv_layers = CustomData_number_of_layers(&bm->ldata, CD_MLOOPUV);
+ int i;
+
+ l1 = NULL;
+ l2 = NULL;
+ BM_ITER_ELEM (l, &iter, v, BM_LOOPS_OF_VERT) {
+ if (l->e == bme) {
+ l1 = l;
+ }
+ else if (l->prev->e == bme) {
+ l2 = l;
+ }
+ }
+ if (l1 == NULL || l2 == NULL) {
+ return;
+ }
+
+ for (i = 0; i < num_of_uv_layers; i++) {
+ int cd_loop_uv_offset = CustomData_get_n_offset(&bm->ldata, CD_MLOOPUV, i);
+
+ if (cd_loop_uv_offset == -1) {
+ return;
+ }
+
+ zero_v2(uv);
+ luv = BM_ELEM_CD_GET_VOID_P(l1, cd_loop_uv_offset);
+ add_v2_v2(uv, luv->uv);
+ luv = BM_ELEM_CD_GET_VOID_P(l2, cd_loop_uv_offset);
+ add_v2_v2(uv, luv->uv);
+ mul_v2_fl(uv, 0.5f);
+ luv = BM_ELEM_CD_GET_VOID_P(l1, cd_loop_uv_offset);
+ copy_v2_v2(luv->uv, uv);
+ luv = BM_ELEM_CD_GET_VOID_P(l2, cd_loop_uv_offset);
+ copy_v2_v2(luv->uv, uv);
+ }
}
/* Calculate coordinates of a point a distance d from v on e->e and return it in slideco */
static void slide_dist(EdgeHalf *e, BMVert *v, float d, float slideco[3])
{
- float dir[3], len;
-
- sub_v3_v3v3(dir, v->co, BM_edge_other_vert(e->e, v)->co);
- len = normalize_v3(dir);
- if (d > len) {
- d = len - (float)(50.0 * BEVEL_EPSILON_D);
- }
- copy_v3_v3(slideco, v->co);
- madd_v3_v3fl(slideco, dir, -d);
+ float dir[3], len;
+
+ sub_v3_v3v3(dir, v->co, BM_edge_other_vert(e->e, v)->co);
+ len = normalize_v3(dir);
+ if (d > len) {
+ d = len - (float)(50.0 * BEVEL_EPSILON_D);
+ }
+ copy_v3_v3(slideco, v->co);
+ madd_v3_v3fl(slideco, dir, -d);
}
/* Is co not on the edge e? if not, return the closer end of e in ret_closer_v */
static bool is_outside_edge(EdgeHalf *e, const float co[3], BMVert **ret_closer_v)
{
- float h[3], u[3], lambda, lenu, *l1 = e->e->v1->co;
-
- sub_v3_v3v3(u, e->e->v2->co, l1);
- sub_v3_v3v3(h, co, l1);
- lenu = normalize_v3(u);
- lambda = dot_v3v3(u, h);
- if (lambda <= -BEVEL_EPSILON_BIG * lenu) {
- *ret_closer_v = e->e->v1;
- return true;
- }
- else if (lambda >= (1.0f + BEVEL_EPSILON_BIG) * lenu) {
- *ret_closer_v = e->e->v2;
- return true;
- }
- else {
- return false;
- }
+ float h[3], u[3], lambda, lenu, *l1 = e->e->v1->co;
+
+ sub_v3_v3v3(u, e->e->v2->co, l1);
+ sub_v3_v3v3(h, co, l1);
+ lenu = normalize_v3(u);
+ lambda = dot_v3v3(u, h);
+ if (lambda <= -BEVEL_EPSILON_BIG * lenu) {
+ *ret_closer_v = e->e->v1;
+ return true;
+ }
+ else if (lambda >= (1.0f + BEVEL_EPSILON_BIG) * lenu) {
+ *ret_closer_v = e->e->v2;
+ return true;
+ }
+ else {
+ return false;
+ }
}
/* Return -1, 0, or 1 as angle from e1 to e2 is <. =, or > 180 degrees */
static int edges_angle_kind(EdgeHalf *e1, EdgeHalf *e2, BMVert *v)
{
- BMVert *v1, *v2;
- float dir1[3], dir2[3], cross[3], *no, dot;
-
- v1 = BM_edge_other_vert(e1->e, v);
- v2 = BM_edge_other_vert(e2->e, v);
- sub_v3_v3v3(dir1, v->co, v1->co);
- sub_v3_v3v3(dir2, v->co, v2->co);
- normalize_v3(dir1);
- normalize_v3(dir2);
- /* angles are in [0,pi]. need to compare cross product with normal to see if they are reflex */
- cross_v3_v3v3(cross, dir1, dir2);
- normalize_v3(cross);
- if (e1->fnext) {
- no = e1->fnext->no;
- }
- else if (e2->fprev) {
- no = e2->fprev->no;
- }
- else {
- no = v->no;
- }
- dot = dot_v3v3(cross, no);
- if (fabsf(dot) < BEVEL_EPSILON_BIG) {
- return 0;
- }
- else if (dot < 0.0f) {
- return 1;
- }
- else {
- return -1;
- }
+ BMVert *v1, *v2;
+ float dir1[3], dir2[3], cross[3], *no, dot;
+
+ v1 = BM_edge_other_vert(e1->e, v);
+ v2 = BM_edge_other_vert(e2->e, v);
+ sub_v3_v3v3(dir1, v->co, v1->co);
+ sub_v3_v3v3(dir2, v->co, v2->co);
+ normalize_v3(dir1);
+ normalize_v3(dir2);
+ /* angles are in [0,pi]. need to compare cross product with normal to see if they are reflex */
+ cross_v3_v3v3(cross, dir1, dir2);
+ normalize_v3(cross);
+ if (e1->fnext) {
+ no = e1->fnext->no;
+ }
+ else if (e2->fprev) {
+ no = e2->fprev->no;
+ }
+ else {
+ no = v->no;
+ }
+ dot = dot_v3v3(cross, no);
+ if (fabsf(dot) < BEVEL_EPSILON_BIG) {
+ return 0;
+ }
+ else if (dot < 0.0f) {
+ return 1;
+ }
+ else {
+ return -1;
+ }
}
/* co should be approximately on the plane between e1 and e2, which share common vert v
@@ -815,30 +829,30 @@ static int edges_angle_kind(EdgeHalf *e1, EdgeHalf *e2, BMVert *v)
* Is it between those edges, sweeping CCW? */
static bool point_between_edges(float co[3], BMVert *v, BMFace *f, EdgeHalf *e1, EdgeHalf *e2)
{
- BMVert *v1, *v2;
- float dir1[3], dir2[3], dirco[3], no[3];
- float ang11, ang1co;
-
- v1 = BM_edge_other_vert(e1->e, v);
- v2 = BM_edge_other_vert(e2->e, v);
- sub_v3_v3v3(dir1, v->co, v1->co);
- sub_v3_v3v3(dir2, v->co, v2->co);
- sub_v3_v3v3(dirco, v->co, co);
- normalize_v3(dir1);
- normalize_v3(dir2);
- normalize_v3(dirco);
- ang11 = angle_normalized_v3v3(dir1, dir2);
- ang1co = angle_normalized_v3v3(dir1, dirco);
- /* angles are in [0,pi]. need to compare cross product with normal to see if they are reflex */
- cross_v3_v3v3(no, dir1, dir2);
- if (dot_v3v3(no, f->no) < 0.0f) {
- ang11 = (float)(M_PI * 2.0) - ang11;
- }
- cross_v3_v3v3(no, dir1, dirco);
- if (dot_v3v3(no, f->no) < 0.0f) {
- ang1co = (float)(M_PI * 2.0) - ang1co;
- }
- return (ang11 - ang1co > -BEVEL_EPSILON_ANG);
+ BMVert *v1, *v2;
+ float dir1[3], dir2[3], dirco[3], no[3];
+ float ang11, ang1co;
+
+ v1 = BM_edge_other_vert(e1->e, v);
+ v2 = BM_edge_other_vert(e2->e, v);
+ sub_v3_v3v3(dir1, v->co, v1->co);
+ sub_v3_v3v3(dir2, v->co, v2->co);
+ sub_v3_v3v3(dirco, v->co, co);
+ normalize_v3(dir1);
+ normalize_v3(dir2);
+ normalize_v3(dirco);
+ ang11 = angle_normalized_v3v3(dir1, dir2);
+ ang1co = angle_normalized_v3v3(dir1, dirco);
+ /* angles are in [0,pi]. need to compare cross product with normal to see if they are reflex */
+ cross_v3_v3v3(no, dir1, dir2);
+ if (dot_v3v3(no, f->no) < 0.0f) {
+ ang11 = (float)(M_PI * 2.0) - ang11;
+ }
+ cross_v3_v3v3(no, dir1, dirco);
+ if (dot_v3v3(no, f->no) < 0.0f) {
+ ang1co = (float)(M_PI * 2.0) - ang1co;
+ }
+ return (ang11 - ang1co > -BEVEL_EPSILON_ANG);
}
/*
@@ -856,157 +870,158 @@ static bool point_between_edges(float co[3], BMVert *v, BMFace *f, EdgeHalf *e1,
* record the change in offset_l (or offset_r); later we can tell that a change has happened because
* the offset will differ from its original value in offset_l_spec (or offset_r_spec).
*/
-static void offset_meet(EdgeHalf *e1, EdgeHalf *e2, BMVert *v, BMFace *f, bool edges_between, float meetco[3])
+static void offset_meet(
+ EdgeHalf *e1, EdgeHalf *e2, BMVert *v, BMFace *f, bool edges_between, float meetco[3])
{
- float dir1[3], dir2[3], dir1n[3], dir2p[3], norm_v[3], norm_v1[3], norm_v2[3];
- float norm_perp1[3], norm_perp2[3], off1a[3], off1b[3], off2a[3], off2b[3];
- float isect2[3], dropco[3], plane[4];
- float ang, d;
- BMVert *closer_v;
- EdgeHalf *e, *e1next, *e2prev;
- BMFace *ff;
- int isect_kind;
-
- /* get direction vectors for two offset lines */
- sub_v3_v3v3(dir1, v->co, BM_edge_other_vert(e1->e, v)->co);
- sub_v3_v3v3(dir2, BM_edge_other_vert(e2->e, v)->co, v->co);
-
- if (edges_between) {
- e1next = e1->next;
- e2prev = e2->prev;
- sub_v3_v3v3(dir1n, BM_edge_other_vert(e1next->e, v)->co, v->co);
- sub_v3_v3v3(dir2p, v->co, BM_edge_other_vert(e2prev->e, v)->co);
- }
- else {
- /* shup up 'maybe unused' warnings */
- zero_v3(dir1n);
- zero_v3(dir2p);
- }
-
- ang = angle_v3v3(dir1, dir2);
- if (ang < BEVEL_EPSILON_ANG) {
- /* special case: e1 and e2 are parallel; put offset point perp to both, from v.
- * need to find a suitable plane.
- * this code used to just use offset and dir1, but that makes for visible errors
- * on a circle with > 200 sides, which trips this "nearly perp" code (see T61214).
- * so use the average of the two, and the offset formula for angle bisector.
- * if offsets are different, we're out of luck:
- * use the max of the two (so get consistent looking results if the same situation
- * arises elsewhere in the object but with opposite roles for e1 and e2 */
- if (f) {
- copy_v3_v3(norm_v, f->no);
- }
- else {
- copy_v3_v3(norm_v, v->no);
- }
- add_v3_v3(dir1, dir2);
- cross_v3_v3v3(norm_perp1, dir1, norm_v);
- normalize_v3(norm_perp1);
- copy_v3_v3(off1a, v->co);
- d = max_ff(e1->offset_r, e2->offset_l);
- d = d / cos(ang / 2.0f);
- madd_v3_v3fl(off1a, norm_perp1, d);
- copy_v3_v3(meetco, off1a);
- }
- else if (fabsf(ang - (float)M_PI) < BEVEL_EPSILON_ANG) {
- /* special case e1 and e2 are antiparallel, so bevel is into
- * a zero-area face. Just make the offset point on the
- * common line, at offset distance from v. */
- d = max_ff(e1->offset_r, e2->offset_l);
- slide_dist(e2, v, d, meetco);
- }
- else {
- /* Get normal to plane where meet point should be,
- * using cross product instead of f->no in case f is non-planar.
- * Except: sometimes locally there can be a small angle
- * between dir1 and dir2 that leads to a normal that is actually almost
- * perpendicular to the face normal; in this case it looks wrong to use
- * the local (cross-product) normal, so use the face normal if the angle
- * between dir1 and dir2 is smallish.
- * If e1-v-e2 is a reflex angle (viewed from vertex normal side), need to flip.
- * Use f->no to figure out which side to look at angle from, as even if
- * f is non-planar, will be more accurate than vertex normal */
- if (f && ang < BEVEL_SMALL_ANG) {
- copy_v3_v3(norm_v1, f->no);
- copy_v3_v3(norm_v2, f->no);
- }
- else if (!edges_between) {
- cross_v3_v3v3(norm_v1, dir2, dir1);
- normalize_v3(norm_v1);
- if (dot_v3v3(norm_v1, f ? f->no : v->no) < 0.0f) {
- negate_v3(norm_v1);
- }
- copy_v3_v3(norm_v2, norm_v1);
- }
- else {
- /* separate faces; get face norms at corners for each separately */
- cross_v3_v3v3(norm_v1, dir1n, dir1);
- normalize_v3(norm_v1);
- f = e1->fnext;
- if (dot_v3v3(norm_v1, f ? f->no : v->no) < 0.0f) {
- negate_v3(norm_v1);
- }
- cross_v3_v3v3(norm_v2, dir2, dir2p);
- normalize_v3(norm_v2);
- f = e2->fprev;
- if (dot_v3v3(norm_v2, f ? f->no : v->no) < 0.0f) {
- negate_v3(norm_v2);
- }
- }
-
- /* get vectors perp to each edge, perp to norm_v, and pointing into face */
- cross_v3_v3v3(norm_perp1, dir1, norm_v1);
- cross_v3_v3v3(norm_perp2, dir2, norm_v2);
- normalize_v3(norm_perp1);
- normalize_v3(norm_perp2);
-
- /* get points that are offset distances from each line, then another point on each line */
- copy_v3_v3(off1a, v->co);
- madd_v3_v3fl(off1a, norm_perp1, e1->offset_r);
- add_v3_v3v3(off1b, off1a, dir1);
- copy_v3_v3(off2a, v->co);
- madd_v3_v3fl(off2a, norm_perp2, e2->offset_l);
- add_v3_v3v3(off2b, off2a, dir2);
-
- /* intersect the lines */
- isect_kind = isect_line_line_v3(off1a, off1b, off2a, off2b, meetco, isect2);
- if (isect_kind == 0) {
- /* lines are collinear: we already tested for this, but this used a different epsilon */
- copy_v3_v3(meetco, off1a); /* just to do something */
- }
- else {
- /* The lines intersect, but is it at a reasonable place?
- * One problem to check: if one of the offsets is 0, then don't
- * want an intersection that is outside that edge itself.
- * This can happen if angle between them is > 180 degrees,
- * or if the offset amount is > the edge length*/
- if (e1->offset_r == 0.0f && is_outside_edge(e1, meetco, &closer_v)) {
- copy_v3_v3(meetco, closer_v->co);
- }
- if (e2->offset_l == 0.0f && is_outside_edge(e2, meetco, &closer_v)) {
- copy_v3_v3(meetco, closer_v->co);
- }
- if (edges_between && e1->offset_r > 0.0f && e2->offset_l > 0.0f) {
- /* Try to drop meetco to a face between e1 and e2 */
- if (isect_kind == 2) {
- /* lines didn't meet in 3d: get average of meetco and isect2 */
- mid_v3_v3v3(meetco, meetco, isect2);
- }
- for (e = e1; e != e2; e = e->next) {
- ff = e->fnext;
- if (!ff) {
- continue;
- }
- plane_from_point_normal_v3(plane, v->co, ff->no);
- closest_to_plane_normalized_v3(dropco, plane, meetco);
- if (point_between_edges(dropco, v, ff, e, e->next)) {
- copy_v3_v3(meetco, dropco);
- break;
- }
- }
- }
- }
- }
+ float dir1[3], dir2[3], dir1n[3], dir2p[3], norm_v[3], norm_v1[3], norm_v2[3];
+ float norm_perp1[3], norm_perp2[3], off1a[3], off1b[3], off2a[3], off2b[3];
+ float isect2[3], dropco[3], plane[4];
+ float ang, d;
+ BMVert *closer_v;
+ EdgeHalf *e, *e1next, *e2prev;
+ BMFace *ff;
+ int isect_kind;
+
+ /* get direction vectors for two offset lines */
+ sub_v3_v3v3(dir1, v->co, BM_edge_other_vert(e1->e, v)->co);
+ sub_v3_v3v3(dir2, BM_edge_other_vert(e2->e, v)->co, v->co);
+
+ if (edges_between) {
+ e1next = e1->next;
+ e2prev = e2->prev;
+ sub_v3_v3v3(dir1n, BM_edge_other_vert(e1next->e, v)->co, v->co);
+ sub_v3_v3v3(dir2p, v->co, BM_edge_other_vert(e2prev->e, v)->co);
+ }
+ else {
+ /* shup up 'maybe unused' warnings */
+ zero_v3(dir1n);
+ zero_v3(dir2p);
+ }
+
+ ang = angle_v3v3(dir1, dir2);
+ if (ang < BEVEL_EPSILON_ANG) {
+ /* special case: e1 and e2 are parallel; put offset point perp to both, from v.
+ * need to find a suitable plane.
+ * this code used to just use offset and dir1, but that makes for visible errors
+ * on a circle with > 200 sides, which trips this "nearly perp" code (see T61214).
+ * so use the average of the two, and the offset formula for angle bisector.
+ * if offsets are different, we're out of luck:
+ * use the max of the two (so get consistent looking results if the same situation
+ * arises elsewhere in the object but with opposite roles for e1 and e2 */
+ if (f) {
+ copy_v3_v3(norm_v, f->no);
+ }
+ else {
+ copy_v3_v3(norm_v, v->no);
+ }
+ add_v3_v3(dir1, dir2);
+ cross_v3_v3v3(norm_perp1, dir1, norm_v);
+ normalize_v3(norm_perp1);
+ copy_v3_v3(off1a, v->co);
+ d = max_ff(e1->offset_r, e2->offset_l);
+ d = d / cos(ang / 2.0f);
+ madd_v3_v3fl(off1a, norm_perp1, d);
+ copy_v3_v3(meetco, off1a);
+ }
+ else if (fabsf(ang - (float)M_PI) < BEVEL_EPSILON_ANG) {
+ /* special case e1 and e2 are antiparallel, so bevel is into
+ * a zero-area face. Just make the offset point on the
+ * common line, at offset distance from v. */
+ d = max_ff(e1->offset_r, e2->offset_l);
+ slide_dist(e2, v, d, meetco);
+ }
+ else {
+ /* Get normal to plane where meet point should be,
+ * using cross product instead of f->no in case f is non-planar.
+ * Except: sometimes locally there can be a small angle
+ * between dir1 and dir2 that leads to a normal that is actually almost
+ * perpendicular to the face normal; in this case it looks wrong to use
+ * the local (cross-product) normal, so use the face normal if the angle
+ * between dir1 and dir2 is smallish.
+ * If e1-v-e2 is a reflex angle (viewed from vertex normal side), need to flip.
+ * Use f->no to figure out which side to look at angle from, as even if
+ * f is non-planar, will be more accurate than vertex normal */
+ if (f && ang < BEVEL_SMALL_ANG) {
+ copy_v3_v3(norm_v1, f->no);
+ copy_v3_v3(norm_v2, f->no);
+ }
+ else if (!edges_between) {
+ cross_v3_v3v3(norm_v1, dir2, dir1);
+ normalize_v3(norm_v1);
+ if (dot_v3v3(norm_v1, f ? f->no : v->no) < 0.0f) {
+ negate_v3(norm_v1);
+ }
+ copy_v3_v3(norm_v2, norm_v1);
+ }
+ else {
+ /* separate faces; get face norms at corners for each separately */
+ cross_v3_v3v3(norm_v1, dir1n, dir1);
+ normalize_v3(norm_v1);
+ f = e1->fnext;
+ if (dot_v3v3(norm_v1, f ? f->no : v->no) < 0.0f) {
+ negate_v3(norm_v1);
+ }
+ cross_v3_v3v3(norm_v2, dir2, dir2p);
+ normalize_v3(norm_v2);
+ f = e2->fprev;
+ if (dot_v3v3(norm_v2, f ? f->no : v->no) < 0.0f) {
+ negate_v3(norm_v2);
+ }
+ }
+
+ /* get vectors perp to each edge, perp to norm_v, and pointing into face */
+ cross_v3_v3v3(norm_perp1, dir1, norm_v1);
+ cross_v3_v3v3(norm_perp2, dir2, norm_v2);
+ normalize_v3(norm_perp1);
+ normalize_v3(norm_perp2);
+
+ /* get points that are offset distances from each line, then another point on each line */
+ copy_v3_v3(off1a, v->co);
+ madd_v3_v3fl(off1a, norm_perp1, e1->offset_r);
+ add_v3_v3v3(off1b, off1a, dir1);
+ copy_v3_v3(off2a, v->co);
+ madd_v3_v3fl(off2a, norm_perp2, e2->offset_l);
+ add_v3_v3v3(off2b, off2a, dir2);
+
+ /* intersect the lines */
+ isect_kind = isect_line_line_v3(off1a, off1b, off2a, off2b, meetco, isect2);
+ if (isect_kind == 0) {
+ /* lines are collinear: we already tested for this, but this used a different epsilon */
+ copy_v3_v3(meetco, off1a); /* just to do something */
+ }
+ else {
+ /* The lines intersect, but is it at a reasonable place?
+ * One problem to check: if one of the offsets is 0, then don't
+ * want an intersection that is outside that edge itself.
+ * This can happen if angle between them is > 180 degrees,
+ * or if the offset amount is > the edge length*/
+ if (e1->offset_r == 0.0f && is_outside_edge(e1, meetco, &closer_v)) {
+ copy_v3_v3(meetco, closer_v->co);
+ }
+ if (e2->offset_l == 0.0f && is_outside_edge(e2, meetco, &closer_v)) {
+ copy_v3_v3(meetco, closer_v->co);
+ }
+ if (edges_between && e1->offset_r > 0.0f && e2->offset_l > 0.0f) {
+ /* Try to drop meetco to a face between e1 and e2 */
+ if (isect_kind == 2) {
+ /* lines didn't meet in 3d: get average of meetco and isect2 */
+ mid_v3_v3v3(meetco, meetco, isect2);
+ }
+ for (e = e1; e != e2; e = e->next) {
+ ff = e->fnext;
+ if (!ff) {
+ continue;
+ }
+ plane_from_point_normal_v3(plane, v->co, ff->no);
+ closest_to_plane_normalized_v3(dropco, plane, meetco);
+ if (point_between_edges(dropco, v, ff, e, e->next)) {
+ copy_v3_v3(meetco, dropco);
+ break;
+ }
+ }
+ }
+ }
+ }
}
/* chosen so that 1/sin(BEVEL_GOOD_ANGLE) is about 4, giving that expansion factor to bevel width */
@@ -1017,60 +1032,60 @@ static void offset_meet(EdgeHalf *e1, EdgeHalf *e2, BMVert *v, BMFace *f, bool e
* If r_angle is provided, return the angle between e and emeet in *r_angle.
* If the angle is 0, or it is 180 degrees or larger, there will be no meeting point;
* return false in that case, else true. */
-static bool offset_meet_edge(EdgeHalf *e1, EdgeHalf *e2, BMVert *v, float meetco[3], float *r_angle)
+static bool offset_meet_edge(
+ EdgeHalf *e1, EdgeHalf *e2, BMVert *v, float meetco[3], float *r_angle)
{
- float dir1[3], dir2[3], fno[3], ang, sinang;
-
- sub_v3_v3v3(dir1, BM_edge_other_vert(e1->e, v)->co, v->co);
- sub_v3_v3v3(dir2, BM_edge_other_vert(e2->e, v)->co, v->co);
- normalize_v3(dir1);
- normalize_v3(dir2);
-
- /* find angle from dir1 to dir2 as viewed from vertex normal side */
- ang = angle_normalized_v3v3(dir1, dir2);
- if (fabsf(ang) < BEVEL_GOOD_ANGLE) {
- if (r_angle) {
- *r_angle = 0.0f;
- }
- return false;
- }
- cross_v3_v3v3(fno, dir1, dir2);
- if (dot_v3v3(fno, v->no) < 0.0f) {
- ang = 2.0f * (float)M_PI - ang; /* angle is reflex */
- if (r_angle) {
- *r_angle = ang;
- }
- return false;
- }
- if (r_angle) {
- *r_angle = ang;
- }
-
- if (fabsf(ang - (float)M_PI) < BEVEL_GOOD_ANGLE) {
- return false;
- }
-
- sinang = sinf(ang);
-
- copy_v3_v3(meetco, v->co);
- if (e1->offset_r == 0.0f) {
- madd_v3_v3fl(meetco, dir1, e2->offset_l / sinang);
- }
- else {
- madd_v3_v3fl(meetco, dir2, e1->offset_r / sinang);
- }
- return true;
+ float dir1[3], dir2[3], fno[3], ang, sinang;
+
+ sub_v3_v3v3(dir1, BM_edge_other_vert(e1->e, v)->co, v->co);
+ sub_v3_v3v3(dir2, BM_edge_other_vert(e2->e, v)->co, v->co);
+ normalize_v3(dir1);
+ normalize_v3(dir2);
+
+ /* find angle from dir1 to dir2 as viewed from vertex normal side */
+ ang = angle_normalized_v3v3(dir1, dir2);
+ if (fabsf(ang) < BEVEL_GOOD_ANGLE) {
+ if (r_angle) {
+ *r_angle = 0.0f;
+ }
+ return false;
+ }
+ cross_v3_v3v3(fno, dir1, dir2);
+ if (dot_v3v3(fno, v->no) < 0.0f) {
+ ang = 2.0f * (float)M_PI - ang; /* angle is reflex */
+ if (r_angle) {
+ *r_angle = ang;
+ }
+ return false;
+ }
+ if (r_angle) {
+ *r_angle = ang;
+ }
+
+ if (fabsf(ang - (float)M_PI) < BEVEL_GOOD_ANGLE) {
+ return false;
+ }
+
+ sinang = sinf(ang);
+
+ copy_v3_v3(meetco, v->co);
+ if (e1->offset_r == 0.0f) {
+ madd_v3_v3fl(meetco, dir1, e2->offset_l / sinang);
+ }
+ else {
+ madd_v3_v3fl(meetco, dir2, e1->offset_r / sinang);
+ }
+ return true;
}
/* Return true if it will look good to put the meeting point where offset_on_edge_between
* would put it. This means that neither side sees a reflex angle */
static bool good_offset_on_edge_between(EdgeHalf *e1, EdgeHalf *e2, EdgeHalf *emid, BMVert *v)
{
- float ang;
- float meet[3];
+ float ang;
+ float meet[3];
- return offset_meet_edge(e1, emid, v, meet, &ang) &&
- offset_meet_edge(emid, e2, v, meet, &ang);
+ return offset_meet_edge(e1, emid, v, meet, &ang) && offset_meet_edge(emid, e2, v, meet, &ang);
}
/* Calculate the best place for a meeting point for the offsets from edges e1 and e2
@@ -1079,39 +1094,38 @@ static bool good_offset_on_edge_between(EdgeHalf *e1, EdgeHalf *e2, EdgeHalf *em
* Return true if we placed meetco as compromise between where two edges met.
* If we did, put ration of sines of angles in *r_sinratio too */
static bool offset_on_edge_between(
- EdgeHalf *e1, EdgeHalf *e2, EdgeHalf *emid,
- BMVert *v, float meetco[3], float *r_sinratio)
+ EdgeHalf *e1, EdgeHalf *e2, EdgeHalf *emid, BMVert *v, float meetco[3], float *r_sinratio)
{
- float ang1, ang2;
- float meet1[3], meet2[3];
- bool ok1, ok2;
- bool retval = false;
-
- BLI_assert(e1->is_bev && e2->is_bev && !emid->is_bev);
-
- ok1 = offset_meet_edge(e1, emid, v, meet1, &ang1);
- ok2 = offset_meet_edge(emid, e2, v, meet2, &ang2);
- if (ok1 && ok2) {
- mid_v3_v3v3(meetco, meet1, meet2);
- if (r_sinratio) {
- /* ang1 should not be 0, but be paranoid */
- *r_sinratio = (ang1 == 0.0f) ? 1.0f : sinf(ang2) / sinf(ang1);
- }
- retval = true;
- }
- else if (ok1 && !ok2) {
- copy_v3_v3(meetco, meet1);
- }
- else if (!ok1 && ok2) {
- copy_v3_v3(meetco, meet2);
- }
- else {
- /* Neither offset line met emid.
- * This should only happen if all three lines are on top of each other */
- slide_dist(emid, v, e1->offset_r, meetco);
- }
-
- return retval;
+ float ang1, ang2;
+ float meet1[3], meet2[3];
+ bool ok1, ok2;
+ bool retval = false;
+
+ BLI_assert(e1->is_bev && e2->is_bev && !emid->is_bev);
+
+ ok1 = offset_meet_edge(e1, emid, v, meet1, &ang1);
+ ok2 = offset_meet_edge(emid, e2, v, meet2, &ang2);
+ if (ok1 && ok2) {
+ mid_v3_v3v3(meetco, meet1, meet2);
+ if (r_sinratio) {
+ /* ang1 should not be 0, but be paranoid */
+ *r_sinratio = (ang1 == 0.0f) ? 1.0f : sinf(ang2) / sinf(ang1);
+ }
+ retval = true;
+ }
+ else if (ok1 && !ok2) {
+ copy_v3_v3(meetco, meet1);
+ }
+ else if (!ok1 && ok2) {
+ copy_v3_v3(meetco, meet2);
+ }
+ else {
+ /* Neither offset line met emid.
+ * This should only happen if all three lines are on top of each other */
+ slide_dist(emid, v, e1->offset_r, meetco);
+ }
+
+ return retval;
}
/* Offset by e->offset in plane with normal plane_no, on left if left==true,
@@ -1119,47 +1133,47 @@ static bool offset_on_edge_between(
* from eh's direction. */
static void offset_in_plane(EdgeHalf *e, const float plane_no[3], bool left, float r[3])
{
- float dir[3], no[3], fdir[3];
- BMVert *v;
-
- v = e->is_rev ? e->e->v2 : e->e->v1;
-
- sub_v3_v3v3(dir, BM_edge_other_vert(e->e, v)->co, v->co);
- normalize_v3(dir);
- if (plane_no) {
- copy_v3_v3(no, plane_no);
- }
- else {
- zero_v3(no);
- if (fabsf(dir[0]) < fabsf(dir[1])) {
- no[0] = 1.0f;
- }
- else {
- no[1] = 1.0f;
- }
- }
- if (left) {
- cross_v3_v3v3(fdir, dir, no);
- }
- else {
- cross_v3_v3v3(fdir, no, dir);
- }
- normalize_v3(fdir);
- copy_v3_v3(r, v->co);
- madd_v3_v3fl(r, fdir, left ? e->offset_l : e->offset_r);
+ float dir[3], no[3], fdir[3];
+ BMVert *v;
+
+ v = e->is_rev ? e->e->v2 : e->e->v1;
+
+ sub_v3_v3v3(dir, BM_edge_other_vert(e->e, v)->co, v->co);
+ normalize_v3(dir);
+ if (plane_no) {
+ copy_v3_v3(no, plane_no);
+ }
+ else {
+ zero_v3(no);
+ if (fabsf(dir[0]) < fabsf(dir[1])) {
+ no[0] = 1.0f;
+ }
+ else {
+ no[1] = 1.0f;
+ }
+ }
+ if (left) {
+ cross_v3_v3v3(fdir, dir, no);
+ }
+ else {
+ cross_v3_v3v3(fdir, no, dir);
+ }
+ normalize_v3(fdir);
+ copy_v3_v3(r, v->co);
+ madd_v3_v3fl(r, fdir, left ? e->offset_l : e->offset_r);
}
/* Calculate the point on e where line (co_a, co_b) comes closest to and return it in projco */
static void project_to_edge(BMEdge *e, const float co_a[3], const float co_b[3], float projco[3])
{
- float otherco[3];
+ float otherco[3];
- if (!isect_line_line_v3(e->v1->co, e->v2->co, co_a, co_b, projco, otherco)) {
+ if (!isect_line_line_v3(e->v1->co, e->v2->co, co_a, co_b, projco, otherco)) {
#ifdef BEVEL_ASSERT_PROJECT
- BLI_assert(!"project meet failure");
+ BLI_assert(!"project meet failure");
#endif
- copy_v3_v3(projco, e->v1->co);
- }
+ copy_v3_v3(projco, e->v1->co);
+ }
}
/* If there is a bndv->ebev edge, find the mid control point if necessary.
@@ -1167,159 +1181,159 @@ static void project_to_edge(BMEdge *e, const float co_a[3], const float co_b[3],
* bndv and bndv->next. */
static void set_profile_params(BevelParams *bp, BevVert *bv, BoundVert *bndv)
{
- EdgeHalf *e;
- Profile *pro;
- float co1[3], co2[3], co3[3], d1[3], d2[3];
- bool do_linear_interp;
-
- copy_v3_v3(co1, bndv->nv.co);
- copy_v3_v3(co2, bndv->next->nv.co);
- pro = &bndv->profile;
- e = bndv->ebev;
- do_linear_interp = true;
- if (e) {
- do_linear_interp = false;
- pro->super_r = bp->pro_super_r;
- /* projection direction is direction of the edge */
- sub_v3_v3v3(pro->proj_dir, e->e->v1->co, e->e->v2->co);
- normalize_v3(pro->proj_dir);
- project_to_edge(e->e, co1, co2, pro->midco);
- if (DEBUG_OLD_PROJ_TO_PERP_PLANE) {
- /* put arc endpoints on plane with normal proj_dir, containing midco */
- add_v3_v3v3(co3, co1, pro->proj_dir);
- if (!isect_line_plane_v3(pro->coa, co1, co3, pro->midco, pro->proj_dir)) {
- /* shouldn't happen */
- copy_v3_v3(pro->coa, co1);
- }
- add_v3_v3v3(co3, co2, pro->proj_dir);
- if (!isect_line_plane_v3(pro->cob, co2, co3, pro->midco, pro->proj_dir)) {
- /* shouldn't happen */
- copy_v3_v3(pro->cob, co2);
- }
- }
- else {
- copy_v3_v3(pro->coa, co1);
- copy_v3_v3(pro->cob, co2);
- }
- /* default plane to project onto is the one with triangle co1 - midco - co2 in it */
- sub_v3_v3v3(d1, pro->midco, co1);
- sub_v3_v3v3(d2, pro->midco, co2);
- normalize_v3(d1);
- normalize_v3(d2);
- cross_v3_v3v3(pro->plane_no, d1, d2);
- normalize_v3(pro->plane_no);
- if (nearly_parallel(d1, d2)) {
- /* co1 - midco -co2 are collinear.
- * Should be case that beveled edge is coplanar with two boundary verts.
- * We want to move the profile to that common plane, if possible.
- * That makes the multi-segment bevels curve nicely in that plane, as users expect.
- * The new midco should be either v (when neighbor edges are unbeveled)
- * or the intersection of the offset lines (if they are).
- * If the profile is going to lead into unbeveled edges on each side
- * (that is, both BoundVerts are "on-edge" points on non-beveled edges)
- */
- if (DEBUG_OLD_PLANE_SPECIAL && (e->prev->is_bev || e->next->is_bev)) {
- do_linear_interp = true;
- }
- else {
- if (DEBUG_OLD_PROJ_TO_PERP_PLANE) {
- copy_v3_v3(pro->coa, co1);
- copy_v3_v3(pro->cob, co2);
- }
- if (DEBUG_OLD_FLAT_MID) {
- copy_v3_v3(pro->midco, bv->v->co);
- }
- else {
- copy_v3_v3(pro->midco, bv->v->co);
- if (e->prev->is_bev && e->next->is_bev && bv->selcount >= 3) {
- /* want mid at the meet point of next and prev offset edges */
- float d3[3], d4[3], co4[3], meetco[3], isect2[3];
- int isect_kind;
-
- sub_v3_v3v3(d3, e->prev->e->v1->co, e->prev->e->v2->co);
- sub_v3_v3v3(d4, e->next->e->v1->co, e->next->e->v2->co);
- normalize_v3(d3);
- normalize_v3(d4);
- if (nearly_parallel(d3, d4)) {
- /* offset lines are collinear - want linear interpolation */
- mid_v3_v3v3(pro->midco, co1, co2);
- do_linear_interp = true;
- }
- else {
- add_v3_v3v3(co3, co1, d3);
- add_v3_v3v3(co4, co2, d4);
- isect_kind = isect_line_line_v3(co1, co3, co2, co4, meetco, isect2);
- if (isect_kind != 0) {
- copy_v3_v3(pro->midco, meetco);
- }
- else {
- /* offset lines don't intersect - want linear interpolation */
- mid_v3_v3v3(pro->midco, co1, co2);
- do_linear_interp = true;
- }
- }
- }
- }
- copy_v3_v3(pro->cob, co2);
- sub_v3_v3v3(d1, pro->midco, co1);
- normalize_v3(d1);
- sub_v3_v3v3(d2, pro->midco, co2);
- normalize_v3(d2);
- cross_v3_v3v3(pro->plane_no, d1, d2);
- normalize_v3(pro->plane_no);
- if (nearly_parallel(d1, d2)) {
- /* whole profile is collinear with edge: just interpolate */
- do_linear_interp = true;
- }
- else {
- copy_v3_v3(pro->plane_co, bv->v->co);
- copy_v3_v3(pro->proj_dir, pro->plane_no);
- }
- }
- }
- copy_v3_v3(pro->plane_co, co1);
- }
- else if (bndv->is_arc_start) {
- /* assume pro->midco was alredy set */
- copy_v3_v3(pro->coa, co1);
- copy_v3_v3(pro->cob, co2);
- pro->super_r = PRO_CIRCLE_R;
- zero_v3(pro->plane_co);
- zero_v3(pro->plane_no);
- zero_v3(pro->proj_dir);
- do_linear_interp = false;
- }
- if (do_linear_interp) {
- pro->super_r = PRO_LINE_R;
- copy_v3_v3(pro->coa, co1);
- copy_v3_v3(pro->cob, co2);
- mid_v3_v3v3(pro->midco, co1, co2);
- /* won't use projection for this line profile */
- zero_v3(pro->plane_co);
- zero_v3(pro->plane_no);
- zero_v3(pro->proj_dir);
- }
+ EdgeHalf *e;
+ Profile *pro;
+ float co1[3], co2[3], co3[3], d1[3], d2[3];
+ bool do_linear_interp;
+
+ copy_v3_v3(co1, bndv->nv.co);
+ copy_v3_v3(co2, bndv->next->nv.co);
+ pro = &bndv->profile;
+ e = bndv->ebev;
+ do_linear_interp = true;
+ if (e) {
+ do_linear_interp = false;
+ pro->super_r = bp->pro_super_r;
+ /* projection direction is direction of the edge */
+ sub_v3_v3v3(pro->proj_dir, e->e->v1->co, e->e->v2->co);
+ normalize_v3(pro->proj_dir);
+ project_to_edge(e->e, co1, co2, pro->midco);
+ if (DEBUG_OLD_PROJ_TO_PERP_PLANE) {
+ /* put arc endpoints on plane with normal proj_dir, containing midco */
+ add_v3_v3v3(co3, co1, pro->proj_dir);
+ if (!isect_line_plane_v3(pro->coa, co1, co3, pro->midco, pro->proj_dir)) {
+ /* shouldn't happen */
+ copy_v3_v3(pro->coa, co1);
+ }
+ add_v3_v3v3(co3, co2, pro->proj_dir);
+ if (!isect_line_plane_v3(pro->cob, co2, co3, pro->midco, pro->proj_dir)) {
+ /* shouldn't happen */
+ copy_v3_v3(pro->cob, co2);
+ }
+ }
+ else {
+ copy_v3_v3(pro->coa, co1);
+ copy_v3_v3(pro->cob, co2);
+ }
+ /* default plane to project onto is the one with triangle co1 - midco - co2 in it */
+ sub_v3_v3v3(d1, pro->midco, co1);
+ sub_v3_v3v3(d2, pro->midco, co2);
+ normalize_v3(d1);
+ normalize_v3(d2);
+ cross_v3_v3v3(pro->plane_no, d1, d2);
+ normalize_v3(pro->plane_no);
+ if (nearly_parallel(d1, d2)) {
+ /* co1 - midco -co2 are collinear.
+ * Should be case that beveled edge is coplanar with two boundary verts.
+ * We want to move the profile to that common plane, if possible.
+ * That makes the multi-segment bevels curve nicely in that plane, as users expect.
+ * The new midco should be either v (when neighbor edges are unbeveled)
+ * or the intersection of the offset lines (if they are).
+ * If the profile is going to lead into unbeveled edges on each side
+ * (that is, both BoundVerts are "on-edge" points on non-beveled edges)
+ */
+ if (DEBUG_OLD_PLANE_SPECIAL && (e->prev->is_bev || e->next->is_bev)) {
+ do_linear_interp = true;
+ }
+ else {
+ if (DEBUG_OLD_PROJ_TO_PERP_PLANE) {
+ copy_v3_v3(pro->coa, co1);
+ copy_v3_v3(pro->cob, co2);
+ }
+ if (DEBUG_OLD_FLAT_MID) {
+ copy_v3_v3(pro->midco, bv->v->co);
+ }
+ else {
+ copy_v3_v3(pro->midco, bv->v->co);
+ if (e->prev->is_bev && e->next->is_bev && bv->selcount >= 3) {
+ /* want mid at the meet point of next and prev offset edges */
+ float d3[3], d4[3], co4[3], meetco[3], isect2[3];
+ int isect_kind;
+
+ sub_v3_v3v3(d3, e->prev->e->v1->co, e->prev->e->v2->co);
+ sub_v3_v3v3(d4, e->next->e->v1->co, e->next->e->v2->co);
+ normalize_v3(d3);
+ normalize_v3(d4);
+ if (nearly_parallel(d3, d4)) {
+ /* offset lines are collinear - want linear interpolation */
+ mid_v3_v3v3(pro->midco, co1, co2);
+ do_linear_interp = true;
+ }
+ else {
+ add_v3_v3v3(co3, co1, d3);
+ add_v3_v3v3(co4, co2, d4);
+ isect_kind = isect_line_line_v3(co1, co3, co2, co4, meetco, isect2);
+ if (isect_kind != 0) {
+ copy_v3_v3(pro->midco, meetco);
+ }
+ else {
+ /* offset lines don't intersect - want linear interpolation */
+ mid_v3_v3v3(pro->midco, co1, co2);
+ do_linear_interp = true;
+ }
+ }
+ }
+ }
+ copy_v3_v3(pro->cob, co2);
+ sub_v3_v3v3(d1, pro->midco, co1);
+ normalize_v3(d1);
+ sub_v3_v3v3(d2, pro->midco, co2);
+ normalize_v3(d2);
+ cross_v3_v3v3(pro->plane_no, d1, d2);
+ normalize_v3(pro->plane_no);
+ if (nearly_parallel(d1, d2)) {
+ /* whole profile is collinear with edge: just interpolate */
+ do_linear_interp = true;
+ }
+ else {
+ copy_v3_v3(pro->plane_co, bv->v->co);
+ copy_v3_v3(pro->proj_dir, pro->plane_no);
+ }
+ }
+ }
+ copy_v3_v3(pro->plane_co, co1);
+ }
+ else if (bndv->is_arc_start) {
+ /* assume pro->midco was alredy set */
+ copy_v3_v3(pro->coa, co1);
+ copy_v3_v3(pro->cob, co2);
+ pro->super_r = PRO_CIRCLE_R;
+ zero_v3(pro->plane_co);
+ zero_v3(pro->plane_no);
+ zero_v3(pro->proj_dir);
+ do_linear_interp = false;
+ }
+ if (do_linear_interp) {
+ pro->super_r = PRO_LINE_R;
+ copy_v3_v3(pro->coa, co1);
+ copy_v3_v3(pro->cob, co2);
+ mid_v3_v3v3(pro->midco, co1, co2);
+ /* won't use projection for this line profile */
+ zero_v3(pro->plane_co);
+ zero_v3(pro->plane_no);
+ zero_v3(pro->proj_dir);
+ }
}
/* Move the profile plane for bndv to the plane containing e1 and e2, which share a vert */
static void move_profile_plane(BoundVert *bndv, EdgeHalf *e1, EdgeHalf *e2)
{
- float d1[3], d2[3], no[3], no2[3], dot;
-
- /* only do this if projecting, and e1, e2, and proj_dir are not coplanar */
- if (is_zero_v3(bndv->profile.proj_dir)) {
- return;
- }
- sub_v3_v3v3(d1, e1->e->v1->co, e1->e->v2->co);
- sub_v3_v3v3(d2, e2->e->v1->co, e2->e->v2->co);
- cross_v3_v3v3(no, d1, d2);
- cross_v3_v3v3(no2, d1, bndv->profile.proj_dir);
- if (normalize_v3(no) > BEVEL_EPSILON_BIG && normalize_v3(no2) > BEVEL_EPSILON_BIG) {
- dot = fabsf(dot_v3v3(no, no2));
- if (fabsf(dot - 1.0f) > BEVEL_EPSILON_BIG) {
- copy_v3_v3(bndv->profile.plane_no, no);
- }
- }
+ float d1[3], d2[3], no[3], no2[3], dot;
+
+ /* only do this if projecting, and e1, e2, and proj_dir are not coplanar */
+ if (is_zero_v3(bndv->profile.proj_dir)) {
+ return;
+ }
+ sub_v3_v3v3(d1, e1->e->v1->co, e1->e->v2->co);
+ sub_v3_v3v3(d2, e2->e->v1->co, e2->e->v2->co);
+ cross_v3_v3v3(no, d1, d2);
+ cross_v3_v3v3(no2, d1, bndv->profile.proj_dir);
+ if (normalize_v3(no) > BEVEL_EPSILON_BIG && normalize_v3(no2) > BEVEL_EPSILON_BIG) {
+ dot = fabsf(dot_v3v3(no, no2));
+ if (fabsf(dot - 1.0f) > BEVEL_EPSILON_BIG) {
+ copy_v3_v3(bndv->profile.plane_no, no);
+ }
+ }
}
/* Move the profile plane for the two BoundVerts involved in a weld.
@@ -1329,49 +1343,49 @@ static void move_profile_plane(BoundVert *bndv, EdgeHalf *e1, EdgeHalf *e2)
* The original vertex should form a third point of the desired plane. */
static void move_weld_profile_planes(BevVert *bv, BoundVert *bndv1, BoundVert *bndv2)
{
- float d1[3], d2[3], no[3], no2[3], no3[3], dot1, dot2, l1, l2, l3;
-
- /* only do this if projecting, and d1, d2, and proj_dir are not coplanar */
- if (is_zero_v3(bndv1->profile.proj_dir) || is_zero_v3(bndv2->profile.proj_dir)) {
- return;
- }
- sub_v3_v3v3(d1, bv->v->co, bndv1->nv.co);
- sub_v3_v3v3(d2, bv->v->co, bndv2->nv.co);
- cross_v3_v3v3(no, d1, d2);
- l1 = normalize_v3(no);
- /* "no" is new normal projection plane, but don't move if
- * it is coplanar with both of the projection dirs */
- cross_v3_v3v3(no2, d1, bndv1->profile.proj_dir);
- l2 = normalize_v3(no2);
- cross_v3_v3v3(no3, d2, bndv2->profile.proj_dir);
- l3 = normalize_v3(no3);
- if (l1 > BEVEL_EPSILON && (l2 > BEVEL_EPSILON || l3 > BEVEL_EPSILON)) {
- dot1 = fabsf(dot_v3v3(no, no2));
- dot2 = fabsf(dot_v3v3(no, no3));
- if (fabsf(dot1 - 1.0f) > BEVEL_EPSILON) {
- copy_v3_v3(bndv1->profile.plane_no, no);
- }
- if (fabsf(dot2 - 1.0f) > BEVEL_EPSILON) {
- copy_v3_v3(bndv2->profile.plane_no, no);
- }
- }
+ float d1[3], d2[3], no[3], no2[3], no3[3], dot1, dot2, l1, l2, l3;
+
+ /* only do this if projecting, and d1, d2, and proj_dir are not coplanar */
+ if (is_zero_v3(bndv1->profile.proj_dir) || is_zero_v3(bndv2->profile.proj_dir)) {
+ return;
+ }
+ sub_v3_v3v3(d1, bv->v->co, bndv1->nv.co);
+ sub_v3_v3v3(d2, bv->v->co, bndv2->nv.co);
+ cross_v3_v3v3(no, d1, d2);
+ l1 = normalize_v3(no);
+ /* "no" is new normal projection plane, but don't move if
+ * it is coplanar with both of the projection dirs */
+ cross_v3_v3v3(no2, d1, bndv1->profile.proj_dir);
+ l2 = normalize_v3(no2);
+ cross_v3_v3v3(no3, d2, bndv2->profile.proj_dir);
+ l3 = normalize_v3(no3);
+ if (l1 > BEVEL_EPSILON && (l2 > BEVEL_EPSILON || l3 > BEVEL_EPSILON)) {
+ dot1 = fabsf(dot_v3v3(no, no2));
+ dot2 = fabsf(dot_v3v3(no, no3));
+ if (fabsf(dot1 - 1.0f) > BEVEL_EPSILON) {
+ copy_v3_v3(bndv1->profile.plane_no, no);
+ }
+ if (fabsf(dot2 - 1.0f) > BEVEL_EPSILON) {
+ copy_v3_v3(bndv2->profile.plane_no, no);
+ }
+ }
}
/* return 1 if a and b are in CCW order on the normal side of f,
* and -1 if they are reversed, and 0 if there is no shared face f */
static int bev_ccw_test(BMEdge *a, BMEdge *b, BMFace *f)
{
- BMLoop *la, *lb;
-
- if (!f) {
- return 0;
- }
- la = BM_face_edge_share_loop(f, a);
- lb = BM_face_edge_share_loop(f, b);
- if (!la || !lb) {
- return 0;
- }
- return lb->next == la ? 1 : -1;
+ BMLoop *la, *lb;
+
+ if (!f) {
+ return 0;
+ }
+ la = BM_face_edge_share_loop(f, a);
+ lb = BM_face_edge_share_loop(f, b);
+ if (!la || !lb) {
+ return 0;
+ }
+ return lb->next == la ? 1 : -1;
}
/* Fill matrix r_mat so that a point in the sheared parallelogram with corners
@@ -1394,44 +1408,45 @@ static int bev_ccw_test(BMEdge *a, BMEdge *b, BMFace *f)
* and B has the right side as columns - both extended into homogeneous coords.
* So M = B*(Ainverse). Doing Ainverse by hand gives the code below.
*/
-static bool make_unit_square_map(
- const float va[3], const float vmid[3], const float vb[3],
- float r_mat[4][4])
+static bool make_unit_square_map(const float va[3],
+ const float vmid[3],
+ const float vb[3],
+ float r_mat[4][4])
{
- float vo[3], vd[3], vb_vmid[3], va_vmid[3], vddir[3];
-
- sub_v3_v3v3(va_vmid, vmid, va);
- sub_v3_v3v3(vb_vmid, vmid, vb);
-
- if (is_zero_v3(va_vmid) || is_zero_v3(vb_vmid)) {
- return false;
- }
-
- if (fabsf(angle_v3v3(va_vmid, vb_vmid) - (float)M_PI) <= BEVEL_EPSILON_ANG) {
- return false;
- }
-
- sub_v3_v3v3(vo, va, vb_vmid);
- cross_v3_v3v3(vddir, vb_vmid, va_vmid);
- normalize_v3(vddir);
- add_v3_v3v3(vd, vo, vddir);
-
- /* The cols of m are: {vmid - va, vmid - vb, vmid + vd - va -vb, va + vb - vmid;
- * blender transform matrices are stored such that m[i][*] is ith column;
- * the last elements of each col remain as they are in unity matrix. */
- sub_v3_v3v3(&r_mat[0][0], vmid, va);
- r_mat[0][3] = 0.0f;
- sub_v3_v3v3(&r_mat[1][0], vmid, vb);
- r_mat[1][3] = 0.0f;
- add_v3_v3v3(&r_mat[2][0], vmid, vd);
- sub_v3_v3(&r_mat[2][0], va);
- sub_v3_v3(&r_mat[2][0], vb);
- r_mat[2][3] = 0.0f;
- add_v3_v3v3(&r_mat[3][0], va, vb);
- sub_v3_v3(&r_mat[3][0], vmid);
- r_mat[3][3] = 1.0f;
-
- return true;
+ float vo[3], vd[3], vb_vmid[3], va_vmid[3], vddir[3];
+
+ sub_v3_v3v3(va_vmid, vmid, va);
+ sub_v3_v3v3(vb_vmid, vmid, vb);
+
+ if (is_zero_v3(va_vmid) || is_zero_v3(vb_vmid)) {
+ return false;
+ }
+
+ if (fabsf(angle_v3v3(va_vmid, vb_vmid) - (float)M_PI) <= BEVEL_EPSILON_ANG) {
+ return false;
+ }
+
+ sub_v3_v3v3(vo, va, vb_vmid);
+ cross_v3_v3v3(vddir, vb_vmid, va_vmid);
+ normalize_v3(vddir);
+ add_v3_v3v3(vd, vo, vddir);
+
+ /* The cols of m are: {vmid - va, vmid - vb, vmid + vd - va -vb, va + vb - vmid;
+ * blender transform matrices are stored such that m[i][*] is ith column;
+ * the last elements of each col remain as they are in unity matrix. */
+ sub_v3_v3v3(&r_mat[0][0], vmid, va);
+ r_mat[0][3] = 0.0f;
+ sub_v3_v3v3(&r_mat[1][0], vmid, vb);
+ r_mat[1][3] = 0.0f;
+ add_v3_v3v3(&r_mat[2][0], vmid, vd);
+ sub_v3_v3(&r_mat[2][0], va);
+ sub_v3_v3(&r_mat[2][0], vb);
+ r_mat[2][3] = 0.0f;
+ add_v3_v3v3(&r_mat[3][0], va, vb);
+ sub_v3_v3(&r_mat[3][0], vmid);
+ r_mat[3][3] = 1.0f;
+
+ return true;
}
/* Like make_unit_square_map, but this one makes a matrix that transforms the
@@ -1450,33 +1465,32 @@ static bool make_unit_square_map(
* and Blender matrices have cols at m[i][*].
*/
static void make_unit_cube_map(
- const float va[3], const float vb[3], const float vc[3],
- const float vd[3], float r_mat[4][4])
+ const float va[3], const float vb[3], const float vc[3], const float vd[3], float r_mat[4][4])
{
- copy_v3_v3(r_mat[0], va);
- sub_v3_v3(r_mat[0], vb);
- sub_v3_v3(r_mat[0], vc);
- add_v3_v3(r_mat[0], vd);
- mul_v3_fl(r_mat[0], 0.5f);
- r_mat[0][3] = 0.0f;
- copy_v3_v3(r_mat[1], vb);
- sub_v3_v3(r_mat[1], va);
- sub_v3_v3(r_mat[1], vc);
- add_v3_v3(r_mat[1], vd);
- mul_v3_fl(r_mat[1], 0.5f);
- r_mat[1][3] = 0.0f;
- copy_v3_v3(r_mat[2], vc);
- sub_v3_v3(r_mat[2], va);
- sub_v3_v3(r_mat[2], vb);
- add_v3_v3(r_mat[2], vd);
- mul_v3_fl(r_mat[2], 0.5f);
- r_mat[2][3] = 0.0f;
- copy_v3_v3(r_mat[3], va);
- add_v3_v3(r_mat[3], vb);
- add_v3_v3(r_mat[3], vc);
- sub_v3_v3(r_mat[3], vd);
- mul_v3_fl(r_mat[3], 0.5f);
- r_mat[3][3] = 1.0f;
+ copy_v3_v3(r_mat[0], va);
+ sub_v3_v3(r_mat[0], vb);
+ sub_v3_v3(r_mat[0], vc);
+ add_v3_v3(r_mat[0], vd);
+ mul_v3_fl(r_mat[0], 0.5f);
+ r_mat[0][3] = 0.0f;
+ copy_v3_v3(r_mat[1], vb);
+ sub_v3_v3(r_mat[1], va);
+ sub_v3_v3(r_mat[1], vc);
+ add_v3_v3(r_mat[1], vd);
+ mul_v3_fl(r_mat[1], 0.5f);
+ r_mat[1][3] = 0.0f;
+ copy_v3_v3(r_mat[2], vc);
+ sub_v3_v3(r_mat[2], va);
+ sub_v3_v3(r_mat[2], vb);
+ add_v3_v3(r_mat[2], vd);
+ mul_v3_fl(r_mat[2], 0.5f);
+ r_mat[2][3] = 0.0f;
+ copy_v3_v3(r_mat[3], va);
+ add_v3_v3(r_mat[3], vb);
+ add_v3_v3(r_mat[3], vc);
+ sub_v3_v3(r_mat[3], vd);
+ mul_v3_fl(r_mat[3], 0.5f);
+ r_mat[3][3] = 1.0f;
}
/* Get the coordinate on the superellipse (x^r + y^r = 1),
@@ -1485,16 +1499,16 @@ static void make_unit_cube_map(
* Assume r > 0.0 */
static double superellipse_co(double x, float r, bool rbig)
{
- BLI_assert(r > 0.0f);
-
- /* If r<1, mirror the superellipse function by (y=x)-line to get a numerically stable range
- * Possible because of symmetry, later mirror back. */
- if (rbig) {
- return pow((1.0 - pow(x, r)), (1.0 / r));
- }
- else {
- return 1.0 - pow((1.0 - pow(1.0 - x, r)), (1.0 / r));
- }
+ BLI_assert(r > 0.0f);
+
+ /* If r<1, mirror the superellipse function by (y=x)-line to get a numerically stable range
+ * Possible because of symmetry, later mirror back. */
+ if (rbig) {
+ return pow((1.0 - pow(x, r)), (1.0 / r));
+ }
+ else {
+ return 1.0 - pow((1.0 - pow(1.0 - x, r)), (1.0 / r));
+ }
}
/* Find the point on given profile at parameter i which goes from 0 to n as
@@ -1506,29 +1520,29 @@ static double superellipse_co(double x, float r, bool rbig)
* method used to make the vmesh pattern. */
static void get_profile_point(BevelParams *bp, const Profile *pro, int i, int n, float r_co[3])
{
- int d;
-
- if (bp->seg == 1) {
- if (i == 0) {
- copy_v3_v3(r_co, pro->coa);
- }
- else {
- copy_v3_v3(r_co, pro->cob);
- }
- }
-
- else {
- if (n == bp->seg) {
- BLI_assert(pro->prof_co != NULL);
- copy_v3_v3(r_co, pro->prof_co + 3 * i);
- }
- else {
- BLI_assert(is_power_of_2_i(n) && n <= bp->pro_spacing.seg_2);
- /* set d to spacing in prof_co_2 between subsamples */
- d = bp->pro_spacing.seg_2 / n;
- copy_v3_v3(r_co, pro->prof_co_2 + 3 * i * d);
- }
- }
+ int d;
+
+ if (bp->seg == 1) {
+ if (i == 0) {
+ copy_v3_v3(r_co, pro->coa);
+ }
+ else {
+ copy_v3_v3(r_co, pro->cob);
+ }
+ }
+
+ else {
+ if (n == bp->seg) {
+ BLI_assert(pro->prof_co != NULL);
+ copy_v3_v3(r_co, pro->prof_co + 3 * i);
+ }
+ else {
+ BLI_assert(is_power_of_2_i(n) && n <= bp->pro_spacing.seg_2);
+ /* set d to spacing in prof_co_2 between subsamples */
+ d = bp->pro_spacing.seg_2 / n;
+ copy_v3_v3(r_co, pro->prof_co_2 + 3 * i * d);
+ }
+ }
}
/* Calculate the actual coordinate values for bndv's profile.
@@ -1540,337 +1554,338 @@ static void get_profile_point(BevelParams *bp, const Profile *pro, int i, int n,
* during construction. */
static void calculate_profile(BevelParams *bp, BoundVert *bndv)
{
- int i, k, ns;
- const double *xvals, *yvals;
- float co[3], co2[3], p[3], m[4][4];
- float *prof_co, *prof_co_k;
- float r;
- bool need_2, map_ok;
- Profile *pro = &bndv->profile;
-
- if (bp->seg == 1) {
- return;
- }
-
- need_2 = bp->seg != bp->pro_spacing.seg_2;
- if (!pro->prof_co) {
- pro->prof_co = (float *)BLI_memarena_alloc(bp->mem_arena, (bp->seg + 1) * 3 * sizeof(float));
- if (need_2) {
- pro->prof_co_2 = (float *)BLI_memarena_alloc(bp->mem_arena, (bp->pro_spacing.seg_2 + 1) * 3 *sizeof(float));
- }
- else {
- pro->prof_co_2 = pro->prof_co;
- }
- }
- r = pro->super_r;
- if (r == PRO_LINE_R) {
- map_ok = false;
- }
- else {
- map_ok = make_unit_square_map(pro->coa, pro->midco, pro->cob, m);
- }
- for (i = 0; i < 2; i++) {
- if (i == 0) {
- ns = bp->seg;
- xvals = bp->pro_spacing.xvals;
- yvals = bp->pro_spacing.yvals;
- prof_co = pro->prof_co;
- }
- else {
- if (!need_2) {
- break; /* shares coords with pro->prof_co */
- }
- ns = bp->pro_spacing.seg_2;
- xvals = bp->pro_spacing.xvals_2;
- yvals = bp->pro_spacing.yvals_2;
- prof_co = pro->prof_co_2;
- }
- BLI_assert((r == PRO_LINE_R || (xvals != NULL && yvals != NULL)) && prof_co != NULL);
- for (k = 0; k <= ns; k++) {
- if (k == 0) {
- copy_v3_v3(co, pro->coa);
- }
- else if (k == ns) {
- copy_v3_v3(co, pro->cob);
- }
- else {
- if (map_ok) {
- p[0] = xvals[k];
- p[1] = yvals[k];
- p[2] = 0.0f;
- mul_v3_m4v3(co, m, p);
- }
- else {
- interp_v3_v3v3(co, pro->coa, pro->cob, (float)k / (float)ns);
- }
- }
- /* project co onto final profile plane */
- prof_co_k = prof_co + 3 * k;
- if (!is_zero_v3(pro->proj_dir)) {
- add_v3_v3v3(co2, co, pro->proj_dir);
- if (!isect_line_plane_v3(prof_co_k, co, co2, pro->plane_co, pro->plane_no)) {
- /* shouldn't happen */
- copy_v3_v3(prof_co_k, co);
- }
- }
- else {
- copy_v3_v3(prof_co_k, co);
- }
- }
- }
+ int i, k, ns;
+ const double *xvals, *yvals;
+ float co[3], co2[3], p[3], m[4][4];
+ float *prof_co, *prof_co_k;
+ float r;
+ bool need_2, map_ok;
+ Profile *pro = &bndv->profile;
+
+ if (bp->seg == 1) {
+ return;
+ }
+
+ need_2 = bp->seg != bp->pro_spacing.seg_2;
+ if (!pro->prof_co) {
+ pro->prof_co = (float *)BLI_memarena_alloc(bp->mem_arena, (bp->seg + 1) * 3 * sizeof(float));
+ if (need_2) {
+ pro->prof_co_2 = (float *)BLI_memarena_alloc(
+ bp->mem_arena, (bp->pro_spacing.seg_2 + 1) * 3 * sizeof(float));
+ }
+ else {
+ pro->prof_co_2 = pro->prof_co;
+ }
+ }
+ r = pro->super_r;
+ if (r == PRO_LINE_R) {
+ map_ok = false;
+ }
+ else {
+ map_ok = make_unit_square_map(pro->coa, pro->midco, pro->cob, m);
+ }
+ for (i = 0; i < 2; i++) {
+ if (i == 0) {
+ ns = bp->seg;
+ xvals = bp->pro_spacing.xvals;
+ yvals = bp->pro_spacing.yvals;
+ prof_co = pro->prof_co;
+ }
+ else {
+ if (!need_2) {
+ break; /* shares coords with pro->prof_co */
+ }
+ ns = bp->pro_spacing.seg_2;
+ xvals = bp->pro_spacing.xvals_2;
+ yvals = bp->pro_spacing.yvals_2;
+ prof_co = pro->prof_co_2;
+ }
+ BLI_assert((r == PRO_LINE_R || (xvals != NULL && yvals != NULL)) && prof_co != NULL);
+ for (k = 0; k <= ns; k++) {
+ if (k == 0) {
+ copy_v3_v3(co, pro->coa);
+ }
+ else if (k == ns) {
+ copy_v3_v3(co, pro->cob);
+ }
+ else {
+ if (map_ok) {
+ p[0] = xvals[k];
+ p[1] = yvals[k];
+ p[2] = 0.0f;
+ mul_v3_m4v3(co, m, p);
+ }
+ else {
+ interp_v3_v3v3(co, pro->coa, pro->cob, (float)k / (float)ns);
+ }
+ }
+ /* project co onto final profile plane */
+ prof_co_k = prof_co + 3 * k;
+ if (!is_zero_v3(pro->proj_dir)) {
+ add_v3_v3v3(co2, co, pro->proj_dir);
+ if (!isect_line_plane_v3(prof_co_k, co, co2, pro->plane_co, pro->plane_no)) {
+ /* shouldn't happen */
+ copy_v3_v3(prof_co_k, co);
+ }
+ }
+ else {
+ copy_v3_v3(prof_co_k, co);
+ }
+ }
+ }
}
/* Snap a direction co to a superellipsoid with parameter super_r.
* For square profiles, midline says whether or not to snap to both planes. */
static void snap_to_superellipsoid(float co[3], const float super_r, bool midline)
{
- float a, b, c, x, y, z, r, rinv, dx, dy;
-
- r = super_r;
- if (r == PRO_CIRCLE_R) {
- normalize_v3(co);
- return;
- }
-
- x = a = max_ff(0.0f, co[0]);
- y = b = max_ff(0.0f, co[1]);
- z = c = max_ff(0.0f, co[2]);
- if (r == PRO_SQUARE_R || r == PRO_SQUARE_IN_R) {
- /* will only be called for 2d profile */
- BLI_assert(fabsf(z) < BEVEL_EPSILON);
- z = 0.0f;
- x = min_ff(1.0f, x);
- y = min_ff(1.0f, y);
- if (r == PRO_SQUARE_R) {
- /* snap to closer of x==1 and y==1 lines, or maybe both */
- dx = 1.0f - x;
- dy = 1.0f - y;
- if (dx < dy) {
- x = 1.0f;
- y = midline ? 1.0f : y;
- }
- else {
- y = 1.0f;
- x = midline ? 1.0f : x;
- }
- }
- else {
- /* snap to closer of x==0 and y==0 lines, or maybe both */
- if (x < y) {
- x = 0.0f;
- y = midline ? 0.0f : y;
- }
- else {
- y = 0.0f;
- x = midline ? 0.0f : x;
- }
- }
- }
- else {
- rinv = 1.0f / r;
- if (a == 0.0f) {
- if (b == 0.0f) {
- x = 0.0f;
- y = 0.0f;
- z = powf(c, rinv);
- }
- else {
- x = 0.0f;
- y = powf(1.0f / (1.0f + powf(c / b, r)), rinv);
- z = c * y / b;
- }
- }
- else {
- x = powf(1.0f / (1.0f + powf(b / a, r) + powf(c / a, r)), rinv);
- y = b * x / a;
- z = c * x / a;
- }
- }
- co[0] = x;
- co[1] = y;
- co[2] = z;
+ float a, b, c, x, y, z, r, rinv, dx, dy;
+
+ r = super_r;
+ if (r == PRO_CIRCLE_R) {
+ normalize_v3(co);
+ return;
+ }
+
+ x = a = max_ff(0.0f, co[0]);
+ y = b = max_ff(0.0f, co[1]);
+ z = c = max_ff(0.0f, co[2]);
+ if (r == PRO_SQUARE_R || r == PRO_SQUARE_IN_R) {
+ /* will only be called for 2d profile */
+ BLI_assert(fabsf(z) < BEVEL_EPSILON);
+ z = 0.0f;
+ x = min_ff(1.0f, x);
+ y = min_ff(1.0f, y);
+ if (r == PRO_SQUARE_R) {
+ /* snap to closer of x==1 and y==1 lines, or maybe both */
+ dx = 1.0f - x;
+ dy = 1.0f - y;
+ if (dx < dy) {
+ x = 1.0f;
+ y = midline ? 1.0f : y;
+ }
+ else {
+ y = 1.0f;
+ x = midline ? 1.0f : x;
+ }
+ }
+ else {
+ /* snap to closer of x==0 and y==0 lines, or maybe both */
+ if (x < y) {
+ x = 0.0f;
+ y = midline ? 0.0f : y;
+ }
+ else {
+ y = 0.0f;
+ x = midline ? 0.0f : x;
+ }
+ }
+ }
+ else {
+ rinv = 1.0f / r;
+ if (a == 0.0f) {
+ if (b == 0.0f) {
+ x = 0.0f;
+ y = 0.0f;
+ z = powf(c, rinv);
+ }
+ else {
+ x = 0.0f;
+ y = powf(1.0f / (1.0f + powf(c / b, r)), rinv);
+ z = c * y / b;
+ }
+ }
+ else {
+ x = powf(1.0f / (1.0f + powf(b / a, r) + powf(c / a, r)), rinv);
+ y = b * x / a;
+ z = c * x / a;
+ }
+ }
+ co[0] = x;
+ co[1] = y;
+ co[2] = z;
}
#define BEV_EXTEND_EDGE_DATA_CHECK(eh, flag) (BM_elem_flag_test(eh->e, flag))
static void check_edge_data_seam_sharp_edges(BevVert *bv, int flag, bool neg)
{
- EdgeHalf *e = &bv->edges[0], *efirst = &bv->edges[0];
-
- /* First first edge with seam or sharp edge data */
- while ((!neg && !BEV_EXTEND_EDGE_DATA_CHECK(e, flag)) || (neg && BEV_EXTEND_EDGE_DATA_CHECK(e, flag))) {
- e = e->next;
- if (e == efirst) {
- break;
- }
- }
-
- /* If no such edge found, return */
- if ((!neg && !BEV_EXTEND_EDGE_DATA_CHECK(e, flag)) || (neg && BEV_EXTEND_EDGE_DATA_CHECK(e, flag))) {
- return;
- }
-
- /* Set efirst to this first encountered edge. */
- efirst = e;
-
- do {
- int flag_count = 0;
- EdgeHalf *ne = e->next;
-
- while (((!neg && !BEV_EXTEND_EDGE_DATA_CHECK(ne, flag)) || (neg && BEV_EXTEND_EDGE_DATA_CHECK(ne, flag))) &&
- ne != efirst)
- {
- if (ne->is_bev) {
- flag_count++;
- }
- ne = ne->next;
- }
- if (ne == e || (ne == efirst && ((!neg && !BEV_EXTEND_EDGE_DATA_CHECK(efirst, flag)) ||
- (neg && BEV_EXTEND_EDGE_DATA_CHECK(efirst, flag)))))
- {
- break;
- }
- /* Set seam_len / sharp_len of starting edge */
- if (flag == BM_ELEM_SEAM) {
- e->rightv->seam_len = flag_count;
- }
- else if (flag == BM_ELEM_SMOOTH) {
- e->rightv->sharp_len = flag_count;
- }
- e = ne;
- } while (e != efirst);
+ EdgeHalf *e = &bv->edges[0], *efirst = &bv->edges[0];
+
+ /* First first edge with seam or sharp edge data */
+ while ((!neg && !BEV_EXTEND_EDGE_DATA_CHECK(e, flag)) ||
+ (neg && BEV_EXTEND_EDGE_DATA_CHECK(e, flag))) {
+ e = e->next;
+ if (e == efirst) {
+ break;
+ }
+ }
+
+ /* If no such edge found, return */
+ if ((!neg && !BEV_EXTEND_EDGE_DATA_CHECK(e, flag)) ||
+ (neg && BEV_EXTEND_EDGE_DATA_CHECK(e, flag))) {
+ return;
+ }
+
+ /* Set efirst to this first encountered edge. */
+ efirst = e;
+
+ do {
+ int flag_count = 0;
+ EdgeHalf *ne = e->next;
+
+ while (((!neg && !BEV_EXTEND_EDGE_DATA_CHECK(ne, flag)) ||
+ (neg && BEV_EXTEND_EDGE_DATA_CHECK(ne, flag))) &&
+ ne != efirst) {
+ if (ne->is_bev) {
+ flag_count++;
+ }
+ ne = ne->next;
+ }
+ if (ne == e || (ne == efirst && ((!neg && !BEV_EXTEND_EDGE_DATA_CHECK(efirst, flag)) ||
+ (neg && BEV_EXTEND_EDGE_DATA_CHECK(efirst, flag))))) {
+ break;
+ }
+ /* Set seam_len / sharp_len of starting edge */
+ if (flag == BM_ELEM_SEAM) {
+ e->rightv->seam_len = flag_count;
+ }
+ else if (flag == BM_ELEM_SMOOTH) {
+ e->rightv->sharp_len = flag_count;
+ }
+ e = ne;
+ } while (e != efirst);
}
static void bevel_extend_edge_data(BevVert *bv)
{
- VMesh *vm = bv->vmesh;
-
- BoundVert *bcur = bv->vmesh->boundstart, *start = bcur;
-
- do {
- /* If current boundvert has a seam length > 0 then it has a seam running along its edges */
- if (bcur->seam_len) {
- if (!bv->vmesh->boundstart->seam_len && start == bv->vmesh->boundstart) {
- start = bcur; /* set start to first boundvert with seam_len > 0 */
- }
-
- /* Now for all the mesh_verts starting at current index and ending at idxlen
- * We go through outermost ring and through all its segments and add seams
- * for those edges */
- int idxlen = bcur->index + bcur->seam_len;
- for (int i = bcur->index; i < idxlen; i++) {
- BMVert *v1 = mesh_vert(vm, i % vm->count, 0, 0)->v, *v2;
- BMEdge *e;
- for (int k = 1; k < vm->seg; k++) {
- v2 = mesh_vert(vm, i % vm->count, 0, k)->v;
-
- /* Here v1 & v2 are current and next BMverts, we find common edge and set its edge data */
- e = v1->e;
- while (e->v1 != v2 && e->v2 != v2) {
- if (e->v1 == v1) {
- e = e->v1_disk_link.next;
- }
- else {
- e = e->v2_disk_link.next;
- }
- }
- BM_elem_flag_set(e, BM_ELEM_SEAM, true);
- v1 = v2;
- }
- BMVert *v3 = mesh_vert(vm, (i + 1) % vm->count, 0, 0)->v;
- e = v1->e; //Do same as above for first and last vert
- while (e->v1 != v3 && e->v2 != v3) {
- if (e->v1 == v1) {
- e = e->v1_disk_link.next;
- }
- else {
- e = e->v2_disk_link.next;
- }
- }
- BM_elem_flag_set(e, BM_ELEM_SEAM, true);
- bcur = bcur->next;
- }
- }
- else {
- bcur = bcur->next;
- }
- } while (bcur != start);
-
-
- bcur = bv->vmesh->boundstart;
- start = bcur;
- do {
- if (bcur->sharp_len) {
- if (!bv->vmesh->boundstart->sharp_len && start == bv->vmesh->boundstart) {
- start = bcur;
- }
-
- int idxlen = bcur->index + bcur->sharp_len;
- for (int i = bcur->index; i < idxlen; i++) {
- BMVert *v1 = mesh_vert(vm, i % vm->count, 0, 0)->v, *v2;
- BMEdge *e;
- for (int k = 1; k < vm->seg; k++) {
- v2 = mesh_vert(vm, i % vm->count, 0, k)->v;
-
- e = v1->e;
- while (e->v1 != v2 && e->v2 != v2) {
- if (e->v1 == v1) {
- e = e->v1_disk_link.next;
- }
- else {
- e = e->v2_disk_link.next;
- }
- }
- BM_elem_flag_set(e, BM_ELEM_SMOOTH, false);
- v1 = v2;
- }
- BMVert *v3 = mesh_vert(vm, (i + 1) % vm->count, 0, 0)->v;
- e = v1->e;
- while (e->v1 != v3 && e->v2 != v3) {
- if (e->v1 == v1) {
- e = e->v1_disk_link.next;
- }
- else {
- e = e->v2_disk_link.next;
- }
- }
- BM_elem_flag_set(e, BM_ELEM_SMOOTH, false);
- bcur = bcur->next;
- }
- }
- else {
- bcur = bcur->next;
- }
- } while (bcur != start);
+ VMesh *vm = bv->vmesh;
+
+ BoundVert *bcur = bv->vmesh->boundstart, *start = bcur;
+
+ do {
+ /* If current boundvert has a seam length > 0 then it has a seam running along its edges */
+ if (bcur->seam_len) {
+ if (!bv->vmesh->boundstart->seam_len && start == bv->vmesh->boundstart) {
+ start = bcur; /* set start to first boundvert with seam_len > 0 */
+ }
+
+ /* Now for all the mesh_verts starting at current index and ending at idxlen
+ * We go through outermost ring and through all its segments and add seams
+ * for those edges */
+ int idxlen = bcur->index + bcur->seam_len;
+ for (int i = bcur->index; i < idxlen; i++) {
+ BMVert *v1 = mesh_vert(vm, i % vm->count, 0, 0)->v, *v2;
+ BMEdge *e;
+ for (int k = 1; k < vm->seg; k++) {
+ v2 = mesh_vert(vm, i % vm->count, 0, k)->v;
+
+ /* Here v1 & v2 are current and next BMverts, we find common edge and set its edge data */
+ e = v1->e;
+ while (e->v1 != v2 && e->v2 != v2) {
+ if (e->v1 == v1) {
+ e = e->v1_disk_link.next;
+ }
+ else {
+ e = e->v2_disk_link.next;
+ }
+ }
+ BM_elem_flag_set(e, BM_ELEM_SEAM, true);
+ v1 = v2;
+ }
+ BMVert *v3 = mesh_vert(vm, (i + 1) % vm->count, 0, 0)->v;
+ e = v1->e; //Do same as above for first and last vert
+ while (e->v1 != v3 && e->v2 != v3) {
+ if (e->v1 == v1) {
+ e = e->v1_disk_link.next;
+ }
+ else {
+ e = e->v2_disk_link.next;
+ }
+ }
+ BM_elem_flag_set(e, BM_ELEM_SEAM, true);
+ bcur = bcur->next;
+ }
+ }
+ else {
+ bcur = bcur->next;
+ }
+ } while (bcur != start);
+
+ bcur = bv->vmesh->boundstart;
+ start = bcur;
+ do {
+ if (bcur->sharp_len) {
+ if (!bv->vmesh->boundstart->sharp_len && start == bv->vmesh->boundstart) {
+ start = bcur;
+ }
+
+ int idxlen = bcur->index + bcur->sharp_len;
+ for (int i = bcur->index; i < idxlen; i++) {
+ BMVert *v1 = mesh_vert(vm, i % vm->count, 0, 0)->v, *v2;
+ BMEdge *e;
+ for (int k = 1; k < vm->seg; k++) {
+ v2 = mesh_vert(vm, i % vm->count, 0, k)->v;
+
+ e = v1->e;
+ while (e->v1 != v2 && e->v2 != v2) {
+ if (e->v1 == v1) {
+ e = e->v1_disk_link.next;
+ }
+ else {
+ e = e->v2_disk_link.next;
+ }
+ }
+ BM_elem_flag_set(e, BM_ELEM_SMOOTH, false);
+ v1 = v2;
+ }
+ BMVert *v3 = mesh_vert(vm, (i + 1) % vm->count, 0, 0)->v;
+ e = v1->e;
+ while (e->v1 != v3 && e->v2 != v3) {
+ if (e->v1 == v1) {
+ e = e->v1_disk_link.next;
+ }
+ else {
+ e = e->v2_disk_link.next;
+ }
+ }
+ BM_elem_flag_set(e, BM_ELEM_SMOOTH, false);
+ bcur = bcur->next;
+ }
+ }
+ else {
+ bcur = bcur->next;
+ }
+ } while (bcur != start);
}
/* Mark edges as sharp if they are between a smooth recon face and a new face. */
static void bevel_edges_sharp_boundary(BMesh *bm, BevelParams *bp)
{
- BMIter fiter, liter;
- BMFace *f, *fother;
- BMLoop *l, *lother;
- FKind fkind;
-
- BM_ITER_MESH(f, &fiter, bm, BM_FACES_OF_MESH) {
- if (!BM_elem_flag_test(f, BM_ELEM_SMOOTH)) {
- continue;
- }
- if (get_face_kind(bp, f) != F_RECON) {
- continue;
- }
- BM_ITER_ELEM(l, &liter, f, BM_LOOPS_OF_FACE) {
- /* cases we care about will have exactly one adjacent face */
- lother = l->radial_next;
- fother = lother->f;
- if (lother != l && fother) {
- fkind = get_face_kind(bp, lother->f);
- if (ELEM(fkind, F_EDGE, F_VERT)) {
- BM_elem_flag_disable(l->e, BM_ELEM_SMOOTH);
- }
- }
- }
- }
+ BMIter fiter, liter;
+ BMFace *f, *fother;
+ BMLoop *l, *lother;
+ FKind fkind;
+
+ BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
+ if (!BM_elem_flag_test(f, BM_ELEM_SMOOTH)) {
+ continue;
+ }
+ if (get_face_kind(bp, f) != F_RECON) {
+ continue;
+ }
+ BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
+ /* cases we care about will have exactly one adjacent face */
+ lother = l->radial_next;
+ fother = lother->f;
+ if (lother != l && fother) {
+ fkind = get_face_kind(bp, lother->f);
+ if (ELEM(fkind, F_EDGE, F_VERT)) {
+ BM_elem_flag_disable(l->e, BM_ELEM_SMOOTH);
+ }
+ }
+ }
+ }
}
/**
@@ -1882,285 +1897,282 @@ static void bevel_edges_sharp_boundary(BMesh *bm, BevelParams *bp)
*/
static void bevel_harden_normals(BMesh *bm, BevelParams *bp)
{
- BMIter liter, fiter;
- BMFace *f;
- BMLoop *l, *lnext, *lprev, *lprevprev, *lnextnext;
- BMEdge *estep;
- FKind fkind, fprevkind, fnextkind, fprevprevkind, fnextnextkind;
- int cd_clnors_offset, l_index;
- short *clnors;
- float *pnorm, norm[3];
-
- if (bp->offset == 0.0 || !bp->harden_normals) {
- return;
- }
-
- /* recalculate all face and vertex normals; side effect: ensures vertex, edge, face indices */
- /* I suspect this is not necessary: TODO: test that guess */
- BM_mesh_normals_update(bm);
-
- cd_clnors_offset = CustomData_get_offset(&bm->ldata, CD_CUSTOMLOOPNORMAL);
-
- /* If there is not already a custom split normal layer then making one (with BM_lnorspace_update)
- * will not respect the autosmooth angle between smooth faces. To get that to happen, we have
- * to mark the sharpen the edges that are only sharp because of the angle test -- otherwise would be smooth.
- */
- if (cd_clnors_offset == -1) {
- BM_edges_sharp_from_angle_set(bm, bp->smoothresh);
- bevel_edges_sharp_boundary(bm, bp);
- }
-
- /* ensure that bm->lnor_spacearr has properly stored loop normals; side effect: ensures loop indices */
- BM_lnorspace_update(bm);
-
- if (cd_clnors_offset == -1) {
- cd_clnors_offset = CustomData_get_offset(&bm->ldata, CD_CUSTOMLOOPNORMAL);
- }
-
- BM_ITER_MESH(f, &fiter, bm, BM_FACES_OF_MESH) {
- fkind = get_face_kind(bp, f);
- if (fkind == F_ORIG || fkind == F_RECON) {
- continue;
- }
- BM_ITER_ELEM(l, &liter, f, BM_LOOPS_OF_FACE) {
- estep = l->prev->e; /* causes CW walk around l->v fan */
- lprev = BM_vert_step_fan_loop(l, &estep);
- estep = l->e; /* causes CCW walk around l->v fan */
- lnext = BM_vert_step_fan_loop(l, &estep);
- fprevkind = lprev ? get_face_kind(bp, lprev->f) : F_NONE;
- fnextkind = lnext ? get_face_kind(bp, lnext->f) : F_NONE;
- pnorm = NULL;
- if (fkind == F_EDGE) {
- if (fprevkind == F_EDGE && BM_elem_flag_test(l, BM_ELEM_LONG_TAG)) {
- add_v3_v3v3(norm, f->no, lprev->f->no);
- pnorm = norm;
- }
- else if (fnextkind == F_EDGE && BM_elem_flag_test(lnext, BM_ELEM_LONG_TAG)) {
- add_v3_v3v3(norm, f->no, lnext->f->no);
- pnorm = norm;
- }
- else if (fprevkind == F_RECON && BM_elem_flag_test(l, BM_ELEM_LONG_TAG)) {
- pnorm = lprev->f->no;
- }
- else if (fnextkind == F_RECON && BM_elem_flag_test(l->prev, BM_ELEM_LONG_TAG)) {
- pnorm = lnext->f->no;
- }
- else {
- /* printf("unexpected harden case (edge)\n"); */
- }
- }
- else if (fkind == F_VERT) {
- if (fprevkind == F_VERT && fnextkind == F_VERT) {
- pnorm = l->v->no;
- }
- else if (fprevkind == F_RECON) {
- pnorm = lprev->f->no;
- }
- else if (fnextkind == F_RECON) {
- pnorm = lnext->f->no;
- }
- else {
- if (lprev) {
- estep = lprev->prev->e;
- lprevprev = BM_vert_step_fan_loop(lprev, &estep);
- }
- else {
- lprevprev = NULL;
- }
- if (lnext) {
- estep = lnext->e;
- lnextnext = BM_vert_step_fan_loop(lnext, &estep);
- }
- else {
- lnextnext = NULL;
- }
- fprevprevkind = lprevprev ? get_face_kind(bp, lprevprev->f) : F_NONE;
- fnextnextkind = lnextnext ? get_face_kind(bp, lnextnext->f) : F_NONE;
- if (fprevkind == F_EDGE && fprevprevkind == F_RECON) {
- pnorm = lprevprev->f->no;
- }
- else if (fprevkind == F_EDGE && fnextkind == F_VERT && fprevprevkind == F_EDGE) {
- add_v3_v3v3(norm, lprev->f->no, lprevprev->f->no);
- pnorm = norm;
- }
- else if (fnextkind == F_EDGE && fprevkind == F_VERT && fnextnextkind == F_EDGE) {
- add_v3_v3v3(norm, lnext->f->no, lnextnext->f->no);
- pnorm = norm;
- }
- else {
- /* printf("unexpected harden case (vert)\n"); */
- }
- }
- }
- if (pnorm) {
- if (pnorm == norm) {
- normalize_v3(norm);
- }
- l_index = BM_elem_index_get(l);
- clnors = BM_ELEM_CD_GET_VOID_P(l, cd_clnors_offset);
- BKE_lnor_space_custom_normal_to_data(
- bm->lnor_spacearr->lspacearr[l_index], pnorm, clnors);
- }
- }
- }
+ BMIter liter, fiter;
+ BMFace *f;
+ BMLoop *l, *lnext, *lprev, *lprevprev, *lnextnext;
+ BMEdge *estep;
+ FKind fkind, fprevkind, fnextkind, fprevprevkind, fnextnextkind;
+ int cd_clnors_offset, l_index;
+ short *clnors;
+ float *pnorm, norm[3];
+
+ if (bp->offset == 0.0 || !bp->harden_normals) {
+ return;
+ }
+
+ /* recalculate all face and vertex normals; side effect: ensures vertex, edge, face indices */
+ /* I suspect this is not necessary: TODO: test that guess */
+ BM_mesh_normals_update(bm);
+
+ cd_clnors_offset = CustomData_get_offset(&bm->ldata, CD_CUSTOMLOOPNORMAL);
+
+ /* If there is not already a custom split normal layer then making one (with BM_lnorspace_update)
+ * will not respect the autosmooth angle between smooth faces. To get that to happen, we have
+ * to mark the sharpen the edges that are only sharp because of the angle test -- otherwise would be smooth.
+ */
+ if (cd_clnors_offset == -1) {
+ BM_edges_sharp_from_angle_set(bm, bp->smoothresh);
+ bevel_edges_sharp_boundary(bm, bp);
+ }
+
+ /* ensure that bm->lnor_spacearr has properly stored loop normals; side effect: ensures loop indices */
+ BM_lnorspace_update(bm);
+
+ if (cd_clnors_offset == -1) {
+ cd_clnors_offset = CustomData_get_offset(&bm->ldata, CD_CUSTOMLOOPNORMAL);
+ }
+
+ BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
+ fkind = get_face_kind(bp, f);
+ if (fkind == F_ORIG || fkind == F_RECON) {
+ continue;
+ }
+ BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
+ estep = l->prev->e; /* causes CW walk around l->v fan */
+ lprev = BM_vert_step_fan_loop(l, &estep);
+ estep = l->e; /* causes CCW walk around l->v fan */
+ lnext = BM_vert_step_fan_loop(l, &estep);
+ fprevkind = lprev ? get_face_kind(bp, lprev->f) : F_NONE;
+ fnextkind = lnext ? get_face_kind(bp, lnext->f) : F_NONE;
+ pnorm = NULL;
+ if (fkind == F_EDGE) {
+ if (fprevkind == F_EDGE && BM_elem_flag_test(l, BM_ELEM_LONG_TAG)) {
+ add_v3_v3v3(norm, f->no, lprev->f->no);
+ pnorm = norm;
+ }
+ else if (fnextkind == F_EDGE && BM_elem_flag_test(lnext, BM_ELEM_LONG_TAG)) {
+ add_v3_v3v3(norm, f->no, lnext->f->no);
+ pnorm = norm;
+ }
+ else if (fprevkind == F_RECON && BM_elem_flag_test(l, BM_ELEM_LONG_TAG)) {
+ pnorm = lprev->f->no;
+ }
+ else if (fnextkind == F_RECON && BM_elem_flag_test(l->prev, BM_ELEM_LONG_TAG)) {
+ pnorm = lnext->f->no;
+ }
+ else {
+ /* printf("unexpected harden case (edge)\n"); */
+ }
+ }
+ else if (fkind == F_VERT) {
+ if (fprevkind == F_VERT && fnextkind == F_VERT) {
+ pnorm = l->v->no;
+ }
+ else if (fprevkind == F_RECON) {
+ pnorm = lprev->f->no;
+ }
+ else if (fnextkind == F_RECON) {
+ pnorm = lnext->f->no;
+ }
+ else {
+ if (lprev) {
+ estep = lprev->prev->e;
+ lprevprev = BM_vert_step_fan_loop(lprev, &estep);
+ }
+ else {
+ lprevprev = NULL;
+ }
+ if (lnext) {
+ estep = lnext->e;
+ lnextnext = BM_vert_step_fan_loop(lnext, &estep);
+ }
+ else {
+ lnextnext = NULL;
+ }
+ fprevprevkind = lprevprev ? get_face_kind(bp, lprevprev->f) : F_NONE;
+ fnextnextkind = lnextnext ? get_face_kind(bp, lnextnext->f) : F_NONE;
+ if (fprevkind == F_EDGE && fprevprevkind == F_RECON) {
+ pnorm = lprevprev->f->no;
+ }
+ else if (fprevkind == F_EDGE && fnextkind == F_VERT && fprevprevkind == F_EDGE) {
+ add_v3_v3v3(norm, lprev->f->no, lprevprev->f->no);
+ pnorm = norm;
+ }
+ else if (fnextkind == F_EDGE && fprevkind == F_VERT && fnextnextkind == F_EDGE) {
+ add_v3_v3v3(norm, lnext->f->no, lnextnext->f->no);
+ pnorm = norm;
+ }
+ else {
+ /* printf("unexpected harden case (vert)\n"); */
+ }
+ }
+ }
+ if (pnorm) {
+ if (pnorm == norm) {
+ normalize_v3(norm);
+ }
+ l_index = BM_elem_index_get(l);
+ clnors = BM_ELEM_CD_GET_VOID_P(l, cd_clnors_offset);
+ BKE_lnor_space_custom_normal_to_data(bm->lnor_spacearr->lspacearr[l_index], pnorm, clnors);
+ }
+ }
+ }
}
static void bevel_set_weighted_normal_face_strength(BMesh *bm, BevelParams *bp)
{
- BMFace *f;
- BMIter fiter;
- FKind fkind;
- int strength;
- int mode = bp->face_strength_mode;
- bool do_set_strength;
- const char *wn_layer_id = MOD_WEIGHTEDNORMALS_FACEWEIGHT_CDLAYER_ID;
- int cd_prop_int_idx = CustomData_get_named_layer_index(&bm->pdata, CD_PROP_INT, wn_layer_id);
-
- if (cd_prop_int_idx == -1) {
- BM_data_layer_add_named(bm, &bm->pdata, CD_PROP_INT, wn_layer_id);
- cd_prop_int_idx = CustomData_get_named_layer_index(&bm->pdata, CD_PROP_INT, wn_layer_id);
- }
- cd_prop_int_idx -= CustomData_get_layer_index(&bm->pdata, CD_PROP_INT);
- const int cd_prop_int_offset = CustomData_get_n_offset(&bm->pdata, CD_PROP_INT, cd_prop_int_idx);
-
- BM_ITER_MESH(f, &fiter, bm, BM_FACES_OF_MESH) {
- fkind = get_face_kind(bp, f);
- do_set_strength = true;
- switch (fkind) {
- case F_VERT:
- strength = FACE_STRENGTH_WEAK;
- do_set_strength = (mode >= BEVEL_FACE_STRENGTH_NEW);
- break;
- case F_EDGE:
- strength = FACE_STRENGTH_MEDIUM;
- do_set_strength = (mode >= BEVEL_FACE_STRENGTH_NEW);
- break;
- case F_RECON:
- strength = FACE_STRENGTH_STRONG;
- do_set_strength = (mode >= BEVEL_FACE_STRENGTH_AFFECTED);
- break;
- case F_ORIG:
- strength = FACE_STRENGTH_STRONG;
- do_set_strength = (mode == BEVEL_FACE_STRENGTH_ALL);
- break;
- default:
- do_set_strength = false;
- }
- if (do_set_strength) {
- int *strength_ptr = BM_ELEM_CD_GET_VOID_P(f, cd_prop_int_offset);
- *strength_ptr = strength;
- }
- }
+ BMFace *f;
+ BMIter fiter;
+ FKind fkind;
+ int strength;
+ int mode = bp->face_strength_mode;
+ bool do_set_strength;
+ const char *wn_layer_id = MOD_WEIGHTEDNORMALS_FACEWEIGHT_CDLAYER_ID;
+ int cd_prop_int_idx = CustomData_get_named_layer_index(&bm->pdata, CD_PROP_INT, wn_layer_id);
+
+ if (cd_prop_int_idx == -1) {
+ BM_data_layer_add_named(bm, &bm->pdata, CD_PROP_INT, wn_layer_id);
+ cd_prop_int_idx = CustomData_get_named_layer_index(&bm->pdata, CD_PROP_INT, wn_layer_id);
+ }
+ cd_prop_int_idx -= CustomData_get_layer_index(&bm->pdata, CD_PROP_INT);
+ const int cd_prop_int_offset = CustomData_get_n_offset(&bm->pdata, CD_PROP_INT, cd_prop_int_idx);
+
+ BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
+ fkind = get_face_kind(bp, f);
+ do_set_strength = true;
+ switch (fkind) {
+ case F_VERT:
+ strength = FACE_STRENGTH_WEAK;
+ do_set_strength = (mode >= BEVEL_FACE_STRENGTH_NEW);
+ break;
+ case F_EDGE:
+ strength = FACE_STRENGTH_MEDIUM;
+ do_set_strength = (mode >= BEVEL_FACE_STRENGTH_NEW);
+ break;
+ case F_RECON:
+ strength = FACE_STRENGTH_STRONG;
+ do_set_strength = (mode >= BEVEL_FACE_STRENGTH_AFFECTED);
+ break;
+ case F_ORIG:
+ strength = FACE_STRENGTH_STRONG;
+ do_set_strength = (mode == BEVEL_FACE_STRENGTH_ALL);
+ break;
+ default:
+ do_set_strength = false;
+ }
+ if (do_set_strength) {
+ int *strength_ptr = BM_ELEM_CD_GET_VOID_P(f, cd_prop_int_offset);
+ *strength_ptr = strength;
+ }
+ }
}
/* Set the any_seam property for a BevVert and all its BoundVerts */
static void set_bound_vert_seams(BevVert *bv, bool mark_seam, bool mark_sharp)
{
- BoundVert *v;
- EdgeHalf *e;
-
- bv->any_seam = false;
- v = bv->vmesh->boundstart;
- do {
- v->any_seam = false;
- for (e = v->efirst; e; e = e->next) {
- v->any_seam |= e->is_seam;
- if (e == v->elast) {
- break;
- }
- }
- bv->any_seam |= v->any_seam;
- } while ((v = v->next) != bv->vmesh->boundstart);
-
- if (mark_seam) {
- check_edge_data_seam_sharp_edges(bv, BM_ELEM_SEAM, false);
- }
- if (mark_sharp) {
- check_edge_data_seam_sharp_edges(bv, BM_ELEM_SMOOTH, true);
- }
+ BoundVert *v;
+ EdgeHalf *e;
+
+ bv->any_seam = false;
+ v = bv->vmesh->boundstart;
+ do {
+ v->any_seam = false;
+ for (e = v->efirst; e; e = e->next) {
+ v->any_seam |= e->is_seam;
+ if (e == v->elast) {
+ break;
+ }
+ }
+ bv->any_seam |= v->any_seam;
+ } while ((v = v->next) != bv->vmesh->boundstart);
+
+ if (mark_seam) {
+ check_edge_data_seam_sharp_edges(bv, BM_ELEM_SEAM, false);
+ }
+ if (mark_sharp) {
+ check_edge_data_seam_sharp_edges(bv, BM_ELEM_SMOOTH, true);
+ }
}
static int count_bound_vert_seams(BevVert *bv)
{
- int ans, i;
-
- if (!bv->any_seam) {
- return 0;
- }
-
- ans = 0;
- for (i = 0; i < bv->edgecount; i++)
- if (bv->edges[i].is_seam) {
- ans++;
- }
- return ans;
+ int ans, i;
+
+ if (!bv->any_seam) {
+ return 0;
+ }
+
+ ans = 0;
+ for (i = 0; i < bv->edgecount; i++)
+ if (bv->edges[i].is_seam) {
+ ans++;
+ }
+ return ans;
}
/* Is e between two planes where angle between is 180? */
static bool eh_on_plane(EdgeHalf *e)
{
- float dot;
-
- if (e->fprev && e->fnext) {
- dot = dot_v3v3(e->fprev->no, e->fnext->no);
- if (fabsf(dot) <= BEVEL_EPSILON_BIG ||
- fabsf(dot - 1.0f) <= BEVEL_EPSILON_BIG)
- {
- return true;
- }
- }
- return false;
+ float dot;
+
+ if (e->fprev && e->fnext) {
+ dot = dot_v3v3(e->fprev->no, e->fnext->no);
+ if (fabsf(dot) <= BEVEL_EPSILON_BIG || fabsf(dot - 1.0f) <= BEVEL_EPSILON_BIG) {
+ return true;
+ }
+ }
+ return false;
}
/* Calculate the profiles for all the BoundVerts of VMesh vm */
static void calculate_vm_profiles(BevelParams *bp, BevVert *bv, VMesh *vm)
{
- BoundVert *v;
+ BoundVert *v;
- v = vm->boundstart;
- do {
- set_profile_params(bp, bv, v);
- calculate_profile(bp, v);
- } while ((v = v->next) != vm->boundstart);
+ v = vm->boundstart;
+ do {
+ set_profile_params(bp, bv, v);
+ calculate_profile(bp, v);
+ } while ((v = v->next) != vm->boundstart);
}
/* Implements build_boundary for vertex-only case */
static void build_boundary_vertex_only(BevelParams *bp, BevVert *bv, bool construct)
{
- VMesh *vm = bv->vmesh;
- EdgeHalf *efirst, *e;
- BoundVert *v;
- float co[3];
-
- BLI_assert(bp->vertex_only);
-
- e = efirst = &bv->edges[0];
- do {
- slide_dist(e, bv->v, e->offset_l, co);
- if (construct) {
- v = add_new_bound_vert(bp->mem_arena, vm, co);
- v->efirst = v->elast = e;
- e->leftv = e->rightv = v;
- }
- else {
- adjust_bound_vert(e->leftv, co);
- }
- } while ((e = e->next) != efirst);
-
- calculate_vm_profiles(bp, bv, vm);
-
- if (construct) {
- set_bound_vert_seams(bv, bp->mark_seam, bp->mark_sharp);
- if (vm->count == 2) {
- vm->mesh_kind = M_NONE;
- }
- else if (bp->seg == 1) {
- vm->mesh_kind = M_POLY;
- }
- else {
- vm->mesh_kind = M_ADJ;
- }
- }
+ VMesh *vm = bv->vmesh;
+ EdgeHalf *efirst, *e;
+ BoundVert *v;
+ float co[3];
+
+ BLI_assert(bp->vertex_only);
+
+ e = efirst = &bv->edges[0];
+ do {
+ slide_dist(e, bv->v, e->offset_l, co);
+ if (construct) {
+ v = add_new_bound_vert(bp->mem_arena, vm, co);
+ v->efirst = v->elast = e;
+ e->leftv = e->rightv = v;
+ }
+ else {
+ adjust_bound_vert(e->leftv, co);
+ }
+ } while ((e = e->next) != efirst);
+
+ calculate_vm_profiles(bp, bv, vm);
+
+ if (construct) {
+ set_bound_vert_seams(bv, bp->mark_seam, bp->mark_sharp);
+ if (vm->count == 2) {
+ vm->mesh_kind = M_NONE;
+ }
+ else if (bp->seg == 1) {
+ vm->mesh_kind = M_POLY;
+ }
+ else {
+ vm->mesh_kind = M_ADJ;
+ }
+ }
}
/**
@@ -2168,199 +2180,202 @@ static void build_boundary_vertex_only(BevelParams *bp, BevVert *bv, bool constr
* The 'width adjust' part of build_boundary has been done already,
* and \a efirst is the first beveled edge at vertex \a bv.
*/
-static void build_boundary_terminal_edge(BevelParams *bp, BevVert *bv, EdgeHalf *efirst, bool construct)
+static void build_boundary_terminal_edge(BevelParams *bp,
+ BevVert *bv,
+ EdgeHalf *efirst,
+ bool construct)
{
- MemArena *mem_arena = bp->mem_arena;
- VMesh *vm = bv->vmesh;
- BoundVert *v;
- EdgeHalf *e;
- const float *no;
- float co[3], d;
-
- e = efirst;
- if (bv->edgecount == 2) {
- /* only 2 edges in, so terminate the edge with an artificial vertex on the unbeveled edge */
- no = e->fprev ? e->fprev->no : (e->fnext ? e->fnext->no : NULL);
- offset_in_plane(e, no, true, co);
- if (construct) {
- v = add_new_bound_vert(mem_arena, vm, co);
- v->efirst = v->elast = v->ebev = e;
- e->leftv = v;
- }
- else {
- adjust_bound_vert(e->leftv, co);
- }
- no = e->fnext ? e->fnext->no : (e->fprev ? e->fprev->no : NULL);
- offset_in_plane(e, no, false, co);
- if (construct) {
- v = add_new_bound_vert(mem_arena, vm, co);
- v->efirst = v->elast = e;
- e->rightv = v;
- }
- else {
- adjust_bound_vert(e->rightv, co);
- }
- /* make artifical extra point along unbeveled edge, and form triangle */
- slide_dist(e->next, bv->v, e->offset_l, co);
- if (construct) {
- v = add_new_bound_vert(mem_arena, vm, co);
- v->efirst = v->elast = e->next;
- e->next->leftv = e->next->rightv = v;
- /* could use M_POLY too, but tri-fan looks nicer)*/
- vm->mesh_kind = M_TRI_FAN;
- set_bound_vert_seams(bv, bp->mark_seam, bp->mark_sharp);
- }
- else {
- adjust_bound_vert(e->next->leftv, co);
- }
- }
- else {
- /* More than 2 edges in. Put on-edge verts on all the other edges
- * and join with the beveled edge to make a poly or adj mesh,
- * Because e->prev has offset 0, offset_meet will put co on that edge. */
- /* TODO: should do something else if angle between e and e->prev > 180 */
- offset_meet(e->prev, e, bv->v, e->fprev, false, co);
- if (construct) {
- v = add_new_bound_vert(mem_arena, vm, co);
- v->efirst = e->prev;
- v->elast = v->ebev = e;
- e->leftv = v;
- e->prev->leftv = e->prev->rightv = v;
- }
- else {
- adjust_bound_vert(e->leftv, co);
- }
- e = e->next;
- offset_meet(e->prev, e, bv->v, e->fprev, false, co);
- if (construct) {
- v = add_new_bound_vert(mem_arena, vm, co);
- v->efirst = e->prev;
- v->elast = e;
- e->leftv = e->rightv = v;
- e->prev->rightv = v;
- }
- else {
- adjust_bound_vert(e->leftv, co);
- }
- /* For the edges not adjacent to the beveled edge, slide the bevel amount along. */
- d = efirst->offset_l_spec;
- for (e = e->next; e->next != efirst; e = e->next) {
- slide_dist(e, bv->v, d, co);
- if (construct) {
- v = add_new_bound_vert(mem_arena, vm, co);
- v->efirst = v->elast = e;
- e->leftv = e->rightv = v;
- }
- else {
- adjust_bound_vert(e->leftv, co);
- }
- }
- }
- calculate_vm_profiles(bp, bv, vm);
-
- if (bv->edgecount >= 3) {
- /* special case: snap profile to plane of adjacent two edges */
- v = vm->boundstart;
- BLI_assert(v->ebev != NULL);
- move_profile_plane(v, v->efirst, v->next->elast);
- calculate_profile(bp, v);
- }
-
- if (construct) {
- set_bound_vert_seams(bv, bp->mark_seam, bp->mark_sharp);
-
- if (vm->count == 2 && bv->edgecount == 3) {
- vm->mesh_kind = M_NONE;
- }
- else if (vm->count == 3) {
- vm->mesh_kind = M_TRI_FAN;
- }
- else {
- vm->mesh_kind = M_POLY;
- }
- }
+ MemArena *mem_arena = bp->mem_arena;
+ VMesh *vm = bv->vmesh;
+ BoundVert *v;
+ EdgeHalf *e;
+ const float *no;
+ float co[3], d;
+
+ e = efirst;
+ if (bv->edgecount == 2) {
+ /* only 2 edges in, so terminate the edge with an artificial vertex on the unbeveled edge */
+ no = e->fprev ? e->fprev->no : (e->fnext ? e->fnext->no : NULL);
+ offset_in_plane(e, no, true, co);
+ if (construct) {
+ v = add_new_bound_vert(mem_arena, vm, co);
+ v->efirst = v->elast = v->ebev = e;
+ e->leftv = v;
+ }
+ else {
+ adjust_bound_vert(e->leftv, co);
+ }
+ no = e->fnext ? e->fnext->no : (e->fprev ? e->fprev->no : NULL);
+ offset_in_plane(e, no, false, co);
+ if (construct) {
+ v = add_new_bound_vert(mem_arena, vm, co);
+ v->efirst = v->elast = e;
+ e->rightv = v;
+ }
+ else {
+ adjust_bound_vert(e->rightv, co);
+ }
+ /* make artifical extra point along unbeveled edge, and form triangle */
+ slide_dist(e->next, bv->v, e->offset_l, co);
+ if (construct) {
+ v = add_new_bound_vert(mem_arena, vm, co);
+ v->efirst = v->elast = e->next;
+ e->next->leftv = e->next->rightv = v;
+ /* could use M_POLY too, but tri-fan looks nicer)*/
+ vm->mesh_kind = M_TRI_FAN;
+ set_bound_vert_seams(bv, bp->mark_seam, bp->mark_sharp);
+ }
+ else {
+ adjust_bound_vert(e->next->leftv, co);
+ }
+ }
+ else {
+ /* More than 2 edges in. Put on-edge verts on all the other edges
+ * and join with the beveled edge to make a poly or adj mesh,
+ * Because e->prev has offset 0, offset_meet will put co on that edge. */
+ /* TODO: should do something else if angle between e and e->prev > 180 */
+ offset_meet(e->prev, e, bv->v, e->fprev, false, co);
+ if (construct) {
+ v = add_new_bound_vert(mem_arena, vm, co);
+ v->efirst = e->prev;
+ v->elast = v->ebev = e;
+ e->leftv = v;
+ e->prev->leftv = e->prev->rightv = v;
+ }
+ else {
+ adjust_bound_vert(e->leftv, co);
+ }
+ e = e->next;
+ offset_meet(e->prev, e, bv->v, e->fprev, false, co);
+ if (construct) {
+ v = add_new_bound_vert(mem_arena, vm, co);
+ v->efirst = e->prev;
+ v->elast = e;
+ e->leftv = e->rightv = v;
+ e->prev->rightv = v;
+ }
+ else {
+ adjust_bound_vert(e->leftv, co);
+ }
+ /* For the edges not adjacent to the beveled edge, slide the bevel amount along. */
+ d = efirst->offset_l_spec;
+ for (e = e->next; e->next != efirst; e = e->next) {
+ slide_dist(e, bv->v, d, co);
+ if (construct) {
+ v = add_new_bound_vert(mem_arena, vm, co);
+ v->efirst = v->elast = e;
+ e->leftv = e->rightv = v;
+ }
+ else {
+ adjust_bound_vert(e->leftv, co);
+ }
+ }
+ }
+ calculate_vm_profiles(bp, bv, vm);
+
+ if (bv->edgecount >= 3) {
+ /* special case: snap profile to plane of adjacent two edges */
+ v = vm->boundstart;
+ BLI_assert(v->ebev != NULL);
+ move_profile_plane(v, v->efirst, v->next->elast);
+ calculate_profile(bp, v);
+ }
+
+ if (construct) {
+ set_bound_vert_seams(bv, bp->mark_seam, bp->mark_sharp);
+
+ if (vm->count == 2 && bv->edgecount == 3) {
+ vm->mesh_kind = M_NONE;
+ }
+ else if (vm->count == 3) {
+ vm->mesh_kind = M_TRI_FAN;
+ }
+ else {
+ vm->mesh_kind = M_POLY;
+ }
+ }
}
/* Helper for build_boundary to handle special miters */
static void adjust_miter_coords(BevelParams *bp, BevVert *bv, EdgeHalf *emiter)
{
- float co1[3], co2[3], co3[3], edge_dir[3], line_p[3];
- BoundVert *v1, *v2, *v3, *v1prev, *v3next;
- BMVert *vother;
- EdgeHalf *emiter_other;
- int miter_outer = bp->miter_outer;
-
- v1 = emiter->rightv;
- if (miter_outer == BEVEL_MITER_PATCH) {
- v2 = v1->next;
- v3 = v2->next;
- }
- else {
- BLI_assert(miter_outer == BEVEL_MITER_ARC);
- v2 = NULL;
- v3 = v1->next;
- }
- v1prev = v1->prev;
- v3next = v3->next;
- copy_v3_v3(co2, v1->nv.co);
- if (v1->is_arc_start) {
- copy_v3_v3(v1->profile.midco, co2);
- }
-
- /* co1 is intersection of line through co2 in dir of emiter->e
- * and plane with normal the dir of emiter->e and through v1prev */
- vother = BM_edge_other_vert(emiter->e, bv->v);
- sub_v3_v3v3(edge_dir, bv->v->co, vother->co);
- normalize_v3(edge_dir);
- float d = bp->offset / (bp->seg / 2.0f); /* a fallback amount to move */
- madd_v3_v3v3fl(line_p, co2, edge_dir, d);
- if (!isect_line_plane_v3(co1, co2, line_p, v1prev->nv.co, edge_dir)) {
- copy_v3_v3(co1, line_p);
- }
- adjust_bound_vert(v1, co1);
-
- /* co3 is similar, but plane is through v3next and line is other side of miter edge */
- emiter_other = v3->elast; /*v3->efirst;*/
- vother = BM_edge_other_vert(emiter_other->e, bv->v);
- sub_v3_v3v3(edge_dir, bv->v->co, vother->co);
- normalize_v3(edge_dir);
- madd_v3_v3v3fl(line_p, co2, edge_dir, d);
- if (!isect_line_plane_v3(co3, co2, line_p, v3next->nv.co, edge_dir)) {
- copy_v3_v3(co1, line_p);
- }
- adjust_bound_vert(v3, co3);
+ float co1[3], co2[3], co3[3], edge_dir[3], line_p[3];
+ BoundVert *v1, *v2, *v3, *v1prev, *v3next;
+ BMVert *vother;
+ EdgeHalf *emiter_other;
+ int miter_outer = bp->miter_outer;
+
+ v1 = emiter->rightv;
+ if (miter_outer == BEVEL_MITER_PATCH) {
+ v2 = v1->next;
+ v3 = v2->next;
+ }
+ else {
+ BLI_assert(miter_outer == BEVEL_MITER_ARC);
+ v2 = NULL;
+ v3 = v1->next;
+ }
+ v1prev = v1->prev;
+ v3next = v3->next;
+ copy_v3_v3(co2, v1->nv.co);
+ if (v1->is_arc_start) {
+ copy_v3_v3(v1->profile.midco, co2);
+ }
+
+ /* co1 is intersection of line through co2 in dir of emiter->e
+ * and plane with normal the dir of emiter->e and through v1prev */
+ vother = BM_edge_other_vert(emiter->e, bv->v);
+ sub_v3_v3v3(edge_dir, bv->v->co, vother->co);
+ normalize_v3(edge_dir);
+ float d = bp->offset / (bp->seg / 2.0f); /* a fallback amount to move */
+ madd_v3_v3v3fl(line_p, co2, edge_dir, d);
+ if (!isect_line_plane_v3(co1, co2, line_p, v1prev->nv.co, edge_dir)) {
+ copy_v3_v3(co1, line_p);
+ }
+ adjust_bound_vert(v1, co1);
+
+ /* co3 is similar, but plane is through v3next and line is other side of miter edge */
+ emiter_other = v3->elast; /*v3->efirst;*/
+ vother = BM_edge_other_vert(emiter_other->e, bv->v);
+ sub_v3_v3v3(edge_dir, bv->v->co, vother->co);
+ normalize_v3(edge_dir);
+ madd_v3_v3v3fl(line_p, co2, edge_dir, d);
+ if (!isect_line_plane_v3(co3, co2, line_p, v3next->nv.co, edge_dir)) {
+ copy_v3_v3(co1, line_p);
+ }
+ adjust_bound_vert(v3, co3);
}
static void adjust_miter_inner_coords(BevelParams *bp, BevVert *bv, EdgeHalf *emiter)
{
- BoundVert *v, *vstart, *v3;
- EdgeHalf *e;
- BMVert *vother;
- float edge_dir[3], co[3];
-
- v = vstart = bv->vmesh->boundstart;
- do {
- if (v->is_arc_start) {
- v3 = v->next;
- e = v->efirst;
- if (e != emiter) {
- copy_v3_v3(co, v->nv.co);
- vother = BM_edge_other_vert(e->e, bv->v);
- sub_v3_v3v3(edge_dir, vother->co, bv->v->co);
- normalize_v3(edge_dir);
- madd_v3_v3v3fl(v->nv.co, co, edge_dir, bp->spread);
- e = v3->elast;
- vother = BM_edge_other_vert(e->e, bv->v);
- sub_v3_v3v3(edge_dir, vother->co, bv->v->co);
- normalize_v3(edge_dir);
- madd_v3_v3v3fl(v3->nv.co, co, edge_dir, bp->spread);
- }
- v = v3->next;
- }
- else {
- v = v->next;
- }
- } while (v != vstart);
+ BoundVert *v, *vstart, *v3;
+ EdgeHalf *e;
+ BMVert *vother;
+ float edge_dir[3], co[3];
+
+ v = vstart = bv->vmesh->boundstart;
+ do {
+ if (v->is_arc_start) {
+ v3 = v->next;
+ e = v->efirst;
+ if (e != emiter) {
+ copy_v3_v3(co, v->nv.co);
+ vother = BM_edge_other_vert(e->e, bv->v);
+ sub_v3_v3v3(edge_dir, vother->co, bv->v->co);
+ normalize_v3(edge_dir);
+ madd_v3_v3v3fl(v->nv.co, co, edge_dir, bp->spread);
+ e = v3->elast;
+ vother = BM_edge_other_vert(e->e, bv->v);
+ sub_v3_v3v3(edge_dir, vother->co, bv->v->co);
+ normalize_v3(edge_dir);
+ madd_v3_v3v3fl(v3->nv.co, co, edge_dir, bp->spread);
+ }
+ v = v3->next;
+ }
+ else {
+ v = v->next;
+ }
+ } while (v != vstart);
}
/* Make a circular list of BoundVerts for bv, each of which has the coordinates
@@ -2377,319 +2392,329 @@ static void adjust_miter_inner_coords(BevelParams *bp, BevVert *bv, EdgeHalf *em
* Doesn't make the actual BMVerts */
static void build_boundary(BevelParams *bp, BevVert *bv, bool construct)
{
- MemArena *mem_arena = bp->mem_arena;
- EdgeHalf *efirst, *e, *e2, *e3, *enip, *eip, *eon, *emiter;
- BoundVert *v, *v1, *v2, *v3;
- VMesh *vm;
- float co[3], r;
- int nip, nnip, miter_outer, miter_inner;
- int ang_kind;
-
- /* Current bevel does nothing if only one edge into a vertex */
- if (bv->edgecount <= 1) {
- return;
- }
-
- if (bp->vertex_only) {
- build_boundary_vertex_only(bp, bv, construct);
- return;
- }
-
- vm = bv->vmesh;
-
- /* Find a beveled edge to be efirst */
- e = efirst = next_bev(bv, NULL);
- BLI_assert(e->is_bev);
-
- if (bv->selcount == 1) {
- /* special case: only one beveled edge in */
- build_boundary_terminal_edge(bp, bv, efirst, construct);
- return;
- }
-
- /* Special miters outside only for 3 or more beveled edges */
- miter_outer = (bv->selcount >= 3) ? bp->miter_outer : BEVEL_MITER_SHARP;
- miter_inner = bp->miter_inner;
-
- /* keep track of the first beveled edge of an outside miter (there can be at most 1 per bv */
- emiter = NULL;
-
- /* Here: there is more than one beveled edge.
- * We make BoundVerts to connect the sides of the beveled edges.
- * Non-beveled edges in between will just join to the appropriate juncture point. */
- e = efirst;
- do {
- BLI_assert(e->is_bev);
- eon = NULL;
- /* Make the BoundVert for the right side of e; other side will be made
- * when the beveled edge to the left of e is handled.
- * Analyze edges until next beveled edge.
- * They are either "in plane" (preceding and subsequent faces are coplanar)
- * or not. The "non-in-plane" edges effect silhouette and we prefer to slide
- * along one of those if possible. */
- nip = nnip = 0; /* counts of in-plane / not-in-plane */
- enip = eip = NULL; /* representatives of each */
- for (e2 = e->next; !e2->is_bev; e2 = e2->next) {
- if (eh_on_plane(e2)) {
- nip++;
- eip = e2;
- }
- else {
- nnip++;
- enip = e2;
- }
- }
- if (nip == 0 && nnip == 0) {
- offset_meet(e, e2, bv->v, e->fnext, false, co);
- }
- else if (nnip > 0) {
- if (bp->loop_slide && nnip == 1 && good_offset_on_edge_between(e, e2, enip, bv->v)) {
- if (offset_on_edge_between(e, e2, enip, bv->v, co, &r)) {
- eon = enip;
- }
- }
- else {
- offset_meet(e, e2, bv->v, NULL, true, co);
- }
- }
- else {
- /* nip > 0 and nnip == 0 */
- if (bp->loop_slide && nip == 1 && good_offset_on_edge_between(e, e2, eip, bv->v)) {
- if (offset_on_edge_between(e, e2, eip, bv->v, co, &r)) {
- eon = eip;
- }
- }
- else {
- offset_meet(e, e2, bv->v, e->fnext, true, co);
- }
- }
- if (construct) {
- v = add_new_bound_vert(mem_arena, vm, co);
- v->efirst = e;
- v->elast = e2;
- v->ebev = e2;
- v->eon = eon;
- if (eon) {
- v->sinratio = r;
- }
- e->rightv = v;
- e2->leftv = v;
- for (e3 = e->next; e3 != e2; e3 = e3->next) {
- e3->leftv = e3->rightv = v;
- }
- ang_kind = edges_angle_kind(e, e2, bv->v);
-
- /* Are we doing special mitering?
- * ang_kind is -1, 0, 1 as angle is <, =, > 180 degrees.
- * There can only be one outer reflex angle, so only one outer miter,
- * and emiter will be set to the first edge of such an edge.
- * A miter kind of BEVEL_MITER_SHARP means no special miter */
-
- if ((miter_outer != BEVEL_MITER_SHARP && !emiter && ang_kind == 1) ||
- (miter_inner != BEVEL_MITER_SHARP && ang_kind == -1))
- {
- if (ang_kind == 1) {
- emiter = e;
- }
- /* make one or two more boundverts; for now all will have same co */
- v1 = v;
- v1->ebev = NULL;
- if (ang_kind == 1 && miter_outer == BEVEL_MITER_PATCH) {
- v2 = add_new_bound_vert(mem_arena, vm, co);
- }
- else {
- v2 = NULL;
- }
- v3 = add_new_bound_vert(mem_arena, vm, co);
- v3->ebev = e2;
- v3->efirst = e2;
- v3->elast = e2;
- v3->eon = NULL;
- e2->leftv = v3;
- if (ang_kind == 1 && miter_outer == BEVEL_MITER_PATCH) {
- v1->is_patch_start = true;
- v2->eon = v1->eon;
- v2->sinratio = v1->sinratio;
- v2->ebev = NULL;
- v1->eon = NULL;
- v1->sinratio = 1.0f;
- v1->elast = e;
- if (e->next == e2) {
- v2->efirst = NULL;
- v2->elast = NULL;
- }
- else {
- v2->efirst = e->next;
- for (e3 = e->next; e3 != e2; e3 = e3->next) {
- e3->leftv = e3->rightv = v2;
- v2->elast = e3;
- }
- }
- }
- else {
- v1->is_arc_start = true;
- copy_v3_v3(v1->profile.midco, co);
- if (e->next == e2) {
- v1->elast = v1->efirst;
- }
- else {
- int between = nip + nnip;
- int bet2 = between / 2;
- bool betodd = (between % 2) == 1;
- int i = 0;
- /* Put first half of in-between edges at index 0,
- * second half at index bp->seg.
- * If between is odd, put middle one at midindex */
- for (e3 = e->next; e3 != e2; e3 = e3->next) {
- v1->elast = e3;
- if (i < bet2) {
- e3->profile_index = 0;
- }
- else if (betodd && i == bet2) {
- e3->profile_index = bp->seg / 2;
- }
- else {
- e3->profile_index = bp->seg;
- }
- i++;
- }
- }
- }
- }
- }
- else {
- ang_kind = edges_angle_kind(e, e2, bv->v);
- if ((miter_outer != BEVEL_MITER_SHARP && !emiter && ang_kind == 1) ||
- (miter_inner != BEVEL_MITER_SHARP && ang_kind == -1))
- {
- if (ang_kind == 1) {
- emiter = e;
- }
- v1 = e->rightv;
- if (ang_kind == 1 && miter_outer == BEVEL_MITER_PATCH) {
- v2 = v1->next;
- v3 = v2->next;
- }
- else {
- v2 = NULL;
- v3 = v1->next;
- }
- adjust_bound_vert(v1, co);
- if (v2) {
- adjust_bound_vert(v2, co);
- }
- adjust_bound_vert(v3, co);
- }
- else {
- adjust_bound_vert(e->rightv, co);
- }
- }
- e = e2;
- } while (e != efirst);
-
- if (miter_inner != BEVEL_MITER_SHARP) {
- adjust_miter_inner_coords(bp, bv, emiter);
- }
- if (emiter) {
- adjust_miter_coords(bp, bv, emiter);
- }
-
- calculate_vm_profiles(bp, bv, vm);
-
- if (construct) {
- set_bound_vert_seams(bv, bp->mark_seam, bp->mark_sharp);
-
- if (vm->count == 2) {
- vm->mesh_kind = M_NONE;
- }
- else if (efirst->seg == 1) {
- vm->mesh_kind = M_POLY;
- }
- else {
- vm->mesh_kind = M_ADJ;
- }
- }
+ MemArena *mem_arena = bp->mem_arena;
+ EdgeHalf *efirst, *e, *e2, *e3, *enip, *eip, *eon, *emiter;
+ BoundVert *v, *v1, *v2, *v3;
+ VMesh *vm;
+ float co[3], r;
+ int nip, nnip, miter_outer, miter_inner;
+ int ang_kind;
+
+ /* Current bevel does nothing if only one edge into a vertex */
+ if (bv->edgecount <= 1) {
+ return;
+ }
+
+ if (bp->vertex_only) {
+ build_boundary_vertex_only(bp, bv, construct);
+ return;
+ }
+
+ vm = bv->vmesh;
+
+ /* Find a beveled edge to be efirst */
+ e = efirst = next_bev(bv, NULL);
+ BLI_assert(e->is_bev);
+
+ if (bv->selcount == 1) {
+ /* special case: only one beveled edge in */
+ build_boundary_terminal_edge(bp, bv, efirst, construct);
+ return;
+ }
+
+ /* Special miters outside only for 3 or more beveled edges */
+ miter_outer = (bv->selcount >= 3) ? bp->miter_outer : BEVEL_MITER_SHARP;
+ miter_inner = bp->miter_inner;
+
+ /* keep track of the first beveled edge of an outside miter (there can be at most 1 per bv */
+ emiter = NULL;
+
+ /* Here: there is more than one beveled edge.
+ * We make BoundVerts to connect the sides of the beveled edges.
+ * Non-beveled edges in between will just join to the appropriate juncture point. */
+ e = efirst;
+ do {
+ BLI_assert(e->is_bev);
+ eon = NULL;
+ /* Make the BoundVert for the right side of e; other side will be made
+ * when the beveled edge to the left of e is handled.
+ * Analyze edges until next beveled edge.
+ * They are either "in plane" (preceding and subsequent faces are coplanar)
+ * or not. The "non-in-plane" edges effect silhouette and we prefer to slide
+ * along one of those if possible. */
+ nip = nnip = 0; /* counts of in-plane / not-in-plane */
+ enip = eip = NULL; /* representatives of each */
+ for (e2 = e->next; !e2->is_bev; e2 = e2->next) {
+ if (eh_on_plane(e2)) {
+ nip++;
+ eip = e2;
+ }
+ else {
+ nnip++;
+ enip = e2;
+ }
+ }
+ if (nip == 0 && nnip == 0) {
+ offset_meet(e, e2, bv->v, e->fnext, false, co);
+ }
+ else if (nnip > 0) {
+ if (bp->loop_slide && nnip == 1 && good_offset_on_edge_between(e, e2, enip, bv->v)) {
+ if (offset_on_edge_between(e, e2, enip, bv->v, co, &r)) {
+ eon = enip;
+ }
+ }
+ else {
+ offset_meet(e, e2, bv->v, NULL, true, co);
+ }
+ }
+ else {
+ /* nip > 0 and nnip == 0 */
+ if (bp->loop_slide && nip == 1 && good_offset_on_edge_between(e, e2, eip, bv->v)) {
+ if (offset_on_edge_between(e, e2, eip, bv->v, co, &r)) {
+ eon = eip;
+ }
+ }
+ else {
+ offset_meet(e, e2, bv->v, e->fnext, true, co);
+ }
+ }
+ if (construct) {
+ v = add_new_bound_vert(mem_arena, vm, co);
+ v->efirst = e;
+ v->elast = e2;
+ v->ebev = e2;
+ v->eon = eon;
+ if (eon) {
+ v->sinratio = r;
+ }
+ e->rightv = v;
+ e2->leftv = v;
+ for (e3 = e->next; e3 != e2; e3 = e3->next) {
+ e3->leftv = e3->rightv = v;
+ }
+ ang_kind = edges_angle_kind(e, e2, bv->v);
+
+ /* Are we doing special mitering?
+ * ang_kind is -1, 0, 1 as angle is <, =, > 180 degrees.
+ * There can only be one outer reflex angle, so only one outer miter,
+ * and emiter will be set to the first edge of such an edge.
+ * A miter kind of BEVEL_MITER_SHARP means no special miter */
+
+ if ((miter_outer != BEVEL_MITER_SHARP && !emiter && ang_kind == 1) ||
+ (miter_inner != BEVEL_MITER_SHARP && ang_kind == -1)) {
+ if (ang_kind == 1) {
+ emiter = e;
+ }
+ /* make one or two more boundverts; for now all will have same co */
+ v1 = v;
+ v1->ebev = NULL;
+ if (ang_kind == 1 && miter_outer == BEVEL_MITER_PATCH) {
+ v2 = add_new_bound_vert(mem_arena, vm, co);
+ }
+ else {
+ v2 = NULL;
+ }
+ v3 = add_new_bound_vert(mem_arena, vm, co);
+ v3->ebev = e2;
+ v3->efirst = e2;
+ v3->elast = e2;
+ v3->eon = NULL;
+ e2->leftv = v3;
+ if (ang_kind == 1 && miter_outer == BEVEL_MITER_PATCH) {
+ v1->is_patch_start = true;
+ v2->eon = v1->eon;
+ v2->sinratio = v1->sinratio;
+ v2->ebev = NULL;
+ v1->eon = NULL;
+ v1->sinratio = 1.0f;
+ v1->elast = e;
+ if (e->next == e2) {
+ v2->efirst = NULL;
+ v2->elast = NULL;
+ }
+ else {
+ v2->efirst = e->next;
+ for (e3 = e->next; e3 != e2; e3 = e3->next) {
+ e3->leftv = e3->rightv = v2;
+ v2->elast = e3;
+ }
+ }
+ }
+ else {
+ v1->is_arc_start = true;
+ copy_v3_v3(v1->profile.midco, co);
+ if (e->next == e2) {
+ v1->elast = v1->efirst;
+ }
+ else {
+ int between = nip + nnip;
+ int bet2 = between / 2;
+ bool betodd = (between % 2) == 1;
+ int i = 0;
+ /* Put first half of in-between edges at index 0,
+ * second half at index bp->seg.
+ * If between is odd, put middle one at midindex */
+ for (e3 = e->next; e3 != e2; e3 = e3->next) {
+ v1->elast = e3;
+ if (i < bet2) {
+ e3->profile_index = 0;
+ }
+ else if (betodd && i == bet2) {
+ e3->profile_index = bp->seg / 2;
+ }
+ else {
+ e3->profile_index = bp->seg;
+ }
+ i++;
+ }
+ }
+ }
+ }
+ }
+ else {
+ ang_kind = edges_angle_kind(e, e2, bv->v);
+ if ((miter_outer != BEVEL_MITER_SHARP && !emiter && ang_kind == 1) ||
+ (miter_inner != BEVEL_MITER_SHARP && ang_kind == -1)) {
+ if (ang_kind == 1) {
+ emiter = e;
+ }
+ v1 = e->rightv;
+ if (ang_kind == 1 && miter_outer == BEVEL_MITER_PATCH) {
+ v2 = v1->next;
+ v3 = v2->next;
+ }
+ else {
+ v2 = NULL;
+ v3 = v1->next;
+ }
+ adjust_bound_vert(v1, co);
+ if (v2) {
+ adjust_bound_vert(v2, co);
+ }
+ adjust_bound_vert(v3, co);
+ }
+ else {
+ adjust_bound_vert(e->rightv, co);
+ }
+ }
+ e = e2;
+ } while (e != efirst);
+
+ if (miter_inner != BEVEL_MITER_SHARP) {
+ adjust_miter_inner_coords(bp, bv, emiter);
+ }
+ if (emiter) {
+ adjust_miter_coords(bp, bv, emiter);
+ }
+
+ calculate_vm_profiles(bp, bv, vm);
+
+ if (construct) {
+ set_bound_vert_seams(bv, bp->mark_seam, bp->mark_sharp);
+
+ if (vm->count == 2) {
+ vm->mesh_kind = M_NONE;
+ }
+ else if (efirst->seg == 1) {
+ vm->mesh_kind = M_POLY;
+ }
+ else {
+ vm->mesh_kind = M_ADJ;
+ }
+ }
}
#ifdef DEBUG_ADJUST
static void print_adjust_stats(BoundVert *vstart)
{
- BoundVert *v;
- EdgeHalf *eleft, *eright;
- double even_residual2, spec_residual2;
- double max_even_r, max_even_r_pct;
- double max_spec_r, max_spec_r_pct;
- double delta, delta_pct;
-
- printf("\nSolution analysis\n");
- even_residual2 = 0.0;
- spec_residual2 = 0.0;
- max_even_r = 0.0;
- max_even_r_pct = 0.0;
- max_spec_r = 0.0;
- max_spec_r_pct = 0.0;
- printf("width matching\n");
- v = vstart;
- do {
- if (v->adjchain != NULL) {
- eright = v->efirst;
- eleft = v->adjchain->elast;
- delta = fabs(eright->offset_r - eleft->offset_l);
- delta_pct = 100.0 * delta / eright->offset_r_spec;
- printf("e%d r(%f) vs l(%f): abs(delta)=%f, delta_pct=%f\n",
- BM_elem_index_get(eright->e), eright->offset_r, eleft->offset_l, delta, delta_pct);
- even_residual2 += delta * delta;
- if (delta > max_even_r) {
- max_even_r = delta;
- }
- if (delta_pct > max_even_r_pct) {
- max_even_r_pct = delta_pct;
- }
- }
- v = v->adjchain;
- } while (v && v != vstart);
-
- printf("spec matching\n");
- v = vstart;
- do {
- if (v->adjchain != NULL) {
- eright = v->efirst;
- eleft = v->adjchain->elast;
- delta = eright->offset_r - eright->offset_r_spec;
- delta_pct = 100.0 * delta / eright->offset_r_spec;
- printf("e%d r(%f) vs r spec(%f): delta=%f, delta_pct=%f\n",
- BM_elem_index_get(eright->e), eright->offset_r, eright->offset_r_spec, delta, delta_pct);
- spec_residual2 += delta * delta;
- delta = fabs(delta);
- delta_pct = fabs(delta_pct);
- if (delta > max_spec_r) {
- max_spec_r = delta;
- }
- if (delta_pct > max_spec_r_pct) {
- max_spec_r_pct = delta_pct;
- }
-
- delta = eleft->offset_l - eleft->offset_l_spec;
- delta_pct = 100.0 * delta / eright->offset_l_spec;
- printf("e%d l(%f) vs l spec(%f): delta=%f, delta_pct=%f\n",
- BM_elem_index_get(eright->e), eleft->offset_l, eleft->offset_l_spec, delta, delta_pct);
- spec_residual2 += delta * delta;
- delta = fabs(delta);
- delta_pct = fabs(delta_pct);
- if (delta > max_spec_r) {
- max_spec_r = delta;
- }
- if (delta_pct > max_spec_r_pct) {
- max_spec_r_pct = delta_pct;
- }
- }
- v = v->adjchain;
- } while (v && v != vstart);
-
- printf("Analysis Result:\n");
- printf("even residual2 = %f, spec residual2 = %f\n", even_residual2, spec_residual2);
- printf("max even delta = %f, max as percent of spec = %f\n", max_even_r, max_even_r_pct);
- printf("max spec delta = %f, max as percent of spec = %f\n", max_spec_r, max_spec_r_pct);
+ BoundVert *v;
+ EdgeHalf *eleft, *eright;
+ double even_residual2, spec_residual2;
+ double max_even_r, max_even_r_pct;
+ double max_spec_r, max_spec_r_pct;
+ double delta, delta_pct;
+
+ printf("\nSolution analysis\n");
+ even_residual2 = 0.0;
+ spec_residual2 = 0.0;
+ max_even_r = 0.0;
+ max_even_r_pct = 0.0;
+ max_spec_r = 0.0;
+ max_spec_r_pct = 0.0;
+ printf("width matching\n");
+ v = vstart;
+ do {
+ if (v->adjchain != NULL) {
+ eright = v->efirst;
+ eleft = v->adjchain->elast;
+ delta = fabs(eright->offset_r - eleft->offset_l);
+ delta_pct = 100.0 * delta / eright->offset_r_spec;
+ printf("e%d r(%f) vs l(%f): abs(delta)=%f, delta_pct=%f\n",
+ BM_elem_index_get(eright->e),
+ eright->offset_r,
+ eleft->offset_l,
+ delta,
+ delta_pct);
+ even_residual2 += delta * delta;
+ if (delta > max_even_r) {
+ max_even_r = delta;
+ }
+ if (delta_pct > max_even_r_pct) {
+ max_even_r_pct = delta_pct;
+ }
+ }
+ v = v->adjchain;
+ } while (v && v != vstart);
+
+ printf("spec matching\n");
+ v = vstart;
+ do {
+ if (v->adjchain != NULL) {
+ eright = v->efirst;
+ eleft = v->adjchain->elast;
+ delta = eright->offset_r - eright->offset_r_spec;
+ delta_pct = 100.0 * delta / eright->offset_r_spec;
+ printf("e%d r(%f) vs r spec(%f): delta=%f, delta_pct=%f\n",
+ BM_elem_index_get(eright->e),
+ eright->offset_r,
+ eright->offset_r_spec,
+ delta,
+ delta_pct);
+ spec_residual2 += delta * delta;
+ delta = fabs(delta);
+ delta_pct = fabs(delta_pct);
+ if (delta > max_spec_r) {
+ max_spec_r = delta;
+ }
+ if (delta_pct > max_spec_r_pct) {
+ max_spec_r_pct = delta_pct;
+ }
+
+ delta = eleft->offset_l - eleft->offset_l_spec;
+ delta_pct = 100.0 * delta / eright->offset_l_spec;
+ printf("e%d l(%f) vs l spec(%f): delta=%f, delta_pct=%f\n",
+ BM_elem_index_get(eright->e),
+ eleft->offset_l,
+ eleft->offset_l_spec,
+ delta,
+ delta_pct);
+ spec_residual2 += delta * delta;
+ delta = fabs(delta);
+ delta_pct = fabs(delta_pct);
+ if (delta > max_spec_r) {
+ max_spec_r = delta;
+ }
+ if (delta_pct > max_spec_r_pct) {
+ max_spec_r_pct = delta_pct;
+ }
+ }
+ v = v->adjchain;
+ } while (v && v != vstart);
+
+ printf("Analysis Result:\n");
+ printf("even residual2 = %f, spec residual2 = %f\n", even_residual2, spec_residual2);
+ printf("max even delta = %f, max as percent of spec = %f\n", max_even_r, max_even_r_pct);
+ printf("max spec delta = %f, max as percent of spec = %f\n", max_spec_r, max_spec_r_pct);
}
#endif
@@ -2704,79 +2729,79 @@ static void print_adjust_stats(BoundVert *vstart)
* But keep it here for a while in case performance issues demand that it be used sometimes. */
static bool adjust_the_cycle_or_chain_fast(BoundVert *vstart, int np, bool iscycle)
{
- BoundVert *v;
- EdgeHalf *eleft, *eright;
- float *g;
- float *g_prod;
- float gprod, gprod_sum, spec_sum, p;
- int i;
-
- g = MEM_mallocN(np * sizeof(float), "beveladjust");
- g_prod = MEM_mallocN(np * sizeof(float), "beveladjust");
-
- v = vstart;
- spec_sum = 0.0f;
- i = 0;
- do {
- g[i] = v->sinratio;
- if (iscycle || v->adjchain != NULL) {
- spec_sum += v->efirst->offset_r;
- }
- else {
- spec_sum += v->elast->offset_l;
- }
- i++;
- v = v->adjchain;
- } while (v && v != vstart);
-
- gprod = 1.00f;
- gprod_sum = 1.0f;
- for (i = np - 1; i > 0; i--) {
- gprod *= g[i];
- g_prod[i] = gprod;
- gprod_sum += gprod;
- }
- g_prod[0] = 1.0f;
- if (iscycle) {
- gprod *= g[0];
- if (fabs(gprod - 1.0f) > BEVEL_EPSILON) {
- /* fast cycle calc only works if total product is 1 */
- MEM_freeN(g);
- MEM_freeN(g_prod);
- return false;
- }
- }
- if (gprod_sum == 0.0f) {
- MEM_freeN(g);
- MEM_freeN(g_prod);
- return false;
- }
- p = spec_sum / gprod_sum;
-
- /* apply the new offsets */
- v = vstart;
- i = 0;
- do {
- if (iscycle || v->adjchain != NULL) {
- eright = v->efirst;
- eleft = v->elast;
- eright->offset_r = g_prod[(i + 1) % np] * p;
- if (iscycle || v != vstart) {
- eleft->offset_l = v->sinratio * eright->offset_r;
- }
- }
- else {
- /* not a cycle, and last of chain */
- eleft = v->elast;
- eleft->offset_l = p;
- }
- i++;
- v = v->adjchain;
- } while (v && v != vstart);
-
- MEM_freeN(g);
- MEM_freeN(g_prod);
- return true;
+ BoundVert *v;
+ EdgeHalf *eleft, *eright;
+ float *g;
+ float *g_prod;
+ float gprod, gprod_sum, spec_sum, p;
+ int i;
+
+ g = MEM_mallocN(np * sizeof(float), "beveladjust");
+ g_prod = MEM_mallocN(np * sizeof(float), "beveladjust");
+
+ v = vstart;
+ spec_sum = 0.0f;
+ i = 0;
+ do {
+ g[i] = v->sinratio;
+ if (iscycle || v->adjchain != NULL) {
+ spec_sum += v->efirst->offset_r;
+ }
+ else {
+ spec_sum += v->elast->offset_l;
+ }
+ i++;
+ v = v->adjchain;
+ } while (v && v != vstart);
+
+ gprod = 1.00f;
+ gprod_sum = 1.0f;
+ for (i = np - 1; i > 0; i--) {
+ gprod *= g[i];
+ g_prod[i] = gprod;
+ gprod_sum += gprod;
+ }
+ g_prod[0] = 1.0f;
+ if (iscycle) {
+ gprod *= g[0];
+ if (fabs(gprod - 1.0f) > BEVEL_EPSILON) {
+ /* fast cycle calc only works if total product is 1 */
+ MEM_freeN(g);
+ MEM_freeN(g_prod);
+ return false;
+ }
+ }
+ if (gprod_sum == 0.0f) {
+ MEM_freeN(g);
+ MEM_freeN(g_prod);
+ return false;
+ }
+ p = spec_sum / gprod_sum;
+
+ /* apply the new offsets */
+ v = vstart;
+ i = 0;
+ do {
+ if (iscycle || v->adjchain != NULL) {
+ eright = v->efirst;
+ eleft = v->elast;
+ eright->offset_r = g_prod[(i + 1) % np] * p;
+ if (iscycle || v != vstart) {
+ eleft->offset_l = v->sinratio * eright->offset_r;
+ }
+ }
+ else {
+ /* not a cycle, and last of chain */
+ eleft = v->elast;
+ eleft->offset_l = p;
+ }
+ i++;
+ v = v->adjchain;
+ } while (v && v != vstart);
+
+ MEM_freeN(g);
+ MEM_freeN(g_prod);
+ return true;
}
#endif
@@ -2789,146 +2814,157 @@ static bool adjust_the_cycle_or_chain_fast(BoundVert *vstart, int np, bool iscyc
*/
static void adjust_the_cycle_or_chain(BoundVert *vstart, bool iscycle)
{
- BoundVert *v;
- EdgeHalf *eleft, *eright, *enextleft;
- LinearSolver *solver;
- double weight, val;
- int i, np, nrows, row;
+ BoundVert *v;
+ EdgeHalf *eleft, *eright, *enextleft;
+ LinearSolver *solver;
+ double weight, val;
+ int i, np, nrows, row;
- np = 0;
+ np = 0;
#ifdef DEBUG_ADJUST
- printf("\nadjust the %s (with eigen)\n", iscycle ? "cycle" : "chain");
+ printf("\nadjust the %s (with eigen)\n", iscycle ? "cycle" : "chain");
#endif
- v = vstart;
- do {
+ v = vstart;
+ do {
#ifdef DEBUG_ADJUST
- eleft = v->elast;
- eright = v->efirst;
- printf(" (left=e%d, right=e%d)", BM_elem_index_get(eleft->e), BM_elem_index_get(eright->e));
+ eleft = v->elast;
+ eright = v->efirst;
+ printf(" (left=e%d, right=e%d)", BM_elem_index_get(eleft->e), BM_elem_index_get(eright->e));
#endif
- np++;
- v = v->adjchain;
- } while (v && v != vstart);
+ np++;
+ v = v->adjchain;
+ } while (v && v != vstart);
#ifdef DEBUG_ADJUST
- printf(" -> %d parms\n", np);
+ printf(" -> %d parms\n", np);
#endif
#ifdef FAST_ADJUST_CODE
- if (adjust_the_cycle_or_chain_fast(vstart, np, iscycle)) {
- return;
- }
+ if (adjust_the_cycle_or_chain_fast(vstart, np, iscycle)) {
+ return;
+ }
#endif
- nrows = iscycle ? 3 * np : 3 * np - 3;
+ nrows = iscycle ? 3 * np : 3 * np - 3;
- solver = EIG_linear_least_squares_solver_new(nrows, np, 1);
+ solver = EIG_linear_least_squares_solver_new(nrows, np, 1);
- v = vstart;
- i = 0;
- weight = BEVEL_MATCH_SPEC_WEIGHT; /* sqrt of factor to weight down importance of spec match */
- do {
- /* except at end of chain, v's indep variable is offset_r of v->efirst */
- if (iscycle || i < np - 1) {
- eright = v->efirst;
- eleft = v->elast;
- enextleft = v->adjchain->elast;
+ v = vstart;
+ i = 0;
+ weight = BEVEL_MATCH_SPEC_WEIGHT; /* sqrt of factor to weight down importance of spec match */
+ do {
+ /* except at end of chain, v's indep variable is offset_r of v->efirst */
+ if (iscycle || i < np - 1) {
+ eright = v->efirst;
+ eleft = v->elast;
+ enextleft = v->adjchain->elast;
#ifdef DEBUG_ADJUST
- printf("p%d: e%d->offset_r = %f\n", i, BM_elem_index_get(eright->e), eright->offset_r);
- if (iscycle || v != vstart) {
- printf(" dependent: e%d->offset_l = %f * p%d\n", BM_elem_index_get(eleft->e), v->sinratio, i);
- }
+ printf("p%d: e%d->offset_r = %f\n", i, BM_elem_index_get(eright->e), eright->offset_r);
+ if (iscycle || v != vstart) {
+ printf(" dependent: e%d->offset_l = %f * p%d\n",
+ BM_elem_index_get(eleft->e),
+ v->sinratio,
+ i);
+ }
#endif
- /* residue i: width difference between eright and eleft of next */
- EIG_linear_solver_matrix_add(solver, i, i, 1.0);
- EIG_linear_solver_right_hand_side_add(solver, 0, i, 0.0);
- if (iscycle) {
- EIG_linear_solver_matrix_add(solver, i > 0 ? i - 1 : np - 1, i, -v->sinratio);
- }
- else {
- if (i > 0) {
- EIG_linear_solver_matrix_add(solver, i - 1, i, -v->sinratio);
- }
- }
-
- /* residue np + 2*i (if cycle) else np - 1 + 2*i:
- * right offset for parm i matches its spec; weighted */
- row = iscycle ? np + 2 * i : np - 1 + 2 * i;
- EIG_linear_solver_matrix_add(solver, row, i, weight);
- EIG_linear_solver_right_hand_side_add(solver, 0, row, weight * eright->offset_r);
+ /* residue i: width difference between eright and eleft of next */
+ EIG_linear_solver_matrix_add(solver, i, i, 1.0);
+ EIG_linear_solver_right_hand_side_add(solver, 0, i, 0.0);
+ if (iscycle) {
+ EIG_linear_solver_matrix_add(solver, i > 0 ? i - 1 : np - 1, i, -v->sinratio);
+ }
+ else {
+ if (i > 0) {
+ EIG_linear_solver_matrix_add(solver, i - 1, i, -v->sinratio);
+ }
+ }
+
+ /* residue np + 2*i (if cycle) else np - 1 + 2*i:
+ * right offset for parm i matches its spec; weighted */
+ row = iscycle ? np + 2 * i : np - 1 + 2 * i;
+ EIG_linear_solver_matrix_add(solver, row, i, weight);
+ EIG_linear_solver_right_hand_side_add(solver, 0, row, weight * eright->offset_r);
#ifdef DEBUG_ADJUST
- printf("b[%d]=%f * %f, for e%d->offset_r\n", row, weight, eright->offset_r, BM_elem_index_get(eright->e));
+ printf("b[%d]=%f * %f, for e%d->offset_r\n",
+ row,
+ weight,
+ eright->offset_r,
+ BM_elem_index_get(eright->e));
#endif
- /* residue np + 2*i + 1 (if cycle) else np - 1 + 2*i + 1:
- * left offset for parm i matches its spec; weighted */
- row = row + 1;
- EIG_linear_solver_matrix_add(solver, row, (i == np - 1) ? 0 : i + 1, weight * v->adjchain->sinratio);
- EIG_linear_solver_right_hand_side_add(solver, 0, row, weight * enextleft->offset_l);
+ /* residue np + 2*i + 1 (if cycle) else np - 1 + 2*i + 1:
+ * left offset for parm i matches its spec; weighted */
+ row = row + 1;
+ EIG_linear_solver_matrix_add(
+ solver, row, (i == np - 1) ? 0 : i + 1, weight * v->adjchain->sinratio);
+ EIG_linear_solver_right_hand_side_add(solver, 0, row, weight * enextleft->offset_l);
#ifdef DEBUG_ADJUST
- printf("b[%d]=%f * %f, for e%d->offset_l\n", row, weight, enextleft->offset_l,
- BM_elem_index_get(enextleft->e));
+ printf("b[%d]=%f * %f, for e%d->offset_l\n",
+ row,
+ weight,
+ enextleft->offset_l,
+ BM_elem_index_get(enextleft->e));
#endif
- }
- else {
- /* not a cycle, and last of chain */
- eleft = v->elast;
+ }
+ else {
+ /* not a cycle, and last of chain */
+ eleft = v->elast;
#ifdef DEBUG_ADJUST
- printf("p%d: e%d->offset_l = %f\n", i, BM_elem_index_get(eleft->e), eleft->offset_l);
+ printf("p%d: e%d->offset_l = %f\n", i, BM_elem_index_get(eleft->e), eleft->offset_l);
#endif
- /* second part of residue i for last i */
- EIG_linear_solver_matrix_add(solver, i - 1, i, -1.0);
- }
- i++;
- v = v->adjchain;
- } while (v && v != vstart);
- EIG_linear_solver_solve(solver);
+ /* second part of residue i for last i */
+ EIG_linear_solver_matrix_add(solver, i - 1, i, -1.0);
+ }
+ i++;
+ v = v->adjchain;
+ } while (v && v != vstart);
+ EIG_linear_solver_solve(solver);
#ifdef DEBUG_ADJUST
- /* Note: this print only works after solve, but by that time b has been cleared */
- EIG_linear_solver_print_matrix(solver);
- printf("\nSolution:\n");
- for (i = 0; i < np; i++) {
- printf("p%d = %f\n", i, EIG_linear_solver_variable_get(solver, 0, i));
- }
+ /* Note: this print only works after solve, but by that time b has been cleared */
+ EIG_linear_solver_print_matrix(solver);
+ printf("\nSolution:\n");
+ for (i = 0; i < np; i++) {
+ printf("p%d = %f\n", i, EIG_linear_solver_variable_get(solver, 0, i));
+ }
#endif
- /* Use the solution to set new widths */
- v = vstart;
- i = 0;
- do {
- val = EIG_linear_solver_variable_get(solver, 0, i);
- if (iscycle || i < np - 1) {
- eright = v->efirst;
- eleft = v->elast;
- eright->offset_r = (float)val;
+ /* Use the solution to set new widths */
+ v = vstart;
+ i = 0;
+ do {
+ val = EIG_linear_solver_variable_get(solver, 0, i);
+ if (iscycle || i < np - 1) {
+ eright = v->efirst;
+ eleft = v->elast;
+ eright->offset_r = (float)val;
#ifdef DEBUG_ADJUST
- printf("e%d->offset_r = %f\n", BM_elem_index_get(eright->e), eright->offset_r);
+ printf("e%d->offset_r = %f\n", BM_elem_index_get(eright->e), eright->offset_r);
#endif
- if (iscycle || v != vstart) {
- eleft->offset_l = (float)(v->sinratio * val);
+ if (iscycle || v != vstart) {
+ eleft->offset_l = (float)(v->sinratio * val);
#ifdef DEBUG_ADJUST
- printf("e%d->offset_l = %f\n", BM_elem_index_get(eleft->e), eleft->offset_l);
+ printf("e%d->offset_l = %f\n", BM_elem_index_get(eleft->e), eleft->offset_l);
#endif
- }
- }
- else {
- /* not a cycle, and last of chain */
- eleft = v->elast;
- eleft->offset_l = (float)val;
+ }
+ }
+ else {
+ /* not a cycle, and last of chain */
+ eleft = v->elast;
+ eleft->offset_l = (float)val;
#ifdef DEBUG_ADJUST
- printf("e%d->offset_l = %f\n", BM_elem_index_get(eleft->e), eleft->offset_l);
+ printf("e%d->offset_l = %f\n", BM_elem_index_get(eleft->e), eleft->offset_l);
#endif
- }
- i++;
- v = v->adjchain;
- } while (v && v != vstart);
+ }
+ i++;
+ v = v->adjchain;
+ } while (v && v != vstart);
#ifdef DEBUG_ADJUST
- print_adjust_stats(vstart);
- EIG_linear_solver_print_matrix(solver);
+ print_adjust_stats(vstart);
+ EIG_linear_solver_print_matrix(solver);
#endif
- EIG_linear_solver_delete(solver);
+ EIG_linear_solver_delete(solver);
}
/* Adjust the offsets to try to make them, as much as possible,
@@ -2943,99 +2979,99 @@ static void adjust_the_cycle_or_chain(BoundVert *vstart, bool iscycle)
*/
static void adjust_offsets(BevelParams *bp, BMesh *bm)
{
- BMVert *bmv;
- BevVert *bv, *bvcur;
- BoundVert *v, *vanchor, *vchainstart, *vchainend, *vnext;
- EdgeHalf *enext;
- BMIter iter;
- bool iscycle;
- int chainlen;
-
- /* find and process chains and cycles of unvisited BoundVerts that have eon set */
- /* note: for repeatability, iterate over all verts of mesh rather than over ghash'ed BMVerts */
- BM_ITER_MESH(bmv, &iter, bm, BM_VERTS_OF_MESH) {
- if (!BM_elem_flag_test(bmv, BM_ELEM_TAG))
- continue;
- bv = bvcur = find_bevvert(bp, bmv);
- if (!bv)
- continue;
- vanchor = bv->vmesh->boundstart;
- do {
- if (vanchor->visited || !vanchor->eon) {
- continue;
- }
-
- /* Find one of (1) a cycle that starts and ends at v
- * where each v has v->eon set and had not been visited before;
- * or (2) a chain of v's where the start and end of the chain do not have
- * v->eon set but all else do.
- * It is OK for the first and last elements to
- * have been visited before, but not any of the inner ones.
- * We chain the v's together through v->adjchain, and are following
- * them in left->right direction, meaning that the left side of one edge
- * pairs with the right side of the next edge in the cycle or chain. */
-
- /* first follow paired edges in left->right direction */
- v = vchainstart = vchainend = vanchor;
- iscycle = false;
- chainlen = 1;
- while (v->eon && !v->visited && !iscycle) {
- v->visited = true;
- if (!v->efirst) {
- break;
- }
- enext = find_other_end_edge_half(bp, v->efirst, &bvcur);
- if (!enext) {
- break;
- }
- BLI_assert(enext != NULL);
- vnext = enext->leftv;
- v->adjchain = vnext;
- vchainend = vnext;
- chainlen++;
- if (vnext->visited) {
- if (vnext != vchainstart) {
- break;
- }
- adjust_the_cycle_or_chain(vchainstart, true);
- iscycle = true;
- }
- v = vnext;
- }
- if (!iscycle) {
- /* right->left direction, changing vchainstart at each step */
- v = vchainstart;
- bvcur = bv;
- do {
- v->visited = true;
- if (!v->elast) {
- break;
- }
- enext = find_other_end_edge_half(bp, v->elast, &bvcur);
- if (!enext) {
- break;
- }
- vnext = enext->rightv;
- vnext->adjchain = v;
- chainlen++;
- vchainstart = vnext;
- v = vnext;
- } while (!v->visited && v->eon);
- if (chainlen >= 3 && !vchainstart->eon && !vchainend->eon) {
- adjust_the_cycle_or_chain(vchainstart, false);
- }
- }
- } while ((vanchor = vanchor->next) != bv->vmesh->boundstart);
- }
-
- /* Rebuild boundaries with new width specs */
- BM_ITER_MESH(bmv, &iter, bm, BM_VERTS_OF_MESH) {
- if (BM_elem_flag_test(bmv, BM_ELEM_TAG)) {
- bv = find_bevvert(bp, bmv);
- if (bv)
- build_boundary(bp, bv, false);
- }
- }
+ BMVert *bmv;
+ BevVert *bv, *bvcur;
+ BoundVert *v, *vanchor, *vchainstart, *vchainend, *vnext;
+ EdgeHalf *enext;
+ BMIter iter;
+ bool iscycle;
+ int chainlen;
+
+ /* find and process chains and cycles of unvisited BoundVerts that have eon set */
+ /* note: for repeatability, iterate over all verts of mesh rather than over ghash'ed BMVerts */
+ BM_ITER_MESH (bmv, &iter, bm, BM_VERTS_OF_MESH) {
+ if (!BM_elem_flag_test(bmv, BM_ELEM_TAG))
+ continue;
+ bv = bvcur = find_bevvert(bp, bmv);
+ if (!bv)
+ continue;
+ vanchor = bv->vmesh->boundstart;
+ do {
+ if (vanchor->visited || !vanchor->eon) {
+ continue;
+ }
+
+ /* Find one of (1) a cycle that starts and ends at v
+ * where each v has v->eon set and had not been visited before;
+ * or (2) a chain of v's where the start and end of the chain do not have
+ * v->eon set but all else do.
+ * It is OK for the first and last elements to
+ * have been visited before, but not any of the inner ones.
+ * We chain the v's together through v->adjchain, and are following
+ * them in left->right direction, meaning that the left side of one edge
+ * pairs with the right side of the next edge in the cycle or chain. */
+
+ /* first follow paired edges in left->right direction */
+ v = vchainstart = vchainend = vanchor;
+ iscycle = false;
+ chainlen = 1;
+ while (v->eon && !v->visited && !iscycle) {
+ v->visited = true;
+ if (!v->efirst) {
+ break;
+ }
+ enext = find_other_end_edge_half(bp, v->efirst, &bvcur);
+ if (!enext) {
+ break;
+ }
+ BLI_assert(enext != NULL);
+ vnext = enext->leftv;
+ v->adjchain = vnext;
+ vchainend = vnext;
+ chainlen++;
+ if (vnext->visited) {
+ if (vnext != vchainstart) {
+ break;
+ }
+ adjust_the_cycle_or_chain(vchainstart, true);
+ iscycle = true;
+ }
+ v = vnext;
+ }
+ if (!iscycle) {
+ /* right->left direction, changing vchainstart at each step */
+ v = vchainstart;
+ bvcur = bv;
+ do {
+ v->visited = true;
+ if (!v->elast) {
+ break;
+ }
+ enext = find_other_end_edge_half(bp, v->elast, &bvcur);
+ if (!enext) {
+ break;
+ }
+ vnext = enext->rightv;
+ vnext->adjchain = v;
+ chainlen++;
+ vchainstart = vnext;
+ v = vnext;
+ } while (!v->visited && v->eon);
+ if (chainlen >= 3 && !vchainstart->eon && !vchainend->eon) {
+ adjust_the_cycle_or_chain(vchainstart, false);
+ }
+ }
+ } while ((vanchor = vanchor->next) != bv->vmesh->boundstart);
+ }
+
+ /* Rebuild boundaries with new width specs */
+ BM_ITER_MESH (bmv, &iter, bm, BM_VERTS_OF_MESH) {
+ if (BM_elem_flag_test(bmv, BM_ELEM_TAG)) {
+ bv = find_bevvert(bp, bmv);
+ if (bv)
+ build_boundary(bp, bv, false);
+ }
+ }
}
/* Do the edges at bv form a "pipe"?
@@ -3047,60 +3083,61 @@ static void adjust_offsets(BevelParams *bp, BMesh *bm)
* whose next boundary vert has a beveled, non-pipe edge. */
static BoundVert *pipe_test(BevVert *bv)
{
- EdgeHalf *e, *epipe;
- VMesh *vm;
- BoundVert *v1, *v2, *v3;
- float dir1[3], dir3[3];
-
- vm = bv->vmesh;
- if (vm->count < 3 || vm->count > 4 || bv->selcount < 3 || bv->selcount > 4) {
- return NULL;
- }
-
- /* find v1, v2, v3 all with beveled edges, where v1 and v3 have collinear edges */
- epipe = NULL;
- v1 = vm->boundstart;
- do {
- v2 = v1->next;
- v3 = v2->next;
- if (v1->ebev && v2->ebev && v3->ebev) {
- sub_v3_v3v3(dir1, bv->v->co, BM_edge_other_vert(v1->ebev->e, bv->v)->co);
- sub_v3_v3v3(dir3, BM_edge_other_vert(v3->ebev->e, bv->v)->co, bv->v->co);
- normalize_v3(dir1);
- normalize_v3(dir3);
- if (angle_normalized_v3v3(dir1, dir3) < BEVEL_EPSILON_ANG) {
- epipe = v1->ebev;
- break;
- }
- }
- } while ((v1 = v1->next) != vm->boundstart);
-
- if (!epipe) {
- return NULL;
- }
-
- /* check face planes: all should have normals perpendicular to epipe */
- for (e = &bv->edges[0]; e != &bv->edges[bv->edgecount]; e++) {
- if (e->fnext) {
- if (dot_v3v3(dir1, e->fnext->no) > BEVEL_EPSILON_BIG) {
- return NULL;
- }
- }
- }
- return v1;
+ EdgeHalf *e, *epipe;
+ VMesh *vm;
+ BoundVert *v1, *v2, *v3;
+ float dir1[3], dir3[3];
+
+ vm = bv->vmesh;
+ if (vm->count < 3 || vm->count > 4 || bv->selcount < 3 || bv->selcount > 4) {
+ return NULL;
+ }
+
+ /* find v1, v2, v3 all with beveled edges, where v1 and v3 have collinear edges */
+ epipe = NULL;
+ v1 = vm->boundstart;
+ do {
+ v2 = v1->next;
+ v3 = v2->next;
+ if (v1->ebev && v2->ebev && v3->ebev) {
+ sub_v3_v3v3(dir1, bv->v->co, BM_edge_other_vert(v1->ebev->e, bv->v)->co);
+ sub_v3_v3v3(dir3, BM_edge_other_vert(v3->ebev->e, bv->v)->co, bv->v->co);
+ normalize_v3(dir1);
+ normalize_v3(dir3);
+ if (angle_normalized_v3v3(dir1, dir3) < BEVEL_EPSILON_ANG) {
+ epipe = v1->ebev;
+ break;
+ }
+ }
+ } while ((v1 = v1->next) != vm->boundstart);
+
+ if (!epipe) {
+ return NULL;
+ }
+
+ /* check face planes: all should have normals perpendicular to epipe */
+ for (e = &bv->edges[0]; e != &bv->edges[bv->edgecount]; e++) {
+ if (e->fnext) {
+ if (dot_v3v3(dir1, e->fnext->no) > BEVEL_EPSILON_BIG) {
+ return NULL;
+ }
+ }
+ }
+ return v1;
}
static VMesh *new_adj_vmesh(MemArena *mem_arena, int count, int seg, BoundVert *bounds)
{
- VMesh *vm;
-
- vm = (VMesh *)BLI_memarena_alloc(mem_arena, sizeof(VMesh));
- vm->count = count;
- vm->seg = seg;
- vm->boundstart = bounds;
- vm->mesh = (NewVert *)BLI_memarena_alloc(mem_arena, count * (1 + seg / 2) * (1 + seg) * sizeof(NewVert));
- vm->mesh_kind = M_ADJ;
- return vm;
+ VMesh *vm;
+
+ vm = (VMesh *)BLI_memarena_alloc(mem_arena, sizeof(VMesh));
+ vm->count = count;
+ vm->seg = seg;
+ vm->boundstart = bounds;
+ vm->mesh = (NewVert *)BLI_memarena_alloc(mem_arena,
+ count * (1 + seg / 2) * (1 + seg) * sizeof(NewVert));
+ vm->mesh_kind = M_ADJ;
+ return vm;
}
/* VMesh verts for vertex i have data for (i, 0 <= j <= ns2, 0 <= k <= ns), where ns2 = floor(nseg / 2).
@@ -3112,274 +3149,271 @@ static VMesh *new_adj_vmesh(MemArena *mem_arena, int count, int seg, BoundVert *
* This function returns the canonical one for any i, j, k in [0,n],[0,ns],[0,ns] */
static NewVert *mesh_vert_canon(VMesh *vm, int i, int j, int k)
{
- int n, ns, ns2, odd;
- NewVert *ans;
-
- n = vm->count;
- ns = vm->seg;
- ns2 = ns / 2;
- odd = ns % 2;
- BLI_assert(0 <= i && i <= n && 0 <= j && j <= ns && 0 <= k && k <= ns);
-
- if (!odd && j == ns2 && k == ns2) {
- ans = mesh_vert(vm, 0, j, k);
- }
- else if (j <= ns2 - 1 + odd && k <= ns2) {
- ans = mesh_vert(vm, i, j, k);
- }
- else if (k <= ns2) {
- ans = mesh_vert(vm, (i + n - 1) % n, k, ns - j);
- }
- else {
- ans = mesh_vert(vm, (i + 1) % n, ns - k, j);
- }
- return ans;
+ int n, ns, ns2, odd;
+ NewVert *ans;
+
+ n = vm->count;
+ ns = vm->seg;
+ ns2 = ns / 2;
+ odd = ns % 2;
+ BLI_assert(0 <= i && i <= n && 0 <= j && j <= ns && 0 <= k && k <= ns);
+
+ if (!odd && j == ns2 && k == ns2) {
+ ans = mesh_vert(vm, 0, j, k);
+ }
+ else if (j <= ns2 - 1 + odd && k <= ns2) {
+ ans = mesh_vert(vm, i, j, k);
+ }
+ else if (k <= ns2) {
+ ans = mesh_vert(vm, (i + n - 1) % n, k, ns - j);
+ }
+ else {
+ ans = mesh_vert(vm, (i + 1) % n, ns - k, j);
+ }
+ return ans;
}
static bool is_canon(VMesh *vm, int i, int j, int k)
{
- int ns2 = vm->seg / 2;
- if (vm->seg % 2 == 1) {
- return (j <= ns2 && k <= ns2);
- }
- else {
- return ((j < ns2 && k <= ns2) || (j == ns2 && k == ns2 && i == 0));
- }
+ int ns2 = vm->seg / 2;
+ if (vm->seg % 2 == 1) {
+ return (j <= ns2 && k <= ns2);
+ }
+ else {
+ return ((j < ns2 && k <= ns2) || (j == ns2 && k == ns2 && i == 0));
+ }
}
/* Copy the vertex data to all of vm verts from canonical ones */
static void vmesh_copy_equiv_verts(VMesh *vm)
{
- int n, ns, ns2, i, j, k;
- NewVert *v0, *v1;
-
- n = vm->count;
- ns = vm->seg;
- ns2 = ns / 2;
- for (i = 0; i < n; i++) {
- for (j = 0; j <= ns2; j++) {
- for (k = 0; k <= ns; k++) {
- if (is_canon(vm, i, j, k)) {
- continue;
- }
- v1 = mesh_vert(vm, i, j, k);
- v0 = mesh_vert_canon(vm, i, j, k);
- copy_v3_v3(v1->co, v0->co);
- v1->v = v0->v;
- }
- }
- }
+ int n, ns, ns2, i, j, k;
+ NewVert *v0, *v1;
+
+ n = vm->count;
+ ns = vm->seg;
+ ns2 = ns / 2;
+ for (i = 0; i < n; i++) {
+ for (j = 0; j <= ns2; j++) {
+ for (k = 0; k <= ns; k++) {
+ if (is_canon(vm, i, j, k)) {
+ continue;
+ }
+ v1 = mesh_vert(vm, i, j, k);
+ v0 = mesh_vert_canon(vm, i, j, k);
+ copy_v3_v3(v1->co, v0->co);
+ v1->v = v0->v;
+ }
+ }
+ }
}
/* Calculate and return in r_cent the centroid of the center poly */
static void vmesh_center(VMesh *vm, float r_cent[3])
{
- int n, ns2, i;
-
- n = vm->count;
- ns2 = vm->seg / 2;
- if (vm->seg % 2) {
- zero_v3(r_cent);
- for (i = 0; i < n; i++) {
- add_v3_v3(r_cent, mesh_vert(vm, i, ns2, ns2)->co);
- }
- mul_v3_fl(r_cent, 1.0f / (float) n);
- }
- else {
- copy_v3_v3(r_cent, mesh_vert(vm, 0, ns2, ns2)->co);
- }
+ int n, ns2, i;
+
+ n = vm->count;
+ ns2 = vm->seg / 2;
+ if (vm->seg % 2) {
+ zero_v3(r_cent);
+ for (i = 0; i < n; i++) {
+ add_v3_v3(r_cent, mesh_vert(vm, i, ns2, ns2)->co);
+ }
+ mul_v3_fl(r_cent, 1.0f / (float)n);
+ }
+ else {
+ copy_v3_v3(r_cent, mesh_vert(vm, 0, ns2, ns2)->co);
+ }
}
static void avg4(
- float co[3],
- const NewVert *v0, const NewVert *v1,
- const NewVert *v2, const NewVert *v3)
+ float co[3], const NewVert *v0, const NewVert *v1, const NewVert *v2, const NewVert *v3)
{
- add_v3_v3v3(co, v0->co, v1->co);
- add_v3_v3(co, v2->co);
- add_v3_v3(co, v3->co);
- mul_v3_fl(co, 0.25f);
+ add_v3_v3v3(co, v0->co, v1->co);
+ add_v3_v3(co, v2->co);
+ add_v3_v3(co, v3->co);
+ mul_v3_fl(co, 0.25f);
}
/* gamma needed for smooth Catmull-Clark, Sabin modification */
static float sabin_gamma(int n)
{
- double ans, k, k2, k4, k6, x, y;
-
- /* precalculated for common cases of n */
- if (n < 3) {
- return 0.0f;
- }
- else if (n == 3) {
- ans = 0.065247584f;
- }
- else if (n == 4) {
- ans = 0.25f;
- }
- else if (n == 5) {
- ans = 0.401983447f;
- }
- else if (n == 6) {
- ans = 0.523423277f;
- }
- else {
- k = cos(M_PI / (double)n);
- /* need x, real root of x^3 + (4k^2 - 3)x - 2k = 0.
- * answer calculated via Wolfram Alpha */
- k2 = k * k;
- k4 = k2 * k2;
- k6 = k4 * k2;
- y = pow(M_SQRT3 * sqrt(64.0 * k6 - 144.0 * k4 + 135.0 * k2 - 27.0) + 9.0 * k,
- 1.0 / 3.0);
- x = 0.480749856769136 * y - (0.231120424783545 * (12.0 * k2 - 9.0)) / y;
- ans = (k * x + 2.0 * k2 - 1.0) / (x * x * (k * x + 1.0));
- }
- return (float)ans;
+ double ans, k, k2, k4, k6, x, y;
+
+ /* precalculated for common cases of n */
+ if (n < 3) {
+ return 0.0f;
+ }
+ else if (n == 3) {
+ ans = 0.065247584f;
+ }
+ else if (n == 4) {
+ ans = 0.25f;
+ }
+ else if (n == 5) {
+ ans = 0.401983447f;
+ }
+ else if (n == 6) {
+ ans = 0.523423277f;
+ }
+ else {
+ k = cos(M_PI / (double)n);
+ /* need x, real root of x^3 + (4k^2 - 3)x - 2k = 0.
+ * answer calculated via Wolfram Alpha */
+ k2 = k * k;
+ k4 = k2 * k2;
+ k6 = k4 * k2;
+ y = pow(M_SQRT3 * sqrt(64.0 * k6 - 144.0 * k4 + 135.0 * k2 - 27.0) + 9.0 * k, 1.0 / 3.0);
+ x = 0.480749856769136 * y - (0.231120424783545 * (12.0 * k2 - 9.0)) / y;
+ ans = (k * x + 2.0 * k2 - 1.0) / (x * x * (k * x + 1.0));
+ }
+ return (float)ans;
}
/* Fill frac with fractions of way along ring 0 for vertex i, for use with interp_range function */
static void fill_vmesh_fracs(VMesh *vm, float *frac, int i)
{
- int k, ns;
- float total = 0.0f;
-
- ns = vm->seg;
- frac[0] = 0.0f;
- for (k = 0; k < ns; k++) {
- total += len_v3v3(mesh_vert(vm, i, 0, k)->co, mesh_vert(vm, i, 0, k + 1)->co);
- frac[k + 1] = total;
- }
- if (total > 0.0f) {
- for (k = 1; k <= ns; k++) {
- frac[k] /= total;
- }
- }
- else {
- frac[ns] = 1.0f;
- }
+ int k, ns;
+ float total = 0.0f;
+
+ ns = vm->seg;
+ frac[0] = 0.0f;
+ for (k = 0; k < ns; k++) {
+ total += len_v3v3(mesh_vert(vm, i, 0, k)->co, mesh_vert(vm, i, 0, k + 1)->co);
+ frac[k + 1] = total;
+ }
+ if (total > 0.0f) {
+ for (k = 1; k <= ns; k++) {
+ frac[k] /= total;
+ }
+ }
+ else {
+ frac[ns] = 1.0f;
+ }
}
/* Like fill_vmesh_fracs but want fractions for profile points of bndv, with ns segments */
static void fill_profile_fracs(BevelParams *bp, BoundVert *bndv, float *frac, int ns)
{
- int k;
- float co[3], nextco[3];
- float total = 0.0f;
-
- frac[0] = 0.0f;
- copy_v3_v3(co, bndv->nv.co);
- for (k = 0; k < ns; k++) {
- get_profile_point(bp, &bndv->profile, k + 1, ns, nextco);
- total += len_v3v3(co, nextco);
- frac[k + 1] = total;
- copy_v3_v3(co, nextco);
- }
- if (total > 0.0f) {
- for (k = 1; k <= ns; k++) {
- frac[k] /= total;
- }
- }
- else {
- frac[ns] = 1.0f;
- }
+ int k;
+ float co[3], nextco[3];
+ float total = 0.0f;
+
+ frac[0] = 0.0f;
+ copy_v3_v3(co, bndv->nv.co);
+ for (k = 0; k < ns; k++) {
+ get_profile_point(bp, &bndv->profile, k + 1, ns, nextco);
+ total += len_v3v3(co, nextco);
+ frac[k + 1] = total;
+ copy_v3_v3(co, nextco);
+ }
+ if (total > 0.0f) {
+ for (k = 1; k <= ns; k++) {
+ frac[k] /= total;
+ }
+ }
+ else {
+ frac[ns] = 1.0f;
+ }
}
/* Return i such that frac[i] <= f <= frac[i + 1], where frac[n] == 1.0
* and put fraction of rest of way between frac[i] and frac[i + 1] into r_rest */
static int interp_range(const float *frac, int n, const float f, float *r_rest)
{
- int i;
- float rest;
-
- /* could binary search in frac, but expect n to be reasonably small */
- for (i = 0; i < n; i++) {
- if (f <= frac[i + 1]) {
- rest = f - frac[i];
- if (rest == 0) {
- *r_rest = 0.0f;
- }
- else {
- *r_rest = rest / (frac[i + 1] - frac[i]);
- }
- if (i == n - 1 && *r_rest == 1.0f) {
- i = n;
- *r_rest = 0.0f;
- }
- return i;
- }
- }
- *r_rest = 0.0f;
- return n;
+ int i;
+ float rest;
+
+ /* could binary search in frac, but expect n to be reasonably small */
+ for (i = 0; i < n; i++) {
+ if (f <= frac[i + 1]) {
+ rest = f - frac[i];
+ if (rest == 0) {
+ *r_rest = 0.0f;
+ }
+ else {
+ *r_rest = rest / (frac[i + 1] - frac[i]);
+ }
+ if (i == n - 1 && *r_rest == 1.0f) {
+ i = n;
+ *r_rest = 0.0f;
+ }
+ return i;
+ }
+ }
+ *r_rest = 0.0f;
+ return n;
}
/* Interpolate given vmesh to make one with target nseg border vertices on the profiles */
static VMesh *interp_vmesh(BevelParams *bp, VMesh *vm0, int nseg)
{
- int n, ns0, nseg2, odd, i, j, k, j0, k0, k0prev, j0inc, k0inc;
- float *prev_frac, *frac, *new_frac, *prev_new_frac;
- float f, restj, restk, restkprev;
- float quad[4][3], co[3], center[3];
- VMesh *vm1;
- BoundVert *bndv;
-
- n = vm0->count;
- ns0 = vm0->seg;
- nseg2 = nseg / 2;
- odd = nseg % 2;
- vm1 = new_adj_vmesh(bp->mem_arena, n, nseg, vm0->boundstart);
-
- prev_frac = BLI_array_alloca(prev_frac, (ns0 + 1));
- frac = BLI_array_alloca(frac, (ns0 + 1));
- new_frac = BLI_array_alloca(new_frac, (nseg + 1));
- prev_new_frac = BLI_array_alloca(prev_new_frac, (nseg + 1));
-
- fill_vmesh_fracs(vm0, prev_frac, n - 1);
- bndv = vm0->boundstart;
- fill_profile_fracs(bp, bndv->prev, prev_new_frac, nseg);
- for (i = 0; i < n; i++) {
- fill_vmesh_fracs(vm0, frac, i);
- fill_profile_fracs(bp, bndv, new_frac, nseg);
- for (j = 0; j <= nseg2 - 1 + odd; j++) {
- for (k = 0; k <= nseg2; k++) {
- f = new_frac[k];
- k0 = interp_range(frac, ns0, f, &restk);
- f = prev_new_frac[nseg - j];
- k0prev = interp_range(prev_frac, ns0, f, &restkprev);
- j0 = ns0 - k0prev;
- restj = -restkprev;
- if (restj > -BEVEL_EPSILON) {
- restj = 0.0f;
- }
- else {
- j0 = j0 - 1;
- restj = 1.0f + restj;
- }
- /* Use bilinear interpolation within the source quad; could be smarter here */
- if (restj < BEVEL_EPSILON && restk < BEVEL_EPSILON) {
- copy_v3_v3(co, mesh_vert_canon(vm0, i, j0, k0)->co);
- }
- else {
- j0inc = (restj < BEVEL_EPSILON || j0 == ns0) ? 0 : 1;
- k0inc = (restk < BEVEL_EPSILON || k0 == ns0) ? 0 : 1;
- copy_v3_v3(quad[0], mesh_vert_canon(vm0, i, j0, k0)->co);
- copy_v3_v3(quad[1], mesh_vert_canon(vm0, i, j0, k0 + k0inc)->co);
- copy_v3_v3(quad[2], mesh_vert_canon(vm0, i, j0 + j0inc, k0 + k0inc)->co);
- copy_v3_v3(quad[3], mesh_vert_canon(vm0, i, j0 + j0inc, k0)->co);
- interp_bilinear_quad_v3(quad, restk, restj, co);
- }
- copy_v3_v3(mesh_vert(vm1, i, j, k)->co, co);
- }
- }
- bndv = bndv->next;
- memcpy(prev_frac, frac, (ns0 + 1) * sizeof(float));
- memcpy(prev_new_frac, new_frac, (nseg + 1) * sizeof(float));
- }
- if (!odd) {
- vmesh_center(vm0, center);
- copy_v3_v3(mesh_vert(vm1, 0, nseg2, nseg2)->co, center);
- }
- vmesh_copy_equiv_verts(vm1);
- return vm1;
+ int n, ns0, nseg2, odd, i, j, k, j0, k0, k0prev, j0inc, k0inc;
+ float *prev_frac, *frac, *new_frac, *prev_new_frac;
+ float f, restj, restk, restkprev;
+ float quad[4][3], co[3], center[3];
+ VMesh *vm1;
+ BoundVert *bndv;
+
+ n = vm0->count;
+ ns0 = vm0->seg;
+ nseg2 = nseg / 2;
+ odd = nseg % 2;
+ vm1 = new_adj_vmesh(bp->mem_arena, n, nseg, vm0->boundstart);
+
+ prev_frac = BLI_array_alloca(prev_frac, (ns0 + 1));
+ frac = BLI_array_alloca(frac, (ns0 + 1));
+ new_frac = BLI_array_alloca(new_frac, (nseg + 1));
+ prev_new_frac = BLI_array_alloca(prev_new_frac, (nseg + 1));
+
+ fill_vmesh_fracs(vm0, prev_frac, n - 1);
+ bndv = vm0->boundstart;
+ fill_profile_fracs(bp, bndv->prev, prev_new_frac, nseg);
+ for (i = 0; i < n; i++) {
+ fill_vmesh_fracs(vm0, frac, i);
+ fill_profile_fracs(bp, bndv, new_frac, nseg);
+ for (j = 0; j <= nseg2 - 1 + odd; j++) {
+ for (k = 0; k <= nseg2; k++) {
+ f = new_frac[k];
+ k0 = interp_range(frac, ns0, f, &restk);
+ f = prev_new_frac[nseg - j];
+ k0prev = interp_range(prev_frac, ns0, f, &restkprev);
+ j0 = ns0 - k0prev;
+ restj = -restkprev;
+ if (restj > -BEVEL_EPSILON) {
+ restj = 0.0f;
+ }
+ else {
+ j0 = j0 - 1;
+ restj = 1.0f + restj;
+ }
+ /* Use bilinear interpolation within the source quad; could be smarter here */
+ if (restj < BEVEL_EPSILON && restk < BEVEL_EPSILON) {
+ copy_v3_v3(co, mesh_vert_canon(vm0, i, j0, k0)->co);
+ }
+ else {
+ j0inc = (restj < BEVEL_EPSILON || j0 == ns0) ? 0 : 1;
+ k0inc = (restk < BEVEL_EPSILON || k0 == ns0) ? 0 : 1;
+ copy_v3_v3(quad[0], mesh_vert_canon(vm0, i, j0, k0)->co);
+ copy_v3_v3(quad[1], mesh_vert_canon(vm0, i, j0, k0 + k0inc)->co);
+ copy_v3_v3(quad[2], mesh_vert_canon(vm0, i, j0 + j0inc, k0 + k0inc)->co);
+ copy_v3_v3(quad[3], mesh_vert_canon(vm0, i, j0 + j0inc, k0)->co);
+ interp_bilinear_quad_v3(quad, restk, restj, co);
+ }
+ copy_v3_v3(mesh_vert(vm1, i, j, k)->co, co);
+ }
+ }
+ bndv = bndv->next;
+ memcpy(prev_frac, frac, (ns0 + 1) * sizeof(float));
+ memcpy(prev_new_frac, new_frac, (nseg + 1) * sizeof(float));
+ }
+ if (!odd) {
+ vmesh_center(vm0, center);
+ copy_v3_v3(mesh_vert(vm1, 0, nseg2, nseg2)->co, center);
+ }
+ vmesh_copy_equiv_verts(vm1);
+ return vm1;
}
/* Do one step of cubic subdivision (Catmull-Clark), with special rules at boundaries.
@@ -3388,203 +3422,206 @@ static VMesh *interp_vmesh(BevelParams *bp, VMesh *vm0, int nseg)
* See Levin 1999 paper: "Filling an N-sided hole using combined subdivision schemes". */
static VMesh *cubic_subdiv(BevelParams *bp, VMesh *vm0)
{
- int n, ns0, ns20, ns1;
- int i, j, k, inext;
- float co[3], co1[3], co2[3], acc[3];
- float beta, gamma;
- VMesh *vm1;
- BoundVert *bndv;
-
- n = vm0->count;
- ns0 = vm0->seg;
- ns20 = ns0 / 2;
- BLI_assert(ns0 % 2 == 0);
- ns1 = 2 * ns0;
- vm1 = new_adj_vmesh(bp->mem_arena, n, ns1, vm0->boundstart);
-
- /* First we adjust the boundary vertices of the input mesh, storing in output mesh */
- for (i = 0; i < n; i++) {
- copy_v3_v3(mesh_vert(vm1, i, 0, 0)->co, mesh_vert(vm0, i, 0, 0)->co);
- for (k = 1; k < ns0; k++) {
- /* smooth boundary rule */
- copy_v3_v3(co, mesh_vert(vm0, i, 0, k)->co);
- copy_v3_v3(co1, mesh_vert(vm0, i, 0, k - 1)->co);
- copy_v3_v3(co2, mesh_vert(vm0, i, 0, k + 1)->co);
-
- add_v3_v3v3(acc, co1, co2);
- madd_v3_v3fl(acc, co, -2.0f);
- madd_v3_v3fl(co, acc, -1.0f / 6.0f);
-
- copy_v3_v3(mesh_vert_canon(vm1, i, 0, 2 * k)->co, co);
- }
- }
- /* now do odd ones in output mesh, based on even ones */
- bndv = vm1->boundstart;
- for (i = 0; i < n; i++) {
- for (k = 1; k < ns1; k += 2) {
- get_profile_point(bp, &bndv->profile, k, ns1, co);
- copy_v3_v3(co1, mesh_vert_canon(vm1, i, 0, k - 1)->co);
- copy_v3_v3(co2, mesh_vert_canon(vm1, i, 0, k + 1)->co);
-
- add_v3_v3v3(acc, co1, co2);
- madd_v3_v3fl(acc, co, -2.0f);
- madd_v3_v3fl(co, acc, -1.0f / 6.0f);
-
- copy_v3_v3(mesh_vert_canon(vm1, i, 0, k)->co, co);
- }
- bndv = bndv->next;
- }
- vmesh_copy_equiv_verts(vm1);
-
- /* Copy adjusted verts back into vm0 */
- for (i = 0; i < n; i++) {
- for (k = 0; k < ns0; k++) {
- copy_v3_v3(mesh_vert(vm0, i, 0, k)->co,
- mesh_vert(vm1, i, 0, 2 * k)->co);
- }
- }
-
- vmesh_copy_equiv_verts(vm0);
-
- /* Now we do the internal vertices, using standard Catmull-Clark
- * and assuming all boundary vertices have valence 4 */
-
- /* The new face vertices */
- for (i = 0; i < n; i++) {
- for (j = 0; j < ns20; j++) {
- for (k = 0; k < ns20; k++) {
- /* face up and right from (j, k) */
- avg4(co,
- mesh_vert(vm0, i, j, k),
- mesh_vert(vm0, i, j, k + 1),
- mesh_vert(vm0, i, j + 1, k),
- mesh_vert(vm0, i, j + 1, k + 1));
- copy_v3_v3(mesh_vert(vm1, i, 2 * j + 1, 2 * k + 1)->co, co);
- }
- }
- }
-
- /* The new vertical edge vertices */
- for (i = 0; i < n; i++) {
- for (j = 0; j < ns20; j++) {
- for (k = 1; k <= ns20; k++) {
- /* vertical edge between (j, k) and (j+1, k) */
- avg4(co, mesh_vert(vm0, i, j, k),
- mesh_vert(vm0, i, j + 1, k),
- mesh_vert_canon(vm1, i, 2 * j + 1, 2 * k - 1),
- mesh_vert_canon(vm1, i, 2 * j + 1, 2 * k + 1));
- copy_v3_v3(mesh_vert(vm1, i, 2 * j + 1, 2 * k)->co, co);
- }
- }
- }
-
- /* The new horizontal edge vertices */
- for (i = 0; i < n; i++) {
- for (j = 1; j < ns20; j++) {
- for (k = 0; k < ns20; k++) {
- /* horizontal edge between (j, k) and (j, k+1) */
- avg4(co, mesh_vert(vm0, i, j, k),
- mesh_vert(vm0, i, j, k + 1),
- mesh_vert_canon(vm1, i, 2 * j - 1, 2 * k + 1),
- mesh_vert_canon(vm1, i, 2 * j + 1, 2 * k + 1));
- copy_v3_v3(mesh_vert(vm1, i, 2 * j, 2 * k + 1)->co, co);
- }
- }
- }
-
- /* The new vertices, not on border */
- gamma = 0.25f;
- beta = -gamma;
- for (i = 0; i < n; i++) {
- for (j = 1; j < ns20; j++) {
- for (k = 1; k <= ns20; k++) {
- /* co1 = centroid of adjacent new edge verts */
- avg4(co1, mesh_vert_canon(vm1, i, 2 * j, 2 * k - 1),
- mesh_vert_canon(vm1, i, 2 * j, 2 * k + 1),
- mesh_vert_canon(vm1, i, 2 * j - 1, 2 * k),
- mesh_vert_canon(vm1, i, 2 * j + 1, 2 * k));
- /* co2 = centroid of adjacent new face verts */
- avg4(co2, mesh_vert_canon(vm1, i, 2 * j - 1, 2 * k - 1),
- mesh_vert_canon(vm1, i, 2 * j + 1, 2 * k - 1),
- mesh_vert_canon(vm1, i, 2 * j - 1, 2 * k + 1),
- mesh_vert_canon(vm1, i, 2 * j + 1, 2 * k + 1));
- /* combine with original vert with alpha, beta, gamma factors */
- copy_v3_v3(co, co1); /* alpha = 1.0 */
- madd_v3_v3fl(co, co2, beta);
- madd_v3_v3fl(co, mesh_vert(vm0, i, j, k)->co, gamma);
- copy_v3_v3(mesh_vert(vm1, i, 2 * j, 2 * k)->co, co);
- }
- }
- }
-
- vmesh_copy_equiv_verts(vm1);
-
- /* The center vertex is special */
- gamma = sabin_gamma(n);
- beta = -gamma;
- /* accumulate edge verts in co1, face verts in co2 */
- zero_v3(co1);
- zero_v3(co2);
- for (i = 0; i < n; i++) {
- add_v3_v3(co1, mesh_vert(vm1, i, ns0, ns0 - 1)->co);
- add_v3_v3(co2, mesh_vert(vm1, i, ns0 - 1, ns0 - 1)->co);
- add_v3_v3(co2, mesh_vert(vm1, i, ns0 - 1, ns0 + 1)->co);
- }
- copy_v3_v3(co, co1);
- mul_v3_fl(co, 1.0f / (float)n);
- madd_v3_v3fl(co, co2, beta / (2.0f * (float)n));
- madd_v3_v3fl(co, mesh_vert(vm0, 0, ns20, ns20)->co, gamma);
- for (i = 0; i < n; i++) {
- copy_v3_v3(mesh_vert(vm1, i, ns0, ns0)->co, co);
- }
-
- /* Final step: sample the boundary vertices at even parameter spacing */
- bndv = vm1->boundstart;
- for (i = 0; i < n; i++) {
- inext = (i + 1) % n;
- for (k = 0; k <= ns1; k++) {
- get_profile_point(bp, &bndv->profile, k, ns1, co);
- copy_v3_v3(mesh_vert(vm1, i, 0, k)->co, co);
- if (k >= ns0 && k < ns1) {
- copy_v3_v3(mesh_vert(vm1, inext, ns1 - k, 0)->co, co);
- }
- }
- bndv = bndv->next;
- }
-
- return vm1;
+ int n, ns0, ns20, ns1;
+ int i, j, k, inext;
+ float co[3], co1[3], co2[3], acc[3];
+ float beta, gamma;
+ VMesh *vm1;
+ BoundVert *bndv;
+
+ n = vm0->count;
+ ns0 = vm0->seg;
+ ns20 = ns0 / 2;
+ BLI_assert(ns0 % 2 == 0);
+ ns1 = 2 * ns0;
+ vm1 = new_adj_vmesh(bp->mem_arena, n, ns1, vm0->boundstart);
+
+ /* First we adjust the boundary vertices of the input mesh, storing in output mesh */
+ for (i = 0; i < n; i++) {
+ copy_v3_v3(mesh_vert(vm1, i, 0, 0)->co, mesh_vert(vm0, i, 0, 0)->co);
+ for (k = 1; k < ns0; k++) {
+ /* smooth boundary rule */
+ copy_v3_v3(co, mesh_vert(vm0, i, 0, k)->co);
+ copy_v3_v3(co1, mesh_vert(vm0, i, 0, k - 1)->co);
+ copy_v3_v3(co2, mesh_vert(vm0, i, 0, k + 1)->co);
+
+ add_v3_v3v3(acc, co1, co2);
+ madd_v3_v3fl(acc, co, -2.0f);
+ madd_v3_v3fl(co, acc, -1.0f / 6.0f);
+
+ copy_v3_v3(mesh_vert_canon(vm1, i, 0, 2 * k)->co, co);
+ }
+ }
+ /* now do odd ones in output mesh, based on even ones */
+ bndv = vm1->boundstart;
+ for (i = 0; i < n; i++) {
+ for (k = 1; k < ns1; k += 2) {
+ get_profile_point(bp, &bndv->profile, k, ns1, co);
+ copy_v3_v3(co1, mesh_vert_canon(vm1, i, 0, k - 1)->co);
+ copy_v3_v3(co2, mesh_vert_canon(vm1, i, 0, k + 1)->co);
+
+ add_v3_v3v3(acc, co1, co2);
+ madd_v3_v3fl(acc, co, -2.0f);
+ madd_v3_v3fl(co, acc, -1.0f / 6.0f);
+
+ copy_v3_v3(mesh_vert_canon(vm1, i, 0, k)->co, co);
+ }
+ bndv = bndv->next;
+ }
+ vmesh_copy_equiv_verts(vm1);
+
+ /* Copy adjusted verts back into vm0 */
+ for (i = 0; i < n; i++) {
+ for (k = 0; k < ns0; k++) {
+ copy_v3_v3(mesh_vert(vm0, i, 0, k)->co, mesh_vert(vm1, i, 0, 2 * k)->co);
+ }
+ }
+
+ vmesh_copy_equiv_verts(vm0);
+
+ /* Now we do the internal vertices, using standard Catmull-Clark
+ * and assuming all boundary vertices have valence 4 */
+
+ /* The new face vertices */
+ for (i = 0; i < n; i++) {
+ for (j = 0; j < ns20; j++) {
+ for (k = 0; k < ns20; k++) {
+ /* face up and right from (j, k) */
+ avg4(co,
+ mesh_vert(vm0, i, j, k),
+ mesh_vert(vm0, i, j, k + 1),
+ mesh_vert(vm0, i, j + 1, k),
+ mesh_vert(vm0, i, j + 1, k + 1));
+ copy_v3_v3(mesh_vert(vm1, i, 2 * j + 1, 2 * k + 1)->co, co);
+ }
+ }
+ }
+
+ /* The new vertical edge vertices */
+ for (i = 0; i < n; i++) {
+ for (j = 0; j < ns20; j++) {
+ for (k = 1; k <= ns20; k++) {
+ /* vertical edge between (j, k) and (j+1, k) */
+ avg4(co,
+ mesh_vert(vm0, i, j, k),
+ mesh_vert(vm0, i, j + 1, k),
+ mesh_vert_canon(vm1, i, 2 * j + 1, 2 * k - 1),
+ mesh_vert_canon(vm1, i, 2 * j + 1, 2 * k + 1));
+ copy_v3_v3(mesh_vert(vm1, i, 2 * j + 1, 2 * k)->co, co);
+ }
+ }
+ }
+
+ /* The new horizontal edge vertices */
+ for (i = 0; i < n; i++) {
+ for (j = 1; j < ns20; j++) {
+ for (k = 0; k < ns20; k++) {
+ /* horizontal edge between (j, k) and (j, k+1) */
+ avg4(co,
+ mesh_vert(vm0, i, j, k),
+ mesh_vert(vm0, i, j, k + 1),
+ mesh_vert_canon(vm1, i, 2 * j - 1, 2 * k + 1),
+ mesh_vert_canon(vm1, i, 2 * j + 1, 2 * k + 1));
+ copy_v3_v3(mesh_vert(vm1, i, 2 * j, 2 * k + 1)->co, co);
+ }
+ }
+ }
+
+ /* The new vertices, not on border */
+ gamma = 0.25f;
+ beta = -gamma;
+ for (i = 0; i < n; i++) {
+ for (j = 1; j < ns20; j++) {
+ for (k = 1; k <= ns20; k++) {
+ /* co1 = centroid of adjacent new edge verts */
+ avg4(co1,
+ mesh_vert_canon(vm1, i, 2 * j, 2 * k - 1),
+ mesh_vert_canon(vm1, i, 2 * j, 2 * k + 1),
+ mesh_vert_canon(vm1, i, 2 * j - 1, 2 * k),
+ mesh_vert_canon(vm1, i, 2 * j + 1, 2 * k));
+ /* co2 = centroid of adjacent new face verts */
+ avg4(co2,
+ mesh_vert_canon(vm1, i, 2 * j - 1, 2 * k - 1),
+ mesh_vert_canon(vm1, i, 2 * j + 1, 2 * k - 1),
+ mesh_vert_canon(vm1, i, 2 * j - 1, 2 * k + 1),
+ mesh_vert_canon(vm1, i, 2 * j + 1, 2 * k + 1));
+ /* combine with original vert with alpha, beta, gamma factors */
+ copy_v3_v3(co, co1); /* alpha = 1.0 */
+ madd_v3_v3fl(co, co2, beta);
+ madd_v3_v3fl(co, mesh_vert(vm0, i, j, k)->co, gamma);
+ copy_v3_v3(mesh_vert(vm1, i, 2 * j, 2 * k)->co, co);
+ }
+ }
+ }
+
+ vmesh_copy_equiv_verts(vm1);
+
+ /* The center vertex is special */
+ gamma = sabin_gamma(n);
+ beta = -gamma;
+ /* accumulate edge verts in co1, face verts in co2 */
+ zero_v3(co1);
+ zero_v3(co2);
+ for (i = 0; i < n; i++) {
+ add_v3_v3(co1, mesh_vert(vm1, i, ns0, ns0 - 1)->co);
+ add_v3_v3(co2, mesh_vert(vm1, i, ns0 - 1, ns0 - 1)->co);
+ add_v3_v3(co2, mesh_vert(vm1, i, ns0 - 1, ns0 + 1)->co);
+ }
+ copy_v3_v3(co, co1);
+ mul_v3_fl(co, 1.0f / (float)n);
+ madd_v3_v3fl(co, co2, beta / (2.0f * (float)n));
+ madd_v3_v3fl(co, mesh_vert(vm0, 0, ns20, ns20)->co, gamma);
+ for (i = 0; i < n; i++) {
+ copy_v3_v3(mesh_vert(vm1, i, ns0, ns0)->co, co);
+ }
+
+ /* Final step: sample the boundary vertices at even parameter spacing */
+ bndv = vm1->boundstart;
+ for (i = 0; i < n; i++) {
+ inext = (i + 1) % n;
+ for (k = 0; k <= ns1; k++) {
+ get_profile_point(bp, &bndv->profile, k, ns1, co);
+ copy_v3_v3(mesh_vert(vm1, i, 0, k)->co, co);
+ if (k >= ns0 && k < ns1) {
+ copy_v3_v3(mesh_vert(vm1, inext, ns1 - k, 0)->co, co);
+ }
+ }
+ bndv = bndv->next;
+ }
+
+ return vm1;
}
/* Special case for cube corner, when r is PRO_SQUARE_R, meaning straight sides */
static VMesh *make_cube_corner_square(MemArena *mem_arena, int nseg)
{
- VMesh *vm;
- float co[3];
- int i, j, k, ns2;
-
- ns2 = nseg / 2;
- vm = new_adj_vmesh(mem_arena, 3, nseg, NULL);
- vm->count = 0; // reset, so following loop will end up with correct count
- for (i = 0; i < 3; i++) {
- zero_v3(co);
- co[i] = 1.0f;
- add_new_bound_vert(mem_arena, vm, co);
- }
- for (i = 0; i < 3; i++) {
- for (j = 0; j <= ns2; j++) {
- for (k = 0; k <= ns2; k++) {
- if (!is_canon(vm, i, j, k)) {
- continue;
- }
- co[i] = 1.0f;
- co[(i + 1) % 3] = (float)k * 2.0f / (float)nseg;
- co[(i + 2) % 3] = (float)j * 2.0f / (float)nseg;
- copy_v3_v3(mesh_vert(vm, i, j, k)->co, co);
- }
- }
- }
- vmesh_copy_equiv_verts(vm);
- return vm;
+ VMesh *vm;
+ float co[3];
+ int i, j, k, ns2;
+
+ ns2 = nseg / 2;
+ vm = new_adj_vmesh(mem_arena, 3, nseg, NULL);
+ vm->count = 0; // reset, so following loop will end up with correct count
+ for (i = 0; i < 3; i++) {
+ zero_v3(co);
+ co[i] = 1.0f;
+ add_new_bound_vert(mem_arena, vm, co);
+ }
+ for (i = 0; i < 3; i++) {
+ for (j = 0; j <= ns2; j++) {
+ for (k = 0; k <= ns2; k++) {
+ if (!is_canon(vm, i, j, k)) {
+ continue;
+ }
+ co[i] = 1.0f;
+ co[(i + 1) % 3] = (float)k * 2.0f / (float)nseg;
+ co[(i + 2) % 3] = (float)j * 2.0f / (float)nseg;
+ copy_v3_v3(mesh_vert(vm, i, j, k)->co, co);
+ }
+ }
+ }
+ vmesh_copy_equiv_verts(vm);
+ return vm;
}
/* Special case for cube corner, when r is PRO_SQUARE_IN_R, meaning inward
@@ -3593,42 +3630,41 @@ static VMesh *make_cube_corner_square(MemArena *mem_arena, int nseg)
* with a triangle in the middle for odd nseg */
static VMesh *make_cube_corner_square_in(MemArena *mem_arena, int nseg)
{
- VMesh *vm;
- float co[3];
- float b;
- int i, k, ns2, odd;
-
- ns2 = nseg / 2;
- odd = nseg % 2;
- vm = new_adj_vmesh(mem_arena, 3, nseg, NULL);
- vm->count = 0; // reset, so following loop will end up with correct count
- for (i = 0; i < 3; i++) {
- zero_v3(co);
- co[i] = 1.0f;
- add_new_bound_vert(mem_arena, vm, co);
- }
- if (odd) {
- b = 2.0f / (2.0f * (float)ns2 + (float)M_SQRT2);
- }
- else {
- b = 2.0f / (float)nseg;
- }
- for (i = 0; i < 3; i++) {
- for (k = 0; k <= ns2; k++) {
- co[i] = 1.0f - (float)k * b;
- co[(i + 1) % 3] = 0.0f;
- co[(i + 2) % 3] = 0.0f;
- copy_v3_v3(mesh_vert(vm, i, 0, k)->co, co);
- co[(i + 1) % 3] = 1.0f - (float)k * b;
- co[(i + 2) % 3] = 0.0f;
- co[i] = 0.0f;
- copy_v3_v3(mesh_vert(vm, i, 0, nseg - k)->co, co);
- }
- }
- return vm;
+ VMesh *vm;
+ float co[3];
+ float b;
+ int i, k, ns2, odd;
+
+ ns2 = nseg / 2;
+ odd = nseg % 2;
+ vm = new_adj_vmesh(mem_arena, 3, nseg, NULL);
+ vm->count = 0; // reset, so following loop will end up with correct count
+ for (i = 0; i < 3; i++) {
+ zero_v3(co);
+ co[i] = 1.0f;
+ add_new_bound_vert(mem_arena, vm, co);
+ }
+ if (odd) {
+ b = 2.0f / (2.0f * (float)ns2 + (float)M_SQRT2);
+ }
+ else {
+ b = 2.0f / (float)nseg;
+ }
+ for (i = 0; i < 3; i++) {
+ for (k = 0; k <= ns2; k++) {
+ co[i] = 1.0f - (float)k * b;
+ co[(i + 1) % 3] = 0.0f;
+ co[(i + 2) % 3] = 0.0f;
+ copy_v3_v3(mesh_vert(vm, i, 0, k)->co, co);
+ co[(i + 1) % 3] = 1.0f - (float)k * b;
+ co[(i + 2) % 3] = 0.0f;
+ co[i] = 0.0f;
+ copy_v3_v3(mesh_vert(vm, i, 0, nseg - k)->co, co);
+ }
+ }
+ return vm;
}
-
/* Make a VMesh with nseg segments that covers the unit radius sphere octant
* with center at (0,0,0).
* This has BoundVerts at (1,0,0), (0,1,0) and (0,0,1), with quarter circle arcs
@@ -3636,248 +3672,247 @@ static VMesh *make_cube_corner_square_in(MemArena *mem_arena, int nseg)
*/
static VMesh *make_cube_corner_adj_vmesh(BevelParams *bp)
{
- MemArena *mem_arena = bp->mem_arena;
- int nseg = bp->seg;
- float r = bp->pro_super_r;
- VMesh *vm0, *vm1;
- BoundVert *bndv;
- int i, j, k, ns2;
- float co[3], coc[3];
-
- if (r == PRO_SQUARE_R) {
- return make_cube_corner_square(mem_arena, nseg);
- }
- else if (r == PRO_SQUARE_IN_R) {
- return make_cube_corner_square_in(mem_arena, nseg);
- }
-
- /* initial mesh has 3 sides, 2 segments */
- vm0 = new_adj_vmesh(mem_arena, 3, 2, NULL);
- vm0->count = 0; // reset, so following loop will end up with correct count
- for (i = 0; i < 3; i++) {
- zero_v3(co);
- co[i] = 1.0f;
- add_new_bound_vert(mem_arena, vm0, co);
- }
- bndv = vm0->boundstart;
- for (i = 0; i < 3; i++) {
- /* Get point, 1/2 of the way around profile, on arc between this and next */
- coc[i] = 1.0f;
- coc[(i + 1) % 3] = 1.0f;
- coc[(i + 2) % 3] = 0.0f;
- bndv->profile.super_r = r;
- copy_v3_v3(bndv->profile.coa, bndv->nv.co);
- copy_v3_v3(bndv->profile.cob, bndv->next->nv.co);
- copy_v3_v3(bndv->profile.midco, coc);
- copy_v3_v3(mesh_vert(vm0, i, 0, 0)->co, bndv->profile.coa);
- copy_v3_v3(bndv->profile.plane_co, bndv->profile.coa);
- cross_v3_v3v3(bndv->profile.plane_no, bndv->profile.coa, bndv->profile.cob);
- copy_v3_v3(bndv->profile.proj_dir, bndv->profile.plane_no);
- calculate_profile(bp, bndv);
- get_profile_point(bp, &bndv->profile, 1, 2, mesh_vert(vm0, i, 0, 1)->co);
-
- bndv = bndv->next;
- }
- /* center vertex */
- copy_v3_fl(co, M_SQRT1_3);
-
- if (nseg > 2) {
- if (r > 1.5f) {
- mul_v3_fl(co, 1.4f);
- }
- else if (r < 0.75f) {
- mul_v3_fl(co, 0.6f);
- }
- }
- copy_v3_v3(mesh_vert(vm0, 0, 1, 1)->co, co);
-
- vmesh_copy_equiv_verts(vm0);
-
- vm1 = vm0;
- while (vm1->seg < nseg) {
- vm1 = cubic_subdiv(bp, vm1);
- }
- if (vm1->seg != nseg) {
- vm1 = interp_vmesh(bp, vm1, nseg);
- }
-
- /* Now snap each vertex to the superellipsoid */
- ns2 = nseg / 2;
- for (i = 0; i < 3; i++) {
- for (j = 0; j <= ns2; j++) {
- for (k = 0; k <= nseg; k++) {
- snap_to_superellipsoid(mesh_vert(vm1, i, j, k)->co, r, false);
- }
- }
- }
-
- return vm1;
+ MemArena *mem_arena = bp->mem_arena;
+ int nseg = bp->seg;
+ float r = bp->pro_super_r;
+ VMesh *vm0, *vm1;
+ BoundVert *bndv;
+ int i, j, k, ns2;
+ float co[3], coc[3];
+
+ if (r == PRO_SQUARE_R) {
+ return make_cube_corner_square(mem_arena, nseg);
+ }
+ else if (r == PRO_SQUARE_IN_R) {
+ return make_cube_corner_square_in(mem_arena, nseg);
+ }
+
+ /* initial mesh has 3 sides, 2 segments */
+ vm0 = new_adj_vmesh(mem_arena, 3, 2, NULL);
+ vm0->count = 0; // reset, so following loop will end up with correct count
+ for (i = 0; i < 3; i++) {
+ zero_v3(co);
+ co[i] = 1.0f;
+ add_new_bound_vert(mem_arena, vm0, co);
+ }
+ bndv = vm0->boundstart;
+ for (i = 0; i < 3; i++) {
+ /* Get point, 1/2 of the way around profile, on arc between this and next */
+ coc[i] = 1.0f;
+ coc[(i + 1) % 3] = 1.0f;
+ coc[(i + 2) % 3] = 0.0f;
+ bndv->profile.super_r = r;
+ copy_v3_v3(bndv->profile.coa, bndv->nv.co);
+ copy_v3_v3(bndv->profile.cob, bndv->next->nv.co);
+ copy_v3_v3(bndv->profile.midco, coc);
+ copy_v3_v3(mesh_vert(vm0, i, 0, 0)->co, bndv->profile.coa);
+ copy_v3_v3(bndv->profile.plane_co, bndv->profile.coa);
+ cross_v3_v3v3(bndv->profile.plane_no, bndv->profile.coa, bndv->profile.cob);
+ copy_v3_v3(bndv->profile.proj_dir, bndv->profile.plane_no);
+ calculate_profile(bp, bndv);
+ get_profile_point(bp, &bndv->profile, 1, 2, mesh_vert(vm0, i, 0, 1)->co);
+
+ bndv = bndv->next;
+ }
+ /* center vertex */
+ copy_v3_fl(co, M_SQRT1_3);
+
+ if (nseg > 2) {
+ if (r > 1.5f) {
+ mul_v3_fl(co, 1.4f);
+ }
+ else if (r < 0.75f) {
+ mul_v3_fl(co, 0.6f);
+ }
+ }
+ copy_v3_v3(mesh_vert(vm0, 0, 1, 1)->co, co);
+
+ vmesh_copy_equiv_verts(vm0);
+
+ vm1 = vm0;
+ while (vm1->seg < nseg) {
+ vm1 = cubic_subdiv(bp, vm1);
+ }
+ if (vm1->seg != nseg) {
+ vm1 = interp_vmesh(bp, vm1, nseg);
+ }
+
+ /* Now snap each vertex to the superellipsoid */
+ ns2 = nseg / 2;
+ for (i = 0; i < 3; i++) {
+ for (j = 0; j <= ns2; j++) {
+ for (k = 0; k <= nseg; k++) {
+ snap_to_superellipsoid(mesh_vert(vm1, i, j, k)->co, r, false);
+ }
+ }
+ }
+
+ return vm1;
}
/* Is this a good candidate for using tri_corner_adj_vmesh? */
static int tri_corner_test(BevelParams *bp, BevVert *bv)
{
- float ang, totang, angdiff;
- EdgeHalf *e;
- int i;
- int in_plane_e = 0;
-
- if (bp->vertex_only) {
- return -1;
- }
- if (bv->vmesh->count != 3) {
- return 0;
- }
- totang = 0.0f;
- for (i = 0; i < bv->edgecount; i++) {
- e = &bv->edges[i];
- ang = BM_edge_calc_face_angle_signed_ex(e->e, 0.0f);
- if (ang <= M_PI_4) {
- in_plane_e++;
- }
- else if (ang >= 3.0f * (float) M_PI_4) {
- return -1;
- }
- totang += ang;
- }
- if (in_plane_e != bv->edgecount - 3) {
- return -1;
- }
- angdiff = fabsf(totang - 3.0f * (float)M_PI_2);
- if ((bp->pro_super_r == PRO_SQUARE_R && angdiff > (float)M_PI / 16.0f) ||
- (angdiff > (float)M_PI_4))
- {
- return -1;
- }
- if (bv->edgecount != 3 || bv->selcount != 3) {
- return 0;
- }
- return 1;
+ float ang, totang, angdiff;
+ EdgeHalf *e;
+ int i;
+ int in_plane_e = 0;
+
+ if (bp->vertex_only) {
+ return -1;
+ }
+ if (bv->vmesh->count != 3) {
+ return 0;
+ }
+ totang = 0.0f;
+ for (i = 0; i < bv->edgecount; i++) {
+ e = &bv->edges[i];
+ ang = BM_edge_calc_face_angle_signed_ex(e->e, 0.0f);
+ if (ang <= M_PI_4) {
+ in_plane_e++;
+ }
+ else if (ang >= 3.0f * (float)M_PI_4) {
+ return -1;
+ }
+ totang += ang;
+ }
+ if (in_plane_e != bv->edgecount - 3) {
+ return -1;
+ }
+ angdiff = fabsf(totang - 3.0f * (float)M_PI_2);
+ if ((bp->pro_super_r == PRO_SQUARE_R && angdiff > (float)M_PI / 16.0f) ||
+ (angdiff > (float)M_PI_4)) {
+ return -1;
+ }
+ if (bv->edgecount != 3 || bv->selcount != 3) {
+ return 0;
+ }
+ return 1;
}
static VMesh *tri_corner_adj_vmesh(BevelParams *bp, BevVert *bv)
{
- int i, j, k, ns, ns2;
- float co0[3], co1[3], co2[3];
- float mat[4][4], v[4];
- VMesh *vm;
- BoundVert *bndv;
-
- /*BLI_assert(bv->edgecount == 3 && bv->selcount == 3); Add support for in plane edges */
- bndv = bv->vmesh->boundstart;
- copy_v3_v3(co0, bndv->nv.co);
- bndv = bndv->next;
- copy_v3_v3(co1, bndv->nv.co);
- bndv = bndv->next;
- copy_v3_v3(co2, bndv->nv.co);
- make_unit_cube_map(co0, co1, co2, bv->v->co, mat);
- ns = bp->seg;
- ns2 = ns / 2;
- vm = make_cube_corner_adj_vmesh(bp);
- for (i = 0; i < 3; i++) {
- for (j = 0; j <= ns2; j++) {
- for (k = 0; k <= ns; k++) {
- copy_v3_v3(v, mesh_vert(vm, i, j, k)->co);
- v[3] = 1.0f;
- mul_m4_v4(mat, v);
- copy_v3_v3(mesh_vert(vm, i, j, k)->co, v);
- }
- }
- }
-
- return vm;
+ int i, j, k, ns, ns2;
+ float co0[3], co1[3], co2[3];
+ float mat[4][4], v[4];
+ VMesh *vm;
+ BoundVert *bndv;
+
+ /*BLI_assert(bv->edgecount == 3 && bv->selcount == 3); Add support for in plane edges */
+ bndv = bv->vmesh->boundstart;
+ copy_v3_v3(co0, bndv->nv.co);
+ bndv = bndv->next;
+ copy_v3_v3(co1, bndv->nv.co);
+ bndv = bndv->next;
+ copy_v3_v3(co2, bndv->nv.co);
+ make_unit_cube_map(co0, co1, co2, bv->v->co, mat);
+ ns = bp->seg;
+ ns2 = ns / 2;
+ vm = make_cube_corner_adj_vmesh(bp);
+ for (i = 0; i < 3; i++) {
+ for (j = 0; j <= ns2; j++) {
+ for (k = 0; k <= ns; k++) {
+ copy_v3_v3(v, mesh_vert(vm, i, j, k)->co);
+ v[3] = 1.0f;
+ mul_m4_v4(mat, v);
+ copy_v3_v3(mesh_vert(vm, i, j, k)->co, v);
+ }
+ }
+ }
+
+ return vm;
}
static VMesh *adj_vmesh(BevelParams *bp, BevVert *bv)
{
- int n, ns, i;
- VMesh *vm0, *vm1;
- float co[3], coa[3], cob[3], dir[3];
- BoundVert *bndv;
- MemArena *mem_arena = bp->mem_arena;
- float r, p, fullness;
- /* best fullness for circles, segs = 2,4,6,8,10 */
+ int n, ns, i;
+ VMesh *vm0, *vm1;
+ float co[3], coa[3], cob[3], dir[3];
+ BoundVert *bndv;
+ MemArena *mem_arena = bp->mem_arena;
+ float r, p, fullness;
+ /* best fullness for circles, segs = 2,4,6,8,10 */
#define CIRCLE_FULLNESS_SEGS 11
- static const float circle_fullness[CIRCLE_FULLNESS_SEGS] = {
- 0.0f, /* nsegs ==1 */
- 0.559f, /* 2 */
- 0.642f, /* 3 */
- 0.551f, /* 4 */
- 0.646f, /* 5 */
- 0.624f, /* 6 */
- 0.646f, /* 7 */
- 0.619f, /* 8 */
- 0.647f, /* 9 */
- 0.639f, /* 10 */
- 0.647f, /* 11 */
- };
-
- n = bv->vmesh->count;
-
- /* Same bevel as that of 3 edges of vert in a cube */
- if (n == 3 && tri_corner_test(bp, bv) != -1 && bp->pro_super_r != PRO_SQUARE_IN_R) {
- return tri_corner_adj_vmesh(bp, bv);
- }
-
- /* First construct an initial control mesh, with nseg==2 */
- ns = bv->vmesh->seg;
- vm0 = new_adj_vmesh(mem_arena, n, 2, bv->vmesh->boundstart);
-
- bndv = vm0->boundstart;
- zero_v3(co);
- for (i = 0; i < n; i++) {
- /* Boundaries just divide input polygon edges into 2 even segments */
- copy_v3_v3(mesh_vert(vm0, i, 0, 0)->co, bndv->nv.co);
- get_profile_point(bp, &bndv->profile, 1, 2, mesh_vert(vm0, i, 0, 1)->co);
- add_v3_v3(co, bndv->nv.co);
- bndv = bndv->next;
- }
- /* To place center vertex:
- * coa is original vertex
- * co is centroid of boundary corners
- * cob is reflection of coa in across co.
- * Calculate 'fullness' = fraction of way
- * from co to coa (if positive) or to cob (if negative).
- */
- copy_v3_v3(coa, bv->v->co);
- mul_v3_fl(co, 1.0f / (float)n);
- sub_v3_v3v3(cob, co, coa);
- add_v3_v3(cob, co);
-
- /* An offline optimization process found fullness that let to closest fit to sphere as
- * a function of r and ns (for case of cube corner) */
- r = bp->pro_super_r;
- p = bp->profile;
- if (r == PRO_LINE_R) {
- fullness = 0.0f;
- }
- else if (r == PRO_CIRCLE_R && ns > 0 && ns <= CIRCLE_FULLNESS_SEGS) {
- fullness = circle_fullness[ns - 1];
- }
- else {
- /* linear regression fit found best linear function, separately for even/odd segs */
- if (ns % 2 == 0) {
- fullness = 2.4506f * p - 0.00000300f * ns - 0.6266f;
- }
- else {
- fullness = 2.3635f * p + 0.000152f * ns - 0.6060f;
- }
- }
- sub_v3_v3v3(dir, coa, co);
- if (len_squared_v3(dir) > BEVEL_EPSILON_SQ) {
- madd_v3_v3fl(co, dir, fullness);
- }
- copy_v3_v3(mesh_vert(vm0, 0, 1, 1)->co, co);
- vmesh_copy_equiv_verts(vm0);
-
- vm1 = vm0;
- do {
- vm1 = cubic_subdiv(bp, vm1);
- } while (vm1->seg < ns);
- if (vm1->seg != ns) {
- vm1 = interp_vmesh(bp, vm1, ns);
- }
- return vm1;
+ static const float circle_fullness[CIRCLE_FULLNESS_SEGS] = {
+ 0.0f, /* nsegs ==1 */
+ 0.559f, /* 2 */
+ 0.642f, /* 3 */
+ 0.551f, /* 4 */
+ 0.646f, /* 5 */
+ 0.624f, /* 6 */
+ 0.646f, /* 7 */
+ 0.619f, /* 8 */
+ 0.647f, /* 9 */
+ 0.639f, /* 10 */
+ 0.647f, /* 11 */
+ };
+
+ n = bv->vmesh->count;
+
+ /* Same bevel as that of 3 edges of vert in a cube */
+ if (n == 3 && tri_corner_test(bp, bv) != -1 && bp->pro_super_r != PRO_SQUARE_IN_R) {
+ return tri_corner_adj_vmesh(bp, bv);
+ }
+
+ /* First construct an initial control mesh, with nseg==2 */
+ ns = bv->vmesh->seg;
+ vm0 = new_adj_vmesh(mem_arena, n, 2, bv->vmesh->boundstart);
+
+ bndv = vm0->boundstart;
+ zero_v3(co);
+ for (i = 0; i < n; i++) {
+ /* Boundaries just divide input polygon edges into 2 even segments */
+ copy_v3_v3(mesh_vert(vm0, i, 0, 0)->co, bndv->nv.co);
+ get_profile_point(bp, &bndv->profile, 1, 2, mesh_vert(vm0, i, 0, 1)->co);
+ add_v3_v3(co, bndv->nv.co);
+ bndv = bndv->next;
+ }
+ /* To place center vertex:
+ * coa is original vertex
+ * co is centroid of boundary corners
+ * cob is reflection of coa in across co.
+ * Calculate 'fullness' = fraction of way
+ * from co to coa (if positive) or to cob (if negative).
+ */
+ copy_v3_v3(coa, bv->v->co);
+ mul_v3_fl(co, 1.0f / (float)n);
+ sub_v3_v3v3(cob, co, coa);
+ add_v3_v3(cob, co);
+
+ /* An offline optimization process found fullness that let to closest fit to sphere as
+ * a function of r and ns (for case of cube corner) */
+ r = bp->pro_super_r;
+ p = bp->profile;
+ if (r == PRO_LINE_R) {
+ fullness = 0.0f;
+ }
+ else if (r == PRO_CIRCLE_R && ns > 0 && ns <= CIRCLE_FULLNESS_SEGS) {
+ fullness = circle_fullness[ns - 1];
+ }
+ else {
+ /* linear regression fit found best linear function, separately for even/odd segs */
+ if (ns % 2 == 0) {
+ fullness = 2.4506f * p - 0.00000300f * ns - 0.6266f;
+ }
+ else {
+ fullness = 2.3635f * p + 0.000152f * ns - 0.6060f;
+ }
+ }
+ sub_v3_v3v3(dir, coa, co);
+ if (len_squared_v3(dir) > BEVEL_EPSILON_SQ) {
+ madd_v3_v3fl(co, dir, fullness);
+ }
+ copy_v3_v3(mesh_vert(vm0, 0, 1, 1)->co, co);
+ vmesh_copy_equiv_verts(vm0);
+
+ vm1 = vm0;
+ do {
+ vm1 = cubic_subdiv(bp, vm1);
+ } while (vm1->seg < ns);
+ if (vm1->seg != ns) {
+ vm1 = interp_vmesh(bp, vm1, ns);
+ }
+ return vm1;
}
/* Snap co to the closest point on the profile for vpipe projected onto the plane
@@ -3886,37 +3921,37 @@ static VMesh *adj_vmesh(BevelParams *bp, BevVert *bv)
* or to the midpoint of the profile; do so if midline is true. */
static void snap_to_pipe_profile(BoundVert *vpipe, bool midline, float co[3])
{
- float va[3], vb[3], edir[3], va0[3], vb0[3], vmid0[3];
- float plane[4], m[4][4], minv[4][4], p[3], snap[3];
- Profile *pro = &vpipe->profile;
- EdgeHalf *e = vpipe->ebev;
-
- copy_v3_v3(va, pro->coa);
- copy_v3_v3(vb, pro->cob);
-
- sub_v3_v3v3(edir, e->e->v1->co, e->e->v2->co);
-
- plane_from_point_normal_v3(plane, co, edir);
- closest_to_plane_v3(va0, plane, va);
- closest_to_plane_v3(vb0, plane, vb);
- closest_to_plane_v3(vmid0, plane, pro->midco);
- if (make_unit_square_map(va0, vmid0, vb0, m)) {
- /* Transform co and project it onto superellipse */
- if (!invert_m4_m4(minv, m)) {
- /* shouldn't happen */
- BLI_assert(!"failed inverse during pipe profile snap");
- return;
- }
- mul_v3_m4v3(p, minv, co);
- snap_to_superellipsoid(p, pro->super_r, midline);
- mul_v3_m4v3(snap, m, p);
- copy_v3_v3(co, snap);
- }
- else {
- /* planar case: just snap to line va0--vb0 */
- closest_to_line_segment_v3(p, co, va0, vb0);
- copy_v3_v3(co, p);
- }
+ float va[3], vb[3], edir[3], va0[3], vb0[3], vmid0[3];
+ float plane[4], m[4][4], minv[4][4], p[3], snap[3];
+ Profile *pro = &vpipe->profile;
+ EdgeHalf *e = vpipe->ebev;
+
+ copy_v3_v3(va, pro->coa);
+ copy_v3_v3(vb, pro->cob);
+
+ sub_v3_v3v3(edir, e->e->v1->co, e->e->v2->co);
+
+ plane_from_point_normal_v3(plane, co, edir);
+ closest_to_plane_v3(va0, plane, va);
+ closest_to_plane_v3(vb0, plane, vb);
+ closest_to_plane_v3(vmid0, plane, pro->midco);
+ if (make_unit_square_map(va0, vmid0, vb0, m)) {
+ /* Transform co and project it onto superellipse */
+ if (!invert_m4_m4(minv, m)) {
+ /* shouldn't happen */
+ BLI_assert(!"failed inverse during pipe profile snap");
+ return;
+ }
+ mul_v3_m4v3(p, minv, co);
+ snap_to_superellipsoid(p, pro->super_r, midline);
+ mul_v3_m4v3(snap, m, p);
+ copy_v3_v3(co, snap);
+ }
+ else {
+ /* planar case: just snap to line va0--vb0 */
+ closest_to_line_segment_v3(p, co, va0, vb0);
+ copy_v3_v3(co, p);
+ }
}
/* See pipe_test for conditions that make 'pipe'; vpipe is the return value from that.
@@ -3926,70 +3961,69 @@ static void snap_to_pipe_profile(BoundVert *vpipe, bool midline, float co[3])
* to snap to the midline on the pipe, not just to one plane or the other. */
static VMesh *pipe_adj_vmesh(BevelParams *bp, BevVert *bv, BoundVert *vpipe)
{
- int i, j, k, n, ns, ns2, ipipe1, ipipe2;
- VMesh *vm;
- bool even, midline;
-
- vm = adj_vmesh(bp, bv);
-
- /* Now snap all interior coordinates to be on the epipe profile */
- n = bv->vmesh->count;
- ns = bv->vmesh->seg;
- ns2 = ns / 2;
- even = (ns % 2) == 0;
- ipipe1 = vpipe->index;
- ipipe2 = vpipe->next->next->index;
- for (i = 0; i < n; i++) {
- for (j = 1; j <= ns2; j++) {
- for (k = 0; k <= ns2; k++) {
- if (!is_canon(vm, i, j, k)) {
- continue;
- }
- midline = even && k == ns2 &&
- ((i == 0 && j == ns2) || (i == ipipe1 || i == ipipe2));
- snap_to_pipe_profile(vpipe, midline, mesh_vert(vm, i, j, k)->co);
- }
- }
- }
-
- return vm;
+ int i, j, k, n, ns, ns2, ipipe1, ipipe2;
+ VMesh *vm;
+ bool even, midline;
+
+ vm = adj_vmesh(bp, bv);
+
+ /* Now snap all interior coordinates to be on the epipe profile */
+ n = bv->vmesh->count;
+ ns = bv->vmesh->seg;
+ ns2 = ns / 2;
+ even = (ns % 2) == 0;
+ ipipe1 = vpipe->index;
+ ipipe2 = vpipe->next->next->index;
+ for (i = 0; i < n; i++) {
+ for (j = 1; j <= ns2; j++) {
+ for (k = 0; k <= ns2; k++) {
+ if (!is_canon(vm, i, j, k)) {
+ continue;
+ }
+ midline = even && k == ns2 && ((i == 0 && j == ns2) || (i == ipipe1 || i == ipipe2));
+ snap_to_pipe_profile(vpipe, midline, mesh_vert(vm, i, j, k)->co);
+ }
+ }
+ }
+
+ return vm;
}
static void get_incident_edges(BMFace *f, BMVert *v, BMEdge **r_e1, BMEdge **r_e2)
{
- BMIter iter;
- BMEdge *e;
-
- *r_e1 = NULL;
- *r_e2 = NULL;
- if (!f) {
- return;
- }
- BM_ITER_ELEM (e, &iter, f, BM_EDGES_OF_FACE) {
- if (e->v1 == v || e->v2 == v) {
- if (*r_e1 == NULL) {
- *r_e1 = e;
- }
- else if (*r_e2 == NULL) {
- *r_e2 = e;
- }
- }
- }
+ BMIter iter;
+ BMEdge *e;
+
+ *r_e1 = NULL;
+ *r_e2 = NULL;
+ if (!f) {
+ return;
+ }
+ BM_ITER_ELEM (e, &iter, f, BM_EDGES_OF_FACE) {
+ if (e->v1 == v || e->v2 == v) {
+ if (*r_e1 == NULL) {
+ *r_e1 = e;
+ }
+ else if (*r_e2 == NULL) {
+ *r_e2 = e;
+ }
+ }
+ }
}
static BMEdge *find_closer_edge(float *co, BMEdge *e1, BMEdge *e2)
{
- float dsq1, dsq2;
-
- BLI_assert(e1 != NULL && e2 != NULL);
- dsq1 = dist_squared_to_line_segment_v3(co, e1->v1->co, e1->v2->co);
- dsq2 = dist_squared_to_line_segment_v3(co, e2->v1->co, e2->v2->co);
- if (dsq1 < dsq2) {
- return e1;
- }
- else {
- return e2;
- }
+ float dsq1, dsq2;
+
+ BLI_assert(e1 != NULL && e2 != NULL);
+ dsq1 = dist_squared_to_line_segment_v3(co, e1->v1->co, e1->v2->co);
+ dsq2 = dist_squared_to_line_segment_v3(co, e2->v1->co, e2->v2->co);
+ if (dsq1 < dsq2) {
+ return e1;
+ }
+ else {
+ return e2;
+ }
}
/* Snap co to the closest edge of face f. Return the edge in *r_snap_e,
@@ -3997,69 +4031,69 @@ static BMEdge *find_closer_edge(float *co, BMEdge *e1, BMEdge *e2)
* and the distance squared to the snap point as function return */
static float snap_face_dist_squared(float *co, BMFace *f, BMEdge **r_snap_e, float *r_snap_co)
{
- BMIter iter;
- BMEdge *beste = NULL;
- float d2, beste_d2;
- BMEdge *e;
- float closest[3];
-
- beste_d2 = 1e20;
- BM_ITER_ELEM(e, &iter, f, BM_EDGES_OF_FACE) {
- closest_to_line_segment_v3(closest, co, e->v1->co, e->v2->co);
- d2 = len_squared_v3v3(closest, co);
- if (d2 < beste_d2) {
- beste_d2 = d2;
- beste = e;
- copy_v3_v3(r_snap_co, closest);
- }
- }
- *r_snap_e = beste;
- return beste_d2;
+ BMIter iter;
+ BMEdge *beste = NULL;
+ float d2, beste_d2;
+ BMEdge *e;
+ float closest[3];
+
+ beste_d2 = 1e20;
+ BM_ITER_ELEM (e, &iter, f, BM_EDGES_OF_FACE) {
+ closest_to_line_segment_v3(closest, co, e->v1->co, e->v2->co);
+ d2 = len_squared_v3v3(closest, co);
+ if (d2 < beste_d2) {
+ beste_d2 = d2;
+ beste = e;
+ copy_v3_v3(r_snap_co, closest);
+ }
+ }
+ *r_snap_e = beste;
+ return beste_d2;
}
static void build_center_ngon(BevelParams *bp, BMesh *bm, BevVert *bv, int mat_nr)
{
- VMesh *vm = bv->vmesh;
- BoundVert *v;
- int i, ns2;
- BMFace *frep, *f;
- BMEdge *frep_e1, *frep_e2, *frep_e;
- BMVert **vv = NULL;
- BMFace **vf = NULL;
- BMEdge **ve = NULL;
- BLI_array_staticdeclare(vv, BM_DEFAULT_NGON_STACK_SIZE);
- BLI_array_staticdeclare(vf, BM_DEFAULT_NGON_STACK_SIZE);
- BLI_array_staticdeclare(ve, BM_DEFAULT_NGON_STACK_SIZE);
-
- ns2 = vm->seg / 2;
- if (bv->any_seam) {
- frep = boundvert_rep_face(vm->boundstart, NULL);
- get_incident_edges(frep, bv->v, &frep_e1, &frep_e2);
- }
- else {
- frep = NULL;
- frep_e1 = frep_e2 = NULL;
- }
- v = vm->boundstart;
- do {
- i = v->index;
- BLI_array_append(vv, mesh_vert(vm, i, ns2, ns2)->v);
- if (frep) {
- BLI_array_append(vf, frep);
- frep_e = find_closer_edge(mesh_vert(vm, i, ns2, ns2)->v->co, frep_e1, frep_e2);
- BLI_array_append(ve, v == vm->boundstart ? NULL : frep_e);
- }
- else {
- BLI_array_append(vf, boundvert_rep_face(v, NULL));
- BLI_array_append(ve, NULL);
- }
- } while ((v = v->next) != vm->boundstart);
- f = bev_create_ngon(bm, vv, BLI_array_len(vv), vf, frep, ve, mat_nr, true);
- record_face_kind(bp, f, F_VERT);
-
- BLI_array_free(vv);
- BLI_array_free(vf);
- BLI_array_free(ve);
+ VMesh *vm = bv->vmesh;
+ BoundVert *v;
+ int i, ns2;
+ BMFace *frep, *f;
+ BMEdge *frep_e1, *frep_e2, *frep_e;
+ BMVert **vv = NULL;
+ BMFace **vf = NULL;
+ BMEdge **ve = NULL;
+ BLI_array_staticdeclare(vv, BM_DEFAULT_NGON_STACK_SIZE);
+ BLI_array_staticdeclare(vf, BM_DEFAULT_NGON_STACK_SIZE);
+ BLI_array_staticdeclare(ve, BM_DEFAULT_NGON_STACK_SIZE);
+
+ ns2 = vm->seg / 2;
+ if (bv->any_seam) {
+ frep = boundvert_rep_face(vm->boundstart, NULL);
+ get_incident_edges(frep, bv->v, &frep_e1, &frep_e2);
+ }
+ else {
+ frep = NULL;
+ frep_e1 = frep_e2 = NULL;
+ }
+ v = vm->boundstart;
+ do {
+ i = v->index;
+ BLI_array_append(vv, mesh_vert(vm, i, ns2, ns2)->v);
+ if (frep) {
+ BLI_array_append(vf, frep);
+ frep_e = find_closer_edge(mesh_vert(vm, i, ns2, ns2)->v->co, frep_e1, frep_e2);
+ BLI_array_append(ve, v == vm->boundstart ? NULL : frep_e);
+ }
+ else {
+ BLI_array_append(vf, boundvert_rep_face(v, NULL));
+ BLI_array_append(ve, NULL);
+ }
+ } while ((v = v->next) != vm->boundstart);
+ f = bev_create_ngon(bm, vv, BLI_array_len(vv), vf, frep, ve, mat_nr, true);
+ record_face_kind(bp, f, F_VERT);
+
+ BLI_array_free(vv);
+ BLI_array_free(vf);
+ BLI_array_free(ve);
}
/* Special case of bevel_build_rings when tri-corner and profile is 0.
@@ -4068,46 +4102,46 @@ static void build_center_ngon(BevelParams *bp, BMesh *bm, BevVert *bv, int mat_n
* (i, 0, k) merged with (i+1, 0, ns-k) for k <= ns/2 */
static void build_square_in_vmesh(BevelParams *bp, BMesh *bm, BevVert *bv, VMesh *vm1)
{
- int n, ns, ns2, odd, i, k;
- VMesh *vm;
-
- vm = bv->vmesh;
- n = vm->count;
- ns = vm->seg;
- ns2 = ns / 2;
- odd = ns % 2;
-
- for (i = 0; i < n; i++) {
- for (k = 1; k < ns; k++) {
- copy_v3_v3(mesh_vert(vm, i, 0, k)->co, mesh_vert(vm1, i, 0, k)->co);
- if (i > 0 && k <= ns2) {
- mesh_vert(vm, i, 0, k)->v = mesh_vert(vm, i - 1, 0, ns - k)->v;
- }
- else if (i == n - 1 && k > ns2) {
- mesh_vert(vm, i, 0, k)->v = mesh_vert(vm, 0, 0, ns - k)->v;
- }
- else {
- create_mesh_bmvert(bm, vm, i, 0, k, bv->v);
- }
- }
- }
- if (odd) {
- for (i = 0; i < n; i++) {
- mesh_vert(vm, i, ns2, ns2)->v = mesh_vert(vm, i, 0, ns2)->v;
- }
- build_center_ngon(bp, bm, bv, bp->mat_nr);
- }
+ int n, ns, ns2, odd, i, k;
+ VMesh *vm;
+
+ vm = bv->vmesh;
+ n = vm->count;
+ ns = vm->seg;
+ ns2 = ns / 2;
+ odd = ns % 2;
+
+ for (i = 0; i < n; i++) {
+ for (k = 1; k < ns; k++) {
+ copy_v3_v3(mesh_vert(vm, i, 0, k)->co, mesh_vert(vm1, i, 0, k)->co);
+ if (i > 0 && k <= ns2) {
+ mesh_vert(vm, i, 0, k)->v = mesh_vert(vm, i - 1, 0, ns - k)->v;
+ }
+ else if (i == n - 1 && k > ns2) {
+ mesh_vert(vm, i, 0, k)->v = mesh_vert(vm, 0, 0, ns - k)->v;
+ }
+ else {
+ create_mesh_bmvert(bm, vm, i, 0, k, bv->v);
+ }
+ }
+ }
+ if (odd) {
+ for (i = 0; i < n; i++) {
+ mesh_vert(vm, i, ns2, ns2)->v = mesh_vert(vm, i, 0, ns2)->v;
+ }
+ build_center_ngon(bp, bm, bv, bp->mat_nr);
+ }
}
/* copy whichever of a and b is closer to v into r */
static void closer_v3_v3v3v3(float r[3], float a[3], float b[3], float v[3])
{
- if (len_squared_v3v3(a, v) <= len_squared_v3v3(b, v)) {
- copy_v3_v3(r, a);
- }
- else {
- copy_v3_v3(r, b);
- }
+ if (len_squared_v3v3(a, v) <= len_squared_v3v3(b, v)) {
+ copy_v3_v3(r, a);
+ }
+ else {
+ copy_v3_v3(r, b);
+ }
}
/* Special case of VMesh when profile == 1 and there are 3 or more beveled edges.
@@ -4121,224 +4155,227 @@ static void closer_v3_v3v3v3(float r[3], float a[3], float b[3], float v[3])
*/
static VMesh *square_out_adj_vmesh(BevelParams *bp, BevVert *bv)
{
- int n, ns, ns2, odd, i, j, k, ikind, im1, clstride, iprev, akind;
- float bndco[3], dir1[3], dir2[3], co1[3], co2[3], meet1[3], meet2[3], v1co[3], v2co[3];
- float *on_edge_cur, *on_edge_prev, *p;
- float ns2inv, finalfrac, ang;
- BoundVert *bndv;
- EdgeHalf *e1, *e2;
- VMesh *vm;
- float *centerline;
- bool *cset, v1set, v2set;
-
- n = bv->vmesh->count;
- ns = bv->vmesh->seg;
- ns2 = ns / 2;
- odd = ns % 2;
- ns2inv = 1.0f / (float) ns2;
- vm = new_adj_vmesh(bp->mem_arena, n, ns, bv->vmesh->boundstart);
- clstride = 3 * (ns2 + 1);
- centerline = MEM_mallocN(clstride * n * sizeof(float), "bevel");
- cset = MEM_callocN(n * sizeof(bool), "bevel");
-
- /* find on_edge, place on bndv[i]'s elast where offset line would meet,
- * taking min-distance-to bv->v with position where next sector's offset line would meet */
- bndv = vm->boundstart;
- for (i = 0; i < n; i++) {
- copy_v3_v3(bndco, bndv->nv.co);
- e1 = bndv->efirst;
- e2 = bndv->elast;
- akind = 0;
- if (e1 && e2) {
- akind = edges_angle_kind(e1, e2, bv->v);
- }
- if (bndv->is_patch_start) {
- mid_v3_v3v3(centerline + clstride * i, bndv->nv.co, bndv->next->nv.co);
- cset[i] = true;
- bndv = bndv->next;
- i++;
- mid_v3_v3v3(centerline + clstride * i, bndv->nv.co, bndv->next->nv.co);
- cset[i] = true;
- bndv = bndv->next;
- i++;
- /* leave cset[i] where it was - probably false, unless i == n - 1 */
- }
- else if (bndv->is_arc_start) {
- e1 = bndv->efirst;
- e2 = bndv->next->efirst;
- copy_v3_v3(centerline + clstride * i, bndv->profile.midco);
- bndv = bndv->next;
- cset[i] = true;
- i++;
- /* leave cset[i] where it was - probably false, unless i == n - 1 */
- }
- else if (akind < 0) {
- sub_v3_v3v3(dir1, e1->e->v1->co, e1->e->v2->co);
- sub_v3_v3v3(dir2, e2->e->v1->co, e2->e->v2->co);
- add_v3_v3v3(co1, bndco, dir1);
- add_v3_v3v3(co2, bndco, dir2);
- /* intersect e1 with line through bndv parallel to e2 to get v1co */
- ikind = isect_line_line_v3(e1->e->v1->co, e1->e->v2->co, bndco, co2, meet1, meet2);
- if (ikind == 0) {
- v1set = false;
- }
- else {
- /* if the lines are skew (ikind == 2), want meet1 which is on e1 */
- copy_v3_v3(v1co, meet1);
- v1set = true;
- }
- /* intersect e2 with line through bndv parallel to e1 to get v2co */
- ikind = isect_line_line_v3(e2->e->v1->co, e2->e->v2->co, bndco, co1, meet1, meet2);
- if (ikind == 0) {
- v2set = false;
- }
- else {
- v2set = true;
- copy_v3_v3(v2co, meet1);
- }
-
- /* want on_edge[i] to be min dist to bv->v of v2co and the v1co of next iteration */
- on_edge_cur = centerline + clstride * i;
- iprev = (i == 0) ? n - 1 : i - 1;
- on_edge_prev = centerline + clstride * iprev;
- if (v2set) {
- if (cset[i]) {
- closer_v3_v3v3v3(on_edge_cur, on_edge_cur, v2co, bv->v->co);
- }
- else {
- copy_v3_v3(on_edge_cur, v2co);
- cset[i] = true;
- }
- }
- if (v1set) {
- if (cset[iprev]) {
- closer_v3_v3v3v3(on_edge_prev, on_edge_prev, v1co, bv->v->co);
- }
- else {
- copy_v3_v3(on_edge_prev, v1co);
- cset[iprev] = true;
- }
- }
- }
- bndv = bndv->next;
- }
- /* Maybe not everything was set by the previous loop */
- bndv = vm->boundstart;
- for (i = 0; i < n; i++) {
- if (!cset[i]) {
- on_edge_cur = centerline + clstride * i;
- e1 = bndv->next->efirst;
- copy_v3_v3(co1, bndv->nv.co);
- copy_v3_v3(co2, bndv->next->nv.co);
- if (e1) {
- if (bndv->prev->is_arc_start && bndv->next->is_arc_start) {
- ikind = isect_line_line_v3(e1->e->v1->co, e1->e->v2->co, co1, co2, meet1, meet2);
- if (ikind != 0) {
- copy_v3_v3(on_edge_cur, meet1);
- cset[i] = true;
- }
- }
- else {
- if (bndv->prev->is_arc_start) {
- closest_to_line_segment_v3(on_edge_cur, co1, e1->e->v1->co, e1->e->v2->co);
- }
- else {
- closest_to_line_segment_v3(on_edge_cur, co2, e1->e->v1->co, e1->e->v2->co);
- }
- cset[i] = true;
- }
- }
- if (!cset[i]) {
- mid_v3_v3v3(on_edge_cur, co1, co2);
- cset[i] = true;
- }
- }
- bndv = bndv->next;
- }
-
- /* fill in rest of centerlines by interpolation */
- copy_v3_v3(co2, bv->v->co);
- bndv = vm->boundstart;
- for (i = 0; i < n; i++) {
- if (odd) {
- ang = 0.5f * angle_v3v3v3(bndv->nv.co, co1, bndv->next->nv.co);
- if (ang > BEVEL_SMALL_ANG) {
- /* finalfrac is length along arms of isoceles triangle with top angle 2*ang
- * such that the base of the triangle is 1.
- * This is used in interpolation along centerline in odd case.
- * To avoid too big a drop from bv, cap finalfrac a 0.8 arbitrarily */
- finalfrac = 0.5f / sin(ang);
- if (finalfrac > 0.8f) {
- finalfrac = 0.8f;
- }
- }
- else {
- finalfrac = 0.8f;
- }
- ns2inv = 1.0f / (ns2 + finalfrac);
- }
-
- p = centerline + clstride * i;
- copy_v3_v3(co1, p);
- p += 3;
- for (j = 1; j <= ns2; j++) {
- interp_v3_v3v3(p, co1, co2, j * ns2inv);
- p += 3;
- }
- bndv = bndv->next;
- }
-
- /* coords of edges and mid or near-mid line */
- bndv = vm->boundstart;
- for (i = 0; i < n; i++) {
- copy_v3_v3(co1, bndv->nv.co);
- copy_v3_v3(co2, centerline + clstride * (i == 0 ? n - 1 : i - 1));
- for (j = 0; j < ns2 + odd; j++) {
- interp_v3_v3v3(mesh_vert(vm, i, j, 0)->co, co1, co2, j * ns2inv);
- }
- copy_v3_v3(co2, centerline + clstride * i);
- for (k = 1; k <= ns2; k++) {
- interp_v3_v3v3(mesh_vert(vm, i, 0, k)->co, co1, co2, k * ns2inv);
- }
- bndv = bndv->next;
- }
- if (!odd) {
- copy_v3_v3(mesh_vert(vm, 0, ns2, ns2)->co, bv->v->co);
- }
- vmesh_copy_equiv_verts(vm);
-
- /* fill in interior points by interpolation from edges to centerlines */
- bndv = vm->boundstart;
- for (i = 0; i < n; i++) {
- im1 = (i == 0) ? n - 1 : i - 1;
- for (j = 1; j < ns2 + odd; j++) {
- for (k = 1; k <= ns2; k++) {
- ikind = isect_line_line_v3(
- mesh_vert(vm, i, 0, k)->co, centerline + clstride * im1 + 3 * k,
- mesh_vert(vm, i, j, 0)->co, centerline + clstride * i + 3 * j,
- meet1, meet2);
- if (ikind == 0) {
- /* how can this happen? fall back on interpolation in one direction if it does */
- interp_v3_v3v3(
- mesh_vert(vm, i, j, k)->co,
- mesh_vert(vm, i, 0, k)->co, centerline + clstride * im1 + 3 * k, j * ns2inv);
- }
- else if (ikind == 1) {
- copy_v3_v3(mesh_vert(vm, i, j, k)->co, meet1);
- }
- else {
- mid_v3_v3v3(mesh_vert(vm, i, j, k)->co, meet1, meet2);
- }
- }
- }
- bndv = bndv->next;
- }
-
- vmesh_copy_equiv_verts(vm);
-
- MEM_freeN(centerline);
- MEM_freeN(cset);
- return vm;
+ int n, ns, ns2, odd, i, j, k, ikind, im1, clstride, iprev, akind;
+ float bndco[3], dir1[3], dir2[3], co1[3], co2[3], meet1[3], meet2[3], v1co[3], v2co[3];
+ float *on_edge_cur, *on_edge_prev, *p;
+ float ns2inv, finalfrac, ang;
+ BoundVert *bndv;
+ EdgeHalf *e1, *e2;
+ VMesh *vm;
+ float *centerline;
+ bool *cset, v1set, v2set;
+
+ n = bv->vmesh->count;
+ ns = bv->vmesh->seg;
+ ns2 = ns / 2;
+ odd = ns % 2;
+ ns2inv = 1.0f / (float)ns2;
+ vm = new_adj_vmesh(bp->mem_arena, n, ns, bv->vmesh->boundstart);
+ clstride = 3 * (ns2 + 1);
+ centerline = MEM_mallocN(clstride * n * sizeof(float), "bevel");
+ cset = MEM_callocN(n * sizeof(bool), "bevel");
+
+ /* find on_edge, place on bndv[i]'s elast where offset line would meet,
+ * taking min-distance-to bv->v with position where next sector's offset line would meet */
+ bndv = vm->boundstart;
+ for (i = 0; i < n; i++) {
+ copy_v3_v3(bndco, bndv->nv.co);
+ e1 = bndv->efirst;
+ e2 = bndv->elast;
+ akind = 0;
+ if (e1 && e2) {
+ akind = edges_angle_kind(e1, e2, bv->v);
+ }
+ if (bndv->is_patch_start) {
+ mid_v3_v3v3(centerline + clstride * i, bndv->nv.co, bndv->next->nv.co);
+ cset[i] = true;
+ bndv = bndv->next;
+ i++;
+ mid_v3_v3v3(centerline + clstride * i, bndv->nv.co, bndv->next->nv.co);
+ cset[i] = true;
+ bndv = bndv->next;
+ i++;
+ /* leave cset[i] where it was - probably false, unless i == n - 1 */
+ }
+ else if (bndv->is_arc_start) {
+ e1 = bndv->efirst;
+ e2 = bndv->next->efirst;
+ copy_v3_v3(centerline + clstride * i, bndv->profile.midco);
+ bndv = bndv->next;
+ cset[i] = true;
+ i++;
+ /* leave cset[i] where it was - probably false, unless i == n - 1 */
+ }
+ else if (akind < 0) {
+ sub_v3_v3v3(dir1, e1->e->v1->co, e1->e->v2->co);
+ sub_v3_v3v3(dir2, e2->e->v1->co, e2->e->v2->co);
+ add_v3_v3v3(co1, bndco, dir1);
+ add_v3_v3v3(co2, bndco, dir2);
+ /* intersect e1 with line through bndv parallel to e2 to get v1co */
+ ikind = isect_line_line_v3(e1->e->v1->co, e1->e->v2->co, bndco, co2, meet1, meet2);
+ if (ikind == 0) {
+ v1set = false;
+ }
+ else {
+ /* if the lines are skew (ikind == 2), want meet1 which is on e1 */
+ copy_v3_v3(v1co, meet1);
+ v1set = true;
+ }
+ /* intersect e2 with line through bndv parallel to e1 to get v2co */
+ ikind = isect_line_line_v3(e2->e->v1->co, e2->e->v2->co, bndco, co1, meet1, meet2);
+ if (ikind == 0) {
+ v2set = false;
+ }
+ else {
+ v2set = true;
+ copy_v3_v3(v2co, meet1);
+ }
+
+ /* want on_edge[i] to be min dist to bv->v of v2co and the v1co of next iteration */
+ on_edge_cur = centerline + clstride * i;
+ iprev = (i == 0) ? n - 1 : i - 1;
+ on_edge_prev = centerline + clstride * iprev;
+ if (v2set) {
+ if (cset[i]) {
+ closer_v3_v3v3v3(on_edge_cur, on_edge_cur, v2co, bv->v->co);
+ }
+ else {
+ copy_v3_v3(on_edge_cur, v2co);
+ cset[i] = true;
+ }
+ }
+ if (v1set) {
+ if (cset[iprev]) {
+ closer_v3_v3v3v3(on_edge_prev, on_edge_prev, v1co, bv->v->co);
+ }
+ else {
+ copy_v3_v3(on_edge_prev, v1co);
+ cset[iprev] = true;
+ }
+ }
+ }
+ bndv = bndv->next;
+ }
+ /* Maybe not everything was set by the previous loop */
+ bndv = vm->boundstart;
+ for (i = 0; i < n; i++) {
+ if (!cset[i]) {
+ on_edge_cur = centerline + clstride * i;
+ e1 = bndv->next->efirst;
+ copy_v3_v3(co1, bndv->nv.co);
+ copy_v3_v3(co2, bndv->next->nv.co);
+ if (e1) {
+ if (bndv->prev->is_arc_start && bndv->next->is_arc_start) {
+ ikind = isect_line_line_v3(e1->e->v1->co, e1->e->v2->co, co1, co2, meet1, meet2);
+ if (ikind != 0) {
+ copy_v3_v3(on_edge_cur, meet1);
+ cset[i] = true;
+ }
+ }
+ else {
+ if (bndv->prev->is_arc_start) {
+ closest_to_line_segment_v3(on_edge_cur, co1, e1->e->v1->co, e1->e->v2->co);
+ }
+ else {
+ closest_to_line_segment_v3(on_edge_cur, co2, e1->e->v1->co, e1->e->v2->co);
+ }
+ cset[i] = true;
+ }
+ }
+ if (!cset[i]) {
+ mid_v3_v3v3(on_edge_cur, co1, co2);
+ cset[i] = true;
+ }
+ }
+ bndv = bndv->next;
+ }
+
+ /* fill in rest of centerlines by interpolation */
+ copy_v3_v3(co2, bv->v->co);
+ bndv = vm->boundstart;
+ for (i = 0; i < n; i++) {
+ if (odd) {
+ ang = 0.5f * angle_v3v3v3(bndv->nv.co, co1, bndv->next->nv.co);
+ if (ang > BEVEL_SMALL_ANG) {
+ /* finalfrac is length along arms of isoceles triangle with top angle 2*ang
+ * such that the base of the triangle is 1.
+ * This is used in interpolation along centerline in odd case.
+ * To avoid too big a drop from bv, cap finalfrac a 0.8 arbitrarily */
+ finalfrac = 0.5f / sin(ang);
+ if (finalfrac > 0.8f) {
+ finalfrac = 0.8f;
+ }
+ }
+ else {
+ finalfrac = 0.8f;
+ }
+ ns2inv = 1.0f / (ns2 + finalfrac);
+ }
+
+ p = centerline + clstride * i;
+ copy_v3_v3(co1, p);
+ p += 3;
+ for (j = 1; j <= ns2; j++) {
+ interp_v3_v3v3(p, co1, co2, j * ns2inv);
+ p += 3;
+ }
+ bndv = bndv->next;
+ }
+
+ /* coords of edges and mid or near-mid line */
+ bndv = vm->boundstart;
+ for (i = 0; i < n; i++) {
+ copy_v3_v3(co1, bndv->nv.co);
+ copy_v3_v3(co2, centerline + clstride * (i == 0 ? n - 1 : i - 1));
+ for (j = 0; j < ns2 + odd; j++) {
+ interp_v3_v3v3(mesh_vert(vm, i, j, 0)->co, co1, co2, j * ns2inv);
+ }
+ copy_v3_v3(co2, centerline + clstride * i);
+ for (k = 1; k <= ns2; k++) {
+ interp_v3_v3v3(mesh_vert(vm, i, 0, k)->co, co1, co2, k * ns2inv);
+ }
+ bndv = bndv->next;
+ }
+ if (!odd) {
+ copy_v3_v3(mesh_vert(vm, 0, ns2, ns2)->co, bv->v->co);
+ }
+ vmesh_copy_equiv_verts(vm);
+
+ /* fill in interior points by interpolation from edges to centerlines */
+ bndv = vm->boundstart;
+ for (i = 0; i < n; i++) {
+ im1 = (i == 0) ? n - 1 : i - 1;
+ for (j = 1; j < ns2 + odd; j++) {
+ for (k = 1; k <= ns2; k++) {
+ ikind = isect_line_line_v3(mesh_vert(vm, i, 0, k)->co,
+ centerline + clstride * im1 + 3 * k,
+ mesh_vert(vm, i, j, 0)->co,
+ centerline + clstride * i + 3 * j,
+ meet1,
+ meet2);
+ if (ikind == 0) {
+ /* how can this happen? fall back on interpolation in one direction if it does */
+ interp_v3_v3v3(mesh_vert(vm, i, j, k)->co,
+ mesh_vert(vm, i, 0, k)->co,
+ centerline + clstride * im1 + 3 * k,
+ j * ns2inv);
+ }
+ else if (ikind == 1) {
+ copy_v3_v3(mesh_vert(vm, i, j, k)->co, meet1);
+ }
+ else {
+ mid_v3_v3v3(mesh_vert(vm, i, j, k)->co, meet1, meet2);
+ }
+ }
+ }
+ bndv = bndv->next;
+ }
+
+ vmesh_copy_equiv_verts(vm);
+
+ MEM_freeN(centerline);
+ MEM_freeN(cset);
+ return vm;
}
/*
@@ -4347,176 +4384,188 @@ static VMesh *square_out_adj_vmesh(BevelParams *bp, BevVert *bv)
* using cubic subdivision, then make the BMVerts and the new faces. */
static void bevel_build_rings(BevelParams *bp, BMesh *bm, BevVert *bv)
{
- int n, ns, ns2, odd, i, j, k, ring;
- VMesh *vm1, *vm;
- BoundVert *v;
- BMVert *bmv1, *bmv2, *bmv3, *bmv4;
- BMFace *f, *f2, *r_f;
- BMEdge *bme, *bme1, *bme2, *bme3;
- EdgeHalf *e;
- BoundVert *vpipe;
- int mat_nr = bp->mat_nr;
-
- n = bv->vmesh->count;
- ns = bv->vmesh->seg;
- ns2 = ns / 2;
- odd = ns % 2;
- BLI_assert(n >= 3 && ns > 1);
-
- /* Add support for profiles in vertex only in-plane bevels */
- if (bp->vertex_only) {
- v = bv->vmesh->boundstart;
- do {
- Profile *pro = &v->profile;
- pro->super_r = bp->pro_super_r;
- copy_v3_v3(pro->midco, bv->v->co);
- calculate_profile(bp, v);
- v = v->next;
- } while (v != bv->vmesh->boundstart);
- }
-
- vpipe = pipe_test(bv);
-
- if (bp->pro_super_r == PRO_SQUARE_R && bv->selcount >= 3 && !odd) {
- vm1 = square_out_adj_vmesh(bp, bv);
- }
- else if (vpipe) {
- vm1 = pipe_adj_vmesh(bp, bv, vpipe);
- }
- else if (tri_corner_test(bp, bv) == 1) {
- vm1 = tri_corner_adj_vmesh(bp, bv);
- /* the PRO_SQUARE_IN_R profile has boundary edges that merge
- * and no internal ring polys except possibly center ngon */
- if (bp->pro_super_r == PRO_SQUARE_IN_R) {
- build_square_in_vmesh(bp, bm, bv, vm1);
- return;
- }
- }
- else {
- vm1 = adj_vmesh(bp, bv);
- }
-
- /* copy final vmesh into bv->vmesh, make BMVerts and BMFaces */
- vm = bv->vmesh;
- for (i = 0; i < n; i++) {
- for (j = 0; j <= ns2; j++) {
- for (k = 0; k <= ns; k++) {
- if (j == 0 && (k == 0 || k == ns)) {
- continue; /* boundary corners already made */
- }
- if (!is_canon(vm, i, j, k)) {
- continue;
- }
- copy_v3_v3(mesh_vert(vm, i, j, k)->co, mesh_vert(vm1, i, j, k)->co);
- create_mesh_bmvert(bm, vm, i, j, k, bv->v);
- }
- }
- }
- vmesh_copy_equiv_verts(vm);
- /* make the polygons */
- v = vm->boundstart;
- do {
- i = v->index;
- f = boundvert_rep_face(v, NULL);
- f2 = boundvert_rep_face(v->next, NULL);
- if (bp->vertex_only) {
- e = v->efirst;
- }
- else {
- e = v->ebev;
- }
- bme = e ? e->e : NULL;
- /* For odd ns, make polys with lower left corner at (i,j,k) for
- * j in [0, ns2-1], k in [0, ns2]. And then the center ngon.
- * For even ns,
- * j in [0, ns2-1], k in [0, ns2-1] */
- for (j = 0; j < ns2; j++) {
- for (k = 0; k < ns2 + odd; k++) {
- bmv1 = mesh_vert(vm, i, j, k)->v;
- bmv2 = mesh_vert(vm, i, j, k + 1)->v;
- bmv3 = mesh_vert(vm, i, j + 1, k + 1)->v;
- bmv4 = mesh_vert(vm, i, j + 1, k)->v;
- BLI_assert(bmv1 && bmv2 && bmv3 && bmv4);
- if (bp->vertex_only) {
- if (j < k) {
- if (k == ns2 && j == ns2 - 1) {
- r_f = bev_create_quad_ex(bm, bmv1, bmv2, bmv3, bmv4, f2, f2, f2, f2,
- NULL, NULL, v->next->efirst->e, bme, mat_nr);
- }
- else {
- r_f = bev_create_quad(bm, bmv1, bmv2, bmv3, bmv4, f2, f2, f2, f2, mat_nr);
- }
- }
- else if (j > k) {
- r_f = bev_create_quad(bm, bmv1, bmv2, bmv3, bmv4, f2, f2, f2, f2, mat_nr);
- }
- else { /* j == k */
- /* only one edge attached to v, since vertex_only */
- if (e->is_seam) {
- r_f = bev_create_quad_ex(bm, bmv1, bmv2, bmv3, bmv4, f2, f2, f2, f2,
- bme, NULL, bme, NULL, mat_nr);
- }
- else {
- r_f = bev_create_quad_ex(bm, bmv1, bmv2, bmv3, bmv4, f2, f2, f2, f,
- bme, NULL, bme, NULL, mat_nr);
- }
- }
- }
- else { /* edge bevel */
- if (odd) {
- if (k == ns2) {
- if (e && e->is_seam) {
- r_f = bev_create_quad_ex(bm, bmv1, bmv2, bmv3, bmv4, f, f, f, f,
- NULL, bme, bme, NULL, mat_nr);
- }
- else {
- r_f = bev_create_quad(bm, bmv1, bmv2, bmv3, bmv4, f, f2, f2, f, mat_nr);
- }
- }
- else {
- r_f = bev_create_quad(bm, bmv1, bmv2, bmv3, bmv4, f, f, f, f, mat_nr);
- }
- }
- else {
- bme1 = k == ns2 - 1 ? bme : NULL;
- bme3 = NULL;
- if (j == ns2 - 1 && v->prev->ebev) {
- bme3 = v->prev->ebev->e;
- }
- bme2 = bme1 != NULL ? bme1 : bme3;
- r_f = bev_create_quad_ex(bm, bmv1, bmv2, bmv3, bmv4, f, f, f, f,
- NULL, bme1, bme2, bme3, mat_nr);
- }
- }
- record_face_kind(bp, r_f, F_VERT);
- }
- }
- } while ((v = v->next) != vm->boundstart);
-
- /* Fix UVs along center lines if even number of segments */
- if (!odd) {
- v = vm->boundstart;
- do {
- i = v->index;
- if (!v->any_seam) {
- for (ring = 1; ring < ns2; ring++) {
- BMVert *v_uv = mesh_vert(vm, i, ring, ns2)->v;
- if (v_uv) {
- bev_merge_uvs(bm, v_uv);
- }
- }
- }
- } while ((v = v->next) != vm->boundstart);
- bmv1 = mesh_vert(vm, 0, ns2, ns2)->v;
- if (bp->vertex_only || count_bound_vert_seams(bv) <= 1) {
- bev_merge_uvs(bm, bmv1);
- }
- }
-
- /* center ngon */
- if (odd) {
- build_center_ngon(bp, bm, bv, mat_nr);
- }
+ int n, ns, ns2, odd, i, j, k, ring;
+ VMesh *vm1, *vm;
+ BoundVert *v;
+ BMVert *bmv1, *bmv2, *bmv3, *bmv4;
+ BMFace *f, *f2, *r_f;
+ BMEdge *bme, *bme1, *bme2, *bme3;
+ EdgeHalf *e;
+ BoundVert *vpipe;
+ int mat_nr = bp->mat_nr;
+
+ n = bv->vmesh->count;
+ ns = bv->vmesh->seg;
+ ns2 = ns / 2;
+ odd = ns % 2;
+ BLI_assert(n >= 3 && ns > 1);
+
+ /* Add support for profiles in vertex only in-plane bevels */
+ if (bp->vertex_only) {
+ v = bv->vmesh->boundstart;
+ do {
+ Profile *pro = &v->profile;
+ pro->super_r = bp->pro_super_r;
+ copy_v3_v3(pro->midco, bv->v->co);
+ calculate_profile(bp, v);
+ v = v->next;
+ } while (v != bv->vmesh->boundstart);
+ }
+
+ vpipe = pipe_test(bv);
+
+ if (bp->pro_super_r == PRO_SQUARE_R && bv->selcount >= 3 && !odd) {
+ vm1 = square_out_adj_vmesh(bp, bv);
+ }
+ else if (vpipe) {
+ vm1 = pipe_adj_vmesh(bp, bv, vpipe);
+ }
+ else if (tri_corner_test(bp, bv) == 1) {
+ vm1 = tri_corner_adj_vmesh(bp, bv);
+ /* the PRO_SQUARE_IN_R profile has boundary edges that merge
+ * and no internal ring polys except possibly center ngon */
+ if (bp->pro_super_r == PRO_SQUARE_IN_R) {
+ build_square_in_vmesh(bp, bm, bv, vm1);
+ return;
+ }
+ }
+ else {
+ vm1 = adj_vmesh(bp, bv);
+ }
+
+ /* copy final vmesh into bv->vmesh, make BMVerts and BMFaces */
+ vm = bv->vmesh;
+ for (i = 0; i < n; i++) {
+ for (j = 0; j <= ns2; j++) {
+ for (k = 0; k <= ns; k++) {
+ if (j == 0 && (k == 0 || k == ns)) {
+ continue; /* boundary corners already made */
+ }
+ if (!is_canon(vm, i, j, k)) {
+ continue;
+ }
+ copy_v3_v3(mesh_vert(vm, i, j, k)->co, mesh_vert(vm1, i, j, k)->co);
+ create_mesh_bmvert(bm, vm, i, j, k, bv->v);
+ }
+ }
+ }
+ vmesh_copy_equiv_verts(vm);
+ /* make the polygons */
+ v = vm->boundstart;
+ do {
+ i = v->index;
+ f = boundvert_rep_face(v, NULL);
+ f2 = boundvert_rep_face(v->next, NULL);
+ if (bp->vertex_only) {
+ e = v->efirst;
+ }
+ else {
+ e = v->ebev;
+ }
+ bme = e ? e->e : NULL;
+ /* For odd ns, make polys with lower left corner at (i,j,k) for
+ * j in [0, ns2-1], k in [0, ns2]. And then the center ngon.
+ * For even ns,
+ * j in [0, ns2-1], k in [0, ns2-1] */
+ for (j = 0; j < ns2; j++) {
+ for (k = 0; k < ns2 + odd; k++) {
+ bmv1 = mesh_vert(vm, i, j, k)->v;
+ bmv2 = mesh_vert(vm, i, j, k + 1)->v;
+ bmv3 = mesh_vert(vm, i, j + 1, k + 1)->v;
+ bmv4 = mesh_vert(vm, i, j + 1, k)->v;
+ BLI_assert(bmv1 && bmv2 && bmv3 && bmv4);
+ if (bp->vertex_only) {
+ if (j < k) {
+ if (k == ns2 && j == ns2 - 1) {
+ r_f = bev_create_quad_ex(bm,
+ bmv1,
+ bmv2,
+ bmv3,
+ bmv4,
+ f2,
+ f2,
+ f2,
+ f2,
+ NULL,
+ NULL,
+ v->next->efirst->e,
+ bme,
+ mat_nr);
+ }
+ else {
+ r_f = bev_create_quad(bm, bmv1, bmv2, bmv3, bmv4, f2, f2, f2, f2, mat_nr);
+ }
+ }
+ else if (j > k) {
+ r_f = bev_create_quad(bm, bmv1, bmv2, bmv3, bmv4, f2, f2, f2, f2, mat_nr);
+ }
+ else { /* j == k */
+ /* only one edge attached to v, since vertex_only */
+ if (e->is_seam) {
+ r_f = bev_create_quad_ex(
+ bm, bmv1, bmv2, bmv3, bmv4, f2, f2, f2, f2, bme, NULL, bme, NULL, mat_nr);
+ }
+ else {
+ r_f = bev_create_quad_ex(
+ bm, bmv1, bmv2, bmv3, bmv4, f2, f2, f2, f, bme, NULL, bme, NULL, mat_nr);
+ }
+ }
+ }
+ else { /* edge bevel */
+ if (odd) {
+ if (k == ns2) {
+ if (e && e->is_seam) {
+ r_f = bev_create_quad_ex(
+ bm, bmv1, bmv2, bmv3, bmv4, f, f, f, f, NULL, bme, bme, NULL, mat_nr);
+ }
+ else {
+ r_f = bev_create_quad(bm, bmv1, bmv2, bmv3, bmv4, f, f2, f2, f, mat_nr);
+ }
+ }
+ else {
+ r_f = bev_create_quad(bm, bmv1, bmv2, bmv3, bmv4, f, f, f, f, mat_nr);
+ }
+ }
+ else {
+ bme1 = k == ns2 - 1 ? bme : NULL;
+ bme3 = NULL;
+ if (j == ns2 - 1 && v->prev->ebev) {
+ bme3 = v->prev->ebev->e;
+ }
+ bme2 = bme1 != NULL ? bme1 : bme3;
+ r_f = bev_create_quad_ex(
+ bm, bmv1, bmv2, bmv3, bmv4, f, f, f, f, NULL, bme1, bme2, bme3, mat_nr);
+ }
+ }
+ record_face_kind(bp, r_f, F_VERT);
+ }
+ }
+ } while ((v = v->next) != vm->boundstart);
+
+ /* Fix UVs along center lines if even number of segments */
+ if (!odd) {
+ v = vm->boundstart;
+ do {
+ i = v->index;
+ if (!v->any_seam) {
+ for (ring = 1; ring < ns2; ring++) {
+ BMVert *v_uv = mesh_vert(vm, i, ring, ns2)->v;
+ if (v_uv) {
+ bev_merge_uvs(bm, v_uv);
+ }
+ }
+ }
+ } while ((v = v->next) != vm->boundstart);
+ bmv1 = mesh_vert(vm, 0, ns2, ns2)->v;
+ if (bp->vertex_only || count_bound_vert_seams(bv) <= 1) {
+ bev_merge_uvs(bm, bmv1);
+ }
+ }
+
+ /* center ngon */
+ if (odd) {
+ build_center_ngon(bp, bm, bv, mat_nr);
+ }
}
/* If we make a poly out of verts around bv, snapping to rep frep, will uv poly have zero area?
@@ -4526,135 +4575,150 @@ static void bevel_build_rings(BevelParams *bp, BMesh *bm, BevVert *bv)
* the other vertices snap to e or snap to an edge at a point that is essentially on e too. */
static bool is_bad_uv_poly(BevVert *bv, BMFace *frep)
{
- BoundVert *v;
- BMEdge *snape, *firste;
- float co[3];
- VMesh *vm = bv->vmesh;
- float d2;
-
- v = vm->boundstart;
- d2 = snap_face_dist_squared(v->nv.v->co, frep, &firste, co);
- if (d2 > BEVEL_EPSILON_BIG_SQ || firste == NULL) {
- return false;
- }
-
- for (v = v->next; v != vm->boundstart; v = v->next) {
- snap_face_dist_squared(v->nv.v->co, frep, &snape, co);
- if (snape != firste) {
- d2 = dist_to_line_v3(co, firste->v1->co, firste->v2->co);
- if (d2 > BEVEL_EPSILON_BIG_SQ) {
- return false;
- }
- }
- }
- return true;
+ BoundVert *v;
+ BMEdge *snape, *firste;
+ float co[3];
+ VMesh *vm = bv->vmesh;
+ float d2;
+
+ v = vm->boundstart;
+ d2 = snap_face_dist_squared(v->nv.v->co, frep, &firste, co);
+ if (d2 > BEVEL_EPSILON_BIG_SQ || firste == NULL) {
+ return false;
+ }
+
+ for (v = v->next; v != vm->boundstart; v = v->next) {
+ snap_face_dist_squared(v->nv.v->co, frep, &snape, co);
+ if (snape != firste) {
+ d2 = dist_to_line_v3(co, firste->v1->co, firste->v2->co);
+ if (d2 > BEVEL_EPSILON_BIG_SQ) {
+ return false;
+ }
+ }
+ }
+ return true;
}
static BMFace *bevel_build_poly(BevelParams *bp, BMesh *bm, BevVert *bv)
{
- BMFace *f, *frep, *frep2;
- int n, k;
- VMesh *vm = bv->vmesh;
- BoundVert *v;
- BMEdge *frep_e1, *frep_e2, *frep_e;
- BMVert **vv = NULL;
- BMFace **vf = NULL;
- BMEdge **ve = NULL;
- BLI_array_staticdeclare(vv, BM_DEFAULT_NGON_STACK_SIZE);
- BLI_array_staticdeclare(vf, BM_DEFAULT_NGON_STACK_SIZE);
- BLI_array_staticdeclare(ve, BM_DEFAULT_NGON_STACK_SIZE);
-
- if (bv->any_seam) {
- frep = boundvert_rep_face(vm->boundstart, &frep2);
- if (frep2 && frep && is_bad_uv_poly(bv, frep)) {
- frep = frep2;
- }
- get_incident_edges(frep, bv->v, &frep_e1, &frep_e2);
- }
- else {
- frep = NULL;
- frep_e1 = frep_e2 = NULL;
- }
- v = vm->boundstart;
- n = 0;
- do {
- /* accumulate vertices for vertex ngon */
- /* also accumulate faces in which uv interpolation is to happen for each */
- BLI_array_append(vv, v->nv.v);
- if (frep) {
- BLI_array_append(vf, frep);
- frep_e = find_closer_edge(v->nv.v->co, frep_e1, frep_e2);
- BLI_array_append(ve, n > 0 ? frep_e : NULL);
- }
- else {
- BLI_array_append(vf, boundvert_rep_face(v, NULL));
- BLI_array_append(ve, NULL);
- }
- n++;
- if (v->ebev && v->ebev->seg > 1) {
- for (k = 1; k < v->ebev->seg; k++) {
- BLI_array_append(vv, mesh_vert(vm, v->index, 0, k)->v);
- if (frep) {
- BLI_array_append(vf, frep);
- frep_e = find_closer_edge(mesh_vert(vm, v->index, 0, k)->v->co, frep_e1, frep_e2);
- BLI_array_append(ve, k < v->ebev->seg / 2 ? NULL : frep_e);
- }
- else {
- BLI_array_append(vf, boundvert_rep_face(v, NULL));
- BLI_array_append(ve, NULL);
- }
- n++;
- }
- }
- } while ((v = v->next) != vm->boundstart);
- if (n > 2) {
- f = bev_create_ngon(bm, vv, n, vf, frep, ve, bp->mat_nr, true);
- record_face_kind(bp, f, F_VERT);
- }
- else {
- f = NULL;
- }
- BLI_array_free(vv);
- BLI_array_free(vf);
- BLI_array_free(ve);
- return f;
+ BMFace *f, *frep, *frep2;
+ int n, k;
+ VMesh *vm = bv->vmesh;
+ BoundVert *v;
+ BMEdge *frep_e1, *frep_e2, *frep_e;
+ BMVert **vv = NULL;
+ BMFace **vf = NULL;
+ BMEdge **ve = NULL;
+ BLI_array_staticdeclare(vv, BM_DEFAULT_NGON_STACK_SIZE);
+ BLI_array_staticdeclare(vf, BM_DEFAULT_NGON_STACK_SIZE);
+ BLI_array_staticdeclare(ve, BM_DEFAULT_NGON_STACK_SIZE);
+
+ if (bv->any_seam) {
+ frep = boundvert_rep_face(vm->boundstart, &frep2);
+ if (frep2 && frep && is_bad_uv_poly(bv, frep)) {
+ frep = frep2;
+ }
+ get_incident_edges(frep, bv->v, &frep_e1, &frep_e2);
+ }
+ else {
+ frep = NULL;
+ frep_e1 = frep_e2 = NULL;
+ }
+ v = vm->boundstart;
+ n = 0;
+ do {
+ /* accumulate vertices for vertex ngon */
+ /* also accumulate faces in which uv interpolation is to happen for each */
+ BLI_array_append(vv, v->nv.v);
+ if (frep) {
+ BLI_array_append(vf, frep);
+ frep_e = find_closer_edge(v->nv.v->co, frep_e1, frep_e2);
+ BLI_array_append(ve, n > 0 ? frep_e : NULL);
+ }
+ else {
+ BLI_array_append(vf, boundvert_rep_face(v, NULL));
+ BLI_array_append(ve, NULL);
+ }
+ n++;
+ if (v->ebev && v->ebev->seg > 1) {
+ for (k = 1; k < v->ebev->seg; k++) {
+ BLI_array_append(vv, mesh_vert(vm, v->index, 0, k)->v);
+ if (frep) {
+ BLI_array_append(vf, frep);
+ frep_e = find_closer_edge(mesh_vert(vm, v->index, 0, k)->v->co, frep_e1, frep_e2);
+ BLI_array_append(ve, k < v->ebev->seg / 2 ? NULL : frep_e);
+ }
+ else {
+ BLI_array_append(vf, boundvert_rep_face(v, NULL));
+ BLI_array_append(ve, NULL);
+ }
+ n++;
+ }
+ }
+ } while ((v = v->next) != vm->boundstart);
+ if (n > 2) {
+ f = bev_create_ngon(bm, vv, n, vf, frep, ve, bp->mat_nr, true);
+ record_face_kind(bp, f, F_VERT);
+ }
+ else {
+ f = NULL;
+ }
+ BLI_array_free(vv);
+ BLI_array_free(vf);
+ BLI_array_free(ve);
+ return f;
}
static void bevel_build_trifan(BevelParams *bp, BMesh *bm, BevVert *bv)
{
- BMFace *f;
- BLI_assert(next_bev(bv, NULL)->seg == 1 || bv->selcount == 1);
-
- f = bevel_build_poly(bp, bm, bv);
-
- if (f) {
- /* we have a polygon which we know starts at the previous vertex, make it into a fan */
- BMLoop *l_fan = BM_FACE_FIRST_LOOP(f)->prev;
- BMVert *v_fan = l_fan->v;
-
- while (f->len > 3) {
- BMLoop *l_new;
- BMFace *f_new;
- BLI_assert(v_fan == l_fan->v);
- f_new = BM_face_split(bm, f, l_fan, l_fan->next->next, &l_new, NULL, false);
- flag_out_edge(bm, l_new->e);
-
- if (f_new->len > f->len) {
- f = f_new;
- if (l_new->v == v_fan) { l_fan = l_new; }
- else if (l_new->next->v == v_fan) { l_fan = l_new->next; }
- else if (l_new->prev->v == v_fan) { l_fan = l_new->prev; }
- else { BLI_assert(0); }
- }
- else {
- if (l_fan->v == v_fan) { /* l_fan = l_fan; */ }
- else if (l_fan->next->v == v_fan) { l_fan = l_fan->next; }
- else if (l_fan->prev->v == v_fan) { l_fan = l_fan->prev; }
- else { BLI_assert(0); }
- }
- record_face_kind(bp, f_new, F_VERT);
- }
- }
+ BMFace *f;
+ BLI_assert(next_bev(bv, NULL)->seg == 1 || bv->selcount == 1);
+
+ f = bevel_build_poly(bp, bm, bv);
+
+ if (f) {
+ /* we have a polygon which we know starts at the previous vertex, make it into a fan */
+ BMLoop *l_fan = BM_FACE_FIRST_LOOP(f)->prev;
+ BMVert *v_fan = l_fan->v;
+
+ while (f->len > 3) {
+ BMLoop *l_new;
+ BMFace *f_new;
+ BLI_assert(v_fan == l_fan->v);
+ f_new = BM_face_split(bm, f, l_fan, l_fan->next->next, &l_new, NULL, false);
+ flag_out_edge(bm, l_new->e);
+
+ if (f_new->len > f->len) {
+ f = f_new;
+ if (l_new->v == v_fan) {
+ l_fan = l_new;
+ }
+ else if (l_new->next->v == v_fan) {
+ l_fan = l_new->next;
+ }
+ else if (l_new->prev->v == v_fan) {
+ l_fan = l_new->prev;
+ }
+ else {
+ BLI_assert(0);
+ }
+ }
+ else {
+ if (l_fan->v == v_fan) { /* l_fan = l_fan; */
+ }
+ else if (l_fan->next->v == v_fan) {
+ l_fan = l_fan->next;
+ }
+ else if (l_fan->prev->v == v_fan) {
+ l_fan = l_fan->prev;
+ }
+ else {
+ BLI_assert(0);
+ }
+ }
+ record_face_kind(bp, f_new, F_VERT);
+ }
+ }
}
/* Special case: vertex bevel with only two boundary verts.
@@ -4664,183 +4728,179 @@ static void bevel_build_trifan(BevelParams *bp, BMesh *bm, BevVert *bv)
* we have to make it here. */
static void bevel_vert_two_edges(BevelParams *bp, BMesh *bm, BevVert *bv)
{
- VMesh *vm = bv->vmesh;
- BMVert *v1, *v2;
- BMEdge *e_eg, *bme;
- Profile *pro;
- float co[3];
- BoundVert *bndv;
- int ns, k;
-
- BLI_assert(vm->count == 2 && bp->vertex_only);
-
- v1 = mesh_vert(vm, 0, 0, 0)->v;
- v2 = mesh_vert(vm, 1, 0, 0)->v;
-
- ns = vm->seg;
- if (ns > 1) {
- /* Set up profile parameters */
- bndv = vm->boundstart;
- pro = &bndv->profile;
- pro->super_r = bp->pro_super_r;
- copy_v3_v3(pro->coa, v1->co);
- copy_v3_v3(pro->cob, v2->co);
- copy_v3_v3(pro->midco, bv->v->co);
- /* don't use projection */
- zero_v3(pro->plane_co);
- zero_v3(pro->plane_no);
- zero_v3(pro->proj_dir);
- calculate_profile(bp, bndv);
- for (k = 1; k < ns; k++) {
- get_profile_point(bp, pro, k, ns, co);
- copy_v3_v3(mesh_vert(vm, 0, 0, k)->co, co);
- create_mesh_bmvert(bm, vm, 0, 0, k, bv->v);
- }
- copy_v3_v3(mesh_vert(vm, 0, 0, ns)->co, v2->co);
- for (k = 1; k < ns; k++) {
- copy_mesh_vert(vm, 1, 0, ns - k, 0, 0, k);
- }
- }
-
- if (BM_vert_face_check(bv->v) == false) {
- e_eg = bv->edges[0].e;
- BLI_assert(e_eg != NULL);
- for (k = 0; k < ns; k++) {
- v1 = mesh_vert(vm, 0, 0, k)->v;
- v2 = mesh_vert(vm, 0, 0, k + 1)->v;
- BLI_assert(v1 != NULL && v2 != NULL);
- bme = BM_edge_create(bm, v1, v2, e_eg, BM_CREATE_NO_DOUBLE);
- if (bme) {
- flag_out_edge(bm, bme);
- }
- }
- }
+ VMesh *vm = bv->vmesh;
+ BMVert *v1, *v2;
+ BMEdge *e_eg, *bme;
+ Profile *pro;
+ float co[3];
+ BoundVert *bndv;
+ int ns, k;
+
+ BLI_assert(vm->count == 2 && bp->vertex_only);
+
+ v1 = mesh_vert(vm, 0, 0, 0)->v;
+ v2 = mesh_vert(vm, 1, 0, 0)->v;
+
+ ns = vm->seg;
+ if (ns > 1) {
+ /* Set up profile parameters */
+ bndv = vm->boundstart;
+ pro = &bndv->profile;
+ pro->super_r = bp->pro_super_r;
+ copy_v3_v3(pro->coa, v1->co);
+ copy_v3_v3(pro->cob, v2->co);
+ copy_v3_v3(pro->midco, bv->v->co);
+ /* don't use projection */
+ zero_v3(pro->plane_co);
+ zero_v3(pro->plane_no);
+ zero_v3(pro->proj_dir);
+ calculate_profile(bp, bndv);
+ for (k = 1; k < ns; k++) {
+ get_profile_point(bp, pro, k, ns, co);
+ copy_v3_v3(mesh_vert(vm, 0, 0, k)->co, co);
+ create_mesh_bmvert(bm, vm, 0, 0, k, bv->v);
+ }
+ copy_v3_v3(mesh_vert(vm, 0, 0, ns)->co, v2->co);
+ for (k = 1; k < ns; k++) {
+ copy_mesh_vert(vm, 1, 0, ns - k, 0, 0, k);
+ }
+ }
+
+ if (BM_vert_face_check(bv->v) == false) {
+ e_eg = bv->edges[0].e;
+ BLI_assert(e_eg != NULL);
+ for (k = 0; k < ns; k++) {
+ v1 = mesh_vert(vm, 0, 0, k)->v;
+ v2 = mesh_vert(vm, 0, 0, k + 1)->v;
+ BLI_assert(v1 != NULL && v2 != NULL);
+ bme = BM_edge_create(bm, v1, v2, e_eg, BM_CREATE_NO_DOUBLE);
+ if (bme) {
+ flag_out_edge(bm, bme);
+ }
+ }
+ }
}
/* Given that the boundary is built, now make the actual BMVerts
* for the boundary and the interior of the vertex mesh. */
static void build_vmesh(BevelParams *bp, BMesh *bm, BevVert *bv)
{
- MemArena *mem_arena = bp->mem_arena;
- VMesh *vm = bv->vmesh;
- BoundVert *v, *weld1, *weld2;
- int n, ns, ns2, i, k, weld;
- float *va, *vb, co[3];
-
- n = vm->count;
- ns = vm->seg;
- ns2 = ns / 2;
-
- vm->mesh = (NewVert *)BLI_memarena_alloc(mem_arena, n * (ns2 + 1) * (ns + 1) * sizeof(NewVert));
-
- /* special case: two beveled ends welded together */
- weld = (bv->selcount == 2) && (vm->count == 2);
- weld1 = weld2 = NULL; /* will hold two BoundVerts involved in weld */
-
- /* make (i, 0, 0) mesh verts for all i */
- v = vm->boundstart;
- do {
- i = v->index;
- copy_v3_v3(mesh_vert(vm, i, 0, 0)->co, v->nv.co);
- create_mesh_bmvert(bm, vm, i, 0, 0, bv->v);
- v->nv.v = mesh_vert(vm, i, 0, 0)->v;
- if (weld && v->ebev) {
- if (!weld1) {
- weld1 = v;
- }
- else {
- weld2 = v;
- move_weld_profile_planes(bv, weld1, weld2);
- calculate_profile(bp, weld1);
- calculate_profile(bp, weld2);
- }
- }
- } while ((v = v->next) != vm->boundstart);
-
- /* copy other ends to (i, 0, ns) for all i, and fill in profiles for edges */
- v = vm->boundstart;
- do {
- i = v->index;
- copy_mesh_vert(vm, i, 0, ns, v->next->index, 0, 0);
- for (k = 1; k < ns; k++) {
- if (v->ebev && vm->mesh_kind != M_ADJ) {
- get_profile_point(bp, &v->profile, k, ns, co);
- copy_v3_v3(mesh_vert(vm, i, 0, k)->co, co);
- if (!weld) {
- create_mesh_bmvert(bm, vm, i, 0, k, bv->v);
- }
- }
- else if (n == 2 && !v->ebev && vm->mesh_kind != M_ADJ) {
- /* case of one edge beveled and this is the v without ebev */
- /* want to copy the verts from other v, in reverse order */
- copy_mesh_vert(vm, i, 0, k, 1 - i, 0, ns - k);
- }
- }
- } while ((v = v->next) != vm->boundstart);
-
- if (weld) {
- vm->mesh_kind = M_NONE;
- for (k = 1; k < ns; k++) {
- va = mesh_vert(vm, weld1->index, 0, k)->co;
- vb = mesh_vert(vm, weld2->index, 0, ns - k)->co;
- /* if one of the profiles is on a flat plane,
- * just use the boundary point of the other */
- if (weld1->profile.super_r == PRO_LINE_R &&
- weld2->profile.super_r != PRO_LINE_R)
- {
- copy_v3_v3(co, vb);
- }
- else if (weld2->profile.super_r == PRO_LINE_R &&
- weld1->profile.super_r != PRO_LINE_R)
- {
- copy_v3_v3(co, va);
- }
- else {
- mid_v3_v3v3(co, va, vb);
- }
- copy_v3_v3(mesh_vert(vm, weld1->index, 0, k)->co, co);
- create_mesh_bmvert(bm, vm, weld1->index, 0, k, bv->v);
- }
- for (k = 1; k < ns; k++) {
- copy_mesh_vert(vm, weld2->index, 0, ns - k, weld1->index, 0, k);
- }
- }
-
- switch (vm->mesh_kind) {
- case M_NONE:
- if (n == 2 && bp->vertex_only) {
- bevel_vert_two_edges(bp, bm, bv);
- }
- break;
- case M_POLY:
- bevel_build_poly(bp, bm, bv);
- break;
- case M_ADJ:
- bevel_build_rings(bp, bm, bv);
- break;
- case M_TRI_FAN:
- bevel_build_trifan(bp, bm, bv);
- break;
- }
+ MemArena *mem_arena = bp->mem_arena;
+ VMesh *vm = bv->vmesh;
+ BoundVert *v, *weld1, *weld2;
+ int n, ns, ns2, i, k, weld;
+ float *va, *vb, co[3];
+
+ n = vm->count;
+ ns = vm->seg;
+ ns2 = ns / 2;
+
+ vm->mesh = (NewVert *)BLI_memarena_alloc(mem_arena, n * (ns2 + 1) * (ns + 1) * sizeof(NewVert));
+
+ /* special case: two beveled ends welded together */
+ weld = (bv->selcount == 2) && (vm->count == 2);
+ weld1 = weld2 = NULL; /* will hold two BoundVerts involved in weld */
+
+ /* make (i, 0, 0) mesh verts for all i */
+ v = vm->boundstart;
+ do {
+ i = v->index;
+ copy_v3_v3(mesh_vert(vm, i, 0, 0)->co, v->nv.co);
+ create_mesh_bmvert(bm, vm, i, 0, 0, bv->v);
+ v->nv.v = mesh_vert(vm, i, 0, 0)->v;
+ if (weld && v->ebev) {
+ if (!weld1) {
+ weld1 = v;
+ }
+ else {
+ weld2 = v;
+ move_weld_profile_planes(bv, weld1, weld2);
+ calculate_profile(bp, weld1);
+ calculate_profile(bp, weld2);
+ }
+ }
+ } while ((v = v->next) != vm->boundstart);
+
+ /* copy other ends to (i, 0, ns) for all i, and fill in profiles for edges */
+ v = vm->boundstart;
+ do {
+ i = v->index;
+ copy_mesh_vert(vm, i, 0, ns, v->next->index, 0, 0);
+ for (k = 1; k < ns; k++) {
+ if (v->ebev && vm->mesh_kind != M_ADJ) {
+ get_profile_point(bp, &v->profile, k, ns, co);
+ copy_v3_v3(mesh_vert(vm, i, 0, k)->co, co);
+ if (!weld) {
+ create_mesh_bmvert(bm, vm, i, 0, k, bv->v);
+ }
+ }
+ else if (n == 2 && !v->ebev && vm->mesh_kind != M_ADJ) {
+ /* case of one edge beveled and this is the v without ebev */
+ /* want to copy the verts from other v, in reverse order */
+ copy_mesh_vert(vm, i, 0, k, 1 - i, 0, ns - k);
+ }
+ }
+ } while ((v = v->next) != vm->boundstart);
+
+ if (weld) {
+ vm->mesh_kind = M_NONE;
+ for (k = 1; k < ns; k++) {
+ va = mesh_vert(vm, weld1->index, 0, k)->co;
+ vb = mesh_vert(vm, weld2->index, 0, ns - k)->co;
+ /* if one of the profiles is on a flat plane,
+ * just use the boundary point of the other */
+ if (weld1->profile.super_r == PRO_LINE_R && weld2->profile.super_r != PRO_LINE_R) {
+ copy_v3_v3(co, vb);
+ }
+ else if (weld2->profile.super_r == PRO_LINE_R && weld1->profile.super_r != PRO_LINE_R) {
+ copy_v3_v3(co, va);
+ }
+ else {
+ mid_v3_v3v3(co, va, vb);
+ }
+ copy_v3_v3(mesh_vert(vm, weld1->index, 0, k)->co, co);
+ create_mesh_bmvert(bm, vm, weld1->index, 0, k, bv->v);
+ }
+ for (k = 1; k < ns; k++) {
+ copy_mesh_vert(vm, weld2->index, 0, ns - k, weld1->index, 0, k);
+ }
+ }
+
+ switch (vm->mesh_kind) {
+ case M_NONE:
+ if (n == 2 && bp->vertex_only) {
+ bevel_vert_two_edges(bp, bm, bv);
+ }
+ break;
+ case M_POLY:
+ bevel_build_poly(bp, bm, bv);
+ break;
+ case M_ADJ:
+ bevel_build_rings(bp, bm, bv);
+ break;
+ case M_TRI_FAN:
+ bevel_build_trifan(bp, bm, bv);
+ break;
+ }
}
/* Return the angle between the two faces adjacent to e.
* If there are not two, return 0. */
static float edge_face_angle(EdgeHalf *e)
{
- if (e->fprev && e->fnext) {
- /* angle between faces is supplement of angle between face normals */
- return (float)M_PI - angle_normalized_v3v3(e->fprev->no, e->fnext->no);
- }
- else {
- return 0.0f;
- }
+ if (e->fprev && e->fnext) {
+ /* angle between faces is supplement of angle between face normals */
+ return (float)M_PI - angle_normalized_v3v3(e->fprev->no, e->fnext->no);
+ }
+ else {
+ return 0.0f;
+ }
}
/* take care, this flag isn't cleared before use, it just so happens that its not set */
-#define BM_BEVEL_EDGE_TAG_ENABLE(bme) BM_ELEM_API_FLAG_ENABLE( (bme), _FLAG_OVERLAP)
-#define BM_BEVEL_EDGE_TAG_DISABLE(bme) BM_ELEM_API_FLAG_DISABLE( (bme), _FLAG_OVERLAP)
-#define BM_BEVEL_EDGE_TAG_TEST(bme) BM_ELEM_API_FLAG_TEST( (bme), _FLAG_OVERLAP)
+#define BM_BEVEL_EDGE_TAG_ENABLE(bme) BM_ELEM_API_FLAG_ENABLE((bme), _FLAG_OVERLAP)
+#define BM_BEVEL_EDGE_TAG_DISABLE(bme) BM_ELEM_API_FLAG_DISABLE((bme), _FLAG_OVERLAP)
+#define BM_BEVEL_EDGE_TAG_TEST(bme) BM_ELEM_API_FLAG_TEST((bme), _FLAG_OVERLAP)
/* Try to extend the bv->edges[] array beyond i by finding more successor edges.
* This is a possibly exponential-time search, but it is only exponential in the number
@@ -4851,59 +4911,60 @@ static float edge_face_angle(EdgeHalf *e)
* The path will have the tags of all of its edges set. */
static int bevel_edge_order_extend(BMesh *bm, BevVert *bv, int i)
{
- BMEdge *bme, *bme2, *nextbme;
- BMLoop *l;
- BMIter iter;
- int j, tryj, bestj, nsucs, sucindex, k;
- BMEdge **sucs = NULL;
- BMEdge **save_path = NULL;
- BLI_array_staticdeclare(sucs, 4); /* likely very few faces attached to same edge */
- BLI_array_staticdeclare(save_path, BM_DEFAULT_NGON_STACK_SIZE);
-
- bme = bv->edges[i].e;
- /* fill sucs with all unmarked edges of bmes */
- BM_ITER_ELEM(l, &iter, bme, BM_LOOPS_OF_EDGE) {
- bme2 = (l->v == bv->v) ? l->prev->e : l->next->e;
- if (!BM_BEVEL_EDGE_TAG_TEST(bme2)) {
- BLI_array_append(sucs, bme2);
- }
- }
- nsucs = BLI_array_len(sucs);
-
- bestj = j = i;
- for (sucindex = 0; sucindex < nsucs; sucindex++) {
- nextbme = sucs[sucindex];
- BLI_assert(nextbme != NULL);
- BLI_assert(!BM_BEVEL_EDGE_TAG_TEST(nextbme));
- BLI_assert(j + 1 < bv->edgecount);
- bv->edges[j + 1].e = nextbme;
- BM_BEVEL_EDGE_TAG_ENABLE(nextbme);
- tryj = bevel_edge_order_extend(bm, bv, j + 1);
- if (tryj > bestj || (tryj == bestj && edges_face_connected_at_vert(bv->edges[tryj].e, bv->edges[0].e))) {
- bestj = tryj;
- BLI_array_clear(save_path);
- for (k = j + 1; k <= bestj; k++) {
- BLI_array_append(save_path, bv->edges[k].e);
- }
- }
- /* now reset to path only-going-to-j state */
- for (k = j + 1; k <= tryj; k++) {
- BM_BEVEL_EDGE_TAG_DISABLE(bv->edges[k].e);
- bv->edges[k].e = NULL;
- }
- }
- /* at this point we should be back at invariant on entrance: path up to j */
- if (bestj > j) {
- /* save_path should have from j + 1 to bestj inclusive edges to add to edges[] before returning */
- for (k = j + 1; k <= bestj; k++) {
- BLI_assert(save_path[k - (j + 1)] != NULL);
- bv->edges[k].e = save_path[k - (j + 1)];
- BM_BEVEL_EDGE_TAG_ENABLE(bv->edges[k].e);
- }
- }
- BLI_array_free(sucs);
- BLI_array_free(save_path);
- return bestj;
+ BMEdge *bme, *bme2, *nextbme;
+ BMLoop *l;
+ BMIter iter;
+ int j, tryj, bestj, nsucs, sucindex, k;
+ BMEdge **sucs = NULL;
+ BMEdge **save_path = NULL;
+ BLI_array_staticdeclare(sucs, 4); /* likely very few faces attached to same edge */
+ BLI_array_staticdeclare(save_path, BM_DEFAULT_NGON_STACK_SIZE);
+
+ bme = bv->edges[i].e;
+ /* fill sucs with all unmarked edges of bmes */
+ BM_ITER_ELEM (l, &iter, bme, BM_LOOPS_OF_EDGE) {
+ bme2 = (l->v == bv->v) ? l->prev->e : l->next->e;
+ if (!BM_BEVEL_EDGE_TAG_TEST(bme2)) {
+ BLI_array_append(sucs, bme2);
+ }
+ }
+ nsucs = BLI_array_len(sucs);
+
+ bestj = j = i;
+ for (sucindex = 0; sucindex < nsucs; sucindex++) {
+ nextbme = sucs[sucindex];
+ BLI_assert(nextbme != NULL);
+ BLI_assert(!BM_BEVEL_EDGE_TAG_TEST(nextbme));
+ BLI_assert(j + 1 < bv->edgecount);
+ bv->edges[j + 1].e = nextbme;
+ BM_BEVEL_EDGE_TAG_ENABLE(nextbme);
+ tryj = bevel_edge_order_extend(bm, bv, j + 1);
+ if (tryj > bestj ||
+ (tryj == bestj && edges_face_connected_at_vert(bv->edges[tryj].e, bv->edges[0].e))) {
+ bestj = tryj;
+ BLI_array_clear(save_path);
+ for (k = j + 1; k <= bestj; k++) {
+ BLI_array_append(save_path, bv->edges[k].e);
+ }
+ }
+ /* now reset to path only-going-to-j state */
+ for (k = j + 1; k <= tryj; k++) {
+ BM_BEVEL_EDGE_TAG_DISABLE(bv->edges[k].e);
+ bv->edges[k].e = NULL;
+ }
+ }
+ /* at this point we should be back at invariant on entrance: path up to j */
+ if (bestj > j) {
+ /* save_path should have from j + 1 to bestj inclusive edges to add to edges[] before returning */
+ for (k = j + 1; k <= bestj; k++) {
+ BLI_assert(save_path[k - (j + 1)] != NULL);
+ bv->edges[k].e = save_path[k - (j + 1)];
+ BM_BEVEL_EDGE_TAG_ENABLE(bv->edges[k].e);
+ }
+ }
+ BLI_array_free(sucs);
+ BLI_array_free(save_path);
+ return bestj;
}
/* See if we have usual case for bevel edge order:
@@ -4920,90 +4981,89 @@ static int bevel_edge_order_extend(BMesh *bm, BevVert *bv, int i)
* so for now will continue to use the legacy code. */
static bool fast_bevel_edge_order(BevVert *bv)
{
- int j, k, nsucs;
- BMEdge *bme, *bme2, *bmenext;
- BMIter iter;
- BMLoop *l;
-
- for (j = 1; j < bv->edgecount; j++) {
- bme = bv->edges[j - 1].e;
- bmenext = NULL;
- nsucs = 0;
- BM_ITER_ELEM(l, &iter, bme, BM_LOOPS_OF_EDGE) {
- bme2 = (l->v == bv->v) ? l->prev->e : l->next->e;
- if (!BM_BEVEL_EDGE_TAG_TEST(bme2)) {
- nsucs++;
- if (bmenext == NULL) {
- bmenext = bme2;
- }
- }
- }
- if (nsucs == 0 || (nsucs == 2 && j != 1) || nsucs > 2 ||
- (j == bv->edgecount - 1 && !edges_face_connected_at_vert(bmenext, bv->edges[0].e)))
- {
- for (k = 1; k < j; k++) {
- BM_BEVEL_EDGE_TAG_DISABLE(bv->edges[k].e);
- bv->edges[k].e = NULL;
- }
- return false;
- }
- bv->edges[j].e = bmenext;
- BM_BEVEL_EDGE_TAG_ENABLE(bmenext);
- }
- return true;
+ int j, k, nsucs;
+ BMEdge *bme, *bme2, *bmenext;
+ BMIter iter;
+ BMLoop *l;
+
+ for (j = 1; j < bv->edgecount; j++) {
+ bme = bv->edges[j - 1].e;
+ bmenext = NULL;
+ nsucs = 0;
+ BM_ITER_ELEM (l, &iter, bme, BM_LOOPS_OF_EDGE) {
+ bme2 = (l->v == bv->v) ? l->prev->e : l->next->e;
+ if (!BM_BEVEL_EDGE_TAG_TEST(bme2)) {
+ nsucs++;
+ if (bmenext == NULL) {
+ bmenext = bme2;
+ }
+ }
+ }
+ if (nsucs == 0 || (nsucs == 2 && j != 1) || nsucs > 2 ||
+ (j == bv->edgecount - 1 && !edges_face_connected_at_vert(bmenext, bv->edges[0].e))) {
+ for (k = 1; k < j; k++) {
+ BM_BEVEL_EDGE_TAG_DISABLE(bv->edges[k].e);
+ bv->edges[k].e = NULL;
+ }
+ return false;
+ }
+ bv->edges[j].e = bmenext;
+ BM_BEVEL_EDGE_TAG_ENABLE(bmenext);
+ }
+ return true;
}
#else
static bool fast_bevel_edge_order(BevVert *bv)
{
- BMEdge *bme, *bme2, *first_suc;
- BMIter iter, iter2;
- BMFace *f;
- EdgeHalf *e;
- int i, k, ntot, num_shared_face;
-
- ntot = bv->edgecount;
-
- /* add edges to bv->edges in order that keeps adjacent edges sharing
- * a unique face, if possible */
- e = &bv->edges[0];
- bme = e->e;
- if (!bme->l) {
- return false;
- }
- for (i = 1; i < ntot; i++) {
- /* find an unflagged edge bme2 that shares a face f with previous bme */
- num_shared_face = 0;
- first_suc = NULL; /* keep track of first successor to match legacy behavior */
- BM_ITER_ELEM (bme2, &iter, bv->v, BM_EDGES_OF_VERT) {
- if (BM_BEVEL_EDGE_TAG_TEST(bme2)) {
- continue;
- }
- BM_ITER_ELEM (f, &iter2, bme2, BM_FACES_OF_EDGE) {
- if (BM_face_edge_share_loop(f, bme)) {
- num_shared_face++;
- if (first_suc == NULL) {
- first_suc = bme2;
- }
- }
- }
- if (num_shared_face >= 3) {
- break;
- }
- }
- if (num_shared_face == 1 || (i == 1 && num_shared_face == 2)) {
- e = &bv->edges[i];
- e->e = bme = first_suc;
- BM_BEVEL_EDGE_TAG_ENABLE(bme);
- }
- else {
- for (k = 1; k < i; k++) {
- BM_BEVEL_EDGE_TAG_DISABLE(bv->edges[k].e);
- bv->edges[k].e = NULL;
- }
- return false;
- }
- }
- return true;
+ BMEdge *bme, *bme2, *first_suc;
+ BMIter iter, iter2;
+ BMFace *f;
+ EdgeHalf *e;
+ int i, k, ntot, num_shared_face;
+
+ ntot = bv->edgecount;
+
+ /* add edges to bv->edges in order that keeps adjacent edges sharing
+ * a unique face, if possible */
+ e = &bv->edges[0];
+ bme = e->e;
+ if (!bme->l) {
+ return false;
+ }
+ for (i = 1; i < ntot; i++) {
+ /* find an unflagged edge bme2 that shares a face f with previous bme */
+ num_shared_face = 0;
+ first_suc = NULL; /* keep track of first successor to match legacy behavior */
+ BM_ITER_ELEM (bme2, &iter, bv->v, BM_EDGES_OF_VERT) {
+ if (BM_BEVEL_EDGE_TAG_TEST(bme2)) {
+ continue;
+ }
+ BM_ITER_ELEM (f, &iter2, bme2, BM_FACES_OF_EDGE) {
+ if (BM_face_edge_share_loop(f, bme)) {
+ num_shared_face++;
+ if (first_suc == NULL) {
+ first_suc = bme2;
+ }
+ }
+ }
+ if (num_shared_face >= 3) {
+ break;
+ }
+ }
+ if (num_shared_face == 1 || (i == 1 && num_shared_face == 2)) {
+ e = &bv->edges[i];
+ e->e = bme = first_suc;
+ BM_BEVEL_EDGE_TAG_ENABLE(bme);
+ }
+ else {
+ for (k = 1; k < i; k++) {
+ BM_BEVEL_EDGE_TAG_DISABLE(bv->edges[k].e);
+ bv->edges[k].e = NULL;
+ }
+ return false;
+ }
+ }
+ return true;
}
#endif
@@ -5013,69 +5073,69 @@ static bool fast_bevel_edge_order(BevVert *bv)
* first_bme is a good edge to start with.*/
static void find_bevel_edge_order(BMesh *bm, BevVert *bv, BMEdge *first_bme)
{
- BMEdge *bme, *bme2;
- BMIter iter;
- BMFace *f, *bestf;
- EdgeHalf *e;
- EdgeHalf *e2;
- BMLoop *l;
- int i, ntot;
-
- ntot = bv->edgecount;
- i = 0;
- for (;;) {
- BLI_assert(first_bme != NULL);
- bv->edges[i].e = first_bme;
- BM_BEVEL_EDGE_TAG_ENABLE(first_bme);
- if (i == 0 && fast_bevel_edge_order(bv)) {
- break;
- }
- i = bevel_edge_order_extend(bm, bv, i);
- i++;
- if (i >= bv->edgecount) {
- break;
- }
- /* Not done yet: find a new first_bme */
- first_bme = NULL;
- BM_ITER_ELEM(bme, &iter, bv->v, BM_EDGES_OF_VERT) {
- if (BM_BEVEL_EDGE_TAG_TEST(bme)) {
- continue;
- }
- if (!first_bme) {
- first_bme = bme;
- }
- if (BM_edge_face_count(bme) == 1) {
- first_bme = bme;
- break;
- }
- }
- }
- /* now fill in the faces ... */
- for (i = 0; i < ntot; i++) {
- e = &bv->edges[i];
- e2 = (i == bv->edgecount - 1) ? &bv->edges[0] : &bv->edges[i + 1];
- bme = e->e;
- bme2 = e2->e;
- BLI_assert(bme != NULL);
- if (e->fnext != NULL || e2->fprev != NULL) {
- continue;
- }
- /* Which faces have successive loops that are for bme and bme2?
- * There could be more than one. E.g., in manifold ntot==2 case.
- * Prefer one that has loop in same direction as e. */
- bestf = NULL;
- BM_ITER_ELEM(l, &iter, bme, BM_LOOPS_OF_EDGE) {
- f = l->f;
- if ((l->prev->e == bme2 || l->next->e == bme2)) {
- if (!bestf || l->v == bv->v) {
- bestf = f;
- }
- }
- if (bestf) {
- e->fnext = e2->fprev = bestf;
- }
- }
- }
+ BMEdge *bme, *bme2;
+ BMIter iter;
+ BMFace *f, *bestf;
+ EdgeHalf *e;
+ EdgeHalf *e2;
+ BMLoop *l;
+ int i, ntot;
+
+ ntot = bv->edgecount;
+ i = 0;
+ for (;;) {
+ BLI_assert(first_bme != NULL);
+ bv->edges[i].e = first_bme;
+ BM_BEVEL_EDGE_TAG_ENABLE(first_bme);
+ if (i == 0 && fast_bevel_edge_order(bv)) {
+ break;
+ }
+ i = bevel_edge_order_extend(bm, bv, i);
+ i++;
+ if (i >= bv->edgecount) {
+ break;
+ }
+ /* Not done yet: find a new first_bme */
+ first_bme = NULL;
+ BM_ITER_ELEM (bme, &iter, bv->v, BM_EDGES_OF_VERT) {
+ if (BM_BEVEL_EDGE_TAG_TEST(bme)) {
+ continue;
+ }
+ if (!first_bme) {
+ first_bme = bme;
+ }
+ if (BM_edge_face_count(bme) == 1) {
+ first_bme = bme;
+ break;
+ }
+ }
+ }
+ /* now fill in the faces ... */
+ for (i = 0; i < ntot; i++) {
+ e = &bv->edges[i];
+ e2 = (i == bv->edgecount - 1) ? &bv->edges[0] : &bv->edges[i + 1];
+ bme = e->e;
+ bme2 = e2->e;
+ BLI_assert(bme != NULL);
+ if (e->fnext != NULL || e2->fprev != NULL) {
+ continue;
+ }
+ /* Which faces have successive loops that are for bme and bme2?
+ * There could be more than one. E.g., in manifold ntot==2 case.
+ * Prefer one that has loop in same direction as e. */
+ bestf = NULL;
+ BM_ITER_ELEM (l, &iter, bme, BM_LOOPS_OF_EDGE) {
+ f = l->f;
+ if ((l->prev->e == bme2 || l->next->e == bme2)) {
+ if (!bestf || l->v == bv->v) {
+ bestf = f;
+ }
+ }
+ if (bestf) {
+ e->fnext = e2->fprev = bestf;
+ }
+ }
+ }
}
/*
@@ -5083,540 +5143,537 @@ static void find_bevel_edge_order(BMesh *bm, BevVert *bv, BMEdge *first_bme)
*/
static BevVert *bevel_vert_construct(BMesh *bm, BevelParams *bp, BMVert *v)
{
- BMEdge *bme;
- BevVert *bv;
- BMEdge *first_bme;
- BMVert *v1, *v2;
- BMIter iter;
- EdgeHalf *e;
- float weight, z;
- int i, ccw_test_sum;
- int nsel = 0;
- int ntot = 0;
- int nwire = 0;
- int fcnt;
-
- /* Gather input selected edges.
- * Only bevel selected edges that have exactly two incident faces.
- * Want edges to be ordered so that they share faces.
- * There may be one or more chains of shared faces broken by
- * gaps where there are no faces.
- * Want to ignore wire edges completely for edge beveling.
- * TODO: make following work when more than one gap.
- */
-
- first_bme = NULL;
- BM_ITER_ELEM (bme, &iter, v, BM_EDGES_OF_VERT) {
- fcnt = BM_edge_face_count(bme);
- BM_BEVEL_EDGE_TAG_DISABLE(bme);
- if (BM_elem_flag_test(bme, BM_ELEM_TAG) && !bp->vertex_only) {
- BLI_assert(fcnt == 2);
- nsel++;
- if (!first_bme) {
- first_bme = bme;
- }
- }
- if (fcnt == 1) {
- /* good to start face chain from this edge */
- first_bme = bme;
- }
- if (fcnt > 0 || bp->vertex_only) {
- ntot++;
- }
- if (BM_edge_is_wire(bme)) {
- nwire++;
- /* If edge beveling, exclude wire edges from edges array.
- * Mark this edge as "chosen" so loop below won't choose it. */
- if (!bp->vertex_only) {
- BM_BEVEL_EDGE_TAG_ENABLE(bme);
- }
- }
- }
- if (!first_bme) {
- first_bme = v->e;
- }
-
- if ((nsel == 0 && !bp->vertex_only) || (ntot < 2 && bp->vertex_only)) {
- /* signal this vert isn't being beveled */
- BM_elem_flag_disable(v, BM_ELEM_TAG);
- return NULL;
- }
-
- bv = (BevVert *)BLI_memarena_alloc(bp->mem_arena, (sizeof(BevVert)));
- bv->v = v;
- bv->edgecount = ntot;
- bv->selcount = nsel;
- bv->wirecount = nwire;
- bv->offset = bp->offset;
- bv->edges = (EdgeHalf *)BLI_memarena_alloc(bp->mem_arena, ntot * sizeof(EdgeHalf));
- if (nwire) {
- bv->wire_edges = (BMEdge **)BLI_memarena_alloc(bp->mem_arena, nwire * sizeof(BMEdge *));
- }
- else {
- bv->wire_edges = NULL;
- }
- bv->vmesh = (VMesh *)BLI_memarena_alloc(bp->mem_arena, sizeof(VMesh));
- bv->vmesh->seg = bp->seg;
-
- if (bp->vertex_only) {
- /* if weighted, modify offset by weight */
- if (bp->dvert != NULL && bp->vertex_group != -1) {
- weight = defvert_find_weight(bp->dvert + BM_elem_index_get(v), bp->vertex_group);
- if (weight <= 0.0f) {
- BM_elem_flag_disable(v, BM_ELEM_TAG);
- return NULL;
- }
- bv->offset *= weight;
- }
- else if (bp->use_weights) {
- weight = BM_elem_float_data_get(&bm->vdata, v, CD_BWEIGHT);
- bv->offset *= weight;
- }
- }
- BLI_ghash_insert(bp->vert_hash, v, bv);
-
- find_bevel_edge_order(bm, bv, first_bme);
-
- /* fill in other attributes of EdgeHalfs */
- for (i = 0; i < ntot; i++) {
- e = &bv->edges[i];
- bme = e->e;
- if (BM_elem_flag_test(bme, BM_ELEM_TAG) && !bp->vertex_only) {
- e->is_bev = true;
- e->seg = bp->seg;
- }
- else {
- e->is_bev = false;
- e->seg = 0;
- }
- e->is_rev = (bme->v2 == v);
- e->leftv = e->rightv = NULL;
- e->profile_index = 0;
- }
-
- /* now done with tag flag */
- BM_ITER_ELEM (bme, &iter, v, BM_EDGES_OF_VERT) {
- BM_BEVEL_EDGE_TAG_DISABLE(bme);
- }
-
- /* if edge array doesn't go CCW around vertex from average normal side,
- * reverse the array, being careful to reverse face pointers too */
- if (ntot > 1) {
- ccw_test_sum = 0;
- for (i = 0; i < ntot; i++) {
- ccw_test_sum += bev_ccw_test(bv->edges[i].e, bv->edges[(i + 1) % ntot].e,
- bv->edges[i].fnext);
- }
- if (ccw_test_sum < 0) {
- for (i = 0; i <= (ntot / 2) - 1; i++) {
- SWAP(EdgeHalf, bv->edges[i], bv->edges[ntot - i - 1]);
- SWAP(BMFace *, bv->edges[i].fprev, bv->edges[i].fnext);
- SWAP(BMFace *, bv->edges[ntot - i - 1].fprev, bv->edges[ntot - i - 1].fnext);
- }
- if (ntot % 2 == 1) {
- i = ntot / 2;
- SWAP(BMFace *, bv->edges[i].fprev, bv->edges[i].fnext);
- }
- }
- }
-
- for (i = 0, e = bv->edges; i < ntot; i++, e++) {
- e->next = &bv->edges[(i + 1) % ntot];
- e->prev = &bv->edges[(i + ntot - 1) % ntot];
-
- /* set offsets */
- if (e->is_bev) {
- /* Convert distance as specified by user into offsets along
- * faces on left side and right side of this edgehalf.
- * Except for percent method, offset will be same on each side. */
-
- switch (bp->offset_type) {
- case BEVEL_AMT_OFFSET:
- e->offset_l_spec = bp->offset;
- break;
- case BEVEL_AMT_WIDTH:
- z = fabsf(2.0f * sinf(edge_face_angle(e) / 2.0f));
- if (z < BEVEL_EPSILON) {
- e->offset_l_spec = 0.01f * bp->offset; /* undefined behavior, so tiny bevel */
- }
- else {
- e->offset_l_spec = bp->offset / z;
- }
- break;
- case BEVEL_AMT_DEPTH:
- z = fabsf(cosf(edge_face_angle(e) / 2.0f));
- if (z < BEVEL_EPSILON) {
- e->offset_l_spec = 0.01f * bp->offset; /* undefined behavior, so tiny bevel */
- }
- else {
- e->offset_l_spec = bp->offset / z;
- }
- break;
- case BEVEL_AMT_PERCENT:
- /* offset needs to be such that it meets adjacent edges at percentage of their lengths */
- v1 = BM_edge_other_vert(e->prev->e, v);
- v2 = BM_edge_other_vert(e->e, v);
- z = sinf(angle_v3v3v3(v1->co, v->co, v2->co));
- e->offset_l_spec = BM_edge_calc_length(e->prev->e) * bp->offset * z / 100.0f;
- v1 = BM_edge_other_vert(e->e, v);
- v2 = BM_edge_other_vert(e->next->e, v);
- z = sinf(angle_v3v3v3(v1->co, v->co, v2->co));
- e->offset_r_spec = BM_edge_calc_length(e->next->e) * bp->offset * z / 100.0f;
- break;
- default:
- BLI_assert(!"bad bevel offset kind");
- e->offset_l_spec = bp->offset;
- break;
- }
- if (bp->offset_type != BEVEL_AMT_PERCENT) {
- e->offset_r_spec = e->offset_l_spec;
- }
- if (bp->use_weights) {
- weight = BM_elem_float_data_get(&bm->edata, e->e, CD_BWEIGHT);
- e->offset_l_spec *= weight;
- e->offset_r_spec *= weight;
- }
- }
- else if (bp->vertex_only) {
- /* Weight has already been applied to bv->offset, if present.
- * Transfer to e->offset_[lr]_spec and treat percent as special case */
- if (bp->offset_type == BEVEL_AMT_PERCENT) {
- v2 = BM_edge_other_vert(e->e, bv->v);
- e->offset_l_spec = BM_edge_calc_length(e->e) * bv->offset / 100.0f;
- }
- else {
- e->offset_l_spec = bv->offset;
- }
- e->offset_r_spec = e->offset_l_spec;
- }
- else {
- e->offset_l_spec = e->offset_r_spec = 0.0f;
- }
- e->offset_l = e->offset_l_spec;
- e->offset_r = e->offset_r_spec;
-
- if (e->fprev && e->fnext) {
- e->is_seam = !contig_ldata_across_edge(bm, e->e, e->fprev, e->fnext);
- }
- else {
- e->is_seam = true;
- }
- }
-
- if (nwire) {
- i = 0;
- BM_ITER_ELEM (bme, &iter, v, BM_EDGES_OF_VERT) {
- if (BM_edge_is_wire(bme)) {
- BLI_assert(i < bv->wirecount);
- bv->wire_edges[i++] = bme;
- }
- }
- BLI_assert(i == bv->wirecount);
- }
-
- return bv;
+ BMEdge *bme;
+ BevVert *bv;
+ BMEdge *first_bme;
+ BMVert *v1, *v2;
+ BMIter iter;
+ EdgeHalf *e;
+ float weight, z;
+ int i, ccw_test_sum;
+ int nsel = 0;
+ int ntot = 0;
+ int nwire = 0;
+ int fcnt;
+
+ /* Gather input selected edges.
+ * Only bevel selected edges that have exactly two incident faces.
+ * Want edges to be ordered so that they share faces.
+ * There may be one or more chains of shared faces broken by
+ * gaps where there are no faces.
+ * Want to ignore wire edges completely for edge beveling.
+ * TODO: make following work when more than one gap.
+ */
+
+ first_bme = NULL;
+ BM_ITER_ELEM (bme, &iter, v, BM_EDGES_OF_VERT) {
+ fcnt = BM_edge_face_count(bme);
+ BM_BEVEL_EDGE_TAG_DISABLE(bme);
+ if (BM_elem_flag_test(bme, BM_ELEM_TAG) && !bp->vertex_only) {
+ BLI_assert(fcnt == 2);
+ nsel++;
+ if (!first_bme) {
+ first_bme = bme;
+ }
+ }
+ if (fcnt == 1) {
+ /* good to start face chain from this edge */
+ first_bme = bme;
+ }
+ if (fcnt > 0 || bp->vertex_only) {
+ ntot++;
+ }
+ if (BM_edge_is_wire(bme)) {
+ nwire++;
+ /* If edge beveling, exclude wire edges from edges array.
+ * Mark this edge as "chosen" so loop below won't choose it. */
+ if (!bp->vertex_only) {
+ BM_BEVEL_EDGE_TAG_ENABLE(bme);
+ }
+ }
+ }
+ if (!first_bme) {
+ first_bme = v->e;
+ }
+
+ if ((nsel == 0 && !bp->vertex_only) || (ntot < 2 && bp->vertex_only)) {
+ /* signal this vert isn't being beveled */
+ BM_elem_flag_disable(v, BM_ELEM_TAG);
+ return NULL;
+ }
+
+ bv = (BevVert *)BLI_memarena_alloc(bp->mem_arena, (sizeof(BevVert)));
+ bv->v = v;
+ bv->edgecount = ntot;
+ bv->selcount = nsel;
+ bv->wirecount = nwire;
+ bv->offset = bp->offset;
+ bv->edges = (EdgeHalf *)BLI_memarena_alloc(bp->mem_arena, ntot * sizeof(EdgeHalf));
+ if (nwire) {
+ bv->wire_edges = (BMEdge **)BLI_memarena_alloc(bp->mem_arena, nwire * sizeof(BMEdge *));
+ }
+ else {
+ bv->wire_edges = NULL;
+ }
+ bv->vmesh = (VMesh *)BLI_memarena_alloc(bp->mem_arena, sizeof(VMesh));
+ bv->vmesh->seg = bp->seg;
+
+ if (bp->vertex_only) {
+ /* if weighted, modify offset by weight */
+ if (bp->dvert != NULL && bp->vertex_group != -1) {
+ weight = defvert_find_weight(bp->dvert + BM_elem_index_get(v), bp->vertex_group);
+ if (weight <= 0.0f) {
+ BM_elem_flag_disable(v, BM_ELEM_TAG);
+ return NULL;
+ }
+ bv->offset *= weight;
+ }
+ else if (bp->use_weights) {
+ weight = BM_elem_float_data_get(&bm->vdata, v, CD_BWEIGHT);
+ bv->offset *= weight;
+ }
+ }
+ BLI_ghash_insert(bp->vert_hash, v, bv);
+
+ find_bevel_edge_order(bm, bv, first_bme);
+
+ /* fill in other attributes of EdgeHalfs */
+ for (i = 0; i < ntot; i++) {
+ e = &bv->edges[i];
+ bme = e->e;
+ if (BM_elem_flag_test(bme, BM_ELEM_TAG) && !bp->vertex_only) {
+ e->is_bev = true;
+ e->seg = bp->seg;
+ }
+ else {
+ e->is_bev = false;
+ e->seg = 0;
+ }
+ e->is_rev = (bme->v2 == v);
+ e->leftv = e->rightv = NULL;
+ e->profile_index = 0;
+ }
+
+ /* now done with tag flag */
+ BM_ITER_ELEM (bme, &iter, v, BM_EDGES_OF_VERT) {
+ BM_BEVEL_EDGE_TAG_DISABLE(bme);
+ }
+
+ /* if edge array doesn't go CCW around vertex from average normal side,
+ * reverse the array, being careful to reverse face pointers too */
+ if (ntot > 1) {
+ ccw_test_sum = 0;
+ for (i = 0; i < ntot; i++) {
+ ccw_test_sum += bev_ccw_test(
+ bv->edges[i].e, bv->edges[(i + 1) % ntot].e, bv->edges[i].fnext);
+ }
+ if (ccw_test_sum < 0) {
+ for (i = 0; i <= (ntot / 2) - 1; i++) {
+ SWAP(EdgeHalf, bv->edges[i], bv->edges[ntot - i - 1]);
+ SWAP(BMFace *, bv->edges[i].fprev, bv->edges[i].fnext);
+ SWAP(BMFace *, bv->edges[ntot - i - 1].fprev, bv->edges[ntot - i - 1].fnext);
+ }
+ if (ntot % 2 == 1) {
+ i = ntot / 2;
+ SWAP(BMFace *, bv->edges[i].fprev, bv->edges[i].fnext);
+ }
+ }
+ }
+
+ for (i = 0, e = bv->edges; i < ntot; i++, e++) {
+ e->next = &bv->edges[(i + 1) % ntot];
+ e->prev = &bv->edges[(i + ntot - 1) % ntot];
+
+ /* set offsets */
+ if (e->is_bev) {
+ /* Convert distance as specified by user into offsets along
+ * faces on left side and right side of this edgehalf.
+ * Except for percent method, offset will be same on each side. */
+
+ switch (bp->offset_type) {
+ case BEVEL_AMT_OFFSET:
+ e->offset_l_spec = bp->offset;
+ break;
+ case BEVEL_AMT_WIDTH:
+ z = fabsf(2.0f * sinf(edge_face_angle(e) / 2.0f));
+ if (z < BEVEL_EPSILON) {
+ e->offset_l_spec = 0.01f * bp->offset; /* undefined behavior, so tiny bevel */
+ }
+ else {
+ e->offset_l_spec = bp->offset / z;
+ }
+ break;
+ case BEVEL_AMT_DEPTH:
+ z = fabsf(cosf(edge_face_angle(e) / 2.0f));
+ if (z < BEVEL_EPSILON) {
+ e->offset_l_spec = 0.01f * bp->offset; /* undefined behavior, so tiny bevel */
+ }
+ else {
+ e->offset_l_spec = bp->offset / z;
+ }
+ break;
+ case BEVEL_AMT_PERCENT:
+ /* offset needs to be such that it meets adjacent edges at percentage of their lengths */
+ v1 = BM_edge_other_vert(e->prev->e, v);
+ v2 = BM_edge_other_vert(e->e, v);
+ z = sinf(angle_v3v3v3(v1->co, v->co, v2->co));
+ e->offset_l_spec = BM_edge_calc_length(e->prev->e) * bp->offset * z / 100.0f;
+ v1 = BM_edge_other_vert(e->e, v);
+ v2 = BM_edge_other_vert(e->next->e, v);
+ z = sinf(angle_v3v3v3(v1->co, v->co, v2->co));
+ e->offset_r_spec = BM_edge_calc_length(e->next->e) * bp->offset * z / 100.0f;
+ break;
+ default:
+ BLI_assert(!"bad bevel offset kind");
+ e->offset_l_spec = bp->offset;
+ break;
+ }
+ if (bp->offset_type != BEVEL_AMT_PERCENT) {
+ e->offset_r_spec = e->offset_l_spec;
+ }
+ if (bp->use_weights) {
+ weight = BM_elem_float_data_get(&bm->edata, e->e, CD_BWEIGHT);
+ e->offset_l_spec *= weight;
+ e->offset_r_spec *= weight;
+ }
+ }
+ else if (bp->vertex_only) {
+ /* Weight has already been applied to bv->offset, if present.
+ * Transfer to e->offset_[lr]_spec and treat percent as special case */
+ if (bp->offset_type == BEVEL_AMT_PERCENT) {
+ v2 = BM_edge_other_vert(e->e, bv->v);
+ e->offset_l_spec = BM_edge_calc_length(e->e) * bv->offset / 100.0f;
+ }
+ else {
+ e->offset_l_spec = bv->offset;
+ }
+ e->offset_r_spec = e->offset_l_spec;
+ }
+ else {
+ e->offset_l_spec = e->offset_r_spec = 0.0f;
+ }
+ e->offset_l = e->offset_l_spec;
+ e->offset_r = e->offset_r_spec;
+
+ if (e->fprev && e->fnext) {
+ e->is_seam = !contig_ldata_across_edge(bm, e->e, e->fprev, e->fnext);
+ }
+ else {
+ e->is_seam = true;
+ }
+ }
+
+ if (nwire) {
+ i = 0;
+ BM_ITER_ELEM (bme, &iter, v, BM_EDGES_OF_VERT) {
+ if (BM_edge_is_wire(bme)) {
+ BLI_assert(i < bv->wirecount);
+ bv->wire_edges[i++] = bme;
+ }
+ }
+ BLI_assert(i == bv->wirecount);
+ }
+
+ return bv;
}
/* Face f has at least one beveled vertex. Rebuild f */
static bool bev_rebuild_polygon(BMesh *bm, BevelParams *bp, BMFace *f)
{
- BMIter liter, eiter, fiter;
- BMLoop *l, *lprev;
- BevVert *bv;
- BoundVert *v, *vstart, *vend;
- EdgeHalf *e, *eprev;
- VMesh *vm;
- int i, k, n, kstart, kend;
- bool do_rebuild = false;
- bool go_ccw, corner3special, keep, on_profile_start;
- BMVert *bmv;
- BMEdge *bme, *bme_new, *bme_prev;
- BMFace *f_new, *f_other;
- BMVert **vv = NULL;
- BMVert **vv_fix = NULL;
- BMEdge **ee = NULL;
- BLI_array_staticdeclare(vv, BM_DEFAULT_NGON_STACK_SIZE);
- BLI_array_staticdeclare(vv_fix, BM_DEFAULT_NGON_STACK_SIZE);
- BLI_array_staticdeclare(ee, BM_DEFAULT_NGON_STACK_SIZE);
-
- BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
- if (BM_elem_flag_test(l->v, BM_ELEM_TAG)) {
- lprev = l->prev;
- bv = find_bevvert(bp, l->v);
- vm = bv->vmesh;
- e = find_edge_half(bv, l->e);
- BLI_assert(e != NULL);
- bme = e->e;
- eprev = find_edge_half(bv, lprev->e);
- BLI_assert(eprev != NULL);
-
- /* which direction around our vertex do we travel to match orientation of f? */
- if (e->prev == eprev) {
- if (eprev->prev == e) {
- /* valence 2 vertex: use f is one of e->fnext or e->fprev to break tie */
- go_ccw = (e->fnext != f);
- }
- else {
- go_ccw = true; /* going ccw around bv to trace this corner */
- }
- }
- else if (eprev->prev == e) {
- go_ccw = false; /* going cw around bv to trace this corner */
- }
- else {
- /* edges in face are non-contiguous in our ordering around bv.
- * Which way should we go when going from eprev to e? */
- if (count_ccw_edges_between(eprev, e) < count_ccw_edges_between(e, eprev)) {
- /* go counterclockewise from eprev to e */
- go_ccw = true;
- }
- else {
- /* go clockwise from eprev to e */
- go_ccw = false;
- }
- }
- on_profile_start = false;
- if (go_ccw) {
- vstart = eprev->rightv;
- vend = e->leftv;
- if (e->profile_index > 0) {
- vstart = vstart->prev;
- on_profile_start = true;
- }
- }
- else {
- vstart = eprev->leftv;
- vend = e->rightv;
- if (eprev->profile_index > 0) {
- vstart = vstart->next;
- on_profile_start = true;
- }
- }
- BLI_assert(vstart != NULL && vend != NULL);
- v = vstart;
- if (!on_profile_start) {
- BLI_array_append(vv, v->nv.v);
- BLI_array_append(ee, bme);
- }
- while (v != vend) {
- /* check for special case: multisegment 3rd face opposite a beveled edge with no vmesh */
- corner3special = (vm->mesh_kind == M_NONE && v->ebev != e && v->ebev != eprev);
- if (go_ccw) {
- i = v->index;
- if (on_profile_start) {
- kstart = e->profile_index;
- on_profile_start = false;
- }
- else {
- kstart = 1;
- }
- if (eprev->rightv == v && eprev->profile_index > 0) {
- kend = eprev->profile_index;
- }
- else {
- kend = vm->seg;
- }
- for (k = kstart; k <= kend; k++) {
- bmv = mesh_vert(vm, i, 0, k)->v;
- if (bmv) {
- BLI_array_append(vv, bmv);
- BLI_array_append(ee, bme); /* TODO: maybe better edge here */
- if (corner3special && v->ebev && !v->ebev->is_seam && k != vm->seg) {
- BLI_array_append(vv_fix, bmv);
- }
- }
- }
- v = v->next;
- }
- else {
- /* going cw */
- i = v->prev->index;
- if (on_profile_start) {
- kstart = eprev->profile_index;
- on_profile_start = false;
- }
- else {
- kstart = vm->seg - 1;
- }
- if (e->rightv == v->prev && e->profile_index > 0) {
- kend = e->profile_index;
- }
- else {
- kend = 0;
- }
- for (k = kstart; k >= kend; k--) {
- bmv = mesh_vert(vm, i, 0, k)->v;
- if (bmv) {
- BLI_array_append(vv, bmv);
- BLI_array_append(ee, bme);
- if (corner3special && v->ebev && !v->ebev->is_seam && k != 0) {
- BLI_array_append(vv_fix, bmv);
- }
- }
- }
- v = v->prev;
- }
- }
- do_rebuild = true;
- }
- else {
- BLI_array_append(vv, l->v);
- BLI_array_append(ee, l->e);
- }
- }
- if (do_rebuild) {
- n = BLI_array_len(vv);
- f_new = bev_create_ngon(bm, vv, n, NULL, f, NULL, -1, true);
-
- for (k = 0; k < BLI_array_len(vv_fix); k++) {
- bev_merge_uvs(bm, vv_fix[k]);
- }
-
- /* copy attributes from old edges */
- BLI_assert(n == BLI_array_len(ee));
- bme_prev = ee[n - 1];
- for (k = 0; k < n; k++) {
- bme_new = BM_edge_exists(vv[k], vv[(k + 1) % n]);
- BLI_assert(ee[k] && bme_new);
- if (ee[k] != bme_new) {
- BM_elem_attrs_copy(bm, bm, ee[k], bme_new);
- /* want to undo seam and smooth for corner segments
- * if those attrs aren't contiguous around face */
- if (k < n - 1 && ee[k] == ee[k + 1]) {
- if (BM_elem_flag_test(ee[k], BM_ELEM_SEAM) &&
- !BM_elem_flag_test(bme_prev, BM_ELEM_SEAM))
- {
- BM_elem_flag_disable(bme_new, BM_ELEM_SEAM);
- }
- /* actually want "sharp" to be contiguous, so reverse the test */
- if (!BM_elem_flag_test(ee[k], BM_ELEM_SMOOTH) &&
- BM_elem_flag_test(bme_prev, BM_ELEM_SMOOTH))
- {
- BM_elem_flag_enable(bme_new, BM_ELEM_SMOOTH);
- }
- }
- else {
- bme_prev = ee[k];
- }
- }
- }
-
- /* don't select newly or return created boundary faces... */
- if (f_new) {
- record_face_kind(bp, f_new, F_RECON);
- BM_elem_flag_disable(f_new, BM_ELEM_TAG);
- /* Also don't want new edges that aren't part of a new bevel face */
- BM_ITER_ELEM(bme, &eiter, f_new, BM_EDGES_OF_FACE) {
- keep = false;
- BM_ITER_ELEM(f_other, &fiter, bme, BM_FACES_OF_EDGE) {
- if (BM_elem_flag_test(f_other, BM_ELEM_TAG)) {
- keep = true;
- break;
- }
- }
- if (!keep) {
- disable_flag_out_edge(bm, bme);
- }
- }
- }
- }
-
- BLI_array_free(vv);
- BLI_array_free(vv_fix);
- BLI_array_free(ee);
- return do_rebuild;
+ BMIter liter, eiter, fiter;
+ BMLoop *l, *lprev;
+ BevVert *bv;
+ BoundVert *v, *vstart, *vend;
+ EdgeHalf *e, *eprev;
+ VMesh *vm;
+ int i, k, n, kstart, kend;
+ bool do_rebuild = false;
+ bool go_ccw, corner3special, keep, on_profile_start;
+ BMVert *bmv;
+ BMEdge *bme, *bme_new, *bme_prev;
+ BMFace *f_new, *f_other;
+ BMVert **vv = NULL;
+ BMVert **vv_fix = NULL;
+ BMEdge **ee = NULL;
+ BLI_array_staticdeclare(vv, BM_DEFAULT_NGON_STACK_SIZE);
+ BLI_array_staticdeclare(vv_fix, BM_DEFAULT_NGON_STACK_SIZE);
+ BLI_array_staticdeclare(ee, BM_DEFAULT_NGON_STACK_SIZE);
+
+ BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
+ if (BM_elem_flag_test(l->v, BM_ELEM_TAG)) {
+ lprev = l->prev;
+ bv = find_bevvert(bp, l->v);
+ vm = bv->vmesh;
+ e = find_edge_half(bv, l->e);
+ BLI_assert(e != NULL);
+ bme = e->e;
+ eprev = find_edge_half(bv, lprev->e);
+ BLI_assert(eprev != NULL);
+
+ /* which direction around our vertex do we travel to match orientation of f? */
+ if (e->prev == eprev) {
+ if (eprev->prev == e) {
+ /* valence 2 vertex: use f is one of e->fnext or e->fprev to break tie */
+ go_ccw = (e->fnext != f);
+ }
+ else {
+ go_ccw = true; /* going ccw around bv to trace this corner */
+ }
+ }
+ else if (eprev->prev == e) {
+ go_ccw = false; /* going cw around bv to trace this corner */
+ }
+ else {
+ /* edges in face are non-contiguous in our ordering around bv.
+ * Which way should we go when going from eprev to e? */
+ if (count_ccw_edges_between(eprev, e) < count_ccw_edges_between(e, eprev)) {
+ /* go counterclockewise from eprev to e */
+ go_ccw = true;
+ }
+ else {
+ /* go clockwise from eprev to e */
+ go_ccw = false;
+ }
+ }
+ on_profile_start = false;
+ if (go_ccw) {
+ vstart = eprev->rightv;
+ vend = e->leftv;
+ if (e->profile_index > 0) {
+ vstart = vstart->prev;
+ on_profile_start = true;
+ }
+ }
+ else {
+ vstart = eprev->leftv;
+ vend = e->rightv;
+ if (eprev->profile_index > 0) {
+ vstart = vstart->next;
+ on_profile_start = true;
+ }
+ }
+ BLI_assert(vstart != NULL && vend != NULL);
+ v = vstart;
+ if (!on_profile_start) {
+ BLI_array_append(vv, v->nv.v);
+ BLI_array_append(ee, bme);
+ }
+ while (v != vend) {
+ /* check for special case: multisegment 3rd face opposite a beveled edge with no vmesh */
+ corner3special = (vm->mesh_kind == M_NONE && v->ebev != e && v->ebev != eprev);
+ if (go_ccw) {
+ i = v->index;
+ if (on_profile_start) {
+ kstart = e->profile_index;
+ on_profile_start = false;
+ }
+ else {
+ kstart = 1;
+ }
+ if (eprev->rightv == v && eprev->profile_index > 0) {
+ kend = eprev->profile_index;
+ }
+ else {
+ kend = vm->seg;
+ }
+ for (k = kstart; k <= kend; k++) {
+ bmv = mesh_vert(vm, i, 0, k)->v;
+ if (bmv) {
+ BLI_array_append(vv, bmv);
+ BLI_array_append(ee, bme); /* TODO: maybe better edge here */
+ if (corner3special && v->ebev && !v->ebev->is_seam && k != vm->seg) {
+ BLI_array_append(vv_fix, bmv);
+ }
+ }
+ }
+ v = v->next;
+ }
+ else {
+ /* going cw */
+ i = v->prev->index;
+ if (on_profile_start) {
+ kstart = eprev->profile_index;
+ on_profile_start = false;
+ }
+ else {
+ kstart = vm->seg - 1;
+ }
+ if (e->rightv == v->prev && e->profile_index > 0) {
+ kend = e->profile_index;
+ }
+ else {
+ kend = 0;
+ }
+ for (k = kstart; k >= kend; k--) {
+ bmv = mesh_vert(vm, i, 0, k)->v;
+ if (bmv) {
+ BLI_array_append(vv, bmv);
+ BLI_array_append(ee, bme);
+ if (corner3special && v->ebev && !v->ebev->is_seam && k != 0) {
+ BLI_array_append(vv_fix, bmv);
+ }
+ }
+ }
+ v = v->prev;
+ }
+ }
+ do_rebuild = true;
+ }
+ else {
+ BLI_array_append(vv, l->v);
+ BLI_array_append(ee, l->e);
+ }
+ }
+ if (do_rebuild) {
+ n = BLI_array_len(vv);
+ f_new = bev_create_ngon(bm, vv, n, NULL, f, NULL, -1, true);
+
+ for (k = 0; k < BLI_array_len(vv_fix); k++) {
+ bev_merge_uvs(bm, vv_fix[k]);
+ }
+
+ /* copy attributes from old edges */
+ BLI_assert(n == BLI_array_len(ee));
+ bme_prev = ee[n - 1];
+ for (k = 0; k < n; k++) {
+ bme_new = BM_edge_exists(vv[k], vv[(k + 1) % n]);
+ BLI_assert(ee[k] && bme_new);
+ if (ee[k] != bme_new) {
+ BM_elem_attrs_copy(bm, bm, ee[k], bme_new);
+ /* want to undo seam and smooth for corner segments
+ * if those attrs aren't contiguous around face */
+ if (k < n - 1 && ee[k] == ee[k + 1]) {
+ if (BM_elem_flag_test(ee[k], BM_ELEM_SEAM) &&
+ !BM_elem_flag_test(bme_prev, BM_ELEM_SEAM)) {
+ BM_elem_flag_disable(bme_new, BM_ELEM_SEAM);
+ }
+ /* actually want "sharp" to be contiguous, so reverse the test */
+ if (!BM_elem_flag_test(ee[k], BM_ELEM_SMOOTH) &&
+ BM_elem_flag_test(bme_prev, BM_ELEM_SMOOTH)) {
+ BM_elem_flag_enable(bme_new, BM_ELEM_SMOOTH);
+ }
+ }
+ else {
+ bme_prev = ee[k];
+ }
+ }
+ }
+
+ /* don't select newly or return created boundary faces... */
+ if (f_new) {
+ record_face_kind(bp, f_new, F_RECON);
+ BM_elem_flag_disable(f_new, BM_ELEM_TAG);
+ /* Also don't want new edges that aren't part of a new bevel face */
+ BM_ITER_ELEM (bme, &eiter, f_new, BM_EDGES_OF_FACE) {
+ keep = false;
+ BM_ITER_ELEM (f_other, &fiter, bme, BM_FACES_OF_EDGE) {
+ if (BM_elem_flag_test(f_other, BM_ELEM_TAG)) {
+ keep = true;
+ break;
+ }
+ }
+ if (!keep) {
+ disable_flag_out_edge(bm, bme);
+ }
+ }
+ }
+ }
+
+ BLI_array_free(vv);
+ BLI_array_free(vv_fix);
+ BLI_array_free(ee);
+ return do_rebuild;
}
/* All polygons touching v need rebuilding because beveling v has made new vertices */
static void bevel_rebuild_existing_polygons(BMesh *bm, BevelParams *bp, BMVert *v)
{
- void *faces_stack[BM_DEFAULT_ITER_STACK_SIZE];
- int faces_len, f_index;
- BMFace **faces = BM_iter_as_arrayN(bm, BM_FACES_OF_VERT, v, &faces_len,
- faces_stack, BM_DEFAULT_ITER_STACK_SIZE);
-
- if (LIKELY(faces != NULL)) {
- for (f_index = 0; f_index < faces_len; f_index++) {
- BMFace *f = faces[f_index];
- if (bev_rebuild_polygon(bm, bp, f)) {
- BM_face_kill(bm, f);
- }
- }
-
- if (faces != (BMFace **)faces_stack) {
- MEM_freeN(faces);
- }
- }
+ void *faces_stack[BM_DEFAULT_ITER_STACK_SIZE];
+ int faces_len, f_index;
+ BMFace **faces = BM_iter_as_arrayN(
+ bm, BM_FACES_OF_VERT, v, &faces_len, faces_stack, BM_DEFAULT_ITER_STACK_SIZE);
+
+ if (LIKELY(faces != NULL)) {
+ for (f_index = 0; f_index < faces_len; f_index++) {
+ BMFace *f = faces[f_index];
+ if (bev_rebuild_polygon(bm, bp, f)) {
+ BM_face_kill(bm, f);
+ }
+ }
+
+ if (faces != (BMFace **)faces_stack) {
+ MEM_freeN(faces);
+ }
+ }
}
/* If there were any wire edges, they need to be reattached somewhere */
static void bevel_reattach_wires(BMesh *bm, BevelParams *bp, BMVert *v)
{
- BMEdge *e;
- BMVert *vclosest, *vother, *votherclosest;
- BevVert *bv, *bvother;
- BoundVert *bndv, *bndvother;
- float d, dclosest;
- int i;
-
- bv = find_bevvert(bp, v);
- if (!bv || bv->wirecount == 0 || !bv->vmesh) {
- return;
- }
-
- for (i = 0; i < bv->wirecount; i++) {
- e = bv->wire_edges[i];
- /* look for the new vertex closest to the other end of e */
- vclosest = NULL;
- dclosest = FLT_MAX;
- votherclosest = NULL;
- vother = BM_edge_other_vert(e, v);
- bvother = NULL;
- if (BM_elem_flag_test(vother, BM_ELEM_TAG)) {
- bvother = find_bevvert(bp, vother);
- if (!bvother || !bvother->vmesh) {
- return; /* shouldn't happen */
- }
- }
- bndv = bv->vmesh->boundstart;
- do {
- if (bvother) {
- bndvother = bvother->vmesh->boundstart;
- do {
- d = len_squared_v3v3(bndvother->nv.co, bndv->nv.co);
- if (d < dclosest) {
- vclosest = bndv->nv.v;
- votherclosest = bndvother->nv.v;
- dclosest = d;
-
- }
- } while ((bndvother = bndvother->next) != bvother->vmesh->boundstart);
- }
- else {
- d = len_squared_v3v3(vother->co, bndv->nv.co);
- if (d < dclosest) {
- vclosest = bndv->nv.v;
- votherclosest = vother;
- dclosest = d;
- }
- }
- } while ((bndv = bndv->next) != bv->vmesh->boundstart);
- if (vclosest) {
- BM_edge_create(bm, vclosest, votherclosest, e, BM_CREATE_NO_DOUBLE);
- }
- }
+ BMEdge *e;
+ BMVert *vclosest, *vother, *votherclosest;
+ BevVert *bv, *bvother;
+ BoundVert *bndv, *bndvother;
+ float d, dclosest;
+ int i;
+
+ bv = find_bevvert(bp, v);
+ if (!bv || bv->wirecount == 0 || !bv->vmesh) {
+ return;
+ }
+
+ for (i = 0; i < bv->wirecount; i++) {
+ e = bv->wire_edges[i];
+ /* look for the new vertex closest to the other end of e */
+ vclosest = NULL;
+ dclosest = FLT_MAX;
+ votherclosest = NULL;
+ vother = BM_edge_other_vert(e, v);
+ bvother = NULL;
+ if (BM_elem_flag_test(vother, BM_ELEM_TAG)) {
+ bvother = find_bevvert(bp, vother);
+ if (!bvother || !bvother->vmesh) {
+ return; /* shouldn't happen */
+ }
+ }
+ bndv = bv->vmesh->boundstart;
+ do {
+ if (bvother) {
+ bndvother = bvother->vmesh->boundstart;
+ do {
+ d = len_squared_v3v3(bndvother->nv.co, bndv->nv.co);
+ if (d < dclosest) {
+ vclosest = bndv->nv.v;
+ votherclosest = bndvother->nv.v;
+ dclosest = d;
+ }
+ } while ((bndvother = bndvother->next) != bvother->vmesh->boundstart);
+ }
+ else {
+ d = len_squared_v3v3(vother->co, bndv->nv.co);
+ if (d < dclosest) {
+ vclosest = bndv->nv.v;
+ votherclosest = vother;
+ dclosest = d;
+ }
+ }
+ } while ((bndv = bndv->next) != bv->vmesh->boundstart);
+ if (vclosest) {
+ BM_edge_create(bm, vclosest, votherclosest, e, BM_CREATE_NO_DOUBLE);
+ }
+ }
}
static void bev_merge_end_uvs(BMesh *bm, BevVert *bv, EdgeHalf *e)
{
- VMesh *vm = bv->vmesh;
- int i, k, nseg;
-
- nseg = e->seg;
- i = e->leftv->index;
- for (k = 1; k < nseg; k++) {
- bev_merge_uvs(bm, mesh_vert(vm, i, 0, k)->v);
- }
+ VMesh *vm = bv->vmesh;
+ int i, k, nseg;
+
+ nseg = e->seg;
+ i = e->leftv->index;
+ for (k = 1; k < nseg; k++) {
+ bev_merge_uvs(bm, mesh_vert(vm, i, 0, k)->v);
+ }
}
/*
@@ -5625,9 +5682,9 @@ static void bev_merge_end_uvs(BMesh *bm, BevVert *bv, EdgeHalf *e)
*/
static bool bevvert_is_weld_cross(BevVert *bv)
{
- return (bv->edgecount == 4 && bv->selcount == 2 &&
- ((bv->edges[0].is_bev && bv->edges[2].is_bev) ||
- (bv->edges[1].is_bev && bv->edges[3].is_bev)));
+ return (bv->edgecount == 4 && bv->selcount == 2 &&
+ ((bv->edges[0].is_bev && bv->edges[2].is_bev) ||
+ (bv->edges[1].is_bev && bv->edges[3].is_bev)));
}
/*
@@ -5651,37 +5708,38 @@ static bool bevvert_is_weld_cross(BevVert *bv)
*/
static void weld_cross_attrs_copy(BMesh *bm, BevVert *bv, VMesh *vm, int vmindex, EdgeHalf *e)
{
- BMEdge *bme_prev, *bme_next, *bme;
- int i, nseg;
- bool disable_seam, enable_smooth;
-
- bme_prev = bme_next = NULL;
- for (i = 0; i < 4; i++) {
- if (&bv->edges[i] == e) {
- bme_prev = bv->edges[(i + 3) % 4].e;
- bme_next = bv->edges[(i + 1) % 4].e;
- break;
- }
- }
- BLI_assert(bme_prev && bme_next);
-
- /* want seams and sharp edges to cross only if that way on both sides */
- disable_seam = BM_elem_flag_test(bme_prev, BM_ELEM_SEAM) != BM_elem_flag_test(bme_next, BM_ELEM_SEAM);
- enable_smooth = BM_elem_flag_test(bme_prev, BM_ELEM_SMOOTH) != BM_elem_flag_test(bme_next, BM_ELEM_SMOOTH);
-
- nseg = e->seg;
- for (i = 0; i < nseg; i++) {
- bme = BM_edge_exists(mesh_vert(vm, vmindex, 0, i)->v,
- mesh_vert(vm, vmindex, 0, i + 1)->v);
- BLI_assert(bme);
- BM_elem_attrs_copy(bm, bm, bme_prev, bme);
- if (disable_seam) {
- BM_elem_flag_disable(bme, BM_ELEM_SEAM);
- }
- if (enable_smooth) {
- BM_elem_flag_enable(bme, BM_ELEM_SMOOTH);
- }
- }
+ BMEdge *bme_prev, *bme_next, *bme;
+ int i, nseg;
+ bool disable_seam, enable_smooth;
+
+ bme_prev = bme_next = NULL;
+ for (i = 0; i < 4; i++) {
+ if (&bv->edges[i] == e) {
+ bme_prev = bv->edges[(i + 3) % 4].e;
+ bme_next = bv->edges[(i + 1) % 4].e;
+ break;
+ }
+ }
+ BLI_assert(bme_prev && bme_next);
+
+ /* want seams and sharp edges to cross only if that way on both sides */
+ disable_seam = BM_elem_flag_test(bme_prev, BM_ELEM_SEAM) !=
+ BM_elem_flag_test(bme_next, BM_ELEM_SEAM);
+ enable_smooth = BM_elem_flag_test(bme_prev, BM_ELEM_SMOOTH) !=
+ BM_elem_flag_test(bme_next, BM_ELEM_SMOOTH);
+
+ nseg = e->seg;
+ for (i = 0; i < nseg; i++) {
+ bme = BM_edge_exists(mesh_vert(vm, vmindex, 0, i)->v, mesh_vert(vm, vmindex, 0, i + 1)->v);
+ BLI_assert(bme);
+ BM_elem_attrs_copy(bm, bm, bme_prev, bme);
+ if (disable_seam) {
+ BM_elem_flag_disable(bme, BM_ELEM_SEAM);
+ }
+ if (enable_smooth) {
+ BM_elem_flag_enable(bme, BM_ELEM_SMOOTH);
+ }
+ }
}
/*
@@ -5689,144 +5747,144 @@ static void weld_cross_attrs_copy(BMesh *bm, BevVert *bv, VMesh *vm, int vmindex
*/
static void bevel_build_edge_polygons(BMesh *bm, BevelParams *bp, BMEdge *bme)
{
- BevVert *bv1, *bv2;
- BMVert *bmv1, *bmv2, *bmv3, *bmv4;
- VMesh *vm1, *vm2;
- EdgeHalf *e1, *e2;
- BMEdge *bme1, *bme2, *center_bme;
- BMFace *f1, *f2, *f, *r_f;
- BMVert *verts[4];
- BMFace *faces[4];
- BMEdge *edges[4];
- BMLoop *l;
- BMIter iter;
- int k, nseg, i1, i2, odd, mid;
- int mat_nr = bp->mat_nr;
-
- if (!BM_edge_is_manifold(bme)) {
- return;
- }
-
- bv1 = find_bevvert(bp, bme->v1);
- bv2 = find_bevvert(bp, bme->v2);
-
- BLI_assert(bv1 && bv2);
-
- e1 = find_edge_half(bv1, bme);
- e2 = find_edge_half(bv2, bme);
-
- BLI_assert(e1 && e2);
-
- /*
- * bme->v1
- * / | \
- * v1--|--v4
- * | | |
- * | | |
- * v2--|--v3
- * \ | /
- * bme->v2
- */
- nseg = e1->seg;
- BLI_assert(nseg > 0 && nseg == e2->seg);
-
- bmv1 = e1->leftv->nv.v;
- bmv4 = e1->rightv->nv.v;
- bmv2 = e2->rightv->nv.v;
- bmv3 = e2->leftv->nv.v;
-
- BLI_assert(bmv1 && bmv2 && bmv3 && bmv4);
-
- f1 = e1->fprev;
- f2 = e1->fnext;
- faces[0] = faces[1] = f1;
- faces[2] = faces[3] = f2;
- i1 = e1->leftv->index;
- i2 = e2->leftv->index;
- vm1 = bv1->vmesh;
- vm2 = bv2->vmesh;
-
- verts[0] = bmv1;
- verts[1] = bmv2;
- odd = nseg % 2;
- mid = nseg / 2;
- center_bme = NULL;
- for (k = 1; k <= nseg; k++) {
- verts[3] = mesh_vert(vm1, i1, 0, k)->v;
- verts[2] = mesh_vert(vm2, i2, 0, nseg - k)->v;
- if (odd && k == mid + 1) {
- if (e1->is_seam) {
- /* straddles a seam: choose to interpolate in f1 and snap right edge to bme */
- edges[0] = edges[1] = NULL;
- edges[2] = edges[3] = bme;
- r_f = bev_create_ngon(bm, verts, 4, NULL, f1, edges, mat_nr, true);
- }
- else {
- /* straddles but not a seam: interpolate left half in f1, right half in f2 */
- r_f = bev_create_ngon(bm, verts, 4, faces, NULL, NULL, mat_nr, true);
- }
- }
- else if (!odd && k == mid) {
- /* left poly that touches an even center line on right */
- edges[0] = edges[1] = NULL;
- edges[2] = edges[3] = bme;
- r_f = bev_create_ngon(bm, verts, 4, NULL, f1, edges, mat_nr, true);
- center_bme = BM_edge_exists(verts[2], verts[3]);
- BLI_assert(center_bme != NULL);
- }
- else if (!odd && k == mid + 1) {
- /* right poly that touches an even center line on left */
- edges[0] = edges[1] = bme;
- edges[2] = edges[3] = NULL;
- r_f = bev_create_ngon(bm, verts, 4, NULL, f2, edges, mat_nr, true);
- }
- else {
- /* doesn't cross or touch the center line, so interpolate in appropriate f1 or f2 */
- f = (k <= mid) ? f1 : f2;
- r_f = bev_create_ngon(bm, verts, 4, NULL, f, NULL, mat_nr, true);
- }
- record_face_kind(bp, r_f, F_EDGE);
- /* tag the long edges: those out of verts[0] and verts[2] */
- BM_ITER_ELEM(l, &iter, r_f, BM_LOOPS_OF_FACE) {
- if (l->v == verts[0] || l->v == verts[2]) {
- BM_elem_flag_enable(l, BM_ELEM_LONG_TAG);
- }
- }
- verts[0] = verts[3];
- verts[1] = verts[2];
- }
- if (!odd) {
- if (!e1->is_seam) {
- bev_merge_edge_uvs(bm, center_bme, mesh_vert(vm1, i1, 0, mid)->v);
- }
- if (!e2->is_seam) {
- bev_merge_edge_uvs(bm, center_bme, mesh_vert(vm2, i2, 0, mid)->v);
- }
- }
-
- /* Fix UVs along end edge joints. A nop unless other side built already. */
- /* TODO: if some seam, may want to do selective merge */
- if (!bv1->any_seam && bv1->vmesh->mesh_kind == M_NONE) {
- bev_merge_end_uvs(bm, bv1, e1);
- }
- if (!bv2->any_seam && bv2->vmesh->mesh_kind == M_NONE) {
- bev_merge_end_uvs(bm, bv2, e2);
- }
-
- /* Copy edge data to first and last edge */
- bme1 = BM_edge_exists(bmv1, bmv2);
- bme2 = BM_edge_exists(bmv3, bmv4);
- BLI_assert(bme1 && bme2);
- BM_elem_attrs_copy(bm, bm, bme, bme1);
- BM_elem_attrs_copy(bm, bm, bme, bme2);
-
- /* If either end is a "weld cross", want continuity of edge attributes across end edge(s) */
- if (bevvert_is_weld_cross(bv1)) {
- weld_cross_attrs_copy(bm, bv1, vm1, i1, e1);
- }
- if (bevvert_is_weld_cross(bv2)) {
- weld_cross_attrs_copy(bm, bv2, vm2, i2, e2);
- }
+ BevVert *bv1, *bv2;
+ BMVert *bmv1, *bmv2, *bmv3, *bmv4;
+ VMesh *vm1, *vm2;
+ EdgeHalf *e1, *e2;
+ BMEdge *bme1, *bme2, *center_bme;
+ BMFace *f1, *f2, *f, *r_f;
+ BMVert *verts[4];
+ BMFace *faces[4];
+ BMEdge *edges[4];
+ BMLoop *l;
+ BMIter iter;
+ int k, nseg, i1, i2, odd, mid;
+ int mat_nr = bp->mat_nr;
+
+ if (!BM_edge_is_manifold(bme)) {
+ return;
+ }
+
+ bv1 = find_bevvert(bp, bme->v1);
+ bv2 = find_bevvert(bp, bme->v2);
+
+ BLI_assert(bv1 && bv2);
+
+ e1 = find_edge_half(bv1, bme);
+ e2 = find_edge_half(bv2, bme);
+
+ BLI_assert(e1 && e2);
+
+ /*
+ * bme->v1
+ * / | \
+ * v1--|--v4
+ * | | |
+ * | | |
+ * v2--|--v3
+ * \ | /
+ * bme->v2
+ */
+ nseg = e1->seg;
+ BLI_assert(nseg > 0 && nseg == e2->seg);
+
+ bmv1 = e1->leftv->nv.v;
+ bmv4 = e1->rightv->nv.v;
+ bmv2 = e2->rightv->nv.v;
+ bmv3 = e2->leftv->nv.v;
+
+ BLI_assert(bmv1 && bmv2 && bmv3 && bmv4);
+
+ f1 = e1->fprev;
+ f2 = e1->fnext;
+ faces[0] = faces[1] = f1;
+ faces[2] = faces[3] = f2;
+ i1 = e1->leftv->index;
+ i2 = e2->leftv->index;
+ vm1 = bv1->vmesh;
+ vm2 = bv2->vmesh;
+
+ verts[0] = bmv1;
+ verts[1] = bmv2;
+ odd = nseg % 2;
+ mid = nseg / 2;
+ center_bme = NULL;
+ for (k = 1; k <= nseg; k++) {
+ verts[3] = mesh_vert(vm1, i1, 0, k)->v;
+ verts[2] = mesh_vert(vm2, i2, 0, nseg - k)->v;
+ if (odd && k == mid + 1) {
+ if (e1->is_seam) {
+ /* straddles a seam: choose to interpolate in f1 and snap right edge to bme */
+ edges[0] = edges[1] = NULL;
+ edges[2] = edges[3] = bme;
+ r_f = bev_create_ngon(bm, verts, 4, NULL, f1, edges, mat_nr, true);
+ }
+ else {
+ /* straddles but not a seam: interpolate left half in f1, right half in f2 */
+ r_f = bev_create_ngon(bm, verts, 4, faces, NULL, NULL, mat_nr, true);
+ }
+ }
+ else if (!odd && k == mid) {
+ /* left poly that touches an even center line on right */
+ edges[0] = edges[1] = NULL;
+ edges[2] = edges[3] = bme;
+ r_f = bev_create_ngon(bm, verts, 4, NULL, f1, edges, mat_nr, true);
+ center_bme = BM_edge_exists(verts[2], verts[3]);
+ BLI_assert(center_bme != NULL);
+ }
+ else if (!odd && k == mid + 1) {
+ /* right poly that touches an even center line on left */
+ edges[0] = edges[1] = bme;
+ edges[2] = edges[3] = NULL;
+ r_f = bev_create_ngon(bm, verts, 4, NULL, f2, edges, mat_nr, true);
+ }
+ else {
+ /* doesn't cross or touch the center line, so interpolate in appropriate f1 or f2 */
+ f = (k <= mid) ? f1 : f2;
+ r_f = bev_create_ngon(bm, verts, 4, NULL, f, NULL, mat_nr, true);
+ }
+ record_face_kind(bp, r_f, F_EDGE);
+ /* tag the long edges: those out of verts[0] and verts[2] */
+ BM_ITER_ELEM (l, &iter, r_f, BM_LOOPS_OF_FACE) {
+ if (l->v == verts[0] || l->v == verts[2]) {
+ BM_elem_flag_enable(l, BM_ELEM_LONG_TAG);
+ }
+ }
+ verts[0] = verts[3];
+ verts[1] = verts[2];
+ }
+ if (!odd) {
+ if (!e1->is_seam) {
+ bev_merge_edge_uvs(bm, center_bme, mesh_vert(vm1, i1, 0, mid)->v);
+ }
+ if (!e2->is_seam) {
+ bev_merge_edge_uvs(bm, center_bme, mesh_vert(vm2, i2, 0, mid)->v);
+ }
+ }
+
+ /* Fix UVs along end edge joints. A nop unless other side built already. */
+ /* TODO: if some seam, may want to do selective merge */
+ if (!bv1->any_seam && bv1->vmesh->mesh_kind == M_NONE) {
+ bev_merge_end_uvs(bm, bv1, e1);
+ }
+ if (!bv2->any_seam && bv2->vmesh->mesh_kind == M_NONE) {
+ bev_merge_end_uvs(bm, bv2, e2);
+ }
+
+ /* Copy edge data to first and last edge */
+ bme1 = BM_edge_exists(bmv1, bmv2);
+ bme2 = BM_edge_exists(bmv3, bmv4);
+ BLI_assert(bme1 && bme2);
+ BM_elem_attrs_copy(bm, bm, bme, bme1);
+ BM_elem_attrs_copy(bm, bm, bme, bme2);
+
+ /* If either end is a "weld cross", want continuity of edge attributes across end edge(s) */
+ if (bevvert_is_weld_cross(bv1)) {
+ weld_cross_attrs_copy(bm, bv1, vm1, i1, e1);
+ }
+ if (bevvert_is_weld_cross(bv2)) {
+ weld_cross_attrs_copy(bm, bv2, vm2, i2, e2);
+ }
}
/* Find xnew > x0 so that distance((x0,y0), (xnew, ynew)) = dtarget.
@@ -5836,64 +5894,64 @@ static void bevel_build_edge_polygons(BMesh *bm, BevelParams *bp, BMEdge *bme)
* x in [x0, x0+dtarget] */
static double find_superellipse_chord_endpoint(double x0, double dtarget, float r, bool rbig)
{
- double xmin, xmax, ymin, ymax, dmaxerr, dminerr, dnewerr, xnew, ynew;
- double y0 = superellipse_co(x0, r, rbig);
- const double tol = 1e-13; // accumulates for many segments so use low value
- const int maxiter = 10;
- bool lastupdated_upper;
-
- /* For gradient between -1 and 1, xnew can only be in
- * [x0 + sqrt(2)/2*dtarget, x0 + dtarget]. */
- xmin = x0 + M_SQRT2 / 2.0 * dtarget;
- if (xmin > 1.0) {
- xmin = 1.0;
- }
- xmax = x0 + dtarget;
- if (xmax > 1.0) {
- xmax = 1.0;
- }
- ymin = superellipse_co(xmin, r, rbig);
- ymax = superellipse_co(xmax, r, rbig);
-
- /* Note: using distance**2 (no sqrt needed) does not converge that well. */
- dmaxerr = sqrt(pow((xmax - x0), 2) + pow((ymax - y0), 2)) - dtarget;
- dminerr = sqrt(pow((xmin - x0), 2) + pow((ymin - y0), 2)) - dtarget;
-
- xnew = xmax - dmaxerr * (xmax - xmin) / (dmaxerr - dminerr);
- lastupdated_upper = true;
-
- for (int iter = 0; iter < maxiter; iter++) {
- ynew = superellipse_co(xnew, r, rbig);
- dnewerr = sqrt(pow((xnew - x0), 2) + pow((ynew - y0), 2)) - dtarget;
- if (fabs(dnewerr) < tol) {
- break;
- }
- if (dnewerr < 0) {
- xmin = xnew;
- ymin = ynew;
- dminerr = dnewerr;
- if (!lastupdated_upper) {
- xnew = (dmaxerr / 2 * xmin - dminerr * xmax) / (dmaxerr / 2 - dminerr);
- }
- else {
- xnew = xmax - dmaxerr * (xmax - xmin) / (dmaxerr - dminerr);
- }
- lastupdated_upper = false;
- }
- else {
- xmax = xnew;
- ymax = ynew;
- dmaxerr = dnewerr;
- if (lastupdated_upper) {
- xnew = (dmaxerr * xmin - dminerr / 2 * xmax) / (dmaxerr - dminerr / 2);
- }
- else {
- xnew = xmax - dmaxerr * (xmax - xmin) / (dmaxerr - dminerr);
- }
- lastupdated_upper = true;
- }
- }
- return xnew;
+ double xmin, xmax, ymin, ymax, dmaxerr, dminerr, dnewerr, xnew, ynew;
+ double y0 = superellipse_co(x0, r, rbig);
+ const double tol = 1e-13; // accumulates for many segments so use low value
+ const int maxiter = 10;
+ bool lastupdated_upper;
+
+ /* For gradient between -1 and 1, xnew can only be in
+ * [x0 + sqrt(2)/2*dtarget, x0 + dtarget]. */
+ xmin = x0 + M_SQRT2 / 2.0 * dtarget;
+ if (xmin > 1.0) {
+ xmin = 1.0;
+ }
+ xmax = x0 + dtarget;
+ if (xmax > 1.0) {
+ xmax = 1.0;
+ }
+ ymin = superellipse_co(xmin, r, rbig);
+ ymax = superellipse_co(xmax, r, rbig);
+
+ /* Note: using distance**2 (no sqrt needed) does not converge that well. */
+ dmaxerr = sqrt(pow((xmax - x0), 2) + pow((ymax - y0), 2)) - dtarget;
+ dminerr = sqrt(pow((xmin - x0), 2) + pow((ymin - y0), 2)) - dtarget;
+
+ xnew = xmax - dmaxerr * (xmax - xmin) / (dmaxerr - dminerr);
+ lastupdated_upper = true;
+
+ for (int iter = 0; iter < maxiter; iter++) {
+ ynew = superellipse_co(xnew, r, rbig);
+ dnewerr = sqrt(pow((xnew - x0), 2) + pow((ynew - y0), 2)) - dtarget;
+ if (fabs(dnewerr) < tol) {
+ break;
+ }
+ if (dnewerr < 0) {
+ xmin = xnew;
+ ymin = ynew;
+ dminerr = dnewerr;
+ if (!lastupdated_upper) {
+ xnew = (dmaxerr / 2 * xmin - dminerr * xmax) / (dmaxerr / 2 - dminerr);
+ }
+ else {
+ xnew = xmax - dmaxerr * (xmax - xmin) / (dmaxerr - dminerr);
+ }
+ lastupdated_upper = false;
+ }
+ else {
+ xmax = xnew;
+ ymax = ynew;
+ dmaxerr = dnewerr;
+ if (lastupdated_upper) {
+ xnew = (dmaxerr * xmin - dminerr / 2 * xmax) / (dmaxerr - dminerr / 2);
+ }
+ else {
+ xnew = xmax - dmaxerr * (xmax - xmin) / (dmaxerr - dminerr);
+ }
+ lastupdated_upper = true;
+ }
+ }
+ return xnew;
}
/**
@@ -5907,100 +5965,99 @@ static double find_superellipse_chord_endpoint(double x0, double dtarget, float
*/
static void find_even_superellipse_chords_general(int seg, float r, double *xvals, double *yvals)
{
- const int smoothitermax = 10;
- const double error_tol = 1e-7;
- int i;
- int imax = (seg + 1) / 2 - 1; /* ceiling division - 1 */
-
- double d, dmin, dmax;
- double davg;
- double mx;
- double sum;
- double temp;
-
- bool precision_reached = true;
- bool seg_odd = seg % 2;
- bool rbig;
-
- if (r > 1.0f) {
- rbig = true;
- mx = pow(0.5, 1.0 / r);
- }
- else {
- rbig = false;
- mx = 1 - pow(0.5, 1.0 / r);
- }
-
- /* Initial positions, linear spacing along x axis. */
- for (i = 0; i <= imax; i++) {
- xvals[i] = i * mx / seg * 2;
- yvals[i] = superellipse_co(xvals[i], r, rbig);
- }
- yvals[0] = 1;
-
- /* Smooth distance loop */
- for (int iter = 0; iter < smoothitermax; iter++) {
- sum = 0.0;
- dmin = 2.0;
- dmax = 0.0;
- /* Update distances between neighbor points. Store the highest and
- * lowest to see if the maximum error to average distance (which isn't
- * known yet) is below required precision. */
- for (i = 0; i < imax; i++) {
- d = sqrt(pow((xvals[i + 1] - xvals[i]), 2) + pow((yvals[i + 1] - yvals[i]), 2));
- sum += d;
- if (d > dmax) {
- dmax = d;
- }
- if (d < dmin) {
- dmin = d;
- }
- }
- /* For last distance, weight with 1/2 if seg_odd. */
- if (seg_odd) {
- sum += M_SQRT2 / 2 * (yvals[imax] - xvals[imax]);
- davg = sum / (imax + 0.5);
- }
- else {
- sum += sqrt(pow((xvals[imax] - mx), 2) + pow((yvals[imax] - mx), 2));
- davg = sum / (imax + 1.0);
- }
- /* Max error in tolerance? -> Quit. */
- if (dmax - davg > error_tol) {
- precision_reached = false;
- }
- if (dmin - davg < error_tol) {
- precision_reached = false;
- }
- if (precision_reached) {
- break;
- }
-
-
- /* Update new coordinates. */
- for (i = 1; i <= imax; i++) {
- xvals[i] = find_superellipse_chord_endpoint(xvals[i - 1], davg, r, rbig);
- yvals[i] = superellipse_co(xvals[i], r, rbig);
- }
- }
-
- /* Fill remaining. */
- if (!seg_odd) {
- xvals[imax + 1] = mx;
- yvals[imax + 1] = mx;
- }
- for (i = imax + 1; i <= seg; i++) {
- yvals[i] = xvals[seg - i];
- xvals[i] = yvals[seg - i];
- }
-
- if (!rbig) {
- for (i = 0; i <= seg; i++) {
- temp = xvals[i];
- xvals[i] = 1.0 - yvals[i];
- yvals[i] = 1.0 - temp;
- }
- }
+ const int smoothitermax = 10;
+ const double error_tol = 1e-7;
+ int i;
+ int imax = (seg + 1) / 2 - 1; /* ceiling division - 1 */
+
+ double d, dmin, dmax;
+ double davg;
+ double mx;
+ double sum;
+ double temp;
+
+ bool precision_reached = true;
+ bool seg_odd = seg % 2;
+ bool rbig;
+
+ if (r > 1.0f) {
+ rbig = true;
+ mx = pow(0.5, 1.0 / r);
+ }
+ else {
+ rbig = false;
+ mx = 1 - pow(0.5, 1.0 / r);
+ }
+
+ /* Initial positions, linear spacing along x axis. */
+ for (i = 0; i <= imax; i++) {
+ xvals[i] = i * mx / seg * 2;
+ yvals[i] = superellipse_co(xvals[i], r, rbig);
+ }
+ yvals[0] = 1;
+
+ /* Smooth distance loop */
+ for (int iter = 0; iter < smoothitermax; iter++) {
+ sum = 0.0;
+ dmin = 2.0;
+ dmax = 0.0;
+ /* Update distances between neighbor points. Store the highest and
+ * lowest to see if the maximum error to average distance (which isn't
+ * known yet) is below required precision. */
+ for (i = 0; i < imax; i++) {
+ d = sqrt(pow((xvals[i + 1] - xvals[i]), 2) + pow((yvals[i + 1] - yvals[i]), 2));
+ sum += d;
+ if (d > dmax) {
+ dmax = d;
+ }
+ if (d < dmin) {
+ dmin = d;
+ }
+ }
+ /* For last distance, weight with 1/2 if seg_odd. */
+ if (seg_odd) {
+ sum += M_SQRT2 / 2 * (yvals[imax] - xvals[imax]);
+ davg = sum / (imax + 0.5);
+ }
+ else {
+ sum += sqrt(pow((xvals[imax] - mx), 2) + pow((yvals[imax] - mx), 2));
+ davg = sum / (imax + 1.0);
+ }
+ /* Max error in tolerance? -> Quit. */
+ if (dmax - davg > error_tol) {
+ precision_reached = false;
+ }
+ if (dmin - davg < error_tol) {
+ precision_reached = false;
+ }
+ if (precision_reached) {
+ break;
+ }
+
+ /* Update new coordinates. */
+ for (i = 1; i <= imax; i++) {
+ xvals[i] = find_superellipse_chord_endpoint(xvals[i - 1], davg, r, rbig);
+ yvals[i] = superellipse_co(xvals[i], r, rbig);
+ }
+ }
+
+ /* Fill remaining. */
+ if (!seg_odd) {
+ xvals[imax + 1] = mx;
+ yvals[imax + 1] = mx;
+ }
+ for (i = imax + 1; i <= seg; i++) {
+ yvals[i] = xvals[seg - i];
+ xvals[i] = yvals[seg - i];
+ }
+
+ if (!rbig) {
+ for (i = 0; i <= seg; i++) {
+ temp = xvals[i];
+ xvals[i] = 1.0 - yvals[i];
+ yvals[i] = 1.0 - temp;
+ }
+ }
}
/**
@@ -6013,79 +6070,78 @@ static void find_even_superellipse_chords_general(int seg, float r, double *xval
*/
static void find_even_superellipse_chords(int n, float r, double *xvals, double *yvals)
{
- int i, n2;
- double temp;
- bool seg_odd = n % 2;
-
- n2 = n / 2;
-
- /* Special cases. */
- if (r == PRO_LINE_R) {
- /* Linear spacing */
- for (i = 0; i <= n; i++) {
- xvals[i] = (double) i / n;
- yvals[i] = 1.0 - (double) i / n;
- }
- return;
- }
- if (r == PRO_CIRCLE_R) {
- temp = (M_PI / 2) / n;
- /* Angle spacing. */
- for (i = 0; i <= n; i++) {
- xvals[i] = sin(i * temp);
- yvals[i] = cos(i * temp);
- }
- return;
- }
- if (r == PRO_SQUARE_IN_R) {
- /* n is even, distribute first and second half linear. */
- if (!seg_odd) {
- for (i = 0; i <= n2; i++) {
- xvals[i] = 0.0;
- yvals[i] = 1.0 - (double) i / n2;
- xvals[n - i] = yvals[i];
- yvals[n - i] = xvals[i];
- }
- }
- /* n is odd, so get one corner-cut chord. */
- else {
- temp = 1.0 / (n2 + M_SQRT2 / 2.0);
- for (i = 0; i <= n2; i++) {
- xvals[i] = 0.0;
- yvals[i] = 1.0 - (double) i * temp;
- xvals[n -i ] = yvals[i];
- yvals[n - i] = xvals[i];
- }
- }
- return;
- }
- if (r == PRO_SQUARE_R) {
- /* n is even, distribute first and second half linear. */
- if (!seg_odd) {
- for (i = 0; i <= n2; i++) {
- xvals[i] = (double) i / n2;
- yvals[i] = 1.0;
- xvals[n - i] = yvals[i];
- yvals[n - i] = xvals[i];
- }
- }
- /* n is odd, so get one corner-cut chord. */
- else {
- temp = 1.0 / (n2 + M_SQRT2 / 2);
- for (i = 0; i <= n2; i++) {
- xvals[i] = (double) i * temp;
- yvals[i] = 1.0;
- xvals[n - i] = yvals[i];
- yvals[n - i] = xvals[i];
- }
- }
- return;
- }
- /* For general case use the more expensive search algorithm. */
- find_even_superellipse_chords_general(n, r, xvals, yvals);
+ int i, n2;
+ double temp;
+ bool seg_odd = n % 2;
+
+ n2 = n / 2;
+
+ /* Special cases. */
+ if (r == PRO_LINE_R) {
+ /* Linear spacing */
+ for (i = 0; i <= n; i++) {
+ xvals[i] = (double)i / n;
+ yvals[i] = 1.0 - (double)i / n;
+ }
+ return;
+ }
+ if (r == PRO_CIRCLE_R) {
+ temp = (M_PI / 2) / n;
+ /* Angle spacing. */
+ for (i = 0; i <= n; i++) {
+ xvals[i] = sin(i * temp);
+ yvals[i] = cos(i * temp);
+ }
+ return;
+ }
+ if (r == PRO_SQUARE_IN_R) {
+ /* n is even, distribute first and second half linear. */
+ if (!seg_odd) {
+ for (i = 0; i <= n2; i++) {
+ xvals[i] = 0.0;
+ yvals[i] = 1.0 - (double)i / n2;
+ xvals[n - i] = yvals[i];
+ yvals[n - i] = xvals[i];
+ }
+ }
+ /* n is odd, so get one corner-cut chord. */
+ else {
+ temp = 1.0 / (n2 + M_SQRT2 / 2.0);
+ for (i = 0; i <= n2; i++) {
+ xvals[i] = 0.0;
+ yvals[i] = 1.0 - (double)i * temp;
+ xvals[n - i] = yvals[i];
+ yvals[n - i] = xvals[i];
+ }
+ }
+ return;
+ }
+ if (r == PRO_SQUARE_R) {
+ /* n is even, distribute first and second half linear. */
+ if (!seg_odd) {
+ for (i = 0; i <= n2; i++) {
+ xvals[i] = (double)i / n2;
+ yvals[i] = 1.0;
+ xvals[n - i] = yvals[i];
+ yvals[n - i] = xvals[i];
+ }
+ }
+ /* n is odd, so get one corner-cut chord. */
+ else {
+ temp = 1.0 / (n2 + M_SQRT2 / 2);
+ for (i = 0; i <= n2; i++) {
+ xvals[i] = (double)i * temp;
+ yvals[i] = 1.0;
+ xvals[n - i] = yvals[i];
+ yvals[n - i] = xvals[i];
+ }
+ }
+ return;
+ }
+ /* For general case use the more expensive search algorithm. */
+ find_even_superellipse_chords_general(n, r, xvals, yvals);
}
-
/* The superellipse used for multisegment profiles does not
* have a closed-form way to generate evenly spaced points
* along an arc. We use an expensive search procedure to find
@@ -6096,35 +6152,41 @@ static void find_even_superellipse_chords(int n, float r, double *xvals, double
* precision for final results. */
static void set_profile_spacing(BevelParams *bp)
{
- int seg, seg_2;
-
- seg = bp->seg;
- if (seg > 1) {
- bp->pro_spacing.xvals = (double *)BLI_memarena_alloc(bp->mem_arena, (seg + 1) * sizeof(double));
- bp->pro_spacing.yvals = (double *)BLI_memarena_alloc(bp->mem_arena, (seg + 1) * sizeof(double));
- find_even_superellipse_chords(seg, bp->pro_super_r, bp->pro_spacing.xvals, bp->pro_spacing.yvals);
- seg_2 = power_of_2_max_i(bp->seg);
- if (seg_2 == 2) {
- seg_2 = 4;
- }
- bp->pro_spacing.seg_2 = seg_2;
- if (seg_2 == seg) {
- bp->pro_spacing.xvals_2 = bp->pro_spacing.xvals;
- bp->pro_spacing.yvals_2 = bp->pro_spacing.yvals;
- }
- else {
- bp->pro_spacing.xvals_2 = (double *)BLI_memarena_alloc(bp->mem_arena, (seg_2 + 1) * sizeof(double));
- bp->pro_spacing.yvals_2 = (double *)BLI_memarena_alloc(bp->mem_arena, (seg_2 + 1) * sizeof(double));
- find_even_superellipse_chords(seg_2, bp->pro_super_r, bp->pro_spacing.xvals_2, bp->pro_spacing.yvals_2);
- }
- }
- else {
- bp->pro_spacing.xvals = NULL;
- bp->pro_spacing.yvals = NULL;
- bp->pro_spacing.xvals_2 = NULL;
- bp->pro_spacing.yvals_2 = NULL;
- bp->pro_spacing.seg_2 = 0;
- }
+ int seg, seg_2;
+
+ seg = bp->seg;
+ if (seg > 1) {
+ bp->pro_spacing.xvals = (double *)BLI_memarena_alloc(bp->mem_arena,
+ (seg + 1) * sizeof(double));
+ bp->pro_spacing.yvals = (double *)BLI_memarena_alloc(bp->mem_arena,
+ (seg + 1) * sizeof(double));
+ find_even_superellipse_chords(
+ seg, bp->pro_super_r, bp->pro_spacing.xvals, bp->pro_spacing.yvals);
+ seg_2 = power_of_2_max_i(bp->seg);
+ if (seg_2 == 2) {
+ seg_2 = 4;
+ }
+ bp->pro_spacing.seg_2 = seg_2;
+ if (seg_2 == seg) {
+ bp->pro_spacing.xvals_2 = bp->pro_spacing.xvals;
+ bp->pro_spacing.yvals_2 = bp->pro_spacing.yvals;
+ }
+ else {
+ bp->pro_spacing.xvals_2 = (double *)BLI_memarena_alloc(bp->mem_arena,
+ (seg_2 + 1) * sizeof(double));
+ bp->pro_spacing.yvals_2 = (double *)BLI_memarena_alloc(bp->mem_arena,
+ (seg_2 + 1) * sizeof(double));
+ find_even_superellipse_chords(
+ seg_2, bp->pro_super_r, bp->pro_spacing.xvals_2, bp->pro_spacing.yvals_2);
+ }
+ }
+ else {
+ bp->pro_spacing.xvals = NULL;
+ bp->pro_spacing.yvals = NULL;
+ bp->pro_spacing.xvals_2 = NULL;
+ bp->pro_spacing.yvals_2 = NULL;
+ bp->pro_spacing.seg_2 = 0;
+ }
}
/*
@@ -6152,100 +6214,100 @@ static void set_profile_spacing(BevelParams *bp)
*/
static float geometry_collide_offset(BevelParams *bp, EdgeHalf *eb)
{
- EdgeHalf *ea, *ec, *ebother;
- BevVert *bvc;
- BMLoop *lb;
- BMVert *va, *vb, *vc, *vd;
- float ka, kb, kc, g, h, t, den, no_collide_offset, th1, th2, sin1, sin2, tan1, tan2, limit;
-
- limit = no_collide_offset = bp->offset + 1e6;
- if (bp->offset == 0.0f) {
- return no_collide_offset;
- }
- kb = eb->offset_l_spec;
- ea = eb->next; /* note: this is in direction b --> a */
- ka = ea->offset_r_spec;
- if (eb->is_rev) {
- vc = eb->e->v1;
- vb = eb->e->v2;
- }
- else {
- vb = eb->e->v1;
- vc = eb->e->v2;
- }
- va = ea->is_rev ? ea->e->v1 : ea->e->v2;
- bvc = NULL;
- ebother = find_other_end_edge_half(bp, eb, &bvc);
- if (ebother != NULL) {
- ec = ebother->prev; /* note: this is in direction c --> d*/
- vc = bvc->v;
- kc = ec->offset_l_spec;
- vd = ec->is_rev ? ec->e->v1 : ec->e->v2;
- }
- else {
- /* No bevvert for w, so C can't be beveled */
- kc = 0.0f;
- ec = NULL;
- /* Find an edge from c that has same face */
- lb = BM_face_edge_share_loop(eb->fnext, eb->e);
- if (!lb) {
- return no_collide_offset;
- }
- if (lb->next->v == vc) {
- vd = lb->next->next->v;
- }
- else if (lb->v == vc) {
- vd = lb->prev->v;
- }
- else {
- return no_collide_offset;
- }
- }
- if (ea->e == eb->e || (ec && ec->e == eb->e)) {
- return no_collide_offset;
- }
- ka = ka / bp->offset;
- kb = kb / bp->offset;
- kc = kc / bp->offset;
- th1 = angle_v3v3v3(va->co, vb->co, vc->co);
- th2 = angle_v3v3v3(vb->co, vc->co, vd->co);
-
- /* First calculate offset at which edge B collapses, which happens
- * when advancing clones of A, B, C all meet at a point.
- * This only happens if at least two of those three edges have non-zero k's */
- sin1 = sinf(th1);
- sin2 = sinf(th2);
- if ((ka > 0.0f) + (kb > 0.0f) + (kc > 0.0f) >= 2) {
- tan1 = tanf(th1);
- tan2 = tanf(th2);
- g = tan1 * tan2;
- h = sin1 * sin2;
- den = g * (ka * sin2 + kc * sin1) + kb * h * (tan1 + tan2);
- if (den != 0.0f) {
- t = BM_edge_calc_length(eb->e);
- t *= g * h / den;
- if (t >= 0.0f) {
- limit = t;
- }
- }
- }
-
- /* Now check edge slide cases */
- if (kb > 0.0f && ka == 0.0f /*&& bvb->selcount == 1 && bvb->edgecount > 2*/) {
- t = BM_edge_calc_length(ea->e);
- t *= sin1 / kb;
- if (t >= 0.0f && t < limit) {
- limit = t;
- }
- }
- if (kb > 0.0f && kc == 0.0f /* && bvc && ec && bvc->selcount == 1 && bvc->edgecount > 2 */) {
- t = BM_edge_calc_length(ec->e);
- t *= sin2 / kb;
- if (t >= 0.0f && t < limit) {
- limit = t;
- }
- }
- return limit;
+ EdgeHalf *ea, *ec, *ebother;
+ BevVert *bvc;
+ BMLoop *lb;
+ BMVert *va, *vb, *vc, *vd;
+ float ka, kb, kc, g, h, t, den, no_collide_offset, th1, th2, sin1, sin2, tan1, tan2, limit;
+
+ limit = no_collide_offset = bp->offset + 1e6;
+ if (bp->offset == 0.0f) {
+ return no_collide_offset;
+ }
+ kb = eb->offset_l_spec;
+ ea = eb->next; /* note: this is in direction b --> a */
+ ka = ea->offset_r_spec;
+ if (eb->is_rev) {
+ vc = eb->e->v1;
+ vb = eb->e->v2;
+ }
+ else {
+ vb = eb->e->v1;
+ vc = eb->e->v2;
+ }
+ va = ea->is_rev ? ea->e->v1 : ea->e->v2;
+ bvc = NULL;
+ ebother = find_other_end_edge_half(bp, eb, &bvc);
+ if (ebother != NULL) {
+ ec = ebother->prev; /* note: this is in direction c --> d*/
+ vc = bvc->v;
+ kc = ec->offset_l_spec;
+ vd = ec->is_rev ? ec->e->v1 : ec->e->v2;
+ }
+ else {
+ /* No bevvert for w, so C can't be beveled */
+ kc = 0.0f;
+ ec = NULL;
+ /* Find an edge from c that has same face */
+ lb = BM_face_edge_share_loop(eb->fnext, eb->e);
+ if (!lb) {
+ return no_collide_offset;
+ }
+ if (lb->next->v == vc) {
+ vd = lb->next->next->v;
+ }
+ else if (lb->v == vc) {
+ vd = lb->prev->v;
+ }
+ else {
+ return no_collide_offset;
+ }
+ }
+ if (ea->e == eb->e || (ec && ec->e == eb->e)) {
+ return no_collide_offset;
+ }
+ ka = ka / bp->offset;
+ kb = kb / bp->offset;
+ kc = kc / bp->offset;
+ th1 = angle_v3v3v3(va->co, vb->co, vc->co);
+ th2 = angle_v3v3v3(vb->co, vc->co, vd->co);
+
+ /* First calculate offset at which edge B collapses, which happens
+ * when advancing clones of A, B, C all meet at a point.
+ * This only happens if at least two of those three edges have non-zero k's */
+ sin1 = sinf(th1);
+ sin2 = sinf(th2);
+ if ((ka > 0.0f) + (kb > 0.0f) + (kc > 0.0f) >= 2) {
+ tan1 = tanf(th1);
+ tan2 = tanf(th2);
+ g = tan1 * tan2;
+ h = sin1 * sin2;
+ den = g * (ka * sin2 + kc * sin1) + kb * h * (tan1 + tan2);
+ if (den != 0.0f) {
+ t = BM_edge_calc_length(eb->e);
+ t *= g * h / den;
+ if (t >= 0.0f) {
+ limit = t;
+ }
+ }
+ }
+
+ /* Now check edge slide cases */
+ if (kb > 0.0f && ka == 0.0f /*&& bvb->selcount == 1 && bvb->edgecount > 2*/) {
+ t = BM_edge_calc_length(ea->e);
+ t *= sin1 / kb;
+ if (t >= 0.0f && t < limit) {
+ limit = t;
+ }
+ }
+ if (kb > 0.0f && kc == 0.0f /* && bvc && ec && bvc->selcount == 1 && bvc->edgecount > 2 */) {
+ t = BM_edge_calc_length(ec->e);
+ t *= sin2 / kb;
+ if (t >= 0.0f && t < limit) {
+ limit = t;
+ }
+ }
+ return limit;
}
/*
@@ -6257,23 +6319,23 @@ static float geometry_collide_offset(BevelParams *bp, EdgeHalf *eb)
*/
static float vertex_collide_offset(BevelParams *bp, EdgeHalf *ea)
{
- float limit, ka, kb, no_collide_offset, la, kab;
- EdgeHalf *eb;
-
- limit = no_collide_offset = bp->offset + 1e6;
- if (bp->offset == 0.0f) {
- return no_collide_offset;
- }
- ka = ea->offset_l_spec / bp->offset;
- eb = find_other_end_edge_half(bp, ea, NULL);
- kb = eb ? eb->offset_l_spec / bp->offset : 0.0f;
- kab = ka + kb;
- la = BM_edge_calc_length(ea->e);
- if (kab <= 0.0f) {
- return no_collide_offset;
- }
- limit = la / kab;
- return limit;
+ float limit, ka, kb, no_collide_offset, la, kab;
+ EdgeHalf *eb;
+
+ limit = no_collide_offset = bp->offset + 1e6;
+ if (bp->offset == 0.0f) {
+ return no_collide_offset;
+ }
+ ka = ea->offset_l_spec / bp->offset;
+ eb = find_other_end_edge_half(bp, ea, NULL);
+ kb = eb ? eb->offset_l_spec / bp->offset : 0.0f;
+ kab = ka + kb;
+ la = BM_edge_calc_length(ea->e);
+ if (kab <= 0.0f) {
+ return no_collide_offset;
+ }
+ limit = la / kab;
+ return limit;
}
/*
@@ -6286,60 +6348,60 @@ static float vertex_collide_offset(BevelParams *bp, EdgeHalf *ea)
*/
static void bevel_limit_offset(BevelParams *bp, BMesh *bm)
{
- BevVert *bv;
- EdgeHalf *eh;
- BMIter iter;
- BMVert *bmv;
- float limited_offset, offset_factor, collision_offset;
- int i;
-
- limited_offset = bp->offset;
- BM_ITER_MESH(bmv, &iter, bm, BM_VERTS_OF_MESH) {
- if (!BM_elem_flag_test(bmv, BM_ELEM_TAG))
- continue;
- bv = find_bevvert(bp, bmv);
- if (!bv)
- continue;
- for (i = 0; i < bv->edgecount; i++) {
- eh = &bv->edges[i];
- if (bp->vertex_only) {
- collision_offset = vertex_collide_offset(bp, eh);
- if (collision_offset < limited_offset) {
- limited_offset = collision_offset;
- }
- }
- else {
- collision_offset = geometry_collide_offset(bp, eh);
- if (collision_offset < limited_offset) {
- limited_offset = collision_offset;
- }
- }
- }
- }
-
- if (limited_offset < bp->offset) {
- /* All current offset specs have some number times bp->offset,
- * so we can just multiply them all by the reduction factor
- * of the offset to have the effect of recalculating the specs
- * with the new limited_offset.
- */
- offset_factor = limited_offset / bp->offset;
- BM_ITER_MESH(bmv, &iter, bm, BM_VERTS_OF_MESH) {
- if (!BM_elem_flag_test(bmv, BM_ELEM_TAG))
- continue;
- bv = find_bevvert(bp, bmv);
- if (!bv)
- continue;
- for (i = 0; i < bv->edgecount; i++) {
- eh = &bv->edges[i];
- eh->offset_l_spec *= offset_factor;
- eh->offset_r_spec *= offset_factor;
- eh->offset_l *= offset_factor;
- eh->offset_r *= offset_factor;
- }
- }
- bp->offset = limited_offset;
- }
+ BevVert *bv;
+ EdgeHalf *eh;
+ BMIter iter;
+ BMVert *bmv;
+ float limited_offset, offset_factor, collision_offset;
+ int i;
+
+ limited_offset = bp->offset;
+ BM_ITER_MESH (bmv, &iter, bm, BM_VERTS_OF_MESH) {
+ if (!BM_elem_flag_test(bmv, BM_ELEM_TAG))
+ continue;
+ bv = find_bevvert(bp, bmv);
+ if (!bv)
+ continue;
+ for (i = 0; i < bv->edgecount; i++) {
+ eh = &bv->edges[i];
+ if (bp->vertex_only) {
+ collision_offset = vertex_collide_offset(bp, eh);
+ if (collision_offset < limited_offset) {
+ limited_offset = collision_offset;
+ }
+ }
+ else {
+ collision_offset = geometry_collide_offset(bp, eh);
+ if (collision_offset < limited_offset) {
+ limited_offset = collision_offset;
+ }
+ }
+ }
+ }
+
+ if (limited_offset < bp->offset) {
+ /* All current offset specs have some number times bp->offset,
+ * so we can just multiply them all by the reduction factor
+ * of the offset to have the effect of recalculating the specs
+ * with the new limited_offset.
+ */
+ offset_factor = limited_offset / bp->offset;
+ BM_ITER_MESH (bmv, &iter, bm, BM_VERTS_OF_MESH) {
+ if (!BM_elem_flag_test(bmv, BM_ELEM_TAG))
+ continue;
+ bv = find_bevvert(bp, bmv);
+ if (!bv)
+ continue;
+ for (i = 0; i < bv->edgecount; i++) {
+ eh = &bv->edges[i];
+ eh->offset_l_spec *= offset_factor;
+ eh->offset_r_spec *= offset_factor;
+ eh->offset_l *= offset_factor;
+ eh->offset_r *= offset_factor;
+ }
+ }
+ bp->offset = limited_offset;
+ }
}
/**
@@ -6354,168 +6416,179 @@ static void bevel_limit_offset(BevelParams *bp, BMesh *bm)
*
* \warning all tagged edges _must_ be manifold.
*/
-void BM_mesh_bevel(
- BMesh *bm, const float offset, const int offset_type,
- const float segments, const float profile,
- const bool vertex_only, const bool use_weights, const bool limit_offset,
- const struct MDeformVert *dvert, const int vertex_group, const int mat,
- const bool loop_slide, const bool mark_seam, const bool mark_sharp,
- const bool harden_normals, const int face_strength_mode,
- const int miter_outer, const int miter_inner, const float spread,
- const float smoothresh)
+void BM_mesh_bevel(BMesh *bm,
+ const float offset,
+ const int offset_type,
+ const float segments,
+ const float profile,
+ const bool vertex_only,
+ const bool use_weights,
+ const bool limit_offset,
+ const struct MDeformVert *dvert,
+ const int vertex_group,
+ const int mat,
+ const bool loop_slide,
+ const bool mark_seam,
+ const bool mark_sharp,
+ const bool harden_normals,
+ const int face_strength_mode,
+ const int miter_outer,
+ const int miter_inner,
+ const float spread,
+ const float smoothresh)
{
- BMIter iter, liter;
- BMVert *v, *v_next;
- BMEdge *e;
- BMFace *f;
- BMLoop *l;
- BevVert *bv;
- BevelParams bp = {NULL};
-
- bp.offset = offset;
- bp.offset_type = offset_type;
- bp.seg = segments;
- bp.profile = profile;
- bp.pro_super_r = -log(2.0) / log(sqrt(profile)); /* convert to superellipse exponent */
- bp.vertex_only = vertex_only;
- bp.use_weights = use_weights;
- bp.loop_slide = loop_slide;
- bp.limit_offset = limit_offset;
- bp.offset_adjust = true;
- bp.dvert = dvert;
- bp.vertex_group = vertex_group;
- bp.mat_nr = mat;
- bp.mark_seam = mark_seam;
- bp.mark_sharp = mark_sharp;
- bp.harden_normals = harden_normals;
- bp.face_strength_mode = face_strength_mode;
- bp.miter_outer = miter_outer;
- bp.miter_inner = miter_inner;
- bp.spread = spread;
- bp.smoothresh = smoothresh;
- bp.face_hash = NULL;
-
- if (profile >= 0.950f) { /* r ~ 692, so PRO_SQUARE_R is 1e4 */
- bp.pro_super_r = PRO_SQUARE_R;
- }
-
- if (bp.offset > 0) {
- /* primary alloc */
- bp.vert_hash = BLI_ghash_ptr_new(__func__);
- bp.mem_arena = BLI_memarena_new(MEM_SIZE_OPTIMAL(1 << 16), __func__);
- BLI_memarena_use_calloc(bp.mem_arena);
- set_profile_spacing(&bp);
-
- bp.face_hash = BLI_ghash_ptr_new(__func__);
- BLI_ghash_flag_set(bp.face_hash, GHASH_FLAG_ALLOW_DUPES);
-
- /* Analyze input vertices, sorting edges and assigning initial new vertex positions */
- BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
- if (BM_elem_flag_test(v, BM_ELEM_TAG)) {
- bv = bevel_vert_construct(bm, &bp, v);
- if (!limit_offset && bv) {
- build_boundary(&bp, bv, true);
- }
- }
- }
-
- /* Perhaps clamp offset to avoid geometry colliisions */
- if (limit_offset) {
- bevel_limit_offset(&bp, bm);
-
- /* Assign initial new vertex positions */
- BM_ITER_MESH(v, &iter, bm, BM_VERTS_OF_MESH) {
- if (BM_elem_flag_test(v, BM_ELEM_TAG)) {
- bv = find_bevvert(&bp, v);
- if (bv)
- build_boundary(&bp, bv, true);
- }
- }
- }
-
- /* Perhaps do a pass to try to even out widths */
- if (!bp.vertex_only && bp.offset_adjust && bp.offset_type != BEVEL_AMT_PERCENT) {
- adjust_offsets(&bp, bm);
- }
-
- /* Build the meshes around vertices, now that positions are final */
- BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
- if (BM_elem_flag_test(v, BM_ELEM_TAG)) {
- bv = find_bevvert(&bp, v);
- if (bv) {
- build_vmesh(&bp, bm, bv);
- }
- }
- }
-
- /* Build polygons for edges */
- if (!bp.vertex_only) {
- BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
- if (BM_elem_flag_test(e, BM_ELEM_TAG)) {
- bevel_build_edge_polygons(bm, &bp, e);
- }
- }
- }
-
- /* Extend edge data like sharp edges and precompute normals for harden */
- BM_ITER_MESH(v, &iter, bm, BM_VERTS_OF_MESH) {
- if (BM_elem_flag_test(v, BM_ELEM_TAG)) {
- bv = find_bevvert(&bp, v);
- if (bv)
- bevel_extend_edge_data(bv);
- }
- }
-
- /* Rebuild face polygons around affected vertices */
- BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
- if (BM_elem_flag_test(v, BM_ELEM_TAG)) {
- bevel_rebuild_existing_polygons(bm, &bp, v);
- bevel_reattach_wires(bm, &bp, v);
- }
- }
-
- BM_ITER_MESH_MUTABLE (v, v_next, &iter, bm, BM_VERTS_OF_MESH) {
- if (BM_elem_flag_test(v, BM_ELEM_TAG)) {
- BLI_assert(find_bevvert(&bp, v) != NULL);
- BM_vert_kill(bm, v);
- }
- }
-
- if (bp.harden_normals) {
- bevel_harden_normals(bm, &bp);
- }
- if (bp.face_strength_mode != BEVEL_FACE_STRENGTH_NONE) {
- bevel_set_weighted_normal_face_strength(bm, &bp);
- }
-
- /* When called from operator (as opposed to modifier), bm->use_toolflags
- * will be set, and we to transfer the oflags to BM_ELEM_TAGs */
- if (bm->use_toolflags) {
- BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
- if (BMO_vert_flag_test(bm, v, VERT_OUT)) {
- BM_elem_flag_enable(v, BM_ELEM_TAG);
- }
- }
- BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
- if (BMO_edge_flag_test(bm, e, EDGE_OUT)) {
- BM_elem_flag_enable(e, BM_ELEM_TAG);
- }
- }
- }
-
- /* clear the BM_ELEM_LONG_TAG tags, which were only set on some edges in F_EDGE faces */
- BM_ITER_MESH(f, &iter, bm, BM_FACES_OF_MESH) {
- if (get_face_kind(&bp, f) != F_EDGE) {
- continue;
- }
- BM_ITER_ELEM(l, &liter, f, BM_LOOPS_OF_FACE) {
- BM_elem_flag_disable(l, BM_ELEM_LONG_TAG);
- }
- }
-
- /* primary free */
- BLI_ghash_free(bp.vert_hash, NULL, NULL);
- BLI_ghash_free(bp.face_hash, NULL, NULL);
- BLI_memarena_free(bp.mem_arena);
- }
+ BMIter iter, liter;
+ BMVert *v, *v_next;
+ BMEdge *e;
+ BMFace *f;
+ BMLoop *l;
+ BevVert *bv;
+ BevelParams bp = {NULL};
+
+ bp.offset = offset;
+ bp.offset_type = offset_type;
+ bp.seg = segments;
+ bp.profile = profile;
+ bp.pro_super_r = -log(2.0) / log(sqrt(profile)); /* convert to superellipse exponent */
+ bp.vertex_only = vertex_only;
+ bp.use_weights = use_weights;
+ bp.loop_slide = loop_slide;
+ bp.limit_offset = limit_offset;
+ bp.offset_adjust = true;
+ bp.dvert = dvert;
+ bp.vertex_group = vertex_group;
+ bp.mat_nr = mat;
+ bp.mark_seam = mark_seam;
+ bp.mark_sharp = mark_sharp;
+ bp.harden_normals = harden_normals;
+ bp.face_strength_mode = face_strength_mode;
+ bp.miter_outer = miter_outer;
+ bp.miter_inner = miter_inner;
+ bp.spread = spread;
+ bp.smoothresh = smoothresh;
+ bp.face_hash = NULL;
+
+ if (profile >= 0.950f) { /* r ~ 692, so PRO_SQUARE_R is 1e4 */
+ bp.pro_super_r = PRO_SQUARE_R;
+ }
+
+ if (bp.offset > 0) {
+ /* primary alloc */
+ bp.vert_hash = BLI_ghash_ptr_new(__func__);
+ bp.mem_arena = BLI_memarena_new(MEM_SIZE_OPTIMAL(1 << 16), __func__);
+ BLI_memarena_use_calloc(bp.mem_arena);
+ set_profile_spacing(&bp);
+
+ bp.face_hash = BLI_ghash_ptr_new(__func__);
+ BLI_ghash_flag_set(bp.face_hash, GHASH_FLAG_ALLOW_DUPES);
+
+ /* Analyze input vertices, sorting edges and assigning initial new vertex positions */
+ BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
+ if (BM_elem_flag_test(v, BM_ELEM_TAG)) {
+ bv = bevel_vert_construct(bm, &bp, v);
+ if (!limit_offset && bv) {
+ build_boundary(&bp, bv, true);
+ }
+ }
+ }
+
+ /* Perhaps clamp offset to avoid geometry colliisions */
+ if (limit_offset) {
+ bevel_limit_offset(&bp, bm);
+
+ /* Assign initial new vertex positions */
+ BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
+ if (BM_elem_flag_test(v, BM_ELEM_TAG)) {
+ bv = find_bevvert(&bp, v);
+ if (bv)
+ build_boundary(&bp, bv, true);
+ }
+ }
+ }
+
+ /* Perhaps do a pass to try to even out widths */
+ if (!bp.vertex_only && bp.offset_adjust && bp.offset_type != BEVEL_AMT_PERCENT) {
+ adjust_offsets(&bp, bm);
+ }
+
+ /* Build the meshes around vertices, now that positions are final */
+ BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
+ if (BM_elem_flag_test(v, BM_ELEM_TAG)) {
+ bv = find_bevvert(&bp, v);
+ if (bv) {
+ build_vmesh(&bp, bm, bv);
+ }
+ }
+ }
+
+ /* Build polygons for edges */
+ if (!bp.vertex_only) {
+ BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
+ if (BM_elem_flag_test(e, BM_ELEM_TAG)) {
+ bevel_build_edge_polygons(bm, &bp, e);
+ }
+ }
+ }
+
+ /* Extend edge data like sharp edges and precompute normals for harden */
+ BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
+ if (BM_elem_flag_test(v, BM_ELEM_TAG)) {
+ bv = find_bevvert(&bp, v);
+ if (bv)
+ bevel_extend_edge_data(bv);
+ }
+ }
+
+ /* Rebuild face polygons around affected vertices */
+ BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
+ if (BM_elem_flag_test(v, BM_ELEM_TAG)) {
+ bevel_rebuild_existing_polygons(bm, &bp, v);
+ bevel_reattach_wires(bm, &bp, v);
+ }
+ }
+
+ BM_ITER_MESH_MUTABLE (v, v_next, &iter, bm, BM_VERTS_OF_MESH) {
+ if (BM_elem_flag_test(v, BM_ELEM_TAG)) {
+ BLI_assert(find_bevvert(&bp, v) != NULL);
+ BM_vert_kill(bm, v);
+ }
+ }
+
+ if (bp.harden_normals) {
+ bevel_harden_normals(bm, &bp);
+ }
+ if (bp.face_strength_mode != BEVEL_FACE_STRENGTH_NONE) {
+ bevel_set_weighted_normal_face_strength(bm, &bp);
+ }
+
+ /* When called from operator (as opposed to modifier), bm->use_toolflags
+ * will be set, and we to transfer the oflags to BM_ELEM_TAGs */
+ if (bm->use_toolflags) {
+ BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
+ if (BMO_vert_flag_test(bm, v, VERT_OUT)) {
+ BM_elem_flag_enable(v, BM_ELEM_TAG);
+ }
+ }
+ BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
+ if (BMO_edge_flag_test(bm, e, EDGE_OUT)) {
+ BM_elem_flag_enable(e, BM_ELEM_TAG);
+ }
+ }
+ }
+
+ /* clear the BM_ELEM_LONG_TAG tags, which were only set on some edges in F_EDGE faces */
+ BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
+ if (get_face_kind(&bp, f) != F_EDGE) {
+ continue;
+ }
+ BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
+ BM_elem_flag_disable(l, BM_ELEM_LONG_TAG);
+ }
+ }
+
+ /* primary free */
+ BLI_ghash_free(bp.vert_hash, NULL, NULL);
+ BLI_ghash_free(bp.face_hash, NULL, NULL);
+ BLI_memarena_free(bp.mem_arena);
+ }
}
diff --git a/source/blender/bmesh/tools/bmesh_bevel.h b/source/blender/bmesh/tools/bmesh_bevel.h
index f45a3bec93a..496be9219b7 100644
--- a/source/blender/bmesh/tools/bmesh_bevel.h
+++ b/source/blender/bmesh/tools/bmesh_bevel.h
@@ -23,12 +23,25 @@
struct MDeformVert;
-void BM_mesh_bevel(
- BMesh *bm, const float offset, const int offset_type, const float segments,
- const float profile, const bool vertex_only, const bool use_weights,
- const bool limit_offset, const struct MDeformVert *dvert, const int vertex_group,
- const int mat, const bool loop_slide, const bool mark_seam, const bool mark_sharp,
- const bool harden_normals, const int face_strength_mode, const int miter_outer,
- const int miter_inner, const float spread, const float smoothresh);
+void BM_mesh_bevel(BMesh *bm,
+ const float offset,
+ const int offset_type,
+ const float segments,
+ const float profile,
+ const bool vertex_only,
+ const bool use_weights,
+ const bool limit_offset,
+ const struct MDeformVert *dvert,
+ const int vertex_group,
+ const int mat,
+ const bool loop_slide,
+ const bool mark_seam,
+ const bool mark_sharp,
+ const bool harden_normals,
+ const int face_strength_mode,
+ const int miter_outer,
+ const int miter_inner,
+ const float spread,
+ const float smoothresh);
#endif /* __BMESH_BEVEL_H__ */
diff --git a/source/blender/bmesh/tools/bmesh_bisect_plane.c b/source/blender/bmesh/tools/bmesh_bisect_plane.c
index da7feff70e6..f314ae6848b 100644
--- a/source/blender/bmesh/tools/bmesh_bisect_plane.c
+++ b/source/blender/bmesh/tools/bmesh_bisect_plane.c
@@ -39,36 +39,43 @@
#include "BLI_math.h"
#include "bmesh.h"
-#include "bmesh_bisect_plane.h" /* own include */
-
-#include "BLI_strict_flags.h" /* keep last */
+#include "bmesh_bisect_plane.h" /* own include */
+#include "BLI_strict_flags.h" /* keep last */
/* -------------------------------------------------------------------- */
/* Math utils */
-static short plane_point_test_v3(const float plane[4], const float co[3], const float eps, float *r_depth)
+static short plane_point_test_v3(const float plane[4],
+ const float co[3],
+ const float eps,
+ float *r_depth)
{
- const float f = plane_point_side_v3(plane, co);
- *r_depth = f;
-
- if (f <= -eps) { return -1; }
- else if (f >= eps) { return 1; }
- else { return 0; }
+ const float f = plane_point_side_v3(plane, co);
+ *r_depth = f;
+
+ if (f <= -eps) {
+ return -1;
+ }
+ else if (f >= eps) {
+ return 1;
+ }
+ else {
+ return 0;
+ }
}
-
/* -------------------------------------------------------------------- */
/* Wrappers to hide internal data-structure abuse,
* later we may want to move this into some hash lookup
* to a separate struct, but for now we can store in BMesh data */
-#define BM_VERT_DIR(v) ((short *)(&(v)->head.index))[0] /* Direction -1/0/1 */
-#define BM_VERT_SKIP(v) ((short *)(&(v)->head.index))[1] /* Skip Vert 0/1 */
-#define BM_VERT_DIST(v) ((v)->no[0]) /* Distance from the plane. */
-#define BM_VERT_SORTVAL(v) ((v)->no[1]) /* Temp value for sorting. */
-#define BM_VERT_LOOPINDEX(v) /* The verts index within a face (temp var) */ \
- (*((uint *)(&(v)->no[2])))
+#define BM_VERT_DIR(v) ((short *)(&(v)->head.index))[0] /* Direction -1/0/1 */
+#define BM_VERT_SKIP(v) ((short *)(&(v)->head.index))[1] /* Skip Vert 0/1 */
+#define BM_VERT_DIST(v) ((v)->no[0]) /* Distance from the plane. */
+#define BM_VERT_SORTVAL(v) ((v)->no[1]) /* Temp value for sorting. */
+#define BM_VERT_LOOPINDEX(v) /* The verts index within a face (temp var) */ \
+ (*((uint *)(&(v)->no[2])))
/**
* Hide flag access
@@ -76,220 +83,247 @@ static short plane_point_test_v3(const float plane[4], const float co[3], const
*/
/* enable when vertex is in the center and its faces have been added to the stack */
-BLI_INLINE void vert_is_center_enable(BMVert *v) { BM_elem_flag_enable(v, BM_ELEM_TAG); }
-BLI_INLINE void vert_is_center_disable(BMVert *v) { BM_elem_flag_disable(v, BM_ELEM_TAG); }
-BLI_INLINE bool vert_is_center_test(BMVert *v) { return (BM_elem_flag_test(v, BM_ELEM_TAG) != 0); }
+BLI_INLINE void vert_is_center_enable(BMVert *v)
+{
+ BM_elem_flag_enable(v, BM_ELEM_TAG);
+}
+BLI_INLINE void vert_is_center_disable(BMVert *v)
+{
+ BM_elem_flag_disable(v, BM_ELEM_TAG);
+}
+BLI_INLINE bool vert_is_center_test(BMVert *v)
+{
+ return (BM_elem_flag_test(v, BM_ELEM_TAG) != 0);
+}
/* enable when the edge can be cut */
-BLI_INLINE void edge_is_cut_enable(BMEdge *e) { BM_elem_flag_enable(e, BM_ELEM_TAG); }
-BLI_INLINE void edge_is_cut_disable(BMEdge *e) { BM_elem_flag_disable(e, BM_ELEM_TAG); }
-BLI_INLINE bool edge_is_cut_test(BMEdge *e) { return (BM_elem_flag_test(e, BM_ELEM_TAG) != 0); }
+BLI_INLINE void edge_is_cut_enable(BMEdge *e)
+{
+ BM_elem_flag_enable(e, BM_ELEM_TAG);
+}
+BLI_INLINE void edge_is_cut_disable(BMEdge *e)
+{
+ BM_elem_flag_disable(e, BM_ELEM_TAG);
+}
+BLI_INLINE bool edge_is_cut_test(BMEdge *e)
+{
+ return (BM_elem_flag_test(e, BM_ELEM_TAG) != 0);
+}
/* enable when the faces are added to the stack */
-BLI_INLINE void face_in_stack_enable(BMFace *f) { BM_elem_flag_disable(f, BM_ELEM_TAG); }
-BLI_INLINE void face_in_stack_disable(BMFace *f) { BM_elem_flag_enable(f, BM_ELEM_TAG); }
-BLI_INLINE bool face_in_stack_test(BMFace *f) { return (BM_elem_flag_test(f, BM_ELEM_TAG) == 0); }
+BLI_INLINE void face_in_stack_enable(BMFace *f)
+{
+ BM_elem_flag_disable(f, BM_ELEM_TAG);
+}
+BLI_INLINE void face_in_stack_disable(BMFace *f)
+{
+ BM_elem_flag_enable(f, BM_ELEM_TAG);
+}
+BLI_INLINE bool face_in_stack_test(BMFace *f)
+{
+ return (BM_elem_flag_test(f, BM_ELEM_TAG) == 0);
+}
/* -------------------------------------------------------------------- */
/* BMesh utils */
static int bm_vert_sortval_cb(const void *v_a_v, const void *v_b_v)
{
- const float val_a = BM_VERT_SORTVAL(*((BMVert **)v_a_v));
- const float val_b = BM_VERT_SORTVAL(*((BMVert **)v_b_v));
-
- if (val_a > val_b) { return 1; }
- else if (val_a < val_b) { return -1; }
- else { return 0; }
+ const float val_a = BM_VERT_SORTVAL(*((BMVert **)v_a_v));
+ const float val_b = BM_VERT_SORTVAL(*((BMVert **)v_b_v));
+
+ if (val_a > val_b) {
+ return 1;
+ }
+ else if (val_a < val_b) {
+ return -1;
+ }
+ else {
+ return 0;
+ }
}
-
-static void bm_face_bisect_verts(BMesh *bm, BMFace *f, const float plane[4], const short oflag_center, const short oflag_new)
+static void bm_face_bisect_verts(
+ BMesh *bm, BMFace *f, const float plane[4], const short oflag_center, const short oflag_new)
{
- /* unlikely more than 2 verts are needed */
- const uint f_len_orig = (uint)f->len;
- BMVert **vert_split_arr = BLI_array_alloca(vert_split_arr, f_len_orig);
- STACK_DECLARE(vert_split_arr);
- BMLoop *l_iter, *l_first;
- bool use_dirs[3] = {false, false, false};
- bool is_inside = false;
-
- STACK_INIT(vert_split_arr, f_len_orig);
-
- l_first = BM_FACE_FIRST_LOOP(f);
-
- /* add plane-aligned verts to the stack
- * and check we have verts from both sides in this face,
- * ... that the face doesn't only have boundary verts on the plane for eg. */
- l_iter = l_first;
- do {
- if (vert_is_center_test(l_iter->v)) {
- BLI_assert(BM_VERT_DIR(l_iter->v) == 0);
-
- /* if both are -1 or 1, or both are zero:
- * don't flip 'inside' var while walking */
- BM_VERT_SKIP(l_iter->v) = (((BM_VERT_DIR(l_iter->prev->v) ^ BM_VERT_DIR(l_iter->next->v))) == 0);
-
- STACK_PUSH(vert_split_arr, l_iter->v);
- }
- use_dirs[BM_VERT_DIR(l_iter->v) + 1] = true;
- } while ((l_iter = l_iter->next) != l_first);
-
- if ((STACK_SIZE(vert_split_arr) > 1) &&
- (use_dirs[0] && use_dirs[2]))
- {
- if (LIKELY(STACK_SIZE(vert_split_arr) == 2)) {
- BMLoop *l_new;
- BMLoop *l_a, *l_b;
-
- l_a = BM_face_vert_share_loop(f, vert_split_arr[0]);
- l_b = BM_face_vert_share_loop(f, vert_split_arr[1]);
-
- /* common case, just cut the face once */
- BM_face_split(bm, f, l_a, l_b, &l_new, NULL, true);
- if (l_new) {
- if (oflag_center | oflag_new) {
- BMO_edge_flag_enable(bm, l_new->e, oflag_center | oflag_new);
- }
- if (oflag_new) {
- BMO_face_flag_enable(bm, l_new->f, oflag_new);
- }
- }
- }
- else {
- /* less common case, _complicated_ we need to calculate how to do multiple cuts */
- float (*face_verts_proj_2d)[2] = BLI_array_alloca(face_verts_proj_2d, f_len_orig);
- float axis_mat[3][3];
-
- BMFace **face_split_arr = BLI_array_alloca(face_split_arr, STACK_SIZE(vert_split_arr));
- STACK_DECLARE(face_split_arr);
-
- float sort_dir[3];
- uint i;
-
-
- /* ---- */
- /* Calculate the direction to sort verts in the face intersecting the plane */
-
- /* exact dir isn't so important,
- * just need a dir for sorting verts across face,
- * 'sort_dir' could be flipped either way, it not important, we only need to order the array
- */
- cross_v3_v3v3(sort_dir, f->no, plane);
- if (UNLIKELY(normalize_v3(sort_dir) == 0.0f)) {
- /* find any 2 verts and get their direction */
- for (i = 0; i < STACK_SIZE(vert_split_arr); i++) {
- if (!equals_v3v3(vert_split_arr[0]->co, vert_split_arr[i]->co)) {
- sub_v3_v3v3(sort_dir, vert_split_arr[0]->co, vert_split_arr[i]->co);
- normalize_v3(sort_dir);
- }
- }
- if (UNLIKELY(i == STACK_SIZE(vert_split_arr))) {
- /* ok, we can't do anything useful here,
- * face has no area or so, bail out, this is highly unlikely but not impossible */
- goto finally;
- }
- }
-
-
- /* ---- */
- /* Calculate 2d coords to use for intersection checks */
-
- /* get the faces 2d coords */
- BLI_assert(BM_face_is_normal_valid(f));
- axis_dominant_v3_to_m3(axis_mat, f->no);
-
- l_iter = l_first;
- i = 0;
- do {
- BM_VERT_LOOPINDEX(l_iter->v) = i;
- mul_v2_m3v3(face_verts_proj_2d[i], axis_mat, l_iter->v->co);
- i++;
- } while ((l_iter = l_iter->next) != l_first);
-
-
- /* ---- */
- /* Sort the verts across the face from one side to another */
- for (i = 0; i < STACK_SIZE(vert_split_arr); i++) {
- BMVert *v = vert_split_arr[i];
- BM_VERT_SORTVAL(v) = dot_v3v3(sort_dir, v->co);
- }
-
- qsort(vert_split_arr, STACK_SIZE(vert_split_arr), sizeof(*vert_split_arr), bm_vert_sortval_cb);
-
-
- /* ---- */
- /* Split the face across sorted splits */
-
- /* note: we don't know which face gets which splits,
- * so at the moment we have to search all faces for the vert pair,
- * while not all that nice, typically there are < 5 resulting faces,
- * so its not _that_ bad. */
-
- STACK_INIT(face_split_arr, STACK_SIZE(vert_split_arr));
- STACK_PUSH(face_split_arr, f);
-
- for (i = 0; i < STACK_SIZE(vert_split_arr) - 1; i++) {
- BMVert *v_a = vert_split_arr[i];
- BMVert *v_b = vert_split_arr[i + 1];
-
- if (!BM_VERT_SKIP(v_a)) {
- is_inside = !is_inside;
- }
-
- if (is_inside) {
- BMLoop *l_a, *l_b;
- bool found = false;
- uint j;
-
- for (j = 0; j < STACK_SIZE(face_split_arr); j++) {
- /* would be nice to avoid loop lookup here,
- * but we need to know which face the verts are in */
- if ((l_a = BM_face_vert_share_loop(face_split_arr[j], v_a)) &&
- (l_b = BM_face_vert_share_loop(face_split_arr[j], v_b)))
- {
- found = true;
- break;
- }
- }
-
- /* ideally wont happen, but it can for self intersecting faces */
- // BLI_assert(found == true);
-
- /* in fact this simple test is good enough,
- * test if the loops are adjacent */
- if (found && !BM_loop_is_adjacent(l_a, l_b)) {
- BMLoop *l_new;
- BMFace *f_tmp;
- f_tmp = BM_face_split(bm, face_split_arr[j], l_a, l_b, &l_new, NULL, true);
-
- if (l_new) {
- if (oflag_center | oflag_new) {
- BMO_edge_flag_enable(bm, l_new->e, oflag_center | oflag_new);
- }
- if (oflag_new) {
- BMO_face_flag_enable(bm, l_new->f, oflag_new);
- }
- }
-
- if (f_tmp) {
- if (f_tmp != face_split_arr[j]) {
- STACK_PUSH(face_split_arr, f_tmp);
- BLI_assert(STACK_SIZE(face_split_arr) <= STACK_SIZE(vert_split_arr));
- }
- }
- }
- }
- else {
- // printf("no intersect\n");
- }
- }
- }
- }
-
+ /* unlikely more than 2 verts are needed */
+ const uint f_len_orig = (uint)f->len;
+ BMVert **vert_split_arr = BLI_array_alloca(vert_split_arr, f_len_orig);
+ STACK_DECLARE(vert_split_arr);
+ BMLoop *l_iter, *l_first;
+ bool use_dirs[3] = {false, false, false};
+ bool is_inside = false;
+
+ STACK_INIT(vert_split_arr, f_len_orig);
+
+ l_first = BM_FACE_FIRST_LOOP(f);
+
+ /* add plane-aligned verts to the stack
+ * and check we have verts from both sides in this face,
+ * ... that the face doesn't only have boundary verts on the plane for eg. */
+ l_iter = l_first;
+ do {
+ if (vert_is_center_test(l_iter->v)) {
+ BLI_assert(BM_VERT_DIR(l_iter->v) == 0);
+
+ /* if both are -1 or 1, or both are zero:
+ * don't flip 'inside' var while walking */
+ BM_VERT_SKIP(l_iter->v) = (((BM_VERT_DIR(l_iter->prev->v) ^ BM_VERT_DIR(l_iter->next->v))) ==
+ 0);
+
+ STACK_PUSH(vert_split_arr, l_iter->v);
+ }
+ use_dirs[BM_VERT_DIR(l_iter->v) + 1] = true;
+ } while ((l_iter = l_iter->next) != l_first);
+
+ if ((STACK_SIZE(vert_split_arr) > 1) && (use_dirs[0] && use_dirs[2])) {
+ if (LIKELY(STACK_SIZE(vert_split_arr) == 2)) {
+ BMLoop *l_new;
+ BMLoop *l_a, *l_b;
+
+ l_a = BM_face_vert_share_loop(f, vert_split_arr[0]);
+ l_b = BM_face_vert_share_loop(f, vert_split_arr[1]);
+
+ /* common case, just cut the face once */
+ BM_face_split(bm, f, l_a, l_b, &l_new, NULL, true);
+ if (l_new) {
+ if (oflag_center | oflag_new) {
+ BMO_edge_flag_enable(bm, l_new->e, oflag_center | oflag_new);
+ }
+ if (oflag_new) {
+ BMO_face_flag_enable(bm, l_new->f, oflag_new);
+ }
+ }
+ }
+ else {
+ /* less common case, _complicated_ we need to calculate how to do multiple cuts */
+ float(*face_verts_proj_2d)[2] = BLI_array_alloca(face_verts_proj_2d, f_len_orig);
+ float axis_mat[3][3];
+
+ BMFace **face_split_arr = BLI_array_alloca(face_split_arr, STACK_SIZE(vert_split_arr));
+ STACK_DECLARE(face_split_arr);
+
+ float sort_dir[3];
+ uint i;
+
+ /* ---- */
+ /* Calculate the direction to sort verts in the face intersecting the plane */
+
+ /* exact dir isn't so important,
+ * just need a dir for sorting verts across face,
+ * 'sort_dir' could be flipped either way, it not important, we only need to order the array
+ */
+ cross_v3_v3v3(sort_dir, f->no, plane);
+ if (UNLIKELY(normalize_v3(sort_dir) == 0.0f)) {
+ /* find any 2 verts and get their direction */
+ for (i = 0; i < STACK_SIZE(vert_split_arr); i++) {
+ if (!equals_v3v3(vert_split_arr[0]->co, vert_split_arr[i]->co)) {
+ sub_v3_v3v3(sort_dir, vert_split_arr[0]->co, vert_split_arr[i]->co);
+ normalize_v3(sort_dir);
+ }
+ }
+ if (UNLIKELY(i == STACK_SIZE(vert_split_arr))) {
+ /* ok, we can't do anything useful here,
+ * face has no area or so, bail out, this is highly unlikely but not impossible */
+ goto finally;
+ }
+ }
+
+ /* ---- */
+ /* Calculate 2d coords to use for intersection checks */
+
+ /* get the faces 2d coords */
+ BLI_assert(BM_face_is_normal_valid(f));
+ axis_dominant_v3_to_m3(axis_mat, f->no);
+
+ l_iter = l_first;
+ i = 0;
+ do {
+ BM_VERT_LOOPINDEX(l_iter->v) = i;
+ mul_v2_m3v3(face_verts_proj_2d[i], axis_mat, l_iter->v->co);
+ i++;
+ } while ((l_iter = l_iter->next) != l_first);
+
+ /* ---- */
+ /* Sort the verts across the face from one side to another */
+ for (i = 0; i < STACK_SIZE(vert_split_arr); i++) {
+ BMVert *v = vert_split_arr[i];
+ BM_VERT_SORTVAL(v) = dot_v3v3(sort_dir, v->co);
+ }
+
+ qsort(
+ vert_split_arr, STACK_SIZE(vert_split_arr), sizeof(*vert_split_arr), bm_vert_sortval_cb);
+
+ /* ---- */
+ /* Split the face across sorted splits */
+
+ /* note: we don't know which face gets which splits,
+ * so at the moment we have to search all faces for the vert pair,
+ * while not all that nice, typically there are < 5 resulting faces,
+ * so its not _that_ bad. */
+
+ STACK_INIT(face_split_arr, STACK_SIZE(vert_split_arr));
+ STACK_PUSH(face_split_arr, f);
+
+ for (i = 0; i < STACK_SIZE(vert_split_arr) - 1; i++) {
+ BMVert *v_a = vert_split_arr[i];
+ BMVert *v_b = vert_split_arr[i + 1];
+
+ if (!BM_VERT_SKIP(v_a)) {
+ is_inside = !is_inside;
+ }
+
+ if (is_inside) {
+ BMLoop *l_a, *l_b;
+ bool found = false;
+ uint j;
+
+ for (j = 0; j < STACK_SIZE(face_split_arr); j++) {
+ /* would be nice to avoid loop lookup here,
+ * but we need to know which face the verts are in */
+ if ((l_a = BM_face_vert_share_loop(face_split_arr[j], v_a)) &&
+ (l_b = BM_face_vert_share_loop(face_split_arr[j], v_b))) {
+ found = true;
+ break;
+ }
+ }
+
+ /* ideally wont happen, but it can for self intersecting faces */
+ // BLI_assert(found == true);
+
+ /* in fact this simple test is good enough,
+ * test if the loops are adjacent */
+ if (found && !BM_loop_is_adjacent(l_a, l_b)) {
+ BMLoop *l_new;
+ BMFace *f_tmp;
+ f_tmp = BM_face_split(bm, face_split_arr[j], l_a, l_b, &l_new, NULL, true);
+
+ if (l_new) {
+ if (oflag_center | oflag_new) {
+ BMO_edge_flag_enable(bm, l_new->e, oflag_center | oflag_new);
+ }
+ if (oflag_new) {
+ BMO_face_flag_enable(bm, l_new->f, oflag_new);
+ }
+ }
+
+ if (f_tmp) {
+ if (f_tmp != face_split_arr[j]) {
+ STACK_PUSH(face_split_arr, f_tmp);
+ BLI_assert(STACK_SIZE(face_split_arr) <= STACK_SIZE(vert_split_arr));
+ }
+ }
+ }
+ }
+ else {
+ // printf("no intersect\n");
+ }
+ }
+ }
+ }
finally:
- (void)vert_split_arr;
+ (void)vert_split_arr;
}
/* -------------------------------------------------------------------- */
@@ -300,163 +334,165 @@ finally:
* \param use_tag: Only bisect tagged edges and faces.
* \param oflag_center: Operator flag, enabled for geometry on the axis (existing and created)
*/
-void BM_mesh_bisect_plane(
- BMesh *bm, const float plane[4],
- const bool use_snap_center, const bool use_tag,
- const short oflag_center, const short oflag_new, const float eps)
+void BM_mesh_bisect_plane(BMesh *bm,
+ const float plane[4],
+ const bool use_snap_center,
+ const bool use_tag,
+ const short oflag_center,
+ const short oflag_new,
+ const float eps)
{
- uint einput_len;
- uint i;
- BMEdge **edges_arr = MEM_mallocN(sizeof(*edges_arr) * (size_t)bm->totedge, __func__);
-
- BLI_LINKSTACK_DECLARE(face_stack, BMFace *);
-
- BMVert *v;
- BMFace *f;
-
- BMIter iter;
-
- if (use_tag) {
- /* build tagged edge array */
- BMEdge *e;
- einput_len = 0;
-
- /* flush edge tags to verts */
- BM_mesh_elem_hflag_disable_all(bm, BM_VERT, BM_ELEM_TAG, false);
-
- /* keep face tags as is */
- BM_ITER_MESH_INDEX (e, &iter, bm, BM_EDGES_OF_MESH, i) {
- if (edge_is_cut_test(e)) {
- edges_arr[einput_len++] = e;
-
- /* flush edge tags to verts */
- BM_elem_flag_enable(e->v1, BM_ELEM_TAG);
- BM_elem_flag_enable(e->v2, BM_ELEM_TAG);
- }
- }
-
- /* face tags are set by caller */
- }
- else {
- BMEdge *e;
- einput_len = (uint)bm->totedge;
- BM_ITER_MESH_INDEX (e, &iter, bm, BM_EDGES_OF_MESH, i) {
- edge_is_cut_enable(e);
- edges_arr[i] = e;
- }
-
- BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
- face_in_stack_disable(f);
- }
- }
-
-
- BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
-
- if (use_tag && !BM_elem_flag_test(v, BM_ELEM_TAG)) {
- vert_is_center_disable(v);
-
- /* these should never be accessed */
- BM_VERT_DIR(v) = 0;
- BM_VERT_DIST(v) = 0.0f;
-
- continue;
- }
-
- vert_is_center_disable(v);
- BM_VERT_DIR(v) = plane_point_test_v3(plane, v->co, eps, &(BM_VERT_DIST(v)));
-
- if (BM_VERT_DIR(v) == 0) {
- if (oflag_center) {
- BMO_vert_flag_enable(bm, v, oflag_center);
- }
- if (use_snap_center) {
- closest_to_plane_v3(v->co, plane, v->co);
- }
- }
- }
-
- /* store a stack of faces to be evaluated for splitting */
- BLI_LINKSTACK_INIT(face_stack);
-
- for (i = 0; i < einput_len; i++) {
- /* we could check edge_is_cut_test(e) but there is no point */
- BMEdge *e = edges_arr[i];
- const int side[2] = {BM_VERT_DIR(e->v1), BM_VERT_DIR(e->v2)};
- const float dist[2] = {BM_VERT_DIST(e->v1), BM_VERT_DIST(e->v2)};
-
- if (side[0] && side[1] && (side[0] != side[1])) {
- const float e_fac = dist[0] / (dist[0] - dist[1]);
- BMVert *v_new;
-
- if (e->l) {
- BMLoop *l_iter, *l_first;
- l_iter = l_first = e->l;
- do {
- if (!face_in_stack_test(l_iter->f)) {
- face_in_stack_enable(l_iter->f);
- BLI_LINKSTACK_PUSH(face_stack, l_iter->f);
- }
- } while ((l_iter = l_iter->radial_next) != l_first);
- }
-
- {
- BMEdge *e_new;
- v_new = BM_edge_split(bm, e, e->v1, &e_new, e_fac);
- if (oflag_new) {
- BMO_edge_flag_enable(bm, e_new, oflag_new);
- }
- }
-
- vert_is_center_enable(v_new);
- if (oflag_new | oflag_center) {
- BMO_vert_flag_enable(bm, v_new, oflag_new | oflag_center);
- }
-
- BM_VERT_DIR(v_new) = 0;
- BM_VERT_DIST(v_new) = 0.0f;
- }
- else if (side[0] == 0 || side[1] == 0) {
- /* check if either edge verts are aligned,
- * if so - tag and push all faces that use it into the stack */
- uint j;
- BM_ITER_ELEM_INDEX (v, &iter, e, BM_VERTS_OF_EDGE, j) {
- if (side[j] == 0) {
- if (vert_is_center_test(v) == 0) {
- BMIter itersub;
- BMLoop *l_iter;
-
- vert_is_center_enable(v);
-
- BM_ITER_ELEM (l_iter, &itersub, v, BM_LOOPS_OF_VERT) {
- if (!face_in_stack_test(l_iter->f)) {
- face_in_stack_enable(l_iter->f);
- BLI_LINKSTACK_PUSH(face_stack, l_iter->f);
- }
- }
-
- }
- }
- }
-
- /* if both verts are on the center - tag it */
- if (oflag_center) {
- if (side[0] == 0 && side[1] == 0) {
- BMO_edge_flag_enable(bm, e, oflag_center);
- }
- }
- }
- }
-
- MEM_freeN(edges_arr);
-
- while ((f = BLI_LINKSTACK_POP(face_stack))) {
- bm_face_bisect_verts(bm, f, plane, oflag_center, oflag_new);
- }
-
- /* Caused by access macros: BM_VERT_DIR, BM_VERT_SKIP. */
- bm->elem_index_dirty |= BM_VERT;
-
- /* now we have all faces to split in the stack */
- BLI_LINKSTACK_FREE(face_stack);
+ uint einput_len;
+ uint i;
+ BMEdge **edges_arr = MEM_mallocN(sizeof(*edges_arr) * (size_t)bm->totedge, __func__);
+
+ BLI_LINKSTACK_DECLARE(face_stack, BMFace *);
+
+ BMVert *v;
+ BMFace *f;
+
+ BMIter iter;
+
+ if (use_tag) {
+ /* build tagged edge array */
+ BMEdge *e;
+ einput_len = 0;
+
+ /* flush edge tags to verts */
+ BM_mesh_elem_hflag_disable_all(bm, BM_VERT, BM_ELEM_TAG, false);
+
+ /* keep face tags as is */
+ BM_ITER_MESH_INDEX (e, &iter, bm, BM_EDGES_OF_MESH, i) {
+ if (edge_is_cut_test(e)) {
+ edges_arr[einput_len++] = e;
+
+ /* flush edge tags to verts */
+ BM_elem_flag_enable(e->v1, BM_ELEM_TAG);
+ BM_elem_flag_enable(e->v2, BM_ELEM_TAG);
+ }
+ }
+
+ /* face tags are set by caller */
+ }
+ else {
+ BMEdge *e;
+ einput_len = (uint)bm->totedge;
+ BM_ITER_MESH_INDEX (e, &iter, bm, BM_EDGES_OF_MESH, i) {
+ edge_is_cut_enable(e);
+ edges_arr[i] = e;
+ }
+
+ BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
+ face_in_stack_disable(f);
+ }
+ }
+
+ BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
+
+ if (use_tag && !BM_elem_flag_test(v, BM_ELEM_TAG)) {
+ vert_is_center_disable(v);
+
+ /* these should never be accessed */
+ BM_VERT_DIR(v) = 0;
+ BM_VERT_DIST(v) = 0.0f;
+
+ continue;
+ }
+
+ vert_is_center_disable(v);
+ BM_VERT_DIR(v) = plane_point_test_v3(plane, v->co, eps, &(BM_VERT_DIST(v)));
+
+ if (BM_VERT_DIR(v) == 0) {
+ if (oflag_center) {
+ BMO_vert_flag_enable(bm, v, oflag_center);
+ }
+ if (use_snap_center) {
+ closest_to_plane_v3(v->co, plane, v->co);
+ }
+ }
+ }
+
+ /* store a stack of faces to be evaluated for splitting */
+ BLI_LINKSTACK_INIT(face_stack);
+
+ for (i = 0; i < einput_len; i++) {
+ /* we could check edge_is_cut_test(e) but there is no point */
+ BMEdge *e = edges_arr[i];
+ const int side[2] = {BM_VERT_DIR(e->v1), BM_VERT_DIR(e->v2)};
+ const float dist[2] = {BM_VERT_DIST(e->v1), BM_VERT_DIST(e->v2)};
+
+ if (side[0] && side[1] && (side[0] != side[1])) {
+ const float e_fac = dist[0] / (dist[0] - dist[1]);
+ BMVert *v_new;
+
+ if (e->l) {
+ BMLoop *l_iter, *l_first;
+ l_iter = l_first = e->l;
+ do {
+ if (!face_in_stack_test(l_iter->f)) {
+ face_in_stack_enable(l_iter->f);
+ BLI_LINKSTACK_PUSH(face_stack, l_iter->f);
+ }
+ } while ((l_iter = l_iter->radial_next) != l_first);
+ }
+
+ {
+ BMEdge *e_new;
+ v_new = BM_edge_split(bm, e, e->v1, &e_new, e_fac);
+ if (oflag_new) {
+ BMO_edge_flag_enable(bm, e_new, oflag_new);
+ }
+ }
+
+ vert_is_center_enable(v_new);
+ if (oflag_new | oflag_center) {
+ BMO_vert_flag_enable(bm, v_new, oflag_new | oflag_center);
+ }
+
+ BM_VERT_DIR(v_new) = 0;
+ BM_VERT_DIST(v_new) = 0.0f;
+ }
+ else if (side[0] == 0 || side[1] == 0) {
+ /* check if either edge verts are aligned,
+ * if so - tag and push all faces that use it into the stack */
+ uint j;
+ BM_ITER_ELEM_INDEX(v, &iter, e, BM_VERTS_OF_EDGE, j)
+ {
+ if (side[j] == 0) {
+ if (vert_is_center_test(v) == 0) {
+ BMIter itersub;
+ BMLoop *l_iter;
+
+ vert_is_center_enable(v);
+
+ BM_ITER_ELEM (l_iter, &itersub, v, BM_LOOPS_OF_VERT) {
+ if (!face_in_stack_test(l_iter->f)) {
+ face_in_stack_enable(l_iter->f);
+ BLI_LINKSTACK_PUSH(face_stack, l_iter->f);
+ }
+ }
+ }
+ }
+ }
+
+ /* if both verts are on the center - tag it */
+ if (oflag_center) {
+ if (side[0] == 0 && side[1] == 0) {
+ BMO_edge_flag_enable(bm, e, oflag_center);
+ }
+ }
+ }
+ }
+
+ MEM_freeN(edges_arr);
+
+ while ((f = BLI_LINKSTACK_POP(face_stack))) {
+ bm_face_bisect_verts(bm, f, plane, oflag_center, oflag_new);
+ }
+
+ /* Caused by access macros: BM_VERT_DIR, BM_VERT_SKIP. */
+ bm->elem_index_dirty |= BM_VERT;
+
+ /* now we have all faces to split in the stack */
+ BLI_LINKSTACK_FREE(face_stack);
}
diff --git a/source/blender/bmesh/tools/bmesh_bisect_plane.h b/source/blender/bmesh/tools/bmesh_bisect_plane.h
index e3e4a737776..ca6281be99f 100644
--- a/source/blender/bmesh/tools/bmesh_bisect_plane.h
+++ b/source/blender/bmesh/tools/bmesh_bisect_plane.h
@@ -21,9 +21,12 @@
* \ingroup bmesh
*/
-void BM_mesh_bisect_plane(
- BMesh *bm, const float plane[4],
- const bool use_snap_center, const bool use_tag,
- const short oflag_center, const short oflag_new, const float eps);
+void BM_mesh_bisect_plane(BMesh *bm,
+ const float plane[4],
+ const bool use_snap_center,
+ const bool use_tag,
+ const short oflag_center,
+ const short oflag_new,
+ const float eps);
#endif /* __BMESH_BISECT_PLANE_H__ */
diff --git a/source/blender/bmesh/tools/bmesh_decimate.h b/source/blender/bmesh/tools/bmesh_decimate.h
index fa25b35b912..669eb629e70 100644
--- a/source/blender/bmesh/tools/bmesh_decimate.h
+++ b/source/blender/bmesh/tools/bmesh_decimate.h
@@ -21,23 +21,29 @@
* \ingroup bmesh
*/
-void BM_mesh_decimate_collapse(
- BMesh *bm, const float factor,
- float *vweights, float vweight_factor,
- const bool do_triangulate,
- const int symmetry_axis, const float symmetry_eps);
+void BM_mesh_decimate_collapse(BMesh *bm,
+ const float factor,
+ float *vweights,
+ float vweight_factor,
+ const bool do_triangulate,
+ const int symmetry_axis,
+ const float symmetry_eps);
void BM_mesh_decimate_unsubdivide_ex(BMesh *bm, const int iterations, const bool tag_only);
void BM_mesh_decimate_unsubdivide(BMesh *bm, const int iterations);
-void BM_mesh_decimate_dissolve_ex(
- BMesh *bm, const float angle_limit, const bool do_dissolve_boundaries,
- BMO_Delimit delimit,
- BMVert **vinput_arr, const int vinput_len,
- BMEdge **einput_arr, const int einput_len,
- const short oflag_out);
-void BM_mesh_decimate_dissolve(
- BMesh *bm, const float angle_limit, const bool do_dissolve_boundaries,
- const BMO_Delimit delimit);
+void BM_mesh_decimate_dissolve_ex(BMesh *bm,
+ const float angle_limit,
+ const bool do_dissolve_boundaries,
+ BMO_Delimit delimit,
+ BMVert **vinput_arr,
+ const int vinput_len,
+ BMEdge **einput_arr,
+ const int einput_len,
+ const short oflag_out);
+void BM_mesh_decimate_dissolve(BMesh *bm,
+ const float angle_limit,
+ const bool do_dissolve_boundaries,
+ const BMO_Delimit delimit);
#endif /* __BMESH_DECIMATE_H__ */
diff --git a/source/blender/bmesh/tools/bmesh_decimate_collapse.c b/source/blender/bmesh/tools/bmesh_decimate_collapse.c
index c60dd04fbb5..3838f199847 100644
--- a/source/blender/bmesh/tools/bmesh_decimate_collapse.c
+++ b/source/blender/bmesh/tools/bmesh_decimate_collapse.c
@@ -24,7 +24,6 @@
#include "MEM_guardedalloc.h"
-
#include "BLI_math.h"
#include "BLI_quadric.h"
#include "BLI_heap.h"
@@ -35,17 +34,16 @@
#include "BLI_polyfill_2d_beautify.h"
#include "BLI_utildefines_stack.h"
-
#include "BKE_customdata.h"
#include "bmesh.h"
-#include "bmesh_decimate.h" /* own include */
+#include "bmesh_decimate.h" /* own include */
#include "../intern/bmesh_structure.h"
#define USE_SYMMETRY
#ifdef USE_SYMMETRY
-#include "BLI_kdtree.h"
+# include "BLI_kdtree.h"
#endif
/* defines for testing */
@@ -56,9 +54,9 @@
/** if the cost from #BLI_quadric_evaluate is 'noise', fallback to topology */
#define USE_TOPOLOGY_FALLBACK
-#ifdef USE_TOPOLOGY_FALLBACK
+#ifdef USE_TOPOLOGY_FALLBACK
/** cost is calculated with double precision, it's ok to use a very small epsilon, see T48154. */
-# define TOPOLOGY_FALLBACK_EPS 1e-12f
+# define TOPOLOGY_FALLBACK_EPS 1e-12f
#endif
#define BOUNDARY_PRESERVE_WEIGHT 100.0f
@@ -68,12 +66,11 @@
#define COST_INVALID FLT_MAX
typedef enum CD_UseFlag {
- CD_DO_VERT = (1 << 0),
- CD_DO_EDGE = (1 << 1),
- CD_DO_LOOP = (1 << 2),
+ CD_DO_VERT = (1 << 0),
+ CD_DO_EDGE = (1 << 1),
+ CD_DO_LOOP = (1 << 2),
} CD_UseFlag;
-
/* BMesh Helper Functions
* ********************** */
@@ -82,150 +79,140 @@ typedef enum CD_UseFlag {
*/
static void bm_decim_build_quadrics(BMesh *bm, Quadric *vquadrics)
{
- BMIter iter;
- BMFace *f;
- BMEdge *e;
-
- BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
- BMLoop *l_first;
- BMLoop *l_iter;
-
- float center[3];
- double plane_db[4];
- Quadric q;
-
- BM_face_calc_center_median(f, center);
- copy_v3db_v3fl(plane_db, f->no);
- plane_db[3] = -dot_v3db_v3fl(plane_db, center);
-
- BLI_quadric_from_plane(&q, plane_db);
-
- l_iter = l_first = BM_FACE_FIRST_LOOP(f);
- do {
- BLI_quadric_add_qu_qu(&vquadrics[BM_elem_index_get(l_iter->v)], &q);
- } while ((l_iter = l_iter->next) != l_first);
- }
-
- /* boundary edges */
- BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
- if (UNLIKELY(BM_edge_is_boundary(e))) {
- float edge_vector[3];
- float edge_plane[3];
- double edge_plane_db[4];
- sub_v3_v3v3(edge_vector, e->v2->co, e->v1->co);
- f = e->l->f;
-
- cross_v3_v3v3(edge_plane, edge_vector, f->no);
- copy_v3db_v3fl(edge_plane_db, edge_plane);
-
- if (normalize_v3_d(edge_plane_db) > (double)FLT_EPSILON) {
- Quadric q;
- float center[3];
-
- mid_v3_v3v3(center, e->v1->co, e->v2->co);
-
- edge_plane_db[3] = -dot_v3db_v3fl(edge_plane_db, center);
- BLI_quadric_from_plane(&q, edge_plane_db);
- BLI_quadric_mul(&q, BOUNDARY_PRESERVE_WEIGHT);
-
- BLI_quadric_add_qu_qu(&vquadrics[BM_elem_index_get(e->v1)], &q);
- BLI_quadric_add_qu_qu(&vquadrics[BM_elem_index_get(e->v2)], &q);
- }
- }
- }
+ BMIter iter;
+ BMFace *f;
+ BMEdge *e;
+
+ BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
+ BMLoop *l_first;
+ BMLoop *l_iter;
+
+ float center[3];
+ double plane_db[4];
+ Quadric q;
+
+ BM_face_calc_center_median(f, center);
+ copy_v3db_v3fl(plane_db, f->no);
+ plane_db[3] = -dot_v3db_v3fl(plane_db, center);
+
+ BLI_quadric_from_plane(&q, plane_db);
+
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ BLI_quadric_add_qu_qu(&vquadrics[BM_elem_index_get(l_iter->v)], &q);
+ } while ((l_iter = l_iter->next) != l_first);
+ }
+
+ /* boundary edges */
+ BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
+ if (UNLIKELY(BM_edge_is_boundary(e))) {
+ float edge_vector[3];
+ float edge_plane[3];
+ double edge_plane_db[4];
+ sub_v3_v3v3(edge_vector, e->v2->co, e->v1->co);
+ f = e->l->f;
+
+ cross_v3_v3v3(edge_plane, edge_vector, f->no);
+ copy_v3db_v3fl(edge_plane_db, edge_plane);
+
+ if (normalize_v3_d(edge_plane_db) > (double)FLT_EPSILON) {
+ Quadric q;
+ float center[3];
+
+ mid_v3_v3v3(center, e->v1->co, e->v2->co);
+
+ edge_plane_db[3] = -dot_v3db_v3fl(edge_plane_db, center);
+ BLI_quadric_from_plane(&q, edge_plane_db);
+ BLI_quadric_mul(&q, BOUNDARY_PRESERVE_WEIGHT);
+
+ BLI_quadric_add_qu_qu(&vquadrics[BM_elem_index_get(e->v1)], &q);
+ BLI_quadric_add_qu_qu(&vquadrics[BM_elem_index_get(e->v2)], &q);
+ }
+ }
+ }
}
-
-static void bm_decim_calc_target_co_db(
- BMEdge *e, double optimize_co[3],
- const Quadric *vquadrics)
+static void bm_decim_calc_target_co_db(BMEdge *e, double optimize_co[3], const Quadric *vquadrics)
{
- /* compute an edge contraction target for edge 'e'
- * this is computed by summing it's vertices quadrics and
- * optimizing the result. */
- Quadric q;
-
- BLI_quadric_add_qu_ququ(
- &q,
- &vquadrics[BM_elem_index_get(e->v1)],
- &vquadrics[BM_elem_index_get(e->v2)]);
-
- if (BLI_quadric_optimize(&q, optimize_co, OPTIMIZE_EPS)) {
- /* all is good */
- return;
- }
- else {
- optimize_co[0] = 0.5 * ((double)e->v1->co[0] + (double)e->v2->co[0]);
- optimize_co[1] = 0.5 * ((double)e->v1->co[1] + (double)e->v2->co[1]);
- optimize_co[2] = 0.5 * ((double)e->v1->co[2] + (double)e->v2->co[2]);
- }
+ /* compute an edge contraction target for edge 'e'
+ * this is computed by summing it's vertices quadrics and
+ * optimizing the result. */
+ Quadric q;
+
+ BLI_quadric_add_qu_ququ(
+ &q, &vquadrics[BM_elem_index_get(e->v1)], &vquadrics[BM_elem_index_get(e->v2)]);
+
+ if (BLI_quadric_optimize(&q, optimize_co, OPTIMIZE_EPS)) {
+ /* all is good */
+ return;
+ }
+ else {
+ optimize_co[0] = 0.5 * ((double)e->v1->co[0] + (double)e->v2->co[0]);
+ optimize_co[1] = 0.5 * ((double)e->v1->co[1] + (double)e->v2->co[1]);
+ optimize_co[2] = 0.5 * ((double)e->v1->co[2] + (double)e->v2->co[2]);
+ }
}
-static void bm_decim_calc_target_co_fl(
- BMEdge *e, float optimize_co[3],
- const Quadric *vquadrics)
+static void bm_decim_calc_target_co_fl(BMEdge *e, float optimize_co[3], const Quadric *vquadrics)
{
- double optimize_co_db[3];
- bm_decim_calc_target_co_db(e, optimize_co_db, vquadrics);
- copy_v3fl_v3db(optimize_co, optimize_co_db);
+ double optimize_co_db[3];
+ bm_decim_calc_target_co_db(e, optimize_co_db, vquadrics);
+ copy_v3fl_v3db(optimize_co, optimize_co_db);
}
-
static bool bm_edge_collapse_is_degenerate_flip(BMEdge *e, const float optimize_co[3])
{
- BMIter liter;
- BMLoop *l;
- uint i;
+ BMIter liter;
+ BMLoop *l;
+ uint i;
- for (i = 0; i < 2; i++) {
- /* loop over both verts */
- BMVert *v = *((&e->v1) + i);
+ for (i = 0; i < 2; i++) {
+ /* loop over both verts */
+ BMVert *v = *((&e->v1) + i);
- BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) {
- if (l->e != e && l->prev->e != e) {
- const float *co_prev = l->prev->v->co;
- const float *co_next = l->next->v->co;
- float cross_exist[3];
- float cross_optim[3];
+ BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) {
+ if (l->e != e && l->prev->e != e) {
+ const float *co_prev = l->prev->v->co;
+ const float *co_next = l->next->v->co;
+ float cross_exist[3];
+ float cross_optim[3];
#if 1
- /* line between the two outer verts, re-use for both cross products */
- float vec_other[3];
- /* before collapse */
- float vec_exist[3];
- /* after collapse */
- float vec_optim[3];
-
- sub_v3_v3v3(vec_other, co_prev, co_next);
- sub_v3_v3v3(vec_exist, co_prev, v->co);
- sub_v3_v3v3(vec_optim, co_prev, optimize_co);
-
- cross_v3_v3v3(cross_exist, vec_other, vec_exist);
- cross_v3_v3v3(cross_optim, vec_other, vec_optim);
-
- /* avoid normalize */
- if (dot_v3v3(cross_exist, cross_optim) <=
- (len_squared_v3(cross_exist) + len_squared_v3(cross_optim)) * 0.01f)
- {
- return true;
- }
+ /* line between the two outer verts, re-use for both cross products */
+ float vec_other[3];
+ /* before collapse */
+ float vec_exist[3];
+ /* after collapse */
+ float vec_optim[3];
+
+ sub_v3_v3v3(vec_other, co_prev, co_next);
+ sub_v3_v3v3(vec_exist, co_prev, v->co);
+ sub_v3_v3v3(vec_optim, co_prev, optimize_co);
+
+ cross_v3_v3v3(cross_exist, vec_other, vec_exist);
+ cross_v3_v3v3(cross_optim, vec_other, vec_optim);
+
+ /* avoid normalize */
+ if (dot_v3v3(cross_exist, cross_optim) <=
+ (len_squared_v3(cross_exist) + len_squared_v3(cross_optim)) * 0.01f) {
+ return true;
+ }
#else
- normal_tri_v3(cross_exist, v->co, co_prev, co_next);
- normal_tri_v3(cross_optim, optimize_co, co_prev, co_next);
-
- /* use a small value rather then zero so we don't flip a face in multiple steps
- * (first making it zero area, then flipping again) */
- if (dot_v3v3(cross_exist, cross_optim) <= FLT_EPSILON) {
- //printf("no flip\n");
- return true;
- }
+ normal_tri_v3(cross_exist, v->co, co_prev, co_next);
+ normal_tri_v3(cross_optim, optimize_co, co_prev, co_next);
+
+ /* use a small value rather then zero so we don't flip a face in multiple steps
+ * (first making it zero area, then flipping again) */
+ if (dot_v3v3(cross_exist, cross_optim) <= FLT_EPSILON) {
+ //printf("no flip\n");
+ return true;
+ }
#endif
+ }
+ }
+ }
- }
- }
- }
-
- return false;
+ return false;
}
#ifdef USE_TOPOLOGY_FALLBACK
@@ -237,242 +224,241 @@ static bool bm_edge_collapse_is_degenerate_flip(BMEdge *e, const float optimize_
*/
static float bm_decim_build_edge_cost_single_squared__topology(BMEdge *e)
{
- return fabsf(dot_v3v3(e->v1->no, e->v2->no)) / min_ff(-len_squared_v3v3(e->v1->co, e->v2->co), -FLT_EPSILON);
+ return fabsf(dot_v3v3(e->v1->no, e->v2->no)) /
+ min_ff(-len_squared_v3v3(e->v1->co, e->v2->co), -FLT_EPSILON);
}
static float bm_decim_build_edge_cost_single__topology(BMEdge *e)
{
- return fabsf(dot_v3v3(e->v1->no, e->v2->no)) / min_ff(-len_v3v3(e->v1->co, e->v2->co), -FLT_EPSILON);
+ return fabsf(dot_v3v3(e->v1->no, e->v2->no)) /
+ min_ff(-len_v3v3(e->v1->co, e->v2->co), -FLT_EPSILON);
}
-#endif /* USE_TOPOLOGY_FALLBACK */
+#endif /* USE_TOPOLOGY_FALLBACK */
-static void bm_decim_build_edge_cost_single(
- BMEdge *e,
- const Quadric *vquadrics,
- const float *vweights, const float vweight_factor,
- Heap *eheap, HeapNode **eheap_table)
+static void bm_decim_build_edge_cost_single(BMEdge *e,
+ const Quadric *vquadrics,
+ const float *vweights,
+ const float vweight_factor,
+ Heap *eheap,
+ HeapNode **eheap_table)
{
- float cost;
-
- if (UNLIKELY(vweights &&
- ((vweights[BM_elem_index_get(e->v1)] == 0.0f) ||
- (vweights[BM_elem_index_get(e->v2)] == 0.0f))))
- {
- goto clear;
- }
-
- /* check we can collapse, some edges we better not touch */
- if (BM_edge_is_boundary(e)) {
- if (e->l->f->len == 3) {
- /* pass */
- }
- else {
- /* only collapse tri's */
- goto clear;
- }
- }
- else if (BM_edge_is_manifold(e)) {
- if ((e->l->f->len == 3) && (e->l->radial_next->f->len == 3)) {
- /* pass */
- }
- else {
- /* only collapse tri's */
- goto clear;
- }
- }
- else {
- goto clear;
- }
- /* end sanity check */
-
- {
- double optimize_co[3];
- bm_decim_calc_target_co_db(e, optimize_co, vquadrics);
-
- const Quadric *q1, *q2;
- q1 = &vquadrics[BM_elem_index_get(e->v1)];
- q2 = &vquadrics[BM_elem_index_get(e->v2)];
-
- cost = (BLI_quadric_evaluate(q1, optimize_co) +
- BLI_quadric_evaluate(q2, optimize_co));
- }
-
- /* note, 'cost' shouldn't be negative but happens sometimes with small values.
- * this can cause faces that make up a flat surface to over-collapse, see [#37121] */
- cost = fabsf(cost);
+ float cost;
+
+ if (UNLIKELY(vweights && ((vweights[BM_elem_index_get(e->v1)] == 0.0f) ||
+ (vweights[BM_elem_index_get(e->v2)] == 0.0f)))) {
+ goto clear;
+ }
+
+ /* check we can collapse, some edges we better not touch */
+ if (BM_edge_is_boundary(e)) {
+ if (e->l->f->len == 3) {
+ /* pass */
+ }
+ else {
+ /* only collapse tri's */
+ goto clear;
+ }
+ }
+ else if (BM_edge_is_manifold(e)) {
+ if ((e->l->f->len == 3) && (e->l->radial_next->f->len == 3)) {
+ /* pass */
+ }
+ else {
+ /* only collapse tri's */
+ goto clear;
+ }
+ }
+ else {
+ goto clear;
+ }
+ /* end sanity check */
+
+ {
+ double optimize_co[3];
+ bm_decim_calc_target_co_db(e, optimize_co, vquadrics);
+
+ const Quadric *q1, *q2;
+ q1 = &vquadrics[BM_elem_index_get(e->v1)];
+ q2 = &vquadrics[BM_elem_index_get(e->v2)];
+
+ cost = (BLI_quadric_evaluate(q1, optimize_co) + BLI_quadric_evaluate(q2, optimize_co));
+ }
+
+ /* note, 'cost' shouldn't be negative but happens sometimes with small values.
+ * this can cause faces that make up a flat surface to over-collapse, see [#37121] */
+ cost = fabsf(cost);
#ifdef USE_TOPOLOGY_FALLBACK
- if (UNLIKELY(cost < TOPOLOGY_FALLBACK_EPS)) {
- /* subtract existing cost to further differentiate edges from one another
- *
- * keep topology cost below 0.0 so their values don't interfere with quadric cost,
- * (and they get handled first).
- * */
- if (vweights == NULL) {
- cost = bm_decim_build_edge_cost_single_squared__topology(e) - cost;
- }
- else {
- /* with weights we need to use the real length so we can scale them properly */
- const float e_weight = (vweights[BM_elem_index_get(e->v1)] +
- vweights[BM_elem_index_get(e->v2)]);
- cost = bm_decim_build_edge_cost_single__topology(e) - cost;
- /* note, this is rather arbitrary max weight is 2 here,
- * allow for skipping edges 4x the length, based on weights */
- if (e_weight) {
- cost *= 1.0f + (e_weight * vweight_factor);
- }
-
- BLI_assert(cost <= 0.0f);
- }
- }
- else
+ if (UNLIKELY(cost < TOPOLOGY_FALLBACK_EPS)) {
+ /* subtract existing cost to further differentiate edges from one another
+ *
+ * keep topology cost below 0.0 so their values don't interfere with quadric cost,
+ * (and they get handled first).
+ * */
+ if (vweights == NULL) {
+ cost = bm_decim_build_edge_cost_single_squared__topology(e) - cost;
+ }
+ else {
+ /* with weights we need to use the real length so we can scale them properly */
+ const float e_weight = (vweights[BM_elem_index_get(e->v1)] +
+ vweights[BM_elem_index_get(e->v2)]);
+ cost = bm_decim_build_edge_cost_single__topology(e) - cost;
+ /* note, this is rather arbitrary max weight is 2 here,
+ * allow for skipping edges 4x the length, based on weights */
+ if (e_weight) {
+ cost *= 1.0f + (e_weight * vweight_factor);
+ }
+
+ BLI_assert(cost <= 0.0f);
+ }
+ }
+ else
#endif
- if (vweights) {
- const float e_weight = 2.0f - (vweights[BM_elem_index_get(e->v1)] +
- vweights[BM_elem_index_get(e->v2)]);
- if (e_weight) {
- cost += (BM_edge_calc_length(e) * ((e_weight * vweight_factor)));
- }
- }
+ if (vweights) {
+ const float e_weight = 2.0f - (vweights[BM_elem_index_get(e->v1)] +
+ vweights[BM_elem_index_get(e->v2)]);
+ if (e_weight) {
+ cost += (BM_edge_calc_length(e) * ((e_weight * vweight_factor)));
+ }
+ }
- BLI_heap_insert_or_update(eheap, &eheap_table[BM_elem_index_get(e)], cost, e);
- return;
+ BLI_heap_insert_or_update(eheap, &eheap_table[BM_elem_index_get(e)], cost, e);
+ return;
clear:
- if (eheap_table[BM_elem_index_get(e)]) {
- BLI_heap_remove(eheap, eheap_table[BM_elem_index_get(e)]);
- }
- eheap_table[BM_elem_index_get(e)] = NULL;
+ if (eheap_table[BM_elem_index_get(e)]) {
+ BLI_heap_remove(eheap, eheap_table[BM_elem_index_get(e)]);
+ }
+ eheap_table[BM_elem_index_get(e)] = NULL;
}
-
/* use this for degenerate cases - add back to the heap with an invalid cost,
* this way it may be calculated again if surrounding geometry changes */
-static void bm_decim_invalid_edge_cost_single(
- BMEdge *e,
- Heap *eheap, HeapNode **eheap_table)
+static void bm_decim_invalid_edge_cost_single(BMEdge *e, Heap *eheap, HeapNode **eheap_table)
{
- BLI_assert(eheap_table[BM_elem_index_get(e)] == NULL);
- eheap_table[BM_elem_index_get(e)] = BLI_heap_insert(eheap, COST_INVALID, e);
+ BLI_assert(eheap_table[BM_elem_index_get(e)] == NULL);
+ eheap_table[BM_elem_index_get(e)] = BLI_heap_insert(eheap, COST_INVALID, e);
}
-static void bm_decim_build_edge_cost(
- BMesh *bm,
- const Quadric *vquadrics,
- const float *vweights, const float vweight_factor,
- Heap *eheap, HeapNode **eheap_table)
+static void bm_decim_build_edge_cost(BMesh *bm,
+ const Quadric *vquadrics,
+ const float *vweights,
+ const float vweight_factor,
+ Heap *eheap,
+ HeapNode **eheap_table)
{
- BMIter iter;
- BMEdge *e;
- uint i;
-
- BM_ITER_MESH_INDEX (e, &iter, bm, BM_EDGES_OF_MESH, i) {
- /* keep sanity check happy */
- eheap_table[i] = NULL;
- bm_decim_build_edge_cost_single(e, vquadrics, vweights, vweight_factor, eheap, eheap_table);
- }
+ BMIter iter;
+ BMEdge *e;
+ uint i;
+
+ BM_ITER_MESH_INDEX (e, &iter, bm, BM_EDGES_OF_MESH, i) {
+ /* keep sanity check happy */
+ eheap_table[i] = NULL;
+ bm_decim_build_edge_cost_single(e, vquadrics, vweights, vweight_factor, eheap, eheap_table);
+ }
}
#ifdef USE_SYMMETRY
struct KD_Symmetry_Data {
- /* pre-flipped coords */
- float e_v1_co[3], e_v2_co[3];
- /* Use to compare the correct endpoints incase v1/v2 are swapped */
- float e_dir[3];
+ /* pre-flipped coords */
+ float e_v1_co[3], e_v2_co[3];
+ /* Use to compare the correct endpoints incase v1/v2 are swapped */
+ float e_dir[3];
- int e_found_index;
+ int e_found_index;
- /* same for all */
- BMEdge **etable;
- float limit_sq;
+ /* same for all */
+ BMEdge **etable;
+ float limit_sq;
};
-static bool bm_edge_symmetry_check_cb(void *user_data, int index, const float UNUSED(co[3]), float UNUSED(dist_sq))
+static bool bm_edge_symmetry_check_cb(void *user_data,
+ int index,
+ const float UNUSED(co[3]),
+ float UNUSED(dist_sq))
{
- struct KD_Symmetry_Data *sym_data = user_data;
- BMEdge *e_other = sym_data->etable[index];
- float e_other_dir[3];
-
- sub_v3_v3v3(e_other_dir, e_other->v2->co, e_other->v1->co);
-
- if (dot_v3v3(e_other_dir, sym_data->e_dir) > 0.0f) {
- if ((len_squared_v3v3(sym_data->e_v1_co, e_other->v1->co) > sym_data->limit_sq) ||
- (len_squared_v3v3(sym_data->e_v2_co, e_other->v2->co) > sym_data->limit_sq))
- {
- return true;
- }
- }
- else {
- if ((len_squared_v3v3(sym_data->e_v1_co, e_other->v2->co) > sym_data->limit_sq) ||
- (len_squared_v3v3(sym_data->e_v2_co, e_other->v1->co) > sym_data->limit_sq))
- {
- return true;
- }
- }
-
- /* exit on first-hit, this is OK since the search range is very small */
- sym_data->e_found_index = index;
- return false;
+ struct KD_Symmetry_Data *sym_data = user_data;
+ BMEdge *e_other = sym_data->etable[index];
+ float e_other_dir[3];
+
+ sub_v3_v3v3(e_other_dir, e_other->v2->co, e_other->v1->co);
+
+ if (dot_v3v3(e_other_dir, sym_data->e_dir) > 0.0f) {
+ if ((len_squared_v3v3(sym_data->e_v1_co, e_other->v1->co) > sym_data->limit_sq) ||
+ (len_squared_v3v3(sym_data->e_v2_co, e_other->v2->co) > sym_data->limit_sq)) {
+ return true;
+ }
+ }
+ else {
+ if ((len_squared_v3v3(sym_data->e_v1_co, e_other->v2->co) > sym_data->limit_sq) ||
+ (len_squared_v3v3(sym_data->e_v2_co, e_other->v1->co) > sym_data->limit_sq)) {
+ return true;
+ }
+ }
+
+ /* exit on first-hit, this is OK since the search range is very small */
+ sym_data->e_found_index = index;
+ return false;
}
static int *bm_edge_symmetry_map(BMesh *bm, uint symmetry_axis, float limit)
{
- struct KD_Symmetry_Data sym_data;
- BMIter iter;
- BMEdge *e, **etable;
- uint i;
- int *edge_symmetry_map;
- const float limit_sq = SQUARE(limit);
- KDTree_3d *tree;
-
- tree = BLI_kdtree_3d_new(bm->totedge);
-
- etable = MEM_mallocN(sizeof(*etable) * bm->totedge, __func__);
- edge_symmetry_map = MEM_mallocN(sizeof(*edge_symmetry_map) * bm->totedge, __func__);
-
- BM_ITER_MESH_INDEX (e, &iter, bm, BM_EDGES_OF_MESH, i) {
- float co[3];
- mid_v3_v3v3(co, e->v1->co, e->v2->co);
- BLI_kdtree_3d_insert(tree, i, co);
- etable[i] = e;
- edge_symmetry_map[i] = -1;
- }
-
- BLI_kdtree_3d_balance(tree);
-
- sym_data.etable = etable;
- sym_data.limit_sq = limit_sq;
-
- BM_ITER_MESH_INDEX (e, &iter, bm, BM_EDGES_OF_MESH, i) {
- if (edge_symmetry_map[i] == -1) {
- float co[3];
- mid_v3_v3v3(co, e->v1->co, e->v2->co);
- co[symmetry_axis] *= -1.0f;
-
- copy_v3_v3(sym_data.e_v1_co, e->v1->co);
- copy_v3_v3(sym_data.e_v2_co, e->v2->co);
- sym_data.e_v1_co[symmetry_axis] *= -1.0f;
- sym_data.e_v2_co[symmetry_axis] *= -1.0f;
- sub_v3_v3v3(sym_data.e_dir, sym_data.e_v2_co, sym_data.e_v1_co);
- sym_data.e_found_index = -1;
-
- BLI_kdtree_3d_range_search_cb(tree, co, limit, bm_edge_symmetry_check_cb, &sym_data);
-
- if (sym_data.e_found_index != -1) {
- const int i_other = sym_data.e_found_index;
- edge_symmetry_map[i] = i_other;
- edge_symmetry_map[i_other] = i;
- }
- }
- }
-
- MEM_freeN(etable);
- BLI_kdtree_3d_free(tree);
-
- return edge_symmetry_map;
+ struct KD_Symmetry_Data sym_data;
+ BMIter iter;
+ BMEdge *e, **etable;
+ uint i;
+ int *edge_symmetry_map;
+ const float limit_sq = SQUARE(limit);
+ KDTree_3d *tree;
+
+ tree = BLI_kdtree_3d_new(bm->totedge);
+
+ etable = MEM_mallocN(sizeof(*etable) * bm->totedge, __func__);
+ edge_symmetry_map = MEM_mallocN(sizeof(*edge_symmetry_map) * bm->totedge, __func__);
+
+ BM_ITER_MESH_INDEX (e, &iter, bm, BM_EDGES_OF_MESH, i) {
+ float co[3];
+ mid_v3_v3v3(co, e->v1->co, e->v2->co);
+ BLI_kdtree_3d_insert(tree, i, co);
+ etable[i] = e;
+ edge_symmetry_map[i] = -1;
+ }
+
+ BLI_kdtree_3d_balance(tree);
+
+ sym_data.etable = etable;
+ sym_data.limit_sq = limit_sq;
+
+ BM_ITER_MESH_INDEX (e, &iter, bm, BM_EDGES_OF_MESH, i) {
+ if (edge_symmetry_map[i] == -1) {
+ float co[3];
+ mid_v3_v3v3(co, e->v1->co, e->v2->co);
+ co[symmetry_axis] *= -1.0f;
+
+ copy_v3_v3(sym_data.e_v1_co, e->v1->co);
+ copy_v3_v3(sym_data.e_v2_co, e->v2->co);
+ sym_data.e_v1_co[symmetry_axis] *= -1.0f;
+ sym_data.e_v2_co[symmetry_axis] *= -1.0f;
+ sub_v3_v3v3(sym_data.e_dir, sym_data.e_v2_co, sym_data.e_v1_co);
+ sym_data.e_found_index = -1;
+
+ BLI_kdtree_3d_range_search_cb(tree, co, limit, bm_edge_symmetry_check_cb, &sym_data);
+
+ if (sym_data.e_found_index != -1) {
+ const int i_other = sym_data.e_found_index;
+ edge_symmetry_map[i] = i_other;
+ edge_symmetry_map[i_other] = i;
+ }
+ }
+ }
+
+ MEM_freeN(etable);
+ BLI_kdtree_3d_free(tree);
+
+ return edge_symmetry_map;
}
-#endif /* USE_SYMMETRY */
+#endif /* USE_SYMMETRY */
#ifdef USE_TRIANGULATE
/* Temp Triangulation
@@ -490,205 +476,208 @@ static int *bm_edge_symmetry_map(BMesh *bm, uint symmetry_axis, float limit)
*
* \return true if any faces were triangulated.
*/
-static bool bm_face_triangulate(
- BMesh *bm, BMFace *f_base, LinkNode **r_faces_double, int *r_edges_tri_tot,
-
- MemArena *pf_arena,
- /* use for MOD_TRIANGULATE_NGON_BEAUTY only! */
- struct Heap *pf_heap)
+static bool bm_face_triangulate(BMesh *bm,
+ BMFace *f_base,
+ LinkNode **r_faces_double,
+ int *r_edges_tri_tot,
+
+ MemArena *pf_arena,
+ /* use for MOD_TRIANGULATE_NGON_BEAUTY only! */
+ struct Heap *pf_heap)
{
- const int f_base_len = f_base->len;
- int faces_array_tot = f_base_len - 3;
- int edges_array_tot = f_base_len - 3;
- BMFace **faces_array = BLI_array_alloca(faces_array, faces_array_tot);
- BMEdge **edges_array = BLI_array_alloca(edges_array, edges_array_tot);
- const int quad_method = 0, ngon_method = 0; /* beauty */
-
- bool has_cut = false;
-
- const int f_index = BM_elem_index_get(f_base);
-
- BM_face_triangulate(
- bm, f_base,
- faces_array, &faces_array_tot,
- edges_array, &edges_array_tot,
- r_faces_double,
- quad_method, ngon_method, false,
- pf_arena, pf_heap);
-
- for (int i = 0; i < edges_array_tot; i++) {
- BMLoop *l_iter, *l_first;
- l_iter = l_first = edges_array[i]->l;
- do {
- BM_elem_index_set(l_iter, f_index); /* set_dirty */
- has_cut = true;
- } while ((l_iter = l_iter->radial_next) != l_first);
- }
-
- for (int i = 0; i < faces_array_tot; i++) {
- BM_face_normal_update(faces_array[i]);
- }
-
- *r_edges_tri_tot += edges_array_tot;
-
- return has_cut;
+ const int f_base_len = f_base->len;
+ int faces_array_tot = f_base_len - 3;
+ int edges_array_tot = f_base_len - 3;
+ BMFace **faces_array = BLI_array_alloca(faces_array, faces_array_tot);
+ BMEdge **edges_array = BLI_array_alloca(edges_array, edges_array_tot);
+ const int quad_method = 0, ngon_method = 0; /* beauty */
+
+ bool has_cut = false;
+
+ const int f_index = BM_elem_index_get(f_base);
+
+ BM_face_triangulate(bm,
+ f_base,
+ faces_array,
+ &faces_array_tot,
+ edges_array,
+ &edges_array_tot,
+ r_faces_double,
+ quad_method,
+ ngon_method,
+ false,
+ pf_arena,
+ pf_heap);
+
+ for (int i = 0; i < edges_array_tot; i++) {
+ BMLoop *l_iter, *l_first;
+ l_iter = l_first = edges_array[i]->l;
+ do {
+ BM_elem_index_set(l_iter, f_index); /* set_dirty */
+ has_cut = true;
+ } while ((l_iter = l_iter->radial_next) != l_first);
+ }
+
+ for (int i = 0; i < faces_array_tot; i++) {
+ BM_face_normal_update(faces_array[i]);
+ }
+
+ *r_edges_tri_tot += edges_array_tot;
+
+ return has_cut;
}
-
static bool bm_decim_triangulate_begin(BMesh *bm, int *r_edges_tri_tot)
{
- BMIter iter;
- BMFace *f;
- bool has_quad = false;
- bool has_ngon = false;
- bool has_cut = false;
-
- BLI_assert((bm->elem_index_dirty & BM_VERT) == 0);
-
- /* first clear loop index values */
- BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
- BMLoop *l_iter;
- BMLoop *l_first;
-
- l_iter = l_first = BM_FACE_FIRST_LOOP(f);
- do {
- BM_elem_index_set(l_iter, -1); /* set_dirty */
- } while ((l_iter = l_iter->next) != l_first);
-
- has_quad |= (f->len > 3);
- has_ngon |= (f->len > 4);
- }
-
- bm->elem_index_dirty |= BM_LOOP;
-
- {
- MemArena *pf_arena;
- Heap *pf_heap;
-
- LinkNode *faces_double = NULL;
-
- if (has_ngon) {
- pf_arena = BLI_memarena_new(BLI_POLYFILL_ARENA_SIZE, __func__);
- pf_heap = BLI_heap_new_ex(BLI_POLYFILL_ALLOC_NGON_RESERVE);
- }
- else {
- pf_arena = NULL;
- pf_heap = NULL;
- }
-
- /* adding new faces as we loop over faces
- * is normally best avoided, however in this case its not so bad because any face touched twice
- * will already be triangulated*/
- BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
- if (f->len > 3) {
- has_cut |= bm_face_triangulate(
- bm, f, &faces_double,
- r_edges_tri_tot,
-
- pf_arena, pf_heap);
- }
- }
-
- while (faces_double) {
- LinkNode *next = faces_double->next;
- BM_face_kill(bm, faces_double->link);
- MEM_freeN(faces_double);
- faces_double = next;
- }
-
- if (has_ngon) {
- BLI_memarena_free(pf_arena);
- BLI_heap_free(pf_heap, NULL);
- }
-
- BLI_assert((bm->elem_index_dirty & BM_VERT) == 0);
-
- if (has_cut) {
- /* now triangulation is done we need to correct index values */
- BM_mesh_elem_index_ensure(bm, BM_EDGE | BM_FACE);
- }
- }
-
- return has_cut;
+ BMIter iter;
+ BMFace *f;
+ bool has_quad = false;
+ bool has_ngon = false;
+ bool has_cut = false;
+
+ BLI_assert((bm->elem_index_dirty & BM_VERT) == 0);
+
+ /* first clear loop index values */
+ BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
+ BMLoop *l_iter;
+ BMLoop *l_first;
+
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ BM_elem_index_set(l_iter, -1); /* set_dirty */
+ } while ((l_iter = l_iter->next) != l_first);
+
+ has_quad |= (f->len > 3);
+ has_ngon |= (f->len > 4);
+ }
+
+ bm->elem_index_dirty |= BM_LOOP;
+
+ {
+ MemArena *pf_arena;
+ Heap *pf_heap;
+
+ LinkNode *faces_double = NULL;
+
+ if (has_ngon) {
+ pf_arena = BLI_memarena_new(BLI_POLYFILL_ARENA_SIZE, __func__);
+ pf_heap = BLI_heap_new_ex(BLI_POLYFILL_ALLOC_NGON_RESERVE);
+ }
+ else {
+ pf_arena = NULL;
+ pf_heap = NULL;
+ }
+
+ /* adding new faces as we loop over faces
+ * is normally best avoided, however in this case its not so bad because any face touched twice
+ * will already be triangulated*/
+ BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
+ if (f->len > 3) {
+ has_cut |= bm_face_triangulate(bm,
+ f,
+ &faces_double,
+ r_edges_tri_tot,
+
+ pf_arena,
+ pf_heap);
+ }
+ }
+
+ while (faces_double) {
+ LinkNode *next = faces_double->next;
+ BM_face_kill(bm, faces_double->link);
+ MEM_freeN(faces_double);
+ faces_double = next;
+ }
+
+ if (has_ngon) {
+ BLI_memarena_free(pf_arena);
+ BLI_heap_free(pf_heap, NULL);
+ }
+
+ BLI_assert((bm->elem_index_dirty & BM_VERT) == 0);
+
+ if (has_cut) {
+ /* now triangulation is done we need to correct index values */
+ BM_mesh_elem_index_ensure(bm, BM_EDGE | BM_FACE);
+ }
+ }
+
+ return has_cut;
}
-
static void bm_decim_triangulate_end(BMesh *bm, const int edges_tri_tot)
{
- /* decimation finished, now re-join */
- BMIter iter;
- BMEdge *e;
-
- /* we need to collect before merging for ngons since the loops indices will be lost */
- BMEdge **edges_tri = MEM_mallocN(MIN2(edges_tri_tot, bm->totedge) * sizeof(*edges_tri), __func__);
- STACK_DECLARE(edges_tri);
-
- STACK_INIT(edges_tri, MIN2(edges_tri_tot, bm->totedge));
-
- /* boundary edges */
- BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
- BMLoop *l_a, *l_b;
- if (BM_edge_loop_pair(e, &l_a, &l_b)) {
- const int l_a_index = BM_elem_index_get(l_a);
- if (l_a_index != -1) {
- const int l_b_index = BM_elem_index_get(l_b);
- if (l_a_index == l_b_index) {
- if (l_a->v != l_b->v) { /* if this is the case, faces have become flipped */
- /* check we are not making a degenerate quad */
-
-#define CAN_LOOP_MERGE(l) \
- (BM_loop_is_manifold(l) && \
- ((l)->v != (l)->radial_next->v) && \
- (l_a_index == BM_elem_index_get(l)) && \
- (l_a_index == BM_elem_index_get((l)->radial_next)))
-
- if ((l_a->f->len == 3 && l_b->f->len == 3) &&
- (!CAN_LOOP_MERGE(l_a->next)) &&
- (!CAN_LOOP_MERGE(l_a->prev)) &&
- (!CAN_LOOP_MERGE(l_b->next)) &&
- (!CAN_LOOP_MERGE(l_b->prev)))
- {
- BMVert *vquad[4] = {
- e->v1,
- BM_vert_in_edge(e, l_a->next->v) ? l_a->prev->v : l_a->next->v,
- e->v2,
- BM_vert_in_edge(e, l_b->next->v) ? l_b->prev->v : l_b->next->v,
- };
-
- BLI_assert(ELEM(vquad[0], vquad[1], vquad[2], vquad[3]) == false);
- BLI_assert(ELEM(vquad[1], vquad[0], vquad[2], vquad[3]) == false);
- BLI_assert(ELEM(vquad[2], vquad[1], vquad[0], vquad[3]) == false);
- BLI_assert(ELEM(vquad[3], vquad[1], vquad[2], vquad[0]) == false);
-
- if (!is_quad_convex_v3(vquad[0]->co, vquad[1]->co, vquad[2]->co, vquad[3]->co)) {
- continue;
- }
- }
-#undef CAN_LOOP_MERGE
-
- /* highly unlikely to fail, but prevents possible double-ups */
- STACK_PUSH(edges_tri, e);
- }
- }
- }
- }
- }
-
- for (int i = 0; i < STACK_SIZE(edges_tri); i++) {
- BMLoop *l_a, *l_b;
- e = edges_tri[i];
- if (BM_edge_loop_pair(e, &l_a, &l_b)) {
- BMFace *f_array[2] = {l_a->f, l_b->f};
- BM_faces_join(bm, f_array, 2, false);
- if (e->l == NULL) {
- BM_edge_kill(bm, e);
- }
- }
- }
- MEM_freeN(edges_tri);
+ /* decimation finished, now re-join */
+ BMIter iter;
+ BMEdge *e;
+
+ /* we need to collect before merging for ngons since the loops indices will be lost */
+ BMEdge **edges_tri = MEM_mallocN(MIN2(edges_tri_tot, bm->totedge) * sizeof(*edges_tri),
+ __func__);
+ STACK_DECLARE(edges_tri);
+
+ STACK_INIT(edges_tri, MIN2(edges_tri_tot, bm->totedge));
+
+ /* boundary edges */
+ BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
+ BMLoop *l_a, *l_b;
+ if (BM_edge_loop_pair(e, &l_a, &l_b)) {
+ const int l_a_index = BM_elem_index_get(l_a);
+ if (l_a_index != -1) {
+ const int l_b_index = BM_elem_index_get(l_b);
+ if (l_a_index == l_b_index) {
+ if (l_a->v != l_b->v) { /* if this is the case, faces have become flipped */
+ /* check we are not making a degenerate quad */
+
+# define CAN_LOOP_MERGE(l) \
+ (BM_loop_is_manifold(l) && ((l)->v != (l)->radial_next->v) && \
+ (l_a_index == BM_elem_index_get(l)) && (l_a_index == BM_elem_index_get((l)->radial_next)))
+
+ if ((l_a->f->len == 3 && l_b->f->len == 3) && (!CAN_LOOP_MERGE(l_a->next)) &&
+ (!CAN_LOOP_MERGE(l_a->prev)) && (!CAN_LOOP_MERGE(l_b->next)) &&
+ (!CAN_LOOP_MERGE(l_b->prev))) {
+ BMVert *vquad[4] = {
+ e->v1,
+ BM_vert_in_edge(e, l_a->next->v) ? l_a->prev->v : l_a->next->v,
+ e->v2,
+ BM_vert_in_edge(e, l_b->next->v) ? l_b->prev->v : l_b->next->v,
+ };
+
+ BLI_assert(ELEM(vquad[0], vquad[1], vquad[2], vquad[3]) == false);
+ BLI_assert(ELEM(vquad[1], vquad[0], vquad[2], vquad[3]) == false);
+ BLI_assert(ELEM(vquad[2], vquad[1], vquad[0], vquad[3]) == false);
+ BLI_assert(ELEM(vquad[3], vquad[1], vquad[2], vquad[0]) == false);
+
+ if (!is_quad_convex_v3(vquad[0]->co, vquad[1]->co, vquad[2]->co, vquad[3]->co)) {
+ continue;
+ }
+ }
+# undef CAN_LOOP_MERGE
+
+ /* highly unlikely to fail, but prevents possible double-ups */
+ STACK_PUSH(edges_tri, e);
+ }
+ }
+ }
+ }
+ }
+
+ for (int i = 0; i < STACK_SIZE(edges_tri); i++) {
+ BMLoop *l_a, *l_b;
+ e = edges_tri[i];
+ if (BM_edge_loop_pair(e, &l_a, &l_b)) {
+ BMFace *f_array[2] = {l_a->f, l_b->f};
+ BM_faces_join(bm, f_array, 2, false);
+ if (e->l == NULL) {
+ BM_edge_kill(bm, e);
+ }
+ }
+ }
+ MEM_freeN(edges_tri);
}
-#endif /* USE_TRIANGULATE */
+#endif /* USE_TRIANGULATE */
/* Edge Collapse Functions
* *********************** */
@@ -699,112 +688,114 @@ static void bm_decim_triangulate_end(BMesh *bm, const int edges_tri_tot)
* \param l: defines the vert to collapse into.
*/
static void bm_edge_collapse_loop_customdata(
- BMesh *bm, BMLoop *l, BMVert *v_clear, BMVert *v_other,
- const float customdata_fac)
+ BMesh *bm, BMLoop *l, BMVert *v_clear, BMVert *v_other, const float customdata_fac)
{
- /* disable seam check - the seam check would have to be done per layer, its not really that important */
-//#define USE_SEAM
- /* these don't need to be updated, since they will get removed when the edge collapses */
- BMLoop *l_clear, *l_other;
- const bool is_manifold = BM_edge_is_manifold(l->e);
- int side;
-
- /* first find the loop of 'v_other' thats attached to the face of 'l' */
- if (l->v == v_clear) {
- l_clear = l;
- l_other = l->next;
- }
- else {
- l_clear = l->next;
- l_other = l;
- }
-
- BLI_assert(l_clear->v == v_clear);
- BLI_assert(l_other->v == v_other);
- /* quiet warnings for release */
- (void)v_other;
-
- /* now we have both corners of the face 'l->f' */
- for (side = 0; side < 2; side++) {
-#ifdef USE_SEAM
- bool is_seam = false;
-#endif
- void *src[2];
- BMFace *f_exit = is_manifold ? l->radial_next->f : NULL;
- BMEdge *e_prev = l->e;
- BMLoop *l_first;
- BMLoop *l_iter;
- float w[2];
-
- if (side == 0) {
- l_iter = l_first = l_clear;
- src[0] = l_clear->head.data;
- src[1] = l_other->head.data;
-
- w[0] = customdata_fac;
- w[1] = 1.0f - customdata_fac;
- }
- else {
- l_iter = l_first = l_other;
- src[0] = l_other->head.data;
- src[1] = l_clear->head.data;
-
- w[0] = 1.0f - customdata_fac;
- w[1] = customdata_fac;
- }
-
- // print_v2("weights", w);
-
- /* WATCH IT! - should NOT reference (_clear or _other) vars for this while loop */
-
- /* walk around the fan using 'e_prev' */
- while (((l_iter = BM_vert_step_fan_loop(l_iter, &e_prev)) != l_first) && (l_iter != NULL)) {
- int i;
- /* quit once we hit the opposite face, if we have one */
- if (f_exit && UNLIKELY(f_exit == l_iter->f)) {
- break;
- }
-
-#ifdef USE_SEAM
- /* break out unless we find a match */
- is_seam = true;
-#endif
-
- /* ok. we have a loop. now be smart with it! */
- for (i = 0; i < bm->ldata.totlayer; i++) {
- if (CustomData_layer_has_math(&bm->ldata, i)) {
- const int offset = bm->ldata.layers[i].offset;
- const int type = bm->ldata.layers[i].type;
- const void *cd_src[2] = {
- POINTER_OFFSET(src[0], offset),
- POINTER_OFFSET(src[1], offset),
- };
- void *cd_iter = POINTER_OFFSET(l_iter->head.data, offset);
-
- /* detect seams */
- if (CustomData_data_equals(type, cd_src[0], cd_iter)) {
- CustomData_bmesh_interp_n(
- &bm->ldata, cd_src, w, NULL, ARRAY_SIZE(cd_src),
- POINTER_OFFSET(l_iter->head.data, offset), i);
-#ifdef USE_SEAM
- is_seam = false;
-#endif
- }
- }
- }
-
-#ifdef USE_SEAM
- if (is_seam) {
- break;
- }
-#endif
- }
- }
-
-//#undef USE_SEAM
-
+ /* disable seam check - the seam check would have to be done per layer, its not really that important */
+ //#define USE_SEAM
+ /* these don't need to be updated, since they will get removed when the edge collapses */
+ BMLoop *l_clear, *l_other;
+ const bool is_manifold = BM_edge_is_manifold(l->e);
+ int side;
+
+ /* first find the loop of 'v_other' thats attached to the face of 'l' */
+ if (l->v == v_clear) {
+ l_clear = l;
+ l_other = l->next;
+ }
+ else {
+ l_clear = l->next;
+ l_other = l;
+ }
+
+ BLI_assert(l_clear->v == v_clear);
+ BLI_assert(l_other->v == v_other);
+ /* quiet warnings for release */
+ (void)v_other;
+
+ /* now we have both corners of the face 'l->f' */
+ for (side = 0; side < 2; side++) {
+# ifdef USE_SEAM
+ bool is_seam = false;
+# endif
+ void *src[2];
+ BMFace *f_exit = is_manifold ? l->radial_next->f : NULL;
+ BMEdge *e_prev = l->e;
+ BMLoop *l_first;
+ BMLoop *l_iter;
+ float w[2];
+
+ if (side == 0) {
+ l_iter = l_first = l_clear;
+ src[0] = l_clear->head.data;
+ src[1] = l_other->head.data;
+
+ w[0] = customdata_fac;
+ w[1] = 1.0f - customdata_fac;
+ }
+ else {
+ l_iter = l_first = l_other;
+ src[0] = l_other->head.data;
+ src[1] = l_clear->head.data;
+
+ w[0] = 1.0f - customdata_fac;
+ w[1] = customdata_fac;
+ }
+
+ // print_v2("weights", w);
+
+ /* WATCH IT! - should NOT reference (_clear or _other) vars for this while loop */
+
+ /* walk around the fan using 'e_prev' */
+ while (((l_iter = BM_vert_step_fan_loop(l_iter, &e_prev)) != l_first) && (l_iter != NULL)) {
+ int i;
+ /* quit once we hit the opposite face, if we have one */
+ if (f_exit && UNLIKELY(f_exit == l_iter->f)) {
+ break;
+ }
+
+# ifdef USE_SEAM
+ /* break out unless we find a match */
+ is_seam = true;
+# endif
+
+ /* ok. we have a loop. now be smart with it! */
+ for (i = 0; i < bm->ldata.totlayer; i++) {
+ if (CustomData_layer_has_math(&bm->ldata, i)) {
+ const int offset = bm->ldata.layers[i].offset;
+ const int type = bm->ldata.layers[i].type;
+ const void *cd_src[2] = {
+ POINTER_OFFSET(src[0], offset),
+ POINTER_OFFSET(src[1], offset),
+ };
+ void *cd_iter = POINTER_OFFSET(l_iter->head.data, offset);
+
+ /* detect seams */
+ if (CustomData_data_equals(type, cd_src[0], cd_iter)) {
+ CustomData_bmesh_interp_n(&bm->ldata,
+ cd_src,
+ w,
+ NULL,
+ ARRAY_SIZE(cd_src),
+ POINTER_OFFSET(l_iter->head.data, offset),
+ i);
+# ifdef USE_SEAM
+ is_seam = false;
+# endif
+ }
+ }
+ }
+
+# ifdef USE_SEAM
+ if (is_seam) {
+ break;
+ }
+# endif
+ }
+ }
+
+ //#undef USE_SEAM
}
-#endif /* USE_CUSTOMDATA */
+#endif /* USE_CUSTOMDATA */
/**
* Check if the collapse will result in a degenerate mesh,
@@ -817,131 +808,129 @@ static void bm_edge_collapse_loop_customdata(
static void bm_edge_tag_enable(BMEdge *e)
{
- BM_elem_flag_enable(e->v1, BM_ELEM_TAG);
- BM_elem_flag_enable(e->v2, BM_ELEM_TAG);
- if (e->l) {
- BM_elem_flag_enable(e->l->f, BM_ELEM_TAG);
- if (e->l != e->l->radial_next) {
- BM_elem_flag_enable(e->l->radial_next->f, BM_ELEM_TAG);
- }
- }
+ BM_elem_flag_enable(e->v1, BM_ELEM_TAG);
+ BM_elem_flag_enable(e->v2, BM_ELEM_TAG);
+ if (e->l) {
+ BM_elem_flag_enable(e->l->f, BM_ELEM_TAG);
+ if (e->l != e->l->radial_next) {
+ BM_elem_flag_enable(e->l->radial_next->f, BM_ELEM_TAG);
+ }
+ }
}
static void bm_edge_tag_disable(BMEdge *e)
{
- BM_elem_flag_disable(e->v1, BM_ELEM_TAG);
- BM_elem_flag_disable(e->v2, BM_ELEM_TAG);
- if (e->l) {
- BM_elem_flag_disable(e->l->f, BM_ELEM_TAG);
- if (e->l != e->l->radial_next) {
- BM_elem_flag_disable(e->l->radial_next->f, BM_ELEM_TAG);
- }
- }
+ BM_elem_flag_disable(e->v1, BM_ELEM_TAG);
+ BM_elem_flag_disable(e->v2, BM_ELEM_TAG);
+ if (e->l) {
+ BM_elem_flag_disable(e->l->f, BM_ELEM_TAG);
+ if (e->l != e->l->radial_next) {
+ BM_elem_flag_disable(e->l->radial_next->f, BM_ELEM_TAG);
+ }
+ }
}
static bool bm_edge_tag_test(BMEdge *e)
{
- /* is the edge or one of its faces tagged? */
- return (BM_elem_flag_test(e->v1, BM_ELEM_TAG) ||
- BM_elem_flag_test(e->v2, BM_ELEM_TAG) ||
- (e->l && (BM_elem_flag_test(e->l->f, BM_ELEM_TAG) ||
- (e->l != e->l->radial_next &&
- BM_elem_flag_test(e->l->radial_next->f, BM_ELEM_TAG))))
- );
+ /* is the edge or one of its faces tagged? */
+ return (BM_elem_flag_test(e->v1, BM_ELEM_TAG) || BM_elem_flag_test(e->v2, BM_ELEM_TAG) ||
+ (e->l &&
+ (BM_elem_flag_test(e->l->f, BM_ELEM_TAG) ||
+ (e->l != e->l->radial_next && BM_elem_flag_test(e->l->radial_next->f, BM_ELEM_TAG)))));
}
/* takes the edges loop */
BLI_INLINE int bm_edge_is_manifold_or_boundary(BMLoop *l)
{
#if 0
- /* less optimized version of check below */
- return (BM_edge_is_manifold(l->e) || BM_edge_is_boundary(l->e);
+ /* less optimized version of check below */
+ return (BM_edge_is_manifold(l->e) || BM_edge_is_boundary(l->e);
#else
- /* if the edge is a boundary it points to its self, else this must be a manifold */
- return LIKELY(l) && LIKELY(l->radial_next->radial_next == l);
+ /* if the edge is a boundary it points to its self, else this must be a manifold */
+ return LIKELY(l) && LIKELY(l->radial_next->radial_next == l);
#endif
}
static bool bm_edge_collapse_is_degenerate_topology(BMEdge *e_first)
{
- /* simply check that there is no overlap between faces and edges of each vert,
- * (excluding the 2 faces attached to 'e' and 'e' its self) */
-
- BMEdge *e_iter;
-
- /* clear flags on both disks */
- e_iter = e_first;
- do {
- if (!bm_edge_is_manifold_or_boundary(e_iter->l)) {
- return true;
- }
- bm_edge_tag_disable(e_iter);
- } while ((e_iter = bmesh_disk_edge_next(e_iter, e_first->v1)) != e_first);
-
- e_iter = e_first;
- do {
- if (!bm_edge_is_manifold_or_boundary(e_iter->l)) {
- return true;
- }
- bm_edge_tag_disable(e_iter);
- } while ((e_iter = bmesh_disk_edge_next(e_iter, e_first->v2)) != e_first);
-
- /* now enable one side... */
- e_iter = e_first;
- do {
- bm_edge_tag_enable(e_iter);
- } while ((e_iter = bmesh_disk_edge_next(e_iter, e_first->v1)) != e_first);
-
- /* ... except for the edge we will collapse, we know thats shared,
- * disable this to avoid false positive. We could be smart and never enable these
- * face/edge tags in the first place but easier to do this */
- // bm_edge_tag_disable(e_first);
- /* do inline... */
- {
+ /* simply check that there is no overlap between faces and edges of each vert,
+ * (excluding the 2 faces attached to 'e' and 'e' its self) */
+
+ BMEdge *e_iter;
+
+ /* clear flags on both disks */
+ e_iter = e_first;
+ do {
+ if (!bm_edge_is_manifold_or_boundary(e_iter->l)) {
+ return true;
+ }
+ bm_edge_tag_disable(e_iter);
+ } while ((e_iter = bmesh_disk_edge_next(e_iter, e_first->v1)) != e_first);
+
+ e_iter = e_first;
+ do {
+ if (!bm_edge_is_manifold_or_boundary(e_iter->l)) {
+ return true;
+ }
+ bm_edge_tag_disable(e_iter);
+ } while ((e_iter = bmesh_disk_edge_next(e_iter, e_first->v2)) != e_first);
+
+ /* now enable one side... */
+ e_iter = e_first;
+ do {
+ bm_edge_tag_enable(e_iter);
+ } while ((e_iter = bmesh_disk_edge_next(e_iter, e_first->v1)) != e_first);
+
+ /* ... except for the edge we will collapse, we know thats shared,
+ * disable this to avoid false positive. We could be smart and never enable these
+ * face/edge tags in the first place but easier to do this */
+ // bm_edge_tag_disable(e_first);
+ /* do inline... */
+ {
#if 0
- BMIter iter;
- BMIter liter;
- BMLoop *l;
- BMVert *v;
- BM_ITER_ELEM (l, &liter, e_first, BM_LOOPS_OF_EDGE) {
- BM_elem_flag_disable(l->f, BM_ELEM_TAG);
- BM_ITER_ELEM (v, &iter, l->f, BM_VERTS_OF_FACE) {
- BM_elem_flag_disable(v, BM_ELEM_TAG);
- }
- }
+ BMIter iter;
+ BMIter liter;
+ BMLoop *l;
+ BMVert *v;
+ BM_ITER_ELEM (l, &liter, e_first, BM_LOOPS_OF_EDGE) {
+ BM_elem_flag_disable(l->f, BM_ELEM_TAG);
+ BM_ITER_ELEM (v, &iter, l->f, BM_VERTS_OF_FACE) {
+ BM_elem_flag_disable(v, BM_ELEM_TAG);
+ }
+ }
#else
- /* we know each face is a triangle, no looping/iterators needed here */
-
- BMLoop *l_radial;
- BMLoop *l_face;
-
- l_radial = e_first->l;
- l_face = l_radial;
- BLI_assert(l_face->f->len == 3);
- BM_elem_flag_disable(l_face->f, BM_ELEM_TAG);
- BM_elem_flag_disable((l_face = l_radial)->v, BM_ELEM_TAG);
- BM_elem_flag_disable((l_face = l_face->next)->v, BM_ELEM_TAG);
- BM_elem_flag_disable(( l_face->next)->v, BM_ELEM_TAG);
- l_face = l_radial->radial_next;
- if (l_radial != l_face) {
- BLI_assert(l_face->f->len == 3);
- BM_elem_flag_disable(l_face->f, BM_ELEM_TAG);
- BM_elem_flag_disable((l_face = l_radial->radial_next)->v, BM_ELEM_TAG);
- BM_elem_flag_disable((l_face = l_face->next)->v, BM_ELEM_TAG);
- BM_elem_flag_disable(( l_face->next)->v, BM_ELEM_TAG);
- }
+ /* we know each face is a triangle, no looping/iterators needed here */
+
+ BMLoop *l_radial;
+ BMLoop *l_face;
+
+ l_radial = e_first->l;
+ l_face = l_radial;
+ BLI_assert(l_face->f->len == 3);
+ BM_elem_flag_disable(l_face->f, BM_ELEM_TAG);
+ BM_elem_flag_disable((l_face = l_radial)->v, BM_ELEM_TAG);
+ BM_elem_flag_disable((l_face = l_face->next)->v, BM_ELEM_TAG);
+ BM_elem_flag_disable((l_face->next)->v, BM_ELEM_TAG);
+ l_face = l_radial->radial_next;
+ if (l_radial != l_face) {
+ BLI_assert(l_face->f->len == 3);
+ BM_elem_flag_disable(l_face->f, BM_ELEM_TAG);
+ BM_elem_flag_disable((l_face = l_radial->radial_next)->v, BM_ELEM_TAG);
+ BM_elem_flag_disable((l_face = l_face->next)->v, BM_ELEM_TAG);
+ BM_elem_flag_disable((l_face->next)->v, BM_ELEM_TAG);
+ }
#endif
- }
+ }
- /* and check for overlap */
- e_iter = e_first;
- do {
- if (bm_edge_tag_test(e_iter)) {
- return true;
- }
- } while ((e_iter = bmesh_disk_edge_next(e_iter, e_first->v2)) != e_first);
+ /* and check for overlap */
+ e_iter = e_first;
+ do {
+ if (bm_edge_tag_test(e_iter)) {
+ return true;
+ }
+ } while ((e_iter = bmesh_disk_edge_next(e_iter, e_first->v2)) != e_first);
- return false;
+ return false;
}
/**
@@ -954,334 +943,340 @@ static bool bm_edge_collapse_is_degenerate_topology(BMEdge *e_first)
* \param r_e_clear_other: Let caller know what edges we remove besides \a e_clear
* \param customdata_flag: Merge factor, scales from 0 - 1 ('v_clear' -> 'v_other')
*/
-static bool bm_edge_collapse(
- BMesh *bm, BMEdge *e_clear, BMVert *v_clear, int r_e_clear_other[2],
+static bool bm_edge_collapse(BMesh *bm,
+ BMEdge *e_clear,
+ BMVert *v_clear,
+ int r_e_clear_other[2],
#ifdef USE_SYMMETRY
- int *edge_symmetry_map,
+ int *edge_symmetry_map,
#endif
#ifdef USE_CUSTOMDATA
- const CD_UseFlag customdata_flag,
- const float customdata_fac
+ const CD_UseFlag customdata_flag,
+ const float customdata_fac
#else
- const CD_UseFlag UNUSED(customdata_flag),
- const float UNUSED(customdata_fac)
+ const CD_UseFlag UNUSED(customdata_flag),
+ const float UNUSED(customdata_fac)
#endif
- )
+)
{
- BMVert *v_other;
-
- v_other = BM_edge_other_vert(e_clear, v_clear);
- BLI_assert(v_other != NULL);
-
- if (BM_edge_is_manifold(e_clear)) {
- BMLoop *l_a, *l_b;
- BMEdge *e_a_other[2], *e_b_other[2];
- bool ok;
-
- ok = BM_edge_loop_pair(e_clear, &l_a, &l_b);
-
- BLI_assert(ok == true);
- BLI_assert(l_a->f->len == 3);
- BLI_assert(l_b->f->len == 3);
- UNUSED_VARS_NDEBUG(ok);
-
- /* keep 'v_clear' 0th */
- if (BM_vert_in_edge(l_a->prev->e, v_clear)) {
- e_a_other[0] = l_a->prev->e;
- e_a_other[1] = l_a->next->e;
- }
- else {
- e_a_other[1] = l_a->prev->e;
- e_a_other[0] = l_a->next->e;
- }
-
- if (BM_vert_in_edge(l_b->prev->e, v_clear)) {
- e_b_other[0] = l_b->prev->e;
- e_b_other[1] = l_b->next->e;
- }
- else {
- e_b_other[1] = l_b->prev->e;
- e_b_other[0] = l_b->next->e;
- }
-
- /* we could assert this case, but better just bail out */
+ BMVert *v_other;
+
+ v_other = BM_edge_other_vert(e_clear, v_clear);
+ BLI_assert(v_other != NULL);
+
+ if (BM_edge_is_manifold(e_clear)) {
+ BMLoop *l_a, *l_b;
+ BMEdge *e_a_other[2], *e_b_other[2];
+ bool ok;
+
+ ok = BM_edge_loop_pair(e_clear, &l_a, &l_b);
+
+ BLI_assert(ok == true);
+ BLI_assert(l_a->f->len == 3);
+ BLI_assert(l_b->f->len == 3);
+ UNUSED_VARS_NDEBUG(ok);
+
+ /* keep 'v_clear' 0th */
+ if (BM_vert_in_edge(l_a->prev->e, v_clear)) {
+ e_a_other[0] = l_a->prev->e;
+ e_a_other[1] = l_a->next->e;
+ }
+ else {
+ e_a_other[1] = l_a->prev->e;
+ e_a_other[0] = l_a->next->e;
+ }
+
+ if (BM_vert_in_edge(l_b->prev->e, v_clear)) {
+ e_b_other[0] = l_b->prev->e;
+ e_b_other[1] = l_b->next->e;
+ }
+ else {
+ e_b_other[1] = l_b->prev->e;
+ e_b_other[0] = l_b->next->e;
+ }
+
+ /* we could assert this case, but better just bail out */
#if 0
- BLI_assert(e_a_other[0] != e_b_other[0]);
- BLI_assert(e_a_other[0] != e_b_other[1]);
- BLI_assert(e_b_other[0] != e_a_other[0]);
- BLI_assert(e_b_other[0] != e_a_other[1]);
+ BLI_assert(e_a_other[0] != e_b_other[0]);
+ BLI_assert(e_a_other[0] != e_b_other[1]);
+ BLI_assert(e_b_other[0] != e_a_other[0]);
+ BLI_assert(e_b_other[0] != e_a_other[1]);
#endif
- /* not totally common but we want to avoid */
- if (ELEM(e_a_other[0], e_b_other[0], e_b_other[1]) ||
- ELEM(e_a_other[1], e_b_other[0], e_b_other[1]))
- {
- return false;
- }
+ /* not totally common but we want to avoid */
+ if (ELEM(e_a_other[0], e_b_other[0], e_b_other[1]) ||
+ ELEM(e_a_other[1], e_b_other[0], e_b_other[1])) {
+ return false;
+ }
- BLI_assert(BM_edge_share_vert(e_a_other[0], e_b_other[0]));
- BLI_assert(BM_edge_share_vert(e_a_other[1], e_b_other[1]));
+ BLI_assert(BM_edge_share_vert(e_a_other[0], e_b_other[0]));
+ BLI_assert(BM_edge_share_vert(e_a_other[1], e_b_other[1]));
- r_e_clear_other[0] = BM_elem_index_get(e_a_other[0]);
- r_e_clear_other[1] = BM_elem_index_get(e_b_other[0]);
+ r_e_clear_other[0] = BM_elem_index_get(e_a_other[0]);
+ r_e_clear_other[1] = BM_elem_index_get(e_b_other[0]);
#ifdef USE_CUSTOMDATA
- /* before killing, do customdata */
- if (customdata_flag & CD_DO_VERT) {
- BM_data_interp_from_verts(bm, v_other, v_clear, v_other, customdata_fac);
- }
- if (customdata_flag & CD_DO_EDGE) {
- BM_data_interp_from_edges(bm, e_a_other[1], e_a_other[0], e_a_other[1], customdata_fac);
- BM_data_interp_from_edges(bm, e_b_other[1], e_b_other[0], e_b_other[1], customdata_fac);
- }
- if (customdata_flag & CD_DO_LOOP) {
- bm_edge_collapse_loop_customdata(bm, e_clear->l, v_clear, v_other, customdata_fac);
- bm_edge_collapse_loop_customdata(bm, e_clear->l->radial_next, v_clear, v_other, customdata_fac);
- }
+ /* before killing, do customdata */
+ if (customdata_flag & CD_DO_VERT) {
+ BM_data_interp_from_verts(bm, v_other, v_clear, v_other, customdata_fac);
+ }
+ if (customdata_flag & CD_DO_EDGE) {
+ BM_data_interp_from_edges(bm, e_a_other[1], e_a_other[0], e_a_other[1], customdata_fac);
+ BM_data_interp_from_edges(bm, e_b_other[1], e_b_other[0], e_b_other[1], customdata_fac);
+ }
+ if (customdata_flag & CD_DO_LOOP) {
+ bm_edge_collapse_loop_customdata(bm, e_clear->l, v_clear, v_other, customdata_fac);
+ bm_edge_collapse_loop_customdata(
+ bm, e_clear->l->radial_next, v_clear, v_other, customdata_fac);
+ }
#endif
- BM_edge_kill(bm, e_clear);
+ BM_edge_kill(bm, e_clear);
- v_other->head.hflag |= v_clear->head.hflag;
- BM_vert_splice(bm, v_other, v_clear);
+ v_other->head.hflag |= v_clear->head.hflag;
+ BM_vert_splice(bm, v_other, v_clear);
- e_a_other[1]->head.hflag |= e_a_other[0]->head.hflag;
- e_b_other[1]->head.hflag |= e_b_other[0]->head.hflag;
- BM_edge_splice(bm, e_a_other[1], e_a_other[0]);
- BM_edge_splice(bm, e_b_other[1], e_b_other[0]);
+ e_a_other[1]->head.hflag |= e_a_other[0]->head.hflag;
+ e_b_other[1]->head.hflag |= e_b_other[0]->head.hflag;
+ BM_edge_splice(bm, e_a_other[1], e_a_other[0]);
+ BM_edge_splice(bm, e_b_other[1], e_b_other[0]);
#ifdef USE_SYMMETRY
- /* update mirror map */
- if (edge_symmetry_map) {
- if (edge_symmetry_map[r_e_clear_other[0]] != -1) {
- edge_symmetry_map[edge_symmetry_map[r_e_clear_other[0]]] = BM_elem_index_get(e_a_other[1]);
- }
- if (edge_symmetry_map[r_e_clear_other[1]] != -1) {
- edge_symmetry_map[edge_symmetry_map[r_e_clear_other[1]]] = BM_elem_index_get(e_b_other[1]);
- }
- }
+ /* update mirror map */
+ if (edge_symmetry_map) {
+ if (edge_symmetry_map[r_e_clear_other[0]] != -1) {
+ edge_symmetry_map[edge_symmetry_map[r_e_clear_other[0]]] = BM_elem_index_get(e_a_other[1]);
+ }
+ if (edge_symmetry_map[r_e_clear_other[1]] != -1) {
+ edge_symmetry_map[edge_symmetry_map[r_e_clear_other[1]]] = BM_elem_index_get(e_b_other[1]);
+ }
+ }
#endif
- // BM_mesh_validate(bm);
+ // BM_mesh_validate(bm);
- return true;
- }
- else if (BM_edge_is_boundary(e_clear)) {
- /* same as above but only one triangle */
- BMLoop *l_a;
- BMEdge *e_a_other[2];
+ return true;
+ }
+ else if (BM_edge_is_boundary(e_clear)) {
+ /* same as above but only one triangle */
+ BMLoop *l_a;
+ BMEdge *e_a_other[2];
- l_a = e_clear->l;
+ l_a = e_clear->l;
- BLI_assert(l_a->f->len == 3);
+ BLI_assert(l_a->f->len == 3);
- /* keep 'v_clear' 0th */
- if (BM_vert_in_edge(l_a->prev->e, v_clear)) {
- e_a_other[0] = l_a->prev->e;
- e_a_other[1] = l_a->next->e;
- }
- else {
- e_a_other[1] = l_a->prev->e;
- e_a_other[0] = l_a->next->e;
- }
+ /* keep 'v_clear' 0th */
+ if (BM_vert_in_edge(l_a->prev->e, v_clear)) {
+ e_a_other[0] = l_a->prev->e;
+ e_a_other[1] = l_a->next->e;
+ }
+ else {
+ e_a_other[1] = l_a->prev->e;
+ e_a_other[0] = l_a->next->e;
+ }
- r_e_clear_other[0] = BM_elem_index_get(e_a_other[0]);
- r_e_clear_other[1] = -1;
+ r_e_clear_other[0] = BM_elem_index_get(e_a_other[0]);
+ r_e_clear_other[1] = -1;
#ifdef USE_CUSTOMDATA
- /* before killing, do customdata */
- if (customdata_flag & CD_DO_VERT) {
- BM_data_interp_from_verts(bm, v_other, v_clear, v_other, customdata_fac);
- }
- if (customdata_flag & CD_DO_EDGE) {
- BM_data_interp_from_edges(bm, e_a_other[1], e_a_other[0], e_a_other[1], customdata_fac);
- }
- if (customdata_flag & CD_DO_LOOP) {
- bm_edge_collapse_loop_customdata(bm, e_clear->l, v_clear, v_other, customdata_fac);
- }
+ /* before killing, do customdata */
+ if (customdata_flag & CD_DO_VERT) {
+ BM_data_interp_from_verts(bm, v_other, v_clear, v_other, customdata_fac);
+ }
+ if (customdata_flag & CD_DO_EDGE) {
+ BM_data_interp_from_edges(bm, e_a_other[1], e_a_other[0], e_a_other[1], customdata_fac);
+ }
+ if (customdata_flag & CD_DO_LOOP) {
+ bm_edge_collapse_loop_customdata(bm, e_clear->l, v_clear, v_other, customdata_fac);
+ }
#endif
- BM_edge_kill(bm, e_clear);
+ BM_edge_kill(bm, e_clear);
- v_other->head.hflag |= v_clear->head.hflag;
- BM_vert_splice(bm, v_other, v_clear);
+ v_other->head.hflag |= v_clear->head.hflag;
+ BM_vert_splice(bm, v_other, v_clear);
- e_a_other[1]->head.hflag |= e_a_other[0]->head.hflag;
- BM_edge_splice(bm, e_a_other[1], e_a_other[0]);
+ e_a_other[1]->head.hflag |= e_a_other[0]->head.hflag;
+ BM_edge_splice(bm, e_a_other[1], e_a_other[0]);
#ifdef USE_SYMMETRY
- /* update mirror map */
- if (edge_symmetry_map) {
- if (edge_symmetry_map[r_e_clear_other[0]] != -1) {
- edge_symmetry_map[edge_symmetry_map[r_e_clear_other[0]]] = BM_elem_index_get(e_a_other[1]);
- }
- }
+ /* update mirror map */
+ if (edge_symmetry_map) {
+ if (edge_symmetry_map[r_e_clear_other[0]] != -1) {
+ edge_symmetry_map[edge_symmetry_map[r_e_clear_other[0]]] = BM_elem_index_get(e_a_other[1]);
+ }
+ }
#endif
- // BM_mesh_validate(bm);
+ // BM_mesh_validate(bm);
- return true;
- }
- else {
- return false;
- }
+ return true;
+ }
+ else {
+ return false;
+ }
}
-
/**
* Collapse e the edge, removing e->v2
*
* \return true when the edge was collapsed.
*/
-static bool bm_decim_edge_collapse(
- BMesh *bm, BMEdge *e,
- Quadric *vquadrics,
- float *vweights, const float vweight_factor,
- Heap *eheap, HeapNode **eheap_table,
+static bool bm_decim_edge_collapse(BMesh *bm,
+ BMEdge *e,
+ Quadric *vquadrics,
+ float *vweights,
+ const float vweight_factor,
+ Heap *eheap,
+ HeapNode **eheap_table,
#ifdef USE_SYMMETRY
- int *edge_symmetry_map,
+ int *edge_symmetry_map,
#endif
- const CD_UseFlag customdata_flag,
- float optimize_co[3], bool optimize_co_calc
- )
+ const CD_UseFlag customdata_flag,
+ float optimize_co[3],
+ bool optimize_co_calc)
{
- int e_clear_other[2];
- BMVert *v_other = e->v1;
- const int v_other_index = BM_elem_index_get(e->v1);
- /* the vert is removed so only store the index */
- const int v_clear_index = BM_elem_index_get(e->v2);
- float customdata_fac;
+ int e_clear_other[2];
+ BMVert *v_other = e->v1;
+ const int v_other_index = BM_elem_index_get(e->v1);
+ /* the vert is removed so only store the index */
+ const int v_clear_index = BM_elem_index_get(e->v2);
+ float customdata_fac;
#ifdef USE_VERT_NORMAL_INTERP
- float v_clear_no[3];
- copy_v3_v3(v_clear_no, e->v2->no);
+ float v_clear_no[3];
+ copy_v3_v3(v_clear_no, e->v2->no);
#endif
- /* when false, use without degenerate checks */
- if (optimize_co_calc) {
- /* disallow collapsing which results in degenerate cases */
- if (UNLIKELY(bm_edge_collapse_is_degenerate_topology(e))) {
- /* add back with a high cost */
- bm_decim_invalid_edge_cost_single(e, eheap, eheap_table);
- return false;
- }
-
- bm_decim_calc_target_co_fl(e, optimize_co, vquadrics);
-
- /* check if this would result in an overlapping face */
- if (UNLIKELY(bm_edge_collapse_is_degenerate_flip(e, optimize_co))) {
- /* add back with a high cost */
- bm_decim_invalid_edge_cost_single(e, eheap, eheap_table);
- return false;
- }
- }
-
- /* use for customdata merging */
- if (LIKELY(compare_v3v3(e->v1->co, e->v2->co, FLT_EPSILON) == false)) {
- customdata_fac = line_point_factor_v3(optimize_co, e->v1->co, e->v2->co);
+ /* when false, use without degenerate checks */
+ if (optimize_co_calc) {
+ /* disallow collapsing which results in degenerate cases */
+ if (UNLIKELY(bm_edge_collapse_is_degenerate_topology(e))) {
+ /* add back with a high cost */
+ bm_decim_invalid_edge_cost_single(e, eheap, eheap_table);
+ return false;
+ }
+
+ bm_decim_calc_target_co_fl(e, optimize_co, vquadrics);
+
+ /* check if this would result in an overlapping face */
+ if (UNLIKELY(bm_edge_collapse_is_degenerate_flip(e, optimize_co))) {
+ /* add back with a high cost */
+ bm_decim_invalid_edge_cost_single(e, eheap, eheap_table);
+ return false;
+ }
+ }
+
+ /* use for customdata merging */
+ if (LIKELY(compare_v3v3(e->v1->co, e->v2->co, FLT_EPSILON) == false)) {
+ customdata_fac = line_point_factor_v3(optimize_co, e->v1->co, e->v2->co);
#if 0
- /* simple test for stupid collapse */
- if (customdata_fac < 0.0 - FLT_EPSILON || customdata_fac > 1.0f + FLT_EPSILON) {
- return false;
- }
+ /* simple test for stupid collapse */
+ if (customdata_fac < 0.0 - FLT_EPSILON || customdata_fac > 1.0f + FLT_EPSILON) {
+ return false;
+ }
#endif
- }
- else {
- /* avoid divide by zero */
- customdata_fac = 0.5f;
- }
-
- if (bm_edge_collapse(
- bm, e, e->v2, e_clear_other,
+ }
+ else {
+ /* avoid divide by zero */
+ customdata_fac = 0.5f;
+ }
+
+ if (bm_edge_collapse(bm,
+ e,
+ e->v2,
+ e_clear_other,
#ifdef USE_SYMMETRY
- edge_symmetry_map,
+ edge_symmetry_map,
#endif
- customdata_flag, customdata_fac))
- {
- /* update collapse info */
- int i;
-
- if (vweights) {
- float v_other_weight = interpf(vweights[v_other_index], vweights[v_clear_index], customdata_fac);
- CLAMP(v_other_weight, 0.0f, 1.0f);
- vweights[v_other_index] = v_other_weight;
- }
-
- /* paranoid safety check */
- e = NULL;
-
- copy_v3_v3(v_other->co, optimize_co);
-
- /* remove eheap */
- for (i = 0; i < 2; i++) {
- /* highly unlikely 'eheap_table[ke_other[i]]' would be NULL, but do for sanity sake */
- if ((e_clear_other[i] != -1) && (eheap_table[e_clear_other[i]] != NULL)) {
- BLI_heap_remove(eheap, eheap_table[e_clear_other[i]]);
- eheap_table[e_clear_other[i]] = NULL;
- }
- }
-
- /* update vertex quadric, add kept vertex from killed vertex */
- BLI_quadric_add_qu_qu(&vquadrics[v_other_index], &vquadrics[v_clear_index]);
-
- /* update connected normals */
-
- /* in fact face normals are not used for progressive updates, no need to update them */
- // BM_vert_normal_update_all(v);
+ customdata_flag,
+ customdata_fac)) {
+ /* update collapse info */
+ int i;
+
+ if (vweights) {
+ float v_other_weight = interpf(
+ vweights[v_other_index], vweights[v_clear_index], customdata_fac);
+ CLAMP(v_other_weight, 0.0f, 1.0f);
+ vweights[v_other_index] = v_other_weight;
+ }
+
+ /* paranoid safety check */
+ e = NULL;
+
+ copy_v3_v3(v_other->co, optimize_co);
+
+ /* remove eheap */
+ for (i = 0; i < 2; i++) {
+ /* highly unlikely 'eheap_table[ke_other[i]]' would be NULL, but do for sanity sake */
+ if ((e_clear_other[i] != -1) && (eheap_table[e_clear_other[i]] != NULL)) {
+ BLI_heap_remove(eheap, eheap_table[e_clear_other[i]]);
+ eheap_table[e_clear_other[i]] = NULL;
+ }
+ }
+
+ /* update vertex quadric, add kept vertex from killed vertex */
+ BLI_quadric_add_qu_qu(&vquadrics[v_other_index], &vquadrics[v_clear_index]);
+
+ /* update connected normals */
+
+ /* in fact face normals are not used for progressive updates, no need to update them */
+ // BM_vert_normal_update_all(v);
#ifdef USE_VERT_NORMAL_INTERP
- interp_v3_v3v3(v_other->no, v_other->no, v_clear_no, customdata_fac);
- normalize_v3(v_other->no);
+ interp_v3_v3v3(v_other->no, v_other->no, v_clear_no, customdata_fac);
+ normalize_v3(v_other->no);
#else
- BM_vert_normal_update(v_other);
+ BM_vert_normal_update(v_other);
#endif
-
- /* update error costs and the eheap */
- if (LIKELY(v_other->e)) {
- BMEdge *e_iter;
- BMEdge *e_first;
- e_iter = e_first = v_other->e;
- do {
- BLI_assert(BM_edge_find_double(e_iter) == NULL);
- bm_decim_build_edge_cost_single(e_iter, vquadrics, vweights, vweight_factor, eheap, eheap_table);
- } while ((e_iter = bmesh_disk_edge_next(e_iter, v_other)) != e_first);
- }
-
- /* this block used to be disabled,
- * but enable now since surrounding faces may have been
- * set to COST_INVALID because of a face overlap that no longer occurs */
+ /* update error costs and the eheap */
+ if (LIKELY(v_other->e)) {
+ BMEdge *e_iter;
+ BMEdge *e_first;
+ e_iter = e_first = v_other->e;
+ do {
+ BLI_assert(BM_edge_find_double(e_iter) == NULL);
+ bm_decim_build_edge_cost_single(
+ e_iter, vquadrics, vweights, vweight_factor, eheap, eheap_table);
+ } while ((e_iter = bmesh_disk_edge_next(e_iter, v_other)) != e_first);
+ }
+
+ /* this block used to be disabled,
+ * but enable now since surrounding faces may have been
+ * set to COST_INVALID because of a face overlap that no longer occurs */
#if 1
- /* optional, update edges around the vertex face fan */
- {
- BMIter liter;
- BMLoop *l;
- BM_ITER_ELEM (l, &liter, v_other, BM_LOOPS_OF_VERT) {
- if (l->f->len == 3) {
- BMEdge *e_outer;
- if (BM_vert_in_edge(l->prev->e, l->v)) {
- e_outer = l->next->e;
- }
- else {
- e_outer = l->prev->e;
- }
-
- BLI_assert(BM_vert_in_edge(e_outer, l->v) == false);
-
- bm_decim_build_edge_cost_single(e_outer, vquadrics, vweights, vweight_factor, eheap, eheap_table);
- }
- }
- }
- /* end optional update */
- return true;
+ /* optional, update edges around the vertex face fan */
+ {
+ BMIter liter;
+ BMLoop *l;
+ BM_ITER_ELEM (l, &liter, v_other, BM_LOOPS_OF_VERT) {
+ if (l->f->len == 3) {
+ BMEdge *e_outer;
+ if (BM_vert_in_edge(l->prev->e, l->v)) {
+ e_outer = l->next->e;
+ }
+ else {
+ e_outer = l->prev->e;
+ }
+
+ BLI_assert(BM_vert_in_edge(e_outer, l->v) == false);
+
+ bm_decim_build_edge_cost_single(
+ e_outer, vquadrics, vweights, vweight_factor, eheap, eheap_table);
+ }
+ }
+ }
+ /* end optional update */
+ return true;
#endif
- }
- else {
- /* add back with a high cost */
- bm_decim_invalid_edge_cost_single(e, eheap, eheap_table);
- return false;
- }
+ }
+ else {
+ /* add back with a high cost */
+ bm_decim_invalid_edge_cost_single(e, eheap, eheap_table);
+ return false;
+ }
}
-
/* Main Decimate Function
* ********************** */
@@ -1294,233 +1289,251 @@ static bool bm_decim_edge_collapse(
* \param symmetry_axis: Axis of symmetry, -1 to disable mirror decimate.
* \param symmetry_eps: Threshold when matching mirror verts.
*/
-void BM_mesh_decimate_collapse(
- BMesh *bm,
- const float factor,
- float *vweights, float vweight_factor,
- const bool do_triangulate,
- const int symmetry_axis, const float symmetry_eps)
+void BM_mesh_decimate_collapse(BMesh *bm,
+ const float factor,
+ float *vweights,
+ float vweight_factor,
+ const bool do_triangulate,
+ const int symmetry_axis,
+ const float symmetry_eps)
{
- /* edge heap */
- Heap *eheap;
- /* edge index aligned table pointing to the eheap */
- HeapNode **eheap_table;
- /* vert index aligned quadrics */
- Quadric *vquadrics;
- int tot_edge_orig;
- int face_tot_target;
+ /* edge heap */
+ Heap *eheap;
+ /* edge index aligned table pointing to the eheap */
+ HeapNode **eheap_table;
+ /* vert index aligned quadrics */
+ Quadric *vquadrics;
+ int tot_edge_orig;
+ int face_tot_target;
- CD_UseFlag customdata_flag = 0;
+ CD_UseFlag customdata_flag = 0;
#ifdef USE_SYMMETRY
- bool use_symmetry = (symmetry_axis != -1);
- int *edge_symmetry_map;
+ bool use_symmetry = (symmetry_axis != -1);
+ int *edge_symmetry_map;
#endif
#ifdef USE_TRIANGULATE
- int edges_tri_tot = 0;
- /* temp convert quads to triangles */
- bool use_triangulate = bm_decim_triangulate_begin(bm, &edges_tri_tot);
+ int edges_tri_tot = 0;
+ /* temp convert quads to triangles */
+ bool use_triangulate = bm_decim_triangulate_begin(bm, &edges_tri_tot);
#else
- UNUSED_VARS(do_triangulate);
+ UNUSED_VARS(do_triangulate);
#endif
+ /* alloc vars */
+ vquadrics = MEM_callocN(sizeof(Quadric) * bm->totvert, __func__);
+ /* since some edges may be degenerate, we might be over allocing a little here */
+ eheap = BLI_heap_new_ex(bm->totedge);
+ eheap_table = MEM_mallocN(sizeof(HeapNode *) * bm->totedge, __func__);
+ tot_edge_orig = bm->totedge;
- /* alloc vars */
- vquadrics = MEM_callocN(sizeof(Quadric) * bm->totvert, __func__);
- /* since some edges may be degenerate, we might be over allocing a little here */
- eheap = BLI_heap_new_ex(bm->totedge);
- eheap_table = MEM_mallocN(sizeof(HeapNode *) * bm->totedge, __func__);
- tot_edge_orig = bm->totedge;
-
-
- /* build initial edge collapse cost data */
- bm_decim_build_quadrics(bm, vquadrics);
+ /* build initial edge collapse cost data */
+ bm_decim_build_quadrics(bm, vquadrics);
- bm_decim_build_edge_cost(bm, vquadrics, vweights, vweight_factor, eheap, eheap_table);
+ bm_decim_build_edge_cost(bm, vquadrics, vweights, vweight_factor, eheap, eheap_table);
- face_tot_target = bm->totface * factor;
- bm->elem_index_dirty |= BM_ALL;
+ face_tot_target = bm->totface * factor;
+ bm->elem_index_dirty |= BM_ALL;
#ifdef USE_SYMMETRY
- edge_symmetry_map = (use_symmetry) ? bm_edge_symmetry_map(bm, symmetry_axis, symmetry_eps) : NULL;
+ edge_symmetry_map = (use_symmetry) ? bm_edge_symmetry_map(bm, symmetry_axis, symmetry_eps) :
+ NULL;
#else
- UNUSED_VARS(symmetry_axis, symmetry_eps);
+ UNUSED_VARS(symmetry_axis, symmetry_eps);
#endif
#ifdef USE_CUSTOMDATA
- /* initialize customdata flag, we only need math for loops */
- if (CustomData_has_interp(&bm->vdata)) { customdata_flag |= CD_DO_VERT; }
- if (CustomData_has_interp(&bm->edata)) { customdata_flag |= CD_DO_EDGE; }
- if (CustomData_has_math(&bm->ldata)) { customdata_flag |= CD_DO_LOOP; }
+ /* initialize customdata flag, we only need math for loops */
+ if (CustomData_has_interp(&bm->vdata)) {
+ customdata_flag |= CD_DO_VERT;
+ }
+ if (CustomData_has_interp(&bm->edata)) {
+ customdata_flag |= CD_DO_EDGE;
+ }
+ if (CustomData_has_math(&bm->ldata)) {
+ customdata_flag |= CD_DO_LOOP;
+ }
#endif
- /* iterative edge collapse and maintain the eheap */
+ /* iterative edge collapse and maintain the eheap */
#ifdef USE_SYMMETRY
- if (use_symmetry == false)
+ if (use_symmetry == false)
#endif
- {
- /* simple non-mirror case */
- while ((bm->totface > face_tot_target) &&
- (BLI_heap_is_empty(eheap) == false) &&
- (BLI_heap_top_value(eheap) != COST_INVALID))
- {
- // const float value = BLI_heap_node_value(BLI_heap_top(eheap));
- BMEdge *e = BLI_heap_pop_min(eheap);
- float optimize_co[3];
- /* handy to detect corruptions elsewhere */
- BLI_assert(BM_elem_index_get(e) < tot_edge_orig);
-
- /* under normal conditions wont be accessed again,
- * but NULL just incase so we don't use freed node */
- eheap_table[BM_elem_index_get(e)] = NULL;
-
- bm_decim_edge_collapse(
- bm, e, vquadrics, vweights, vweight_factor, eheap, eheap_table,
+ {
+ /* simple non-mirror case */
+ while ((bm->totface > face_tot_target) && (BLI_heap_is_empty(eheap) == false) &&
+ (BLI_heap_top_value(eheap) != COST_INVALID)) {
+ // const float value = BLI_heap_node_value(BLI_heap_top(eheap));
+ BMEdge *e = BLI_heap_pop_min(eheap);
+ float optimize_co[3];
+ /* handy to detect corruptions elsewhere */
+ BLI_assert(BM_elem_index_get(e) < tot_edge_orig);
+
+ /* under normal conditions wont be accessed again,
+ * but NULL just incase so we don't use freed node */
+ eheap_table[BM_elem_index_get(e)] = NULL;
+
+ bm_decim_edge_collapse(bm,
+ e,
+ vquadrics,
+ vweights,
+ vweight_factor,
+ eheap,
+ eheap_table,
#ifdef USE_SYMMETRY
- edge_symmetry_map,
+ edge_symmetry_map,
#endif
- customdata_flag,
- optimize_co, true
- );
- }
- }
+ customdata_flag,
+ optimize_co,
+ true);
+ }
+ }
#ifdef USE_SYMMETRY
- else {
- while ((bm->totface > face_tot_target) &&
- (BLI_heap_is_empty(eheap) == false) &&
- (BLI_heap_top_value(eheap) != COST_INVALID))
- {
- /**
- * \note
- * - `eheap_table[e_index_mirr]` is only removed from the heap at the last moment
- * since its possible (in theory) for collapsing `e` to remove `e_mirr`.
- * - edges sharing a vertex are ignored, so the pivot vertex isnt moved to one side.
- */
-
- BMEdge *e = BLI_heap_pop_min(eheap);
- const int e_index = BM_elem_index_get(e);
- const int e_index_mirr = edge_symmetry_map[e_index];
- BMEdge *e_mirr = NULL;
- float optimize_co[3];
- char e_invalidate = 0;
-
- BLI_assert(e_index < tot_edge_orig);
-
- eheap_table[e_index] = NULL;
-
- if (e_index_mirr != -1) {
- if (e_index_mirr == e_index) {
- /* pass */
- }
- else if (eheap_table[e_index_mirr]) {
- e_mirr = BLI_heap_node_ptr(eheap_table[e_index_mirr]);
- /* for now ignore edges with a shared vertex */
- if (BM_edge_share_vert_check(e, e_mirr)) {
- /* ignore permanently!
- * Otherwise we would keep re-evaluating and attempting to collapse. */
- // e_invalidate |= (1 | 2);
- goto invalidate;
- }
- }
- else {
- /* mirror edge can't be operated on (happens with asymmetrical meshes) */
- e_invalidate |= 1;
- goto invalidate;
- }
- }
-
- /* when false, use without degenerate checks */
- {
- /* run both before checking (since they invalidate surrounding geometry) */
- bool ok_a, ok_b;
-
- ok_a = !bm_edge_collapse_is_degenerate_topology(e);
- ok_b = e_mirr ? !bm_edge_collapse_is_degenerate_topology(e_mirr) : true;
-
- /* disallow collapsing which results in degenerate cases */
-
- if (UNLIKELY(!ok_a || !ok_b)) {
- e_invalidate |= (1 | (e_mirr ? 2 : 0));
- goto invalidate;
- }
-
- bm_decim_calc_target_co_fl(e, optimize_co, vquadrics);
-
- if (e_index_mirr == e_index) {
- optimize_co[symmetry_axis] = 0.0f;
- }
-
- /* check if this would result in an overlapping face */
- if (UNLIKELY(bm_edge_collapse_is_degenerate_flip(e, optimize_co))) {
- e_invalidate |= (1 | (e_mirr ? 2 : 0));
- goto invalidate;
- }
- }
-
- if (bm_decim_edge_collapse(
- bm, e, vquadrics, vweights, vweight_factor, eheap, eheap_table,
- edge_symmetry_map,
- customdata_flag,
- optimize_co, false))
- {
- if (e_mirr && (eheap_table[e_index_mirr])) {
- BLI_assert(e_index_mirr != e_index);
- BLI_heap_remove(eheap, eheap_table[e_index_mirr]);
- eheap_table[e_index_mirr] = NULL;
- optimize_co[symmetry_axis] *= -1.0f;
- bm_decim_edge_collapse(
- bm, e_mirr, vquadrics, vweights, vweight_factor, eheap, eheap_table,
- edge_symmetry_map,
- customdata_flag,
- optimize_co, false);
- }
- }
- else {
- if (e_mirr && (eheap_table[e_index_mirr])) {
- e_invalidate |= 2;
- goto invalidate;
- }
- }
-
- BLI_assert(e_invalidate == 0);
- continue;
-
-invalidate:
- if (e_invalidate & 1) {
- bm_decim_invalid_edge_cost_single(e, eheap, eheap_table);
- }
-
- if (e_invalidate & 2) {
- BLI_assert(eheap_table[e_index_mirr] != NULL);
- BLI_heap_remove(eheap, eheap_table[e_index_mirr]);
- eheap_table[e_index_mirr] = NULL;
- bm_decim_invalid_edge_cost_single(e_mirr, eheap, eheap_table);
- }
- }
-
- MEM_freeN((void *)edge_symmetry_map);
- }
-#endif /* USE_SYMMETRY */
+ else {
+ while ((bm->totface > face_tot_target) && (BLI_heap_is_empty(eheap) == false) &&
+ (BLI_heap_top_value(eheap) != COST_INVALID)) {
+ /**
+ * \note
+ * - `eheap_table[e_index_mirr]` is only removed from the heap at the last moment
+ * since its possible (in theory) for collapsing `e` to remove `e_mirr`.
+ * - edges sharing a vertex are ignored, so the pivot vertex isnt moved to one side.
+ */
+
+ BMEdge *e = BLI_heap_pop_min(eheap);
+ const int e_index = BM_elem_index_get(e);
+ const int e_index_mirr = edge_symmetry_map[e_index];
+ BMEdge *e_mirr = NULL;
+ float optimize_co[3];
+ char e_invalidate = 0;
+
+ BLI_assert(e_index < tot_edge_orig);
+
+ eheap_table[e_index] = NULL;
+
+ if (e_index_mirr != -1) {
+ if (e_index_mirr == e_index) {
+ /* pass */
+ }
+ else if (eheap_table[e_index_mirr]) {
+ e_mirr = BLI_heap_node_ptr(eheap_table[e_index_mirr]);
+ /* for now ignore edges with a shared vertex */
+ if (BM_edge_share_vert_check(e, e_mirr)) {
+ /* ignore permanently!
+ * Otherwise we would keep re-evaluating and attempting to collapse. */
+ // e_invalidate |= (1 | 2);
+ goto invalidate;
+ }
+ }
+ else {
+ /* mirror edge can't be operated on (happens with asymmetrical meshes) */
+ e_invalidate |= 1;
+ goto invalidate;
+ }
+ }
+
+ /* when false, use without degenerate checks */
+ {
+ /* run both before checking (since they invalidate surrounding geometry) */
+ bool ok_a, ok_b;
+
+ ok_a = !bm_edge_collapse_is_degenerate_topology(e);
+ ok_b = e_mirr ? !bm_edge_collapse_is_degenerate_topology(e_mirr) : true;
+
+ /* disallow collapsing which results in degenerate cases */
+
+ if (UNLIKELY(!ok_a || !ok_b)) {
+ e_invalidate |= (1 | (e_mirr ? 2 : 0));
+ goto invalidate;
+ }
+
+ bm_decim_calc_target_co_fl(e, optimize_co, vquadrics);
+
+ if (e_index_mirr == e_index) {
+ optimize_co[symmetry_axis] = 0.0f;
+ }
+
+ /* check if this would result in an overlapping face */
+ if (UNLIKELY(bm_edge_collapse_is_degenerate_flip(e, optimize_co))) {
+ e_invalidate |= (1 | (e_mirr ? 2 : 0));
+ goto invalidate;
+ }
+ }
+
+ if (bm_decim_edge_collapse(bm,
+ e,
+ vquadrics,
+ vweights,
+ vweight_factor,
+ eheap,
+ eheap_table,
+ edge_symmetry_map,
+ customdata_flag,
+ optimize_co,
+ false)) {
+ if (e_mirr && (eheap_table[e_index_mirr])) {
+ BLI_assert(e_index_mirr != e_index);
+ BLI_heap_remove(eheap, eheap_table[e_index_mirr]);
+ eheap_table[e_index_mirr] = NULL;
+ optimize_co[symmetry_axis] *= -1.0f;
+ bm_decim_edge_collapse(bm,
+ e_mirr,
+ vquadrics,
+ vweights,
+ vweight_factor,
+ eheap,
+ eheap_table,
+ edge_symmetry_map,
+ customdata_flag,
+ optimize_co,
+ false);
+ }
+ }
+ else {
+ if (e_mirr && (eheap_table[e_index_mirr])) {
+ e_invalidate |= 2;
+ goto invalidate;
+ }
+ }
+
+ BLI_assert(e_invalidate == 0);
+ continue;
+
+ invalidate:
+ if (e_invalidate & 1) {
+ bm_decim_invalid_edge_cost_single(e, eheap, eheap_table);
+ }
+
+ if (e_invalidate & 2) {
+ BLI_assert(eheap_table[e_index_mirr] != NULL);
+ BLI_heap_remove(eheap, eheap_table[e_index_mirr]);
+ eheap_table[e_index_mirr] = NULL;
+ bm_decim_invalid_edge_cost_single(e_mirr, eheap, eheap_table);
+ }
+ }
+
+ MEM_freeN((void *)edge_symmetry_map);
+ }
+#endif /* USE_SYMMETRY */
#ifdef USE_TRIANGULATE
- if (do_triangulate == false) {
- /* its possible we only had triangles, skip this step in that case */
- if (LIKELY(use_triangulate)) {
- /* temp convert quads to triangles */
- bm_decim_triangulate_end(bm, edges_tri_tot);
- }
- }
+ if (do_triangulate == false) {
+ /* its possible we only had triangles, skip this step in that case */
+ if (LIKELY(use_triangulate)) {
+ /* temp convert quads to triangles */
+ bm_decim_triangulate_end(bm, edges_tri_tot);
+ }
+ }
#endif
- /* free vars */
- MEM_freeN(vquadrics);
- MEM_freeN(eheap_table);
- BLI_heap_free(eheap, NULL);
+ /* free vars */
+ MEM_freeN(vquadrics);
+ MEM_freeN(eheap_table);
+ BLI_heap_free(eheap, NULL);
- /* testing only */
- // BM_mesh_validate(bm);
+ /* testing only */
+ // BM_mesh_validate(bm);
- /* quiet release build warning */
- (void)tot_edge_orig;
+ /* quiet release build warning */
+ (void)tot_edge_orig;
}
diff --git a/source/blender/bmesh/tools/bmesh_decimate_dissolve.c b/source/blender/bmesh/tools/bmesh_decimate_dissolve.c
index 6069175348c..0fbb2d14766 100644
--- a/source/blender/bmesh/tools/bmesh_decimate_dissolve.c
+++ b/source/blender/bmesh/tools/bmesh_decimate_dissolve.c
@@ -20,7 +20,6 @@
* BMesh decimator that dissolves flat areas into polygons (ngons).
*/
-
#include "MEM_guardedalloc.h"
#include "BLI_math.h"
@@ -29,14 +28,13 @@
#include "BKE_customdata.h"
#include "bmesh.h"
-#include "bmesh_decimate.h" /* own include */
+#include "bmesh_decimate.h" /* own include */
/* check that collapsing a vertex between 2 edges doesn't cause a degenerate face. */
#define USE_DEGENERATE_CHECK
#define COST_INVALID FLT_MAX
-
/* multiply vertex edge angle by face angle
* this means we are not left with sharp corners between _almost_ planer faces
* convert angles [0-PI/2] -> [0-1], multiply together, then convert back to radians. */
@@ -45,492 +43,477 @@ static float bm_vert_edge_face_angle(BMVert *v)
#define UNIT_TO_ANGLE DEG2RADF(90.0f)
#define ANGLE_TO_UNIT (1.0f / UNIT_TO_ANGLE)
- const float angle = BM_vert_calc_edge_angle(v);
- /* note: could be either edge, it doesn't matter */
- if (v->e && BM_edge_is_manifold(v->e)) {
- return ((angle * ANGLE_TO_UNIT) * (BM_edge_calc_face_angle(v->e) * ANGLE_TO_UNIT)) * UNIT_TO_ANGLE;
- }
- else {
- return angle;
- }
+ const float angle = BM_vert_calc_edge_angle(v);
+ /* note: could be either edge, it doesn't matter */
+ if (v->e && BM_edge_is_manifold(v->e)) {
+ return ((angle * ANGLE_TO_UNIT) * (BM_edge_calc_face_angle(v->e) * ANGLE_TO_UNIT)) *
+ UNIT_TO_ANGLE;
+ }
+ else {
+ return angle;
+ }
#undef UNIT_TO_ANGLE
#undef ANGLE_TO_UNIT
}
struct DelimitData {
- int cd_loop_type;
- int cd_loop_size;
- int cd_loop_offset;
- int cd_loop_offset_end;
+ int cd_loop_type;
+ int cd_loop_size;
+ int cd_loop_offset;
+ int cd_loop_offset_end;
};
-static bool bm_edge_is_contiguous_loop_cd_all(
- const BMEdge *e, const struct DelimitData *delimit_data)
+static bool bm_edge_is_contiguous_loop_cd_all(const BMEdge *e,
+ const struct DelimitData *delimit_data)
{
- int cd_loop_offset;
- for (cd_loop_offset = delimit_data->cd_loop_offset;
- cd_loop_offset < delimit_data->cd_loop_offset_end;
- cd_loop_offset += delimit_data->cd_loop_size)
- {
- if (BM_edge_is_contiguous_loop_cd(e, delimit_data->cd_loop_type, cd_loop_offset) == false) {
- return false;
- }
- }
-
- return true;
+ int cd_loop_offset;
+ for (cd_loop_offset = delimit_data->cd_loop_offset;
+ cd_loop_offset < delimit_data->cd_loop_offset_end;
+ cd_loop_offset += delimit_data->cd_loop_size) {
+ if (BM_edge_is_contiguous_loop_cd(e, delimit_data->cd_loop_type, cd_loop_offset) == false) {
+ return false;
+ }
+ }
+
+ return true;
}
-static float bm_edge_calc_dissolve_error(
- const BMEdge *e, const BMO_Delimit delimit,
- const struct DelimitData *delimit_data)
+static float bm_edge_calc_dissolve_error(const BMEdge *e,
+ const BMO_Delimit delimit,
+ const struct DelimitData *delimit_data)
{
- if (!BM_edge_is_manifold(e)) {
- goto fail;
- }
-
- if ((delimit & BMO_DELIM_SEAM) &&
- (BM_elem_flag_test(e, BM_ELEM_SEAM)))
- {
- goto fail;
- }
-
- if ((delimit & BMO_DELIM_SHARP) &&
- (BM_elem_flag_test(e, BM_ELEM_SMOOTH) == 0))
- {
- goto fail;
- }
-
- if ((delimit & BMO_DELIM_MATERIAL) &&
- (e->l->f->mat_nr != e->l->radial_next->f->mat_nr))
- {
- goto fail;
- }
-
- const bool is_contig = BM_edge_is_contiguous(e);
-
- if ((delimit & BMO_DELIM_NORMAL) &&
- (is_contig == false))
- {
- goto fail;
- }
-
- if ((delimit & BMO_DELIM_UV) &&
- (bm_edge_is_contiguous_loop_cd_all(e, delimit_data) == 0))
- {
- goto fail;
- }
-
- float angle_cos_neg = dot_v3v3(e->l->f->no, e->l->radial_next->f->no);
- if (is_contig) {
- angle_cos_neg *= -1;
- }
-
- return angle_cos_neg;
+ if (!BM_edge_is_manifold(e)) {
+ goto fail;
+ }
+
+ if ((delimit & BMO_DELIM_SEAM) && (BM_elem_flag_test(e, BM_ELEM_SEAM))) {
+ goto fail;
+ }
+
+ if ((delimit & BMO_DELIM_SHARP) && (BM_elem_flag_test(e, BM_ELEM_SMOOTH) == 0)) {
+ goto fail;
+ }
+
+ if ((delimit & BMO_DELIM_MATERIAL) && (e->l->f->mat_nr != e->l->radial_next->f->mat_nr)) {
+ goto fail;
+ }
+
+ const bool is_contig = BM_edge_is_contiguous(e);
+
+ if ((delimit & BMO_DELIM_NORMAL) && (is_contig == false)) {
+ goto fail;
+ }
+
+ if ((delimit & BMO_DELIM_UV) && (bm_edge_is_contiguous_loop_cd_all(e, delimit_data) == 0)) {
+ goto fail;
+ }
+
+ float angle_cos_neg = dot_v3v3(e->l->f->no, e->l->radial_next->f->no);
+ if (is_contig) {
+ angle_cos_neg *= -1;
+ }
+
+ return angle_cos_neg;
fail:
- return COST_INVALID;
+ return COST_INVALID;
}
-
#ifdef USE_DEGENERATE_CHECK
static void mul_v2_m3v3_center(float r[2], float m[3][3], const float a[3], const float center[3])
{
- BLI_assert(r != a);
- BLI_assert(r != center);
+ BLI_assert(r != a);
+ BLI_assert(r != center);
- float co[3];
- sub_v3_v3v3(co, a, center);
+ float co[3];
+ sub_v3_v3v3(co, a, center);
- r[0] = m[0][0] * co[0] + m[1][0] * co[1] + m[2][0] * co[2];
- r[1] = m[0][1] * co[0] + m[1][1] * co[1] + m[2][1] * co[2];
+ r[0] = m[0][0] * co[0] + m[1][0] * co[1] + m[2][0] * co[2];
+ r[1] = m[0][1] * co[0] + m[1][1] * co[1] + m[2][1] * co[2];
}
static bool bm_loop_collapse_is_degenerate(BMLoop *l_ear)
{
- /* calculate relative to the centeral vertex for higher precision */
- const float *center = l_ear->v->co;
-
- float tri_2d[3][2];
- float axis_mat[3][3];
-
- axis_dominant_v3_to_m3(axis_mat, l_ear->f->no);
-
- {
- mul_v2_m3v3_center(tri_2d[0], axis_mat, l_ear->prev->v->co, center);
-#if 0
- mul_v2_m3v3_center(tri_2d[1], axis_mat, l_ear->v->co, center);
-#else
- zero_v2(tri_2d[1]);
-#endif
- mul_v2_m3v3_center(tri_2d[2], axis_mat, l_ear->next->v->co, center);
- }
-
- /* check we're not flipping face corners before or after the ear */
- {
- float adjacent_2d[2];
-
- if (!BM_vert_is_edge_pair(l_ear->prev->v)) {
- mul_v2_m3v3_center(adjacent_2d, axis_mat, l_ear->prev->prev->v->co, center);
- if (signum_i(cross_tri_v2(adjacent_2d, tri_2d[0], tri_2d[1])) !=
- signum_i(cross_tri_v2(adjacent_2d, tri_2d[0], tri_2d[2])))
- {
- return true;
- }
- }
-
- if (!BM_vert_is_edge_pair(l_ear->next->v)) {
- mul_v2_m3v3_center(adjacent_2d, axis_mat, l_ear->next->next->v->co, center);
- if (signum_i(cross_tri_v2(adjacent_2d, tri_2d[2], tri_2d[1])) !=
- signum_i(cross_tri_v2(adjacent_2d, tri_2d[2], tri_2d[0])))
- {
- return true;
- }
- }
- }
-
- /* check no existing verts are inside the triangle */
- {
- /* triangle may be concave, if so - flip so we can use clockwise check */
- if (cross_tri_v2(UNPACK3(tri_2d)) < 0.0f) {
- swap_v2_v2(tri_2d[1], tri_2d[2]);
- }
-
- /* skip l_ear and adjacent verts */
- BMLoop *l_iter, *l_first;
-
- l_iter = l_ear->next->next;
- l_first = l_ear->prev;
- do {
- float co_2d[2];
- mul_v2_m3v3_center(co_2d, axis_mat, l_iter->v->co, center);
- if (isect_point_tri_v2_cw(co_2d, tri_2d[0], tri_2d[1], tri_2d[2])) {
- return true;
- }
- } while ((l_iter = l_iter->next) != l_first);
- }
-
- return false;
+ /* calculate relative to the centeral vertex for higher precision */
+ const float *center = l_ear->v->co;
+
+ float tri_2d[3][2];
+ float axis_mat[3][3];
+
+ axis_dominant_v3_to_m3(axis_mat, l_ear->f->no);
+
+ {
+ mul_v2_m3v3_center(tri_2d[0], axis_mat, l_ear->prev->v->co, center);
+# if 0
+ mul_v2_m3v3_center(tri_2d[1], axis_mat, l_ear->v->co, center);
+# else
+ zero_v2(tri_2d[1]);
+# endif
+ mul_v2_m3v3_center(tri_2d[2], axis_mat, l_ear->next->v->co, center);
+ }
+
+ /* check we're not flipping face corners before or after the ear */
+ {
+ float adjacent_2d[2];
+
+ if (!BM_vert_is_edge_pair(l_ear->prev->v)) {
+ mul_v2_m3v3_center(adjacent_2d, axis_mat, l_ear->prev->prev->v->co, center);
+ if (signum_i(cross_tri_v2(adjacent_2d, tri_2d[0], tri_2d[1])) !=
+ signum_i(cross_tri_v2(adjacent_2d, tri_2d[0], tri_2d[2]))) {
+ return true;
+ }
+ }
+
+ if (!BM_vert_is_edge_pair(l_ear->next->v)) {
+ mul_v2_m3v3_center(adjacent_2d, axis_mat, l_ear->next->next->v->co, center);
+ if (signum_i(cross_tri_v2(adjacent_2d, tri_2d[2], tri_2d[1])) !=
+ signum_i(cross_tri_v2(adjacent_2d, tri_2d[2], tri_2d[0]))) {
+ return true;
+ }
+ }
+ }
+
+ /* check no existing verts are inside the triangle */
+ {
+ /* triangle may be concave, if so - flip so we can use clockwise check */
+ if (cross_tri_v2(UNPACK3(tri_2d)) < 0.0f) {
+ swap_v2_v2(tri_2d[1], tri_2d[2]);
+ }
+
+ /* skip l_ear and adjacent verts */
+ BMLoop *l_iter, *l_first;
+
+ l_iter = l_ear->next->next;
+ l_first = l_ear->prev;
+ do {
+ float co_2d[2];
+ mul_v2_m3v3_center(co_2d, axis_mat, l_iter->v->co, center);
+ if (isect_point_tri_v2_cw(co_2d, tri_2d[0], tri_2d[1], tri_2d[2])) {
+ return true;
+ }
+ } while ((l_iter = l_iter->next) != l_first);
+ }
+
+ return false;
}
-static bool bm_vert_collapse_is_degenerate(BMVert *v)
+static bool bm_vert_collapse_is_degenerate(BMVert *v)
{
- BMEdge *e_pair[2];
- BMVert *v_pair[2];
-
- if (BM_vert_edge_pair(v, &e_pair[0], &e_pair[1])) {
-
- /* allow wire edges */
- if (BM_edge_is_wire(e_pair[0]) || BM_edge_is_wire(e_pair[1])) {
- return false;
- }
-
- v_pair[0] = BM_edge_other_vert(e_pair[0], v);
- v_pair[1] = BM_edge_other_vert(e_pair[1], v);
-
- if (fabsf(cos_v3v3v3(v_pair[0]->co, v->co, v_pair[1]->co)) < (1.0f - FLT_EPSILON)) {
- BMLoop *l_iter, *l_first;
- l_iter = l_first = e_pair[1]->l;
- do {
- if (l_iter->f->len > 3) {
- BMLoop *l_pivot = (l_iter->v == v ? l_iter : l_iter->next);
- BLI_assert(v == l_pivot->v);
- if (bm_loop_collapse_is_degenerate(l_pivot)) {
- return true;
- }
- }
- } while ((l_iter = l_iter->radial_next) != l_first);
- }
- return false;
- }
- else {
- return true;
- }
+ BMEdge *e_pair[2];
+ BMVert *v_pair[2];
+
+ if (BM_vert_edge_pair(v, &e_pair[0], &e_pair[1])) {
+
+ /* allow wire edges */
+ if (BM_edge_is_wire(e_pair[0]) || BM_edge_is_wire(e_pair[1])) {
+ return false;
+ }
+
+ v_pair[0] = BM_edge_other_vert(e_pair[0], v);
+ v_pair[1] = BM_edge_other_vert(e_pair[1], v);
+
+ if (fabsf(cos_v3v3v3(v_pair[0]->co, v->co, v_pair[1]->co)) < (1.0f - FLT_EPSILON)) {
+ BMLoop *l_iter, *l_first;
+ l_iter = l_first = e_pair[1]->l;
+ do {
+ if (l_iter->f->len > 3) {
+ BMLoop *l_pivot = (l_iter->v == v ? l_iter : l_iter->next);
+ BLI_assert(v == l_pivot->v);
+ if (bm_loop_collapse_is_degenerate(l_pivot)) {
+ return true;
+ }
+ }
+ } while ((l_iter = l_iter->radial_next) != l_first);
+ }
+ return false;
+ }
+ else {
+ return true;
+ }
}
-#endif /* USE_DEGENERATE_CHECK */
-
-
-void BM_mesh_decimate_dissolve_ex(
- BMesh *bm, const float angle_limit, const bool do_dissolve_boundaries,
- BMO_Delimit delimit,
- BMVert **vinput_arr, const int vinput_len,
- BMEdge **einput_arr, const int einput_len,
- const short oflag_out)
+#endif /* USE_DEGENERATE_CHECK */
+
+void BM_mesh_decimate_dissolve_ex(BMesh *bm,
+ const float angle_limit,
+ const bool do_dissolve_boundaries,
+ BMO_Delimit delimit,
+ BMVert **vinput_arr,
+ const int vinput_len,
+ BMEdge **einput_arr,
+ const int einput_len,
+ const short oflag_out)
{
- const float angle_limit_cos_neg = -cosf(angle_limit);
- struct DelimitData delimit_data = {0};
- const int eheap_table_len = do_dissolve_boundaries ? einput_len : max_ii(einput_len, vinput_len);
- void *_heap_table = MEM_mallocN(sizeof(HeapNode *) * eheap_table_len, __func__);
-
- int i;
-
- if (delimit & BMO_DELIM_UV) {
- const int layer_len = CustomData_number_of_layers(&bm->ldata, CD_MLOOPUV);
- if (layer_len == 0) {
- delimit &= ~BMO_DELIM_UV;
- }
- else {
- delimit_data.cd_loop_type = CD_MLOOPUV;
- delimit_data.cd_loop_size = CustomData_sizeof(delimit_data.cd_loop_type);
- delimit_data.cd_loop_offset = CustomData_get_n_offset(&bm->ldata, CD_MLOOPUV, 0);
- delimit_data.cd_loop_offset_end = delimit_data.cd_loop_size * layer_len;
- }
- }
-
- /* --- first edges --- */
- if (1) {
- BMEdge **earray;
- Heap *eheap;
- HeapNode **eheap_table = _heap_table;
- HeapNode *enode_top;
- int *vert_reverse_lookup;
- BMIter iter;
- BMEdge *e_iter;
-
- /* --- setup heap --- */
- eheap = BLI_heap_new_ex(einput_len);
-
- /* wire -> tag */
- BM_ITER_MESH (e_iter, &iter, bm, BM_EDGES_OF_MESH) {
- BM_elem_flag_set(e_iter, BM_ELEM_TAG, BM_edge_is_wire(e_iter));
- BM_elem_index_set(e_iter, -1); /* set dirty */
- }
- bm->elem_index_dirty |= BM_EDGE;
-
- /* build heap */
- for (i = 0; i < einput_len; i++) {
- BMEdge *e = einput_arr[i];
- const float cost = bm_edge_calc_dissolve_error(e, delimit, &delimit_data);
- eheap_table[i] = BLI_heap_insert(eheap, cost, e);
- BM_elem_index_set(e, i); /* set dirty */
- }
-
- while ((BLI_heap_is_empty(eheap) == false) &&
- (BLI_heap_node_value((enode_top = BLI_heap_top(eheap))) < angle_limit_cos_neg))
- {
- BMFace *f_new = NULL;
- BMEdge *e;
-
- e = BLI_heap_node_ptr(enode_top);
- i = BM_elem_index_get(e);
-
- if (BM_edge_is_manifold(e)) {
- f_new = BM_faces_join_pair(bm, e->l, e->l->radial_next, false);
-
- if (f_new) {
- BMLoop *l_first, *l_iter;
-
- BLI_heap_remove(eheap, enode_top);
- eheap_table[i] = NULL;
-
- /* update normal */
- BM_face_normal_update(f_new);
- if (oflag_out) {
- BMO_face_flag_enable(bm, f_new, oflag_out);
- }
-
- /* re-calculate costs */
- l_iter = l_first = BM_FACE_FIRST_LOOP(f_new);
- do {
- const int j = BM_elem_index_get(l_iter->e);
- if (j != -1 && eheap_table[j]) {
- const float cost = bm_edge_calc_dissolve_error(l_iter->e, delimit, &delimit_data);
- BLI_heap_node_value_update(eheap, eheap_table[j], cost);
- }
- } while ((l_iter = l_iter->next) != l_first);
- }
- else {
- BMO_error_clear(bm);
- }
- }
-
- if (UNLIKELY(f_new == NULL)) {
- BLI_heap_node_value_update(eheap, enode_top, COST_INVALID);
- }
- }
-
- /* prepare for cleanup */
- BM_mesh_elem_index_ensure(bm, BM_VERT);
- vert_reverse_lookup = MEM_mallocN(sizeof(int) * bm->totvert, __func__);
- copy_vn_i(vert_reverse_lookup, bm->totvert, -1);
- for (i = 0; i < vinput_len; i++) {
- BMVert *v = vinput_arr[i];
- vert_reverse_lookup[BM_elem_index_get(v)] = i;
- }
-
- /* --- cleanup --- */
- earray = MEM_mallocN(sizeof(BMEdge *) * bm->totedge, __func__);
- BM_ITER_MESH_INDEX (e_iter, &iter, bm, BM_EDGES_OF_MESH, i) {
- earray[i] = e_iter;
- }
- /* remove all edges/verts left behind from dissolving, NULL'ing the vertex array so we dont re-use */
- for (i = bm->totedge - 1; i != -1; i--) {
- e_iter = earray[i];
-
- if (BM_edge_is_wire(e_iter) && (BM_elem_flag_test(e_iter, BM_ELEM_TAG) == false)) {
- /* edge has become wire */
- int vidx_reverse;
- BMVert *v1 = e_iter->v1;
- BMVert *v2 = e_iter->v2;
- BM_edge_kill(bm, e_iter);
- if (v1->e == NULL) {
- vidx_reverse = vert_reverse_lookup[BM_elem_index_get(v1)];
- if (vidx_reverse != -1) {
- vinput_arr[vidx_reverse] = NULL;
- }
- BM_vert_kill(bm, v1);
- }
- if (v2->e == NULL) {
- vidx_reverse = vert_reverse_lookup[BM_elem_index_get(v2)];
- if (vidx_reverse != -1) {
- vinput_arr[vidx_reverse] = NULL;
- }
- BM_vert_kill(bm, v2);
- }
- }
- }
- MEM_freeN(vert_reverse_lookup);
- MEM_freeN(earray);
-
- BLI_heap_free(eheap, NULL);
- }
-
-
- /* --- second verts --- */
- if (do_dissolve_boundaries) {
- /* simple version of the branch below, since we will dissolve _all_ verts that use 2 edges */
- for (i = 0; i < vinput_len; i++) {
- BMVert *v = vinput_arr[i];
- if (LIKELY(v != NULL) &&
- BM_vert_is_edge_pair(v))
- {
- BM_vert_collapse_edge(bm, v->e, v, true, true); /* join edges */
- }
- }
- }
- else {
- Heap *vheap;
- HeapNode **vheap_table = _heap_table;
- HeapNode *vnode_top;
-
- BMVert *v_iter;
- BMIter iter;
-
- BM_ITER_MESH (v_iter, &iter, bm, BM_VERTS_OF_MESH) {
- BM_elem_index_set(v_iter, -1); /* set dirty */
- }
- bm->elem_index_dirty |= BM_VERT;
-
- vheap = BLI_heap_new_ex(vinput_len);
-
- for (i = 0; i < vinput_len; i++) {
- BMVert *v = vinput_arr[i];
- if (LIKELY(v != NULL)) {
- const float cost = bm_vert_edge_face_angle(v);
- vheap_table[i] = BLI_heap_insert(vheap, cost, v);
- BM_elem_index_set(v, i); /* set dirty */
- }
- }
-
- while ((BLI_heap_is_empty(vheap) == false) &&
- (BLI_heap_node_value((vnode_top = BLI_heap_top(vheap))) < angle_limit))
- {
- BMEdge *e_new = NULL;
- BMVert *v;
-
- v = BLI_heap_node_ptr(vnode_top);
- i = BM_elem_index_get(v);
-
- if (
+ const float angle_limit_cos_neg = -cosf(angle_limit);
+ struct DelimitData delimit_data = {0};
+ const int eheap_table_len = do_dissolve_boundaries ? einput_len : max_ii(einput_len, vinput_len);
+ void *_heap_table = MEM_mallocN(sizeof(HeapNode *) * eheap_table_len, __func__);
+
+ int i;
+
+ if (delimit & BMO_DELIM_UV) {
+ const int layer_len = CustomData_number_of_layers(&bm->ldata, CD_MLOOPUV);
+ if (layer_len == 0) {
+ delimit &= ~BMO_DELIM_UV;
+ }
+ else {
+ delimit_data.cd_loop_type = CD_MLOOPUV;
+ delimit_data.cd_loop_size = CustomData_sizeof(delimit_data.cd_loop_type);
+ delimit_data.cd_loop_offset = CustomData_get_n_offset(&bm->ldata, CD_MLOOPUV, 0);
+ delimit_data.cd_loop_offset_end = delimit_data.cd_loop_size * layer_len;
+ }
+ }
+
+ /* --- first edges --- */
+ if (1) {
+ BMEdge **earray;
+ Heap *eheap;
+ HeapNode **eheap_table = _heap_table;
+ HeapNode *enode_top;
+ int *vert_reverse_lookup;
+ BMIter iter;
+ BMEdge *e_iter;
+
+ /* --- setup heap --- */
+ eheap = BLI_heap_new_ex(einput_len);
+
+ /* wire -> tag */
+ BM_ITER_MESH (e_iter, &iter, bm, BM_EDGES_OF_MESH) {
+ BM_elem_flag_set(e_iter, BM_ELEM_TAG, BM_edge_is_wire(e_iter));
+ BM_elem_index_set(e_iter, -1); /* set dirty */
+ }
+ bm->elem_index_dirty |= BM_EDGE;
+
+ /* build heap */
+ for (i = 0; i < einput_len; i++) {
+ BMEdge *e = einput_arr[i];
+ const float cost = bm_edge_calc_dissolve_error(e, delimit, &delimit_data);
+ eheap_table[i] = BLI_heap_insert(eheap, cost, e);
+ BM_elem_index_set(e, i); /* set dirty */
+ }
+
+ while ((BLI_heap_is_empty(eheap) == false) &&
+ (BLI_heap_node_value((enode_top = BLI_heap_top(eheap))) < angle_limit_cos_neg)) {
+ BMFace *f_new = NULL;
+ BMEdge *e;
+
+ e = BLI_heap_node_ptr(enode_top);
+ i = BM_elem_index_get(e);
+
+ if (BM_edge_is_manifold(e)) {
+ f_new = BM_faces_join_pair(bm, e->l, e->l->radial_next, false);
+
+ if (f_new) {
+ BMLoop *l_first, *l_iter;
+
+ BLI_heap_remove(eheap, enode_top);
+ eheap_table[i] = NULL;
+
+ /* update normal */
+ BM_face_normal_update(f_new);
+ if (oflag_out) {
+ BMO_face_flag_enable(bm, f_new, oflag_out);
+ }
+
+ /* re-calculate costs */
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f_new);
+ do {
+ const int j = BM_elem_index_get(l_iter->e);
+ if (j != -1 && eheap_table[j]) {
+ const float cost = bm_edge_calc_dissolve_error(l_iter->e, delimit, &delimit_data);
+ BLI_heap_node_value_update(eheap, eheap_table[j], cost);
+ }
+ } while ((l_iter = l_iter->next) != l_first);
+ }
+ else {
+ BMO_error_clear(bm);
+ }
+ }
+
+ if (UNLIKELY(f_new == NULL)) {
+ BLI_heap_node_value_update(eheap, enode_top, COST_INVALID);
+ }
+ }
+
+ /* prepare for cleanup */
+ BM_mesh_elem_index_ensure(bm, BM_VERT);
+ vert_reverse_lookup = MEM_mallocN(sizeof(int) * bm->totvert, __func__);
+ copy_vn_i(vert_reverse_lookup, bm->totvert, -1);
+ for (i = 0; i < vinput_len; i++) {
+ BMVert *v = vinput_arr[i];
+ vert_reverse_lookup[BM_elem_index_get(v)] = i;
+ }
+
+ /* --- cleanup --- */
+ earray = MEM_mallocN(sizeof(BMEdge *) * bm->totedge, __func__);
+ BM_ITER_MESH_INDEX (e_iter, &iter, bm, BM_EDGES_OF_MESH, i) {
+ earray[i] = e_iter;
+ }
+ /* remove all edges/verts left behind from dissolving, NULL'ing the vertex array so we dont re-use */
+ for (i = bm->totedge - 1; i != -1; i--) {
+ e_iter = earray[i];
+
+ if (BM_edge_is_wire(e_iter) && (BM_elem_flag_test(e_iter, BM_ELEM_TAG) == false)) {
+ /* edge has become wire */
+ int vidx_reverse;
+ BMVert *v1 = e_iter->v1;
+ BMVert *v2 = e_iter->v2;
+ BM_edge_kill(bm, e_iter);
+ if (v1->e == NULL) {
+ vidx_reverse = vert_reverse_lookup[BM_elem_index_get(v1)];
+ if (vidx_reverse != -1) {
+ vinput_arr[vidx_reverse] = NULL;
+ }
+ BM_vert_kill(bm, v1);
+ }
+ if (v2->e == NULL) {
+ vidx_reverse = vert_reverse_lookup[BM_elem_index_get(v2)];
+ if (vidx_reverse != -1) {
+ vinput_arr[vidx_reverse] = NULL;
+ }
+ BM_vert_kill(bm, v2);
+ }
+ }
+ }
+ MEM_freeN(vert_reverse_lookup);
+ MEM_freeN(earray);
+
+ BLI_heap_free(eheap, NULL);
+ }
+
+ /* --- second verts --- */
+ if (do_dissolve_boundaries) {
+ /* simple version of the branch below, since we will dissolve _all_ verts that use 2 edges */
+ for (i = 0; i < vinput_len; i++) {
+ BMVert *v = vinput_arr[i];
+ if (LIKELY(v != NULL) && BM_vert_is_edge_pair(v)) {
+ BM_vert_collapse_edge(bm, v->e, v, true, true); /* join edges */
+ }
+ }
+ }
+ else {
+ Heap *vheap;
+ HeapNode **vheap_table = _heap_table;
+ HeapNode *vnode_top;
+
+ BMVert *v_iter;
+ BMIter iter;
+
+ BM_ITER_MESH (v_iter, &iter, bm, BM_VERTS_OF_MESH) {
+ BM_elem_index_set(v_iter, -1); /* set dirty */
+ }
+ bm->elem_index_dirty |= BM_VERT;
+
+ vheap = BLI_heap_new_ex(vinput_len);
+
+ for (i = 0; i < vinput_len; i++) {
+ BMVert *v = vinput_arr[i];
+ if (LIKELY(v != NULL)) {
+ const float cost = bm_vert_edge_face_angle(v);
+ vheap_table[i] = BLI_heap_insert(vheap, cost, v);
+ BM_elem_index_set(v, i); /* set dirty */
+ }
+ }
+
+ while ((BLI_heap_is_empty(vheap) == false) &&
+ (BLI_heap_node_value((vnode_top = BLI_heap_top(vheap))) < angle_limit)) {
+ BMEdge *e_new = NULL;
+ BMVert *v;
+
+ v = BLI_heap_node_ptr(vnode_top);
+ i = BM_elem_index_get(v);
+
+ if (
#ifdef USE_DEGENERATE_CHECK
- !bm_vert_collapse_is_degenerate(v)
+ !bm_vert_collapse_is_degenerate(v)
#else
- BM_vert_is_edge_pair(v)
+ BM_vert_is_edge_pair(v)
#endif
- )
- {
- e_new = BM_vert_collapse_edge(bm, v->e, v, true, true); /* join edges */
-
- if (e_new) {
-
- BLI_heap_remove(vheap, vnode_top);
- vheap_table[i] = NULL;
-
- /* update normal */
- if (e_new->l) {
- BMLoop *l_first, *l_iter;
- l_iter = l_first = e_new->l;
- do {
- BM_face_normal_update(l_iter->f);
- } while ((l_iter = l_iter->radial_next) != l_first);
- }
-
- /* re-calculate costs */
- BM_ITER_ELEM (v_iter, &iter, e_new, BM_VERTS_OF_EDGE) {
- const int j = BM_elem_index_get(v_iter);
- if (j != -1 && vheap_table[j]) {
- const float cost = bm_vert_edge_face_angle(v_iter);
- BLI_heap_node_value_update(vheap, vheap_table[j], cost);
- }
- }
+ ) {
+ e_new = BM_vert_collapse_edge(bm, v->e, v, true, true); /* join edges */
+
+ if (e_new) {
+
+ BLI_heap_remove(vheap, vnode_top);
+ vheap_table[i] = NULL;
+
+ /* update normal */
+ if (e_new->l) {
+ BMLoop *l_first, *l_iter;
+ l_iter = l_first = e_new->l;
+ do {
+ BM_face_normal_update(l_iter->f);
+ } while ((l_iter = l_iter->radial_next) != l_first);
+ }
+
+ /* re-calculate costs */
+ BM_ITER_ELEM (v_iter, &iter, e_new, BM_VERTS_OF_EDGE) {
+ const int j = BM_elem_index_get(v_iter);
+ if (j != -1 && vheap_table[j]) {
+ const float cost = bm_vert_edge_face_angle(v_iter);
+ BLI_heap_node_value_update(vheap, vheap_table[j], cost);
+ }
+ }
#ifdef USE_DEGENERATE_CHECK
- /* dissolving a vertex may mean vertices we previously weren't able to dissolve
- * can now be re-evaluated. */
- if (e_new->l) {
- BMLoop *l_first, *l_iter;
- l_iter = l_first = e_new->l;
- do {
- /* skip vertices part of this edge, evaluated above */
- BMLoop *l_cycle_first, *l_cycle_iter;
- l_cycle_iter = l_iter->next->next;
- l_cycle_first = l_iter->prev;
- do {
- const int j = BM_elem_index_get(l_cycle_iter->v);
- if (j != -1 && vheap_table[j] &&
- (BLI_heap_node_value(vheap_table[j]) == COST_INVALID))
- {
- const float cost = bm_vert_edge_face_angle(l_cycle_iter->v);
- BLI_heap_node_value_update(vheap, vheap_table[j], cost);
- }
- } while ((l_cycle_iter = l_cycle_iter->next) != l_cycle_first);
-
- } while ((l_iter = l_iter->radial_next) != l_first);
- }
-#endif /* USE_DEGENERATE_CHECK */
-
- }
- }
-
- if (UNLIKELY(e_new == NULL)) {
- BLI_heap_node_value_update(vheap, vnode_top, COST_INVALID);
- }
- }
-
- BLI_heap_free(vheap, NULL);
- }
-
- MEM_freeN(_heap_table);
+ /* dissolving a vertex may mean vertices we previously weren't able to dissolve
+ * can now be re-evaluated. */
+ if (e_new->l) {
+ BMLoop *l_first, *l_iter;
+ l_iter = l_first = e_new->l;
+ do {
+ /* skip vertices part of this edge, evaluated above */
+ BMLoop *l_cycle_first, *l_cycle_iter;
+ l_cycle_iter = l_iter->next->next;
+ l_cycle_first = l_iter->prev;
+ do {
+ const int j = BM_elem_index_get(l_cycle_iter->v);
+ if (j != -1 && vheap_table[j] &&
+ (BLI_heap_node_value(vheap_table[j]) == COST_INVALID)) {
+ const float cost = bm_vert_edge_face_angle(l_cycle_iter->v);
+ BLI_heap_node_value_update(vheap, vheap_table[j], cost);
+ }
+ } while ((l_cycle_iter = l_cycle_iter->next) != l_cycle_first);
+
+ } while ((l_iter = l_iter->radial_next) != l_first);
+ }
+#endif /* USE_DEGENERATE_CHECK */
+ }
+ }
+
+ if (UNLIKELY(e_new == NULL)) {
+ BLI_heap_node_value_update(vheap, vnode_top, COST_INVALID);
+ }
+ }
+
+ BLI_heap_free(vheap, NULL);
+ }
+
+ MEM_freeN(_heap_table);
}
-void BM_mesh_decimate_dissolve(
- BMesh *bm, const float angle_limit, const bool do_dissolve_boundaries,
- const BMO_Delimit delimit)
+void BM_mesh_decimate_dissolve(BMesh *bm,
+ const float angle_limit,
+ const bool do_dissolve_boundaries,
+ const BMO_Delimit delimit)
{
- int vinput_len;
- int einput_len;
-
- BMVert **vinput_arr = BM_iter_as_arrayN(bm, BM_VERTS_OF_MESH, NULL, &vinput_len, NULL, 0);
- BMEdge **einput_arr = BM_iter_as_arrayN(bm, BM_EDGES_OF_MESH, NULL, &einput_len, NULL, 0);
-
-
- BM_mesh_decimate_dissolve_ex(bm, angle_limit, do_dissolve_boundaries,
- delimit,
- vinput_arr, vinput_len,
- einput_arr, einput_len,
- 0);
-
- MEM_freeN(vinput_arr);
- MEM_freeN(einput_arr);
+ int vinput_len;
+ int einput_len;
+
+ BMVert **vinput_arr = BM_iter_as_arrayN(bm, BM_VERTS_OF_MESH, NULL, &vinput_len, NULL, 0);
+ BMEdge **einput_arr = BM_iter_as_arrayN(bm, BM_EDGES_OF_MESH, NULL, &einput_len, NULL, 0);
+
+ BM_mesh_decimate_dissolve_ex(bm,
+ angle_limit,
+ do_dissolve_boundaries,
+ delimit,
+ vinput_arr,
+ vinput_len,
+ einput_arr,
+ einput_len,
+ 0);
+
+ MEM_freeN(vinput_arr);
+ MEM_freeN(einput_arr);
}
diff --git a/source/blender/bmesh/tools/bmesh_decimate_unsubdivide.c b/source/blender/bmesh/tools/bmesh_decimate_unsubdivide.c
index 90fca4fe184..13ada1756de 100644
--- a/source/blender/bmesh/tools/bmesh_decimate_unsubdivide.c
+++ b/source/blender/bmesh/tools/bmesh_decimate_unsubdivide.c
@@ -20,149 +20,146 @@
* BMesh decimator that uses a grid un-subdivide method.
*/
-
#include "MEM_guardedalloc.h"
#include "BLI_math.h"
#include "bmesh.h"
-#include "bmesh_decimate.h" /* own include */
-
+#include "bmesh_decimate.h" /* own include */
static bool bm_vert_dissolve_fan_test(BMVert *v)
{
- /* check if we should walk over these verts */
- BMIter iter;
- BMEdge *e;
-
- BMVert *varr[4];
-
- uint tot_edge = 0;
- uint tot_edge_boundary = 0;
- uint tot_edge_manifold = 0;
- uint tot_edge_wire = 0;
-
- BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) {
- if (BM_edge_is_boundary(e)) {
- tot_edge_boundary++;
- }
- else if (BM_edge_is_manifold(e)) {
- tot_edge_manifold++;
- }
- else if (BM_edge_is_wire(e)) {
- tot_edge_wire++;
- }
-
- /* bail out early */
- if (tot_edge == 4) {
- return false;
- }
-
- /* used to check overlapping faces */
- varr[tot_edge] = BM_edge_other_vert(e, v);
-
- tot_edge++;
- }
-
- if (((tot_edge == 4) && (tot_edge_boundary == 0) && (tot_edge_manifold == 4)) ||
- ((tot_edge == 3) && (tot_edge_boundary == 0) && (tot_edge_manifold == 3)) ||
- ((tot_edge == 3) && (tot_edge_boundary == 2) && (tot_edge_manifold == 1)))
- {
- if (!BM_face_exists(varr, tot_edge)) {
- return true;
- }
- }
- else if ((tot_edge == 2) && (tot_edge_wire == 2)) {
- return true;
- }
- return false;
+ /* check if we should walk over these verts */
+ BMIter iter;
+ BMEdge *e;
+
+ BMVert *varr[4];
+
+ uint tot_edge = 0;
+ uint tot_edge_boundary = 0;
+ uint tot_edge_manifold = 0;
+ uint tot_edge_wire = 0;
+
+ BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) {
+ if (BM_edge_is_boundary(e)) {
+ tot_edge_boundary++;
+ }
+ else if (BM_edge_is_manifold(e)) {
+ tot_edge_manifold++;
+ }
+ else if (BM_edge_is_wire(e)) {
+ tot_edge_wire++;
+ }
+
+ /* bail out early */
+ if (tot_edge == 4) {
+ return false;
+ }
+
+ /* used to check overlapping faces */
+ varr[tot_edge] = BM_edge_other_vert(e, v);
+
+ tot_edge++;
+ }
+
+ if (((tot_edge == 4) && (tot_edge_boundary == 0) && (tot_edge_manifold == 4)) ||
+ ((tot_edge == 3) && (tot_edge_boundary == 0) && (tot_edge_manifold == 3)) ||
+ ((tot_edge == 3) && (tot_edge_boundary == 2) && (tot_edge_manifold == 1))) {
+ if (!BM_face_exists(varr, tot_edge)) {
+ return true;
+ }
+ }
+ else if ((tot_edge == 2) && (tot_edge_wire == 2)) {
+ return true;
+ }
+ return false;
}
static bool bm_vert_dissolve_fan(BMesh *bm, BMVert *v)
{
- /* collapse under 2 conditions.
- * - vert connects to 4 manifold edges (and 4 faces).
- * - vert connects to 1 manifold edge, 2 boundary edges (and 2 faces).
- *
- * This covers boundary verts of a quad grid and center verts.
- * note that surrounding faces dont have to be quads.
- */
-
- BMIter iter;
- BMEdge *e;
-
- uint tot_loop = 0;
- uint tot_edge = 0;
- uint tot_edge_boundary = 0;
- uint tot_edge_manifold = 0;
- uint tot_edge_wire = 0;
-
- BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) {
- if (BM_edge_is_boundary(e)) {
- tot_edge_boundary++;
- }
- else if (BM_edge_is_manifold(e)) {
- tot_edge_manifold++;
- }
- else if (BM_edge_is_wire(e)) {
- tot_edge_wire++;
- }
- tot_edge++;
- }
-
- if (tot_edge == 2) {
- /* check for 2 wire verts only */
- if (tot_edge_wire == 2) {
- return (BM_vert_collapse_edge(bm, v->e, v, true, true) != NULL);
- }
- }
- else if (tot_edge == 4) {
- /* check for 4 faces surrounding */
- if (tot_edge_boundary == 0 && tot_edge_manifold == 4) {
- /* good to go! */
- tot_loop = 4;
- }
- }
- else if (tot_edge == 3) {
- /* check for 2 faces surrounding at a boundary */
- if (tot_edge_boundary == 2 && tot_edge_manifold == 1) {
- /* good to go! */
- tot_loop = 2;
- }
- else if (tot_edge_boundary == 0 && tot_edge_manifold == 3) {
- /* good to go! */
- tot_loop = 3;
- }
- }
-
- if (tot_loop) {
- BMLoop *f_loop[4];
- uint i;
-
- /* ensure there are exactly tot_loop loops */
- BLI_assert(BM_iter_at_index(bm, BM_LOOPS_OF_VERT, v, tot_loop) == NULL);
- BM_iter_as_array(bm, BM_LOOPS_OF_VERT, v, (void **)f_loop, tot_loop);
-
- for (i = 0; i < tot_loop; i++) {
- BMLoop *l = f_loop[i];
- if (l->f->len > 3) {
- BMLoop *l_new;
- BLI_assert(l->prev->v != l->next->v);
- BM_face_split(bm, l->f, l->prev, l->next, &l_new, NULL, true);
- BM_elem_flag_merge_into(l_new->e, l->e, l->prev->e);
- }
- }
-
- return BM_vert_dissolve(bm, v);
- }
-
- return false;
+ /* collapse under 2 conditions.
+ * - vert connects to 4 manifold edges (and 4 faces).
+ * - vert connects to 1 manifold edge, 2 boundary edges (and 2 faces).
+ *
+ * This covers boundary verts of a quad grid and center verts.
+ * note that surrounding faces dont have to be quads.
+ */
+
+ BMIter iter;
+ BMEdge *e;
+
+ uint tot_loop = 0;
+ uint tot_edge = 0;
+ uint tot_edge_boundary = 0;
+ uint tot_edge_manifold = 0;
+ uint tot_edge_wire = 0;
+
+ BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) {
+ if (BM_edge_is_boundary(e)) {
+ tot_edge_boundary++;
+ }
+ else if (BM_edge_is_manifold(e)) {
+ tot_edge_manifold++;
+ }
+ else if (BM_edge_is_wire(e)) {
+ tot_edge_wire++;
+ }
+ tot_edge++;
+ }
+
+ if (tot_edge == 2) {
+ /* check for 2 wire verts only */
+ if (tot_edge_wire == 2) {
+ return (BM_vert_collapse_edge(bm, v->e, v, true, true) != NULL);
+ }
+ }
+ else if (tot_edge == 4) {
+ /* check for 4 faces surrounding */
+ if (tot_edge_boundary == 0 && tot_edge_manifold == 4) {
+ /* good to go! */
+ tot_loop = 4;
+ }
+ }
+ else if (tot_edge == 3) {
+ /* check for 2 faces surrounding at a boundary */
+ if (tot_edge_boundary == 2 && tot_edge_manifold == 1) {
+ /* good to go! */
+ tot_loop = 2;
+ }
+ else if (tot_edge_boundary == 0 && tot_edge_manifold == 3) {
+ /* good to go! */
+ tot_loop = 3;
+ }
+ }
+
+ if (tot_loop) {
+ BMLoop *f_loop[4];
+ uint i;
+
+ /* ensure there are exactly tot_loop loops */
+ BLI_assert(BM_iter_at_index(bm, BM_LOOPS_OF_VERT, v, tot_loop) == NULL);
+ BM_iter_as_array(bm, BM_LOOPS_OF_VERT, v, (void **)f_loop, tot_loop);
+
+ for (i = 0; i < tot_loop; i++) {
+ BMLoop *l = f_loop[i];
+ if (l->f->len > 3) {
+ BMLoop *l_new;
+ BLI_assert(l->prev->v != l->next->v);
+ BM_face_split(bm, l->f, l->prev, l->next, &l_new, NULL, true);
+ BM_elem_flag_merge_into(l_new->e, l->e, l->prev->e);
+ }
+ }
+
+ return BM_vert_dissolve(bm, v);
+ }
+
+ return false;
}
enum {
- VERT_INDEX_DO_COLLAPSE = -1,
- VERT_INDEX_INIT = 0,
- VERT_INDEX_IGNORE = 1,
+ VERT_INDEX_DO_COLLAPSE = -1,
+ VERT_INDEX_INIT = 0,
+ VERT_INDEX_IGNORE = 1,
};
// #define USE_WALKER /* gives uneven results, disable for now */
@@ -178,172 +175,176 @@ void BM_mesh_decimate_unsubdivide_ex(BMesh *bm, const int iterations, const bool
#ifdef USE_WALKER
# define ELE_VERT_TAG 1
#else
- BMVert **vert_seek_a = MEM_mallocN(sizeof(BMVert *) * bm->totvert, __func__);
- BMVert **vert_seek_b = MEM_mallocN(sizeof(BMVert *) * bm->totvert, __func__);
- unsigned vert_seek_a_tot = 0;
- unsigned vert_seek_b_tot = 0;
+ BMVert **vert_seek_a = MEM_mallocN(sizeof(BMVert *) * bm->totvert, __func__);
+ BMVert **vert_seek_b = MEM_mallocN(sizeof(BMVert *) * bm->totvert, __func__);
+ unsigned vert_seek_a_tot = 0;
+ unsigned vert_seek_b_tot = 0;
#endif
- BMIter iter;
+ BMIter iter;
- const uint offset = 0;
- const uint nth = 2;
+ const uint offset = 0;
+ const uint nth = 2;
- int iter_step;
+ int iter_step;
- /* if tag_only is set, we assume the caller knows what verts to tag
- * needed for the operator */
- if (tag_only == false) {
- BMVert *v;
- BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
- BM_elem_flag_enable(v, BM_ELEM_TAG);
- }
- }
+ /* if tag_only is set, we assume the caller knows what verts to tag
+ * needed for the operator */
+ if (tag_only == false) {
+ BMVert *v;
+ BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
+ BM_elem_flag_enable(v, BM_ELEM_TAG);
+ }
+ }
- for (iter_step = 0; iter_step < iterations; iter_step++) {
- BMVert *v, *v_next;
- bool iter_done;
+ for (iter_step = 0; iter_step < iterations; iter_step++) {
+ BMVert *v, *v_next;
+ bool iter_done;
- BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
- if (BM_elem_flag_test(v, BM_ELEM_TAG) && bm_vert_dissolve_fan_test(v)) {
+ BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
+ if (BM_elem_flag_test(v, BM_ELEM_TAG) && bm_vert_dissolve_fan_test(v)) {
#ifdef USE_WALKER
- BMO_vert_flag_enable(bm, v, ELE_VERT_TAG);
+ BMO_vert_flag_enable(bm, v, ELE_VERT_TAG);
#endif
- BM_elem_index_set(v, VERT_INDEX_INIT); /* set_dirty! */
- }
- else {
- BM_elem_index_set(v, VERT_INDEX_IGNORE); /* set_dirty! */
- }
- }
- /* done with selecting tagged verts */
-
-
- /* main loop, keep tagging until we can't tag any more islands */
- while (true) {
+ BM_elem_index_set(v, VERT_INDEX_INIT); /* set_dirty! */
+ }
+ else {
+ BM_elem_index_set(v, VERT_INDEX_IGNORE); /* set_dirty! */
+ }
+ }
+ /* done with selecting tagged verts */
+
+ /* main loop, keep tagging until we can't tag any more islands */
+ while (true) {
#ifdef USE_WALKER
- BMWalker walker;
+ BMWalker walker;
#else
- uint depth = 1;
- uint i;
+ uint depth = 1;
+ uint i;
#endif
- BMVert *v_first = NULL;
+ BMVert *v_first = NULL;
- /* we could avoid iterating from the start each time */
- BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
- if (v->e && (BM_elem_index_get(v) == VERT_INDEX_INIT)) {
+ /* we could avoid iterating from the start each time */
+ BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
+ if (v->e && (BM_elem_index_get(v) == VERT_INDEX_INIT)) {
#ifdef USE_WALKER
- if (BMO_vert_flag_test(bm, v, ELE_VERT_TAG))
+ if (BMO_vert_flag_test(bm, v, ELE_VERT_TAG))
#endif
- {
- /* check again incase the topology changed */
- if (bm_vert_dissolve_fan_test(v)) {
- v_first = v;
- }
- break;
- }
- }
- }
- if (v_first == NULL) {
- break;
- }
+ {
+ /* check again incase the topology changed */
+ if (bm_vert_dissolve_fan_test(v)) {
+ v_first = v;
+ }
+ break;
+ }
+ }
+ }
+ if (v_first == NULL) {
+ break;
+ }
#ifdef USE_WALKER
- /* Walk over selected elements starting at active */
- BMW_init(&walker, bm, BMW_CONNECTED_VERTEX,
- ELE_VERT_TAG, BMW_MASK_NOP, BMW_MASK_NOP,
- BMW_FLAG_NOP, /* don't use BMW_FLAG_TEST_HIDDEN here since we want to desel all */
- BMW_NIL_LAY);
-
- BLI_assert(walker.order == BMW_BREADTH_FIRST);
- for (v = BMW_begin(&walker, v_first); v != NULL; v = BMW_step(&walker)) {
- /* Deselect elements that aren't at "nth" depth from active */
- if (BM_elem_index_get(v) == VERT_INDEX_INIT) {
- if ((offset + BMW_current_depth(&walker)) % nth) {
- /* tag for removal */
- BM_elem_index_set(v, VERT_INDEX_DO_COLLAPSE); /* set_dirty! */
- }
- else {
- /* works better to allow these verts to be checked again */
- //BM_elem_index_set(v, VERT_INDEX_IGNORE); /* set_dirty! */
- }
- }
- }
- BMW_end(&walker);
+ /* Walk over selected elements starting at active */
+ BMW_init(&walker,
+ bm,
+ BMW_CONNECTED_VERTEX,
+ ELE_VERT_TAG,
+ BMW_MASK_NOP,
+ BMW_MASK_NOP,
+ BMW_FLAG_NOP, /* don't use BMW_FLAG_TEST_HIDDEN here since we want to desel all */
+ BMW_NIL_LAY);
+
+ BLI_assert(walker.order == BMW_BREADTH_FIRST);
+ for (v = BMW_begin(&walker, v_first); v != NULL; v = BMW_step(&walker)) {
+ /* Deselect elements that aren't at "nth" depth from active */
+ if (BM_elem_index_get(v) == VERT_INDEX_INIT) {
+ if ((offset + BMW_current_depth(&walker)) % nth) {
+ /* tag for removal */
+ BM_elem_index_set(v, VERT_INDEX_DO_COLLAPSE); /* set_dirty! */
+ }
+ else {
+ /* works better to allow these verts to be checked again */
+ //BM_elem_index_set(v, VERT_INDEX_IGNORE); /* set_dirty! */
+ }
+ }
+ }
+ BMW_end(&walker);
#else
- BM_elem_index_set(v_first, ((offset + depth) % nth) ? VERT_INDEX_IGNORE : VERT_INDEX_DO_COLLAPSE); /* set_dirty! */
-
- vert_seek_b_tot = 0;
- vert_seek_b[vert_seek_b_tot++] = v_first;
-
- while (true) {
- BMEdge *e;
-
- if ((offset + depth) % nth) {
- vert_seek_a_tot = 0;
- for (i = 0; i < vert_seek_b_tot; i++) {
- v = vert_seek_b[i];
- BLI_assert(BM_elem_index_get(v) == VERT_INDEX_IGNORE);
- BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) {
- BMVert *v_other = BM_edge_other_vert(e, v);
- if (BM_elem_index_get(v_other) == VERT_INDEX_INIT) {
- BM_elem_index_set(v_other, VERT_INDEX_DO_COLLAPSE); /* set_dirty! */
- vert_seek_a[vert_seek_a_tot++] = v_other;
- }
- }
- }
- if (vert_seek_a_tot == 0) {
- break;
- }
- }
- else {
- vert_seek_b_tot = 0;
- for (i = 0; i < vert_seek_a_tot; i++) {
- v = vert_seek_a[i];
- BLI_assert(BM_elem_index_get(v) == VERT_INDEX_DO_COLLAPSE);
- BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) {
- BMVert *v_other = BM_edge_other_vert(e, v);
- if (BM_elem_index_get(v_other) == VERT_INDEX_INIT) {
- BM_elem_index_set(v_other, VERT_INDEX_IGNORE); /* set_dirty! */
- vert_seek_b[vert_seek_b_tot++] = v_other;
- }
- }
- }
- if (vert_seek_b_tot == 0) {
- break;
- }
- }
-
- depth++;
- }
-#endif /* USE_WALKER */
-
- }
-
- /* now we tagged all verts -1 for removal, lets loop over and rebuild faces */
- iter_done = false;
- BM_ITER_MESH_MUTABLE (v, v_next, &iter, bm, BM_VERTS_OF_MESH) {
- if (BM_elem_index_get(v) == VERT_INDEX_DO_COLLAPSE) {
- if (bm_vert_dissolve_fan(bm, v)) {
- iter_done = true;
- }
- }
- }
-
- if (iter_done == false) {
- break;
- }
- }
-
- bm->elem_index_dirty |= BM_VERT;
+ BM_elem_index_set(v_first,
+ ((offset + depth) % nth) ? VERT_INDEX_IGNORE :
+ VERT_INDEX_DO_COLLAPSE); /* set_dirty! */
+
+ vert_seek_b_tot = 0;
+ vert_seek_b[vert_seek_b_tot++] = v_first;
+
+ while (true) {
+ BMEdge *e;
+
+ if ((offset + depth) % nth) {
+ vert_seek_a_tot = 0;
+ for (i = 0; i < vert_seek_b_tot; i++) {
+ v = vert_seek_b[i];
+ BLI_assert(BM_elem_index_get(v) == VERT_INDEX_IGNORE);
+ BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) {
+ BMVert *v_other = BM_edge_other_vert(e, v);
+ if (BM_elem_index_get(v_other) == VERT_INDEX_INIT) {
+ BM_elem_index_set(v_other, VERT_INDEX_DO_COLLAPSE); /* set_dirty! */
+ vert_seek_a[vert_seek_a_tot++] = v_other;
+ }
+ }
+ }
+ if (vert_seek_a_tot == 0) {
+ break;
+ }
+ }
+ else {
+ vert_seek_b_tot = 0;
+ for (i = 0; i < vert_seek_a_tot; i++) {
+ v = vert_seek_a[i];
+ BLI_assert(BM_elem_index_get(v) == VERT_INDEX_DO_COLLAPSE);
+ BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) {
+ BMVert *v_other = BM_edge_other_vert(e, v);
+ if (BM_elem_index_get(v_other) == VERT_INDEX_INIT) {
+ BM_elem_index_set(v_other, VERT_INDEX_IGNORE); /* set_dirty! */
+ vert_seek_b[vert_seek_b_tot++] = v_other;
+ }
+ }
+ }
+ if (vert_seek_b_tot == 0) {
+ break;
+ }
+ }
+
+ depth++;
+ }
+#endif /* USE_WALKER */
+ }
+
+ /* now we tagged all verts -1 for removal, lets loop over and rebuild faces */
+ iter_done = false;
+ BM_ITER_MESH_MUTABLE (v, v_next, &iter, bm, BM_VERTS_OF_MESH) {
+ if (BM_elem_index_get(v) == VERT_INDEX_DO_COLLAPSE) {
+ if (bm_vert_dissolve_fan(bm, v)) {
+ iter_done = true;
+ }
+ }
+ }
+
+ if (iter_done == false) {
+ break;
+ }
+ }
+
+ bm->elem_index_dirty |= BM_VERT;
#ifndef USE_WALKER
- MEM_freeN(vert_seek_a);
- MEM_freeN(vert_seek_b);
+ MEM_freeN(vert_seek_a);
+ MEM_freeN(vert_seek_b);
#endif
}
void BM_mesh_decimate_unsubdivide(BMesh *bm, const int iterations)
{
- BM_mesh_decimate_unsubdivide_ex(bm, iterations, false);
+ BM_mesh_decimate_unsubdivide_ex(bm, iterations, false);
}
diff --git a/source/blender/bmesh/tools/bmesh_edgenet.c b/source/blender/bmesh/tools/bmesh_edgenet.c
index 528a89a06ab..a3b9ce76b47 100644
--- a/source/blender/bmesh/tools/bmesh_edgenet.c
+++ b/source/blender/bmesh/tools/bmesh_edgenet.c
@@ -30,21 +30,20 @@
#include "BLI_linklist.h"
#include "bmesh.h"
-#include "bmesh_edgenet.h" /* own include */
-
-#include "BLI_strict_flags.h" /* keep last */
+#include "bmesh_edgenet.h" /* own include */
+#include "BLI_strict_flags.h" /* keep last */
/* Struct for storing a path of verts walked over */
typedef struct VertNetInfo {
- BMVert *prev; /* previous vertex */
- int pass; /* path scanning pass value, for internal calculation */
- int face; /* face index connected to the edge between this and the previous vert */
- int flag; /* flag */
+ BMVert *prev; /* previous vertex */
+ int pass; /* path scanning pass value, for internal calculation */
+ int face; /* face index connected to the edge between this and the previous vert */
+ int flag; /* flag */
} VertNetInfo;
enum {
- VNINFO_FLAG_IS_MIXFACE = (1 << 0),
+ VNINFO_FLAG_IS_MIXFACE = (1 << 0),
};
/**
@@ -52,137 +51,134 @@ enum {
*/
static bool bm_edge_step_ok(BMEdge *e)
{
- return BM_elem_flag_test(e, BM_ELEM_TAG) && ((e->l == NULL) || (e->l->radial_next == e->l));
+ return BM_elem_flag_test(e, BM_ELEM_TAG) && ((e->l == NULL) || (e->l->radial_next == e->l));
}
static int bm_edge_face(BMEdge *e)
{
- return e->l ? BM_elem_index_get(e->l->f) : -1;
+ return e->l ? BM_elem_index_get(e->l->f) : -1;
}
/**
* Get the next available edge we can use to attempt tp calculate a path from.
*/
-static BMEdge *bm_edgenet_edge_get_next(
- BMesh *bm,
- LinkNode **edge_queue, BLI_mempool *edge_queue_pool)
+static BMEdge *bm_edgenet_edge_get_next(BMesh *bm,
+ LinkNode **edge_queue,
+ BLI_mempool *edge_queue_pool)
{
- BMEdge *e;
- BMIter iter;
-
- while (*edge_queue) {
- e = BLI_linklist_pop_pool(edge_queue, edge_queue_pool);
- if (bm_edge_step_ok(e)) {
- return e;
- }
- }
-
- BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
- if (bm_edge_step_ok(e)) {
- return e;
- }
- }
-
- return NULL;
+ BMEdge *e;
+ BMIter iter;
+
+ while (*edge_queue) {
+ e = BLI_linklist_pop_pool(edge_queue, edge_queue_pool);
+ if (bm_edge_step_ok(e)) {
+ return e;
+ }
+ }
+
+ BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
+ if (bm_edge_step_ok(e)) {
+ return e;
+ }
+ }
+
+ return NULL;
}
-
/**
* Edge loops are built up using links to the 'prev' member.
* with each side of the loop having its own pass (negated from the other).
*
* This function returns half a loop, the caller needs to run twice to get both sides.
*/
-static uint bm_edgenet_path_from_pass(
- BMVert *v, LinkNode **v_ls,
- VertNetInfo *vnet_info, BLI_mempool *path_pool)
+static uint bm_edgenet_path_from_pass(BMVert *v,
+ LinkNode **v_ls,
+ VertNetInfo *vnet_info,
+ BLI_mempool *path_pool)
{
- VertNetInfo *vn = &vnet_info[BM_elem_index_get(v)];
- const int pass = vn->pass;
- uint v_ls_tot = 0;
-
- do {
- BLI_linklist_prepend_pool(v_ls, v, path_pool);
- v_ls_tot += 1;
- v = vn->prev;
- vn = &vnet_info[BM_elem_index_get(v)];
- } while (vn->pass == pass);
-
- return v_ls_tot;
+ VertNetInfo *vn = &vnet_info[BM_elem_index_get(v)];
+ const int pass = vn->pass;
+ uint v_ls_tot = 0;
+
+ do {
+ BLI_linklist_prepend_pool(v_ls, v, path_pool);
+ v_ls_tot += 1;
+ v = vn->prev;
+ vn = &vnet_info[BM_elem_index_get(v)];
+ } while (vn->pass == pass);
+
+ return v_ls_tot;
}
/**
* Specialized wrapper for #BM_face_exists_overlap_subset
* that gets the verts from a path before we allocate it in the correct order.
*/
-static bool bm_edgenet_path_check_overlap(
- BMVert *v1, BMVert *v2,
- VertNetInfo *vnet_info)
+static bool bm_edgenet_path_check_overlap(BMVert *v1, BMVert *v2, VertNetInfo *vnet_info)
{
- /* vert order doesn't matter */
- uint v_ls_tot = 0;
- LinkNode *v_ls = NULL;
- BMVert *v_pair[2] = {v1, v2};
- uint i;
-
- for (i = 0; i < 2; i++) {
- BMVert *v = v_pair[i];
- VertNetInfo *vn = &vnet_info[BM_elem_index_get(v)];
- const int pass = vn->pass;
- do {
- BLI_linklist_prepend_alloca(&v_ls, v);
- v_ls_tot += 1;
- v = vn->prev;
- vn = &vnet_info[BM_elem_index_get(v)];
- } while (vn->pass == pass);
- }
-
- if (v_ls_tot) {
- BMVert **vert_arr = BLI_array_alloca(vert_arr, v_ls_tot);
- LinkNode *v_lnk;
- for (i = 0, v_lnk = v_ls; i < v_ls_tot; v_lnk = v_lnk->next, i++) {
- vert_arr[i] = v_lnk->link;
- }
-
- return BM_face_exists_overlap_subset(vert_arr, (int)v_ls_tot);
- }
- else {
- return false;
- }
+ /* vert order doesn't matter */
+ uint v_ls_tot = 0;
+ LinkNode *v_ls = NULL;
+ BMVert *v_pair[2] = {v1, v2};
+ uint i;
+
+ for (i = 0; i < 2; i++) {
+ BMVert *v = v_pair[i];
+ VertNetInfo *vn = &vnet_info[BM_elem_index_get(v)];
+ const int pass = vn->pass;
+ do {
+ BLI_linklist_prepend_alloca(&v_ls, v);
+ v_ls_tot += 1;
+ v = vn->prev;
+ vn = &vnet_info[BM_elem_index_get(v)];
+ } while (vn->pass == pass);
+ }
+
+ if (v_ls_tot) {
+ BMVert **vert_arr = BLI_array_alloca(vert_arr, v_ls_tot);
+ LinkNode *v_lnk;
+ for (i = 0, v_lnk = v_ls; i < v_ls_tot; v_lnk = v_lnk->next, i++) {
+ vert_arr[i] = v_lnk->link;
+ }
+
+ return BM_face_exists_overlap_subset(vert_arr, (int)v_ls_tot);
+ }
+ else {
+ return false;
+ }
}
/**
* Create a face from the path.
*/
-static BMFace *bm_edgenet_face_from_path(
- BMesh *bm, LinkNode *path, const uint path_len)
+static BMFace *bm_edgenet_face_from_path(BMesh *bm, LinkNode *path, const uint path_len)
{
- BMFace *f;
- LinkNode *v_lnk;
- int i;
- bool ok;
+ BMFace *f;
+ LinkNode *v_lnk;
+ int i;
+ bool ok;
- BMVert **vert_arr = BLI_array_alloca(vert_arr, path_len);
- BMEdge **edge_arr = BLI_array_alloca(edge_arr, path_len);
+ BMVert **vert_arr = BLI_array_alloca(vert_arr, path_len);
+ BMEdge **edge_arr = BLI_array_alloca(edge_arr, path_len);
- for (v_lnk = path, i = 0; v_lnk; v_lnk = v_lnk->next, i++) {
- vert_arr[i] = v_lnk->link;
- }
+ for (v_lnk = path, i = 0; v_lnk; v_lnk = v_lnk->next, i++) {
+ vert_arr[i] = v_lnk->link;
+ }
- ok = BM_edges_from_verts(edge_arr, vert_arr, i);
- BLI_assert(ok);
- UNUSED_VARS_NDEBUG(ok);
+ ok = BM_edges_from_verts(edge_arr, vert_arr, i);
+ BLI_assert(ok);
+ UNUSED_VARS_NDEBUG(ok);
- /* no need for this, we do overlap checks before allowing the path to be used */
+ /* no need for this, we do overlap checks before allowing the path to be used */
#if 0
- if (BM_face_exists_multi(vert_arr, edge_arr, path_len)) {
- return NULL;
- }
+ if (BM_face_exists_multi(vert_arr, edge_arr, path_len)) {
+ return NULL;
+ }
#endif
- f = BM_face_create(bm, vert_arr, edge_arr, (int)path_len, NULL, BM_CREATE_NOP);
+ f = BM_face_create(bm, vert_arr, edge_arr, (int)path_len, NULL, BM_CREATE_NOP);
- return f;
+ return f;
}
/**
@@ -190,78 +186,75 @@ static BMFace *bm_edgenet_face_from_path(
*
* \return The connecting edge if the path is found, otherwise NULL.
*/
-static BMEdge *bm_edgenet_path_step(
- BMVert *v_curr, LinkNode **v_ls,
- VertNetInfo *vnet_info, BLI_mempool *path_pool)
+static BMEdge *bm_edgenet_path_step(BMVert *v_curr,
+ LinkNode **v_ls,
+ VertNetInfo *vnet_info,
+ BLI_mempool *path_pool)
{
- const VertNetInfo *vn_curr;
-
- BMEdge *e;
- BMIter iter;
- uint tot;
- uint v_ls_tot;
+ const VertNetInfo *vn_curr;
+ BMEdge *e;
+ BMIter iter;
+ uint tot;
+ uint v_ls_tot;
begin:
- tot = 0;
- v_ls_tot = 0;
- vn_curr = &vnet_info[BM_elem_index_get(v_curr)];
-
- BM_ITER_ELEM (e, &iter, v_curr, BM_EDGES_OF_VERT) {
- BMVert *v_next = BM_edge_other_vert(e, v_curr);
- if (v_next != vn_curr->prev) {
- if (bm_edge_step_ok(e)) {
- VertNetInfo *vn_next = &vnet_info[BM_elem_index_get(v_next)];
-
- /* check we're not looping back on ourselves */
- if (vn_curr->pass != vn_next->pass) {
-
- if (vn_curr->pass == -vn_next->pass) {
- if ((vn_curr->flag & VNINFO_FLAG_IS_MIXFACE) ||
- (vn_next->flag & VNINFO_FLAG_IS_MIXFACE))
- {
- /* found connecting edge */
- if (bm_edgenet_path_check_overlap(v_curr, v_next, vnet_info) == false) {
- return e;
- }
- }
- }
- else {
- vn_next->face = bm_edge_face(e);
- vn_next->pass = vn_curr->pass;
- vn_next->prev = v_curr;
-
- /* flush flag down the path */
- vn_next->flag &= ~VNINFO_FLAG_IS_MIXFACE;
- if ((vn_curr->flag & VNINFO_FLAG_IS_MIXFACE) ||
- (vn_next->face == -1) ||
- (vn_next->face != vn_curr->face))
- {
- vn_next->flag |= VNINFO_FLAG_IS_MIXFACE;
- }
-
- /* add to the list! */
- BLI_linklist_prepend_pool(v_ls, v_next, path_pool);
- v_ls_tot += 1;
- }
- }
- }
- tot += 1;
- }
- }
-
- /* trick to walk along wire-edge paths */
- if (v_ls_tot == 1 && tot == 1) {
- v_curr = BLI_linklist_pop_pool(v_ls, path_pool);
- /* avoid recursion, can crash on very large nets */
+ tot = 0;
+ v_ls_tot = 0;
+ vn_curr = &vnet_info[BM_elem_index_get(v_curr)];
+
+ BM_ITER_ELEM (e, &iter, v_curr, BM_EDGES_OF_VERT) {
+ BMVert *v_next = BM_edge_other_vert(e, v_curr);
+ if (v_next != vn_curr->prev) {
+ if (bm_edge_step_ok(e)) {
+ VertNetInfo *vn_next = &vnet_info[BM_elem_index_get(v_next)];
+
+ /* check we're not looping back on ourselves */
+ if (vn_curr->pass != vn_next->pass) {
+
+ if (vn_curr->pass == -vn_next->pass) {
+ if ((vn_curr->flag & VNINFO_FLAG_IS_MIXFACE) ||
+ (vn_next->flag & VNINFO_FLAG_IS_MIXFACE)) {
+ /* found connecting edge */
+ if (bm_edgenet_path_check_overlap(v_curr, v_next, vnet_info) == false) {
+ return e;
+ }
+ }
+ }
+ else {
+ vn_next->face = bm_edge_face(e);
+ vn_next->pass = vn_curr->pass;
+ vn_next->prev = v_curr;
+
+ /* flush flag down the path */
+ vn_next->flag &= ~VNINFO_FLAG_IS_MIXFACE;
+ if ((vn_curr->flag & VNINFO_FLAG_IS_MIXFACE) || (vn_next->face == -1) ||
+ (vn_next->face != vn_curr->face)) {
+ vn_next->flag |= VNINFO_FLAG_IS_MIXFACE;
+ }
+
+ /* add to the list! */
+ BLI_linklist_prepend_pool(v_ls, v_next, path_pool);
+ v_ls_tot += 1;
+ }
+ }
+ }
+ tot += 1;
+ }
+ }
+
+ /* trick to walk along wire-edge paths */
+ if (v_ls_tot == 1 && tot == 1) {
+ v_curr = BLI_linklist_pop_pool(v_ls, path_pool);
+ /* avoid recursion, can crash on very large nets */
#if 0
- bm_edgenet_path_step(v_curr, v_ls, vnet_info, path_pool);
+ bm_edgenet_path_step(v_curr, v_ls, vnet_info, path_pool);
#else
- goto begin;
+ goto begin;
#endif
- }
+ }
- return NULL;
+ return NULL;
}
/**
@@ -269,166 +262,167 @@ begin:
*
* \return A linked list of verts.
*/
-static LinkNode *bm_edgenet_path_calc(
- BMEdge *e, const int pass_nr, const uint path_cost_max,
- uint *r_path_len, uint *r_path_cost,
- VertNetInfo *vnet_info, BLI_mempool *path_pool)
+static LinkNode *bm_edgenet_path_calc(BMEdge *e,
+ const int pass_nr,
+ const uint path_cost_max,
+ uint *r_path_len,
+ uint *r_path_cost,
+ VertNetInfo *vnet_info,
+ BLI_mempool *path_pool)
{
- VertNetInfo *vn_1, *vn_2;
- const int f_index = bm_edge_face(e);
- bool found;
-
- LinkNode *v_ls_prev = NULL;
- LinkNode *v_ls_next = NULL;
+ VertNetInfo *vn_1, *vn_2;
+ const int f_index = bm_edge_face(e);
+ bool found;
- uint path_cost_accum = 0;
+ LinkNode *v_ls_prev = NULL;
+ LinkNode *v_ls_next = NULL;
- BLI_assert(bm_edge_step_ok(e));
+ uint path_cost_accum = 0;
- *r_path_len = 0;
- *r_path_cost = 0;
+ BLI_assert(bm_edge_step_ok(e));
- vn_1 = &vnet_info[BM_elem_index_get(e->v1)];
- vn_2 = &vnet_info[BM_elem_index_get(e->v2)];
+ *r_path_len = 0;
+ *r_path_cost = 0;
- vn_1->pass = pass_nr;
- vn_2->pass = -pass_nr;
+ vn_1 = &vnet_info[BM_elem_index_get(e->v1)];
+ vn_2 = &vnet_info[BM_elem_index_get(e->v2)];
- vn_1->prev = e->v2;
- vn_2->prev = e->v1;
+ vn_1->pass = pass_nr;
+ vn_2->pass = -pass_nr;
- vn_1->face =
- vn_2->face = f_index;
+ vn_1->prev = e->v2;
+ vn_2->prev = e->v1;
- vn_1->flag =
- vn_2->flag = (f_index == -1) ? VNINFO_FLAG_IS_MIXFACE : 0;
+ vn_1->face = vn_2->face = f_index;
- /* prime the searchlist */
- BLI_linklist_prepend_pool(&v_ls_prev, e->v1, path_pool);
- BLI_linklist_prepend_pool(&v_ls_prev, e->v2, path_pool);
+ vn_1->flag = vn_2->flag = (f_index == -1) ? VNINFO_FLAG_IS_MIXFACE : 0;
- do {
- found = false;
+ /* prime the searchlist */
+ BLI_linklist_prepend_pool(&v_ls_prev, e->v1, path_pool);
+ BLI_linklist_prepend_pool(&v_ls_prev, e->v2, path_pool);
- /* no point to continue, we're over budget */
- if (path_cost_accum >= path_cost_max) {
- BLI_linklist_free_pool(v_ls_next, NULL, path_pool);
- BLI_linklist_free_pool(v_ls_prev, NULL, path_pool);
- return NULL;
- }
+ do {
+ found = false;
- while (v_ls_prev) {
- const LinkNode *v_ls_next_old = v_ls_next;
- BMVert *v = BLI_linklist_pop_pool(&v_ls_prev, path_pool);
- BMEdge *e_found = bm_edgenet_path_step(v, &v_ls_next, vnet_info, path_pool);
+ /* no point to continue, we're over budget */
+ if (path_cost_accum >= path_cost_max) {
+ BLI_linklist_free_pool(v_ls_next, NULL, path_pool);
+ BLI_linklist_free_pool(v_ls_prev, NULL, path_pool);
+ return NULL;
+ }
- if (e_found) {
- LinkNode *path = NULL;
- uint path_len;
- BLI_linklist_free_pool(v_ls_next, NULL, path_pool);
- BLI_linklist_free_pool(v_ls_prev, NULL, path_pool);
+ while (v_ls_prev) {
+ const LinkNode *v_ls_next_old = v_ls_next;
+ BMVert *v = BLI_linklist_pop_pool(&v_ls_prev, path_pool);
+ BMEdge *e_found = bm_edgenet_path_step(v, &v_ls_next, vnet_info, path_pool);
- // BLI_assert(BLI_mempool_len(path_pool) == 0);
+ if (e_found) {
+ LinkNode *path = NULL;
+ uint path_len;
+ BLI_linklist_free_pool(v_ls_next, NULL, path_pool);
+ BLI_linklist_free_pool(v_ls_prev, NULL, path_pool);
- path_len = bm_edgenet_path_from_pass(e_found->v1, &path, vnet_info, path_pool);
- BLI_linklist_reverse(&path);
- path_len += bm_edgenet_path_from_pass(e_found->v2, &path, vnet_info, path_pool);
- *r_path_len = path_len;
- *r_path_cost = path_cost_accum;
- return path;
- }
- else {
- /* check if a change was made */
- if (v_ls_next_old != v_ls_next) {
- found = true;
- }
- }
+ // BLI_assert(BLI_mempool_len(path_pool) == 0);
- }
- BLI_assert(v_ls_prev == NULL);
+ path_len = bm_edgenet_path_from_pass(e_found->v1, &path, vnet_info, path_pool);
+ BLI_linklist_reverse(&path);
+ path_len += bm_edgenet_path_from_pass(e_found->v2, &path, vnet_info, path_pool);
+ *r_path_len = path_len;
+ *r_path_cost = path_cost_accum;
+ return path;
+ }
+ else {
+ /* check if a change was made */
+ if (v_ls_next_old != v_ls_next) {
+ found = true;
+ }
+ }
+ }
+ BLI_assert(v_ls_prev == NULL);
- path_cost_accum++;
+ path_cost_accum++;
- /* swap */
- v_ls_prev = v_ls_next;
- v_ls_next = NULL;
+ /* swap */
+ v_ls_prev = v_ls_next;
+ v_ls_next = NULL;
- } while (found);
+ } while (found);
- BLI_assert(v_ls_prev == NULL);
- BLI_assert(v_ls_next == NULL);
+ BLI_assert(v_ls_prev == NULL);
+ BLI_assert(v_ls_next == NULL);
- /* tag not to search again */
- BM_elem_flag_disable(e, BM_ELEM_TAG);
+ /* tag not to search again */
+ BM_elem_flag_disable(e, BM_ELEM_TAG);
- return NULL;
+ return NULL;
}
/**
* Wrapper for #bm_edgenet_path_calc which ensures all included edges
* _don't_ have a better option.
*/
-static LinkNode *bm_edgenet_path_calc_best(
- BMEdge *e, int *pass_nr, uint path_cost_max,
- uint *r_path_len, uint *r_path_cost,
- VertNetInfo *vnet_info, BLI_mempool *path_pool)
+static LinkNode *bm_edgenet_path_calc_best(BMEdge *e,
+ int *pass_nr,
+ uint path_cost_max,
+ uint *r_path_len,
+ uint *r_path_cost,
+ VertNetInfo *vnet_info,
+ BLI_mempool *path_pool)
{
- LinkNode *path;
- uint path_cost;
-
- path = bm_edgenet_path_calc(e, *pass_nr, path_cost_max,
- r_path_len, &path_cost,
- vnet_info, path_pool);
- (*pass_nr)++;
-
- if (path == NULL) {
- return NULL;
- }
- else if (path_cost < 1) {
- /* any face that takes 1 iteration to find we consider valid */
- return path;
- }
- else {
- /* Check every edge to see if any can give a better path.
- * This avoids very strange/long paths from being created. */
-
- const uint path_len = *r_path_len;
- uint i, i_prev;
- BMVert **vert_arr = BLI_array_alloca(vert_arr, path_len);
- LinkNode *v_lnk;
-
- for (v_lnk = path, i = 0; v_lnk; v_lnk = v_lnk->next, i++) {
- vert_arr[i] = v_lnk->link;
- }
-
- i_prev = path_len - 1;
- for (i = 0; i < path_len; i++) {
- BMEdge *e_other = BM_edge_exists(vert_arr[i], vert_arr[i_prev]);
- if (e_other != e) {
- LinkNode *path_test;
- uint path_len_test;
- uint path_cost_test;
-
- path_test = bm_edgenet_path_calc(e_other, *pass_nr, path_cost,
- &path_len_test, &path_cost_test,
- vnet_info, path_pool);
- (*pass_nr)++;
-
- if (path_test) {
- BLI_assert(path_cost_test < path_cost);
-
- BLI_linklist_free_pool(path, NULL, path_pool);
- path = path_test;
- *r_path_len = path_len_test;
- *r_path_cost = path_cost_test;
- path_cost = path_cost_test;
- }
- }
-
- i_prev = i;
- }
- }
- return path;
+ LinkNode *path;
+ uint path_cost;
+
+ path = bm_edgenet_path_calc(
+ e, *pass_nr, path_cost_max, r_path_len, &path_cost, vnet_info, path_pool);
+ (*pass_nr)++;
+
+ if (path == NULL) {
+ return NULL;
+ }
+ else if (path_cost < 1) {
+ /* any face that takes 1 iteration to find we consider valid */
+ return path;
+ }
+ else {
+ /* Check every edge to see if any can give a better path.
+ * This avoids very strange/long paths from being created. */
+
+ const uint path_len = *r_path_len;
+ uint i, i_prev;
+ BMVert **vert_arr = BLI_array_alloca(vert_arr, path_len);
+ LinkNode *v_lnk;
+
+ for (v_lnk = path, i = 0; v_lnk; v_lnk = v_lnk->next, i++) {
+ vert_arr[i] = v_lnk->link;
+ }
+
+ i_prev = path_len - 1;
+ for (i = 0; i < path_len; i++) {
+ BMEdge *e_other = BM_edge_exists(vert_arr[i], vert_arr[i_prev]);
+ if (e_other != e) {
+ LinkNode *path_test;
+ uint path_len_test;
+ uint path_cost_test;
+
+ path_test = bm_edgenet_path_calc(
+ e_other, *pass_nr, path_cost, &path_len_test, &path_cost_test, vnet_info, path_pool);
+ (*pass_nr)++;
+
+ if (path_test) {
+ BLI_assert(path_cost_test < path_cost);
+
+ BLI_linklist_free_pool(path, NULL, path_pool);
+ path = path_test;
+ *r_path_len = path_len_test;
+ *r_path_cost = path_cost_test;
+ path_cost = path_cost_test;
+ }
+ }
+
+ i_prev = i;
+ }
+ }
+ return path;
}
/**
@@ -440,70 +434,67 @@ static LinkNode *bm_edgenet_path_calc_best(
* \param bm: The mesh to operate on.
* \param use_edge_tag: Only fill tagged edges.
*/
-void BM_mesh_edgenet(
- BMesh *bm,
- const bool use_edge_tag, const bool use_new_face_tag)
+void BM_mesh_edgenet(BMesh *bm, const bool use_edge_tag, const bool use_new_face_tag)
{
- VertNetInfo *vnet_info = MEM_callocN(sizeof(*vnet_info) * (size_t)bm->totvert, __func__);
- BLI_mempool *edge_queue_pool = BLI_mempool_create(sizeof(LinkNode), 0, 512, BLI_MEMPOOL_NOP);
- BLI_mempool *path_pool = BLI_mempool_create(sizeof(LinkNode), 0, 512, BLI_MEMPOOL_NOP);
- LinkNode *edge_queue = NULL;
-
- BMEdge *e;
- BMIter iter;
-
- int pass_nr = 1;
-
- if (use_edge_tag == false) {
- BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
- BM_elem_flag_set(e, BM_ELEM_TAG, bm_edge_step_ok(e));
- }
- }
-
- BM_mesh_elem_index_ensure(bm, BM_VERT | BM_FACE);
-
- while (true) {
- LinkNode *path = NULL;
- uint path_len;
- uint path_cost;
-
- e = bm_edgenet_edge_get_next(bm, &edge_queue, edge_queue_pool);
- if (e == NULL) {
- break;
- }
-
- BLI_assert(bm_edge_step_ok(e) == true);
-
- path = bm_edgenet_path_calc_best(e, &pass_nr, UINT_MAX,
- &path_len, &path_cost,
- vnet_info, path_pool);
-
- if (path) {
- BMFace *f = bm_edgenet_face_from_path(bm, path, path_len);
- /* queue edges to operate on */
- BMLoop *l_first, *l_iter;
- l_iter = l_first = BM_FACE_FIRST_LOOP(f);
- do {
- if (bm_edge_step_ok(l_iter->e)) {
- BLI_linklist_prepend_pool(&edge_queue, l_iter->e, edge_queue_pool);
- }
- } while ((l_iter = l_iter->next) != l_first);
-
- if (use_new_face_tag) {
- BM_elem_flag_enable(f, BM_ELEM_TAG);
- }
-
- /* the face index only needs to be unique, not kept valid */
- BM_elem_index_set(f, bm->totface - 1); /* set_dirty */
- }
-
- BLI_linklist_free_pool(path, NULL, path_pool);
- BLI_assert(BLI_mempool_len(path_pool) == 0);
- }
-
- bm->elem_index_dirty |= BM_FACE | BM_LOOP;
-
- BLI_mempool_destroy(edge_queue_pool);
- BLI_mempool_destroy(path_pool);
- MEM_freeN(vnet_info);
+ VertNetInfo *vnet_info = MEM_callocN(sizeof(*vnet_info) * (size_t)bm->totvert, __func__);
+ BLI_mempool *edge_queue_pool = BLI_mempool_create(sizeof(LinkNode), 0, 512, BLI_MEMPOOL_NOP);
+ BLI_mempool *path_pool = BLI_mempool_create(sizeof(LinkNode), 0, 512, BLI_MEMPOOL_NOP);
+ LinkNode *edge_queue = NULL;
+
+ BMEdge *e;
+ BMIter iter;
+
+ int pass_nr = 1;
+
+ if (use_edge_tag == false) {
+ BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
+ BM_elem_flag_set(e, BM_ELEM_TAG, bm_edge_step_ok(e));
+ }
+ }
+
+ BM_mesh_elem_index_ensure(bm, BM_VERT | BM_FACE);
+
+ while (true) {
+ LinkNode *path = NULL;
+ uint path_len;
+ uint path_cost;
+
+ e = bm_edgenet_edge_get_next(bm, &edge_queue, edge_queue_pool);
+ if (e == NULL) {
+ break;
+ }
+
+ BLI_assert(bm_edge_step_ok(e) == true);
+
+ path = bm_edgenet_path_calc_best(
+ e, &pass_nr, UINT_MAX, &path_len, &path_cost, vnet_info, path_pool);
+
+ if (path) {
+ BMFace *f = bm_edgenet_face_from_path(bm, path, path_len);
+ /* queue edges to operate on */
+ BMLoop *l_first, *l_iter;
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ if (bm_edge_step_ok(l_iter->e)) {
+ BLI_linklist_prepend_pool(&edge_queue, l_iter->e, edge_queue_pool);
+ }
+ } while ((l_iter = l_iter->next) != l_first);
+
+ if (use_new_face_tag) {
+ BM_elem_flag_enable(f, BM_ELEM_TAG);
+ }
+
+ /* the face index only needs to be unique, not kept valid */
+ BM_elem_index_set(f, bm->totface - 1); /* set_dirty */
+ }
+
+ BLI_linklist_free_pool(path, NULL, path_pool);
+ BLI_assert(BLI_mempool_len(path_pool) == 0);
+ }
+
+ bm->elem_index_dirty |= BM_FACE | BM_LOOP;
+
+ BLI_mempool_destroy(edge_queue_pool);
+ BLI_mempool_destroy(path_pool);
+ MEM_freeN(vnet_info);
}
diff --git a/source/blender/bmesh/tools/bmesh_edgenet.h b/source/blender/bmesh/tools/bmesh_edgenet.h
index 0a72ded8949..5db0e1170f3 100644
--- a/source/blender/bmesh/tools/bmesh_edgenet.h
+++ b/source/blender/bmesh/tools/bmesh_edgenet.h
@@ -21,8 +21,6 @@
* \ingroup bmesh
*/
-void BM_mesh_edgenet(
- BMesh *bm,
- const bool use_edge_tag, const bool use_new_face_tag);
+void BM_mesh_edgenet(BMesh *bm, const bool use_edge_tag, const bool use_new_face_tag);
#endif /* __BMESH_EDGENET_H__ */
diff --git a/source/blender/bmesh/tools/bmesh_edgesplit.c b/source/blender/bmesh/tools/bmesh_edgesplit.c
index 198b3efa8cc..332672d7c3c 100644
--- a/source/blender/bmesh/tools/bmesh_edgesplit.c
+++ b/source/blender/bmesh/tools/bmesh_edgesplit.c
@@ -26,113 +26,112 @@
#include "bmesh.h"
-#include "bmesh_edgesplit.h" /* own include */
+#include "bmesh_edgesplit.h" /* own include */
/**
* \param use_verts: Use flagged verts instead of edges.
* \param tag_only: Only split tagged edges.
* \param copy_select: Copy selection history.
*/
-void BM_mesh_edgesplit(
- BMesh *bm,
- const bool use_verts,
- const bool tag_only, const bool copy_select)
+void BM_mesh_edgesplit(BMesh *bm,
+ const bool use_verts,
+ const bool tag_only,
+ const bool copy_select)
{
- BMIter iter;
- BMEdge *e;
-
- bool use_ese = false;
- GHash *ese_gh = NULL;
-
- if (copy_select && bm->selected.first) {
- BMEditSelection *ese;
-
- ese_gh = BLI_ghash_ptr_new(__func__);
- for (ese = bm->selected.first; ese; ese = ese->next) {
- if (ese->htype != BM_FACE) {
- BLI_ghash_insert(ese_gh, ese->ele, ese);
- }
- }
-
- use_ese = true;
- }
-
- if (tag_only == false) {
- BM_mesh_elem_hflag_enable_all(bm, BM_EDGE | (use_verts ? BM_VERT : 0), BM_ELEM_TAG, false);
- }
-
- if (use_verts) {
- /* prevent one edge having both verts unflagged
- * we could alternately disable these edges, either way its a corner case.
- *
- * This is needed so we don't split off the edge but then none of its verts which
- * would leave a duplicate edge.
- */
- BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
- if (BM_elem_flag_test(e, BM_ELEM_TAG)) {
- if (UNLIKELY(((BM_elem_flag_test(e->v1, BM_ELEM_TAG) == false) &&
- (BM_elem_flag_test(e->v2, BM_ELEM_TAG) == false))))
- {
- BM_elem_flag_enable(e->v1, BM_ELEM_TAG);
- BM_elem_flag_enable(e->v2, BM_ELEM_TAG);
- }
- }
- }
- }
-
- BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
- if (BM_elem_flag_test(e, BM_ELEM_TAG)) {
- BM_elem_flag_enable(e->v1, BM_ELEM_TAG);
- BM_elem_flag_enable(e->v2, BM_ELEM_TAG);
- }
- }
-
- BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
- if (BM_elem_flag_test(e, BM_ELEM_TAG)) {
- uint i;
- for (i = 0; i < 2; i++) {
- BMVert *v = ((&e->v1)[i]);
- if (BM_elem_flag_test(v, BM_ELEM_TAG)) {
- BM_elem_flag_disable(v, BM_ELEM_TAG);
-
- if (use_ese) {
- BMVert **vtar;
- int vtar_len;
-
- BM_vert_separate_hflag(bm, v, BM_ELEM_TAG, copy_select, &vtar, &vtar_len);
-
- /* first value is always in 'v' */
- if (vtar_len > 1) {
- BMEditSelection *ese = BLI_ghash_lookup(ese_gh, v);
- BLI_assert(v == vtar[0]);
- if (UNLIKELY(ese)) {
- int j;
- for (j = 1; j < vtar_len; j++) {
- BLI_assert(v != vtar[j]);
- BM_select_history_store_after_notest(bm, ese, vtar[j]);
- }
- }
- }
- MEM_freeN(vtar);
- }
- else {
- BM_vert_separate_hflag(bm, v, BM_ELEM_TAG, copy_select, NULL, NULL);
- }
- }
- }
- }
- }
+ BMIter iter;
+ BMEdge *e;
+
+ bool use_ese = false;
+ GHash *ese_gh = NULL;
+
+ if (copy_select && bm->selected.first) {
+ BMEditSelection *ese;
+
+ ese_gh = BLI_ghash_ptr_new(__func__);
+ for (ese = bm->selected.first; ese; ese = ese->next) {
+ if (ese->htype != BM_FACE) {
+ BLI_ghash_insert(ese_gh, ese->ele, ese);
+ }
+ }
+
+ use_ese = true;
+ }
+
+ if (tag_only == false) {
+ BM_mesh_elem_hflag_enable_all(bm, BM_EDGE | (use_verts ? BM_VERT : 0), BM_ELEM_TAG, false);
+ }
+
+ if (use_verts) {
+ /* prevent one edge having both verts unflagged
+ * we could alternately disable these edges, either way its a corner case.
+ *
+ * This is needed so we don't split off the edge but then none of its verts which
+ * would leave a duplicate edge.
+ */
+ BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
+ if (BM_elem_flag_test(e, BM_ELEM_TAG)) {
+ if (UNLIKELY(((BM_elem_flag_test(e->v1, BM_ELEM_TAG) == false) &&
+ (BM_elem_flag_test(e->v2, BM_ELEM_TAG) == false)))) {
+ BM_elem_flag_enable(e->v1, BM_ELEM_TAG);
+ BM_elem_flag_enable(e->v2, BM_ELEM_TAG);
+ }
+ }
+ }
+ }
+
+ BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
+ if (BM_elem_flag_test(e, BM_ELEM_TAG)) {
+ BM_elem_flag_enable(e->v1, BM_ELEM_TAG);
+ BM_elem_flag_enable(e->v2, BM_ELEM_TAG);
+ }
+ }
+
+ BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
+ if (BM_elem_flag_test(e, BM_ELEM_TAG)) {
+ uint i;
+ for (i = 0; i < 2; i++) {
+ BMVert *v = ((&e->v1)[i]);
+ if (BM_elem_flag_test(v, BM_ELEM_TAG)) {
+ BM_elem_flag_disable(v, BM_ELEM_TAG);
+
+ if (use_ese) {
+ BMVert **vtar;
+ int vtar_len;
+
+ BM_vert_separate_hflag(bm, v, BM_ELEM_TAG, copy_select, &vtar, &vtar_len);
+
+ /* first value is always in 'v' */
+ if (vtar_len > 1) {
+ BMEditSelection *ese = BLI_ghash_lookup(ese_gh, v);
+ BLI_assert(v == vtar[0]);
+ if (UNLIKELY(ese)) {
+ int j;
+ for (j = 1; j < vtar_len; j++) {
+ BLI_assert(v != vtar[j]);
+ BM_select_history_store_after_notest(bm, ese, vtar[j]);
+ }
+ }
+ }
+ MEM_freeN(vtar);
+ }
+ else {
+ BM_vert_separate_hflag(bm, v, BM_ELEM_TAG, copy_select, NULL, NULL);
+ }
+ }
+ }
+ }
+ }
#ifndef NDEBUG
- /* ensure we don't have any double edges! */
- BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
- if (BM_elem_flag_test(e, BM_ELEM_TAG)) {
- BLI_assert(BM_edge_find_double(e) == NULL);
- }
- }
+ /* ensure we don't have any double edges! */
+ BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
+ if (BM_elem_flag_test(e, BM_ELEM_TAG)) {
+ BLI_assert(BM_edge_find_double(e) == NULL);
+ }
+ }
#endif
- if (use_ese) {
- BLI_ghash_free(ese_gh, NULL, NULL);
- }
+ if (use_ese) {
+ BLI_ghash_free(ese_gh, NULL, NULL);
+ }
}
diff --git a/source/blender/bmesh/tools/bmesh_edgesplit.h b/source/blender/bmesh/tools/bmesh_edgesplit.h
index f7faeb1fa19..0b3884ec888 100644
--- a/source/blender/bmesh/tools/bmesh_edgesplit.h
+++ b/source/blender/bmesh/tools/bmesh_edgesplit.h
@@ -21,9 +21,9 @@
* \ingroup bmesh
*/
-void BM_mesh_edgesplit(
- BMesh *bm,
- const bool use_verts,
- const bool tag_only, const bool copy_select);
+void BM_mesh_edgesplit(BMesh *bm,
+ const bool use_verts,
+ const bool tag_only,
+ const bool copy_select);
#endif /* __BMESH_EDGESPLIT_H__ */
diff --git a/source/blender/bmesh/tools/bmesh_intersect.c b/source/blender/bmesh/tools/bmesh_intersect.c
index 2445978e294..66845b6f33c 100644
--- a/source/blender/bmesh/tools/bmesh_intersect.c
+++ b/source/blender/bmesh/tools/bmesh_intersect.c
@@ -50,7 +50,7 @@
#include "bmesh.h"
#include "intern/bmesh_private.h"
-#include "bmesh_intersect.h" /* own include */
+#include "bmesh_intersect.h" /* own include */
#include "tools/bmesh_edgesplit.h"
@@ -78,61 +78,59 @@
// #define USE_DUMP
-static void tri_v3_scale(
- float v1[3], float v2[3], float v3[3],
- const float t)
+static void tri_v3_scale(float v1[3], float v2[3], float v3[3], const float t)
{
- float p[3];
+ float p[3];
- mid_v3_v3v3v3(p, v1, v2, v3);
+ mid_v3_v3v3v3(p, v1, v2, v3);
- interp_v3_v3v3(v1, p, v1, t);
- interp_v3_v3v3(v2, p, v2, t);
- interp_v3_v3v3(v3, p, v3, t);
+ interp_v3_v3v3(v1, p, v1, t);
+ interp_v3_v3v3(v2, p, v2, t);
+ interp_v3_v3v3(v3, p, v3, t);
}
#ifdef USE_DISSOLVE
/* other edge when a vert only has 2 edges */
static BMEdge *bm_vert_other_edge(BMVert *v, BMEdge *e)
{
- BLI_assert(BM_vert_is_edge_pair(v));
- BLI_assert(BM_vert_in_edge(e, v));
-
- if (v->e != e) {
- return v->e;
- }
- else {
- return BM_DISK_EDGE_NEXT(v->e, v);
- }
+ BLI_assert(BM_vert_is_edge_pair(v));
+ BLI_assert(BM_vert_in_edge(e, v));
+
+ if (v->e != e) {
+ return v->e;
+ }
+ else {
+ return BM_DISK_EDGE_NEXT(v->e, v);
+ }
}
#endif
enum ISectType {
- IX_NONE = -1,
- IX_EDGE_TRI_EDGE0,
- IX_EDGE_TRI_EDGE1,
- IX_EDGE_TRI_EDGE2,
- IX_EDGE_TRI,
- IX_TOT,
+ IX_NONE = -1,
+ IX_EDGE_TRI_EDGE0,
+ IX_EDGE_TRI_EDGE1,
+ IX_EDGE_TRI_EDGE2,
+ IX_EDGE_TRI,
+ IX_TOT,
};
struct ISectEpsilon {
- float eps, eps_sq;
- float eps2x, eps2x_sq;
- float eps_margin, eps_margin_sq;
+ float eps, eps_sq;
+ float eps2x, eps2x_sq;
+ float eps_margin, eps_margin_sq;
};
struct ISectState {
- BMesh *bm;
- GHash *edgetri_cache; /* int[4]: BMVert */
- GHash *edge_verts; /* BMEdge: LinkList(of verts), new and original edges */
- GHash *face_edges; /* BMFace-index: LinkList(of edges), only original faces */
- GSet *wire_edges; /* BMEdge (could use tags instead) */
- LinkNode *vert_dissolve; /* BMVert's */
+ BMesh *bm;
+ GHash *edgetri_cache; /* int[4]: BMVert */
+ GHash *edge_verts; /* BMEdge: LinkList(of verts), new and original edges */
+ GHash *face_edges; /* BMFace-index: LinkList(of edges), only original faces */
+ GSet *wire_edges; /* BMEdge (could use tags instead) */
+ LinkNode *vert_dissolve; /* BMVert's */
- MemArena *mem_arena;
+ MemArena *mem_arena;
- struct ISectEpsilon epsilon;
+ struct ISectEpsilon epsilon;
};
/**
@@ -140,829 +138,809 @@ struct ISectState {
* Also means we don't need to update the GHash value each time.
*/
struct LinkBase {
- LinkNode *list;
- uint list_len;
+ LinkNode *list;
+ uint list_len;
};
-static bool ghash_insert_link(
- GHash *gh, void *key, void *val, bool use_test,
- MemArena *mem_arena)
+static bool ghash_insert_link(GHash *gh, void *key, void *val, bool use_test, MemArena *mem_arena)
{
- void **ls_base_p;
- struct LinkBase *ls_base;
- LinkNode *ls;
-
- if (!BLI_ghash_ensure_p(gh, key, &ls_base_p)) {
- ls_base = *ls_base_p = BLI_memarena_alloc(mem_arena, sizeof(*ls_base));
- ls_base->list = NULL;
- ls_base->list_len = 0;
- }
- else {
- ls_base = *ls_base_p;
- if (use_test && (BLI_linklist_index(ls_base->list, val) != -1)) {
- return false;
- }
- }
-
- ls = BLI_memarena_alloc(mem_arena, sizeof(*ls));
- ls->next = ls_base->list;
- ls->link = val;
- ls_base->list = ls;
- ls_base->list_len += 1;
-
- return true;
+ void **ls_base_p;
+ struct LinkBase *ls_base;
+ LinkNode *ls;
+
+ if (!BLI_ghash_ensure_p(gh, key, &ls_base_p)) {
+ ls_base = *ls_base_p = BLI_memarena_alloc(mem_arena, sizeof(*ls_base));
+ ls_base->list = NULL;
+ ls_base->list_len = 0;
+ }
+ else {
+ ls_base = *ls_base_p;
+ if (use_test && (BLI_linklist_index(ls_base->list, val) != -1)) {
+ return false;
+ }
+ }
+
+ ls = BLI_memarena_alloc(mem_arena, sizeof(*ls));
+ ls->next = ls_base->list;
+ ls->link = val;
+ ls_base->list = ls;
+ ls_base->list_len += 1;
+
+ return true;
}
struct vert_sort_t {
- float val;
- BMVert *v;
+ float val;
+ BMVert *v;
};
#ifdef USE_SPLICE
static void edge_verts_sort(const float co[3], struct LinkBase *v_ls_base)
{
- /* not optimal but list will be typically < 5 */
- uint i;
- struct vert_sort_t *vert_sort = BLI_array_alloca(vert_sort, v_ls_base->list_len);
- LinkNode *node;
+ /* not optimal but list will be typically < 5 */
+ uint i;
+ struct vert_sort_t *vert_sort = BLI_array_alloca(vert_sort, v_ls_base->list_len);
+ LinkNode *node;
- BLI_assert(v_ls_base->list_len > 1);
+ BLI_assert(v_ls_base->list_len > 1);
- for (i = 0, node = v_ls_base->list; i < v_ls_base->list_len; i++, node = node->next) {
- BMVert *v = node->link;
- BLI_assert(v->head.htype == BM_VERT);
- vert_sort[i].val = len_squared_v3v3(co, v->co);
- vert_sort[i].v = v;
- }
+ for (i = 0, node = v_ls_base->list; i < v_ls_base->list_len; i++, node = node->next) {
+ BMVert *v = node->link;
+ BLI_assert(v->head.htype == BM_VERT);
+ vert_sort[i].val = len_squared_v3v3(co, v->co);
+ vert_sort[i].v = v;
+ }
- qsort(vert_sort, v_ls_base->list_len, sizeof(*vert_sort), BLI_sortutil_cmp_float);
+ qsort(vert_sort, v_ls_base->list_len, sizeof(*vert_sort), BLI_sortutil_cmp_float);
- for (i = 0, node = v_ls_base->list; i < v_ls_base->list_len; i++, node = node->next) {
- node->link = vert_sort[i].v;
- }
+ for (i = 0, node = v_ls_base->list; i < v_ls_base->list_len; i++, node = node->next) {
+ node->link = vert_sort[i].v;
+ }
}
#endif
-static void edge_verts_add(
- struct ISectState *s,
- BMEdge *e,
- BMVert *v,
- const bool use_test
- )
+static void edge_verts_add(struct ISectState *s, BMEdge *e, BMVert *v, const bool use_test)
{
- BLI_assert(e->head.htype == BM_EDGE);
- BLI_assert(v->head.htype == BM_VERT);
- ghash_insert_link(s->edge_verts, (void *)e, v, use_test, s->mem_arena);
+ BLI_assert(e->head.htype == BM_EDGE);
+ BLI_assert(v->head.htype == BM_VERT);
+ ghash_insert_link(s->edge_verts, (void *)e, v, use_test, s->mem_arena);
}
-static void face_edges_add(
- struct ISectState *s,
- const int f_index,
- BMEdge *e,
- const bool use_test)
+static void face_edges_add(struct ISectState *s, const int f_index, BMEdge *e, const bool use_test)
{
- void *f_index_key = POINTER_FROM_INT(f_index);
- BLI_assert(e->head.htype == BM_EDGE);
- BLI_assert(BM_edge_in_face(e, s->bm->ftable[f_index]) == false);
- BLI_assert(BM_elem_index_get(s->bm->ftable[f_index]) == f_index);
+ void *f_index_key = POINTER_FROM_INT(f_index);
+ BLI_assert(e->head.htype == BM_EDGE);
+ BLI_assert(BM_edge_in_face(e, s->bm->ftable[f_index]) == false);
+ BLI_assert(BM_elem_index_get(s->bm->ftable[f_index]) == f_index);
- ghash_insert_link(s->face_edges, f_index_key, e, use_test, s->mem_arena);
+ ghash_insert_link(s->face_edges, f_index_key, e, use_test, s->mem_arena);
}
#ifdef USE_NET
-static void face_edges_split(
- BMesh *bm, BMFace *f, struct LinkBase *e_ls_base,
- bool use_island_connect, bool use_partial_connect,
- MemArena *mem_arena_edgenet)
+static void face_edges_split(BMesh *bm,
+ BMFace *f,
+ struct LinkBase *e_ls_base,
+ bool use_island_connect,
+ bool use_partial_connect,
+ MemArena *mem_arena_edgenet)
{
- uint i;
- uint edge_arr_len = e_ls_base->list_len;
- BMEdge **edge_arr = BLI_array_alloca(edge_arr, edge_arr_len);
- LinkNode *node;
- BLI_assert(f->head.htype == BM_FACE);
-
- for (i = 0, node = e_ls_base->list; i < e_ls_base->list_len; i++, node = node->next) {
- edge_arr[i] = node->link;
- }
- BLI_assert(node == NULL);
-
-#ifdef USE_DUMP
- printf("# %s: %d %u\n", __func__, BM_elem_index_get(f), e_ls_base->list_len);
-#endif
-
-#ifdef USE_NET_ISLAND_CONNECT
- if (use_island_connect) {
- uint edge_arr_holes_len;
- BMEdge **edge_arr_holes;
- if (BM_face_split_edgenet_connect_islands(
- bm, f,
- edge_arr, edge_arr_len,
- use_partial_connect,
- mem_arena_edgenet,
- &edge_arr_holes, &edge_arr_holes_len))
- {
- edge_arr_len = edge_arr_holes_len;
- edge_arr = edge_arr_holes; /* owned by the arena */
- }
- }
-#else
- UNUSED_VARS(use_island_connect, mem_arena_edgenet);
-#endif
-
- BM_face_split_edgenet(bm, f, edge_arr, (int)edge_arr_len, NULL, NULL);
+ uint i;
+ uint edge_arr_len = e_ls_base->list_len;
+ BMEdge **edge_arr = BLI_array_alloca(edge_arr, edge_arr_len);
+ LinkNode *node;
+ BLI_assert(f->head.htype == BM_FACE);
+
+ for (i = 0, node = e_ls_base->list; i < e_ls_base->list_len; i++, node = node->next) {
+ edge_arr[i] = node->link;
+ }
+ BLI_assert(node == NULL);
+
+# ifdef USE_DUMP
+ printf("# %s: %d %u\n", __func__, BM_elem_index_get(f), e_ls_base->list_len);
+# endif
+
+# ifdef USE_NET_ISLAND_CONNECT
+ if (use_island_connect) {
+ uint edge_arr_holes_len;
+ BMEdge **edge_arr_holes;
+ if (BM_face_split_edgenet_connect_islands(bm,
+ f,
+ edge_arr,
+ edge_arr_len,
+ use_partial_connect,
+ mem_arena_edgenet,
+ &edge_arr_holes,
+ &edge_arr_holes_len)) {
+ edge_arr_len = edge_arr_holes_len;
+ edge_arr = edge_arr_holes; /* owned by the arena */
+ }
+ }
+# else
+ UNUSED_VARS(use_island_connect, mem_arena_edgenet);
+# endif
+
+ BM_face_split_edgenet(bm, f, edge_arr, (int)edge_arr_len, NULL, NULL);
}
#endif
#ifdef USE_DISSOLVE
-static void vert_dissolve_add(
- struct ISectState *s,
- BMVert *v)
+static void vert_dissolve_add(struct ISectState *s, BMVert *v)
{
- BLI_assert(v->head.htype == BM_VERT);
- BLI_assert(!BM_elem_flag_test(v, BM_ELEM_TAG));
- BLI_assert(BLI_linklist_index(s->vert_dissolve, v) == -1);
+ BLI_assert(v->head.htype == BM_VERT);
+ BLI_assert(!BM_elem_flag_test(v, BM_ELEM_TAG));
+ BLI_assert(BLI_linklist_index(s->vert_dissolve, v) == -1);
- BM_elem_flag_enable(v, BM_ELEM_TAG);
- BLI_linklist_prepend_arena(&s->vert_dissolve, v, s->mem_arena);
+ BM_elem_flag_enable(v, BM_ELEM_TAG);
+ BLI_linklist_prepend_arena(&s->vert_dissolve, v, s->mem_arena);
}
#endif
-static enum ISectType intersect_line_tri(
- const float p0[3], const float p1[3],
- const float *t_cos[3], const float t_nor[3],
- float r_ix[3],
- const struct ISectEpsilon *e)
+static enum ISectType intersect_line_tri(const float p0[3],
+ const float p1[3],
+ const float *t_cos[3],
+ const float t_nor[3],
+ float r_ix[3],
+ const struct ISectEpsilon *e)
{
- float p_dir[3];
- uint i_t0;
- float fac;
-
- sub_v3_v3v3(p_dir, p0, p1);
- normalize_v3(p_dir);
-
- for (i_t0 = 0; i_t0 < 3; i_t0++) {
- const uint i_t1 = (i_t0 + 1) % 3;
- float te_dir[3];
-
- sub_v3_v3v3(te_dir, t_cos[i_t0], t_cos[i_t1]);
- normalize_v3(te_dir);
- if (fabsf(dot_v3v3(p_dir, te_dir)) >= 1.0f - e->eps) {
- /* co-linear */
- }
- else {
- float ix_pair[2][3];
- int ix_pair_type;
-
- ix_pair_type = isect_line_line_epsilon_v3(p0, p1, t_cos[i_t0], t_cos[i_t1], ix_pair[0], ix_pair[1], 0.0f);
-
- if (ix_pair_type != 0) {
- if (ix_pair_type == 1) {
- copy_v3_v3(ix_pair[1], ix_pair[0]);
- }
-
- if ((ix_pair_type == 1) ||
- (len_squared_v3v3(ix_pair[0], ix_pair[1]) <= e->eps_margin_sq))
- {
- fac = line_point_factor_v3(ix_pair[1], t_cos[i_t0], t_cos[i_t1]);
- if ((fac >= e->eps_margin) && (fac <= 1.0f - e->eps_margin)) {
- fac = line_point_factor_v3(ix_pair[0], p0, p1);
- if ((fac >= e->eps_margin) && (fac <= 1.0f - e->eps_margin)) {
- copy_v3_v3(r_ix, ix_pair[0]);
- return (IX_EDGE_TRI_EDGE0 + (enum ISectType)i_t0);
- }
- }
- }
- }
- }
- }
-
- /* check ray isn't planar with tri */
- if (fabsf(dot_v3v3(p_dir, t_nor)) >= e->eps) {
- if (isect_line_segment_tri_epsilon_v3(p0, p1, t_cos[0], t_cos[1], t_cos[2], &fac, NULL, 0.0f)) {
- if ((fac >= e->eps_margin) && (fac <= 1.0f - e->eps_margin)) {
- interp_v3_v3v3(r_ix, p0, p1, fac);
- if (min_fff(len_squared_v3v3(t_cos[0], r_ix),
- len_squared_v3v3(t_cos[1], r_ix),
- len_squared_v3v3(t_cos[2], r_ix)) >= e->eps_margin_sq)
- {
- return IX_EDGE_TRI;
- }
- }
- }
- }
-
- /* r_ix may be unset */
- return IX_NONE;
+ float p_dir[3];
+ uint i_t0;
+ float fac;
+
+ sub_v3_v3v3(p_dir, p0, p1);
+ normalize_v3(p_dir);
+
+ for (i_t0 = 0; i_t0 < 3; i_t0++) {
+ const uint i_t1 = (i_t0 + 1) % 3;
+ float te_dir[3];
+
+ sub_v3_v3v3(te_dir, t_cos[i_t0], t_cos[i_t1]);
+ normalize_v3(te_dir);
+ if (fabsf(dot_v3v3(p_dir, te_dir)) >= 1.0f - e->eps) {
+ /* co-linear */
+ }
+ else {
+ float ix_pair[2][3];
+ int ix_pair_type;
+
+ ix_pair_type = isect_line_line_epsilon_v3(
+ p0, p1, t_cos[i_t0], t_cos[i_t1], ix_pair[0], ix_pair[1], 0.0f);
+
+ if (ix_pair_type != 0) {
+ if (ix_pair_type == 1) {
+ copy_v3_v3(ix_pair[1], ix_pair[0]);
+ }
+
+ if ((ix_pair_type == 1) ||
+ (len_squared_v3v3(ix_pair[0], ix_pair[1]) <= e->eps_margin_sq)) {
+ fac = line_point_factor_v3(ix_pair[1], t_cos[i_t0], t_cos[i_t1]);
+ if ((fac >= e->eps_margin) && (fac <= 1.0f - e->eps_margin)) {
+ fac = line_point_factor_v3(ix_pair[0], p0, p1);
+ if ((fac >= e->eps_margin) && (fac <= 1.0f - e->eps_margin)) {
+ copy_v3_v3(r_ix, ix_pair[0]);
+ return (IX_EDGE_TRI_EDGE0 + (enum ISectType)i_t0);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* check ray isn't planar with tri */
+ if (fabsf(dot_v3v3(p_dir, t_nor)) >= e->eps) {
+ if (isect_line_segment_tri_epsilon_v3(
+ p0, p1, t_cos[0], t_cos[1], t_cos[2], &fac, NULL, 0.0f)) {
+ if ((fac >= e->eps_margin) && (fac <= 1.0f - e->eps_margin)) {
+ interp_v3_v3v3(r_ix, p0, p1, fac);
+ if (min_fff(len_squared_v3v3(t_cos[0], r_ix),
+ len_squared_v3v3(t_cos[1], r_ix),
+ len_squared_v3v3(t_cos[2], r_ix)) >= e->eps_margin_sq) {
+ return IX_EDGE_TRI;
+ }
+ }
+ }
+ }
+
+ /* r_ix may be unset */
+ return IX_NONE;
}
-static BMVert *bm_isect_edge_tri(
- struct ISectState *s,
- BMVert *e_v0, BMVert *e_v1,
- BMVert *t[3], const int t_index,
- const float *t_cos[3], const float t_nor[3],
- enum ISectType *r_side)
+static BMVert *bm_isect_edge_tri(struct ISectState *s,
+ BMVert *e_v0,
+ BMVert *e_v1,
+ BMVert *t[3],
+ const int t_index,
+ const float *t_cos[3],
+ const float t_nor[3],
+ enum ISectType *r_side)
{
- BMesh *bm = s->bm;
- int k_arr[IX_TOT][4];
- uint i;
- const int ti[3] = {UNPACK3_EX(BM_elem_index_get, t, )};
- float ix[3];
+ BMesh *bm = s->bm;
+ int k_arr[IX_TOT][4];
+ uint i;
+ const int ti[3] = {UNPACK3_EX(BM_elem_index_get, t, )};
+ float ix[3];
- if (BM_elem_index_get(e_v0) > BM_elem_index_get(e_v1)) {
- SWAP(BMVert *, e_v0, e_v1);
- }
+ if (BM_elem_index_get(e_v0) > BM_elem_index_get(e_v1)) {
+ SWAP(BMVert *, e_v0, e_v1);
+ }
#ifdef USE_PARANOID
- BLI_assert(len_squared_v3v3(e_v0->co, t[0]->co) >= s->epsilon.eps_sq);
- BLI_assert(len_squared_v3v3(e_v0->co, t[1]->co) >= s->epsilon.eps_sq);
- BLI_assert(len_squared_v3v3(e_v0->co, t[2]->co) >= s->epsilon.eps_sq);
- BLI_assert(len_squared_v3v3(e_v1->co, t[0]->co) >= s->epsilon.eps_sq);
- BLI_assert(len_squared_v3v3(e_v1->co, t[1]->co) >= s->epsilon.eps_sq);
- BLI_assert(len_squared_v3v3(e_v1->co, t[2]->co) >= s->epsilon.eps_sq);
+ BLI_assert(len_squared_v3v3(e_v0->co, t[0]->co) >= s->epsilon.eps_sq);
+ BLI_assert(len_squared_v3v3(e_v0->co, t[1]->co) >= s->epsilon.eps_sq);
+ BLI_assert(len_squared_v3v3(e_v0->co, t[2]->co) >= s->epsilon.eps_sq);
+ BLI_assert(len_squared_v3v3(e_v1->co, t[0]->co) >= s->epsilon.eps_sq);
+ BLI_assert(len_squared_v3v3(e_v1->co, t[1]->co) >= s->epsilon.eps_sq);
+ BLI_assert(len_squared_v3v3(e_v1->co, t[2]->co) >= s->epsilon.eps_sq);
#endif
-#define KEY_SET(k, i0, i1, i2, i3) { \
- (k)[0] = i0; \
- (k)[1] = i1; \
- (k)[2] = i2; \
- (k)[3] = i3; \
-} (void)0
-
- /* order tri, then order (1-2, 2-3)*/
-#define KEY_EDGE_TRI_ORDER(k) { \
- if (k[2] > k[3]) { \
- SWAP(int, k[2], k[3]); \
- } \
- if (k[0] > k[2]) { \
- SWAP(int, k[0], k[2]); \
- SWAP(int, k[1], k[3]); \
- } \
-} (void)0
-
- KEY_SET(k_arr[IX_EDGE_TRI], BM_elem_index_get(e_v0), BM_elem_index_get(e_v1), t_index, -1);
- /* need to order here */
- KEY_SET(k_arr[IX_EDGE_TRI_EDGE0], BM_elem_index_get(e_v0), BM_elem_index_get(e_v1), ti[0], ti[1]);
- KEY_SET(k_arr[IX_EDGE_TRI_EDGE1], BM_elem_index_get(e_v0), BM_elem_index_get(e_v1), ti[1], ti[2]);
- KEY_SET(k_arr[IX_EDGE_TRI_EDGE2], BM_elem_index_get(e_v0), BM_elem_index_get(e_v1), ti[2], ti[0]);
-
- KEY_EDGE_TRI_ORDER(k_arr[IX_EDGE_TRI_EDGE0]);
- KEY_EDGE_TRI_ORDER(k_arr[IX_EDGE_TRI_EDGE1]);
- KEY_EDGE_TRI_ORDER(k_arr[IX_EDGE_TRI_EDGE2]);
+#define KEY_SET(k, i0, i1, i2, i3) \
+ { \
+ (k)[0] = i0; \
+ (k)[1] = i1; \
+ (k)[2] = i2; \
+ (k)[3] = i3; \
+ } \
+ (void)0
+
+ /* order tri, then order (1-2, 2-3)*/
+#define KEY_EDGE_TRI_ORDER(k) \
+ { \
+ if (k[2] > k[3]) { \
+ SWAP(int, k[2], k[3]); \
+ } \
+ if (k[0] > k[2]) { \
+ SWAP(int, k[0], k[2]); \
+ SWAP(int, k[1], k[3]); \
+ } \
+ } \
+ (void)0
+
+ KEY_SET(k_arr[IX_EDGE_TRI], BM_elem_index_get(e_v0), BM_elem_index_get(e_v1), t_index, -1);
+ /* need to order here */
+ KEY_SET(
+ k_arr[IX_EDGE_TRI_EDGE0], BM_elem_index_get(e_v0), BM_elem_index_get(e_v1), ti[0], ti[1]);
+ KEY_SET(
+ k_arr[IX_EDGE_TRI_EDGE1], BM_elem_index_get(e_v0), BM_elem_index_get(e_v1), ti[1], ti[2]);
+ KEY_SET(
+ k_arr[IX_EDGE_TRI_EDGE2], BM_elem_index_get(e_v0), BM_elem_index_get(e_v1), ti[2], ti[0]);
+
+ KEY_EDGE_TRI_ORDER(k_arr[IX_EDGE_TRI_EDGE0]);
+ KEY_EDGE_TRI_ORDER(k_arr[IX_EDGE_TRI_EDGE1]);
+ KEY_EDGE_TRI_ORDER(k_arr[IX_EDGE_TRI_EDGE2]);
#undef KEY_SET
#undef KEY_EDGE_TRI_ORDER
+ for (i = 0; i < ARRAY_SIZE(k_arr); i++) {
+ BMVert *iv;
+ iv = BLI_ghash_lookup(s->edgetri_cache, k_arr[i]);
- for (i = 0; i < ARRAY_SIZE(k_arr); i++) {
- BMVert *iv;
-
- iv = BLI_ghash_lookup(s->edgetri_cache, k_arr[i]);
-
- if (iv) {
+ if (iv) {
#ifdef USE_DUMP
- printf("# cache hit (%d, %d, %d, %d)\n", UNPACK4(k_arr[i]));
+ printf("# cache hit (%d, %d, %d, %d)\n", UNPACK4(k_arr[i]));
#endif
- *r_side = (enum ISectType)i;
- return iv;
- }
- }
-
- *r_side = intersect_line_tri(e_v0->co, e_v1->co, t_cos, t_nor, ix, &s->epsilon);
- if (*r_side != IX_NONE) {
- BMVert *iv;
- BMEdge *e;
+ *r_side = (enum ISectType)i;
+ return iv;
+ }
+ }
+
+ *r_side = intersect_line_tri(e_v0->co, e_v1->co, t_cos, t_nor, ix, &s->epsilon);
+ if (*r_side != IX_NONE) {
+ BMVert *iv;
+ BMEdge *e;
#ifdef USE_DUMP
- printf("# new vertex (%.6f, %.6f, %.6f) %d\n", UNPACK3(ix), *r_side);
+ printf("# new vertex (%.6f, %.6f, %.6f) %d\n", UNPACK3(ix), *r_side);
#endif
#ifdef USE_PARANOID
- BLI_assert(len_squared_v3v3(ix, e_v0->co) > s->epsilon.eps_sq);
- BLI_assert(len_squared_v3v3(ix, e_v1->co) > s->epsilon.eps_sq);
- BLI_assert(len_squared_v3v3(ix, t[0]->co) > s->epsilon.eps_sq);
- BLI_assert(len_squared_v3v3(ix, t[1]->co) > s->epsilon.eps_sq);
- BLI_assert(len_squared_v3v3(ix, t[2]->co) > s->epsilon.eps_sq);
+ BLI_assert(len_squared_v3v3(ix, e_v0->co) > s->epsilon.eps_sq);
+ BLI_assert(len_squared_v3v3(ix, e_v1->co) > s->epsilon.eps_sq);
+ BLI_assert(len_squared_v3v3(ix, t[0]->co) > s->epsilon.eps_sq);
+ BLI_assert(len_squared_v3v3(ix, t[1]->co) > s->epsilon.eps_sq);
+ BLI_assert(len_squared_v3v3(ix, t[2]->co) > s->epsilon.eps_sq);
#endif
- iv = BM_vert_create(bm, ix, NULL, 0);
+ iv = BM_vert_create(bm, ix, NULL, 0);
- e = BM_edge_exists(e_v0, e_v1);
- if (e) {
+ e = BM_edge_exists(e_v0, e_v1);
+ if (e) {
#ifdef USE_DUMP
- printf("# adding to edge %d\n", BM_elem_index_get(e));
+ printf("# adding to edge %d\n", BM_elem_index_get(e));
#endif
- edge_verts_add(s, e, iv, false);
- }
- else {
+ edge_verts_add(s, e, iv, false);
+ }
+ else {
#ifdef USE_DISSOLVE
- vert_dissolve_add(s, iv);
+ vert_dissolve_add(s, iv);
#endif
- }
+ }
- if ((*r_side >= IX_EDGE_TRI_EDGE0) && (*r_side <= IX_EDGE_TRI_EDGE2)) {
- i = (uint)(*r_side - IX_EDGE_TRI_EDGE0);
- e = BM_edge_exists(t[i], t[(i + 1) % 3]);
- if (e) {
- edge_verts_add(s, e, iv, false);
- }
- }
+ if ((*r_side >= IX_EDGE_TRI_EDGE0) && (*r_side <= IX_EDGE_TRI_EDGE2)) {
+ i = (uint)(*r_side - IX_EDGE_TRI_EDGE0);
+ e = BM_edge_exists(t[i], t[(i + 1) % 3]);
+ if (e) {
+ edge_verts_add(s, e, iv, false);
+ }
+ }
- {
- int *k = BLI_memarena_alloc(s->mem_arena, sizeof(int[4]));
- memcpy(k, k_arr[*r_side], sizeof(int[4]));
- BLI_ghash_insert(s->edgetri_cache, k, iv);
- }
+ {
+ int *k = BLI_memarena_alloc(s->mem_arena, sizeof(int[4]));
+ memcpy(k, k_arr[*r_side], sizeof(int[4]));
+ BLI_ghash_insert(s->edgetri_cache, k, iv);
+ }
- return iv;
+ return iv;
+ }
- }
+ *r_side = IX_NONE;
- *r_side = IX_NONE;
-
- return NULL;
+ return NULL;
}
struct LoopFilterWrap {
- int (*test_fn)(BMFace *f, void *user_data);
- void *user_data;
+ int (*test_fn)(BMFace *f, void *user_data);
+ void *user_data;
};
static bool bm_loop_filter_fn(const BMLoop *l, void *user_data)
{
- if (BM_elem_flag_test(l->e, BM_ELEM_TAG)) {
- return false;
- }
-
- if (l->radial_next != l) {
- struct LoopFilterWrap *data = user_data;
- BMLoop *l_iter = l->radial_next;
- const int face_side = data->test_fn(l->f, data->user_data);
- do {
- const int face_side_other = data->test_fn(l_iter->f, data->user_data);
- if (UNLIKELY(face_side_other == -1)) {
- /* pass */
- }
- else if (face_side_other != face_side) {
- return false;
- }
- } while ((l_iter = l_iter->radial_next) != l);
- return true;
- }
- return false;
+ if (BM_elem_flag_test(l->e, BM_ELEM_TAG)) {
+ return false;
+ }
+
+ if (l->radial_next != l) {
+ struct LoopFilterWrap *data = user_data;
+ BMLoop *l_iter = l->radial_next;
+ const int face_side = data->test_fn(l->f, data->user_data);
+ do {
+ const int face_side_other = data->test_fn(l_iter->f, data->user_data);
+ if (UNLIKELY(face_side_other == -1)) {
+ /* pass */
+ }
+ else if (face_side_other != face_side) {
+ return false;
+ }
+ } while ((l_iter = l_iter->radial_next) != l);
+ return true;
+ }
+ return false;
}
/**
* Return true if we have any intersections.
*/
static void bm_isect_tri_tri(
- struct ISectState *s,
- int a_index, int b_index,
- BMLoop **a, BMLoop **b)
+ struct ISectState *s, int a_index, int b_index, BMLoop **a, BMLoop **b)
{
- BMFace *f_a = (*a)->f;
- BMFace *f_b = (*b)->f;
- BMVert *fv_a[3] = {UNPACK3_EX(, a, ->v)};
- BMVert *fv_b[3] = {UNPACK3_EX(, b, ->v)};
- const float *f_a_cos[3] = {UNPACK3_EX(, fv_a, ->co)};
- const float *f_b_cos[3] = {UNPACK3_EX(, fv_b, ->co)};
- float f_a_nor[3];
- float f_b_nor[3];
- uint i;
-
-
- /* should be enough but may need to bump */
- BMVert *iv_ls_a[8];
- BMVert *iv_ls_b[8];
- STACK_DECLARE(iv_ls_a);
- STACK_DECLARE(iv_ls_b);
-
- if (UNLIKELY(ELEM(fv_a[0], UNPACK3(fv_b)) ||
- ELEM(fv_a[1], UNPACK3(fv_b)) ||
- ELEM(fv_a[2], UNPACK3(fv_b))))
- {
- return;
- }
-
- STACK_INIT(iv_ls_a, ARRAY_SIZE(iv_ls_a));
- STACK_INIT(iv_ls_b, ARRAY_SIZE(iv_ls_b));
+ BMFace *f_a = (*a)->f;
+ BMFace *f_b = (*b)->f;
+ BMVert *fv_a[3] = {UNPACK3_EX(, a, ->v)};
+ BMVert *fv_b[3] = {UNPACK3_EX(, b, ->v)};
+ const float *f_a_cos[3] = {UNPACK3_EX(, fv_a, ->co)};
+ const float *f_b_cos[3] = {UNPACK3_EX(, fv_b, ->co)};
+ float f_a_nor[3];
+ float f_b_nor[3];
+ uint i;
+
+ /* should be enough but may need to bump */
+ BMVert *iv_ls_a[8];
+ BMVert *iv_ls_b[8];
+ STACK_DECLARE(iv_ls_a);
+ STACK_DECLARE(iv_ls_b);
+
+ if (UNLIKELY(ELEM(fv_a[0], UNPACK3(fv_b)) || ELEM(fv_a[1], UNPACK3(fv_b)) ||
+ ELEM(fv_a[2], UNPACK3(fv_b)))) {
+ return;
+ }
+
+ STACK_INIT(iv_ls_a, ARRAY_SIZE(iv_ls_a));
+ STACK_INIT(iv_ls_b, ARRAY_SIZE(iv_ls_b));
#define VERT_VISIT_A _FLAG_WALK
#define VERT_VISIT_B _FLAG_WALK_ALT
#define STACK_PUSH_TEST_A(ele) \
- if (BM_ELEM_API_FLAG_TEST(ele, VERT_VISIT_A) == 0) { \
- BM_ELEM_API_FLAG_ENABLE(ele, VERT_VISIT_A); \
- STACK_PUSH(iv_ls_a, ele); \
- } ((void)0)
+ if (BM_ELEM_API_FLAG_TEST(ele, VERT_VISIT_A) == 0) { \
+ BM_ELEM_API_FLAG_ENABLE(ele, VERT_VISIT_A); \
+ STACK_PUSH(iv_ls_a, ele); \
+ } \
+ ((void)0)
#define STACK_PUSH_TEST_B(ele) \
- if (BM_ELEM_API_FLAG_TEST(ele, VERT_VISIT_B) == 0) { \
- BM_ELEM_API_FLAG_ENABLE(ele, VERT_VISIT_B); \
- STACK_PUSH(iv_ls_b, ele); \
- } ((void)0)
-
-
- /* vert-vert
- * --------- */
- {
- /* first check in any verts are touching
- * (any case where we wont create new verts)
- */
- uint i_a;
- for (i_a = 0; i_a < 3; i_a++) {
- uint i_b;
- for (i_b = 0; i_b < 3; i_b++) {
- if (len_squared_v3v3(fv_a[i_a]->co, fv_b[i_b]->co) <= s->epsilon.eps2x_sq) {
+ if (BM_ELEM_API_FLAG_TEST(ele, VERT_VISIT_B) == 0) { \
+ BM_ELEM_API_FLAG_ENABLE(ele, VERT_VISIT_B); \
+ STACK_PUSH(iv_ls_b, ele); \
+ } \
+ ((void)0)
+
+ /* vert-vert
+ * --------- */
+ {
+ /* first check in any verts are touching
+ * (any case where we wont create new verts)
+ */
+ uint i_a;
+ for (i_a = 0; i_a < 3; i_a++) {
+ uint i_b;
+ for (i_b = 0; i_b < 3; i_b++) {
+ if (len_squared_v3v3(fv_a[i_a]->co, fv_b[i_b]->co) <= s->epsilon.eps2x_sq) {
#ifdef USE_DUMP
- if (BM_ELEM_API_FLAG_TEST(fv_a[i_a], VERT_VISIT) == 0) {
- printf(" ('VERT-VERT-A') %d, %d),\n",
- i_a, BM_elem_index_get(fv_a[i_a]));
- }
- if (BM_ELEM_API_FLAG_TEST(fv_b[i_b], VERT_VISIT) == 0) {
- printf(" ('VERT-VERT-B') %d, %d),\n",
- i_b, BM_elem_index_get(fv_b[i_b]));
- }
+ if (BM_ELEM_API_FLAG_TEST(fv_a[i_a], VERT_VISIT) == 0) {
+ printf(" ('VERT-VERT-A') %d, %d),\n", i_a, BM_elem_index_get(fv_a[i_a]));
+ }
+ if (BM_ELEM_API_FLAG_TEST(fv_b[i_b], VERT_VISIT) == 0) {
+ printf(" ('VERT-VERT-B') %d, %d),\n", i_b, BM_elem_index_get(fv_b[i_b]));
+ }
#endif
- STACK_PUSH_TEST_A(fv_a[i_a]);
- STACK_PUSH_TEST_B(fv_b[i_b]);
- }
- }
- }
- }
-
- /* vert-edge
- * --------- */
- {
- uint i_a;
- for (i_a = 0; i_a < 3; i_a++) {
- if (BM_ELEM_API_FLAG_TEST(fv_a[i_a], VERT_VISIT_A) == 0) {
- uint i_b_e0;
- for (i_b_e0 = 0; i_b_e0 < 3; i_b_e0++) {
- uint i_b_e1 = (i_b_e0 + 1) % 3;
-
- if (BM_ELEM_API_FLAG_TEST(fv_b[i_b_e0], VERT_VISIT_B) ||
- BM_ELEM_API_FLAG_TEST(fv_b[i_b_e1], VERT_VISIT_B))
- {
- continue;
- }
-
- const float fac = line_point_factor_v3(fv_a[i_a]->co, fv_b[i_b_e0]->co, fv_b[i_b_e1]->co);
- if ((fac > 0.0f - s->epsilon.eps) && (fac < 1.0f + s->epsilon.eps)) {
- float ix[3];
- interp_v3_v3v3(ix, fv_b[i_b_e0]->co, fv_b[i_b_e1]->co, fac);
- if (len_squared_v3v3(ix, fv_a[i_a]->co) <= s->epsilon.eps2x_sq) {
- BMEdge *e;
- STACK_PUSH_TEST_B(fv_a[i_a]);
- // STACK_PUSH_TEST_A(fv_a[i_a]);
- e = BM_edge_exists(fv_b[i_b_e0], fv_b[i_b_e1]);
+ STACK_PUSH_TEST_A(fv_a[i_a]);
+ STACK_PUSH_TEST_B(fv_b[i_b]);
+ }
+ }
+ }
+ }
+
+ /* vert-edge
+ * --------- */
+ {
+ uint i_a;
+ for (i_a = 0; i_a < 3; i_a++) {
+ if (BM_ELEM_API_FLAG_TEST(fv_a[i_a], VERT_VISIT_A) == 0) {
+ uint i_b_e0;
+ for (i_b_e0 = 0; i_b_e0 < 3; i_b_e0++) {
+ uint i_b_e1 = (i_b_e0 + 1) % 3;
+
+ if (BM_ELEM_API_FLAG_TEST(fv_b[i_b_e0], VERT_VISIT_B) ||
+ BM_ELEM_API_FLAG_TEST(fv_b[i_b_e1], VERT_VISIT_B)) {
+ continue;
+ }
+
+ const float fac = line_point_factor_v3(
+ fv_a[i_a]->co, fv_b[i_b_e0]->co, fv_b[i_b_e1]->co);
+ if ((fac > 0.0f - s->epsilon.eps) && (fac < 1.0f + s->epsilon.eps)) {
+ float ix[3];
+ interp_v3_v3v3(ix, fv_b[i_b_e0]->co, fv_b[i_b_e1]->co, fac);
+ if (len_squared_v3v3(ix, fv_a[i_a]->co) <= s->epsilon.eps2x_sq) {
+ BMEdge *e;
+ STACK_PUSH_TEST_B(fv_a[i_a]);
+ // STACK_PUSH_TEST_A(fv_a[i_a]);
+ e = BM_edge_exists(fv_b[i_b_e0], fv_b[i_b_e1]);
#ifdef USE_DUMP
- printf(" ('VERT-EDGE-A', %d, %d),\n",
- BM_elem_index_get(fv_b[i_b_e0]), BM_elem_index_get(fv_b[i_b_e1]));
+ printf(" ('VERT-EDGE-A', %d, %d),\n",
+ BM_elem_index_get(fv_b[i_b_e0]),
+ BM_elem_index_get(fv_b[i_b_e1]));
#endif
- if (e) {
+ if (e) {
#ifdef USE_DUMP
- printf("# adding to edge %d\n", BM_elem_index_get(e));
+ printf("# adding to edge %d\n", BM_elem_index_get(e));
#endif
- edge_verts_add(s, e, fv_a[i_a], true);
- }
- break;
- }
- }
- }
- }
- }
- }
-
- {
- uint i_b;
- for (i_b = 0; i_b < 3; i_b++) {
- if (BM_ELEM_API_FLAG_TEST(fv_b[i_b], VERT_VISIT_B) == 0) {
- uint i_a_e0;
- for (i_a_e0 = 0; i_a_e0 < 3; i_a_e0++) {
- uint i_a_e1 = (i_a_e0 + 1) % 3;
-
- if (BM_ELEM_API_FLAG_TEST(fv_a[i_a_e0], VERT_VISIT_A) ||
- BM_ELEM_API_FLAG_TEST(fv_a[i_a_e1], VERT_VISIT_A))
- {
- continue;
- }
-
- const float fac = line_point_factor_v3(fv_b[i_b]->co, fv_a[i_a_e0]->co, fv_a[i_a_e1]->co);
- if ((fac > 0.0f - s->epsilon.eps) && (fac < 1.0f + s->epsilon.eps)) {
- float ix[3];
- interp_v3_v3v3(ix, fv_a[i_a_e0]->co, fv_a[i_a_e1]->co, fac);
- if (len_squared_v3v3(ix, fv_b[i_b]->co) <= s->epsilon.eps2x_sq) {
- BMEdge *e;
- STACK_PUSH_TEST_A(fv_b[i_b]);
- // STACK_PUSH_NOTEST(iv_ls_b, fv_b[i_b]);
- e = BM_edge_exists(fv_a[i_a_e0], fv_a[i_a_e1]);
+ edge_verts_add(s, e, fv_a[i_a], true);
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ {
+ uint i_b;
+ for (i_b = 0; i_b < 3; i_b++) {
+ if (BM_ELEM_API_FLAG_TEST(fv_b[i_b], VERT_VISIT_B) == 0) {
+ uint i_a_e0;
+ for (i_a_e0 = 0; i_a_e0 < 3; i_a_e0++) {
+ uint i_a_e1 = (i_a_e0 + 1) % 3;
+
+ if (BM_ELEM_API_FLAG_TEST(fv_a[i_a_e0], VERT_VISIT_A) ||
+ BM_ELEM_API_FLAG_TEST(fv_a[i_a_e1], VERT_VISIT_A)) {
+ continue;
+ }
+
+ const float fac = line_point_factor_v3(
+ fv_b[i_b]->co, fv_a[i_a_e0]->co, fv_a[i_a_e1]->co);
+ if ((fac > 0.0f - s->epsilon.eps) && (fac < 1.0f + s->epsilon.eps)) {
+ float ix[3];
+ interp_v3_v3v3(ix, fv_a[i_a_e0]->co, fv_a[i_a_e1]->co, fac);
+ if (len_squared_v3v3(ix, fv_b[i_b]->co) <= s->epsilon.eps2x_sq) {
+ BMEdge *e;
+ STACK_PUSH_TEST_A(fv_b[i_b]);
+ // STACK_PUSH_NOTEST(iv_ls_b, fv_b[i_b]);
+ e = BM_edge_exists(fv_a[i_a_e0], fv_a[i_a_e1]);
#ifdef USE_DUMP
- printf(" ('VERT-EDGE-B', %d, %d),\n",
- BM_elem_index_get(fv_a[i_a_e0]), BM_elem_index_get(fv_a[i_a_e1]));
+ printf(" ('VERT-EDGE-B', %d, %d),\n",
+ BM_elem_index_get(fv_a[i_a_e0]),
+ BM_elem_index_get(fv_a[i_a_e1]));
#endif
- if (e) {
+ if (e) {
#ifdef USE_DUMP
- printf("# adding to edge %d\n", BM_elem_index_get(e));
+ printf("# adding to edge %d\n", BM_elem_index_get(e));
#endif
- edge_verts_add(s, e, fv_b[i_b], true);
- }
- break;
- }
- }
- }
- }
- }
- }
-
- /* vert-tri
- * -------- */
- {
-
- float t_scale[3][3];
- uint i_a;
-
- copy_v3_v3(t_scale[0], fv_b[0]->co);
- copy_v3_v3(t_scale[1], fv_b[1]->co);
- copy_v3_v3(t_scale[2], fv_b[2]->co);
- tri_v3_scale(UNPACK3(t_scale), 1.0f - s->epsilon.eps2x);
-
- // second check for verts intersecting the triangle
- for (i_a = 0; i_a < 3; i_a++) {
- if (BM_ELEM_API_FLAG_TEST(fv_a[i_a], VERT_VISIT_A)) {
- continue;
- }
-
- float ix[3];
- if (isect_point_tri_v3(fv_a[i_a]->co, UNPACK3(t_scale), ix)) {
- if (len_squared_v3v3(ix, fv_a[i_a]->co) <= s->epsilon.eps2x_sq) {
- STACK_PUSH_TEST_A(fv_a[i_a]);
- STACK_PUSH_TEST_B(fv_a[i_a]);
+ edge_verts_add(s, e, fv_b[i_b], true);
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* vert-tri
+ * -------- */
+ {
+
+ float t_scale[3][3];
+ uint i_a;
+
+ copy_v3_v3(t_scale[0], fv_b[0]->co);
+ copy_v3_v3(t_scale[1], fv_b[1]->co);
+ copy_v3_v3(t_scale[2], fv_b[2]->co);
+ tri_v3_scale(UNPACK3(t_scale), 1.0f - s->epsilon.eps2x);
+
+ // second check for verts intersecting the triangle
+ for (i_a = 0; i_a < 3; i_a++) {
+ if (BM_ELEM_API_FLAG_TEST(fv_a[i_a], VERT_VISIT_A)) {
+ continue;
+ }
+
+ float ix[3];
+ if (isect_point_tri_v3(fv_a[i_a]->co, UNPACK3(t_scale), ix)) {
+ if (len_squared_v3v3(ix, fv_a[i_a]->co) <= s->epsilon.eps2x_sq) {
+ STACK_PUSH_TEST_A(fv_a[i_a]);
+ STACK_PUSH_TEST_B(fv_a[i_a]);
#ifdef USE_DUMP
- printf(" 'VERT TRI-A',\n");
+ printf(" 'VERT TRI-A',\n");
#endif
- }
- }
- }
- }
-
- {
- float t_scale[3][3];
- uint i_b;
-
- copy_v3_v3(t_scale[0], fv_a[0]->co);
- copy_v3_v3(t_scale[1], fv_a[1]->co);
- copy_v3_v3(t_scale[2], fv_a[2]->co);
- tri_v3_scale(UNPACK3(t_scale), 1.0f - s->epsilon.eps2x);
-
- for (i_b = 0; i_b < 3; i_b++) {
- if (BM_ELEM_API_FLAG_TEST(fv_b[i_b], VERT_VISIT_B)) {
- continue;
- }
-
- float ix[3];
- if (isect_point_tri_v3(fv_b[i_b]->co, UNPACK3(t_scale), ix)) {
- if (len_squared_v3v3(ix, fv_b[i_b]->co) <= s->epsilon.eps2x_sq) {
- STACK_PUSH_TEST_A(fv_b[i_b]);
- STACK_PUSH_TEST_B(fv_b[i_b]);
+ }
+ }
+ }
+ }
+
+ {
+ float t_scale[3][3];
+ uint i_b;
+
+ copy_v3_v3(t_scale[0], fv_a[0]->co);
+ copy_v3_v3(t_scale[1], fv_a[1]->co);
+ copy_v3_v3(t_scale[2], fv_a[2]->co);
+ tri_v3_scale(UNPACK3(t_scale), 1.0f - s->epsilon.eps2x);
+
+ for (i_b = 0; i_b < 3; i_b++) {
+ if (BM_ELEM_API_FLAG_TEST(fv_b[i_b], VERT_VISIT_B)) {
+ continue;
+ }
+
+ float ix[3];
+ if (isect_point_tri_v3(fv_b[i_b]->co, UNPACK3(t_scale), ix)) {
+ if (len_squared_v3v3(ix, fv_b[i_b]->co) <= s->epsilon.eps2x_sq) {
+ STACK_PUSH_TEST_A(fv_b[i_b]);
+ STACK_PUSH_TEST_B(fv_b[i_b]);
#ifdef USE_DUMP
- printf(" 'VERT TRI-B',\n");
+ printf(" 'VERT TRI-B',\n");
#endif
- }
- }
- }
- }
-
- if ((STACK_SIZE(iv_ls_a) >= 3) &&
- (STACK_SIZE(iv_ls_b) >= 3))
- {
+ }
+ }
+ }
+ }
+
+ if ((STACK_SIZE(iv_ls_a) >= 3) && (STACK_SIZE(iv_ls_b) >= 3)) {
#ifdef USE_DUMP
- printf("# OVERLAP\n");
+ printf("# OVERLAP\n");
#endif
- goto finally;
- }
-
- normal_tri_v3(f_a_nor, UNPACK3(f_a_cos));
- normal_tri_v3(f_b_nor, UNPACK3(f_b_cos));
-
- /* edge-tri & edge-edge
- * -------------------- */
- {
- for (uint i_a_e0 = 0; i_a_e0 < 3; i_a_e0++) {
- uint i_a_e1 = (i_a_e0 + 1) % 3;
- enum ISectType side;
- BMVert *iv;
-
- if (BM_ELEM_API_FLAG_TEST(fv_a[i_a_e0], VERT_VISIT_A) ||
- BM_ELEM_API_FLAG_TEST(fv_a[i_a_e1], VERT_VISIT_A))
- {
- continue;
- }
-
- iv = bm_isect_edge_tri(s, fv_a[i_a_e0], fv_a[i_a_e1], fv_b, b_index, f_b_cos, f_b_nor, &side);
- if (iv) {
- STACK_PUSH_TEST_A(iv);
- STACK_PUSH_TEST_B(iv);
+ goto finally;
+ }
+
+ normal_tri_v3(f_a_nor, UNPACK3(f_a_cos));
+ normal_tri_v3(f_b_nor, UNPACK3(f_b_cos));
+
+ /* edge-tri & edge-edge
+ * -------------------- */
+ {
+ for (uint i_a_e0 = 0; i_a_e0 < 3; i_a_e0++) {
+ uint i_a_e1 = (i_a_e0 + 1) % 3;
+ enum ISectType side;
+ BMVert *iv;
+
+ if (BM_ELEM_API_FLAG_TEST(fv_a[i_a_e0], VERT_VISIT_A) ||
+ BM_ELEM_API_FLAG_TEST(fv_a[i_a_e1], VERT_VISIT_A)) {
+ continue;
+ }
+
+ iv = bm_isect_edge_tri(
+ s, fv_a[i_a_e0], fv_a[i_a_e1], fv_b, b_index, f_b_cos, f_b_nor, &side);
+ if (iv) {
+ STACK_PUSH_TEST_A(iv);
+ STACK_PUSH_TEST_B(iv);
#ifdef USE_DUMP
- printf(" ('EDGE-TRI-A', %d),\n", side);
+ printf(" ('EDGE-TRI-A', %d),\n", side);
#endif
- }
- }
-
- for (uint i_b_e0 = 0; i_b_e0 < 3; i_b_e0++) {
- uint i_b_e1 = (i_b_e0 + 1) % 3;
- enum ISectType side;
- BMVert *iv;
-
- if (BM_ELEM_API_FLAG_TEST(fv_b[i_b_e0], VERT_VISIT_B) ||
- BM_ELEM_API_FLAG_TEST(fv_b[i_b_e1], VERT_VISIT_B))
- {
- continue;
- }
-
- iv = bm_isect_edge_tri(s, fv_b[i_b_e0], fv_b[i_b_e1], fv_a, a_index, f_a_cos, f_a_nor, &side);
- if (iv) {
- STACK_PUSH_TEST_A(iv);
- STACK_PUSH_TEST_B(iv);
+ }
+ }
+
+ for (uint i_b_e0 = 0; i_b_e0 < 3; i_b_e0++) {
+ uint i_b_e1 = (i_b_e0 + 1) % 3;
+ enum ISectType side;
+ BMVert *iv;
+
+ if (BM_ELEM_API_FLAG_TEST(fv_b[i_b_e0], VERT_VISIT_B) ||
+ BM_ELEM_API_FLAG_TEST(fv_b[i_b_e1], VERT_VISIT_B)) {
+ continue;
+ }
+
+ iv = bm_isect_edge_tri(
+ s, fv_b[i_b_e0], fv_b[i_b_e1], fv_a, a_index, f_a_cos, f_a_nor, &side);
+ if (iv) {
+ STACK_PUSH_TEST_A(iv);
+ STACK_PUSH_TEST_B(iv);
#ifdef USE_DUMP
- printf(" ('EDGE-TRI-B', %d),\n", side);
+ printf(" ('EDGE-TRI-B', %d),\n", side);
#endif
- }
- }
- }
-
- {
- for (i = 0; i < 2; i++) {
- BMVert **ie_vs;
- BMFace *f;
- bool ie_exists;
- BMEdge *ie;
-
- if (i == 0) {
- if (STACK_SIZE(iv_ls_a) != 2) {
- continue;
- }
- ie_vs = iv_ls_a;
- f = f_a;
- }
- else {
- if (STACK_SIZE(iv_ls_b) != 2) {
- continue;
- }
- ie_vs = iv_ls_b;
- f = f_b;
- }
-
- /* possible but unlikely we get this - for edge-edge intersection */
- ie = BM_edge_exists(UNPACK2(ie_vs));
- if (ie == NULL) {
- ie_exists = false;
- /* one of the verts must be new if we are making an edge
- * ...no, we need this in case 2x quads intersect at either ends.
- * if not (ie_vs[0].index == -1 or ie_vs[1].index == -1):
- * continue */
- ie = BM_edge_create(s->bm, UNPACK2(ie_vs), NULL, 0);
- BLI_gset_insert(s->wire_edges, ie);
- }
- else {
- ie_exists = true;
- /* may already exist */
- BLI_gset_add(s->wire_edges, ie);
-
- if (BM_edge_in_face(ie, f)) {
- continue;
- }
- }
-
- face_edges_add(s, BM_elem_index_get(f), ie, ie_exists);
- // BLI_assert(len(ie_vs) <= 2)
- }
- }
+ }
+ }
+ }
+
+ {
+ for (i = 0; i < 2; i++) {
+ BMVert **ie_vs;
+ BMFace *f;
+ bool ie_exists;
+ BMEdge *ie;
+
+ if (i == 0) {
+ if (STACK_SIZE(iv_ls_a) != 2) {
+ continue;
+ }
+ ie_vs = iv_ls_a;
+ f = f_a;
+ }
+ else {
+ if (STACK_SIZE(iv_ls_b) != 2) {
+ continue;
+ }
+ ie_vs = iv_ls_b;
+ f = f_b;
+ }
+
+ /* possible but unlikely we get this - for edge-edge intersection */
+ ie = BM_edge_exists(UNPACK2(ie_vs));
+ if (ie == NULL) {
+ ie_exists = false;
+ /* one of the verts must be new if we are making an edge
+ * ...no, we need this in case 2x quads intersect at either ends.
+ * if not (ie_vs[0].index == -1 or ie_vs[1].index == -1):
+ * continue */
+ ie = BM_edge_create(s->bm, UNPACK2(ie_vs), NULL, 0);
+ BLI_gset_insert(s->wire_edges, ie);
+ }
+ else {
+ ie_exists = true;
+ /* may already exist */
+ BLI_gset_add(s->wire_edges, ie);
+
+ if (BM_edge_in_face(ie, f)) {
+ continue;
+ }
+ }
+
+ face_edges_add(s, BM_elem_index_get(f), ie, ie_exists);
+ // BLI_assert(len(ie_vs) <= 2)
+ }
+ }
finally:
- for (i = 0; i < STACK_SIZE(iv_ls_a); i++) {
- BM_ELEM_API_FLAG_DISABLE(iv_ls_a[i], VERT_VISIT_A); \
- }
- for (i = 0; i < STACK_SIZE(iv_ls_b); i++) {
- BM_ELEM_API_FLAG_DISABLE(iv_ls_b[i], VERT_VISIT_B); \
- }
-
+ for (i = 0; i < STACK_SIZE(iv_ls_a); i++) {
+ BM_ELEM_API_FLAG_DISABLE(iv_ls_a[i], VERT_VISIT_A);
+ }
+ for (i = 0; i < STACK_SIZE(iv_ls_b); i++) {
+ BM_ELEM_API_FLAG_DISABLE(iv_ls_b[i], VERT_VISIT_B);
+ }
}
#ifdef USE_BVH
struct RaycastData {
- const float **looptris;
- BLI_Buffer *z_buffer;
+ const float **looptris;
+ BLI_Buffer *z_buffer;
};
-#ifdef USE_KDOPBVH_WATERTIGHT
+# ifdef USE_KDOPBVH_WATERTIGHT
static const struct IsectRayPrecalc isect_precalc_x = {1, 2, 0, 0, 0, 1};
-#endif
+# endif
static void raycast_callback(void *userdata,
int index,
const BVHTreeRay *ray,
BVHTreeRayHit *UNUSED(hit))
{
- struct RaycastData *raycast_data = userdata;
- const float **looptris = raycast_data->looptris;
- const float *v0 = looptris[index * 3 + 0];
- const float *v1 = looptris[index * 3 + 1];
- const float *v2 = looptris[index * 3 + 2];
- float dist;
-
- if (
-#ifdef USE_KDOPBVH_WATERTIGHT
- isect_ray_tri_watertight_v3(ray->origin, &isect_precalc_x, v0, v1, v2, &dist, NULL)
-#else
- isect_ray_tri_epsilon_v3(ray->origin, ray->direction, v0, v1, v2, &dist, NULL, FLT_EPSILON)
-#endif
- )
- {
- if (dist >= 0.0f) {
-#ifdef USE_DUMP
- printf("%s:\n", __func__);
- print_v3(" origin", ray->origin);
- print_v3(" direction", ray->direction);
- printf(" dist %f\n", dist);
- print_v3(" v0", v0);
- print_v3(" v1", v1);
- print_v3(" v2", v2);
-#endif
-
-#ifdef USE_DUMP
- printf("%s: Adding depth %f\n", __func__, dist);
-#endif
- BLI_buffer_append(raycast_data->z_buffer, float, dist);
- }
- }
+ struct RaycastData *raycast_data = userdata;
+ const float **looptris = raycast_data->looptris;
+ const float *v0 = looptris[index * 3 + 0];
+ const float *v1 = looptris[index * 3 + 1];
+ const float *v2 = looptris[index * 3 + 2];
+ float dist;
+
+ if (
+# ifdef USE_KDOPBVH_WATERTIGHT
+ isect_ray_tri_watertight_v3(ray->origin, &isect_precalc_x, v0, v1, v2, &dist, NULL)
+# else
+ isect_ray_tri_epsilon_v3(ray->origin, ray->direction, v0, v1, v2, &dist, NULL, FLT_EPSILON)
+# endif
+ ) {
+ if (dist >= 0.0f) {
+# ifdef USE_DUMP
+ printf("%s:\n", __func__);
+ print_v3(" origin", ray->origin);
+ print_v3(" direction", ray->direction);
+ printf(" dist %f\n", dist);
+ print_v3(" v0", v0);
+ print_v3(" v1", v1);
+ print_v3(" v2", v2);
+# endif
+
+# ifdef USE_DUMP
+ printf("%s: Adding depth %f\n", __func__, dist);
+# endif
+ BLI_buffer_append(raycast_data->z_buffer, float, dist);
+ }
+ }
}
-static int isect_bvhtree_point_v3(
- BVHTree *tree,
- const float **looptris,
- const float co[3])
+static int isect_bvhtree_point_v3(BVHTree *tree, const float **looptris, const float co[3])
{
- BLI_buffer_declare_static(float, z_buffer, BLI_BUFFER_NOP, 64);
-
- struct RaycastData raycast_data = {
- looptris,
- &z_buffer,
- };
- BVHTreeRayHit hit = {0};
- float dir[3] = {1.0f, 0.0f, 0.0f};
-
- /* Need to initialize hit even tho it's not used.
- * This is to make it so kdotree believes we didn't intersect anything and
- * keeps calling the intersect callback.
- */
- hit.index = -1;
- hit.dist = BVH_RAYCAST_DIST_MAX;
-
- BLI_bvhtree_ray_cast(tree,
- co, dir,
- 0.0f,
- &hit,
- raycast_callback,
- &raycast_data);
-
-#ifdef USE_DUMP
- printf("%s: Total intersections: %d\n", __func__, z_buffer.count);
-#endif
-
- int num_isect;
-
- if (z_buffer.count == 0) {
- num_isect = 0;
- }
- else if (z_buffer.count == 1) {
- num_isect = 1;
- }
- else {
- /* 2 or more */
- const float eps = FLT_EPSILON * 10;
- num_isect = 1; /* always count first */
-
- qsort(z_buffer.data, z_buffer.count, sizeof(float), BLI_sortutil_cmp_float);
-
- const float *depth_arr = z_buffer.data;
- float depth_last = depth_arr[0];
-
- for (uint i = 1; i < z_buffer.count; i++) {
- if (depth_arr[i] - depth_last > eps) {
- depth_last = depth_arr[i];
- num_isect++;
- }
- }
-
- BLI_buffer_free(&z_buffer);
- }
-
-
- // return (num_isect & 1) == 1;
- return num_isect;
+ BLI_buffer_declare_static(float, z_buffer, BLI_BUFFER_NOP, 64);
+
+ struct RaycastData raycast_data = {
+ looptris,
+ &z_buffer,
+ };
+ BVHTreeRayHit hit = {0};
+ float dir[3] = {1.0f, 0.0f, 0.0f};
+
+ /* Need to initialize hit even tho it's not used.
+ * This is to make it so kdotree believes we didn't intersect anything and
+ * keeps calling the intersect callback.
+ */
+ hit.index = -1;
+ hit.dist = BVH_RAYCAST_DIST_MAX;
+
+ BLI_bvhtree_ray_cast(tree, co, dir, 0.0f, &hit, raycast_callback, &raycast_data);
+
+# ifdef USE_DUMP
+ printf("%s: Total intersections: %d\n", __func__, z_buffer.count);
+# endif
+
+ int num_isect;
+
+ if (z_buffer.count == 0) {
+ num_isect = 0;
+ }
+ else if (z_buffer.count == 1) {
+ num_isect = 1;
+ }
+ else {
+ /* 2 or more */
+ const float eps = FLT_EPSILON * 10;
+ num_isect = 1; /* always count first */
+
+ qsort(z_buffer.data, z_buffer.count, sizeof(float), BLI_sortutil_cmp_float);
+
+ const float *depth_arr = z_buffer.data;
+ float depth_last = depth_arr[0];
+
+ for (uint i = 1; i < z_buffer.count; i++) {
+ if (depth_arr[i] - depth_last > eps) {
+ depth_last = depth_arr[i];
+ num_isect++;
+ }
+ }
+
+ BLI_buffer_free(&z_buffer);
+ }
+
+ // return (num_isect & 1) == 1;
+ return num_isect;
}
-#endif /* USE_BVH */
+#endif /* USE_BVH */
/**
* Intersect tessellated faces
@@ -972,710 +950,690 @@ static int isect_bvhtree_point_v3(
* \param boolean_mode: -1: no-boolean, 0: intersection... see #BMESH_ISECT_BOOLEAN_ISECT.
* \return true if the mesh is changed (intersections cut or faces removed from boolean).
*/
-bool BM_mesh_intersect(
- BMesh *bm,
- struct BMLoop *(*looptris)[3], const int looptris_tot,
- int (*test_fn)(BMFace *f, void *user_data), void *user_data,
- const bool use_self, const bool use_separate, const bool use_dissolve, const bool use_island_connect,
- const bool use_partial_connect, const bool use_edge_tag, const int boolean_mode,
- const float eps)
+bool BM_mesh_intersect(BMesh *bm,
+ struct BMLoop *(*looptris)[3],
+ const int looptris_tot,
+ int (*test_fn)(BMFace *f, void *user_data),
+ void *user_data,
+ const bool use_self,
+ const bool use_separate,
+ const bool use_dissolve,
+ const bool use_island_connect,
+ const bool use_partial_connect,
+ const bool use_edge_tag,
+ const int boolean_mode,
+ const float eps)
{
- struct ISectState s;
- const int totface_orig = bm->totface;
+ struct ISectState s;
+ const int totface_orig = bm->totface;
- /* use to check if we made any changes */
- bool has_edit_isect = false, has_edit_boolean = false;
+ /* use to check if we made any changes */
+ bool has_edit_isect = false, has_edit_boolean = false;
- /* needed for boolean, since cutting up faces moves the loops within the face */
- const float **looptri_coords = NULL;
+ /* needed for boolean, since cutting up faces moves the loops within the face */
+ const float **looptri_coords = NULL;
#ifdef USE_BVH
- BVHTree *tree_a, *tree_b;
- uint tree_overlap_tot;
- BVHTreeOverlap *overlap;
+ BVHTree *tree_a, *tree_b;
+ uint tree_overlap_tot;
+ BVHTreeOverlap *overlap;
#else
- int i_a, i_b;
+ int i_a, i_b;
#endif
- s.bm = bm;
+ s.bm = bm;
- s.edgetri_cache = BLI_ghash_new(BLI_ghashutil_inthash_v4_p, BLI_ghashutil_inthash_v4_cmp, __func__);
+ s.edgetri_cache = BLI_ghash_new(
+ BLI_ghashutil_inthash_v4_p, BLI_ghashutil_inthash_v4_cmp, __func__);
- s.edge_verts = BLI_ghash_ptr_new(__func__);
- s.face_edges = BLI_ghash_int_new(__func__);
- s.wire_edges = BLI_gset_ptr_new(__func__);
- s.vert_dissolve = NULL;
+ s.edge_verts = BLI_ghash_ptr_new(__func__);
+ s.face_edges = BLI_ghash_int_new(__func__);
+ s.wire_edges = BLI_gset_ptr_new(__func__);
+ s.vert_dissolve = NULL;
- s.mem_arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
+ s.mem_arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
- /* setup epsilon from base */
- s.epsilon.eps = eps;
- s.epsilon.eps2x = eps * 2.0f;
- s.epsilon.eps_margin = s.epsilon.eps2x * 10.0f;
+ /* setup epsilon from base */
+ s.epsilon.eps = eps;
+ s.epsilon.eps2x = eps * 2.0f;
+ s.epsilon.eps_margin = s.epsilon.eps2x * 10.0f;
- s.epsilon.eps_sq = s.epsilon.eps * s.epsilon.eps;
- s.epsilon.eps2x_sq = s.epsilon.eps2x * s.epsilon.eps2x;
- s.epsilon.eps_margin_sq = s.epsilon.eps_margin * s.epsilon.eps_margin;
+ s.epsilon.eps_sq = s.epsilon.eps * s.epsilon.eps;
+ s.epsilon.eps2x_sq = s.epsilon.eps2x * s.epsilon.eps2x;
+ s.epsilon.eps_margin_sq = s.epsilon.eps_margin * s.epsilon.eps_margin;
- BM_mesh_elem_index_ensure(
- bm,
- BM_VERT |
- BM_EDGE |
+ BM_mesh_elem_index_ensure(bm,
+ BM_VERT | BM_EDGE |
#ifdef USE_NET
- BM_FACE |
+ BM_FACE |
#endif
- 0);
-
+ 0);
- BM_mesh_elem_table_ensure(
- bm,
+ BM_mesh_elem_table_ensure(bm,
#ifdef USE_SPLICE
- BM_EDGE |
+ BM_EDGE |
#endif
#ifdef USE_NET
- BM_FACE |
+ BM_FACE |
#endif
- 0);
+ 0);
#ifdef USE_DISSOLVE
- if (use_dissolve) {
- BM_mesh_elem_hflag_disable_all(bm, BM_EDGE | BM_VERT, BM_ELEM_TAG, false);
- }
+ if (use_dissolve) {
+ BM_mesh_elem_hflag_disable_all(bm, BM_EDGE | BM_VERT, BM_ELEM_TAG, false);
+ }
#else
- UNUSED_VARS(use_dissolve);
+ UNUSED_VARS(use_dissolve);
#endif
#ifdef USE_DUMP
- printf("data = [\n");
+ printf("data = [\n");
#endif
- if (boolean_mode != BMESH_ISECT_BOOLEAN_NONE) {
- /* keep original geometrty for raycast callbacks */
- float **cos;
- int i, j;
+ if (boolean_mode != BMESH_ISECT_BOOLEAN_NONE) {
+ /* keep original geometrty for raycast callbacks */
+ float **cos;
+ int i, j;
- cos = MEM_mallocN((size_t)looptris_tot * sizeof(*looptri_coords) * 3, __func__);
- for (i = 0, j = 0; i < looptris_tot; i++) {
- cos[j++] = looptris[i][0]->v->co;
- cos[j++] = looptris[i][1]->v->co;
- cos[j++] = looptris[i][2]->v->co;
- }
- looptri_coords = (const float **)cos;
- }
+ cos = MEM_mallocN((size_t)looptris_tot * sizeof(*looptri_coords) * 3, __func__);
+ for (i = 0, j = 0; i < looptris_tot; i++) {
+ cos[j++] = looptris[i][0]->v->co;
+ cos[j++] = looptris[i][1]->v->co;
+ cos[j++] = looptris[i][2]->v->co;
+ }
+ looptri_coords = (const float **)cos;
+ }
#ifdef USE_BVH
- {
- int i;
- tree_a = BLI_bvhtree_new(looptris_tot, s.epsilon.eps_margin, 8, 8);
- for (i = 0; i < looptris_tot; i++) {
- if (test_fn(looptris[i][0]->f, user_data) == 0) {
- const float t_cos[3][3] = {
- {UNPACK3(looptris[i][0]->v->co)},
- {UNPACK3(looptris[i][1]->v->co)},
- {UNPACK3(looptris[i][2]->v->co)},
- };
-
- BLI_bvhtree_insert(tree_a, i, (const float *)t_cos, 3);
- }
- }
- BLI_bvhtree_balance(tree_a);
- }
-
- if (use_self == false) {
- int i;
- tree_b = BLI_bvhtree_new(looptris_tot, s.epsilon.eps_margin, 8, 8);
- for (i = 0; i < looptris_tot; i++) {
- if (test_fn(looptris[i][0]->f, user_data) == 1) {
- const float t_cos[3][3] = {
- {UNPACK3(looptris[i][0]->v->co)},
- {UNPACK3(looptris[i][1]->v->co)},
- {UNPACK3(looptris[i][2]->v->co)},
- };
-
- BLI_bvhtree_insert(tree_b, i, (const float *)t_cos, 3);
- }
- }
- BLI_bvhtree_balance(tree_b);
- }
- else {
- tree_b = tree_a;
- }
-
- overlap = BLI_bvhtree_overlap(tree_b, tree_a, &tree_overlap_tot, NULL, NULL);
-
- if (overlap) {
- uint i;
-
- for (i = 0; i < tree_overlap_tot; i++) {
-#ifdef USE_DUMP
- printf(" ((%d, %d), (\n",
- overlap[i].indexA,
- overlap[i].indexB);
-#endif
- bm_isect_tri_tri(
- &s,
- overlap[i].indexA,
- overlap[i].indexB,
- looptris[overlap[i].indexA],
- looptris[overlap[i].indexB]);
-#ifdef USE_DUMP
- printf(")),\n");
-#endif
- }
- MEM_freeN(overlap);
- }
-
- if (boolean_mode == BMESH_ISECT_BOOLEAN_NONE) {
- /* no booleans, just free immediate */
- BLI_bvhtree_free(tree_a);
- if (tree_a != tree_b) {
- BLI_bvhtree_free(tree_b);
- }
- }
+ {
+ int i;
+ tree_a = BLI_bvhtree_new(looptris_tot, s.epsilon.eps_margin, 8, 8);
+ for (i = 0; i < looptris_tot; i++) {
+ if (test_fn(looptris[i][0]->f, user_data) == 0) {
+ const float t_cos[3][3] = {
+ {UNPACK3(looptris[i][0]->v->co)},
+ {UNPACK3(looptris[i][1]->v->co)},
+ {UNPACK3(looptris[i][2]->v->co)},
+ };
+
+ BLI_bvhtree_insert(tree_a, i, (const float *)t_cos, 3);
+ }
+ }
+ BLI_bvhtree_balance(tree_a);
+ }
+
+ if (use_self == false) {
+ int i;
+ tree_b = BLI_bvhtree_new(looptris_tot, s.epsilon.eps_margin, 8, 8);
+ for (i = 0; i < looptris_tot; i++) {
+ if (test_fn(looptris[i][0]->f, user_data) == 1) {
+ const float t_cos[3][3] = {
+ {UNPACK3(looptris[i][0]->v->co)},
+ {UNPACK3(looptris[i][1]->v->co)},
+ {UNPACK3(looptris[i][2]->v->co)},
+ };
+
+ BLI_bvhtree_insert(tree_b, i, (const float *)t_cos, 3);
+ }
+ }
+ BLI_bvhtree_balance(tree_b);
+ }
+ else {
+ tree_b = tree_a;
+ }
+
+ overlap = BLI_bvhtree_overlap(tree_b, tree_a, &tree_overlap_tot, NULL, NULL);
+
+ if (overlap) {
+ uint i;
+
+ for (i = 0; i < tree_overlap_tot; i++) {
+# ifdef USE_DUMP
+ printf(" ((%d, %d), (\n", overlap[i].indexA, overlap[i].indexB);
+# endif
+ bm_isect_tri_tri(&s,
+ overlap[i].indexA,
+ overlap[i].indexB,
+ looptris[overlap[i].indexA],
+ looptris[overlap[i].indexB]);
+# ifdef USE_DUMP
+ printf(")),\n");
+# endif
+ }
+ MEM_freeN(overlap);
+ }
+
+ if (boolean_mode == BMESH_ISECT_BOOLEAN_NONE) {
+ /* no booleans, just free immediate */
+ BLI_bvhtree_free(tree_a);
+ if (tree_a != tree_b) {
+ BLI_bvhtree_free(tree_b);
+ }
+ }
#else
- {
- for (i_a = 0; i_a < looptris_tot; i_a++) {
- const int t_a = test_fn(looptris[i_a][0]->f, user_data);
- for (i_b = i_a + 1; i_b < looptris_tot; i_b++) {
- const int t_b = test_fn(looptris[i_b][0]->f, user_data);
-
- if (use_self) {
- if ((t_a != 0) || (t_b != 0)) {
- continue;
- }
- }
- else {
- if ((t_a != t_b) && !ELEM(-1, t_a, t_b)) {
- continue;
- }
- }
-
-#ifdef USE_DUMP
- printf(" ((%d, %d), (",
- i_a, i_b);
-#endif
- bm_isect_tri_tri(
- &s,
- i_a,
- i_b,
- looptris[i_a],
- looptris[i_b]);
-#ifdef USE_DUMP
- printf(")),\n");
-#endif
- }
- }
- }
-#endif /* USE_BVH */
+ {
+ for (i_a = 0; i_a < looptris_tot; i_a++) {
+ const int t_a = test_fn(looptris[i_a][0]->f, user_data);
+ for (i_b = i_a + 1; i_b < looptris_tot; i_b++) {
+ const int t_b = test_fn(looptris[i_b][0]->f, user_data);
+
+ if (use_self) {
+ if ((t_a != 0) || (t_b != 0)) {
+ continue;
+ }
+ }
+ else {
+ if ((t_a != t_b) && !ELEM(-1, t_a, t_b)) {
+ continue;
+ }
+ }
+
+# ifdef USE_DUMP
+ printf(" ((%d, %d), (", i_a, i_b);
+# endif
+ bm_isect_tri_tri(&s, i_a, i_b, looptris[i_a], looptris[i_b]);
+# ifdef USE_DUMP
+ printf(")),\n");
+# endif
+ }
+ }
+ }
+#endif /* USE_BVH */
#ifdef USE_DUMP
- printf("]\n");
+ printf("]\n");
#endif
- /* --------- */
+ /* --------- */
#ifdef USE_SPLICE
- {
- GHashIterator gh_iter;
-
- GHASH_ITER (gh_iter, s.edge_verts) {
- BMEdge *e = BLI_ghashIterator_getKey(&gh_iter);
- struct LinkBase *v_ls_base = BLI_ghashIterator_getValue(&gh_iter);
-
- BMVert *v_start;
- BMVert *v_end;
- BMVert *v_prev;
- bool is_wire;
-
- LinkNode *node;
-
- /* direction is arbitrary, could be swapped */
- v_start = e->v1;
- v_end = e->v2;
-
- if (v_ls_base->list_len > 1) {
- edge_verts_sort(v_start->co, v_ls_base);
- }
-
-#ifdef USE_DUMP
- printf("# SPLITTING EDGE: %d, %d\n", BM_elem_index_get(e), v_ls_base->list_len);
+ {
+ GHashIterator gh_iter;
+
+ GHASH_ITER (gh_iter, s.edge_verts) {
+ BMEdge *e = BLI_ghashIterator_getKey(&gh_iter);
+ struct LinkBase *v_ls_base = BLI_ghashIterator_getValue(&gh_iter);
+
+ BMVert *v_start;
+ BMVert *v_end;
+ BMVert *v_prev;
+ bool is_wire;
+
+ LinkNode *node;
+
+ /* direction is arbitrary, could be swapped */
+ v_start = e->v1;
+ v_end = e->v2;
+
+ if (v_ls_base->list_len > 1) {
+ edge_verts_sort(v_start->co, v_ls_base);
+ }
+
+# ifdef USE_DUMP
+ printf("# SPLITTING EDGE: %d, %d\n", BM_elem_index_get(e), v_ls_base->list_len);
+# endif
+ /* intersect */
+ is_wire = BLI_gset_haskey(s.wire_edges, e);
+
+# ifdef USE_PARANOID
+ for (node = v_ls_base->list; node; node = node->next) {
+ BMVert *_v = node->link;
+ BLI_assert(len_squared_v3v3(_v->co, e->v1->co) > s.epsilon.eps_sq);
+ BLI_assert(len_squared_v3v3(_v->co, e->v2->co) > s.epsilon.eps_sq);
+ }
+# endif
+
+ v_prev = v_start;
+
+ for (node = v_ls_base->list; node; node = node->next) {
+ BMVert *vi = node->link;
+ const float fac = line_point_factor_v3(vi->co, e->v1->co, e->v2->co);
+
+ if (BM_vert_in_edge(e, v_prev)) {
+ BMEdge *e_split;
+ v_prev = BM_edge_split(bm, e, v_prev, &e_split, clamp_f(fac, 0.0f, 1.0f));
+ BLI_assert(BM_vert_in_edge(e, v_end));
+
+ if (!BM_edge_exists(v_prev, vi) && !BM_vert_splice_check_double(v_prev, vi) &&
+ !BM_vert_pair_share_face_check(v_prev, vi)) {
+ BM_vert_splice(bm, vi, v_prev);
+ }
+ else {
+ copy_v3_v3(v_prev->co, vi->co);
+ }
+ v_prev = vi;
+ if (is_wire) {
+ BLI_gset_insert(s.wire_edges, e_split);
+ }
+ }
+ }
+ UNUSED_VARS_NDEBUG(v_end);
+ }
+ }
#endif
- /* intersect */
- is_wire = BLI_gset_haskey(s.wire_edges, e);
-#ifdef USE_PARANOID
- for (node = v_ls_base->list; node; node = node->next) {
- BMVert *_v = node->link;
- BLI_assert(len_squared_v3v3(_v->co, e->v1->co) > s.epsilon.eps_sq);
- BLI_assert(len_squared_v3v3(_v->co, e->v2->co) > s.epsilon.eps_sq);
- }
-#endif
+ /* important to handle before edgenet */
+#ifdef USE_DISSOLVE
+ if (use_dissolve && (boolean_mode == BMESH_ISECT_BOOLEAN_NONE)) {
+ /* first pass */
+ BMVert *(*splice_ls)[2];
+ STACK_DECLARE(splice_ls);
+ LinkNode *node;
+
+ for (node = s.vert_dissolve; node; node = node->next) {
+ BMVert *v = node->link;
+ if (BM_elem_flag_test(v, BM_ELEM_TAG)) {
+ if (!BM_vert_is_edge_pair(v)) {
+ BM_elem_flag_disable(v, BM_ELEM_TAG);
+ }
+ }
+ }
+
+ splice_ls = MEM_mallocN(BLI_gset_len(s.wire_edges) * sizeof(*splice_ls), __func__);
+ STACK_INIT(splice_ls, BLI_gset_len(s.wire_edges));
+
+ for (node = s.vert_dissolve; node; node = node->next) {
+ BMEdge *e_pair[2];
+ BMVert *v = node->link;
+ BMVert *v_a, *v_b;
+
+ if (!BM_elem_flag_test(v, BM_ELEM_TAG)) {
+ continue;
+ }
+
+ /* get chain */
+ e_pair[0] = v->e;
+ e_pair[1] = BM_DISK_EDGE_NEXT(v->e, v);
+
+ if (BM_elem_flag_test(e_pair[0], BM_ELEM_TAG) || BM_elem_flag_test(e_pair[1], BM_ELEM_TAG)) {
+ continue;
+ }
+
+ v_a = BM_edge_other_vert(e_pair[0], v);
+ v_b = BM_edge_other_vert(e_pair[1], v);
+
+ /* simple case */
+ if (BM_elem_flag_test(v_a, BM_ELEM_TAG) && BM_elem_flag_test(v_b, BM_ELEM_TAG)) {
+ /* only start on an edge-case */
+ /* pass */
+ }
+ else if ((!BM_elem_flag_test(v_a, BM_ELEM_TAG)) && (!BM_elem_flag_test(v_b, BM_ELEM_TAG))) {
+ /* simple case, single edge spans face */
+ BMVert **splice_pair;
+ BM_elem_flag_enable(e_pair[1], BM_ELEM_TAG);
+ splice_pair = STACK_PUSH_RET(splice_ls);
+ splice_pair[0] = v;
+ splice_pair[1] = v_b;
+# ifdef USE_DUMP
+ printf("# Simple Case!\n");
+# endif
+ }
+ else {
+# ifdef USE_PARANOID
+ BMEdge *e_keep;
+# endif
+ BMEdge *e;
+ BMEdge *e_step;
+ BMVert *v_step;
+
+ /* walk the chain! */
+ if (BM_elem_flag_test(v_a, BM_ELEM_TAG)) {
+ e = e_pair[0];
+# ifdef USE_PARANOID
+ e_keep = e_pair[1];
+# endif
+ }
+ else {
+ SWAP(BMVert *, v_a, v_b);
+ e = e_pair[1];
+# ifdef USE_PARANOID
+ e_keep = e_pair[0];
+# endif
+ }
+
+ /* WALK */
+ v_step = v;
+ e_step = e;
+
+ while (true) {
+ BMEdge *e_next;
+ BMVert *v_next;
+
+ v_next = BM_edge_other_vert(e_step, v_step);
+ BM_elem_flag_enable(e_step, BM_ELEM_TAG);
+ if (!BM_elem_flag_test(v_next, BM_ELEM_TAG)) {
+ BMVert **splice_pair;
+# ifdef USE_PARANOID
+ BLI_assert(e_step != e_keep);
+# endif
+ splice_pair = STACK_PUSH_RET(splice_ls);
+ splice_pair[0] = v;
+ splice_pair[1] = v_next;
+ break;
+ }
+ else {
+ e_next = bm_vert_other_edge(v_next, e_step);
+ }
+
+ e_step = e_next;
+ v_step = v_next;
+ BM_elem_flag_enable(e_step, BM_ELEM_TAG);
+# ifdef USE_PARANOID
+ BLI_assert(e_step != e_keep);
+# endif
+# ifdef USE_DUMP
+ printf("# walk step %p %p\n", e_next, v_next);
+# endif
+ }
+# ifdef USE_PARANOID
+ BLI_assert(BM_elem_flag_test(e_keep, BM_ELEM_TAG) == 0);
+# endif
+ }
+ }
+
+ /* Remove edges! */
+ {
+ GHashIterator gh_iter;
+
+ GHASH_ITER (gh_iter, s.face_edges) {
+ struct LinkBase *e_ls_base = BLI_ghashIterator_getValue(&gh_iter);
+ LinkNode **node_prev_p;
+ uint i;
+
+ node_prev_p = &e_ls_base->list;
+ for (i = 0, node = e_ls_base->list; node; i++, node = node->next) {
+ BMEdge *e = node->link;
+ if (BM_elem_flag_test(e, BM_ELEM_TAG)) {
+ /* allocated by arena, don't free */
+ *node_prev_p = node->next;
+ e_ls_base->list_len--;
+ }
+ else {
+ node_prev_p = &node->next;
+ }
+ }
+ }
+ }
+
+ {
+ BMIter eiter;
+ BMEdge *e, *e_next;
+
+ BM_ITER_MESH_MUTABLE (e, e_next, &eiter, bm, BM_EDGES_OF_MESH) {
+ if (BM_elem_flag_test(e, BM_ELEM_TAG)) {
+
+ /* in rare and annoying cases,
+ * there can be faces from 's.face_edges' removed by the edges.
+ * These are degenerate cases, so just make sure we don't reference the faces again. */
+ if (e->l) {
+ BMLoop *l_iter = e->l;
+ BMFace **faces;
+
+ faces = bm->ftable;
+
+ do {
+ const int f_index = BM_elem_index_get(l_iter->f);
+ if (f_index >= 0) {
+ BLI_assert(f_index < totface_orig);
+ /* we could check if these are in: 's.face_edges', but easier just to remove */
+ faces[f_index] = NULL;
+ }
+ } while ((l_iter = l_iter->radial_next) != e->l);
+ }
+
+ BLI_gset_remove(s.wire_edges, e, NULL);
+ BM_edge_kill(bm, e);
+ }
+ }
+ }
+
+ /* Remove verts! */
+ {
+ GSet *verts_invalid = BLI_gset_ptr_new(__func__);
+
+ for (node = s.vert_dissolve; node; node = node->next) {
+ /* arena allocated, don't free */
+ BMVert *v = node->link;
+ if (BM_elem_flag_test(v, BM_ELEM_TAG)) {
+ if (!v->e) {
+ BLI_gset_add(verts_invalid, v);
+ BM_vert_kill(bm, v);
+ }
+ }
+ }
+
+ {
+ uint i;
+ for (i = 0; i < STACK_SIZE(splice_ls); i++) {
+ if (!BLI_gset_haskey(verts_invalid, splice_ls[i][0]) &&
+ !BLI_gset_haskey(verts_invalid, splice_ls[i][1])) {
+ if (!BM_edge_exists(UNPACK2(splice_ls[i])) &&
+ !BM_vert_splice_check_double(UNPACK2(splice_ls[i]))) {
+ BM_vert_splice(bm, splice_ls[i][1], splice_ls[i][0]);
+ }
+ }
+ }
+ }
+
+ BLI_gset_free(verts_invalid, NULL);
+ }
+
+ MEM_freeN(splice_ls);
+ }
+#endif /* USE_DISSOLVE */
+
+ /* now split faces */
+#ifdef USE_NET
+ {
+ GHashIterator gh_iter;
+ BMFace **faces;
- v_prev = v_start;
-
- for (node = v_ls_base->list; node; node = node->next) {
- BMVert *vi = node->link;
- const float fac = line_point_factor_v3(vi->co, e->v1->co, e->v2->co);
-
- if (BM_vert_in_edge(e, v_prev)) {
- BMEdge *e_split;
- v_prev = BM_edge_split(bm, e, v_prev, &e_split, clamp_f(fac, 0.0f, 1.0f));
- BLI_assert(BM_vert_in_edge(e, v_end));
-
- if (!BM_edge_exists(v_prev, vi) &&
- !BM_vert_splice_check_double(v_prev, vi) &&
- !BM_vert_pair_share_face_check(v_prev, vi))
- {
- BM_vert_splice(bm, vi, v_prev);
- }
- else {
- copy_v3_v3(v_prev->co, vi->co);
- }
- v_prev = vi;
- if (is_wire) {
- BLI_gset_insert(s.wire_edges, e_split);
- }
- }
- }
- UNUSED_VARS_NDEBUG(v_end);
- }
- }
-#endif
+ MemArena *mem_arena_edgenet = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
+ faces = bm->ftable;
- /* important to handle before edgenet */
-#ifdef USE_DISSOLVE
- if (use_dissolve && (boolean_mode == BMESH_ISECT_BOOLEAN_NONE)) {
- /* first pass */
- BMVert *(*splice_ls)[2];
- STACK_DECLARE(splice_ls);
- LinkNode *node;
-
-
- for (node = s.vert_dissolve; node; node = node->next) {
- BMVert *v = node->link;
- if (BM_elem_flag_test(v, BM_ELEM_TAG)) {
- if (!BM_vert_is_edge_pair(v)) {
- BM_elem_flag_disable(v, BM_ELEM_TAG);
- }
- }
- }
-
- splice_ls = MEM_mallocN(BLI_gset_len(s.wire_edges) * sizeof(*splice_ls), __func__);
- STACK_INIT(splice_ls, BLI_gset_len(s.wire_edges));
-
- for (node = s.vert_dissolve; node; node = node->next) {
- BMEdge *e_pair[2];
- BMVert *v = node->link;
- BMVert *v_a, *v_b;
-
- if (!BM_elem_flag_test(v, BM_ELEM_TAG)) {
- continue;
- }
-
- /* get chain */
- e_pair[0] = v->e;
- e_pair[1] = BM_DISK_EDGE_NEXT(v->e, v);
-
- if (BM_elem_flag_test(e_pair[0], BM_ELEM_TAG) ||
- BM_elem_flag_test(e_pair[1], BM_ELEM_TAG))
- {
- continue;
- }
-
- v_a = BM_edge_other_vert(e_pair[0], v);
- v_b = BM_edge_other_vert(e_pair[1], v);
-
- /* simple case */
- if (BM_elem_flag_test(v_a, BM_ELEM_TAG) &&
- BM_elem_flag_test(v_b, BM_ELEM_TAG))
- {
- /* only start on an edge-case */
- /* pass */
- }
- else if ((!BM_elem_flag_test(v_a, BM_ELEM_TAG)) &&
- (!BM_elem_flag_test(v_b, BM_ELEM_TAG)))
- {
- /* simple case, single edge spans face */
- BMVert **splice_pair;
- BM_elem_flag_enable(e_pair[1], BM_ELEM_TAG);
- splice_pair = STACK_PUSH_RET(splice_ls);
- splice_pair[0] = v;
- splice_pair[1] = v_b;
-#ifdef USE_DUMP
- printf("# Simple Case!\n");
-#endif
- }
- else {
-#ifdef USE_PARANOID
- BMEdge *e_keep;
-#endif
- BMEdge *e;
- BMEdge *e_step;
- BMVert *v_step;
+ GHASH_ITER (gh_iter, s.face_edges) {
+ const int f_index = POINTER_AS_INT(BLI_ghashIterator_getKey(&gh_iter));
+ BMFace *f;
+ struct LinkBase *e_ls_base = BLI_ghashIterator_getValue(&gh_iter);
- /* walk the chain! */
- if (BM_elem_flag_test(v_a, BM_ELEM_TAG)) {
- e = e_pair[0];
-#ifdef USE_PARANOID
- e_keep = e_pair[1];
-#endif
- }
- else {
- SWAP(BMVert *, v_a, v_b);
- e = e_pair[1];
-#ifdef USE_PARANOID
- e_keep = e_pair[0];
-#endif
- }
+ BLI_assert(f_index >= 0 && f_index < totface_orig);
- /* WALK */
- v_step = v;
- e_step = e;
+ f = faces[f_index];
+ if (UNLIKELY(f == NULL)) {
+ continue;
+ }
- while (true) {
- BMEdge *e_next;
- BMVert *v_next;
+ BLI_assert(BM_elem_index_get(f) == f_index);
- v_next = BM_edge_other_vert(e_step, v_step);
- BM_elem_flag_enable(e_step, BM_ELEM_TAG);
- if (!BM_elem_flag_test(v_next, BM_ELEM_TAG)) {
- BMVert **splice_pair;
-#ifdef USE_PARANOID
- BLI_assert(e_step != e_keep);
-#endif
- splice_pair = STACK_PUSH_RET(splice_ls);
- splice_pair[0] = v;
- splice_pair[1] = v_next;
- break;
- }
- else {
- e_next = bm_vert_other_edge(v_next, e_step);
- }
-
- e_step = e_next;
- v_step = v_next;
- BM_elem_flag_enable(e_step, BM_ELEM_TAG);
-#ifdef USE_PARANOID
- BLI_assert(e_step != e_keep);
-#endif
-#ifdef USE_DUMP
- printf("# walk step %p %p\n", e_next, v_next);
-#endif
- }
-#ifdef USE_PARANOID
- BLI_assert(BM_elem_flag_test(e_keep, BM_ELEM_TAG) == 0);
-#endif
- }
- }
-
- /* Remove edges! */
- {
- GHashIterator gh_iter;
-
- GHASH_ITER (gh_iter, s.face_edges) {
- struct LinkBase *e_ls_base = BLI_ghashIterator_getValue(&gh_iter);
- LinkNode **node_prev_p;
- uint i;
-
- node_prev_p = &e_ls_base->list;
- for (i = 0, node = e_ls_base->list; node; i++, node = node->next) {
- BMEdge *e = node->link;
- if (BM_elem_flag_test(e, BM_ELEM_TAG)) {
- /* allocated by arena, don't free */
- *node_prev_p = node->next;
- e_ls_base->list_len--;
- }
- else {
- node_prev_p = &node->next;
- }
- }
- }
- }
-
- {
- BMIter eiter;
- BMEdge *e, *e_next;
-
- BM_ITER_MESH_MUTABLE (e, e_next, &eiter, bm, BM_EDGES_OF_MESH) {
- if (BM_elem_flag_test(e, BM_ELEM_TAG)) {
-
- /* in rare and annoying cases,
- * there can be faces from 's.face_edges' removed by the edges.
- * These are degenerate cases, so just make sure we don't reference the faces again. */
- if (e->l) {
- BMLoop *l_iter = e->l;
- BMFace **faces;
-
- faces = bm->ftable;
-
- do {
- const int f_index = BM_elem_index_get(l_iter->f);
- if (f_index >= 0) {
- BLI_assert(f_index < totface_orig);
- /* we could check if these are in: 's.face_edges', but easier just to remove */
- faces[f_index] = NULL;
- }
- } while ((l_iter = l_iter->radial_next) != e->l);
- }
-
- BLI_gset_remove(s.wire_edges, e, NULL);
- BM_edge_kill(bm, e);
- }
- }
- }
-
- /* Remove verts! */
- {
- GSet *verts_invalid = BLI_gset_ptr_new(__func__);
-
- for (node = s.vert_dissolve; node; node = node->next) {
- /* arena allocated, don't free */
- BMVert *v = node->link;
- if (BM_elem_flag_test(v, BM_ELEM_TAG)) {
- if (!v->e) {
- BLI_gset_add(verts_invalid, v);
- BM_vert_kill(bm, v);
- }
- }
- }
-
- {
- uint i;
- for (i = 0; i < STACK_SIZE(splice_ls); i++) {
- if (!BLI_gset_haskey(verts_invalid, splice_ls[i][0]) &&
- !BLI_gset_haskey(verts_invalid, splice_ls[i][1]))
- {
- if (!BM_edge_exists(UNPACK2(splice_ls[i])) &&
- !BM_vert_splice_check_double(UNPACK2(splice_ls[i])))
- {
- BM_vert_splice(bm, splice_ls[i][1], splice_ls[i][0]);
- }
- }
- }
- }
-
- BLI_gset_free(verts_invalid, NULL);
- }
-
- MEM_freeN(splice_ls);
- }
-#endif /* USE_DISSOLVE */
-
-
- /* now split faces */
-#ifdef USE_NET
- {
- GHashIterator gh_iter;
- BMFace **faces;
+ face_edges_split(
+ bm, f, e_ls_base, use_island_connect, use_partial_connect, mem_arena_edgenet);
- MemArena *mem_arena_edgenet = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
+ BLI_memarena_clear(mem_arena_edgenet);
+ }
- faces = bm->ftable;
-
- GHASH_ITER (gh_iter, s.face_edges) {
- const int f_index = POINTER_AS_INT(BLI_ghashIterator_getKey(&gh_iter));
- BMFace *f;
- struct LinkBase *e_ls_base = BLI_ghashIterator_getValue(&gh_iter);
+ BLI_memarena_free(mem_arena_edgenet);
+ }
+#else
+ UNUSED_VARS(use_island_connect);
+#endif /* USE_NET */
+ (void)totface_orig;
- BLI_assert(f_index >= 0 && f_index < totface_orig);
+#ifdef USE_SEPARATE
+ if (use_separate) {
+ GSetIterator gs_iter;
- f = faces[f_index];
- if (UNLIKELY(f == NULL)) {
- continue;
- }
+ BM_mesh_elem_hflag_disable_all(bm, BM_EDGE, BM_ELEM_TAG, false);
- BLI_assert(BM_elem_index_get(f) == f_index);
+ GSET_ITER (gs_iter, s.wire_edges) {
+ BMEdge *e = BLI_gsetIterator_getKey(&gs_iter);
+ BM_elem_flag_enable(e, BM_ELEM_TAG);
+ }
- face_edges_split(bm, f, e_ls_base, use_island_connect, use_partial_connect, mem_arena_edgenet);
+ BM_mesh_edgesplit(bm, false, true, false);
+ }
+ else if (boolean_mode != BMESH_ISECT_BOOLEAN_NONE || use_edge_tag) {
+ GSetIterator gs_iter;
- BLI_memarena_clear(mem_arena_edgenet);
- }
+ /* no need to clear for boolean */
- BLI_memarena_free(mem_arena_edgenet);
- }
+ GSET_ITER (gs_iter, s.wire_edges) {
+ BMEdge *e = BLI_gsetIterator_getKey(&gs_iter);
+ BM_elem_flag_enable(e, BM_ELEM_TAG);
+ }
+ }
#else
- UNUSED_VARS(use_island_connect);
-#endif /* USE_NET */
- (void)totface_orig;
-
-#ifdef USE_SEPARATE
- if (use_separate) {
- GSetIterator gs_iter;
+ (void)use_separate;
+#endif /* USE_SEPARATE */
- BM_mesh_elem_hflag_disable_all(bm, BM_EDGE, BM_ELEM_TAG, false);
+ if ((boolean_mode != BMESH_ISECT_BOOLEAN_NONE)) {
+ BVHTree *tree_pair[2] = {tree_a, tree_b};
- GSET_ITER (gs_iter, s.wire_edges) {
- BMEdge *e = BLI_gsetIterator_getKey(&gs_iter);
- BM_elem_flag_enable(e, BM_ELEM_TAG);
- }
+ /* group vars */
+ int *groups_array;
+ int(*group_index)[2];
+ int group_tot;
+ int i;
+ BMFace **ftable;
- BM_mesh_edgesplit(bm, false, true, false);
- }
- else if (boolean_mode != BMESH_ISECT_BOOLEAN_NONE || use_edge_tag) {
- GSetIterator gs_iter;
+ BM_mesh_elem_table_ensure(bm, BM_FACE);
+ ftable = bm->ftable;
- /* no need to clear for boolean */
+ /* wrap the face-test callback to make it into an edge-loop delimiter */
+ struct LoopFilterWrap user_data_wrap = {
+ .test_fn = test_fn,
+ .user_data = user_data,
+ };
- GSET_ITER (gs_iter, s.wire_edges) {
- BMEdge *e = BLI_gsetIterator_getKey(&gs_iter);
- BM_elem_flag_enable(e, BM_ELEM_TAG);
- }
- }
-#else
- (void)use_separate;
-#endif /* USE_SEPARATE */
-
- if ((boolean_mode != BMESH_ISECT_BOOLEAN_NONE)) {
- BVHTree *tree_pair[2] = {tree_a, tree_b};
-
- /* group vars */
- int *groups_array;
- int (*group_index)[2];
- int group_tot;
- int i;
- BMFace **ftable;
-
- BM_mesh_elem_table_ensure(bm, BM_FACE);
- ftable = bm->ftable;
-
- /* wrap the face-test callback to make it into an edge-loop delimiter */
- struct LoopFilterWrap user_data_wrap = {
- .test_fn = test_fn,
- .user_data = user_data,
- };
-
- groups_array = MEM_mallocN(sizeof(*groups_array) * (size_t)bm->totface, __func__);
- group_tot = BM_mesh_calc_face_groups(
- bm, groups_array, &group_index,
- bm_loop_filter_fn, &user_data_wrap,
- 0, BM_EDGE);
+ groups_array = MEM_mallocN(sizeof(*groups_array) * (size_t)bm->totface, __func__);
+ group_tot = BM_mesh_calc_face_groups(
+ bm, groups_array, &group_index, bm_loop_filter_fn, &user_data_wrap, 0, BM_EDGE);
#ifdef USE_DUMP
- printf("%s: Total face-groups: %d\n", __func__, group_tot);
+ printf("%s: Total face-groups: %d\n", __func__, group_tot);
#endif
- /* Check if island is inside/outside */
- for (i = 0; i < group_tot; i++) {
- int fg = group_index[i][0];
- int fg_end = group_index[i][1] + fg;
- bool do_remove, do_flip;
-
- {
- /* for now assyme this is an OK face to test with (not degenerate!) */
- BMFace *f = ftable[groups_array[fg]];
- float co[3];
- int hits;
- int side = test_fn(f, user_data);
-
- if (side == -1) {
- continue;
- }
- BLI_assert(ELEM(side, 0, 1));
- side = !side;
-
- // BM_face_calc_center_median(f, co);
- BM_face_calc_point_in_face(f, co);
-
- hits = isect_bvhtree_point_v3(tree_pair[side], looptri_coords, co);
-
- switch (boolean_mode) {
- case BMESH_ISECT_BOOLEAN_ISECT:
- do_remove = ((hits & 1) != 1);
- do_flip = false;
- break;
- case BMESH_ISECT_BOOLEAN_UNION:
- do_remove = ((hits & 1) == 1);
- do_flip = false;
- break;
- case BMESH_ISECT_BOOLEAN_DIFFERENCE:
- do_remove = ((hits & 1) == 1) == side;
- do_flip = (side == 0);
- break;
- }
- }
-
- if (do_remove) {
- for (; fg != fg_end; fg++) {
- /* postpone killing the face since we access below, mark instead */
- // BM_face_kill_loose(bm, ftable[groups_array[fg]]);
- ftable[groups_array[fg]]->mat_nr = -1;
- }
- }
- else if (do_flip) {
- for (; fg != fg_end; fg++) {
- BM_face_normal_flip(bm, ftable[groups_array[fg]]);
- }
- }
-
- has_edit_boolean |= (do_flip || do_remove);
- }
-
- MEM_freeN(groups_array);
- MEM_freeN(group_index);
+ /* Check if island is inside/outside */
+ for (i = 0; i < group_tot; i++) {
+ int fg = group_index[i][0];
+ int fg_end = group_index[i][1] + fg;
+ bool do_remove, do_flip;
+
+ {
+ /* for now assyme this is an OK face to test with (not degenerate!) */
+ BMFace *f = ftable[groups_array[fg]];
+ float co[3];
+ int hits;
+ int side = test_fn(f, user_data);
+
+ if (side == -1) {
+ continue;
+ }
+ BLI_assert(ELEM(side, 0, 1));
+ side = !side;
+
+ // BM_face_calc_center_median(f, co);
+ BM_face_calc_point_in_face(f, co);
+
+ hits = isect_bvhtree_point_v3(tree_pair[side], looptri_coords, co);
+
+ switch (boolean_mode) {
+ case BMESH_ISECT_BOOLEAN_ISECT:
+ do_remove = ((hits & 1) != 1);
+ do_flip = false;
+ break;
+ case BMESH_ISECT_BOOLEAN_UNION:
+ do_remove = ((hits & 1) == 1);
+ do_flip = false;
+ break;
+ case BMESH_ISECT_BOOLEAN_DIFFERENCE:
+ do_remove = ((hits & 1) == 1) == side;
+ do_flip = (side == 0);
+ break;
+ }
+ }
+
+ if (do_remove) {
+ for (; fg != fg_end; fg++) {
+ /* postpone killing the face since we access below, mark instead */
+ // BM_face_kill_loose(bm, ftable[groups_array[fg]]);
+ ftable[groups_array[fg]]->mat_nr = -1;
+ }
+ }
+ else if (do_flip) {
+ for (; fg != fg_end; fg++) {
+ BM_face_normal_flip(bm, ftable[groups_array[fg]]);
+ }
+ }
+
+ has_edit_boolean |= (do_flip || do_remove);
+ }
+
+ MEM_freeN(groups_array);
+ MEM_freeN(group_index);
#ifdef USE_DISSOLVE
- /* We have dissolve code above, this is alternative logic,
- * we need to do it after the boolean is executed. */
- if (use_dissolve) {
- LinkNode *node;
- for (node = s.vert_dissolve; node; node = node->next) {
- BMVert *v = node->link;
- if (BM_vert_is_edge_pair(v)) {
- /* we wont create degenerate faces from this */
- bool ok = true;
-
- /* would we create a 2-sided-face?
- * if so, don't dissolve this since we may */
- if (v->e->l) {
- BMLoop *l_iter = v->e->l;
- do {
- if (l_iter->f->len == 3) {
- ok = false;
- break;
- }
- } while ((l_iter = l_iter->radial_next) != v->e->l);
- }
-
- if (ok) {
- BM_vert_collapse_edge(bm, v->e, v, true, false);
- }
- }
- }
- }
+ /* We have dissolve code above, this is alternative logic,
+ * we need to do it after the boolean is executed. */
+ if (use_dissolve) {
+ LinkNode *node;
+ for (node = s.vert_dissolve; node; node = node->next) {
+ BMVert *v = node->link;
+ if (BM_vert_is_edge_pair(v)) {
+ /* we wont create degenerate faces from this */
+ bool ok = true;
+
+ /* would we create a 2-sided-face?
+ * if so, don't dissolve this since we may */
+ if (v->e->l) {
+ BMLoop *l_iter = v->e->l;
+ do {
+ if (l_iter->f->len == 3) {
+ ok = false;
+ break;
+ }
+ } while ((l_iter = l_iter->radial_next) != v->e->l);
+ }
+
+ if (ok) {
+ BM_vert_collapse_edge(bm, v->e, v, true, false);
+ }
+ }
+ }
+ }
#endif
- {
- int tot = bm->totface;
- for (i = 0; i < tot; i++) {
- if (ftable[i]->mat_nr == -1) {
- BM_face_kill_loose(bm, ftable[i]);
- }
- }
- }
- }
+ {
+ int tot = bm->totface;
+ for (i = 0; i < tot; i++) {
+ if (ftable[i]->mat_nr == -1) {
+ BM_face_kill_loose(bm, ftable[i]);
+ }
+ }
+ }
+ }
- if (boolean_mode != BMESH_ISECT_BOOLEAN_NONE) {
- MEM_freeN((void *)looptri_coords);
+ if (boolean_mode != BMESH_ISECT_BOOLEAN_NONE) {
+ MEM_freeN((void *)looptri_coords);
- /* no booleans, just free immediate */
- BLI_bvhtree_free(tree_a);
- if (tree_a != tree_b) {
- BLI_bvhtree_free(tree_b);
- }
- }
+ /* no booleans, just free immediate */
+ BLI_bvhtree_free(tree_a);
+ if (tree_a != tree_b) {
+ BLI_bvhtree_free(tree_b);
+ }
+ }
- has_edit_isect = (BLI_ghash_len(s.face_edges) != 0);
+ has_edit_isect = (BLI_ghash_len(s.face_edges) != 0);
- /* cleanup */
- BLI_ghash_free(s.edgetri_cache, NULL, NULL);
+ /* cleanup */
+ BLI_ghash_free(s.edgetri_cache, NULL, NULL);
- BLI_ghash_free(s.edge_verts, NULL, NULL);
- BLI_ghash_free(s.face_edges, NULL, NULL);
- BLI_gset_free(s.wire_edges, NULL);
+ BLI_ghash_free(s.edge_verts, NULL, NULL);
+ BLI_ghash_free(s.face_edges, NULL, NULL);
+ BLI_gset_free(s.wire_edges, NULL);
- BLI_memarena_free(s.mem_arena);
+ BLI_memarena_free(s.mem_arena);
- return (has_edit_isect || has_edit_boolean);
+ return (has_edit_isect || has_edit_boolean);
}
diff --git a/source/blender/bmesh/tools/bmesh_intersect.h b/source/blender/bmesh/tools/bmesh_intersect.h
index 6e8e1d42161..cbbc74d3f82 100644
--- a/source/blender/bmesh/tools/bmesh_intersect.h
+++ b/source/blender/bmesh/tools/bmesh_intersect.h
@@ -21,20 +21,26 @@
* \ingroup bmesh
*/
-bool BM_mesh_intersect(
- BMesh *bm,
- struct BMLoop *(*looptris)[3], const int looptris_tot,
- int (*test_fn)(BMFace *f, void *user_data), void *user_data,
- const bool use_self, const bool use_separate, const bool use_dissolve, const bool use_island_connect,
- const bool use_partial_connect, const bool use_edge_tag, const int boolean_mode,
- const float eps);
+bool BM_mesh_intersect(BMesh *bm,
+ struct BMLoop *(*looptris)[3],
+ const int looptris_tot,
+ int (*test_fn)(BMFace *f, void *user_data),
+ void *user_data,
+ const bool use_self,
+ const bool use_separate,
+ const bool use_dissolve,
+ const bool use_island_connect,
+ const bool use_partial_connect,
+ const bool use_edge_tag,
+ const int boolean_mode,
+ const float eps);
enum {
- BMESH_ISECT_BOOLEAN_NONE = -1,
- /* aligned with BooleanModifierOp */
- BMESH_ISECT_BOOLEAN_ISECT = 0,
- BMESH_ISECT_BOOLEAN_UNION = 1,
- BMESH_ISECT_BOOLEAN_DIFFERENCE = 2,
+ BMESH_ISECT_BOOLEAN_NONE = -1,
+ /* aligned with BooleanModifierOp */
+ BMESH_ISECT_BOOLEAN_ISECT = 0,
+ BMESH_ISECT_BOOLEAN_UNION = 1,
+ BMESH_ISECT_BOOLEAN_DIFFERENCE = 2,
};
#endif /* __BMESH_INTERSECT_H__ */
diff --git a/source/blender/bmesh/tools/bmesh_path.c b/source/blender/bmesh/tools/bmesh_path.c
index 4710c3929c4..a874965c978 100644
--- a/source/blender/bmesh/tools/bmesh_path.c
+++ b/source/blender/bmesh/tools/bmesh_path.c
@@ -27,8 +27,7 @@
#include "BLI_heap_simple.h"
#include "bmesh.h"
-#include "bmesh_path.h" /* own include */
-
+#include "bmesh_path.h" /* own include */
/* -------------------------------------------------------------------- */
/* Generic Helpers */
@@ -37,161 +36,161 @@
* Use skip options when we want to start measuring from a boundary.
*/
static float step_cost_3_v3_ex(
- const float v1[3], const float v2[3], const float v3[3],
- bool skip_12, bool skip_23)
+ const float v1[3], const float v2[3], const float v3[3], bool skip_12, bool skip_23)
{
- float d1[3], d2[3];
-
- /* The cost is based on the simple sum of the length of the two edgees... */
- sub_v3_v3v3(d1, v2, v1);
- sub_v3_v3v3(d2, v3, v2);
- const float cost_12 = normalize_v3(d1);
- const float cost_23 = normalize_v3(d2);
- const float cost = ((skip_12 ? 0.0f : cost_12) +
- (skip_23 ? 0.0f : cost_23));
-
- /* but is biased to give higher values to sharp turns, so that it will take
- * paths with fewer "turns" when selecting between equal-weighted paths between
- * the two edges */
- return cost * (1.0f + 0.5f * (2.0f - sqrtf(fabsf(dot_v3v3(d1, d2)))));
+ float d1[3], d2[3];
+
+ /* The cost is based on the simple sum of the length of the two edgees... */
+ sub_v3_v3v3(d1, v2, v1);
+ sub_v3_v3v3(d2, v3, v2);
+ const float cost_12 = normalize_v3(d1);
+ const float cost_23 = normalize_v3(d2);
+ const float cost = ((skip_12 ? 0.0f : cost_12) + (skip_23 ? 0.0f : cost_23));
+
+ /* but is biased to give higher values to sharp turns, so that it will take
+ * paths with fewer "turns" when selecting between equal-weighted paths between
+ * the two edges */
+ return cost * (1.0f + 0.5f * (2.0f - sqrtf(fabsf(dot_v3v3(d1, d2)))));
}
-static float step_cost_3_v3(
- const float v1[3], const float v2[3], const float v3[3])
+static float step_cost_3_v3(const float v1[3], const float v2[3], const float v3[3])
{
- return step_cost_3_v3_ex(v1, v2, v3, false, false);
+ return step_cost_3_v3_ex(v1, v2, v3, false, false);
}
-
/* -------------------------------------------------------------------- */
/* BM_mesh_calc_path_vert */
-static void verttag_add_adjacent(
- HeapSimple *heap, BMVert *v_a, BMVert **verts_prev, float *cost,
- const struct BMCalcPathParams *params)
+static void verttag_add_adjacent(HeapSimple *heap,
+ BMVert *v_a,
+ BMVert **verts_prev,
+ float *cost,
+ const struct BMCalcPathParams *params)
{
- const int v_a_index = BM_elem_index_get(v_a);
-
- {
- BMIter eiter;
- BMEdge *e;
- /* loop over faces of face, but do so by first looping over loops */
- BM_ITER_ELEM (e, &eiter, v_a, BM_EDGES_OF_VERT) {
- BMVert *v_b = BM_edge_other_vert(e, v_a);
- if (!BM_elem_flag_test(v_b, BM_ELEM_TAG)) {
- /* we know 'v_b' is not visited, check it out! */
- const int v_b_index = BM_elem_index_get(v_b);
- const float cost_cut = params->use_topology_distance ?
- 1.0f : len_v3v3(v_a->co, v_b->co);
- const float cost_new = cost[v_a_index] + cost_cut;
-
- if (cost[v_b_index] > cost_new) {
- cost[v_b_index] = cost_new;
- verts_prev[v_b_index] = v_a;
- BLI_heapsimple_insert(heap, cost_new, v_b);
- }
- }
- }
- }
-
- if (params->use_step_face) {
- BMIter liter;
- BMLoop *l;
- /* loop over faces of face, but do so by first looping over loops */
- BM_ITER_ELEM (l, &liter, v_a, BM_LOOPS_OF_VERT) {
- if (l->f->len > 3) {
- /* skip loops on adjacent edges */
- BMLoop *l_iter = l->next->next;
- do {
- BMVert *v_b = l_iter->v;
- if (!BM_elem_flag_test(v_b, BM_ELEM_TAG)) {
- /* we know 'v_b' is not visited, check it out! */
- const int v_b_index = BM_elem_index_get(v_b);
- const float cost_cut = params->use_topology_distance ?
- 1.0f : len_v3v3(v_a->co, v_b->co);
- const float cost_new = cost[v_a_index] + cost_cut;
-
- if (cost[v_b_index] > cost_new) {
- cost[v_b_index] = cost_new;
- verts_prev[v_b_index] = v_a;
- BLI_heapsimple_insert(heap, cost_new, v_b);
- }
- }
- } while ((l_iter = l_iter->next) != l->prev);
- }
- }
- }
+ const int v_a_index = BM_elem_index_get(v_a);
+
+ {
+ BMIter eiter;
+ BMEdge *e;
+ /* loop over faces of face, but do so by first looping over loops */
+ BM_ITER_ELEM (e, &eiter, v_a, BM_EDGES_OF_VERT) {
+ BMVert *v_b = BM_edge_other_vert(e, v_a);
+ if (!BM_elem_flag_test(v_b, BM_ELEM_TAG)) {
+ /* we know 'v_b' is not visited, check it out! */
+ const int v_b_index = BM_elem_index_get(v_b);
+ const float cost_cut = params->use_topology_distance ? 1.0f : len_v3v3(v_a->co, v_b->co);
+ const float cost_new = cost[v_a_index] + cost_cut;
+
+ if (cost[v_b_index] > cost_new) {
+ cost[v_b_index] = cost_new;
+ verts_prev[v_b_index] = v_a;
+ BLI_heapsimple_insert(heap, cost_new, v_b);
+ }
+ }
+ }
+ }
+
+ if (params->use_step_face) {
+ BMIter liter;
+ BMLoop *l;
+ /* loop over faces of face, but do so by first looping over loops */
+ BM_ITER_ELEM (l, &liter, v_a, BM_LOOPS_OF_VERT) {
+ if (l->f->len > 3) {
+ /* skip loops on adjacent edges */
+ BMLoop *l_iter = l->next->next;
+ do {
+ BMVert *v_b = l_iter->v;
+ if (!BM_elem_flag_test(v_b, BM_ELEM_TAG)) {
+ /* we know 'v_b' is not visited, check it out! */
+ const int v_b_index = BM_elem_index_get(v_b);
+ const float cost_cut = params->use_topology_distance ? 1.0f :
+ len_v3v3(v_a->co, v_b->co);
+ const float cost_new = cost[v_a_index] + cost_cut;
+
+ if (cost[v_b_index] > cost_new) {
+ cost[v_b_index] = cost_new;
+ verts_prev[v_b_index] = v_a;
+ BLI_heapsimple_insert(heap, cost_new, v_b);
+ }
+ }
+ } while ((l_iter = l_iter->next) != l->prev);
+ }
+ }
+ }
}
-LinkNode *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)
+LinkNode *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)
{
- LinkNode *path = NULL;
- /* BM_ELEM_TAG flag is used to store visited edges */
- BMVert *v;
- BMIter viter;
- HeapSimple *heap;
- float *cost;
- BMVert **verts_prev;
- int i, totvert;
-
- /* note, would pass BM_EDGE except we are looping over all faces anyway */
- // BM_mesh_elem_index_ensure(bm, BM_VERT /* | BM_EDGE */); // NOT NEEDED FOR FACETAG
-
- BM_ITER_MESH_INDEX (v, &viter, bm, BM_VERTS_OF_MESH, i) {
- BM_elem_flag_set(v, BM_ELEM_TAG, !filter_fn(v, user_data));
- BM_elem_index_set(v, i); /* set_inline */
- }
- bm->elem_index_dirty &= ~BM_VERT;
-
- /* alloc */
- totvert = bm->totvert;
- verts_prev = MEM_callocN(sizeof(*verts_prev) * totvert, __func__);
- cost = MEM_mallocN(sizeof(*cost) * totvert, __func__);
-
- copy_vn_fl(cost, totvert, 1e20f);
-
- /*
- * Arrays are now filled as follows:
- *
- * As the search continues, verts_prev[n] will be the previous verts on the shortest
- * path found so far to face n. BM_ELEM_TAG is used to tag elements we have visited,
- * cost[n] will contain the length of the shortest
- * path to face n found so far, Finally, heap is a priority heap which is built on the
- * the same data as the cost array, but inverted: it is a worklist of faces prioritized
- * by the shortest path found so far to the face.
- */
-
- /* regular dijkstra shortest path, but over faces instead of vertices */
- heap = BLI_heapsimple_new();
- BLI_heapsimple_insert(heap, 0.0f, v_src);
- cost[BM_elem_index_get(v_src)] = 0.0f;
-
- while (!BLI_heapsimple_is_empty(heap)) {
- v = BLI_heapsimple_pop_min(heap);
-
- if (v == v_dst) {
- break;
- }
-
- if (!BM_elem_flag_test(v, BM_ELEM_TAG)) {
- BM_elem_flag_enable(v, BM_ELEM_TAG);
- verttag_add_adjacent(heap, v, verts_prev, cost, params);
- }
- }
-
- if (v == v_dst) {
- do {
- BLI_linklist_prepend(&path, v);
- } while ((v = verts_prev[BM_elem_index_get(v)]));
- }
-
- MEM_freeN(verts_prev);
- MEM_freeN(cost);
- BLI_heapsimple_free(heap, NULL);
-
- return path;
+ LinkNode *path = NULL;
+ /* BM_ELEM_TAG flag is used to store visited edges */
+ BMVert *v;
+ BMIter viter;
+ HeapSimple *heap;
+ float *cost;
+ BMVert **verts_prev;
+ int i, totvert;
+
+ /* note, would pass BM_EDGE except we are looping over all faces anyway */
+ // BM_mesh_elem_index_ensure(bm, BM_VERT /* | BM_EDGE */); // NOT NEEDED FOR FACETAG
+
+ BM_ITER_MESH_INDEX (v, &viter, bm, BM_VERTS_OF_MESH, i) {
+ BM_elem_flag_set(v, BM_ELEM_TAG, !filter_fn(v, user_data));
+ BM_elem_index_set(v, i); /* set_inline */
+ }
+ bm->elem_index_dirty &= ~BM_VERT;
+
+ /* alloc */
+ totvert = bm->totvert;
+ verts_prev = MEM_callocN(sizeof(*verts_prev) * totvert, __func__);
+ cost = MEM_mallocN(sizeof(*cost) * totvert, __func__);
+
+ copy_vn_fl(cost, totvert, 1e20f);
+
+ /*
+ * Arrays are now filled as follows:
+ *
+ * As the search continues, verts_prev[n] will be the previous verts on the shortest
+ * path found so far to face n. BM_ELEM_TAG is used to tag elements we have visited,
+ * cost[n] will contain the length of the shortest
+ * path to face n found so far, Finally, heap is a priority heap which is built on the
+ * the same data as the cost array, but inverted: it is a worklist of faces prioritized
+ * by the shortest path found so far to the face.
+ */
+
+ /* regular dijkstra shortest path, but over faces instead of vertices */
+ heap = BLI_heapsimple_new();
+ BLI_heapsimple_insert(heap, 0.0f, v_src);
+ cost[BM_elem_index_get(v_src)] = 0.0f;
+
+ while (!BLI_heapsimple_is_empty(heap)) {
+ v = BLI_heapsimple_pop_min(heap);
+
+ if (v == v_dst) {
+ break;
+ }
+
+ if (!BM_elem_flag_test(v, BM_ELEM_TAG)) {
+ BM_elem_flag_enable(v, BM_ELEM_TAG);
+ verttag_add_adjacent(heap, v, verts_prev, cost, params);
+ }
+ }
+
+ if (v == v_dst) {
+ do {
+ BLI_linklist_prepend(&path, v);
+ } while ((v = verts_prev[BM_elem_index_get(v)]));
+ }
+
+ MEM_freeN(verts_prev);
+ MEM_freeN(cost);
+ BLI_heapsimple_free(heap, NULL);
+
+ return path;
}
/* -------------------------------------------------------------------- */
@@ -199,357 +198,372 @@ LinkNode *BM_mesh_calc_path_vert(
static float edgetag_cut_cost_vert(BMEdge *e_a, BMEdge *e_b, BMVert *v)
{
- BMVert *v1 = BM_edge_other_vert(e_a, v);
- BMVert *v2 = BM_edge_other_vert(e_b, v);
- return step_cost_3_v3(v1->co, v->co, v2->co);
+ BMVert *v1 = BM_edge_other_vert(e_a, v);
+ BMVert *v2 = BM_edge_other_vert(e_b, v);
+ return step_cost_3_v3(v1->co, v->co, v2->co);
}
static float edgetag_cut_cost_face(BMEdge *e_a, BMEdge *e_b, BMFace *f)
{
- float e_a_cent[3], e_b_cent[3], f_cent[3];
+ float e_a_cent[3], e_b_cent[3], f_cent[3];
- mid_v3_v3v3(e_a_cent, e_a->v1->co, e_a->v1->co);
- mid_v3_v3v3(e_b_cent, e_b->v1->co, e_b->v1->co);
+ mid_v3_v3v3(e_a_cent, e_a->v1->co, e_a->v1->co);
+ mid_v3_v3v3(e_b_cent, e_b->v1->co, e_b->v1->co);
- BM_face_calc_center_median_weighted(f, f_cent);
+ BM_face_calc_center_median_weighted(f, f_cent);
- return step_cost_3_v3(e_a_cent, e_b_cent, f_cent);
+ return step_cost_3_v3(e_a_cent, e_b_cent, f_cent);
}
-static void edgetag_add_adjacent(
- HeapSimple *heap, BMEdge *e_a, BMEdge **edges_prev, float *cost,
- const struct BMCalcPathParams *params)
+static void edgetag_add_adjacent(HeapSimple *heap,
+ BMEdge *e_a,
+ BMEdge **edges_prev,
+ float *cost,
+ const struct BMCalcPathParams *params)
{
- const int e_a_index = BM_elem_index_get(e_a);
-
- /* unlike vert/face, stepping faces disables scanning connected edges
- * and only steps over faces (selecting a ring of edges instead of a loop) */
- if (params->use_step_face == false) {
- BMIter viter;
- BMVert *v;
-
- BMIter eiter;
- BMEdge *e_b;
-
- BM_ITER_ELEM (v, &viter, e_a, BM_VERTS_OF_EDGE) {
-
- /* don't walk over previous vertex */
- if ((edges_prev[e_a_index]) &&
- (BM_vert_in_edge(edges_prev[e_a_index], v)))
- {
- continue;
- }
-
- BM_ITER_ELEM (e_b, &eiter, v, BM_EDGES_OF_VERT) {
- if (!BM_elem_flag_test(e_b, BM_ELEM_TAG)) {
- /* we know 'e_b' is not visited, check it out! */
- const int e_b_index = BM_elem_index_get(e_b);
- const float cost_cut = params->use_topology_distance ?
- 1.0f : edgetag_cut_cost_vert(e_a, e_b, v);
- const float cost_new = cost[e_a_index] + cost_cut;
-
- if (cost[e_b_index] > cost_new) {
- cost[e_b_index] = cost_new;
- edges_prev[e_b_index] = e_a;
- BLI_heapsimple_insert(heap, cost_new, e_b);
- }
- }
- }
- }
- }
- else {
- BMLoop *l_first, *l_iter;
-
- l_iter = l_first = e_a->l;
- do {
- BMLoop *l_cycle_iter, *l_cycle_end;
-
- l_cycle_iter = l_iter->next;
- l_cycle_end = l_iter;
-
- /* good, but we need to allow this otherwise paths may fail to connect at all */
+ const int e_a_index = BM_elem_index_get(e_a);
+
+ /* unlike vert/face, stepping faces disables scanning connected edges
+ * and only steps over faces (selecting a ring of edges instead of a loop) */
+ if (params->use_step_face == false) {
+ BMIter viter;
+ BMVert *v;
+
+ BMIter eiter;
+ BMEdge *e_b;
+
+ BM_ITER_ELEM (v, &viter, e_a, BM_VERTS_OF_EDGE) {
+
+ /* don't walk over previous vertex */
+ if ((edges_prev[e_a_index]) && (BM_vert_in_edge(edges_prev[e_a_index], v))) {
+ continue;
+ }
+
+ BM_ITER_ELEM (e_b, &eiter, v, BM_EDGES_OF_VERT) {
+ if (!BM_elem_flag_test(e_b, BM_ELEM_TAG)) {
+ /* we know 'e_b' is not visited, check it out! */
+ const int e_b_index = BM_elem_index_get(e_b);
+ const float cost_cut = params->use_topology_distance ?
+ 1.0f :
+ edgetag_cut_cost_vert(e_a, e_b, v);
+ const float cost_new = cost[e_a_index] + cost_cut;
+
+ if (cost[e_b_index] > cost_new) {
+ cost[e_b_index] = cost_new;
+ edges_prev[e_b_index] = e_a;
+ BLI_heapsimple_insert(heap, cost_new, e_b);
+ }
+ }
+ }
+ }
+ }
+ else {
+ BMLoop *l_first, *l_iter;
+
+ l_iter = l_first = e_a->l;
+ do {
+ BMLoop *l_cycle_iter, *l_cycle_end;
+
+ l_cycle_iter = l_iter->next;
+ l_cycle_end = l_iter;
+
+ /* good, but we need to allow this otherwise paths may fail to connect at all */
#if 0
- if (l_iter->f->len > 3) {
- l_cycle_iter = l_cycle_iter->next;
- l_cycle_end = l_cycle_end->prev;
- }
+ if (l_iter->f->len > 3) {
+ l_cycle_iter = l_cycle_iter->next;
+ l_cycle_end = l_cycle_end->prev;
+ }
#endif
- do {
- BMEdge *e_b = l_cycle_iter->e;
- if (!BM_elem_flag_test(e_b, BM_ELEM_TAG)) {
- /* we know 'e_b' is not visited, check it out! */
- const int e_b_index = BM_elem_index_get(e_b);
- const float cost_cut = params->use_topology_distance ?
- 1.0f : edgetag_cut_cost_face(e_a, e_b, l_iter->f);
- const float cost_new = cost[e_a_index] + cost_cut;
-
- if (cost[e_b_index] > cost_new) {
- cost[e_b_index] = cost_new;
- edges_prev[e_b_index] = e_a;
- BLI_heapsimple_insert(heap, cost_new, e_b);
- }
- }
- } while ((l_cycle_iter = l_cycle_iter->next) != l_cycle_end);
- } while ((l_iter = l_iter->radial_next) != l_first);
- }
+ do {
+ BMEdge *e_b = l_cycle_iter->e;
+ if (!BM_elem_flag_test(e_b, BM_ELEM_TAG)) {
+ /* we know 'e_b' is not visited, check it out! */
+ const int e_b_index = BM_elem_index_get(e_b);
+ const float cost_cut = params->use_topology_distance ?
+ 1.0f :
+ edgetag_cut_cost_face(e_a, e_b, l_iter->f);
+ const float cost_new = cost[e_a_index] + cost_cut;
+
+ if (cost[e_b_index] > cost_new) {
+ cost[e_b_index] = cost_new;
+ edges_prev[e_b_index] = e_a;
+ BLI_heapsimple_insert(heap, cost_new, e_b);
+ }
+ }
+ } while ((l_cycle_iter = l_cycle_iter->next) != l_cycle_end);
+ } while ((l_iter = l_iter->radial_next) != l_first);
+ }
}
-
-LinkNode *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)
+LinkNode *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)
{
- LinkNode *path = NULL;
- /* BM_ELEM_TAG flag is used to store visited edges */
- BMEdge *e;
- BMIter eiter;
- HeapSimple *heap;
- float *cost;
- BMEdge **edges_prev;
- int i, totedge;
-
- /* note, would pass BM_EDGE except we are looping over all edges anyway */
- BM_mesh_elem_index_ensure(bm, BM_VERT /* | BM_EDGE */);
-
- BM_ITER_MESH_INDEX (e, &eiter, bm, BM_EDGES_OF_MESH, i) {
- BM_elem_flag_set(e, BM_ELEM_TAG, !filter_fn(e, user_data));
- BM_elem_index_set(e, i); /* set_inline */
- }
- bm->elem_index_dirty &= ~BM_EDGE;
-
- /* alloc */
- totedge = bm->totedge;
- edges_prev = MEM_callocN(sizeof(*edges_prev) * totedge, "SeamPathPrevious");
- cost = MEM_mallocN(sizeof(*cost) * totedge, "SeamPathCost");
-
- copy_vn_fl(cost, totedge, 1e20f);
-
- /*
- * Arrays are now filled as follows:
- *
- * As the search continues, prevedge[n] will be the previous edge on the shortest
- * path found so far to edge n. BM_ELEM_TAG is used to tag elements we have visited,
- * cost[n] will contain the length of the shortest
- * path to edge n found so far, Finally, heap is a priority heap which is built on the
- * the same data as the cost array, but inverted: it is a worklist of edges prioritized
- * by the shortest path found so far to the edge.
- */
-
- /* regular dijkstra shortest path, but over edges instead of vertices */
- heap = BLI_heapsimple_new();
- BLI_heapsimple_insert(heap, 0.0f, e_src);
- cost[BM_elem_index_get(e_src)] = 0.0f;
-
- while (!BLI_heapsimple_is_empty(heap)) {
- e = BLI_heapsimple_pop_min(heap);
-
- if (e == e_dst) {
- break;
- }
-
- if (!BM_elem_flag_test(e, BM_ELEM_TAG)) {
- BM_elem_flag_enable(e, BM_ELEM_TAG);
- edgetag_add_adjacent(heap, e, edges_prev, cost, params);
- }
- }
-
- if (e == e_dst) {
- do {
- BLI_linklist_prepend(&path, e);
- } while ((e = edges_prev[BM_elem_index_get(e)]));
- }
-
- MEM_freeN(edges_prev);
- MEM_freeN(cost);
- BLI_heapsimple_free(heap, NULL);
-
- return path;
+ LinkNode *path = NULL;
+ /* BM_ELEM_TAG flag is used to store visited edges */
+ BMEdge *e;
+ BMIter eiter;
+ HeapSimple *heap;
+ float *cost;
+ BMEdge **edges_prev;
+ int i, totedge;
+
+ /* note, would pass BM_EDGE except we are looping over all edges anyway */
+ BM_mesh_elem_index_ensure(bm, BM_VERT /* | BM_EDGE */);
+
+ BM_ITER_MESH_INDEX (e, &eiter, bm, BM_EDGES_OF_MESH, i) {
+ BM_elem_flag_set(e, BM_ELEM_TAG, !filter_fn(e, user_data));
+ BM_elem_index_set(e, i); /* set_inline */
+ }
+ bm->elem_index_dirty &= ~BM_EDGE;
+
+ /* alloc */
+ totedge = bm->totedge;
+ edges_prev = MEM_callocN(sizeof(*edges_prev) * totedge, "SeamPathPrevious");
+ cost = MEM_mallocN(sizeof(*cost) * totedge, "SeamPathCost");
+
+ copy_vn_fl(cost, totedge, 1e20f);
+
+ /*
+ * Arrays are now filled as follows:
+ *
+ * As the search continues, prevedge[n] will be the previous edge on the shortest
+ * path found so far to edge n. BM_ELEM_TAG is used to tag elements we have visited,
+ * cost[n] will contain the length of the shortest
+ * path to edge n found so far, Finally, heap is a priority heap which is built on the
+ * the same data as the cost array, but inverted: it is a worklist of edges prioritized
+ * by the shortest path found so far to the edge.
+ */
+
+ /* regular dijkstra shortest path, but over edges instead of vertices */
+ heap = BLI_heapsimple_new();
+ BLI_heapsimple_insert(heap, 0.0f, e_src);
+ cost[BM_elem_index_get(e_src)] = 0.0f;
+
+ while (!BLI_heapsimple_is_empty(heap)) {
+ e = BLI_heapsimple_pop_min(heap);
+
+ if (e == e_dst) {
+ break;
+ }
+
+ if (!BM_elem_flag_test(e, BM_ELEM_TAG)) {
+ BM_elem_flag_enable(e, BM_ELEM_TAG);
+ edgetag_add_adjacent(heap, e, edges_prev, cost, params);
+ }
+ }
+
+ if (e == e_dst) {
+ do {
+ BLI_linklist_prepend(&path, e);
+ } while ((e = edges_prev[BM_elem_index_get(e)]));
+ }
+
+ MEM_freeN(edges_prev);
+ MEM_freeN(cost);
+ BLI_heapsimple_free(heap, NULL);
+
+ return path;
}
-
/* -------------------------------------------------------------------- */
/* BM_mesh_calc_path_face */
-static float facetag_cut_cost_edge(BMFace *f_a, BMFace *f_b, BMEdge *e, const void * const f_endpoints[2])
+static float facetag_cut_cost_edge(BMFace *f_a,
+ BMFace *f_b,
+ BMEdge *e,
+ const void *const f_endpoints[2])
{
- float f_a_cent[3];
- float f_b_cent[3];
- float e_cent[3];
+ float f_a_cent[3];
+ float f_b_cent[3];
+ float e_cent[3];
- BM_face_calc_center_median_weighted(f_a, f_a_cent);
- BM_face_calc_center_median_weighted(f_b, f_b_cent);
+ BM_face_calc_center_median_weighted(f_a, f_a_cent);
+ BM_face_calc_center_median_weighted(f_b, f_b_cent);
#if 0
- mid_v3_v3v3(e_cent, e->v1->co, e->v2->co);
+ mid_v3_v3v3(e_cent, e->v1->co, e->v2->co);
#else
- /* for triangle fans it gives better results to pick a point on the edge */
- {
- float ix_e[3], ix_f[3], f;
- isect_line_line_v3(e->v1->co, e->v2->co, f_a_cent, f_b_cent, ix_e, ix_f);
- f = line_point_factor_v3(ix_e, e->v1->co, e->v2->co);
- if (f < 0.0f) {
- copy_v3_v3(e_cent, e->v1->co);
- }
- else if (f > 1.0f) {
- copy_v3_v3(e_cent, e->v2->co);
- }
- else {
- copy_v3_v3(e_cent, ix_e);
- }
- }
+ /* for triangle fans it gives better results to pick a point on the edge */
+ {
+ float ix_e[3], ix_f[3], f;
+ isect_line_line_v3(e->v1->co, e->v2->co, f_a_cent, f_b_cent, ix_e, ix_f);
+ f = line_point_factor_v3(ix_e, e->v1->co, e->v2->co);
+ if (f < 0.0f) {
+ copy_v3_v3(e_cent, e->v1->co);
+ }
+ else if (f > 1.0f) {
+ copy_v3_v3(e_cent, e->v2->co);
+ }
+ else {
+ copy_v3_v3(e_cent, ix_e);
+ }
+ }
#endif
- return step_cost_3_v3_ex(
- f_a_cent, e_cent, f_b_cent,
- (f_a == f_endpoints[0]), (f_b == f_endpoints[1]));
+ return step_cost_3_v3_ex(
+ f_a_cent, e_cent, f_b_cent, (f_a == f_endpoints[0]), (f_b == f_endpoints[1]));
}
-static float facetag_cut_cost_vert(BMFace *f_a, BMFace *f_b, BMVert *v, const void * const f_endpoints[2])
+static float facetag_cut_cost_vert(BMFace *f_a,
+ BMFace *f_b,
+ BMVert *v,
+ const void *const f_endpoints[2])
{
- float f_a_cent[3];
- float f_b_cent[3];
+ float f_a_cent[3];
+ float f_b_cent[3];
- BM_face_calc_center_median_weighted(f_a, f_a_cent);
- BM_face_calc_center_median_weighted(f_b, f_b_cent);
+ BM_face_calc_center_median_weighted(f_a, f_a_cent);
+ BM_face_calc_center_median_weighted(f_b, f_b_cent);
- return step_cost_3_v3_ex(
- f_a_cent, v->co, f_b_cent,
- (f_a == f_endpoints[0]), (f_b == f_endpoints[1]));
+ return step_cost_3_v3_ex(
+ f_a_cent, v->co, f_b_cent, (f_a == f_endpoints[0]), (f_b == f_endpoints[1]));
}
-static void facetag_add_adjacent(
- HeapSimple *heap, BMFace *f_a, BMFace **faces_prev, float *cost,
- const void * const f_endpoints[2], const struct BMCalcPathParams *params)
+static void facetag_add_adjacent(HeapSimple *heap,
+ BMFace *f_a,
+ BMFace **faces_prev,
+ float *cost,
+ const void *const f_endpoints[2],
+ const struct BMCalcPathParams *params)
{
- const int f_a_index = BM_elem_index_get(f_a);
-
- /* loop over faces of face, but do so by first looping over loops */
- {
- BMIter liter;
- BMLoop *l_a;
-
- BM_ITER_ELEM (l_a, &liter, f_a, BM_LOOPS_OF_FACE) {
- BMLoop *l_first, *l_iter;
-
- l_iter = l_first = l_a;
- do {
- BMFace *f_b = l_iter->f;
- if (!BM_elem_flag_test(f_b, BM_ELEM_TAG)) {
- /* we know 'f_b' is not visited, check it out! */
- const int f_b_index = BM_elem_index_get(f_b);
- const float cost_cut = params->use_topology_distance ?
- 1.0f : facetag_cut_cost_edge(f_a, f_b, l_iter->e, f_endpoints);
- const float cost_new = cost[f_a_index] + cost_cut;
-
- if (cost[f_b_index] > cost_new) {
- cost[f_b_index] = cost_new;
- faces_prev[f_b_index] = f_a;
- BLI_heapsimple_insert(heap, cost_new, f_b);
- }
- }
- } while ((l_iter = l_iter->radial_next) != l_first);
- }
- }
-
- if (params->use_step_face) {
- BMIter liter;
- BMLoop *l_a;
-
- BM_ITER_ELEM (l_a, &liter, f_a, BM_LOOPS_OF_FACE) {
- BMIter litersub;
- BMLoop *l_b;
- BM_ITER_ELEM (l_b, &litersub, l_a->v, BM_LOOPS_OF_VERT) {
- if ((l_a != l_b) && !BM_loop_share_edge_check(l_a, l_b)) {
- BMFace *f_b = l_b->f;
- if (!BM_elem_flag_test(f_b, BM_ELEM_TAG)) {
- /* we know 'f_b' is not visited, check it out! */
- const int f_b_index = BM_elem_index_get(f_b);
- const float cost_cut = params->use_topology_distance ?
- 1.0f : facetag_cut_cost_vert(f_a, f_b, l_a->v, f_endpoints);
- const float cost_new = cost[f_a_index] + cost_cut;
-
- if (cost[f_b_index] > cost_new) {
- cost[f_b_index] = cost_new;
- faces_prev[f_b_index] = f_a;
- BLI_heapsimple_insert(heap, cost_new, f_b);
- }
- }
- }
- }
- }
- }
+ const int f_a_index = BM_elem_index_get(f_a);
+
+ /* loop over faces of face, but do so by first looping over loops */
+ {
+ BMIter liter;
+ BMLoop *l_a;
+
+ BM_ITER_ELEM (l_a, &liter, f_a, BM_LOOPS_OF_FACE) {
+ BMLoop *l_first, *l_iter;
+
+ l_iter = l_first = l_a;
+ do {
+ BMFace *f_b = l_iter->f;
+ if (!BM_elem_flag_test(f_b, BM_ELEM_TAG)) {
+ /* we know 'f_b' is not visited, check it out! */
+ const int f_b_index = BM_elem_index_get(f_b);
+ const float cost_cut = params->use_topology_distance ?
+ 1.0f :
+ facetag_cut_cost_edge(f_a, f_b, l_iter->e, f_endpoints);
+ const float cost_new = cost[f_a_index] + cost_cut;
+
+ if (cost[f_b_index] > cost_new) {
+ cost[f_b_index] = cost_new;
+ faces_prev[f_b_index] = f_a;
+ BLI_heapsimple_insert(heap, cost_new, f_b);
+ }
+ }
+ } while ((l_iter = l_iter->radial_next) != l_first);
+ }
+ }
+
+ if (params->use_step_face) {
+ BMIter liter;
+ BMLoop *l_a;
+
+ BM_ITER_ELEM (l_a, &liter, f_a, BM_LOOPS_OF_FACE) {
+ BMIter litersub;
+ BMLoop *l_b;
+ BM_ITER_ELEM (l_b, &litersub, l_a->v, BM_LOOPS_OF_VERT) {
+ if ((l_a != l_b) && !BM_loop_share_edge_check(l_a, l_b)) {
+ BMFace *f_b = l_b->f;
+ if (!BM_elem_flag_test(f_b, BM_ELEM_TAG)) {
+ /* we know 'f_b' is not visited, check it out! */
+ const int f_b_index = BM_elem_index_get(f_b);
+ const float cost_cut = params->use_topology_distance ?
+ 1.0f :
+ facetag_cut_cost_vert(f_a, f_b, l_a->v, f_endpoints);
+ const float cost_new = cost[f_a_index] + cost_cut;
+
+ if (cost[f_b_index] > cost_new) {
+ cost[f_b_index] = cost_new;
+ faces_prev[f_b_index] = f_a;
+ BLI_heapsimple_insert(heap, cost_new, f_b);
+ }
+ }
+ }
+ }
+ }
+ }
}
-LinkNode *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)
+LinkNode *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)
{
- LinkNode *path = NULL;
- /* BM_ELEM_TAG flag is used to store visited edges */
- BMFace *f;
- BMIter fiter;
- HeapSimple *heap;
- float *cost;
- BMFace **faces_prev;
- int i, totface;
-
- /* Start measuring face path at the face edges, ignoring their centers. */
- const void * const f_endpoints[2] = {f_src, f_dst};
-
- /* note, would pass BM_EDGE except we are looping over all faces anyway */
- // BM_mesh_elem_index_ensure(bm, BM_VERT /* | BM_EDGE */); // NOT NEEDED FOR FACETAG
-
- BM_ITER_MESH_INDEX (f, &fiter, bm, BM_FACES_OF_MESH, i) {
- BM_elem_flag_set(f, BM_ELEM_TAG, !filter_fn(f, user_data));
- BM_elem_index_set(f, i); /* set_inline */
- }
- bm->elem_index_dirty &= ~BM_FACE;
-
- /* alloc */
- totface = bm->totface;
- faces_prev = MEM_callocN(sizeof(*faces_prev) * totface, __func__);
- cost = MEM_mallocN(sizeof(*cost) * totface, __func__);
-
- copy_vn_fl(cost, totface, 1e20f);
-
- /*
- * Arrays are now filled as follows:
- *
- * As the search continues, faces_prev[n] will be the previous face on the shortest
- * path found so far to face n. BM_ELEM_TAG is used to tag elements we have visited,
- * cost[n] will contain the length of the shortest
- * path to face n found so far, Finally, heap is a priority heap which is built on the
- * the same data as the cost array, but inverted: it is a worklist of faces prioritized
- * by the shortest path found so far to the face.
- */
-
- /* regular dijkstra shortest path, but over faces instead of vertices */
- heap = BLI_heapsimple_new();
- BLI_heapsimple_insert(heap, 0.0f, f_src);
- cost[BM_elem_index_get(f_src)] = 0.0f;
-
- while (!BLI_heapsimple_is_empty(heap)) {
- f = BLI_heapsimple_pop_min(heap);
-
- if (f == f_dst) {
- break;
- }
-
- if (!BM_elem_flag_test(f, BM_ELEM_TAG)) {
- BM_elem_flag_enable(f, BM_ELEM_TAG);
- facetag_add_adjacent(heap, f, faces_prev, cost, f_endpoints, params);
- }
- }
-
- if (f == f_dst) {
- do {
- BLI_linklist_prepend(&path, f);
- } while ((f = faces_prev[BM_elem_index_get(f)]));
- }
-
- MEM_freeN(faces_prev);
- MEM_freeN(cost);
- BLI_heapsimple_free(heap, NULL);
-
- return path;
+ LinkNode *path = NULL;
+ /* BM_ELEM_TAG flag is used to store visited edges */
+ BMFace *f;
+ BMIter fiter;
+ HeapSimple *heap;
+ float *cost;
+ BMFace **faces_prev;
+ int i, totface;
+
+ /* Start measuring face path at the face edges, ignoring their centers. */
+ const void *const f_endpoints[2] = {f_src, f_dst};
+
+ /* note, would pass BM_EDGE except we are looping over all faces anyway */
+ // BM_mesh_elem_index_ensure(bm, BM_VERT /* | BM_EDGE */); // NOT NEEDED FOR FACETAG
+
+ BM_ITER_MESH_INDEX (f, &fiter, bm, BM_FACES_OF_MESH, i) {
+ BM_elem_flag_set(f, BM_ELEM_TAG, !filter_fn(f, user_data));
+ BM_elem_index_set(f, i); /* set_inline */
+ }
+ bm->elem_index_dirty &= ~BM_FACE;
+
+ /* alloc */
+ totface = bm->totface;
+ faces_prev = MEM_callocN(sizeof(*faces_prev) * totface, __func__);
+ cost = MEM_mallocN(sizeof(*cost) * totface, __func__);
+
+ copy_vn_fl(cost, totface, 1e20f);
+
+ /*
+ * Arrays are now filled as follows:
+ *
+ * As the search continues, faces_prev[n] will be the previous face on the shortest
+ * path found so far to face n. BM_ELEM_TAG is used to tag elements we have visited,
+ * cost[n] will contain the length of the shortest
+ * path to face n found so far, Finally, heap is a priority heap which is built on the
+ * the same data as the cost array, but inverted: it is a worklist of faces prioritized
+ * by the shortest path found so far to the face.
+ */
+
+ /* regular dijkstra shortest path, but over faces instead of vertices */
+ heap = BLI_heapsimple_new();
+ BLI_heapsimple_insert(heap, 0.0f, f_src);
+ cost[BM_elem_index_get(f_src)] = 0.0f;
+
+ while (!BLI_heapsimple_is_empty(heap)) {
+ f = BLI_heapsimple_pop_min(heap);
+
+ if (f == f_dst) {
+ break;
+ }
+
+ if (!BM_elem_flag_test(f, BM_ELEM_TAG)) {
+ BM_elem_flag_enable(f, BM_ELEM_TAG);
+ facetag_add_adjacent(heap, f, faces_prev, cost, f_endpoints, params);
+ }
+ }
+
+ if (f == f_dst) {
+ do {
+ BLI_linklist_prepend(&path, f);
+ } while ((f = faces_prev[BM_elem_index_get(f)]));
+ }
+
+ MEM_freeN(faces_prev);
+ MEM_freeN(cost);
+ BLI_heapsimple_free(heap, NULL);
+
+ return path;
}
diff --git a/source/blender/bmesh/tools/bmesh_path.h b/source/blender/bmesh/tools/bmesh_path.h
index 792ba6c7dce..6d22a7e7e07 100644
--- a/source/blender/bmesh/tools/bmesh_path.h
+++ b/source/blender/bmesh/tools/bmesh_path.h
@@ -22,23 +22,32 @@
*/
struct BMCalcPathParams {
- uint use_topology_distance : 1;
- uint use_step_face : 1;
+ uint use_topology_distance : 1;
+ uint use_step_face : 1;
};
-struct LinkNode *BM_mesh_calc_path_vert(
- BMesh *bm, BMVert *v_src, BMVert *v_dst, const struct BMCalcPathParams *params,
- bool (*filter_fn)(BMVert *, void *), void *user_data)
-ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2, 3, 5);
+struct LinkNode *BM_mesh_calc_path_vert(BMesh *bm,
+ BMVert *v_src,
+ BMVert *v_dst,
+ const struct BMCalcPathParams *params,
+ bool (*filter_fn)(BMVert *, void *),
+ void *user_data) ATTR_WARN_UNUSED_RESULT
+ ATTR_NONNULL(1, 2, 3, 5);
-struct LinkNode *BM_mesh_calc_path_edge(
- BMesh *bm, BMEdge *e_src, BMEdge *e_dst, const struct BMCalcPathParams *params,
- bool (*filter_fn)(BMEdge *, void *), void *user_data)
-ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2, 3, 5);
+struct LinkNode *BM_mesh_calc_path_edge(BMesh *bm,
+ BMEdge *e_src,
+ BMEdge *e_dst,
+ const struct BMCalcPathParams *params,
+ bool (*filter_fn)(BMEdge *, void *),
+ void *user_data) ATTR_WARN_UNUSED_RESULT
+ ATTR_NONNULL(1, 2, 3, 5);
-struct LinkNode *BM_mesh_calc_path_face(
- BMesh *bm, BMFace *f_src, BMFace *f_dst, const struct BMCalcPathParams *params,
- bool (*filter_fn)(BMFace *, void *), void *user_data)
-ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2, 3, 5);
+struct LinkNode *BM_mesh_calc_path_face(BMesh *bm,
+ BMFace *f_src,
+ BMFace *f_dst,
+ const struct BMCalcPathParams *params,
+ bool (*filter_fn)(BMFace *, void *),
+ void *user_data) ATTR_WARN_UNUSED_RESULT
+ ATTR_NONNULL(1, 2, 3, 5);
#endif /* __BMESH_PATH_H__ */
diff --git a/source/blender/bmesh/tools/bmesh_path_region.c b/source/blender/bmesh/tools/bmesh_path_region.c
index 8eb5b50b2a2..9ec3b51f29a 100644
--- a/source/blender/bmesh/tools/bmesh_path_region.c
+++ b/source/blender/bmesh/tools/bmesh_path_region.c
@@ -29,8 +29,7 @@
#include "BLI_alloca.h"
#include "bmesh.h"
-#include "bmesh_path_region.h" /* own include */
-
+#include "bmesh_path_region.h" /* own include */
/**
* Special handling of vertices with 2 edges
@@ -45,7 +44,6 @@
*/
#define USE_EDGE_CHAIN
-
#ifdef USE_EDGE_CHAIN
/**
* Takes a vertex with 2 edge users and assigns the vertices at each end-point,
@@ -54,66 +52,62 @@
*/
static bool bm_vert_pair_ends(BMVert *v_pivot, BMVert *v_end_pair[2])
{
- BMEdge *e = v_pivot->e;
- int j = 0;
- do {
- BMEdge *e_chain = e;
- BMVert *v_other = BM_edge_other_vert(e_chain, v_pivot);
- while (BM_vert_is_edge_pair_manifold(v_other)) {
- BMEdge *e_chain_next = BM_DISK_EDGE_NEXT(e_chain, v_other);
- BLI_assert(BM_DISK_EDGE_NEXT(e_chain_next, v_other) == e_chain);
- v_other = BM_edge_other_vert(e_chain_next, v_other);
- if (v_other == v_pivot) {
- return false;
- }
- e_chain = e_chain_next;
- }
- v_end_pair[j++] = v_other;
- } while ((e = BM_DISK_EDGE_NEXT(e, v_pivot)) != v_pivot->e);
-
- BLI_assert(j == 2);
- return true;
+ BMEdge *e = v_pivot->e;
+ int j = 0;
+ do {
+ BMEdge *e_chain = e;
+ BMVert *v_other = BM_edge_other_vert(e_chain, v_pivot);
+ while (BM_vert_is_edge_pair_manifold(v_other)) {
+ BMEdge *e_chain_next = BM_DISK_EDGE_NEXT(e_chain, v_other);
+ BLI_assert(BM_DISK_EDGE_NEXT(e_chain_next, v_other) == e_chain);
+ v_other = BM_edge_other_vert(e_chain_next, v_other);
+ if (v_other == v_pivot) {
+ return false;
+ }
+ e_chain = e_chain_next;
+ }
+ v_end_pair[j++] = v_other;
+ } while ((e = BM_DISK_EDGE_NEXT(e, v_pivot)) != v_pivot->e);
+
+ BLI_assert(j == 2);
+ return true;
}
-#endif /* USE_EDGE_CHAIN */
-
+#endif /* USE_EDGE_CHAIN */
/** \name Vertex in Region Checks
* \{ */
-static bool bm_vert_region_test(BMVert *v, int * const depths[2], const int pass)
+static bool bm_vert_region_test(BMVert *v, int *const depths[2], const int pass)
{
- const int index = BM_elem_index_get(v);
- return (((depths[0][index] != -1) && (depths[1][index] != -1)) && \
- ((depths[0][index] + depths[1][index]) < pass));
+ const int index = BM_elem_index_get(v);
+ return (((depths[0][index] != -1) && (depths[1][index] != -1)) &&
+ ((depths[0][index] + depths[1][index]) < pass));
}
#ifdef USE_EDGE_CHAIN
-static bool bm_vert_region_test_chain(BMVert *v, int * const depths[2], const int pass)
+static bool bm_vert_region_test_chain(BMVert *v, int *const depths[2], const int pass)
{
- BMVert *v_end_pair[2];
- if (bm_vert_region_test(v, depths, pass)) {
- return true;
- }
- else if (BM_vert_is_edge_pair_manifold(v) &&
- bm_vert_pair_ends(v, v_end_pair) &&
- bm_vert_region_test(v_end_pair[0], depths, pass) &&
- bm_vert_region_test(v_end_pair[1], depths, pass))
- {
- return true;
- }
-
- return false;
+ BMVert *v_end_pair[2];
+ if (bm_vert_region_test(v, depths, pass)) {
+ return true;
+ }
+ else if (BM_vert_is_edge_pair_manifold(v) && bm_vert_pair_ends(v, v_end_pair) &&
+ bm_vert_region_test(v_end_pair[0], depths, pass) &&
+ bm_vert_region_test(v_end_pair[1], depths, pass)) {
+ return true;
+ }
+
+ return false;
}
#else
-static bool bm_vert_region_test_chain(BMVert *v, int * const depths[2], const int pass)
+static bool bm_vert_region_test_chain(BMVert *v, int *const depths[2], const int pass)
{
- return bm_vert_region_test(v, depths, pass);
+ return bm_vert_region_test(v, depths, pass);
}
#endif
/** \} */
-
/**
* Main logic for calculating region between 2 elements.
*
@@ -126,358 +120,359 @@ static bool bm_vert_region_test_chain(BMVert *v, int * const depths[2], const in
*
* \note Only verts without BM_ELEM_TAG will be walked over.
*/
-static LinkNode *mesh_calc_path_region_elem(
- BMesh *bm,
- BMElem *ele_src, BMElem *ele_dst,
- const char path_htype)
+static LinkNode *mesh_calc_path_region_elem(BMesh *bm,
+ BMElem *ele_src,
+ BMElem *ele_dst,
+ const char path_htype)
{
- int ele_verts_len[2];
- BMVert **ele_verts[2];
-
- /* Get vertices from any `ele_src/ele_dst` elements. */
- for (int side = 0; side < 2; side++) {
- BMElem *ele = side ? ele_dst : ele_src;
- int j = 0;
-
- if (ele->head.htype == BM_FACE) {
- BMFace *f = (BMFace *)ele;
- ele_verts[side] = BLI_array_alloca(ele_verts[side], f->len);
-
- BMLoop *l_first, *l_iter;
- l_iter = l_first = BM_FACE_FIRST_LOOP(f);
- do {
- ele_verts[side][j++] = l_iter->v;
- } while ((l_iter = l_iter->next) != l_first);
- }
- else if (ele->head.htype == BM_EDGE) {
- BMEdge *e = (BMEdge *)ele;
- ele_verts[side] = BLI_array_alloca(ele_verts[side], 2);
-
- ele_verts[side][j++] = e->v1;
- ele_verts[side][j++] = e->v2;
- }
- else if (ele->head.htype == BM_VERT) {
- BMVert *v = (BMVert *)ele;
- ele_verts[side] = BLI_array_alloca(ele_verts[side], 1);
-
- ele_verts[side][j++] = v;
- }
- else {
- BLI_assert(0);
- }
- ele_verts_len[side] = j;
- }
-
- int *depths[2] = {NULL};
- int pass = 0;
-
- BMVert **stack = MEM_mallocN(sizeof(*stack) * bm->totvert, __func__);
- BMVert **stack_other = MEM_mallocN(sizeof(*stack_other) * bm->totvert, __func__);
-
- STACK_DECLARE(stack);
- STACK_INIT(stack, bm->totvert);
-
- STACK_DECLARE(stack_other);
- STACK_INIT(stack_other, bm->totvert);
-
- BM_mesh_elem_index_ensure(bm, BM_VERT);
-
- /* After exhausting all possible elements, we should have found all elements on the 'side_other'.
- * otherwise, exit early. */
- bool found_all = false;
-
- for (int side = 0; side < 2; side++) {
- const int side_other = !side;
-
- /* initialize depths to -1 (un-touched), fill in with the depth as we walk over the edges. */
- depths[side] = MEM_mallocN(sizeof(*depths[side]) * bm->totvert, __func__);
- copy_vn_i(depths[side], bm->totvert, -1);
-
- /* needed for second side */
- STACK_CLEAR(stack);
- STACK_CLEAR(stack_other);
-
- for (int i = 0; i < ele_verts_len[side]; i++) {
- BMVert *v = ele_verts[side][i];
- depths[side][BM_elem_index_get(v)] = 0;
- if (v->e && !BM_elem_flag_test(v, BM_ELEM_TAG)) {
- STACK_PUSH(stack, v);
- }
- }
+ int ele_verts_len[2];
+ BMVert **ele_verts[2];
+
+ /* Get vertices from any `ele_src/ele_dst` elements. */
+ for (int side = 0; side < 2; side++) {
+ BMElem *ele = side ? ele_dst : ele_src;
+ int j = 0;
+
+ if (ele->head.htype == BM_FACE) {
+ BMFace *f = (BMFace *)ele;
+ ele_verts[side] = BLI_array_alloca(ele_verts[side], f->len);
+
+ BMLoop *l_first, *l_iter;
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ ele_verts[side][j++] = l_iter->v;
+ } while ((l_iter = l_iter->next) != l_first);
+ }
+ else if (ele->head.htype == BM_EDGE) {
+ BMEdge *e = (BMEdge *)ele;
+ ele_verts[side] = BLI_array_alloca(ele_verts[side], 2);
+
+ ele_verts[side][j++] = e->v1;
+ ele_verts[side][j++] = e->v2;
+ }
+ else if (ele->head.htype == BM_VERT) {
+ BMVert *v = (BMVert *)ele;
+ ele_verts[side] = BLI_array_alloca(ele_verts[side], 1);
+
+ ele_verts[side][j++] = v;
+ }
+ else {
+ BLI_assert(0);
+ }
+ ele_verts_len[side] = j;
+ }
+
+ int *depths[2] = {NULL};
+ int pass = 0;
+
+ BMVert **stack = MEM_mallocN(sizeof(*stack) * bm->totvert, __func__);
+ BMVert **stack_other = MEM_mallocN(sizeof(*stack_other) * bm->totvert, __func__);
+
+ STACK_DECLARE(stack);
+ STACK_INIT(stack, bm->totvert);
+
+ STACK_DECLARE(stack_other);
+ STACK_INIT(stack_other, bm->totvert);
+
+ BM_mesh_elem_index_ensure(bm, BM_VERT);
+
+ /* After exhausting all possible elements, we should have found all elements on the 'side_other'.
+ * otherwise, exit early. */
+ bool found_all = false;
+
+ for (int side = 0; side < 2; side++) {
+ const int side_other = !side;
+
+ /* initialize depths to -1 (un-touched), fill in with the depth as we walk over the edges. */
+ depths[side] = MEM_mallocN(sizeof(*depths[side]) * bm->totvert, __func__);
+ copy_vn_i(depths[side], bm->totvert, -1);
+
+ /* needed for second side */
+ STACK_CLEAR(stack);
+ STACK_CLEAR(stack_other);
+
+ for (int i = 0; i < ele_verts_len[side]; i++) {
+ BMVert *v = ele_verts[side][i];
+ depths[side][BM_elem_index_get(v)] = 0;
+ if (v->e && !BM_elem_flag_test(v, BM_ELEM_TAG)) {
+ STACK_PUSH(stack, v);
+ }
+ }
#ifdef USE_EDGE_CHAIN
- /* Expand initial state to end-point vertices when they only have 2x edges,
- * this prevents odd behavior when source or destination are in the middle of a long chain of edges. */
- if (ELEM(path_htype, BM_VERT, BM_EDGE)) {
- for (int i = 0; i < ele_verts_len[side]; i++) {
- BMVert *v = ele_verts[side][i];
- BMVert *v_end_pair[2];
- if (BM_vert_is_edge_pair_manifold(v) && bm_vert_pair_ends(v, v_end_pair)) {
- for (int j = 0; j < 2; j++) {
- const int v_end_index = BM_elem_index_get(v_end_pair[j]);
- if (depths[side][v_end_index] == -1) {
- depths[side][v_end_index] = 0;
- if (!BM_elem_flag_test(v_end_pair[j], BM_ELEM_TAG)) {
- STACK_PUSH(stack, v_end_pair[j]);
- }
- }
- }
- }
- }
- }
-#endif /* USE_EDGE_CHAIN */
-
- /* Keep walking over connected geometry until we find all the vertices in `ele_verts[side_other]`,
- * or exit the loop when theres no connection. */
- found_all = false;
- for (pass = 1; (STACK_SIZE(stack) != 0); pass++) {
- while (STACK_SIZE(stack) != 0) {
- BMVert *v_a = STACK_POP(stack);
- // const int v_a_index = BM_elem_index_get(v_a); /* only for assert */
- BMEdge *e = v_a->e;
-
- do {
- BMVert *v_b = BM_edge_other_vert(e, v_a);
- int v_b_index = BM_elem_index_get(v_b);
- if (depths[side][v_b_index] == -1) {
+ /* Expand initial state to end-point vertices when they only have 2x edges,
+ * this prevents odd behavior when source or destination are in the middle of a long chain of edges. */
+ if (ELEM(path_htype, BM_VERT, BM_EDGE)) {
+ for (int i = 0; i < ele_verts_len[side]; i++) {
+ BMVert *v = ele_verts[side][i];
+ BMVert *v_end_pair[2];
+ if (BM_vert_is_edge_pair_manifold(v) && bm_vert_pair_ends(v, v_end_pair)) {
+ for (int j = 0; j < 2; j++) {
+ const int v_end_index = BM_elem_index_get(v_end_pair[j]);
+ if (depths[side][v_end_index] == -1) {
+ depths[side][v_end_index] = 0;
+ if (!BM_elem_flag_test(v_end_pair[j], BM_ELEM_TAG)) {
+ STACK_PUSH(stack, v_end_pair[j]);
+ }
+ }
+ }
+ }
+ }
+ }
+#endif /* USE_EDGE_CHAIN */
+
+ /* Keep walking over connected geometry until we find all the vertices in `ele_verts[side_other]`,
+ * or exit the loop when theres no connection. */
+ found_all = false;
+ for (pass = 1; (STACK_SIZE(stack) != 0); pass++) {
+ while (STACK_SIZE(stack) != 0) {
+ BMVert *v_a = STACK_POP(stack);
+ // const int v_a_index = BM_elem_index_get(v_a); /* only for assert */
+ BMEdge *e = v_a->e;
+
+ do {
+ BMVert *v_b = BM_edge_other_vert(e, v_a);
+ int v_b_index = BM_elem_index_get(v_b);
+ if (depths[side][v_b_index] == -1) {
#ifdef USE_EDGE_CHAIN
- /* Walk along the chain, fill in values until we reach a vertex with 3+ edges. */
- {
- BMEdge *e_chain = e;
- while (BM_vert_is_edge_pair_manifold(v_b) &&
- ((depths[side][v_b_index] == -1)))
- {
- depths[side][v_b_index] = pass;
-
- BMEdge *e_chain_next = BM_DISK_EDGE_NEXT(e_chain, v_b);
- BLI_assert(BM_DISK_EDGE_NEXT(e_chain_next, v_b) == e_chain);
- v_b = BM_edge_other_vert(e_chain_next, v_b);
- v_b_index = BM_elem_index_get(v_b);
- e_chain = e_chain_next;
- }
- }
-#endif /* USE_EDGE_CHAIN */
-
- /* Add the other vertex to the stack, to be traversed in the next pass. */
- if (depths[side][v_b_index] == -1) {
+ /* Walk along the chain, fill in values until we reach a vertex with 3+ edges. */
+ {
+ BMEdge *e_chain = e;
+ while (BM_vert_is_edge_pair_manifold(v_b) && ((depths[side][v_b_index] == -1))) {
+ depths[side][v_b_index] = pass;
+
+ BMEdge *e_chain_next = BM_DISK_EDGE_NEXT(e_chain, v_b);
+ BLI_assert(BM_DISK_EDGE_NEXT(e_chain_next, v_b) == e_chain);
+ v_b = BM_edge_other_vert(e_chain_next, v_b);
+ v_b_index = BM_elem_index_get(v_b);
+ e_chain = e_chain_next;
+ }
+ }
+#endif /* USE_EDGE_CHAIN */
+
+ /* Add the other vertex to the stack, to be traversed in the next pass. */
+ if (depths[side][v_b_index] == -1) {
#ifdef USE_EDGE_CHAIN
- BLI_assert(!BM_vert_is_edge_pair_manifold(v_b));
+ BLI_assert(!BM_vert_is_edge_pair_manifold(v_b));
#endif
- BLI_assert(pass == depths[side][BM_elem_index_get(v_a)] + 1);
- depths[side][v_b_index] = pass;
- if (!BM_elem_flag_test(v_b, BM_ELEM_TAG)) {
- STACK_PUSH(stack_other, v_b);
- }
- }
- }
- } while ((e = BM_DISK_EDGE_NEXT(e, v_a)) != v_a->e);
- }
-
- /* Stop searching once theres none left.
- * Note that this looks in-efficient, however until the target elements reached,
- * it will exit immediately.
- * After that, it takes as many passes as the element has edges to finish off. */
- found_all = true;
- for (int i = 0; i < ele_verts_len[side_other]; i++) {
- if (depths[side][BM_elem_index_get(ele_verts[side_other][i])] == -1) {
- found_all = false;
- break;
- }
- }
- if (found_all == true) {
- pass++;
- break;
- }
-
- STACK_SWAP(stack, stack_other);
- }
-
- /* if we have nothing left, and didn't find all elements on the other side,
- * exit early and don't continue */
- if (found_all == false) {
- break;
- }
- }
-
- MEM_freeN(stack);
- MEM_freeN(stack_other);
-
-
- /* Now we have depths recorded from both sides,
- * select elements that use tagged verts. */
- LinkNode *path = NULL;
-
- if (found_all == false) {
- /* fail! (do nothing) */
- }
- else if (path_htype == BM_FACE) {
- BMIter fiter;
- BMFace *f;
-
- BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
- if (!BM_elem_flag_test(f, BM_ELEM_TAG)) {
- /* check all verts in face are tagged */
- BMLoop *l_first, *l_iter;
- l_iter = l_first = BM_FACE_FIRST_LOOP(f);
- bool ok = true;
+ BLI_assert(pass == depths[side][BM_elem_index_get(v_a)] + 1);
+ depths[side][v_b_index] = pass;
+ if (!BM_elem_flag_test(v_b, BM_ELEM_TAG)) {
+ STACK_PUSH(stack_other, v_b);
+ }
+ }
+ }
+ } while ((e = BM_DISK_EDGE_NEXT(e, v_a)) != v_a->e);
+ }
+
+ /* Stop searching once theres none left.
+ * Note that this looks in-efficient, however until the target elements reached,
+ * it will exit immediately.
+ * After that, it takes as many passes as the element has edges to finish off. */
+ found_all = true;
+ for (int i = 0; i < ele_verts_len[side_other]; i++) {
+ if (depths[side][BM_elem_index_get(ele_verts[side_other][i])] == -1) {
+ found_all = false;
+ break;
+ }
+ }
+ if (found_all == true) {
+ pass++;
+ break;
+ }
+
+ STACK_SWAP(stack, stack_other);
+ }
+
+ /* if we have nothing left, and didn't find all elements on the other side,
+ * exit early and don't continue */
+ if (found_all == false) {
+ break;
+ }
+ }
+
+ MEM_freeN(stack);
+ MEM_freeN(stack_other);
+
+ /* Now we have depths recorded from both sides,
+ * select elements that use tagged verts. */
+ LinkNode *path = NULL;
+
+ if (found_all == false) {
+ /* fail! (do nothing) */
+ }
+ else if (path_htype == BM_FACE) {
+ BMIter fiter;
+ BMFace *f;
+
+ BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
+ if (!BM_elem_flag_test(f, BM_ELEM_TAG)) {
+ /* check all verts in face are tagged */
+ BMLoop *l_first, *l_iter;
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ bool ok = true;
#if 0
- do {
- if (!bm_vert_region_test_chain(l_iter->v, depths, pass)) {
- ok = false;
- break;
- }
- } while ((l_iter = l_iter->next) != l_first);
+ do {
+ if (!bm_vert_region_test_chain(l_iter->v, depths, pass)) {
+ ok = false;
+ break;
+ }
+ } while ((l_iter = l_iter->next) != l_first);
#else
- /* Allowing a single failure on a face gives fewer 'gaps'.
- * While correct, in practice they're often part of what a user would consider the 'region'. */
- int ok_tests = f->len > 3 ? 1 : 0; /* how many times we may fail */
- do {
- if (!bm_vert_region_test_chain(l_iter->v, depths, pass)) {
- if (ok_tests == 0) {
- ok = false;
- break;
- }
- ok_tests--;
- }
- } while ((l_iter = l_iter->next) != l_first);
+ /* Allowing a single failure on a face gives fewer 'gaps'.
+ * While correct, in practice they're often part of what a user would consider the 'region'. */
+ int ok_tests = f->len > 3 ? 1 : 0; /* how many times we may fail */
+ do {
+ if (!bm_vert_region_test_chain(l_iter->v, depths, pass)) {
+ if (ok_tests == 0) {
+ ok = false;
+ break;
+ }
+ ok_tests--;
+ }
+ } while ((l_iter = l_iter->next) != l_first);
#endif
- if (ok) {
- BLI_linklist_prepend(&path, f);
- }
- }
- }
- }
- else if (path_htype == BM_EDGE) {
- BMIter eiter;
- BMEdge *e;
-
- BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) {
- if (!BM_elem_flag_test(e, BM_ELEM_TAG)) {
- /* check all verts in edge are tagged */
- bool ok = true;
- for (int j = 0; j < 2; j++) {
- if (!bm_vert_region_test_chain(*((&e->v1) + j), depths, pass)) {
- ok = false;
- break;
- }
- }
-
- if (ok) {
- BLI_linklist_prepend(&path, e);
- }
- }
- }
- }
- else if (path_htype == BM_VERT) {
- BMIter viter;
- BMVert *v;
-
- BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) {
- if (bm_vert_region_test_chain(v, depths, pass)) {
- BLI_linklist_prepend(&path, v);
- }
- }
- }
-
-
- for (int side = 0; side < 2; side++) {
- if (depths[side]) {
- MEM_freeN(depths[side]);
- }
- }
-
- return path;
+ if (ok) {
+ BLI_linklist_prepend(&path, f);
+ }
+ }
+ }
+ }
+ else if (path_htype == BM_EDGE) {
+ BMIter eiter;
+ BMEdge *e;
+
+ BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) {
+ if (!BM_elem_flag_test(e, BM_ELEM_TAG)) {
+ /* check all verts in edge are tagged */
+ bool ok = true;
+ for (int j = 0; j < 2; j++) {
+ if (!bm_vert_region_test_chain(*((&e->v1) + j), depths, pass)) {
+ ok = false;
+ break;
+ }
+ }
+
+ if (ok) {
+ BLI_linklist_prepend(&path, e);
+ }
+ }
+ }
+ }
+ else if (path_htype == BM_VERT) {
+ BMIter viter;
+ BMVert *v;
+
+ BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) {
+ if (bm_vert_region_test_chain(v, depths, pass)) {
+ BLI_linklist_prepend(&path, v);
+ }
+ }
+ }
+
+ for (int side = 0; side < 2; side++) {
+ if (depths[side]) {
+ MEM_freeN(depths[side]);
+ }
+ }
+
+ return path;
}
#undef USE_EDGE_CHAIN
-
/** \name Main Functions (exposed externally).
* \{ */
-LinkNode *BM_mesh_calc_path_region_vert(
- BMesh *bm, BMElem *ele_src, BMElem *ele_dst,
- bool (*filter_fn)(BMVert *, void *user_data), void *user_data)
+LinkNode *BM_mesh_calc_path_region_vert(BMesh *bm,
+ BMElem *ele_src,
+ BMElem *ele_dst,
+ bool (*filter_fn)(BMVert *, void *user_data),
+ void *user_data)
{
- LinkNode *path = NULL;
- /* BM_ELEM_TAG flag is used to store visited verts */
- BMVert *v;
- BMIter viter;
- int i;
+ LinkNode *path = NULL;
+ /* BM_ELEM_TAG flag is used to store visited verts */
+ BMVert *v;
+ BMIter viter;
+ int i;
- BM_ITER_MESH_INDEX (v, &viter, bm, BM_VERTS_OF_MESH, i) {
- BM_elem_flag_set(v, BM_ELEM_TAG, !filter_fn(v, user_data));
- BM_elem_index_set(v, i); /* set_inline */
- }
- bm->elem_index_dirty &= ~BM_VERT;
+ BM_ITER_MESH_INDEX (v, &viter, bm, BM_VERTS_OF_MESH, i) {
+ BM_elem_flag_set(v, BM_ELEM_TAG, !filter_fn(v, user_data));
+ BM_elem_index_set(v, i); /* set_inline */
+ }
+ bm->elem_index_dirty &= ~BM_VERT;
- path = mesh_calc_path_region_elem(bm, ele_src, ele_dst, BM_VERT);
+ path = mesh_calc_path_region_elem(bm, ele_src, ele_dst, BM_VERT);
- return path;
+ return path;
}
-LinkNode *BM_mesh_calc_path_region_edge(
- BMesh *bm, BMElem *ele_src, BMElem *ele_dst,
- bool (*filter_fn)(BMEdge *, void *user_data), void *user_data)
+LinkNode *BM_mesh_calc_path_region_edge(BMesh *bm,
+ BMElem *ele_src,
+ BMElem *ele_dst,
+ bool (*filter_fn)(BMEdge *, void *user_data),
+ void *user_data)
{
- LinkNode *path = NULL;
- /* BM_ELEM_TAG flag is used to store visited verts */
- BMEdge *e;
- BMIter eiter;
- int i;
-
- /* flush flag to verts */
- BM_mesh_elem_hflag_enable_all(bm, BM_VERT, BM_ELEM_TAG, false);
-
- BM_ITER_MESH_INDEX (e, &eiter, bm, BM_EDGES_OF_MESH, i) {
- bool test;
- BM_elem_flag_set(e, BM_ELEM_TAG, test = !filter_fn(e, user_data));
-
- /* flush tag to verts */
- if (test == false) {
- for (int j = 0; j < 2; j++) {
- BM_elem_flag_disable(*((&e->v1) + j), BM_ELEM_TAG);
- }
- }
- }
-
- path = mesh_calc_path_region_elem(bm, ele_src, ele_dst, BM_EDGE);
-
- return path;
+ LinkNode *path = NULL;
+ /* BM_ELEM_TAG flag is used to store visited verts */
+ BMEdge *e;
+ BMIter eiter;
+ int i;
+
+ /* flush flag to verts */
+ BM_mesh_elem_hflag_enable_all(bm, BM_VERT, BM_ELEM_TAG, false);
+
+ BM_ITER_MESH_INDEX (e, &eiter, bm, BM_EDGES_OF_MESH, i) {
+ bool test;
+ BM_elem_flag_set(e, BM_ELEM_TAG, test = !filter_fn(e, user_data));
+
+ /* flush tag to verts */
+ if (test == false) {
+ for (int j = 0; j < 2; j++) {
+ BM_elem_flag_disable(*((&e->v1) + j), BM_ELEM_TAG);
+ }
+ }
+ }
+
+ path = mesh_calc_path_region_elem(bm, ele_src, ele_dst, BM_EDGE);
+
+ return path;
}
-LinkNode *BM_mesh_calc_path_region_face(
- BMesh *bm, BMElem *ele_src, BMElem *ele_dst,
- bool (*filter_fn)(BMFace *, void *user_data), void *user_data)
+LinkNode *BM_mesh_calc_path_region_face(BMesh *bm,
+ BMElem *ele_src,
+ BMElem *ele_dst,
+ bool (*filter_fn)(BMFace *, void *user_data),
+ void *user_data)
{
- LinkNode *path = NULL;
- /* BM_ELEM_TAG flag is used to store visited verts */
- BMFace *f;
- BMIter fiter;
- int i;
-
- /* flush flag to verts */
- BM_mesh_elem_hflag_enable_all(bm, BM_VERT, BM_ELEM_TAG, false);
-
- BM_ITER_MESH_INDEX (f, &fiter, bm, BM_FACES_OF_MESH, i) {
- bool test;
- BM_elem_flag_set(f, BM_ELEM_TAG, test = !filter_fn(f, user_data));
-
- /* flush tag to verts */
- if (test == false) {
- BMLoop *l_first, *l_iter;
- l_iter = l_first = BM_FACE_FIRST_LOOP(f);
- do {
- BM_elem_flag_disable(l_iter->v, BM_ELEM_TAG);
- } while ((l_iter = l_iter->next) != l_first);
- }
- }
-
- path = mesh_calc_path_region_elem(bm, ele_src, ele_dst, BM_FACE);
-
- return path;
+ LinkNode *path = NULL;
+ /* BM_ELEM_TAG flag is used to store visited verts */
+ BMFace *f;
+ BMIter fiter;
+ int i;
+
+ /* flush flag to verts */
+ BM_mesh_elem_hflag_enable_all(bm, BM_VERT, BM_ELEM_TAG, false);
+
+ BM_ITER_MESH_INDEX (f, &fiter, bm, BM_FACES_OF_MESH, i) {
+ bool test;
+ BM_elem_flag_set(f, BM_ELEM_TAG, test = !filter_fn(f, user_data));
+
+ /* flush tag to verts */
+ if (test == false) {
+ BMLoop *l_first, *l_iter;
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ BM_elem_flag_disable(l_iter->v, BM_ELEM_TAG);
+ } while ((l_iter = l_iter->next) != l_first);
+ }
+ }
+
+ path = mesh_calc_path_region_elem(bm, ele_src, ele_dst, BM_FACE);
+
+ return path;
}
/** \} */
diff --git a/source/blender/bmesh/tools/bmesh_path_region.h b/source/blender/bmesh/tools/bmesh_path_region.h
index f3ed50f91fd..5204aa45da2 100644
--- a/source/blender/bmesh/tools/bmesh_path_region.h
+++ b/source/blender/bmesh/tools/bmesh_path_region.h
@@ -21,19 +21,25 @@
* \ingroup bmesh
*/
-struct LinkNode *BM_mesh_calc_path_region_vert(
- BMesh *bm, BMElem *ele_src, BMElem *ele_dst,
- bool (*test_fn)(BMVert *, void *user_data), void *user_data)
-ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2, 3);
+struct LinkNode *BM_mesh_calc_path_region_vert(BMesh *bm,
+ BMElem *ele_src,
+ BMElem *ele_dst,
+ bool (*test_fn)(BMVert *, void *user_data),
+ void *user_data) ATTR_WARN_UNUSED_RESULT
+ ATTR_NONNULL(1, 2, 3);
-struct LinkNode *BM_mesh_calc_path_region_edge(
- BMesh *bm, BMElem *ele_src, BMElem *ele_dst,
- bool (*test_fn)(BMEdge *, void *user_data), void *user_data)
-ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2, 3);
+struct LinkNode *BM_mesh_calc_path_region_edge(BMesh *bm,
+ BMElem *ele_src,
+ BMElem *ele_dst,
+ bool (*test_fn)(BMEdge *, void *user_data),
+ void *user_data) ATTR_WARN_UNUSED_RESULT
+ ATTR_NONNULL(1, 2, 3);
-struct LinkNode *BM_mesh_calc_path_region_face(
- BMesh *bm, BMElem *ele_src, BMElem *ele_dst,
- bool (*test_fn)(BMFace *, void *user_data), void *user_data)
-ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2, 3);
+struct LinkNode *BM_mesh_calc_path_region_face(BMesh *bm,
+ BMElem *ele_src,
+ BMElem *ele_dst,
+ bool (*test_fn)(BMFace *, void *user_data),
+ void *user_data) ATTR_WARN_UNUSED_RESULT
+ ATTR_NONNULL(1, 2, 3);
#endif /* __BMESH_PATH_REGION_H__ */
diff --git a/source/blender/bmesh/tools/bmesh_region_match.c b/source/blender/bmesh/tools/bmesh_region_match.c
index a89c41eecc0..6ddbaa6bb2e 100644
--- a/source/blender/bmesh/tools/bmesh_region_match.c
+++ b/source/blender/bmesh/tools/bmesh_region_match.c
@@ -43,7 +43,7 @@
#include "bmesh.h"
-#include "tools/bmesh_region_match.h" /* own incldue */
+#include "tools/bmesh_region_match.h" /* own incldue */
/* avoid re-creating ghash and pools for each search */
#define USE_WALKER_REUSE
@@ -66,7 +66,6 @@
#include "BLI_strict_flags.h"
-
/* -------------------------------------------------------------------- */
/* UUID-Walk API */
@@ -79,261 +78,251 @@ typedef uintptr_t UUID_Int;
typedef struct UUIDWalk {
- /* List of faces we can step onto (UUIDFaceStep's) */
- ListBase faces_step;
+ /* List of faces we can step onto (UUIDFaceStep's) */
+ ListBase faces_step;
- /* Face & Vert UUID's */
- GHash *verts_uuid;
- GHash *faces_uuid;
+ /* Face & Vert UUID's */
+ GHash *verts_uuid;
+ GHash *faces_uuid;
- /* memory pool for LinkNode's */
- BLI_mempool *link_pool;
+ /* memory pool for LinkNode's */
+ BLI_mempool *link_pool;
- /* memory pool for LinkBase's */
- BLI_mempool *lbase_pool;
+ /* memory pool for LinkBase's */
+ BLI_mempool *lbase_pool;
- /* memory pool for UUIDFaceStep's */
- BLI_mempool *step_pool;
- BLI_mempool *step_pool_items;
+ /* memory pool for UUIDFaceStep's */
+ BLI_mempool *step_pool;
+ BLI_mempool *step_pool_items;
- /* Optionaly use face-tag to isolate search */
- bool use_face_isolate;
+ /* Optionaly use face-tag to isolate search */
+ bool use_face_isolate;
- /* Increment for each pass added */
- UUID_Int pass;
+ /* Increment for each pass added */
+ UUID_Int pass;
- /* runtime vars, aviod re-creating each pass */
- struct {
- GHash *verts_uuid; /* BMVert -> UUID */
- GSet *faces_step; /* BMFace */
+ /* runtime vars, aviod re-creating each pass */
+ struct {
+ GHash *verts_uuid; /* BMVert -> UUID */
+ GSet *faces_step; /* BMFace */
- GHash *faces_from_uuid; /* UUID -> UUIDFaceStepItem */
+ GHash *faces_from_uuid; /* UUID -> UUIDFaceStepItem */
- UUID_Int *rehash_store;
- uint rehash_store_len;
- } cache;
+ UUID_Int *rehash_store;
+ uint rehash_store_len;
+ } cache;
} UUIDWalk;
/* stores a set of potential faces to step onto */
typedef struct UUIDFaceStep {
- struct UUIDFaceStep *next, *prev;
+ struct UUIDFaceStep *next, *prev;
- /* unsorted 'BMFace' */
- LinkNode *faces;
+ /* unsorted 'BMFace' */
+ LinkNode *faces;
- /* faces sorted into 'UUIDFaceStepItem' */
- ListBase items;
+ /* faces sorted into 'UUIDFaceStepItem' */
+ ListBase items;
} UUIDFaceStep;
/* store face-lists with same uuid */
typedef struct UUIDFaceStepItem {
- struct UUIDFaceStepItem *next, *prev;
- uintptr_t uuid;
+ struct UUIDFaceStepItem *next, *prev;
+ uintptr_t uuid;
- LinkNode *list;
- uint list_len;
+ LinkNode *list;
+ uint list_len;
} UUIDFaceStepItem;
-BLI_INLINE bool bm_uuidwalk_face_test(
- UUIDWalk *uuidwalk, BMFace *f)
+BLI_INLINE bool bm_uuidwalk_face_test(UUIDWalk *uuidwalk, BMFace *f)
{
- if (uuidwalk->use_face_isolate) {
- return BM_elem_flag_test_bool(f, BM_ELEM_TAG);
- }
- else {
- return true;
- }
+ if (uuidwalk->use_face_isolate) {
+ return BM_elem_flag_test_bool(f, BM_ELEM_TAG);
+ }
+ else {
+ return true;
+ }
}
-BLI_INLINE bool bm_uuidwalk_vert_lookup(
- UUIDWalk *uuidwalk, BMVert *v, UUID_Int *r_uuid)
+BLI_INLINE bool bm_uuidwalk_vert_lookup(UUIDWalk *uuidwalk, BMVert *v, UUID_Int *r_uuid)
{
- void **ret;
- ret = BLI_ghash_lookup_p(uuidwalk->verts_uuid, v);
- if (ret) {
- *r_uuid = (UUID_Int)(*ret);
- return true;
- }
- else {
- return false;
- }
+ void **ret;
+ ret = BLI_ghash_lookup_p(uuidwalk->verts_uuid, v);
+ if (ret) {
+ *r_uuid = (UUID_Int)(*ret);
+ return true;
+ }
+ else {
+ return false;
+ }
}
-BLI_INLINE bool bm_uuidwalk_face_lookup(
- UUIDWalk *uuidwalk, BMFace *f, UUID_Int *r_uuid)
+BLI_INLINE bool bm_uuidwalk_face_lookup(UUIDWalk *uuidwalk, BMFace *f, UUID_Int *r_uuid)
{
- void **ret;
- ret = BLI_ghash_lookup_p(uuidwalk->faces_uuid, f);
- if (ret) {
- *r_uuid = (UUID_Int)(*ret);
- return true;
- }
- else {
- return false;
- }
+ void **ret;
+ ret = BLI_ghash_lookup_p(uuidwalk->faces_uuid, f);
+ if (ret) {
+ *r_uuid = (UUID_Int)(*ret);
+ return true;
+ }
+ else {
+ return false;
+ }
}
static uint ghashutil_bmelem_indexhash(const void *key)
{
- const BMElem *ele = key;
- return (uint)BM_elem_index_get(ele);
+ const BMElem *ele = key;
+ return (uint)BM_elem_index_get(ele);
}
static bool ghashutil_bmelem_indexcmp(const void *a, const void *b)
{
- BLI_assert((a != b) == (BM_elem_index_get((BMElem *)a) != BM_elem_index_get((BMElem *)b)));
- return (a != b);
+ BLI_assert((a != b) == (BM_elem_index_get((BMElem *)a) != BM_elem_index_get((BMElem *)b)));
+ return (a != b);
}
-static GHash *ghash_bmelem_new_ex(
- const char *info,
- const uint nentries_reserve)
+static GHash *ghash_bmelem_new_ex(const char *info, const uint nentries_reserve)
{
- return BLI_ghash_new_ex(ghashutil_bmelem_indexhash, ghashutil_bmelem_indexcmp, info, nentries_reserve);
+ return BLI_ghash_new_ex(
+ ghashutil_bmelem_indexhash, ghashutil_bmelem_indexcmp, info, nentries_reserve);
}
-static GSet *gset_bmelem_new_ex(
- const char *info,
- const uint nentries_reserve)
+static GSet *gset_bmelem_new_ex(const char *info, const uint nentries_reserve)
{
- return BLI_gset_new_ex(ghashutil_bmelem_indexhash, ghashutil_bmelem_indexcmp, info, nentries_reserve);
+ return BLI_gset_new_ex(
+ ghashutil_bmelem_indexhash, ghashutil_bmelem_indexcmp, info, nentries_reserve);
}
-
static GHash *ghash_bmelem_new(const char *info)
{
- return ghash_bmelem_new_ex(info, 0);
+ return ghash_bmelem_new_ex(info, 0);
}
static GSet *gset_bmelem_new(const char *info)
{
- return gset_bmelem_new_ex(info, 0);
+ return gset_bmelem_new_ex(info, 0);
}
-
-static void bm_uuidwalk_init(
- UUIDWalk *uuidwalk,
- const uint faces_src_region_len,
- const uint verts_src_region_len)
+static void bm_uuidwalk_init(UUIDWalk *uuidwalk,
+ const uint faces_src_region_len,
+ const uint verts_src_region_len)
{
- BLI_listbase_clear(&uuidwalk->faces_step);
+ BLI_listbase_clear(&uuidwalk->faces_step);
- uuidwalk->verts_uuid = ghash_bmelem_new_ex(__func__, verts_src_region_len);
- uuidwalk->faces_uuid = ghash_bmelem_new_ex(__func__, faces_src_region_len);
+ uuidwalk->verts_uuid = ghash_bmelem_new_ex(__func__, verts_src_region_len);
+ uuidwalk->faces_uuid = ghash_bmelem_new_ex(__func__, faces_src_region_len);
- uuidwalk->cache.verts_uuid = ghash_bmelem_new(__func__);
- uuidwalk->cache.faces_step = gset_bmelem_new(__func__);
+ uuidwalk->cache.verts_uuid = ghash_bmelem_new(__func__);
+ uuidwalk->cache.faces_step = gset_bmelem_new(__func__);
- /* works because 'int' ghash works for intptr_t too */
- uuidwalk->cache.faces_from_uuid = BLI_ghash_int_new(__func__);
+ /* works because 'int' ghash works for intptr_t too */
+ uuidwalk->cache.faces_from_uuid = BLI_ghash_int_new(__func__);
- uuidwalk->cache.rehash_store = NULL;
- uuidwalk->cache.rehash_store_len = 0;
+ uuidwalk->cache.rehash_store = NULL;
+ uuidwalk->cache.rehash_store_len = 0;
- uuidwalk->use_face_isolate = false;
+ uuidwalk->use_face_isolate = false;
- /* smaller pool's for faster clearing */
- uuidwalk->link_pool = BLI_mempool_create(sizeof(LinkNode), 64, 64, BLI_MEMPOOL_NOP);
- uuidwalk->step_pool = BLI_mempool_create(sizeof(UUIDFaceStep), 64, 64, BLI_MEMPOOL_NOP);
- uuidwalk->step_pool_items = BLI_mempool_create(sizeof(UUIDFaceStepItem), 64, 64, BLI_MEMPOOL_NOP);
+ /* smaller pool's for faster clearing */
+ uuidwalk->link_pool = BLI_mempool_create(sizeof(LinkNode), 64, 64, BLI_MEMPOOL_NOP);
+ uuidwalk->step_pool = BLI_mempool_create(sizeof(UUIDFaceStep), 64, 64, BLI_MEMPOOL_NOP);
+ uuidwalk->step_pool_items = BLI_mempool_create(
+ sizeof(UUIDFaceStepItem), 64, 64, BLI_MEMPOOL_NOP);
- uuidwalk->pass = 1;
+ uuidwalk->pass = 1;
}
-static void bm_uuidwalk_clear(
- UUIDWalk *uuidwalk)
+static void bm_uuidwalk_clear(UUIDWalk *uuidwalk)
{
- BLI_listbase_clear(&uuidwalk->faces_step);
+ BLI_listbase_clear(&uuidwalk->faces_step);
- BLI_ghash_clear(uuidwalk->verts_uuid, NULL, NULL);
- BLI_ghash_clear(uuidwalk->faces_uuid, NULL, NULL);
+ BLI_ghash_clear(uuidwalk->verts_uuid, NULL, NULL);
+ BLI_ghash_clear(uuidwalk->faces_uuid, NULL, NULL);
- BLI_ghash_clear(uuidwalk->cache.verts_uuid, NULL, NULL);
- BLI_gset_clear(uuidwalk->cache.faces_step, NULL);
- BLI_ghash_clear(uuidwalk->cache.faces_from_uuid, NULL, NULL);
+ BLI_ghash_clear(uuidwalk->cache.verts_uuid, NULL, NULL);
+ BLI_gset_clear(uuidwalk->cache.faces_step, NULL);
+ BLI_ghash_clear(uuidwalk->cache.faces_from_uuid, NULL, NULL);
- /* keep rehash_store as-is, for reuse */
+ /* keep rehash_store as-is, for reuse */
- uuidwalk->use_face_isolate = false;
+ uuidwalk->use_face_isolate = false;
- BLI_mempool_clear(uuidwalk->link_pool);
- BLI_mempool_clear(uuidwalk->step_pool);
- BLI_mempool_clear(uuidwalk->step_pool_items);
+ BLI_mempool_clear(uuidwalk->link_pool);
+ BLI_mempool_clear(uuidwalk->step_pool);
+ BLI_mempool_clear(uuidwalk->step_pool_items);
- uuidwalk->pass = 1;
+ uuidwalk->pass = 1;
}
-static void bm_uuidwalk_free(
- UUIDWalk *uuidwalk)
+static void bm_uuidwalk_free(UUIDWalk *uuidwalk)
{
- /**
- * Handled by pools
- *
- * - uuidwalk->faces_step
- */
-
- BLI_ghash_free(uuidwalk->verts_uuid, NULL, NULL);
- BLI_ghash_free(uuidwalk->faces_uuid, NULL, NULL);
-
- /* cache */
- BLI_ghash_free(uuidwalk->cache.verts_uuid, NULL, NULL);
- BLI_gset_free(uuidwalk->cache.faces_step, NULL);
- BLI_ghash_free(uuidwalk->cache.faces_from_uuid, NULL, NULL);
- MEM_SAFE_FREE(uuidwalk->cache.rehash_store);
-
- BLI_mempool_destroy(uuidwalk->link_pool);
- BLI_mempool_destroy(uuidwalk->step_pool);
- BLI_mempool_destroy(uuidwalk->step_pool_items);
+ /**
+ * Handled by pools
+ *
+ * - uuidwalk->faces_step
+ */
+
+ BLI_ghash_free(uuidwalk->verts_uuid, NULL, NULL);
+ BLI_ghash_free(uuidwalk->faces_uuid, NULL, NULL);
+
+ /* cache */
+ BLI_ghash_free(uuidwalk->cache.verts_uuid, NULL, NULL);
+ BLI_gset_free(uuidwalk->cache.faces_step, NULL);
+ BLI_ghash_free(uuidwalk->cache.faces_from_uuid, NULL, NULL);
+ MEM_SAFE_FREE(uuidwalk->cache.rehash_store);
+
+ BLI_mempool_destroy(uuidwalk->link_pool);
+ BLI_mempool_destroy(uuidwalk->step_pool);
+ BLI_mempool_destroy(uuidwalk->step_pool_items);
}
-static UUID_Int bm_uuidwalk_calc_vert_uuid(
- UUIDWalk *uuidwalk, BMVert *v)
+static UUID_Int bm_uuidwalk_calc_vert_uuid(UUIDWalk *uuidwalk, BMVert *v)
{
-#define PRIME_VERT_SMALL 7
-#define PRIME_VERT_MID 43
-#define PRIME_VERT_LARGE 1031
-
-#define PRIME_FACE_SMALL 13
-#define PRIME_FACE_MID 53
-
- UUID_Int uuid;
-
- uuid = uuidwalk->pass * PRIME_VERT_LARGE;
-
- /* vert -> other */
- {
- uint tot = 0;
- BMIter eiter;
- BMEdge *e;
- BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
- BMVert *v_other = BM_edge_other_vert(e, v);
- UUID_Int uuid_other;
- if (bm_uuidwalk_vert_lookup(uuidwalk, v_other, &uuid_other)) {
- uuid ^= (uuid_other * PRIME_VERT_SMALL);
- tot += 1;
- }
- }
- uuid ^= (tot * PRIME_VERT_MID);
- }
-
- /* faces */
- {
- uint tot = 0;
- BMIter iter;
- BMFace *f;
-
- BM_ITER_ELEM (f, &iter, v, BM_FACES_OF_VERT) {
- UUID_Int uuid_other;
- if (bm_uuidwalk_face_lookup(uuidwalk, f, &uuid_other)) {
- uuid ^= (uuid_other * PRIME_FACE_SMALL);
- tot += 1;
- }
- }
- uuid ^= (tot * PRIME_FACE_MID);
- }
-
- return uuid;
+#define PRIME_VERT_SMALL 7
+#define PRIME_VERT_MID 43
+#define PRIME_VERT_LARGE 1031
+
+#define PRIME_FACE_SMALL 13
+#define PRIME_FACE_MID 53
+
+ UUID_Int uuid;
+
+ uuid = uuidwalk->pass * PRIME_VERT_LARGE;
+
+ /* vert -> other */
+ {
+ uint tot = 0;
+ BMIter eiter;
+ BMEdge *e;
+ BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
+ BMVert *v_other = BM_edge_other_vert(e, v);
+ UUID_Int uuid_other;
+ if (bm_uuidwalk_vert_lookup(uuidwalk, v_other, &uuid_other)) {
+ uuid ^= (uuid_other * PRIME_VERT_SMALL);
+ tot += 1;
+ }
+ }
+ uuid ^= (tot * PRIME_VERT_MID);
+ }
+
+ /* faces */
+ {
+ uint tot = 0;
+ BMIter iter;
+ BMFace *f;
+
+ BM_ITER_ELEM (f, &iter, v, BM_FACES_OF_VERT) {
+ UUID_Int uuid_other;
+ if (bm_uuidwalk_face_lookup(uuidwalk, f, &uuid_other)) {
+ uuid ^= (uuid_other * PRIME_FACE_SMALL);
+ tot += 1;
+ }
+ }
+ uuid ^= (tot * PRIME_FACE_MID);
+ }
+
+ return uuid;
#undef PRIME_VERT_SMALL
#undef PRIME_VERT_MID
@@ -343,50 +332,49 @@ static UUID_Int bm_uuidwalk_calc_vert_uuid(
#undef PRIME_FACE_MID
}
-static UUID_Int bm_uuidwalk_calc_face_uuid(
- UUIDWalk *uuidwalk, BMFace *f)
+static UUID_Int bm_uuidwalk_calc_face_uuid(UUIDWalk *uuidwalk, BMFace *f)
{
-#define PRIME_VERT_SMALL 11
-
-#define PRIME_FACE_SMALL 17
-#define PRIME_FACE_LARGE 1013
-
- UUID_Int uuid;
-
- uuid = uuidwalk->pass * (uint)f->len * PRIME_FACE_LARGE;
-
- /* face-verts */
- {
- BMLoop *l_iter, *l_first;
-
- l_iter = l_first = BM_FACE_FIRST_LOOP(f);
- do {
- UUID_Int uuid_other;
- if (bm_uuidwalk_vert_lookup(uuidwalk, l_iter->v, &uuid_other)) {
- uuid ^= (uuid_other * PRIME_VERT_SMALL);
- }
- } while ((l_iter = l_iter->next) != l_first);
- }
-
- /* face-faces (connected by edge) */
- {
- BMLoop *l_iter, *l_first;
-
- l_iter = l_first = BM_FACE_FIRST_LOOP(f);
- do {
- if (l_iter->radial_next != l_iter) {
- BMLoop *l_iter_radial = l_iter->radial_next;
- do {
- UUID_Int uuid_other;
- if (bm_uuidwalk_face_lookup(uuidwalk, l_iter_radial->f, &uuid_other)) {
- uuid ^= (uuid_other * PRIME_FACE_SMALL);
- }
- } while ((l_iter_radial = l_iter_radial->radial_next) != l_iter);
- }
- } while ((l_iter = l_iter->next) != l_first);
- }
-
- return uuid;
+#define PRIME_VERT_SMALL 11
+
+#define PRIME_FACE_SMALL 17
+#define PRIME_FACE_LARGE 1013
+
+ UUID_Int uuid;
+
+ uuid = uuidwalk->pass * (uint)f->len * PRIME_FACE_LARGE;
+
+ /* face-verts */
+ {
+ BMLoop *l_iter, *l_first;
+
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ UUID_Int uuid_other;
+ if (bm_uuidwalk_vert_lookup(uuidwalk, l_iter->v, &uuid_other)) {
+ uuid ^= (uuid_other * PRIME_VERT_SMALL);
+ }
+ } while ((l_iter = l_iter->next) != l_first);
+ }
+
+ /* face-faces (connected by edge) */
+ {
+ BMLoop *l_iter, *l_first;
+
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ if (l_iter->radial_next != l_iter) {
+ BMLoop *l_iter_radial = l_iter->radial_next;
+ do {
+ UUID_Int uuid_other;
+ if (bm_uuidwalk_face_lookup(uuidwalk, l_iter_radial->f, &uuid_other)) {
+ uuid ^= (uuid_other * PRIME_FACE_SMALL);
+ }
+ } while ((l_iter_radial = l_iter_radial->radial_next) != l_iter);
+ }
+ } while ((l_iter = l_iter->next) != l_first);
+ }
+
+ return uuid;
#undef PRIME_VERT_SMALL
@@ -394,346 +382,342 @@ static UUID_Int bm_uuidwalk_calc_face_uuid(
#undef PRIME_FACE_LARGE
}
-static void bm_uuidwalk_rehash_reserve(
- UUIDWalk *uuidwalk, uint rehash_store_len_new)
+static void bm_uuidwalk_rehash_reserve(UUIDWalk *uuidwalk, uint rehash_store_len_new)
{
- if (UNLIKELY(rehash_store_len_new > uuidwalk->cache.rehash_store_len)) {
- /* avoid re-allocs */
- rehash_store_len_new *= 2;
- uuidwalk->cache.rehash_store =
- MEM_reallocN(uuidwalk->cache.rehash_store,
- rehash_store_len_new * sizeof(*uuidwalk->cache.rehash_store));
- uuidwalk->cache.rehash_store_len = rehash_store_len_new;
- }
+ if (UNLIKELY(rehash_store_len_new > uuidwalk->cache.rehash_store_len)) {
+ /* avoid re-allocs */
+ rehash_store_len_new *= 2;
+ uuidwalk->cache.rehash_store = MEM_reallocN(uuidwalk->cache.rehash_store,
+ rehash_store_len_new *
+ sizeof(*uuidwalk->cache.rehash_store));
+ uuidwalk->cache.rehash_store_len = rehash_store_len_new;
+ }
}
/**
* Re-hash all elements, delay updating so as not to create feedback loop.
*/
-static void bm_uuidwalk_rehash(
- UUIDWalk *uuidwalk)
+static void bm_uuidwalk_rehash(UUIDWalk *uuidwalk)
{
- GHashIterator gh_iter;
- UUID_Int *uuid_store;
- uint i;
-
- uint rehash_store_len_new = MAX2(BLI_ghash_len(uuidwalk->verts_uuid),
- BLI_ghash_len(uuidwalk->faces_uuid));
-
- bm_uuidwalk_rehash_reserve(uuidwalk, rehash_store_len_new);
- uuid_store = uuidwalk->cache.rehash_store;
-
- /* verts */
- i = 0;
- GHASH_ITER (gh_iter, uuidwalk->verts_uuid) {
- BMVert *v = BLI_ghashIterator_getKey(&gh_iter);
- uuid_store[i++] = bm_uuidwalk_calc_vert_uuid(uuidwalk, v);
- }
- i = 0;
- GHASH_ITER (gh_iter, uuidwalk->verts_uuid) {
- void **uuid_p = BLI_ghashIterator_getValue_p(&gh_iter);
- *((UUID_Int *)uuid_p) = uuid_store[i++];
- }
-
- /* faces */
- i = 0;
- GHASH_ITER (gh_iter, uuidwalk->faces_uuid) {
- BMFace *f = BLI_ghashIterator_getKey(&gh_iter);
- uuid_store[i++] = bm_uuidwalk_calc_face_uuid(uuidwalk, f);
- }
- i = 0;
- GHASH_ITER (gh_iter, uuidwalk->faces_uuid) {
- void **uuid_p = BLI_ghashIterator_getValue_p(&gh_iter);
- *((UUID_Int *)uuid_p) = uuid_store[i++];
- }
+ GHashIterator gh_iter;
+ UUID_Int *uuid_store;
+ uint i;
+
+ uint rehash_store_len_new = MAX2(BLI_ghash_len(uuidwalk->verts_uuid),
+ BLI_ghash_len(uuidwalk->faces_uuid));
+
+ bm_uuidwalk_rehash_reserve(uuidwalk, rehash_store_len_new);
+ uuid_store = uuidwalk->cache.rehash_store;
+
+ /* verts */
+ i = 0;
+ GHASH_ITER (gh_iter, uuidwalk->verts_uuid) {
+ BMVert *v = BLI_ghashIterator_getKey(&gh_iter);
+ uuid_store[i++] = bm_uuidwalk_calc_vert_uuid(uuidwalk, v);
+ }
+ i = 0;
+ GHASH_ITER (gh_iter, uuidwalk->verts_uuid) {
+ void **uuid_p = BLI_ghashIterator_getValue_p(&gh_iter);
+ *((UUID_Int *)uuid_p) = uuid_store[i++];
+ }
+
+ /* faces */
+ i = 0;
+ GHASH_ITER (gh_iter, uuidwalk->faces_uuid) {
+ BMFace *f = BLI_ghashIterator_getKey(&gh_iter);
+ uuid_store[i++] = bm_uuidwalk_calc_face_uuid(uuidwalk, f);
+ }
+ i = 0;
+ GHASH_ITER (gh_iter, uuidwalk->faces_uuid) {
+ void **uuid_p = BLI_ghashIterator_getValue_p(&gh_iter);
+ *((UUID_Int *)uuid_p) = uuid_store[i++];
+ }
}
-static void bm_uuidwalk_rehash_facelinks(
- UUIDWalk *uuidwalk,
- LinkNode *faces, const uint faces_len,
- const bool is_init)
+static void bm_uuidwalk_rehash_facelinks(UUIDWalk *uuidwalk,
+ LinkNode *faces,
+ const uint faces_len,
+ const bool is_init)
{
- UUID_Int *uuid_store;
- LinkNode *f_link;
- uint i;
-
- bm_uuidwalk_rehash_reserve(uuidwalk, faces_len);
- uuid_store = uuidwalk->cache.rehash_store;
-
- i = 0;
- for (f_link = faces; f_link; f_link = f_link->next) {
- BMFace *f = f_link->link;
- uuid_store[i++] = bm_uuidwalk_calc_face_uuid(uuidwalk, f);
- }
-
- i = 0;
- if (is_init) {
- for (f_link = faces; f_link; f_link = f_link->next) {
- BMFace *f = f_link->link;
- BLI_ghash_insert(uuidwalk->faces_uuid, f, (void *)uuid_store[i++]);
- }
- }
- else {
- for (f_link = faces; f_link; f_link = f_link->next) {
- BMFace *f = f_link->link;
- void **uuid_p = BLI_ghash_lookup_p(uuidwalk->faces_uuid, f);
- *((UUID_Int *)uuid_p) = uuid_store[i++];
- }
- }
+ UUID_Int *uuid_store;
+ LinkNode *f_link;
+ uint i;
+
+ bm_uuidwalk_rehash_reserve(uuidwalk, faces_len);
+ uuid_store = uuidwalk->cache.rehash_store;
+
+ i = 0;
+ for (f_link = faces; f_link; f_link = f_link->next) {
+ BMFace *f = f_link->link;
+ uuid_store[i++] = bm_uuidwalk_calc_face_uuid(uuidwalk, f);
+ }
+
+ i = 0;
+ if (is_init) {
+ for (f_link = faces; f_link; f_link = f_link->next) {
+ BMFace *f = f_link->link;
+ BLI_ghash_insert(uuidwalk->faces_uuid, f, (void *)uuid_store[i++]);
+ }
+ }
+ else {
+ for (f_link = faces; f_link; f_link = f_link->next) {
+ BMFace *f = f_link->link;
+ void **uuid_p = BLI_ghash_lookup_p(uuidwalk->faces_uuid, f);
+ *((UUID_Int *)uuid_p) = uuid_store[i++];
+ }
+ }
}
-static bool bm_vert_is_uuid_connect(
- UUIDWalk *uuidwalk, BMVert *v)
+static bool bm_vert_is_uuid_connect(UUIDWalk *uuidwalk, BMVert *v)
{
- BMIter eiter;
- BMEdge *e;
-
- BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
- BMVert *v_other = BM_edge_other_vert(e, v);
- if (BLI_ghash_haskey(uuidwalk->verts_uuid, v_other)) {
- return true;
- }
- }
- return false;
+ BMIter eiter;
+ BMEdge *e;
+
+ BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
+ BMVert *v_other = BM_edge_other_vert(e, v);
+ if (BLI_ghash_haskey(uuidwalk->verts_uuid, v_other)) {
+ return true;
+ }
+ }
+ return false;
}
-static void bm_uuidwalk_pass_add(
- UUIDWalk *uuidwalk, LinkNode *faces_pass, const uint faces_pass_len)
+static void bm_uuidwalk_pass_add(UUIDWalk *uuidwalk,
+ LinkNode *faces_pass,
+ const uint faces_pass_len)
{
- GHashIterator gh_iter;
- GHash *verts_uuid_pass;
- GSet *faces_step_next;
- LinkNode *f_link;
-
- UUIDFaceStep *fstep;
-
- BLI_assert(faces_pass_len == (uint)BLI_linklist_count(faces_pass));
-
- /* rehash faces now all their verts have been added */
- bm_uuidwalk_rehash_facelinks(uuidwalk, faces_pass, faces_pass_len, true);
-
- /* create verts_new */
- verts_uuid_pass = uuidwalk->cache.verts_uuid;
- faces_step_next = uuidwalk->cache.faces_step;
-
- BLI_assert(BLI_ghash_len(verts_uuid_pass) == 0);
- BLI_assert(BLI_gset_len(faces_step_next) == 0);
-
- /* Add the face_step data from connected faces, creating new passes */
- fstep = BLI_mempool_alloc(uuidwalk->step_pool);
- BLI_addhead(&uuidwalk->faces_step, fstep);
- fstep->faces = NULL;
- BLI_listbase_clear(&fstep->items);
-
- for (f_link = faces_pass; f_link; f_link = f_link->next) {
- BMFace *f = f_link->link;
- BMLoop *l_iter, *l_first;
-
- l_iter = l_first = BM_FACE_FIRST_LOOP(f);
- do {
- /* fill verts_new */
- void **val_p;
- if (!BLI_ghash_haskey(uuidwalk->verts_uuid, l_iter->v) &&
- !BLI_ghash_ensure_p(verts_uuid_pass, l_iter->v, &val_p) &&
- (bm_vert_is_uuid_connect(uuidwalk, l_iter->v) == true))
- {
- const UUID_Int uuid = bm_uuidwalk_calc_vert_uuid(uuidwalk, l_iter->v);
- *val_p = (void *)uuid;
- }
-
- /* fill faces_step_next */
- if (l_iter->radial_next != l_iter) {
- BMLoop *l_iter_radial = l_iter->radial_next;
- do {
- if (!BLI_ghash_haskey(uuidwalk->faces_uuid, l_iter_radial->f) &&
- !BLI_gset_haskey(faces_step_next, l_iter_radial->f) &&
- (bm_uuidwalk_face_test(uuidwalk, l_iter_radial->f)))
- {
- BLI_gset_insert(faces_step_next, l_iter_radial->f);
-
- /* add to fstep */
- BLI_linklist_prepend_pool(&fstep->faces, l_iter_radial->f, uuidwalk->link_pool);
- }
- } while ((l_iter_radial = l_iter_radial->radial_next) != l_iter);
- }
- } while ((l_iter = l_iter->next) != l_first);
- }
-
- /* faces_uuid.update(verts_new) */
- GHASH_ITER (gh_iter, verts_uuid_pass) {
- BMVert *v = BLI_ghashIterator_getKey(&gh_iter);
- void *uuid_p = BLI_ghashIterator_getValue(&gh_iter);
- BLI_ghash_insert(uuidwalk->verts_uuid, v, uuid_p);
- }
-
- /* rehash faces now all their verts have been added */
- bm_uuidwalk_rehash_facelinks(uuidwalk, faces_pass, faces_pass_len, false);
-
- uuidwalk->pass += 1;
-
- BLI_ghash_clear(uuidwalk->cache.verts_uuid, NULL, NULL);
- BLI_gset_clear(uuidwalk->cache.faces_step, NULL);
+ GHashIterator gh_iter;
+ GHash *verts_uuid_pass;
+ GSet *faces_step_next;
+ LinkNode *f_link;
+
+ UUIDFaceStep *fstep;
+
+ BLI_assert(faces_pass_len == (uint)BLI_linklist_count(faces_pass));
+
+ /* rehash faces now all their verts have been added */
+ bm_uuidwalk_rehash_facelinks(uuidwalk, faces_pass, faces_pass_len, true);
+
+ /* create verts_new */
+ verts_uuid_pass = uuidwalk->cache.verts_uuid;
+ faces_step_next = uuidwalk->cache.faces_step;
+
+ BLI_assert(BLI_ghash_len(verts_uuid_pass) == 0);
+ BLI_assert(BLI_gset_len(faces_step_next) == 0);
+
+ /* Add the face_step data from connected faces, creating new passes */
+ fstep = BLI_mempool_alloc(uuidwalk->step_pool);
+ BLI_addhead(&uuidwalk->faces_step, fstep);
+ fstep->faces = NULL;
+ BLI_listbase_clear(&fstep->items);
+
+ for (f_link = faces_pass; f_link; f_link = f_link->next) {
+ BMFace *f = f_link->link;
+ BMLoop *l_iter, *l_first;
+
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ /* fill verts_new */
+ void **val_p;
+ if (!BLI_ghash_haskey(uuidwalk->verts_uuid, l_iter->v) &&
+ !BLI_ghash_ensure_p(verts_uuid_pass, l_iter->v, &val_p) &&
+ (bm_vert_is_uuid_connect(uuidwalk, l_iter->v) == true)) {
+ const UUID_Int uuid = bm_uuidwalk_calc_vert_uuid(uuidwalk, l_iter->v);
+ *val_p = (void *)uuid;
+ }
+
+ /* fill faces_step_next */
+ if (l_iter->radial_next != l_iter) {
+ BMLoop *l_iter_radial = l_iter->radial_next;
+ do {
+ if (!BLI_ghash_haskey(uuidwalk->faces_uuid, l_iter_radial->f) &&
+ !BLI_gset_haskey(faces_step_next, l_iter_radial->f) &&
+ (bm_uuidwalk_face_test(uuidwalk, l_iter_radial->f))) {
+ BLI_gset_insert(faces_step_next, l_iter_radial->f);
+
+ /* add to fstep */
+ BLI_linklist_prepend_pool(&fstep->faces, l_iter_radial->f, uuidwalk->link_pool);
+ }
+ } while ((l_iter_radial = l_iter_radial->radial_next) != l_iter);
+ }
+ } while ((l_iter = l_iter->next) != l_first);
+ }
+
+ /* faces_uuid.update(verts_new) */
+ GHASH_ITER (gh_iter, verts_uuid_pass) {
+ BMVert *v = BLI_ghashIterator_getKey(&gh_iter);
+ void *uuid_p = BLI_ghashIterator_getValue(&gh_iter);
+ BLI_ghash_insert(uuidwalk->verts_uuid, v, uuid_p);
+ }
+
+ /* rehash faces now all their verts have been added */
+ bm_uuidwalk_rehash_facelinks(uuidwalk, faces_pass, faces_pass_len, false);
+
+ uuidwalk->pass += 1;
+
+ BLI_ghash_clear(uuidwalk->cache.verts_uuid, NULL, NULL);
+ BLI_gset_clear(uuidwalk->cache.faces_step, NULL);
}
static int bm_face_len_cmp(const void *v1, const void *v2)
{
- const BMFace *f1 = v1, *f2 = v2;
-
- if (f1->len > f2->len) { return 1; }
- else if (f1->len < f2->len) { return -1; }
- else { return 0; }
+ const BMFace *f1 = v1, *f2 = v2;
+
+ if (f1->len > f2->len) {
+ return 1;
+ }
+ else if (f1->len < f2->len) {
+ return -1;
+ }
+ else {
+ return 0;
+ }
}
-static uint bm_uuidwalk_init_from_edge(
- UUIDWalk *uuidwalk, BMEdge *e)
+static uint bm_uuidwalk_init_from_edge(UUIDWalk *uuidwalk, BMEdge *e)
{
- BMLoop *l_iter = e->l;
- uint f_arr_len = (uint)BM_edge_face_count(e);
- BMFace **f_arr = BLI_array_alloca(f_arr, f_arr_len);
- uint fstep_num = 0, i = 0;
-
- do {
- BMFace *f = l_iter->f;
- if (bm_uuidwalk_face_test(uuidwalk, f)) {
- f_arr[i++] = f;
- }
- } while ((l_iter = l_iter->radial_next) != e->l);
- BLI_assert(i <= f_arr_len);
- f_arr_len = i;
-
- qsort(f_arr, f_arr_len, sizeof(*f_arr), bm_face_len_cmp);
-
- /* start us off! */
- {
- const UUID_Int uuid = PRIME_VERT_INIT;
- BLI_ghash_insert(uuidwalk->verts_uuid, e->v1, (void *)uuid);
- BLI_ghash_insert(uuidwalk->verts_uuid, e->v2, (void *)uuid);
- }
-
- /* turning an array into LinkNode's seems odd,
- * but this is just for initialization,
- * elsewhere using LinkNode's makes more sense */
- for (i = 0; i < f_arr_len; ) {
- LinkNode *faces_pass = NULL;
- const uint i_init = i;
- const int f_len = f_arr[i]->len;
-
- do {
- BLI_linklist_prepend_pool(&faces_pass, f_arr[i++], uuidwalk->link_pool);
- } while (i < f_arr_len && (f_len == f_arr[i]->len));
-
- bm_uuidwalk_pass_add(uuidwalk, faces_pass, i - i_init);
- BLI_linklist_free_pool(faces_pass, NULL, uuidwalk->link_pool);
- fstep_num += 1;
- }
-
- return fstep_num;
+ BMLoop *l_iter = e->l;
+ uint f_arr_len = (uint)BM_edge_face_count(e);
+ BMFace **f_arr = BLI_array_alloca(f_arr, f_arr_len);
+ uint fstep_num = 0, i = 0;
+
+ do {
+ BMFace *f = l_iter->f;
+ if (bm_uuidwalk_face_test(uuidwalk, f)) {
+ f_arr[i++] = f;
+ }
+ } while ((l_iter = l_iter->radial_next) != e->l);
+ BLI_assert(i <= f_arr_len);
+ f_arr_len = i;
+
+ qsort(f_arr, f_arr_len, sizeof(*f_arr), bm_face_len_cmp);
+
+ /* start us off! */
+ {
+ const UUID_Int uuid = PRIME_VERT_INIT;
+ BLI_ghash_insert(uuidwalk->verts_uuid, e->v1, (void *)uuid);
+ BLI_ghash_insert(uuidwalk->verts_uuid, e->v2, (void *)uuid);
+ }
+
+ /* turning an array into LinkNode's seems odd,
+ * but this is just for initialization,
+ * elsewhere using LinkNode's makes more sense */
+ for (i = 0; i < f_arr_len;) {
+ LinkNode *faces_pass = NULL;
+ const uint i_init = i;
+ const int f_len = f_arr[i]->len;
+
+ do {
+ BLI_linklist_prepend_pool(&faces_pass, f_arr[i++], uuidwalk->link_pool);
+ } while (i < f_arr_len && (f_len == f_arr[i]->len));
+
+ bm_uuidwalk_pass_add(uuidwalk, faces_pass, i - i_init);
+ BLI_linklist_free_pool(faces_pass, NULL, uuidwalk->link_pool);
+ fstep_num += 1;
+ }
+
+ return fstep_num;
}
#undef PRIME_VERT_INIT
/** \} */
-
/** \name Internal UUIDFaceStep API
* \{ */
static int facestep_sort(const void *a, const void *b)
{
- const UUIDFaceStepItem *fstep_a = a;
- const UUIDFaceStepItem *fstep_b = b;
- return (fstep_a->uuid > fstep_b->uuid) ? 1 : 0;
+ const UUIDFaceStepItem *fstep_a = a;
+ const UUIDFaceStepItem *fstep_b = b;
+ return (fstep_a->uuid > fstep_b->uuid) ? 1 : 0;
}
/**
* Put faces in lists based on their uuid's,
* re-run for each pass since rehashing may differentiate face-groups.
*/
-static bool bm_uuidwalk_facestep_begin(
- UUIDWalk *uuidwalk, UUIDFaceStep *fstep)
+static bool bm_uuidwalk_facestep_begin(UUIDWalk *uuidwalk, UUIDFaceStep *fstep)
{
- LinkNode *f_link, *f_link_next, **f_link_prev_p;
- bool ok = false;
-
- BLI_assert(BLI_ghash_len(uuidwalk->cache.faces_from_uuid) == 0);
- BLI_assert(BLI_listbase_is_empty(&fstep->items));
-
- f_link_prev_p = &fstep->faces;
- for (f_link = fstep->faces; f_link; f_link = f_link_next) {
- BMFace *f = f_link->link;
- f_link_next = f_link->next;
-
- /* possible another pass added this face already, free in that case */
- if (!BLI_ghash_haskey(uuidwalk->faces_uuid, f)) {
- const UUID_Int uuid = bm_uuidwalk_calc_face_uuid(uuidwalk, f);
- UUIDFaceStepItem *fstep_item;
- void **val_p;
-
- ok = true;
-
- if (BLI_ghash_ensure_p(uuidwalk->cache.faces_from_uuid, (void *)uuid, &val_p)) {
- fstep_item = *val_p;
- }
- else {
- fstep_item = *val_p = BLI_mempool_alloc(uuidwalk->step_pool_items);
-
- /* add to start, so its handled on the next round of passes */
- BLI_addhead(&fstep->items, fstep_item);
- fstep_item->uuid = uuid;
- fstep_item->list = NULL;
- fstep_item->list_len = 0;
- }
-
- BLI_linklist_prepend_pool(&fstep_item->list, f, uuidwalk->link_pool);
- fstep_item->list_len += 1;
-
- f_link_prev_p = &f_link->next;
- }
- else {
- *f_link_prev_p = f_link->next;
- BLI_mempool_free(uuidwalk->link_pool, f_link);
- }
- }
-
- BLI_ghash_clear(uuidwalk->cache.faces_from_uuid, NULL, NULL);
-
- BLI_listbase_sort(&fstep->items, facestep_sort);
-
- return ok;
+ LinkNode *f_link, *f_link_next, **f_link_prev_p;
+ bool ok = false;
+
+ BLI_assert(BLI_ghash_len(uuidwalk->cache.faces_from_uuid) == 0);
+ BLI_assert(BLI_listbase_is_empty(&fstep->items));
+
+ f_link_prev_p = &fstep->faces;
+ for (f_link = fstep->faces; f_link; f_link = f_link_next) {
+ BMFace *f = f_link->link;
+ f_link_next = f_link->next;
+
+ /* possible another pass added this face already, free in that case */
+ if (!BLI_ghash_haskey(uuidwalk->faces_uuid, f)) {
+ const UUID_Int uuid = bm_uuidwalk_calc_face_uuid(uuidwalk, f);
+ UUIDFaceStepItem *fstep_item;
+ void **val_p;
+
+ ok = true;
+
+ if (BLI_ghash_ensure_p(uuidwalk->cache.faces_from_uuid, (void *)uuid, &val_p)) {
+ fstep_item = *val_p;
+ }
+ else {
+ fstep_item = *val_p = BLI_mempool_alloc(uuidwalk->step_pool_items);
+
+ /* add to start, so its handled on the next round of passes */
+ BLI_addhead(&fstep->items, fstep_item);
+ fstep_item->uuid = uuid;
+ fstep_item->list = NULL;
+ fstep_item->list_len = 0;
+ }
+
+ BLI_linklist_prepend_pool(&fstep_item->list, f, uuidwalk->link_pool);
+ fstep_item->list_len += 1;
+
+ f_link_prev_p = &f_link->next;
+ }
+ else {
+ *f_link_prev_p = f_link->next;
+ BLI_mempool_free(uuidwalk->link_pool, f_link);
+ }
+ }
+
+ BLI_ghash_clear(uuidwalk->cache.faces_from_uuid, NULL, NULL);
+
+ BLI_listbase_sort(&fstep->items, facestep_sort);
+
+ return ok;
}
/**
* Cleans up temp data from #bm_uuidwalk_facestep_begin
*/
-static void bm_uuidwalk_facestep_end(
- UUIDWalk *uuidwalk, UUIDFaceStep *fstep)
+static void bm_uuidwalk_facestep_end(UUIDWalk *uuidwalk, UUIDFaceStep *fstep)
{
- UUIDFaceStepItem *fstep_item;
+ UUIDFaceStepItem *fstep_item;
- while ((fstep_item = BLI_pophead(&fstep->items))) {
- BLI_mempool_free(uuidwalk->step_pool_items, fstep_item);
- }
+ while ((fstep_item = BLI_pophead(&fstep->items))) {
+ BLI_mempool_free(uuidwalk->step_pool_items, fstep_item);
+ }
}
-static void bm_uuidwalk_facestep_free(
- UUIDWalk *uuidwalk, UUIDFaceStep *fstep)
+static void bm_uuidwalk_facestep_free(UUIDWalk *uuidwalk, UUIDFaceStep *fstep)
{
- LinkNode *f_link, *f_link_next;
+ LinkNode *f_link, *f_link_next;
- BLI_assert(BLI_listbase_is_empty(&fstep->items));
+ BLI_assert(BLI_listbase_is_empty(&fstep->items));
- for (f_link = fstep->faces; f_link; f_link = f_link_next) {
- f_link_next = f_link->next;
- BLI_mempool_free(uuidwalk->link_pool, f_link);
- }
+ for (f_link = fstep->faces; f_link; f_link = f_link_next) {
+ f_link_next = f_link->next;
+ BLI_mempool_free(uuidwalk->link_pool, f_link);
+ }
- BLI_remlink(&uuidwalk->faces_step, fstep);
- BLI_mempool_free(uuidwalk->step_pool, fstep);
+ BLI_remlink(&uuidwalk->faces_step, fstep);
+ BLI_mempool_free(uuidwalk->step_pool, fstep);
}
/** \} */
-
/* -------------------------------------------------------------------- */
/* Main Loop to match up regions */
@@ -743,197 +727,191 @@ static void bm_uuidwalk_facestep_free(
*/
static BMFace **bm_mesh_region_match_pair(
#ifdef USE_WALKER_REUSE
- UUIDWalk *w_src, UUIDWalk *w_dst,
+ UUIDWalk *w_src,
+ UUIDWalk *w_dst,
#endif
- BMEdge *e_src, BMEdge *e_dst,
- const uint faces_src_region_len,
- const uint verts_src_region_len,
- uint *r_faces_result_len)
+ BMEdge *e_src,
+ BMEdge *e_dst,
+ const uint faces_src_region_len,
+ const uint verts_src_region_len,
+ uint *r_faces_result_len)
{
#ifndef USE_WALKER_REUSE
- UUIDWalk w_src_, w_dst_;
- UUIDWalk *w_src = &w_src_, *w_dst = &w_dst_;
+ UUIDWalk w_src_, w_dst_;
+ UUIDWalk *w_src = &w_src_, *w_dst = &w_dst_;
#endif
- BMFace **faces_result = NULL;
- bool found = false;
+ BMFace **faces_result = NULL;
+ bool found = false;
- BLI_assert(e_src != e_dst);
+ BLI_assert(e_src != e_dst);
#ifndef USE_WALKER_REUSE
- bm_uuidwalk_init(w_src, faces_src_region_len, verts_src_region_len);
- bm_uuidwalk_init(w_dst, faces_src_region_len, verts_src_region_len);
+ bm_uuidwalk_init(w_src, faces_src_region_len, verts_src_region_len);
+ bm_uuidwalk_init(w_dst, faces_src_region_len, verts_src_region_len);
#endif
- w_src->use_face_isolate = true;
-
- /* setup the initial state */
- if (UNLIKELY(bm_uuidwalk_init_from_edge(w_src, e_src) !=
- bm_uuidwalk_init_from_edge(w_dst, e_dst)))
- {
- /* should never happen, if verts passed are compatible, but to be safe... */
- goto finally;
- }
-
- bm_uuidwalk_rehash_reserve(w_src, MAX2(faces_src_region_len, verts_src_region_len));
- bm_uuidwalk_rehash_reserve(w_dst, MAX2(faces_src_region_len, verts_src_region_len));
-
- while (true) {
- bool ok = false;
-
- UUIDFaceStep *fstep_src = w_src->faces_step.first;
- UUIDFaceStep *fstep_dst = w_dst->faces_step.first;
-
- BLI_assert(BLI_listbase_count(&w_src->faces_step) == BLI_listbase_count(&w_dst->faces_step));
-
- while (fstep_src) {
-
- /* even if the destination has faces,
- * it's not important, since the source doesn't, free and move-on. */
- if (fstep_src->faces == NULL) {
- UUIDFaceStep *fstep_src_next = fstep_src->next;
- UUIDFaceStep *fstep_dst_next = fstep_dst->next;
- bm_uuidwalk_facestep_free(w_src, fstep_src);
- bm_uuidwalk_facestep_free(w_dst, fstep_dst);
- fstep_src = fstep_src_next;
- fstep_dst = fstep_dst_next;
- continue;
- }
-
- if (bm_uuidwalk_facestep_begin(w_src, fstep_src) &&
- bm_uuidwalk_facestep_begin(w_dst, fstep_dst))
- {
- /* Step over face-lists with matching UUID's
- * both lists are sorted, so no need for lookups.
- * The data is created on 'begin' and cleared on 'end' */
- UUIDFaceStepItem *fstep_item_src;
- UUIDFaceStepItem *fstep_item_dst;
- for (fstep_item_src = fstep_src->items.first,
- fstep_item_dst = fstep_dst->items.first;
- fstep_item_src && fstep_item_dst;
- fstep_item_src = fstep_item_src->next,
- fstep_item_dst = fstep_item_dst->next)
- {
- while ((fstep_item_dst != NULL) &&
- (fstep_item_dst->uuid < fstep_item_src->uuid))
- {
- fstep_item_dst = fstep_item_dst->next;
- }
-
- if ((fstep_item_dst == NULL) ||
- (fstep_item_src->uuid != fstep_item_dst->uuid) ||
- (fstep_item_src->list_len > fstep_item_dst->list_len))
- {
- /* if the target walker has less than the source
- * then the islands don't match, bail early */
- ok = false;
- break;
- }
-
- if (fstep_item_src->list_len == fstep_item_dst->list_len) {
- /* found a match */
- bm_uuidwalk_pass_add(w_src, fstep_item_src->list, fstep_item_src->list_len);
- bm_uuidwalk_pass_add(w_dst, fstep_item_dst->list, fstep_item_dst->list_len);
-
- BLI_linklist_free_pool(fstep_item_src->list, NULL, w_src->link_pool);
- BLI_linklist_free_pool(fstep_item_dst->list, NULL, w_dst->link_pool);
-
- fstep_item_src->list = NULL;
- fstep_item_src->list_len = 0;
-
- fstep_item_dst->list = NULL;
- fstep_item_dst->list_len = 0;
-
- ok = true;
- }
- }
- }
-
- bm_uuidwalk_facestep_end(w_src, fstep_src);
- bm_uuidwalk_facestep_end(w_dst, fstep_dst);
-
- /* lock-step */
- fstep_src = fstep_src->next;
- fstep_dst = fstep_dst->next;
- }
-
- if (!ok) {
- break;
- }
-
- found = (BLI_ghash_len(w_dst->faces_uuid) == faces_src_region_len);
- if (found) {
- break;
- }
-
- /* Expensive! but some cases fails without.
- * (also faster in other cases since it can rule-out invalid regions) */
- bm_uuidwalk_rehash(w_src);
- bm_uuidwalk_rehash(w_dst);
- }
-
- if (found) {
- GHashIterator gh_iter;
- const uint faces_result_len = BLI_ghash_len(w_dst->faces_uuid);
- uint i;
-
- faces_result = MEM_mallocN(sizeof(*faces_result) * (faces_result_len + 1), __func__);
- GHASH_ITER_INDEX (gh_iter, w_dst->faces_uuid, i) {
- BMFace *f = BLI_ghashIterator_getKey(&gh_iter);
- faces_result[i] = f;
- }
- faces_result[faces_result_len] = NULL;
- *r_faces_result_len = faces_result_len;
- }
- else {
- *r_faces_result_len = 0;
- }
+ w_src->use_face_isolate = true;
+
+ /* setup the initial state */
+ if (UNLIKELY(bm_uuidwalk_init_from_edge(w_src, e_src) !=
+ bm_uuidwalk_init_from_edge(w_dst, e_dst))) {
+ /* should never happen, if verts passed are compatible, but to be safe... */
+ goto finally;
+ }
+
+ bm_uuidwalk_rehash_reserve(w_src, MAX2(faces_src_region_len, verts_src_region_len));
+ bm_uuidwalk_rehash_reserve(w_dst, MAX2(faces_src_region_len, verts_src_region_len));
+
+ while (true) {
+ bool ok = false;
+
+ UUIDFaceStep *fstep_src = w_src->faces_step.first;
+ UUIDFaceStep *fstep_dst = w_dst->faces_step.first;
+
+ BLI_assert(BLI_listbase_count(&w_src->faces_step) == BLI_listbase_count(&w_dst->faces_step));
+
+ while (fstep_src) {
+
+ /* even if the destination has faces,
+ * it's not important, since the source doesn't, free and move-on. */
+ if (fstep_src->faces == NULL) {
+ UUIDFaceStep *fstep_src_next = fstep_src->next;
+ UUIDFaceStep *fstep_dst_next = fstep_dst->next;
+ bm_uuidwalk_facestep_free(w_src, fstep_src);
+ bm_uuidwalk_facestep_free(w_dst, fstep_dst);
+ fstep_src = fstep_src_next;
+ fstep_dst = fstep_dst_next;
+ continue;
+ }
+
+ if (bm_uuidwalk_facestep_begin(w_src, fstep_src) &&
+ bm_uuidwalk_facestep_begin(w_dst, fstep_dst)) {
+ /* Step over face-lists with matching UUID's
+ * both lists are sorted, so no need for lookups.
+ * The data is created on 'begin' and cleared on 'end' */
+ UUIDFaceStepItem *fstep_item_src;
+ UUIDFaceStepItem *fstep_item_dst;
+ for (fstep_item_src = fstep_src->items.first, fstep_item_dst = fstep_dst->items.first;
+ fstep_item_src && fstep_item_dst;
+ fstep_item_src = fstep_item_src->next, fstep_item_dst = fstep_item_dst->next) {
+ while ((fstep_item_dst != NULL) && (fstep_item_dst->uuid < fstep_item_src->uuid)) {
+ fstep_item_dst = fstep_item_dst->next;
+ }
+
+ if ((fstep_item_dst == NULL) || (fstep_item_src->uuid != fstep_item_dst->uuid) ||
+ (fstep_item_src->list_len > fstep_item_dst->list_len)) {
+ /* if the target walker has less than the source
+ * then the islands don't match, bail early */
+ ok = false;
+ break;
+ }
+
+ if (fstep_item_src->list_len == fstep_item_dst->list_len) {
+ /* found a match */
+ bm_uuidwalk_pass_add(w_src, fstep_item_src->list, fstep_item_src->list_len);
+ bm_uuidwalk_pass_add(w_dst, fstep_item_dst->list, fstep_item_dst->list_len);
+
+ BLI_linklist_free_pool(fstep_item_src->list, NULL, w_src->link_pool);
+ BLI_linklist_free_pool(fstep_item_dst->list, NULL, w_dst->link_pool);
+
+ fstep_item_src->list = NULL;
+ fstep_item_src->list_len = 0;
+
+ fstep_item_dst->list = NULL;
+ fstep_item_dst->list_len = 0;
+
+ ok = true;
+ }
+ }
+ }
+
+ bm_uuidwalk_facestep_end(w_src, fstep_src);
+ bm_uuidwalk_facestep_end(w_dst, fstep_dst);
+
+ /* lock-step */
+ fstep_src = fstep_src->next;
+ fstep_dst = fstep_dst->next;
+ }
+
+ if (!ok) {
+ break;
+ }
+
+ found = (BLI_ghash_len(w_dst->faces_uuid) == faces_src_region_len);
+ if (found) {
+ break;
+ }
+
+ /* Expensive! but some cases fails without.
+ * (also faster in other cases since it can rule-out invalid regions) */
+ bm_uuidwalk_rehash(w_src);
+ bm_uuidwalk_rehash(w_dst);
+ }
+
+ if (found) {
+ GHashIterator gh_iter;
+ const uint faces_result_len = BLI_ghash_len(w_dst->faces_uuid);
+ uint i;
+
+ faces_result = MEM_mallocN(sizeof(*faces_result) * (faces_result_len + 1), __func__);
+ GHASH_ITER_INDEX(gh_iter, w_dst->faces_uuid, i)
+ {
+ BMFace *f = BLI_ghashIterator_getKey(&gh_iter);
+ faces_result[i] = f;
+ }
+ faces_result[faces_result_len] = NULL;
+ *r_faces_result_len = faces_result_len;
+ }
+ else {
+ *r_faces_result_len = 0;
+ }
finally:
#ifdef USE_WALKER_REUSE
- bm_uuidwalk_clear(w_src);
- bm_uuidwalk_clear(w_dst);
+ bm_uuidwalk_clear(w_src);
+ bm_uuidwalk_clear(w_dst);
#else
- bm_uuidwalk_free(w_src);
- bm_uuidwalk_free(w_dst);
+ bm_uuidwalk_free(w_src);
+ bm_uuidwalk_free(w_dst);
#endif
- return faces_result;
+ return faces_result;
}
/**
* Tag as visited, avoid re-use.
*/
-static void bm_face_array_visit(
- BMFace **faces, const uint faces_len,
- uint *r_verts_len,
- bool visit_faces)
+static void bm_face_array_visit(BMFace **faces,
+ const uint faces_len,
+ uint *r_verts_len,
+ bool visit_faces)
{
- uint verts_len = 0;
- uint i;
- for (i = 0; i < faces_len; i++) {
- BMFace *f = faces[i];
- BMLoop *l_iter, *l_first;
- l_iter = l_first = BM_FACE_FIRST_LOOP(f);
- do {
- if (r_verts_len) {
- if (!BM_elem_flag_test(l_iter->v, BM_ELEM_TAG)) {
- verts_len += 1;
- }
- }
-
- BM_elem_flag_enable(l_iter->e, BM_ELEM_TAG);
- BM_elem_flag_enable(l_iter->v, BM_ELEM_TAG);
- } while ((l_iter = l_iter->next) != l_first);
-
- if (visit_faces) {
- BM_elem_flag_enable(f, BM_ELEM_TAG);
- }
- }
-
- if (r_verts_len) {
- *r_verts_len = verts_len;
- }
+ uint verts_len = 0;
+ uint i;
+ for (i = 0; i < faces_len; i++) {
+ BMFace *f = faces[i];
+ BMLoop *l_iter, *l_first;
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ if (r_verts_len) {
+ if (!BM_elem_flag_test(l_iter->v, BM_ELEM_TAG)) {
+ verts_len += 1;
+ }
+ }
+
+ BM_elem_flag_enable(l_iter->e, BM_ELEM_TAG);
+ BM_elem_flag_enable(l_iter->v, BM_ELEM_TAG);
+ } while ((l_iter = l_iter->next) != l_first);
+
+ if (visit_faces) {
+ BM_elem_flag_enable(f, BM_ELEM_TAG);
+ }
+ }
+
+ if (r_verts_len) {
+ *r_verts_len = verts_len;
+ }
}
#ifdef USE_PIVOT_SEARCH
@@ -946,74 +924,73 @@ typedef intptr_t SUID_Int;
static bool bm_edge_is_region_boundary(BMEdge *e)
{
- if (e->l->radial_next != e->l) {
- BMLoop *l_iter = e->l;
- do {
- if (!BM_elem_flag_test(l_iter->f, BM_ELEM_TAG)) {
- return true;
- }
- } while ((l_iter = l_iter->radial_next) != e->l);
- return false;
- }
- else {
- /* boundary */
- return true;
- }
+ if (e->l->radial_next != e->l) {
+ BMLoop *l_iter = e->l;
+ do {
+ if (!BM_elem_flag_test(l_iter->f, BM_ELEM_TAG)) {
+ return true;
+ }
+ } while ((l_iter = l_iter->radial_next) != e->l);
+ return false;
+ }
+ else {
+ /* boundary */
+ return true;
+ }
}
-static void bm_face_region_pivot_edge_use_best(
- GHash *gh, BMEdge *e_test,
- BMEdge **r_e_pivot_best,
- SUID_Int e_pivot_best_id[2])
+static void bm_face_region_pivot_edge_use_best(GHash *gh,
+ BMEdge *e_test,
+ BMEdge **r_e_pivot_best,
+ SUID_Int e_pivot_best_id[2])
{
- SUID_Int e_pivot_test_id[2];
-
- e_pivot_test_id[0] = (SUID_Int)BLI_ghash_lookup(gh, e_test->v1);
- e_pivot_test_id[1] = (SUID_Int)BLI_ghash_lookup(gh, e_test->v2);
- if (e_pivot_test_id[0] > e_pivot_test_id[1]) {
- SWAP(SUID_Int, e_pivot_test_id[0], e_pivot_test_id[1]);
- }
-
- if ((*r_e_pivot_best == NULL) ||
- ((e_pivot_best_id[0] != e_pivot_test_id[0]) ?
- (e_pivot_best_id[0] < e_pivot_test_id[0]) :
- (e_pivot_best_id[1] < e_pivot_test_id[1])))
- {
- e_pivot_best_id[0] = e_pivot_test_id[0];
- e_pivot_best_id[1] = e_pivot_test_id[1];
-
- /* both verts are from the same pass, record this! */
- *r_e_pivot_best = e_test;
- }
+ SUID_Int e_pivot_test_id[2];
+
+ e_pivot_test_id[0] = (SUID_Int)BLI_ghash_lookup(gh, e_test->v1);
+ e_pivot_test_id[1] = (SUID_Int)BLI_ghash_lookup(gh, e_test->v2);
+ if (e_pivot_test_id[0] > e_pivot_test_id[1]) {
+ SWAP(SUID_Int, e_pivot_test_id[0], e_pivot_test_id[1]);
+ }
+
+ if ((*r_e_pivot_best == NULL) ||
+ ((e_pivot_best_id[0] != e_pivot_test_id[0]) ? (e_pivot_best_id[0] < e_pivot_test_id[0]) :
+ (e_pivot_best_id[1] < e_pivot_test_id[1]))) {
+ e_pivot_best_id[0] = e_pivot_test_id[0];
+ e_pivot_best_id[1] = e_pivot_test_id[1];
+
+ /* both verts are from the same pass, record this! */
+ *r_e_pivot_best = e_test;
+ }
}
/* quick id from a boundary vertex */
static SUID_Int bm_face_region_vert_boundary_id(BMVert *v)
{
-#define PRIME_VERT_SMALL_A 7
-#define PRIME_VERT_SMALL_B 13
-#define PRIME_VERT_MID_A 103
-#define PRIME_VERT_MID_B 131
-
- int tot = 0;
- BMIter iter;
- BMLoop *l;
- SUID_Int id = PRIME_VERT_MID_A;
-
- BM_ITER_ELEM (l, &iter, v, BM_LOOPS_OF_VERT) {
- const bool is_boundary_vert = (bm_edge_is_region_boundary(l->e) || bm_edge_is_region_boundary(l->prev->e));
- id ^= l->f->len * (is_boundary_vert ? PRIME_VERT_SMALL_A : PRIME_VERT_SMALL_B);
- tot += 1;
- }
-
- id ^= (tot * PRIME_VERT_MID_B);
-
- return id ? ABS(id) : 1;
-
-#undef PRIME_VERT_SMALL_A
-#undef PRIME_VERT_SMALL_B
-#undef PRIME_VERT_MID_A
-#undef PRIME_VERT_MID_B
+# define PRIME_VERT_SMALL_A 7
+# define PRIME_VERT_SMALL_B 13
+# define PRIME_VERT_MID_A 103
+# define PRIME_VERT_MID_B 131
+
+ int tot = 0;
+ BMIter iter;
+ BMLoop *l;
+ SUID_Int id = PRIME_VERT_MID_A;
+
+ BM_ITER_ELEM (l, &iter, v, BM_LOOPS_OF_VERT) {
+ const bool is_boundary_vert = (bm_edge_is_region_boundary(l->e) ||
+ bm_edge_is_region_boundary(l->prev->e));
+ id ^= l->f->len * (is_boundary_vert ? PRIME_VERT_SMALL_A : PRIME_VERT_SMALL_B);
+ tot += 1;
+ }
+
+ id ^= (tot * PRIME_VERT_MID_B);
+
+ return id ? ABS(id) : 1;
+
+# undef PRIME_VERT_SMALL_A
+# undef PRIME_VERT_SMALL_B
+# undef PRIME_VERT_MID_A
+# undef PRIME_VERT_MID_B
}
/**
@@ -1021,52 +998,52 @@ static SUID_Int bm_face_region_vert_boundary_id(BMVert *v)
*/
static SUID_Int bm_face_region_vert_pass_id(GHash *gh, BMVert *v)
{
- BMIter eiter;
- BMEdge *e;
- SUID_Int tot = 0;
- SUID_Int v_sum_face_len = 0;
- SUID_Int v_sum_id = 0;
- SUID_Int id;
- SUID_Int id_min = INTPTR_MIN + 1;
-
-#define PRIME_VERT_MID_A 23
-#define PRIME_VERT_MID_B 31
-
- BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
- if (BM_elem_flag_test(e, BM_ELEM_TAG)) {
- BMVert *v_other = BM_edge_other_vert(e, v);
- if (BM_elem_flag_test(v_other, BM_ELEM_TAG)) {
- /* non-zero values aren't allowed... so no need to check haskey */
- SUID_Int v_other_id = (SUID_Int)BLI_ghash_lookup(gh, v_other);
- if (v_other_id > 0) {
- v_sum_id += v_other_id;
- tot += 1;
-
- /* face-count */
- {
- BMLoop *l_iter = e->l;
- do {
- if (BM_elem_flag_test(l_iter->f, BM_ELEM_TAG)) {
- v_sum_face_len += l_iter->f->len;
- }
- } while ((l_iter = l_iter->radial_next) != e->l);
- }
- }
- }
- }
- }
-
- id = (tot * PRIME_VERT_MID_A);
- id ^= (v_sum_face_len * PRIME_VERT_MID_B);
- id ^= v_sum_id;
-
- /* disallow 0 & min (since it can't be flipped) */
- id = (UNLIKELY(id == 0) ? 1 : UNLIKELY(id < id_min) ? id_min : id);
-
- return ABS(id);
-
-#undef PRIME_VERT_MID_A
-#undef PRIME_VERT_MID_B
+ BMIter eiter;
+ BMEdge *e;
+ SUID_Int tot = 0;
+ SUID_Int v_sum_face_len = 0;
+ SUID_Int v_sum_id = 0;
+ SUID_Int id;
+ SUID_Int id_min = INTPTR_MIN + 1;
+
+# define PRIME_VERT_MID_A 23
+# define PRIME_VERT_MID_B 31
+
+ BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
+ if (BM_elem_flag_test(e, BM_ELEM_TAG)) {
+ BMVert *v_other = BM_edge_other_vert(e, v);
+ if (BM_elem_flag_test(v_other, BM_ELEM_TAG)) {
+ /* non-zero values aren't allowed... so no need to check haskey */
+ SUID_Int v_other_id = (SUID_Int)BLI_ghash_lookup(gh, v_other);
+ if (v_other_id > 0) {
+ v_sum_id += v_other_id;
+ tot += 1;
+
+ /* face-count */
+ {
+ BMLoop *l_iter = e->l;
+ do {
+ if (BM_elem_flag_test(l_iter->f, BM_ELEM_TAG)) {
+ v_sum_face_len += l_iter->f->len;
+ }
+ } while ((l_iter = l_iter->radial_next) != e->l);
+ }
+ }
+ }
+ }
+ }
+
+ id = (tot * PRIME_VERT_MID_A);
+ id ^= (v_sum_face_len * PRIME_VERT_MID_B);
+ id ^= v_sum_id;
+
+ /* disallow 0 & min (since it can't be flipped) */
+ id = (UNLIKELY(id == 0) ? 1 : UNLIKELY(id < id_min) ? id_min : id);
+
+ return ABS(id);
+
+# undef PRIME_VERT_MID_A
+# undef PRIME_VERT_MID_B
}
/**
@@ -1076,185 +1053,184 @@ static SUID_Int bm_face_region_vert_pass_id(GHash *gh, BMVert *v)
*
* This is only called once on the source region (no need to be highly optimized).
*/
-static BMEdge *bm_face_region_pivot_edge_find(
- BMFace **faces_region, uint faces_region_len,
- uint verts_region_len,
- uint *r_depth)
+static BMEdge *bm_face_region_pivot_edge_find(BMFace **faces_region,
+ uint faces_region_len,
+ uint verts_region_len,
+ uint *r_depth)
{
- /* note, keep deterministic where possible (geometry order independent)
- * this function assumed all visit faces & edges are tagged */
-
- BLI_LINKSTACK_DECLARE(vert_queue_prev, BMVert *);
- BLI_LINKSTACK_DECLARE(vert_queue_next, BMVert *);
-
- GHash *gh = BLI_ghash_ptr_new(__func__);
- uint i;
-
- BMEdge *e_pivot = NULL;
- /* pick any non-boundary edge (not ideal) */
- BMEdge *e_pivot_fallback = NULL;
-
- SUID_Int pass = 0;
-
- /* total verts in 'gs' we have visited - aka - not v_init_none */
- uint vert_queue_used = 0;
-
- BLI_LINKSTACK_INIT(vert_queue_prev);
- BLI_LINKSTACK_INIT(vert_queue_next);
-
- /* face-verts */
- for (i = 0; i < faces_region_len; i++) {
- BMFace *f = faces_region[i];
-
- BMLoop *l_iter, *l_first;
- l_iter = l_first = BM_FACE_FIRST_LOOP(f);
- do {
- BMEdge *e = l_iter->e;
- if (bm_edge_is_region_boundary(e)) {
- uint j;
- for (j = 0; j < 2; j++) {
- void **val_p;
- if (!BLI_ghash_ensure_p(gh, (&e->v1)[j], &val_p)) {
- SUID_Int v_id = bm_face_region_vert_boundary_id((&e->v1)[j]);
- *val_p = (void *)v_id;
- BLI_LINKSTACK_PUSH(vert_queue_prev, (&e->v1)[j]);
- vert_queue_used += 1;
- }
- }
- }
- else {
- /* use incase (depth == 0), no interior verts */
- e_pivot_fallback = e;
- }
- } while ((l_iter = l_iter->next) != l_first);
- }
-
- while (BLI_LINKSTACK_SIZE(vert_queue_prev)) {
- BMVert *v;
- while ((v = BLI_LINKSTACK_POP(vert_queue_prev))) {
- BMIter eiter;
- BMEdge *e;
- BLI_assert(BLI_ghash_haskey(gh, v));
- BLI_assert((SUID_Int)BLI_ghash_lookup(gh, v) > 0);
- BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
- if (BM_elem_flag_test(e, BM_ELEM_TAG)) {
- BMVert *v_other = BM_edge_other_vert(e, v);
- if (BM_elem_flag_test(v_other, BM_ELEM_TAG)) {
- void **val_p;
- if (!BLI_ghash_ensure_p(gh, v_other, &val_p)) {
- /* add as negative, so we know not to read from them this pass */
- const SUID_Int v_id_other = -bm_face_region_vert_pass_id(gh, v_other);
- *val_p = (void *)v_id_other;
- BLI_LINKSTACK_PUSH(vert_queue_next, v_other);
- vert_queue_used += 1;
- }
- }
- }
- }
- }
-
- /* flip all the newly added hashes to positive */
- {
- LinkNode *v_link;
- for (v_link = vert_queue_next; v_link; v_link = v_link->next) {
- SUID_Int *v_id_p = (SUID_Int *)BLI_ghash_lookup_p(gh, v_link->link);
- *v_id_p = -(*v_id_p);
- BLI_assert(*v_id_p > 0);
- }
- }
-
- BLI_LINKSTACK_SWAP(vert_queue_prev, vert_queue_next);
- pass += 1;
-
- if (vert_queue_used == verts_region_len) {
- break;
- }
- }
-
- if (BLI_LINKSTACK_SIZE(vert_queue_prev) >= 2) {
- /* common case - we managed to find some interior verts */
- LinkNode *v_link;
- BMEdge *e_pivot_best = NULL;
- SUID_Int e_pivot_best_id[2] = {0, 0};
-
- /* temp untag, so we can quickly know what other verts are in this last pass */
- for (v_link = vert_queue_prev; v_link; v_link = v_link->next) {
- BMVert *v = v_link->link;
- BM_elem_flag_disable(v, BM_ELEM_TAG);
- }
-
- /* restore correct tagging */
- for (v_link = vert_queue_prev; v_link; v_link = v_link->next) {
- BMIter eiter;
- BMEdge *e_test;
-
- BMVert *v = v_link->link;
- BM_elem_flag_enable(v, BM_ELEM_TAG);
-
- BM_ITER_ELEM (e_test, &eiter, v, BM_EDGES_OF_VERT) {
- if (BM_elem_flag_test(e_test, BM_ELEM_TAG)) {
- BMVert *v_other = BM_edge_other_vert(e_test, v);
- if (BM_elem_flag_test(v_other, BM_ELEM_TAG) == false) {
- bm_face_region_pivot_edge_use_best(gh, e_test, &e_pivot_best, e_pivot_best_id);
- }
- }
- }
- }
-
- e_pivot = e_pivot_best;
- }
-
- if ((e_pivot == NULL) && BLI_LINKSTACK_SIZE(vert_queue_prev)) {
- /* find the best single edge */
- BMEdge *e_pivot_best = NULL;
- SUID_Int e_pivot_best_id[2] = {0, 0};
-
- LinkNode *v_link;
-
- /* reduce a pass since we're having to step into a previous passes vert,
- * and will be closer to the boundary */
- BLI_assert(pass != 0);
- pass -= 1;
-
- for (v_link = vert_queue_prev; v_link; v_link = v_link->next) {
- BMVert *v = v_link->link;
-
- BMIter eiter;
- BMEdge *e_test;
- BM_ITER_ELEM (e_test, &eiter, v, BM_EDGES_OF_VERT) {
- if (BM_elem_flag_test(e_test, BM_ELEM_TAG)) {
- BMVert *v_other = BM_edge_other_vert(e_test, v);
- if (BM_elem_flag_test(v_other, BM_ELEM_TAG)) {
- bm_face_region_pivot_edge_use_best(gh, e_test, &e_pivot_best, e_pivot_best_id);
- }
- }
- }
- }
-
- e_pivot = e_pivot_best;
- }
-
- BLI_LINKSTACK_FREE(vert_queue_prev);
- BLI_LINKSTACK_FREE(vert_queue_next);
-
- BLI_ghash_free(gh, NULL, NULL);
-
- if (e_pivot == NULL) {
-#ifdef DEBUG_PRINT
- printf("%s: using fallback edge!\n", __func__);
-#endif
- e_pivot = e_pivot_fallback;
- pass = 0;
- }
-
- *r_depth = (uint)pass;
-
- return e_pivot;
+ /* note, keep deterministic where possible (geometry order independent)
+ * this function assumed all visit faces & edges are tagged */
+
+ BLI_LINKSTACK_DECLARE(vert_queue_prev, BMVert *);
+ BLI_LINKSTACK_DECLARE(vert_queue_next, BMVert *);
+
+ GHash *gh = BLI_ghash_ptr_new(__func__);
+ uint i;
+
+ BMEdge *e_pivot = NULL;
+ /* pick any non-boundary edge (not ideal) */
+ BMEdge *e_pivot_fallback = NULL;
+
+ SUID_Int pass = 0;
+
+ /* total verts in 'gs' we have visited - aka - not v_init_none */
+ uint vert_queue_used = 0;
+
+ BLI_LINKSTACK_INIT(vert_queue_prev);
+ BLI_LINKSTACK_INIT(vert_queue_next);
+
+ /* face-verts */
+ for (i = 0; i < faces_region_len; i++) {
+ BMFace *f = faces_region[i];
+
+ BMLoop *l_iter, *l_first;
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ BMEdge *e = l_iter->e;
+ if (bm_edge_is_region_boundary(e)) {
+ uint j;
+ for (j = 0; j < 2; j++) {
+ void **val_p;
+ if (!BLI_ghash_ensure_p(gh, (&e->v1)[j], &val_p)) {
+ SUID_Int v_id = bm_face_region_vert_boundary_id((&e->v1)[j]);
+ *val_p = (void *)v_id;
+ BLI_LINKSTACK_PUSH(vert_queue_prev, (&e->v1)[j]);
+ vert_queue_used += 1;
+ }
+ }
+ }
+ else {
+ /* use incase (depth == 0), no interior verts */
+ e_pivot_fallback = e;
+ }
+ } while ((l_iter = l_iter->next) != l_first);
+ }
+
+ while (BLI_LINKSTACK_SIZE(vert_queue_prev)) {
+ BMVert *v;
+ while ((v = BLI_LINKSTACK_POP(vert_queue_prev))) {
+ BMIter eiter;
+ BMEdge *e;
+ BLI_assert(BLI_ghash_haskey(gh, v));
+ BLI_assert((SUID_Int)BLI_ghash_lookup(gh, v) > 0);
+ BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
+ if (BM_elem_flag_test(e, BM_ELEM_TAG)) {
+ BMVert *v_other = BM_edge_other_vert(e, v);
+ if (BM_elem_flag_test(v_other, BM_ELEM_TAG)) {
+ void **val_p;
+ if (!BLI_ghash_ensure_p(gh, v_other, &val_p)) {
+ /* add as negative, so we know not to read from them this pass */
+ const SUID_Int v_id_other = -bm_face_region_vert_pass_id(gh, v_other);
+ *val_p = (void *)v_id_other;
+ BLI_LINKSTACK_PUSH(vert_queue_next, v_other);
+ vert_queue_used += 1;
+ }
+ }
+ }
+ }
+ }
+
+ /* flip all the newly added hashes to positive */
+ {
+ LinkNode *v_link;
+ for (v_link = vert_queue_next; v_link; v_link = v_link->next) {
+ SUID_Int *v_id_p = (SUID_Int *)BLI_ghash_lookup_p(gh, v_link->link);
+ *v_id_p = -(*v_id_p);
+ BLI_assert(*v_id_p > 0);
+ }
+ }
+
+ BLI_LINKSTACK_SWAP(vert_queue_prev, vert_queue_next);
+ pass += 1;
+
+ if (vert_queue_used == verts_region_len) {
+ break;
+ }
+ }
+
+ if (BLI_LINKSTACK_SIZE(vert_queue_prev) >= 2) {
+ /* common case - we managed to find some interior verts */
+ LinkNode *v_link;
+ BMEdge *e_pivot_best = NULL;
+ SUID_Int e_pivot_best_id[2] = {0, 0};
+
+ /* temp untag, so we can quickly know what other verts are in this last pass */
+ for (v_link = vert_queue_prev; v_link; v_link = v_link->next) {
+ BMVert *v = v_link->link;
+ BM_elem_flag_disable(v, BM_ELEM_TAG);
+ }
+
+ /* restore correct tagging */
+ for (v_link = vert_queue_prev; v_link; v_link = v_link->next) {
+ BMIter eiter;
+ BMEdge *e_test;
+
+ BMVert *v = v_link->link;
+ BM_elem_flag_enable(v, BM_ELEM_TAG);
+
+ BM_ITER_ELEM (e_test, &eiter, v, BM_EDGES_OF_VERT) {
+ if (BM_elem_flag_test(e_test, BM_ELEM_TAG)) {
+ BMVert *v_other = BM_edge_other_vert(e_test, v);
+ if (BM_elem_flag_test(v_other, BM_ELEM_TAG) == false) {
+ bm_face_region_pivot_edge_use_best(gh, e_test, &e_pivot_best, e_pivot_best_id);
+ }
+ }
+ }
+ }
+
+ e_pivot = e_pivot_best;
+ }
+
+ if ((e_pivot == NULL) && BLI_LINKSTACK_SIZE(vert_queue_prev)) {
+ /* find the best single edge */
+ BMEdge *e_pivot_best = NULL;
+ SUID_Int e_pivot_best_id[2] = {0, 0};
+
+ LinkNode *v_link;
+
+ /* reduce a pass since we're having to step into a previous passes vert,
+ * and will be closer to the boundary */
+ BLI_assert(pass != 0);
+ pass -= 1;
+
+ for (v_link = vert_queue_prev; v_link; v_link = v_link->next) {
+ BMVert *v = v_link->link;
+
+ BMIter eiter;
+ BMEdge *e_test;
+ BM_ITER_ELEM (e_test, &eiter, v, BM_EDGES_OF_VERT) {
+ if (BM_elem_flag_test(e_test, BM_ELEM_TAG)) {
+ BMVert *v_other = BM_edge_other_vert(e_test, v);
+ if (BM_elem_flag_test(v_other, BM_ELEM_TAG)) {
+ bm_face_region_pivot_edge_use_best(gh, e_test, &e_pivot_best, e_pivot_best_id);
+ }
+ }
+ }
+ }
+
+ e_pivot = e_pivot_best;
+ }
+
+ BLI_LINKSTACK_FREE(vert_queue_prev);
+ BLI_LINKSTACK_FREE(vert_queue_next);
+
+ BLI_ghash_free(gh, NULL, NULL);
+
+ if (e_pivot == NULL) {
+# ifdef DEBUG_PRINT
+ printf("%s: using fallback edge!\n", __func__);
+# endif
+ e_pivot = e_pivot_fallback;
+ pass = 0;
+ }
+
+ *r_depth = (uint)pass;
+
+ return e_pivot;
}
/** \} */
-#endif /* USE_PIVOT_SEARCH */
-
+#endif /* USE_PIVOT_SEARCH */
/* -------------------------------------------------------------------- */
/* Quick UUID pass - identify candidates */
@@ -1268,104 +1244,96 @@ typedef uintptr_t UUIDFashMatch;
static UUIDFashMatch bm_vert_fasthash_single(BMVert *v)
{
- BMIter eiter;
- BMEdge *e;
- UUIDFashMatch e_num = 0, f_num = 0, l_num = 0;
-
-#define PRIME_EDGE 7
-#define PRIME_FACE 31
-#define PRIME_LOOP 61
-
- BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
- if (!BM_edge_is_wire(e)) {
- BMLoop *l_iter = e->l;
- e_num += 1;
- do {
- f_num += 1;
- l_num += (uint)l_iter->f->len;
- } while ((l_iter = l_iter->radial_next) != e->l);
- }
- }
-
- return ((e_num * PRIME_EDGE) ^
- (f_num * PRIME_FACE) *
- (l_num * PRIME_LOOP));
-
-#undef PRIME_EDGE
-#undef PRIME_FACE
-#undef PRIME_LOOP
+ BMIter eiter;
+ BMEdge *e;
+ UUIDFashMatch e_num = 0, f_num = 0, l_num = 0;
+
+# define PRIME_EDGE 7
+# define PRIME_FACE 31
+# define PRIME_LOOP 61
+
+ BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
+ if (!BM_edge_is_wire(e)) {
+ BMLoop *l_iter = e->l;
+ e_num += 1;
+ do {
+ f_num += 1;
+ l_num += (uint)l_iter->f->len;
+ } while ((l_iter = l_iter->radial_next) != e->l);
+ }
+ }
+
+ return ((e_num * PRIME_EDGE) ^ (f_num * PRIME_FACE) * (l_num * PRIME_LOOP));
+
+# undef PRIME_EDGE
+# undef PRIME_FACE
+# undef PRIME_LOOP
}
-static UUIDFashMatch *bm_vert_fasthash_create(
- BMesh *bm, const uint depth)
+static UUIDFashMatch *bm_vert_fasthash_create(BMesh *bm, const uint depth)
{
- UUIDFashMatch *id_prev;
- UUIDFashMatch *id_curr;
- uint pass, i;
- BMVert *v;
- BMIter iter;
+ UUIDFashMatch *id_prev;
+ UUIDFashMatch *id_curr;
+ uint pass, i;
+ BMVert *v;
+ BMIter iter;
- id_prev = MEM_mallocN(sizeof(*id_prev) * (uint)bm->totvert, __func__);
- id_curr = MEM_mallocN(sizeof(*id_curr) * (uint)bm->totvert, __func__);
+ id_prev = MEM_mallocN(sizeof(*id_prev) * (uint)bm->totvert, __func__);
+ id_curr = MEM_mallocN(sizeof(*id_curr) * (uint)bm->totvert, __func__);
- BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) {
- id_prev[i] = bm_vert_fasthash_single(v);
- }
+ BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) {
+ id_prev[i] = bm_vert_fasthash_single(v);
+ }
- for (pass = 0; pass < depth; pass++) {
- BMEdge *e;
+ for (pass = 0; pass < depth; pass++) {
+ BMEdge *e;
- memcpy(id_curr, id_prev, sizeof(*id_prev) * (uint)bm->totvert);
+ memcpy(id_curr, id_prev, sizeof(*id_prev) * (uint)bm->totvert);
- BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
- if (BM_edge_is_wire(e) == false) {
- const int i1 = BM_elem_index_get(e->v1);
- const int i2 = BM_elem_index_get(e->v2);
+ BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
+ if (BM_edge_is_wire(e) == false) {
+ const int i1 = BM_elem_index_get(e->v1);
+ const int i2 = BM_elem_index_get(e->v2);
- id_curr[i1] += id_prev[i2];
- id_curr[i2] += id_prev[i1];
- }
- }
- }
- MEM_freeN(id_prev);
+ id_curr[i1] += id_prev[i2];
+ id_curr[i2] += id_prev[i1];
+ }
+ }
+ }
+ MEM_freeN(id_prev);
- return id_curr;
+ return id_curr;
}
-static void bm_vert_fasthash_edge_order(
- UUIDFashMatch *fm, const BMEdge *e, UUIDFashMatch e_fm[2])
+static void bm_vert_fasthash_edge_order(UUIDFashMatch *fm, const BMEdge *e, UUIDFashMatch e_fm[2])
{
- e_fm[0] = fm[BM_elem_index_get(e->v1)];
- e_fm[1] = fm[BM_elem_index_get(e->v2)];
+ e_fm[0] = fm[BM_elem_index_get(e->v1)];
+ e_fm[1] = fm[BM_elem_index_get(e->v2)];
- if (e_fm[0] > e_fm[1]) {
- SWAP(UUIDFashMatch, e_fm[0], e_fm[1]);
- }
+ if (e_fm[0] > e_fm[1]) {
+ SWAP(UUIDFashMatch, e_fm[0], e_fm[1]);
+ }
}
-static bool bm_vert_fasthash_edge_is_match(
- UUIDFashMatch *fm, const BMEdge *e_a, const BMEdge *e_b)
+static bool bm_vert_fasthash_edge_is_match(UUIDFashMatch *fm, const BMEdge *e_a, const BMEdge *e_b)
{
- UUIDFashMatch e_a_fm[2];
- UUIDFashMatch e_b_fm[2];
+ UUIDFashMatch e_a_fm[2];
+ UUIDFashMatch e_b_fm[2];
- bm_vert_fasthash_edge_order(fm, e_a, e_a_fm);
- bm_vert_fasthash_edge_order(fm, e_b, e_b_fm);
+ bm_vert_fasthash_edge_order(fm, e_a, e_a_fm);
+ bm_vert_fasthash_edge_order(fm, e_b, e_b_fm);
- return ((e_a_fm[0] == e_b_fm[0]) &&
- (e_a_fm[1] == e_b_fm[1]));
+ return ((e_a_fm[0] == e_b_fm[0]) && (e_a_fm[1] == e_b_fm[1]));
}
-static void bm_vert_fasthash_destroy(
- UUIDFashMatch *fm)
+static void bm_vert_fasthash_destroy(UUIDFashMatch *fm)
{
- MEM_freeN(fm);
+ MEM_freeN(fm);
}
/** \} */
-#endif /* USE_PIVOT_FASTMATCH */
-
+#endif /* USE_PIVOT_FASTMATCH */
/**
* Take a face-region and return a list of matching face-regions.
@@ -1373,143 +1341,142 @@ static void bm_vert_fasthash_destroy(
* \param faces_region: A single, contiguous face-region.
* \return A list of matching null-terminated face-region arrays.
*/
-int BM_mesh_region_match(
- BMesh *bm,
- BMFace **faces_region, uint faces_region_len,
- ListBase *r_face_regions)
+int BM_mesh_region_match(BMesh *bm,
+ BMFace **faces_region,
+ uint faces_region_len,
+ ListBase *r_face_regions)
{
- BMEdge *e_src;
- BMEdge *e_dst;
- BMIter iter;
- uint verts_region_len = 0;
- uint faces_result_len = 0;
- /* number of steps from e_src to a boundary vert */
- uint depth;
-
+ BMEdge *e_src;
+ BMEdge *e_dst;
+ BMIter iter;
+ uint verts_region_len = 0;
+ uint faces_result_len = 0;
+ /* number of steps from e_src to a boundary vert */
+ uint depth;
#ifdef USE_WALKER_REUSE
- UUIDWalk w_src, w_dst;
+ UUIDWalk w_src, w_dst;
#endif
#ifdef USE_PIVOT_FASTMATCH
- UUIDFashMatch *fm;
+ UUIDFashMatch *fm;
#endif
#ifdef DEBUG_PRINT
- int search_num = 0;
+ int search_num = 0;
#endif
#ifdef DEBUG_TIME
- TIMEIT_START(region_match);
+ TIMEIT_START(region_match);
#endif
- /* initialize visited verts */
- BM_mesh_elem_hflag_disable_all(bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_TAG, false);
- bm_face_array_visit(faces_region, faces_region_len, &verts_region_len, true);
+ /* initialize visited verts */
+ BM_mesh_elem_hflag_disable_all(bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_TAG, false);
+ bm_face_array_visit(faces_region, faces_region_len, &verts_region_len, true);
- /* needed for 'ghashutil_bmelem_indexhash' */
- BM_mesh_elem_index_ensure(bm, BM_VERT | BM_FACE);
+ /* needed for 'ghashutil_bmelem_indexhash' */
+ BM_mesh_elem_index_ensure(bm, BM_VERT | BM_FACE);
#ifdef USE_PIVOT_SEARCH
- e_src = bm_face_region_pivot_edge_find(
- faces_region, faces_region_len,
- verts_region_len, &depth);
-
- /* see which edge is added */
-#if 0
- BM_select_history_clear(bm);
- if (e_src) {
- BM_select_history_store(bm, e_src);
- }
-#endif
+ e_src = bm_face_region_pivot_edge_find(faces_region, faces_region_len, verts_region_len, &depth);
+
+ /* see which edge is added */
+# if 0
+ BM_select_history_clear(bm);
+ if (e_src) {
+ BM_select_history_store(bm, e_src);
+ }
+# endif
#else
- /* quick test only! */
- e_src = BM_mesh_active_edge_get(bm);
+ /* quick test only! */
+ e_src = BM_mesh_active_edge_get(bm);
#endif
- if (e_src == NULL) {
+ if (e_src == NULL) {
#ifdef DEBUG_PRINT
- printf("Couldn't find 'e_src'");
+ printf("Couldn't find 'e_src'");
#endif
- return 0;
- }
+ return 0;
+ }
- BLI_listbase_clear(r_face_regions);
+ BLI_listbase_clear(r_face_regions);
#ifdef USE_PIVOT_FASTMATCH
- if (depth > 0) {
- fm = bm_vert_fasthash_create(bm, depth);
- }
- else {
- fm = NULL;
- }
+ if (depth > 0) {
+ fm = bm_vert_fasthash_create(bm, depth);
+ }
+ else {
+ fm = NULL;
+ }
#endif
#ifdef USE_WALKER_REUSE
- bm_uuidwalk_init(&w_src, faces_region_len, verts_region_len);
- bm_uuidwalk_init(&w_dst, faces_region_len, verts_region_len);
+ bm_uuidwalk_init(&w_src, faces_region_len, verts_region_len);
+ bm_uuidwalk_init(&w_dst, faces_region_len, verts_region_len);
#endif
- BM_ITER_MESH (e_dst, &iter, bm, BM_EDGES_OF_MESH) {
- BMFace **faces_result;
- uint faces_result_len_out;
+ BM_ITER_MESH (e_dst, &iter, bm, BM_EDGES_OF_MESH) {
+ BMFace **faces_result;
+ uint faces_result_len_out;
- if (BM_elem_flag_test(e_dst, BM_ELEM_TAG) || BM_edge_is_wire(e_dst)) {
- continue;
- }
+ if (BM_elem_flag_test(e_dst, BM_ELEM_TAG) || BM_edge_is_wire(e_dst)) {
+ continue;
+ }
#ifdef USE_PIVOT_FASTMATCH
- if (fm && !bm_vert_fasthash_edge_is_match(fm, e_src, e_dst)) {
- continue;
- }
+ if (fm && !bm_vert_fasthash_edge_is_match(fm, e_src, e_dst)) {
+ continue;
+ }
#endif
#ifdef DEBUG_PRINT
- search_num += 1;
+ search_num += 1;
#endif
- faces_result = bm_mesh_region_match_pair(
+ faces_result = bm_mesh_region_match_pair(
#ifdef USE_WALKER_REUSE
- &w_src, &w_dst,
+ &w_src,
+ &w_dst,
#endif
- e_src, e_dst,
- faces_region_len,
- verts_region_len,
- &faces_result_len_out);
+ e_src,
+ e_dst,
+ faces_region_len,
+ verts_region_len,
+ &faces_result_len_out);
- /* tag verts as visited */
- if (faces_result) {
- LinkData *link;
+ /* tag verts as visited */
+ if (faces_result) {
+ LinkData *link;
- bm_face_array_visit(faces_result, faces_result_len_out, NULL, false);
+ bm_face_array_visit(faces_result, faces_result_len_out, NULL, false);
- link = BLI_genericNodeN(faces_result);
- BLI_addtail(r_face_regions, link);
- faces_result_len += 1;
- }
- }
+ link = BLI_genericNodeN(faces_result);
+ BLI_addtail(r_face_regions, link);
+ faces_result_len += 1;
+ }
+ }
#ifdef USE_WALKER_REUSE
- bm_uuidwalk_free(&w_src);
- bm_uuidwalk_free(&w_dst);
+ bm_uuidwalk_free(&w_src);
+ bm_uuidwalk_free(&w_dst);
#else
- (void)bm_uuidwalk_clear;
+ (void)bm_uuidwalk_clear;
#endif
#ifdef USE_PIVOT_FASTMATCH
- if (fm) {
- bm_vert_fasthash_destroy(fm);
- }
+ if (fm) {
+ bm_vert_fasthash_destroy(fm);
+ }
#endif
#ifdef DEBUG_PRINT
- printf("%s: search: %d, found %d\n", __func__, search_num, faces_result_len);
+ printf("%s: search: %d, found %d\n", __func__, search_num, faces_result_len);
#endif
#ifdef DEBUG_TIME
- TIMEIT_END(region_match);
+ TIMEIT_END(region_match);
#endif
- return (int)faces_result_len;
+ return (int)faces_result_len;
}
diff --git a/source/blender/bmesh/tools/bmesh_region_match.h b/source/blender/bmesh/tools/bmesh_region_match.h
index 1c460bb7ede..a0625543c51 100644
--- a/source/blender/bmesh/tools/bmesh_region_match.h
+++ b/source/blender/bmesh/tools/bmesh_region_match.h
@@ -21,9 +21,9 @@
* \ingroup bmesh
*/
-int BM_mesh_region_match(
- BMesh *bm,
- BMFace **faces_region, uint faces_region_len,
- ListBase *r_face_regions);
+int BM_mesh_region_match(BMesh *bm,
+ BMFace **faces_region,
+ uint faces_region_len,
+ ListBase *r_face_regions);
#endif /* __BMESH_REGION_MATCH_H__ */
diff --git a/source/blender/bmesh/tools/bmesh_separate.c b/source/blender/bmesh/tools/bmesh_separate.c
index 9e8163c167b..59c82448fa9 100644
--- a/source/blender/bmesh/tools/bmesh_separate.c
+++ b/source/blender/bmesh/tools/bmesh_separate.c
@@ -30,100 +30,97 @@
#include "bmesh.h"
#include "intern/bmesh_private.h"
-#include "bmesh_separate.h" /* own include */
+#include "bmesh_separate.h" /* own include */
/**
* Split all faces that match `filter_fn`.
* \note
*/
-void BM_mesh_separate_faces(
- BMesh *bm,
- BMFaceFilterFunc filter_fn, void *user_data)
+void BM_mesh_separate_faces(BMesh *bm, BMFaceFilterFunc filter_fn, void *user_data)
{
- BMFace **faces_array_all = MEM_mallocN(bm->totface * sizeof(BMFace *), __func__);
- /*
- * - Create an array of faces based on 'filter_fn'.
- * First part of array for match, for non-match.
- *
- * - Enable all vertex tags, then clear all tagged vertices from 'faces_b'.
- *
- * - Loop over 'faces_a', checking each vertex,
- * splitting out any which aren't tagged (and therefor shared), disabling tags as we go.
- */
-
- BMFace *f;
- BMIter iter;
-
- uint faces_a_len = 0;
- uint faces_b_len = 0;
- {
- int i_a = 0;
- int i_b = bm->totface;
- BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
- faces_array_all[filter_fn(f, user_data) ? i_a++ : --i_b] = f;
- }
- faces_a_len = i_a;
- faces_b_len = bm->totface - i_a;
- }
-
- BMFace **faces_a = faces_array_all;
- BMFace **faces_b = faces_array_all + faces_a_len;
-
- /* Enable for all */
- BM_mesh_elem_hflag_enable_all(bm, BM_VERT, BM_ELEM_TAG, false);
-
- /* Disable vert tag on faces_b */
- for (uint i = 0; i < faces_b_len; i++) {
- BMLoop *l_iter, *l_first;
- l_iter = l_first = BM_FACE_FIRST_LOOP(faces_b[i]);
- do {
- BM_elem_flag_disable(l_iter->v, BM_ELEM_TAG);
- } while ((l_iter = l_iter->next) != l_first);
- }
-
-
- BLI_buffer_declare_static(BMLoop **, loop_split, 0, 128);
-
- /* Check shared verts ('faces_a' tag and disable) */
- for (uint i = 0; i < faces_a_len; i++) {
- BMLoop *l_iter, *l_first;
- l_iter = l_first = BM_FACE_FIRST_LOOP(faces_a[i]);
- do {
- if (!BM_elem_flag_test(l_iter->v, BM_ELEM_TAG)) {
- BMVert *v = l_iter->v;
- /* Enable, since we may visit this vertex again on other faces */
- BM_elem_flag_enable(v, BM_ELEM_TAG);
-
- /* We know the vertex is shared, collect all vertices and split them off. */
-
- /* Fill 'loop_split' */
- {
- BMEdge *e_first, *e_iter;
- e_iter = e_first = l_iter->e;
- do {
- if (e_iter->l != NULL) {
- BMLoop *l_radial_first, *l_radial_iter;
- l_radial_first = l_radial_iter = e_iter->l;
- do {
- if (l_radial_iter->v == v) {
- if (filter_fn(l_radial_iter->f, user_data)) {
- BLI_buffer_append(&loop_split, BMLoop *, l_radial_iter);
- }
- }
- } while ((l_radial_iter = l_radial_iter->radial_next) != l_radial_first);
- }
- } while ((e_iter = bmesh_disk_edge_next(e_iter, v)) != e_first);
- }
-
- /* Perform the split */
- BM_face_loop_separate_multi(bm, loop_split.data, loop_split.count);
-
- BLI_buffer_clear(&loop_split);
- }
- } while ((l_iter = l_iter->next) != l_first);
- }
-
- BLI_buffer_free(&loop_split);
-
- MEM_freeN(faces_array_all);
+ BMFace **faces_array_all = MEM_mallocN(bm->totface * sizeof(BMFace *), __func__);
+ /*
+ * - Create an array of faces based on 'filter_fn'.
+ * First part of array for match, for non-match.
+ *
+ * - Enable all vertex tags, then clear all tagged vertices from 'faces_b'.
+ *
+ * - Loop over 'faces_a', checking each vertex,
+ * splitting out any which aren't tagged (and therefor shared), disabling tags as we go.
+ */
+
+ BMFace *f;
+ BMIter iter;
+
+ uint faces_a_len = 0;
+ uint faces_b_len = 0;
+ {
+ int i_a = 0;
+ int i_b = bm->totface;
+ BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
+ faces_array_all[filter_fn(f, user_data) ? i_a++ : --i_b] = f;
+ }
+ faces_a_len = i_a;
+ faces_b_len = bm->totface - i_a;
+ }
+
+ BMFace **faces_a = faces_array_all;
+ BMFace **faces_b = faces_array_all + faces_a_len;
+
+ /* Enable for all */
+ BM_mesh_elem_hflag_enable_all(bm, BM_VERT, BM_ELEM_TAG, false);
+
+ /* Disable vert tag on faces_b */
+ for (uint i = 0; i < faces_b_len; i++) {
+ BMLoop *l_iter, *l_first;
+ l_iter = l_first = BM_FACE_FIRST_LOOP(faces_b[i]);
+ do {
+ BM_elem_flag_disable(l_iter->v, BM_ELEM_TAG);
+ } while ((l_iter = l_iter->next) != l_first);
+ }
+
+ BLI_buffer_declare_static(BMLoop **, loop_split, 0, 128);
+
+ /* Check shared verts ('faces_a' tag and disable) */
+ for (uint i = 0; i < faces_a_len; i++) {
+ BMLoop *l_iter, *l_first;
+ l_iter = l_first = BM_FACE_FIRST_LOOP(faces_a[i]);
+ do {
+ if (!BM_elem_flag_test(l_iter->v, BM_ELEM_TAG)) {
+ BMVert *v = l_iter->v;
+ /* Enable, since we may visit this vertex again on other faces */
+ BM_elem_flag_enable(v, BM_ELEM_TAG);
+
+ /* We know the vertex is shared, collect all vertices and split them off. */
+
+ /* Fill 'loop_split' */
+ {
+ BMEdge *e_first, *e_iter;
+ e_iter = e_first = l_iter->e;
+ do {
+ if (e_iter->l != NULL) {
+ BMLoop *l_radial_first, *l_radial_iter;
+ l_radial_first = l_radial_iter = e_iter->l;
+ do {
+ if (l_radial_iter->v == v) {
+ if (filter_fn(l_radial_iter->f, user_data)) {
+ BLI_buffer_append(&loop_split, BMLoop *, l_radial_iter);
+ }
+ }
+ } while ((l_radial_iter = l_radial_iter->radial_next) != l_radial_first);
+ }
+ } while ((e_iter = bmesh_disk_edge_next(e_iter, v)) != e_first);
+ }
+
+ /* Perform the split */
+ BM_face_loop_separate_multi(bm, loop_split.data, loop_split.count);
+
+ BLI_buffer_clear(&loop_split);
+ }
+ } while ((l_iter = l_iter->next) != l_first);
+ }
+
+ BLI_buffer_free(&loop_split);
+
+ MEM_freeN(faces_array_all);
}
diff --git a/source/blender/bmesh/tools/bmesh_separate.h b/source/blender/bmesh/tools/bmesh_separate.h
index 711a94c9242..13293b155fd 100644
--- a/source/blender/bmesh/tools/bmesh_separate.h
+++ b/source/blender/bmesh/tools/bmesh_separate.h
@@ -21,8 +21,6 @@
* \ingroup bmesh
*/
-void BM_mesh_separate_faces(
- BMesh *bm,
- BMFaceFilterFunc filter_fn, void *user_data);
+void BM_mesh_separate_faces(BMesh *bm, BMFaceFilterFunc filter_fn, void *user_data);
#endif /* __BMESH_SEPARATE_H__ */
diff --git a/source/blender/bmesh/tools/bmesh_triangulate.c b/source/blender/bmesh/tools/bmesh_triangulate.c
index 3209732ba66..5c13292e556 100644
--- a/source/blender/bmesh/tools/bmesh_triangulate.c
+++ b/source/blender/bmesh/tools/bmesh_triangulate.c
@@ -20,7 +20,7 @@
* Triangulate.
*/
-#include "DNA_modifier_types.h" /* for MOD_TRIANGULATE_NGON_BEAUTY only */
+#include "DNA_modifier_types.h" /* for MOD_TRIANGULATE_NGON_BEAUTY only */
#include "MEM_guardedalloc.h"
@@ -36,113 +36,133 @@
#include "bmesh.h"
-#include "bmesh_triangulate.h" /* own include */
+#include "bmesh_triangulate.h" /* own include */
/**
* a version of #BM_face_triangulate that maps to #BMOpSlot
*/
-static void bm_face_triangulate_mapping(
- BMesh *bm, BMFace *face,
- const int quad_method, const int ngon_method,
- const bool use_tag,
- BMOperator *op, BMOpSlot *slot_facemap_out, BMOpSlot *slot_facemap_double_out,
-
- MemArena *pf_arena,
- /* use for MOD_TRIANGULATE_NGON_BEAUTY only! */
- struct Heap *pf_heap)
+static void bm_face_triangulate_mapping(BMesh *bm,
+ BMFace *face,
+ const int quad_method,
+ const int ngon_method,
+ const bool use_tag,
+ BMOperator *op,
+ BMOpSlot *slot_facemap_out,
+ BMOpSlot *slot_facemap_double_out,
+
+ MemArena *pf_arena,
+ /* use for MOD_TRIANGULATE_NGON_BEAUTY only! */
+ struct Heap *pf_heap)
{
- int faces_array_tot = face->len - 3;
- BMFace **faces_array = BLI_array_alloca(faces_array, faces_array_tot);
- LinkNode *faces_double = NULL;
- BLI_assert(face->len > 3);
-
- BM_face_triangulate(
- bm, face,
- faces_array, &faces_array_tot,
- NULL, NULL,
- &faces_double,
- quad_method, ngon_method, use_tag,
- pf_arena,
- pf_heap);
-
- if (faces_array_tot) {
- int i;
- BMO_slot_map_elem_insert(op, slot_facemap_out, face, face);
- for (i = 0; i < faces_array_tot; i++) {
- BMO_slot_map_elem_insert(op, slot_facemap_out, faces_array[i], face);
- }
-
- while (faces_double) {
- LinkNode *next = faces_double->next;
- BMO_slot_map_elem_insert(op, slot_facemap_double_out, faces_double->link, face);
- MEM_freeN(faces_double);
- faces_double = next;
- }
- }
+ int faces_array_tot = face->len - 3;
+ BMFace **faces_array = BLI_array_alloca(faces_array, faces_array_tot);
+ LinkNode *faces_double = NULL;
+ BLI_assert(face->len > 3);
+
+ BM_face_triangulate(bm,
+ face,
+ faces_array,
+ &faces_array_tot,
+ NULL,
+ NULL,
+ &faces_double,
+ quad_method,
+ ngon_method,
+ use_tag,
+ pf_arena,
+ pf_heap);
+
+ if (faces_array_tot) {
+ int i;
+ BMO_slot_map_elem_insert(op, slot_facemap_out, face, face);
+ for (i = 0; i < faces_array_tot; i++) {
+ BMO_slot_map_elem_insert(op, slot_facemap_out, faces_array[i], face);
+ }
+
+ while (faces_double) {
+ LinkNode *next = faces_double->next;
+ BMO_slot_map_elem_insert(op, slot_facemap_double_out, faces_double->link, face);
+ MEM_freeN(faces_double);
+ faces_double = next;
+ }
+ }
}
-
-void BM_mesh_triangulate(
- BMesh *bm, const int quad_method, const int ngon_method, const int min_vertices,
- const bool tag_only, BMOperator *op, BMOpSlot *slot_facemap_out,
- BMOpSlot *slot_facemap_double_out)
+void BM_mesh_triangulate(BMesh *bm,
+ const int quad_method,
+ const int ngon_method,
+ const int min_vertices,
+ const bool tag_only,
+ BMOperator *op,
+ BMOpSlot *slot_facemap_out,
+ BMOpSlot *slot_facemap_double_out)
{
- BMIter iter;
- BMFace *face;
- MemArena *pf_arena;
- Heap *pf_heap;
-
- pf_arena = BLI_memarena_new(BLI_POLYFILL_ARENA_SIZE, __func__);
-
- if (ngon_method == MOD_TRIANGULATE_NGON_BEAUTY) {
- pf_heap = BLI_heap_new_ex(BLI_POLYFILL_ALLOC_NGON_RESERVE);
- }
- else {
- pf_heap = NULL;
- }
-
- if (slot_facemap_out) {
- /* same as below but call: bm_face_triangulate_mapping() */
- BM_ITER_MESH (face, &iter, bm, BM_FACES_OF_MESH) {
- if (face->len >= min_vertices) {
- if (tag_only == false || BM_elem_flag_test(face, BM_ELEM_TAG)) {
- bm_face_triangulate_mapping(
- bm, face,
- quad_method, ngon_method, tag_only,
- op, slot_facemap_out, slot_facemap_double_out,
- pf_arena, pf_heap);
- }
- }
- }
- }
- else {
- LinkNode *faces_double = NULL;
-
- BM_ITER_MESH (face, &iter, bm, BM_FACES_OF_MESH) {
- if (face->len >= min_vertices) {
- if (tag_only == false || BM_elem_flag_test(face, BM_ELEM_TAG)) {
- BM_face_triangulate(
- bm, face,
- NULL, NULL,
- NULL, NULL,
- &faces_double,
- quad_method, ngon_method, tag_only,
- pf_arena, pf_heap);
- }
- }
- }
-
- while (faces_double) {
- LinkNode *next = faces_double->next;
- BM_face_kill(bm, faces_double->link);
- MEM_freeN(faces_double);
- faces_double = next;
- }
- }
-
- BLI_memarena_free(pf_arena);
-
- if (ngon_method == MOD_TRIANGULATE_NGON_BEAUTY) {
- BLI_heap_free(pf_heap, NULL);
- }
+ BMIter iter;
+ BMFace *face;
+ MemArena *pf_arena;
+ Heap *pf_heap;
+
+ pf_arena = BLI_memarena_new(BLI_POLYFILL_ARENA_SIZE, __func__);
+
+ if (ngon_method == MOD_TRIANGULATE_NGON_BEAUTY) {
+ pf_heap = BLI_heap_new_ex(BLI_POLYFILL_ALLOC_NGON_RESERVE);
+ }
+ else {
+ pf_heap = NULL;
+ }
+
+ if (slot_facemap_out) {
+ /* same as below but call: bm_face_triangulate_mapping() */
+ BM_ITER_MESH (face, &iter, bm, BM_FACES_OF_MESH) {
+ if (face->len >= min_vertices) {
+ if (tag_only == false || BM_elem_flag_test(face, BM_ELEM_TAG)) {
+ bm_face_triangulate_mapping(bm,
+ face,
+ quad_method,
+ ngon_method,
+ tag_only,
+ op,
+ slot_facemap_out,
+ slot_facemap_double_out,
+ pf_arena,
+ pf_heap);
+ }
+ }
+ }
+ }
+ else {
+ LinkNode *faces_double = NULL;
+
+ BM_ITER_MESH (face, &iter, bm, BM_FACES_OF_MESH) {
+ if (face->len >= min_vertices) {
+ if (tag_only == false || BM_elem_flag_test(face, BM_ELEM_TAG)) {
+ BM_face_triangulate(bm,
+ face,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ &faces_double,
+ quad_method,
+ ngon_method,
+ tag_only,
+ pf_arena,
+ pf_heap);
+ }
+ }
+ }
+
+ while (faces_double) {
+ LinkNode *next = faces_double->next;
+ BM_face_kill(bm, faces_double->link);
+ MEM_freeN(faces_double);
+ faces_double = next;
+ }
+ }
+
+ BLI_memarena_free(pf_arena);
+
+ if (ngon_method == MOD_TRIANGULATE_NGON_BEAUTY) {
+ BLI_heap_free(pf_heap, NULL);
+ }
}
diff --git a/source/blender/bmesh/tools/bmesh_triangulate.h b/source/blender/bmesh/tools/bmesh_triangulate.h
index b254246720c..ababd78f9a1 100644
--- a/source/blender/bmesh/tools/bmesh_triangulate.h
+++ b/source/blender/bmesh/tools/bmesh_triangulate.h
@@ -23,9 +23,13 @@
#ifndef __BMESH_TRIANGULATE_H__
#define __BMESH_TRIANGULATE_H__
-void BM_mesh_triangulate(
- BMesh *bm, const int quad_method, const int ngon_method,
- const int min_vertices, const bool tag_only,
- BMOperator *op, BMOpSlot *slot_facemap_out, BMOpSlot *slot_doubles_out);
+void BM_mesh_triangulate(BMesh *bm,
+ const int quad_method,
+ const int ngon_method,
+ const int min_vertices,
+ const bool tag_only,
+ BMOperator *op,
+ BMOpSlot *slot_facemap_out,
+ BMOpSlot *slot_doubles_out);
-#endif /* __BMESH_TRIANGULATE_H__ */
+#endif /* __BMESH_TRIANGULATE_H__ */
diff --git a/source/blender/bmesh/tools/bmesh_wireframe.c b/source/blender/bmesh/tools/bmesh_wireframe.c
index 82fc4b2334e..0026cab7419 100644
--- a/source/blender/bmesh/tools/bmesh_wireframe.c
+++ b/source/blender/bmesh/tools/bmesh_wireframe.c
@@ -35,122 +35,121 @@
static BMLoop *bm_edge_tag_faceloop(BMEdge *e)
{
- BMLoop *l, *l_first;
+ BMLoop *l, *l_first;
- l = l_first = e->l;
- do {
- if (BM_elem_flag_test(l->f, BM_ELEM_TAG)) {
- return l;
- }
- } while ((l = l->radial_next) != l_first);
+ l = l_first = e->l;
+ do {
+ if (BM_elem_flag_test(l->f, BM_ELEM_TAG)) {
+ return l;
+ }
+ } while ((l = l->radial_next) != l_first);
- /* in the case this is used, we know this will never happen */
- return NULL;
+ /* in the case this is used, we know this will never happen */
+ return NULL;
}
static void bm_vert_boundary_tangent(
- BMVert *v, float r_no[3], float r_no_face[3],
- BMVert **r_va_other, BMVert **r_vb_other)
+ BMVert *v, float r_no[3], float r_no_face[3], BMVert **r_va_other, BMVert **r_vb_other)
{
- BMIter iter;
- BMEdge *e_iter;
-
- BMEdge *e_a = NULL, *e_b = NULL;
- BMVert *v_a, *v_b;
-
- BMLoop *l_a, *l_b;
-
- float no_face[3], no_edge[3];
- float tvec_a[3], tvec_b[3];
-
- /* get 2 boundary edges, there should only _be_ 2,
- * in case there are more - results wont be valid of course */
- BM_ITER_ELEM (e_iter, &iter, v, BM_EDGES_OF_VERT) {
- if (BM_elem_flag_test(e_iter, BM_ELEM_TAG)) {
- if (e_a == NULL) {
- e_a = e_iter;
- }
- else {
- e_b = e_iter;
- break;
- }
- }
- }
-
- if (e_a && e_b) {
- /* note, with an incorrectly flushed selection this can crash */
- l_a = bm_edge_tag_faceloop(e_a);
- l_b = bm_edge_tag_faceloop(e_b);
-
- /* average edge face normal */
- add_v3_v3v3(no_face, l_a->f->no, l_b->f->no);
- normalize_v3(no_face);
-
- /* average edge direction */
- v_a = BM_edge_other_vert(e_a, v);
- v_b = BM_edge_other_vert(e_b, v);
-
- sub_v3_v3v3(tvec_a, v->co, v_a->co);
- sub_v3_v3v3(tvec_b, v_b->co, v->co);
- normalize_v3(tvec_a);
- normalize_v3(tvec_b);
- add_v3_v3v3(no_edge, tvec_a, tvec_b); /* not unit length but this is ok */
-
- /* check are we flipped the right way */
- BM_edge_calc_face_tangent(e_a, l_a, tvec_a);
- BM_edge_calc_face_tangent(e_b, l_b, tvec_b);
- add_v3_v3(tvec_a, tvec_b);
-
- *r_va_other = v_a;
- *r_vb_other = v_b;
- }
- else {
- /* degenerate case - vertex connects a boundary edged face to other faces,
- * so we have only one boundary face - only use it for calculations */
- l_a = bm_edge_tag_faceloop(e_a);
-
- copy_v3_v3(no_face, l_a->f->no);
-
- /* edge direction */
- v_a = BM_edge_other_vert(e_a, v);
- v_b = NULL;
-
- sub_v3_v3v3(no_edge, v->co, v_a->co);
-
- /* check are we flipped the right way */
- BM_edge_calc_face_tangent(e_a, l_a, tvec_a);
-
- *r_va_other = NULL;
- *r_vb_other = NULL;
- }
-
- /* find the normal */
- cross_v3_v3v3(r_no, no_edge, no_face);
- normalize_v3(r_no);
-
- if (dot_v3v3(r_no, tvec_a) > 0.0f) {
- negate_v3(r_no);
- }
-
- copy_v3_v3(r_no_face, no_face);
+ BMIter iter;
+ BMEdge *e_iter;
+
+ BMEdge *e_a = NULL, *e_b = NULL;
+ BMVert *v_a, *v_b;
+
+ BMLoop *l_a, *l_b;
+
+ float no_face[3], no_edge[3];
+ float tvec_a[3], tvec_b[3];
+
+ /* get 2 boundary edges, there should only _be_ 2,
+ * in case there are more - results wont be valid of course */
+ BM_ITER_ELEM (e_iter, &iter, v, BM_EDGES_OF_VERT) {
+ if (BM_elem_flag_test(e_iter, BM_ELEM_TAG)) {
+ if (e_a == NULL) {
+ e_a = e_iter;
+ }
+ else {
+ e_b = e_iter;
+ break;
+ }
+ }
+ }
+
+ if (e_a && e_b) {
+ /* note, with an incorrectly flushed selection this can crash */
+ l_a = bm_edge_tag_faceloop(e_a);
+ l_b = bm_edge_tag_faceloop(e_b);
+
+ /* average edge face normal */
+ add_v3_v3v3(no_face, l_a->f->no, l_b->f->no);
+ normalize_v3(no_face);
+
+ /* average edge direction */
+ v_a = BM_edge_other_vert(e_a, v);
+ v_b = BM_edge_other_vert(e_b, v);
+
+ sub_v3_v3v3(tvec_a, v->co, v_a->co);
+ sub_v3_v3v3(tvec_b, v_b->co, v->co);
+ normalize_v3(tvec_a);
+ normalize_v3(tvec_b);
+ add_v3_v3v3(no_edge, tvec_a, tvec_b); /* not unit length but this is ok */
+
+ /* check are we flipped the right way */
+ BM_edge_calc_face_tangent(e_a, l_a, tvec_a);
+ BM_edge_calc_face_tangent(e_b, l_b, tvec_b);
+ add_v3_v3(tvec_a, tvec_b);
+
+ *r_va_other = v_a;
+ *r_vb_other = v_b;
+ }
+ else {
+ /* degenerate case - vertex connects a boundary edged face to other faces,
+ * so we have only one boundary face - only use it for calculations */
+ l_a = bm_edge_tag_faceloop(e_a);
+
+ copy_v3_v3(no_face, l_a->f->no);
+
+ /* edge direction */
+ v_a = BM_edge_other_vert(e_a, v);
+ v_b = NULL;
+
+ sub_v3_v3v3(no_edge, v->co, v_a->co);
+
+ /* check are we flipped the right way */
+ BM_edge_calc_face_tangent(e_a, l_a, tvec_a);
+
+ *r_va_other = NULL;
+ *r_vb_other = NULL;
+ }
+
+ /* find the normal */
+ cross_v3_v3v3(r_no, no_edge, no_face);
+ normalize_v3(r_no);
+
+ if (dot_v3v3(r_no, tvec_a) > 0.0f) {
+ negate_v3(r_no);
+ }
+
+ copy_v3_v3(r_no_face, no_face);
}
/* check if we are the only tagged loop-face around this edge */
static bool bm_loop_is_radial_boundary(BMLoop *l_first)
{
- BMLoop *l = l_first->radial_next;
-
- if (l == l_first) {
- return true; /* a real boundary */
- }
- else {
- do {
- if (BM_elem_flag_test(l->f, BM_ELEM_TAG)) {
- return false;
- }
- } while ((l = l->radial_next) != l_first);
- }
- return true;
+ BMLoop *l = l_first->radial_next;
+
+ if (l == l_first) {
+ return true; /* a real boundary */
+ }
+ else {
+ do {
+ if (BM_elem_flag_test(l->f, BM_ELEM_TAG)) {
+ return false;
+ }
+ } while ((l = l->radial_next) != l_first);
+ }
+ return true;
}
/**
@@ -159,445 +158,442 @@ static bool bm_loop_is_radial_boundary(BMLoop *l_first)
* \note All edge tags must be cleared.
* \note Behavior matches MOD_solidify.c
*/
-void BM_mesh_wireframe(
- BMesh *bm,
- const float offset,
- const float offset_fac,
- const float offset_fac_vg,
- const bool use_replace,
- const bool use_boundary,
- const bool use_even_offset,
- const bool use_relative_offset,
- const bool use_crease,
- const float crease_weight,
- const int defgrp_index,
- const bool defgrp_invert,
- const short mat_offset,
- const short mat_max,
- /* for operators */
- const bool use_tag
- )
+void BM_mesh_wireframe(BMesh *bm,
+ const float offset,
+ const float offset_fac,
+ const float offset_fac_vg,
+ const bool use_replace,
+ const bool use_boundary,
+ const bool use_even_offset,
+ const bool use_relative_offset,
+ const bool use_crease,
+ const float crease_weight,
+ const int defgrp_index,
+ const bool defgrp_invert,
+ const short mat_offset,
+ const short mat_max,
+ /* for operators */
+ const bool use_tag)
{
- const float ofs_orig = -(((-offset_fac + 1.0f) * 0.5f) * offset);
- const float ofs_new = offset + ofs_orig;
- const float ofs_mid = (ofs_orig + ofs_new) / 2.0f;
- const float inset = offset / 2.0f;
- int cd_edge_crease_offset = use_crease ? CustomData_get_offset(&bm->edata, CD_CREASE) : -1;
- const int cd_dvert_offset = (defgrp_index != -1) ? CustomData_get_offset(&bm->vdata, CD_MDEFORMVERT) : -1;
- const float offset_fac_vg_inv = 1.0f - offset_fac_vg;
-
- const int totvert_orig = bm->totvert;
-
- BMIter iter;
- BMIter itersub;
-
- /* filled only with boundary verts */
- BMVert **verts_src = MEM_mallocN(sizeof(BMVert *) * totvert_orig, __func__);
- BMVert **verts_neg = MEM_mallocN(sizeof(BMVert *) * totvert_orig, __func__);
- BMVert **verts_pos = MEM_mallocN(sizeof(BMVert *) * totvert_orig, __func__);
-
- /* will over-alloc, but makes for easy lookups by index to keep aligned */
- BMVert **verts_boundary = use_boundary ?
- MEM_mallocN(sizeof(BMVert *) * totvert_orig, __func__) : NULL;
-
- float *verts_relfac = (use_relative_offset || (cd_dvert_offset != -1)) ?
- MEM_mallocN(sizeof(float) * totvert_orig, __func__) : NULL;
-
- /* may over-alloc if not all faces have wire */
- BMVert **verts_loop;
- int verts_loop_tot = 0;
-
- BMVert *v_src;
-
- BMFace *f_src;
- BMLoop *l;
-
- float tvec[3];
- float fac, fac_shell;
-
- int i;
-
- if (use_crease && cd_edge_crease_offset == -1) {
- BM_data_layer_add(bm, &bm->edata, CD_CREASE);
- cd_edge_crease_offset = CustomData_get_offset(&bm->edata, CD_CREASE);
- }
-
- BM_ITER_MESH_INDEX (v_src, &iter, bm, BM_VERTS_OF_MESH, i) {
- BM_elem_index_set(v_src, i); /* set_inline */
-
- verts_src[i] = v_src;
- BM_elem_flag_disable(v_src, BM_ELEM_TAG);
- }
- bm->elem_index_dirty &= ~BM_VERT;
-
- /* setup tags, all faces and verts will be tagged which will be duplicated */
-
- BM_ITER_MESH_INDEX (f_src, &iter, bm, BM_FACES_OF_MESH, i) {
- BM_elem_index_set(f_src, i); /* set_inline */
-
- if (use_tag) {
- if (!BM_elem_flag_test(f_src, BM_ELEM_TAG)) {
- continue;
- }
- }
- else {
- BM_elem_flag_enable(f_src, BM_ELEM_TAG);
- }
-
-
- verts_loop_tot += f_src->len;
- BM_ITER_ELEM (l, &itersub, f_src, BM_LOOPS_OF_FACE) {
- BM_elem_flag_enable(l->v, BM_ELEM_TAG);
-
- /* also tag boundary edges */
- BM_elem_flag_set(l->e, BM_ELEM_TAG, bm_loop_is_radial_boundary(l));
- }
- }
- bm->elem_index_dirty &= ~BM_FACE;
-
- /* duplicate tagged verts */
- for (i = 0; i < totvert_orig; i++) {
- v_src = verts_src[i];
- if (BM_elem_flag_test(v_src, BM_ELEM_TAG)) {
- fac = 1.0f;
-
- if (verts_relfac) {
- if (use_relative_offset) {
- verts_relfac[i] = BM_vert_calc_median_tagged_edge_length(v_src);
- }
- else {
- verts_relfac[i] = 1.0f;
- }
-
-
- if (cd_dvert_offset != -1) {
- MDeformVert *dvert = BM_ELEM_CD_GET_VOID_P(v_src, cd_dvert_offset);
- float defgrp_fac = defvert_find_weight(dvert, defgrp_index);
-
- if (defgrp_invert) {
- defgrp_fac = 1.0f - defgrp_fac;
- }
-
- if (offset_fac_vg > 0.0f) {
- defgrp_fac = (offset_fac_vg + (defgrp_fac * offset_fac_vg_inv));
- }
-
- verts_relfac[i] *= defgrp_fac;
- }
-
- fac *= verts_relfac[i];
- }
-
-
- verts_neg[i] = BM_vert_create(bm, NULL, v_src, BM_CREATE_NOP);
- verts_pos[i] = BM_vert_create(bm, NULL, v_src, BM_CREATE_NOP);
-
- if (offset == 0.0f) {
- madd_v3_v3v3fl(verts_neg[i]->co, v_src->co, v_src->no, ofs_orig * fac);
- madd_v3_v3v3fl(verts_pos[i]->co, v_src->co, v_src->no, ofs_new * fac);
- }
- else {
- madd_v3_v3v3fl(tvec, v_src->co, v_src->no, ofs_mid * fac);
-
- madd_v3_v3v3fl(verts_neg[i]->co, tvec, v_src->no, (ofs_orig - ofs_mid) * fac);
- madd_v3_v3v3fl(verts_pos[i]->co, tvec, v_src->no, (ofs_new - ofs_mid) * fac);
- }
- }
- else {
- /* could skip this */
- verts_neg[i] = NULL;
- verts_pos[i] = NULL;
- }
-
- /* conflicts with BM_vert_calc_median_tagged_edge_length */
- if (use_relative_offset == false) {
- BM_elem_flag_disable(v_src, BM_ELEM_TAG);
- }
- }
-
- if (use_relative_offset) {
- BM_mesh_elem_hflag_disable_all(bm, BM_VERT, BM_ELEM_TAG, false);
- }
-
- verts_loop = MEM_mallocN(sizeof(BMVert *) * verts_loop_tot, __func__);
- verts_loop_tot = 0; /* count up again */
-
- BM_ITER_MESH (f_src, &iter, bm, BM_FACES_OF_MESH) {
-
- if (use_tag && !BM_elem_flag_test(f_src, BM_ELEM_TAG)) {
- continue;
- }
-
- BM_ITER_ELEM (l, &itersub, f_src, BM_LOOPS_OF_FACE) {
- /* Because some faces might be skipped! */
- BM_elem_index_set(l, verts_loop_tot); /* set_dirty */
-
- BM_loop_calc_face_tangent(l, tvec);
-
- /* create offset vert */
- fac = 1.0f;
-
- if (verts_relfac) {
- fac *= verts_relfac[BM_elem_index_get(l->v)];
- }
-
- fac_shell = fac;
- if (use_even_offset) {
- fac_shell *= shell_angle_to_dist(((float)M_PI - BM_loop_calc_face_angle(l)) * 0.5f);
- }
-
-
- madd_v3_v3v3fl(tvec, l->v->co, tvec, inset * fac_shell);
- if (offset != 0.0f) {
- madd_v3_v3fl(tvec, l->v->no, ofs_mid * fac);
- }
- verts_loop[verts_loop_tot] = BM_vert_create(bm, tvec, l->v, BM_CREATE_NOP);
-
-
- if (use_boundary) {
- if (BM_elem_flag_test(l->e, BM_ELEM_TAG)) { /* is this a boundary? */
- BMVert *v_pair[2] = {l->v, l->next->v};
-
- for (i = 0; i < 2; i++) {
- BMVert *v_boundary = v_pair[i];
- if (!BM_elem_flag_test(v_boundary, BM_ELEM_TAG)) {
- const int v_boundary_index = BM_elem_index_get(v_boundary);
- float no_face[3];
- BMVert *va_other;
- BMVert *vb_other;
-
- BM_elem_flag_enable(v_boundary, BM_ELEM_TAG);
-
- bm_vert_boundary_tangent(v_boundary, tvec, no_face, &va_other, &vb_other);
-
- /* create offset vert */
- /* similar to code above but different angle calc */
- fac = 1.0f;
-
- if (verts_relfac) {
- fac *= verts_relfac[v_boundary_index];
- }
-
- fac_shell = fac;
- if (use_even_offset) {
- if (va_other) { /* for verts with only one boundary edge - this will be NULL */
- fac_shell *= shell_angle_to_dist(((float)M_PI -
- angle_on_axis_v3v3v3_v3(va_other->co,
- v_boundary->co,
- vb_other->co,
- no_face)) * 0.5f);
- }
- }
-
-
- madd_v3_v3v3fl(tvec, v_boundary->co, tvec, inset * fac_shell);
- if (offset != 0.0f) {
- madd_v3_v3fl(tvec, v_boundary->no, ofs_mid * fac);
- }
- verts_boundary[v_boundary_index] = BM_vert_create(bm, tvec, v_boundary, BM_CREATE_NOP);
- }
- }
- }
- }
-
- verts_loop_tot++;
- }
- }
- bm->elem_index_dirty |= BM_LOOP;
-
- BM_ITER_MESH (f_src, &iter, bm, BM_FACES_OF_MESH) {
-
- /* skip recently added faces */
- if (BM_elem_index_get(f_src) == -1) {
- continue;
- }
-
- if (use_tag && !BM_elem_flag_test(f_src, BM_ELEM_TAG)) {
- continue;
- }
-
- BM_elem_flag_disable(f_src, BM_ELEM_TAG);
-
- BM_ITER_ELEM (l, &itersub, f_src, BM_LOOPS_OF_FACE) {
- BMFace *f_new;
- BMLoop *l_new;
- BMLoop *l_next = l->next;
- BMVert *v_l1 = verts_loop[BM_elem_index_get(l)];
- BMVert *v_l2 = verts_loop[BM_elem_index_get(l_next)];
-
- BMVert *v_src_l1 = l->v;
- BMVert *v_src_l2 = l_next->v;
-
- const int i_1 = BM_elem_index_get(v_src_l1);
- const int i_2 = BM_elem_index_get(v_src_l2);
-
- BMVert *v_neg1 = verts_neg[i_1];
- BMVert *v_neg2 = verts_neg[i_2];
-
- BMVert *v_pos1 = verts_pos[i_1];
- BMVert *v_pos2 = verts_pos[i_2];
-
- f_new = BM_face_create_quad_tri(bm, v_l1, v_l2, v_neg2, v_neg1, f_src, BM_CREATE_NOP);
- if (mat_offset) {
- f_new->mat_nr = CLAMPIS(f_new->mat_nr + mat_offset, 0, mat_max);
- }
- BM_elem_flag_enable(f_new, BM_ELEM_TAG);
- l_new = BM_FACE_FIRST_LOOP(f_new);
-
- BM_elem_attrs_copy(bm, bm, l, l_new);
- BM_elem_attrs_copy(bm, bm, l, l_new->prev);
- BM_elem_attrs_copy(bm, bm, l_next, l_new->next);
- BM_elem_attrs_copy(bm, bm, l_next, l_new->next->next);
-
- f_new = BM_face_create_quad_tri(bm, v_l2, v_l1, v_pos1, v_pos2, f_src, BM_CREATE_NOP);
-
- if (mat_offset) {
- f_new->mat_nr = CLAMPIS(f_new->mat_nr + mat_offset, 0, mat_max);
- }
- BM_elem_flag_enable(f_new, BM_ELEM_TAG);
- l_new = BM_FACE_FIRST_LOOP(f_new);
-
- BM_elem_attrs_copy(bm, bm, l_next, l_new);
- BM_elem_attrs_copy(bm, bm, l_next, l_new->prev);
- BM_elem_attrs_copy(bm, bm, l, l_new->next);
- BM_elem_attrs_copy(bm, bm, l, l_new->next->next);
-
- if (use_boundary) {
- if (BM_elem_flag_test(l->e, BM_ELEM_TAG)) {
- /* we know its a boundary and this is the only face user (which is being wire'd) */
- /* we know we only touch this edge/face once */
- BMVert *v_b1 = verts_boundary[i_1];
- BMVert *v_b2 = verts_boundary[i_2];
-
- f_new = BM_face_create_quad_tri(bm, v_b2, v_b1, v_neg1, v_neg2, f_src, BM_CREATE_NOP);
- if (mat_offset) {
- f_new->mat_nr = CLAMPIS(f_new->mat_nr + mat_offset, 0, mat_max);
- }
- BM_elem_flag_enable(f_new, BM_ELEM_TAG);
- l_new = BM_FACE_FIRST_LOOP(f_new);
-
- BM_elem_attrs_copy(bm, bm, l_next, l_new);
- BM_elem_attrs_copy(bm, bm, l_next, l_new->prev);
- BM_elem_attrs_copy(bm, bm, l, l_new->next);
- BM_elem_attrs_copy(bm, bm, l, l_new->next->next);
-
- f_new = BM_face_create_quad_tri(bm, v_b1, v_b2, v_pos2, v_pos1, f_src, BM_CREATE_NOP);
- if (mat_offset) {
- f_new->mat_nr = CLAMPIS(f_new->mat_nr + mat_offset, 0, mat_max);
- }
- BM_elem_flag_enable(f_new, BM_ELEM_TAG);
- l_new = BM_FACE_FIRST_LOOP(f_new);
-
- BM_elem_attrs_copy(bm, bm, l, l_new);
- BM_elem_attrs_copy(bm, bm, l, l_new->prev);
- BM_elem_attrs_copy(bm, bm, l_next, l_new->next);
- BM_elem_attrs_copy(bm, bm, l_next, l_new->next->next);
-
- if (use_crease) {
- BMEdge *e_new;
- e_new = BM_edge_exists(v_pos1, v_b1);
- BM_ELEM_CD_SET_FLOAT(e_new, cd_edge_crease_offset, crease_weight);
-
- e_new = BM_edge_exists(v_pos2, v_b2);
- BM_ELEM_CD_SET_FLOAT(e_new, cd_edge_crease_offset, crease_weight);
-
- e_new = BM_edge_exists(v_neg1, v_b1);
- BM_ELEM_CD_SET_FLOAT(e_new, cd_edge_crease_offset, crease_weight);
-
- e_new = BM_edge_exists(v_neg2, v_b2);
- BM_ELEM_CD_SET_FLOAT(e_new, cd_edge_crease_offset, crease_weight);
- }
- }
- }
-
- if (use_crease) {
- BMEdge *e_new;
- e_new = BM_edge_exists(v_pos1, v_l1);
- BM_ELEM_CD_SET_FLOAT(e_new, cd_edge_crease_offset, crease_weight);
-
- e_new = BM_edge_exists(v_pos2, v_l2);
- BM_ELEM_CD_SET_FLOAT(e_new, cd_edge_crease_offset, crease_weight);
-
- e_new = BM_edge_exists(v_neg1, v_l1);
- BM_ELEM_CD_SET_FLOAT(e_new, cd_edge_crease_offset, crease_weight);
-
- e_new = BM_edge_exists(v_neg2, v_l2);
- BM_ELEM_CD_SET_FLOAT(e_new, cd_edge_crease_offset, crease_weight);
- }
-
- }
- }
-
- if (use_boundary) {
- MEM_freeN(verts_boundary);
- }
-
- if (verts_relfac) {
- MEM_freeN(verts_relfac);
- }
-
- if (use_replace) {
-
- if (use_tag) {
- /* only remove faces which are original and used to make wire,
- * use 'verts_pos' and 'verts_neg' to avoid a feedback loop. */
-
- /* vertex must be from 'verts_src' */
-#define VERT_DUPE_TEST_ORIG(v) (verts_neg[BM_elem_index_get(v)] != NULL)
-#define VERT_DUPE_TEST(v) (verts_pos[BM_elem_index_get(v)] != NULL)
-#define VERT_DUPE_CLEAR(v) { verts_pos[BM_elem_index_get(v)] = NULL; } (void)0
-
- /* first ensure we keep all verts which are used in faces that weren't
- * entirely made into wire. */
- BM_ITER_MESH (f_src, &iter, bm, BM_FACES_OF_MESH) {
- int mix_flag = 0;
- BMLoop *l_iter, *l_first;
-
- /* skip new faces */
- if (BM_elem_index_get(f_src) == -1) {
- continue;
- }
-
- l_iter = l_first = BM_FACE_FIRST_LOOP(f_src);
- do {
- mix_flag |= (VERT_DUPE_TEST_ORIG(l_iter->v) ? 1 : 2);
- if (mix_flag == (1 | 2)) {
- break;
- }
- } while ((l_iter = l_iter->next) != l_first);
-
- if (mix_flag == (1 | 2)) {
- l_iter = l_first = BM_FACE_FIRST_LOOP(f_src);
- do {
- VERT_DUPE_CLEAR(l_iter->v);
- } while ((l_iter = l_iter->next) != l_first);
- }
- }
-
- /* now remove any verts which were made into wire by all faces */
- for (i = 0; i < totvert_orig; i++) {
- v_src = verts_src[i];
- BLI_assert(i == BM_elem_index_get(v_src));
- if (VERT_DUPE_TEST(v_src)) {
- BM_vert_kill(bm, v_src);
- }
- }
+ const float ofs_orig = -(((-offset_fac + 1.0f) * 0.5f) * offset);
+ const float ofs_new = offset + ofs_orig;
+ const float ofs_mid = (ofs_orig + ofs_new) / 2.0f;
+ const float inset = offset / 2.0f;
+ int cd_edge_crease_offset = use_crease ? CustomData_get_offset(&bm->edata, CD_CREASE) : -1;
+ const int cd_dvert_offset = (defgrp_index != -1) ?
+ CustomData_get_offset(&bm->vdata, CD_MDEFORMVERT) :
+ -1;
+ const float offset_fac_vg_inv = 1.0f - offset_fac_vg;
+
+ const int totvert_orig = bm->totvert;
+
+ BMIter iter;
+ BMIter itersub;
+
+ /* filled only with boundary verts */
+ BMVert **verts_src = MEM_mallocN(sizeof(BMVert *) * totvert_orig, __func__);
+ BMVert **verts_neg = MEM_mallocN(sizeof(BMVert *) * totvert_orig, __func__);
+ BMVert **verts_pos = MEM_mallocN(sizeof(BMVert *) * totvert_orig, __func__);
+
+ /* will over-alloc, but makes for easy lookups by index to keep aligned */
+ BMVert **verts_boundary = use_boundary ? MEM_mallocN(sizeof(BMVert *) * totvert_orig, __func__) :
+ NULL;
+
+ float *verts_relfac = (use_relative_offset || (cd_dvert_offset != -1)) ?
+ MEM_mallocN(sizeof(float) * totvert_orig, __func__) :
+ NULL;
+
+ /* may over-alloc if not all faces have wire */
+ BMVert **verts_loop;
+ int verts_loop_tot = 0;
+
+ BMVert *v_src;
+
+ BMFace *f_src;
+ BMLoop *l;
+
+ float tvec[3];
+ float fac, fac_shell;
+
+ int i;
+
+ if (use_crease && cd_edge_crease_offset == -1) {
+ BM_data_layer_add(bm, &bm->edata, CD_CREASE);
+ cd_edge_crease_offset = CustomData_get_offset(&bm->edata, CD_CREASE);
+ }
+
+ BM_ITER_MESH_INDEX (v_src, &iter, bm, BM_VERTS_OF_MESH, i) {
+ BM_elem_index_set(v_src, i); /* set_inline */
+
+ verts_src[i] = v_src;
+ BM_elem_flag_disable(v_src, BM_ELEM_TAG);
+ }
+ bm->elem_index_dirty &= ~BM_VERT;
+
+ /* setup tags, all faces and verts will be tagged which will be duplicated */
+
+ BM_ITER_MESH_INDEX (f_src, &iter, bm, BM_FACES_OF_MESH, i) {
+ BM_elem_index_set(f_src, i); /* set_inline */
+
+ if (use_tag) {
+ if (!BM_elem_flag_test(f_src, BM_ELEM_TAG)) {
+ continue;
+ }
+ }
+ else {
+ BM_elem_flag_enable(f_src, BM_ELEM_TAG);
+ }
+
+ verts_loop_tot += f_src->len;
+ BM_ITER_ELEM (l, &itersub, f_src, BM_LOOPS_OF_FACE) {
+ BM_elem_flag_enable(l->v, BM_ELEM_TAG);
+
+ /* also tag boundary edges */
+ BM_elem_flag_set(l->e, BM_ELEM_TAG, bm_loop_is_radial_boundary(l));
+ }
+ }
+ bm->elem_index_dirty &= ~BM_FACE;
+
+ /* duplicate tagged verts */
+ for (i = 0; i < totvert_orig; i++) {
+ v_src = verts_src[i];
+ if (BM_elem_flag_test(v_src, BM_ELEM_TAG)) {
+ fac = 1.0f;
+
+ if (verts_relfac) {
+ if (use_relative_offset) {
+ verts_relfac[i] = BM_vert_calc_median_tagged_edge_length(v_src);
+ }
+ else {
+ verts_relfac[i] = 1.0f;
+ }
+
+ if (cd_dvert_offset != -1) {
+ MDeformVert *dvert = BM_ELEM_CD_GET_VOID_P(v_src, cd_dvert_offset);
+ float defgrp_fac = defvert_find_weight(dvert, defgrp_index);
+
+ if (defgrp_invert) {
+ defgrp_fac = 1.0f - defgrp_fac;
+ }
+
+ if (offset_fac_vg > 0.0f) {
+ defgrp_fac = (offset_fac_vg + (defgrp_fac * offset_fac_vg_inv));
+ }
+
+ verts_relfac[i] *= defgrp_fac;
+ }
+
+ fac *= verts_relfac[i];
+ }
+
+ verts_neg[i] = BM_vert_create(bm, NULL, v_src, BM_CREATE_NOP);
+ verts_pos[i] = BM_vert_create(bm, NULL, v_src, BM_CREATE_NOP);
+
+ if (offset == 0.0f) {
+ madd_v3_v3v3fl(verts_neg[i]->co, v_src->co, v_src->no, ofs_orig * fac);
+ madd_v3_v3v3fl(verts_pos[i]->co, v_src->co, v_src->no, ofs_new * fac);
+ }
+ else {
+ madd_v3_v3v3fl(tvec, v_src->co, v_src->no, ofs_mid * fac);
+
+ madd_v3_v3v3fl(verts_neg[i]->co, tvec, v_src->no, (ofs_orig - ofs_mid) * fac);
+ madd_v3_v3v3fl(verts_pos[i]->co, tvec, v_src->no, (ofs_new - ofs_mid) * fac);
+ }
+ }
+ else {
+ /* could skip this */
+ verts_neg[i] = NULL;
+ verts_pos[i] = NULL;
+ }
+
+ /* conflicts with BM_vert_calc_median_tagged_edge_length */
+ if (use_relative_offset == false) {
+ BM_elem_flag_disable(v_src, BM_ELEM_TAG);
+ }
+ }
+
+ if (use_relative_offset) {
+ BM_mesh_elem_hflag_disable_all(bm, BM_VERT, BM_ELEM_TAG, false);
+ }
+
+ verts_loop = MEM_mallocN(sizeof(BMVert *) * verts_loop_tot, __func__);
+ verts_loop_tot = 0; /* count up again */
+
+ BM_ITER_MESH (f_src, &iter, bm, BM_FACES_OF_MESH) {
+
+ if (use_tag && !BM_elem_flag_test(f_src, BM_ELEM_TAG)) {
+ continue;
+ }
+
+ BM_ITER_ELEM (l, &itersub, f_src, BM_LOOPS_OF_FACE) {
+ /* Because some faces might be skipped! */
+ BM_elem_index_set(l, verts_loop_tot); /* set_dirty */
+
+ BM_loop_calc_face_tangent(l, tvec);
+
+ /* create offset vert */
+ fac = 1.0f;
+
+ if (verts_relfac) {
+ fac *= verts_relfac[BM_elem_index_get(l->v)];
+ }
+
+ fac_shell = fac;
+ if (use_even_offset) {
+ fac_shell *= shell_angle_to_dist(((float)M_PI - BM_loop_calc_face_angle(l)) * 0.5f);
+ }
+
+ madd_v3_v3v3fl(tvec, l->v->co, tvec, inset * fac_shell);
+ if (offset != 0.0f) {
+ madd_v3_v3fl(tvec, l->v->no, ofs_mid * fac);
+ }
+ verts_loop[verts_loop_tot] = BM_vert_create(bm, tvec, l->v, BM_CREATE_NOP);
+
+ if (use_boundary) {
+ if (BM_elem_flag_test(l->e, BM_ELEM_TAG)) { /* is this a boundary? */
+ BMVert *v_pair[2] = {l->v, l->next->v};
+
+ for (i = 0; i < 2; i++) {
+ BMVert *v_boundary = v_pair[i];
+ if (!BM_elem_flag_test(v_boundary, BM_ELEM_TAG)) {
+ const int v_boundary_index = BM_elem_index_get(v_boundary);
+ float no_face[3];
+ BMVert *va_other;
+ BMVert *vb_other;
+
+ BM_elem_flag_enable(v_boundary, BM_ELEM_TAG);
+
+ bm_vert_boundary_tangent(v_boundary, tvec, no_face, &va_other, &vb_other);
+
+ /* create offset vert */
+ /* similar to code above but different angle calc */
+ fac = 1.0f;
+
+ if (verts_relfac) {
+ fac *= verts_relfac[v_boundary_index];
+ }
+
+ fac_shell = fac;
+ if (use_even_offset) {
+ if (va_other) { /* for verts with only one boundary edge - this will be NULL */
+ fac_shell *= shell_angle_to_dist(
+ ((float)M_PI - angle_on_axis_v3v3v3_v3(
+ va_other->co, v_boundary->co, vb_other->co, no_face)) *
+ 0.5f);
+ }
+ }
+
+ madd_v3_v3v3fl(tvec, v_boundary->co, tvec, inset * fac_shell);
+ if (offset != 0.0f) {
+ madd_v3_v3fl(tvec, v_boundary->no, ofs_mid * fac);
+ }
+ verts_boundary[v_boundary_index] = BM_vert_create(
+ bm, tvec, v_boundary, BM_CREATE_NOP);
+ }
+ }
+ }
+ }
+
+ verts_loop_tot++;
+ }
+ }
+ bm->elem_index_dirty |= BM_LOOP;
+
+ BM_ITER_MESH (f_src, &iter, bm, BM_FACES_OF_MESH) {
+
+ /* skip recently added faces */
+ if (BM_elem_index_get(f_src) == -1) {
+ continue;
+ }
+
+ if (use_tag && !BM_elem_flag_test(f_src, BM_ELEM_TAG)) {
+ continue;
+ }
+
+ BM_elem_flag_disable(f_src, BM_ELEM_TAG);
+
+ BM_ITER_ELEM (l, &itersub, f_src, BM_LOOPS_OF_FACE) {
+ BMFace *f_new;
+ BMLoop *l_new;
+ BMLoop *l_next = l->next;
+ BMVert *v_l1 = verts_loop[BM_elem_index_get(l)];
+ BMVert *v_l2 = verts_loop[BM_elem_index_get(l_next)];
+
+ BMVert *v_src_l1 = l->v;
+ BMVert *v_src_l2 = l_next->v;
+
+ const int i_1 = BM_elem_index_get(v_src_l1);
+ const int i_2 = BM_elem_index_get(v_src_l2);
+
+ BMVert *v_neg1 = verts_neg[i_1];
+ BMVert *v_neg2 = verts_neg[i_2];
+
+ BMVert *v_pos1 = verts_pos[i_1];
+ BMVert *v_pos2 = verts_pos[i_2];
+
+ f_new = BM_face_create_quad_tri(bm, v_l1, v_l2, v_neg2, v_neg1, f_src, BM_CREATE_NOP);
+ if (mat_offset) {
+ f_new->mat_nr = CLAMPIS(f_new->mat_nr + mat_offset, 0, mat_max);
+ }
+ BM_elem_flag_enable(f_new, BM_ELEM_TAG);
+ l_new = BM_FACE_FIRST_LOOP(f_new);
+
+ BM_elem_attrs_copy(bm, bm, l, l_new);
+ BM_elem_attrs_copy(bm, bm, l, l_new->prev);
+ BM_elem_attrs_copy(bm, bm, l_next, l_new->next);
+ BM_elem_attrs_copy(bm, bm, l_next, l_new->next->next);
+
+ f_new = BM_face_create_quad_tri(bm, v_l2, v_l1, v_pos1, v_pos2, f_src, BM_CREATE_NOP);
+
+ if (mat_offset) {
+ f_new->mat_nr = CLAMPIS(f_new->mat_nr + mat_offset, 0, mat_max);
+ }
+ BM_elem_flag_enable(f_new, BM_ELEM_TAG);
+ l_new = BM_FACE_FIRST_LOOP(f_new);
+
+ BM_elem_attrs_copy(bm, bm, l_next, l_new);
+ BM_elem_attrs_copy(bm, bm, l_next, l_new->prev);
+ BM_elem_attrs_copy(bm, bm, l, l_new->next);
+ BM_elem_attrs_copy(bm, bm, l, l_new->next->next);
+
+ if (use_boundary) {
+ if (BM_elem_flag_test(l->e, BM_ELEM_TAG)) {
+ /* we know its a boundary and this is the only face user (which is being wire'd) */
+ /* we know we only touch this edge/face once */
+ BMVert *v_b1 = verts_boundary[i_1];
+ BMVert *v_b2 = verts_boundary[i_2];
+
+ f_new = BM_face_create_quad_tri(bm, v_b2, v_b1, v_neg1, v_neg2, f_src, BM_CREATE_NOP);
+ if (mat_offset) {
+ f_new->mat_nr = CLAMPIS(f_new->mat_nr + mat_offset, 0, mat_max);
+ }
+ BM_elem_flag_enable(f_new, BM_ELEM_TAG);
+ l_new = BM_FACE_FIRST_LOOP(f_new);
+
+ BM_elem_attrs_copy(bm, bm, l_next, l_new);
+ BM_elem_attrs_copy(bm, bm, l_next, l_new->prev);
+ BM_elem_attrs_copy(bm, bm, l, l_new->next);
+ BM_elem_attrs_copy(bm, bm, l, l_new->next->next);
+
+ f_new = BM_face_create_quad_tri(bm, v_b1, v_b2, v_pos2, v_pos1, f_src, BM_CREATE_NOP);
+ if (mat_offset) {
+ f_new->mat_nr = CLAMPIS(f_new->mat_nr + mat_offset, 0, mat_max);
+ }
+ BM_elem_flag_enable(f_new, BM_ELEM_TAG);
+ l_new = BM_FACE_FIRST_LOOP(f_new);
+
+ BM_elem_attrs_copy(bm, bm, l, l_new);
+ BM_elem_attrs_copy(bm, bm, l, l_new->prev);
+ BM_elem_attrs_copy(bm, bm, l_next, l_new->next);
+ BM_elem_attrs_copy(bm, bm, l_next, l_new->next->next);
+
+ if (use_crease) {
+ BMEdge *e_new;
+ e_new = BM_edge_exists(v_pos1, v_b1);
+ BM_ELEM_CD_SET_FLOAT(e_new, cd_edge_crease_offset, crease_weight);
+
+ e_new = BM_edge_exists(v_pos2, v_b2);
+ BM_ELEM_CD_SET_FLOAT(e_new, cd_edge_crease_offset, crease_weight);
+
+ e_new = BM_edge_exists(v_neg1, v_b1);
+ BM_ELEM_CD_SET_FLOAT(e_new, cd_edge_crease_offset, crease_weight);
+
+ e_new = BM_edge_exists(v_neg2, v_b2);
+ BM_ELEM_CD_SET_FLOAT(e_new, cd_edge_crease_offset, crease_weight);
+ }
+ }
+ }
+
+ if (use_crease) {
+ BMEdge *e_new;
+ e_new = BM_edge_exists(v_pos1, v_l1);
+ BM_ELEM_CD_SET_FLOAT(e_new, cd_edge_crease_offset, crease_weight);
+
+ e_new = BM_edge_exists(v_pos2, v_l2);
+ BM_ELEM_CD_SET_FLOAT(e_new, cd_edge_crease_offset, crease_weight);
+
+ e_new = BM_edge_exists(v_neg1, v_l1);
+ BM_ELEM_CD_SET_FLOAT(e_new, cd_edge_crease_offset, crease_weight);
+
+ e_new = BM_edge_exists(v_neg2, v_l2);
+ BM_ELEM_CD_SET_FLOAT(e_new, cd_edge_crease_offset, crease_weight);
+ }
+ }
+ }
+
+ if (use_boundary) {
+ MEM_freeN(verts_boundary);
+ }
+
+ if (verts_relfac) {
+ MEM_freeN(verts_relfac);
+ }
+
+ if (use_replace) {
+
+ if (use_tag) {
+ /* only remove faces which are original and used to make wire,
+ * use 'verts_pos' and 'verts_neg' to avoid a feedback loop. */
+
+ /* vertex must be from 'verts_src' */
+#define VERT_DUPE_TEST_ORIG(v) (verts_neg[BM_elem_index_get(v)] != NULL)
+#define VERT_DUPE_TEST(v) (verts_pos[BM_elem_index_get(v)] != NULL)
+#define VERT_DUPE_CLEAR(v) \
+ { \
+ verts_pos[BM_elem_index_get(v)] = NULL; \
+ } \
+ (void)0
+
+ /* first ensure we keep all verts which are used in faces that weren't
+ * entirely made into wire. */
+ BM_ITER_MESH (f_src, &iter, bm, BM_FACES_OF_MESH) {
+ int mix_flag = 0;
+ BMLoop *l_iter, *l_first;
+
+ /* skip new faces */
+ if (BM_elem_index_get(f_src) == -1) {
+ continue;
+ }
+
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f_src);
+ do {
+ mix_flag |= (VERT_DUPE_TEST_ORIG(l_iter->v) ? 1 : 2);
+ if (mix_flag == (1 | 2)) {
+ break;
+ }
+ } while ((l_iter = l_iter->next) != l_first);
+
+ if (mix_flag == (1 | 2)) {
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f_src);
+ do {
+ VERT_DUPE_CLEAR(l_iter->v);
+ } while ((l_iter = l_iter->next) != l_first);
+ }
+ }
+
+ /* now remove any verts which were made into wire by all faces */
+ for (i = 0; i < totvert_orig; i++) {
+ v_src = verts_src[i];
+ BLI_assert(i == BM_elem_index_get(v_src));
+ if (VERT_DUPE_TEST(v_src)) {
+ BM_vert_kill(bm, v_src);
+ }
+ }
#undef VERT_DUPE_TEST_ORIG
#undef VERT_DUPE_TEST
#undef VERT_DUPE_CLEAR
-
- }
- else {
- /* simple case, no tags - replace all */
- for (i = 0; i < totvert_orig; i++) {
- BM_vert_kill(bm, verts_src[i]);
- }
- }
- }
-
- MEM_freeN(verts_src);
- MEM_freeN(verts_neg);
- MEM_freeN(verts_pos);
- MEM_freeN(verts_loop);
+ }
+ else {
+ /* simple case, no tags - replace all */
+ for (i = 0; i < totvert_orig; i++) {
+ BM_vert_kill(bm, verts_src[i]);
+ }
+ }
+ }
+
+ MEM_freeN(verts_src);
+ MEM_freeN(verts_neg);
+ MEM_freeN(verts_pos);
+ MEM_freeN(verts_loop);
}
diff --git a/source/blender/bmesh/tools/bmesh_wireframe.h b/source/blender/bmesh/tools/bmesh_wireframe.h
index 7c71e15beb9..3be43b2e9f5 100644
--- a/source/blender/bmesh/tools/bmesh_wireframe.h
+++ b/source/blender/bmesh/tools/bmesh_wireframe.h
@@ -23,21 +23,20 @@
#ifndef __BMESH_WIREFRAME_H__
#define __BMESH_WIREFRAME_H__
-void BM_mesh_wireframe(
- BMesh *bm,
- const float offset,
- const float offset_fac,
- const float offset_fac_vg,
- const bool use_replace,
- const bool use_boundary,
- const bool use_even_offset,
- const bool use_relative_offset,
- const bool use_crease,
- const float crease_weight,
- const int defgrp_index,
- const bool defgrp_invert,
- const short mat_offset,
- const short mat_max,
- const bool use_tag);
+void BM_mesh_wireframe(BMesh *bm,
+ const float offset,
+ const float offset_fac,
+ const float offset_fac_vg,
+ const bool use_replace,
+ const bool use_boundary,
+ const bool use_even_offset,
+ const bool use_relative_offset,
+ const bool use_crease,
+ const float crease_weight,
+ const int defgrp_index,
+ const bool defgrp_invert,
+ const short mat_offset,
+ const short mat_max,
+ const bool use_tag);
-#endif /* __BMESH_WIREFRAME_H__ */
+#endif /* __BMESH_WIREFRAME_H__ */