[Bf-blender-cvs] [ac5f011e9c1] master: Fix T70455: Knife Tool failing to cut edges

Germano Cavalcante noreply at git.blender.org
Mon Jul 20 13:54:38 CEST 2020


Commit: ac5f011e9c1fa7256b028c4b829f56470b1e8217
Author: Germano Cavalcante
Date:   Mon Jul 20 08:52:11 2020 -0300
Branches: master
https://developer.blender.org/rBac5f011e9c1fa7256b028c4b829f56470b1e8217

Fix T70455: Knife Tool failing to cut edges

Analyzing the cuts, the points shown in the viewport (indicating the
previous and current cuts) do not correspond to the final cuts.

Sometimes a point, even snapped to a vert, is a point that cuts an edge and
sometimes a point, even snapped to an edge, is a point that cuts only the face.

This is because the detection of snapping vertices from mouse is different
from the "snap" that detects vertices that are cut.

So small projection inaccuracies can result in detection failures.

The solution for this is simply to confirm the cuts whose vertices
indicate the `prev` ou and `cur` point.

The tolerance distance does not need to be calculated in these cases.

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

M	source/blender/editors/mesh/editmesh_knife.c

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

diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c
index 873bdf2a674..347f6806d13 100644
--- a/source/blender/editors/mesh/editmesh_knife.c
+++ b/source/blender/editors/mesh/editmesh_knife.c
@@ -1564,15 +1564,12 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd)
   void **val_p;
   float s[2], se1[2], se2[2], sint[2];
   float r1[3], r2[3];
-  float d, d1, d2, lambda;
+  float d1, d2, lambda;
   float vert_tol, vert_tol_sq;
   float line_tol, line_tol_sq;
   float face_tol, face_tol_sq;
-  int isect_kind;
   uint tot;
   int i;
-  const bool use_hit_prev = true;
-  const bool use_hit_curr = (kcd->is_drag_hold == false);
 
   if (kcd->linehits) {
     MEM_freeN(kcd->linehits);
@@ -1703,10 +1700,25 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd)
        val_p = BLI_smallhash_iternext_p(&hiter, (uintptr_t *)&v)) {
     KnifeEdge *kfe_hit = NULL;
 
-    knife_project_v2(kcd, v->cageco, s);
-    d = dist_squared_to_line_segment_v2(s, s1, s2);
-    if ((d <= vert_tol_sq) &&
-        (point_is_visible(kcd, v->cageco, s, bm_elem_from_knife_vert(v, &kfe_hit)))) {
+    bool kfv_is_in_cut = false;
+    if (ELEM(v, kcd->prev.vert, kcd->curr.vert)) {
+      /* This KnifeVert was captured by the snap system.
+       * Since the tolerance distance can be different, add this vertex directly.
+       * Otherwise, the cut may fail or a close cut on a connected edge can be performed. */
+      bm_elem_from_knife_vert(v, &kfe_hit);
+      copy_v2_v2(s, (v == kcd->prev.vert) ? kcd->prev.mval : kcd->curr.mval);
+      kfv_is_in_cut = true;
+    }
+    else {
+      knife_project_v2(kcd, v->cageco, s);
+      float d = dist_squared_to_line_segment_v2(s, s1, s2);
+      if ((d <= vert_tol_sq) &&
+          (point_is_visible(kcd, v->cageco, s, bm_elem_from_knife_vert(v, &kfe_hit)))) {
+        kfv_is_in_cut = true;
+      }
+    }
+
+    if (kfv_is_in_cut) {
       memset(&hit, 0, sizeof(hit));
       hit.v = v;
 
@@ -1724,7 +1736,9 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd)
       BLI_array_append(linehits, hit);
     }
     else {
-      /* note that these vertes aren't used */
+      /* This vertex isn't used so remove from `kfvs`.
+       * This is useful to detect KnifeEdges that can be skipped.
+       * And it optimizes smallhash_iternext a little bit. */
       *val_p = NULL;
     }
   }
