2 * ***** BEGIN GPL LICENSE BLOCK *****
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software Foundation,
16 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 * The Original Code is Copyright (C) 2007 Blender Foundation.
19 * All rights reserved.
22 * Contributor(s): Joseph Eagar, Joshua Leung, Howard Trickey,
25 * ***** END GPL LICENSE BLOCK *****
28 /** \file blender/editors/mesh/editmesh_knife.c
33 # define _USE_MATH_DEFINES
36 #include "MEM_guardedalloc.h"
38 #include "BLI_blenlib.h"
39 #include "BLI_array.h"
40 #include "BLI_linklist.h"
42 #include "BLI_smallhash.h"
43 #include "BLI_memarena.h"
45 #include "BLF_translation.h"
47 #include "BKE_DerivedMesh.h"
48 #include "BKE_context.h"
51 #include "BIF_glutil.h" /* for paint cursor */
53 #include "ED_screen.h"
54 #include "ED_space_api.h"
55 #include "ED_view3d.h"
61 #include "DNA_scene_types.h"
62 #include "DNA_object_types.h"
63 #include "BKE_tessmesh.h"
64 #include "UI_resources.h"
66 #include "RNA_access.h"
67 #include "RNA_define.h"
69 #include "mesh_intern.h"
71 /* this code here is kindof messy. . .I might need to eventually rework it - joeedh */
73 #define KMAXDIST 10 /* max mouse distance from edge before not detecting it */
75 #define KNIFE_FLT_EPS 0.00001f
76 #define KNIFE_FLT_EPS_SQUARED (KNIFE_FLT_EPS * KNIFE_FLT_EPS)
78 typedef struct KnifeColors {
79 unsigned char line[3];
80 unsigned char edge[3];
81 unsigned char curpoint[3];
82 unsigned char curpoint_a[4];
83 unsigned char point[3];
84 unsigned char point_a[4];
87 /* knifetool operator */
88 typedef struct KnifeVert {
89 BMVert *v; /* non-NULL if this is an original vert */
93 float co[3], cageco[3], sco[3]; /* sco is screen coordinates for cageco */
94 short flag, draw, isface, inspace;
98 struct Ref *next, *prev;
102 typedef struct KnifeEdge {
104 BMFace *basef; /* face to restrict face fill to */
108 BMEdge *e /* , *e_old */; /* non-NULL if this is an original edge */
111 typedef struct BMEdgeHit {
113 float hit[3], cagehit[3];
114 float realhit[3]; /* used in midpoint mode */
116 float l; /* lambda along cut line */
117 float perc; /* lambda along hit line */
118 KnifeVert *v; /* set if snapped to a vert */
122 typedef struct KnifePosData {
126 /* At most one of vert, edge, or bmface should be non-NULL,
127 * saying whether the point is snapped to a vertex, edge, or in a face.
128 * If none are set, this point is in space and is_space should be true. */
134 float mval[2]; /* mouse screen position (may be non-integral if snapped to something) */
137 /* struct for properties used while drawing */
138 typedef struct KnifeTool_OpData {
139 ARegion *ar; /* region that knifetool was activated in */
140 void *draw_handle; /* for drawing preview loop */
141 ViewContext vc; /* note: _don't_ use 'mval', instead use the one we define below */
142 float mval[2]; /* mouse value with snapping applied */
163 /* used for drag-cutting */
167 /* Data for mouse-position-derived data (cur) and previous click (prev) */
168 KnifePosData curr, prev;
170 int totkedge, totkvert;
178 /* operatpr options */
179 bool cut_through; /* preference, can be modified at runtime (that feature may go) */
180 bool only_select; /* set on initialization */
181 bool select_result; /* set on initialization */
185 float clipsta, clipend;
194 int snap_midpoints, prevmode, extend;
195 int ignore_edge_snapping, ignore_vert_snapping;
208 static ListBase *knife_get_face_kedges(KnifeTool_OpData *kcd, BMFace *f);
211 static void knife_input_ray_cast(KnifeTool_OpData *kcd, const float mval[2],
212 float r_origin[3], float r_ray[3]);
214 static void knife_input_ray_segment(KnifeTool_OpData *kcd, const float mval[2], const float ofs,
215 float r_origin[3], float r_dest[3]);
217 static void knife_update_header(bContext *C, KnifeTool_OpData *kcd)
219 #define HEADER_LENGTH 256
220 char header[HEADER_LENGTH];
222 BLI_snprintf(header, HEADER_LENGTH, IFACE_("LMB: define cut lines, Return/Spacebar: confirm, Esc or RMB: cancel, "
223 "E: new cut, Ctrl: midpoint snap (%s), Shift: ignore snap (%s), "
224 "C: angle constrain (%s), Z: cut through (%s)"),
225 kcd->snap_midpoints ? IFACE_("On") : IFACE_("Off"),
226 kcd->ignore_edge_snapping ? IFACE_("On") : IFACE_("Off"),
227 kcd->angle_snapping ? IFACE_("On") : IFACE_("Off"),
228 kcd->cut_through ? IFACE_("On") : IFACE_("Off"));
230 ED_area_headerprint(CTX_wm_area(C), header);
233 BLI_INLINE int round_ftoi(float x)
235 return x > 0.0f ? (int)(x + 0.5f) : (int)(x - 0.5f);
238 static void knife_project_v3(const KnifeTool_OpData *kcd, const float co[3], float sco[3])
240 ED_view3d_project_float_v3_m4(kcd->ar, co, sco, (float (*)[4])kcd->projmat);
243 static void knife_pos_data_clear(KnifePosData *kpd)
253 static ListBase *knife_empty_list(KnifeTool_OpData *kcd)
257 lst = BLI_memarena_alloc(kcd->arena, sizeof(ListBase));
258 lst->first = lst->last = NULL;
262 static void knife_append_list(KnifeTool_OpData *kcd, ListBase *lst, void *elem)
266 ref = BLI_mempool_calloc(kcd->refs);
268 BLI_addtail(lst, ref);
271 static Ref *find_ref(ListBase *lb, void *ref)
275 for (ref1 = lb->first; ref1; ref1 = ref1->next) {
276 if (ref1->ref == ref)
283 static KnifeEdge *new_knife_edge(KnifeTool_OpData *kcd)
286 return BLI_mempool_calloc(kcd->kedges);
289 static void knife_add_to_vert_edges(KnifeTool_OpData *kcd, KnifeEdge *kfe)
291 knife_append_list(kcd, &kfe->v1->edges, kfe);
292 knife_append_list(kcd, &kfe->v2->edges, kfe);
295 /* Add faces of an edge to a KnifeVert's faces list. No checks for dups. */
296 static void knife_add_edge_faces_to_vert(KnifeTool_OpData *kcd, KnifeVert *kfv, BMEdge *e)
301 BM_ITER_ELEM(f, &bmiter, e, BM_FACES_OF_EDGE) {
302 knife_append_list(kcd, &kfv->faces, f);
306 /* Find a face in common in the two faces lists.
307 * If more than one, return the first; if none, return NULL */
308 static BMFace *knife_find_common_face(ListBase *faces1, ListBase *faces2)
312 for (ref1 = faces1->first; ref1; ref1 = ref1->next) {
313 for (ref2 = faces2->first; ref2; ref2 = ref2->next) {
314 if (ref1->ref == ref2->ref)
315 return (BMFace *)(ref1->ref);
321 static KnifeVert *new_knife_vert(KnifeTool_OpData *kcd, const float co[3], float *cageco)
323 KnifeVert *kfv = BLI_mempool_calloc(kcd->kverts);
327 copy_v3_v3(kfv->co, co);
328 copy_v3_v3(kfv->cageco, cageco);
329 copy_v3_v3(kfv->sco, co);
331 knife_project_v3(kcd, kfv->co, kfv->sco);
336 /* get a KnifeVert wrapper for an existing BMVert */
337 static KnifeVert *get_bm_knife_vert(KnifeTool_OpData *kcd, BMVert *v)
339 KnifeVert *kfv = BLI_ghash_lookup(kcd->origvertmap, v);
345 kfv = new_knife_vert(kcd, v->co, kcd->cagecos[BM_elem_index_get(v)]);
347 BLI_ghash_insert(kcd->origvertmap, v, kfv);
348 BM_ITER_ELEM(f, &bmiter, v, BM_FACES_OF_VERT) {
349 knife_append_list(kcd, &kfv->faces, f);
356 /* get a KnifeEdge wrapper for an existing BMEdge */
357 static KnifeEdge *get_bm_knife_edge(KnifeTool_OpData *kcd, BMEdge *e)
359 KnifeEdge *kfe = BLI_ghash_lookup(kcd->origedgemap, e);
364 kfe = new_knife_edge(kcd);
366 kfe->v1 = get_bm_knife_vert(kcd, e->v1);
367 kfe->v2 = get_bm_knife_vert(kcd, e->v2);
369 knife_add_to_vert_edges(kcd, kfe);
371 BLI_ghash_insert(kcd->origedgemap, e, kfe);
373 BM_ITER_ELEM(f, &bmiter, e, BM_FACES_OF_EDGE) {
374 knife_append_list(kcd, &kfe->faces, f);
381 /* User has just clicked for first time or first time after a restart (E key).
382 * Copy the current position data into prev. */
383 static void knife_start_cut(KnifeTool_OpData *kcd)
385 kcd->prev = kcd->curr;
386 kcd->curr.is_space = 0; /*TODO: why do we do this? */
388 if (kcd->prev.vert == NULL && kcd->prev.edge == NULL && is_zero_v3(kcd->prev.cage)) {
389 /* Make prevcage a point on the view ray to mouse closest to a point on model: choose vertex 0 */
390 float origin[3], origin_ofs[3];
393 knife_input_ray_segment(kcd, kcd->curr.mval, 1.0f, origin, origin_ofs);
394 v0 = BM_vert_at_index(kcd->em->bm, 0);
396 closest_to_line_v3(kcd->prev.cage, v0->co, origin_ofs, origin);
397 copy_v3_v3(kcd->prev.co, kcd->prev.cage); /*TODO: do we need this? */
398 copy_v3_v3(kcd->curr.cage, kcd->prev.cage);
399 copy_v3_v3(kcd->curr.co, kcd->prev.co);
404 static ListBase *knife_get_face_kedges(KnifeTool_OpData *kcd, BMFace *f)
406 ListBase *lst = BLI_ghash_lookup(kcd->kedgefacemap, f);
412 lst = knife_empty_list(kcd);
414 BM_ITER_ELEM(e, &bmiter, f, BM_EDGES_OF_FACE) {
415 knife_append_list(kcd, lst, get_bm_knife_edge(kcd, e));
418 BLI_ghash_insert(kcd->kedgefacemap, f, lst);
424 /* finds the proper face to restrict face fill to */
425 static void knife_find_basef(KnifeEdge *kfe)
427 kfe->basef = knife_find_common_face(&kfe->v1->faces, &kfe->v2->faces);
430 static void knife_edge_append_face(KnifeTool_OpData *kcd, KnifeEdge *kfe, BMFace *f)
432 knife_append_list(kcd, knife_get_face_kedges(kcd, f), kfe);
433 knife_append_list(kcd, &kfe->faces, f);
436 static KnifeVert *knife_split_edge(KnifeTool_OpData *kcd, KnifeEdge *kfe, float co[3], KnifeEdge **newkfe_out)
438 KnifeEdge *newkfe = new_knife_edge(kcd);
441 float perc, cageco[3], l12;
443 l12 = len_v3v3(kfe->v1->co, kfe->v2->co);
444 if (l12 < KNIFE_FLT_EPS) {
445 copy_v3_v3(cageco, kfe->v1->cageco);
448 perc = len_v3v3(co, kfe->v1->co) / l12;
449 interp_v3_v3v3(cageco, kfe->v1->cageco, kfe->v2->cageco, perc);
452 newkfe->v1 = kfe->v1;
453 newkfe->v2 = new_knife_vert(kcd, co, cageco);
454 newkfe->v2->draw = 1;
456 knife_add_edge_faces_to_vert(kcd, newkfe->v2, kfe->e);
459 /* kfe cuts across an existing face.
460 * If v1 and v2 are in multiple faces together (e.g., if they
461 * are in doubled polys) then this arbitrarily chooses one of them */
462 f = knife_find_common_face(&kfe->v1->faces, &kfe->v2->faces);
464 knife_append_list(kcd, &newkfe->v2->faces, f);
466 newkfe->basef = kfe->basef;
468 ref = find_ref(&kfe->v1->edges, kfe);
469 BLI_remlink(&kfe->v1->edges, ref);
471 kfe->v1 = newkfe->v2;
472 BLI_addtail(&kfe->v1->edges, ref);
474 for (ref = kfe->faces.first; ref; ref = ref->next)
475 knife_edge_append_face(kcd, newkfe, ref->ref);
477 knife_add_to_vert_edges(kcd, newkfe);
479 newkfe->draw = kfe->draw;
482 *newkfe_out = newkfe;
487 /* Make a single KnifeEdge for cut from kcd->prev to kcd->curr.
488 * and move cur data to prev. */
489 static void knife_add_single_cut(KnifeTool_OpData *kcd)
491 KnifeEdge *kfe = new_knife_edge(kcd), *kfe2 = NULL, *kfe3 = NULL;
493 if (kcd->prev.vert && kcd->prev.vert == kcd->curr.vert)
495 if (kcd->prev.edge && kcd->prev.edge == kcd->curr.edge)
500 if (kcd->prev.vert) {
501 kfe->v1 = kcd->prev.vert;
503 else if (kcd->prev.edge) {
504 kfe->v1 = knife_split_edge(kcd, kcd->prev.edge, kcd->prev.co, &kfe2);
507 kfe->v1 = new_knife_vert(kcd, kcd->prev.co, kcd->prev.co);
508 kfe->v1->draw = kfe->draw = !kcd->prev.is_space;
509 kfe->v1->inspace = kcd->prev.is_space;
510 kfe->draw = !kcd->prev.is_space;
512 if (kfe->v1->draw && kcd->prev.bmface)
513 knife_append_list(kcd, &kfe->v1->faces, kcd->prev.bmface);
516 if (kcd->curr.vert) {
517 kfe->v2 = kcd->curr.vert;
519 else if (kcd->curr.edge) {
520 kfe->v2 = knife_split_edge(kcd, kcd->curr.edge, kcd->curr.co, &kfe3);
521 kcd->curr.vert = kfe->v2;
524 kfe->v2 = new_knife_vert(kcd, kcd->curr.co, kcd->curr.co);
525 kfe->v2->draw = !kcd->curr.is_space;
527 kfe->v2->inspace = kcd->curr.is_space;
528 if (kfe->v2->draw && kcd->curr.bmface)
529 knife_append_list(kcd, &kfe->v2->faces, kcd->curr.bmface);
531 if (kcd->curr.is_space)
534 kcd->curr.vert = kfe->v2;
537 knife_find_basef(kfe);
539 knife_add_to_vert_edges(kcd, kfe);
541 if (kfe->basef && !find_ref(&kfe->faces, kfe->basef))
542 knife_edge_append_face(kcd, kfe, kfe->basef);
544 /* sanity check to make sure we're in the right edge/face lists */
545 if (kcd->curr.bmface) {
546 if (!find_ref(&kfe->faces, kcd->curr.bmface)) {
547 knife_edge_append_face(kcd, kfe, kcd->curr.bmface);
550 if (kcd->prev.bmface && kcd->prev.bmface != kcd->curr.bmface) {
551 if (!find_ref(&kfe->faces, kcd->prev.bmface)) {
552 knife_edge_append_face(kcd, kfe, kcd->prev.bmface);
557 /* set up for next cut */
558 kcd->prev = kcd->curr;
561 static int verge_linehit(const void *vlh1, const void *vlh2)
563 const BMEdgeHit *lh1 = vlh1, *lh2 = vlh2;
565 if (lh1->l < lh2->l) return -1;
566 else if (lh1->l > lh2->l) return 1;
570 /* If there's a linehit connected (same face) as testi in range [firsti, lasti], return the first such, else -1.
571 * If testi is out of range, look for connection to f instead, if f is non-NULL */
572 static int find_connected_linehit(KnifeTool_OpData *kcd, int testi, BMFace *f, int firsti, int lasti)
576 for (i = firsti; i <= lasti; i++) {
577 if (testi >= 0 && testi < kcd->totlinehit) {
578 if (knife_find_common_face(&kcd->linehits[testi].kfe->faces,
579 &kcd->linehits[i].kfe->faces))
585 if (find_ref(&kcd->linehits[i].kfe->faces, f))
592 /* Sort in order of distance along cut line, but take care when distances are equal */
593 static void knife_sort_linehits(KnifeTool_OpData *kcd)
595 int i, j, k, nexti, nsame;
597 qsort(kcd->linehits, kcd->totlinehit, sizeof(BMEdgeHit), verge_linehit);
599 /* for ranges of equal "l", swap if neccesary to make predecessor and
600 * successor faces connected to the linehits at either end of the range */
601 for (i = 0; i < kcd->totlinehit - 1; i = nexti) {
602 for (j = i + 1; j < kcd->totlinehit; j++) {
603 if (fabsf(kcd->linehits[j].l - kcd->linehits[i].l) > KNIFE_FLT_EPS)
610 /* find something connected to predecessor of equal range */
611 k = find_connected_linehit(kcd, i - 1, kcd->prev.bmface, i, j);
614 SWAP(BMEdgeHit, kcd->linehits[i], kcd->linehits[k]);
620 /* find something connected to successor of equal range */
621 k = find_connected_linehit(kcd, j + 1, kcd->curr.bmface, i, j);
622 if (k != -1 && k != j) {
623 SWAP(BMEdgeHit, kcd->linehits[j], kcd->linehits[k]);
626 /* rest of same range doesn't matter because we won't connect them */
631 static void knife_add_single_cut_through(KnifeTool_OpData *kcd, KnifeVert *v1, KnifeVert *v2, BMFace *f)
635 kfenew = new_knife_edge(kcd);
642 knife_add_to_vert_edges(kcd, kfenew);
644 if (!find_ref(&kfenew->faces, f))
645 knife_edge_append_face(kcd, kfenew, f);
648 static void knife_get_vert_faces(KnifeTool_OpData *kcd, KnifeVert *kfv, BMFace *facef, ListBase *lst)
654 if (kfv->isface && facef) {
655 knife_append_list(kcd, lst, facef);
658 BM_ITER_ELEM (f, &bmiter, kfv->v, BM_FACES_OF_VERT) {
659 knife_append_list(kcd, lst, f);
663 for (r = kfv->faces.first; r; r = r->next) {
664 knife_append_list(kcd, lst, r->ref);
669 static void knife_get_edge_faces(KnifeTool_OpData *kcd, KnifeEdge *kfe, ListBase *lst)
675 BM_ITER_ELEM (f, &bmiter, kfe->e, BM_FACES_OF_EDGE) {
676 knife_append_list(kcd, lst, f);
681 /* BMESH_TODO: add more functionality to cut-through:
682 * - cutting "in face" (e.g., holes) should cut in all faces, not just visible one
683 * - perhaps improve O(n^2) algorithm used here */
684 static void knife_cut_through(KnifeTool_OpData *kcd)
688 KnifeEdge *kfe, *kfe2, *kfe3;
689 KnifeVert *v1, *v2, *firstv = NULL, *lastv = NULL;
690 ListBase firstfaces = {NULL, NULL}, lastfaces = {NULL, NULL};
692 KnifeEdge **splitkfe;
695 if (!kcd->totlinehit) {
696 /* if no linehits then no interesting back face stuff to do */
697 knife_add_single_cut(kcd);
701 /* TODO: probably don't need to sort at all */
702 qsort(kcd->linehits, kcd->totlinehit, sizeof(BMEdgeHit), verge_linehit);
703 splitkfe = MEM_callocN(kcd->totlinehit * sizeof(KnifeEdge *), "knife_cut_through");
705 if (kcd->prev.vert) {
706 if (kcd->prev.vert == kcd->curr.vert)
708 firstv = kcd->prev.vert;
709 knife_get_vert_faces(kcd, firstv, kcd->prev.bmface, &firstfaces);
711 else if (kcd->prev.edge) {
712 if (kcd->prev.edge == kcd->curr.edge)
714 firstv = knife_split_edge(kcd, kcd->prev.edge, kcd->prev.co, &kfe3);
715 knife_get_edge_faces(kcd, kcd->prev.edge, &firstfaces);
718 if (kcd->curr.vert) {
719 lastv = kcd->curr.vert;
720 knife_get_vert_faces(kcd, lastv, kcd->curr.bmface, &lastfaces);
722 else if (kcd->curr.edge) {
723 lastv = knife_split_edge(kcd, kcd->curr.edge, kcd->curr.co, &kfe3);
724 knife_get_edge_faces(kcd, kcd->curr.edge, &lastfaces);
728 /* For each face incident to firstv,
729 * find the first following linehit (if any) sharing that face and connect */
730 for (r = firstfaces.first; r; r = r->next) {
733 for (j = 0, lh2 = kcd->linehits; j < kcd->totlinehit && !found; j++, lh2++) {
735 for (r2 = kfe2->faces.first; r2; r2 = r2->next) {
737 v2 = splitkfe[j] ? kfe2->v1 : knife_split_edge(kcd, kfe2, lh2->hit, &splitkfe[j]);
738 knife_add_single_cut_through(kcd, firstv, v2, f);
744 if (!found && lastv) {
745 for (r2 = lastfaces.first; r2; r2 = r2->next) {
747 knife_add_single_cut_through(kcd, firstv, lastv, f);
755 for (i = 0, lh = kcd->linehits; i < kcd->totlinehit; i++, lh++) {
758 /* For each face attached to edge for this linehit,
759 * find the first following linehit (if any) sharing that face and connect */
760 for (r = kfe->faces.first; r; r = r->next) {
763 for (j = i + 1, lh2 = lh + 1; j < kcd->totlinehit && !found; j++, lh2++) {
765 for (r2 = kfe2->faces.first; r2; r2 = r2->next) {
767 v1 = splitkfe[i] ? kfe->v1 : knife_split_edge(kcd, kfe, lh->hit, &splitkfe[i]);
768 v2 = splitkfe[j] ? kfe2->v1 : knife_split_edge(kcd, kfe2, lh2->hit, &splitkfe[j]);
769 knife_add_single_cut_through(kcd, v1, v2, f);
775 if (!found && lastv) {
776 for (r2 = lastfaces.first; r2; r2 = r2->next) {
778 v1 = splitkfe[i] ? kfe->v1 : knife_split_edge(kcd, kfe, lh->hit, &splitkfe[i]);
779 knife_add_single_cut_through(kcd, v1, lastv, f);
788 MEM_freeN(kcd->linehits);
789 kcd->linehits = NULL;
792 /* set up for next cut */
793 kcd->curr.vert = lastv;
794 kcd->prev = kcd->curr;
797 /* User has just left-clicked after the first time.
798 * Add all knife cuts implied by line from prev to curr.
799 * If that line crossed edges then kcd->linehits will be non-NULL. */
800 static void knife_add_cut(KnifeTool_OpData *kcd)
802 KnifePosData savcur = kcd->curr;
804 if (kcd->cut_through) {
805 knife_cut_through(kcd);
807 else if (kcd->linehits) {
808 BMEdgeHit *lh, *lastlh, *firstlh;
811 knife_sort_linehits(kcd);
814 lastlh = firstlh = NULL;
815 for (i = 0; i < kcd->totlinehit; i++, (lastlh = lh), lh++) {
816 BMFace *f = lastlh ? lastlh->f : lh->f;
818 if (lastlh && len_squared_v3v3(lastlh->hit, lh->hit) == 0.0f) {
823 else if (lastlh && firstlh) {
824 if (firstlh->v || lastlh->v) {
825 KnifeVert *kfv = firstlh->v ? firstlh->v : lastlh->v;
827 kcd->prev.vert = kfv;
828 copy_v3_v3(kcd->prev.co, firstlh->hit);
829 copy_v3_v3(kcd->prev.cage, firstlh->cagehit);
830 kcd->prev.edge = NULL;
831 kcd->prev.bmface = f;
832 /* TODO: should we set prev.in_space = 0 ? */
834 lastlh = firstlh = NULL;
837 if (len_squared_v3v3(kcd->prev.cage, lh->realhit) < KNIFE_FLT_EPS_SQUARED)
839 if (len_squared_v3v3(kcd->curr.cage, lh->realhit) < KNIFE_FLT_EPS_SQUARED)
842 /* first linehit may be down face parallel to view */
843 if (!lastlh && fabsf(lh->l) < KNIFE_FLT_EPS)
846 if (kcd->prev.is_space) {
847 kcd->prev.is_space = 0;
848 copy_v3_v3(kcd->prev.co, lh->hit);
849 copy_v3_v3(kcd->prev.cage, lh->cagehit);
850 kcd->prev.vert = NULL;
851 kcd->prev.edge = lh->kfe;
852 kcd->prev.bmface = lh->f;
856 kcd->curr.is_space = 0;
857 kcd->curr.edge = lh->kfe;
858 kcd->curr.bmface = lh->f;
859 kcd->curr.vert = lh->v;
860 copy_v3_v3(kcd->curr.co, lh->hit);
861 copy_v3_v3(kcd->curr.cage, lh->cagehit);
863 /* don't draw edges down faces parallel to view */
864 if (lastlh && fabsf(lastlh->l - lh->l) < KNIFE_FLT_EPS) {
865 kcd->prev = kcd->curr;
869 knife_add_single_cut(kcd);
872 if (savcur.is_space) {
877 knife_add_single_cut(kcd);
880 MEM_freeN(kcd->linehits);
881 kcd->linehits = NULL;
885 knife_add_single_cut(kcd);
889 static void knife_finish_cut(KnifeTool_OpData *UNUSED(kcd))
894 static void knifetool_draw_angle_snapping(const KnifeTool_OpData *kcd)
897 double u[3], u1[2], u2[2], v1[3], v2[3], dx, dy;
898 double wminx, wminy, wmaxx, wmaxy;
900 /* make u the window coords of prevcage */
901 view3d_get_transformation(kcd->ar, kcd->vc.rv3d, kcd->ob, &mats);
902 gluProject(kcd->prev.cage[0], kcd->prev.cage[1], kcd->prev.cage[2],
903 mats.modelview, mats.projection, mats.viewport,
904 &u[0], &u[1], &u[2]);
906 /* make u1, u2 the points on window going through u at snap angle */
907 wminx = kcd->ar->winrct.xmin;
908 wmaxx = kcd->ar->winrct.xmin + kcd->ar->winx;
909 wminy = kcd->ar->winrct.ymin;
910 wmaxy = kcd->ar->winrct.ymin + kcd->ar->winy;
912 switch (kcd->angle_snapping) {
916 u1[1] = u2[1] = u[1];
919 u1[0] = u2[0] = u[0];
924 /* clip against left or bottom */
935 /* clip against right or top */
948 /* clip against right or bottom */
959 /* clip against left or top */
975 /* unproject u1 and u2 back into object space */
976 gluUnProject(u1[0], u1[1], 0.0,
977 mats.modelview, mats.projection, mats.viewport,
978 &v1[0], &v1[1], &v1[2]);
979 gluUnProject(u2[0], u2[1], 0.0,
980 mats.modelview, mats.projection, mats.viewport,
981 &v2[0], &v2[1], &v2[2]);
983 UI_ThemeColor(TH_TRANSFORM);
991 static void knife_init_colors(KnifeColors *colors)
993 /* possible BMESH_TODO: add explicit themes or calculate these by
994 * figuring out contrasting colors with grid / edges / verts
995 * a la UI_make_axis_color */
996 UI_GetThemeColor3ubv(TH_NURB_VLINE, colors->line);
997 UI_GetThemeColor3ubv(TH_NURB_ULINE, colors->edge);
998 UI_GetThemeColor3ubv(TH_HANDLE_SEL_VECT, colors->curpoint);
999 UI_GetThemeColor3ubv(TH_HANDLE_SEL_VECT, colors->curpoint_a);
1000 colors->curpoint_a[3] = 102;
1001 UI_GetThemeColor3ubv(TH_ACTIVE_SPLINE, colors->point);
1002 UI_GetThemeColor3ubv(TH_ACTIVE_SPLINE, colors->point_a);
1003 colors->point_a[3] = 102;
1006 /* modal loop selection drawing callback */
1007 static void knifetool_draw(const bContext *C, ARegion *UNUSED(ar), void *arg)
1009 View3D *v3d = CTX_wm_view3d(C);
1010 const KnifeTool_OpData *kcd = arg;
1012 if (v3d->zbuf) glDisable(GL_DEPTH_TEST);
1014 glPolygonOffset(1.0f, 1.0f);
1017 glMultMatrixf(kcd->ob->obmat);
1019 if (kcd->mode == MODE_DRAGGING) {
1020 if (kcd->angle_snapping != ANGLE_FREE)
1021 knifetool_draw_angle_snapping(kcd);
1023 glColor3ubv(kcd->colors.line);
1028 glVertex3fv(kcd->prev.cage);
1029 glVertex3fv(kcd->curr.cage);
1035 if (kcd->curr.edge) {
1036 glColor3ubv(kcd->colors.edge);
1040 glVertex3fv(kcd->curr.edge->v1->cageco);
1041 glVertex3fv(kcd->curr.edge->v2->cageco);
1046 else if (kcd->curr.vert) {
1047 glColor3ubv(kcd->colors.point);
1051 glVertex3fv(kcd->curr.cage);
1055 if (kcd->curr.bmface) {
1056 glColor3ubv(kcd->colors.curpoint);
1060 glVertex3fv(kcd->curr.cage);
1064 if (kcd->totlinehit > 0) {
1065 const float vthresh4 = kcd->vthresh / 4.0f;
1066 const float vthresh4_squared = vthresh4 * vthresh4;
1072 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1074 /* draw any snapped verts first */
1075 glColor4ubv(kcd->colors.point_a);
1079 for (i = 0; i < kcd->totlinehit; i++, lh++) {
1080 float sv1[3], sv2[3];
1082 knife_project_v3(kcd, lh->kfe->v1->cageco, sv1);
1083 knife_project_v3(kcd, lh->kfe->v2->cageco, sv2);
1084 knife_project_v3(kcd, lh->cagehit, lh->schit);
1086 if (len_squared_v2v2(lh->schit, sv1) < vthresh4_squared) {
1087 copy_v3_v3(lh->cagehit, lh->kfe->v1->cageco);
1088 glVertex3fv(lh->cagehit);
1089 lh->v = lh->kfe->v1;
1091 else if (len_squared_v2v2(lh->schit, sv2) < vthresh4_squared) {
1092 copy_v3_v3(lh->cagehit, lh->kfe->v2->cageco);
1093 glVertex3fv(lh->cagehit);
1094 lh->v = lh->kfe->v2;
1099 /* now draw the rest */
1100 glColor4ubv(kcd->colors.curpoint_a);
1104 for (i = 0; i < kcd->totlinehit; i++, lh++) {
1105 glVertex3fv(lh->cagehit);
1108 glDisable(GL_BLEND);
1111 if (kcd->totkedge > 0) {
1112 BLI_mempool_iter iter;
1118 BLI_mempool_iternew(kcd->kedges, &iter);
1119 for (kfe = BLI_mempool_iterstep(&iter); kfe; kfe = BLI_mempool_iterstep(&iter)) {
1123 glColor3ubv(kcd->colors.line);
1125 glVertex3fv(kfe->v1->cageco);
1126 glVertex3fv(kfe->v2->cageco);
1133 if (kcd->totkvert > 0) {
1134 BLI_mempool_iter iter;
1140 BLI_mempool_iternew(kcd->kverts, &iter);
1141 for (kfv = BLI_mempool_iterstep(&iter); kfv; kfv = BLI_mempool_iterstep(&iter)) {
1145 glColor3ubv(kcd->colors.point);
1147 glVertex3fv(kfv->cageco);
1155 if (v3d->zbuf) glEnable(GL_DEPTH_TEST);
1158 static float len_v3_tri_side_max(const float v1[3], const float v2[3], const float v3[3])
1160 const float s1 = len_squared_v3v3(v1, v2);
1161 const float s2 = len_squared_v3v3(v2, v3);
1162 const float s3 = len_squared_v3v3(v3, v1);
1164 return sqrtf(max_fff(s1, s2, s3));
1167 static BMEdgeHit *knife_edge_tri_isect(KnifeTool_OpData *kcd, BMBVHTree *bmtree,
1168 const float v1[3], const float v2[3], const float v3[3],
1169 SmallHash *ehash, bglMats *mats, int *count)
1171 BVHTree *tree2 = BLI_bvhtree_new(3, FLT_EPSILON * 4, 8, 8), *tree = BMBVH_BVHTree(bmtree);
1172 BMEdgeHit *edges = NULL;
1173 BLI_array_declare(edges);
1174 BVHTreeOverlap *results, *result;
1176 float cos[9], lambda;
1177 unsigned int tot = 0;
1180 /* for comparing distances, error of intersection depends on triangle scale.
1181 * need to scale down before squaring for accurate comparison */
1182 const float depsilon = (FLT_EPSILON / 2.0f) * len_v3_tri_side_max(v1, v2, v3);
1183 const float depsilon_squared = depsilon * depsilon;
1185 copy_v3_v3(cos + 0, v1);
1186 copy_v3_v3(cos + 3, v2);
1187 copy_v3_v3(cos + 6, v3);
1189 BLI_bvhtree_insert(tree2, 0, cos, 3);
1190 BLI_bvhtree_balance(tree2);
1192 result = results = BLI_bvhtree_overlap(tree, tree2, &tot);
1194 for (i = 0; i < tot; i++, result++) {
1200 ls = (BMLoop **)kcd->em->looptris[result->indexA];
1203 lst = knife_get_face_kedges(kcd, l1->f);
1205 for (ref = lst->first; ref; ref = ref->next) {
1206 KnifeEdge *kfe = ref->ref;
1208 if (BLI_smallhash_haskey(ehash, (intptr_t)kfe)) {
1209 continue; /* We already found a hit on this knife edge */
1212 if (isect_line_tri_v3(kfe->v1->cageco, kfe->v2->cageco, v1, v2, v3, &lambda, NULL)) {
1213 float p[3], no[3], view[3], sp[3];
1215 interp_v3_v3v3(p, kfe->v1->cageco, kfe->v2->cageco, lambda);
1217 if (kcd->curr.vert && len_squared_v3v3(kcd->curr.vert->cageco, p) < depsilon_squared) {
1220 if (kcd->prev.vert && len_squared_v3v3(kcd->prev.vert->cageco, p) < depsilon_squared) {
1223 if (len_squared_v3v3(kcd->prev.cage, p) < depsilon_squared ||
1224 len_squared_v3v3(kcd->curr.cage, p) < depsilon_squared)
1228 if ((kcd->vc.rv3d->rflag & RV3D_CLIPPING) &&
1229 ED_view3d_clipping_test(kcd->vc.rv3d, p, TRUE))
1234 knife_project_v3(kcd, p, sp);
1235 ED_view3d_unproject(mats, view, sp[0], sp[1], 0.0f);
1236 mul_m4_v3(kcd->ob->imat, view);
1238 if (kcd->cut_through) {
1242 /* check if this point is visible in the viewport */
1243 float p1[3], lambda1;
1245 /* if face isn't planer, p may be behind the current tesselated tri,
1246 * so move it onto that and then a little towards eye */
1247 if (isect_line_tri_v3(p, view, ls[0]->v->co, ls[1]->v->co, ls[2]->v->co, &lambda1, NULL)) {
1248 interp_v3_v3v3(p1, p, view, lambda1);
1253 sub_v3_v3(view, p1);
1256 copy_v3_v3(no, view);
1257 mul_v3_fl(no, 0.003);
1259 /* go towards view a bit */
1263 hitf = BMBVH_RayCast(bmtree, p1, no, NULL, NULL);
1266 /* ok, if visible add the new point */
1267 if (!hitf && !BLI_smallhash_haskey(ehash, (intptr_t)kfe)) {
1270 if (len_squared_v3v3(p, kcd->curr.co) < depsilon_squared ||
1271 len_squared_v3v3(p, kcd->prev.co) < depsilon_squared)
1279 knife_find_basef(kfe);
1281 hit.perc = len_v3v3(p, kfe->v1->cageco) / len_v3v3(kfe->v1->cageco, kfe->v2->cageco);
1282 copy_v3_v3(hit.cagehit, p);
1284 interp_v3_v3v3(p, kfe->v1->co, kfe->v2->co, hit.perc);
1285 copy_v3_v3(hit.realhit, p);
1287 /* BMESH_TODO: should also snap to vertices */
1288 if (kcd->snap_midpoints) {
1289 float perc = hit.perc;
1291 /* select the closest from the edge endpoints or the midpoint */
1295 else if (perc < 0.75f) {
1302 interp_v3_v3v3(hit.hit, kfe->v1->co, kfe->v2->co, perc);
1303 interp_v3_v3v3(hit.cagehit, kfe->v1->cageco, kfe->v2->cageco, perc);
1306 copy_v3_v3(hit.hit, p);
1308 knife_project_v3(kcd, hit.cagehit, hit.schit);
1310 BLI_array_append(edges, hit);
1311 BLI_smallhash_insert(ehash, (intptr_t)kfe, NULL);
1320 BLI_bvhtree_free(tree2);
1321 *count = BLI_array_count(edges);
1326 static void knife_bgl_get_mats(KnifeTool_OpData *UNUSED(kcd), bglMats *mats)
1329 //copy_m4_m4(mats->modelview, kcd->vc.rv3d->viewmat);
1330 //copy_m4_m4(mats->projection, kcd->vc.rv3d->winmat);
1333 /* Calculate maximum excursion from (0,0,0) of mesh */
1334 static void calc_ortho_extent(KnifeTool_OpData *kcd)
1338 BMesh *bm = kcd->em->bm;
1339 float max_xyz = 0.0f;
1342 BM_ITER_MESH(v, &iter, bm, BM_VERTS_OF_MESH) {
1343 for (i = 0; i < 3; i++)
1344 max_xyz = max_ff(max_xyz, fabs(v->co[i]));
1346 kcd->ortho_extent = max_xyz;
1349 /* Clip the line (v1, v2) to planes perpendicular to it and distances d from
1350 * the closest point on the line to the origin */
1351 static void clip_to_ortho_planes(float v1[3], float v2[3], float d)
1354 const float origin[3] = {0.0f, 0.0f, 0.0f};
1356 closest_to_line_v3(closest, origin, v1, v2);
1357 dist_ensure_v3_v3fl(v1, closest, d);
1358 dist_ensure_v3_v3fl(v2, closest, d);
1361 /* Finds visible (or all, if cutting through) edges that intersects the current screen drag line */
1362 static void knife_find_line_hits(KnifeTool_OpData *kcd)
1366 SmallHash hash, *ehash = &hash;
1367 float v1[3], v2[3], v3[3], v4[4], s1[3], s2[3];
1370 knife_bgl_get_mats(kcd, &mats);
1372 if (kcd->linehits) {
1373 MEM_freeN(kcd->linehits);
1374 kcd->linehits = NULL;
1375 kcd->totlinehit = 0;
1378 copy_v3_v3(v1, kcd->prev.cage);
1379 copy_v3_v3(v2, kcd->curr.cage);
1381 /* project screen line's 3d coordinates back into 2d */
1382 knife_project_v3(kcd, v1, s1);
1383 knife_project_v3(kcd, v2, s2);
1385 if (len_v2v2(s1, s2) < 1)
1388 /* unproject screen line */
1389 ED_view3d_win_to_segment_clip(kcd->ar, kcd->vc.v3d, s1, v1, v3);
1390 ED_view3d_win_to_segment_clip(kcd->ar, kcd->vc.v3d, s2, v2, v4);
1392 mul_m4_v3(kcd->ob->imat, v1);
1393 mul_m4_v3(kcd->ob->imat, v2);
1394 mul_m4_v3(kcd->ob->imat, v3);
1395 mul_m4_v3(kcd->ob->imat, v4);
1397 /* numeric error, 'v1' -> 'v2', 'v2' -> 'v4' can end up being ~2000 units apart in otho mode
1398 * (from ED_view3d_win_to_segment_clip() above)
1399 * this gives precision error in 'knife_edge_tri_isect', rather then solving properly
1400 * (which may involve using doubles everywhere!),
1401 * limit the distance between these points */
1402 if (kcd->is_ortho) {
1403 if (kcd->ortho_extent == 0.0f)
1404 calc_ortho_extent(kcd);
1405 clip_to_ortho_planes(v1, v3, kcd->ortho_extent + 10.0f);
1406 clip_to_ortho_planes(v2, v4, kcd->ortho_extent + 10.0f);
1409 BLI_smallhash_init(ehash);
1411 /* test two triangles of sceen line's plane */
1412 e1 = knife_edge_tri_isect(kcd, kcd->bmbvh, v1, v2, v3, ehash, &mats, &c1);
1413 e2 = knife_edge_tri_isect(kcd, kcd->bmbvh, v2, v3, v4, ehash, &mats, &c2);
1415 e1 = MEM_reallocN(e1, sizeof(BMEdgeHit) * (c1 + c2));
1416 memcpy(e1 + c1, e2, sizeof(BMEdgeHit) * c2);
1424 kcd->totlinehit = c1 + c2;
1426 /* find position along screen line, used for sorting */
1427 for (i = 0; i < kcd->totlinehit; i++) {
1428 BMEdgeHit *lh = e1 + i;
1430 lh->l = len_v2v2(lh->schit, s1) / len_v2v2(s2, s1);
1433 BLI_smallhash_release(ehash);
1436 /* this works but gives numeric problems [#33400] */
1438 static void knife_input_ray_cast(KnifeTool_OpData *kcd, const float mval[2],
1439 float r_origin[3], float r_ray[3])
1444 knife_bgl_get_mats(kcd, &mats);
1446 /* unproject to find view ray */
1447 ED_view3d_unproject(&mats, r_origin, mval[0], mval[1], 0.0f);
1449 if (kcd->is_ortho) {
1450 negate_v3_v3(r_ray, kcd->vc.rv3d->viewinv[2]);
1453 sub_v3_v3v3(r_ray, r_origin, kcd->vc.rv3d->viewinv[3]);
1455 normalize_v3(r_ray);
1457 /* transform into object space */
1458 invert_m4_m4(kcd->ob->imat, kcd->ob->obmat);
1459 copy_m3_m4(imat, kcd->ob->obmat);
1462 mul_m4_v3(kcd->ob->imat, r_origin);
1463 mul_m3_v3(imat, r_ray);
1467 static void knife_input_ray_segment(KnifeTool_OpData *kcd, const float mval[2], const float ofs,
1468 float r_origin[3], float r_origin_ofs[3])
1472 knife_bgl_get_mats(kcd, &mats);
1474 /* unproject to find view ray */
1475 ED_view3d_unproject(&mats, r_origin, mval[0], mval[1], 0.0f);
1476 ED_view3d_unproject(&mats, r_origin_ofs, mval[0], mval[1], ofs);
1478 /* transform into object space */
1479 invert_m4_m4(kcd->ob->imat, kcd->ob->obmat);
1481 mul_m4_v3(kcd->ob->imat, r_origin);
1482 mul_m4_v3(kcd->ob->imat, r_origin_ofs);
1485 static BMFace *knife_find_closest_face(KnifeTool_OpData *kcd, float co[3], float cageco[3], int *is_space)
1488 float dist = KMAXDIST;
1490 float origin_ofs[3];
1493 /* unproject to find view ray */
1494 knife_input_ray_segment(kcd, kcd->curr.mval, 1.0f, origin, origin_ofs);
1495 sub_v3_v3v3(ray, origin_ofs, origin);
1497 f = BMBVH_RayCast(kcd->bmbvh, origin, ray, co, cageco);
1503 /* try to use backbuffer selection method if ray casting failed */
1504 f = EDBM_face_find_nearest(&kcd->vc, &dist);
1506 /* cheat for now; just put in the origin instead
1507 * of a true coordinate on the face.
1508 * This just puts a point 1.0f infront of the view. */
1509 add_v3_v3v3(co, origin, ray);
1515 /* find the 2d screen space density of vertices within a radius. used to scale snapping
1516 * distance for picking edges/verts.*/
1517 static int knife_sample_screen_density(KnifeTool_OpData *kcd, float radius)
1521 float co[3], cageco[3], sco[3];
1523 f = knife_find_closest_face(kcd, co, cageco, &is_space);
1525 if (f && !is_space) {
1531 knife_project_v3(kcd, cageco, sco);
1533 lst = knife_get_face_kedges(kcd, f);
1534 for (ref = lst->first; ref; ref = ref->next) {
1535 KnifeEdge *kfe = ref->ref;
1538 for (i = 0; i < 2; i++) {
1539 KnifeVert *kfv = i ? kfe->v2 : kfe->v1;
1541 knife_project_v3(kcd, kfv->cageco, kfv->sco);
1543 dis = len_v2v2(kfv->sco, sco);
1545 if (kcd->vc.rv3d->rflag & RV3D_CLIPPING) {
1546 if (ED_view3d_clipping_test(kcd->vc.rv3d, kfv->cageco, TRUE) == 0) {
1563 /* returns snapping distance for edges/verts, scaled by the density of the
1564 * surrounding mesh (in screen space)*/
1565 static float knife_snap_size(KnifeTool_OpData *kcd, float maxsize)
1567 float density = (float)knife_sample_screen_density(kcd, maxsize * 2.0f);
1572 return min_ff(maxsize / (density * 0.5f), maxsize);
1575 /* p is closest point on edge to the mouse cursor */
1576 static KnifeEdge *knife_find_closest_edge(KnifeTool_OpData *kcd, float p[3], float cagep[3], BMFace **fptr, int *is_space)
1579 float co[3], cageco[3], sco[3], maxdist = knife_snap_size(kcd, kcd->ethresh);
1581 if (kcd->ignore_vert_snapping)
1584 f = knife_find_closest_face(kcd, co, cageco, NULL);
1587 /* set p to co, in case we don't find anything, means a face cut */
1589 copy_v3_v3(cagep, cageco);
1591 kcd->curr.bmface = f;
1594 KnifeEdge *cure = NULL;
1597 float dis, curdis = FLT_MAX;
1599 knife_project_v3(kcd, cageco, sco);
1601 /* look through all edges associated with this face */
1602 lst = knife_get_face_kedges(kcd, f);
1603 for (ref = lst->first; ref; ref = ref->next) {
1604 KnifeEdge *kfe = ref->ref;
1606 /* project edge vertices into screen space */
1607 knife_project_v3(kcd, kfe->v1->cageco, kfe->v1->sco);
1608 knife_project_v3(kcd, kfe->v2->cageco, kfe->v2->sco);
1610 dis = dist_to_line_segment_v2(sco, kfe->v1->sco, kfe->v2->sco);
1611 if (dis < curdis && dis < maxdist) {
1612 if (kcd->vc.rv3d->rflag & RV3D_CLIPPING) {
1613 float lambda = line_point_factor_v2(sco, kfe->v1->sco, kfe->v2->sco);
1616 interp_v3_v3v3(vec, kfe->v1->cageco, kfe->v2->cageco, lambda);
1618 if (ED_view3d_clipping_test(kcd->vc.rv3d, vec, TRUE) == 0) {
1634 if (!kcd->ignore_edge_snapping || !(cure->e)) {
1635 KnifeVert *edgesnap = NULL;
1637 if (kcd->snap_midpoints) {
1638 mid_v3_v3v3(p, cure->v1->co, cure->v2->co);
1639 mid_v3_v3v3(cagep, cure->v1->cageco, cure->v2->cageco);
1644 closest_to_line_segment_v3(cagep, cageco, cure->v1->cageco, cure->v2->cageco);
1645 d = len_v3v3(cagep, cure->v1->cageco) / len_v3v3(cure->v1->cageco, cure->v2->cageco);
1646 interp_v3_v3v3(p, cure->v1->co, cure->v2->co, d);
1649 /* update mouse coordinates to the snapped-to edge's screen coordinates
1650 * this is important for angle snap, which uses the previous mouse position */
1651 edgesnap = new_knife_vert(kcd, p, cagep);
1652 kcd->curr.mval[0] = edgesnap->sco[0];
1653 kcd->curr.mval[1] = edgesnap->sco[1];
1670 /* find a vertex near the mouse cursor, if it exists */
1671 static KnifeVert *knife_find_closest_vert(KnifeTool_OpData *kcd, float p[3], float cagep[3], BMFace **fptr,
1675 float co[3], cageco[3], sco[3], maxdist = knife_snap_size(kcd, kcd->vthresh);
1677 if (kcd->ignore_vert_snapping)
1680 f = knife_find_closest_face(kcd, co, cageco, is_space);
1682 /* set p to co, in case we don't find anything, means a face cut */
1684 copy_v3_v3(cagep, p);
1685 kcd->curr.bmface = f;
1690 KnifeVert *curv = NULL;
1691 float dis, curdis = FLT_MAX;
1693 knife_project_v3(kcd, cageco, sco);
1695 lst = knife_get_face_kedges(kcd, f);
1696 for (ref = lst->first; ref; ref = ref->next) {
1697 KnifeEdge *kfe = ref->ref;
1700 for (i = 0; i < 2; i++) {
1701 KnifeVert *kfv = i ? kfe->v2 : kfe->v1;
1703 knife_project_v3(kcd, kfv->cageco, kfv->sco);
1705 dis = len_v2v2(kfv->sco, sco);
1706 if (dis < curdis && dis < maxdist) {
1707 if (kcd->vc.rv3d->rflag & RV3D_CLIPPING) {
1708 if (ED_view3d_clipping_test(kcd->vc.rv3d, kfv->cageco, TRUE) == 0) {
1721 if (!kcd->ignore_vert_snapping || !(curv && curv->v)) {
1726 copy_v3_v3(p, curv->co);
1727 copy_v3_v3(cagep, curv->cageco);
1729 /* update mouse coordinates to the snapped-to vertex's screen coordinates
1730 * this is important for angle snap, which uses the previous mouse position */
1731 kcd->curr.mval[0] = curv->sco[0];
1732 kcd->curr.mval[1] = curv->sco[1];
1751 /* update both kcd->curr.mval and kcd->mval to snap to required angle */
1752 static void knife_snap_angle(KnifeTool_OpData *kcd)
1757 dx = kcd->curr.mval[0] - kcd->prev.mval[0];
1758 dy = kcd->curr.mval[1] - kcd->prev.mval[1];
1759 if (dx == 0.0f && dy == 0.0f)
1763 kcd->angle_snapping = ANGLE_90;
1764 kcd->curr.mval[0] = kcd->prev.mval[0];
1769 if (abs_tan <= 0.4142f) { /* tan(22.5 degrees) = 0.4142 */
1770 kcd->angle_snapping = ANGLE_0;
1771 kcd->curr.mval[1] = kcd->prev.mval[1];
1773 else if (abs_tan < 2.4142f) { /* tan(67.5 degrees) = 2.4142 */
1775 kcd->angle_snapping = ANGLE_45;
1776 kcd->curr.mval[1] = kcd->prev.mval[1] + dx;
1779 kcd->angle_snapping = ANGLE_135;
1780 kcd->curr.mval[1] = kcd->prev.mval[1] - dx;
1784 kcd->angle_snapping = ANGLE_90;
1785 kcd->curr.mval[0] = kcd->prev.mval[0];
1788 copy_v2_v2(kcd->mval, kcd->curr.mval);
1791 /* update active knife edge/vert pointers */
1792 static int knife_update_active(KnifeTool_OpData *kcd)
1794 knife_pos_data_clear(&kcd->curr);
1795 copy_v2_v2(kcd->curr.mval, kcd->mval);
1796 if (kcd->angle_snapping != ANGLE_FREE && kcd->mode == MODE_DRAGGING)
1797 knife_snap_angle(kcd);
1799 /* XXX knife_snap_angle updates the view coordinate mouse values to constrained angles,
1800 * which current mouse values are set to current mouse values are then used
1801 * for vertex and edge snap detection, without regard to the exact angle constraint */
1802 kcd->curr.vert = knife_find_closest_vert(kcd, kcd->curr.co, kcd->curr.cage, &kcd->curr.bmface, &kcd->curr.is_space);
1804 if (!kcd->curr.vert) {
1805 kcd->curr.edge = knife_find_closest_edge(kcd, kcd->curr.co, kcd->curr.cage, &kcd->curr.bmface, &kcd->curr.is_space);
1808 /* if no hits are found this would normally default to (0, 0, 0) so instead
1809 * get a point at the mouse ray closest to the previous point.
1810 * Note that drawing lines in `free-space` isn't properly supported
1811 * but theres no guarantee (0, 0, 0) has any geometry either - campbell */
1812 if (kcd->curr.vert == NULL && kcd->curr.edge == NULL) {
1814 float origin_ofs[3];
1816 knife_input_ray_segment(kcd, kcd->curr.mval, 1.0f, origin, origin_ofs);
1818 closest_to_line_v3(kcd->curr.cage, kcd->prev.cage, origin_ofs, origin);
1821 if (kcd->mode == MODE_DRAGGING) {
1822 knife_find_line_hits(kcd);
1827 #define SCANFILL_CUTS 0
1832 #define VERT_ON_EDGE 16
1833 #define VERT_ORIG 32
1834 #define FACE_FLIP 64
1835 #define BOUNDARY 128
1836 #define FACE_NEW 256
1838 typedef struct facenet_entry {
1839 struct facenet_entry *next, *prev;
1843 static void rnd_offset_co(float co[3], float scale)
1847 for (i = 0; i < 3; i++) {
1848 co[i] += (BLI_frand() - 0.5) * scale;
1852 static void remerge_faces(KnifeTool_OpData *kcd)
1854 BMesh *bm = kcd->em->bm;
1855 SmallHash svisit, *visit = &svisit;
1858 BMFace **stack = NULL;
1859 BLI_array_declare(stack);
1860 BMFace **faces = NULL;
1861 BLI_array_declare(faces);
1865 BMO_op_initf(bm, &bmop, "beautify_fill faces=%ff edges=%Fe", FACE_NEW, BOUNDARY);
1867 BMO_op_exec(bm, &bmop);
1868 BMO_slot_buffer_flag_enable(bm, &bmop, "geom.out", BM_FACE, FACE_NEW);
1870 BMO_op_finish(bm, &bmop);
1872 BLI_smallhash_init(visit);
1873 BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
1878 if (!BMO_elem_flag_test(bm, f, FACE_NEW))
1881 if (BLI_smallhash_haskey(visit, (intptr_t)f))
1884 BLI_array_empty(stack);
1885 BLI_array_empty(faces);
1886 BLI_array_append(stack, f);
1887 BLI_smallhash_insert(visit, (intptr_t)f, NULL);
1890 f2 = BLI_array_pop(stack);
1892 BLI_array_append(faces, f2);
1894 BM_ITER_ELEM (e, &eiter, f2, BM_EDGES_OF_FACE) {
1898 if (BMO_elem_flag_test(bm, e, BOUNDARY))
1901 BM_ITER_ELEM (f3, &fiter, e, BM_FACES_OF_EDGE) {
1902 if (!BMO_elem_flag_test(bm, f3, FACE_NEW))
1904 if (BLI_smallhash_haskey(visit, (intptr_t)f3))
1907 BLI_smallhash_insert(visit, (intptr_t)f3, NULL);
1908 BLI_array_append(stack, f3);
1911 } while (BLI_array_count(stack) > 0);
1913 if (BLI_array_count(faces) > 0) {
1914 idx = BM_elem_index_get(faces[0]);
1916 f2 = BM_faces_join(bm, faces, BLI_array_count(faces), TRUE);
1918 BMO_elem_flag_enable(bm, f2, FACE_NEW);
1919 BM_elem_index_set(f2, idx); /* set_dirty! *//* BMESH_TODO, check if this is valid or not */
1923 /* BMESH_TODO, check if the code above validates the indices */
1924 /* bm->elem_index_dirty &= ~BM_FACE; */
1925 bm->elem_index_dirty |= BM_FACE;
1927 BLI_smallhash_release(visit);
1929 BLI_array_free(stack);
1930 BLI_array_free(faces);
1933 /* use edgenet to fill faces. this is a bit annoying and convoluted.*/
1934 static void knifenet_fill_faces(KnifeTool_OpData *kcd)
1936 ScanFillContext sf_ctx;
1937 BMesh *bm = kcd->em->bm;
1939 BLI_mempool_iter iter;
1944 facenet_entry *entry;
1945 ListBase *face_nets = MEM_callocN(sizeof(ListBase) * bm->totface, "face_nets");
1946 BMFace **faces = MEM_callocN(sizeof(BMFace *) * bm->totface, "faces knife");
1947 MemArena *arena = BLI_memarena_new(1 << 16, "knifenet_fill_faces");
1949 int i, j, k = 0, totface = bm->totface;
1952 bmesh_edit_begin(bm, BMO_OP_FLAG_UNTAN_MULTIRES);
1954 /* BMESH_TODO this should be valid now, leaving here until we can ensure this - campbell */
1956 BM_ITER_MESH (f, &bmiter, bm, BM_FACES_OF_MESH) {
1957 BM_elem_index_set(f, i); /* set_inline */
1961 bm->elem_index_dirty &= ~BM_FACE;
1963 BM_ITER_MESH (e, &bmiter, bm, BM_EDGES_OF_MESH) {
1964 BMO_elem_flag_enable(bm, e, BOUNDARY);
1967 /* turn knife verts into real verts, as necessary */
1968 BLI_mempool_iternew(kcd->kverts, &iter);
1969 for (kfv = BLI_mempool_iterstep(&iter); kfv; kfv = BLI_mempool_iterstep(&iter)) {
1971 /* shouldn't we be at least copying the normal? - if not some comment here should explain why - campbell */
1972 kfv->v = BM_vert_create(bm, kfv->co, NULL);
1974 BMO_elem_flag_enable(bm, kfv->v, DEL);
1978 BMO_elem_flag_enable(bm, kfv->v, VERT_ORIG);
1981 BMO_elem_flag_enable(bm, kfv->v, MARK);
1984 /* we want to only do changed faces. first, go over new edges and add to
1987 BLI_mempool_iternew(kcd->kedges, &iter);
1988 for (kfe = BLI_mempool_iterstep(&iter); kfe; kfe = BLI_mempool_iterstep(&iter)) {
1990 if (!kfe->v1 || !kfe->v2 || kfe->v1->inspace || kfe->v2->inspace)
1995 if (kfe->e && kfe->v1->v == kfe->e->v1 && kfe->v2->v == kfe->e->v2) {
1996 kfe->e_old = kfe->e;
2003 kfe->e_old = kfe->e;
2005 BMO_elem_flag_enable(bm, kfe->e, DEL);
2006 BMO_elem_flag_disable(bm, kfe->e, BOUNDARY);
2010 kfe->e = BM_edge_create(bm, kfe->v1->v, kfe->v2->v, NULL, BM_CREATE_NO_DOUBLE);
2011 BMO_elem_flag_enable(bm, kfe->e, BOUNDARY);
2013 for (ref = kfe->faces.first; ref; ref = ref->next) {
2016 entry = BLI_memarena_alloc(arena, sizeof(*entry));
2018 BLI_addtail(face_nets + BM_elem_index_get(f), entry);
2022 /* go over original edges, and add to faces with new geometry */
2023 BLI_mempool_iternew(kcd->kedges, &iter);
2024 for (kfe = BLI_mempool_iterstep(&iter); kfe; kfe = BLI_mempool_iterstep(&iter)) {
2027 if (!kfe->v1 || !kfe->v2 || kfe->v1->inspace || kfe->v2->inspace)
2029 if (!(kfe->e_old && kfe->v1->v == kfe->e_old->v1 && kfe->v2->v == kfe->e_old->v2))
2034 BMO_elem_flag_enable(bm, kfe->e, BOUNDARY);
2035 kfe->e_old = kfe->e;
2037 for (ref = kfe->faces.first; ref; ref = ref->next) {
2040 if (face_nets[BM_elem_index_get(f)].first) {
2041 entry = BLI_memarena_alloc(arena, sizeof(*entry));
2043 BLI_addtail(face_nets + BM_elem_index_get(f), entry);
2050 for (i = 0; i < totface; i++) {
2051 SmallHash *hash = &shash;
2052 ScanFillFace *sf_tri;
2053 ScanFillVert *sf_vert, *sf_vert_last;
2055 float rndscale = (KNIFE_FLT_EPS / 4.0f);
2058 BLI_smallhash_init(hash);
2060 if (face_nets[i].first)
2061 BMO_elem_flag_enable(bm, f, DEL);
2063 BLI_scanfill_begin(&sf_ctx);
2065 for (entry = face_nets[i].first; entry; entry = entry->next) {
2066 if (!BLI_smallhash_haskey(hash, (intptr_t)entry->kfe->v1)) {
2067 sf_vert = BLI_scanfill_vert_add(&sf_ctx, entry->kfe->v1->v->co);
2068 sf_vert->poly_nr = 0;
2069 rnd_offset_co(sf_vert->co, rndscale);
2070 sf_vert->tmp.p = entry->kfe->v1->v;
2071 BLI_smallhash_insert(hash, (intptr_t)entry->kfe->v1, sf_vert);
2074 if (!BLI_smallhash_haskey(hash, (intptr_t)entry->kfe->v2)) {
2075 sf_vert = BLI_scanfill_vert_add(&sf_ctx, entry->kfe->v2->v->co);
2076 sf_vert->poly_nr = 0;
2077 rnd_offset_co(sf_vert->co, rndscale);
2078 sf_vert->tmp.p = entry->kfe->v2->v;
2079 BLI_smallhash_insert(hash, (intptr_t)entry->kfe->v2, sf_vert);
2083 for (j = 0, entry = face_nets[i].first; entry; entry = entry->next, j++) {
2084 sf_vert_last = BLI_smallhash_lookup(hash, (intptr_t)entry->kfe->v1);
2085 sf_vert = BLI_smallhash_lookup(hash, (intptr_t)entry->kfe->v2);
2088 sf_vert_last->poly_nr++;
2091 for (j = 0, entry = face_nets[i].first; entry; entry = entry->next, j++) {
2092 sf_vert_last = BLI_smallhash_lookup(hash, (intptr_t)entry->kfe->v1);
2093 sf_vert = BLI_smallhash_lookup(hash, (intptr_t)entry->kfe->v2);
2095 if (sf_vert->poly_nr > 1 && sf_vert_last->poly_nr > 1) {
2096 ScanFillEdge *sf_edge;
2097 sf_edge = BLI_scanfill_edge_add(&sf_ctx, sf_vert_last, sf_vert);
2098 if (entry->kfe->e_old)
2099 sf_edge->f = SF_EDGE_BOUNDARY; /* mark as original boundary edge */
2101 BMO_elem_flag_disable(bm, entry->kfe->e->v1, DEL);
2102 BMO_elem_flag_disable(bm, entry->kfe->e->v2, DEL);
2105 if (sf_vert_last->poly_nr < 2)
2106 BLI_remlink(&sf_ctx.fillvertbase, sf_vert_last);
2107 if (sf_vert->poly_nr < 2)
2108 BLI_remlink(&sf_ctx.fillvertbase, sf_vert);
2112 BLI_scanfill_calc(&sf_ctx, 0);
2114 for (sf_tri = sf_ctx.fillfacebase.first; sf_tri; sf_tri = sf_tri->next) {
2115 BMVert *v1 = sf_tri->v3->tmp.p, *v2 = sf_tri->v2->tmp.p, *v3 = sf_tri->v1->tmp.p;
2118 BMVert *verts[3] = {v1, v2, v3};
2120 if (v1 == v2 || v2 == v3 || v1 == v3)
2122 if (BM_face_exists(bm, verts, 3, &f2))
2125 f2 = BM_face_create_quad_tri(bm,
2129 BMO_elem_flag_enable(bm, f2, FACE_NEW);
2131 l_iter = BM_FACE_FIRST_LOOP(f2);
2133 BMO_elem_flag_disable(bm, l_iter->e, DEL);
2134 } while ((l_iter = l_iter->next) != BM_FACE_FIRST_LOOP(f2));
2136 BMO_elem_flag_disable(bm, f2, DEL);
2137 BM_elem_index_set(f2, i); /* set_dirty! *//* note, not 100% sure this is dirty? need to check */
2139 BM_face_normal_update(f2);
2140 if (dot_v3v3(f->no, f2->no) < 0.0f) {
2141 BM_face_normal_flip(bm, f2);
2145 BLI_scanfill_end(&sf_ctx);
2146 BLI_smallhash_release(hash);
2148 bm->elem_index_dirty |= BM_FACE;
2150 /* interpolate customdata */
2151 BM_ITER_MESH (f, &bmiter, bm, BM_FACES_OF_MESH) {
2156 if (!BMO_elem_flag_test(bm, f, FACE_NEW))
2159 f2 = faces[BM_elem_index_get(f)];
2160 if (BM_elem_index_get(f) < 0 || BM_elem_index_get(f) >= totface) {
2161 fprintf(stderr, "%s: face index out of range! (bmesh internal error)\n", __func__);
2164 BM_elem_attrs_copy(bm, bm, f2, f);
2166 BM_ITER_ELEM (l1, &liter1, f, BM_LOOPS_OF_FACE) {
2167 BM_loop_interp_from_face(bm, l1, f2, TRUE, TRUE);
2171 /* merge triangles back into faces */
2174 /* delete left over faces */
2175 BMO_op_callf(bm, BMO_FLAG_DEFAULTS, "delete geom=%ff context=%i", DEL, DEL_ONLYFACES);
2176 BMO_op_callf(bm, BMO_FLAG_DEFAULTS, "delete geom=%fe context=%i", DEL, DEL_EDGES);
2177 BMO_op_callf(bm, BMO_FLAG_DEFAULTS, "delete geom=%fv context=%i", DEL, DEL_VERTS);
2180 MEM_freeN(face_nets);
2183 BLI_memarena_free(arena);
2185 BMO_error_clear(bm); /* remerge_faces sometimes raises errors, so make sure to clear them */
2187 bmesh_edit_end(bm, BMO_OP_FLAG_UNTAN_MULTIRES);
2191 #else /* use direct (non-scanfill) method for cuts */
2193 /* assuming v is on line ab, what fraction of the way is v from a to b? */
2194 static float frac_along(const float a[3], const float b[3], const float v[3])
2198 lab = len_v3v3(a, b);
2203 return len_v3v3(a, v) / lab;
2207 /* sort list of kverts by fraction along edge e */
2208 static void sort_by_frac_along(ListBase *lst, BMEdge *e)
2210 KnifeVert *vcur, *vprev;
2212 Ref *cur = NULL, *prev = NULL, *next = NULL;
2214 if (lst->first == lst->last)
2220 for (cur = ((Ref *)lst->first)->next; cur; cur = next) {
2224 BLI_remlink(lst, cur);
2229 if (frac_along(v1co, v2co, vprev->co) <= frac_along(v1co, v2co, vcur->co))
2234 BLI_insertlinkafter(lst, prev, cur);
2238 /* The chain so far goes from an instantiated vertex to kfv (some may be reversed).
2239 * If possible, complete the chain to another instantiated vertex and return 1, else return 0.
2240 * The visited hash says which KnifeVert's have already been tried, not including kfv. */
2241 static int find_chain_search(KnifeTool_OpData *kcd, KnifeVert *kfv, ListBase *fedges, SmallHash *visited,
2246 KnifeVert *kfv_other;
2251 BLI_smallhash_insert(visited, (uintptr_t)kfv, NULL);
2252 /* Try all possible next edges. Could either go through fedges
2253 * (all the KnifeEdges for the face being cut) or could go through
2254 * kve->edges and restrict to cutting face and uninstantiated edges.
2255 * Not clear which is better. Let's do the first. */
2256 for (r = fedges->first; r; r = r->next) {
2260 kfv_other = kfe->v2;
2261 else if (kfe->v2 == kfv)
2262 kfv_other = kfe->v1;
2263 if (kfv_other && !BLI_smallhash_haskey(visited, (uintptr_t)kfv_other)) {
2264 knife_append_list(kcd, chain, kfe);
2265 if (find_chain_search(kcd, kfv_other, fedges, visited, chain))
2267 BLI_remlink(chain, chain->last);
2273 static ListBase *find_chain_from_vertex(KnifeTool_OpData *kcd, KnifeEdge *kfe, BMVert *v, ListBase *fedges)
2275 SmallHash visited_, *visited = &visited_;
2279 ans = knife_empty_list(kcd);
2280 knife_append_list(kcd, ans, kfe);
2282 BLI_smallhash_init(visited);
2283 if (kfe->v1->v == v) {
2284 BLI_smallhash_insert(visited, (uintptr_t)(kfe->v1), NULL);
2285 found = find_chain_search(kcd, kfe->v2, fedges, visited, ans);
2288 BLI_assert(kfe->v2->v == v);
2289 BLI_smallhash_insert(visited, (uintptr_t)(kfe->v2), NULL);
2290 found = find_chain_search(kcd, kfe->v1, fedges, visited, ans);
2293 BLI_smallhash_release(visited);
2301 /* Find a chain in fedges from one instantiated vertex to another.
2302 * Remove the edges in the chain from fedges and return a separate list of the chain. */
2303 static ListBase *find_chain(KnifeTool_OpData *kcd, ListBase *fedges)
2312 for (r = fedges->first; r; r = r->next) {
2317 ans = knife_empty_list(kcd);
2318 knife_append_list(kcd, ans, kfe);
2322 ans = find_chain_from_vertex(kcd, kfe, v1, fedges);
2324 ans = find_chain_from_vertex(kcd, kfe, v2, fedges);
2329 BLI_assert(BLI_countlist(ans) > 0);
2330 for (r = ans->first; r; r = r->next) {
2331 ref = find_ref(fedges, r->ref);
2332 BLI_assert(ref != NULL);
2333 BLI_remlink(fedges, ref);
2339 /* The hole so far goes from kfvfirst to kfv (some may be reversed).
2340 * If possible, complete the hole back to kfvfirst and return 1, else return 0.
2341 * The visited hash says which KnifeVert's have already been tried, not including kfv or kfvfirst. */
2342 static int find_hole_search(KnifeTool_OpData *kcd, KnifeVert *kfvfirst, KnifeVert *kfv, ListBase *fedges,
2343 SmallHash *visited, ListBase *hole)
2346 KnifeEdge *kfe, *kfelast;
2347 KnifeVert *kfv_other;
2349 if (kfv == kfvfirst)
2352 BLI_smallhash_insert(visited, (uintptr_t)kfv, NULL);
2353 kfelast = ((Ref *)hole->last)->ref;
2354 for (r = fedges->first; r; r = r->next) {
2358 if (kfe->v1->v || kfe->v2->v)
2362 kfv_other = kfe->v2;
2363 else if (kfe->v2 == kfv)
2364 kfv_other = kfe->v1;
2365 if (kfv_other && !BLI_smallhash_haskey(visited, (uintptr_t)kfv_other)) {
2366 knife_append_list(kcd, hole, kfe);
2367 if (find_hole_search(kcd, kfvfirst, kfv_other, fedges, visited, hole))
2369 BLI_remlink(hole, hole->last);
2375 /* Find a hole (simple cycle with no instantiated vertices).
2376 * Remove the edges in the cycle from fedges and return a separate list of the cycle */
2377 static ListBase *find_hole(KnifeTool_OpData *kcd, ListBase *fedges)
2382 SmallHash visited_, *visited = &visited_;
2388 for (r = fedges->first; r && !found; r = r->next) {
2390 if (kfe->v1->v || kfe->v2->v || kfe->v1 == kfe->v2)
2393 BLI_smallhash_init(visited);
2394 ans = knife_empty_list(kcd);
2395 knife_append_list(kcd, ans, kfe);
2397 found = find_hole_search(kcd, kfe->v1, kfe->v2, fedges, visited, ans);
2399 BLI_smallhash_release(visited);
2403 for (r = ans->first; r; r = r->next) {
2405 ref = find_ref(fedges, r->ref);
2407 BLI_remlink(fedges, ref);
2416 /* Try to find "nice" diagonals - short, and far apart from each other.
2417 * If found, return TRUE and make a 'main chain' going across f which uses
2418 * the two diagonals and one part of the hole, and a 'side chain' that
2419 * completes the hole. */
2420 static int find_hole_chains(KnifeTool_OpData *kcd, ListBase *hole, BMFace *f, ListBase **mainchain,
2421 ListBase **sidechain)
2428 KnifeVert *kfv, *kfvother;
2433 int nh, nf, i, j, k, m, ax, ay, ok, sep = 0 /* Quite warnings */, bestsep;
2434 int besti[2], bestj[2];
2437 nh = BLI_countlist(hole);
2439 if (nh < 2 || nf < 3)
2442 /* Gather 2d projections of hole and face vertex coordinates.
2443 * Use best-axis projection - not completely accurate, maybe revisit */
2444 axis_dominant_v3(&ax, &ay, f->no);
2445 hco = BLI_memarena_alloc(kcd->arena, nh * sizeof(float *));
2446 fco = BLI_memarena_alloc(kcd->arena, nf * sizeof(float *));
2447 hv = BLI_memarena_alloc(kcd->arena, nh * sizeof(KnifeVert *));
2448 fv = BLI_memarena_alloc(kcd->arena, nf * sizeof(BMVert *));
2449 he = BLI_memarena_alloc(kcd->arena, nh * sizeof(KnifeEdge *));
2454 for (r = hole->first; r; r = r->next) {
2457 if (kfvother == NULL) {
2462 BLI_assert(kfv == kfe->v1 || kfv == kfe->v2);
2464 hco[i] = BLI_memarena_alloc(kcd->arena, 2 * sizeof(float));
2465 hco[i][0] = kfv->co[ax];
2466 hco[i][1] = kfv->co[ay];
2468 kfvother = (kfe->v1 == kfv) ? kfe->v2 : kfe->v1;
2473 BM_ITER_ELEM (v, &iter, f, BM_VERTS_OF_FACE) {
2474 fco[j] = BLI_memarena_alloc(kcd->arena, 2 * sizeof(float));
2475 fco[j][0] = v->co[ax];
2476 fco[j][1] = v->co[ay];
2481 /* For first diagonal (m == 0), want shortest length.
2482 * For second diagonal (m == 1), want max separation of index of hole
2483 * vertex from the hole vertex used in the first diagonal, and from there
2484 * want the one with shortest length not to the same vertex as the first diagonal. */
2485 for (m = 0; m < 2; m++) {
2490 for (i = 0; i < nh; i++) {
2494 sep = (i + nh - besti[0]) % nh;
2495 sep = MIN2(sep, nh - sep);
2500 for (j = 0; j < nf; j++) {
2501 if (m == 1 && j == bestj[0])
2503 d = len_squared_v2v2(hco[i], fco[j]);
2508 for (k = 0; k < nh && ok; k++) {
2509 if (k == i || (k + 1) % nh == i)
2511 if (isect_line_line_v2(hco[i], fco[j], hco[k], hco[(k + 1) % nh]))
2516 for (k = 0; k < nf && ok; k++) {
2517 if (k == j || (k + 1) % nf == j)
2519 if (isect_line_line_v2(hco[i], fco[j], fco[k], fco[(k + 1) % nf]))
2533 if (besti[0] != -1 && besti[1] != -1) {
2534 BLI_assert(besti[0] != besti[1] && bestj[0] != bestj[1]);
2535 kfe = new_knife_edge(kcd);
2536 kfe->v1 = get_bm_knife_vert(kcd, fv[bestj[0]]);
2537 kfe->v2 = hv[besti[0]];
2538 chain = knife_empty_list(kcd);
2539 knife_append_list(kcd, chain, kfe);
2540 for (i = besti[0]; i != besti[1]; i = (i + 1) % nh) {
2541 knife_append_list(kcd, chain, he[i]);
2543 kfe = new_knife_edge(kcd);
2544 kfe->v1 = hv[besti[1]];
2545 kfe->v2 = get_bm_knife_vert(kcd, fv[bestj[1]]);
2546 knife_append_list(kcd, chain, kfe);
2549 chain = knife_empty_list(kcd);
2550 for (i = besti[1]; i != besti[0]; i = (i + 1) % nh) {
2551 knife_append_list(kcd, chain, he[i]);
2562 static int knife_edge_in_face(KnifeTool_OpData *UNUSED(kcd), KnifeEdge *kfe, BMFace *f)
2564 /* BMesh *bm = kcd->em->bm; */ /* UNUSED */
2566 BMLoop *l1, *l2, *l;
2569 int v1inside, v2inside;
2579 /* find out if v1 and v2, if set, are part of the face */
2580 BM_ITER_ELEM (l, &iter, f, BM_LOOPS_OF_FACE) {
2581 if (v1 && l->v == v1)
2583 if (v2 && l->v == v2)
2587 /* BM_face_point_inside_test uses best-axis projection so this isn't most accurate test... */
2588 v1inside = l1 ? 0 : BM_face_point_inside_test(f, kfe->v1->co);
2589 v2inside = l2 ? 0 : BM_face_point_inside_test(f, kfe->v2->co);
2590 if ((l1 && v2inside) || (l2 && v1inside) || (v1inside && v2inside))
2593 /* Can have case where v1 and v2 are on shared chain between two faces.
2594 * BM_face_legal_splits does visibility and self-intersection tests,
2595 * but it is expensive and maybe a bit buggy, so use a simple
2596 * "is the midpoint in the face" test */
2597 mid_v3_v3v3(mid, kfe->v1->co, kfe->v2->co);
2598 return BM_face_point_inside_test(f, mid);
2603 /* Split face f with KnifeEdges on chain. f remains as one side, the face formed is put in *newface.
2604 * The new face will be on the left side of the chain as viewed from the normal-out side of f. */
2605 static void knife_make_chain_cut(KnifeTool_OpData *kcd, BMFace *f, ListBase *chain, BMFace **newface)
2607 BMesh *bm = kcd->em->bm;
2608 KnifeEdge *kfe, *kfelast;
2612 KnifeVert *kfv, *kfvprev;
2613 BMLoop *lnew, *l_iter;
2615 int nco = BLI_countlist(chain) - 1;
2616 float (*cos)[3] = BLI_array_alloca(cos, nco);
2617 KnifeVert **kverts = BLI_array_alloca(kverts, nco);
2619 kfe = ((Ref *)chain->first)->ref;
2620 v1 = kfe->v1->v ? kfe->v1->v : kfe->v2->v;
2621 kfelast = ((Ref *)chain->last)->ref;
2622 v2 = kfelast->v2->v ? kfelast->v2->v : kfelast->v1->v;
2623 BLI_assert(v1 != NULL && v2 != NULL);
2624 kfvprev = kfe->v1->v == v1 ? kfe->v1 : kfe->v2;
2625 for (ref = chain->first, i = 0; i < nco && ref != chain->last; ref = ref->next, i++) {
2627 BLI_assert(kfvprev == kfe->v1 || kfvprev == kfe->v2);
2628 kfv = kfe->v1 == kfvprev ? kfe->v2 : kfe->v1;
2629 copy_v3_v3(cos[i], kfv->co);
2633 BLI_assert(i == nco);
2636 /* Want to prevent creating two-sided polygons */
2637 if (BM_edge_exists(v1, v2)) {
2641 *newface = BM_face_split(bm, f, v1, v2, &lnew, NULL, TRUE);
2645 fnew = BM_face_split_n(bm, f, v1, v2, cos, nco, &lnew, NULL);
2649 /* Now go through lnew chain matching up chain kv's and assign real v's to them */
2650 for (l_iter = lnew->next, i = 0; i < nco; l_iter = l_iter->next, i++) {
2651 BLI_assert(equals_v3v3(cos[i], l_iter->v->co));
2652 if (kcd->select_result) {
2653 BM_edge_select_set(bm, l_iter->e, TRUE);
2655 kverts[i]->v = l_iter->v;
2660 /* the select chain above doesnt account for the first loop */
2661 if (kcd->select_result) {
2663 BM_edge_select_set(bm, lnew->e, TRUE);
2668 static void knife_make_face_cuts(KnifeTool_OpData *kcd, BMFace *f, ListBase *kfedges)
2670 BMesh *bm = kcd->em->bm;
2672 BMFace *fnew, *fnew2, *fhole;
2673 ListBase *chain, *hole, *sidechain;
2674 ListBase *fnew_kfedges, *fnew2_kfedges;
2676 int count, oldcount;
2678 oldcount = BLI_countlist(kfedges);
2679 while ((chain = find_chain(kcd, kfedges)) != NULL) {
2680 knife_make_chain_cut(kcd, f, chain, &fnew);
2685 /* Move kfedges to fnew_kfedges if they are now in fnew.
2686 * The chain edges were removed already */
2687 fnew_kfedges = knife_empty_list(kcd);
2688 for (ref = kfedges->first; ref; ref = refnext) {
2690 refnext = ref->next;
2691 if (knife_edge_in_face(kcd, kfe, fnew)) {
2692 BLI_remlink(kfedges, ref);
2694 knife_append_list(kcd, fnew_kfedges, kfe);
2697 if (fnew_kfedges->first)
2698 knife_make_face_cuts(kcd, fnew, fnew_kfedges);
2700 /* find_chain should always remove edges if it returns TRUE,
2701 * but guard against infinite loop anyway */
2702 count = BLI_countlist(kfedges);
2703 if (count >= oldcount) {
2704 BLI_assert(!"knife find_chain infinite loop");
2710 while ((hole = find_hole(kcd, kfedges)) != NULL) {
2711 if (find_hole_chains(kcd, hole, f, &chain, &sidechain)) {
2712 /* chain goes across f and sidechain comes back
2713 * from the second last vertex to the second vertex.
2715 knife_make_chain_cut(kcd, f, chain, &fnew);
2717 BLI_assert(!"knife failed hole cut");
2720 kfe = ((Ref *)sidechain->first)->ref;
2721 if (knife_edge_in_face(kcd, kfe, f)) {
2722 knife_make_chain_cut(kcd, f, sidechain, &fnew2);
2725 else if (knife_edge_in_face(kcd, kfe, fnew)) {
2726 knife_make_chain_cut(kcd, fnew, sidechain, &fnew2);
2730 /* shouldn't happen except in funny edge cases */
2733 BM_face_kill(bm, fhole);
2734 /* Move kfedges to either fnew or fnew2 if appropriate.
2735 * The hole edges were removed already */
2736 fnew_kfedges = knife_empty_list(kcd);
2737 fnew2_kfedges = knife_empty_list(kcd);
2738 for (ref = kfedges->first; ref; ref = refnext) {
2740 refnext = ref->next;
2741 if (knife_edge_in_face(kcd, kfe, fnew)) {
2742 BLI_remlink(kfedges, ref);
2744 knife_append_list(kcd, fnew_kfedges, kfe);
2746 else if (knife_edge_in_face(kcd, kfe, fnew2)) {
2747 BLI_remlink(kfedges, ref);
2749 knife_append_list(kcd, fnew2_kfedges, kfe);
2752 /* We'll skip knife edges that are in the newly formed hole.
2753 * (Maybe we shouldn't have made a hole in the first place?) */
2754 if (fnew != fhole && fnew_kfedges->first)
2755 knife_make_face_cuts(kcd, fnew, fnew_kfedges);
2756 if (fnew2 != fhole && fnew2_kfedges->first)
2757 knife_make_face_cuts(kcd, fnew2, fnew2_kfedges);
2760 /* find_hole should always remove edges if it returns TRUE,
2761 * but guard against infinite loop anyway */
2762 count = BLI_countlist(kfedges);
2763 if (count >= oldcount) {
2764 BLI_assert(!"knife find_hole infinite loop");
2772 /* Use the network of KnifeEdges and KnifeVerts accumulated to make real BMVerts and BMEdedges */
2773 static void knife_make_cuts(KnifeTool_OpData *kcd)
2775 BMesh *bm = kcd->em->bm;
2783 SmallHashIter hiter;
2784 BLI_mempool_iter iter;
2785 SmallHash fhash_, *fhash = &fhash_;
2786 SmallHash ehash_, *ehash = &ehash_;
2788 BLI_smallhash_init(fhash);
2789 BLI_smallhash_init(ehash);
2791 /* put list of cutting edges for a face into fhash, keyed by face */
2792 BLI_mempool_iternew(kcd->kedges, &iter);
2793 for (kfe = BLI_mempool_iterstep(&iter); kfe; kfe = BLI_mempool_iterstep(&iter)) {
2797 lst = BLI_smallhash_lookup(fhash, (uintptr_t)f);
2799 lst = knife_empty_list(kcd);
2800 BLI_smallhash_insert(fhash, (uintptr_t)f, lst);
2802 knife_append_list(kcd, lst, kfe);
2805 /* put list of splitting vertices for an edge into ehash, keyed by edge */
2806 BLI_mempool_iternew(kcd->kverts, &iter);
2807 for (kfv = BLI_mempool_iterstep(&iter); kfv; kfv = BLI_mempool_iterstep(&iter)) {
2809 continue; /* already have a BMVert */
2810 for (ref = kfv->edges.first; ref; ref = ref->next) {
2815 lst = BLI_smallhash_lookup(ehash, (uintptr_t)e);
2817 lst = knife_empty_list(kcd);
2818 BLI_smallhash_insert(ehash, (uintptr_t)e, lst);
2820 /* there can be more than one kfe in kfv's list with same e */
2821 if (!find_ref(lst, kfv))
2822 knife_append_list(kcd, lst, kfv);
2826 /* split bmesh edges where needed */
2827 for (lst = BLI_smallhash_iternew(ehash, &hiter, (uintptr_t *)&e); lst;
2828 lst = BLI_smallhash_iternext(&hiter, (uintptr_t *)&e))
2830 sort_by_frac_along(lst, e);
2831 for (ref = lst->first; ref; ref = ref->next) {
2833 pct = frac_along(e->v1->co, e->v2->co, kfv->co);
2834 kfv->v = BM_edge_split(bm, e, e->v1, &enew, pct);
2838 if (kcd->only_select) {
2839 EDBM_flag_disable_all(kcd->em, BM_ELEM_SELECT);
2842 /* do cuts for each face */
2843 for (lst = BLI_smallhash_iternew(fhash, &hiter, (uintptr_t *)&f); lst;
2844 lst = BLI_smallhash_iternext(&hiter, (uintptr_t *)&f))
2846 knife_make_face_cuts(kcd, f, lst);
2849 BLI_smallhash_release(fhash);
2850 BLI_smallhash_release(ehash);
2854 /* called on tool confirmation */
2855 static void knifetool_finish_ex(KnifeTool_OpData *kcd)
2858 knifenet_fill_faces(kcd);
2860 knife_make_cuts(kcd);
2863 EDBM_mesh_normals_update(kcd->em);
2864 EDBM_update_generic(kcd->em, TRUE, TRUE);
2866 static void knifetool_finish(wmOperator *op)
2868 KnifeTool_OpData *kcd = op->customdata;
2869 knifetool_finish_ex(kcd);
2872 static void knife_recalc_projmat(KnifeTool_OpData *kcd)
2874 invert_m4_m4(kcd->ob->imat, kcd->ob->obmat);
2875 ED_view3d_ob_project_mat_get(kcd->ar->regiondata, kcd->ob, kcd->projmat);
2876 //mult_m4_m4m4(kcd->projmat, kcd->vc.rv3d->winmat, kcd->vc.rv3d->viewmat);
2878 kcd->is_ortho = ED_view3d_clip_range_get(kcd->vc.v3d, kcd->vc.rv3d,
2879 &kcd->clipsta, &kcd->clipend, true);
2882 /* called when modal loop selection is done... */
2883 static void knifetool_exit_ex(bContext *C, KnifeTool_OpData *kcd)
2888 WM_cursor_restore(CTX_wm_window(C));
2890 /* deactivate the extra drawing stuff in 3D-View */
2891 ED_region_draw_cb_exit(kcd->ar->type, kcd->draw_handle);
2893 /* free the custom data */
2894 BLI_mempool_destroy(kcd->refs);
2895 BLI_mempool_destroy(kcd->kverts);
2896 BLI_mempool_destroy(kcd->kedges);
2898 BLI_ghash_free(kcd->origedgemap, NULL, NULL);
2899 BLI_ghash_free(kcd->origvertmap, NULL, NULL);
2900 BLI_ghash_free(kcd->kedgefacemap, NULL, NULL);
2902 BMBVH_FreeBVH(kcd->bmbvh);
2903 BLI_memarena_free(kcd->arena);
2905 /* tag for redraw */
2906 ED_region_tag_redraw(kcd->ar);
2909 MEM_freeN(kcd->cagecos);
2912 MEM_freeN(kcd->linehits);
2914 /* destroy kcd itself */
2917 static void knifetool_exit(bContext *C, wmOperator *op)
2919 KnifeTool_OpData *kcd = op->customdata;
2920 knifetool_exit_ex(C, kcd);
2921 op->customdata = NULL;
2924 static void cage_mapped_verts_callback(void *userData, int index, const float co[3],
2925 const float UNUSED(no_f[3]), const short UNUSED(no_s[3]))
2927 void **data = userData;
2928 BMEditMesh *em = data[0];
2929 float (*cagecos)[3] = data[1];
2930 SmallHash *hash = data[2];
2932 if (index >= 0 && index < em->bm->totvert && !BLI_smallhash_haskey(hash, index)) {
2933 BLI_smallhash_insert(hash, index, NULL);
2934 copy_v3_v3(cagecos[index], co);
2938 static void knifetool_update_mval(KnifeTool_OpData *kcd, const float mval[2])
2940 knife_recalc_projmat(kcd);
2941 copy_v2_v2(kcd->mval, mval);
2943 if (knife_update_active(kcd)) {
2944 ED_region_tag_redraw(kcd->ar);
2948 static void knifetool_update_mval_i(KnifeTool_OpData *kcd, const int mval_i[2])
2950 float mval[2] = {UNPACK2(mval_i)};
2951 knifetool_update_mval(kcd, mval);
2954 /* called when modal loop selection gets set up... */
2955 static void knifetool_init(bContext *C, KnifeTool_OpData *kcd,
2956 const bool only_select, const bool cut_through)
2958 Scene *scene = CTX_data_scene(C);
2959 Object *obedit = CTX_data_edit_object(C);
2960 DerivedMesh *cage, *final;
2964 /* assign the drawing handle for drawing preview line... */
2966 kcd->ar = CTX_wm_region(C);
2967 kcd->draw_handle = ED_region_draw_cb_activate(kcd->ar->type, knifetool_draw, kcd, REGION_DRAW_POST_VIEW);
2968 em_setup_viewcontext(C, &kcd->vc);
2970 kcd->em = BMEdit_FromObject(kcd->ob);
2972 BM_mesh_elem_index_ensure(kcd->em->bm, BM_VERT);
2974 cage = editbmesh_get_derived_cage_and_final(scene, obedit, kcd->em, &final, CD_MASK_DERIVEDMESH);
2975 kcd->cagecos = MEM_callocN(sizeof(float) * 3 * kcd->em->bm->totvert, "knife cagecos");
2977 data[1] = kcd->cagecos;
2980 BLI_smallhash_init(&shash);
2981 cage->foreachMappedVert(cage, cage_mapped_verts_callback, data);
2982 BLI_smallhash_release(&shash);
2984 kcd->bmbvh = BMBVH_NewBVH(kcd->em,
2985 (BMBVH_USE_CAGE | BMBVH_RETURN_ORIG) |
2986 (only_select ? BMBVH_RESPECT_SELECT : BMBVH_RESPECT_HIDDEN),
2989 kcd->arena = BLI_memarena_new(1 << 15, "knife");
2990 kcd->vthresh = KMAXDIST - 1;
2991 kcd->ethresh = KMAXDIST;
2995 knife_recalc_projmat(kcd);
2997 ED_region_tag_redraw(kcd->ar);
2999 kcd->refs = BLI_mempool_create(sizeof(Ref), 1, 2048, 0);
3000 kcd->kverts = BLI_mempool_create(sizeof(KnifeVert), 1, 512, BLI_MEMPOOL_ALLOW_ITER);
3001 kcd->kedges = BLI_mempool_create(sizeof(KnifeEdge), 1, 512, BLI_MEMPOOL_ALLOW_ITER);
3003 kcd->origedgemap = BLI_ghash_ptr_new("knife origedgemap");
3004 kcd->origvertmap = BLI_ghash_ptr_new("knife origvertmap");
3005 kcd->kedgefacemap = BLI_ghash_ptr_new("knife origvertmap");
3007 /* cut all the way through the mesh if use_occlude_geometry button not pushed */
3008 kcd->cut_through = cut_through;
3009 kcd->only_select = only_select;
3011 /* can't usefully select resulting edges in face mode */
3012 kcd->select_result = (kcd->em->selectmode != SCE_SELECT_FACE);
3014 knife_pos_data_clear(&kcd->curr);
3015 knife_pos_data_clear(&kcd->prev);
3017 knife_init_colors(&kcd->colors);
3020 static int knifetool_cancel(bContext *C, wmOperator *op)
3022 /* this is just a wrapper around exit() */
3023 knifetool_exit(C, op);
3024 return OPERATOR_CANCELLED;
3027 static int knifetool_invoke(bContext *C, wmOperator *op, const wmEvent *event)
3029 const bool only_select = RNA_boolean_get(op->ptr, "only_selected");
3030 const bool cut_through = !RNA_boolean_get(op->ptr, "use_occlude_geometry");
3032 KnifeTool_OpData *kcd;
3034 view3d_operator_needs_opengl(C);
3036 /* alloc new customdata */
3037 kcd = op->customdata = MEM_callocN(sizeof(KnifeTool_OpData), __func__);
3039 knifetool_init(C, kcd, only_select, cut_through);
3041 /* add a modal handler for this operator - handles loop selection */
3042 WM_cursor_modal(CTX_wm_window(C), BC_KNIFECURSOR);
3043 WM_event_add_modal_handler(C, op);
3045 knifetool_update_mval_i(kcd, event->mval);
3047 knife_update_header(C, kcd);
3049 return OPERATOR_RUNNING_MODAL;
3053 KNF_MODAL_CANCEL = 1,
3055 KNF_MODAL_MIDPOINT_ON,
3056 KNF_MODAL_MIDPOINT_OFF,
3058 KNF_MODEL_IGNORE_SNAP_ON,
3059 KNF_MODEL_IGNORE_SNAP_OFF,