[Bf-blender-cvs] [e57b14feae9] master: Edit Mesh AutoMerge: Improve `Split Edges & Faces` option

mano-wii noreply at git.blender.org
Tue Aug 27 06:44:16 CEST 2019


Commit: e57b14feae9b4c206de7d33f53342210c01c8278
Author: mano-wii
Date:   Tue Aug 27 01:41:05 2019 -0300
Branches: master
https://developer.blender.org/rBe57b14feae9b4c206de7d33f53342210c01c8278

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

===================================================================

M	source/blender/editors/include/ED_mesh.h
M	source/blender/editors/mesh/editmesh_select.c
M	source/blender/editors/transform/transform_conversions.c

===================================================================

diff --git a/source/blender/editors/include/ED_mesh.h b/source/blender/editors/include/ED_mesh.h
index 30d4aa10c1b..234f36a587b 100644
--- a/source/blender/editors/include/ED_mesh.h
+++ b/source/blender/editors/include/ED_mesh.h
@@ -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,
diff --git a/source/blender/editors/mesh/editmesh_select.c b/source/blender/editors/mesh/editmesh_select.c
index e60934734bc..2273c3fffcf 100644
--- a/source/blender/editors/mesh/editmesh_select.c
+++ b/source/blender/editors/mesh/editmesh_select.c
@@ -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) {
+  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], vert_other->co);
-      sub_v3_v3v3(data[1], v_dst->co, data[0]);
+      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);
 
-      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);
+      best_face = data.r_best_face;
+    }
 
-      if (f) {
-        BM_face_split(bm, f, l_a, l_b, NULL, NULL, true);
-        return true;
-      }
+    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);
 
diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c
index 845ff43bed5..2e328457faf 100644
--- a/source/blender/editors/transform/transform_conversions.c
+++ b/source/blender/editors/transform/transform_conversions.c
@@ -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);



More information about the Bf-blender-cvs mailing list