[gimp/wip/gradient-edit: 19/35] app: improve num. stability of gimp_gradient_segment_range_compress()



commit 0b60be290f4fc8e80276daa4945bb847ffc12a37
Author: Ell <ell_se yahoo com>
Date:   Tue Aug 1 13:39:01 2017 -0400

    app: improve num. stability of gimp_gradient_segment_range_compress()
    
    When using gimp_gradient_segment_range_compress() to expand a 0-
    length segment, redistribute the range's endpoints and midpoints
    uniformly, rather than using the regular code path, which would
    result in NaN values.
    
    Make sure that the left and right endpoints of the range are
    *exactly* equal to the new left and right values.  Previously,
    they could be slightly off due to numerical errors.

 app/core/gimpgradient.c |   55 +++++++++++++++++++++++++++++++++++-----------
 1 files changed, 42 insertions(+), 13 deletions(-)
---
diff --git a/app/core/gimpgradient.c b/app/core/gimpgradient.c
index 4d99a8e..1be0cec 100644
--- a/app/core/gimpgradient.c
+++ b/app/core/gimpgradient.c
@@ -1182,7 +1182,6 @@ gimp_gradient_segment_range_compress (GimpGradient        *gradient,
                                       gdouble              new_r)
 {
   gdouble              orig_l, orig_r;
-  gdouble              scale;
   GimpGradientSegment *seg, *aseg;
 
   g_return_if_fail (GIMP_IS_GRADIENT (gradient));
@@ -1196,24 +1195,54 @@ gimp_gradient_segment_range_compress (GimpGradient        *gradient,
   orig_l = range_l->left;
   orig_r = range_r->right;
 
-  scale = (new_r - new_l) / (orig_r - orig_l);
+  if (orig_r - orig_l > EPSILON)
+    {
+      gdouble scale;
 
-  seg = range_l;
+      scale = (new_r - new_l) / (orig_r - orig_l);
 
-  do
+      seg = range_l;
+
+      do
+        {
+          if (seg->prev)
+            seg->left  = new_l + (seg->left - orig_l) * scale;
+          seg->middle  = new_l + (seg->middle - orig_l) * scale;
+          if (seg->next)
+            seg->right = new_l + (seg->right - orig_l) * scale;
+
+          /* Next */
+
+          aseg = seg;
+          seg  = seg->next;
+        }
+      while (aseg != range_r);
+    }
+  else
     {
-      if (seg->prev)
-        seg->left   = new_l + (seg->left - orig_l) * scale;
-      seg->middle = new_l + (seg->middle - orig_l) * scale;
-      if (seg->next)
-        seg->right  = new_l + (seg->right - orig_l) * scale;
+      gint n;
+      gint i;
 
-      /* Next */
+      n = gimp_gradient_segment_range_get_n_segments (gradient,
+                                                      range_l, range_r);
 
-      aseg = seg;
-      seg  = seg->next;
+      for (i = 0, seg = range_l; i < n; i++, seg = seg->next)
+        {
+          if (seg->prev)
+            seg->left  = new_l + (new_r - new_l) * (i + 0.0) / n;
+          seg->middle  = new_l + (new_r - new_l) * (i + 0.5) / n;;
+          if (seg->next)
+            seg->right = new_l + (new_r - new_l) * (i + 1.0) / n;
+        }
     }
-  while (aseg != range_r);
+
+  /* Make sure that the left and right endpoints of the range are *exactly*
+   * equal to new_l and new_r; the above computations can introduce
+   * numerical inaccuracies.
+   */
+
+  range_l->left  = new_l;
+  range_l->right = new_r;
 
   gimp_data_thaw (GIMP_DATA (gradient));
 }


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]