Commit: d615f4d65e44109d1843441e9b3c5f145901c3c7
Author: Siddhartha Jejurkar
Date:   Sat Jul 3 14:29:56 2021 +0530
Branches: soc-2021-uv-editor-improvements
https://developer.blender.org/rBd615f4d65e44109d1843441e9b3c5f145901c3c7

Fix: Pack islands to area operator

* Correct packing area coordinates for cases when user sets the maximum
  coordinates to be lower than the minimum coordinates
* Cancel operator when scale option is disabled and packing area is not
  big enough for selected islands. Also display warning message in UI
  when this happens

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

M       source/blender/blenlib/BLI_boxpack_2d.h
M       source/blender/blenlib/intern/boxpack_2d.c
M       source/blender/editors/include/ED_uvedit.h
M       source/blender/editors/uvedit/uvedit_islands.c
M       source/blender/editors/uvedit/uvedit_unwrap_ops.c

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

diff --git a/source/blender/blenlib/BLI_boxpack_2d.h 
b/source/blender/blenlib/BLI_boxpack_2d.h
index 5b70cd3f410..89339b66021 100644
--- a/source/blender/blenlib/BLI_boxpack_2d.h
+++ b/source/blender/blenlib/BLI_boxpack_2d.h
@@ -64,7 +64,7 @@ void BLI_box_pack_2d_fixedarea(struct ListBase *boxes,
                                int height,
                                struct ListBase *packed);
 