@@ -1732,30 +1746,38 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd)
   /* now edge hits; don't add if a vertex at end of edge should have hit */
   for (val = BLI_smallhash_iternew(&kfes, &hiter, (uintptr_t *)&kfe); val;
        val = BLI_smallhash_iternext(&hiter, (uintptr_t *)&kfe)) {
-    int kfe_verts_in_cut;
-    /* if we intersect both verts, don't attempt to intersect the edge */
-
-    kfe_verts_in_cut = (BLI_smallhash_lookup(&kfvs, (intptr_t)kfe->v1) != NULL) +
-                       (BLI_smallhash_lookup(&kfvs, (intptr_t)kfe->v2) != NULL);
 
-    if (kfe_verts_in_cut == 2) {
+    /* If we intersect any of the vertices, don't attempt to intersect the edge. */
+    if (BLI_smallhash_lookup(&kfvs, (intptr_t)kfe->v1) ||
+        BLI_smallhash_lookup(&kfvs, (intptr_t)kfe->v2)) {
       continue;
     }
 
     knife_project_v2(kcd, kfe->v1->cageco, se1);
     knife_project_v2(kcd, kfe->v2->cageco, se2);
-    isect_kind = (kfe_verts_in_cut) ? -1 : isect_seg_seg_v2_point(s1, s2, se1, se2, sint);
-    if (isect_kind == -1) {
-      /* isect_seg_seg_v2_simple doesn't do tolerance test around ends of s1-s2 */
-      closest_to_line_segment_v2(sint, s1, se1, se2);
-      if (len_squared_v2v2(sint, s1) <= line_tol_sq) {
-        isect_kind = 1;
-      }
-      else {
-        closest_to_line_segment_v2(sint, s2, se1, se2);
-        if (len_squared_v2v2(sint, s2) <= line_tol_sq) {
+    int isect_kind = 1;
+    if (kfe == kcd->prev.edge) {
+      /* This KnifeEdge was captured by the snap system. */
+      copy_v2_v2(sint, kcd->prev.mval);
+    }
+    else if (kfe == kcd->curr.edge) {
+      /* This KnifeEdge was captured by the snap system. */
+      copy_v2_v2(sint, kcd->curr.mval);
+    }
+    else {
+      isect_kind = isect_seg_seg_v2_point_ex(s1, s2, se1, se2, 0.0f, sint);
+      if (isect_kind == -1) {
+        /* isect_seg_seg_v2_point doesn't do tolerance test around ends of s1-s2 */
+        closest_to_line_segment_v2(sint, s1, se1, se2);
+        if (len_squared_v2v2(sint, s1) <= line_tol_sq) {
           isect_kind = 1;
         }
+        else {
+          closest_to_line_segment_v2(sint, s2, se1, se2);
+          if (len_squared_v2v2(sint, s2) <= line_tol_sq) {
+            isect_kind = 1;
+          }
+        }
       }
     }
     if (isect_kind == 1) {
@@ -1790,32 +1812,38 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd)
       }
     }
   }
+
   /* now face hits; don't add if a vertex or edge in face should have hit */
-  for (val = BLI_smallhash_iternew(&faces, &hiter, (uintptr_t *)&f); val;
-       val = BLI_smallhash_iternext(&hiter, (uintptr_t *)&f)) {
-    float p[3], p_cage[3];
-
-    if (use_hit_prev && knife_ray_intersect_face(kcd, s1, v1, v3, f, face_tol_sq, p, p_cage)) {
-      if (point_is_visible(kcd, p_cage, s1, (BMElem *)f)) {
-        memset(&hit, 0, sizeof(hit));
-        hit.f = f;
-        copy_v3_v3(hit.hit, p);
-        copy_v3_v3(hit.cagehit, p_cage);
-        copy_v2_v2(hit.schit, s1);
-        set_linehit_depth(kcd, &hit);
-        BLI_array_append(linehits, hit);
+  const bool use_hit_prev = (kcd->prev.vert == NULL) && (kcd->prev.edge == NULL);
+  const bool use_hit_curr = (kcd->curr.vert == NULL) && (kcd->curr.edge == NULL) &&
+                            !kcd->is_drag_hold;
+  if (use_hit_prev || use_hit_curr) {
+    for (val = BLI_smallhash_iternew(&faces, &hiter, (uintptr_t *)&f); val;
+         val = BLI_smallhash_iternext(&hiter, (uintptr_t *)&f)) {
+      float p[3], p_cage[3];
+
+      if (use_hit_prev && knife_ray_intersect_face(kcd, s1, v1, v3, f, face_tol_sq, p, p_cage)) {
+        if (point_is_visible(kcd, p_cage, s1, (BMElem *)f)) {
+          memset(&hit, 0, sizeof(hit));
+          hit.f = f;
+          copy_v3_v3(hit.hit, p);
+          copy_v3_v3(hit.cagehit, p_cage);
+          copy_v2_v2(hit.schit, s1);
+          set_linehit_depth(kcd, &hit);
+          BLI_array_append(linehits, hit);
+        }
       }
-    }
 
-    if (use_hit_curr && knife_ray_intersect_face(kcd, s2, v2, v4, f, face_tol_sq, p, p_cage)) {
-      if (point_is_visible(kcd, p_cage, s2, (BMElem *)f)) {
-        memset(&hit, 0, sizeof(hit));
-        hit.f = f;
-        copy_v3_v3(hit.hit, p);
-        copy_v3_v3(hit.cagehit, p_cage);
-        copy_v2_v2(hit.schit, s2);
-        set_linehit_depth(kcd, &hit);
-        BLI_array_append(linehits, hit);
+      if (use_hit_curr && knife_ray_intersect_face(kcd, s2, v2, v4, f, face_tol_sq, p, p_cage)) {
+        if (point_is_visible(kcd, p_cage, s2, (BMElem *)f)) {
+          memset(&hit, 0, sizeof(hit));
+          hit.f = f;
+          copy_v3_v3(hit.hit, p);
+          copy_v3_v3(hit.cagehit, p_cage);
+          copy_v2_v2(hit.schit, s2);
+          set_linehit_depth(kcd, &hit);
+          BLI_array_append(linehits, hit);
+        }
       }
     }
   }



More information about the Bf-blender-cvs mailing list