[Bf-blender-cvs] [ea5fe7abc18] master: UV: path selection support

Campbell Barton noreply at git.blender.org
Thu Jul 9 10:43:49 CEST 2020


Commit: ea5fe7abc183c1e53d327f97280f589499fe60bb
Author: Campbell Barton
Date:   Tue Jul 7 17:29:17 2020 +1000
Branches: master
https://developer.blender.org/rBea5fe7abc183c1e53d327f97280f589499fe60bb

UV: path selection support

This adds support for path selection for vertex edge & face selection
modes, matching mesh editing behavior, useful with the UV rip tool.

Region select & edge tagging are currently not supported,
although they could be added eventually.

===================================================================

M	release/scripts/presets/keyconfig/keymap_data/blender_default.py
M	source/blender/bmesh/CMakeLists.txt
M	source/blender/bmesh/bmesh_tools.h
A	source/blender/bmesh/tools/bmesh_path_uv.c
A	source/blender/bmesh/tools/bmesh_path_uv.h
M	source/blender/editors/include/ED_uvedit.h
M	source/blender/editors/mesh/mesh_intern.h
M	source/blender/editors/uvedit/CMakeLists.txt
M	source/blender/editors/uvedit/uvedit_intern.h
M	source/blender/editors/uvedit/uvedit_ops.c
A	source/blender/editors/uvedit/uvedit_path.c
M	source/blender/editors/uvedit/uvedit_select.c

===================================================================

diff --git a/release/scripts/presets/keyconfig/keymap_data/blender_default.py b/release/scripts/presets/keyconfig/keymap_data/blender_default.py
index 96d3e2e24c1..3a885837444 100644
--- a/release/scripts/presets/keyconfig/keymap_data/blender_default.py
+++ b/release/scripts/presets/keyconfig/keymap_data/blender_default.py
@@ -850,6 +850,7 @@ def km_uv_editor(params):
          {"properties": [("extend", False)]}),
         ("uv.select_loop", {"type": params.select_mouse, "value": params.select_mouse_value, "shift": True, "alt": True},
          {"properties": [("extend", True)]}),
+        ("uv.shortest_path_pick", {"type": params.select_mouse, "value": params.select_mouse_value, "ctrl": True}, None),
         ("uv.select_split", {"type": 'Y', "value": 'PRESS'}, None),
         ("uv.select_box", {"type": 'B', "value": 'PRESS'},
          {"properties": [("pinned", False)]}),
