Fix T69536: Setting dimensions for parented objects fails
authorCampbell Barton <ideasman42@gmail.com>
Fri, 6 Sep 2019 10:00:45 +0000 (20:00 +1000)
committerCampbell Barton <ideasman42@gmail.com>
Fri, 6 Sep 2019 10:04:09 +0000 (20:04 +1000)
Parenting/constraints/delta-scaled all caused setting dimensions to fail.

Take the difference between the input scale and final scale into
account when applying the dimensions.

source/blender/blenkernel/BKE_object.h
source/blender/blenkernel/intern/object.c
source/blender/editors/space_view3d/view3d_buttons.c

index cf4bce3a20940168d57fe87f8cf6868c802dbcca..5162e1cf51d41363d6e7ad7fe9a4aef0ee7894f1 100644 (file)
@@ -222,7 +222,13 @@ void BKE_boundbox_minmax(const struct BoundBox *bb,
 
 struct BoundBox *BKE_object_boundbox_get(struct Object *ob);
 void BKE_object_dimensions_get(struct Object *ob, float vec[3]);
+void BKE_object_dimensions_set_ex(struct Object *ob,
+                                  const float value[3],
+                                  int axis_mask,
+                                  const float ob_scale_orig[3],
+                                  const float ob_obmat_orig[4][4]);
 void BKE_object_dimensions_set(struct Object *ob, const float value[3], int axis_mask);
+
 void BKE_object_empty_draw_type_set(struct Object *ob, const int value);
 void BKE_object_boundbox_flag(struct Object *ob, int flag, const bool set);
 void BKE_object_boundbox_calc_from_mesh(struct Object *ob, struct Mesh *me_eval);
index ed517bfc5137e42e3c6fa5733f124ff7576e5983..acfa6085d451fa214e17cfe87b0005919268701f 100644 (file)
@@ -2799,6 +2799,12 @@ void BKE_object_boundbox_calc_from_mesh(struct Object *ob, struct Mesh *me_eval)
   ob->runtime.bb->flag &= ~BOUNDBOX_DIRTY;
 }
 
+/* -------------------------------------------------------------------- */
+/** \name Object Dimension Get/Set
+ *
+ * \warning Setting dimensions is prone to feedback loops in evaluation.
+ * \{ */
+
 void BKE_object_dimensions_get(Object *ob, float vec[3])
 {
   BoundBox *bb = NULL;
@@ -2818,7 +2824,19 @@ void BKE_object_dimensions_get(Object *ob, float vec[3])
   }
 }
 
-void BKE_object_dimensions_set(Object *ob, const float value[3], int axis_mask)
+/**
+ * The original scale and object matrix can be passed in so any difference
+ * of the objects matrix and the final matrix can be accounted for,
+ * typically this caused by parenting, constraints or delta-scale.
+ *
+ * Re-using these values from the object causes a feedback loop
+ * when multiple values are modified at once in some situations. see: T69536.
+ */
+void BKE_object_dimensions_set_ex(Object *ob,
+                                  const float value[3],
+                                  int axis_mask,
+                                  const float ob_scale_orig[3],
+                                  const float ob_obmat_orig[4][4])
 {
   BoundBox *bb = NULL;
 
@@ -2832,7 +2850,16 @@ void BKE_object_dimensions_set(Object *ob, const float value[3], int axis_mask)
 
     for (int i = 0; i < 3; i++) {
       if (((1 << i) & axis_mask) == 0) {
+
+        if (ob_scale_orig != NULL) {
+          const float scale_delta = len_v3(ob_obmat_orig[i]) / ob_scale_orig[i];
+          if (isfinite(scale_delta)) {
+            len[i] *= scale_delta;
+          }
+        }
+
         if (len[i] > 0.0f) {
+
           ob->scale[i] = copysignf(value[i] / len[i], ob->scale[i]);
         }
       }
@@ -2840,6 +2867,11 @@ void BKE_object_dimensions_set(Object *ob, const float value[3], int axis_mask)
   }
 }
 
+void BKE_object_dimensions_set(Object *ob, const float value[3], int axis_mask)
+{
+  BKE_object_dimensions_set_ex(ob, value, axis_mask, NULL, NULL);
+}
+
 void BKE_object_minmax(Object *ob, float min_r[3], float max_r[3], const bool use_hidden)
 {
   BoundBox bb;
index 3d3c73ad27c0ef7cd25b113bbe28fb75af3bf8a7..1ace1198795801495b051d7fb8842c3acbf622cb 100644 (file)
@@ -106,7 +106,9 @@ typedef union {
 /* temporary struct for storing transform properties */
 
 typedef struct {
+  float ob_obmat_orig[4][4];
   float ob_dims_orig[3];
+  float ob_scale_orig[3];
   float ob_dims[3];
   /* Floats only (treated as an array). */
   TransformMedian ve_median, median;
@@ -1050,6 +1052,8 @@ static void v3d_object_dimension_buts(bContext *C, uiLayout *layout, View3D *v3d
 
     BKE_object_dimensions_get(ob, tfp->ob_dims);
     copy_v3_v3(tfp->ob_dims_orig, tfp->ob_dims);
+    copy_v3_v3(tfp->ob_scale_orig, ob->scale);
+    copy_m4_m4(tfp->ob_obmat_orig, ob->obmat);
 
     uiDefBut(block,
              UI_BTYPE_LABEL,
@@ -1095,7 +1099,8 @@ static void v3d_object_dimension_buts(bContext *C, uiLayout *layout, View3D *v3d
         axis_mask |= (1 << i);
       }
     }
-    BKE_object_dimensions_set(ob, tfp->ob_dims, axis_mask);
+    BKE_object_dimensions_set_ex(
+        ob, tfp->ob_dims, axis_mask, tfp->ob_scale_orig, tfp->ob_obmat_orig);
 
     PointerRNA obptr;
     RNA_id_pointer_create(&ob->id, &obptr);