Fix to knife: would sometimes miss cuts on non-planar faces.
authorHoward Trickey <howard.trickey@gmail.com>
Mon, 6 Aug 2012 13:37:25 +0000 (13:37 +0000)
committerHoward Trickey <howard.trickey@gmail.com>
Mon, 6 Aug 2012 13:37:25 +0000 (13:37 +0000)
Also, there was a needless loop through all three loops of
a tesselation triangle, which all share the same original face.
Also, made an early out for case where an edge cut had already
been discovered on a Knife edge.

source/blender/editors/mesh/editmesh_knife.c

index 8a3cf87e96a19e89c23434b93e772743b438efba..4d636e64430257d12cd73dcf3bccd059cb3edf51 100644 (file)
@@ -1092,9 +1092,9 @@ static BMEdgeHit *knife_edge_tri_isect(KnifeTool_OpData *kcd, BMBVHTree *bmtree,
        BLI_array_declare(edges);
        BVHTreeOverlap *results, *result;
        BMLoop **ls;
-       float cos[9], uv[3], lambda;
+       float cos[9], lambda;
        unsigned int tot = 0;
-       int i, j;
+       int i;
 
        /* for comparing distances, error of intersection depends on triangle scale.
         * need to scale down before squaring for accurate comparison */
@@ -1112,105 +1112,107 @@ static BMEdgeHit *knife_edge_tri_isect(KnifeTool_OpData *kcd, BMBVHTree *bmtree,
 
        for (i = 0; i < tot; i++, result++) {
                float p[3];
+               BMLoop *l1;
+               BMFace *hitf;
+               ListBase *lst;
+               Ref *ref;
 
                ls = (BMLoop **)kcd->em->looptris[result->indexA];
 
-               for (j = 0; j < 3; j++) {
-                       BMLoop *l1 = ls[j];
-                       BMFace *hitf;
-                       ListBase *lst = knife_get_face_kedges(kcd, l1->f);
-                       Ref *ref;
+               l1 = ls[0];
+               lst = knife_get_face_kedges(kcd, l1->f);
 
-                       for (ref = lst->first; ref; ref = ref->next) {
-                               KnifeEdge *kfe = ref->ref;
+               for (ref = lst->first; ref; ref = ref->next) {
+                       KnifeEdge *kfe = ref->ref;
 
-                               //if (kfe == kcd->cur.edge || kfe == kcd->prev.edge)
-                               //      continue;
+                       if (BLI_smallhash_haskey(ehash, (intptr_t)kfe)) {
+                               continue;  // We already found a hit on this knife edge
+                       }
 
-                               if (isect_line_tri_v3(kfe->v1->cageco, kfe->v2->cageco, v1, v2, v3, &lambda, uv)) {
-                                       float no[3], view[3], sp[3];
+                       if (isect_line_tri_v3(kfe->v1->cageco, kfe->v2->cageco, v1, v2, v3, &lambda, NULL)) {
+                               float no[3], view[3], sp[3];
 
-                                       interp_v3_v3v3(p, kfe->v1->cageco, kfe->v2->cageco, lambda);
+                               interp_v3_v3v3(p, kfe->v1->cageco, kfe->v2->cageco, lambda);
 
-                                       if (kcd->cur.vert && len_squared_v3v3(kcd->cur.vert->cageco, p) < depsilon_squared)
-                                               continue;
-                                       if (kcd->prev.vert && len_squared_v3v3(kcd->prev.vert->cageco, p) < depsilon_squared)
-                                               continue;
-                                       if (len_squared_v3v3(kcd->prev.cage, p) < depsilon_squared ||
-                                           len_squared_v3v3(kcd->cur.cage, p) < depsilon_squared)
-                                       {
-                                               continue;
+                               if (kcd->cur.vert && len_squared_v3v3(kcd->cur.vert->cageco, p) < depsilon_squared)
+                                       continue;
+                               if (kcd->prev.vert && len_squared_v3v3(kcd->prev.vert->cageco, p) < depsilon_squared)
+                                       continue;
+                               if (len_squared_v3v3(kcd->prev.cage, p) < depsilon_squared ||
+                                          len_squared_v3v3(kcd->cur.cage, p) < depsilon_squared)
+                                       continue;
+
+                               knife_project_v3(kcd, p, sp);
+                               view3d_unproject(mats, view, sp[0], sp[1], 0.0f);
+                               mul_m4_v3(kcd->ob->imat, view);
+
+                               if (kcd->cut_through) {
+                                       hitf = FALSE;
+                               } else {
+                                       /* check if this point is visible in the viewport */
+                                       float p1[3], lambda1;
+
+                                       /* if face isn't planer, p may be behind the current tesselated tri,
+                                          so move it onto that and then a little towards eye */
+                                       if (isect_line_tri_v3(p, view, ls[0]->v->co, ls[1]->v->co, ls[2]->v->co, &lambda1, NULL)) {
+                                               interp_v3_v3v3(p1, p, view, lambda1);
+                                       } else {
+                                               copy_v3_v3(p1, p);
                                        }
+                                       sub_v3_v3(view, p1);
+                                       normalize_v3(view);
 
-                                       knife_project_v3(kcd, p, sp);
-                                       view3d_unproject(mats, view, sp[0], sp[1], 0.0f);
-                                       mul_m4_v3(kcd->ob->imat, view);
+                                       copy_v3_v3(no, view);
+                                       mul_v3_fl(no, 0.003);
 
-                                       if (kcd->cut_through) {
-                                               hitf = FALSE;
-                                       }
-                                       else {
-                                               /* check if this point is visible in the viewport */
-                                               sub_v3_v3(view, p);
-                                               normalize_v3(view);
+                                       /* go towards view a bit */
+                                       add_v3_v3(p1, no);
+                                               
+                                       /* ray cast */
+                                       hitf = BMBVH_RayCast(bmtree, p1, no, NULL, NULL);
+                               }
+
+                               /* ok, if visible add the new point */
+                               if (!hitf && !BLI_smallhash_haskey(ehash, (intptr_t)kfe)) {
+                                       BMEdgeHit hit;
+       
+                                       if (len_squared_v3v3(p, kcd->cur.co) < depsilon_squared ||
+                                           len_squared_v3v3(p, kcd->prev.co) < depsilon_squared)
+                                               continue;
 
-                                               copy_v3_v3(no, view);
-                                               mul_v3_fl(no, 0.003);
+                                       hit.kfe = kfe;
+                                       hit.v = NULL;
 
-                                               /* go towards view a bit */
-                                               add_v3_v3(p, no);
+                                       knife_find_basef(kfe);
+                                       hit.f = kfe->basef;
+                                       hit.perc = len_v3v3(p, kfe->v1->cageco) / len_v3v3(kfe->v1->cageco, kfe->v2->cageco);
+                                       copy_v3_v3(hit.cagehit, p);
 
-                                               /* ray cast */
-                                               hitf = BMBVH_RayCast(bmtree, p, no, NULL, NULL);
-                                       }
+                                       interp_v3_v3v3(p, kfe->v1->co, kfe->v2->co, hit.perc);
+                                       copy_v3_v3(hit.realhit, p);
 
-                                       /* ok, if visible add the new point */
-                                       if (!hitf && !BLI_smallhash_haskey(ehash, (intptr_t)kfe)) {
-                                               BMEdgeHit hit;
-                                               
-                                               if (len_squared_v3v3(p, kcd->cur.co) < depsilon_squared ||
-                                                   len_squared_v3v3(p, kcd->prev.co) < depsilon_squared)
-                                               {
-                                                       continue;
-                                               }
+                                       /* BMESH_TODO: should also snap to vertices */
+                                       if (kcd->snap_midpoints) {
+                                               float perc = hit.perc;
 
-                                               hit.kfe = kfe;
-                                               hit.v = NULL;
-
-                                               knife_find_basef(kfe);
-                                               hit.f = kfe->basef;
-                                               hit.perc = len_v3v3(p, kfe->v1->cageco) / len_v3v3(kfe->v1->cageco, kfe->v2->cageco);
-                                               copy_v3_v3(hit.cagehit, p);
-
-                                               interp_v3_v3v3(p, kfe->v1->co, kfe->v2->co, hit.perc);
-                                               copy_v3_v3(hit.realhit, p);
-
-                                               /* BMESH_TODO: should also snap to vertices */
-                                               if (kcd->snap_midpoints) {
-                                                       float perc = hit.perc;
-
-                                                       /* select the closest from the edge endpoints or the midpoint */
-                                                       if (perc < 0.25f) {
-                                                               perc = 0.0f;
-                                                       }
-                                                       else if (perc < 0.75f) {
-                                                               perc = 0.5f;
-                                                       }
-                                                       else {
-                                                               perc = 1.0f;
-                                                       }
-
-                                                       interp_v3_v3v3(hit.hit, kfe->v1->co, kfe->v2->co, perc);
-                                                       interp_v3_v3v3(hit.cagehit, kfe->v1->cageco, kfe->v2->cageco, perc);
-                                               }
-                                               else {
-                                                       copy_v3_v3(hit.hit, p);
+                                               /* select the closest from the edge endpoints or the midpoint */
+                                               if (perc < 0.25f) {
+                                                       perc = 0.0f;
+                                               } else if (perc < 0.75f) {
+                                                       perc = 0.5f;
+                                               } else {
+                                                       perc = 1.0f;
                                                }
-                                               knife_project_v3(kcd, hit.cagehit, hit.schit);
 
-                                               BLI_array_append(edges, hit);
-                                               BLI_smallhash_insert(ehash, (intptr_t)kfe, NULL);
+                                               interp_v3_v3v3(hit.hit, kfe->v1->co, kfe->v2->co, perc);
+                                               interp_v3_v3v3(hit.cagehit, kfe->v1->cageco, kfe->v2->cageco, perc);
+                                       } else {
+                                               copy_v3_v3(hit.hit, p);
                                        }
+                                       knife_project_v3(kcd, hit.cagehit, hit.schit);
+
+                                       BLI_array_append(edges, hit);
+                                       BLI_smallhash_insert(ehash, (intptr_t)kfe, NULL);
                                }
                        }
                }