diff options
Diffstat (limited to 'source/blender/editors/mesh/editmesh_intersect.c')
-rw-r--r-- | source/blender/editors/mesh/editmesh_intersect.c | 1538 |
1 files changed, 776 insertions, 762 deletions
diff --git a/source/blender/editors/mesh/editmesh_intersect.c b/source/blender/editors/mesh/editmesh_intersect.c index c500683a228..06e2ef6e304 100644 --- a/source/blender/editors/mesh/editmesh_intersect.c +++ b/source/blender/editors/mesh/editmesh_intersect.c @@ -44,12 +44,11 @@ #include "intern/bmesh_private.h" -#include "mesh_intern.h" /* own include */ +#include "mesh_intern.h" /* own include */ #include "tools/bmesh_intersect.h" #include "tools/bmesh_separate.h" - /* detect isolated holes and fill them */ #define USE_NET_ISLAND_CONNECT @@ -58,12 +57,12 @@ */ static int bm_face_isect_self(BMFace *f, void *UNUSED(user_data)) { - if (BM_elem_flag_test(f, BM_ELEM_SELECT)) { - return 0; - } - else { - return -1; - } + if (BM_elem_flag_test(f, BM_ELEM_SELECT)) { + return 0; + } + else { + return -1; + } } /** @@ -71,15 +70,15 @@ static int bm_face_isect_self(BMFace *f, void *UNUSED(user_data)) */ static int bm_face_isect_pair(BMFace *f, void *UNUSED(user_data)) { - if (BM_elem_flag_test(f, BM_ELEM_HIDDEN)) { - return -1; - } - else if (BM_elem_flag_test(f, BM_ELEM_SELECT)) { - return 1; - } - else { - return 0; - } + if (BM_elem_flag_test(f, BM_ELEM_HIDDEN)) { + return -1; + } + else if (BM_elem_flag_test(f, BM_ELEM_SELECT)) { + return 1; + } + else { + return 0; + } } /** @@ -88,15 +87,15 @@ static int bm_face_isect_pair(BMFace *f, void *UNUSED(user_data)) */ static int bm_face_isect_pair_swap(BMFace *f, void *UNUSED(user_data)) { - if (BM_elem_flag_test(f, BM_ELEM_HIDDEN)) { - return -1; - } - else if (BM_elem_flag_test(f, BM_ELEM_SELECT)) { - return 0; - } - else { - return 1; - } + if (BM_elem_flag_test(f, BM_ELEM_HIDDEN)) { + return -1; + } + else if (BM_elem_flag_test(f, BM_ELEM_SELECT)) { + return 0; + } + else { + return 1; + } } /** @@ -104,22 +103,21 @@ static int bm_face_isect_pair_swap(BMFace *f, void *UNUSED(user_data)) */ static void edbm_intersect_select(BMEditMesh *em) { - BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT, false); - - if (em->bm->selectmode & (SCE_SELECT_VERTEX | SCE_SELECT_EDGE)) { - BMIter iter; - BMEdge *e; + BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT, false); - BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) { - if (BM_elem_flag_test(e, BM_ELEM_TAG)) { - BM_edge_select_set(em->bm, e, true); - } - } - } + if (em->bm->selectmode & (SCE_SELECT_VERTEX | SCE_SELECT_EDGE)) { + BMIter iter; + BMEdge *e; - EDBM_mesh_normals_update(em); - EDBM_update_generic(em, true, true); + BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) { + if (BM_elem_flag_test(e, BM_ELEM_TAG)) { + BM_edge_select_set(em->bm, e, true); + } + } + } + EDBM_mesh_normals_update(em); + EDBM_update_generic(em, true, true); } /* -------------------------------------------------------------------- */ @@ -130,138 +128,148 @@ static void edbm_intersect_select(BMEditMesh *em) */ enum { - ISECT_SEL = 0, - ISECT_SEL_UNSEL = 1, + ISECT_SEL = 0, + ISECT_SEL_UNSEL = 1, }; enum { - ISECT_SEPARATE_ALL = 0, - ISECT_SEPARATE_CUT = 1, - ISECT_SEPARATE_NONE = 2, + ISECT_SEPARATE_ALL = 0, + ISECT_SEPARATE_CUT = 1, + ISECT_SEPARATE_NONE = 2, }; static int edbm_intersect_exec(bContext *C, wmOperator *op) { - const int mode = RNA_enum_get(op->ptr, "mode"); - int (*test_fn)(BMFace *, void *); - bool use_separate_all = false; - bool use_separate_cut = false; - const int separate_mode = RNA_enum_get(op->ptr, "separate_mode"); - const float eps = RNA_float_get(op->ptr, "threshold"); - bool use_self; - bool has_isect; - - switch (mode) { - case ISECT_SEL: - test_fn = bm_face_isect_self; - use_self = true; - break; - default: /* ISECT_SEL_UNSEL */ - test_fn = bm_face_isect_pair; - use_self = false; - break; - } - - switch (separate_mode) { - case ISECT_SEPARATE_ALL: - use_separate_all = true; - break; - case ISECT_SEPARATE_CUT: - if (use_self == false) { - use_separate_cut = true; - } - else { - /* we could support this but would require more advanced logic inside 'BM_mesh_intersect' - * for now just separate all */ - use_separate_all = true; - } - break; - default: /* ISECT_SEPARATE_NONE */ - break; - } - ViewLayer *view_layer = CTX_data_view_layer(C); - uint objects_len = 0; - uint isect_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - - if (em->bm->totfacesel == 0) { - continue; - } - - has_isect = BM_mesh_intersect( - em->bm, - em->looptris, em->tottri, - test_fn, NULL, - use_self, use_separate_all, true, true, true, true, - -1, - eps); - - if (use_separate_cut) { - /* detach selected/un-selected faces */ - BM_mesh_separate_faces( - em->bm, - BM_elem_cb_check_hflag_enabled_simple(const BMFace *, BM_ELEM_SELECT)); - } - - if (has_isect) { - edbm_intersect_select(em); - } - else { - isect_len++; - } - } - MEM_freeN(objects); - - if (isect_len == objects_len) { - BKE_report(op->reports, RPT_WARNING, "No intersections found"); - } - return OPERATOR_FINISHED; + const int mode = RNA_enum_get(op->ptr, "mode"); + int (*test_fn)(BMFace *, void *); + bool use_separate_all = false; + bool use_separate_cut = false; + const int separate_mode = RNA_enum_get(op->ptr, "separate_mode"); + const float eps = RNA_float_get(op->ptr, "threshold"); + bool use_self; + bool has_isect; + + switch (mode) { + case ISECT_SEL: + test_fn = bm_face_isect_self; + use_self = true; + break; + default: /* ISECT_SEL_UNSEL */ + test_fn = bm_face_isect_pair; + use_self = false; + break; + } + + switch (separate_mode) { + case ISECT_SEPARATE_ALL: + use_separate_all = true; + break; + case ISECT_SEPARATE_CUT: + if (use_self == false) { + use_separate_cut = true; + } + else { + /* we could support this but would require more advanced logic inside 'BM_mesh_intersect' + * for now just separate all */ + use_separate_all = true; + } + break; + default: /* ISECT_SEPARATE_NONE */ + break; + } + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + uint isect_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + + if (em->bm->totfacesel == 0) { + continue; + } + + has_isect = BM_mesh_intersect(em->bm, + em->looptris, + em->tottri, + test_fn, + NULL, + use_self, + use_separate_all, + true, + true, + true, + true, + -1, + eps); + + if (use_separate_cut) { + /* detach selected/un-selected faces */ + BM_mesh_separate_faces( + em->bm, BM_elem_cb_check_hflag_enabled_simple(const BMFace *, BM_ELEM_SELECT)); + } + + if (has_isect) { + edbm_intersect_select(em); + } + else { + isect_len++; + } + } + MEM_freeN(objects); + + if (isect_len == objects_len) { + BKE_report(op->reports, RPT_WARNING, "No intersections found"); + } + return OPERATOR_FINISHED; } void MESH_OT_intersect(struct wmOperatorType *ot) { - static const EnumPropertyItem isect_mode_items[] = { - {ISECT_SEL, "SELECT", 0, "Self Intersect", - "Self intersect selected faces"}, - {ISECT_SEL_UNSEL, "SELECT_UNSELECT", 0, "Selected/Unselected", - "Intersect selected with unselected faces"}, - {0, NULL, 0, NULL, NULL}, - }; - - static const EnumPropertyItem isect_separate_items[] = { - {ISECT_SEPARATE_ALL, "ALL", 0, "All", - "Separate all geometry from intersections"}, - {ISECT_SEPARATE_CUT, "CUT", 0, "Cut", - "Cut into geometry keeping each side separate (Selected/Unselected only)"}, - {ISECT_SEPARATE_NONE, "NONE", 0, "Merge", - "Merge all geometry from the intersection"}, - {0, NULL, 0, NULL, NULL}, - }; - - /* identifiers */ - ot->name = "Intersect (Knife)"; - ot->description = "Cut an intersection into faces"; - ot->idname = "MESH_OT_intersect"; - - /* api callbacks */ - ot->exec = edbm_intersect_exec; - ot->poll = ED_operator_editmesh; - - /* props */ - RNA_def_enum(ot->srna, "mode", isect_mode_items, ISECT_SEL_UNSEL, "Source", ""); - RNA_def_enum(ot->srna, "separate_mode", isect_separate_items, ISECT_SEPARATE_CUT, "Separate Mode", ""); - RNA_def_float_distance(ot->srna, "threshold", 0.000001f, 0.0, 0.01, "Merge threshold", "", 0.0, 0.001); - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + static const EnumPropertyItem isect_mode_items[] = { + {ISECT_SEL, "SELECT", 0, "Self Intersect", "Self intersect selected faces"}, + {ISECT_SEL_UNSEL, + "SELECT_UNSELECT", + 0, + "Selected/Unselected", + "Intersect selected with unselected faces"}, + {0, NULL, 0, NULL, NULL}, + }; + + static const EnumPropertyItem isect_separate_items[] = { + {ISECT_SEPARATE_ALL, "ALL", 0, "All", "Separate all geometry from intersections"}, + {ISECT_SEPARATE_CUT, + "CUT", + 0, + "Cut", + "Cut into geometry keeping each side separate (Selected/Unselected only)"}, + {ISECT_SEPARATE_NONE, "NONE", 0, "Merge", "Merge all geometry from the intersection"}, + {0, NULL, 0, NULL, NULL}, + }; + + /* identifiers */ + ot->name = "Intersect (Knife)"; + ot->description = "Cut an intersection into faces"; + ot->idname = "MESH_OT_intersect"; + + /* api callbacks */ + ot->exec = edbm_intersect_exec; + ot->poll = ED_operator_editmesh; + + /* props */ + RNA_def_enum(ot->srna, "mode", isect_mode_items, ISECT_SEL_UNSEL, "Source", ""); + RNA_def_enum( + ot->srna, "separate_mode", isect_separate_items, ISECT_SEPARATE_CUT, "Separate Mode", ""); + RNA_def_float_distance( + ot->srna, "threshold", 0.000001f, 0.0, 0.01, "Merge threshold", "", 0.0, 0.001); + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } /** \} */ - /* -------------------------------------------------------------------- */ /* Boolean (a kind of intersect) */ @@ -275,74 +283,90 @@ void MESH_OT_intersect(struct wmOperatorType *ot) static int edbm_intersect_boolean_exec(bContext *C, wmOperator *op) { - const int boolean_operation = RNA_enum_get(op->ptr, "operation"); - bool use_swap = RNA_boolean_get(op->ptr, "use_swap"); - const float eps = RNA_float_get(op->ptr, "threshold"); - int (*test_fn)(BMFace *, void *); - bool has_isect; - - test_fn = use_swap ? bm_face_isect_pair_swap : bm_face_isect_pair; - ViewLayer *view_layer = CTX_data_view_layer(C); - uint objects_len = 0; - uint isect_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - - if (em->bm->totfacesel == 0) { - continue; - } - - has_isect = BM_mesh_intersect( - em->bm, - em->looptris, em->tottri, - test_fn, NULL, - false, false, true, true, false, true, - boolean_operation, - eps); - - - if (has_isect) { - edbm_intersect_select(em); - } - else { - isect_len++; - } - } - MEM_freeN(objects); - - if (isect_len == objects_len) { - BKE_report(op->reports, RPT_WARNING, "No intersections found"); - } - return OPERATOR_FINISHED; + const int boolean_operation = RNA_enum_get(op->ptr, "operation"); + bool use_swap = RNA_boolean_get(op->ptr, "use_swap"); + const float eps = RNA_float_get(op->ptr, "threshold"); + int (*test_fn)(BMFace *, void *); + bool has_isect; + + test_fn = use_swap ? bm_face_isect_pair_swap : bm_face_isect_pair; + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + uint isect_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + + if (em->bm->totfacesel == 0) { + continue; + } + + has_isect = BM_mesh_intersect(em->bm, + em->looptris, + em->tottri, + test_fn, + NULL, + false, + false, + true, + true, + false, + true, + boolean_operation, + eps); + + if (has_isect) { + edbm_intersect_select(em); + } + else { + isect_len++; + } + } + MEM_freeN(objects); + + if (isect_len == objects_len) { + BKE_report(op->reports, RPT_WARNING, "No intersections found"); + } + return OPERATOR_FINISHED; } void MESH_OT_intersect_boolean(struct wmOperatorType *ot) { - static const EnumPropertyItem isect_boolean_operation_items[] = { - {BMESH_ISECT_BOOLEAN_ISECT, "INTERSECT", 0, "Intersect", ""}, - {BMESH_ISECT_BOOLEAN_UNION, "UNION", 0, "Union", ""}, - {BMESH_ISECT_BOOLEAN_DIFFERENCE, "DIFFERENCE", 0, "Difference", ""}, - {0, NULL, 0, NULL, NULL}, - }; - - /* identifiers */ - ot->name = "Intersect (Boolean)"; - ot->description = "Cut solid geometry from selected to unselected"; - ot->idname = "MESH_OT_intersect_boolean"; - - /* api callbacks */ - ot->exec = edbm_intersect_boolean_exec; - ot->poll = ED_operator_editmesh; - - /* props */ - RNA_def_enum(ot->srna, "operation", isect_boolean_operation_items, BMESH_ISECT_BOOLEAN_DIFFERENCE, "Boolean", ""); - RNA_def_boolean(ot->srna, "use_swap", false, "Swap", "Use with difference intersection to swap which side is kept"); - RNA_def_float_distance(ot->srna, "threshold", 0.000001f, 0.0, 0.01, "Merge threshold", "", 0.0, 0.001); - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + static const EnumPropertyItem isect_boolean_operation_items[] = { + {BMESH_ISECT_BOOLEAN_ISECT, "INTERSECT", 0, "Intersect", ""}, + {BMESH_ISECT_BOOLEAN_UNION, "UNION", 0, "Union", ""}, + {BMESH_ISECT_BOOLEAN_DIFFERENCE, "DIFFERENCE", 0, "Difference", ""}, + {0, NULL, 0, NULL, NULL}, + }; + + /* identifiers */ + ot->name = "Intersect (Boolean)"; + ot->description = "Cut solid geometry from selected to unselected"; + ot->idname = "MESH_OT_intersect_boolean"; + + /* api callbacks */ + ot->exec = edbm_intersect_boolean_exec; + ot->poll = ED_operator_editmesh; + + /* props */ + RNA_def_enum(ot->srna, + "operation", + isect_boolean_operation_items, + BMESH_ISECT_BOOLEAN_DIFFERENCE, + "Boolean", + ""); + RNA_def_boolean(ot->srna, + "use_swap", + false, + "Swap", + "Use with difference intersection to swap which side is kept"); + RNA_def_float_distance( + ot->srna, "threshold", 0.000001f, 0.0, 0.01, "Merge threshold", "", 0.0, 0.001); + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } /** \} */ @@ -353,88 +377,82 @@ void MESH_OT_intersect_boolean(struct wmOperatorType *ot) /** \name Face/Edge Split * \{ */ -static void bm_face_split_by_edges( - BMesh *bm, BMFace *f, const char hflag, - /* reusable memory buffer */ - BLI_Buffer *edge_net_temp_buf) +static void bm_face_split_by_edges(BMesh *bm, + BMFace *f, + const char hflag, + /* reusable memory buffer */ + BLI_Buffer *edge_net_temp_buf) { - const int f_index = BM_elem_index_get(f); - - BMLoop *l_iter; - BMLoop *l_first; - BMVert *v; - - BMFace **face_arr; - int face_arr_len; - - /* likely this will stay very small - * all verts pushed into this stack _must_ have their previous edges set! */ - BLI_SMALLSTACK_DECLARE(vert_stack, BMVert *); - BLI_SMALLSTACK_DECLARE(vert_stack_next, BMVert *); - - BLI_assert(edge_net_temp_buf->count == 0); - - /* collect all edges */ - l_iter = l_first = BM_FACE_FIRST_LOOP(f); - do { - BMIter iter; - BMEdge *e; - - BM_ITER_ELEM (e, &iter, l_iter->v, BM_EDGES_OF_VERT) { - if (BM_elem_flag_test(e, hflag) && - (BM_elem_index_get(e) == f_index)) - { - v = BM_edge_other_vert(e, l_iter->v); - v->e = e; - - BLI_SMALLSTACK_PUSH(vert_stack, v); - BLI_buffer_append(edge_net_temp_buf, BMEdge *, e); - } - } - } while ((l_iter = l_iter->next) != l_first); - - - - /* now assign all */ - /* pop free values into the next stack */ - while ((v = BLI_SMALLSTACK_POP_EX(vert_stack, vert_stack_next))) { - BMIter eiter; - BMEdge *e_next; - - BM_ITER_ELEM (e_next, &eiter, v, BM_EDGES_OF_VERT) { - if (BM_elem_flag_test(e_next, hflag) && - (BM_elem_index_get(e_next) == -1)) - { - BMVert *v_next; - v_next = BM_edge_other_vert(e_next, v); - BM_elem_index_set(e_next, f_index); - BLI_SMALLSTACK_PUSH(vert_stack_next, v_next); - BLI_buffer_append(edge_net_temp_buf, BMEdge *, e_next); - } - } - - if (BLI_SMALLSTACK_IS_EMPTY(vert_stack)) { - BLI_SMALLSTACK_SWAP(vert_stack, vert_stack_next); - } - } - - BM_face_split_edgenet( - bm, f, edge_net_temp_buf->data, edge_net_temp_buf->count, - &face_arr, &face_arr_len); - - BLI_buffer_clear(edge_net_temp_buf); - - if (face_arr_len) { - int i; - for (i = 0; i < face_arr_len; i++) { - BM_face_select_set(bm, face_arr[i], true); - BM_elem_flag_disable(face_arr[i], hflag); - } - } - - if (face_arr) { - MEM_freeN(face_arr); - } + const int f_index = BM_elem_index_get(f); + + BMLoop *l_iter; + BMLoop *l_first; + BMVert *v; + + BMFace **face_arr; + int face_arr_len; + + /* likely this will stay very small + * all verts pushed into this stack _must_ have their previous edges set! */ + BLI_SMALLSTACK_DECLARE(vert_stack, BMVert *); + BLI_SMALLSTACK_DECLARE(vert_stack_next, BMVert *); + + BLI_assert(edge_net_temp_buf->count == 0); + + /* collect all edges */ + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + do { + BMIter iter; + BMEdge *e; + + BM_ITER_ELEM (e, &iter, l_iter->v, BM_EDGES_OF_VERT) { + if (BM_elem_flag_test(e, hflag) && (BM_elem_index_get(e) == f_index)) { + v = BM_edge_other_vert(e, l_iter->v); + v->e = e; + + BLI_SMALLSTACK_PUSH(vert_stack, v); + BLI_buffer_append(edge_net_temp_buf, BMEdge *, e); + } + } + } while ((l_iter = l_iter->next) != l_first); + + /* now assign all */ + /* pop free values into the next stack */ + while ((v = BLI_SMALLSTACK_POP_EX(vert_stack, vert_stack_next))) { + BMIter eiter; + BMEdge *e_next; + + BM_ITER_ELEM (e_next, &eiter, v, BM_EDGES_OF_VERT) { + if (BM_elem_flag_test(e_next, hflag) && (BM_elem_index_get(e_next) == -1)) { + BMVert *v_next; + v_next = BM_edge_other_vert(e_next, v); + BM_elem_index_set(e_next, f_index); + BLI_SMALLSTACK_PUSH(vert_stack_next, v_next); + BLI_buffer_append(edge_net_temp_buf, BMEdge *, e_next); + } + } + + if (BLI_SMALLSTACK_IS_EMPTY(vert_stack)) { + BLI_SMALLSTACK_SWAP(vert_stack, vert_stack_next); + } + } + + BM_face_split_edgenet( + bm, f, edge_net_temp_buf->data, edge_net_temp_buf->count, &face_arr, &face_arr_len); + + BLI_buffer_clear(edge_net_temp_buf); + + if (face_arr_len) { + int i; + for (i = 0; i < face_arr_len; i++) { + BM_face_select_set(bm, face_arr[i], true); + BM_elem_flag_disable(face_arr[i], hflag); + } + } + + if (face_arr) { + MEM_freeN(face_arr); + } } /** @@ -443,113 +461,114 @@ static void bm_face_split_by_edges( */ static bool bm_vert_in_faces_radial(BMVert *v, BMEdge *e_radial, BMFace *f_ignore) { - BLI_assert(BM_vert_in_face(v, f_ignore) == false); - if (e_radial->l) { - BMLoop *l_iter = e_radial->l; - do { - if (l_iter->f != f_ignore) { - if (BM_vert_in_face(v, l_iter->f)) { - return true; - } - } - } while ((l_iter = l_iter->radial_next) != e_radial->l); - } - return false; + BLI_assert(BM_vert_in_face(v, f_ignore) == false); + if (e_radial->l) { + BMLoop *l_iter = e_radial->l; + do { + if (l_iter->f != f_ignore) { + if (BM_vert_in_face(v, l_iter->f)) { + return true; + } + } + } while ((l_iter = l_iter->radial_next) != e_radial->l); + } + return false; } #ifdef USE_NET_ISLAND_CONNECT struct LinkBase { - LinkNode *list; - unsigned int list_len; + LinkNode *list; + unsigned int list_len; }; -static void ghash_insert_face_edge_link( - GHash *gh, BMFace *f_key, BMEdge *e_val, - MemArena *mem_arena) +static void ghash_insert_face_edge_link(GHash *gh, + BMFace *f_key, + BMEdge *e_val, + MemArena *mem_arena) { - void **ls_base_p; - struct LinkBase *ls_base; - LinkNode *ls; - - if (!BLI_ghash_ensure_p(gh, f_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; - } - - ls = BLI_memarena_alloc(mem_arena, sizeof(*ls)); - ls->next = ls_base->list; - ls->link = e_val; - ls_base->list = ls; - ls_base->list_len += 1; + void **ls_base_p; + struct LinkBase *ls_base; + LinkNode *ls; + + if (!BLI_ghash_ensure_p(gh, f_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; + } + + ls = BLI_memarena_alloc(mem_arena, sizeof(*ls)); + ls->next = ls_base->list; + ls->link = e_val; + ls_base->list = ls; + ls_base->list_len += 1; } static int bm_edge_sort_length_cb(const void *e_a_v, const void *e_b_v) { - const float val_a = -BM_edge_calc_length_squared(*((BMEdge **)e_a_v)); - const float val_b = -BM_edge_calc_length_squared(*((BMEdge **)e_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_edge_calc_length_squared(*((BMEdge **)e_a_v)); + const float val_b = -BM_edge_calc_length_squared(*((BMEdge **)e_b_v)); + + if (val_a > val_b) + return 1; + else if (val_a < val_b) + return -1; + else + return 0; } static void bm_face_split_by_edges_island_connect( - BMesh *bm, BMFace *f, - LinkNode *e_link, const int e_link_len, - MemArena *mem_arena_edgenet) + BMesh *bm, BMFace *f, LinkNode *e_link, const int e_link_len, MemArena *mem_arena_edgenet) { - BMEdge **edge_arr = BLI_memarena_alloc(mem_arena_edgenet, sizeof(*edge_arr) * e_link_len); - int edge_arr_len = 0; - - while (e_link) { - edge_arr[edge_arr_len++] = e_link->link; - e_link = e_link->next; - } - - { - unsigned int edge_arr_holes_len; - BMEdge **edge_arr_holes; - if (BM_face_split_edgenet_connect_islands( - bm, f, - edge_arr, e_link_len, - true, - 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 */ - } - } - - BM_face_split_edgenet( - bm, f, edge_arr, edge_arr_len, - NULL, NULL); - - for (int i = e_link_len; i < edge_arr_len; i++) { - BM_edge_select_set(bm, edge_arr[i], true); - } - - if (e_link_len != edge_arr_len) { - /* connecting partial islands can add redundant edges - * sort before removal to give deterministic outcome */ - qsort(edge_arr, edge_arr_len - e_link_len, sizeof(*edge_arr), bm_edge_sort_length_cb); - for (int i = e_link_len; i < edge_arr_len; i++) { - BMFace *f_pair[2]; - if (BM_edge_face_pair(edge_arr[i], &f_pair[0], &f_pair[1])) { - if (BM_face_share_vert_count(f_pair[0], f_pair[1]) == 2) { - BMFace *f_new = BM_faces_join(bm, f_pair, 2, true); - if (f_new) { - BM_face_select_set(bm, f_new, true); - } - } - } - } - } + BMEdge **edge_arr = BLI_memarena_alloc(mem_arena_edgenet, sizeof(*edge_arr) * e_link_len); + int edge_arr_len = 0; + + while (e_link) { + edge_arr[edge_arr_len++] = e_link->link; + e_link = e_link->next; + } + + { + unsigned int edge_arr_holes_len; + BMEdge **edge_arr_holes; + if (BM_face_split_edgenet_connect_islands(bm, + f, + edge_arr, + e_link_len, + true, + 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 */ + } + } + + BM_face_split_edgenet(bm, f, edge_arr, edge_arr_len, NULL, NULL); + + for (int i = e_link_len; i < edge_arr_len; i++) { + BM_edge_select_set(bm, edge_arr[i], true); + } + + if (e_link_len != edge_arr_len) { + /* connecting partial islands can add redundant edges + * sort before removal to give deterministic outcome */ + qsort(edge_arr, edge_arr_len - e_link_len, sizeof(*edge_arr), bm_edge_sort_length_cb); + for (int i = e_link_len; i < edge_arr_len; i++) { + BMFace *f_pair[2]; + if (BM_edge_face_pair(edge_arr[i], &f_pair[0], &f_pair[1])) { + if (BM_face_share_vert_count(f_pair[0], f_pair[1]) == 2) { + BMFace *f_new = BM_faces_join(bm, f_pair, 2, true); + if (f_new) { + BM_face_select_set(bm, f_new, true); + } + } + } + } + } } /** @@ -570,394 +589,389 @@ static void bm_face_split_by_edges_island_connect( * * \note Currently we don't snap to verts or split chains by verts on-edges. */ -static BMEdge *bm_face_split_edge_find( - BMEdge *e_a, BMFace *f_a, BMVert *v_pivot, BMFace **ftable, const int ftable_len, - float r_v_pivot_co[3], float *r_v_pivot_fac) +static BMEdge *bm_face_split_edge_find(BMEdge *e_a, + BMFace *f_a, + BMVert *v_pivot, + BMFace **ftable, + const int ftable_len, + float r_v_pivot_co[3], + float *r_v_pivot_fac) { - const int f_a_index = BM_elem_index_get(e_a); - bool found_other_self = false; - int found_other_face = 0; - BLI_SMALLSTACK_DECLARE(face_stack, BMFace *); - - /* loop over surrounding edges to check if we're part of a chain or a delimiter vertex */ - BMEdge *e_b = v_pivot->e; - do { - if (e_b != e_a) { - const int f_b_index = BM_elem_index_get(e_b); - if (f_b_index == f_a_index) { - /* not an endpoint */ - found_other_self = true; - } - else if (f_b_index != -1) { - BLI_assert(f_b_index < ftable_len); - UNUSED_VARS_NDEBUG(ftable_len); - - /* 'v_pivot' spans 2+ faces, - * tag to ensure we pick an edge that includes this face */ - BMFace *f_b = ftable[f_b_index]; - if (!BM_elem_flag_test(f_b, BM_ELEM_INTERNAL_TAG)) { - BM_elem_flag_enable(f_b, BM_ELEM_INTERNAL_TAG); - BLI_SMALLSTACK_PUSH(face_stack, f_b); - found_other_face++; - } - } - } - } while ((e_b = BM_DISK_EDGE_NEXT(e_b, v_pivot)) != v_pivot->e); - - BMEdge *e_split = NULL; - - /* if we have no others or the other edge is outside this face, - * we're an endpoint to connect to a boundary */ - if ((found_other_self == false) || found_other_face) { - - BMLoop *l_iter, *l_first; - l_iter = l_first = BM_FACE_FIRST_LOOP(f_a); - float dist_best_sq = FLT_MAX; - - do { - float v_pivot_co_test[3]; - float v_pivot_fac = line_point_factor_v3(v_pivot->co, l_iter->e->v1->co, l_iter->e->v2->co); - CLAMP(v_pivot_fac, 0.0f, 1.0f); - interp_v3_v3v3(v_pivot_co_test, l_iter->e->v1->co, l_iter->e->v2->co, v_pivot_fac); - - float dist_test_sq = len_squared_v3v3(v_pivot_co_test, v_pivot->co); - if ((dist_test_sq < dist_best_sq) || (e_split == NULL)) { - bool ok = true; - - if (UNLIKELY(BM_edge_exists(v_pivot, l_iter->e->v1) || - BM_edge_exists(v_pivot, l_iter->e->v2))) - { - /* very unlikely but will cause complications splicing the verts together, - * so just skip this case */ - ok = false; - } - else if (found_other_face) { - /* double check that _all_ the faces used by v_pivot's edges are attached - * to this edge otherwise don't attempt the split since it will give - * non-deterministic results */ - BMLoop *l_radial_iter = l_iter->radial_next; - int other_face_shared = 0; - if (l_radial_iter != l_iter) { - do { - if (BM_elem_flag_test(l_radial_iter->f, BM_ELEM_INTERNAL_TAG)) { - other_face_shared++; - } - } while ((l_radial_iter = l_radial_iter->radial_next) != l_iter); - } - if (other_face_shared != found_other_face) { - ok = false; - } - } - - if (ok) { - e_split = l_iter->e; - dist_best_sq = dist_test_sq; - copy_v3_v3(r_v_pivot_co, v_pivot_co_test); - *r_v_pivot_fac = v_pivot_fac; - } - } - } while ((l_iter = l_iter->next) != l_first); - } - - { - /* reset the flag, for future use */ - BMFace *f; - while ((f = BLI_SMALLSTACK_POP(face_stack))) { - BM_elem_flag_disable(f, BM_ELEM_INTERNAL_TAG); - } - } - - return e_split; + const int f_a_index = BM_elem_index_get(e_a); + bool found_other_self = false; + int found_other_face = 0; + BLI_SMALLSTACK_DECLARE(face_stack, BMFace *); + + /* loop over surrounding edges to check if we're part of a chain or a delimiter vertex */ + BMEdge *e_b = v_pivot->e; + do { + if (e_b != e_a) { + const int f_b_index = BM_elem_index_get(e_b); + if (f_b_index == f_a_index) { + /* not an endpoint */ + found_other_self = true; + } + else if (f_b_index != -1) { + BLI_assert(f_b_index < ftable_len); + UNUSED_VARS_NDEBUG(ftable_len); + + /* 'v_pivot' spans 2+ faces, + * tag to ensure we pick an edge that includes this face */ + BMFace *f_b = ftable[f_b_index]; + if (!BM_elem_flag_test(f_b, BM_ELEM_INTERNAL_TAG)) { + BM_elem_flag_enable(f_b, BM_ELEM_INTERNAL_TAG); + BLI_SMALLSTACK_PUSH(face_stack, f_b); + found_other_face++; + } + } + } + } while ((e_b = BM_DISK_EDGE_NEXT(e_b, v_pivot)) != v_pivot->e); + + BMEdge *e_split = NULL; + + /* if we have no others or the other edge is outside this face, + * we're an endpoint to connect to a boundary */ + if ((found_other_self == false) || found_other_face) { + + BMLoop *l_iter, *l_first; + l_iter = l_first = BM_FACE_FIRST_LOOP(f_a); + float dist_best_sq = FLT_MAX; + + do { + float v_pivot_co_test[3]; + float v_pivot_fac = line_point_factor_v3(v_pivot->co, l_iter->e->v1->co, l_iter->e->v2->co); + CLAMP(v_pivot_fac, 0.0f, 1.0f); + interp_v3_v3v3(v_pivot_co_test, l_iter->e->v1->co, l_iter->e->v2->co, v_pivot_fac); + + float dist_test_sq = len_squared_v3v3(v_pivot_co_test, v_pivot->co); + if ((dist_test_sq < dist_best_sq) || (e_split == NULL)) { + bool ok = true; + + if (UNLIKELY(BM_edge_exists(v_pivot, l_iter->e->v1) || + BM_edge_exists(v_pivot, l_iter->e->v2))) { + /* very unlikely but will cause complications splicing the verts together, + * so just skip this case */ + ok = false; + } + else if (found_other_face) { + /* double check that _all_ the faces used by v_pivot's edges are attached + * to this edge otherwise don't attempt the split since it will give + * non-deterministic results */ + BMLoop *l_radial_iter = l_iter->radial_next; + int other_face_shared = 0; + if (l_radial_iter != l_iter) { + do { + if (BM_elem_flag_test(l_radial_iter->f, BM_ELEM_INTERNAL_TAG)) { + other_face_shared++; + } + } while ((l_radial_iter = l_radial_iter->radial_next) != l_iter); + } + if (other_face_shared != found_other_face) { + ok = false; + } + } + + if (ok) { + e_split = l_iter->e; + dist_best_sq = dist_test_sq; + copy_v3_v3(r_v_pivot_co, v_pivot_co_test); + *r_v_pivot_fac = v_pivot_fac; + } + } + } while ((l_iter = l_iter->next) != l_first); + } + + { + /* reset the flag, for future use */ + BMFace *f; + while ((f = BLI_SMALLSTACK_POP(face_stack))) { + BM_elem_flag_disable(f, BM_ELEM_INTERNAL_TAG); + } + } + + return e_split; } -#endif /* USE_NET_ISLAND_CONNECT */ - +#endif /* USE_NET_ISLAND_CONNECT */ static int edbm_face_split_by_edges_exec(bContext *C, wmOperator *UNUSED(op)) { - const char hflag = BM_ELEM_TAG; - - BMEdge *e; - BMIter iter; - - ViewLayer *view_layer = CTX_data_view_layer(C); - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMesh *bm = em->bm; - - if ((bm->totedgesel == 0) || - (bm->totfacesel == 0)) - { - continue; - } - - BLI_SMALLSTACK_DECLARE(loop_stack, BMLoop *); - - { - BMVert *v; - BM_ITER_MESH(v, &iter, bm, BM_VERTS_OF_MESH) { - BM_elem_flag_disable(v, hflag); - } - } - - /* edge index is set to -1 then used to associate them with faces */ - BM_ITER_MESH(e, &iter, bm, BM_EDGES_OF_MESH) { - if (BM_elem_flag_test(e, BM_ELEM_SELECT) && BM_edge_is_wire(e)) { - BM_elem_flag_enable(e, hflag); - - BM_elem_flag_enable(e->v1, hflag); - BM_elem_flag_enable(e->v2, hflag); - - } - else { - BM_elem_flag_disable(e, hflag); - } - BM_elem_index_set(e, -1); /* set_dirty */ - } - bm->elem_index_dirty |= BM_EDGE; - - { - BMFace *f; - int i; - BM_ITER_MESH_INDEX(f, &iter, bm, BM_FACES_OF_MESH, i) { - if (BM_elem_flag_test(f, BM_ELEM_SELECT)) { - BM_elem_flag_enable(f, hflag); - } - else { - BM_elem_flag_disable(f, hflag); - } - BM_elem_flag_disable(f, BM_ELEM_INTERNAL_TAG); - BM_elem_index_set(f, i); /* set_ok */ - } - } - bm->elem_index_dirty &= ~BM_FACE; - - BM_ITER_MESH(e, &iter, bm, BM_EDGES_OF_MESH) { - if (BM_elem_flag_test(e, hflag)) { - BMIter viter; - BMVert *v; - BM_ITER_ELEM(v, &viter, e, BM_VERTS_OF_EDGE) { - BMIter liter; - BMLoop *l; - - unsigned int loop_stack_len; - BMLoop *l_best = NULL; - - BLI_assert(BLI_SMALLSTACK_IS_EMPTY(loop_stack)); - loop_stack_len = 0; - - BM_ITER_ELEM(l, &liter, v, BM_LOOPS_OF_VERT) { - if (BM_elem_flag_test(l->f, hflag)) { - BLI_SMALLSTACK_PUSH(loop_stack, l); - loop_stack_len++; - } - } - - if (loop_stack_len == 0) { - /* pass */ - } - else if (loop_stack_len == 1) { - l_best = BLI_SMALLSTACK_POP(loop_stack); - } - else { - /* complicated case, match the edge with a face-loop */ - - BMVert *v_other = BM_edge_other_vert(e, v); - float e_dir[3]; - - /* we want closest to zero */ - float dot_best = FLT_MAX; - - sub_v3_v3v3(e_dir, v_other->co, v->co); - normalize_v3(e_dir); - - while ((l = BLI_SMALLSTACK_POP(loop_stack))) { - float dot_test; - - /* Check dot first to save on expensive angle-comparison. - * ideal case is 90d difference == 0.0 dot */ - dot_test = fabsf(dot_v3v3(e_dir, l->f->no)); - if (dot_test < dot_best) { - - /* check we're in the correct corner - * (works with convex loops too) */ - if (angle_signed_on_axis_v3v3v3_v3(l->prev->v->co, l->v->co, v_other->co, l->f->no) < - angle_signed_on_axis_v3v3v3_v3(l->prev->v->co, l->v->co, l->next->v->co, l->f->no)) - { - dot_best = dot_test; - l_best = l; - } - } - } - } - - if (l_best) { - BM_elem_index_set(e, BM_elem_index_get(l_best->f)); /* set_dirty */ - } - } - } - } - - { - BMFace *f; - BLI_buffer_declare_static(BMEdge **, edge_net_temp_buf, 0, 128); - - BM_ITER_MESH(f, &iter, bm, BM_FACES_OF_MESH) { - if (BM_elem_flag_test(f, hflag)) { - bm_face_split_by_edges(bm, f, hflag, &edge_net_temp_buf); - } - } - BLI_buffer_free(&edge_net_temp_buf); - } + const char hflag = BM_ELEM_TAG; + + BMEdge *e; + BMIter iter; + + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMesh *bm = em->bm; + + if ((bm->totedgesel == 0) || (bm->totfacesel == 0)) { + continue; + } + + BLI_SMALLSTACK_DECLARE(loop_stack, BMLoop *); + + { + BMVert *v; + BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { + BM_elem_flag_disable(v, hflag); + } + } + + /* edge index is set to -1 then used to associate them with faces */ + BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { + if (BM_elem_flag_test(e, BM_ELEM_SELECT) && BM_edge_is_wire(e)) { + BM_elem_flag_enable(e, hflag); + + BM_elem_flag_enable(e->v1, hflag); + BM_elem_flag_enable(e->v2, hflag); + } + else { + BM_elem_flag_disable(e, hflag); + } + BM_elem_index_set(e, -1); /* set_dirty */ + } + bm->elem_index_dirty |= BM_EDGE; + + { + BMFace *f; + int i; + BM_ITER_MESH_INDEX (f, &iter, bm, BM_FACES_OF_MESH, i) { + if (BM_elem_flag_test(f, BM_ELEM_SELECT)) { + BM_elem_flag_enable(f, hflag); + } + else { + BM_elem_flag_disable(f, hflag); + } + BM_elem_flag_disable(f, BM_ELEM_INTERNAL_TAG); + BM_elem_index_set(f, i); /* set_ok */ + } + } + bm->elem_index_dirty &= ~BM_FACE; + + BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { + if (BM_elem_flag_test(e, hflag)) { + BMIter viter; + BMVert *v; + BM_ITER_ELEM (v, &viter, e, BM_VERTS_OF_EDGE) { + BMIter liter; + BMLoop *l; + + unsigned int loop_stack_len; + BMLoop *l_best = NULL; + + BLI_assert(BLI_SMALLSTACK_IS_EMPTY(loop_stack)); + loop_stack_len = 0; + + BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) { + if (BM_elem_flag_test(l->f, hflag)) { + BLI_SMALLSTACK_PUSH(loop_stack, l); + loop_stack_len++; + } + } + + if (loop_stack_len == 0) { + /* pass */ + } + else if (loop_stack_len == 1) { + l_best = BLI_SMALLSTACK_POP(loop_stack); + } + else { + /* complicated case, match the edge with a face-loop */ + + BMVert *v_other = BM_edge_other_vert(e, v); + float e_dir[3]; + + /* we want closest to zero */ + float dot_best = FLT_MAX; + + sub_v3_v3v3(e_dir, v_other->co, v->co); + normalize_v3(e_dir); + + while ((l = BLI_SMALLSTACK_POP(loop_stack))) { + float dot_test; + + /* Check dot first to save on expensive angle-comparison. + * ideal case is 90d difference == 0.0 dot */ + dot_test = fabsf(dot_v3v3(e_dir, l->f->no)); + if (dot_test < dot_best) { + + /* check we're in the correct corner + * (works with convex loops too) */ + if (angle_signed_on_axis_v3v3v3_v3( + l->prev->v->co, l->v->co, v_other->co, l->f->no) < + angle_signed_on_axis_v3v3v3_v3( + l->prev->v->co, l->v->co, l->next->v->co, l->f->no)) { + dot_best = dot_test; + l_best = l; + } + } + } + } + + if (l_best) { + BM_elem_index_set(e, BM_elem_index_get(l_best->f)); /* set_dirty */ + } + } + } + } + + { + BMFace *f; + BLI_buffer_declare_static(BMEdge **, edge_net_temp_buf, 0, 128); + + BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { + if (BM_elem_flag_test(f, hflag)) { + bm_face_split_by_edges(bm, f, hflag, &edge_net_temp_buf); + } + } + BLI_buffer_free(&edge_net_temp_buf); + } #ifdef USE_NET_ISLAND_CONNECT - /* before overwriting edge index values, collect edges left untouched */ - BLI_Stack *edges_loose = BLI_stack_new(sizeof(BMEdge *), __func__); - BM_ITER_MESH(e, &iter, bm, BM_EDGES_OF_MESH) { - if (BM_elem_flag_test(e, BM_ELEM_SELECT) && BM_edge_is_wire(e)) { - BLI_stack_push(edges_loose, &e); - } - } + /* before overwriting edge index values, collect edges left untouched */ + BLI_Stack *edges_loose = BLI_stack_new(sizeof(BMEdge *), __func__); + BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { + if (BM_elem_flag_test(e, BM_ELEM_SELECT) && BM_edge_is_wire(e)) { + BLI_stack_push(edges_loose, &e); + } + } #endif - EDBM_mesh_normals_update(em); - EDBM_update_generic(em, true, true); - + EDBM_mesh_normals_update(em); + EDBM_update_generic(em, true, true); #ifdef USE_NET_ISLAND_CONNECT - /* we may have remaining isolated regions remaining, - * these will need to have connecting edges created */ - if (!BLI_stack_is_empty(edges_loose)) { - GHash *face_edge_map = BLI_ghash_ptr_new(__func__); - - MemArena *mem_arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__); - - BM_mesh_elem_index_ensure(bm, BM_FACE); - - { - BMBVHTree *bmbvh = BKE_bmbvh_new(bm, em->looptris, em->tottri, BMBVH_RESPECT_SELECT, NULL, false); - - BM_ITER_MESH(e, &iter, bm, BM_EDGES_OF_MESH) { - BM_elem_index_set(e, -1); /* set_dirty */ - } - - while (!BLI_stack_is_empty(edges_loose)) { - BLI_stack_pop(edges_loose, &e); - float e_center[3]; - mid_v3_v3v3(e_center, e->v1->co, e->v2->co); - - BMFace *f = BKE_bmbvh_find_face_closest(bmbvh, e_center, FLT_MAX); - if (f) { - ghash_insert_face_edge_link(face_edge_map, f, e, mem_arena); - BM_elem_index_set(e, BM_elem_index_get(f)); /* set_dirty */ - } - } - - BKE_bmbvh_free(bmbvh); - } - - bm->elem_index_dirty |= BM_EDGE; - - BM_mesh_elem_table_ensure(bm, BM_FACE); - - /* detect edges chains that span faces - * and splice vertices into the closest edges */ - { - GHashIterator gh_iter; - - GHASH_ITER(gh_iter, face_edge_map) { - BMFace *f = BLI_ghashIterator_getKey(&gh_iter); - struct LinkBase *e_ls_base = BLI_ghashIterator_getValue(&gh_iter); - LinkNode *e_link = e_ls_base->list; - - do { - e = e_link->link; - - for (int j = 0; j < 2; j++) { - BMVert *v_pivot = (&e->v1)[j]; - /* checking that \a v_pivot isn't in the face prevents attempting - * to splice the same vertex into an edge from multiple faces */ - if (!BM_vert_in_face(v_pivot, f)) { - float v_pivot_co[3]; - float v_pivot_fac; - BMEdge *e_split = bm_face_split_edge_find( - e, f, v_pivot, bm->ftable, bm->totface, - v_pivot_co, &v_pivot_fac); - - if (e_split) { - /* for degenerate cases this vertex may be in one - * of this edges radial faces */ - if (!bm_vert_in_faces_radial(v_pivot, e_split, f)) { - BMEdge *e_new; - BMVert *v_new = BM_edge_split(bm, e_split, e_split->v1, &e_new, v_pivot_fac); - if (v_new) { - /* we _know_ these don't share an edge */ - BM_vert_splice(bm, v_pivot, v_new); - BM_elem_index_set(e_new, BM_elem_index_get(e_split)); - } - } - } - } - } - - } while ((e_link = e_link->next)); - } - } - - - { - MemArena *mem_arena_edgenet = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__); - - GHashIterator gh_iter; - - GHASH_ITER(gh_iter, face_edge_map) { - BMFace *f = BLI_ghashIterator_getKey(&gh_iter); - struct LinkBase *e_ls_base = BLI_ghashIterator_getValue(&gh_iter); - - bm_face_split_by_edges_island_connect( - bm, f, - e_ls_base->list, e_ls_base->list_len, - mem_arena_edgenet); - - BLI_memarena_clear(mem_arena_edgenet); - } - - BLI_memarena_free(mem_arena_edgenet); - } - - BLI_memarena_free(mem_arena); - - BLI_ghash_free(face_edge_map, NULL, NULL); - - EDBM_mesh_normals_update(em); - EDBM_update_generic(em, true, true); - } - - BLI_stack_free(edges_loose); -#endif /* USE_NET_ISLAND_CONNECT */ - - } - MEM_freeN(objects); - return OPERATOR_FINISHED; + /* we may have remaining isolated regions remaining, + * these will need to have connecting edges created */ + if (!BLI_stack_is_empty(edges_loose)) { + GHash *face_edge_map = BLI_ghash_ptr_new(__func__); + + MemArena *mem_arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__); + + BM_mesh_elem_index_ensure(bm, BM_FACE); + + { + BMBVHTree *bmbvh = BKE_bmbvh_new( + bm, em->looptris, em->tottri, BMBVH_RESPECT_SELECT, NULL, false); + + BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { + BM_elem_index_set(e, -1); /* set_dirty */ + } + + while (!BLI_stack_is_empty(edges_loose)) { + BLI_stack_pop(edges_loose, &e); + float e_center[3]; + mid_v3_v3v3(e_center, e->v1->co, e->v2->co); + + BMFace *f = BKE_bmbvh_find_face_closest(bmbvh, e_center, FLT_MAX); + if (f) { + ghash_insert_face_edge_link(face_edge_map, f, e, mem_arena); + BM_elem_index_set(e, BM_elem_index_get(f)); /* set_dirty */ + } + } + + BKE_bmbvh_free(bmbvh); + } + + bm->elem_index_dirty |= BM_EDGE; + + BM_mesh_elem_table_ensure(bm, BM_FACE); + + /* detect edges chains that span faces + * and splice vertices into the closest edges */ + { + GHashIterator gh_iter; + + GHASH_ITER (gh_iter, face_edge_map) { + BMFace *f = BLI_ghashIterator_getKey(&gh_iter); + struct LinkBase *e_ls_base = BLI_ghashIterator_getValue(&gh_iter); + LinkNode *e_link = e_ls_base->list; + + do { + e = e_link->link; + + for (int j = 0; j < 2; j++) { + BMVert *v_pivot = (&e->v1)[j]; + /* checking that \a v_pivot isn't in the face prevents attempting + * to splice the same vertex into an edge from multiple faces */ + if (!BM_vert_in_face(v_pivot, f)) { + float v_pivot_co[3]; + float v_pivot_fac; + BMEdge *e_split = bm_face_split_edge_find( + e, f, v_pivot, bm->ftable, bm->totface, v_pivot_co, &v_pivot_fac); + + if (e_split) { + /* for degenerate cases this vertex may be in one + * of this edges radial faces */ + if (!bm_vert_in_faces_radial(v_pivot, e_split, f)) { + BMEdge *e_new; + BMVert *v_new = BM_edge_split(bm, e_split, e_split->v1, &e_new, v_pivot_fac); + if (v_new) { + /* we _know_ these don't share an edge */ + BM_vert_splice(bm, v_pivot, v_new); + BM_elem_index_set(e_new, BM_elem_index_get(e_split)); + } + } + } + } + } + + } while ((e_link = e_link->next)); + } + } + + { + MemArena *mem_arena_edgenet = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__); + + GHashIterator gh_iter; + + GHASH_ITER (gh_iter, face_edge_map) { + BMFace *f = BLI_ghashIterator_getKey(&gh_iter); + struct LinkBase *e_ls_base = BLI_ghashIterator_getValue(&gh_iter); + + bm_face_split_by_edges_island_connect( + bm, f, e_ls_base->list, e_ls_base->list_len, mem_arena_edgenet); + + BLI_memarena_clear(mem_arena_edgenet); + } + + BLI_memarena_free(mem_arena_edgenet); + } + + BLI_memarena_free(mem_arena); + + BLI_ghash_free(face_edge_map, NULL, NULL); + + EDBM_mesh_normals_update(em); + EDBM_update_generic(em, true, true); + } + + BLI_stack_free(edges_loose); +#endif /* USE_NET_ISLAND_CONNECT */ + } + MEM_freeN(objects); + return OPERATOR_FINISHED; } - void MESH_OT_face_split_by_edges(struct wmOperatorType *ot) { - /* identifiers */ - ot->name = "Weld Edges into Faces"; - ot->description = "Weld loose edges into faces (splitting them into new faces)"; - ot->idname = "MESH_OT_face_split_by_edges"; + /* identifiers */ + ot->name = "Weld Edges into Faces"; + ot->description = "Weld loose edges into faces (splitting them into new faces)"; + ot->idname = "MESH_OT_face_split_by_edges"; - /* api callbacks */ - ot->exec = edbm_face_split_by_edges_exec; - ot->poll = ED_operator_editmesh; + /* api callbacks */ + ot->exec = edbm_face_split_by_edges_exec; + ot->poll = ED_operator_editmesh; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } /** \} */ |