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;
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 ()
{
--- /dev/null
+
+\version "2.15.9"
+
+\header {
+ texidoc = "Slurs handle avoid objects better.
+"
+}
+
+{
+ a'8 ( b''4 \fermata )
+}
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
{
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.
*/
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;
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);
}
(side-axis . ,Y)
;; padding set in script definitions.
+ (slur-padding . 0.2)
(staff-padding . 0.25)
(stencil . ,ly:script-interface::print)
. (
(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"
. (