Fix T41164: Knife creates duplicate verts
[blender-staging.git] / source / blender / editors / mesh / editmesh_knife.c
index eb8ebefa6c9347f3d3d1e0485a82de975493deeb..7421acac9b592f6f1cd6e4e8bffb3b874c904ea8 100644 (file)
@@ -77,7 +77,8 @@
 
 #define KNIFE_FLT_EPS          0.00001f
 #define KNIFE_FLT_EPS_SQUARED  (KNIFE_FLT_EPS * KNIFE_FLT_EPS)
-#define KNIFE_FLT_EPSBIG       0.001f
+#define KNIFE_FLT_EPSBIG       0.0005f
+#define KNIFE_FLT_EPS_PX       0.2f
 
 typedef struct KnifeColors {
        unsigned char line[3];
@@ -208,6 +209,9 @@ typedef struct KnifeTool_OpData {
        bool ignore_edge_snapping;
        bool ignore_vert_snapping;
 
+       /* use to check if we're currently dragging an angle snapped line */
+       bool is_angle_snapping;
+
        enum {
                ANGLE_FREE,
                ANGLE_0,
@@ -228,7 +232,7 @@ static bool knife_verts_edge_in_face(KnifeVert *v1, KnifeVert *v2, BMFace *f);
 
 static void knife_update_header(bContext *C, KnifeTool_OpData *kcd)
 {
-       #define HEADER_LENGTH 256
+#define HEADER_LENGTH 256
        char header[HEADER_LENGTH];
 
        BLI_snprintf(header, HEADER_LENGTH, IFACE_("LMB: define cut lines, Return/Spacebar: confirm, Esc or RMB: cancel, "
@@ -238,8 +242,8 @@ static void knife_update_header(bContext *C, KnifeTool_OpData *kcd)
                     WM_bool_as_string(kcd->ignore_edge_snapping),
                     WM_bool_as_string(kcd->angle_snapping),
                     WM_bool_as_string(kcd->cut_through));
-
        ED_area_headerprint(CTX_wm_area(C), header);
+#undef HEADER_LENGTH
 }
 
 static void knife_project_v2(const KnifeTool_OpData *kcd, const float co[3], float sco[2])
@@ -262,7 +266,7 @@ static ListBase *knife_empty_list(KnifeTool_OpData *kcd)
        ListBase *lst;
 
        lst = BLI_memarena_alloc(kcd->arena, sizeof(ListBase));
-       lst->first = lst->last = NULL;
+       BLI_listbase_clear(lst);
        return lst;
 }
 
@@ -653,7 +657,7 @@ static void knife_add_single_cut(KnifeTool_OpData *kcd, KnifeLineHit *lh1, Knife
        }
 
        /* Check if edge actually lies within face (might not, if this face is concave) */
-       if (lh1->v && lh2->v) {
+       if ((lh1->v && !lh1->kfe) && (lh2->v && !lh2->kfe)) {
                if (!knife_verts_edge_in_face(lh1->v, lh2->v, f)) {
                        return;
                }
@@ -1076,7 +1080,7 @@ static void knifetool_draw(const bContext *C, ARegion *UNUSED(ar), void *arg)
  * In such a case we should have gotten hits on edges or verts of the face. */
 static bool knife_ray_intersect_face(KnifeTool_OpData *kcd,
                                      const float s[2],
-                                     const float v1[2], const float v2[2],
+                                     const float v1[3], const float v2[3],
                                      BMFace *f,
                                      const float face_tol,
                                      float intersectp[3])
@@ -1147,7 +1151,7 @@ static void calc_ortho_extent(KnifeTool_OpData *kcd)
 
        BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
                for (i = 0; i < 3; i++)
-                       max_xyz = max_ff(max_xyz, fabs(v->co[i]));
+                       max_xyz = max_ff(max_xyz, fabsf(v->co[i]));
        }
        kcd->ortho_extent = max_xyz;
 }
@@ -1156,36 +1160,52 @@ static void calc_ortho_extent(KnifeTool_OpData *kcd)
  * s in screen projection of p. */
 static bool point_is_visible(KnifeTool_OpData *kcd, const float p[3], const float s[2], bglMats *mats)
 {
-       float p1[3], no[3], view[3];
        BMFace *f_hit;
 
+       /* If box clipping on, make sure p is not clipped */
+       if (kcd->vc.rv3d->rflag & RV3D_CLIPPING &&
+           ED_view3d_clipping_test(kcd->vc.rv3d, p, true))
+       {
+               return false;
+       }
+
        /* If not cutting through, make sure no face is in front of p */
        if (!kcd->cut_through) {
+               float dist;
+               float view[3], p_ofs[3];
+
                /* TODO: I think there's a simpler way to get the required raycast ray */
                ED_view3d_unproject(mats, view, s[0], s[1], 0.0f);
+
                mul_m4_v3(kcd->ob->imat, view);
 
-               /* make p1 a little towards view, so ray doesn't hit p's face. */
-               copy_v3_v3(p1, p);
-               sub_v3_v3(view, p1);
-               normalize_v3(view);
-               copy_v3_v3(no, view);
-               mul_v3_fl(no, 3.0f * KNIFE_FLT_EPSBIG);
-               add_v3_v3(p1, no);
+               /* make p_ofs a little towards view, so ray doesn't hit p's face. */
+               sub_v3_v3(view, p);
+               dist = normalize_v3(view);
+               madd_v3_v3v3fl(p_ofs, p, view, KNIFE_FLT_EPSBIG * 3.0f);
+
+               /* avoid projecting behind the viewpoint */
+               if (kcd->is_ortho && (kcd->vc.rv3d->persp != RV3D_CAMOB)) {
+                       dist = kcd->vc.v3d->far * 2.0f;
+               }
+
+               if (kcd->vc.rv3d->rflag & RV3D_CLIPPING) {
+                       float view_clip[2][3];
+                       /* note: view_clip[0] should never get clipped */
+                       copy_v3_v3(view_clip[0], p_ofs);
+                       madd_v3_v3v3fl(view_clip[1], p_ofs, view, dist);
+
+                       if (clip_segment_v3_plane_n(view_clip[0], view_clip[1], kcd->vc.rv3d->clip_local, 6)) {
+                               dist = len_v3v3(p_ofs, view_clip[1]);
+                       }
+               }
 
                /* see if there's a face hit between p1 and the view */
-               f_hit = BKE_bmbvh_ray_cast(kcd->bmbvh, p1, no, KNIFE_FLT_EPS, NULL, NULL, NULL);
+               f_hit = BKE_bmbvh_ray_cast(kcd->bmbvh, p_ofs, view, KNIFE_FLT_EPS, &dist, NULL, NULL);
                if (f_hit)
                        return false;
        }
 
-       /* If box clipping on, make sure p is not clipped */
-       if (kcd->vc.rv3d->rflag & RV3D_CLIPPING &&
-           ED_view3d_clipping_test(kcd->vc.rv3d, p, true))
-       {
-               return false;
-       }
-
        return true;
 }
 
@@ -1207,7 +1227,7 @@ static void set_linehit_depth(KnifeTool_OpData *kcd, KnifeLineHit *lh)
 
        ED_view3d_win_to_segment(kcd->ar, kcd->vc.v3d, lh->schit, vnear, vfar, true);
        mul_m4_v3(kcd->ob->imat, vnear);
-       if (kcd->is_ortho) {
+       if (kcd->is_ortho && (kcd->vc.rv3d->persp != RV3D_CAMOB)) {
                if (kcd->ortho_extent == 0.0f)
                        calc_ortho_extent(kcd);
                clip_to_ortho_planes(vnear, vfar, kcd->ortho_extent + 10.0f);
@@ -1239,6 +1259,7 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd)
        float p[3], p2[3], r1[3], r2[3];
        float d, d1, d2, lambda;
        float vert_tol, vert_tol_sq, line_tol, face_tol;
+       float eps_scale;
        int isect_kind;
        unsigned int tot;
        int i;
@@ -1283,7 +1304,7 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd)
         * this gives precision error; rather then solving properly
         * (which may involve using doubles everywhere!),
         * limit the distance between these points */
-       if (kcd->is_ortho) {
+       if (kcd->is_ortho && (kcd->vc.rv3d->persp != RV3D_CAMOB)) {
                if (kcd->ortho_extent == 0.0f)
                        calc_ortho_extent(kcd);
                clip_to_ortho_planes(v1, v3, kcd->ortho_extent + 10.0f);
@@ -1293,9 +1314,6 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd)
        /* First use bvh tree to find faces, knife edges, and knife verts that might
         * intersect the cut plane with rays v1-v3 and v2-v4.
         * This deduplicates the candidates before doing more expensive intersection tests. */
-       BLI_smallhash_init(&faces);
-       BLI_smallhash_init(&kfes);
-       BLI_smallhash_init(&kfvs);
 
        tree = BKE_bmbvh_tree_get(kcd->bmbvh);
        planetree = BLI_bvhtree_new(4, FLT_EPSILON * 4, 8, 8);
@@ -1308,13 +1326,14 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd)
 
        results = BLI_bvhtree_overlap(tree, planetree, &tot);
        if (!results) {
-               BLI_smallhash_release(&faces);
-               BLI_smallhash_release(&kfes);
-               BLI_smallhash_release(&kfvs);
                BLI_bvhtree_free(planetree);
                return;
        }
 
+       BLI_smallhash_init(&faces);
+       BLI_smallhash_init(&kfes);
+       BLI_smallhash_init(&kfvs);
+
        for (i = 0, result = results; i < tot; i++, result++) {
                ls = (BMLoop **)kcd->em->looptris[result->indexA];
                f = ls[0]->f;
@@ -1343,8 +1362,16 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd)
 
        /* Now go through the candidates and find intersections */
        /* These tolerances, in screen space, are for intermediate hits, as ends are already snapped to screen */
-       vert_tol = KNIFE_FLT_EPS * 2000.0f;
-       line_tol = KNIFE_FLT_EPS * 2000.0f;
+       {
+               /* Scale the epsilon by the zoom level
+                * to compensate for projection imprecision, see T41164 */
+               float zoom_xy[2] = {kcd->vc.rv3d->winmat[0][0],
+                                   kcd->vc.rv3d->winmat[1][1]};
+               eps_scale = len_v2(zoom_xy);
+       }
+
+       vert_tol = KNIFE_FLT_EPS_PX * eps_scale;
+       line_tol = KNIFE_FLT_EPS_PX * eps_scale;
        vert_tol_sq = vert_tol * vert_tol;
        face_tol = max_ff(vert_tol, line_tol);
        /* Assume these tolerances swamp floating point rounding errors in calculations below */
@@ -1391,12 +1418,18 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd)
                        if (!(d1 <= vert_tol || d2 <= vert_tol || fabsf(d1 - d2) <= vert_tol)) {
                                lambda = d1 / d2;
                                /* Can't just interpolate between ends of kfe because
-                               * that doesn't work with perspective transformation.
-                               * Need to find 3d intersection of ray through sint */
+                                * that doesn't work with perspective transformation.
+                                * Need to find 3d intersection of ray through sint */
                                knife_input_ray_segment(kcd, sint, 1.0f, r1, r2);
                                isect_kind = isect_line_line_v3(kfe->v1->cageco, kfe->v2->cageco, r1, r2, p, p2);
                                if (isect_kind >= 1 && point_is_visible(kcd, p, sint, &mats)) {
                                        memset(&hit, 0, sizeof(hit));
+                                       if (kcd->snap_midpoints) {
+                                               /* choose intermediate point snap too */
+                                               mid_v3_v3v3(p, kfe->v1->cageco, kfe->v2->cageco);
+                                               mid_v2_v2v2(sint, se1, se2);
+                                               lambda = 0.5f;
+                                       }
                                        hit.kfe = kfe;
                                        copy_v3_v3(hit.hit, p);
                                        copy_v3_v3(hit.cagehit, p);
@@ -1597,6 +1630,7 @@ static KnifeEdge *knife_find_closest_edge(KnifeTool_OpData *kcd, float p[3], flo
        if (f) {
                const float maxdist_sq = maxdist * maxdist;
                KnifeEdge *cure = NULL;
+               float cur_cagep[3];
                ListBase *lst;
                Ref *ref;
                float dis_sq, curdis_sq = FLT_MAX;
@@ -1607,29 +1641,56 @@ static KnifeEdge *knife_find_closest_edge(KnifeTool_OpData *kcd, float p[3], flo
                lst = knife_get_face_kedges(kcd, f);
                for (ref = lst->first; ref; ref = ref->next) {
                        KnifeEdge *kfe = ref->ref;
+                       float test_cagep[3];
+                       float lambda;
 
                        /* project edge vertices into screen space */
                        knife_project_v2(kcd, kfe->v1->cageco, kfe->v1->sco);
                        knife_project_v2(kcd, kfe->v2->cageco, kfe->v2->sco);
 
-                       dis_sq = dist_squared_to_line_segment_v2(sco, kfe->v1->sco, kfe->v2->sco);
-                       if (dis_sq < curdis_sq && dis_sq < maxdist_sq) {
-                               if (kcd->vc.rv3d->rflag & RV3D_CLIPPING) {
-                                       float lambda = line_point_factor_v2(sco, kfe->v1->sco, kfe->v2->sco);
-                                       float vec[3];
+                       /* check if we're close enough and calculate 'lambda' */
+                       if (kcd->is_angle_snapping) {
+                       /* if snapping, check we're in bounds */
+                               float sco_snap[2];
+                               isect_line_line_v2_point(kfe->v1->sco, kfe->v2->sco, kcd->prev.mval, kcd->curr.mval, sco_snap);
+                               lambda = line_point_factor_v2(sco_snap, kfe->v1->sco, kfe->v2->sco);
 
-                                       interp_v3_v3v3(vec, kfe->v1->cageco, kfe->v2->cageco, lambda);
+                               /* be strict about angle-snapping within edge */
+                               if ((lambda < 0.0f - KNIFE_FLT_EPSBIG) || (lambda > 1.0f + KNIFE_FLT_EPSBIG)) {
+                                       continue;
+                               }
 
-                                       if (ED_view3d_clipping_test(kcd->vc.rv3d, vec, true) == 0) {
-                                               cure = kfe;
-                                               curdis_sq = dis_sq;
-                                       }
+                               dis_sq = len_squared_v2v2(sco, sco_snap);
+                               if (dis_sq < curdis_sq && dis_sq < maxdist_sq) {
+                                       /* we already have 'lambda' */
                                }
                                else {
-                                       cure = kfe;
-                                       curdis_sq = dis_sq;
+                                       continue;
+                               }
+                       }
+                       else {
+                               dis_sq = dist_squared_to_line_segment_v2(sco, kfe->v1->sco, kfe->v2->sco);
+                               if (dis_sq < curdis_sq && dis_sq < maxdist_sq) {
+                                       lambda = line_point_factor_v2(sco, kfe->v1->sco, kfe->v2->sco);
+                               }
+                               else {
+                                       continue;
+                               }
+                       }
+
+                       /* now we have 'lambda' calculated */
+                       interp_v3_v3v3(test_cagep, kfe->v1->cageco, kfe->v2->cageco, lambda);
+
+                       if (kcd->vc.rv3d->rflag & RV3D_CLIPPING) {
+                               /* check we're in the view */
+                               if (ED_view3d_clipping_test(kcd->vc.rv3d, test_cagep, true)) {
+                                       continue;
                                }
                        }
+
+                       cure = kfe;
+                       curdis_sq = dis_sq;
+                       copy_v3_v3(cur_cagep, test_cagep);
                }
 
                if (fptr)
@@ -1644,11 +1705,9 @@ static KnifeEdge *knife_find_closest_edge(KnifeTool_OpData *kcd, float p[3], flo
                                        mid_v3_v3v3(cagep, cure->v1->cageco, cure->v2->cageco);
                                }
                                else {
-                                       float d;
-
-                                       closest_to_line_segment_v3(cagep, cageco, cure->v1->cageco, cure->v2->cageco);
-                                       d = len_v3v3(cagep, cure->v1->cageco) / len_v3v3(cure->v1->cageco, cure->v2->cageco);
-                                       interp_v3_v3v3(p, cure->v1->co, cure->v2->co, d);
+                                       float lambda = line_point_factor_v3(cur_cagep, cure->v1->cageco, cure->v2->cageco);
+                                       copy_v3_v3(cagep, cur_cagep);
+                                       interp_v3_v3v3(p, cure->v1->co, cure->v2->co, lambda);
                                }
 
                                /* update mouse coordinates to the snapped-to edge's screen coordinates
@@ -1708,6 +1767,13 @@ static KnifeVert *knife_find_closest_vert(KnifeTool_OpData *kcd, float p[3], flo
 
                                knife_project_v2(kcd, kfv->cageco, kfv->sco);
 
+                               /* be strict about angle snapping, the vertex needs to be very close to the angle, or we ignore */
+                               if (kcd->is_angle_snapping) {
+                                       if (dist_squared_to_line_segment_v2(kfv->sco, kcd->prev.mval, kcd->curr.mval) > KNIFE_FLT_EPSBIG) {
+                                               continue;
+                                       }
+                               }
+
                                dis_sq = len_squared_v2v2(kfv->sco, sco);
                                if (dis_sq < curdis_sq && dis_sq < maxdist_sq) {
                                        if (kcd->vc.rv3d->rflag & RV3D_CLIPPING) {
@@ -1755,7 +1821,7 @@ static KnifeVert *knife_find_closest_vert(KnifeTool_OpData *kcd, float p[3], flo
 }
 
 /* update both kcd->curr.mval and kcd->mval to snap to required angle */
-static void knife_snap_angle(KnifeTool_OpData *kcd)
+static bool knife_snap_angle(KnifeTool_OpData *kcd)
 {
        float dx, dy;
        float w, abs_tan;
@@ -1763,7 +1829,7 @@ static void knife_snap_angle(KnifeTool_OpData *kcd)
        dx = kcd->curr.mval[0] - kcd->prev.mval[0];
        dy = kcd->curr.mval[1] - kcd->prev.mval[1];
        if (dx == 0.0f && dy == 0.0f)
-               return;
+               return false;
 
        if (dx == 0.0f) {
                kcd->angle_snapping = ANGLE_90;
@@ -1792,6 +1858,8 @@ static void knife_snap_angle(KnifeTool_OpData *kcd)
        }
 
        copy_v2_v2(kcd->mval, kcd->curr.mval);
+
+       return true;
 }
 
 /* update active knife edge/vert pointers */
@@ -1799,12 +1867,17 @@ static int knife_update_active(KnifeTool_OpData *kcd)
 {
        knife_pos_data_clear(&kcd->curr);
        copy_v2_v2(kcd->curr.mval, kcd->mval);
-       if (kcd->angle_snapping != ANGLE_FREE && kcd->mode == MODE_DRAGGING)
-               knife_snap_angle(kcd);
 
-       /* XXX knife_snap_angle updates the view coordinate mouse values to constrained angles,
-        * which current mouse values are set to current mouse values are then used
-        * for vertex and edge snap detection, without regard to the exact angle constraint */
+       /* view matrix may have changed, reproject */
+       knife_project_v2(kcd, kcd->prev.co, kcd->prev.mval);
+
+       if (kcd->angle_snapping != ANGLE_FREE && kcd->mode == MODE_DRAGGING) {
+               kcd->is_angle_snapping = knife_snap_angle(kcd);
+       }
+       else {
+               kcd->is_angle_snapping = false;
+       }
+
        kcd->curr.vert = knife_find_closest_vert(kcd, kcd->curr.co, kcd->curr.cage, &kcd->curr.bmface, &kcd->curr.is_space);
 
        if (!kcd->curr.vert) {
@@ -1844,7 +1917,7 @@ static void sort_by_frac_along(ListBase *lst, BMEdge *e)
 
        for (cur = ((Ref *)lst->first)->next; cur; cur = next) {
                KnifeVert *vcur = cur->ref;
-               const float vcur_fac = len_squared_v3v3(v1co, vcur->co);
+               const float vcur_fac_sq = len_squared_v3v3(v1co, vcur->co);
 
                next = cur->next;
                prev = cur->prev;
@@ -1853,7 +1926,7 @@ static void sort_by_frac_along(ListBase *lst, BMEdge *e)
 
                while (prev) {
                        KnifeVert *vprev = prev->ref;
-                       if (len_squared_v3v3(v1co, vprev->co) <= vcur_fac)
+                       if (len_squared_v3v3(v1co, vprev->co) <= vcur_fac_sq)
                                break;
                        prev = prev->prev;
                }
@@ -2059,7 +2132,7 @@ static bool find_hole_chains(KnifeTool_OpData *kcd, ListBase *hole, BMFace *f, L
        BMIter iter;
        int nh, nf, i, j, k, m, ax, ay, sep = 0 /* Quite warnings */, bestsep;
        int besti[2], bestj[2];
-       float d, bestd;
+       float dist_sq, dist_best_sq;
 
        nh = BLI_countlist(hole);
        nf = f->len;
@@ -2112,7 +2185,7 @@ static bool find_hole_chains(KnifeTool_OpData *kcd, ListBase *hole, BMFace *f, L
        for (m = 0; m < 2; m++) {
                besti[m] = -1;
                bestj[m] = -1;
-               bestd = FLT_MAX;
+               dist_best_sq = FLT_MAX;
                bestsep = 0;
                for (i = 0; i < nh; i++) {
                        if (m == 1) {
@@ -2122,15 +2195,15 @@ static bool find_hole_chains(KnifeTool_OpData *kcd, ListBase *hole, BMFace *f, L
                                sep = MIN2(sep, nh - sep);
                                if (sep < bestsep)
                                        continue;
-                               bestd = FLT_MAX;
+                               dist_best_sq = FLT_MAX;
                        }
                        for (j = 0; j < nf; j++) {
                                bool ok;
 
                                if (m == 1 && j == bestj[0])
                                        continue;
-                               d = len_squared_v2v2(hco[i], fco[j]);
-                               if (d > bestd)
+                               dist_sq = len_squared_v2v2(hco[i], fco[j]);
+                               if (dist_sq > dist_best_sq)
                                        continue;
 
                                ok = true;
@@ -2153,7 +2226,7 @@ static bool find_hole_chains(KnifeTool_OpData *kcd, ListBase *hole, BMFace *f, L
                                        bestj[m] = j;
                                        if (m == 1)
                                                bestsep = sep;
-                                       bestd = d;
+                                       dist_best_sq = dist_sq;
                                }
                        }
                }
@@ -2216,7 +2289,7 @@ static bool knife_verts_edge_in_face(KnifeVert *v1, KnifeVert *v2, BMFace *f)
                return true;
        if (l1 && l2) {
                /* Can have case where v1 and v2 are on shared chain between two faces.
-                * BM_face_legal_splits does visibility and self-intersection tests,
+                * BM_face_splits_check_legal does visibility and self-intersection tests,
                 * but it is expensive and maybe a bit buggy, so use a simple
                 * "is the midpoint in the face" test */
                mid_v3_v3v3(mid, v1->co, v2->co);
@@ -2237,6 +2310,7 @@ static void knife_make_chain_cut(KnifeTool_OpData *kcd, BMFace *f, ListBase *cha
        BMesh *bm = kcd->em->bm;
        KnifeEdge *kfe, *kfelast;
        BMVert *v1, *v2;
+       BMLoop *l_v1, *l_v2;
        BMFace *f_new;
        Ref *ref;
        KnifeVert *kfv, *kfvprev;
@@ -2262,28 +2336,36 @@ static void knife_make_chain_cut(KnifeTool_OpData *kcd, BMFace *f, ListBase *cha
        }
        BLI_assert(i == nco);
        l_new = NULL;
-       if (nco == 0) {
-               /* Want to prevent creating two-sided polygons */
-               if (v1 == v2 || BM_edge_exists(v1, v2)) {
-                       f_new = NULL;
+
+       if ((l_v1 = BM_face_vert_share_loop(f, v1)) &&
+           (l_v2 = BM_face_vert_share_loop(f, v2)))
+       {
+               if (nco == 0) {
+                       /* Want to prevent creating two-sided polygons */
+                       if (v1 == v2 || BM_edge_exists(v1, v2)) {
+                               f_new = NULL;
+                       }
+                       else {
+                               f_new = BM_face_split(bm, f, l_v1, l_v2, &l_new, NULL, true);
+                       }
                }
                else {
-                       f_new = BM_face_split(bm, f, v1, v2, &l_new, NULL, true);
-               }
-       }
-       else {
-               f_new = BM_face_split_n(bm, f, v1, v2, cos, nco, &l_new, NULL);
-               if (f_new) {
-                       /* Now go through lnew chain matching up chain kv's and assign real v's to them */
-                       for (l_iter = l_new->next, i = 0; i < nco; l_iter = l_iter->next, i++) {
-                               BLI_assert(equals_v3v3(cos[i], l_iter->v->co));
-                               if (kcd->select_result) {
-                                       BM_edge_select_set(bm, l_iter->e, true);
+                       f_new = BM_face_split_n(bm, f, l_v1, l_v2, cos, nco, &l_new, NULL);
+                       if (f_new) {
+                               /* Now go through lnew chain matching up chain kv's and assign real v's to them */
+                               for (l_iter = l_new->next, i = 0; i < nco; l_iter = l_iter->next, i++) {
+                                       BLI_assert(equals_v3v3(cos[i], l_iter->v->co));
+                                       if (kcd->select_result) {
+                                               BM_edge_select_set(bm, l_iter->e, true);
+                                       }
+                                       kverts[i]->v = l_iter->v;
                                }
-                               kverts[i]->v = l_iter->v;
                        }
                }
        }
+       else {
+               f_new = NULL;
+       }
 
        /* the select chain above doesnt account for the first loop */
        if (kcd->select_result) {
@@ -2607,9 +2689,9 @@ static void knifetool_init(bContext *C, KnifeTool_OpData *kcd,
 
        ED_region_tag_redraw(kcd->ar);
 
-       kcd->refs = BLI_mempool_create(sizeof(Ref), 1, 2048, 0);
-       kcd->kverts = BLI_mempool_create(sizeof(KnifeVert), 1, 512, BLI_MEMPOOL_ALLOW_ITER);
-       kcd->kedges = BLI_mempool_create(sizeof(KnifeEdge), 1, 512, BLI_MEMPOOL_ALLOW_ITER);
+       kcd->refs = BLI_mempool_create(sizeof(Ref), 0, 2048, 0);
+       kcd->kverts = BLI_mempool_create(sizeof(KnifeVert), 0, 512, BLI_MEMPOOL_ALLOW_ITER);
+       kcd->kedges = BLI_mempool_create(sizeof(KnifeEdge), 0, 512, BLI_MEMPOOL_ALLOW_ITER);
 
        kcd->origedgemap = BLI_ghash_ptr_new("knife origedgemap");
        kcd->origvertmap = BLI_ghash_ptr_new("knife origvertmap");
@@ -2850,7 +2932,6 @@ static int knifetool_modal(bContext *C, wmOperator *op, const wmEvent *event)
 
                                ED_region_tag_redraw(kcd->ar);
                                return OPERATOR_PASS_THROUGH;
-                               break;
                }
        }
        else { /* non-modal-mapped events */
@@ -2918,7 +2999,7 @@ static void edvm_mesh_knife_face_point(BMFace *f, float r_cent[3])
        unsigned int  (*index)[3] = BLI_array_alloca(index, tottri);
        int j;
 
-       float const *best_co[3] = {NULL};
+       const float *best_co[3] = {NULL};
        float best_area  = -1.0f;
        bool ok = false;