Blender  V2.93
editmesh_path.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) 2004 Blender Foundation.
17  * All rights reserved.
18  */
19 
24 #include "MEM_guardedalloc.h"
25 
26 #include "DNA_mesh_types.h"
27 #include "DNA_object_types.h"
28 #include "DNA_scene_types.h"
30 
31 #ifdef WITH_FREESTYLE
32 # include "DNA_meshdata_types.h"
33 #endif
34 
35 #include "BLI_linklist.h"
36 #include "BLI_math.h"
37 
38 #include "BKE_context.h"
39 #include "BKE_editmesh.h"
40 #include "BKE_layer.h"
41 #include "BKE_report.h"
42 
43 #include "ED_mesh.h"
44 #include "ED_object.h"
45 #include "ED_screen.h"
46 #include "ED_uvedit.h"
47 #include "ED_view3d.h"
48 
49 #include "RNA_access.h"
50 #include "RNA_define.h"
51 
52 #include "WM_api.h"
53 #include "WM_types.h"
54 
55 #include "bmesh.h"
56 #include "bmesh_tools.h"
57 
58 #include "DEG_depsgraph.h"
59 
60 #include "mesh_intern.h" /* own include */
61 
62 /* -------------------------------------------------------------------- */
66 enum {
73 };
74 
80  bool use_fill;
81  char edge_mode;
83 };
84 
86 {
87  static const EnumPropertyItem edge_tag_items[] = {
88  {EDGE_MODE_SELECT, "SELECT", 0, "Select", ""},
89  {EDGE_MODE_TAG_SEAM, "SEAM", 0, "Tag Seam", ""},
90  {EDGE_MODE_TAG_SHARP, "SHARP", 0, "Tag Sharp", ""},
91  {EDGE_MODE_TAG_CREASE, "CREASE", 0, "Tag Crease", ""},
92  {EDGE_MODE_TAG_BEVEL, "BEVEL", 0, "Tag Bevel", ""},
93  {EDGE_MODE_TAG_FREESTYLE, "FREESTYLE", 0, "Tag Freestyle Edge Mark", ""},
94  {0, NULL, 0, NULL, NULL},
95  };
96 
98  "edge_mode",
99  edge_tag_items,
101  "Edge Tag",
102  "The edge flag to tag when selecting the shortest path");
103 
105  "use_face_step",
106  false,
107  "Face Stepping",
108  "Traverse connected faces (includes diagonals and edge-rings)");
110  "use_topology_distance",
111  false,
112  "Topology Distance",
113  "Find the minimum number of steps, ignoring spatial distance");
115  "use_fill",
116  false,
117  "Fill Region",
118  "Select all paths between the source/destination elements");
120 }
121 
123  ToolSettings *ts,
124  struct PathSelectParams *op_params)
125 {
126  {
127  PropertyRNA *prop = RNA_struct_find_property(op->ptr, "edge_mode");
128  if (RNA_property_is_set(op->ptr, prop)) {
129  op_params->edge_mode = RNA_property_enum_get(op->ptr, prop);
130  if (op->flag & OP_IS_INVOKE) {
131  ts->edge_mode = op_params->edge_mode;
132  }
133  }
134  else {
135  op_params->edge_mode = ts->edge_mode;
136  RNA_property_enum_set(op->ptr, prop, op_params->edge_mode);
137  }
138  }
139 
140  op_params->track_active = false;
141  op_params->use_face_step = RNA_boolean_get(op->ptr, "use_face_step");
142  op_params->use_fill = RNA_boolean_get(op->ptr, "use_fill");
143  op_params->use_topology_distance = RNA_boolean_get(op->ptr, "use_topology_distance");
145 }
146 
148  wmOperator *UNUSED(op),
149  const PropertyRNA *prop)
150 {
151  const char *prop_id = RNA_property_identifier(prop);
152  if (STREQ(prop_id, "edge_mode")) {
153  const Scene *scene = CTX_data_scene(C);
155  if ((ts->selectmode & SCE_SELECT_EDGE) == 0) {
156  return false;
157  }
158  }
159  return true;
160 }
161 
162 struct UserData {
166 };
167 
170 /* -------------------------------------------------------------------- */
174 /* callbacks */
175 static bool verttag_filter_cb(BMVert *v, void *UNUSED(user_data_v))
176 {
178 }
179 static bool verttag_test_cb(BMVert *v, void *UNUSED(user_data_v))
180 {
182 }
183 static void verttag_set_cb(BMVert *v, bool val, void *user_data_v)
184 {
185  struct UserData *user_data = user_data_v;
186  BM_vert_select_set(user_data->bm, v, val);
187 }
188 
190  Object *obedit,
191  const struct PathSelectParams *op_params,
192  BMVert *v_act,
193  BMVert *v_dst)
194 {
195  BMEditMesh *em = BKE_editmesh_from_object(obedit);
196  BMesh *bm = em->bm;
197 
198  struct UserData user_data = {bm, obedit->data, op_params};
199  LinkNode *path = NULL;
200  bool is_path_ordered = false;
201 
202  if (v_act && (v_act != v_dst)) {
203  if (op_params->use_fill) {
205  bm, (BMElem *)v_act, (BMElem *)v_dst, verttag_filter_cb, &user_data);
206  }
207  else {
208  is_path_ordered = true;
209  path = BM_mesh_calc_path_vert(bm,
210  v_act,
211  v_dst,
212  &(const struct BMCalcPathParams){
213  .use_topology_distance = op_params->use_topology_distance,
214  .use_step_face = op_params->use_face_step,
215  },
217  &user_data);
218  }
219 
220  if (path) {
221  if (op_params->track_active) {
223  }
224  }
225  }
226 
227  BMVert *v_dst_last = v_dst;
228 
229  if (path) {
230  /* toggle the flag */
231  bool all_set = true;
232  LinkNode *node;
233 
234  node = path;
235  do {
236  if (!verttag_test_cb((BMVert *)node->link, &user_data)) {
237  all_set = false;
238  break;
239  }
240  } while ((node = node->next));
241 
242  int depth = -1;
243  node = path;
244  do {
245  if ((is_path_ordered == false) ||
247  verttag_set_cb((BMVert *)node->link, !all_set, &user_data);
248  if (is_path_ordered) {
249  v_dst_last = node->link;
250  }
251  }
252  } while ((void)depth++, (node = node->next));
253 
254  BLI_linklist_free(path, NULL);
255  }
256  else {
257  const bool is_act = !verttag_test_cb(v_dst, &user_data);
258  verttag_set_cb(v_dst, is_act, &user_data); /* switch the face option */
259  }
260 
262 
263  if (op_params->track_active) {
264  /* even if this is selected it may not be in the selection list */
265  if (BM_elem_flag_test(v_dst_last, BM_ELEM_SELECT) == 0) {
266  BM_select_history_remove(bm, v_dst_last);
267  }
268  else {
269  BM_select_history_store(bm, v_dst_last);
270  }
271  }
272 
273  EDBM_update_generic(obedit->data, false, false);
274 }
275 
278 /* -------------------------------------------------------------------- */
282 /* callbacks */
283 static bool edgetag_filter_cb(BMEdge *e, void *UNUSED(user_data_v))
284 {
286 }
287 static bool edgetag_test_cb(BMEdge *e, void *user_data_v)
288 {
289  struct UserData *user_data = user_data_v;
290  const char edge_mode = user_data->op_params->edge_mode;
291  BMesh *bm = user_data->bm;
292 
293  switch (edge_mode) {
294  case EDGE_MODE_SELECT:
295  return BM_elem_flag_test(e, BM_ELEM_SELECT) ? true : false;
296  case EDGE_MODE_TAG_SEAM:
297  return BM_elem_flag_test(e, BM_ELEM_SEAM) ? true : false;
298  case EDGE_MODE_TAG_SHARP:
299  return BM_elem_flag_test(e, BM_ELEM_SMOOTH) ? false : true;
301  return BM_elem_float_data_get(&bm->edata, e, CD_CREASE) ? true : false;
302  case EDGE_MODE_TAG_BEVEL:
303  return BM_elem_float_data_get(&bm->edata, e, CD_BWEIGHT) ? true : false;
304 #ifdef WITH_FREESTYLE
307  return (!fed) ? false : (fed->flag & FREESTYLE_EDGE_MARK) ? true : false;
308  }
309 #endif
310  }
311  return 0;
312 }
313 static void edgetag_set_cb(BMEdge *e, bool val, void *user_data_v)
314 {
315  struct UserData *user_data = user_data_v;
316  const char edge_mode = user_data->op_params->edge_mode;
317  BMesh *bm = user_data->bm;
318 
319  switch (edge_mode) {
320  case EDGE_MODE_SELECT:
321  BM_edge_select_set(bm, e, val);
322  break;
323  case EDGE_MODE_TAG_SEAM:
325  break;
326  case EDGE_MODE_TAG_SHARP:
328  break;
330  BM_elem_float_data_set(&bm->edata, e, CD_CREASE, (val) ? 1.0f : 0.0f);
331  break;
332  case EDGE_MODE_TAG_BEVEL:
333  BM_elem_float_data_set(&bm->edata, e, CD_BWEIGHT, (val) ? 1.0f : 0.0f);
334  break;
335 #ifdef WITH_FREESTYLE
337  FreestyleEdge *fed;
339  if (!val) {
340  fed->flag &= ~FREESTYLE_EDGE_MARK;
341  }
342  else {
343  fed->flag |= FREESTYLE_EDGE_MARK;
344  }
345  break;
346  }
347 #endif
348  }
349 }
350 
351 static void edgetag_ensure_cd_flag(Mesh *me, const char edge_mode)
352 {
353  BMesh *bm = me->edit_mesh->bm;
354 
355  switch (edge_mode) {
358  break;
359  case EDGE_MODE_TAG_BEVEL:
361  break;
362 #ifdef WITH_FREESTYLE
366  }
367  break;
368 #endif
369  default:
370  break;
371  }
372 }
373 
374 /* mesh shortest path select, uses prev-selected edge */
375 
376 /* since you want to create paths with multiple selects, it doesn't have extend option */
378  Object *obedit,
379  const struct PathSelectParams *op_params,
380  BMEdge *e_act,
381  BMEdge *e_dst)
382 {
383  BMEditMesh *em = BKE_editmesh_from_object(obedit);
384  BMesh *bm = em->bm;
385 
386  struct UserData user_data = {bm, obedit->data, op_params};
387  LinkNode *path = NULL;
388  bool is_path_ordered = false;
389 
391 
392  if (e_act && (e_act != e_dst)) {
393  if (op_params->use_fill) {
395  bm, (BMElem *)e_act, (BMElem *)e_dst, edgetag_filter_cb, &user_data);
396  }
397  else {
398  is_path_ordered = true;
399  path = BM_mesh_calc_path_edge(bm,
400  e_act,
401  e_dst,
402  &(const struct BMCalcPathParams){
403  .use_topology_distance = op_params->use_topology_distance,
404  .use_step_face = op_params->use_face_step,
405  },
407  &user_data);
408  }
409 
410  if (path) {
411  if (op_params->track_active) {
413  }
414  }
415  }
416 
417  BMEdge *e_dst_last = e_dst;
418 
419  if (path) {
420  /* toggle the flag */
421  bool all_set = true;
422  LinkNode *node;
423 
424  node = path;
425  do {
426  if (!edgetag_test_cb((BMEdge *)node->link, &user_data)) {
427  all_set = false;
428  break;
429  }
430  } while ((node = node->next));
431 
432  int depth = -1;
433  node = path;
434  do {
435  if ((is_path_ordered == false) ||
437  edgetag_set_cb((BMEdge *)node->link, !all_set, &user_data);
438  if (is_path_ordered) {
439  e_dst_last = node->link;
440  }
441  }
442  } while ((void)depth++, (node = node->next));
443 
444  BLI_linklist_free(path, NULL);
445  }
446  else {
447  const bool is_act = !edgetag_test_cb(e_dst, &user_data);
449  edgetag_set_cb(e_dst, is_act, &user_data); /* switch the edge option */
450  }
451 
453  if (op_params->track_active) {
454  /* simple rules - last edge is _always_ active and selected */
455  if (e_act) {
456  BM_edge_select_set(bm, e_act, false);
457  }
458  BM_edge_select_set(bm, e_dst_last, true);
459  BM_select_history_store(bm, e_dst_last);
460  }
461  }
462 
464 
465  if (op_params->track_active) {
466  /* even if this is selected it may not be in the selection list */
468  if (edgetag_test_cb(e_dst_last, &user_data) == 0) {
469  BM_select_history_remove(bm, e_dst_last);
470  }
471  else {
472  BM_select_history_store(bm, e_dst_last);
473  }
474  }
475  }
476 
477  EDBM_update_generic(obedit->data, false, false);
478 
480  ED_uvedit_live_unwrap(scene, &obedit, 1);
481  }
482 }
483 
486 /* -------------------------------------------------------------------- */
490 /* callbacks */
491 static bool facetag_filter_cb(BMFace *f, void *UNUSED(user_data_v))
492 {
493  return !BM_elem_flag_test(f, BM_ELEM_HIDDEN);
494 }
495 // static bool facetag_test_cb(Scene *UNUSED(scene), BMesh *UNUSED(bm), BMFace *f)
496 static bool facetag_test_cb(BMFace *f, void *UNUSED(user_data_v))
497 {
499 }
500 // static void facetag_set_cb(BMesh *bm, Scene *UNUSED(scene), BMFace *f, const bool val)
501 static void facetag_set_cb(BMFace *f, bool val, void *user_data_v)
502 {
503  struct UserData *user_data = user_data_v;
504  BM_face_select_set(user_data->bm, f, val);
505 }
506 
508  Object *obedit,
509  const struct PathSelectParams *op_params,
510  BMFace *f_act,
511  BMFace *f_dst)
512 {
513  BMEditMesh *em = BKE_editmesh_from_object(obedit);
514  BMesh *bm = em->bm;
515 
516  struct UserData user_data = {bm, obedit->data, op_params};
517  LinkNode *path = NULL;
518  bool is_path_ordered = false;
519 
520  if (f_act) {
521  if (op_params->use_fill) {
523  bm, (BMElem *)f_act, (BMElem *)f_dst, facetag_filter_cb, &user_data);
524  }
525  else {
526  is_path_ordered = true;
527  path = BM_mesh_calc_path_face(bm,
528  f_act,
529  f_dst,
530  &(const struct BMCalcPathParams){
531  .use_topology_distance = op_params->use_topology_distance,
532  .use_step_face = op_params->use_face_step,
533  },
535  &user_data);
536  }
537 
538  if (f_act != f_dst) {
539  if (path) {
540  if (op_params->track_active) {
542  }
543  }
544  }
545  }
546 
547  BMFace *f_dst_last = f_dst;
548 
549  if (path) {
550  /* toggle the flag */
551  bool all_set = true;
552  LinkNode *node;
553 
554  node = path;
555  do {
556  if (!facetag_test_cb((BMFace *)node->link, &user_data)) {
557  all_set = false;
558  break;
559  }
560  } while ((node = node->next));
561 
562  int depth = -1;
563  node = path;
564  do {
565  if ((is_path_ordered == false) ||
567  facetag_set_cb((BMFace *)node->link, !all_set, &user_data);
568  if (is_path_ordered) {
569  f_dst_last = node->link;
570  }
571  }
572  } while ((void)depth++, (node = node->next));
573 
574  BLI_linklist_free(path, NULL);
575  }
576  else {
577  const bool is_act = !facetag_test_cb(f_dst, &user_data);
578  facetag_set_cb(f_dst, is_act, &user_data); /* switch the face option */
579  }
580 
582 
583  if (op_params->track_active) {
584  /* even if this is selected it may not be in the selection list */
585  if (facetag_test_cb(f_dst_last, &user_data) == 0) {
586  BM_select_history_remove(bm, f_dst_last);
587  }
588  else {
589  BM_select_history_store(bm, f_dst_last);
590  }
591  BM_mesh_active_face_set(bm, f_dst_last);
592  }
593 
594  EDBM_update_generic(obedit->data, false, false);
595 }
596 
599 /* -------------------------------------------------------------------- */
604  Object *obedit,
605  const struct PathSelectParams *op_params,
606  BMElem *ele_src,
607  BMElem *ele_dst)
608 {
609  bool ok = false;
610 
611  if (ELEM(NULL, ele_src, ele_dst) || (ele_src->head.htype != ele_dst->head.htype)) {
612  /* pass */
613  }
614  else if (ele_src->head.htype == BM_VERT) {
615  mouse_mesh_shortest_path_vert(scene, obedit, op_params, (BMVert *)ele_src, (BMVert *)ele_dst);
616  ok = true;
617  }
618  else if (ele_src->head.htype == BM_EDGE) {
619  mouse_mesh_shortest_path_edge(scene, obedit, op_params, (BMEdge *)ele_src, (BMEdge *)ele_dst);
620  ok = true;
621  }
622  else if (ele_src->head.htype == BM_FACE) {
623  mouse_mesh_shortest_path_face(scene, obedit, op_params, (BMFace *)ele_src, (BMFace *)ele_dst);
624  ok = true;
625  }
626 
627  if (ok) {
630  }
631 
632  return ok;
633 }
634 
636 
637 static BMElem *edbm_elem_find_nearest(ViewContext *vc, const char htype)
638 {
639  BMEditMesh *em = vc->em;
640  float dist = ED_view3d_select_dist_px();
641 
642  if ((em->selectmode & SCE_SELECT_VERTEX) && (htype == BM_VERT)) {
643  return (BMElem *)EDBM_vert_find_nearest(vc, &dist);
644  }
645  if ((em->selectmode & SCE_SELECT_EDGE) && (htype == BM_EDGE)) {
646  return (BMElem *)EDBM_edge_find_nearest(vc, &dist);
647  }
648  if ((em->selectmode & SCE_SELECT_FACE) && (htype == BM_FACE)) {
649  return (BMElem *)EDBM_face_find_nearest(vc, &dist);
650  }
651 
652  return NULL;
653 }
654 
656 {
658 
659  if ((ele == NULL) && bm->act_face && BM_elem_flag_test(bm->act_face, BM_ELEM_SELECT)) {
660  ele = (BMElem *)bm->act_face;
661  }
662 
663  return ele;
664 }
665 
667 {
668  if (RNA_struct_property_is_set(op->ptr, "index")) {
669  return edbm_shortest_path_pick_exec(C, op);
670  }
671 
672  BMVert *eve = NULL;
673  BMEdge *eed = NULL;
674  BMFace *efa = NULL;
675 
676  ViewContext vc;
677  bool track_active = true;
678 
679  em_setup_viewcontext(C, &vc);
680  copy_v2_v2_int(vc.mval, event->mval);
681  Base *basact = BASACT(vc.view_layer);
682  BMEditMesh *em = vc.em;
683 
685 
686  {
687  int base_index = -1;
688  uint bases_len = 0;
689  Base **bases = BKE_view_layer_array_from_bases_in_edit_mode(vc.view_layer, vc.v3d, &bases_len);
690  if (EDBM_unified_findnearest(&vc, bases, bases_len, &base_index, &eve, &eed, &efa)) {
691  basact = bases[base_index];
693  em = vc.em;
694  }
695  MEM_freeN(bases);
696  }
697 
698  /* If nothing is selected, let's select the picked vertex/edge/face. */
699  if ((vc.em->bm->totvertsel == 0) && (eve || eed || efa)) {
700  /* TODO(dfelinto): right now we try to find the closest element twice.
701  * The ideal is to refactor EDBM_select_pick so it doesn't
702  * have to pick the nearest vert/edge/face again. */
703  EDBM_select_pick(C, event->mval, true, false, false);
704  return OPERATOR_FINISHED;
705  }
706 
707  struct PathSelectParams op_params;
708  path_select_params_from_op(op, vc.scene->toolsettings, &op_params);
709 
710  BMElem *ele_src, *ele_dst;
711  if (!(ele_src = edbm_elem_active_elem_or_face_get(em->bm)) ||
712  !(ele_dst = edbm_elem_find_nearest(&vc, ele_src->head.htype))) {
713  /* special case, toggle edge tags even when we don't have a path */
714  if (((em->selectmode & SCE_SELECT_EDGE) && (op_params.edge_mode != EDGE_MODE_SELECT)) &&
715  /* check if we only have a destination edge */
716  ((ele_src == NULL) && (ele_dst = edbm_elem_find_nearest(&vc, BM_EDGE)))) {
717  ele_src = ele_dst;
718  track_active = false;
719  }
720  else {
721  return OPERATOR_PASS_THROUGH;
722  }
723  }
724 
725  op_params.track_active = track_active;
726 
727  if (!edbm_shortest_path_pick_ex(vc.scene, vc.obedit, &op_params, ele_src, ele_dst)) {
728  return OPERATOR_PASS_THROUGH;
729  }
730 
731  if (vc.view_layer->basact != basact) {
732  ED_object_base_activate(C, basact);
733  }
734 
735  /* to support redo */
736  BM_mesh_elem_index_ensure(em->bm, ele_dst->head.htype);
737  int index = EDBM_elem_to_index_any(em, ele_dst);
738 
739  RNA_int_set(op->ptr, "index", index);
740 
741  return OPERATOR_FINISHED;
742 }
743 
745 {
747  Object *obedit = CTX_data_edit_object(C);
748  BMEditMesh *em = BKE_editmesh_from_object(obedit);
749  BMesh *bm = em->bm;
750 
751  const int index = RNA_int_get(op->ptr, "index");
752  if (index < 0 || index >= (bm->totvert + bm->totedge + bm->totface)) {
753  return OPERATOR_CANCELLED;
754  }
755 
756  BMElem *ele_src, *ele_dst;
757  if (!(ele_src = edbm_elem_active_elem_or_face_get(em->bm)) ||
758  !(ele_dst = EDBM_elem_from_index_any(em, index))) {
759  return OPERATOR_CANCELLED;
760  }
761 
762  struct PathSelectParams op_params;
764  op_params.track_active = true;
765 
766  if (!edbm_shortest_path_pick_ex(scene, obedit, &op_params, ele_src, ele_dst)) {
767  return OPERATOR_CANCELLED;
768  }
769 
770  return OPERATOR_FINISHED;
771 }
772 
774 {
775  PropertyRNA *prop;
776 
777  /* identifiers */
778  ot->name = "Pick Shortest Path";
779  ot->idname = "MESH_OT_shortest_path_pick";
780  ot->description = "Select shortest path between two selections";
781 
782  /* api callbacks */
787 
788  /* flags */
790 
791  /* properties */
793 
794  /* use for redo */
795  prop = RNA_def_int(ot->srna, "index", -1, -1, INT_MAX, "", "", 0, INT_MAX);
797 }
798 
801 /* -------------------------------------------------------------------- */
806 {
808  bool found_valid_elements = false;
809 
810  ViewLayer *view_layer = CTX_data_view_layer(C);
811  uint objects_len = 0;
813  view_layer, CTX_wm_view3d(C), &objects_len);
814  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
815  Object *obedit = objects[ob_index];
816  BMEditMesh *em = BKE_editmesh_from_object(obedit);
817  BMesh *bm = em->bm;
818  BMIter iter;
819  BMEditSelection *ese_src, *ese_dst;
820  BMElem *ele_src = NULL, *ele_dst = NULL, *ele;
821 
822  if ((em->bm->totvertsel == 0) && (em->bm->totedgesel == 0) && (em->bm->totfacesel == 0)) {
823  continue;
824  }
825 
826  /* first try to find vertices in edit selection */
827  ese_src = bm->selected.last;
828  if (ese_src && (ese_dst = ese_src->prev) && (ese_src->htype == ese_dst->htype)) {
829  ele_src = ese_src->ele;
830  ele_dst = ese_dst->ele;
831  }
832  else {
833  /* if selection history isn't available, find two selected elements */
834  ele_src = ele_dst = NULL;
835  if ((em->selectmode & SCE_SELECT_VERTEX) && (bm->totvertsel >= 2)) {
836  BM_ITER_MESH (ele, &iter, bm, BM_VERTS_OF_MESH) {
837  if (BM_elem_flag_test(ele, BM_ELEM_SELECT)) {
838  if (ele_src == NULL) {
839  ele_src = ele;
840  }
841  else if (ele_dst == NULL) {
842  ele_dst = ele;
843  }
844  else {
845  break;
846  }
847  }
848  }
849  }
850 
851  if ((ele_dst == NULL) && (em->selectmode & SCE_SELECT_EDGE) && (bm->totedgesel >= 2)) {
852  ele_src = NULL;
853  BM_ITER_MESH (ele, &iter, bm, BM_EDGES_OF_MESH) {
854  if (BM_elem_flag_test(ele, BM_ELEM_SELECT)) {
855  if (ele_src == NULL) {
856  ele_src = ele;
857  }
858  else if (ele_dst == NULL) {
859  ele_dst = ele;
860  }
861  else {
862  break;
863  }
864  }
865  }
866  }
867 
868  if ((ele_dst == NULL) && (em->selectmode & SCE_SELECT_FACE) && (bm->totfacesel >= 2)) {
869  ele_src = NULL;
870  BM_ITER_MESH (ele, &iter, bm, BM_FACES_OF_MESH) {
871  if (BM_elem_flag_test(ele, BM_ELEM_SELECT)) {
872  if (ele_src == NULL) {
873  ele_src = ele;
874  }
875  else if (ele_dst == NULL) {
876  ele_dst = ele;
877  }
878  else {
879  break;
880  }
881  }
882  }
883  }
884  }
885 
886  if (ele_src && ele_dst) {
887  struct PathSelectParams op_params;
889 
890  edbm_shortest_path_pick_ex(scene, obedit, &op_params, ele_src, ele_dst);
891 
892  found_valid_elements = true;
893  }
894  }
895  MEM_freeN(objects);
896 
897  if (!found_valid_elements) {
898  BKE_report(
899  op->reports, RPT_WARNING, "Path selection requires two matching elements to be selected");
900  return OPERATOR_CANCELLED;
901  }
902 
903  return OPERATOR_FINISHED;
904 }
905 
907 {
908  /* identifiers */
909  ot->name = "Select Shortest Path";
910  ot->idname = "MESH_OT_shortest_path_select";
911  ot->description = "Selected shortest path between two vertices/edges/faces";
912 
913  /* api callbacks */
917 
918  /* flags */
920 
921  /* properties */
923 }
924 
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 ViewLayer * CTX_data_view_layer(const bContext *C)
Definition: context.c:1044
struct View3D * CTX_wm_view3d(const bContext *C)
Definition: context.c:760
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:85
#define BKE_view_layer_array_from_bases_in_edit_mode(view_layer, v3d, r_len)
Definition: BKE_layer.h:423
#define BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, v3d, r_len)
Definition: BKE_layer.h:426
void BKE_report(ReportList *reports, ReportType type, const char *message)
Definition: report.c:104
MINLINE void copy_v2_v2_int(int r[2], const int a[2])
unsigned int uint
Definition: BLI_sys_types.h:83
#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:638
@ 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)
struct BMEdge * EDBM_edge_find_nearest(struct ViewContext *vc, float *dist_px_manhattan_p)
void em_setup_viewcontext(struct bContext *C, struct ViewContext *vc)
struct BMFace * EDBM_face_find_nearest(struct ViewContext *vc, float *dist_px_manhattan_p)
bool EDBM_unified_findnearest(struct ViewContext *vc, struct Base **bases, const uint bases_len, int *r_base_index, struct BMVert **r_eve, struct BMEdge **r_eed, struct BMFace **r_efa)
void EDBM_update_generic(struct Mesh *me, const bool do_tessellation, const bool is_destructive)
bool EDBM_select_pick(struct bContext *C, const int mval[2], bool extend, bool deselect, bool toggle)
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:418
bool ED_operator_editmesh(struct bContext *C)
Definition: screen_ops.c:404
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:204
@ PROP_HIDDEN
Definition: RNA_types.h:202
#define C
Definition: RandGen.cpp:39
#define NC_GEOM
Definition: WM_types.h:294
@ OPTYPE_UNDO
Definition: WM_types.h:155
@ OPTYPE_REGISTER
Definition: WM_types.h:153
#define ND_SELECT
Definition: WM_types.h:407
@ 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:30
#define BM_elem_flag_test(ele, hflag)
Definition: bmesh_inline.h:26
#define BM_elem_flag_test_bool(ele, hflag)
Definition: bmesh_inline.h:27
float BM_elem_float_data_get(CustomData *cd, void *element, int type)
void BM_data_layer_add(BMesh *bm, CustomData *data, int type)
Definition: bmesh_interp.c:894
void BM_elem_float_data_set(CustomData *cd, void *element, int type, const float val)
#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.c:2152
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:129
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:309
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:507
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)
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:85
@ EDGE_MODE_SELECT
Definition: editmesh_path.c:67
@ EDGE_MODE_TAG_SEAM
Definition: editmesh_path.c:68
@ EDGE_MODE_TAG_BEVEL
Definition: editmesh_path.c:71
@ EDGE_MODE_TAG_FREESTYLE
Definition: editmesh_path.c:72
@ EDGE_MODE_TAG_SHARP
Definition: editmesh_path.c:69
@ EDGE_MODE_TAG_CREASE
Definition: editmesh_path.c:70
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)
int EDBM_elem_to_index_any(BMEditMesh *em, BMElem *ele)
BMElem * EDBM_elem_from_index_any(BMEditMesh *em, int index)
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:41
const char * RNA_property_identifier(const PropertyRNA *prop)
Definition: rna_access.c:1145
bool RNA_property_is_set(PointerRNA *ptr, PropertyRNA *prop)
Definition: rna_access.c:6655
void RNA_int_set(PointerRNA *ptr, const char *name, int value)
Definition: rna_access.c:6319
void RNA_property_enum_set(PointerRNA *ptr, PropertyRNA *prop, int value)
Definition: rna_access.c:3562
PropertyRNA * RNA_struct_find_property(PointerRNA *ptr, const char *identifier)
Definition: rna_access.c:866
int RNA_int_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:6308
int RNA_property_enum_get(PointerRNA *ptr, PropertyRNA *prop)
Definition: rna_access.c:3543
bool RNA_struct_property_is_set(PointerRNA *ptr, const char *identifier)
Definition: rna_access.c:6685
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
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:3585
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:3771
short selectmode
Definition: BKE_editmesh.h:72
struct BMesh * bm
Definition: BKE_editmesh.h:52
struct BMEditSelection * prev
Definition: bmesh_marking.h:24
BMHeader head
Definition: bmesh_class.h:255
char htype
Definition: bmesh_class.h:76
void * data
Definition: bmesh_class.h:63
BMHeader head
Definition: bmesh_class.h:97
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:47
struct BMEditMesh * edit_mesh
void * data
struct CheckerIntervalParams interval_params
Definition: editmesh_path.c:82
bool use_topology_distance
Definition: editmesh_path.c:78
struct ToolSettings * toolsettings
const struct PathSelectParams * op_params
BMesh * bm
Mesh * me
int mval[2]
Definition: ED_view3d.h:85
struct Scene * scene
Definition: ED_view3d.h:76
struct ViewLayer * view_layer
Definition: ED_view3d.h:77
struct BMEditMesh * em
Definition: ED_view3d.h:84
struct Object * obedit
Definition: ED_view3d.h:79
struct View3D * v3d
Definition: ED_view3d.h:81
struct Base * basact
int mval[2]
Definition: WM_types.h:583
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
const char * idname
Definition: WM_types.h:723
bool(* poll)(struct bContext *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:776
bool(* poll_property)(const struct bContext *C, struct wmOperator *op, const PropertyRNA *prop) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:782
struct StructRNA * srna
Definition: WM_types.h:802
const char * description
Definition: WM_types.h:726
int(* exec)(struct bContext *, struct wmOperator *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:736
struct ReportList * reports
struct PointerRNA * ptr
void WM_main_add_notifier(unsigned int type, void *reference)
wmOperatorType * ot
Definition: wm_files.c:3156
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)