Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCampbell Barton <ideasman42@gmail.com>2015-12-12 19:46:36 +0300
committerCampbell Barton <ideasman42@gmail.com>2015-12-12 19:46:36 +0300
commit9df6a539a2c93c2b8fe32d0d5b564c62bbadba9a (patch)
tree8f356a524f445259c4e0ae2d43d769e1cb582c22
parentf117f45d86c0c3c028b280c84c64e94ded7664ed (diff)
Knife: use BM_face_split_edgenet for detecting holes
Knife had its own code for detecting holes which worked quite well, but would prefer to use generic bmesh API call here.
-rw-r--r--source/blender/editors/mesh/editmesh_knife.c587
1 files changed, 93 insertions, 494 deletions
diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c
index 818526ab772..5b9af2fa75c 100644
--- a/source/blender/editors/mesh/editmesh_knife.c
+++ b/source/blender/editors/mesh/editmesh_knife.c
@@ -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;