]> git.donarmstrong.com Git - lilypond.git/commitdiff
Fixes issue 1328.
authorMike Solomon <mike@apollinemike.com>
Thu, 25 Aug 2011 07:16:51 +0000 (09:16 +0200)
committerMike Solomon <mike@apollinemike.com>
Thu, 25 Aug 2011 07:16:51 +0000 (09:16 +0200)
Finds the local minimum or maximum of a Bezier curve along the X
axis in the range of an intersection and shifts intersecting
curves up over this range plus slur padding.

Adds default slur padding to all scripts, as this algorithm makes
them almost just touch with the slur whereas the previous one already
had a bit of padding built into it because it was a generous approximation.

flower/include/polynomial.hh
flower/polynomial.cc
input/regression/slur-avoid.ly [new file with mode: 0644]
lily/bezier.cc
lily/include/bezier.hh
lily/slur.cc
scm/define-grobs.scm
scm/script.scm

index f575be35fd5a4ec5a0b17d2cfc2f0232360429f3..c58cb935004e2d324381f4b8229d949e63ce7960 100644 (file)
@@ -44,6 +44,7 @@ struct Polynomial
   Real lc () const;
   void print () const;
   Real eval (Real) const;
+  Real minmax (Real, Real, bool) const;
   void print_sols (vector<Real>) const;
   void check_sols (vector<Real>) const;
   void check_sol (Real x) const;
index 2cd0eaf2e07912f566c837413091b56f02c7114f..05faf4209738a164f170ae86485a6e3059e51e24 100644 (file)
@@ -61,6 +61,32 @@ Polynomial::multiply (const Polynomial &p1, const Polynomial &p2)
   return dest;
 }
 
+Real
+Polynomial::minmax (Real l, Real r, bool ret_max) const
+{
+  vector<Real> sols;
+  if (l > r)
+    {
+      programming_error ("left bound greater than right bound for polynomial minmax.  flipping bounds.");
+      l = l + r;
+      r = l - r;
+      l = l - r;
+    }
+
+  sols.push_back (eval (l));
+  sols.push_back (eval (r));
+
+  Polynomial deriv (*this);
+  deriv.differentiate ();
+  vector<Real> maxmins = deriv.solve ();
+  for (vsize i = 0; i < maxmins.size (); i++)
+    if (maxmins[i] >= l && maxmins[i] <= r)
+      sols.push_back (eval (maxmins[i]));
+  vector_sort (sols, less<Real> ());
+
+  return ret_max ? sols.back () : sols[0];
+}
+
 void
 Polynomial::differentiate ()
 {
diff --git a/input/regression/slur-avoid.ly b/input/regression/slur-avoid.ly
new file mode 100644 (file)
index 0000000..372b8c8
--- /dev/null
@@ -0,0 +1,11 @@
+
+\version "2.15.9"
+
+\header {
+  texidoc = "Slurs handle avoid objects better.
+"
+}
+
+{
+ a'8 (  b''4 \fermata )
+}
index f230d1057d49b0ddb608f87af9d65b9eedbadc70..ce84ce8da89c7623c68548539c49112c67b4c481 100644 (file)
@@ -81,6 +81,17 @@ Bezier::get_other_coordinate (Axis a, Real x) const
   return curve_coordinate (ts[0], other);
 }
 
+vector<Real>
+Bezier::get_other_coordinates (Axis a, Real x) const
+{
+  Axis other = other_axis (a);
+  vector<Real> ts = solve_point (a, x);
+  vector<Real> sols;
+  for (vsize i = 0; i < ts.size (); i++)
+    sols.push_back (curve_coordinate (ts[i], other));
+  return sols;
+}
+
 Real
 Bezier::curve_coordinate (Real t, Axis a) const
 {
@@ -202,6 +213,51 @@ Bezier::solve_point (Axis ax, Real coordinate) const
   return filter_solutions (sol);
 }
 
+Real
+Bezier::minmax (Axis ax, Real l, Real r, Direction d) const
+{
+  return minmax (ax, l, r, d, 0, 0);
+}
+
+Real
+Bezier::minmax (Axis axis, Real l, Real r, Direction d, vsize left_index, vsize right_index) const
+{
+  Axis other = other_axis (axis);
+  Interval lr (l, r);
+  Drul_array<vector<Real> > sol;
+  Direction dir = LEFT;
+  do
+    {
+      Polynomial p (polynomial (axis));
+      p.coefs_[0] -= lr[dir];
+
+      sol[dir] = filter_solutions (p.solve ());
+    }
+  while (flip (&dir) != LEFT);
+
+  if (!sol[LEFT].size () || !sol[RIGHT].size ())
+    {
+      programming_error ("no solution found for Bezier intersection");
+      return 0.0;
+    }
+
+  Polynomial p (polynomial (other));
+
+  Drul_array<vsize> indices(left_index, right_index);
+  do
+    {
+      vector_sort (sol[dir], less<Real> ());
+      if (!Interval (0, sol[LEFT].size () - 1).contains (indices[dir]))
+        {
+          programming_error ("requested bezier solution outside range of solutions.  defaulting to lowest solution.");
+          indices[dir] = 0;
+        }
+    }
+  while (flip (&dir) != LEFT);
+
+  return p.minmax (sol[LEFT][indices[LEFT]], sol[RIGHT][indices[RIGHT]], d != LEFT);
+}
+
 /**
    Compute the bounding box dimensions in direction of A.
 */
