Blender  V3.3
editmesh_path.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2004 Blender Foundation. All rights reserved. */
3 
8 #include "MEM_guardedalloc.h"
9 
10 #include "DNA_mesh_types.h"
11 #include "DNA_object_types.h"
12 #include "DNA_scene_types.h"
14 
15 #ifdef WITH_FREESTYLE
16 # include "BKE_customdata.h"
17 # include "DNA_meshdata_types.h"
18 #endif
19 
20 #include "BLI_linklist.h"
21 #include "BLI_math.h"
22 
23 #include "BKE_context.h"
24 #include "BKE_editmesh.h"
25 #include "BKE_layer.h"
26 #include "BKE_report.h"
27 
28 #include "ED_mesh.h"
29 #include "ED_object.h"
30 #include "ED_screen.h"
31 #include "ED_select_utils.h"
32 #include "ED_uvedit.h"
33 #include "ED_view3d.h"
34 
35 #include "RNA_access.h"
36 #include "RNA_define.h"
37 
38 #include "WM_api.h"
39 #include "WM_types.h"
40 
41 #include "bmesh.h"
42 #include "bmesh_tools.h"
43 
44 #include "DEG_depsgraph.h"
45 
46 #include "mesh_intern.h" /* own include */
47 
48 /* -------------------------------------------------------------------- */
52 enum {
59 };
60 
66  bool use_fill;
67  char edge_mode;
69 };
70 
72 {
73  static const EnumPropertyItem edge_tag_items[] = {
74  {EDGE_MODE_SELECT, "SELECT", 0, "Select", ""},
75  {EDGE_MODE_TAG_SEAM, "SEAM", 0, "Tag Seam", ""},
76  {EDGE_MODE_TAG_SHARP, "SHARP", 0, "Tag Sharp", ""},
77  {EDGE_MODE_TAG_CREASE, "CREASE", 0, "Tag Crease", ""},
78  {EDGE_MODE_TAG_BEVEL, "BEVEL", 0, "Tag Bevel", ""},
79  {EDGE_MODE_TAG_FREESTYLE, "FREESTYLE", 0, "Tag Freestyle Edge Mark", ""},
80  {0, NULL, 0, NULL, NULL},
81  };
82 
84  "edge_mode",
85  edge_tag_items,
87  "Edge Tag",
88  "The edge flag to tag when selecting the shortest path");
89 
91  "use_face_step",
92  false,
93  "Face Stepping",
94  "Traverse connected faces (includes diagonals and edge-rings)");
96  "use_topology_distance",
97  false,
98  "Topology Distance",
99  "Find the minimum number of steps, ignoring spatial distance");
101  "use_fill",
102  false,
103  "Fill Region",
104  "Select all paths between the source/destination elements");
106 }
107 
109  ToolSettings *ts,
110  struct PathSelectParams *op_params)
111 {
112  {
113  PropertyRNA *prop = RNA_struct_find_property(op->ptr, "edge_mode");
114  if (RNA_property_is_set(op->ptr, prop)) {
115  op_params->edge_mode = RNA_property_enum_get(op->ptr, prop);
116  if (op->flag & OP_IS_INVOKE) {
117  ts->edge_mode = op_params->edge_mode;
118  }
119  }
120  else {
121  op_params->edge_mode = ts->edge_mode;
122  RNA_property_enum_set(op->ptr, prop, op_params->edge_mode);
123  }
124  }
125 
126  op_params->track_active = false;
127  op_params->use_face_step = RNA_boolean_get(op->ptr, "use_face_step");
128  op_params->use_fill = RNA_boolean_get(op->ptr, "use_fill");
129  op_params->use_topology_distance = RNA_boolean_get(op->ptr, "use_topology_distance");
131 }
132 
134  wmOperator *UNUSED(op),
135  const PropertyRNA *prop)
136 {
137  const char *prop_id = RNA_property_identifier(prop);
138  if (STREQ(prop_id, "edge_mode")) {
139  const Scene *scene = CTX_data_scene(C);
141  if ((ts->selectmode & SCE_SELECT_EDGE) == 0) {
142  return false;
143  }
144  }
145  return true;
146 }
147 
148 struct UserData {
152 };
153 
156 /* -------------------------------------------------------------------- */
160 /* callbacks */
161 static bool verttag_filter_cb(BMVert *v, void *UNUSED(user_data_v))
162 {
164 }
165 static bool verttag_test_cb(BMVert *v, void *UNUSED(user_data_v))
166 {
168 }
169 static void verttag_set_cb(BMVert *v, bool val, void *user_data_v)
170 {
171  struct UserData *user_data = user_data_v;
172  BM_vert_select_set(user_data->bm, v, val);
173 }
174 
176  Object *obedit,
177  const struct PathSelectParams *op_params,
178  BMVert *v_act,
179  BMVert *v_dst)
180 {
181  BMEditMesh *em = BKE_editmesh_from_object(obedit);
182  BMesh *bm = em->bm;
183 
184  struct UserData user_data = {bm, obedit->data, op_params};
185  LinkNode *path = NULL;
186  bool is_path_ordered = false;
187 
188  if (v_act && (v_act != v_dst)) {
189  if (op_params->use_fill) {
191  bm, (BMElem *)v_act, (BMElem *)v_dst, verttag_filter_cb, &user_data);
192  }
193  else {
194  is_path_ordered = true;
195  path = BM_mesh_calc_path_vert(bm,
196  v_act,
197  v_dst,
198  &(const struct BMCalcPathParams){
199  .use_topology_distance = op_params->use_topology_distance,
200  .use_step_face = op_params->use_face_step,
201  },
203  &user_data);
204  }
205 
206  if (path) {
207  if (op_params->track_active) {
209  }
210  }
211  }
212 
213  BMVert *v_dst_last = v_dst;
214 
215  if (path) {
216  /* toggle the flag */
217  bool all_set = true;
218  LinkNode *node;
219 
220  node = path;
221  do {
222  if (!verttag_test_cb((BMVert *)node->link, &user_data)) {
223  all_set = false;
224  break;
225  }
226  } while ((node = node->next));
227 
228  int depth = -1;
229  node = path;
230  do {
231  if ((is_path_ordered == false) ||
233  verttag_set_cb((BMVert *)node->link, !all_set, &user_data);
234  if (is_path_ordered) {
235  v_dst_last = node->link;
236  }
237  }
238  } while ((void)depth++, (node = node->next));
239 
240  BLI_linklist_free(path, NULL);
241  }
242  else {
243  const bool is_act = !verttag_test_cb(v_dst, &user_data);
244  verttag_set_cb(v_dst, is_act, &user_data); /* switch the face option */
245  }
246 
248 
249  if (op_params->track_active) {
250  /* even if this is selected it may not be in the selection list */
251  if (BM_elem_flag_test(v_dst_last, BM_ELEM_SELECT) == 0) {
252  BM_select_history_remove(bm, v_dst_last);
253  }
254  else {
255  BM_select_history_store(bm, v_dst_last);
256  }
257  }
258 
259  EDBM_update(obedit->data,
260  &(const struct EDBMUpdate_Params){
261  .calc_looptri = false,
262  .calc_normals = false,
263  .is_destructive = false,
264  });
265 }
266 
269 /* -------------------------------------------------------------------- */
273 /* callbacks */
274 static bool edgetag_filter_cb(BMEdge *e, void *UNUSED(user_data_v))
275 {
277 }
278 static bool edgetag_test_cb(BMEdge *e, void *user_data_v)
279 {
280  struct UserData *user_data = user_data_v;
281  const char edge_mode = user_data->op_params->edge_mode;
282  BMesh *bm = user_data->bm;
283 
284  switch (edge_mode) {
285  case EDGE_MODE_SELECT:
286  return BM_elem_flag_test(e, BM_ELEM_SELECT) ? true : false;
287  case EDGE_MODE_TAG_SEAM:
288  return BM_elem_flag_test(e, BM_ELEM_SEAM) ? true : false;
289  case EDGE_MODE_TAG_SHARP:
290  return BM_elem_flag_test(e, BM_ELEM_SMOOTH) ? false : true;
292  return BM_elem_float_data_get(&bm->edata, e, CD_CREASE) ? true : false;
293  case EDGE_MODE_TAG_BEVEL:
294  return BM_elem_float_data_get(&bm->edata, e, CD_BWEIGHT) ? true : false;
295 #ifdef WITH_FREESTYLE
298  return (!fed) ? false : (fed->flag & FREESTYLE_EDGE_MARK) ? true : false;
299  }
300 #endif
301  }
302  return 0;
303 }
304 static void edgetag_set_cb(BMEdge *e, bool val, void *user_data_v)
305 {
306  struct UserData *user_data = user_data_v;
307  const char edge_mode = user_data->op_params->edge_mode;
308  BMesh *bm = user_data->bm;
309 
310  switch (edge_mode) {
311  case EDGE_MODE_SELECT:
312  BM_edge_select_set(bm, e, val);
313  break;
314  case EDGE_MODE_TAG_SEAM:
316  break;
317  case EDGE_MODE_TAG_SHARP:
319  break;
321  BM_elem_float_data_set(&bm->edata, e, CD_CREASE, (val) ? 1.0f : 0.0f);
322  break;
323  case EDGE_MODE_TAG_BEVEL:
324  BM_elem_float_data_set(&bm->edata, e, CD_BWEIGHT, (val) ? 1.0f : 0.0f);
325  break;
326 #ifdef WITH_FREESTYLE
328  FreestyleEdge *fed;
330  if (!val) {
331  fed->flag &= ~FREESTYLE_EDGE_MARK;
332  }
333  else {
334  fed->flag |= FREESTYLE_EDGE_MARK;
335  }
336  break;
337  }
338 #endif
339  }
340 }
341 
342 static void edgetag_ensure_cd_flag(Mesh *me, const char edge_mode)
343 {
344  BMesh *bm = me->edit_mesh->bm;
345 
346  switch (edge_mode) {
349  break;
350  case EDGE_MODE_TAG_BEVEL:
352  break;
353 #ifdef WITH_FREESTYLE
357  }
358  break;
359 #endif
360  default:
361  break;
362  }
363 }
364 
365 /* Mesh shortest path select, uses previously-selected edge. */
366 
367 /* since you want to create paths with multiple selects, it doesn't have extend option */
369  Object *obedit,
370  const struct PathSelectParams *op_params,
371  BMEdge *e_act,
372  BMEdge *e_dst)
373 {
374  BMEditMesh *em = BKE_editmesh_from_object(obedit);
375  BMesh *bm = em->bm;
376 
377  struct UserData user_data = {bm, obedit->data, op_params};
378  LinkNode *path = NULL;
379  bool is_path_ordered = false;
380 
382 
383  if (e_act && (e_act != e_dst)) {
384  if (op_params->use_fill) {
386  bm, (BMElem *)e_act, (BMElem *)e_dst, edgetag_filter_cb, &user_data);
387  }
388  else {
389  is_path_ordered = true;
390  path = BM_mesh_calc_path_edge(bm,
391  e_act,
392  e_dst,
393  &(const struct BMCalcPathParams){
394  .use_topology_distance = op_params->use_topology_distance,
395  .use_step_face = op_params->use_face_step,
396  },
398  &user_data);
399  }
400 
401  if (path) {
402  if (op_params->track_active) {
404  }
405  }
406  }
407 
408  BMEdge *e_dst_last = e_dst;
409 
410  if (path) {
411  /* toggle the flag */
412  bool all_set = true;
413  LinkNode *node;
414 
415  node = path;
416  do {
417  if (!edgetag_test_cb((BMEdge *)node->link, &user_data)) {
418  all_set = false;
419  break;
420  }
421  } while ((node = node->next));
422 
423  int depth = -1;
424  node = path;
425  do {
426  if ((is_path_ordered == false) ||
428  edgetag_set_cb((BMEdge *)node->link, !all_set, &user_data);
429  if (is_path_ordered) {
430  e_dst_last = node->link;
431  }
432  }
433  } while ((void)depth++, (node = node->next));
434 
435  BLI_linklist_free(path, NULL);
436  }
437  else {
438  const bool is_act = !edgetag_test_cb(e_dst, &user_data);
440  edgetag_set_cb(e_dst, is_act, &user_data); /* switch the edge option */
441  }
442 
444  if (op_params->track_active) {
445  /* simple rules - last edge is _always_ active and selected */
446  if (e_act) {
447  BM_edge_select_set(bm, e_act, false);
448  }
449  BM_edge_select_set(bm, e_dst_last, true);
450  BM_select_history_store(bm, e_dst_last);
451  }
452  }
453 
455 
456  if (op_params->track_active) {
457  /* even if this is selected it may not be in the selection list */
459  if (edgetag_test_cb(e_dst_last, &user_data) == 0) {
460  BM_select_history_remove(bm, e_dst_last);
461  }
462  else {
463  BM_select_history_store(bm, e_dst_last);
464  }
465  }
466  }
467 
468  EDBM_update(obedit->data,
469  &(const struct EDBMUpdate_Params){
470  .calc_looptri = false,
471  .calc_normals = false,
472  .is_destructive = false,
473  });
474 
476  ED_uvedit_live_unwrap(scene, &obedit, 1);
477  }
478 }
479 
482 /* -------------------------------------------------------------------- */
486 /* callbacks */
487 static bool facetag_filter_cb(BMFace *f, void *UNUSED(user_data_v))
488 {
489  return !BM_elem_flag_test(f, BM_ELEM_HIDDEN);
490 }
491 // static bool facetag_test_cb(Scene *UNUSED(scene), BMesh *UNUSED(bm), BMFace *f)
492 static bool facetag_test_cb(BMFace *f, void *UNUSED(user_data_v))
493 {
495 }
496 // static void facetag_set_cb(BMesh *bm, Scene *UNUSED(scene), BMFace *f, const bool val)
497 static void facetag_set_cb(BMFace *f, bool val, void *user_data_v)
498 {
499  struct UserData *user_data = user_data_v;
500  BM_face_select_set(user_data->bm, f, val);
501 }
502 
504  Object *obedit,
505  const struct PathSelectParams *op_params,
506  BMFace *f_act,
507  BMFace *f_dst)
508 {
509  BMEditMesh *em = BKE_editmesh_from_object(obedit);
510  BMesh *bm = em->bm;
511 
512  struct UserData user_data = {bm, obedit->data, op_params};
513  LinkNode *path = NULL;
514  bool is_path_ordered = false;
515 
516  if (f_act) {
517  if (op_params->use_fill) {
519  bm, (BMElem *)f_act, (BMElem *)f_dst, facetag_filter_cb, &user_data);
520  }
521  else {
522  is_path_ordered = true;
523  path = BM_mesh_calc_path_face(bm,
524  f_act,
525  f_dst,
526  &(const struct BMCalcPathParams){
527  .use_topology_distance = op_params->use_topology_distance,
528  .use_step_face = op_params->use_face_step,
529  },
531  &user_data);
532  }
533 
534  if (f_act != f_dst) {
535  if (path) {
536  if (op_params->track_active) {
538  }
539  }
540  }
541  }
542 
543  BMFace *f_dst_last = f_dst;
544 
545  if (path) {
546  /* toggle the flag */
547  bool all_set = true;
548  LinkNode *node;
549 
550  node = path;
551  do {
552  if (!facetag_test_cb((BMFace *)node->link, &user_data)) {
553  all_set = false;
554  break;
555  }
556  } while ((node = node->next));
557 
558  int depth = -1;
559  node = path;
560  do {
561  if ((is_path_ordered == false) ||
563  facetag_set_cb((BMFace *)node->link, !all_set, &user_data);
564  if (is_path_ordered) {
565  f_dst_last = node->link;
566  }
567  }
568  } while ((void)depth++, (node = node->next));
569 
570  BLI_linklist_free(path, NULL);
571  }
572  else {
573  const bool is_act = !facetag_test_cb(f_dst, &user_data);
574  facetag_set_cb(f_dst, is_act, &user_data); /* switch the face option */
575  }
576 
578 
579  if (op_params->track_active) {
580  /* even if this is selected it may not be in the selection list */
581  if (facetag_test_cb(f_dst_last, &user_data) == 0) {
582  BM_select_history_remove(bm, f_dst_last);
583  }
584  else {
585  BM_select_history_store(bm, f_dst_last);
586  }
587  BM_mesh_active_face_set(bm, f_dst_last);
588  }
589 
590  EDBM_update(obedit->data,
591  &(const struct EDBMUpdate_Params){
592  .calc_looptri = false,
593  .calc_normals = false,
594  .is_destructive = false,
595  });
596 }
597 
600 /* -------------------------------------------------------------------- */
605  Object *obedit,
606  const struct PathSelectParams *op_params,
607  BMElem *ele_src,
608  BMElem *ele_dst)
609 {
610  bool ok = false;
611 
612  if (ELEM(NULL, ele_src, ele_dst) || (ele_src->head.htype != ele_dst->head.htype)) {
613  /* pass */
614  }
615  else if (ele_src->head.htype == BM_VERT) {
616  mouse_mesh_shortest_path_vert(scene, obedit, op_params, (BMVert *)ele_src, (BMVert *)ele_dst);
617  ok = true;
618  }
619  else if (ele_src->head.htype == BM_EDGE) {
620  mouse_mesh_shortest_path_edge(scene, obedit, op_params, (BMEdge *)ele_src, (BMEdge *)ele_dst);
621  ok = true;
622  }
623  else if (ele_src->head.htype == BM_FACE) {
624  mouse_mesh_shortest_path_face(scene, obedit, op_params, (BMFace *)ele_src, (BMFace *)ele_dst);
625  ok = true;
626  }
627 
628  if (ok) {
631  }
632 
633  return ok;
634 }
635 
637 
638 static BMElem *edbm_elem_find_nearest(ViewContext *vc, const char htype)
639 {
640  BMEditMesh *em = vc->em;
641  float dist = ED_view3d_select_dist_px();
642 
643  if ((em->selectmode & SCE_SELECT_VERTEX) && (htype == BM_VERT)) {
644  return (BMElem *)EDBM_vert_find_nearest(vc, &dist);
645  }
646  if ((em->selectmode & SCE_SELECT_EDGE) && (htype == BM_EDGE)) {
647  return (BMElem *)EDBM_edge_find_nearest(vc, &dist);
648  }
649  if ((em->selectmode & SCE_SELECT_FACE) && (htype == BM_FACE)) {
650  return (BMElem *)EDBM_face_find_nearest(vc, &dist);
651  }
652 
653  return NULL;
654 }
655 
657 {
659 
660  if ((ele == NULL) && bm->act_face && BM_elem_flag_test(bm->act_face, BM_ELEM_SELECT)) {
661  ele = (BMElem *)bm->act_face;
662  }
663 
664  return ele;
665 }
666 
668 {
669  if (RNA_struct_property_is_set(op->ptr, "index")) {
670  return edbm_shortest_path_pick_exec(C, op);
671  }
672 
673  BMVert *eve = NULL;
674  BMEdge *eed = NULL;
675  BMFace *efa = NULL;
676 
677  ViewContext vc;
678  bool track_active = true;
679 
680  em_setup_viewcontext(C, &vc);
681  copy_v2_v2_int(vc.mval, event->mval);
682  Base *basact = BASACT(vc.view_layer);
683  BMEditMesh *em = vc.em;
684 
686 
687  {
688  int base_index = -1;
689  uint bases_len = 0;
690  Base **bases = BKE_view_layer_array_from_bases_in_edit_mode(vc.view_layer, vc.v3d, &bases_len);
691  if (EDBM_unified_findnearest(&vc, bases, bases_len, &base_index, &eve, &eed, &efa)) {
692  basact = bases[base_index];
694  em = vc.em;
695  }
696  MEM_freeN(bases);
697  }
698 
699  /* If nothing is selected, let's select the picked vertex/edge/face. */
700  if ((vc.em->bm->totvertsel == 0) && (eve || eed || efa)) {
701  /* TODO(dfelinto): right now we try to find the closest element twice.
702  * The ideal is to refactor EDBM_select_pick so it doesn't
703  * have to pick the nearest vert/edge/face again. */
704  const struct SelectPick_Params params = {
705  .sel_op = SEL_OP_ADD,
706  };
707  EDBM_select_pick(C, event->mval, &params);
708  return OPERATOR_FINISHED;
709  }
710 
711  struct PathSelectParams op_params;
712  path_select_params_from_op(op, vc.scene->toolsettings, &op_params);
713 
714  BMElem *ele_src, *ele_dst;
715  if (!(ele_src = edbm_elem_active_elem_or_face_get(em->bm)) ||
716  !(ele_dst = edbm_elem_find_nearest(&vc, ele_src->head.htype))) {
717  /* special case, toggle edge tags even when we don't have a path */
718  if (((em->selectmode & SCE_SELECT_EDGE) && (op_params.edge_mode != EDGE_MODE_SELECT)) &&
719  /* check if we only have a destination edge */
720  ((ele_src == NULL) && (ele_dst = edbm_elem_find_nearest(&vc, BM_EDGE)))) {
721  ele_src = ele_dst;
722  track_active = false;
723  }
724  else {
725  return OPERATOR_PASS_THROUGH;
726  }
727  }
728 
729  op_params.track_active = track_active;
730 
731  if (!edbm_shortest_path_pick_ex(vc.scene, vc.obedit, &op_params, ele_src, ele_dst)) {
732  return OPERATOR_PASS_THROUGH;
733  }
734 
735  if (vc.view_layer->basact != basact) {
736  ED_object_base_activate(C, basact);
737  }
738 
739  /* to support redo */
740  BM_mesh_elem_index_ensure(em->bm, ele_dst->head.htype);
741  int index = EDBM_elem_to_index_any(em, ele_dst);
742 
743  RNA_int_set(op->ptr, "index", index);
744 
745  return OPERATOR_FINISHED;
746 }
747 
749 {
751  Object *obedit = CTX_data_edit_object(C);
752  BMEditMesh *em = BKE_editmesh_from_object(obedit);
753  BMesh *bm = em->bm;
754 
755  const int index = RNA_int_get(op->ptr, "index");
756  if (index < 0 || index >= (bm->totvert + bm->totedge + bm->totface)) {
757  return OPERATOR_CANCELLED;
758  }
759 
760  BMElem *ele_src, *ele_dst;
761  if (!(ele_src = edbm_elem_active_elem_or_face_get(em->bm)) ||
762  !(ele_dst = EDBM_elem_from_index_any(em, index))) {
763  return OPERATOR_CANCELLED;
764  }
765 
766  struct PathSelectParams op_params;
768  op_params.track_active = true;
769 
770  if (!edbm_shortest_path_pick_ex(scene, obedit, &op_params, ele_src, ele_dst)) {
771  return OPERATOR_CANCELLED;
772  }
773 
774  return OPERATOR_FINISHED;
775 }
776 
778 {
779  PropertyRNA *prop;
780 
781  /* identifiers */
782  ot->name = "Pick Shortest Path";
783  ot->idname = "MESH_OT_shortest_path_pick";
784  ot->description = "Select shortest path between two selections";
785 
786  /* api callbacks */
791 
792  /* flags */
794 
795  /* properties */
797 
798  /* use for redo */
799  prop = RNA_def_int(ot->srna, "index", -1, -1, INT_MAX, "", "", 0, INT_MAX);
801 }
802 
805 /* -------------------------------------------------------------------- */
810 {
812  bool found_valid_elements = false;
813 
814  ViewLayer *view_layer = CTX_data_view_layer(C);
815  uint objects_len = 0;
817  view_layer, CTX_wm_view3d(C), &objects_len);
818  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
819  Object *obedit = objects[ob_index];
820  BMEditMesh *em = BKE_editmesh_from_object(obedit);
821  BMesh *bm = em->bm;
822  BMIter iter;
823  BMEditSelection *ese_src, *ese_dst;
824  BMElem *ele_src = NULL, *ele_dst = NULL, *ele;
825 
826  if ((em->bm->totvertsel == 0) && (em->bm->totedgesel == 0) && (em->bm->totfacesel == 0)) {
827  continue;
828  }
829 
830  /* first try to find vertices in edit selection */
831  ese_src = bm->selected.last;
832  if (ese_src && (ese_dst = ese_src->prev) && (ese_src->htype == ese_dst->htype)) {
833  ele_src = ese_src->ele;
834  ele_dst = ese_dst->ele;
835  }
836  else {
837  /* if selection history isn't available, find two selected elements */
838  ele_src = ele_dst = NULL;
839  if ((em->selectmode & SCE_SELECT_VERTEX) && (bm->totvertsel >= 2)) {
840  BM_ITER_MESH (ele, &iter, bm, BM_VERTS_OF_MESH) {
841  if (BM_elem_flag_test(ele, BM_ELEM_SELECT)) {
842  if (ele_src == NULL) {
843  ele_src = ele;
844  }
845  else if (ele_dst == NULL) {
846  ele_dst = ele;
847  }
848  else {
849  break;
850  }
851  }
852  }
853  }
854 
855  if ((ele_dst == NULL) && (em->selectmode & SCE_SELECT_EDGE) && (bm->totedgesel >= 2)) {
856  ele_src = NULL;
857  BM_ITER_MESH (ele, &iter, bm, BM_EDGES_OF_MESH) {
858  if (BM_elem_flag_test(ele, BM_ELEM_SELECT)) {
859  if (ele_src == NULL) {
860  ele_src = ele;
861  }
862  else if (ele_dst == NULL) {
863  ele_dst = ele;
864  }
865  else {
866  break;
867  }
868  }
869  }
870  }
871 
872  if ((ele_dst == NULL) && (em->selectmode & SCE_SELECT_FACE) && (bm->totfacesel >= 2)) {
873  ele_src = NULL;
874  BM_ITER_MESH (ele, &iter, bm, BM_FACES_OF_MESH) {
875  if (BM_elem_flag_test(ele, BM_ELEM_SELECT)) {
876  if (ele_src == NULL) {
877  ele_src = ele;
878  }
879  else if (ele_dst == NULL) {
880  ele_dst = ele;
881  }
882  else {
883  break;
884  }
885  }
886  }
887  }
888  }
889 
890  if (ele_src && ele_dst) {
891  struct PathSelectParams op_params;
893 
894  edbm_shortest_path_pick_ex(scene, obedit, &op_params, ele_src, ele_dst);
895 
896  found_valid_elements = true;
897  }
898  }
899  MEM_freeN(objects);
900 
901  if (!found_valid_elements) {
902  BKE_report(
903  op->reports, RPT_WARNING, "Path selection requires two matching elements to be selected");
904  return OPERATOR_CANCELLED;
905  }
906 
907  return OPERATOR_FINISHED;
908 }
909 
911 {
912  /* identifiers */
913  ot->name = "Select Shortest Path";
914  ot->idname = "MESH_OT_shortest_path_select";
915  ot->description = "Selected shortest path between two vertices/edges/faces";
916 
917  /* api callbacks */
921 
922  /* flags */
924 
925  /* properties */
927 }
928 
struct Scene * CTX_data_scene(const bContext *C)
Definition: context.c:1090
struct Object * CTX_data_edit_object(const bContext *C)
Definition: context.c:1370
struct ViewLayer * CTX_data_view_layer(const bContext *C)
Definition: context.c:1100
struct View3D * CTX_wm_view3d(const bContext *C)
Definition: context.c:784
CustomData interface, see also DNA_customdata_types.h.
bool CustomData_has_layer(const struct CustomData *data, int type)
void * CustomData_bmesh_get(const struct CustomData *data, void *block, int type)
BMEditMesh * BKE_editmesh_from_object(struct Object *ob)
Return the BMEditMesh for a given object.
Definition: editmesh.c:58
#define BKE_view_layer_array_from_bases_in_edit_mode(view_layer, v3d, r_len)
Definition: BKE_layer.h:539
#define BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, v3d, r_len)
Definition: BKE_layer.h:542
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition: report.c:83
MINLINE void copy_v2_v2_int(int r[2], const int a[2])
unsigned int uint
Definition: BLI_sys_types.h:67
#define UNUSED(x)
#define ELEM(...)
#define STREQ(a, b)
void DEG_id_tag_update(struct ID *id, int flag)
@ ID_RECALC_SELECT
Definition: DNA_ID.h:818
@ CD_FREESTYLE_EDGE
@ CD_BWEIGHT
@ ME_CDFLAG_EDGE_CREASE
@ ME_CDFLAG_EDGE_BWEIGHT
@ FREESTYLE_EDGE_MARK
Object is a sort of wrapper for general info.
#define SCE_SELECT_FACE
#define BASACT(_view_layer)
#define SCE_SELECT_VERTEX
#define SCE_SELECT_EDGE
@ OPERATOR_CANCELLED
@ OPERATOR_FINISHED
@ OPERATOR_PASS_THROUGH
struct BMVert * EDBM_vert_find_nearest(struct ViewContext *vc, float *dist_px_manhattan_p)
bool EDBM_select_pick(struct bContext *C, const int mval[2], const struct SelectPick_Params *params)
void EDBM_update(struct Mesh *me, const struct EDBMUpdate_Params *params)
struct BMEdge * EDBM_edge_find_nearest(struct ViewContext *vc, float *dist_px_manhattan_p)
void em_setup_viewcontext(struct bContext *C, struct ViewContext *vc)
bool EDBM_unified_findnearest(struct ViewContext *vc, struct Base **bases, uint bases_len, int *r_base_index, struct BMVert **r_eve, struct BMEdge **r_eed, struct BMFace **r_efa)
struct BMFace * EDBM_face_find_nearest(struct ViewContext *vc, float *dist_px_manhattan_p)
void EDBM_selectmode_flush(struct BMEditMesh *em)
void ED_object_base_activate(struct bContext *C, struct Base *base)
bool ED_operator_editmesh_region_view3d(struct bContext *C)
Definition: screen_ops.c:447
bool ED_operator_editmesh(struct bContext *C)
Definition: screen_ops.c:433
@ SEL_OP_ADD
void ED_uvedit_live_unwrap(const struct Scene *scene, struct Object **objects, int objects_len)
void ED_view3d_viewcontext_init_object(struct ViewContext *vc, struct Object *obact)
void view3d_operator_needs_opengl(const struct bContext *C)
float ED_view3d_select_dist_px(void)
Read Guarded memory(de)allocation.
@ PROP_SKIP_SAVE
Definition: RNA_types.h:218
@ PROP_HIDDEN
Definition: RNA_types.h:216
#define C
Definition: RandGen.cpp:25
@ OPTYPE_UNDO
Definition: WM_types.h:148
@ OPTYPE_REGISTER
Definition: WM_types.h:146
#define NC_GEOM
Definition: WM_types.h:343
#define ND_SELECT
Definition: WM_types.h:455
@ BM_FACE
Definition: bmesh_class.h:386
@ BM_VERT
Definition: bmesh_class.h:383
@ BM_EDGE
Definition: bmesh_class.h:384
@ BM_ELEM_HIDDEN
Definition: bmesh_class.h:472
@ BM_ELEM_SEAM
Definition: bmesh_class.h:473
@ BM_ELEM_SELECT
Definition: bmesh_class.h:471
@ BM_ELEM_SMOOTH
Definition: bmesh_class.h:477
#define BM_elem_flag_set(ele, hflag, val)
Definition: bmesh_inline.h:16
#define BM_elem_flag_test(ele, hflag)
Definition: bmesh_inline.h:12
#define BM_elem_flag_test_bool(ele, hflag)
Definition: bmesh_inline.h:13
float BM_elem_float_data_get(CustomData *cd, void *element, int type)
Definition: bmesh_interp.c:990
void BM_data_layer_add(BMesh *bm, CustomData *data, int type)
Definition: bmesh_interp.c:839
void BM_elem_float_data_set(CustomData *cd, void *element, int type, const float val)
Definition: bmesh_interp.c:996
#define BM_ITER_MESH(ele, iter, bm, itype)
@ BM_EDGES_OF_MESH
@ BM_VERTS_OF_MESH
@ BM_FACES_OF_MESH
ATTR_WARN_UNUSED_RESULT BMesh * bm
void BM_face_select_set(BMesh *bm, BMFace *f, const bool select)
Select Face.
void BM_vert_select_set(BMesh *bm, BMVert *v, const bool select)
Select Vert.
void BM_edge_select_set(BMesh *bm, BMEdge *e, const bool select)
Select Edge.
void BM_mesh_active_face_set(BMesh *bm, BMFace *f)
BMElem * BM_mesh_active_elem_get(BMesh *bm)
#define BM_select_history_store(bm, ele)
#define BM_select_history_remove(bm, ele)
void BM_mesh_elem_index_ensure(BMesh *bm, const char htype)
Definition: bmesh_mesh.cc:446
void BM_mesh_cd_flag_ensure(BMesh *bm, Mesh *mesh, const char cd_flag)
LinkNode * BM_mesh_calc_path_vert(BMesh *bm, BMVert *v_src, BMVert *v_dst, const struct BMCalcPathParams *params, bool(*filter_fn)(BMVert *, void *user_data), void *user_data)
Definition: bmesh_path.c:115
LinkNode * BM_mesh_calc_path_edge(BMesh *bm, BMEdge *e_src, BMEdge *e_dst, const struct BMCalcPathParams *params, bool(*filter_fn)(BMEdge *, void *user_data), void *user_data)
Definition: bmesh_path.c:295
LinkNode * BM_mesh_calc_path_face(BMesh *bm, BMFace *f_src, BMFace *f_dst, const struct BMCalcPathParams *params, bool(*filter_fn)(BMFace *, void *user_data), void *user_data)
Definition: bmesh_path.c:493
LinkNode * BM_mesh_calc_path_region_edge(BMesh *bm, BMElem *ele_src, BMElem *ele_dst, bool(*filter_fn)(BMEdge *, void *user_data), void *user_data)
LinkNode * BM_mesh_calc_path_region_vert(BMesh *bm, BMElem *ele_src, BMElem *ele_dst, bool(*filter_fn)(BMVert *, void *user_data), void *user_data)
LinkNode * BM_mesh_calc_path_region_face(BMesh *bm, BMElem *ele_src, BMElem *ele_dst, bool(*filter_fn)(BMFace *, void *user_data), void *user_data)
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
ATTR_WARN_UNUSED_RESULT const BMVert * v
OperationNode * node
Scene scene
void * user_data
static bool edgetag_test_cb(BMEdge *e, void *user_data_v)
static void edgetag_ensure_cd_flag(Mesh *me, const char edge_mode)
static bool path_select_poll_property(const bContext *C, wmOperator *UNUSED(op), const PropertyRNA *prop)
static BMElem * edbm_elem_active_elem_or_face_get(BMesh *bm)
static int edbm_shortest_path_select_exec(bContext *C, wmOperator *op)
@ EDGE_MODE_SELECT
Definition: editmesh_path.c:53
@ EDGE_MODE_TAG_SEAM
Definition: editmesh_path.c:54
@ EDGE_MODE_TAG_BEVEL
Definition: editmesh_path.c:57
@ EDGE_MODE_TAG_FREESTYLE
Definition: editmesh_path.c:58
@ EDGE_MODE_TAG_SHARP
Definition: editmesh_path.c:55
@ EDGE_MODE_TAG_CREASE
Definition: editmesh_path.c:56
static void verttag_set_cb(BMVert *v, bool val, void *user_data_v)
static bool edgetag_filter_cb(BMEdge *e, void *UNUSED(user_data_v))
static int edbm_shortest_path_pick_exec(bContext *C, wmOperator *op)
static bool verttag_test_cb(BMVert *v, void *UNUSED(user_data_v))
static bool facetag_filter_cb(BMFace *f, void *UNUSED(user_data_v))
static void mouse_mesh_shortest_path_vert(Scene *UNUSED(scene), Object *obedit, const struct PathSelectParams *op_params, BMVert *v_act, BMVert *v_dst)
static void mouse_mesh_shortest_path_edge(Scene *scene, Object *obedit, const struct PathSelectParams *op_params, BMEdge *e_act, BMEdge *e_dst)
void MESH_OT_shortest_path_select(wmOperatorType *ot)
static void path_select_params_from_op(wmOperator *op, ToolSettings *ts, struct PathSelectParams *op_params)
static bool edbm_shortest_path_pick_ex(Scene *scene, Object *obedit, const struct PathSelectParams *op_params, BMElem *ele_src, BMElem *ele_dst)
static void path_select_properties(wmOperatorType *ot)
Definition: editmesh_path.c:71
static bool facetag_test_cb(BMFace *f, void *UNUSED(user_data_v))
static BMElem * edbm_elem_find_nearest(ViewContext *vc, const char htype)
static void edgetag_set_cb(BMEdge *e, bool val, void *user_data_v)
static int edbm_shortest_path_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static void mouse_mesh_shortest_path_face(Scene *UNUSED(scene), Object *obedit, const struct PathSelectParams *op_params, BMFace *f_act, BMFace *f_dst)
static bool verttag_filter_cb(BMVert *v, void *UNUSED(user_data_v))
static void facetag_set_cb(BMFace *f, bool val, void *user_data_v)
void MESH_OT_shortest_path_pick(wmOperatorType *ot)
BMElem * EDBM_elem_from_index_any(BMEditMesh *em, uint index)
int EDBM_elem_to_index_any(BMEditMesh *em, BMElem *ele)
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
const char * RNA_property_identifier(const PropertyRNA *prop)
Definition: rna_access.c:1000
bool RNA_property_is_set(PointerRNA *ptr, PropertyRNA *prop)
Definition: rna_access.c:5271
void RNA_int_set(PointerRNA *ptr, const char *name, int value)
Definition: rna_access.c:4921
void RNA_property_enum_set(PointerRNA *ptr, PropertyRNA *prop, int value)
Definition: rna_access.c:3421
PropertyRNA * RNA_struct_find_property(PointerRNA *ptr, const char *identifier)
Definition: rna_access.c:717
int RNA_int_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:4910
int RNA_property_enum_get(PointerRNA *ptr, PropertyRNA *prop)
Definition: rna_access.c:3402
bool RNA_struct_property_is_set(PointerRNA *ptr, const char *identifier)
Definition: rna_access.c:5301
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:4863
PropertyRNA * RNA_def_boolean(StructOrFunctionRNA *cont_, const char *identifier, bool default_value, const char *ui_name, const char *ui_description)
Definition: rna_define.c:3493
void RNA_def_property_flag(PropertyRNA *prop, PropertyFlag flag)
Definition: rna_define.c:1490
PropertyRNA * RNA_def_int(StructOrFunctionRNA *cont_, const char *identifier, int default_value, int hardmin, int hardmax, const char *ui_name, const char *ui_description, int softmin, int softmax)
Definition: rna_define.c:3597
PropertyRNA * RNA_def_enum(StructOrFunctionRNA *cont_, const char *identifier, const EnumPropertyItem *items, int default_value, const char *ui_name, const char *ui_description)
Definition: rna_define.c:3783
short selectmode
Definition: BKE_editmesh.h:52
struct BMesh * bm
Definition: BKE_editmesh.h:40
struct BMEditSelection * prev
Definition: bmesh_marking.h:10
BMHeader head
Definition: bmesh_class.h:243
char htype
Definition: bmesh_class.h:64
void * data
Definition: bmesh_class.h:51
BMHeader head
Definition: bmesh_class.h:85
int totvert
Definition: bmesh_class.h:297
int totfacesel
Definition: bmesh_class.h:298
int totedge
Definition: bmesh_class.h:297
ListBase selected
Definition: bmesh_class.h:356
CustomData edata
Definition: bmesh_class.h:337
int totvertsel
Definition: bmesh_class.h:298
BMFace * act_face
Definition: bmesh_class.h:366
int totedgesel
Definition: bmesh_class.h:298
int totface
Definition: bmesh_class.h:297
struct Object * object
void * last
Definition: DNA_listBase.h:31
struct BMEditMesh * edit_mesh
void * data
struct CheckerIntervalParams interval_params
Definition: editmesh_path.c:68
bool use_topology_distance
Definition: editmesh_path.c:64
struct ToolSettings * toolsettings
const struct PathSelectParams * op_params
BMesh * bm
Mesh * me
int mval[2]
Definition: ED_view3d.h:74
struct Scene * scene
Definition: ED_view3d.h:65
struct ViewLayer * view_layer
Definition: ED_view3d.h:66
struct BMEditMesh * em
Definition: ED_view3d.h:73
struct Object * obedit
Definition: ED_view3d.h:68
struct View3D * v3d
Definition: ED_view3d.h:70
struct Base * basact
int mval[2]
Definition: WM_types.h:684
int(* invoke)(struct bContext *, struct wmOperator *, const struct wmEvent *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:919
const char * name
Definition: WM_types.h:888
const char * idname
Definition: WM_types.h:890
bool(* poll)(struct bContext *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:943
bool(* poll_property)(const struct bContext *C, struct wmOperator *op, const PropertyRNA *prop) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:949
struct StructRNA * srna
Definition: WM_types.h:969
const char * description
Definition: WM_types.h:893
int(* exec)(struct bContext *, struct wmOperator *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:903
struct ReportList * reports
struct PointerRNA * ptr
void WM_main_add_notifier(unsigned int type, void *reference)
wmOperatorType * ot
Definition: wm_files.c:3479
bool WM_operator_properties_checker_interval_test(const struct CheckerIntervalParams *op_params, int depth)
void WM_operator_properties_checker_interval_from_op(struct wmOperator *op, struct CheckerIntervalParams *op_params)
void WM_operator_properties_checker_interval(wmOperatorType *ot, bool nth_can_disable)