Knife: use BM_face_split_edgenet for detecting holes
authorCampbell Barton <ideasman42@gmail.com>
Sat, 12 Dec 2015 16:46:36 +0000 (03:46 +1100)
committerCampbell Barton <ideasman42@gmail.com>
Sat, 12 Dec 2015 16:46:36 +0000 (03:46 +1100)
Knife had its own code for detecting holes which worked quite well,
but would prefer to use generic bmesh API call here.

source/blender/editors/mesh/editmesh_knife.c

index 818526ab772163bfc8613f28bd10f2de7e484e41..5b9af2fa75c8b249a9afedc0c8a61eb463070c7c 100644 (file)
@@ -75,6 +75,9 @@
 
 #include "mesh_intern.h"  /* own include */
 
+/* detect isolated holes and fill them */
+#define USE_NET_ISLAND_CONNECT
+
 #define KMAXDIST    10  /* max mouse distance from edge before not detecting it */
 
 /* WARNING: knife float precision is fragile:
@@ -166,6 +169,11 @@ typedef struct KnifeTool_OpData {
 
        MemArena *arena;
 
+#ifdef USE_NET_ISLAND_CONNECT
+       /* cleared each use */
+       MemArena *arena_edgenet;
+#endif
+
        GHash *origvertmap;
        GHash *origedgemap;
        GHash *kedgefacemap;
@@ -2205,330 +2213,6 @@ static int sort_verts_by_dist_cb(void *co_p, const void *cur_a_p, const void *cu
        else                  return  0;
 }
 
