[Bf-blender-cvs] [a5814607289] master: UV: Add options for uv select similar in island mode

Chris Blackbourn noreply at git.blender.org
Sat Jul 30 13:32:43 CEST 2022


Commit: a5814607289a7e01d4844ee5ef724e6388cf044e
Author: Chris Blackbourn
Date:   Sat Jul 30 23:20:13 2022 +1200
Branches: master
https://developer.blender.org/rBa5814607289a7e01d4844ee5ef724e6388cf044e

UV: Add options for uv select similar in island mode

In island selection mode, add new options for uv select similar:

* Area UV
* Area 3D
* Face (number of faces in island)

See also https://developer.blender.org/T47437
Differential Revision: https://developer.blender.org/D15553

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

M	source/blender/editors/include/ED_uvedit.h
M	source/blender/editors/uvedit/uvedit_islands.c
M	source/blender/editors/uvedit/uvedit_select.c

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

diff --git a/source/blender/editors/include/ED_uvedit.h b/source/blender/editors/include/ED_uvedit.h
index 80a75da27f8..24d6819536d 100644
--- a/source/blender/editors/include/ED_uvedit.h
+++ b/source/blender/editors/include/ED_uvedit.h
@@ -305,6 +305,29 @@ void ED_uvedit_buttons_register(struct ARegionType *art);
 
 /* uvedit_islands.c */
 