index a144e4a7553447babe424fcd25b087ac1a553815..839c8ddc8f8299ab7f96fc32deff91eb96fef630 100644 (file)
@@ -39,7 +39,10 @@ public:
   Bezier extract (Real, Real) const;
 
   Real get_other_coordinate (Axis a, Real x) const;
+  vector<Real> get_other_coordinates (Axis a, Real x) const;
   vector<Real> solve_point (Axis, Real coordinate) const;
+  Real minmax (Axis, Real, Real, Direction) const;
+  Real minmax (Axis, Real, Real, Direction, vsize, vsize) const;
   vector<Real> solve_derivative (Offset) const;
   Interval extent (Axis) const;
   Interval control_point_extent (Axis) const;
index 32149e8412c8be7f71c43f9168b8379fd4eb342e..964a4d091b210e0ab78f4bb8c980291679a317e1 100644 (file)
@@ -279,42 +279,47 @@ Slur::outside_slur_callback (SCM grob, SCM offset_scm)
                                          0.0);
   yext.widen (slur_padding);
 
-  const Real EPS = 1e-3;
-  Interval bezext (curve.control_[0][X_AXIS], curve.control_[3][X_AXIS]);
-  bool consider[] = {false, false, false};
-  Real ys[] = {0, 0, 0};
+  Interval exts[] = {xext, yext};
   bool do_shift = false;
-
-  for (int d = LEFT, k = 0; d <= RIGHT; d++, k++)
+  Real EPS = 1.0e-5;
+  if (avoid == ly_symbol2scm ("outside"))
     {
-      Real x = xext.linear_combination ((Direction) d);
-      consider[k] = bezext.contains (x);
-
-      if (consider[k])
+      Direction d = LEFT;
+      do
         {
-          ys[k]
-            = (fabs (bezext[LEFT] - x) < EPS)
-              ? curve.control_[0][Y_AXIS]
-              : ((fabs (bezext[RIGHT] - x) < EPS)
-                 ? curve.control_[3][Y_AXIS]
-                 : curve.get_other_coordinate (X_AXIS, x));
-
-          /* Request shift if slur is contained script's Y, or if
-             script is inside slur and avoid == outside.  */
-          if (yext.contains (ys[k])
-              || (dir * ys[k] > dir * yext[-dir] && avoid == ly_symbol2scm ("outside")))
-            do_shift = true;
+          Real x = minmax (-d, xext[d], curve.control_[d == LEFT ? 0 : 3][X_AXIS] + -d * EPS);
+          Real y = curve.get_other_coordinate (X_AXIS, x);
+          do_shift = y == minmax (dir, yext[-dir], y);
+          if (do_shift)
+            break;
         }
+      while (flip (&d) != LEFT);
     }
-
-  Real avoidance_offset = 0.0;
-  if (do_shift)
+  else
     {
-      for (int d = LEFT, k = 0; d <= RIGHT; d++, k++)
-        if (consider[k])
-          avoidance_offset = dir * (max (dir * avoidance_offset,
-                                         dir * (ys[k] - yext[-dir] + dir * slur_padding)));
+      for (int a = X_AXIS; a < NO_AXES; a++)
+        {
+          Direction d = LEFT;
+          do
+            {
+              vector<Real> coords = curve.get_other_coordinates (Axis (a), exts[a][d]);
+              for (vsize i = 0; i < coords.size (); i++)
+                {
+                  do_shift = exts[(a + 1) % NO_AXES].contains (coords[i]);
+                  if (do_shift)
+                    break;
+                }
+              if (do_shift)
+                break;
+            }
+          while (flip (&d) != LEFT);
+          if (do_shift)
+            break;
+        }
     }
+
+  Real avoidance_offset = do_shift ? curve.minmax (X_AXIS, max (xext[LEFT], curve.control_[0][X_AXIS] + EPS), min (xext[RIGHT], curve.control_[3][X_AXIS] - EPS), dir) - yext[-dir] : 0.0;
+
   return scm_from_double (offset + avoidance_offset);
 }
 
index e1d076c29684d7c71b4a79a281cdd946e0fad86a..3055af219bfb916547a7e1e1b9bad26fa48e2c4a 100644 (file)
        (side-axis . ,Y)
 
        ;; padding set in script definitions.
+       (slur-padding . 0.2)
        (staff-padding . 0.25)
 
        (stencil . ,ly:script-interface::print)
index 417df4cbee435084d093bcb65036ff59e1620dce..4d6dc05a8ea6eb5bcbe8f346cca4470c5b3fe6c1 100644 (file)
      . (
        (script-stencil . (feta . ("uportato" . "dportato")))
        (avoid-slur . around)
-       (slur-padding . 0.3)
        (padding . 0.45)
        (side-relative-direction . ,DOWN)))
     ("prall"
        (avoid-slur . around)
        (padding . 0.50)
        (direction . ,UP)
-       (slur-padding . 0.2)
        (staff-padding . 0.5)))
     ("trill"
      . (