-/* The chain so far goes from an instantiated vertex to kfv (some may be reversed).
- * If possible, complete the chain to another instantiated vertex and return 1, else return 0.
- * The visited hash says which KnifeVert's have already been tried, not including kfv. */
-static bool find_chain_search(KnifeTool_OpData *kcd, KnifeVert *kfv, ListBase *fedges, SmallHash *visited,
-                              ListBase *chain)
-{
-       Ref *r;
-       KnifeEdge *kfe;
-       KnifeVert *kfv_other;
-
-       if (kfv->v)
-               return true;
-
-       BLI_smallhash_insert(visited, (uintptr_t)kfv, NULL);
-       /* Try all possible next edges. Could either go through fedges
-        * (all the KnifeEdges for the face being cut) or could go through
-        * kve->edges and restrict to cutting face and uninstantiated edges.
-        * Not clear which is better. Let's do the first. */
-       for (r = fedges->first; r; r = r->next) {
-               kfe = r->ref;
-               kfv_other = NULL;
-               if (kfe->v1 == kfv)
-                       kfv_other = kfe->v2;
-               else if (kfe->v2 == kfv)
-                       kfv_other = kfe->v1;
-               if (kfv_other && !BLI_smallhash_haskey(visited, (uintptr_t)kfv_other)) {
-                       knife_append_list(kcd, chain, kfe);
-                       if (find_chain_search(kcd, kfv_other, fedges, visited, chain))
-                               return true;
-                       BLI_remlink(chain, chain->last);
-               }
-       }
-       return false;
-}
-
-static ListBase *find_chain_from_vertex(KnifeTool_OpData *kcd, KnifeEdge *kfe, BMVert *v, ListBase *fedges)
-{
-       SmallHash visited_, *visited = &visited_;
-       ListBase *ans;
-       bool found;
-
-       ans = knife_empty_list(kcd);
-       knife_append_list(kcd, ans, kfe);
-       found = false;
-       BLI_smallhash_init(visited);
-       if (kfe->v1->v == v) {
-               BLI_smallhash_insert(visited, (uintptr_t)(kfe->v1), NULL);
-               found = find_chain_search(kcd, kfe->v2, fedges, visited, ans);
-       }
-       else {
-               BLI_assert(kfe->v2->v == v);
-               BLI_smallhash_insert(visited, (uintptr_t)(kfe->v2), NULL);
-               found = find_chain_search(kcd, kfe->v1, fedges, visited, ans);
-       }
-
-       BLI_smallhash_release(visited);
-
-       if (found)
-               return ans;
-       else
-               return NULL;
-}
-
-/* Find a chain in fedges from one instantiated vertex to another.
- * Remove the edges in the chain from fedges and return a separate list of the chain. */
-static ListBase *find_chain(KnifeTool_OpData *kcd, ListBase *fedges)
-{
-       Ref *r, *ref;
-       KnifeEdge *kfe;
-       BMVert *v1, *v2;
-       ListBase *ans;
-
-       ans = NULL;
-
-       for (r = fedges->first; r; r = r->next) {
-               kfe = r->ref;
-               v1 = kfe->v1->v;
-               v2 = kfe->v2->v;
-               if (v1 && v2) {
-                       ans = knife_empty_list(kcd);
-                       knife_append_list(kcd, ans, kfe);
-                       break;
-               }
-               if (v1)
-                       ans = find_chain_from_vertex(kcd, kfe, v1, fedges);
-               else if (v2)
-                       ans = find_chain_from_vertex(kcd, kfe, v2, fedges);
-               if (ans)
-                       break;
-       }
-       if (ans) {
-               BLI_assert(!BLI_listbase_is_empty(ans));
-               for (r = ans->first; r; r = r->next) {
-                       ref = find_ref(fedges, r->ref);
-                       BLI_assert(ref != NULL);
-                       BLI_remlink(fedges, ref);
-               }
-       }
-       return ans;
-}
-
-/* The hole so far goes from kfvfirst to kfv (some may be reversed).
- * If possible, complete the hole back to kfvfirst and return 1, else return 0.
- * The visited hash says which KnifeVert's have already been tried, not including kfv or kfvfirst. */
-static bool find_hole_search(KnifeTool_OpData *kcd, KnifeVert *kfvfirst, KnifeVert *kfv, ListBase *fedges,
-                             SmallHash *visited, ListBase *hole)
-{
-       Ref *r;
-       KnifeEdge *kfe, *kfelast;
-       KnifeVert *kfv_other;
-
-       if (kfv == kfvfirst)
-               return true;
-
-       BLI_smallhash_insert(visited, (uintptr_t)kfv, NULL);
-       kfelast = ((Ref *)hole->last)->ref;
-       for (r = fedges->first; r; r = r->next) {
-               kfe = r->ref;
-               if (kfe == kfelast)
-                       continue;
-               if (kfe->v1->v || kfe->v2->v)
-                       continue;
-               kfv_other = NULL;
-               if (kfe->v1 == kfv)
-                       kfv_other = kfe->v2;
-               else if (kfe->v2 == kfv)
-                       kfv_other = kfe->v1;
-               if (kfv_other && !BLI_smallhash_haskey(visited, (uintptr_t)kfv_other)) {
-                       knife_append_list(kcd, hole, kfe);
-                       if (find_hole_search(kcd, kfvfirst, kfv_other, fedges, visited, hole))
-                               return true;
-                       BLI_remlink(hole, hole->last);
-               }
-       }
-       return false;
-}
-
-/* Find a hole (simple cycle with no instantiated vertices).
- * Remove the edges in the cycle from fedges and return a separate list of the cycle */
-static ListBase *find_hole(KnifeTool_OpData *kcd, ListBase *fedges)
-{
-       ListBase *ans;
-       Ref *r, *ref;
-       KnifeEdge *kfe;
-       SmallHash visited_, *visited = &visited_;
-       bool found;
-
-       ans = NULL;
-       found = false;
-
-       for (r = fedges->first; r && !found; r = r->next) {
-               kfe = r->ref;
-               if (kfe->v1->v || kfe->v2->v || kfe->v1 == kfe->v2)
-                       continue;
-
-               BLI_smallhash_init(visited);
-               ans = knife_empty_list(kcd);
-               knife_append_list(kcd, ans, kfe);
-
-               found = find_hole_search(kcd, kfe->v1, kfe->v2, fedges, visited, ans);
-
-               BLI_smallhash_release(visited);
-       }
-
-       if (found) {
-               for (r = ans->first; r; r = r->next) {
-                       kfe = r->ref;
-                       ref = find_ref(fedges, r->ref);
-                       if (ref)
-                               BLI_remlink(fedges, ref);
-               }
-               return ans;
-       }
-       else {
-               return NULL;
-       }
-}
-
-/* Try to find "nice" diagonals - short, and far apart from each other.
- * If found, return true and make a 'main chain' going across f which uses
- * the two diagonals and one part of the hole, and a 'side chain' that
- * completes the hole. */
-static bool find_hole_chains(KnifeTool_OpData *kcd, ListBase *hole, BMFace *f, ListBase **mainchain,
-                             ListBase **sidechain)
-{
-       float (*fco)[2], (*hco)[2];
-       BMVert **fv;
-       KnifeVert **hv;
-       KnifeEdge **he;
-       Ref *r;
-       KnifeVert *kfv, *kfvother;
-       KnifeEdge *kfe;
-       ListBase *chain;
-       BMVert *v;
-       BMIter iter;
-       int nh, nf, i, j, k, m, ax, ay, sep = 0 /* Quite warnings */, bestsep;
-       int besti[2], bestj[2];
-       float dist_sq, dist_best_sq;
-
-       nh = BLI_listbase_count(hole);
-       nf = f->len;
-       if (nh < 2 || nf < 3)
-               return false;
-
-       /* Gather 2d projections of hole and face vertex coordinates.
-        * Use best-axis projection - not completely accurate, maybe revisit */
-       axis_dominant_v3(&ax, &ay, f->no);
-       hco = BLI_memarena_alloc(kcd->arena, nh * sizeof(float[2]));
-       fco = BLI_memarena_alloc(kcd->arena, nf * sizeof(float[2]));
-       hv = BLI_memarena_alloc(kcd->arena, nh * sizeof(KnifeVert *));
-       fv = BLI_memarena_alloc(kcd->arena, nf * sizeof(BMVert *));
-       he = BLI_memarena_alloc(kcd->arena, nh * sizeof(KnifeEdge *));
-
-       i = 0;
-       kfv = NULL;
-       kfvother = NULL;
-       for (r = hole->first; r; r = r->next) {
-               kfe = r->ref;
-               he[i] = kfe;
-               if (kfvother == NULL) {
-                       kfv = kfe->v1;
-               }
-               else {
-                       kfv = kfvother;
-                       BLI_assert(kfv == kfe->v1 || kfv == kfe->v2);
-               }
-               hco[i][0] = kfv->co[ax];
-               hco[i][1] = kfv->co[ay];
-               hv[i] = kfv;
-               kfvother = (kfe->v1 == kfv) ? kfe->v2 : kfe->v1;
-               i++;
-       }
-
-       j = 0;
-       BM_ITER_ELEM (v, &iter, f, BM_VERTS_OF_FACE) {
-               fco[j][0] = v->co[ax];
-               fco[j][1] = v->co[ay];
-               fv[j] = v;
-               j++;
-       }
-
-       /* For first diagonal  (m == 0), want shortest length.
-        * For second diagonal (m == 1), want max separation of index of hole
-        * vertex from the hole vertex used in the first diagonal, and from there
-        * want the one with shortest length not to the same vertex as the first diagonal. */
-       for (m = 0; m < 2; m++) {
-               besti[m] = -1;
-               bestj[m] = -1;
-               dist_best_sq = FLT_MAX;
-               bestsep = 0;
-               for (i = 0; i < nh; i++) {
-                       if (m == 1) {
-                               if (i == besti[0])
-                                       continue;
-                               sep = (i + nh - besti[0]) % nh;
-                               sep = MIN2(sep, nh - sep);
-                               if (sep < bestsep)
-                                       continue;
-                               dist_best_sq = FLT_MAX;
-                       }
-                       for (j = 0; j < nf; j++) {
-                               bool ok;
-
-                               if (m == 1 && j == bestj[0])
-                                       continue;
-                               dist_sq = len_squared_v2v2(hco[i], fco[j]);
-                               if (dist_sq > dist_best_sq)
-                                       continue;
-
-                               ok = true;
-                               for (k = 0; k < nh && ok; k++) {
-                                       if (k == i || (k + 1) % nh == i)
-                                               continue;
-                                       if (isect_seg_seg_v2(hco[i], fco[j], hco[k], hco[(k + 1) % nh]))
-                                               ok = false;
-                               }
-                               if (!ok)
-                                       continue;
-                               for (k = 0; k < nf && ok; k++) {
-                                       if (k == j || (k + 1) % nf == j)
-                                               continue;
-                                       if (isect_seg_seg_v2(hco[i], fco[j], fco[k], fco[(k + 1) % nf]))
-                                               ok = false;
-                               }
-                               if (ok) {
-                                       besti[m] = i;
-                                       bestj[m] = j;
-                                       if (m == 1)
-                                               bestsep = sep;
-                                       dist_best_sq = dist_sq;
-                               }
-                       }
-               }
-       }
-
-       if (besti[0] != -1 && besti[1] != -1) {
-               BLI_assert(besti[0] != besti[1] && bestj[0] != bestj[1]);
-               kfe = new_knife_edge(kcd);
-               kfe->v1 = get_bm_knife_vert(kcd, fv[bestj[0]]);
-               kfe->v2 = hv[besti[0]];
-               chain = knife_empty_list(kcd);
-               knife_append_list(kcd, chain, kfe);
-               for (i = besti[0]; i != besti[1]; i = (i + 1) % nh) {
-                       knife_append_list(kcd, chain, he[i]);
-               }
-               kfe = new_knife_edge(kcd);
-               kfe->v1 = hv[besti[1]];
-               kfe->v2 = get_bm_knife_vert(kcd, fv[bestj[1]]);
-               knife_append_list(kcd, chain, kfe);
-               *mainchain = chain;
-
-               chain = knife_empty_list(kcd);
-               for (i = besti[1]; i != besti[0]; i = (i + 1) % nh) {
-                       knife_append_list(kcd, chain, he[i]);
-               }
-               *sidechain = chain;
-
-               return true;
-       }
-       else {
-               return false;
-       }
-}
-
 static bool knife_verts_edge_in_face(KnifeVert *v1, KnifeVert *v2, BMFace *f)
 {
        bool v1_inside, v2_inside;
@@ -2572,201 +2256,110 @@ static bool knife_verts_edge_in_face(KnifeVert *v1, KnifeVert *v2, BMFace *f)
        return false;
 }
 
