Fix T42864 (partial): knife-project included uncut backfaces
authorCampbell Barton <ideasman42@gmail.com>
Mon, 15 Dec 2014 13:17:28 +0000 (14:17 +0100)
committerCampbell Barton <ideasman42@gmail.com>
Mon, 15 Dec 2014 14:10:49 +0000 (15:10 +0100)
When knife-project ran with cut-through disabled,
it would still try to select faces behind the cut.

Now check if the faces are obscured.

source/blender/editors/mesh/editmesh_knife.c

index c94e4ca2c956b32dcfa53e1ea48f2f1e8e20ece9..c2aafba924970c2b64ed1920b758854977609190 100644 (file)
@@ -3168,16 +3168,14 @@ void MESH_OT_knife_tool(wmOperatorType *ot)
  * tessellation here seems way overkill,
  * but without this its very hard to know of a point is inside the face
  */
-static void edvm_mesh_knife_face_point(BMFace *f, float r_cent[3])
+static void edbm_mesh_knife_face_point(BMFace *f, float r_cent[3])
 {
        const int tottri = f->len - 2;
        BMLoop **loops = BLI_array_alloca(loops, f->len);
        unsigned int  (*index)[3] = BLI_array_alloca(index, tottri);
        int j;
-
-       const float *best_co[3] = {NULL};
-       float best_area  = -1.0f;
-       bool ok = false;
+       int j_best = 0;  /* use as fallback when unset */
+       float area_best  = -1.0f;
 
        BM_face_calc_tessellation(f, loops, index);
 
@@ -3190,49 +3188,34 @@ static void edvm_mesh_knife_face_point(BMFace *f, float r_cent[3])
                float cross[3];
                cross_v3_v3v3(cross, p2, p3);
                area = fabsf(dot_v3v3(p1, cross));
-               if (area > best_area) {
-                       best_co[0] = p1;
-                       best_co[1] = p2;
-                       best_co[2] = p3;
-                       best_area = area;
-                       ok = true;
+               if (area > area_best) {
+                       j_best = j;
+                       area_best = area;
                }
        }
 
-       if (ok) {
-               mid_v3_v3v3v3(r_cent, best_co[0], best_co[1], best_co[2]);
-       }
-       else {
-               mid_v3_v3v3v3(r_cent, loops[0]->v->co, loops[1]->v->co, loops[2]->v->co);
-       }
+       mid_v3_v3v3v3(
+               r_cent,
+               loops[index[j_best][0]]->v->co,
+               loops[index[j_best][1]]->v->co,
+               loops[index[j_best][2]]->v->co);
 }
 
-static bool edbm_mesh_knife_face_isect(ARegion *ar, LinkNode *polys, BMFace *f, float projmat[4][4])
+static bool edbm_mesh_knife_point_isect(LinkNode *polys, const float cent_ss[2])
 {
-       float cent_ss[2];
-       float cent[3];
-
-       edvm_mesh_knife_face_point(f, cent);
-
-       ED_view3d_project_float_v2_m4(ar, cent, cent_ss, projmat);
-
-       /* check */
-       {
-               LinkNode *p = polys;
-               int isect = 0;
-
-               while (p) {
-                       const float (*mval_fl)[2] = p->link;
-                       const int mval_tot = MEM_allocN_len(mval_fl) / sizeof(*mval_fl);
-                       isect += (int)isect_point_poly_v2(cent_ss, mval_fl, mval_tot - 1, false);
-                       p = p->next;
-               }
+       LinkNode *p = polys;
+       int isect = 0;
 
-               if (isect % 2) {
-                       return true;
-               }
+       while (p) {
+               const float (*mval_fl)[2] = p->link;
+               const int mval_tot = MEM_allocN_len(mval_fl) / sizeof(*mval_fl);
+               isect += (int)isect_point_poly_v2(cent_ss, mval_fl, mval_tot - 1, false);
+               p = p->next;
        }
 
+       if (isect % 2) {
+               return true;
+       }
        return false;
 }
 
@@ -3242,6 +3225,7 @@ static bool edbm_mesh_knife_face_isect(ARegion *ar, LinkNode *polys, BMFace *f,
 void EDBM_mesh_knife(bContext *C, LinkNode *polys, bool use_tag, bool cut_through)
 {
        KnifeTool_OpData *kcd;
+       bglMats mats;
 
        view3d_operator_needs_opengl(C);
 
@@ -3260,6 +3244,10 @@ void EDBM_mesh_knife(bContext *C, LinkNode *polys, bool use_tag, bool cut_throug
                if (use_tag) {
                        BM_mesh_elem_hflag_enable_all(kcd->em->bm, BM_EDGE, BM_ELEM_TAG, false);
                }
+
+               if (kcd->cut_through == false) {
+                       bgl_get_mats(&mats);
+               }
        }
 
        /* execute */
@@ -3324,7 +3312,10 @@ void EDBM_mesh_knife(bContext *C, LinkNode *polys, bool use_tag, bool cut_throug
                                        BMFace *f;
                                        BMIter fiter;
                                        BM_ITER_ELEM (f, &fiter, e, BM_FACES_OF_EDGE) {
-                                               if (edbm_mesh_knife_face_isect(kcd->ar, polys, f, projmat)) {
+                                               float cent[3], cent_ss[2];
+                                               edbm_mesh_knife_face_point(f, cent);
+                                               knife_project_v2(kcd, cent, cent_ss);
+                                               if (edbm_mesh_knife_point_isect(polys, cent_ss)) {
                                                        BM_elem_flag_enable(f, BM_ELEM_TAG);
                                                }
                                        }
@@ -3357,7 +3348,12 @@ void EDBM_mesh_knife(bContext *C, LinkNode *polys, bool use_tag, bool cut_throug
                                                } while ((l_iter = l_iter->next) != l_first && (found == false));
 
                                                if (found) {
-                                                       if (edbm_mesh_knife_face_isect(kcd->ar, polys, f, projmat)) {
+                                                       float cent[3], cent_ss[2];
+                                                       edbm_mesh_knife_face_point(f, cent);
+                                                       knife_project_v2(kcd, cent, cent_ss);
+                                                       if ((kcd->cut_through || point_is_visible(kcd, cent, cent_ss, &mats)) &&
+                                                           edbm_mesh_knife_point_isect(polys, cent_ss))
+                                                       {
                                                                BM_elem_flag_enable(f, BM_ELEM_TAG);
                                                                keep_search = true;
                                                        }