/*
This file is part of LilyPond, the GNU music typesetter.
- Copyright (C) 2004--2011 Han-Wen Nienhuys <hanwen@xs4all.nl>
+ Copyright (C) 2004--2015 Han-Wen Nienhuys <hanwen@xs4all.nl>
LilyPond is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
#include "spanner.hh"
#include "staff-symbol-referencer.hh"
#include "stem.hh"
+#include "tie.hh"
#include "warn.hh"
+using std::string;
+using std::vector;
+
Bezier
avoid_staff_line (Slur_score_state const &state,
Bezier bez)
&& (state.extremes_[LEFT].staff_ == state.extremes_[RIGHT].staff_)
&& state.extremes_[LEFT].staff_ && state.extremes_[RIGHT].staff_)
{
- Real y = bez.curve_point (ts[0])[Y_AXIS];
+ Real t = ts[0]; //the first (usually only) point where slur is horizontal
+ Real y = bez.curve_point (t)[Y_AXIS];
+ // A Bezier curve at t moves 3t-3t² as far as the middle control points
+ Real factor = 3.0 * t * (1.0 - t);
Grob *staff = state.extremes_[LEFT].staff_;
Real p = 2 * (y - staff->relative_coordinate (state.common_[Y_AXIS], Y_AXIS))
/ state.staff_space_;
- Real distance = fabs (my_round (p) - p); // in halfspaces
- if (distance < 4 * state.thickness_
- && (int) fabs (my_round (p))
- <= 2 * Staff_symbol_referencer::staff_radius (staff) + 0.1
- && (int (fabs (my_round (p))) % 2
- != Staff_symbol_referencer::line_count (staff) % 2))
+ int round_p = (int) my_round (p);
+ if (!Staff_symbol_referencer::on_staff_line (staff, round_p))
+ round_p += (p > round_p) ? 1 : -1;
+ if (!Staff_symbol_referencer::on_staff_line (staff, round_p))
+ return bez;
+
+ Real const distance = (p - round_p) * state.staff_space_ / 2.0;
+ // Allow half the thickness of the slur at the point t, plus one basic
+ // blot-diameter (half for the slur outline, half for the staff line)
+ Real const min_distance = 0.5 * state.thickness_ * factor
+ + state.line_thickness_
+ + ((state.dir_ * distance > 0.0)
+ ? state.parameters_.gap_to_staffline_inside_
+ : state.parameters_.gap_to_staffline_outside_);
+ if (fabs (distance) < min_distance)
{
- Direction resolution_dir
- = (distance ? state.dir_ : Direction (sign (p - my_round (p))));
-
- // TODO: parameter
- Real newp = my_round (p) + resolution_dir
- * 5 * state.thickness_;
+ Direction resolution_dir = (distance > 0.0) ? UP : DOWN;
- Real dy = (newp - p) * state.staff_space_ / 2.0;
+ Real dy = resolution_dir * (min_distance - fabs (distance));
+ // Shape the curve, moving the horizontal point by factor * dy
bez.control_[1][Y_AXIS] += dy;
bez.control_[2][Y_AXIS] += dy;
+ // Move the entire curve by the remaining amount
+ bez.translate (Offset (0.0, dy - factor * dy));
}
}
return bez;
d * dot_product (z, dz_perp));
bool close_to_edge = false;
- Direction d = LEFT;
- do
+ for (LEFT_and_RIGHT (d))
close_to_edge = close_to_edge || -d * (p[X_AXIS] - curve_xext[d]) < close_to_edge_length;
- while (flip (&d) != LEFT);
if (close_to_edge)
continue;
Real y = curve.get_other_coordinate (X_AXIS, p[X_AXIS]);
if (y)
- fit_factor = max (fit_factor, (p[Y_AXIS] / y));
+ fit_factor = std::max (fit_factor, (p[Y_AXIS] / y));
}
return fit_factor;
}
(control3 - control0). */
Real max_indent = len / 3.1;
- indent = min (indent, max_indent);
+ indent = std::min (indent, max_indent);
Real a1 = sqr (len) / 3.0;
Real a2 = 0.75 * sqr (indent + len / 3.0);
Real ff = fit_factor (dz_unit, dz_perp, state.parameters_.close_to_edge_length_,
curve, state.dir_, avoid);
- height = max (height, min (height * ff, max_h));
+ height = std::max (height, std::min (height * ff, max_h));
curve.control_[0] = attachment_[LEFT];
curve.control_[1] = attachment_[LEFT] + dz_perp * height * state.dir_
};
void
-Slur_configuration::add_score (Real s, string desc)
+Slur_configuration::add_score (Real s, const string &desc)
{
if (s < 0)
{
- programming_error ("Negative demerits found for slur. Ignoring");
+ programming_error ("Negative demerits found for slur. Ignoring");
s = 0.0;
}
Real hd = (head_dy)
? (1 / fabs (head_dy) - 1 / state.parameters_.free_head_distance_)
: state.parameters_.head_encompass_penalty_;
- hd = min (max (hd, 0.0), state.parameters_.head_encompass_penalty_);
+ hd = std::min (std::max (hd, 0.0), state.parameters_.head_encompass_penalty_);
demerit += hd;
}
{
Real closest
- = state.dir_ * max (state.dir_ * state.encompass_infos_[j].get_point (state.dir_), state.dir_ * line_y);
+ = state.dir_ * std::max (state.dir_ * state.encompass_infos_[j].get_point (state.dir_), state.dir_ * line_y);
Real d = fabs (closest - y);
convex_head_distances.push_back (d);
}
add_score (demerit, "encompass");
- if (convex_head_distances.size ())
+ if (vsize n = convex_head_distances.size ())
{
Real avg_distance = 0.0;
Real min_dist = infinity_f;
- for (vsize j = 0; j < convex_head_distances.size (); j++)
+
+ for (vsize j = 0; j < n; j++)
{
- min_dist = min (min_dist, convex_head_distances[j]);
+ min_dist = std::min (min_dist, convex_head_distances[j]);
avg_distance += convex_head_distances[j];
}
For slurs over 3 or 4 heads, the average distance is not a
good normalizer.
*/
- Real n = convex_head_distances.size ();
if (n <= 2)
{
Real fact = 1.0;
avg_distance += height_ * fact;
- n += fact;
+ ++n;
}
/*
Real variance_penalty = state.parameters_.head_slur_distance_max_ratio_;
if (min_dist > 0.0)
variance_penalty
- = min ((avg_distance / (min_dist + state.parameters_.absolute_closeness_measure_) - 1.0), variance_penalty);
+ = std::min ((avg_distance / (min_dist + state.parameters_.absolute_closeness_measure_) - 1.0), variance_penalty);
- variance_penalty = max (variance_penalty, 0.0);
+ variance_penalty = std::max (variance_penalty, 0.0);
variance_penalty *= state.parameters_.head_slur_distance_factor_;
add_score (variance_penalty, "variance");
void
Slur_configuration::score_extra_encompass (Slur_score_state const &state)
{
+ // we find forbidden attachments
+ vector<Offset> forbidden_attachments;
+ for (vsize i = 0; i < state.extra_encompass_infos_.size (); i++)
+ if (has_interface<Tie> (state.extra_encompass_infos_[i].grob_))
+ {
+ Grob *t = state.extra_encompass_infos_[i].grob_;
+ Grob *common_x = Grob::get_vertical_axis_group (t);
+ Real rp = t->relative_coordinate (common_x, X_AXIS);
+ SCM cp = t->get_property ("control-points");
+
+ Bezier b;
+ int j = 0;
+ for (SCM s = cp; scm_is_pair (s); s = scm_cdr (s))
+ {
+ b.control_[j] = ly_scm2offset (scm_car (s));
+ j++;
+ }
+ forbidden_attachments.push_back (Offset (b.control_[0]) + Offset (rp, 0));
+ forbidden_attachments.push_back (Offset (b.control_[3]) + Offset (rp, 0));
+ }
+
+ bool too_close = false;
+ for (vsize k = 0; k < forbidden_attachments.size (); k++)
+ for (LEFT_and_RIGHT (side))
+ if ((forbidden_attachments[k] - attachment_[side]).length () < state.parameters_.slur_tie_extrema_min_distance_)
+ {
+ too_close = true;
+ break;
+ }
+
+ if (too_close)
+ add_score (state.parameters_.slur_tie_extrema_min_distance_penalty_, "extra");
+
for (vsize j = 0; j < state.extra_encompass_infos_.size (); j++)
{
Drul_array<Offset> attachment = attachment_;
to prevent numerical inaccuracies in
Bezier::get_other_coordinate ().
*/
- Direction d = LEFT;
+
bool found = false;
Real y = 0.0;
- do
+ for (LEFT_and_RIGHT (d))
{
/*
We need to check for the bound explicitly, since the
}
}
- while (flip (&d) != LEFT);
if (!found)
{
}
Real dist = 0.0;
- if (info.type_ == ly_symbol2scm ("around"))
+ if (scm_is_eq (info.type_, ly_symbol2scm ("around")))
dist = info.extents_[Y_AXIS].distance (y);
/*
Have to score too: the curve enumeration is limited in its
shape, and may produce curves which collide anyway.
*/
- else if (info.type_ == ly_symbol2scm ("inside"))
+ else if (scm_is_eq (info.type_, ly_symbol2scm ("inside")))
dist = state.dir_ * (y - info.extents_[Y_AXIS][state.dir_]);
else
programming_error ("unknown avoidance type");
- dist = max (dist, 0.0);
+ dist = std::max (dist, 0.0);
Real penalty = info.penalty_ * peak_around (0.1 * state.parameters_.extra_encompass_free_distance_,
state.parameters_.extra_encompass_free_distance_,
void
Slur_configuration::score_edges (Slur_score_state const &state)
{
- Direction d = LEFT;
+
Offset dz = attachment_[RIGHT]
- attachment_[LEFT];
Real slope = dz[Y_AXIS] / dz[X_AXIS];
- do
+ for (LEFT_and_RIGHT (d))
{
Real y = attachment_[d][Y_AXIS];
Real dy = fabs (y - state.base_attachments_[d][Y_AXIS]);
string dir_str = d == LEFT ? "L" : "R";
add_score (demerit, dir_str + " edge");
}
- while (flip (&d) != LEFT);
}
void
Real slur_dy = slur_dz[Y_AXIS];
Real demerit = 0.0;
- demerit += max ((fabs (slur_dy / slur_dz[X_AXIS])
+ demerit += std::max ((fabs (slur_dy / slur_dz[X_AXIS])
- state.parameters_.max_slope_), 0.0)
* state.parameters_.max_slope_factor_;
if (!state.is_broken_)
demerit += state.parameters_.steeper_slope_factor_
- * (max (fabs (slur_dy) - max_dy, 0.0));
+ * (std::max (fabs (slur_dy) - max_dy, 0.0));
- demerit += max ((fabs (slur_dy / slur_dz[X_AXIS])
+ demerit += std::max ((fabs (slur_dy / slur_dz[X_AXIS])
- state.parameters_.max_slope_), 0.0)
* state.parameters_.max_slope_factor_;