Blender  V2.93
uvedit_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 
23 #include <math.h>
24 #include <stdlib.h>
25 #include <string.h>
26 
27 #include "BLI_linklist.h"
29 #include "MEM_guardedalloc.h"
30 
31 #include "BLI_ghash.h"
32 #include "BLI_linklist_stack.h"
33 #include "BLI_math.h"
34 #include "BLI_math_vector.h"
35 #include "BLI_utildefines.h"
36 
37 #include "DNA_image_types.h"
38 #include "DNA_mesh_types.h"
39 #include "DNA_meshdata_types.h"
40 #include "DNA_node_types.h"
41 #include "DNA_object_types.h"
42 #include "DNA_scene_types.h"
43 #include "DNA_space_types.h"
44 
45 #include "BKE_context.h"
46 #include "BKE_customdata.h"
47 #include "BKE_editmesh.h"
48 #include "BKE_layer.h"
49 #include "BKE_mesh.h"
50 #include "BKE_report.h"
51 
52 #include "DEG_depsgraph.h"
53 #include "DEG_depsgraph_query.h"
54 
55 #include "ED_screen.h"
56 #include "ED_transform.h"
57 #include "ED_uvedit.h"
58 
59 #include "RNA_access.h"
60 #include "RNA_define.h"
61 
62 #include "WM_api.h"
63 #include "WM_types.h"
64 
65 #include "UI_view2d.h"
66 
67 #include "intern/bmesh_marking.h"
68 #include "uvedit_intern.h"
69 
70 #include "bmesh_tools.h"
71 
72 /* -------------------------------------------------------------------- */
88 static void bm_loop_calc_vert_pair_from_edge_pair(const bool use_nearest,
89  const int cd_loop_uv_offset,
90  const float aspect_y,
91  BMElem **ele_src_p,
92  BMElem **ele_dst_p,
93  BMElem **r_ele_dst_final)
94 {
95  BMLoop *l_src = (BMLoop *)*ele_src_p;
96  BMLoop *l_dst = (BMLoop *)*ele_dst_p;
97 
98  const MLoopUV *luv_src_v1 = BM_ELEM_CD_GET_VOID_P(l_src, cd_loop_uv_offset);
99  const MLoopUV *luv_src_v2 = BM_ELEM_CD_GET_VOID_P(l_src->next, cd_loop_uv_offset);
100  const MLoopUV *luv_dst_v1 = BM_ELEM_CD_GET_VOID_P(l_dst, cd_loop_uv_offset);
101  const MLoopUV *luv_dst_v2 = BM_ELEM_CD_GET_VOID_P(l_dst->next, cd_loop_uv_offset);
102 
103  const float uv_src_v1[2] = {luv_src_v1->uv[0], luv_src_v1->uv[1] / aspect_y};
104  const float uv_src_v2[2] = {luv_src_v2->uv[0], luv_src_v2->uv[1] / aspect_y};
105  const float uv_dst_v1[2] = {luv_dst_v1->uv[0], luv_dst_v1->uv[1] / aspect_y};
106  const float uv_dst_v2[2] = {luv_dst_v2->uv[0], luv_dst_v2->uv[1] / aspect_y};
107 
108  struct {
109  int src_index;
110  int dst_index;
111  float len_sq;
112  } tests[4] = {
113  {0, 0, len_squared_v2v2(uv_src_v1, uv_dst_v1)},
114  {0, 1, len_squared_v2v2(uv_src_v1, uv_dst_v2)},
115  {1, 0, len_squared_v2v2(uv_src_v2, uv_dst_v1)},
116  {1, 1, len_squared_v2v2(uv_src_v2, uv_dst_v2)},
117  };
118  int i_best = 0;
119  for (int i = 1; i < ARRAY_SIZE(tests); i++) {
120  if (use_nearest) {
121  if (tests[i].len_sq < tests[i_best].len_sq) {
122  i_best = i;
123  }
124  }
125  else {
126  if (tests[i].len_sq > tests[i_best].len_sq) {
127  i_best = i;
128  }
129  }
130  }
131 
132  *ele_src_p = (BMElem *)(tests[i_best].src_index ? l_src->next : l_src);
133  *ele_dst_p = (BMElem *)(tests[i_best].dst_index ? l_dst->next : l_dst);
134 
135  /* Ensure the edge is selected, not just the vertices up until we hit it. */
136  *r_ele_dst_final = (BMElem *)(tests[i_best].dst_index ? l_dst : l_dst->next);
137 }
138 
141 /* -------------------------------------------------------------------- */
145 struct PathSelectParams {
147  bool track_active;
149  bool use_face_step;
150  bool use_fill;
152 };
153 
154 struct UserData_UV {
155  const SpaceImage *sima;
159 };
160 
162 {
164  "use_face_step",
165  false,
166  "Face Stepping",
167  "Traverse connected faces (includes diagonals and edge-rings)");
169  "use_topology_distance",
170  false,
171  "Topology Distance",
172  "Find the minimum number of steps, ignoring spatial distance");
174  "use_fill",
175  false,
176  "Fill Region",
177  "Select all paths between the source/destination elements");
178 
180 }
181 
182 static void path_select_params_from_op(wmOperator *op, struct PathSelectParams *op_params)
183 {
184  op_params->track_active = false;
185  op_params->use_face_step = RNA_boolean_get(op->ptr, "use_face_step");
186  op_params->use_fill = RNA_boolean_get(op->ptr, "use_fill");
187  op_params->use_topology_distance = RNA_boolean_get(op->ptr, "use_topology_distance");
189 }
190 
193 /* -------------------------------------------------------------------- */
197 /* callbacks */
198 static bool looptag_filter_cb(BMLoop *l, void *user_data_v)
199 {
200  struct UserData_UV *user_data = user_data_v;
201  return uvedit_face_visible_test(user_data->scene, l->f);
202 }
203 static bool looptag_test_cb(BMLoop *l, void *user_data_v)
204 {
205  /* All connected loops are selected or we return false. */
206  struct UserData_UV *user_data = user_data_v;
207  const Scene *scene = user_data->scene;
208  const uint cd_loop_uv_offset = user_data->cd_loop_uv_offset;
210  BMIter iter;
211  BMLoop *l_iter;
212  BM_ITER_ELEM (l_iter, &iter, l->v, BM_LOOPS_OF_VERT) {
213  if (looptag_filter_cb(l_iter, user_data)) {
214  const MLoopUV *luv_iter = BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_uv_offset);
215  if (equals_v2v2(luv->uv, luv_iter->uv)) {
217  return false;
218  }
219  }
220  }
221  }
222  return true;
223 }
224 static void looptag_set_cb(BMLoop *l, bool val, void *user_data_v)
225 {
226  struct UserData_UV *user_data = user_data_v;
227  const Scene *scene = user_data->scene;
228  BMEditMesh *em = user_data->em;
229  const uint cd_loop_uv_offset = user_data->cd_loop_uv_offset;
231  BMIter iter;
232  BMLoop *l_iter;
233  BM_ITER_ELEM (l_iter, &iter, l->v, BM_LOOPS_OF_VERT) {
234  if (looptag_filter_cb(l_iter, user_data)) {
235  MLoopUV *luv_iter = BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_uv_offset);
236  if (equals_v2v2(luv->uv, luv_iter->uv)) {
237  uvedit_uv_select_set(scene, em, l_iter, val, false, cd_loop_uv_offset);
238  }
239  }
240  }
241 }
242 
244  Scene *scene,
245  Object *obedit,
246  const struct PathSelectParams *op_params,
247  BMLoop *l_src,
248  BMLoop *l_dst,
249  const float aspect_y,
250  const int cd_loop_uv_offset)
251 {
252  const char uv_selectmode = ED_uvedit_select_mode_get(scene);
253  const bool use_fake_edge_select = (uv_selectmode & UV_SELECT_EDGE);
255  BMesh *bm = em->bm;
256  int flush = 0;
257 
258  /* Variables to use when `use_fake_edge_select` is set. */
259  struct {
260  BMLoop *l_dst_activate;
261  BMLoop *l_dst_add_to_path;
262  } fake_edge_select = {NULL};
263 
264  if (use_fake_edge_select) {
265  fake_edge_select.l_dst_activate = l_dst;
266 
267  /* Use most distant when doing region selection.
268  * without this we get dangling edges outside the region. */
269  bool use_neaerst = (op_params->use_fill == false);
270  BMElem *ele_src = (BMElem *)l_src;
271  BMElem *ele_dst = (BMElem *)l_dst;
272  BMElem *ele_dst_final = NULL;
274  use_neaerst, cd_loop_uv_offset, aspect_y, &ele_src, &ele_dst, &ele_dst_final);
275 
276  if (op_params->use_fill == false) {
277  /* Always activate the item under the cursor. */
278  fake_edge_select.l_dst_add_to_path = (BMLoop *)ele_dst_final;
279  }
280 
281  l_src = (BMLoop *)ele_src;
282  l_dst = (BMLoop *)ele_dst;
283  }
284 
285  struct UserData_UV user_data = {
286  .sima = sima,
287  .scene = scene,
288  .em = em,
289  .cd_loop_uv_offset = cd_loop_uv_offset,
290  };
291 
292  const struct BMCalcPathUVParams params = {
293  .use_topology_distance = op_params->use_topology_distance,
294  .use_step_face = op_params->use_face_step,
295  .aspect_y = aspect_y,
296  .cd_loop_uv_offset = cd_loop_uv_offset,
297  };
298 
299  LinkNode *path = NULL;
300  bool is_path_ordered = false;
301 
302  if (l_src != l_dst) {
303  if (op_params->use_fill) {
305  (BMElem *)l_src,
306  (BMElem *)l_dst,
307  params.cd_loop_uv_offset,
309  &user_data);
310  }
311  else {
312  is_path_ordered = true;
314  }
315  }
316 
317  BMLoop *l_dst_last = l_dst;
318 
319  if (path) {
320  if (use_fake_edge_select) {
321  if ((fake_edge_select.l_dst_add_to_path != NULL) &&
322  (BLI_linklist_index(path, fake_edge_select.l_dst_add_to_path) == -1)) {
323  /* Append, this isn't optimal compared to #BLI_linklist_append, it's a one-off lookup. */
324  LinkNode *path_last = BLI_linklist_find_last(path);
325  BLI_linklist_insert_after(&path_last, fake_edge_select.l_dst_add_to_path);
326  BLI_assert(BLI_linklist_find_last(path)->link == fake_edge_select.l_dst_add_to_path);
327  }
328  }
329 
330  /* toggle the flag */
331  bool all_set = true;
332  LinkNode *node = path;
333  do {
334  if (!looptag_test_cb((BMLoop *)node->link, &user_data)) {
335  all_set = false;
336  break;
337  }
338  } while ((node = node->next));
339 
340  int depth = -1;
341  node = path;
342  do {
343  if ((is_path_ordered == false) ||
345  looptag_set_cb((BMLoop *)node->link, !all_set, &user_data);
346  if (is_path_ordered) {
347  l_dst_last = node->link;
348  }
349  }
350  } while ((void)depth++, (node = node->next));
351 
352  BLI_linklist_free(path, NULL);
353  flush = all_set ? -1 : 1;
354  }
355  else {
356  const bool is_act = !looptag_test_cb(l_dst, &user_data);
357  looptag_set_cb(l_dst, is_act, &user_data); /* switch the face option */
358  }
359 
360  if (op_params->track_active) {
361  /* Fake edge selection. */
362  if (use_fake_edge_select) {
363  BMLoop *l_dst_activate = fake_edge_select.l_dst_activate;
364  /* TODO(campbell): Search for an active loop attached to 'l_dst'.
365  * when `BLI_linklist_index(path, l_dst_activate) == -1`
366  * In practice this rarely happens though. */
367  ED_uvedit_active_edge_loop_set(bm, l_dst_activate);
368  }
369  else {
370  ED_uvedit_active_vert_loop_set(bm, l_dst_last);
371  }
372  }
373  return flush;
374 }
375 
378 /* -------------------------------------------------------------------- */
382 /* callbacks */
383 static bool facetag_filter_cb(BMFace *f, void *user_data_v)
384 {
385  struct UserData_UV *user_data = user_data_v;
386  return uvedit_face_visible_test(user_data->scene, f);
387 }
388 static bool facetag_test_cb(BMFace *f, void *user_data_v)
389 {
390  /* All connected loops are selected or we return false. */
391  struct UserData_UV *user_data = user_data_v;
392  const Scene *scene = user_data->scene;
393  const uint cd_loop_uv_offset = user_data->cd_loop_uv_offset;
394  BMIter iter;
395  BMLoop *l_iter;
396  BM_ITER_ELEM (l_iter, &iter, f, BM_LOOPS_OF_FACE) {
398  return false;
399  }
400  }
401  return true;
402 }
403 static void facetag_set_cb(BMFace *f, bool val, void *user_data_v)
404 {
405  struct UserData_UV *user_data = user_data_v;
406  const SpaceImage *sima = user_data->sima;
407  const Scene *scene = user_data->scene;
408  BMEditMesh *em = user_data->em;
409  const uint cd_loop_uv_offset = user_data->cd_loop_uv_offset;
411 }
412 
414  Scene *scene,
415  Object *obedit,
416  const struct PathSelectParams *op_params,
417  BMFace *f_src,
418  BMFace *f_dst,
419  const float aspect_y,
420  const int cd_loop_uv_offset)
421 {
423  BMesh *bm = em->bm;
424  int flush = 0;
425 
426  struct UserData_UV user_data = {
427  .sima = sima,
428  .scene = scene,
429  .em = em,
430  .cd_loop_uv_offset = cd_loop_uv_offset,
431  };
432 
433  const struct BMCalcPathUVParams params = {
434  .use_topology_distance = op_params->use_topology_distance,
435  .use_step_face = op_params->use_face_step,
436  .aspect_y = aspect_y,
437  .cd_loop_uv_offset = cd_loop_uv_offset,
438  };
439 
440  LinkNode *path = NULL;
441  bool is_path_ordered = false;
442 
443  if (f_src != f_dst) {
444  if (op_params->use_fill) {
446  (BMElem *)f_src,
447  (BMElem *)f_dst,
448  params.cd_loop_uv_offset,
450  &user_data);
451  }
452  else {
453  is_path_ordered = true;
455  }
456  }
457 
458  BMFace *f_dst_last = f_dst;
459 
460  if (path) {
461  /* toggle the flag */
462  bool all_set = true;
463  LinkNode *node = path;
464  do {
465  if (!facetag_test_cb((BMFace *)node->link, &user_data)) {
466  all_set = false;
467  break;
468  }
469  } while ((node = node->next));
470 
471  int depth = -1;
472  node = path;
473  do {
474  if ((is_path_ordered == false) ||
476  facetag_set_cb((BMFace *)node->link, !all_set, &user_data);
477  if (is_path_ordered) {
478  f_dst_last = node->link;
479  }
480  }
481  } while ((void)depth++, (node = node->next));
482 
483  BLI_linklist_free(path, NULL);
484  flush = all_set ? -1 : 1;
485  }
486  else {
487  const bool is_act = !facetag_test_cb(f_dst, &user_data);
488  facetag_set_cb(f_dst, is_act, &user_data); /* switch the face option */
489  }
490 
491  if (op_params->track_active) {
492  /* Unlike other types, we can track active without it being selected. */
493  BM_mesh_active_face_set(bm, f_dst_last);
494  }
495  return flush;
496 }
497 
500 /* -------------------------------------------------------------------- */
505 
506 static bool uv_shortest_path_pick_ex(const SpaceImage *sima,
507  Scene *scene,
509  Object *obedit,
510  const struct PathSelectParams *op_params,
511  BMElem *ele_src,
512  BMElem *ele_dst,
513  const float aspect_y,
514  const int cd_loop_uv_offset)
515 {
516  const ToolSettings *ts = scene->toolsettings;
517  const char uv_selectmode = ED_uvedit_select_mode_get(scene);
518  bool ok = false;
519  int flush = 0;
520 
521  if (ELEM(NULL, ele_src, ele_dst) || (ele_src->head.htype != ele_dst->head.htype)) {
522  /* pass */
523  }
524  else if (ele_src->head.htype == BM_FACE) {
526  scene,
527  obedit,
528  op_params,
529  (BMFace *)ele_src,
530  (BMFace *)ele_dst,
531  aspect_y,
533  ok = true;
534  }
535  else if (ele_src->head.htype == BM_LOOP) {
537  scene,
538  obedit,
539  op_params,
540  (BMLoop *)ele_src,
541  (BMLoop *)ele_dst,
542  aspect_y,
544  ok = true;
545  }
546 
547  if (ok) {
548  if (flush != 0) {
549  const bool select = (flush == 1);
550  BMEditMesh *em = BKE_editmesh_from_object(obedit);
551  if (ts->uv_flag & UV_SYNC_SELECTION) {
552  if (uv_selectmode & UV_SELECT_EDGE) {
553  /* Special case as we don't use true edge selection,
554  * flush the selection from the vertices. */
556  }
557  }
559  }
560 
561  if (ts->uv_flag & UV_SYNC_SELECTION) {
563  }
564  else {
565  Object *obedit_eval = DEG_get_evaluated_object(depsgraph, obedit);
567  }
568  /* Only for region redraw. */
570  }
571 
572  return ok;
573 }
574 
576 {
579  const ToolSettings *ts = scene->toolsettings;
580  const char uv_selectmode = ED_uvedit_select_mode_get(scene);
581 
582  /* We could support this, it needs further testing. */
583  if (RNA_struct_property_is_set(op->ptr, "index")) {
584  return uv_shortest_path_pick_exec(C, op);
585  }
586 
587  struct PathSelectParams op_params;
588  path_select_params_from_op(op, &op_params);
589 
590  /* Set false if we support edge tagging. */
591  op_params.track_active = true;
592 
594 
595  float co[2];
596 
597  const ARegion *region = CTX_wm_region(C);
598 
599  Object *obedit = CTX_data_edit_object(C);
600  BMEditMesh *em = BKE_editmesh_from_object(obedit);
601  BMesh *bm = em->bm;
602  const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
603 
604  float aspect_y;
605  {
606  float aspx, aspy;
607  ED_uvedit_get_aspect(obedit, &aspx, &aspy);
608  aspect_y = aspx / aspy;
609  }
610 
611  UI_view2d_region_to_view(&region->v2d, event->mval[0], event->mval[1], &co[0], &co[1]);
612 
613  BMElem *ele_src = NULL, *ele_dst = NULL;
614 
615  if (uv_selectmode == UV_SELECT_FACE) {
616  UvNearestHit hit = UV_NEAREST_HIT_INIT_MAX(&region->v2d);
617  if (!uv_find_nearest_face(scene, obedit, co, &hit)) {
618  return OPERATOR_CANCELLED;
619  }
620 
621  BMFace *f_src = BM_mesh_active_face_get(bm, false, false);
622  /* Check selection? */
623 
624  ele_src = (BMElem *)f_src;
625  ele_dst = (BMElem *)hit.efa;
626  }
627 
628  else if (uv_selectmode & UV_SELECT_EDGE) {
629  UvNearestHit hit = UV_NEAREST_HIT_INIT_MAX(&region->v2d);
630  if (!uv_find_nearest_edge(scene, obedit, co, &hit)) {
631  return OPERATOR_CANCELLED;
632  }
633 
634  BMLoop *l_src = NULL;
635  if (ts->uv_flag & UV_SYNC_SELECTION) {
637  if (e_src != NULL) {
638  l_src = uv_find_nearest_loop_from_edge(scene, obedit, e_src, co);
639  }
640  }
641  else {
643  if (l_src != NULL) {
644  if ((!uvedit_uv_select_test(scene, l_src, cd_loop_uv_offset)) &&
645  (!uvedit_uv_select_test(scene, l_src->next, cd_loop_uv_offset))) {
646  l_src = NULL;
647  }
648  ele_src = (BMElem *)l_src;
649  }
650  }
651  ele_src = (BMElem *)l_src;
652  ele_dst = (BMElem *)hit.l;
653  }
654  else {
655  UvNearestHit hit = UV_NEAREST_HIT_INIT_MAX(&region->v2d);
656  if (!uv_find_nearest_vert(scene, obedit, co, 0.0f, &hit)) {
657  return OPERATOR_CANCELLED;
658  }
659 
660  BMLoop *l_src = NULL;
661  if (ts->uv_flag & UV_SYNC_SELECTION) {
663  if (v_src != NULL) {
664  l_src = uv_find_nearest_loop_from_vert(scene, obedit, v_src, co);
665  }
666  }
667  else {
669  if (l_src != NULL) {
670  if (!uvedit_uv_select_test(scene, l_src, cd_loop_uv_offset)) {
671  l_src = NULL;
672  }
673  }
674  }
675  ele_src = (BMElem *)l_src;
676  ele_dst = (BMElem *)hit.l;
677  }
678 
679  if (ele_src == NULL || ele_dst == NULL) {
680  return OPERATOR_CANCELLED;
681  }
682 
684  sima, scene, depsgraph, obedit, &op_params, ele_src, ele_dst, aspect_y, cd_loop_uv_offset);
685 
686  /* To support redo. */
687  int index;
688  if (uv_selectmode & UV_SELECT_FACE) {
690  index = BM_elem_index_get(ele_dst);
691  }
692  else if (uv_selectmode & UV_SELECT_EDGE) {
694  index = BM_elem_index_get(ele_dst);
695  }
696  else {
698  index = BM_elem_index_get(ele_dst);
699  }
700  RNA_int_set(op->ptr, "index", index);
701 
702  return OPERATOR_FINISHED;
703 }
704 
706 {
708  const SpaceImage *sima = CTX_wm_space_image(C);
710  const char uv_selectmode = ED_uvedit_select_mode_get(scene);
711  Object *obedit = CTX_data_edit_object(C);
712  BMEditMesh *em = BKE_editmesh_from_object(obedit);
713  BMesh *bm = em->bm;
714  const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
715 
716  float aspect_y;
717  {
718  float aspx, aspy;
719  ED_uvedit_get_aspect(obedit, &aspx, &aspy);
720  aspect_y = aspx / aspy;
721  }
722 
723  const int index = RNA_int_get(op->ptr, "index");
724 
725  BMElem *ele_src, *ele_dst;
726 
727  if (uv_selectmode & UV_SELECT_FACE) {
728  if (index < 0 || index >= bm->totface) {
729  return OPERATOR_CANCELLED;
730  }
731  if (!(ele_src = (BMElem *)BM_mesh_active_face_get(bm, false, false)) ||
732  !(ele_dst = (BMElem *)BM_face_at_index_find_or_table(bm, index))) {
733  return OPERATOR_CANCELLED;
734  }
735  }
736  else if (uv_selectmode & UV_SELECT_EDGE) {
737  if (index < 0 || index >= bm->totloop) {
738  return OPERATOR_CANCELLED;
739  }
740  if (!(ele_src = (BMElem *)ED_uvedit_active_edge_loop_get(bm)) ||
741  !(ele_dst = (BMElem *)BM_loop_at_index_find(bm, index))) {
742  return OPERATOR_CANCELLED;
743  }
744  }
745  else {
746  if (index < 0 || index >= bm->totloop) {
747  return OPERATOR_CANCELLED;
748  }
749  if (!(ele_src = (BMElem *)ED_uvedit_active_vert_loop_get(bm)) ||
750  !(ele_dst = (BMElem *)BM_loop_at_index_find(bm, index))) {
751  return OPERATOR_CANCELLED;
752  }
753  }
754 
755  struct PathSelectParams op_params;
756  path_select_params_from_op(op, &op_params);
757  op_params.track_active = true;
758 
759  if (!uv_shortest_path_pick_ex(sima,
760  scene,
761  depsgraph,
762  obedit,
763  &op_params,
764  ele_src,
765  ele_dst,
766  aspect_y,
767  cd_loop_uv_offset)) {
768  return OPERATOR_CANCELLED;
769  }
770 
771  return OPERATOR_FINISHED;
772 }
773 
775 {
776  PropertyRNA *prop;
777 
778  /* identifiers */
779  ot->name = "Pick Shortest Path";
780  ot->idname = "UV_OT_shortest_path_pick";
781  ot->description = "Select shortest path between two selections";
782 
783  /* 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  const SpaceImage *sima = CTX_wm_space_image(C);
810  const char uv_selectmode = ED_uvedit_select_mode_get(scene);
811  bool found_valid_elements = false;
812 
813  float aspect_y;
814  {
815  Object *obedit = CTX_data_edit_object(C);
816  float aspx, aspy;
817  ED_uvedit_get_aspect(obedit, &aspx, &aspy);
818  aspect_y = aspx / aspy;
819  }
820 
821  ViewLayer *view_layer = CTX_data_view_layer(C);
822  uint objects_len = 0;
824  view_layer, CTX_wm_view3d(C), &objects_len);
825  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
826  Object *obedit = objects[ob_index];
827  BMEditMesh *em = BKE_editmesh_from_object(obedit);
828  BMesh *bm = em->bm;
829  const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
830  BMElem *ele_src = NULL, *ele_dst = NULL;
831 
832  /* Find 2x elements. */
833  {
834  BMElem **ele_array = NULL;
835  int ele_array_len = 0;
836  if (uv_selectmode & UV_SELECT_FACE) {
837  ele_array = (BMElem **)ED_uvedit_selected_faces(scene, bm, 3, &ele_array_len);
838  }
839  else if (uv_selectmode & UV_SELECT_EDGE) {
840  ele_array = (BMElem **)ED_uvedit_selected_edges(scene, bm, 3, &ele_array_len);
841  }
842  else {
843  ele_array = (BMElem **)ED_uvedit_selected_verts(scene, bm, 3, &ele_array_len);
844  }
845 
846  if (ele_array_len == 2) {
847  ele_src = ele_array[0];
848  ele_dst = ele_array[1];
849  }
850  MEM_freeN(ele_array);
851  }
852 
853  if (ele_src && ele_dst) {
854  struct PathSelectParams op_params;
855  path_select_params_from_op(op, &op_params);
856 
858  scene,
859  depsgraph,
860  obedit,
861  &op_params,
862  ele_src,
863  ele_dst,
864  aspect_y,
865  cd_loop_uv_offset);
866 
867  found_valid_elements = true;
868  }
869  }
870  MEM_freeN(objects);
871 
872  if (!found_valid_elements) {
873  BKE_report(
874  op->reports, RPT_WARNING, "Path selection requires two matching elements to be selected");
875  return OPERATOR_CANCELLED;
876  }
877 
878  return OPERATOR_FINISHED;
879 }
880 
882 {
883  /* identifiers */
884  ot->name = "Select Shortest Path";
885  ot->idname = "UV_OT_shortest_path_select";
886  ot->description = "Selected shortest path between two vertices/edges/faces";
887 
888  /* api callbacks */
891 
892  /* flags */
894 
895  /* properties */
897 }
898 
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 Depsgraph * CTX_data_ensure_evaluated_depsgraph(const bContext *C)
Definition: context.c:1424
struct View3D * CTX_wm_view3d(const bContext *C)
Definition: context.c:760
struct ARegion * CTX_wm_region(const bContext *C)
Definition: context.c:725
struct SpaceImage * CTX_wm_space_image(const bContext *C)
Definition: context.c:800
CustomData interface, see also DNA_customdata_types.h.
int CustomData_get_offset(const struct CustomData *data, 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_objects_in_edit_mode_unique_data(view_layer, v3d, r_len)
Definition: BKE_layer.h:426
void BKE_mesh_batch_cache_dirty_tag(struct Mesh *me, eMeshBatchDirtyMode mode)
Definition: mesh_runtime.c:251
@ BKE_MESH_BATCH_DIRTY_UVEDIT_SELECT
void BKE_report(ReportList *reports, ReportType type, const char *message)
Definition: report.c:104
#define BLI_assert(a)
Definition: BLI_assert.h:58
MINLINE float len_squared_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT
MINLINE bool equals_v2v2(const float v1[2], const float v2[2]) ATTR_WARN_UNUSED_RESULT
unsigned int uint
Definition: BLI_sys_types.h:83
#define ARRAY_SIZE(arr)
#define ELEM(...)
struct Depsgraph Depsgraph
Definition: DEG_depsgraph.h:51
void DEG_id_tag_update(struct ID *id, int flag)
struct Object * DEG_get_evaluated_object(const struct Depsgraph *depsgraph, struct Object *object)
@ ID_RECALC_SELECT
Definition: DNA_ID.h:638
@ CD_MLOOPUV
Object is a sort of wrapper for general info.
#define UV_SELECT_EDGE
#define UV_SELECT_FACE
#define UV_SYNC_SELECTION
#define SCE_SELECT_VERTEX
@ OPERATOR_CANCELLED
@ OPERATOR_FINISHED
bool ED_operator_uvedit_space_image(struct bContext *C)
Definition: screen_ops.c:518
struct BMLoop * ED_uvedit_active_edge_loop_get(struct BMesh *bm)
struct BMFace ** ED_uvedit_selected_faces(struct Scene *scene, struct BMesh *bm, int len_max, int *r_faces_len)
void ED_uvedit_get_aspect(struct Object *obedit, float *r_aspx, float *r_aspy)
bool uvedit_uv_select_test(const struct Scene *scene, struct BMLoop *l, const int cd_loop_uv_offset)
void ED_uvedit_active_vert_loop_set(struct BMesh *bm, struct BMLoop *l)
void uvedit_uv_select_set(const struct Scene *scene, struct BMEditMesh *em, struct BMLoop *l, const bool select, const bool do_history, const int cd_loop_uv_offset)
void ED_uvedit_select_sync_flush(const struct ToolSettings *ts, struct BMEditMesh *em, const bool select)
struct BMLoop ** ED_uvedit_selected_verts(struct Scene *scene, struct BMesh *bm, int len_max, int *r_verts_len)
char ED_uvedit_select_mode_get(const struct Scene *scene)
struct BMLoop * ED_uvedit_active_vert_loop_get(struct BMesh *bm)
void uvedit_face_select_set_with_sticky(const struct SpaceImage *sima, const struct Scene *scene, struct BMEditMesh *em, struct BMFace *efa, const bool select, const bool do_history, const int cd_loop_uv_offset)
struct BMLoop ** ED_uvedit_selected_edges(struct Scene *scene, struct BMesh *bm, int len_max, int *r_edges_len)
void ED_uvedit_active_edge_loop_set(struct BMesh *bm, struct BMLoop *l)
bool uvedit_face_visible_test(const struct Scene *scene, struct BMFace *efa)
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
void UI_view2d_region_to_view(const struct View2D *v2d, float x, float y, float *r_view_x, float *r_view_y) ATTR_NONNULL()
#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_LOOP
Definition: bmesh_class.h:385
@ BM_FACE
Definition: bmesh_class.h:386
#define BM_ELEM_CD_GET_VOID_P(ele, offset)
Definition: bmesh_class.h:530
#define BM_elem_index_get(ele)
Definition: bmesh_inline.h:124
#define BM_ITER_ELEM(ele, iter, data, itype)
@ BM_LOOPS_OF_VERT
@ BM_LOOPS_OF_FACE
ATTR_WARN_UNUSED_RESULT BMesh * bm
BMEdge * BM_mesh_active_edge_get(BMesh *bm)
BMVert * BM_mesh_active_vert_get(BMesh *bm)
void BM_mesh_active_face_set(BMesh *bm, BMFace *f)
BMFace * BM_mesh_active_face_get(BMesh *bm, const bool is_sloppy, const bool is_selected)
void BM_mesh_select_mode_flush_ex(BMesh *bm, const short selectmode)
Select Mode Flush.
BMFace * BM_face_at_index_find_or_table(BMesh *bm, const int index)
Definition: bmesh_mesh.c:2433
void BM_mesh_elem_index_ensure(BMesh *bm, const char htype)
Definition: bmesh_mesh.c:2152
BMLoop * BM_loop_at_index_find(BMesh *bm, const int index)
Definition: bmesh_mesh.c:2391
LinkNode * BM_mesh_calc_path_uv_region_vert(BMesh *bm, BMElem *ele_src, BMElem *ele_dst, const uint cd_loop_uv_offset, bool(*filter_fn)(BMLoop *, void *user_data), void *user_data)
LinkNode * BM_mesh_calc_path_uv_region_face(BMesh *bm, BMElem *ele_src, BMElem *ele_dst, const uint cd_loop_uv_offset, bool(*filter_fn)(BMFace *, void *user_data), void *user_data)
struct LinkNode * BM_mesh_calc_path_uv_vert(BMesh *bm, BMLoop *l_src, BMLoop *l_dst, const struct BMCalcPathUVParams *params, bool(*filter_fn)(BMLoop *, void *), void *user_data)
struct LinkNode * BM_mesh_calc_path_uv_face(BMesh *bm, BMFace *f_src, BMFace *f_dst, const struct BMCalcPathUVParams *params, bool(*filter_fn)(BMFace *, void *), void *user_data)
ATTR_WARN_UNUSED_RESULT const BMLoop * l
OperationNode * node
Scene scene
const Depsgraph * depsgraph
void * user_data
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:41
void RNA_int_set(PointerRNA *ptr, const char *name, int value)
Definition: rna_access.c:6319
int RNA_int_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:6308
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
struct BMesh * bm
Definition: BKE_editmesh.h:52
BMHeader head
Definition: bmesh_class.h:255
char htype
Definition: bmesh_class.h:76
struct BMVert * v
Definition: bmesh_class.h:165
struct BMFace * f
Definition: bmesh_class.h:183
struct BMLoop * next
Definition: bmesh_class.h:245
int totloop
Definition: bmesh_class.h:297
CustomData ldata
Definition: bmesh_class.h:337
int totface
Definition: bmesh_class.h:297
void * data
struct CheckerIntervalParams interval_params
Definition: editmesh_path.c:82
bool use_topology_distance
Definition: editmesh_path.c:78
struct ToolSettings * toolsettings
Scene * scene
Definition: uvedit_path.c:156
const SpaceImage * sima
Definition: uvedit_path.c:155
BMEditMesh * em
Definition: uvedit_path.c:157
uint cd_loop_uv_offset
Definition: uvedit_path.c:158
struct BMLoop * l
Definition: uvedit_intern.h:43
struct BMFace * efa
Definition: uvedit_intern.h:42
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
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
__forceinline const avxb select(const avxb &m, const avxb &t, const avxb &f)
Definition: util_avxb.h:167
BMLoop * uv_find_nearest_loop_from_vert(struct Scene *scene, struct Object *obedit, struct BMVert *v, const float co[2])
BMLoop * uv_find_nearest_loop_from_edge(struct Scene *scene, struct Object *obedit, struct BMEdge *e, const float co[2])
bool uv_find_nearest_vert(struct Scene *scene, struct Object *obedit, const float co[2], const float penalty_dist, struct UvNearestHit *hit)
#define UV_NEAREST_HIT_INIT_MAX(v2d)
Definition: uvedit_intern.h:65
bool uv_find_nearest_edge(struct Scene *scene, struct Object *obedit, const float co[2], struct UvNearestHit *hit)
bool uv_find_nearest_face(struct Scene *scene, struct Object *obedit, const float co[2], struct UvNearestHit *hit)
static bool facetag_filter_cb(BMFace *f, void *user_data_v)
Definition: uvedit_path.c:383
void UV_OT_shortest_path_pick(wmOperatorType *ot)
Definition: uvedit_path.c:774
static bool facetag_test_cb(BMFace *f, void *user_data_v)
Definition: uvedit_path.c:388
static int mouse_mesh_uv_shortest_path_vert(const SpaceImage *sima, Scene *scene, Object *obedit, const struct PathSelectParams *op_params, BMLoop *l_src, BMLoop *l_dst, const float aspect_y, const int cd_loop_uv_offset)
Definition: uvedit_path.c:243
static void bm_loop_calc_vert_pair_from_edge_pair(const bool use_nearest, const int cd_loop_uv_offset, const float aspect_y, BMElem **ele_src_p, BMElem **ele_dst_p, BMElem **r_ele_dst_final)
Definition: uvedit_path.c:88
static void path_select_properties(wmOperatorType *ot)
Definition: uvedit_path.c:161
static int uv_shortest_path_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event)
Definition: uvedit_path.c:575
static void looptag_set_cb(BMLoop *l, bool val, void *user_data_v)
Definition: uvedit_path.c:224
static bool looptag_filter_cb(BMLoop *l, void *user_data_v)
Definition: uvedit_path.c:198
static int mouse_mesh_uv_shortest_path_face(const SpaceImage *sima, Scene *scene, Object *obedit, const struct PathSelectParams *op_params, BMFace *f_src, BMFace *f_dst, const float aspect_y, const int cd_loop_uv_offset)
Definition: uvedit_path.c:413
void UV_OT_shortest_path_select(wmOperatorType *ot)
Definition: uvedit_path.c:881
static bool looptag_test_cb(BMLoop *l, void *user_data_v)
Definition: uvedit_path.c:203
static void path_select_params_from_op(wmOperator *op, struct PathSelectParams *op_params)
Definition: uvedit_path.c:182
static int uv_shortest_path_select_exec(bContext *C, wmOperator *op)
Definition: uvedit_path.c:805
static bool uv_shortest_path_pick_ex(const SpaceImage *sima, Scene *scene, Depsgraph *depsgraph, Object *obedit, const struct PathSelectParams *op_params, BMElem *ele_src, BMElem *ele_dst, const float aspect_y, const int cd_loop_uv_offset)
Definition: uvedit_path.c:506
static void facetag_set_cb(BMFace *f, bool val, void *user_data_v)
Definition: uvedit_path.c:403
static int uv_shortest_path_pick_exec(bContext *C, wmOperator *op)
Definition: uvedit_path.c:705
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)