+struct FaceIsland {
+  struct FaceIsland *next;
+  struct FaceIsland *prev;
+  struct BMFace **faces;
+  int faces_len;
+  rctf bounds_rect;
+  /**
+   * \note While this is duplicate information,
+   * it allows islands from multiple meshes to be stored in the same list.
+   */
+  uint cd_loop_uv_offset;
+  float aspect_y;
+};
+
+int bm_mesh_calc_uv_islands(const Scene *scene,
+                            struct BMesh *bm,
+                            ListBase *island_list,
+                            const bool only_selected_faces,
+                            const bool only_selected_uvs,
+                            const bool use_seams,
+                            const float aspect_y,
+                            const uint cd_loop_uv_offset);
+
 struct UVMapUDIM_Params {
   const struct Image *image;
   /** Copied from #SpaceImage.tile_grid_shape */
diff --git a/source/blender/editors/uvedit/uvedit_islands.c b/source/blender/editors/uvedit/uvedit_islands.c
index 9a31fd6469d..2afc60a4b5c 100644
--- a/source/blender/editors/uvedit/uvedit_islands.c
+++ b/source/blender/editors/uvedit/uvedit_islands.c
@@ -309,23 +309,8 @@ static float uv_nearest_grid_tile_distance(const int udim_grid[2],
 
 /* -------------------------------------------------------------------- */
 /** \name Calculate UV Islands
- *
- * \note Currently this is a private API/type, it could be made public.
  * \{ */
 
-struct FaceIsland {
-  struct FaceIsland *next, *prev;
-  BMFace **faces;
-  int faces_len;
-  rctf bounds_rect;
-  /**
-   * \note While this is duplicate information,
-   * it allows islands from multiple meshes to be stored in the same list.
-   */
-  uint cd_loop_uv_offset;
-  float aspect_y;
-};
-
 struct SharedUVLoopData {
   uint cd_loop_uv_offset;
   bool use_seams;
@@ -347,14 +332,14 @@ static bool bm_loop_uv_shared_edge_check(const BMLoop *l_a, const BMLoop *l_b, v
 /**
  * Calculate islands and add them to \a island_list returning the number of items added.
  */
-static int bm_mesh_calc_uv_islands(const Scene *scene,
-                                   BMesh *bm,
-                                   ListBase *island_list,
-                                   const bool only_selected_faces,
-                                   const bool only_selected_uvs,
-                                   const bool use_seams,
-                                   const float aspect_y,
-                                   const uint cd_loop_uv_offset)
+int bm_mesh_calc_uv_islands(const Scene *scene,
+                            BMesh *bm,
+                            ListBase *island_list,
+                            const bool only_selected_faces,
+                            const bool only_selected_uvs,
+                            const bool use_seams,
+                            const float aspect_y,
+                            const uint cd_loop_uv_offset)
 {
   int island_added = 0;
   BM_mesh_elem_table_ensure(bm, BM_FACE);
diff --git a/source/blender/editors/uvedit/uvedit_select.c b/source/blender/editors/uvedit/uvedit_select.c
index d59dcb4f4ed..b1ed00e2c57 100644
--- a/source/blender/editors/uvedit/uvedit_select.c
+++ b/source/blender/editors/uvedit/uvedit_select.c
@@ -81,6 +81,7 @@ static void uv_select_tag_update_for_object(Depsgraph *depsgraph,
 typedef enum {
   UV_SSIM_AREA_UV = 1000,
   UV_SSIM_AREA_3D,
+  UV_SSIM_FACE,
   UV_SSIM_LENGTH_UV,
   UV_SSIM_LENGTH_3D,
   UV_SSIM_SIDES,
@@ -4638,6 +4639,33 @@ static float get_uv_face_needle(const eUVSelectSimilar type,
   return result;
 }
 
+static float get_uv_island_needle(const eUVSelectSimilar type,
+                                  const struct FaceIsland *island,
+                                  const float ob_m3[3][3],
+                                  const int cd_loop_uv_offset)
+
+{
+  float result = 0.0f;
+  switch (type) {
+    case UV_SSIM_AREA_UV:
+      for (int i = 0; i < island->faces_len; i++) {
+        result += BM_face_calc_area_uv(island->faces[i], cd_loop_uv_offset);
+      }
+      break;
+    case UV_SSIM_AREA_3D:
+      for (int i = 0; i < island->faces_len; i++) {
+        result += BM_face_calc_area_with_mat3(island->faces[i], ob_m3);
+      }
+      break;
+    case UV_SSIM_FACE:
+      return island->faces_len;
+    default:
+      BLI_assert_unreachable();
+      return false;
+  }
+  return result;
+}
+
 static int uv_select_similar_vert_exec(bContext *C, wmOperator *op)
 {
   Scene *scene = CTX_data_scene(C);
@@ -4969,6 +4997,136 @@ static int uv_select_similar_face_exec(bContext *C, wmOperator *op)
   return OPERATOR_FINISHED;
 }
 
+static bool uv_island_selected(const Scene *scene, struct FaceIsland *island)
+{
+  BLI_assert(island && island->faces_len);
+  return uvedit_face_select_test(scene, island->faces[0], island->cd_loop_uv_offset);
+}
+
+static int uv_select_similar_island_exec(bContext *C, wmOperator *op)
+{
+  Scene *scene = CTX_data_scene(C);
+  ViewLayer *view_layer = CTX_data_view_layer(C);
+  Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+  ToolSettings *ts = CTX_data_tool_settings(C);
+
+  const eUVSelectSimilar type = RNA_enum_get(op->ptr, "type");
+  const float threshold = RNA_float_get(op->ptr, "threshold");
+  const eSimilarCmp compare = RNA_enum_get(op->ptr, "compare");
+
+  uint objects_len = 0;
+  Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
+      view_layer, ((View3D *)NULL), &objects_len);
+
+  ListBase *island_list_ptr = MEM_callocN(sizeof(*island_list_ptr) * objects_len, __func__);
+  int island_list_len = 0;
+
+  const bool face_selected = !(scene->toolsettings->uv_flag & UV_SYNC_SELECTION);
+
+  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+    Object *obedit = objects[ob_index];
+    BMEditMesh *em = BKE_editmesh_from_object(obedit);
+    const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+    if (cd_loop_uv_offset == -1) {
+      continue;
+    }
+
+    float aspect_y = 1.0f; /* Placeholder value, aspect doesn't change connectivity. */
+    island_list_len += bm_mesh_calc_uv_islands(scene,
+                                               em->bm,
+                                               &island_list_ptr[ob_index],
+                                               face_selected,
+                                               false,
+                                               false,
+                                               aspect_y,
+                                               cd_loop_uv_offset);
+  }
+
+  struct FaceIsland **island_array = MEM_callocN(sizeof(*island_array) * island_list_len,
+                                                 __func__);
+
+  int tree_index = 0;
+  KDTree_1d *tree_1d = BLI_kdtree_1d_new(island_list_len);
+
+  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+    Object *obedit = objects[ob_index];
+    BMEditMesh *em = BKE_editmesh_from_object(obedit);
+    const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+    if (cd_loop_uv_offset == -1) {
+      continue;
+    }
+
+    float ob_m3[3][3];
+    copy_m3_m4(ob_m3, obedit->obmat);
+
+    int index;
+    LISTBASE_FOREACH_INDEX (struct FaceIsland *, island, &island_list_ptr[ob_index], index) {
+      island_array[index] = island;
+      if (!uv_island_selected(scene, island)) {
+        continue;
+      }
+      float needle = get_uv_island_needle(type, island, ob_m3, cd_loop_uv_offset);
+      if (tree_1d) {
+        BLI_kdtree_1d_insert(tree_1d, tree_index++, &needle);
+      }
+    }
+  }
+
+  if (tree_1d != NULL) {
+    BLI_kdtree_1d_deduplicate(tree_1d);
+    BLI_kdtree_1d_balance(tree_1d);
+  }
+
+  int tot_island_index = 0;
+  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+    Object *obedit = objects[ob_index];
+    BMEditMesh *em = BKE_editmesh_from_object(obedit);
+    const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+    if (cd_loop_uv_offset == -1) {
+      continue;
+    }
+    float ob_m3[3][3];
+    copy_m3_m4(ob_m3, obedit->obmat);
+
+    bool changed = false;
+    int index;
+    LISTBASE_FOREACH_INDEX (struct FaceIsland *, island, &island_list_ptr[ob_index], index) {
+      island_array[tot_island_index++] = island; /* To deallocate later. */
+      if (uv_island_selected(scene, island)) {
+        continue;
+      }
+      float needle = get_uv_island_needle(type, island, ob_m3, cd_loop_uv_offset);
+      bool select = ED_select_similar_compare_float_tree(tree_1d, needle, threshold, compare);
+      if (!select) {
+        continue;
+      }
+      bool do_history = false;
+      for (int j = 0; j < island->faces_len; j++) {
+        uvedit_face_select_set(
+            scene, em, island->faces[j], select, do_history, island->cd_loop_uv_offset);
+      }
+      changed = true;
+    }
+
+    if (changed) {
+      uv_select_tag_update_for_object(depsgraph, ts, obedit);
+    }
+  }
+
+  BLI_assert(tot_island_index == island_list_len);
+  for (int i = 0; i < island_list_len; i++) {
+    MEM_SAFE_FREE(island_array[i]->faces);
+    MEM_SAFE_FREE(island_array[i]);
+  }
+
+  MEM_SAFE_FREE(island_array);
+  MEM_SAFE_FREE(island_list_ptr);
+  MEM_SAFE_FREE(objects);
+  BLI_kdtree_1d_free(tree_1d);
+
+  return OPERATOR_FINISHED;
+}
+
 /* Select similar UV faces/edges/verts based on current selection. */
 static int uv_select_similar_exec(bContext *C, wmOperator *op)
 {
@@ -4990,7 +5148,7 @@ static int uv_select_similar_exec(bContext *C, wmOperator *op)
     return uv_select_similar_face_exec(C, op);
   }
   if (selectmode & UV_SELECT_ISLAND) {
-    // return uv_select_similar_island_exec(C, op);
+    return uv_select_similar_island_exec(C, op);
   }
 
   return uv_select_similar_vert_exec(C, op);
@@ -5011,6 +5169,12 @@ static EnumPropertyItem prop_face_similar_types[] = {
     {UV_SSIM_MATERIAL, "MATE

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list