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>
*/
#include <math.h>
+#include "main.hh"
#include "font-interface.hh"
#include "text-item.hh"
#include "directional-element-interface.hh"
#include "stem.hh"
#include "stencil.hh"
#include "warn.hh"
+#include "beam.hh"
/*
TODO:
- curve around flag/stem for x coordinate
- better scoring.
- */
-
+*/
struct Encompass_info {
Real x_;
Real stem_;
}
};
+struct Bound_info {
+
+ Box stem_extent_;
+ Direction stem_dir_;
+ Grob *bound_;
+ Grob *note_column_;
+ Grob *slur_head_;
+ Grob *staff_;
+ Grob *stem_;
+ Interval slur_head_extent_;
+ Real neighbor_y_;
+
+ Bound_info () {
+ stem_ = 0;
+ neighbor_y_ = 0;
+ staff_ = 0;
+ slur_head_ = 0;
+ stem_dir_ = CENTER;
+ note_column_ = 0;
+ }
+};
+
/*
- 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;
+ 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
public:
static void add_column (Grob *me, Grob *col);
DECLARE_SCHEME_CALLBACK (print, (SCM));
- static void score_slopes (Grob * me, Grob *common[], Drul_array<Offset> base_attach,
+ 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_encompass (Grob * me, Grob *common[],
- Drul_array<Offset>, Array<Slur_score> * scores);
+ static void score_edges (Grob * me, Grob *common[],
+ 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 Offset broken_trend_offset (Grob *me, 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 Real broken_trend_y (Grob *me, Grob**, Direction dir);
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
+New_slur::broken_trend_y (Grob *me, Grob**common, Direction hdir)
+{
+ /*
+ A broken slur should maintain the same vertical trend
+ the unbroken slur would have had.
+ */
+ Real by = 0.0;
+ if (Spanner *mother = dynamic_cast<Spanner*> (me->original_))
+ {
+ int k = broken_spanner_index (dynamic_cast<Spanner*> (me));
+ int j = k + hdir;
+ if (j < 0 || j >= mother->broken_intos_.size ())
+ return by;
+
+ Grob *neighbor = mother->broken_intos_[j];
+ if (hdir == RIGHT)
+ neighbor->set_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]));
+ int common_j = common_k + hdir;
+
+ if (common_j < 0 || common_j >= common_mother->broken_intos_.size())
+ return by;
+
+
+ Grob *common_next_system = common_mother->broken_intos_[common_j];
+ Link_array<Grob> neighbor_cols =
+ Pointer_group_interface__extract_grobs (neighbor, (Grob*)0, "note-columns");
+
+ Grob * neighbor_col = (hdir == RIGHT) ? neighbor_cols[0] : neighbor_cols.top ();
+ Grob * neighbor_common = common_next_system->common_refpoint (neighbor_col, Y_AXIS);
+
+ Direction vdir = get_grob_direction (me);
+ Real neighbor_y =
+ neighbor_col->extent (neighbor_common, Y_AXIS)
+ .linear_combination (int(neighbor_cols.size()==1 ? CENTER : vdir))
+ - common_next_system->relative_coordinate (neighbor_common, Y_AXIS);
+
+ Link_array<Grob> my_cols =
+ Pointer_group_interface__extract_grobs (me, (Grob*)0, "note-columns");
+
+ Grob *extreme_col = (hdir == RIGHT) ? my_cols.top() : my_cols[0];
+ Real y = extreme_col->extent (common[Y_AXIS], Y_AXIS).linear_combination (vdir);
+
+ by = (y*neighbor_cols.size() + neighbor_y*my_cols.size()) /
+ (my_cols.size() + neighbor_cols.size());
+ }
+ return by;
+}
+
void
New_slur::set_interface (Grob*me)
{
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"));
{
programming_error ("No stem for note column?");
ei.x_ = col->relative_coordinate (common[X_AXIS], X_AXIS);
- ei.head_ = ei.stem_ = col->relative_coordinate (common[Y_AXIS], Y_AXIS);
+ ei.head_ = ei.stem_ = col->extent (common[Y_AXIS], Y_AXIS)[get_grob_direction (me)];
return ei;
}
Direction stem_dir = get_grob_direction (stem);
Grob * h = Stem::extremal_heads (stem)[Direction (dir)];
if (!h)
{
- ei.head_ = ei.stem_ = col->relative_coordinate (common[Y_AXIS], Y_AXIS);
+ ei.head_ = ei.stem_ = col->extent (common[Y_AXIS], Y_AXIS)[dir];
return ei;
}
&& !stem->extent (stem, Y_AXIS).is_empty ())
{
ei.stem_ = stem->extent (common[Y_AXIS], Y_AXIS)[dir];
+ if (Grob * b = Stem::get_beam (stem))
+ {
+ ei.stem_ += stem_dir * 0.5 *Beam::get_thickness (b);
+ }
+
}
else
ei.stem_ = ei.head_;
set_grob_direction (me, get_default_dir (me));
- if (!Note_column::has_interface (me->get_bound (LEFT))
- || !Note_column::has_interface (me->get_bound (RIGHT)))
- me->suicide (); // fixme.
-
set_end_points (me);
return SCM_UNSPECIFIED;
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);
- Drul_array<Grob *> extremes (columns[0], columns.top ());
- Direction dir = get_grob_direction (me);
-
- 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 (RIGHT), X_AXIS);
common[X_AXIS] = common[X_AXIS]->common_refpoint (sp->get_bound (LEFT), X_AXIS);
- Direction d = LEFT;
- Drul_array<Grob*> staves;
-
- do {
- Grob *stem = Note_column::get_stem (extremes[d]);
- Grob * h = Stem::extremal_heads (stem)[Direction (dir)];
- staves[d] = Staff_symbol_referencer::get_staff_symbol (h);
- common[Y_AXIS] = common[Y_AXIS]->common_refpoint (staves[d], Y_AXIS);
- } while (flip (&d) != LEFT);
-
- do
+ 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--;)
{
- // c&p
- Grob *stem = Note_column::get_stem (extremes[d]);
- Grob * h = Stem::extremal_heads (stem)[dir];
-
- Real y;
-
- if (stem
- && get_grob_direction (stem) == dir
- && Stem::get_beam (stem))
+ if (scores[i].score_ < opt)
{
- y = stem->extent (common[Y_AXIS], Y_AXIS)[dir];
+ opt = scores[i].score_;
+ opt_idx = i;
}
- else
+ }
+
+#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 ++)
{
- y = h->extent (common[Y_AXIS], Y_AXIS)[dir];
+ 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);
+ }
- y += dir * 0.5 * staff_space;
+ me->set_property ("control-points", controls);
+}
- Grob * staff = Staff_symbol_referencer::get_staff_symbol (h);
- Real pos = 2.0 * (y - staff->relative_coordinate (common[Y_AXIS], Y_AXIS)) / Staff_symbol::staff_space (staff);
-
- /*
- start off staffline.
- */
- if (fabs (pos - round (pos)) < 0.2
- && Staff_symbol_referencer::on_staffline (h, (int) rint (pos)))
- y += staff_space * dir / 10 ;
+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 {
+ 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);
-
-
- Grob * fh = Note_column::first_head (extremes[d]);
- Real x = fh->extent (common[X_AXIS], X_AXIS).linear_combination (CENTER);
+ return end_ys;
+}
- if (get_grob_direction (stem) == dir
- && dir == -d)
+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_;
+ Grob *head = extremes[d].slur_head_;
+
+ Real x,y;
+ if (!extremes[d].note_column_)
{
- x -= d * fh->extent(fh, X_AXIS).length ();
+ y = extremes[d].neighbor_y_;
+ if (d== RIGHT)
+ x = extremes[d].bound_->extent (common[X_AXIS], X_AXIS)[d];
+ else
+ x = me->get_broken_left_end_align ();
+ }
+ else
+ {
+ if (stem
+ && extremes[d].stem_dir_ == dir
+ && Stem::get_beaming (stem, -d)
+ && columns.size () > 2
+ )
+ {
+ y = extremes[d].stem_extent_[Y_AXIS][dir];
+ }
+ else if (head)
+ {
+ y = head->extent (common[Y_AXIS], Y_AXIS)[dir];
+ }
+ y += dir * 0.5 * staff_space;
+
+ Real pos = 2.0 * (y - extremes[d].staff_->relative_coordinate (common[Y_AXIS], Y_AXIS))
+ / Staff_symbol::staff_space (extremes[d].staff_);
+
+ /*
+ start off staffline.
+ */
+ if (fabs (pos - round (pos)) < 0.2
+ && Staff_symbol_referencer::on_staffline (head, (int) rint (pos))
+ && Staff_symbol_referencer::line_count (head) -1 >= rint (pos)
+ )
+ y += staff_space * dir / 10 ;
+
+ Grob * fh = Note_column::first_head (extremes[d].note_column_);
+ x = fh->extent (common[X_AXIS], X_AXIS).linear_combination (CENTER);
}
-
base_attachment[d] = Offset (x, y);
} while (flip (&d) != LEFT);
- Drul_array<Real> staff_offsets;
- Interval end_ys;
+ return base_attachment;
+}
- do {
- staff_offsets[d] = staves[d]->relative_coordinate (common[Y_AXIS], Y_AXIS);
- end_ys[d] = dir * ((dir * (base_attachment[d][Y_AXIS] + 4.0 *dir)) >?
- (dir * (dir + extremes[d]->extent(common[Y_AXIS],Y_AXIS)[dir])));
- } while (flip (&d) != LEFT);
-
+
+
+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];
-
- for (int i = 0; dir * os[LEFT][Y_AXIS] < dir * end_ys[LEFT]; i++)
+ 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];
- for (int j = 0; dir *os[RIGHT][Y_AXIS] < dir * end_ys[RIGHT]; j++)
+ for (int j = 0; dir *os[RIGHT][Y_AXIS] <= dir * end_ys[RIGHT]; j++)
{
Slur_score s;
- s.attachment_ = os;
+ Direction d = LEFT;
+
+ do {
+ os[d][X_AXIS] = base_attachment[d][X_AXIS];
+ if (extremes[d].stem_
+ && !Stem::is_invisible (extremes[d].stem_)
+ && extremes[d].stem_dir_ == dir
+ && dir == -d)
+ {
+ if (extremes[d].stem_extent_[Y_AXIS].contains (os[d][Y_AXIS]))
+ {
+ os[d][X_AXIS] = extremes[d].slur_head_extent_[-d]
+ - d * 0.3;
+ }
+ else if (dir *extremes[d].stem_extent_[Y_AXIS][dir] < dir * os[d][Y_AXIS])
+ {
+ os[d][X_AXIS] = extremes[d].stem_extent_[X_AXIS].center();
+ }
+ }
+ } while (flip (&d) != LEFT);
+
+ Offset dz = os[RIGHT] - os[LEFT];
+ if (dz[X_AXIS] < minimum_length
+ || fabs (dz[Y_AXIS] / dz[X_AXIS]) > score_param->MAX_SLOPE
+ )
+ {
+ do {
+ if (extremes[d].slur_head_)
+ os[d][X_AXIS] = extremes[d].slur_head_extent_.center ();
+ } while (flip (&d) != LEFT);
+ }
+
+ s.attachment_ = os;
scores.push (s);
-
- Real incr = dir * staff_space;
- if (Staff_symbol_referencer::staff_radius (staves[RIGHT])
- < fabs ((os[RIGHT][Y_AXIS] - staff_offsets[RIGHT]) / staff_space))
- incr /= 2;
-
- os[RIGHT][Y_AXIS] += incr;
+
+ os[RIGHT][Y_AXIS] += dir * staff_space / 2;
}
- Real incr = dir * staff_space;
- if (Staff_symbol_referencer::staff_radius (staves[LEFT])
- < fabs ((os[LEFT][Y_AXIS] - staff_offsets[LEFT]) / staff_space))
- incr /= 2;
-
- os[LEFT][Y_AXIS] += incr;
- }
-
- {
- 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_encompass (me, common, base_attachment, &scores);
- score_slopes (me, common, 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;
- }
- }
-
- 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);
+ os[LEFT][Y_AXIS] += dir * staff_space /2 ;
}
- me->set_property ("control-points", controls);
-
-#if DEBUG_SLUR_QUANTING
- 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
-
+ return scores;
}
+
void
-New_slur::score_encompass (Grob * me, Grob *common[], Drul_array<Offset> base_attach,
+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)
{
Link_array<Grob> encompasses =
Array<Encompass_info> infos;
- int first = 1;
- int last = encompasses.size () - 2;
-
- for (int i = first; i <= last; i++)
+ for (int i = 0; i < encompasses.size(); i++)
infos.push (get_encompass_info (me, encompasses[i], common));
-
+
for (int i =0 ; i < scores->size (); i++)
{
Bezier const &bez (scores->elem (i).curve_);
Real x = infos[j].x_;
if (!(x < scores->elem (i).attachment_[RIGHT][X_AXIS]
- &&x > scores->elem (i).attachment_[LEFT][X_AXIS]))
+ && x > scores->elem (i).attachment_[LEFT][X_AXIS]))
continue;
Real y = bez.get_other_coordinate (X_AXIS, x);
- if (dir * (y - infos[j].head_) < 0)
- demerit += HEAD_ENCOMPASS_PENALTY;
-
+ if (j && j < infos.size () -1)
+ {
+ Real head_dy = (y - infos[j].head_);
+ if (dir * head_dy < 0)
+ {
+ demerit += score_param->HEAD_ENCOMPASS_PENALTY;
+ }
+ else
+ {
+ Real hd =
+ (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;
- else
+ 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 ();
}
}
- Direction d = LEFT;
- do {
- demerit +=
- EDGE_ATTRACTION_FACTOR
- * fabs (scores->elem (i).attachment_[d][Y_AXIS] - base_attach[d][Y_AXIS]);
- } while (flip (&d) != LEFT);
-
#if DEBUG_SLUR_QUANTING
- (*scores)[i].score_card_ += to_string ("E%.2f", demerit);
+ (*scores)[i].score_card_ += to_string ("C%.2f", demerit);
#endif
(*scores)[i].score_ += demerit;
void
-New_slur::score_slopes (Grob * me, Grob *common[], Drul_array<Offset> base_attach,
- Array<Slur_score> * scores)
+New_slur::score_edges (Grob * me, Grob *common[],
+ Slur_score_parameters * score_param,
+
+ Drul_array<Bound_info> extremes,
+ Drul_array<Offset> base_attach,
+ Array<Slur_score> * scores)
{
- Link_array<Grob> columns =
- Pointer_group_interface__extract_grobs (me, (Grob*)0, "note-columns");
+ Direction dir = get_grob_direction (me);
+
+ for (int i =0 ; i < scores->size (); i++)
+ {
+
+ Direction d = LEFT;
+ do {
+ Real y = scores->elem (i).attachment_[d][Y_AXIS];
+ Real dy = fabs (y - base_attach[d][Y_AXIS]);
+
+ Real factor = score_param->EDGE_ATTRACTION_FACTOR;
+
+ Real demerit =
+ score_param->EDGE_ATTRACTION_FACTOR
+ * fabs (scores->elem (i).attachment_[d][Y_AXIS] - base_attach[d][Y_AXIS]);
+
+ if (extremes[d].stem_
+ && extremes[d].stem_dir_ == dir
+ && !Stem::get_beaming (extremes[d].stem_, -d)
+ )
+ demerit /= 5;
+
+ (*scores)[i].score_ += demerit;
+#if DEBUG_SLUR_QUANTING
+ (*scores)[i].score_card_ += to_string ("E%.2f", demerit);
+#endif
+ } while (flip (&d) != LEFT);
+ }
+}
- Drul_array<Grob *> extremes (columns[0], columns.top ());
+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)
+{
Direction dir = get_grob_direction (me);
Drul_array<Real> ys;
Direction d = LEFT;
- Drul_array<Direction> stem_dirs;
- Drul_array<bool> beams;
do {
- Grob *stem = Note_column::get_stem (extremes [d]);
- ys[d] = Stem::extremal_heads (stem)[Direction (dir)]
- ->relative_coordinate (common[Y_AXIS], Y_AXIS);
- stem_dirs[d] = get_grob_direction (stem);
- beams[d] = Stem::get_beam (stem);
+ if (extremes[d].slur_head_)
+ ys[d] = extremes[d].slur_head_ ->relative_coordinate (common[Y_AXIS], Y_AXIS);
+ else
+ ys[d] = extremes[d].neighbor_y_;
} while (flip (&d) != LEFT);
+ bool has_beams =
+ (extremes[LEFT].stem_ && Stem::get_beam (extremes[LEFT].stem_))
+ || (extremes[RIGHT].stem_ && Stem::get_beam (extremes[RIGHT].stem_));
Real dy = ys[RIGHT] - ys[LEFT];
for (int i =0 ; i < scores->size (); i++)
{
- Real slur_dy = (*scores)[i].attachment_[RIGHT][Y_AXIS]
- - (*scores)[i].attachment_[LEFT][Y_AXIS];
+ Offset slur_dz = (*scores)[i].attachment_[RIGHT]
+ - (*scores)[i].attachment_[LEFT];
+
+ Real slur_dy = slur_dz[Y_AXIS];
+
Real demerit = 0.0;
+ if (!has_beams)
+ /*
+ 0.2: account for staffline offset.
+ */
+ demerit += score_param->STEEPER_SLOPE_FACTOR * (dir * (fabs (slur_dy) - fabs (dy + 0.2)) >? 0);
- if(! (beams[LEFT] || beams[RIGHT]))
- demerit += STEEPER_SLOPE_FACTOR * (dir * (fabs (slur_dy) - fabs (dy)) >? 0);
+ 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 +=
- (beams[LEFT] || beams[RIGHT])
- ? 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 ?
- */
MAKE_SCHEME_CALLBACK (New_slur, height, 2);
SCM
New_slur::height (SCM smob, SCM ax)
/*
Ugh should have dash-length + dash-period
- */
+*/
MAKE_SCHEME_CALLBACK (New_slur, print,1);
SCM
New_slur::print (SCM smob)
Real ss = Staff_symbol_referencer::staff_space (me);
Bezier one = get_curve (me);
- // get_curve may suicide
- if (!scm_ilength (me->get_property ("note-columns")))
- return SCM_EOL;
-
Stencil a;
/*
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));
#if DEBUG_SLUR_QUANTING
SCM quant_score = me->get_property ("quant-score");
- if (// debug_beam_quanting_flag &&
+
+ if (to_boolean (me->get_paper ()->lookup_variable (ly_symbol2scm ("debug-slur-quanting"))) &&
ly_c_string_p (quant_score))
{
String str;
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");