-static bool knife_edge_in_face(KnifeEdge *kfe, BMFace *f)
-{
-       return knife_verts_edge_in_face(kfe->v1, kfe->v2, f);
-}
-
-/* Split face f with KnifeEdges on chain.  f remains as one side, the face formed is put in *newface.
- * The new face will be on the left side of the chain as viewed from the normal-out side of f. */
-static void knife_make_chain_cut(KnifeTool_OpData *kcd, BMFace *f, ListBase *chain, BMFace **r_f_new)
+static void knife_make_face_cuts(KnifeTool_OpData *kcd, BMFace *f, ListBase *kfedges)
 {
        BMesh *bm = kcd->em->bm;
-       KnifeEdge *kfe, *kfelast;
-       BMVert *v1, *v2;
-       BMLoop *l_v1, *l_v2;
-       BMFace *f_new;
+       KnifeEdge *kfe;
        Ref *ref;
-       KnifeVert *kfv, *kfvprev;
-       BMLoop *l_new, *l_iter;
+       int edge_array_len = BLI_listbase_count(kfedges);
+       bool ok;
        int i;
-       int nco = BLI_listbase_count(chain) - 1;
-       float (*cos)[3] = BLI_array_alloca(cos, nco);
-       KnifeVert **kverts = BLI_array_alloca(kverts, nco);
-
-       kfe = ((Ref *)chain->first)->ref;
-       v1 = kfe->v1->v ? kfe->v1->v : kfe->v2->v;
-       kfelast = ((Ref *)chain->last)->ref;
-       v2 = kfelast->v2->v ? kfelast->v2->v : kfelast->v1->v;
-       BLI_assert(v1 != NULL && v2 != NULL);
-       kfvprev = kfe->v1->v == v1 ? kfe->v1 : kfe->v2;
-       for (ref = chain->first, i = 0; i < nco && ref != chain->last; ref = ref->next, i++) {
+
+       BMFace **face_arr;
+       int face_arr_len;
+
+       BMEdge **edge_array = BLI_array_alloca(edge_array, edge_array_len);
+
+        /* point to knife edges we've created edges in, edge_array aligned */
+       KnifeEdge **kfe_array = BLI_array_alloca(kfe_array, edge_array_len);
+
+       i = 0;
+       for (ref = kfedges->first; ref; ref = ref->next) {
+               bool is_new_edge = false;
                kfe = ref->ref;
-               BLI_assert(kfvprev == kfe->v1 || kfvprev == kfe->v2);
-               kfv = kfe->v1 == kfvprev ? kfe->v2 : kfe->v1;
-               copy_v3_v3(cos[i], kfv->co);
-               kverts[i] = kfv;
-               kfvprev = kfv;
-       }
-       BLI_assert(i == nco);
-       l_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;
+               if (kfe->e == NULL) {
+                       if (kfe->v1->v && kfe->v2->v) {
+                               kfe->e = BM_edge_exists(kfe->v1->v, kfe->v2->v);
                        }
-                       else {
-                               f_new = BM_face_split(bm, f, l_v1, l_v2, &l_new, NULL, true);
+               }
+
+               if (kfe->e) {
+                       if (BM_edge_in_face(kfe->e, f)) {
+                               /* shouldn't happen, but in this case - just ignore */
+                               continue;
                        }
                }
                else {
-                       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;
+                       if (kfe->v1->v == NULL) {
+                               kfe->v1->v = BM_vert_create(bm, kfe->v1->co, NULL, 0);
+                       }
+                       if (kfe->v2->v == NULL) {
+                               kfe->v2->v = BM_vert_create(bm, kfe->v2->co, NULL, 0);
+                       }
+                       BLI_assert(kfe->e == NULL);
+                       kfe->e = BM_edge_create(bm, kfe->v1->v, kfe->v2->v, NULL, 0);
+                       if (kfe->e) {
+                               if (kcd->select_result || BM_elem_flag_test(f, BM_ELEM_SELECT)) {
+                                       BM_edge_select_set(bm, kfe->e, true);
                                }
+                               is_new_edge = true;
                        }
                }
-       }
-       else {
-               f_new = NULL;
-       }
 
-       /* the select chain above doesnt account for the first loop */
-       if (kcd->select_result) {
-               if (l_new) {
-                       BM_edge_select_set(bm, l_new->e, true);
-               }
-       }
-       else if (f_new) {
-               BM_elem_select_copy(bm, bm, f_new, f);
+               BLI_assert(kfe->e);
+
+               kfe_array[i] = is_new_edge ? kfe : 0;
+               edge_array[i] = kfe->e;
+               i += 1;
        }
 
-       *r_f_new = f_new;
-}
+       if (i) {
+               const int edge_array_len_orig = i;
+               edge_array_len = i;
 
-static void knife_make_face_cuts(KnifeTool_OpData *kcd, BMFace *f, ListBase *kfedges)
-{
-       BMesh *bm = kcd->em->bm;
-       KnifeEdge *kfe;
-       BMFace *fnew, *fnew2, *fhole;
-       ListBase *chain, *hole, *sidechain;
-       Ref *ref, *refnext;
-       int count, oldcount;
-
-       oldcount = BLI_listbase_count(kfedges);
-       while ((chain = find_chain(kcd, kfedges)) != NULL) {
-               ListBase fnew_kfedges;
-               knife_make_chain_cut(kcd, f, chain, &fnew);
-               if (!fnew) {
-                       return;
-               }
-
-               /* Move kfedges to fnew_kfedges if they are now in fnew.
-                * The chain edges were removed already */
-               BLI_listbase_clear(&fnew_kfedges);
-               for (ref = kfedges->first; ref; ref = refnext) {
-                       kfe = ref->ref;
-                       refnext = ref->next;
-                       if (knife_edge_in_face(kfe, fnew)) {
-                               BLI_remlink(kfedges, ref);
-                               kfe->basef = fnew;
-                               BLI_addtail(&fnew_kfedges, ref);
-                       }
-                       else if (!knife_edge_in_face(kfe, f)) {
-                               /* Concave ngon's - this edge might not be in either faces, T41730 */
-                               BLI_remlink(kfedges, ref);
+#ifdef USE_NET_ISLAND_CONNECT
+               unsigned int edge_array_holes_len;
+               BMEdge **edge_array_holes;
+               if (BM_face_split_edgenet_connect_islands(
+                       bm, f,
+                       edge_array, edge_array_len,
+                       kcd->arena_edgenet,
+                       &edge_array_holes, &edge_array_holes_len))
+               {
+                       if (BM_elem_flag_test(f, BM_ELEM_SELECT)) {
+                               for (i = edge_array_len; i < edge_array_holes_len; i++) {
+                                       BM_edge_select_set(bm, edge_array_holes[i], true);
+                               }
                        }
-               }
-               if (fnew_kfedges.first)
-                       knife_make_face_cuts(kcd, fnew, &fnew_kfedges);
 
-               /* find_chain should always remove edges if it returns true,
-                * but guard against infinite loop anyway */
-               count = BLI_listbase_count(kfedges);
-               if (count >= oldcount) {
-                       BLI_assert(!"knife find_chain infinite loop");
-                       return;
+                       edge_array_len = edge_array_holes_len;
+                       edge_array = edge_array_holes;  /* owned by the arena */
                }
-               oldcount = count;
-       }
+#endif
 
-       while ((hole = find_hole(kcd, kfedges)) != NULL) {
-               if (find_hole_chains(kcd, hole, f, &chain, &sidechain)) {
-                       ListBase fnew_kfedges, fnew2_kfedges;
+               ok = BM_face_split_edgenet(
+                        bm, f, edge_array, edge_array_len,
+                        &face_arr, &face_arr_len);
 
-                       /* chain goes across f and sidechain comes back
-                        * from the second last vertex to the second vertex.
-                        */
-                       knife_make_chain_cut(kcd, f, chain, &fnew);
-                       if (!fnew) {
-                               BLI_assert(!"knife failed hole cut");
-                               return;
-                       }
-                       kfe = ((Ref *)sidechain->first)->ref;
-                       if (knife_edge_in_face(kfe, f)) {
-                               knife_make_chain_cut(kcd, f, sidechain, &fnew2);
-                               if (fnew2 == NULL) {
-                                       return;
-                               }
-                               fhole = f;
-                       }
-                       else if (knife_edge_in_face(kfe, fnew)) {
-                               knife_make_chain_cut(kcd, fnew, sidechain, &fnew2);
-                               if (fnew2 == NULL) {
-                                       return;
-                               }
-                               fhole = fnew2;
-                       }
-                       else {
-                               /* shouldn't happen except in funny edge cases */
-                               return;
-                       }
-                       BM_face_kill(bm, fhole);
-                       /* Move kfedges to either fnew or fnew2 if appropriate.
-                        * The hole edges were removed already */
-                       BLI_listbase_clear(&fnew_kfedges);
-                       BLI_listbase_clear(&fnew2_kfedges);
-                       for (ref = kfedges->first; ref; ref = refnext) {
-                               kfe = ref->ref;
-                               refnext = ref->next;
-                               if (knife_edge_in_face(kfe, fnew)) {
-                                       BLI_remlink(kfedges, ref);
-                                       kfe->basef = fnew;
-                                       BLI_addtail(&fnew_kfedges, ref);
-                               }
-                               else if (knife_edge_in_face(kfe, fnew2)) {
-                                       BLI_remlink(kfedges, ref);
-                                       kfe->basef = fnew2;
-                                       BLI_addtail(&fnew2_kfedges, ref);
+               if (ok) {
+                       MEM_freeN(face_arr);
+               }
+
+               /* remove dangling edges, not essential - but nice for users */
+               for (i = 0; i < edge_array_len_orig; i++) {
+                       if (kfe_array[i]) {
+                               if (BM_edge_is_wire(kfe_array[i]->e)) {
+                                       BM_edge_kill(bm, kfe_array[i]->e);
+                                       kfe_array[i]->e = NULL;
                                }
                        }
-                       /* We'll skip knife edges that are in the newly formed hole.
-                        * (Maybe we shouldn't have made a hole in the first place?) */
-                       if (fnew != fhole && fnew_kfedges.first)
-                               knife_make_face_cuts(kcd, fnew, &fnew_kfedges);
-                       if (fnew2 != fhole && fnew2_kfedges.first)
-                               knife_make_face_cuts(kcd, fnew2, &fnew2_kfedges);
-                       if (f == fhole)
-                               break;
-                       /* find_hole should always remove edges if it returns true,
-                        * but guard against infinite loop anyway */
-                       count = BLI_listbase_count(kfedges);
-                       if (count >= oldcount) {
-                               BLI_assert(!"knife find_hole infinite loop");
-                               return;
-                       }
-                       oldcount = count;
                }
+
+
+#ifdef USE_NET_ISLAND_CONNECT
+               BLI_memarena_clear(kcd->arena_edgenet);
+#endif
        }
 }
 
@@ -2915,6 +2508,9 @@ static void knifetool_exit_ex(bContext *C, KnifeTool_OpData *kcd)
        BLI_ghash_free(kcd->facetrimap, NULL, NULL);
 
        BLI_memarena_free(kcd->arena);
+#ifdef USE_NET_ISLAND_CONNECT
+       BLI_memarena_free(kcd->arena_edgenet);
+#endif
 
        /* tag for redraw */
        ED_region_tag_redraw(kcd->ar);
@@ -3000,6 +2596,9 @@ static void knifetool_init(bContext *C, KnifeTool_OpData *kcd,
        knifetool_init_bmbvh(kcd);
 
        kcd->arena = BLI_memarena_new(MEM_SIZE_OPTIMAL(1 << 15), "knife");
+#ifdef USE_NET_ISLAND_CONNECT
+       kcd->arena_edgenet = BLI_memarena_new(MEM_SIZE_OPTIMAL(1 << 15), __func__);
+#endif
        kcd->vthresh = KMAXDIST - 1;
        kcd->ethresh = KMAXDIST;