diff --git a/source/blender/bmesh/CMakeLists.txt b/source/blender/bmesh/CMakeLists.txt
index 09b8a06bff3..43d12e8eeed 100644
--- a/source/blender/bmesh/CMakeLists.txt
+++ b/source/blender/bmesh/CMakeLists.txt
@@ -153,6 +153,8 @@ set(SRC
   tools/bmesh_path.h
   tools/bmesh_path_region.c
   tools/bmesh_path_region.h
+  tools/bmesh_path_uv.c
+  tools/bmesh_path_uv.h
   tools/bmesh_region_match.c
   tools/bmesh_region_match.h
   tools/bmesh_separate.c
diff --git a/source/blender/bmesh/bmesh_tools.h b/source/blender/bmesh/bmesh_tools.h
index d0e91d033fb..a0dc6abf009 100644
--- a/source/blender/bmesh/bmesh_tools.h
+++ b/source/blender/bmesh/bmesh_tools.h
@@ -36,6 +36,7 @@ extern "C" {
 #include "tools/bmesh_edgesplit.h"
 #include "tools/bmesh_path.h"
 #include "tools/bmesh_path_region.h"
+#include "tools/bmesh_path_uv.h"
 #include "tools/bmesh_region_match.h"
 #include "tools/bmesh_separate.h"
 #include "tools/bmesh_triangulate.h"
diff --git a/source/blender/bmesh/tools/bmesh_path_uv.c b/source/blender/bmesh/tools/bmesh_path_uv.c
new file mode 100644
index 00000000000..b2999b305e0
--- /dev/null
+++ b/source/blender/bmesh/tools/bmesh_path_uv.c
@@ -0,0 +1,432 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup bmesh
+ *
+ * Find a path between 2 elements in UV space.
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_heap_simple.h"
+#include "BLI_linklist.h"
+#include "BLI_math.h"
+
+#include "DNA_meshdata_types.h"
+
+#include "bmesh.h"
+#include "bmesh_path_uv.h" /* own include */
+#include "intern/bmesh_query.h"
+#include "intern/bmesh_query_uv.h"
+
+/* -------------------------------------------------------------------- */
+/** \name Generic Helpers
+ * \{ */
+
+/**
+ * Use skip options when we want to start measuring from a boundary.
+ *
+ * See #step_cost_3_v3_ex in bmesh_path.c which follows the same logic.
+ */
+static float step_cost_3_v2_ex(
+    const float v1[2], const float v2[2], const float v3[2], bool skip_12, bool skip_23)
+{
+  float d1[2], d2[2];
+
+  /* The cost is based on the simple sum of the length of the two edges. */
+  sub_v2_v2v2(d1, v2, v1);
+  sub_v2_v2v2(d2, v3, v2);
+  const float cost_12 = normalize_v2(d1);
+  const float cost_23 = normalize_v2(d2);
+  const float cost = ((skip_12 ? 0.0f : cost_12) + (skip_23 ? 0.0f : cost_23));
+
+  /* But is biased to give higher values to sharp turns, so that it will take paths with
+   * fewer "turns" when selecting between equal-weighted paths between the two edges. */
+  return cost * (1.0f + 0.5f * (2.0f - sqrtf(fabsf(dot_v2v2(d1, d2)))));
+}
+
+static float UNUSED_FUNCTION(step_cost_3_v2)(const float v1[2],
+                                             const float v2[2],
+                                             const float v3[2])
+{
+  return step_cost_3_v2_ex(v1, v2, v3, false, false);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name BM_mesh_calc_path_uv_vert
+ * \{ */
+
+static void looptag_add_adjacent_uv(HeapSimple *heap,
+                                    BMLoop *l_a,
+                                    BMLoop **loops_prev,
+                                    float *cost,
+                                    const struct BMCalcPathUVParams *params)
+{
+  BLI_assert(params->aspect_y != 0.0f);
+  const uint cd_loop_uv_offset = params->cd_loop_uv_offset;
+  const int l_a_index = BM_elem_index_get(l_a);
+  const MLoopUV *luv_a = BM_ELEM_CD_GET_VOID_P(l_a, cd_loop_uv_offset);
+  const float uv_a[2] = {luv_a->uv[0], luv_a->uv[1] / params->aspect_y};
+
+  {
+    BMIter liter;
+    BMLoop *l;
+    /* Loop over faces of face, but do so by first looping over loops. */
+    BM_ITER_ELEM (l, &liter, l_a->v, BM_LOOPS_OF_VERT) {
+      const MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+      if (equals_v2v2(luv_a->uv, luv->uv)) {
+        /* 'l_a' is already tagged, tag all adjacent. */
+        BM_elem_flag_enable(l, BM_ELEM_TAG);
+        BMLoop *l_b = l->next;
+        do {
+          if (!BM_elem_flag_test(l_b, BM_ELEM_TAG)) {
+            const MLoopUV *luv_b = BM_ELEM_CD_GET_VOID_P(l_b, cd_loop_uv_offset);
+            const float uv_b[2] = {luv_b->uv[0], luv_b->uv[1] / params->aspect_y};
+            /* We know 'l_b' is not visited, check it out! */
+            const int l_b_index = BM_elem_index_get(l_b);
+            const float cost_cut = params->use_topology_distance ? 1.0f : len_v2v2(uv_a, uv_b);
+            const float cost_new = cost[l_a_index] + cost_cut;
+
+            if (cost[l_b_index] > cost_new) {
+              cost[l_b_index] = cost_new;
+              loops_prev[l_b_index] = l_a;
+              BLI_heapsimple_insert(heap, cost_new, l_b);
+            }
+          }
+          /* This means we only step onto `l->prev` & `l->next`. */
+          if (params->use_step_face == false) {
+            if (l_b == l->next) {
+              l_b = l->prev->prev;
+            }
+          }
+        } while ((l_b = l_b->next) != l);
+      }
+    }
+  }
+}
+
+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)
+{
+  LinkNode *path = NULL;
+  /* BM_ELEM_TAG flag is used to store visited edges */
+  BMIter viter;
+  HeapSimple *heap;
+  float *cost;
+  BMLoop **loops_prev;
+  int i = 0, totloop;
+  BMFace *f;
+
+  /* Note, would pass BM_EDGE except we are looping over all faces anyway. */
+  // BM_mesh_elem_index_ensure(bm, BM_LOOP); // NOT NEEDED FOR FACETAG
+
+  BM_ITER_MESH (f, &viter, bm, BM_FACES_OF_MESH) {
+    BMLoop *l_first = BM_FACE_FIRST_LOOP(f);
+    BMLoop *l_iter = l_first;
+    do {
+      BM_elem_flag_set(l_iter, BM_ELEM_TAG, !filter_fn(l_iter, user_data));
+      BM_elem_index_set(l_iter, i); /* set_inline */
+      i += 1;
+    } while ((l_iter = l_iter->next) != l_first);
+  }
+  bm->elem_index_dirty &= ~BM_LOOP;
+
+  /* Allocate. */
+  totloop = bm->totloop;
+  loops_prev = MEM_callocN(sizeof(*loops_prev) * totloop, __func__);
+  cost = MEM_mallocN(sizeof(*cost) * totloop, __func__);
+
+  copy_vn_fl(cost, totloop, 1e20f);
+
+  /* Regular dijkstra shortest path, but over UV loops instead of vertices. */
+  heap = BLI_heapsimple_new();
+  BLI_heapsimple_insert(heap, 0.0f, l_src);
+  cost[BM_elem_index_get(l_src)] = 0.0f;
+
+  BMLoop *l = NULL;
+  while (!BLI_heapsimple_is_empty(heap)) {
+    l = BLI_heapsimple_pop_min(heap);
+
+    if (l->v == l_dst->v) {
+      break;
+    }
+
+    if (!BM_elem_flag_test(l, BM_ELEM_TAG)) {
+      /* Adjacent loops are tagged while stepping to avoid 2x loops. */
+      BM_elem_flag_enable(l, BM_ELEM_TAG);
+      looptag_add_adjacent_uv(heap, l, loops_prev, cost, params);
+    }
+  }
+
+  if (l->v == l_dst->v) {
+    do {
+      BLI_linklist_prepend(&path, l);
+    } while ((l = loops_prev[BM_elem_index_get(l)]));
+  }
+
+  MEM_freeN(loops_prev);
+  MEM_freeN(cost);
+  BLI_heapsimple_free(heap, NULL);
+
+  return path;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name BM_mesh_calc_path_uv_edge
+ * \{ */
+
+/* TODO(campbell): not very urgent. */
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name BM_mesh_calc_path_uv_face
+ * \{ */
+
+static float facetag_cut_cost_edge_uv(BMFace *f_a,
+                                      BMFace *f_b,
+                                      BMLoop *l_edge,
+                                      const void *const f_endpoints[2],
+                                      const float aspect_v2[2],
+                                      const int cd_loop_uv_offset)
+{
+  float f_a_cent[2];
+  float f_b_cent[2];
+  float e_cent[2];
+
+  BM_face_uv_calc_center_median_weighted(f_a, aspect_v2, cd_loop_uv_offset, f_a_cent);
+  BM_face_uv_calc_center_median_weighted(f_b, aspect_v2, cd_loop_uv_offset, f_b_cent);
+
+  const float *co_v1 = ((const MLoopUV *)BM_ELEM_CD_GET_VOID_P(l_edge, cd_loop_uv_offset))->uv;
+  const float *co_v2 =
+      ((const MLoopUV *)BM_ELEM_CD_GET_VOID_P(l_edge->next, cd_loop_uv_offset))->uv;
+
+#if 0
+  mid_v2_v2v2(e_cent, co_v1, co_v2);
+#else
+  /* For triangle fans it gives better results to pick a point on the edge. */
+  {
+    float ix_e[2], factor;
+    isect_line_line_v2_point(co_v1, co_v2, f_a_cent, f_b_cent, ix_e);
+    factor = line_point_factor_v2(ix_e, co_v1, co_v2);
+

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list