-void BLI_rect_pack_2d(BoxPack *boxarray,
+bool BLI_rect_pack_2d(BoxPack *boxarray,
                       const uint len,
                       const float rect_width,
                       const float rect_height);
diff --git a/source/blender/blenlib/intern/boxpack_2d.c 
b/source/blender/blenlib/intern/boxpack_2d.c
index 1679da7fc13..bddb9878a36 100644
--- a/source/blender/blenlib/intern/boxpack_2d.c
+++ b/source/blender/blenlib/intern/boxpack_2d.c
@@ -786,14 +786,8 @@ void BLI_box_pack_2d_fixedarea(ListBase *boxes, int width, 
int height, ListBase
 }
 
 /* Similar implementation of BLI_box_pack_2d_fixedarea() that works with 
BoxPack array and float
- * variables.
- * A current problem with the algorithm is that boxes that do not fit are not 
packed (skipped), so
- * that finally causes those boxes to be placed at the bottom left position 
overlapping with other
- * boxes.
- * TODO : Fix this issue by setting a callback that cancels the operator (and 
possibly prints an
- * error message saying the area is too small for packing islands without 
scaling) when a
- * particular box does not fit any empty space */
-void BLI_rect_pack_2d(BoxPack *boxarray,
+ * variables */
+bool BLI_rect_pack_2d(BoxPack *boxarray,
                       const uint len,
                       const float rect_width,
                       const float rect_height)
@@ -802,11 +796,19 @@ void BLI_rect_pack_2d(BoxPack *boxarray,
   RectSizeBoxPack *full_rect = MEM_callocN(sizeof(RectSizeBoxPack), __func__);
   full_rect->w = rect_width;
   full_rect->h = rect_height;
+  bool is_box_packed;
 
   BLI_addhead(&spaces, full_rect);
+  /* CHECK : Sorting is probably used incorrectly here */
   qsort(boxarray, (size_t)len, sizeof(BoxPack), box_areasort);
 
+  /* Rotating islands in uvedits_islands.c doesn't work well with this 
algorithm
+   * TODO : Implement heuristic for rotating islands - Rotate islands if they 
don't fit in any
+   * empty space, but can fit if they are rotated. A boolean might be needed 
per island to check if
+   * islands need to be rotated when they are translated in uvedit_islands.c */
+
   for (uint i = 0; i < len; i++) {
+    is_box_packed = false;
     LISTBASE_FOREACH (RectSizeBoxPack *, space, &spaces) {
       /* Skip this space if it's too small. */
       if (boxarray[i].w > space->w || boxarray[i].h > space->h) {
@@ -816,6 +818,7 @@ void BLI_rect_pack_2d(BoxPack *boxarray,
       /* Pack this box into this space. */
       boxarray[i].x = space->x;
       boxarray[i].y = space->y;
+      is_box_packed = true;
 
       if (boxarray[i].w == space->w && boxarray[i].h == space->h) {
         /* Box exactly fills space, so just remove the space. */
@@ -867,7 +870,14 @@ void BLI_rect_pack_2d(BoxPack *boxarray,
 
       break;
     }
+    /* Packing area not big enough to pack all boxes */
+    if (!is_box_packed) {
+      BLI_freelistN(&spaces);
+      return false;
+    }
   }
 
+  /* All boxes packed successfully */
   BLI_freelistN(&spaces);
+  return true;
 }
\ No newline at end of file
diff --git a/source/blender/editors/include/ED_uvedit.h 
b/source/blender/editors/include/ED_uvedit.h
index 2dc9635a494..269590197ee 100644
--- a/source/blender/editors/include/ED_uvedit.h
+++ b/source/blender/editors/include/ED_uvedit.h
@@ -253,7 +253,7 @@ void ED_uvedit_pack_islands_multi(const struct Scene *scene,
                                   bool use_target,
                                   const struct UVPackIsland_Params *params);
 
-void ED_uvedit_pack_islands_to_area_multi(const struct Scene *scene,
+bool ED_uvedit_pack_islands_to_area_multi(const struct Scene *scene,
                                           Object **objects,
                                           const uint objects_len,
                                           const float min_co[2],
diff --git a/source/blender/editors/uvedit/uvedit_islands.c 
b/source/blender/editors/uvedit/uvedit_islands.c
index 07c8263d618..9181699a283 100644
--- a/source/blender/editors/uvedit/uvedit_islands.c
+++ b/source/blender/editors/uvedit/uvedit_islands.c
@@ -593,7 +593,7 @@ void ED_uvedit_pack_islands_multi(const Scene *scene,
 /* Almost similar to ED_uvedit_pack_islands_multi().
  * TODO : Break some of the code into smaller functions since same operations 
are being done in
  * both ED_uvedit_pack_islands_to_area_multi() and 
ED_uvedit_pack_islands_multi() */
-void ED_uvedit_pack_islands_to_area_multi(const Scene *scene,
+bool ED_uvedit_pack_islands_to_area_multi(const Scene *scene,
                                           Object **objects,
                                           const uint objects_len,
                                           const float min_co[2],
@@ -628,7 +628,7 @@ void ED_uvedit_pack_islands_to_area_multi(const Scene 
*scene,
 
   /* This check could probably be removed */
   if (island_list_len == 0) {
-    return;
+    return true;
   }
 
   float margin = scene->toolsettings->uvcalc_margin;
@@ -641,7 +641,7 @@ void ED_uvedit_pack_islands_to_area_multi(const Scene 
*scene,
   int index;
   LISTBASE_FOREACH_INDEX (struct FaceIsland *, island, &island_list, index) {
     /* For now using the same conditions for rotating islands when scaling is 
enabled and disabled.
-     * TODO : New heuristic for rotating islands when scaling is disabled 
(using the
+     * TODO : Use new heuristic for rotating islands when scaling is disabled 
(using the
      * RectPack2D algorithm) */
     if (params->rotate) {
       if (island->aspect_y != 1.0f) {
@@ -714,7 +714,17 @@ void ED_uvedit_pack_islands_to_area_multi(const Scene 
*scene,
     scale[1] = 1.0f / boxarray_size[1];
   }
   else {
-    BLI_rect_pack_2d(boxarray, island_list_len, (max_co[0] - min_co[0]), 
(max_co[1] - min_co[1]));
+    if (!BLI_rect_pack_2d(
+            boxarray, island_list_len, (max_co[0] - min_co[0]), (max_co[1] - 
min_co[1]))) {
+      /* Cancel operator : Packing area not big enough for selected islands */
+      for (int i = 0; i < island_list_len; i++) {
+        MEM_freeN(island_array[i]->faces);
+        MEM_freeN(island_array[i]);
+      }
+      MEM_freeN(island_array);
+      MEM_freeN(boxarray);
+      return false;
+    }
   }
 
   for (int i = 0; i < island_list_len; i++) {
@@ -758,4 +768,7 @@ void ED_uvedit_pack_islands_to_area_multi(const Scene 
*scene,
 
   MEM_freeN(island_array);
   MEM_freeN(boxarray);
+
+  /* All islands packed successfully */
+  return true;
 }
diff --git a/source/blender/editors/uvedit/uvedit_unwrap_ops.c 
b/source/blender/editors/uvedit/uvedit_unwrap_ops.c
index 745a242050f..c780e7134f6 100644
--- a/source/blender/editors/uvedit/uvedit_unwrap_ops.c
+++ b/source/blender/editors/uvedit/uvedit_unwrap_ops.c
@@ -1185,38 +1185,65 @@ static int pack_islands_to_area_exec(bContext *C, 
wmOperator *op)
       view_layer, CTX_wm_view3d(C), &objects_len);
 
   /* Packing area coordinates */
-  float min_co[2] = {0.0f, 0.0f};
-  float max_co[2] = {1.0f, 1.0f};
-
-  /* Fixes the issue of modified packing coordinates when user reuses the 
operator from the
-   * properties panel after zooming in/out in the UV editor */
-  if (RNA_struct_property_is_set(op->ptr, "box_min_co") ||
-      RNA_struct_property_is_set(op->ptr, "box_max_co") ||
-      RNA_struct_property_is_set(op->ptr, "rotate") ||
-      RNA_struct_property_is_set(op->ptr, "scale") ||
-      RNA_struct_property_is_set(op->ptr, "margin")) {
-    RNA_float_get_array(op->ptr, "box_min_co", min_co);
-    RNA_float_get_array(op->ptr, "box_max_co", max_co);
-  }
-  /* MISSING : Implement a way to clamp box coordinates properly so that 
invalid cases such as
-   * (max_co < min_co) are handled */
+  float box_min_co[2] = {0.0f, 0.0f};
+  float box_max_co[2] = {1.0f, 1.0f};
+  /* Store coordinates for operator rerun */
+  float pack_area[4] = {0.0f, 0.0f, 1.0f, 1.0f};
+
+  rctf bounds;
+  WM_operator_properties_border_to_rctf(op, &bounds);
+  UI_view2d_region_to_view_rctf(&region->v2d, &bounds, &bounds);
+  /* Bounding coordinates for the user-defined area */
+  box_min_co[0] = bounds.xmin;
+  box_min_co[1] = bounds.ymin;
+  box_max_co[0] = bounds.xmax;
+  box_max_co[1] = bounds.ymax;
+
+  RNA_float_get_array(op->ptr, "pack_area", pack_area);
+
+  /* Running operator through modal callback */
+  if (!RNA_struct_property_is_set(op->ptr, "pack_area")) {
+    RNA_float_set_array(op->ptr, "box_min_co", box_min_co);
+    RNA_float_set_array(op->ptr, "box_max_co", box_max_co);
+
+    pack_area[0] = box_min_co[0];
+    pack_area[1] = box_min_co[1];
+    pack_area[2] = box_max_co[0];
+    pack_area[3] = box_max_co[1];
+
+    RNA_float_set_array(op->ptr, "pack_area", pack_area);
+    /* Scale always true when box select used to define area */
+    RNA_boolean_set(op->ptr, "scale", true);
+  }
+  /* Re-running operator theough properties panel */
   else {
-    rctf bounds;
-    WM_operator_properties_border_to_rctf(op, &bounds);
-    UI_view2d_region_to_view_rctf(&region->v2d, &bounds, &bounds);
-    /* Bounding coordinates for the user-defined area */
-    min_co[0] = bounds.xmin;
-    min_co[1] = bounds.ymin;
-    max_co[0] = bounds.xmax;
-    max_co[1] = bounds.ymax;
-    RNA_float_set_array(op->ptr, "box_min_co", min_co);
-    RNA_float_set_array(op->ptr, "box_max_co", max_co);
+    RNA_float_get_array(op->ptr, "box_min_co", box_min_co);
+    RNA_float_get_array(op->ptr, "box_max_co", box_max_co);
+    if ((box_max_co[0] - box_min_co[0]) <= 0.001f || (box_max_co[1] - 
box_min_co[1]) <= 0.001f) {
+      box_min_co[0] = pack_area[0];
+      box_min_co[1] = pack_area[1];
+      box_max_co[0] = pack_area[2];
+      box_max_co[1] = pack_area[3];
+      RNA_float_set_array(op->ptr, "box_min_co", box_min_co);
+      RNA_float_set_array(op->ptr, "box_max_co", box_max_co);
+      RNA_float_set_array(op->ptr, "pack_area", pack_area);
+      /* CANCEL OPERATOR SINCE 

@@ Diff output truncated at 10240 characters. @@

_______________________________________________
Bf-blender-cvs mailing list
[email protected]
List details, subscription details or unsubscribe:
https://lists.blender.org/mailman/listinfo/bf-blender-cvs

Reply via email to