Edit Mesh AutoMerge: Improve `Split Edges & Faces` option

Now all wire edges linked to the merged vertex are used for split faces.

Reviewers: campbellbarton

Differential Revision: https://developer.blender.org/D5603
This commit is contained in:
Germano Cavalcante 2019-08-27 01:41:05 -03:00
parent 60ba7d4539
commit e57b14feae
3 changed files with 139 additions and 32 deletions

View File

@ -145,8 +145,12 @@ void ED_mesh_undosys_type(struct UndoType *ut);
void EDBM_select_mirrored(
struct BMEditMesh *em, const int axis, const bool extend, int *r_totmirr, int *r_totfail);
void EDBM_automerge(struct Scene *scene, struct Object *ob, bool update, const char hflag);
void EDBM_automerge_and_split(
struct Scene *scene, struct Object *ob, bool split_edges, bool update, const char hflag);
void EDBM_automerge_and_split(struct Scene *scene,
struct Object *ob,
bool split_edges,
bool split_faces,
bool update,
const char hflag);
struct BMVert *EDBM_vert_find_nearest_ex(struct ViewContext *vc,
float *r_dist,

View File

@ -201,6 +201,14 @@ struct EDBMSplitEdge {
float lambda;
};
struct EDBMSplitBestFaceData {
BMEdge **edgenet;
int edgenet_len;
float average;
BMFace *r_best_face;
};
struct EDBMSplitEdgeData {
BMesh *bm;
@ -208,10 +216,49 @@ struct EDBMSplitEdgeData {
float r_lambda;
};
static bool edbm_automerge_and_split_check_best_face_cb(BMFace *UNUSED(f),
BMLoop *l_a,
BMLoop *l_b,
void *userdata)
static bool edbm_vert_pair_share_best_splittable_face_cb(BMFace *f,
BMLoop *l_a,
BMLoop *l_b,
void *userdata)
{
struct EDBMSplitBestFaceData *data = userdata;
float no[3], min = FLT_MAX, max = -FLT_MAX;
copy_v3_v3(no, f->no);
BMVert *verts[2] = {NULL};
BMEdge **e_iter = &data->edgenet[0];
for (int i = data->edgenet_len; i--; e_iter++) {
BMIter iter;
BMVert *v;
BM_ITER_ELEM (v, &iter, *e_iter, BM_VERTS_OF_EDGE) {
if (!ELEM(v, verts[0], verts[1])) {
float dot = dot_v3v3(v->co, no);
if (dot < min) {
min = dot;
}
if (dot > max) {
max = dot;
}
}
}
verts[0] = (*e_iter)->v1;
verts[1] = (*e_iter)->v2;
}
float average = max - min;
if (average < data->average) {
data->average = average;
data->r_best_face = f;
}
return false;
}
/* find the best splittable face between the two vertices. */
static bool edbm_vert_pair_share_splittable_face_cb(BMFace *f,
BMLoop *l_a,
BMLoop *l_b,
void *userdata)
{
float(*data)[3] = userdata;
float *v_a_co = data[0];
@ -225,32 +272,71 @@ static bool edbm_automerge_and_split_check_best_face_cb(BMFace *UNUSED(f),
}
}
}
return false;
}
static bool edbm_automerge_check_and_split_faces(BMesh *bm, BMVert *v_src, BMVert *v_dst)
static void edbm_automerge_weld_linked_wire_edges_into_linked_faces(BMesh *bm,
BMVert *v,
BMEdge **r_edgenet[],
int *r_edgenet_max_len)
{
BMEdge **edgenet = *r_edgenet;
int edgenet_max_len = *r_edgenet_max_len;
BMIter iter;
BMEdge *e_iter;
BM_ITER_ELEM (e_iter, &iter, v_src, BM_EDGES_OF_VERT) {
BMVert *vert_other = BM_edge_other_vert(e_iter, v_src);
if (vert_other != v_dst) {
float data[2][3];
copy_v3_v3(data[0], vert_other->co);
sub_v3_v3v3(data[1], v_dst->co, data[0]);
BMLoop *l_a, *l_b;
BMFace *f = BM_vert_pair_shared_face_cb(
vert_other, v_dst, false, edbm_automerge_and_split_check_best_face_cb, data, &l_a, &l_b);
if (f) {
BM_face_split(bm, f, l_a, l_b, NULL, NULL, true);
return true;
BMEdge *e;
BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) {
int edgenet_len = 0;
BMVert *v_other = v;
while (BM_edge_is_wire(e)) {
if (edgenet_max_len == edgenet_len) {
edgenet_max_len = (edgenet_max_len + 1) * 2;
edgenet = MEM_reallocN(edgenet, (edgenet_max_len) * sizeof(*edgenet));
}
edgenet[edgenet_len++] = e;
v_other = BM_edge_other_vert(e, v_other);
BMEdge *e_next = BM_DISK_EDGE_NEXT(e, v_other);
if (e_next == e) {
/* Vert is wire_endpoint */
edgenet_len = 0;
break;
}
e = e_next;
}
BMLoop *dummy;
BMFace *best_face;
if (edgenet_len == 0) {
/* Nothing to do. */
continue;
}
if (edgenet_len == 1) {
float data[2][3];
copy_v3_v3(data[0], v_other->co);
sub_v3_v3v3(data[1], v->co, data[0]);
best_face = BM_vert_pair_shared_face_cb(
v_other, v, true, edbm_vert_pair_share_splittable_face_cb, &data, &dummy, &dummy);
}
else {
struct EDBMSplitBestFaceData data = {
.edgenet = edgenet,
.edgenet_len = edgenet_len,
.average = FLT_MAX,
.r_best_face = NULL,
};
BM_vert_pair_shared_face_cb(
v_other, v, true, edbm_vert_pair_share_best_splittable_face_cb, &data, &dummy, &dummy);
best_face = data.r_best_face;
}
if (best_face) {
BM_face_split_edgenet(bm, best_face, edgenet, edgenet_len, NULL, NULL);
}
}
return false;
*r_edgenet = edgenet;
*r_edgenet_max_len = edgenet_max_len;
}
static void ebbm_automerge_and_split_find_duplicate_cb(void *userdata,
@ -291,8 +377,12 @@ static int edbm_automerge_and_split_sort_cmp_by_keys_cb(const void *index1_v,
}
}
void EDBM_automerge_and_split(
Scene *scene, Object *obedit, bool split_edges, bool update, const char hflag)
void EDBM_automerge_and_split(Scene *scene,
Object *obedit,
bool split_edges,
bool split_faces,
bool update,
const char hflag)
{
bool ok = false;
@ -342,8 +432,6 @@ void EDBM_automerge_and_split(
BLI_assert(BM_elem_flag_test(v, BM_ELEM_TAG));
BM_elem_flag_disable(v, BM_ELEM_TAG);
edbm_automerge_check_and_split_faces(bm, v, v_dst);
ok = true;
verts_len--;
}
@ -369,6 +457,9 @@ void EDBM_automerge_and_split(
}
if (edges_len) {
/* Use `e->head.index` to count intersections. */
bm->elem_index_dirty &= ~BM_EDGE;
/* Create a BVHTree of edges with `dist` as epsilon. */
BVHTree *tree_edges = BLI_bvhtree_new(edges_len, dist, 2, 6);
int i;
@ -380,7 +471,6 @@ void EDBM_automerge_and_split(
BLI_bvhtree_insert(tree_edges, i, co[0], 2);
/* Use `e->head.index` to count intersections. */
e->head.index = 0;
}
}
@ -463,7 +553,7 @@ void EDBM_automerge_and_split(
for (i = 0; i < map_len;
e_map_iter = (void *)&e_map->as_int[i], i += 1 + e_map_iter->cuts_len) {
/* sort by lambda! */
/* sort by lambda. */
BLI_qsort_r(e_map_iter->cuts_index,
e_map_iter->cuts_len,
sizeof(*(e_map->cuts_index)),
@ -480,7 +570,6 @@ void EDBM_automerge_and_split(
BMVert *v_new = BM_edge_split(bm, e, e->v1, NULL, lambda);
edbm_automerge_check_and_split_faces(bm, v, v_new);
BMO_slot_map_elem_insert(&weldop, slot_targetmap, v_new, v);
}
}
@ -495,6 +584,20 @@ void EDBM_automerge_and_split(
BMO_op_exec(bm, &weldop);
BMEdge **edgenet = NULL;
int edgenet_len_max = 0;
if (split_faces) {
GHASH_ITER (gh_iter, ghash_targetmap) {
v = BLI_ghashIterator_getValue(&gh_iter);
BLI_assert(BM_elem_flag_test(v, hflag) || hflag == BM_ELEM_TAG);
edbm_automerge_weld_linked_wire_edges_into_linked_faces(bm, v, &edgenet, &edgenet_len_max);
}
}
if (edgenet) {
MEM_freeN(edgenet);
}
BMO_op_finish(bm, &findop);
BMO_op_finish(bm, &weldop);

View File

@ -7128,7 +7128,7 @@ static void special_aftertrans_update__mesh(bContext *UNUSED(C), TransInfo *t)
if (t->scene->toolsettings->automerge & AUTO_MERGE) {
if (t->scene->toolsettings->automerge & AUTO_MERGE_AND_SPLIT) {
EDBM_automerge_and_split(t->scene, tc->obedit, true, true, hflag);
EDBM_automerge_and_split(t->scene, tc->obedit, true, true, true, hflag);
}
else {
EDBM_automerge(t->scene, tc->obedit, true, hflag);