source file of the GNU LilyPond music typesetter
(c) 1996--2004 Han-Wen Nienhuys <hanwen@cs.uu.nl>
- Jan Nieuwenhuizen <janneke@gnu.org>
+ Jan Nieuwenhuizen <janneke@gnu.org>
*/
};
/*
- TODO: put in details list.
- */
-const int SLUR_REGION_SIZE = 5;
-const Real HEAD_ENCOMPASS_PENALTY = 1000.0;
-const Real STEM_ENCOMPASS_PENALTY = 30.0;
-const Real CLOSENESS_FACTOR = 10;
-const Real EDGE_ATTRACTION_FACTOR = 4;
-const Real HEAD_FREE_SPACE = 0.3;
-const Real SAME_SLOPE_PENALTY = 20;
-const Real STEEPER_SLOPE_FACTOR = 50;
-const Real NON_HORIZONTAL_PENALTY = 15;
-const Real HEAD_STRICT_FREE_SPACE = 0.2;
-const Real MAX_SLOPE = 1.1;
-const Real MAX_SLOPE_FACTOR = 10;
-const Real FREE_HEAD_DISTANCE = 0.5 ;
+ TODO: put in details property.
+*/
+struct Slur_score_parameters
+{
+ int SLUR_REGION_SIZE ;
+ Real HEAD_ENCOMPASS_PENALTY ;
+ Real STEM_ENCOMPASS_PENALTY ;
+ Real CLOSENESS_FACTOR ;
+ Real EDGE_ATTRACTION_FACTOR ;
+ Real SAME_SLOPE_PENALTY ;
+ Real STEEPER_SLOPE_FACTOR ;
+ Real NON_HORIZONTAL_PENALTY ;
+ Real HEAD_STRICT_FREE_SPACE ;
+ Real MAX_SLOPE ;
+ Real MAX_SLOPE_FACTOR ;
+ Real FREE_HEAD_DISTANCE ;
+ Slur_score_parameters ();
+};
+
+void
+init_score_param (Slur_score_parameters *score_param)
+{
+ score_param->SLUR_REGION_SIZE = 5;
+ score_param->HEAD_ENCOMPASS_PENALTY = 1000.0;
+ score_param->STEM_ENCOMPASS_PENALTY = 30.0;
+ score_param->CLOSENESS_FACTOR = 10;
+ score_param->EDGE_ATTRACTION_FACTOR = 4;
+ score_param->SAME_SLOPE_PENALTY = 20;
+ score_param->STEEPER_SLOPE_FACTOR = 50;
+ score_param->NON_HORIZONTAL_PENALTY = 15;
+ score_param->HEAD_STRICT_FREE_SPACE = 0.2;
+ score_param->MAX_SLOPE = 1.1;
+ score_param->MAX_SLOPE_FACTOR = 10;
+ score_param->FREE_HEAD_DISTANCE = 0.3 ;
+}
+
+Slur_score_parameters::Slur_score_parameters()
+{
+ init_score_param (this);
+}
#define DEBUG_SLUR_QUANTING 1
static void add_column (Grob *me, Grob *col);
DECLARE_SCHEME_CALLBACK (print, (SCM));
static void score_slopes (Grob * me, Grob *common[],
+ Slur_score_parameters * score_param,
+
Drul_array<Bound_info>,
Drul_array<Offset> base_attach,
Array<Slur_score> * scores);
static void score_edges (Grob * me, Grob *common[],
- Drul_array<Bound_info> extremes,
- Drul_array<Offset> base_attach,
- Array<Slur_score> * scores);
- static void score_encompass (Grob * me, Grob *common[],
- Drul_array<Bound_info>,
- Drul_array<Offset>, Array<Slur_score> * scores);
+ Slur_score_parameters * score_param,
+
+ Drul_array<Bound_info> extremes,
+ Drul_array<Offset> base_attach,
+ Array<Slur_score> * scores);
+ static void score_encompass (Grob * me, Grob *common[],
+ Slur_score_parameters*,
+ Drul_array<Bound_info>,
+ Drul_array<Offset>, Array<Slur_score> * scores);
+
+ static Encompass_info get_encompass_info (Grob *me,
+ Grob *col,
+ Grob **common) ;
static void set_interface (Grob*);
static bool has_interface (Grob*);
- static Array<Offset> get_encompass_offsets (Grob *me);
static Bezier get_curve (Grob *me);
static Bezier get_bezier (Grob *me, Drul_array<Offset>,Real,Real);
static Direction get_default_dir (Grob *me);
DECLARE_SCHEME_CALLBACK (after_line_breaking, (SCM));
DECLARE_SCHEME_CALLBACK (height, (SCM,SCM));
-private:
+
static void set_end_points (Grob*);
static Real get_boundary_notecolumn_y (Grob *me, Direction dir);
static Real broken_trend_y (Grob *me, Grob**, Direction dir);
- static Offset get_attachment (Grob *me,Direction dir, Grob **common);
- static void de_uglyfy (Grob *me,Slur_bezier_bow* bb, Real default_height);
- static SCM set_extremities (Grob *me);
static void set_control_points (Grob *me);
- static void check_slope (Grob *me);
- static Encompass_info get_encompass_info (Grob *me, Grob *col, Grob **common);
+ static Drul_array<Bound_info> get_bound_info (Spanner* me,
+ Grob **common);
+
+ static void generate_curves (Grob*me, Array<Slur_score> *scores);
+ static Array<Slur_score> enumerate_attachments (Grob * me, Grob *common[],
+ Slur_score_parameters * score_param,
+ Drul_array<Bound_info> extremes,
+ Drul_array<Offset> base_attachment, Drul_array<Real> end_ys);
+ ;
+ static Drul_array<Offset> get_base_attachments (Spanner*sp,
+ Grob **common,
+
+ Drul_array<Bound_info> extremes);
+
+ static Drul_array<Real> get_y_attachment_range (Spanner*sp,
+ Grob **common,
+
+ Drul_array<Bound_info> extremes,
+ Drul_array<Offset> base_attachment);
};
Real
Grob *neighbor = mother->broken_intos_[j];
if (hdir == RIGHT)
neighbor->set_property ("direction",
- me->get_property ("direction"));
+ me->get_property ("direction"));
Spanner * common_mother = dynamic_cast<Spanner*> (common[Y_AXIS]->original_);
int common_k = broken_spanner_index (dynamic_cast<Spanner*> (common[Y_AXIS]));
Encompass_info
New_slur::get_encompass_info (Grob *me,
- Grob *col,
- Grob **common)
+ Grob *col,
+ Grob **common)
{
Grob* stem = unsmob_grob (col->get_property ("stem"));
return bb.get_bezier ();
}
+
+Drul_array<Bound_info>
+New_slur::get_bound_info (Spanner* me,
+ Grob **common)
+{
+ Drul_array<Bound_info> extremes;
+ Direction d = LEFT;
+ Direction dir = get_grob_direction (me);
+
+ do {
+ extremes[d].bound_ = me->get_bound (d);
+
+ if (Note_column::has_interface (extremes[d].bound_))
+ {
+ extremes[d].note_column_ = extremes[d].bound_;
+ extremes[d].stem_ = Note_column::get_stem (extremes[d].note_column_);
+ extremes[d].stem_dir_ = get_grob_direction (extremes[d].stem_);
+ extremes[d].stem_extent_[X_AXIS] = extremes[d].stem_->extent (common[X_AXIS], X_AXIS);
+ extremes[d].stem_extent_[Y_AXIS] = extremes[d].stem_->extent (common[Y_AXIS], Y_AXIS);
+ extremes[d].slur_head_ = Stem::extremal_heads (extremes[d].stem_)[dir];
+ extremes[d].slur_head_extent_ = extremes[d].slur_head_->extent (common[X_AXIS], X_AXIS);
+ extremes[d].staff_ = Staff_symbol_referencer::get_staff_symbol (extremes[d].slur_head_);
+ }
+ else
+ {
+ extremes[d].neighbor_y_ = broken_trend_y (me, common, d);
+ }
+ } while (flip (&d) != LEFT);
+
+ return extremes;
+}
+
void
New_slur::set_end_points (Grob *me)
{
Link_array<Grob> columns =
Pointer_group_interface__extract_grobs (me, (Grob*)0, "note-columns");
+
+ Slur_score_parameters params;
if (columns.is_empty ())
{
me->suicide ();
return ;
}
- Real staff_space = Staff_symbol_referencer::staff_space ((Grob*)me);
- Real minimum_length = staff_space * robust_scm2double (me->get_property ("minimum-length"),
- 2.0);
-
- Drul_array<Offset> base_attachment;
SCM eltlist = me->get_property ("note-columns");
Grob *common[] = {common_refpoint_of_list (eltlist, me, X_AXIS),
common[X_AXIS] = common[X_AXIS]->common_refpoint (sp->get_bound (LEFT), X_AXIS);
- Drul_array<Bound_info> extremes;
- Direction dir = get_grob_direction (me);
+ Drul_array<Bound_info> extremes = get_bound_info (sp, common);
+ Drul_array<Offset> base_attachment = get_base_attachments (sp, common, extremes);
+ Drul_array<Real> end_ys = get_y_attachment_range (sp, common, extremes, base_attachment);
+ Array<Slur_score> scores = enumerate_attachments (me, common,
+ ¶ms, extremes, base_attachment, end_ys);
+ generate_curves (me, &scores);
+
+ score_edges (me, common, ¶ms,extremes, base_attachment, &scores);
+ score_slopes (me, common, ¶ms,extremes, base_attachment, &scores);
+ score_encompass (me, common, ¶ms,extremes, base_attachment, &scores);
+
+ Real opt = 1e6;
+ int opt_idx = 0;
+ for (int i = scores.size (); i--;)
+ {
+ if (scores[i].score_ < opt)
+ {
+ opt = scores[i].score_;
+ opt_idx = i;
+ }
+ }
+
+#if DEBUG_SLUR_QUANTING
+ SCM inspect_quants = me->get_property ("inspect-quants");
+ if (to_boolean (me->get_paper ()->lookup_variable (ly_symbol2scm ("debug-slur-quanting")))
+ && ly_c_pair_p (inspect_quants))
+ {
+ Drul_array<Real> ins = ly_scm2interval (inspect_quants);
+ int i = 0;
+
+ Real mindist = 1e6;
+ for (; i < scores.size (); i ++)
+ {
+ Real d =fabs (scores[i].attachment_[LEFT][Y_AXIS] - ins[LEFT])
+ + fabs (scores[i].attachment_[RIGHT][Y_AXIS] - ins[RIGHT]);
+ if (d < mindist)
+ {
+ opt_idx = i;
+ mindist= d;
+ }
+ }
+ if (mindist > 1e5)
+ programming_error ("Could not find quant.");
+ }
+ scores[opt_idx].score_card_ += to_string ("i%d", opt_idx);
+
+ // debug quanting
+ me->set_property ("quant-score",
+ scm_makfrom0str (scores[opt_idx].score_card_.to_str0 ()));
+#endif
+
+ Bezier const &b = scores[opt_idx].curve_;
+
+ SCM controls = SCM_EOL;
+ for (int i = 4; i--;)
+ {
+ Offset o = b.control_[i] -
+ Offset (me->relative_coordinate (common[X_AXIS], X_AXIS),
+ me->relative_coordinate (common[Y_AXIS], Y_AXIS));
+
+ controls = scm_cons (ly_offset2scm (o), controls);
+ }
+
+ me->set_property ("control-points", controls);
+}
+
+
+Drul_array<Real>
+New_slur::get_y_attachment_range (Spanner*me,
+ Grob **common,
+ Drul_array<Bound_info> extremes,
+ Drul_array<Offset> base_attachment)
+{
+ Drul_array<Real> end_ys;
+ Direction dir = get_grob_direction (me);
Direction d = LEFT;
do {
- extremes[d].bound_ = dynamic_cast<Spanner*> (me)->get_bound (d);
-
- if (Note_column::has_interface (extremes[d].bound_))
+ if (extremes[d].note_column_)
{
- extremes[d].note_column_ = extremes[d].bound_;
- extremes[d].stem_ = Note_column::get_stem (extremes[d].note_column_);
- extremes[d].stem_dir_ = get_grob_direction (extremes[d].stem_);
- extremes[d].stem_extent_[X_AXIS] = extremes[d].stem_->extent (common[X_AXIS], X_AXIS);
- extremes[d].stem_extent_[Y_AXIS] = extremes[d].stem_->extent (common[Y_AXIS], Y_AXIS);
- extremes[d].slur_head_ = Stem::extremal_heads (extremes[d].stem_)[dir];
- extremes[d].slur_head_extent_ = extremes[d].slur_head_->extent (common[X_AXIS], X_AXIS);
- extremes[d].staff_ = Staff_symbol_referencer::get_staff_symbol (extremes[d].slur_head_);
+ end_ys[d] = dir * ((dir * (base_attachment[d][Y_AXIS] + 4.0 *dir))
+ >? (dir * (dir + extremes[d].note_column_->extent(common[Y_AXIS],Y_AXIS)[dir]))
+ >? (dir * base_attachment[-d][Y_AXIS])
+ );
}
else
{
- extremes[d].neighbor_y_ = broken_trend_y (me, common, d);
+ end_ys[d] = extremes[d].neighbor_y_ + 4.0 * dir ;
}
} while (flip (&d) != LEFT);
-
+
+ return end_ys;
+}
+
+Drul_array<Offset>
+New_slur::get_base_attachments (Spanner*me,
+ Grob **common,
+ Drul_array<Bound_info> extremes)
+{
+ Link_array<Grob> columns =
+ Pointer_group_interface__extract_grobs (me, (Grob*)0, "note-columns");
+ Drul_array<Offset> base_attachment;
+
+
+ Slur_score_parameters params;
+
+ Real staff_space = Staff_symbol_referencer::staff_space ((Grob*)me);
+
+ Direction dir = get_grob_direction (me);
+ Direction d = LEFT;
do
{
Grob *stem = extremes[d].stem_;
if (d== RIGHT)
x = extremes[d].bound_->extent (common[X_AXIS], X_AXIS)[d];
else
- x = sp->get_broken_left_end_align ();
+ x = me->get_broken_left_end_align ();
}
else
{
} while (flip (&d) != LEFT);
-
- Interval end_ys;
- do {
- if (extremes[d].note_column_)
- {
- end_ys[d] = dir * ((dir * (base_attachment[d][Y_AXIS] + 4.0 *dir))
- >? (dir * (dir + extremes[d].note_column_->extent(common[Y_AXIS],Y_AXIS)[dir]))
- >? (dir * base_attachment[-d][Y_AXIS])
- );
- }
- else
- {
- end_ys[d] = extremes[d].neighbor_y_ + 4.0 * dir ;
- }
- } while (flip (&d) != LEFT);
-
+ return base_attachment;
+}
+
+
+
+void
+New_slur::generate_curves (Grob*me, Array<Slur_score> *scores)
+
+{
+
+ Real staff_space = Staff_symbol_referencer::staff_space ((Grob*)me);
+
+ Real r_0 = robust_scm2double (me->get_property ("ratio"), 1);
+ Real h_inf = staff_space * ly_scm2double (me->get_property ("height-limit"));
+ for (int i = scores->size(); i-- ;)
+ {
+ (*scores)[i].curve_ = get_bezier (me, (*scores)[i].attachment_,
+ r_0, h_inf);
+ }
+}
+
+Array<Slur_score>
+New_slur::enumerate_attachments (Grob * me, Grob *common[],
+ Slur_score_parameters * score_param,
+ Drul_array<Bound_info> extremes,
+ Drul_array<Offset> base_attachment,
+ Drul_array<Real> end_ys)
+{
+ /*ugh. */
Array<Slur_score> scores;
+
+ Direction dir = get_grob_direction (me);
+ Real staff_space = Staff_symbol_referencer::staff_space ((Grob*)me);
Drul_array<Offset> os;
-
- /*ugh. */
os[LEFT] = base_attachment[LEFT];
-
+ Real minimum_length = staff_space * robust_scm2double (me->get_property ("minimum-length"),
+ 2.0);
+
for (int i = 0; dir * os[LEFT][Y_AXIS] <= dir * end_ys[LEFT]; i++)
{
os[RIGHT] = base_attachment[RIGHT];
Offset dz = os[RIGHT] - os[LEFT];
if (dz[X_AXIS] < minimum_length
- || fabs (dz[Y_AXIS] / dz[X_AXIS]) > MAX_SLOPE
+ || fabs (dz[Y_AXIS] / dz[X_AXIS]) > score_param->MAX_SLOPE
)
{
do {
os[LEFT][Y_AXIS] += dir * staff_space /2 ;
}
-
- {
- Real r_0 = robust_scm2double (me->get_property ("ratio"), 1);
- Real h_inf = staff_space * ly_scm2double (me->get_property ("height-limit"));
- for (int i = scores.size(); i-- ;)
- {
- scores[i].curve_ = get_bezier (me, scores[i].attachment_,
- r_0, h_inf);
- }
- }
-
- score_edges (me, common, extremes, base_attachment, &scores);
- score_slopes (me, common, extremes, base_attachment, &scores);
- score_encompass (me, common, extremes, base_attachment, &scores);
-
- Real opt = 1e6;
- int opt_idx = 0;
- for (int i = scores.size (); i--;)
- {
- if (scores[i].score_ < opt)
- {
- opt = scores[i].score_;
- opt_idx = i;
- }
- }
-
-
-#if DEBUG_SLUR_QUANTING
- SCM inspect_quants = me->get_property ("inspect-quants");
- if (to_boolean (me->get_paper ()->lookup_variable (ly_symbol2scm ("debug-slur-quanting")))
- && ly_c_pair_p (inspect_quants))
- {
- Drul_array<Real> ins = ly_scm2interval (inspect_quants);
- int i = 0;
-
- Real mindist = 1e6;
- for (; i < scores.size (); i ++)
- {
- Real d =fabs (scores[i].attachment_[LEFT][Y_AXIS] - ins[LEFT])
- + fabs (scores[i].attachment_[RIGHT][Y_AXIS] - ins[RIGHT]);
- if (d < mindist)
- {
- opt_idx = i;
- mindist= d;
- }
- }
- if (mindist > 1e5)
- programming_error ("Could not find quant.");
- }
-
-
- scores[opt_idx].score_card_ += to_string ("i%d", opt_idx);
-
- // debug quanting
- me->set_property ("quant-score",
- scm_makfrom0str (scores[opt_idx].score_card_.to_str0 ()));
-#endif
-
- Bezier const &b = scores[opt_idx].curve_;
-
- SCM controls = SCM_EOL;
- for (int i = 4; i--;)
- {
- Offset o = b.control_[i] -
- Offset (me->relative_coordinate (common[X_AXIS], X_AXIS),
- me->relative_coordinate (common[Y_AXIS], Y_AXIS));
-
- controls = scm_cons (ly_offset2scm (o), controls);
- }
-
- me->set_property ("control-points", controls);
+ return scores;
}
+
void
New_slur::score_encompass (Grob * me, Grob *common[],
+ Slur_score_parameters * score_param,
+
Drul_array<Bound_info> extremes,
Drul_array<Offset> base_attach,
Array<Slur_score> * scores)
Real head_dy = (y - infos[j].head_);
if (dir * head_dy < 0)
{
- demerit += HEAD_ENCOMPASS_PENALTY;
+ demerit += score_param->HEAD_ENCOMPASS_PENALTY;
}
else
{
Real hd =
- (head_dy) ? (1/(fabs (head_dy) - 1/FREE_HEAD_DISTANCE))
- : HEAD_ENCOMPASS_PENALTY;
- hd = (hd >? 0)<? HEAD_ENCOMPASS_PENALTY;
+ (head_dy) ? (1/(fabs (head_dy) - 1/score_param->FREE_HEAD_DISTANCE))
+ : score_param->HEAD_ENCOMPASS_PENALTY;
+ hd = (hd >? 0)<? score_param->HEAD_ENCOMPASS_PENALTY;
demerit += hd;
}
if (dir * (y - infos[j].stem_) < 0)
- demerit += STEM_ENCOMPASS_PENALTY;
+ demerit += score_param->STEM_ENCOMPASS_PENALTY;
else if (j && j < encompasses.size () - 1)
{
Interval ext;
ext.add_point (infos[j].stem_);
ext.add_point (infos[j].head_);
- demerit += - CLOSENESS_FACTOR * (dir * (y - (ext[dir] + dir * HEAD_FREE_SPACE)) <? 0) /
+ demerit += - score_param->CLOSENESS_FACTOR * (dir * (y - (ext[dir] + dir * score_param->FREE_HEAD_DISTANCE)) <? 0) /
infos.size ();
}
}
void
New_slur::score_edges (Grob * me, Grob *common[],
- Drul_array<Bound_info> extremes,
- Drul_array<Offset> base_attach,
- Array<Slur_score> * scores)
+ Slur_score_parameters * score_param,
+
+ Drul_array<Bound_info> extremes,
+ Drul_array<Offset> base_attach,
+ Array<Slur_score> * scores)
{
- Direction dir = get_grob_direction (me);
+ Direction dir = get_grob_direction (me);
for (int i =0 ; i < scores->size (); i++)
{
Real y = scores->elem (i).attachment_[d][Y_AXIS];
Real dy = fabs (y - base_attach[d][Y_AXIS]);
- Real factor = EDGE_ATTRACTION_FACTOR;
+ Real factor = score_param->EDGE_ATTRACTION_FACTOR;
-#if 0
- if (extremes[d].stem_ && extremes[d].stem_dir_ == dir)
- {
- if (!extremes[d].stem_extent_[Y_AXIS].contains (y))
- {
- dy = fabs (extremes[d].stem_extent_[Y_AXIS][dir] - y);
- }
- else
- factor *= 0.3;
- }
- Real demerit = dy * factor;
-#else
Real demerit =
- EDGE_ATTRACTION_FACTOR
+ score_param->EDGE_ATTRACTION_FACTOR
* fabs (scores->elem (i).attachment_[d][Y_AXIS] - base_attach[d][Y_AXIS]);
if (extremes[d].stem_
&& !Stem::get_beaming (extremes[d].stem_, -d)
)
demerit /= 5;
-
-#endif
(*scores)[i].score_ += demerit;
#if DEBUG_SLUR_QUANTING
void
New_slur::score_slopes (Grob * me, Grob *common[],
+ Slur_score_parameters*score_param,
Drul_array<Bound_info> extremes,
Drul_array<Offset> base_attach,
Array<Slur_score> * scores)
Real demerit = 0.0;
if (!has_beams)
- demerit += STEEPER_SLOPE_FACTOR * (dir * (fabs (slur_dy) - fabs (dy)) >? 0);
+ demerit += score_param->STEEPER_SLOPE_FACTOR * (dir * (fabs (slur_dy) - fabs (dy)) >? 0);
- demerit += ((fabs (slur_dy/slur_dz[X_AXIS]) - MAX_SLOPE)>?0) * MAX_SLOPE_FACTOR;
+ demerit += ((fabs (slur_dy/slur_dz[X_AXIS]) - score_param->MAX_SLOPE)>?0) * score_param->MAX_SLOPE_FACTOR;
if (sign (dy) == 0 &&
sign (slur_dy) != 0)
- demerit += NON_HORIZONTAL_PENALTY;
+ demerit += score_param->NON_HORIZONTAL_PENALTY;
if (sign (dy)
&& sign (slur_dy)
&& sign (slur_dy) != sign (dy))
demerit +=
- has_beams ? SAME_SLOPE_PENALTY/10 : SAME_SLOPE_PENALTY;
+ has_beams ? score_param->SAME_SLOPE_PENALTY/10 : score_param->SAME_SLOPE_PENALTY;
#if DEBUG_SLUR_QUANTING
(*scores)[i].score_card_ += to_string ("S%.2f",d);
/*
Ugh should have dash-length + dash-period
- */
+*/
MAKE_SCHEME_CALLBACK (New_slur, print,1);
SCM
New_slur::print (SCM smob)
/*
TODO: replace dashed with generic property.
- */
+ */
SCM d = me->get_property ("dashed");
if (ly_c_number_p (d))
a = Lookup::dashed_slur (one, thick, thick * robust_scm2double (d, 0));
SCM properties = Font_interface::text_font_alist_chain (me);
Stencil tm = *unsmob_stencil (Text_item::interpret_markup
- (me->get_paper ()->self_scm (), properties, quant_score));
+ (me->get_paper ()->self_scm (), properties, quant_score));
a.add_at_edge (Y_AXIS, get_grob_direction (me), tm, 1.0, 0);
}
#endif
ADD_INTERFACE (New_slur, "new-slur-interface",
- "A slur",
- "attachment attachment-offset beautiful control-points dashed details de-uglify-parameters direction extremity-function extremity-offset-alist height-limit note-columns ratio slope-limit thickness y-free");
+ "A slur",
+ "control-points dashed details direction height-limit note-columns ratio slope-limit thickness");