Blender  V2.93
editmesh_knife.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2007 Blender Foundation.
17  * All rights reserved.
18  */
19 
26 #ifdef _MSC_VER
27 # define _USE_MATH_DEFINES
28 #endif
29 
30 #include "MEM_guardedalloc.h"
31 
32 #include "BLI_alloca.h"
33 #include "BLI_array.h"
34 #include "BLI_linklist.h"
35 #include "BLI_listbase.h"
36 #include "BLI_math.h"
37 #include "BLI_memarena.h"
38 #include "BLI_smallhash.h"
39 #include "BLI_string.h"
40 
41 #include "BLT_translation.h"
42 
43 #include "BKE_bvhutils.h"
44 #include "BKE_context.h"
45 #include "BKE_editmesh.h"
46 #include "BKE_editmesh_bvh.h"
47 #include "BKE_report.h"
48 
49 #include "GPU_immediate.h"
50 #include "GPU_matrix.h"
51 #include "GPU_state.h"
52 
53 #include "ED_mesh.h"
54 #include "ED_screen.h"
55 #include "ED_space_api.h"
56 #include "ED_view3d.h"
57 
58 #include "WM_api.h"
59 #include "WM_types.h"
60 
61 #include "DNA_object_types.h"
62 
63 #include "UI_interface.h"
64 #include "UI_resources.h"
65 
66 #include "RNA_access.h"
67 #include "RNA_define.h"
68 
69 #include "DEG_depsgraph.h"
70 #include "DEG_depsgraph_query.h"
71 
72 #include "mesh_intern.h" /* own include */
73 
74 /* detect isolated holes and fill them */
75 #define USE_NET_ISLAND_CONNECT
76 
77 #define KMAXDIST (10 * U.dpi_fac) /* max mouse distance from edge before not detecting it */
78 
79 /* WARNING: knife float precision is fragile:
80  * be careful before making changes here see: (T43229, T42864, T42459, T41164).
81  */
82 #define KNIFE_FLT_EPS 0.00001f
83 #define KNIFE_FLT_EPS_SQUARED (KNIFE_FLT_EPS * KNIFE_FLT_EPS)
84 #define KNIFE_FLT_EPSBIG 0.0005f
85 
86 #define KNIFE_FLT_EPS_PX_VERT 0.5f
87 #define KNIFE_FLT_EPS_PX_EDGE 0.05f
88 #define KNIFE_FLT_EPS_PX_FACE 0.05f
89 
90 typedef struct KnifeColors {
91  uchar line[3];
92  uchar edge[3];
98 
99 /* knifetool operator */
100 typedef struct KnifeVert {
101  BMVert *v; /* non-NULL if this is an original vert */
104 
105  float co[3], cageco[3];
107  bool is_cut; /* along a cut created by user input (will draw too) */
109 
110 typedef struct Ref {
111  struct Ref *next, *prev;
112  void *ref;
113 } Ref;
114 
115 typedef struct KnifeEdge {
117  BMFace *basef; /* face to restrict face fill to */
119 
120  BMEdge *e /* , *e_old */; /* non-NULL if this is an original edge */
121  bool is_cut; /* along a cut created by user input (will draw too) */
123 
124 typedef struct KnifeLineHit {
125  float hit[3], cagehit[3];
126  float schit[2]; /* screen coordinates for cagehit */
127  float l; /* lambda along cut line */
128  float perc; /* lambda along hit line */
129  float m; /* depth front-to-back */
130 
131  /* Exactly one of kfe, v, or f should be non-NULL,
132  * saying whether cut line crosses and edge,
133  * is snapped to a vert, or is in the middle of some face. */
138 
139 typedef struct KnifePosData {
140  float co[3];
141  float cage[3];
142 
143  /* At most one of vert, edge, or bmface should be non-NULL,
144  * saying whether the point is snapped to a vertex, edge, or in a face.
145  * If none are set, this point is in space and is_space should be true. */
149 
151  bool is_space;
152 
153  float mval[2]; /* mouse screen position (may be non-integral if snapped to something) */
155 
156 /* struct for properties used while drawing */
157 typedef struct KnifeTool_OpData {
158  ARegion *region; /* region that knifetool was activated in */
159  void *draw_handle; /* for drawing preview loop */
160  ViewContext vc; /* note: _don't_ use 'mval', instead use the one we define below */
161  float mval[2]; /* mouse value with snapping applied */
162  // bContext *C;
163 
167 
169 
170  /* reused for edge-net filling */
171  struct {
172  /* cleared each use */
174 #ifdef USE_NET_ISLAND_CONNECT
175  MemArena *arena;
176 #endif
178 
183 
185 
188 
189  float vthresh;
190  float ethresh;
191 
192  /* used for drag-cutting */
195 
196  /* Data for mouse-position-derived data */
197  KnifePosData curr; /* current point under the cursor */
198  KnifePosData prev; /* last added cut (a line draws from the cursor to this) */
199  KnifePosData init; /* the first point in the cut-list, used for closing the loop */
200 
202  int totkedge;
204  int totkvert;
205 
207 
212  float ob_imat[4][4];
213 
214  float projmat[4][4];
215  float projmat_inv[4][4];
216  /* vector along view z axis (object space, normalized) */
217  float proj_zaxis[3];
218 
220 
221  /* run by the UI or not */
223 
224  /* Operator options. */
225  bool cut_through; /* preference, can be modified at runtime (that feature may go) */
226  bool only_select; /* set on initialization */
227  bool select_result; /* set on initialization */
228 
229  bool is_ortho;
232 
233  float clipsta, clipend;
234 
237 
238  int prevmode;
242 
243  /* use to check if we're currently dragging an angle snapped line */
246  float angle;
247 
248  const float (*cagecos)[3];
250 
251 enum {
264 };
265 
266 /* -------------------------------------------------------------------- */
271 {
272  float v1[3], v2[3];
273  float planes[4][4];
274 
276  (const float(*)[4])kcd->projmat, planes[2], planes[0], planes[3], planes[1], NULL, NULL);
277 
278  /* ray-cast all planes */
279  {
280  float ray_dir[3];
281  float ray_hit_best[2][3] = {{UNPACK3(kcd->prev.cage)}, {UNPACK3(kcd->curr.cage)}};
282  float lambda_best[2] = {-FLT_MAX, FLT_MAX};
283  int i;
284 
285  /* we (sometimes) need the lines to be at the same depth before projecting */
286 #if 0
287  sub_v3_v3v3(ray_dir, kcd->curr.cage, kcd->prev.cage);
288 #else
289  {
290  float curr_cage_adjust[3];
291  float co_depth[3];
292 
293  copy_v3_v3(co_depth, kcd->prev.cage);
294  mul_m4_v3(kcd->ob->obmat, co_depth);
295  ED_view3d_win_to_3d(kcd->vc.v3d, kcd->region, co_depth, kcd->curr.mval, curr_cage_adjust);
296  mul_m4_v3(kcd->ob_imat, curr_cage_adjust);
297 
298  sub_v3_v3v3(ray_dir, curr_cage_adjust, kcd->prev.cage);
299  }
300 #endif
301 
302  for (i = 0; i < 4; i++) {
303  float ray_hit[3];
304  float lambda_test;
305  if (isect_ray_plane_v3(kcd->prev.cage, ray_dir, planes[i], &lambda_test, false)) {
306  madd_v3_v3v3fl(ray_hit, kcd->prev.cage, ray_dir, lambda_test);
307  if (lambda_test < 0.0f) {
308  if (lambda_test > lambda_best[0]) {
309  copy_v3_v3(ray_hit_best[0], ray_hit);
310  lambda_best[0] = lambda_test;
311  }
312  }
313  else {
314  if (lambda_test < lambda_best[1]) {
315  copy_v3_v3(ray_hit_best[1], ray_hit);
316  lambda_best[1] = lambda_test;
317  }
318  }
319  }
320  }
321 
322  copy_v3_v3(v1, ray_hit_best[0]);
323  copy_v3_v3(v2, ray_hit_best[1]);
324  }
325 
327 
330  GPU_line_width(2.0);
331 
333  immVertex3fv(pos, v1);
334  immVertex3fv(pos, v2);
335  immEnd();
336 
338 }
339 
340 /* modal loop selection drawing callback */
341 static void knifetool_draw(const bContext *UNUSED(C), ARegion *UNUSED(region), void *arg)
342 {
343  const KnifeTool_OpData *kcd = arg;
345 
347  GPU_polygon_offset(1.0f, 1.0f);
348 
349  GPU_matrix_push();
350  GPU_matrix_mul(kcd->ob->obmat);
351 
352  if (kcd->mode == MODE_DRAGGING && kcd->is_angle_snapping) {
354  }
355 
358 
360 
361  if (kcd->mode == MODE_DRAGGING) {
363  GPU_line_width(2.0);
364 
366  immVertex3fv(pos, kcd->prev.cage);
367  immVertex3fv(pos, kcd->curr.cage);
368  immEnd();
369  }
370 
371  if (kcd->prev.vert) {
374 
376  immVertex3fv(pos, kcd->prev.cage);
377  immEnd();
378  }
379 
380  if (kcd->prev.bmface || kcd->prev.edge) {
383 
385  immVertex3fv(pos, kcd->prev.cage);
386  immEnd();
387  }
388 
389  if (kcd->curr.vert) {
392 
394  immVertex3fv(pos, kcd->curr.cage);
395  immEnd();
396  }
397  else if (kcd->curr.edge) {
399  GPU_line_width(2.0);
400 
402  immVertex3fv(pos, kcd->curr.edge->v1->cageco);
403  immVertex3fv(pos, kcd->curr.edge->v2->cageco);
404  immEnd();
405  }
406 
407  if (kcd->curr.bmface || kcd->curr.edge) {
410 
412  immVertex3fv(pos, kcd->curr.cage);
413  immEnd();
414  }
415 
416  if (kcd->totlinehit > 0) {
417  KnifeLineHit *lh;
418  int i, snapped_verts_count, other_verts_count;
419  float fcol[4];
420 
422 
425 
426  lh = kcd->linehits;
427  for (i = 0, snapped_verts_count = 0, other_verts_count = 0; i < kcd->totlinehit; i++, lh++) {
428  if (lh->v) {
429  GPU_vertbuf_attr_set(vert, pos, snapped_verts_count++, lh->cagehit);
430  }
431  else {
432  GPU_vertbuf_attr_set(vert, pos, kcd->totlinehit - 1 - other_verts_count++, lh->cagehit);
433  }
434  }
435 
438 
439  /* draw any snapped verts first */
440  rgba_uchar_to_float(fcol, kcd->colors.point_a);
441  GPU_batch_uniform_4fv(batch, "color", fcol);
443  if (snapped_verts_count > 0) {
444  GPU_batch_draw_range(batch, 0, snapped_verts_count);
445  }
446 
447  /* now draw the rest */
449  GPU_batch_uniform_4fv(batch, "color", fcol);
451  if (other_verts_count > 0) {
452  GPU_batch_draw_range(batch, snapped_verts_count, other_verts_count);
453  }
454 
456 
458  }
459 
460  if (kcd->totkedge > 0) {
461  BLI_mempool_iter iter;
462  KnifeEdge *kfe;
463 
465  GPU_line_width(1.0);
466 
468 
469  BLI_mempool_iternew(kcd->kedges, &iter);
470  for (kfe = BLI_mempool_iterstep(&iter); kfe; kfe = BLI_mempool_iterstep(&iter)) {
471  if (!kfe->is_cut) {
472  continue;
473  }
474 
475  immVertex3fv(pos, kfe->v1->cageco);
476  immVertex3fv(pos, kfe->v2->cageco);
477  }
478 
479  immEnd();
480 
483  }
484 
485  if (kcd->totkvert > 0) {
486  BLI_mempool_iter iter;
487  KnifeVert *kfv;
488 
490  GPU_point_size(5.0 * UI_DPI_FAC);
491 
493 
494  BLI_mempool_iternew(kcd->kverts, &iter);
495  for (kfv = BLI_mempool_iterstep(&iter); kfv; kfv = BLI_mempool_iterstep(&iter)) {
496  if (!kfv->is_cut) {
497  continue;
498  }
499 
500  immVertex3fv(pos, kfv->cageco);
501  }
502 
503  immEnd();
504 
507  }
508 
510 
511  GPU_matrix_pop();
513 
514  /* Reset default */
516 }
517 
520 /* -------------------------------------------------------------------- */
525 {
526  char header[UI_MAX_DRAW_STR];
527  char buf[UI_MAX_DRAW_STR];
528 
529  char *p = buf;
530  int available_len = sizeof(buf);
531 
532 #define WM_MODALKEY(_id) \
533  WM_modalkeymap_operator_items_to_string_buf( \
534  op->type, (_id), true, UI_MAX_SHORTCUT_STR, &available_len, &p)
535 
536  BLI_snprintf(header,
537  sizeof(header),
538  TIP_("%s: confirm, %s: cancel, "
539  "%s: start/define cut, %s: close cut, %s: new cut, "
540  "%s: midpoint snap (%s), %s: ignore snap (%s), "
541  "%s: angle constraint (%s), %s: cut through (%s), "
542  "%s: panning"),
557 
558 #undef WM_MODALKEY
559 
560  ED_workspace_status_text(C, header);
561 }
562 
565 /* -------------------------------------------------------------------- */
569 static void knife_project_v2(const KnifeTool_OpData *kcd, const float co[3], float sco[2])
570 {
571  ED_view3d_project_float_v2_m4(kcd->region, co, sco, (float(*)[4])kcd->projmat);
572 }
573 
575  const float mval[2],
576  const float ofs,
577  float r_origin[3],
578  float r_origin_ofs[3])
579 {
580  /* unproject to find view ray */
581  ED_view3d_unproject(kcd->vc.region, mval[0], mval[1], 0.0f, r_origin);
582  ED_view3d_unproject(kcd->vc.region, mval[0], mval[1], ofs, r_origin_ofs);
583 
584  /* transform into object space */
585  mul_m4_v3(kcd->ob_imat, r_origin);
586  mul_m4_v3(kcd->ob_imat, r_origin_ofs);
587 }
588 
590 {
591  bool v1_inside, v2_inside;
592  bool v1_inface, v2_inface;
593  BMLoop *l1, *l2;
594 
595  if (!f || !v1 || !v2) {
596  return false;
597  }
598 
599  l1 = v1->v ? BM_face_vert_share_loop(f, v1->v) : NULL;
600  l2 = v2->v ? BM_face_vert_share_loop(f, v2->v) : NULL;
601 
602  if ((l1 && l2) && BM_loop_is_adjacent(l1, l2)) {
603  /* boundary-case, always false to avoid edge-in-face checks below */
604  return false;
605  }
606 
607  /* find out if v1 and v2, if set, are part of the face */
608  v1_inface = (l1 != NULL);
609  v2_inface = (l2 != NULL);
610 
611  /* BM_face_point_inside_test uses best-axis projection so this isn't most accurate test... */
612  v1_inside = v1_inface ? false : BM_face_point_inside_test(f, v1->co);
613  v2_inside = v2_inface ? false : BM_face_point_inside_test(f, v2->co);
614  if ((v1_inface && v2_inside) || (v2_inface && v1_inside) || (v1_inside && v2_inside)) {
615  return true;
616  }
617 
618  if (v1_inface && v2_inface) {
619  float mid[3];
620  /* Can have case where v1 and v2 are on shared chain between two faces.
621  * BM_face_splits_check_legal does visibility and self-intersection tests,
622  * but it is expensive and maybe a bit buggy, so use a simple
623  * "is the midpoint in the face" test */
624  mid_v3_v3v3(mid, v1->co, v2->co);
625  return BM_face_point_inside_test(f, mid);
626  }
627  return false;
628 }
629 
631 {
633  invert_m4_m4(kcd->projmat_inv, kcd->projmat);
634 
636  mul_v3_mat3_m4v3(kcd->proj_zaxis, kcd->ob_imat, kcd->vc.rv3d->viewinv[2]);
637  normalize_v3(kcd->proj_zaxis);
638 
640  kcd->vc.depsgraph, kcd->vc.v3d, kcd->vc.rv3d, &kcd->clipsta, &kcd->clipend, true);
641 }
642 
645 /* -------------------------------------------------------------------- */
652 {
653  BMElem *ele_test;
654  KnifeEdge *kfe = NULL;
655 
656  /* vert? */
657  ele_test = (BMElem *)kfv->v;
658 
659  if (r_kfe || ele_test == NULL) {
660  if (kfv->v == NULL) {
661  Ref *ref;
662  for (ref = kfv->edges.first; ref; ref = ref->next) {
663  kfe = ref->ref;
664  if (kfe->e) {
665  if (r_kfe) {
666  *r_kfe = kfe;
667  }
668  break;
669  }
670  }
671  }
672  }
673 
674  /* edge? */
675  if (ele_test == NULL) {
676  if (kfe) {
677  ele_test = (BMElem *)kfe->e;
678  }
679  }
680 
681  /* face? */
682  if (ele_test == NULL) {
683  if (BLI_listbase_is_single(&kfe->faces)) {
684  ele_test = ((Ref *)kfe->faces.first)->ref;
685  }
686  }
687 
688  return ele_test;
689 }
690 
692 {
693  BMElem *ele_test;
694 
695  ele_test = (BMElem *)kfe->e;
696 
697  if (ele_test == NULL) {
698  ele_test = (BMElem *)kfe->basef;
699  }
700 
701  return ele_test;
702 }
703 
706 /* -------------------------------------------------------------------- */
711 {
712  ListBase *list;
713 
714  list = BLI_memarena_alloc(kcd->arena, sizeof(ListBase));
715  BLI_listbase_clear(list);
716  return list;
717 }
718 
719 static void knife_append_list(KnifeTool_OpData *kcd, ListBase *lst, void *elem)
720 {
721  Ref *ref;
722 
723  ref = BLI_mempool_calloc(kcd->refs);
724  ref->ref = elem;
725  BLI_addtail(lst, ref);
726 }
727 
728 static Ref *find_ref(ListBase *lb, void *ref)
729 {
730  Ref *ref1;
731 
732  for (ref1 = lb->first; ref1; ref1 = ref1->next) {
733  if (ref1->ref == ref) {
734  return ref1;
735  }
736  }
737 
738  return NULL;
739 }
740 
741 static void knife_append_list_no_dup(KnifeTool_OpData *kcd, ListBase *lst, void *elem)
742 {
743  if (!find_ref(lst, elem)) {
744  knife_append_list(kcd, lst, elem);
745  }
746 }
747 
749 {
750  knife_append_list(kcd, &kfe->v1->edges, kfe);
751  knife_append_list(kcd, &kfe->v2->edges, kfe);
752 }
753 
754 /* Add faces of an edge to a KnifeVert's faces list. No checks for dups. */
756 {
757  BMIter bmiter;
758  BMFace *f;
759 
760  BM_ITER_ELEM (f, &bmiter, e, BM_FACES_OF_EDGE) {
761  knife_append_list(kcd, &kfv->faces, f);
762  }
763 }
764 
765 /* Find a face in common in the two faces lists.
766  * If more than one, return the first; if none, return NULL */
768 {
769  Ref *ref1, *ref2;
770 
771  for (ref1 = faces1->first; ref1; ref1 = ref1->next) {
772  for (ref2 = faces2->first; ref2; ref2 = ref2->next) {
773  if (ref1->ref == ref2->ref) {
774  return (BMFace *)(ref1->ref);
775  }
776  }
777  }
778  return NULL;
779 }
780 
783 /* -------------------------------------------------------------------- */
787 static KnifeVert *new_knife_vert(KnifeTool_OpData *kcd, const float co[3], const float cageco[3])
788 {
789  KnifeVert *kfv = BLI_mempool_calloc(kcd->kverts);
790 
791  kcd->totkvert++;
792 
793  copy_v3_v3(kfv->co, co);
794  copy_v3_v3(kfv->cageco, cageco);
795 
796  return kfv;
797 }
798 
800 {
801  kcd->totkedge++;
802  return BLI_mempool_calloc(kcd->kedges);
803 }
804 
805 /* get a KnifeVert wrapper for an existing BMVert */
807 {
808  KnifeVert *kfv = BLI_ghash_lookup(kcd->origvertmap, v);
809  const float *cageco;
810 
811  if (!kfv) {
812  BMIter bmiter;
813  BMFace *f;
814 
815  if (BM_elem_index_get(v) >= 0) {
816  cageco = kcd->cagecos[BM_elem_index_get(v)];
817  }
818  else {
819  cageco = v->co;
820  }
821  kfv = new_knife_vert(kcd, v->co, cageco);
822  kfv->v = v;
823  BLI_ghash_insert(kcd->origvertmap, v, kfv);
824  BM_ITER_ELEM (f, &bmiter, v, BM_FACES_OF_VERT) {
825  knife_append_list(kcd, &kfv->faces, f);
826  }
827  }
828 
829  return kfv;
830 }
831 
832 /* get a KnifeEdge wrapper for an existing BMEdge */
834 {
835  KnifeEdge *kfe = BLI_ghash_lookup(kcd->origedgemap, e);
836  if (!kfe) {
837  BMIter bmiter;
838  BMFace *f;
839 
840  kfe = new_knife_edge(kcd);
841  kfe->e = e;
842  kfe->v1 = get_bm_knife_vert(kcd, e->v1);
843  kfe->v2 = get_bm_knife_vert(kcd, e->v2);
844 
845  knife_add_to_vert_edges(kcd, kfe);
846 
847  BLI_ghash_insert(kcd->origedgemap, e, kfe);
848 
849  BM_ITER_ELEM (f, &bmiter, e, BM_FACES_OF_EDGE) {
850  knife_append_list(kcd, &kfe->faces, f);
851  }
852  }
853 
854  return kfe;
855 }
856 
858 {
859  ListBase *list = BLI_ghash_lookup(kcd->kedgefacemap, f);
860 
861  if (!list) {
862  BMIter bmiter;
863  BMEdge *e;
864 
865  list = knife_empty_list(kcd);
866 
867  BM_ITER_ELEM (e, &bmiter, f, BM_EDGES_OF_FACE) {
868  knife_append_list(kcd, list, get_bm_knife_edge(kcd, e));
869  }
870 
871  BLI_ghash_insert(kcd->kedgefacemap, f, list);
872  }
873 
874  return list;
875 }
876 
878 {
879  knife_append_list(kcd, knife_get_face_kedges(kcd, f), kfe);
880  knife_append_list(kcd, &kfe->faces, f);
881 }
882 
884  KnifeEdge *kfe,
885  const float co[3],
886  const float cageco[3],
887  KnifeEdge **r_kfe)
888 {
889  KnifeEdge *newkfe = new_knife_edge(kcd);
890  Ref *ref;
891  BMFace *f;
892 
893  newkfe->v1 = kfe->v1;
894  newkfe->v2 = new_knife_vert(kcd, co, cageco);
895  newkfe->v2->is_cut = true;
896  if (kfe->e) {
897  knife_add_edge_faces_to_vert(kcd, newkfe->v2, kfe->e);
898  }
899  else {
900  /* kfe cuts across an existing face.
901  * If v1 and v2 are in multiple faces together (e.g., if they
902  * are in doubled polys) then this arbitrarily chooses one of them */
903  f = knife_find_common_face(&kfe->v1->faces, &kfe->v2->faces);
904  if (f) {
905  knife_append_list(kcd, &newkfe->v2->faces, f);
906  }
907  }
908  newkfe->basef = kfe->basef;
909 
910  ref = find_ref(&kfe->v1->edges, kfe);
911  BLI_remlink(&kfe->v1->edges, ref);
912 
913  kfe->v1 = newkfe->v2;
914  BLI_addtail(&kfe->v1->edges, ref);
915 
916  for (ref = kfe->faces.first; ref; ref = ref->next) {
917  knife_edge_append_face(kcd, newkfe, ref->ref);
918  }
919 
920  knife_add_to_vert_edges(kcd, newkfe);
921 
922  newkfe->is_cut = kfe->is_cut;
923  newkfe->e = kfe->e;
924 
925  *r_kfe = newkfe;
926 
927  return newkfe->v2;
928 }
929 
932 /* -------------------------------------------------------------------- */
936 /* User has just clicked for first time or first time after a restart (E key).
937  * Copy the current position data into prev. */
939 {
940  kcd->prev = kcd->curr;
941  kcd->curr.is_space = 0; /*TODO: why do we do this? */
942 
943  if (kcd->prev.vert == NULL && kcd->prev.edge == NULL) {
944  float origin[3], origin_ofs[3];
945  float ofs_local[3];
946 
947  negate_v3_v3(ofs_local, kcd->vc.rv3d->ofs);
948  mul_m4_v3(kcd->ob_imat, ofs_local);
949 
950  knife_input_ray_segment(kcd, kcd->curr.mval, 1.0f, origin, origin_ofs);
951 
952  if (!isect_line_plane_v3(kcd->prev.cage, origin, origin_ofs, ofs_local, kcd->proj_zaxis)) {
953  zero_v3(kcd->prev.cage);
954  }
955 
956  copy_v3_v3(kcd->prev.co, kcd->prev.cage); /*TODO: do we need this? */
957  copy_v3_v3(kcd->curr.cage, kcd->prev.cage);
958  copy_v3_v3(kcd->curr.co, kcd->prev.co);
959  }
960 }
961 
963 {
964  kpos->bmface = lh->f;
965  kpos->vert = lh->v;
966  kpos->edge = lh->kfe;
967  copy_v3_v3(kpos->cage, lh->cagehit);
968  copy_v3_v3(kpos->co, lh->hit);
969  copy_v2_v2(kpos->mval, lh->schit);
970 }
971 
972 /* primary key: lambda along cut
973  * secondary key: lambda along depth
974  * tertiary key: pointer comparisons of verts if both snapped to verts
975  */
976 static int linehit_compare(const void *vlh1, const void *vlh2)
977 {
978  const KnifeLineHit *lh1 = vlh1;
979  const KnifeLineHit *lh2 = vlh2;
980 
981  if (lh1->l < lh2->l) {
982  return -1;
983  }
984  if (lh1->l > lh2->l) {
985  return 1;
986  }
987  if (lh1->m < lh2->m) {
988  return -1;
989  }
990  if (lh1->m > lh2->m) {
991  return 1;
992  }
993  if (lh1->v < lh2->v) {
994  return -1;
995  }
996  if (lh1->v > lh2->v) {
997  return 1;
998  }
999  return 0;
1000 }
1001 
1002 /*
1003  * Sort linehits by distance along cut line, and secondarily from
1004  * front to back (from eye), and tertiarily by snap vertex,
1005  * and remove any duplicates.
1006  */
1008 {
1009  bool is_double = false;
1010 
1011  int n = kcd->totlinehit;
1012  KnifeLineHit *linehits = kcd->linehits;
1013  if (n == 0) {
1014  return;
1015  }
1016 
1017  qsort(linehits, n, sizeof(KnifeLineHit), linehit_compare);
1018 
1019  /* Remove any edge hits that are preceded or followed
1020  * by a vertex hit that is very near. Mark such edge hits using
1021  * l == -1 and then do another pass to actually remove.
1022  * Also remove all but one of a series of vertex hits for the same vertex. */
1023  for (int i = 0; i < n; i++) {
1024  KnifeLineHit *lhi = &linehits[i];
1025  if (lhi->v) {
1026  for (int j = i - 1; j >= 0; j--) {
1027  KnifeLineHit *lhj = &linehits[j];
1028  if (!lhj->kfe || fabsf(lhi->l - lhj->l) > KNIFE_FLT_EPSBIG ||
1029  fabsf(lhi->m - lhj->m) > KNIFE_FLT_EPSBIG) {
1030  break;
1031  }
1032 
1033  if (lhi->kfe == lhj->kfe) {
1034  lhj->l = -1.0f;
1035  is_double = true;
1036  }
1037  }
1038  for (int j = i + 1; j < n; j++) {
1039  KnifeLineHit *lhj = &linehits[j];
1040  if (fabsf(lhi->l - lhj->l) > KNIFE_FLT_EPSBIG ||
1041  fabsf(lhi->m - lhj->m) > KNIFE_FLT_EPSBIG) {
1042  break;
1043  }
1044  if ((lhj->kfe && (lhi->kfe == lhj->kfe)) || (lhi->v == lhj->v)) {
1045  lhj->l = -1.0f;
1046  is_double = true;
1047  }
1048  }
1049  }
1050  }
1051 
1052  if (is_double) {
1053  /* delete-in-place loop: copying from pos j to pos i+1 */
1054  int i = 0;
1055  int j = 1;
1056  while (j < n) {
1057  KnifeLineHit *lhi = &linehits[i];
1058  KnifeLineHit *lhj = &linehits[j];
1059  if (lhj->l == -1.0f) {
1060  j++; /* skip copying this one */
1061  }
1062  else {
1063  /* copy unless a no-op */
1064  if (lhi->l == -1.0f) {
1065  /* could happen if linehits[0] is being deleted */
1066  memcpy(&linehits[i], &linehits[j], sizeof(KnifeLineHit));
1067  }
1068  else {
1069  if (i + 1 != j) {
1070  memcpy(&linehits[i + 1], &linehits[j], sizeof(KnifeLineHit));
1071  }
1072  i++;
1073  }
1074  j++;
1075  }
1076  }
1077  kcd->totlinehit = i + 1;
1078  }
1079 }
1080 
1081 /* Add hit to list of hits in facehits[f], where facehits is a map, if not already there */
1083  GHash *facehits,
1084  BMFace *f,
1085  KnifeLineHit *hit)
1086 {
1087  ListBase *list = BLI_ghash_lookup(facehits, f);
1088 
1089  if (!list) {
1090  list = knife_empty_list(kcd);
1091  BLI_ghash_insert(facehits, f, list);
1092  }
1093  knife_append_list_no_dup(kcd, list, hit);
1094 }
1095 
1101  const KnifeLineHit *lh,
1102  const float co[3])
1103 {
1104 
1105  if (lh->v && lh->v->v) {
1106  BMLoop *l; /* side-of-loop */
1107  if ((l = BM_face_vert_share_loop(f, lh->v->v)) &&
1108  (BM_loop_point_side_of_loop_test(l, co) < 0.0f)) {
1109  return true;
1110  }
1111  }
1112  else if ((lh->kfe && lh->kfe->e)) {
1113  BMLoop *l; /* side-of-edge */
1114  if ((l = BM_face_edge_share_loop(f, lh->kfe->e)) &&
1115  (BM_loop_point_side_of_edge_test(l, co) < 0.0f)) {
1116  return true;
1117  }
1118  }
1119 
1120  return false;
1121 }
1122 
1124  KnifeLineHit *lh1,
1125  KnifeLineHit *lh2,
1126  BMFace *f)
1127 {
1128  KnifeEdge *kfe, *kfe2;
1129  BMEdge *e_base;
1130 
1131  if ((lh1->v && lh1->v == lh2->v) || (lh1->kfe && lh1->kfe == lh2->kfe)) {
1132  return;
1133  }
1134 
1135  /* if the cut is on an edge, just tag that its a cut and return */
1136  if ((lh1->v && lh2->v) && (lh1->v->v && lh2->v && lh2->v->v) &&
1137  (e_base = BM_edge_exists(lh1->v->v, lh2->v->v))) {
1138  kfe = get_bm_knife_edge(kcd, e_base);
1139  kfe->is_cut = true;
1140  kfe->e = e_base;
1141  return;
1142  }
1145  return;
1146  }
1147 
1148  /* Check if edge actually lies within face (might not, if this face is concave) */
1149  if ((lh1->v && !lh1->kfe) && (lh2->v && !lh2->kfe)) {
1150  if (!knife_verts_edge_in_face(lh1->v, lh2->v, f)) {
1151  return;
1152  }
1153  }
1154 
1155  kfe = new_knife_edge(kcd);
1156  kfe->is_cut = true;
1157  kfe->basef = f;
1158 
1159  if (lh1->v) {
1160  kfe->v1 = lh1->v;
1161  }
1162  else if (lh1->kfe) {
1163  kfe->v1 = knife_split_edge(kcd, lh1->kfe, lh1->hit, lh1->cagehit, &kfe2);
1164  lh1->v = kfe->v1; /* record the KnifeVert for this hit */
1165  }
1166  else {
1167  BLI_assert(lh1->f);
1168  kfe->v1 = new_knife_vert(kcd, lh1->hit, lh1->cagehit);
1169  kfe->v1->is_cut = true;
1170  kfe->v1->is_face = true;
1171  knife_append_list(kcd, &kfe->v1->faces, lh1->f);
1172  lh1->v = kfe->v1; /* record the KnifeVert for this hit */
1173  }
1174 
1175  if (lh2->v) {
1176  kfe->v2 = lh2->v;
1177  }
1178  else if (lh2->kfe) {
1179  kfe->v2 = knife_split_edge(kcd, lh2->kfe, lh2->hit, lh2->cagehit, &kfe2);
1180  lh2->v = kfe->v2; /* future uses of lh2 won't split again */
1181  }
1182  else {
1183  BLI_assert(lh2->f);
1184  kfe->v2 = new_knife_vert(kcd, lh2->hit, lh2->cagehit);
1185  kfe->v2->is_cut = true;
1186  kfe->v2->is_face = true;
1187  knife_append_list(kcd, &kfe->v2->faces, lh2->f);
1188  lh2->v = kfe->v2; /* record the KnifeVert for this hit */
1189  }
1190 
1191  knife_add_to_vert_edges(kcd, kfe);
1192 
1193  /* TODO: check if this is ever needed */
1194  if (kfe->basef && !find_ref(&kfe->faces, kfe->basef)) {
1195  knife_edge_append_face(kcd, kfe, kfe->basef);
1196  }
1197 }
1198 
1199 /* Given a list of KnifeLineHits for one face, sorted by l
1200  * and then by m, make the required KnifeVerts and
1201  * KnifeEdges.
1202  */
1203 static void knife_cut_face(KnifeTool_OpData *kcd, BMFace *f, ListBase *hits)
1204 {
1205  Ref *r;
1206 
1207  if (BLI_listbase_count_at_most(hits, 2) != 2) {
1208  return;
1209  }
1210 
1211  for (r = hits->first; r->next; r = r->next) {
1212  knife_add_single_cut(kcd, r->ref, r->next->ref, f);
1213  }
1214 }
1215 
1216 static void knife_make_face_cuts(KnifeTool_OpData *kcd, BMFace *f, ListBase *kfedges)
1217 {
1218  BMesh *bm = kcd->em->bm;
1219  KnifeEdge *kfe;
1220  Ref *ref;
1221  int edge_array_len = BLI_listbase_count(kfedges);
1222  int i;
1223 
1224  BMEdge **edge_array = BLI_array_alloca(edge_array, edge_array_len);
1225 
1226  /* point to knife edges we've created edges in, edge_array aligned */
1227  KnifeEdge **kfe_array = BLI_array_alloca(kfe_array, edge_array_len);
1228 
1230 
1231  i = 0;
1232  for (ref = kfedges->first; ref; ref = ref->next) {
1233  bool is_new_edge = false;
1234  kfe = ref->ref;
1235 
1236  if (kfe->e == NULL) {
1237  if (kfe->v1->v && kfe->v2->v) {
1238  kfe->e = BM_edge_exists(kfe->v1->v, kfe->v2->v);
1239  }
1240  }
1241 
1242  if (kfe->e) {
1243  if (BM_edge_in_face(kfe->e, f)) {
1244  /* shouldn't happen, but in this case - just ignore */
1245  continue;
1246  }
1247  }
1248  else {
1249  if (kfe->v1->v == NULL) {
1250  kfe->v1->v = BM_vert_create(bm, kfe->v1->co, NULL, 0);
1251  }
1252  if (kfe->v2->v == NULL) {
1253  kfe->v2->v = BM_vert_create(bm, kfe->v2->co, NULL, 0);
1254  }
1255  BLI_assert(kfe->e == NULL);
1256  kfe->e = BM_edge_create(bm, kfe->v1->v, kfe->v2->v, NULL, 0);
1257  if (kfe->e) {
1259  BM_edge_select_set(bm, kfe->e, true);
1260  }
1261  is_new_edge = true;
1262  }
1263  }
1264 
1265  BLI_assert(kfe->e);
1266 
1267  if (BLI_gset_add(kcd->edgenet.edge_visit, kfe->e)) {
1268  kfe_array[i] = is_new_edge ? kfe : 0;
1269  edge_array[i] = kfe->e;
1270  i += 1;
1271  }
1272  }
1273 
1274  if (i) {
1275  const int edge_array_len_orig = i;
1276  edge_array_len = i;
1277 
1278 #ifdef USE_NET_ISLAND_CONNECT
1279  uint edge_array_holes_len;
1280  BMEdge **edge_array_holes;
1282  f,
1283  edge_array,
1284  edge_array_len,
1285  true,
1286  kcd->edgenet.arena,
1287  &edge_array_holes,
1288  &edge_array_holes_len)) {
1290  for (i = edge_array_len; i < edge_array_holes_len; i++) {
1291  BM_edge_select_set(bm, edge_array_holes[i], true);
1292  }
1293  }
1294 
1295  edge_array_len = edge_array_holes_len;
1296  edge_array = edge_array_holes; /* owned by the arena */
1297  }
1298 #endif
1299 
1300  {
1301  BMFace **face_arr = NULL;
1302  int face_arr_len;
1303 
1304  BM_face_split_edgenet(bm, f, edge_array, edge_array_len, &face_arr, &face_arr_len);
1305 
1306  if (face_arr) {
1307  MEM_freeN(face_arr);
1308  }
1309  }
1310 
1311  /* remove dangling edges, not essential - but nice for users */
1312  for (i = 0; i < edge_array_len_orig; i++) {
1313  if (kfe_array[i]) {
1314  if (BM_edge_is_wire(kfe_array[i]->e)) {
1315  BM_edge_kill(bm, kfe_array[i]->e);
1316  kfe_array[i]->e = NULL;
1317  }
1318  }
1319  }
1320 
1321 #ifdef USE_NET_ISLAND_CONNECT
1323 #endif
1324  }
1325 
1327 }
1328 
1329 static int sort_verts_by_dist_cb(void *co_p, const void *cur_a_p, const void *cur_b_p)
1330 {
1331  const KnifeVert *cur_a = ((const Ref *)cur_a_p)->ref;
1332  const KnifeVert *cur_b = ((const Ref *)cur_b_p)->ref;
1333  const float *co = co_p;
1334  const float a_sq = len_squared_v3v3(co, cur_a->co);
1335  const float b_sq = len_squared_v3v3(co, cur_b->co);
1336 
1337  if (a_sq < b_sq) {
1338  return -1;
1339  }
1340  if (a_sq > b_sq) {
1341  return 1;
1342  }
1343  return 0;
1344 }
1345 
1346 /* Use the network of KnifeEdges and KnifeVerts accumulated to make real BMVerts and BMEdedges */
1348 {
1349  BMesh *bm = kcd->em->bm;
1350  KnifeEdge *kfe;
1351  KnifeVert *kfv;
1352  BMFace *f;
1353  BMEdge *e, *enew;
1354  ListBase *list;
1355  Ref *ref;
1356  float pct;
1357  SmallHashIter hiter;
1358  BLI_mempool_iter iter;
1359  SmallHash fhash_, *fhash = &fhash_;
1360  SmallHash ehash_, *ehash = &ehash_;
1361 
1362  BLI_smallhash_init(fhash);
1363  BLI_smallhash_init(ehash);
1364 
1365  /* put list of cutting edges for a face into fhash, keyed by face */
1366  BLI_mempool_iternew(kcd->kedges, &iter);
1367  for (kfe = BLI_mempool_iterstep(&iter); kfe; kfe = BLI_mempool_iterstep(&iter)) {
1368 
1369  /* select edges that lie directly on the cut */
1370  if (kcd->select_result) {
1371  if (kfe->e && kfe->is_cut) {
1372  BM_edge_select_set(bm, kfe->e, true);
1373  }
1374  }
1375 
1376  f = kfe->basef;
1377  if (!f || kfe->e) {
1378  continue;
1379  }
1380  list = BLI_smallhash_lookup(fhash, (uintptr_t)f);
1381  if (!list) {
1382  list = knife_empty_list(kcd);
1383  BLI_smallhash_insert(fhash, (uintptr_t)f, list);
1384  }
1385  knife_append_list(kcd, list, kfe);
1386  }
1387 
1388  /* put list of splitting vertices for an edge into ehash, keyed by edge */
1389  BLI_mempool_iternew(kcd->kverts, &iter);
1390  for (kfv = BLI_mempool_iterstep(&iter); kfv; kfv = BLI_mempool_iterstep(&iter)) {
1391  if (kfv->v) {
1392  continue; /* already have a BMVert */
1393  }
1394  for (ref = kfv->edges.first; ref; ref = ref->next) {
1395  kfe = ref->ref;
1396  e = kfe->e;
1397  if (!e) {
1398  continue;
1399  }
1400  list = BLI_smallhash_lookup(ehash, (uintptr_t)e);
1401  if (!list) {
1402  list = knife_empty_list(kcd);
1403  BLI_smallhash_insert(ehash, (uintptr_t)e, list);
1404  }
1405  /* there can be more than one kfe in kfv's list with same e */
1406  if (!find_ref(list, kfv)) {
1407  knife_append_list(kcd, list, kfv);
1408  }
1409  }
1410  }
1411 
1412  /* split bmesh edges where needed */
1413  for (list = BLI_smallhash_iternew(ehash, &hiter, (uintptr_t *)&e); list;
1414  list = BLI_smallhash_iternext(&hiter, (uintptr_t *)&e)) {
1416 
1417  for (ref = list->first; ref; ref = ref->next) {
1418  kfv = ref->ref;
1419  pct = line_point_factor_v3(kfv->co, e->v1->co, e->v2->co);
1420  kfv->v = BM_edge_split(bm, e, e->v1, &enew, pct);
1421  }
1422  }
1423 
1424  if (kcd->only_select) {
1426  }
1427 
1428  /* do cuts for each face */
1429  for (list = BLI_smallhash_iternew(fhash, &hiter, (uintptr_t *)&f); list;
1430  list = BLI_smallhash_iternext(&hiter, (uintptr_t *)&f)) {
1431  knife_make_face_cuts(kcd, f, list);
1432  }
1433 
1434  BLI_smallhash_release(fhash);
1435  BLI_smallhash_release(ehash);
1436 }
1437 
1438 /* User has just left-clicked after the first time.
1439  * Add all knife cuts implied by line from prev to curr.
1440  * If that line crossed edges then kcd->linehits will be non-NULL.
1441  * Make all of the KnifeVerts and KnifeEdges implied by this cut.
1442  */
1444 {
1445  int i;
1446  GHash *facehits;
1447  BMFace *f;
1448  Ref *r;
1449  GHashIterator giter;
1450  ListBase *list;
1451 
1453  if (kcd->totlinehit == 0) {
1454  if (kcd->is_drag_hold == false) {
1455  kcd->prev = kcd->curr;
1456  }
1457  return;
1458  }
1459 
1460  /* make facehits: map face -> list of linehits touching it */
1461  facehits = BLI_ghash_ptr_new("knife facehits");
1462  for (i = 0; i < kcd->totlinehit; i++) {
1463  KnifeLineHit *lh = &kcd->linehits[i];
1464  if (lh->f) {
1465  add_hit_to_facehits(kcd, facehits, lh->f, lh);
1466  }
1467  if (lh->v) {
1468  for (r = lh->v->faces.first; r; r = r->next) {
1469  add_hit_to_facehits(kcd, facehits, r->ref, lh);
1470  }
1471  }
1472  if (lh->kfe) {
1473  for (r = lh->kfe->faces.first; r; r = r->next) {
1474  add_hit_to_facehits(kcd, facehits, r->ref, lh);
1475  }
1476  }
1477  }
1478 
1479  /* Note: as following loop progresses, the 'v' fields of
1480  * the linehits will be filled in (as edges are split or
1481  * in-face verts are made), so it may be true that both
1482  * the v and the kfe or f fields will be non-NULL. */
1483  GHASH_ITER (giter, facehits) {
1484  f = (BMFace *)BLI_ghashIterator_getKey(&giter);
1485  list = (ListBase *)BLI_ghashIterator_getValue(&giter);
1486  knife_cut_face(kcd, f, list);
1487  }
1488 
1489  /* set up for next cut */
1490  kcd->prev = kcd->curr;
1491 
1492  if (kcd->prev.bmface) {
1493  /* was "in face" but now we have a KnifeVert it is snapped to */
1494  KnifeLineHit *lh = &kcd->linehits[kcd->totlinehit - 1];
1495  kcd->prev.vert = lh->v;
1496  kcd->prev.bmface = NULL;
1497  }
1498 
1499  if (kcd->is_drag_hold) {
1500  KnifeLineHit *lh = &kcd->linehits[kcd->totlinehit - 1];
1501  linehit_to_knifepos(&kcd->prev, lh);
1502  }
1503 
1504  BLI_ghash_free(facehits, NULL, NULL);
1505  MEM_freeN(kcd->linehits);
1506  kcd->linehits = NULL;
1507  kcd->totlinehit = 0;
1508 }
1509 
1511 {
1512  if (kcd->linehits) {
1513  MEM_freeN(kcd->linehits);
1514  kcd->linehits = NULL;
1515  kcd->totlinehit = 0;
1516  }
1517 }
1518 
1521 /* -------------------------------------------------------------------- */
1525 /* Record the index in kcd->em->looptris of first looptri triple for a given face,
1526  * given an index for some triple in that array.
1527  * This assumes that all of the triangles for a given face are contiguous
1528  * in that array (as they are by the current tessellation routines).
1529  * Actually store index + 1 in the hash, because 0 looks like "no entry"
1530  * to hash lookup routine; will reverse this in the get routine.
1531  * Doing this lazily rather than all at once for all faces.
1532  */
1533 static void set_lowest_face_tri(KnifeTool_OpData *kcd, BMFace *f, int index)
1534 {
1535  int i;
1536 
1537  if (BLI_ghash_lookup(kcd->facetrimap, f)) {
1538  return;
1539  }
1540 
1541  BLI_assert(index >= 0 && index < kcd->em->tottri);
1542  BLI_assert(kcd->em->looptris[index][0]->f == f);
1543  for (i = index - 1; i >= 0; i--) {
1544  if (kcd->em->looptris[i][0]->f != f) {
1545  i++;
1546  break;
1547  }
1548  }
1549  if (i == -1) {
1550  i++;
1551  }
1552 
1553  BLI_ghash_insert(kcd->facetrimap, f, POINTER_FROM_INT(i + 1));
1554 }
1555 
1556 /* This should only be called for faces that have had a lowest face tri set by previous function */
1558 {
1559  int ans;
1560 
1561  ans = POINTER_AS_INT(BLI_ghash_lookup(kcd->facetrimap, f));
1562  BLI_assert(ans != 0);
1563  return ans - 1;
1564 }
1565 
1575  const float s[2],
1576  const float v1[3],
1577  const float v2[3],
1578  BMFace *f,
1579  const float face_tol_sq,
1580  float hit_co[3],
1581  float hit_cageco[3])
1582 {
1583  int tottri, tri_i;
1584  float raydir[3];
1585  float tri_norm[3], tri_plane[4];
1586  float se1[2], se2[2];
1587  float d, lambda;
1588  BMLoop **tri;
1589  ListBase *list;
1590  Ref *ref;
1591  KnifeEdge *kfe;
1592 
1593  sub_v3_v3v3(raydir, v2, v1);
1594  normalize_v3(raydir);
1595  tri_i = get_lowest_face_tri(kcd, f);
1596  tottri = kcd->em->tottri;
1597  BLI_assert(tri_i >= 0 && tri_i < tottri);
1598 
1599  for (; tri_i < tottri; tri_i++) {
1600  const float *lv1, *lv2, *lv3;
1601  float ray_tri_uv[2];
1602 
1603  tri = kcd->em->looptris[tri_i];
1604  if (tri[0]->f != f) {
1605  break;
1606  }
1607  lv1 = kcd->cagecos[BM_elem_index_get(tri[0]->v)];
1608  lv2 = kcd->cagecos[BM_elem_index_get(tri[1]->v)];
1609  lv3 = kcd->cagecos[BM_elem_index_get(tri[2]->v)];
1610  /* using epsilon test in case ray is directly through an internal
1611  * tessellation edge and might not hit either tessellation tri with
1612  * an exact test;
1613  * we will exclude hits near real edges by a later test */
1614  if (isect_ray_tri_epsilon_v3(v1, raydir, lv1, lv2, lv3, &lambda, ray_tri_uv, KNIFE_FLT_EPS)) {
1615  /* check if line coplanar with tri */
1616  normal_tri_v3(tri_norm, lv1, lv2, lv3);
1617  plane_from_point_normal_v3(tri_plane, lv1, tri_norm);
1618  if ((dist_squared_to_plane_v3(v1, tri_plane) < KNIFE_FLT_EPS) &&
1619  (dist_squared_to_plane_v3(v2, tri_plane) < KNIFE_FLT_EPS)) {
1620  return false;
1621  }
1622  interp_v3_v3v3v3_uv(hit_cageco, lv1, lv2, lv3, ray_tri_uv);
1623  /* Now check that far enough away from verts and edges */
1624  list = knife_get_face_kedges(kcd, f);
1625  for (ref = list->first; ref; ref = ref->next) {
1626  kfe = ref->ref;
1627  knife_project_v2(kcd, kfe->v1->cageco, se1);
1628  knife_project_v2(kcd, kfe->v2->cageco, se2);
1629  d = dist_squared_to_line_segment_v2(s, se1, se2);
1630  if (d < face_tol_sq) {
1631  return false;
1632  }
1633  }
1634  interp_v3_v3v3v3_uv(hit_co, tri[0]->v->co, tri[1]->v->co, tri[2]->v->co, ray_tri_uv);
1635  return true;
1636  }
1637  }
1638  return false;
1639 }
1640 
1645 {
1646  BMIter iter;
1647  BMVert *v;
1648  BMesh *bm = kcd->em->bm;
1649  float min[3], max[3];
1650 
1651  INIT_MINMAX(min, max);
1652 
1653  if (kcd->cagecos) {
1655  }
1656  else {
1657  BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
1658  minmax_v3v3_v3(min, max, v->co);
1659  }
1660  }
1661 
1662  kcd->ortho_extent = len_v3v3(min, max) / 2;
1664 }
1665 
1666 /* Do edges e1 and e2 go between exactly the same coordinates? */
1667 static bool coinciding_edges(BMEdge *e1, BMEdge *e2)
1668 {
1669  const float *co11, *co12, *co21, *co22;
1670 
1671  co11 = e1->v1->co;
1672  co12 = e1->v2->co;
1673  co21 = e2->v1->co;
1674  co22 = e2->v2->co;
1675  if ((equals_v3v3(co11, co21) && equals_v3v3(co12, co22)) ||
1676  (equals_v3v3(co11, co22) && equals_v3v3(co12, co21))) {
1677  return true;
1678  }
1679  return false;
1680 }
1681 
1682 /* Callback used in point_is_visible to exclude hits on the faces that are the same
1683  * as or contain the hitting element (which is in user_data).
1684  * Also (see T44492) want to exclude hits on faces that butt up to the hitting element
1685  * (e.g., when you double an edge by an edge split).
1686  */
1688 {
1689  bool ans;
1690  BMEdge *e, *e2;
1691  BMIter iter;
1692 
1693  switch (((BMElem *)user_data)->head.htype) {
1694  case BM_FACE:
1695  ans = (BMFace *)user_data != f;
1696  break;
1697  case BM_EDGE:
1698  e = (BMEdge *)user_data;
1699  ans = !BM_edge_in_face(e, f);
1700  if (ans) {
1701  /* Is it a boundary edge, coincident with a split edge? */
1702  if (BM_edge_is_boundary(e)) {
1703  BM_ITER_ELEM (e2, &iter, f, BM_EDGES_OF_FACE) {
1704  if (coinciding_edges(e, e2)) {
1705  ans = false;
1706  break;
1707  }
1708  }
1709  }
1710  }
1711  break;
1712  case BM_VERT:
1713  ans = !BM_vert_in_face((BMVert *)user_data, f);
1714  break;
1715  default:
1716  ans = true;
1717  break;
1718  }
1719  return ans;
1720 }
1721 
1730  const float p[3],
1731  const float s[2],
1732  BMElem *ele_test)
1733 {
1734  BMFace *f_hit;
1735 
1736  /* If box clipping on, make sure p is not clipped */
1737  if (RV3D_CLIPPING_ENABLED(kcd->vc.v3d, kcd->vc.rv3d) &&
1738  ED_view3d_clipping_test(kcd->vc.rv3d, p, true)) {
1739  return false;
1740  }
1741 
1742  /* If not cutting through, make sure no face is in front of p */
1743  if (!kcd->cut_through) {
1744  float dist;
1745  float view[3], p_ofs[3];
1746 
1747  /* TODO: I think there's a simpler way to get the required raycast ray */
1748  ED_view3d_unproject(kcd->vc.region, s[0], s[1], 0.0f, view);
1749 
1750  mul_m4_v3(kcd->ob_imat, view);
1751 
1752  /* make p_ofs a little towards view, so ray doesn't hit p's face. */
1753  sub_v3_v3(view, p);
1754  dist = normalize_v3(view);
1755  copy_v3_v3(p_ofs, p);
1756 
1757  /* avoid projecting behind the viewpoint */
1758  if (kcd->is_ortho && (kcd->vc.rv3d->persp != RV3D_CAMOB)) {
1759  dist = kcd->vc.v3d->clip_end * 2.0f;
1760  }
1761 
1762  if (RV3D_CLIPPING_ENABLED(kcd->vc.v3d, kcd->vc.rv3d)) {
1763  float view_clip[2][3];
1764  /* note: view_clip[0] should never get clipped */
1765  copy_v3_v3(view_clip[0], p_ofs);
1766  madd_v3_v3v3fl(view_clip[1], p_ofs, view, dist);
1767 
1768  if (clip_segment_v3_plane_n(view_clip[0],
1769  view_clip[1],
1770  kcd->vc.rv3d->clip_local,
1771  6,
1772  view_clip[0],
1773  view_clip[1])) {
1774  dist = len_v3v3(p_ofs, view_clip[1]);
1775  }
1776  }
1777 
1778  /* see if there's a face hit between p1 and the view */
1779  if (ele_test) {
1780  f_hit = BKE_bmbvh_ray_cast_filter(kcd->bmbvh,
1781  p_ofs,
1782  view,
1783  KNIFE_FLT_EPS,
1784  &dist,
1785  NULL,
1786  NULL,
1788  ele_test);
1789  }
1790  else {
1791  f_hit = BKE_bmbvh_ray_cast(kcd->bmbvh, p_ofs, view, KNIFE_FLT_EPS, &dist, NULL, NULL);
1792  }
1793 
1794  if (f_hit) {
1795  return false;
1796  }
1797  }
1798 
1799  return true;
1800 }
1801 
1802 /* Clip the line (v1, v2) to planes perpendicular to it and distances d from
1803  * the closest point on the line to the origin */
1804 static void clip_to_ortho_planes(float v1[3], float v2[3], const float center[3], const float d)
1805 {
1806  float closest[3], dir[3];
1807 
1808  sub_v3_v3v3(dir, v1, v2);
1809  normalize_v3(dir);
1810 
1811  /* could be v1 or v2 */
1812  sub_v3_v3(v1, center);
1815 
1816  madd_v3_v3v3fl(v1, closest, dir, d);
1817  madd_v3_v3v3fl(v2, closest, dir, -d);
1818 }
1819 
1821 {
1822  lh->m = dot_m4_v3_row_z(kcd->vc.rv3d->persmatob, lh->cagehit);
1823 }
1824 
1825 /* Finds visible (or all, if cutting through) edges that intersects the current screen drag line */
1827 {
1828  SmallHash faces, kfes, kfvs;
1829  float v1[3], v2[3], v3[3], v4[3], s1[2], s2[2];
1830  BVHTree *tree;
1831  int *results, *result;
1832  BMLoop **ls;
1833  BMFace *f;
1834  KnifeEdge *kfe;
1835  KnifeVert *v;
1836  ListBase *list;
1837  Ref *ref;
1838  KnifeLineHit *linehits = NULL;
1839  BLI_array_declare(linehits);
1840  SmallHashIter hiter;
1841  KnifeLineHit hit;
1842  void *val;
1843  void **val_p;
1844  float s[2], se1[2], se2[2], sint[2];
1845  float r1[3], r2[3];
1846  float d1, d2, lambda;
1847  float vert_tol, vert_tol_sq;
1848  float line_tol, line_tol_sq;
1849  float face_tol, face_tol_sq;
1850  uint tot;
1851  int i;
1852 
1853  if (kcd->linehits) {
1854  MEM_freeN(kcd->linehits);
1855  kcd->linehits = NULL;
1856  kcd->totlinehit = 0;
1857  }
1858 
1859  copy_v3_v3(v1, kcd->prev.cage);
1860  copy_v3_v3(v2, kcd->curr.cage);
1861 
1862  /* project screen line's 3d coordinates back into 2d */
1863  knife_project_v2(kcd, v1, s1);
1864  knife_project_v2(kcd, v2, s2);
1865 
1866  if (kcd->is_interactive) {
1867  if (len_squared_v2v2(s1, s2) < 1.0f) {
1868  return;
1869  }
1870  }
1871  else {
1872  if (len_squared_v2v2(s1, s2) < KNIFE_FLT_EPS_SQUARED) {
1873  return;
1874  }
1875  }
1876 
1877  /* unproject screen line */
1878  ED_view3d_win_to_segment_clipped(kcd->vc.depsgraph, kcd->region, kcd->vc.v3d, s1, v1, v3, true);
1879  ED_view3d_win_to_segment_clipped(kcd->vc.depsgraph, kcd->region, kcd->vc.v3d, s2, v2, v4, true);
1880 
1881  mul_m4_v3(kcd->ob_imat, v1);
1882  mul_m4_v3(kcd->ob_imat, v2);
1883  mul_m4_v3(kcd->ob_imat, v3);
1884  mul_m4_v3(kcd->ob_imat, v4);
1885 
1886  /* Numeric error, 'v1' -> 'v2', 'v2' -> 'v4'
1887  * can end up being ~2000 units apart with an orthogonal perspective.
1888  *
1889  * (from ED_view3d_win_to_segment_clipped() above)
1890  * this gives precision error; rather than solving properly
1891  * (which may involve using doubles everywhere!),
1892  * limit the distance between these points */
1893  if (kcd->is_ortho && (kcd->vc.rv3d->persp != RV3D_CAMOB)) {
1894  if (kcd->ortho_extent == 0.0f) {
1895  calc_ortho_extent(kcd);
1896  }
1897  clip_to_ortho_planes(v1, v3, kcd->ortho_extent_center, kcd->ortho_extent + 10.0f);
1898  clip_to_ortho_planes(v2, v4, kcd->ortho_extent_center, kcd->ortho_extent + 10.0f);
1899  }
1900 
1901  float plane[4];
1902  {
1903  float v1_v2[3], v1_v3[3];
1904  sub_v3_v3v3(v1_v2, v2, v1);
1905  sub_v3_v3v3(v1_v3, v3, v1);
1906  cross_v3_v3v3(plane, v1_v2, v1_v3);
1907  plane_from_point_normal_v3(plane, v1, plane);
1908  }
1909 
1910  /* First use BVH tree to find faces, knife edges, and knife verts that might
1911  * intersect the cut plane with rays v1-v3 and v2-v4.
1912  * This de-duplicates the candidates before doing more expensive intersection tests. */
1913 
1914  tree = BKE_bmbvh_tree_get(kcd->bmbvh);
1915  results = BLI_bvhtree_intersect_plane(tree, plane, &tot);
1916  if (!results) {
1917  return;
1918  }
1919 
1921  BLI_smallhash_init(&kfes);
1922  BLI_smallhash_init(&kfvs);
1923 
1924  for (i = 0, result = results; i < tot; i++, result++) {
1925  ls = (BMLoop **)kcd->em->looptris[*result];
1926  f = ls[0]->f;
1927  set_lowest_face_tri(kcd, f, *result);
1928 
1929  /* occlude but never cut unselected faces (when only_select is used) */
1930  if (kcd->only_select && !BM_elem_flag_test(f, BM_ELEM_SELECT)) {
1931  continue;
1932  }
1933  /* for faces, store index of lowest hit looptri in hash */
1934  if (BLI_smallhash_haskey(&faces, (uintptr_t)f)) {
1935  continue;
1936  }
1937  /* don't care what the value is except that it is non-NULL, for iterator */
1939 
1940  list = knife_get_face_kedges(kcd, f);
1941  for (ref = list->first; ref; ref = ref->next) {
1942  kfe = ref->ref;
1943  if (BLI_smallhash_haskey(&kfes, (uintptr_t)kfe)) {
1944  continue;
1945  }
1946  BLI_smallhash_insert(&kfes, (uintptr_t)kfe, kfe);
1947  v = kfe->v1;
1948  BLI_smallhash_reinsert(&kfvs, (uintptr_t)v, v);
1949  v = kfe->v2;
1950  BLI_smallhash_reinsert(&kfvs, (uintptr_t)v, v);
1951  }
1952  }
1953 
1954  /* Now go through the candidates and find intersections */
1955  /* These tolerances, in screen space, are for intermediate hits,
1956  * as ends are already snapped to screen. */
1957 
1958  if (kcd->is_interactive) {
1959  vert_tol = KNIFE_FLT_EPS_PX_VERT;
1960  line_tol = KNIFE_FLT_EPS_PX_EDGE;
1961  face_tol = KNIFE_FLT_EPS_PX_FACE;
1962  }
1963  else {
1964  /* Use 1/100th of a pixel, see T43896 (too big), T47910 (too small).
1965  *
1966  * Update, leave this as is until we investigate not using pixel coords
1967  * for geometry calculations: T48023. */
1968  vert_tol = line_tol = face_tol = 0.5f;
1969  }
1970 
1971  vert_tol_sq = vert_tol * vert_tol;
1972  line_tol_sq = line_tol * line_tol;
1973  face_tol_sq = face_tol * face_tol;
1974 
1975  /* Assume these tolerances swamp floating point rounding errors in calculations below */
1976 
1977  /* first look for vertex hits */
1978  for (val_p = BLI_smallhash_iternew_p(&kfvs, &hiter, (uintptr_t *)&v); val_p;
1979  val_p = BLI_smallhash_iternext_p(&hiter, (uintptr_t *)&v)) {
1980  KnifeEdge *kfe_hit = NULL;
1981 
1982  bool kfv_is_in_cut = false;
1983  if (ELEM(v, kcd->prev.vert, kcd->curr.vert)) {
1984  /* This KnifeVert was captured by the snap system.
1985  * Since the tolerance distance can be different, add this vertex directly.
1986  * Otherwise, the cut may fail or a close cut on a connected edge can be performed. */
1987  bm_elem_from_knife_vert(v, &kfe_hit);
1988  copy_v2_v2(s, (v == kcd->prev.vert) ? kcd->prev.mval : kcd->curr.mval);
1989  kfv_is_in_cut = true;
1990  }
1991  else {
1992  knife_project_v2(kcd, v->cageco, s);
1993  float d = dist_squared_to_line_segment_v2(s, s1, s2);
1994  if ((d <= vert_tol_sq) &&
1995  (point_is_visible(kcd, v->cageco, s, bm_elem_from_knife_vert(v, &kfe_hit)))) {
1996  kfv_is_in_cut = true;
1997  }
1998  }
1999 
2000  if (kfv_is_in_cut) {
2001  memset(&hit, 0, sizeof(hit));
2002  hit.v = v;
2003 
2004  /* If this isn't from an existing BMVert, it may have been added to a BMEdge originally.
2005  * knowing if the hit comes from an edge is important for edge-in-face checks later on
2006  * see: #knife_add_single_cut -> #knife_verts_edge_in_face, T42611 */
2007  if (kfe_hit) {
2008  hit.kfe = kfe_hit;
2009  }
2010 
2011  copy_v3_v3(hit.hit, v->co);
2012  copy_v3_v3(hit.cagehit, v->cageco);
2013  copy_v2_v2(hit.schit, s);
2014  set_linehit_depth(kcd, &hit);
2015  BLI_array_append(linehits, hit);
2016  }
2017  else {
2018  /* This vertex isn't used so remove from `kfvs`.
2019  * This is useful to detect KnifeEdges that can be skipped.
2020  * And it optimizes smallhash_iternext a little bit. */
2021  *val_p = NULL;
2022  }
2023  }
2024 
2025  /* now edge hits; don't add if a vertex at end of edge should have hit */
2026  for (val = BLI_smallhash_iternew(&kfes, &hiter, (uintptr_t *)&kfe); val;
2027  val = BLI_smallhash_iternext(&hiter, (uintptr_t *)&kfe)) {
2028 
2029  /* If we intersect any of the vertices, don't attempt to intersect the edge. */
2030  if (BLI_smallhash_lookup(&kfvs, (intptr_t)kfe->v1) ||
2031  BLI_smallhash_lookup(&kfvs, (intptr_t)kfe->v2)) {
2032  continue;
2033  }
2034 
2035  knife_project_v2(kcd, kfe->v1->cageco, se1);
2036  knife_project_v2(kcd, kfe->v2->cageco, se2);
2037  int isect_kind = 1;
2038  if (kfe == kcd->prev.edge) {
2039  /* This KnifeEdge was captured by the snap system. */
2040  copy_v2_v2(sint, kcd->prev.mval);
2041  }
2042  else if (kfe == kcd->curr.edge) {
2043  /* This KnifeEdge was captured by the snap system. */
2044  copy_v2_v2(sint, kcd->curr.mval);
2045  }
2046  else {
2047  isect_kind = isect_seg_seg_v2_point_ex(s1, s2, se1, se2, 0.0f, sint);
2048  if (isect_kind == -1) {
2049  /* isect_seg_seg_v2_point doesn't do tolerance test around ends of s1-s2 */
2050  closest_to_line_segment_v2(sint, s1, se1, se2);
2051  if (len_squared_v2v2(sint, s1) <= line_tol_sq) {
2052  isect_kind = 1;
2053  }
2054  else {
2055  closest_to_line_segment_v2(sint, s2, se1, se2);
2056  if (len_squared_v2v2(sint, s2) <= line_tol_sq) {
2057  isect_kind = 1;
2058  }
2059  }
2060  }
2061  }
2062  if (isect_kind == 1) {
2063  d1 = len_v2v2(sint, se1);
2064  d2 = len_v2v2(se2, se1);
2065  if (!(d1 <= line_tol || d2 <= line_tol || fabsf(d1 - d2) <= line_tol)) {
2066  float p_cage[3], p_cage_tmp[3];
2067  lambda = d1 / d2;
2068  /* Can't just interpolate between ends of kfe because
2069  * that doesn't work with perspective transformation.
2070  * Need to find 3d intersection of ray through sint */
2071  knife_input_ray_segment(kcd, sint, 1.0f, r1, r2);
2072  isect_kind = isect_line_line_v3(
2073  kfe->v1->cageco, kfe->v2->cageco, r1, r2, p_cage, p_cage_tmp);
2074  if (isect_kind >= 1 && point_is_visible(kcd, p_cage, sint, bm_elem_from_knife_edge(kfe))) {
2075  memset(&hit, 0, sizeof(hit));
2076  if (kcd->snap_midpoints) {
2077  /* choose intermediate point snap too */
2078  mid_v3_v3v3(p_cage, kfe->v1->cageco, kfe->v2->cageco);
2079  mid_v2_v2v2(sint, se1, se2);
2080  lambda = 0.5f;
2081  }
2082  hit.kfe = kfe;
2084  hit.hit, p_cage, kfe->v1->co, kfe->v2->co, kfe->v1->cageco, kfe->v2->cageco);
2085  copy_v3_v3(hit.cagehit, p_cage);
2086  copy_v2_v2(hit.schit, sint);
2087  hit.perc = lambda;
2088  set_linehit_depth(kcd, &hit);
2089  BLI_array_append(linehits, hit);
2090  }
2091  }
2092  }
2093  }
2094 
2095  /* now face hits; don't add if a vertex or edge in face should have hit */
2096  const bool use_hit_prev = (kcd->prev.vert == NULL) && (kcd->prev.edge == NULL);
2097  const bool use_hit_curr = (kcd->curr.vert == NULL) && (kcd->curr.edge == NULL) &&
2098  !kcd->is_drag_hold;
2099  if (use_hit_prev || use_hit_curr) {
2100  for (val = BLI_smallhash_iternew(&faces, &hiter, (uintptr_t *)&f); val;
2101  val = BLI_smallhash_iternext(&hiter, (uintptr_t *)&f)) {
2102  float p[3], p_cage[3];
2103 
2104  if (use_hit_prev && knife_ray_intersect_face(kcd, s1, v1, v3, f, face_tol_sq, p, p_cage)) {
2105  if (point_is_visible(kcd, p_cage, s1, (BMElem *)f)) {
2106  memset(&hit, 0, sizeof(hit));
2107  hit.f = f;
2108  copy_v3_v3(hit.hit, p);
2109  copy_v3_v3(hit.cagehit, p_cage);
2110  copy_v2_v2(hit.schit, s1);
2111  set_linehit_depth(kcd, &hit);
2112  BLI_array_append(linehits, hit);
2113  }
2114  }
2115 
2116  if (use_hit_curr && knife_ray_intersect_face(kcd, s2, v2, v4, f, face_tol_sq, p, p_cage)) {
2117  if (point_is_visible(kcd, p_cage, s2, (BMElem *)f)) {
2118  memset(&hit, 0, sizeof(hit));
2119  hit.f = f;
2120  copy_v3_v3(hit.hit, p);
2121  copy_v3_v3(hit.cagehit, p_cage);
2122  copy_v2_v2(hit.schit, s2);
2123  set_linehit_depth(kcd, &hit);
2124  BLI_array_append(linehits, hit);
2125  }
2126  }
2127  }
2128  }
2129 
2130  kcd->linehits = linehits;
2131  kcd->totlinehit = BLI_array_len(linehits);
2132 
2133  /* find position along screen line, used for sorting */
2134  for (i = 0; i < kcd->totlinehit; i++) {
2135  KnifeLineHit *lh = kcd->linehits + i;
2136 
2137  lh->l = len_v2v2(lh->schit, s1) / len_v2v2(s2, s1);
2138  }
2139 
2141  BLI_smallhash_release(&kfes);
2142  BLI_smallhash_release(&kfvs);
2143  if (results) {
2144  MEM_freeN(results);
2145  }
2146 }
2147 
2150 /* -------------------------------------------------------------------- */
2155 {
2156  zero_v3(kpd->co);
2157  zero_v3(kpd->cage);
2158  kpd->vert = NULL;
2159  kpd->edge = NULL;
2160  kpd->bmface = NULL;
2161  zero_v2(kpd->mval);
2162 }
2163 
2166 /* -------------------------------------------------------------------- */
2171  float co[3],
2172  float cageco[3],
2173  bool *is_space)
2174 {
2175  BMFace *f;
2176  float dist = KMAXDIST;
2177  float origin[3];
2178  float origin_ofs[3];
2179  float ray[3], ray_normal[3];
2180 
2181  /* unproject to find view ray */
2182  knife_input_ray_segment(kcd, kcd->curr.mval, 1.0f, origin, origin_ofs);
2183  sub_v3_v3v3(ray, origin_ofs, origin);
2184  normalize_v3_v3(ray_normal, ray);
2185 
2186  f = BKE_bmbvh_ray_cast(kcd->bmbvh, origin, ray_normal, 0.0f, NULL, co, cageco);
2187 
2188  if (f && kcd->only_select && BM_elem_flag_test(f, BM_ELEM_SELECT) == 0) {
2189  f = NULL;
2190  }
2191 
2192  if (is_space) {
2193  *is_space = !f;
2194  }
2195 
2196  if (!f) {
2197  if (kcd->is_interactive) {
2198  /* Try to use back-buffer selection method if ray casting failed.
2199  *
2200  * Apply the mouse coordinates to a copy of the view-context
2201  * since we don't want to rely on this being set elsewhere. */
2202  ViewContext vc = kcd->vc;
2203  vc.mval[0] = (int)kcd->curr.mval[0];
2204  vc.mval[1] = (int)kcd->curr.mval[1];
2205 
2206  f = EDBM_face_find_nearest(&vc, &dist);
2207 
2208  /* cheat for now; just put in the origin instead
2209  * of a true coordinate on the face.
2210  * This just puts a point 1.0f in front of the view. */
2211  add_v3_v3v3(co, origin, ray);
2212  /* Use this value for the cage location too as it's used to find near edges/vertices. */
2213  copy_v3_v3(cageco, co);
2214  }
2215  }
2216 
2217  return f;
2218 }
2219 
2227  const float radius,
2228  BMFace *f,
2229  const float cageco[3])
2230 {
2231  const float radius_sq = radius * radius;
2232  ListBase *list;
2233  Ref *ref;
2234  float sco[2];
2235  float dis_sq;
2236  int c = 0;
2237 
2238  knife_project_v2(kcd, cageco, sco);
2239 
2240  list = knife_get_face_kedges(kcd, f);
2241  for (ref = list->first; ref; ref = ref->next) {
2242  KnifeEdge *kfe = ref->ref;
2243  int i;
2244 
2245  for (i = 0; i < 2; i++) {
2246  KnifeVert *kfv = i ? kfe->v2 : kfe->v1;
2247  float kfv_sco[2];
2248 
2249  knife_project_v2(kcd, kfv->cageco, kfv_sco);
2250 
2251  dis_sq = len_squared_v2v2(kfv_sco, sco);
2252  if (dis_sq < radius_sq) {
2253  if (RV3D_CLIPPING_ENABLED(kcd->vc.v3d, kcd->vc.rv3d)) {
2254  if (ED_view3d_clipping_test(kcd->vc.rv3d, kfv->cageco, true) == 0) {
2255  c++;
2256  }
2257  }
2258  else {
2259  c++;
2260  }
2261  }
2262  }
2263  }
2264 
2265  return c;
2266 }
2267 
2274 static float knife_snap_size(KnifeTool_OpData *kcd, float maxsize)
2275 {
2276  BLI_assert(kcd->is_interactive == true);
2277  int density = 0;
2278 
2279  if (!kcd->curr.is_space) {
2281  kcd, maxsize * 2.0f, kcd->curr.bmface, kcd->curr.cage);
2282  }
2283 
2284  return density ? min_ff(maxsize / ((float)density * 0.5f), maxsize) : maxsize;
2285 }
2286 
2287 /* Snap to edge in a specified angle.
2288  * Returns 'lambda' calculated (in screen-space). */
2290  const float sco[3],
2291  const float kfv1_sco[2],
2292  const float kfv2_sco[2],
2293  float *r_dist_sq,
2294  float *r_lambda)
2295 {
2296  /* if snapping, check we're in bounds */
2297  float sco_snap[2];
2298  isect_line_line_v2_point(kfv1_sco, kfv2_sco, kcd->prev.mval, kcd->curr.mval, sco_snap);
2299  float lambda = line_point_factor_v2(sco_snap, kfv1_sco, kfv2_sco);
2300 
2301  /* be strict about angle-snapping within edge */
2302  if ((lambda < 0.0f - KNIFE_FLT_EPSBIG) || (lambda > 1.0f + KNIFE_FLT_EPSBIG)) {
2303  return false;
2304  }
2305 
2306  float dis_sq = len_squared_v2v2(sco, sco_snap);
2307  if (dis_sq < *r_dist_sq) {
2308  *r_dist_sq = dis_sq;
2309  *r_lambda = lambda;
2310  return true;
2311  }
2312  return false;
2313 }
2314 
2315 /* use when lambda is in screen-space */
2317  float r_co[3],
2318  const float v1[3],
2319  const float v2[3],
2320  float lambda_ss)
2321 {
2322  if (kcd->is_ortho) {
2323  interp_v3_v3v3(r_co, v1, v2, lambda_ss);
2324  }
2325  else {
2326  /* transform into screen-space, interp, then transform back */
2327  float v1_ss[3], v2_ss[3];
2328 
2329  mul_v3_project_m4_v3(v1_ss, (float(*)[4])kcd->projmat, v1);
2330  mul_v3_project_m4_v3(v2_ss, (float(*)[4])kcd->projmat, v2);
2331 
2332  interp_v3_v3v3(r_co, v1_ss, v2_ss, lambda_ss);
2333 
2334  mul_project_m4_v3((float(*)[4])kcd->projmat_inv, r_co);
2335  }
2336 }
2337 
2338 /* p is closest point on edge to the mouse cursor */
2340  BMFace *f,
2341  float p[3],
2342  float cagep[3])
2343 {
2344  float sco[2];
2345  float maxdist;
2346 
2347  if (kcd->is_interactive) {
2348  maxdist = knife_snap_size(kcd, kcd->ethresh);
2349 
2350  if (kcd->ignore_vert_snapping) {
2351  maxdist *= 0.5f;
2352  }
2353  }
2354  else {
2355  maxdist = KNIFE_FLT_EPS;
2356  }
2357 
2358  const float maxdist_sq = maxdist * maxdist;
2359  KnifeEdge *cure = NULL;
2360  float cur_cagep[3];
2361  ListBase *list;
2362  Ref *ref;
2363  float dis_sq, curdis_sq = maxdist_sq;
2364 
2365  knife_project_v2(kcd, cagep, sco);
2366 
2367  /* look through all edges associated with this face */
2368  list = knife_get_face_kedges(kcd, f);
2369  for (ref = list->first; ref; ref = ref->next) {
2370  KnifeEdge *kfe = ref->ref;
2371  float kfv1_sco[2], kfv2_sco[2], test_cagep[3];
2372  float lambda;
2373 
2374  /* project edge vertices into screen space */
2375  knife_project_v2(kcd, kfe->v1->cageco, kfv1_sco);
2376  knife_project_v2(kcd, kfe->v2->cageco, kfv2_sco);
2377 
2378  /* check if we're close enough and calculate 'lambda' */
2379  if (kcd->is_angle_snapping) {
2380  dis_sq = curdis_sq;
2381  if (!knife_snap_edge_in_angle(kcd, sco, kfv1_sco, kfv2_sco, &dis_sq, &lambda)) {
2382  continue;
2383  }
2384  }
2385  else {
2386  dis_sq = dist_squared_to_line_segment_v2(sco, kfv1_sco, kfv2_sco);
2387  if (dis_sq < curdis_sq) {
2388  lambda = line_point_factor_v2(sco, kfv1_sco, kfv2_sco);
2389  }
2390  else {
2391  continue;
2392  }
2393  }
2394 
2395  /* now we have 'lambda' calculated (in screen-space) */
2396  knife_interp_v3_v3v3(kcd, test_cagep, kfe->v1->cageco, kfe->v2->cageco, lambda);
2397 
2398  if (RV3D_CLIPPING_ENABLED(kcd->vc.v3d, kcd->vc.rv3d)) {
2399  /* check we're in the view */
2400  if (ED_view3d_clipping_test(kcd->vc.rv3d, test_cagep, true)) {
2401  continue;
2402  }
2403  }
2404 
2405  cure = kfe;
2406  curdis_sq = dis_sq;
2407  copy_v3_v3(cur_cagep, test_cagep);
2408  }
2409 
2410  if (cure && !kcd->ignore_edge_snapping) {
2411  KnifeVert *edgesnap = NULL;
2412 
2413  if (kcd->snap_midpoints) {
2414  mid_v3_v3v3(p, cure->v1->co, cure->v2->co);
2415  mid_v3_v3v3(cagep, cure->v1->cageco, cure->v2->cageco);
2416  }
2417  else {
2418  float lambda = line_point_factor_v3(cur_cagep, cure->v1->cageco, cure->v2->cageco);
2419  copy_v3_v3(cagep, cur_cagep);
2420  interp_v3_v3v3(p, cure->v1->co, cure->v2->co, lambda);
2421  }
2422 
2423  /* update mouse coordinates to the snapped-to edge's screen coordinates
2424  * this is important for angle snap, which uses the previous mouse position */
2425  edgesnap = new_knife_vert(kcd, p, cagep);
2426  knife_project_v2(kcd, edgesnap->cageco, kcd->curr.mval);
2427  }
2428 
2429  return cure;
2430 }
2431 
2432 /* find a vertex near the mouse cursor, if it exists */
2434  KnifeEdge *kfe,
2435  float p[3],
2436  float cagep[3])
2437 {
2438  float sco[2];
2439  float maxdist;
2440 
2441  if (kcd->is_interactive) {
2442  maxdist = knife_snap_size(kcd, kcd->vthresh);
2443  if (kcd->ignore_vert_snapping) {
2444  maxdist *= 0.5f;
2445  }
2446  }
2447  else {
2448  maxdist = KNIFE_FLT_EPS;
2449  }
2450 
2451  const float maxdist_sq = maxdist * maxdist;
2452  KnifeVert *curv = NULL;
2453  float cur_kfv_sco[2];
2454  float dis_sq, curdis_sq = FLT_MAX;
2455 
2456  knife_project_v2(kcd, cagep, sco);
2457 
2458  for (int i = 0; i < 2; i++) {
2459  KnifeVert *kfv = i ? kfe->v2 : kfe->v1;
2460  float kfv_sco[2];
2461 
2462  knife_project_v2(kcd, kfv->cageco, kfv_sco);
2463 
2464  /* be strict about angle snapping, the vertex needs to be very close to the angle,
2465  * or we ignore */
2466  if (kcd->is_angle_snapping) {
2467  if (dist_squared_to_line_segment_v2(kfv_sco, kcd->prev.mval, kcd->curr.mval) >
2468  KNIFE_FLT_EPSBIG) {
2469  continue;
2470  }
2471  }
2472 
2473  dis_sq = len_squared_v2v2(kfv_sco, sco);
2474  if (dis_sq < curdis_sq && dis_sq < maxdist_sq) {
2475  if (!RV3D_CLIPPING_ENABLED(kcd->vc.v3d, kcd->vc.rv3d) ||
2476  !ED_view3d_clipping_test(kcd->vc.rv3d, kfv->cageco, true)) {
2477  curv = kfv;
2478  curdis_sq = dis_sq;
2479  copy_v2_v2(cur_kfv_sco, kfv_sco);
2480  }
2481  }
2482  }
2483 
2484  if (curv && !kcd->ignore_vert_snapping) {
2485  copy_v3_v3(p, curv->co);
2486  copy_v3_v3(cagep, curv->cageco);
2487 
2488  /* update mouse coordinates to the snapped-to vertex's screen coordinates
2489  * this is important for angle snap, which uses the previous mouse position */
2490  copy_v2_v2(kcd->curr.mval, cur_kfv_sco);
2491  }
2492 
2493  return curv;
2494 }
2495 
2499 static float snap_v2_angle(float r[2], const float v[2], const float v_ref[2], float angle_snap)
2500 {
2501  float m2[2][2];
2502  float v_unit[2];
2503  float angle, angle_delta;
2504 
2505  BLI_ASSERT_UNIT_V2(v_ref);
2506 
2507  normalize_v2_v2(v_unit, v);
2508  angle = angle_signed_v2v2(v_unit, v_ref);
2509  angle_delta = (roundf(angle / angle_snap) * angle_snap) - angle;
2510  angle_to_mat2(m2, angle_delta);
2511 
2512  mul_v2_m2v2(r, m2, v);
2513  return angle + angle_delta;
2514 }
2515 
2516 /* update both kcd->curr.mval and kcd->mval to snap to required angle */
2518 {
2519  const float dvec_ref[2] = {0.0f, 1.0f};
2520  float dvec[2], dvec_snap[2];
2521  float snap_step = DEG2RADF(45);
2522 
2523  sub_v2_v2v2(dvec, kcd->curr.mval, kcd->prev.mval);
2524  if (is_zero_v2(dvec)) {
2525  return false;
2526  }
2527 
2528  kcd->angle = snap_v2_angle(dvec_snap, dvec, dvec_ref, snap_step);
2529 
2530  add_v2_v2v2(kcd->curr.mval, kcd->prev.mval, dvec_snap);
2531 
2532  copy_v2_v2(kcd->mval, kcd->curr.mval);
2533 
2534  return true;
2535 }
2536 
2545 static bool knife_snap_update_from_mval(KnifeTool_OpData *kcd, const float mval[2])
2546 {
2547  knife_pos_data_clear(&kcd->curr);
2548  copy_v2_v2(kcd->curr.mval, mval);
2549 
2550  /* view matrix may have changed, reproject */
2551  knife_project_v2(kcd, kcd->prev.cage, kcd->prev.mval);
2552 
2553  if (kcd->angle_snapping && (kcd->mode == MODE_DRAGGING)) {
2554  kcd->is_angle_snapping = knife_snap_angle(kcd);
2555  }
2556  else {
2557  kcd->is_angle_snapping = false;
2558  }
2559 
2560  {
2562  kcd, kcd->curr.co, kcd->curr.cage, &kcd->curr.is_space);
2563 
2564  if (kcd->curr.bmface) {
2566  kcd, kcd->curr.bmface, kcd->curr.co, kcd->curr.cage);
2567  }
2568 
2569  if (kcd->curr.edge) {
2571  kcd, kcd->curr.edge, kcd->curr.co, kcd->curr.cage);
2572 
2573  if (kcd->ignore_edge_snapping) {
2574  kcd->curr.edge = NULL;
2575  }
2576  }
2577  }
2578 
2579  return kcd->curr.vert || kcd->curr.edge || (kcd->curr.bmface && !kcd->curr.is_space);
2580 }
2581 
2584 /* -------------------------------------------------------------------- */
2589 {
2591 
2592  Scene *scene_eval = (Scene *)DEG_get_evaluated_id(kcd->vc.depsgraph, &kcd->scene->id);
2593  Object *obedit_eval = (Object *)DEG_get_evaluated_id(kcd->vc.depsgraph, &kcd->ob->id);
2594  BMEditMesh *em_eval = BKE_editmesh_from_object(obedit_eval);
2595 
2596  kcd->cagecos = (const float(*)[3])BKE_editmesh_vert_coords_alloc(
2597  kcd->vc.depsgraph, em_eval, scene_eval, obedit_eval, NULL);
2598 
2600  kcd->em,
2603  kcd->cagecos,
2604  false);
2605 }
2606 
2608 {
2609  if (kcd->bmbvh) {
2610  BKE_bmbvh_free(kcd->bmbvh);
2611  kcd->bmbvh = NULL;
2612  }
2613 
2614  if (kcd->cagecos) {
2615  MEM_freeN((void *)kcd->cagecos);
2616  kcd->cagecos = NULL;
2617  }
2618 }
2619 
2620 static void knife_init_colors(KnifeColors *colors)
2621 {
2622  /* possible BMESH_TODO: add explicit themes or calculate these by
2623  * figuring out contrasting colors with grid / edges / verts
2624  * a la UI_make_axis_color */
2629  colors->curpoint_a[3] = 102;
2632  colors->point_a[3] = 102;
2633 }
2634 
2635 /* called when modal loop selection gets set up... */
2637  KnifeTool_OpData *kcd,
2638  const bool only_select,
2639  const bool cut_through,
2640  const bool is_interactive)
2641 {
2643  Object *obedit = CTX_data_edit_object(C);
2644 
2645  /* assign the drawing handle for drawing preview line... */
2646  kcd->scene = scene;
2647  kcd->ob = obedit;
2648  kcd->region = CTX_wm_region(C);
2649 
2650  invert_m4_m4_safe_ortho(kcd->ob_imat, kcd->ob->obmat);
2651 
2652  em_setup_viewcontext(C, &kcd->vc);
2653 
2654  kcd->em = BKE_editmesh_from_object(kcd->ob);
2655 
2656  /* cut all the way through the mesh if use_occlude_geometry button not pushed */
2657  kcd->is_interactive = is_interactive;
2658  kcd->cut_through = cut_through;
2659  kcd->only_select = only_select;
2660 
2661  knifetool_init_bmbvh(kcd);
2662 
2663  kcd->arena = BLI_memarena_new(MEM_SIZE_OPTIMAL(1 << 15), "knife");
2664 #ifdef USE_NET_ISLAND_CONNECT
2665  kcd->edgenet.arena = BLI_memarena_new(MEM_SIZE_OPTIMAL(1 << 15), __func__);
2666 #endif
2667  kcd->edgenet.edge_visit = BLI_gset_ptr_new(__func__);
2668 
2669  kcd->vthresh = KMAXDIST - 1;
2670  kcd->ethresh = KMAXDIST;
2671 
2672  knife_recalc_projmat(kcd);
2673 
2675 
2676  kcd->refs = BLI_mempool_create(sizeof(Ref), 0, 2048, 0);
2677  kcd->kverts = BLI_mempool_create(sizeof(KnifeVert), 0, 512, BLI_MEMPOOL_ALLOW_ITER);
2678  kcd->kedges = BLI_mempool_create(sizeof(KnifeEdge), 0, 512, BLI_MEMPOOL_ALLOW_ITER);
2679 
2680  kcd->origedgemap = BLI_ghash_ptr_new("knife origedgemap");
2681  kcd->origvertmap = BLI_ghash_ptr_new("knife origvertmap");
2682  kcd->kedgefacemap = BLI_ghash_ptr_new("knife kedgefacemap");
2683  kcd->facetrimap = BLI_ghash_ptr_new("knife facetrimap");
2684 
2685  /* can't usefully select resulting edges in face mode */
2686  kcd->select_result = (kcd->em->selectmode != SCE_SELECT_FACE);
2687 
2688  knife_pos_data_clear(&kcd->curr);
2689  knife_pos_data_clear(&kcd->prev);
2690 
2691  if (is_interactive) {
2694 
2695  knife_init_colors(&kcd->colors);
2696  }
2697 }
2698 
2699 /* called when modal loop selection is done... */
2701 {
2702  if (!kcd) {
2703  return;
2704  }
2705 
2706  if (kcd->is_interactive) {
2708 
2709  /* deactivate the extra drawing stuff in 3D-View */
2711  }
2712 
2713  /* free the custom data */
2714  BLI_mempool_destroy(kcd->refs);
2717 
2722 
2723  BLI_memarena_free(kcd->arena);
2724 #ifdef USE_NET_ISLAND_CONNECT
2726 #endif
2728 
2729  /* tag for redraw */
2731 
2732  knifetool_free_bmbvh(kcd);
2733 
2734  if (kcd->linehits) {
2735  MEM_freeN(kcd->linehits);
2736  }
2737 
2738  /* destroy kcd itself */
2739  MEM_freeN(kcd);
2740 }
2742 {
2743  KnifeTool_OpData *kcd = op->customdata;
2744  knifetool_exit_ex(C, kcd);
2745  op->customdata = NULL;
2746 }
2747 
2750 /* -------------------------------------------------------------------- */
2754 /* update active knife edge/vert pointers */
2756 {
2757  /* if no hits are found this would normally default to (0, 0, 0) so instead
2758  * get a point at the mouse ray closest to the previous point.
2759  * Note that drawing lines in `free-space` isn't properly supported
2760  * but there's no guarantee (0, 0, 0) has any geometry either - campbell */
2761  if (!knife_snap_update_from_mval(kcd, kcd->mval)) {
2762  float origin[3];
2763  float origin_ofs[3];
2764 
2765  knife_input_ray_segment(kcd, kcd->curr.mval, 1.0f, origin, origin_ofs);
2766 
2767  if (!isect_line_plane_v3(
2768  kcd->curr.cage, origin, origin_ofs, kcd->prev.cage, kcd->proj_zaxis)) {
2769  copy_v3_v3(kcd->curr.cage, kcd->prev.cage);
2770 
2771  /* should never fail! */
2772  BLI_assert(0);
2773  }
2774  }
2775 
2776  if (kcd->mode == MODE_DRAGGING) {
2777  knife_find_line_hits(kcd);
2778  }
2779  return 1;
2780 }
2781 
2782 static void knifetool_update_mval(KnifeTool_OpData *kcd, const float mval[2])
2783 {
2784  knife_recalc_projmat(kcd);
2785  copy_v2_v2(kcd->mval, mval);
2786 
2787  if (knife_update_active(kcd)) {
2789  }
2790 }
2791 
2792 static void knifetool_update_mval_i(KnifeTool_OpData *kcd, const int mval_i[2])
2793 {
2794  const float mval[2] = {UNPACK2(mval_i)};
2795  knifetool_update_mval(kcd, mval);
2796 }
2797 
2800 /* -------------------------------------------------------------------- */
2804 /* called on tool confirmation */
2806 {
2807  knife_make_cuts(kcd);
2808 
2809  EDBM_selectmode_flush(kcd->em);
2811  EDBM_update_generic(kcd->ob->data, true, true);
2812 
2813  /* Re-tessellating makes this invalid, don't use again by accident. */
2814  knifetool_free_bmbvh(kcd);
2815 }
2816 
2818 {
2819  KnifeTool_OpData *kcd = op->customdata;
2820  knifetool_finish_ex(kcd);
2821 }
2822 
2825 /* -------------------------------------------------------------------- */
2830 {
2831  /* this is just a wrapper around exit() */
2832  knifetool_exit(C, op);
2833 }
2834 
2836 {
2837  static const EnumPropertyItem modal_items[] = {
2838  {KNF_MODAL_CANCEL, "CANCEL", 0, "Cancel", ""},
2839  {KNF_MODAL_CONFIRM, "CONFIRM", 0, "Confirm", ""},
2840  {KNF_MODAL_MIDPOINT_ON, "SNAP_MIDPOINTS_ON", 0, "Snap to Midpoints On", ""},
2841  {KNF_MODAL_MIDPOINT_OFF, "SNAP_MIDPOINTS_OFF", 0, "Snap to Midpoints Off", ""},
2842  {KNF_MODAL_IGNORE_SNAP_ON, "IGNORE_SNAP_ON", 0, "Ignore Snapping On", ""},
2843  {KNF_MODAL_IGNORE_SNAP_OFF, "IGNORE_SNAP_OFF", 0, "Ignore Snapping Off", ""},
2844  {KNF_MODAL_ANGLE_SNAP_TOGGLE, "ANGLE_SNAP_TOGGLE", 0, "Toggle Angle Snapping", ""},
2845  {KNF_MODAL_CUT_THROUGH_TOGGLE, "CUT_THROUGH_TOGGLE", 0, "Toggle Cut Through", ""},
2846  {KNF_MODAL_NEW_CUT, "NEW_CUT", 0, "End Current Cut", ""},
2847  {KNF_MODAL_ADD_CUT, "ADD_CUT", 0, "Add Cut", ""},
2848  {KNF_MODAL_ADD_CUT_CLOSED, "ADD_CUT_CLOSED", 0, "Add Cut Closed", ""},
2849  {KNF_MODAL_PANNING, "PANNING", 0, "Panning", ""},
2850  {0, NULL, 0, NULL, NULL},
2851  };
2852 
2853  wmKeyMap *keymap = WM_modalkeymap_find(keyconf, "Knife Tool Modal Map");
2854 
2855  /* this function is called for each spacetype, only needs to add map once */
2856  if (keymap && keymap->modal_items) {
2857  return NULL;
2858  }
2859 
2860  keymap = WM_modalkeymap_ensure(keyconf, "Knife Tool Modal Map", modal_items);
2861 
2862  WM_modalkeymap_assign(keymap, "MESH_OT_knife_tool");
2863 
2864  return keymap;
2865 }
2866 
2867 static int knifetool_modal(bContext *C, wmOperator *op, const wmEvent *event)
2868 {
2869  Object *obedit = CTX_data_edit_object(C);
2870  KnifeTool_OpData *kcd = op->customdata;
2871  bool do_refresh = false;
2872 
2873  if (!obedit || obedit->type != OB_MESH || BKE_editmesh_from_object(obedit) != kcd->em) {
2874  knifetool_exit(C, op);
2876  return OPERATOR_FINISHED;
2877  }
2878 
2879  em_setup_viewcontext(C, &kcd->vc);
2880  kcd->region = kcd->vc.region;
2881 
2882  ED_view3d_init_mats_rv3d(obedit, kcd->vc.rv3d); /* needed to initialize clipping */
2883 
2884  if (kcd->mode == MODE_PANNING) {
2885  kcd->mode = kcd->prevmode;
2886  }
2887 
2888  /* handle modal keymap */
2889  if (event->type == EVT_MODAL_MAP) {
2890  switch (event->val) {
2891  case KNF_MODAL_CANCEL:
2892  /* finish */
2894 
2895  knifetool_exit(C, op);
2897 
2898  return OPERATOR_CANCELLED;
2899  case KNF_MODAL_CONFIRM:
2900  /* finish */
2902 
2903  knifetool_finish(op);
2904  knifetool_exit(C, op);
2906 
2907  return OPERATOR_FINISHED;
2908  case KNF_MODAL_MIDPOINT_ON:
2909  kcd->snap_midpoints = true;
2910 
2911  knife_recalc_projmat(kcd);
2912  knife_update_active(kcd);
2913  knife_update_header(C, op, kcd);
2915  do_refresh = true;
2916  break;
2918  kcd->snap_midpoints = false;
2919 
2920  knife_recalc_projmat(kcd);
2921  knife_update_active(kcd);
2922  knife_update_header(C, op, kcd);
2924  do_refresh = true;
2925  break;
2928  kcd->ignore_vert_snapping = kcd->ignore_edge_snapping = true;
2929  knife_update_header(C, op, kcd);
2930  do_refresh = true;
2931  break;
2934  kcd->ignore_vert_snapping = kcd->ignore_edge_snapping = false;
2935  knife_update_header(C, op, kcd);
2936  do_refresh = true;
2937  break;
2939  kcd->angle_snapping = !kcd->angle_snapping;
2940  knife_update_header(C, op, kcd);
2941  do_refresh = true;
2942  break;
2944  kcd->cut_through = !kcd->cut_through;
2945  knife_update_header(C, op, kcd);
2946  do_refresh = true;
2947  break;
2948  case KNF_MODAL_NEW_CUT:
2950  knife_finish_cut(kcd);
2951  kcd->mode = MODE_IDLE;
2952  break;
2953  case KNF_MODAL_ADD_CUT:
2954  knife_recalc_projmat(kcd);
2955 
2956  /* get the value of the event which triggered this one */
2957  if (event->prevval != KM_RELEASE) {
2958  if (kcd->mode == MODE_DRAGGING) {
2959  knife_add_cut(kcd);
2960  }
2961  else if (kcd->mode != MODE_PANNING) {
2962  knife_start_cut(kcd);
2963  kcd->mode = MODE_DRAGGING;
2964  kcd->init = kcd->curr;
2965  }
2966 
2967  /* freehand drawing is incompatible with cut-through */
2968  if (kcd->cut_through == false) {
2969  kcd->is_drag_hold = true;
2970  /* No edge snapping while dragging (edges are too sticky when cuts are immediate). */
2971  kcd->ignore_edge_snapping = true;
2972  }
2973  }
2974  else {
2975  kcd->is_drag_hold = false;
2976  kcd->ignore_edge_snapping = false;
2977 
2978  /* needed because the last face 'hit' is ignored when dragging */
2979  knifetool_update_mval(kcd, kcd->curr.mval);
2980  }
2981 
2983  break;
2985  if (kcd->mode == MODE_DRAGGING) {
2986 
2987  /* Shouldn't be possible with default key-layout, just in case. */
2988  if (kcd->is_drag_hold) {
2989  kcd->is_drag_hold = false;
2990  knifetool_update_mval(kcd, kcd->curr.mval);
2991  }
2992 
2993  kcd->prev = kcd->curr;
2994  kcd->curr = kcd->init;
2995 
2996  knife_project_v2(kcd, kcd->curr.cage, kcd->curr.mval);
2997  knifetool_update_mval(kcd, kcd->curr.mval);
2998 
2999  knife_add_cut(kcd);
3000 
3001  /* KNF_MODAL_NEW_CUT */
3002  knife_finish_cut(kcd);
3003  kcd->mode = MODE_IDLE;
3004  }
3005  break;
3006  case KNF_MODAL_PANNING:
3007  if (event->val != KM_RELEASE) {
3008  if (kcd->mode != MODE_PANNING) {
3009  kcd->prevmode = kcd->mode;
3010  kcd->mode = MODE_PANNING;
3011  }
3012  }
3013  else {
3014  kcd->mode = kcd->prevmode;
3015  }
3016 
3018  return OPERATOR_PASS_THROUGH;
3019  }
3020  }
3021  else { /* non-modal-mapped events */
3022  switch (event->type) {
3023  case MOUSEPAN:
3024  case MOUSEZOOM:
3025  case MOUSEROTATE:
3026  case WHEELUPMOUSE:
3027  case WHEELDOWNMOUSE:
3028  case NDOF_MOTION:
3029  return OPERATOR_PASS_THROUGH;
3030  case MOUSEMOVE: /* mouse moved somewhere to select another loop */
3031  if (kcd->mode != MODE_PANNING) {
3032  knifetool_update_mval_i(kcd, event->mval);
3033 
3034  if (kcd->is_drag_hold) {
3035  if (kcd->totlinehit >= 2) {
3036  knife_add_cut(kcd);
3037  }
3038  }
3039  }
3040 
3041  break;
3042  }
3043  }
3044 
3045  if (kcd->mode == MODE_DRAGGING) {
3047  }
3048  else {
3050  }
3051 
3052  if (do_refresh) {
3053  /* we don't really need to update mval,
3054  * but this happens to be the best way to refresh at the moment */
3055  knifetool_update_mval_i(kcd, event->mval);
3056  }
3057 
3058  /* keep going until the user confirms */
3059  return OPERATOR_RUNNING_MODAL;
3060 }
3061 
3062 static int knifetool_invoke(bContext *C, wmOperator *op, const wmEvent *event)
3063 {
3064  const bool only_select = RNA_boolean_get(op->ptr, "only_selected");
3065  const bool cut_through = !RNA_boolean_get(op->ptr, "use_occlude_geometry");
3066  const bool wait_for_input = RNA_boolean_get(op->ptr, "wait_for_input");
3067 
3068  KnifeTool_OpData *kcd;
3069 
3070  if (only_select) {
3071  Object *obedit = CTX_data_edit_object(C);
3072  BMEditMesh *em = BKE_editmesh_from_object(obedit);
3073  if (em->bm->totfacesel == 0) {
3074  BKE_report(op->reports, RPT_ERROR, "Selected faces required");
3075  return OPERATOR_CANCELLED;
3076  }
3077  }
3078 
3079  /* alloc new customdata */
3080  kcd = op->customdata = MEM_callocN(sizeof(KnifeTool_OpData), __func__);
3081 
3082  knifetool_init(C, kcd, only_select, cut_through, true);
3083 
3085 
3086  /* add a modal handler for this operator - handles loop selection */
3089 
3090  knifetool_update_mval_i(kcd, event->mval);
3091 
3092  if (wait_for_input == false) {
3093  /* Avoid copy-paste logic. */
3094  wmEvent event_modal = {
3095  .prevval = KM_NOTHING,
3096  .type = EVT_MODAL_MAP,
3097  .val = KNF_MODAL_ADD_CUT,
3098  };
3099  int ret = knifetool_modal(C, op, &event_modal);
3102  }
3103 
3104  knife_update_header(C, op, kcd);
3105 
3106  return OPERATOR_RUNNING_MODAL;
3107 }
3108 
3110 {
3111  /* description */
3112  ot->name = "Knife Topology Tool";
3113  ot->idname = "MESH_OT_knife_tool";
3114  ot->description = "Cut new topology";
3115 
3116  /* callbacks */
3121 
3122  /* flags */
3124 
3125  /* properties */
3126  PropertyRNA *prop;
3128  "use_occlude_geometry",
3129  true,
3130  "Occlude Geometry",
3131  "Only cut the front most geometry");
3132  RNA_def_boolean(ot->srna, "only_selected", false, "Only Selected", "Only cut selected geometry");
3133 
3134  prop = RNA_def_boolean(ot->srna, "wait_for_input", true, "Wait for Input", "");
3136 }
3137 
3140 /* -------------------------------------------------------------------- */
3146 static bool edbm_mesh_knife_point_isect(LinkNode *polys, const float cent_ss[2])
3147 {
3148  LinkNode *p = polys;
3149  int isect = 0;
3150 
3151  while (p) {
3152  const float(*mval_fl)[2] = p->link;
3153  const int mval_tot = MEM_allocN_len(mval_fl) / sizeof(*mval_fl);
3154  isect += (int)isect_point_poly_v2(cent_ss, mval_fl, mval_tot - 1, false);
3155  p = p->next;
3156  }
3157 
3158  if (isect % 2) {
3159  return true;
3160  }
3161  return false;
3162 }
3163 
3167 void EDBM_mesh_knife(bContext *C, LinkNode *polys, bool use_tag, bool cut_through)
3168 {
3169  KnifeTool_OpData *kcd;
3170 
3171  /* init */
3172  {
3173  const bool only_select = false;
3174  const bool is_interactive = false; /* can enable for testing */
3175 
3176  kcd = MEM_callocN(sizeof(KnifeTool_OpData), __func__);
3177 
3178  knifetool_init(C, kcd, only_select, cut_through, is_interactive);
3179 
3180  kcd->ignore_edge_snapping = true;
3181  kcd->ignore_vert_snapping = true;
3182 
3183  if (use_tag) {
3185  }
3186  }
3187 
3188  /* execute */
3189  {
3190  LinkNode *p = polys;
3191 
3192  knife_recalc_projmat(kcd);
3193 
3194  while (p) {
3195  const float(*mval_fl)[2] = p->link;
3196  const int mval_tot = MEM_allocN_len(mval_fl) / sizeof(*mval_fl);
3197  int i;
3198 
3199  for (i = 0; i < mval_tot; i++) {
3200  knifetool_update_mval(kcd, mval_fl[i]);
3201  if (i == 0) {
3202  knife_start_cut(kcd);
3203  kcd->mode = MODE_DRAGGING;
3204  }
3205  else {
3206  knife_add_cut(kcd);
3207  }
3208  }
3209  knife_finish_cut(kcd);
3210  kcd->mode = MODE_IDLE;
3211  p = p->next;
3212  }
3213  }
3214 
3215  /* finish */
3216  {
3217  knifetool_finish_ex(kcd);
3218 
3219  /* tag faces inside! */
3220  if (use_tag) {
3221  BMesh *bm = kcd->em->bm;
3222  float projmat[4][4];
3223 
3224  BMEdge *e;
3225  BMIter iter;
3226 
3227  bool keep_search;
3228 
3229  /* freed on knifetool_finish_ex, but we need again to check if points are visible */
3230  if (kcd->cut_through == false) {
3231  knifetool_init_bmbvh(kcd);
3232  }
3233 
3234  ED_view3d_ob_project_mat_get(kcd->region->regiondata, kcd->ob, projmat);
3235 
3236  /* use face-loop tag to store if we have intersected */
3237 #define F_ISECT_IS_UNKNOWN(f) BM_elem_flag_test(BM_FACE_FIRST_LOOP(f), BM_ELEM_TAG)
3238 #define F_ISECT_SET_UNKNOWN(f) BM_elem_flag_enable(BM_FACE_FIRST_LOOP(f), BM_ELEM_TAG)
3239 #define F_ISECT_SET_OUTSIDE(f) BM_elem_flag_disable(BM_FACE_FIRST_LOOP(f), BM_ELEM_TAG)
3240  {
3241  BMFace *f;
3242  BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
3245  }
3246  }
3247 
3248  /* tag all faces linked to cut edges */
3249  BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
3250  /* check are we tagged?, then we are an original face */
3251  if (BM_elem_flag_test(e, BM_ELEM_TAG) == false) {
3252  BMFace *f;
3253  BMIter fiter;
3254  BM_ITER_ELEM (f, &fiter, e, BM_FACES_OF_EDGE) {
3255  float cent[3], cent_ss[2];
3256  BM_face_calc_point_in_face(f, cent);
3257  knife_project_v2(kcd, cent, cent_ss);
3258  if (edbm_mesh_knife_point_isect(polys, cent_ss)) {
3260  }
3261  }
3262  }
3263  }
3264 
3265  /* expand tags for faces which are not cut, but are inside the polys */
3266  do {
3267  BMFace *f;
3268  keep_search = false;
3269  BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
3270  if (BM_elem_flag_test(f, BM_ELEM_TAG) == false && (F_ISECT_IS_UNKNOWN(f))) {
3271  /* am I connected to a tagged face via an un-tagged edge
3272  * (ie, not across a cut) */
3273  BMLoop *l_first = BM_FACE_FIRST_LOOP(f);
3274  BMLoop *l_iter = l_first;
3275  bool found = false;
3276 
3277  do {
3278  if (BM_elem_flag_test(l_iter->e, BM_ELEM_TAG) != false) {
3279  /* now check if the adjacent faces is tagged */
3280  BMLoop *l_radial_iter = l_iter->radial_next;
3281  if (l_radial_iter != l_iter) {
3282  do {
3283  if (BM_elem_flag_test(l_radial_iter->f, BM_ELEM_TAG)) {
3284  found = true;
3285  }
3286  } while ((l_radial_iter = l_radial_iter->radial_next) != l_iter &&
3287  (found == false));
3288  }
3289  }
3290  } while ((l_iter = l_iter->next) != l_first && (found == false));
3291 
3292  if (found) {
3293  float cent[3], cent_ss[2];
3294  BM_face_calc_point_in_face(f, cent);
3295  knife_project_v2(kcd, cent, cent_ss);
3296  if ((kcd->cut_through || point_is_visible(kcd, cent, cent_ss, (BMElem *)f)) &&
3297  edbm_mesh_knife_point_isect(polys, cent_ss)) {
3299  keep_search = true;
3300  }
3301  else {
3302  /* don't lose time on this face again, set it as outside */
3304  }
3305  }
3306  }
3307  }
3308  } while (keep_search);
3309 
3310 #undef F_ISECT_IS_UNKNOWN
3311 #undef F_ISECT_SET_UNKNOWN
3312 #undef F_ISECT_SET_OUTSIDE
3313  }
3314 
3315  knifetool_exit_ex(C, kcd);
3316  kcd = NULL;
3317  }
3318 }
3319 
typedef float(TangentPoint)[2]
struct Scene * CTX_data_scene(const bContext *C)
Definition: context.c:1034
struct Object * CTX_data_edit_object(const bContext *C)
Definition: context.c:1296
struct ARegion * CTX_wm_region(const bContext *C)
Definition: context.c:725
struct wmWindow * CTX_wm_window(const bContext *C)
Definition: context.c:699
float(* BKE_editmesh_vert_coords_alloc(struct Depsgraph *depsgraph, struct BMEditMesh *em, struct Scene *scene, struct Object *ob, int *r_vert_len))[3]
Definition: editmesh.c:198
BMEditMesh * BKE_editmesh_from_object(struct Object *ob)
Return the BMEditMesh for a given object.
Definition: editmesh.c:85
@ BMBVH_RETURN_ORIG
@ BMBVH_RESPECT_HIDDEN
@ BMBVH_RESPECT_SELECT
struct BMFace * BKE_bmbvh_ray_cast(BMBVHTree *tree, const float co[3], const float dir[3], const float radius, float *r_dist, float r_hitout[3], float r_cagehit[3])
Definition: editmesh_bvh.c:306
struct BVHTree * BKE_bmbvh_tree_get(BMBVHTree *tree)
Definition: editmesh_bvh.c:197
struct BMFace * BKE_bmbvh_ray_cast_filter(BMBVHTree *tree, const float co[3], const float dir[3], const float radius, float *r_dist, float r_hitout[3], float r_cagehit[3], BMBVHTree_FaceFilter filter_cb, void *filter_userdata)
Definition: editmesh_bvh.c:364
void BKE_bmbvh_free(BMBVHTree *tree)
Definition: editmesh_bvh.c:186
BMBVHTree * BKE_bmbvh_new_from_editmesh(struct BMEditMesh *em, int flag, const float(*cos_cage)[3], const bool cos_cage_free)
Definition: editmesh_bvh.c:47
void BKE_report(ReportList *reports, ReportType type, const char *message)
Definition: report.c:104
#define BLI_array_alloca(arr, realsize)
Definition: BLI_alloca.h:36
A (mainly) macro array library.
#define BLI_array_append(arr, item)
Definition: BLI_array.h:104
#define BLI_array_declare(arr)
Definition: BLI_array.h:62
#define BLI_array_len(arr)
Definition: BLI_array.h:74
#define BLI_assert(a)
Definition: BLI_assert.h:58
struct GSet GSet
Definition: BLI_ghash.h:189
BLI_INLINE void * BLI_ghashIterator_getKey(GHashIterator *ghi) ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.h:146
BLI_INLINE void * BLI_ghashIterator_getValue(GHashIterator *ghi) ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.h:150
unsigned int BLI_gset_len(GSet *gs) ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.c:1138
#define GHASH_ITER(gh_iter_, ghash_)
Definition: BLI_ghash.h:169
GSet * BLI_gset_ptr_new(const char *info)
void BLI_gset_clear(GSet *gs, GSetKeyFreeFP keyfreefp)
Definition: BLI_ghash.c:1248
void BLI_ghash_insert(GHash *gh, void *key, void *val)
Definition: BLI_ghash.c:756
void BLI_ghash_free(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
Definition: BLI_ghash.c:1008
void BLI_gset_free(GSet *gs, GSetKeyFreeFP keyfreefp)
Definition: BLI_ghash.c:1253
GHash * BLI_ghash_ptr_new(const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
bool BLI_gset_add(GSet *gs, void *key)
Definition: BLI_ghash.c:1160
void * BLI_ghash_lookup(GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.c:803
int * BLI_bvhtree_intersect_plane(BVHTree *tree, float plane[4], uint *r_intersect_tot)
Definition: BLI_kdopbvh.c:1458
BLI_INLINE void BLI_listbase_clear(struct ListBase *lb)
Definition: BLI_listbase.h:128
int BLI_listbase_count_at_most(const struct ListBase *listbase, const int count_max) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
void void BLI_INLINE bool BLI_listbase_is_single(const struct ListBase *lb)
Definition: BLI_listbase.h:120
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:110
void BLI_remlink(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:133
void void void BLI_listbase_sort_r(ListBase *listbase, int(*cmp)(void *, const void *, const void *), void *thunk) ATTR_NONNULL(1
int BLI_listbase_count(const struct ListBase *listbase) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
#define BLI_ASSERT_UNIT_V2(v)
MINLINE float min_ff(float a, float b)
void rgba_uchar_to_float(float r_col[4], const unsigned char col_ub[4])
Definition: math_color.c:414
void plane_from_point_normal_v3(float r_plane[4], const float plane_co[3], const float plane_no[3])
Definition: math_geom.c:243
int isect_line_line_v3(const float v1[3], const float v2[3], const float v3[3], const float v4[3], float r_i1[3], float r_i2[3])
Definition: math_geom.c:3103
float dist_squared_to_plane_v3(const float p[3], const float plane[4])
Definition: math_geom.c:440
void transform_point_by_seg_v3(float p_dst[3], const float p_src[3], const float l_dst_p1[3], const float l_dst_p2[3], const float l_src_p1[3], const float l_src_p2[3])
Definition: math_geom.c:4169
bool isect_point_poly_v2(const float pt[2], const float verts[][2], const unsigned int nr, const bool use_holes)
void closest_to_line_segment_v2(float r_close[2], const float p[2], const float l1[2], const float l2[2])
Definition: math_geom.c:353
float line_point_factor_v2(const float p[2], const float l1[2], const float l2[2])
Definition: math_geom.c:3469
int isect_seg_seg_v2_point_ex(const float v0[2], const float v1[2], const float v2[2], const float v3[2], const float endpoint_bias, float vi[2])
Definition: math_geom.c:1252
float line_point_factor_v3(const float p[3], const float l1[3], const float l2[3])
Definition: math_geom.c:3449
int isect_line_line_v2_point(const float v0[2], const float v1[2], const float v2[2], const float v3[2], float r_vi[2])
Definition: math_geom.c:1127
void planes_from_projmat(const float mat[4][4], float left[4], float right[4], float top[4], float bottom[4], float near[4], float far[4])
Definition: math_geom.c:4911
bool isect_line_plane_v3(float r_isect_co[3], const float l1[3], const float l2[3], const float plane_co[3], const float plane_no[3]) ATTR_WARN_UNUSED_RESULT
Definition: math_geom.c:2191
bool isect_ray_tri_epsilon_v3(const float ray_origin[3], const float ray_direction[3], const float v0[3], const float v1[3], const float v2[3], float *r_lambda, float r_uv[2], const float epsilon)
Definition: math_geom.c:1830
float normal_tri_v3(float n[3], const float v1[3], const float v2[3], const float v3[3])
Definition: math_geom.c:51
bool clip_segment_v3_plane_n(const float p1[3], const float p2[3], const float plane_array[][4], const int plane_tot, float r_p1[3], float r_p2[3])
Definition: math_geom.c:3679
bool isect_ray_plane_v3(const float ray_origin[3], const float ray_direction[3], const float plane[4], float *r_lambda, const bool clip)
Definition: math_geom.c:1808
float dist_squared_to_line_segment_v2(const float p[2], const float l1[2], const float l2[2])
Definition: math_geom.c:338
void mul_project_m4_v3(const float M[4][4], float vec[3])
Definition: math_matrix.c:824
void mul_v3_project_m4_v3(float r[3], const float mat[4][4], const float vec[3])
Definition: math_matrix.c:835
void mul_v2_m2v2(float r[2], const float M[2][2], const float v[2])
Definition: math_matrix.c:780
void invert_m4_m4_safe_ortho(float Ainv[4][4], const float A[4][4])
Definition: math_matrix.c:3287
bool invert_m4_m4(float R[4][4], const float A[4][4])
Definition: math_matrix.c:1278
void mul_m4_v3(const float M[4][4], float r[3])
Definition: math_matrix.c:732
void mul_v3_mat3_m4v3(float r[3], const float M[4][4], const float v[3])
Definition: math_matrix.c:804
void angle_to_mat2(float R[2][2], const float angle)
#define DEG2RADF(_deg)
void interp_v3_v3v3(float r[3], const float a[3], const float b[3], const float t)
Definition: math_vector.c:49
MINLINE float len_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
void minmax_v3v3_v3(float min[3], float max[3], const float vec[3])
Definition: math_vector.c:1020
MINLINE float len_squared_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT
void minmax_v3v3_v3_array(float r_min[3], float r_max[3], const float(*vec_arr)[3], int nbr)
Definition: math_vector.c:1060
MINLINE float normalize_v3(float r[3])
MINLINE void sub_v3_v3(float r[3], const float a[3])
MINLINE float len_squared_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void copy_v2_v2(float r[2], const float a[2])
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE void negate_v3_v3(float r[3], const float a[3])
void project_plane_normalized_v3_v3v3(float out[3], const float p[3], const float v_plane[3])
Definition: math_vector.c:757
MINLINE void add_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void cross_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE float dot_m4_v3_row_z(const float M[4][4], const float a[3]) ATTR_WARN_UNUSED_RESULT
float angle_signed_v2v2(const float v1[2], const float v2[2]) ATTR_WARN_UNUSED_RESULT
Definition: math_vector.c:499
void mid_v2_v2v2(float r[2], const float a[2], const float b[2])
Definition: math_vector.c:277
MINLINE float normalize_v3_v3(float r[3], const float a[3])
MINLINE void add_v2_v2v2(float r[2], const float a[2], const float b[2])
MINLINE void sub_v2_v2v2(float r[2], const float a[2], const float b[2])
MINLINE void zero_v2(float r[2])
MINLINE bool equals_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
void mid_v3_v3v3(float r[3], const float a[3], const float b[3])
Definition: math_vector.c:270
MINLINE void madd_v3_v3v3fl(float r[3], const float a[3], const float b[3], float f)
MINLINE bool is_zero_v2(const float a[3]) ATTR_WARN_UNUSED_RESULT
MINLINE float len_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT
MINLINE void zero_v3(float r[3])
MINLINE void add_v3_v3(float r[3], const float a[3])
MINLINE float normalize_v2_v2(float r[2], const float a[2])
void interp_v3_v3v3v3_uv(float p[3], const float v1[3], const float v2[3], const float v3[3], const float uv[2])
Definition: math_vector.c:235
void BLI_memarena_free(struct MemArena *ma) ATTR_NONNULL(1)
Definition: BLI_memarena.c:109
void * BLI_memarena_alloc(struct MemArena *ma, size_t size) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1) ATTR_MALLOC ATTR_ALLOC_SIZE(2)
Definition: BLI_memarena.c:131
void BLI_memarena_clear(MemArena *ma) ATTR_NONNULL(1)
Definition: BLI_memarena.c:185
struct MemArena * BLI_memarena_new(const size_t bufsize, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(2) ATTR_MALLOC
Definition: BLI_memarena.c:79
void * BLI_mempool_calloc(BLI_mempool *pool) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition: BLI_mempool.c:362
void BLI_mempool_iternew(BLI_mempool *pool, BLI_mempool_iter *iter) ATTR_NONNULL()
Definition: BLI_mempool.c:537
@ BLI_MEMPOOL_ALLOW_ITER
Definition: BLI_mempool.h:85
void * BLI_mempool_iterstep(BLI_mempool_iter *iter) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: BLI_mempool.c:645
BLI_mempool * BLI_mempool_create(unsigned int esize, unsigned int totelem, unsigned int pchunk, unsigned int flag) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
Definition: BLI_mempool.c:268
void BLI_mempool_destroy(BLI_mempool *pool) ATTR_NONNULL(1)
Definition: BLI_mempool.c:757
int BLI_mempool_len(BLI_mempool *pool) ATTR_NONNULL(1)
Definition: BLI_mempool.c:454
void ** BLI_smallhash_iternew_p(const SmallHash *sh, SmallHashIter *iter, uintptr_t *key) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT
Definition: smallhash.c:344
void * BLI_smallhash_iternext(SmallHashIter *iter, uintptr_t *key) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT
Definition: smallhash.c:322
bool BLI_smallhash_haskey(const SmallHash *sh, uintptr_t key) ATTR_NONNULL(1)
Definition: smallhash.c:293
void BLI_smallhash_init(SmallHash *sh) ATTR_NONNULL(1)
Definition: smallhash.c:212
void ** BLI_smallhash_iternext_p(SmallHashIter *iter, uintptr_t *key) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT
Definition: smallhash.c:329
void BLI_smallhash_insert(SmallHash *sh, uintptr_t key, void *item) ATTR_NONNULL(1)
Definition: smallhash.c:225
void BLI_smallhash_release(SmallHash *sh) ATTR_NONNULL(1)
Definition: smallhash.c:218
void * BLI_smallhash_lookup(const SmallHash *sh, uintptr_t key) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT
Definition: smallhash.c:279
bool BLI_smallhash_reinsert(SmallHash *sh, uintptr_t key, void *item) ATTR_NONNULL(1)
Definition: smallhash.c:249
void * BLI_smallhash_iternew(const SmallHash *sh, SmallHashIter *iter, uintptr_t *key) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT
Definition: smallhash.c:336
size_t BLI_snprintf(char *__restrict dst, size_t maxncpy, const char *__restrict format,...) ATTR_NONNULL(1
unsigned char uchar
Definition: BLI_sys_types.h:86
unsigned int uint
Definition: BLI_sys_types.h:83
#define UNPACK2(a)
#define INIT_MINMAX(min, max)
#define POINTER_FROM_INT(i)
#define UNUSED_VARS_NDEBUG(...)
#define UNUSED(x)
#define POINTER_AS_INT(i)
#define UNPACK3(a)
#define ELEM(...)
#define TIP_(msgid)
struct ID * DEG_get_evaluated_id(const struct Depsgraph *depsgraph, struct ID *id)
Object is a sort of wrapper for general info.
@ OB_MESH
#define SCE_SELECT_FACE
@ SPACE_VIEW3D
#define RV3D_CAMOB
#define RV3D_CLIPPING_ENABLED(v3d, rv3d)
@ OPERATOR_CANCELLED
@ OPERATOR_FINISHED
@ OPERATOR_RUNNING_MODAL
@ OPERATOR_PASS_THROUGH
@ OP_IS_MODAL_CURSOR_REGION
void em_setup_viewcontext(struct bContext *C, struct ViewContext *vc)
struct BMFace * EDBM_face_find_nearest(struct ViewContext *vc, float *dist_px_manhattan_p)
void EDBM_update_generic(struct Mesh *me, const bool do_tessellation, const bool is_destructive)
void EDBM_flag_disable_all(struct BMEditMesh *em, const char hflag)
void EDBM_selectmode_flush(struct BMEditMesh *em)
void EDBM_mesh_normals_update(struct BMEditMesh *em)
bool ED_operator_editmesh_view3d(struct bContext *C)
Definition: screen_ops.c:413
void ED_region_tag_redraw(struct ARegion *region)
Definition: area.c:667
void ED_workspace_status_text(struct bContext *C, const char *str)
Definition: area.c:840
#define REGION_DRAW_POST_VIEW
Definition: ED_space_api.h:66
void * ED_region_draw_cb_activate(struct ARegionType *art, void(*draw)(const struct bContext *, struct ARegion *, void *), void *customdata, int type)
Definition: spacetypes.c:238
void ED_region_draw_cb_exit(struct ARegionType *, void *)
Definition: spacetypes.c:253
bool ED_view3d_win_to_segment_clipped(struct Depsgraph *depsgraph, const struct ARegion *region, struct View3D *v3d, const float mval[2], float r_ray_start[3], float r_ray_end[3], const bool do_clip)
void ED_view3d_init_mats_rv3d(struct Object *ob, struct RegionView3D *rv3d)
Definition: space_view3d.c:190
void ED_view3d_ob_project_mat_get(const struct RegionView3D *v3d, struct Object *ob, float r_pmat[4][4])
void ED_view3d_project_float_v2_m4(const struct ARegion *region, const float co[3], float r_co[2], float mat[4][4])
bool ED_view3d_clip_range_get(struct Depsgraph *depsgraph, const struct View3D *v3d, const struct RegionView3D *rv3d, float *r_clipsta, float *r_clipend, const bool use_ortho_factor)
void ED_view3d_win_to_3d(const struct View3D *v3d, const struct ARegion *region, const float depth_pt[3], const float mval[2], float r_out[3])
bool ED_view3d_clipping_test(const struct RegionView3D *rv3d, const float co[3], const bool is_local)
bool ED_view3d_unproject(const struct ARegion *region, float regionx, float regiony, float regionz, float world[3])
static AppView * view
NSNotificationCenter * center
GPUBatch
Definition: GPU_batch.h:93
void GPU_batch_draw_range(GPUBatch *batch, int v_first, int v_count)
Definition: gpu_batch.cc:240
void GPU_batch_discard(GPUBatch *)
Definition: gpu_batch.cc:127
void GPU_batch_program_set_builtin(GPUBatch *batch, eGPUBuiltinShader shader_id)
Definition: gpu_batch.cc:299
GPUBatch * GPU_batch_create_ex(GPUPrimType prim, GPUVertBuf *vert, GPUIndexBuf *elem, eGPUBatchFlag owns_flag)
Definition: gpu_batch.cc:60
void GPU_batch_draw(GPUBatch *batch)
Definition: gpu_batch.cc:234
#define GPU_batch_uniform_4fv(batch, name, val)
Definition: GPU_batch.h:142
@ GPU_BATCH_OWNS_VBO
Definition: GPU_batch.h:45
void immUnbindProgram(void)
void immBindBuiltinProgram(eGPUBuiltinShader shader_id)
void immUniformColor3ubv(const unsigned char rgb[3])
GPUBatch * immBeginBatchAtMost(GPUPrimType, uint vertex_len)
void immUniformThemeColor3(int color_id)
GPUVertFormat * immVertexFormat(void)
void immVertex3fv(uint attr_id, const float data[3])
void immBegin(GPUPrimType, uint vertex_len)
void immEnd(void)
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble u2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLdouble GLdouble v2 _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLdouble GLdouble nz _GL_VOID_RET _GL_VOID GLfloat GLfloat nz _GL_VOID_RET _GL_VOID GLint GLint nz _GL_VOID_RET _GL_VOID GLshort GLshort nz _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const GLfloat *values _GL_VOID_RET _GL_VOID GLsizei const GLushort *values _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID const GLuint const GLclampf *priorities _GL_VOID_RET _GL_VOID GLdouble y _GL_VOID_RET _GL_VOID GLfloat y _GL_VOID_RET _GL_VOID GLint y _GL_VOID_RET _GL_VOID GLshort y _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLfloat GLfloat z _GL_VOID_RET _GL_VOID GLint GLint z _GL_VOID_RET _GL_VOID GLshort GLshort z _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble w _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat w _GL_VOID_RET _GL_VOID GLint GLint GLint w _GL_VOID_RET _GL_VOID GLshort GLshort GLshort w _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble y2 _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat y2 _GL_VOID_RET _GL_VOID GLint GLint GLint y2 _GL_VOID_RET _GL_VOID GLshort GLshort GLshort y2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLuint *buffer _GL_VOID_RET _GL_VOID GLdouble t _GL_VOID_RET _GL_VOID GLfloat t _GL_VOID_RET _GL_VOID GLint t _GL_VOID_RET _GL_VOID GLshort t _GL_VOID_RET _GL_VOID GLdouble GLdouble r _GL_VOID_RET _GL_VOID GLfloat GLfloat r _GL_VOID_RET _GL_VOID GLint GLint r _GL_VOID_RET _GL_VOID GLshort GLshort r _GL_VOID_RET _GL_VOID GLdouble GLdouble r
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble v1
void GPU_matrix_pop(void)
Definition: gpu_matrix.cc:142
void GPU_matrix_pop_projection(void)
Definition: gpu_matrix.cc:156
#define GPU_matrix_mul(x)
Definition: GPU_matrix.h:223
void GPU_matrix_push(void)
Definition: gpu_matrix.cc:135
void GPU_polygon_offset(float viewdist, float dist)
Definition: gpu_matrix.cc:758
void GPU_matrix_push_projection(void)
Definition: gpu_matrix.cc:149
@ GPU_PRIM_LINES
Definition: GPU_primitive.h:36
@ GPU_PRIM_POINTS
Definition: GPU_primitive.h:35
@ GPU_SHADER_3D_UNIFORM_COLOR
Definition: GPU_shader.h:200
@ GPU_BLEND_NONE
Definition: GPU_state.h:55
@ GPU_BLEND_ALPHA
Definition: GPU_state.h:57
void GPU_blend(eGPUBlend blend)
Definition: gpu_state.cc:55
void GPU_line_width(float width)
Definition: gpu_state.cc:173
void GPU_point_size(float size)
Definition: gpu_state.cc:179
@ GPU_DEPTH_LESS_EQUAL
Definition: GPU_state.h:81
@ GPU_DEPTH_NONE
Definition: GPU_state.h:78
void GPU_depth_test(eGPUDepthTest test)
Definition: gpu_state.cc:75
#define GPU_vertbuf_create_with_format(format)
struct GPUVertBuf GPUVertBuf
void GPU_vertbuf_data_alloc(GPUVertBuf *, uint v_len)
void GPU_vertbuf_attr_set(GPUVertBuf *, uint a_idx, uint v_idx, const void *data)
@ GPU_FETCH_FLOAT
uint GPU_vertformat_attr_add(GPUVertFormat *, const char *name, GPUVertCompType, uint comp_len, GPUVertFetchMode)
@ GPU_COMP_F32
Read Guarded memory(de)allocation.
#define MEM_SIZE_OPTIMAL(size)
@ PROP_SKIP_SAVE
Definition: RNA_types.h:204
@ PROP_HIDDEN
Definition: RNA_types.h:202
#define C
Definition: RandGen.cpp:39
#define UI_MAX_DRAW_STR
Definition: UI_interface.h:90
#define UI_DPI_FAC
Definition: UI_interface.h:309
void UI_GetThemeColorType3ubv(int colorid, int spacetype, unsigned char col[3])
Definition: resources.c:1398
@ TH_ACTIVE_SPLINE
Definition: UI_resources.h:136
@ TH_TRANSFORM
Definition: UI_resources.h:92
@ TH_NURB_VLINE
Definition: UI_resources.h:120
@ TH_NURB_ULINE
Definition: UI_resources.h:119
@ TH_HANDLE_SEL_VECT
Definition: UI_resources.h:132
@ OPTYPE_BLOCKING
Definition: WM_types.h:157
@ OPTYPE_UNDO
Definition: WM_types.h:155
@ OPTYPE_REGISTER
Definition: WM_types.h:153
#define KM_NOTHING
Definition: WM_types.h:241
#define KM_RELEASE
Definition: WM_types.h:243
@ BM_FACE
Definition: bmesh_class.h:386
@ BM_VERT
Definition: bmesh_class.h:383
@ BM_EDGE
Definition: bmesh_class.h:384
@ BM_ELEM_SELECT
Definition: bmesh_class.h:471
@ BM_ELEM_TAG
Definition: bmesh_class.h:484
#define BM_FACE_FIRST_LOOP(p)
Definition: bmesh_class.h:553
BMVert * BM_vert_create(BMesh *bm, const float co[3], const BMVert *v_example, const eBMCreateFlag create_flag)
Main function for creating a new vertex.
Definition: bmesh_core.c:58
void BM_edge_kill(BMesh *bm, BMEdge *e)
Definition: bmesh_core.c:987
BMEdge * BM_edge_create(BMesh *bm, BMVert *v1, BMVert *v2, const BMEdge *e_example, const eBMCreateFlag create_flag)
Main function for creating a new edge.
Definition: bmesh_core.c:147
#define BM_elem_index_get(ele)
Definition: bmesh_inline.h:124
#define BM_elem_flag_disable(ele, hflag)
Definition: bmesh_inline.h:29
#define BM_elem_flag_test(ele, hflag)
Definition: bmesh_inline.h:26
#define BM_elem_flag_enable(ele, hflag)
Definition: bmesh_inline.h:28
#define BM_ITER_ELEM(ele, iter, data, itype)
#define BM_ITER_MESH(ele, iter, bm, itype)
@ BM_FACES_OF_EDGE
@ BM_FACES_OF_VERT
@ BM_EDGES_OF_MESH
@ BM_VERTS_OF_MESH
@ BM_FACES_OF_MESH
@ BM_EDGES_OF_FACE
ATTR_WARN_UNUSED_RESULT BMesh * bm
void BM_mesh_elem_hflag_enable_all(BMesh *bm, const char htype, const char hflag, const bool respecthide)
void BM_edge_select_set(BMesh *bm, BMEdge *e, const bool select)
Select Edge.
void BM_mesh_elem_index_ensure(BMesh *bm, const char htype)
Definition: bmesh_mesh.c:2152
BMVert * BM_edge_split(BMesh *bm, BMEdge *e, BMVert *v, BMEdge **r_e, float fac)
Edge Split.
Definition: bmesh_mods.c:591
void BM_face_calc_point_in_face(const BMFace *f, float r_co[3])
bool BM_face_point_inside_test(const BMFace *f, const float co[3])
bool BM_face_split_edgenet_connect_islands(BMesh *bm, BMFace *f, BMEdge **edge_net_init, const uint edge_net_init_len, bool use_partial_connect, MemArena *mem_arena, BMEdge ***r_edge_net_new, uint *r_edge_net_new_len)
bool BM_face_split_edgenet(BMesh *bm, BMFace *f, BMEdge **edge_net, const int edge_net_len, BMFace ***r_face_arr, int *r_face_arr_len)
BMEdge * BM_edge_exists(BMVert *v_a, BMVert *v_b)
Definition: bmesh_query.c:1995
float BM_loop_point_side_of_loop_test(const BMLoop *l, const float co[3])
Definition: bmesh_query.c:334
bool BM_edge_in_face(const BMEdge *e, const BMFace *f)
Definition: bmesh_query.c:555
BMLoop * BM_face_edge_share_loop(BMFace *f, BMEdge *e)
Return the Loop Shared by Face and Edge.
Definition: bmesh_query.c:1426
bool BM_vert_in_face(BMVert *v, BMFace *f)
Definition: bmesh_query.c:431
BMLoop * BM_face_vert_share_loop(BMFace *f, BMVert *v)
Return the Loop Shared by Face and Vertex.
Definition: bmesh_query.c:1403
float BM_loop_point_side_of_edge_test(const BMLoop *l, const float co[3])
Definition: bmesh_query.c:346
BLI_INLINE bool BM_edge_is_boundary(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
BLI_INLINE bool BM_loop_is_adjacent(const BMLoop *l_a, const BMLoop *l_b) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
BLI_INLINE bool BM_edge_is_wire(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
ATTR_WARN_UNUSED_RESULT const BMVert * v2
ATTR_WARN_UNUSED_RESULT const BMLoop * l
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
ATTR_WARN_UNUSED_RESULT const BMVert * v
SIMD_FORCE_INLINE btScalar angle(const btVector3 &v) const
Return the angle between this and another vector.
Definition: btVector3.h:356
bool closest(btVector3 &v)
Scene scene
void * user_data
GPUBatch * batch
Definition: drawnode.c:3779
static void knife_edge_append_face(KnifeTool_OpData *kcd, KnifeEdge *kfe, BMFace *f)
static void knife_find_line_hits(KnifeTool_OpData *kcd)
static void knife_input_ray_segment(KnifeTool_OpData *kcd, const float mval[2], const float ofs, float r_origin[3], float r_origin_ofs[3])
struct Ref Ref
static void knife_make_cuts(KnifeTool_OpData *kcd)
#define KNIFE_FLT_EPS_PX_VERT
static void calc_ortho_extent(KnifeTool_OpData *kcd)
void EDBM_mesh_knife(bContext *C, LinkNode *polys, bool use_tag, bool cut_through)
struct KnifePosData KnifePosData
static ListBase * knife_empty_list(KnifeTool_OpData *kcd)
static void knife_project_v2(const KnifeTool_OpData *kcd, const float co[3], float sco[2])
static void knifetool_init_bmbvh(KnifeTool_OpData *kcd)
static void knife_make_face_cuts(KnifeTool_OpData *kcd, BMFace *f, ListBase *kfedges)
static void linehit_to_knifepos(KnifePosData *kpos, KnifeLineHit *lh)
static bool knife_verts_edge_in_face(KnifeVert *v1, KnifeVert *v2, BMFace *f)
static void knifetool_update_mval_i(KnifeTool_OpData *kcd, const int mval_i[2])
static void knifetool_exit_ex(bContext *C, KnifeTool_OpData *kcd)
static void knifetool_draw(const bContext *UNUSED(C), ARegion *UNUSED(region), void *arg)
#define KNIFE_FLT_EPS_PX_EDGE
wmKeyMap * knifetool_modal_keymap(wmKeyConfig *keyconf)
static BMFace * knife_find_closest_face(KnifeTool_OpData *kcd, float co[3], float cageco[3], bool *is_space)
static void knifetool_finish_ex(KnifeTool_OpData *kcd)
static int linehit_compare(const void *vlh1, const void *vlh2)
static void knife_append_list(KnifeTool_OpData *kcd, ListBase *lst, void *elem)
static KnifeVert * knife_split_edge(KnifeTool_OpData *kcd, KnifeEdge *kfe, const float co[3], const float cageco[3], KnifeEdge **r_kfe)
static void prepare_linehits_for_cut(KnifeTool_OpData *kcd)
#define F_ISECT_SET_UNKNOWN(f)
@ KNF_MODAL_CANCEL
@ KNF_MODAL_MIDPOINT_OFF
@ KNF_MODAL_PANNING
@ KNF_MODAL_NEW_CUT
@ KNF_MODAL_ANGLE_SNAP_TOGGLE
@ KNF_MODAL_IGNORE_SNAP_OFF
@ KNF_MODAL_ADD_CUT_CLOSED
@ KNF_MODAL_ADD_CUT
@ KNF_MODAL_IGNORE_SNAP_ON
@ KNF_MODAL_CONFIRM
@ KNF_MODAL_MIDPOINT_ON
@ KNF_MODAL_CUT_THROUGH_TOGGLE
static bool knife_ray_intersect_face(KnifeTool_OpData *kcd, const float s[2], const float v1[3], const float v2[3], BMFace *f, const float face_tol_sq, float hit_co[3], float hit_cageco[3])
static int knifetool_invoke(bContext *C, wmOperator *op, const wmEvent *event)
#define WM_MODALKEY(_id)
static void knifetool_update_mval(KnifeTool_OpData *kcd, const float mval[2])
static void set_lowest_face_tri(KnifeTool_OpData *kcd, BMFace *f, int index)
static KnifeEdge * knife_find_closest_edge_of_face(KnifeTool_OpData *kcd, BMFace *f, float p[3], float cagep[3])
static void knife_finish_cut(KnifeTool_OpData *kcd)
static BMElem * bm_elem_from_knife_vert(KnifeVert *kfv, KnifeEdge **r_kfe)
static void knifetool_cancel(bContext *C, wmOperator *op)
#define F_ISECT_SET_OUTSIDE(f)
static void knife_add_to_vert_edges(KnifeTool_OpData *kcd, KnifeEdge *kfe)
void MESH_OT_knife_tool(wmOperatorType *ot)
static void clip_to_ortho_planes(float v1[3], float v2[3], const float center[3], const float d)
#define KNIFE_FLT_EPSBIG
struct KnifeColors KnifeColors
static ListBase * knife_get_face_kedges(KnifeTool_OpData *kcd, BMFace *f)
static void knifetool_free_bmbvh(KnifeTool_OpData *kcd)
struct KnifeVert KnifeVert
static KnifeEdge * new_knife_edge(KnifeTool_OpData *kcd)
static void knife_recalc_projmat(KnifeTool_OpData *kcd)
static KnifeVert * knife_find_closest_vert_of_edge(KnifeTool_OpData *kcd, KnifeEdge *kfe, float p[3], float cagep[3])
static void add_hit_to_facehits(KnifeTool_OpData *kcd, GHash *facehits, BMFace *f, KnifeLineHit *hit)
static int get_lowest_face_tri(KnifeTool_OpData *kcd, BMFace *f)
static void knife_pos_data_clear(KnifePosData *kpd)
static Ref * find_ref(ListBase *lb, void *ref)
static KnifeEdge * get_bm_knife_edge(KnifeTool_OpData *kcd, BMEdge *e)
static KnifeVert * new_knife_vert(KnifeTool_OpData *kcd, const float co[3], const float cageco[3])
static bool knife_add_single_cut__is_linehit_outside_face(BMFace *f, const KnifeLineHit *lh, const float co[3])
static void knifetool_draw_angle_snapping(const KnifeTool_OpData *kcd)
static float snap_v2_angle(float r[2], const float v[2], const float v_ref[2], float angle_snap)
static void knife_cut_face(KnifeTool_OpData *kcd, BMFace *f, ListBase *hits)
static bool bm_ray_cast_cb_elem_not_in_face_check(BMFace *f, void *user_data)
static int knife_sample_screen_density_from_closest_face(KnifeTool_OpData *kcd, const float radius, BMFace *f, const float cageco[3])
static bool knife_snap_angle(KnifeTool_OpData *kcd)
static void knife_start_cut(KnifeTool_OpData *kcd)
static void knifetool_init(bContext *C, KnifeTool_OpData *kcd, const bool only_select, const bool cut_through, const bool is_interactive)
static void knife_add_single_cut(KnifeTool_OpData *kcd, KnifeLineHit *lh1, KnifeLineHit *lh2, BMFace *f)
static int knife_update_active(KnifeTool_OpData *kcd)
static KnifeVert * get_bm_knife_vert(KnifeTool_OpData *kcd, BMVert *v)
#define KNIFE_FLT_EPS_PX_FACE
static float knife_snap_size(KnifeTool_OpData *kcd, float maxsize)
#define KMAXDIST
static BMElem * bm_elem_from_knife_edge(KnifeEdge *kfe)
static bool point_is_visible(KnifeTool_OpData *kcd, const float p[3], const float s[2], BMElem *ele_test)
static void knife_add_cut(KnifeTool_OpData *kcd)
static bool knife_snap_update_from_mval(KnifeTool_OpData *kcd, const float mval[2])
static void knifetool_finish(wmOperator *op)
static void knife_update_header(bContext *C, wmOperator *op, KnifeTool_OpData *kcd)
static void knife_append_list_no_dup(KnifeTool_OpData *kcd, ListBase *lst, void *elem)
static bool knife_snap_edge_in_angle(KnifeTool_OpData *kcd, const float sco[3], const float kfv1_sco[2], const float kfv2_sco[2], float *r_dist_sq, float *r_lambda)
static BMFace * knife_find_common_face(ListBase *faces1, ListBase *faces2)
struct KnifeEdge KnifeEdge
#define KNIFE_FLT_EPS_SQUARED
static int knifetool_modal(bContext *C, wmOperator *op, const wmEvent *event)
#define KNIFE_FLT_EPS
struct KnifeTool_OpData KnifeTool_OpData
static void knife_interp_v3_v3v3(const KnifeTool_OpData *kcd, float r_co[3], const float v1[3], const float v2[3], float lambda_ss)
static int sort_verts_by_dist_cb(void *co_p, const void *cur_a_p, const void *cur_b_p)
static void knife_add_edge_faces_to_vert(KnifeTool_OpData *kcd, KnifeVert *kfv, BMEdge *e)
static void knifetool_exit(bContext *C, wmOperator *op)
static bool coinciding_edges(BMEdge *e1, BMEdge *e2)
static bool edbm_mesh_knife_point_isect(LinkNode *polys, const float cent_ss[2])
static void knife_init_colors(KnifeColors *colors)
static void set_linehit_depth(KnifeTool_OpData *kcd, KnifeLineHit *lh)
struct KnifeLineHit KnifeLineHit
#define F_ISECT_IS_UNKNOWN(f)
void * tree
uint pos
#define fabsf(x)
format
Definition: logImageCore.h:47
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:41
size_t(* MEM_allocN_len)(const void *vmemh)
Definition: mallocn.c:40
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:45
static char faces[256]
static unsigned c
Definition: RandGen.cpp:97
return ret
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:6261
PropertyRNA * RNA_def_boolean(StructOrFunctionRNA *cont_, const char *identifier, bool default_value, const char *ui_name, const char *ui_description)
Definition: rna_define.c:3481
void RNA_def_property_flag(PropertyRNA *prop, PropertyFlag flag)
Definition: rna_define.c:1512
#define min(a, b)
Definition: sort.c:51
_W64 unsigned int uintptr_t
Definition: stdint.h:122
_W64 int intptr_t
Definition: stdint.h:121
void * regiondata
struct ARegionType * type
BMVert * v1
Definition: bmesh_class.h:134
BMVert * v2
Definition: bmesh_class.h:134
short selectmode
Definition: BKE_editmesh.h:72
struct BMLoop *(* looptris)[3]
Definition: BKE_editmesh.h:60
struct BMesh * bm
Definition: BKE_editmesh.h:52
struct BMVert * v
Definition: bmesh_class.h:165
struct BMEdge * e
Definition: bmesh_class.h:176
struct BMLoop * radial_next
Definition: bmesh_class.h:216
struct BMFace * f
Definition: bmesh_class.h:183
struct BMLoop * next
Definition: bmesh_class.h:245
float co[3]
Definition: bmesh_class.h:99
int totvert
Definition: bmesh_class.h:297
int totfacesel
Definition: bmesh_class.h:298
uchar curpoint[3]
uchar curpoint_a[4]
uchar point_a[4]
uchar point[3]
uchar line[3]
uchar edge[3]
BMFace * basef
BMEdge * e
KnifeVert * v1
ListBase faces
KnifeVert * v2
float cagehit[3]
float schit[2]
KnifeEdge * kfe
KnifeVert * v
KnifeVert * vert
BMFace * bmface
KnifeEdge * edge
KnifePosData curr
const float(* cagecos)[3]
struct KnifeTool_OpData::@442 edgenet
BMBVHTree * bmbvh
float projmat[4][4]
BLI_mempool * refs
KnifePosData prev
float projmat_inv[4][4]
float ob_imat[4][4]
BMEditMesh * em
BLI_mempool * kverts
BLI_mempool * kedges
KnifeColors colors
KnifeLineHit * linehits
KnifePosData init
float ortho_extent_center[3]
enum KnifeTool_OpData::@443 mode
float co[3]
float cageco[3]
BMVert * v
ListBase edges
ListBase faces
void * link
Definition: BLI_linklist.h:40
struct LinkNode * next
Definition: BLI_linklist.h:39
void * first
Definition: DNA_listBase.h:47
float obmat[4][4]
void * data
void * ref
struct Ref * next
struct Ref * prev
float persmatob[4][4]
float clip_local[6][4]
float viewinv[4][4]
float clip_end
struct Depsgraph * depsgraph
Definition: ED_view3d.h:75
int mval[2]
Definition: ED_view3d.h:85
struct ARegion * region
Definition: ED_view3d.h:80
struct View3D * v3d
Definition: ED_view3d.h:81
struct RegionView3D * rv3d
Definition: ED_view3d.h:83
short val
Definition: WM_types.h:579
int mval[2]
Definition: WM_types.h:583
short prevval
Definition: WM_types.h:604
short type
Definition: WM_types.h:577
const void * modal_items
int(* invoke)(struct bContext *, struct wmOperator *, const struct wmEvent *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:752
const char * name
Definition: WM_types.h:721
int(* modal)(struct bContext *, struct wmOperator *, const struct wmEvent *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:768
const char * idname
Definition: WM_types.h:723
bool(* poll)(struct bContext *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:776
void(* cancel)(struct bContext *, struct wmOperator *)
Definition: WM_types.h:760
struct StructRNA * srna
Definition: WM_types.h:802
const char * description
Definition: WM_types.h:726
struct ReportList * reports
struct PointerRNA * ptr
float max
void WM_cursor_modal_set(wmWindow *win, int val)
Definition: wm_cursors.c:207
void WM_cursor_modal_restore(wmWindow *win)
Definition: wm_cursors.c:216
@ WM_CURSOR_KNIFE
Definition: wm_cursors.h:47
wmEventHandler_Op * WM_event_add_modal_handler(bContext *C, wmOperator *op)
@ MOUSEPAN
@ EVT_MODAL_MAP
@ MOUSEZOOM
@ MOUSEROTATE
@ WHEELUPMOUSE
@ WHEELDOWNMOUSE
@ MOUSEMOVE
@ NDOF_MOTION
wmOperatorType * ot
Definition: wm_files.c:3156
wmKeyMap * WM_modalkeymap_find(wmKeyConfig *keyconf, const char *idname)
Definition: wm_keymap.c:914
void WM_modalkeymap_assign(wmKeyMap *km, const char *opname)
Definition: wm_keymap.c:985
const char * WM_bool_as_string(bool test)
Definition: wm_keymap.c:2003
wmKeyMap * WM_modalkeymap_ensure(wmKeyConfig *keyconf, const char *idname, const EnumPropertyItem *items)
Definition: wm_keymap.c:888