X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=lily%2Fslur-scoring.cc;h=7230c975e9e573a3334e27c23b688f3b8eba105c;hb=e24df7c27635dc996c466295eacf2981bddccaf7;hp=6f91aa9b12895bb6c4cfb72265638d0b2acdfb1b;hpb=d24fed0a5d785a02e40d9f1a19522453f96f1847;p=lilypond.git diff --git a/lily/slur-scoring.cc b/lily/slur-scoring.cc index 6f91aa9b12..7230c975e9 100644 --- a/lily/slur-scoring.cc +++ b/lily/slur-scoring.cc @@ -1,40 +1,40 @@ /* - slur-quanting.cc -- Score based slur formatting + slur-scoring.cc -- Score based slur formatting source file of the GNU LilyPond music typesetter - (c) 1996--2004 Han-Wen Nienhuys + (c) 1996--2005 Han-Wen Nienhuys Jan Nieuwenhuizen */ +#include "slur-scoring.hh" + #include -#include "accidental-interface.hh" +#include "libc-extension.hh" +#include "slur-configuration.hh" #include "beam.hh" #include "directional-element-interface.hh" #include "group-interface.hh" -#include "libc-extension.hh" -#include "lily-guile.hh" #include "slur.hh" #include "note-column.hh" #include "output-def.hh" #include "pitch.hh" -#include "bezier.hh" #include "spanner.hh" #include "staff-symbol-referencer.hh" #include "staff-symbol.hh" #include "stem.hh" #include "warn.hh" #include "paper-column.hh" +#include "accidental-interface.hh" /* TODO: - curve around flag for y coordinate - - this file is a big mess, clean it up + - this file is a mess, clean it up - - short-cut: try a smaller region first. - handle non-visible stems better. @@ -49,317 +49,176 @@ - optimize. */ +struct Slur_score_state; -struct Slur_score +Slur_score_state::Slur_score_state() { - Drul_array attachment_; - Real score_; - Bezier curve_; - -#if DEBUG_SLUR_QUANTING - String score_card_; -#endif - - Slur_score() - { - score_ = 0.0; - } -}; - -struct Slur_score_parameters -{ - int 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 max_slope_; - Real max_slope_factor_; - Real extra_object_collision_; - Real accidental_collision_; - Real free_slur_distance_; - Real free_head_distance_; - Real extra_encompass_free_distance_; - Real edge_slope_exponent_; - Real head_slur_distance_max_ratio_; - Real head_slur_distance_factor_; - - - - Slur_score_parameters (Grob*); -}; - + musical_dy_ = 0.0; + valid_ = false; + edge_has_beams_ = false; + has_same_beam_ = false; + is_broken_ = false; + dir_ = CENTER; + slur_ = 0; + common_[X_AXIS] = 0; + common_[Y_AXIS] = 0; +} -struct Encompass_info -{ - Real x_; - Real stem_; - Real head_; - Encompass_info () - { - x_ = 0.0; - stem_ = 0.0; - head_ = 0.0; - } - Real get_point (Direction dir) - { - Interval y; - y.add_point (stem_); - y.add_point (head_); - return y[dir]; - } -}; - -struct Bound_info +Slur_score_state::~Slur_score_state () { - Box stem_extent_; - Direction stem_dir_; - Item *bound_; - Grob *note_column_; - Grob *slur_head_; - Grob *staff_; - Grob *stem_; - Interval slur_head_extent_; - Real neighbor_y_; - Real staff_space_; - - Bound_info () - { - stem_ = 0; - neighbor_y_ = 0; - staff_ = 0; - slur_head_ = 0; - stem_dir_ = CENTER; - note_column_ = 0; - } -}; - -/* - TODO: create one object for passing all parameters. - */ - - -static void -score_extra_encompass (Grob *me, Grob *common[], - Slur_score_parameters *score_param, - Drul_array , - Drul_array , - Array * scores); -static void score_slopes (Grob *me, Grob *common[], - Slur_score_parameters *score_param, - Drul_array, - Drul_array base_attach, - Array *scores); - -static void score_edges (Grob *me, Grob *common[], - Slur_score_parameters *score_param, - Drul_array extremes, - Drul_array base_attach, - Array *scores); -static void score_encompass (Grob *me, Grob *common[], - Slur_score_parameters*, - Drul_array, - Drul_array, Array *scores); -static Bezier avoid_staff_line (Grob *me, Grob **common, - Drul_array extremes, - Bezier bez); - -static Encompass_info get_encompass_info (Grob *me, - Grob *col, - Grob **common); -static Bezier get_bezier (Grob *me, - Grob **common, - Slur_score_parameters*, - Drul_array extremes, - Drul_array attachments, - Real r_0, Real h_inf); -static Direction get_default_dir (Grob *me); - -static void set_end_points (Grob *); -static Real broken_trend_y (Grob *me, Grob **, Direction dir); -static Drul_array get_bound_info (Spanner *me, Grob **common); - -static void generate_curves (Grob *me, - Grob *common[],Slur_score_parameters*, - Drul_array extremes, - Drul_array base_attach, - Array *scores); -static Array enumerate_attachments -(Grob *me, Grob *common[], Slur_score_parameters*, - Drul_array extremes, - Drul_array base_attachment, Drul_array end_ys); -static Drul_array get_base_attachments -(Spanner *sp, Grob **common, Drul_array extremes); -static Drul_array get_y_attachment_range -(Spanner *sp, Grob **common, - Slur_score_parameters*, - Drul_array extremes, - Drul_array base_attachment); - + junk_pointers (configurations_); +} Real get_detail (SCM alist, SCM sym) { SCM entry = scm_assq (sym, alist); - return robust_scm2double (ly_c_pair_p (entry) - ? ly_cdr (entry) + return robust_scm2double (scm_is_pair (entry) + ? scm_cdr (entry) : SCM_EOL, 0.0); } void -init_score_param (Grob *me, - Slur_score_parameters *score_param) +Slur_score_parameters::fill (Grob *me) { SCM details = me->get_property ("slur-details"); - - score_param->region_size_ + + region_size_ = (int) get_detail (details, ly_symbol2scm ("region-size")); - score_param->head_encompass_penalty_ + head_encompass_penalty_ = get_detail (details, ly_symbol2scm ("head-encompass-penalty")); - score_param->stem_encompass_penalty_ + stem_encompass_penalty_ = get_detail (details, ly_symbol2scm ("stem-encompass-penalty")); - score_param->closeness_factor_ + closeness_factor_ = get_detail (details, ly_symbol2scm ("closeness-factor")); - score_param->edge_attraction_factor_ + edge_attraction_factor_ = get_detail (details, ly_symbol2scm ("edge-attraction-factor")); - score_param->same_slope_penalty_ + same_slope_penalty_ = get_detail (details, ly_symbol2scm ("same-slope-penalty")); - score_param->steeper_slope_factor_ + steeper_slope_factor_ = get_detail (details, ly_symbol2scm ("steeper-slope-factor")); - score_param->non_horizontal_penalty_ + non_horizontal_penalty_ = get_detail (details, ly_symbol2scm ("non-horizontal-penalty")); - score_param->max_slope_ + max_slope_ = get_detail (details, ly_symbol2scm ("max-slope")); - score_param->max_slope_factor_ + max_slope_factor_ = get_detail (details, ly_symbol2scm ("max-slope-factor")); - score_param->free_head_distance_ + free_head_distance_ = get_detail (details, ly_symbol2scm ("free-head-distance")); - score_param->extra_object_collision_ + absolute_closeness_measure_ + = get_detail (details, ly_symbol2scm ("absolute-closeness-measure")); + extra_object_collision_ = get_detail (details, ly_symbol2scm ("extra-object-collision")); - score_param->accidental_collision_ + accidental_collision_ = get_detail (details, ly_symbol2scm ("accidental-collision")); - score_param->extra_encompass_free_distance_ + extra_encompass_free_distance_ = get_detail (details, ly_symbol2scm ("extra-encompass-free-distance")); - score_param->head_slur_distance_factor_ + head_slur_distance_factor_ = get_detail (details, ly_symbol2scm ("head-slur-distance-factor")); - score_param->head_slur_distance_max_ratio_ + head_slur_distance_max_ratio_ = get_detail (details, ly_symbol2scm ("head-slur-distance-max-ratio")); - score_param->free_slur_distance_ + free_slur_distance_ = get_detail (details, ly_symbol2scm ("free-slur-distance")); - score_param->edge_slope_exponent_ + edge_slope_exponent_ = get_detail (details, ly_symbol2scm ("edge-slope-exponent")); } - -Slur_score_parameters::Slur_score_parameters(Grob *me) -{ - init_score_param (me, this); -} - -/* HDIR indicates which side (left or right) we are processing here. */ Real -broken_trend_y (Grob *me, Grob **common, Direction hdir) +broken_trend_y (Slur_score_state const &state, 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 (me->original_)) + if (Spanner *mother = dynamic_cast (state.slur_->original_)) { - int k = broken_spanner_index (dynamic_cast (me)); + int k = broken_spanner_index (state.slur_); 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 (common[Y_AXIS]->original_); + = dynamic_cast (state.common_[Y_AXIS]->original_); int common_k - = broken_spanner_index (dynamic_cast (common[Y_AXIS])); + = broken_spanner_index (dynamic_cast (state.common_[Y_AXIS])); int common_j = common_k + hdir; - if (common_j < 0 || common_j >= common_mother->broken_intos_.size()) + 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 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(vdir)) - - common_next_system->relative_coordinate (neighbor_common, Y_AXIS); - - Link_array 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 (int ((my_cols.size() == 1) ? CENTER : vdir)); - by = (y*neighbor_cols.size() + neighbor_y*my_cols.size()) / - (my_cols.size() + neighbor_cols.size()); + + SCM last_point = scm_car (scm_last_pair (neighbor->get_property ("control-points"))); + + return scm_to_double (scm_cdr (last_point)) + + neighbor->relative_coordinate (common_next_system, Y_AXIS); } return by; } + +/* + copy slur dir forwards across line break. +*/ +void +Slur_score_state::set_next_direction () +{ + if (extremes_[RIGHT].note_column_) + return; + + if (Spanner *mother = dynamic_cast (slur_->original_)) + { + int k = broken_spanner_index (slur_); + int j = k + 1; + if (j < 0 || j >= mother->broken_intos_.size ()) + return; + + Grob *neighbor = mother->broken_intos_[j]; + set_grob_direction (neighbor, dir_); + } +} + Encompass_info -get_encompass_info (Grob *me, - Grob *col, - Grob **common) +Slur_score_state::get_encompass_info (Grob *col) const { Grob *stem = unsmob_grob (col->get_property ("stem")); Encompass_info ei; - Direction dir = get_grob_direction (me); if (!stem) { programming_error ("No stem for note column?"); - ei.x_ = col->relative_coordinate (common[X_AXIS], X_AXIS); - ei.head_ = ei.stem_ = col->extent (common[Y_AXIS], - Y_AXIS)[get_grob_direction (me)]; + ei.x_ = col->relative_coordinate (common_[X_AXIS], X_AXIS); + ei.head_ = ei.stem_ = col->extent (common_[Y_AXIS], + Y_AXIS)[dir_]; return ei; } Direction stem_dir = get_grob_direction (stem); if (Grob *head = Note_column::first_head (col)) - ei.x_ = head->extent (common[X_AXIS], X_AXIS).center (); + ei.x_ = head->extent (common_[X_AXIS], X_AXIS).center (); else - ei.x_ = col->extent (common[X_AXIS], X_AXIS).center (); + ei.x_ = col->extent (common_[X_AXIS], X_AXIS).center (); - Grob *h = Stem::extremal_heads (stem)[Direction (dir)]; + Grob *h = Stem::extremal_heads (stem)[Direction (dir_)]; if (!h) { - ei.head_ = ei.stem_ = col->extent (common[Y_AXIS], Y_AXIS)[dir]; + ei.head_ = ei.stem_ = col->extent (common_[Y_AXIS], Y_AXIS)[dir_]; return ei; } - ei.head_ = h->extent (common[Y_AXIS], Y_AXIS)[dir]; + ei.head_ = h->extent (common_[Y_AXIS], Y_AXIS)[dir_]; - if ((stem_dir == dir) + if ((stem_dir == dir_) && !stem->extent (stem, Y_AXIS).is_empty ()) { - ei.stem_ = stem->extent (common[Y_AXIS], Y_AXIS)[dir]; + 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); - Interval x = stem->extent (common[X_AXIS], X_AXIS); + Interval x = stem->extent (common_[X_AXIS], X_AXIS); ei.x_ = x.is_empty () - ? stem->relative_coordinate (common[X_AXIS], X_AXIS) + ? stem->relative_coordinate (common_[X_AXIS], X_AXIS) : x.center (); } else @@ -369,66 +228,28 @@ get_encompass_info (Grob *me, } -Direction -get_default_dir (Grob*me) -{ - Link_array encompasses - = Pointer_group_interface__extract_grobs (me, (Grob*) 0, "note-columns"); - - Direction d = DOWN; - for (int i= 0; i < encompasses.size (); i ++) - { - if (Note_column::dir (encompasses[i]) < 0) - { - d = UP; - break; - } - } - return d; -} - -MAKE_SCHEME_CALLBACK (Slur, after_line_breaking,1); -SCM -Slur::after_line_breaking (SCM smob) -{ - Spanner *me = dynamic_cast (unsmob_grob (smob)); - if (!scm_ilength (me->get_property ("note-columns"))) - { - me->suicide (); - return SCM_UNSPECIFIED; - } - - if (!get_grob_direction (me)) - set_grob_direction (me, get_default_dir (me)); - - if (scm_ilength (me->get_property ("control-points")) < 4) - set_end_points (me); - - return SCM_UNSPECIFIED; -} - Drul_array -get_bound_info (Spanner* me, Grob **common) +Slur_score_state::get_bound_info () const { Drul_array extremes; - Direction d = RIGHT; - Direction dir = get_grob_direction (me); + Direction d = LEFT; + Direction dir = dir_; do { - extremes[d].bound_ = me->get_bound (d); + extremes[d].bound_ = slur_->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 (common_[X_AXIS], X_AXIS); extremes[d].stem_extent_[Y_AXIS] - = extremes[d].stem_->extent (common[Y_AXIS], Y_AXIS); + = extremes[d].stem_->extent (common_[Y_AXIS], Y_AXIS); extremes[d].slur_head_ = Stem::extremal_heads (extremes[d].stem_)[dir]; if (!extremes[d].slur_head_ @@ -439,146 +260,220 @@ get_bound_info (Spanner* me, Grob **common) if (extremes[d].slur_head_) extremes[d].slur_head_extent_ - = extremes[d].slur_head_->extent (common[X_AXIS], X_AXIS); + = extremes[d].slur_head_->extent (common_[X_AXIS], X_AXIS); extremes[d].staff_ = Staff_symbol_referencer ::get_staff_symbol (extremes[d].stem_); extremes[d].staff_space_ = Staff_symbol_referencer ::staff_space (extremes[d].stem_); } - else if (d == RIGHT) - /* - right side anticipates on the next note. - */ - extremes[d].neighbor_y_ = broken_trend_y (me, common, d); } - while (flip (&d) != RIGHT); + while (flip (&d) != LEFT); return extremes; } void -set_end_points (Grob *me) +Slur_score_state::fill (Grob *me) { - Link_array columns + slur_ = dynamic_cast (me); + columns_ = Pointer_group_interface__extract_grobs (me, (Grob *) 0, "note-columns"); - - if (columns.is_empty ()) + + if (columns_.is_empty ()) { me->suicide (); - return; + return ; } + staff_space_ = Staff_symbol_referencer::staff_space (me); + Real lt = me->get_layout ()->get_dimension (ly_symbol2scm ("linethickness")); + thickness_ = robust_scm2double (me->get_property ("thickness"), 1.0) * lt; + + dir_ = get_grob_direction (me); + parameters_.fill (me); + SCM eltlist = me->get_property ("note-columns"); SCM extra_list = me->get_property ("encompass-objects"); Spanner *sp = dynamic_cast (me); - Grob *common[] = {0, 0}; for (int i = X_AXIS; i < NO_AXES; i++) { Axis a = (Axis)i; - common[a] = common_refpoint_of_list (eltlist, me, a); - common[a] = common_refpoint_of_list (extra_list, common[a], a); + common_[a] = common_refpoint_of_list (eltlist, me, a); + common_[a] = common_refpoint_of_list (extra_list, common_[a], a); + + Direction d = LEFT; + do { + /* + If bound is not in note-columns, we don't want to know about + its Y-position + */ + if (a != Y_AXIS) + common_[a] = common_[a]->common_refpoint (sp->get_bound (d), a); + } + while (flip (&d) != LEFT); } - 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); + extremes_ = get_bound_info (); + is_broken_ = (!extremes_[LEFT].note_column_ + || !extremes_[RIGHT].note_column_); + + has_same_beam_ = + (extremes_[LEFT].stem_ && extremes_[RIGHT].stem_ + && Stem::get_beam (extremes_[LEFT].stem_) == Stem::get_beam (extremes_[RIGHT].stem_)); + + base_attachments_ = get_base_attachments (); - Drul_array extremes = get_bound_info (sp, common); - Drul_array base_attachment - = get_base_attachments (sp, common, extremes); - Slur_score_parameters params (me); Drul_array end_ys - = get_y_attachment_range (sp, common, ¶ms, extremes, base_attachment); - Array scores = enumerate_attachments (me, common, ¶ms, - extremes, base_attachment, - end_ys); - - generate_curves (me, common, ¶ms, extremes, base_attachment, &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); - score_extra_encompass (me, common, ¶ms,extremes, base_attachment, - &scores); + = get_y_attachment_range (); + + configurations_ = enumerate_attachments ( end_ys); + for (int i = 0; i < columns_.size (); i++) + encompass_infos_.push (get_encompass_info ( columns_[i])); + + extra_encompass_infos_ = get_extra_encompass_infos (); + valid_ = true; + + + musical_dy_ = 0.0; + Direction d = LEFT; + do + { + if (!is_broken_) + musical_dy_ += d + * extremes_[d].slur_head_->relative_coordinate (common_[Y_AXIS], Y_AXIS); + } + while (flip (&d) != LEFT); + + edge_has_beams_ + = (extremes_[LEFT].stem_ && Stem::get_beam (extremes_[LEFT].stem_)) + || (extremes_[RIGHT].stem_ && Stem::get_beam (extremes_[RIGHT].stem_)); + + + + set_next_direction (); + + if (is_broken_) + musical_dy_ = 0.0; +} + +void +set_slur_control_points (Grob *me) +{ + Slur_score_state state; + state.fill (me); + + if (!state.valid_) + return; + + state.generate_curves (); + + SCM end_ys = me->get_property ("positions"); + Bezier best; + + if (is_number_pair (end_ys)) + { + best = state.configurations_[state.get_closest_index (end_ys)]->curve_; + } + else + { + best = state.get_best_curve(); + } + + SCM controls = SCM_EOL; + for (int i = 4; i--;) + { + Offset o = best.control_[i] + - Offset (me->relative_coordinate (state.common_[X_AXIS], X_AXIS), + me->relative_coordinate (state.common_[Y_AXIS], Y_AXIS)); + controls = scm_cons (ly_offset2scm (o), controls); + } + me->set_property ("control-points", controls); +} + +Bezier +Slur_score_state::get_best_curve () +{ + for (int i = 0; i < configurations_.size (); i++) + { + configurations_[i]->score (*this); + } + Real opt = 1e6; int opt_idx = -1; - for (int i = 0; i < scores.size (); i++) + for (int i = 0; i < configurations_.size (); i++) { - if (scores[i].score_ < opt) + if (configurations_[i]->score_ < opt) { - opt = scores[i].score_; + opt = configurations_[i]->score_; opt_idx = i; } } -#if DEBUG_SLUR_QUANTING - SCM inspect_quants = me->get_property ("inspect-quants"); - if (to_boolean (me->get_paper () +#if DEBUG_SLUR_SCORING + SCM inspect_quants = slur_->get_property ("inspect-quants"); + if (to_boolean (slur_->get_layout () ->lookup_variable (ly_symbol2scm ("debug-slur-scoring"))) - && ly_c_pair_p (inspect_quants)) - { - Drul_array ins = ly_scm2interval (inspect_quants); - Real mindist = 1e6; - for (int i = 0; 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); + && scm_is_pair (inspect_quants)) + opt_idx = get_closest_index (inspect_quants); + + configurations_[opt_idx]->score_card_ += to_string ("=%.2f", opt); + configurations_[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 ())); + slur_->set_property ("quant-score", + scm_makfrom0str (configurations_[opt_idx]->score_card_.to_str0 ())); + #endif - Bezier b = scores[opt_idx].curve_; - SCM controls = SCM_EOL; - for (int i = 4; i--;) + return configurations_[opt_idx]->curve_; +} + +int +Slur_score_state::get_closest_index (SCM inspect_quants) const +{ + Drul_array ins = ly_scm2interval (inspect_quants); + + int opt_idx = -1; + Real mindist = 1e6; + for (int i = 0; i < configurations_.size (); 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); + Real d = fabs (configurations_[i]->attachment_[LEFT][Y_AXIS] - ins[LEFT]) + + fabs (configurations_[i]->attachment_[RIGHT][Y_AXIS] - ins[RIGHT]); + if (d < mindist) + { + opt_idx = i; + mindist = d; + } } - me->set_property ("control-points", controls); + if (mindist > 1e5) + programming_error ("Could not find quant."); + return opt_idx; } /* TODO: should analyse encompasses to determine sensible region, and - should limit slopes available. + should limit slopes available. */ Drul_array -get_y_attachment_range (Spanner*me, - Grob **common, Slur_score_parameters *score_param, - Drul_array extremes, - Drul_array base_attachment) +Slur_score_state::get_y_attachment_range () const { Drul_array end_ys; - Direction dir = get_grob_direction (me); Direction d = LEFT; do { - if (extremes[d].note_column_) + if (extremes_[d].note_column_) { - end_ys[d] = dir - * ((dir * (base_attachment[d][Y_AXIS] + score_param->region_size_* dir)) - >? (dir * (dir + extremes[d].note_column_->extent(common[Y_AXIS], - Y_AXIS)[dir])) - >? (dir * base_attachment[-d][Y_AXIS])); + end_ys[d] = dir_ + * ((dir_ * (base_attachments_[d][Y_AXIS] + parameters_.region_size_* dir_)) + >? (dir_ * (dir_ + extremes_[d].note_column_->extent (common_[Y_AXIS], + Y_AXIS)[dir_])) + >? (dir_ * base_attachments_[-d][Y_AXIS])); } else - end_ys[d] = base_attachment[d][Y_AXIS] + score_param->region_size_ * dir; + end_ys[d] = base_attachments_[d][Y_AXIS] + parameters_.region_size_ * dir_; } while (flip (&d) != LEFT); @@ -594,7 +489,7 @@ spanner_less (Spanner *s1, Spanner* s2) { b1[d] = s1->get_bound (d)->get_column ()->rank_; b2[d] = s2->get_bound (d)->get_column ()->rank_; - } while (flip (&d) != LEFT); + } while (flip (&d) != LEFT); return b2[LEFT] <= b1[LEFT] && b2[RIGHT] >= b1[RIGHT] && (b2[LEFT] != b1[LEFT] || b2[RIGHT] != b1[RIGHT]); @@ -602,206 +497,156 @@ spanner_less (Spanner *s1, Spanner* s2) Drul_array -get_base_attachments (Spanner *me, - Grob **common, Drul_array extremes) +Slur_score_state::get_base_attachments () const { - Link_array columns - = Pointer_group_interface__extract_grobs (me, (Grob *)0, "note-columns"); Drul_array base_attachment; - Real staff_space = Staff_symbol_referencer::staff_space ((Grob *) me); - Direction dir = get_grob_direction (me); - Direction d = RIGHT; + Direction d = LEFT; do { - Grob *stem = extremes[d].stem_; - Grob *head = extremes[d].slur_head_; + Grob *stem = extremes_[d].stem_; + Grob *head = extremes_[d].slur_head_; - Real x, y; - if (!extremes[d].note_column_) + Real x = 0.0; + Real y = 0.0; + if (extremes_[d].note_column_) { - if (d == RIGHT) - { - y = extremes[d].neighbor_y_; - x = extremes[d].bound_->extent (common[X_AXIS], X_AXIS)[d]; - } - else - { - x = me->get_broken_left_end_align (); - if (extremes[RIGHT].bound_ == columns[0]) - { - y = base_attachment[RIGHT][Y_AXIS]; - } - else - { - y = columns[0]->extent (common[Y_AXIS], Y_AXIS)[dir]; - } - } - } - else - { - bool same_beam = - (extremes[d].stem_ && extremes[-d].stem_ - && Stem::get_beam (extremes[d].stem_) == Stem::get_beam (extremes[-d].stem_)); - + /* fixme: X coord should also be set in this case. */ if (stem - && extremes[d].stem_dir_ == dir + && extremes_[d].stem_dir_ == dir_ && Stem::get_beaming (stem, -d) - && (!spanner_less (me, Stem::get_beam (stem)) - || same_beam)) - y = extremes[d].stem_extent_[Y_AXIS][dir]; + && (!spanner_less (slur_, Stem::get_beam (stem)) + || has_same_beam_)) + 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 - = (y - extremes[d].staff_->relative_coordinate (common[Y_AXIS], - Y_AXIS)) - * 2.0 / Staff_symbol::staff_space (extremes[d].staff_); - - /* start off staffline. */ - if (fabs (pos - my_round (pos)) < 0.2 - && Staff_symbol_referencer::on_staffline (head, (int) rint (pos)) - && Staff_symbol_referencer::line_count (head) - 1 >= rint (pos) - ) - // TODO: calc from slur thick & line thick, parameter. - y += 1.5 * staff_space * dir / 10; + y = head->extent (common_[Y_AXIS], Y_AXIS)[dir_]; + y += dir_ * 0.5 * staff_space_; + + + y = move_away_from_staffline (y, head); - Grob * fh = Note_column::first_head (extremes[d].note_column_); + Grob * fh = Note_column::first_head (extremes_[d].note_column_); x = - (fh ? fh->extent (common[X_AXIS], X_AXIS) - : extremes[d].bound_->extent (common[X_AXIS], X_AXIS)) + (fh ? fh->extent (common_[X_AXIS], X_AXIS) + : extremes_[d].bound_->extent (common_[X_AXIS], X_AXIS)) .linear_combination (CENTER); } base_attachment[d] = Offset (x, y); - } while (flip (&d) != RIGHT); + } while (flip (&d) != LEFT); + + do + { + if (!extremes_[d].note_column_) + { + Real x, y; + if (d == RIGHT) + { + x = extremes_[d].bound_->extent (common_[X_AXIS], X_AXIS)[d]; + } + else + { + x = slur_->get_broken_left_end_align (); + } + Grob * col = (d == LEFT) ? columns_[0] : columns_.top(); + + if (extremes_[-d].bound_ != col) + { + y = robust_relative_extent (col, common_[Y_AXIS], Y_AXIS)[dir_]; + y += dir_ * 0.5 * staff_space_; + + if (get_grob_direction (col) == dir_ + && Note_column::get_stem (col) + && !Stem::is_invisible (Note_column::get_stem (col))) + y -= dir_ * 1.5 * staff_space_; + } + else + y = base_attachment[-d][Y_AXIS]; + + + y = move_away_from_staffline (y, col); + + base_attachment[d] = Offset (x, y); + } + } + while (flip (&d) != LEFT); return base_attachment; } -void -generate_curves (Grob *me, Grob **common, - Slur_score_parameters *score_param, - Drul_array extremes, - Drul_array, - Array *scores) +Real +Slur_score_state::move_away_from_staffline (Real y, + Grob *on_staff) const { - (void) common; - (void) extremes; - Real staff_space = Staff_symbol_referencer::staff_space ((Grob *) me); - Real r_0 = robust_scm2double (me->get_property ("ratio"), 0.33); - Real h_inf = staff_space * scm_to_double (me->get_property ("height-limit")); - for (int i = 0; i < scores->size(); i++) - { - Bezier bez = get_bezier (me, - common, - score_param, - extremes, - (*scores)[i].attachment_, r_0, h_inf); - - bez = avoid_staff_line (me, common, extremes, bez); - (*scores)[i].attachment_[LEFT] = bez.control_[0]; - (*scores)[i].attachment_[RIGHT] = bez.control_[3]; - (*scores)[i].curve_ = bez; - } + Real pos + = (y - Staff_symbol_referencer::get_staff_symbol (on_staff)->relative_coordinate (common_[Y_AXIS], + Y_AXIS)) + * 2.0 / staff_space_; + + if (fabs (pos - my_round (pos)) < 0.2 + && Staff_symbol_referencer::on_staffline (on_staff, (int) rint (pos)) + && Staff_symbol_referencer::line_count (on_staff) - 1 >= rint (pos) + ) + y += 1.5 * staff_space_ * dir_ / 10; + + return y; } -Bezier -avoid_staff_line (Grob *me, Grob **common, - Drul_array extremes, - Bezier bez) +void +Slur_score_state::generate_curves () const { - Offset horiz (1,0); - Array ts = bez.solve_derivative (horiz); - Real lt = me->get_paper ()->get_dimension (ly_symbol2scm ("linethickness")); - Real thick = robust_scm2double (me->get_property ("thickness"), 1.0) * lt; - - /* TODO: handle case of broken slur. */ - if (!ts.is_empty () - && (extremes[LEFT].staff_ == extremes[RIGHT].staff_) - && extremes[LEFT].staff_ && extremes[RIGHT].staff_) - { - Real y = bez.curve_point (ts[0])[Y_AXIS]; - - Grob *staff = extremes[LEFT].staff_; + Real r_0 = robust_scm2double (slur_->get_property ("ratio"), 0.33); + Real h_inf = staff_space_ *scm_to_double (slur_->get_property ("height-limit")); + for (int i = 0; i < configurations_.size (); i++) + configurations_[i]->generate_curve (*this, r_0, h_inf); +} - Real staff_space = extremes[LEFT].staff_space_; - Real p = 2 * (y - staff->relative_coordinate (common[Y_AXIS], Y_AXIS)) - / staff_space; - Real distance = fabs (my_round (p) - p); // in halfspaces - if (distance < 4 * thick - && (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)) - { - Direction resolution_dir = - (distance ? get_grob_direction (me) : Direction (sign (p - my_round(p)))); - // TODO: parameter - Real newp = my_round (p) + resolution_dir - * 5 * thick; - - Real dy = (newp - p) * staff_space / 2.0; - - bez.control_[1][Y_AXIS] += dy; - bez.control_[2][Y_AXIS] += dy; - } - } - return bez; -} -Array -enumerate_attachments (Grob *me, Grob *common[], - Slur_score_parameters *score_param, - Drul_array extremes, - Drul_array base_attachment, - Drul_array end_ys) +Link_array +Slur_score_state::enumerate_attachments (Drul_array end_ys) const { - (void) common; /*ugh. */ - Array scores; + Link_array scores; - Direction dir = get_grob_direction (me); - Real staff_space = Staff_symbol_referencer::staff_space ((Grob *) me); Drul_array os; - os[LEFT] = base_attachment[LEFT]; - Real minimum_length = staff_space - * robust_scm2double (me->get_property ("minimum-length"), 2.0); + os[LEFT] = base_attachments_[LEFT]; + Real minimum_length = staff_space_ + * robust_scm2double (slur_->get_property ("minimum-length"), 2.0); - for (int i = 0; dir * os[LEFT][Y_AXIS] <= dir * end_ys[LEFT]; i++) + 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++) + os[RIGHT] = base_attachments_[RIGHT]; + for (int j = 0; dir_ * os[RIGHT][Y_AXIS] <= dir_ * end_ys[RIGHT]; j++) { - Slur_score s; + Slur_configuration s; Direction d = LEFT; Drul_array attach_to_stem (false, false); 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) + os[d][X_AXIS] = base_attachments_[d][X_AXIS]; + if (extremes_[d].stem_ + && !Stem::is_invisible (extremes_[d].stem_) + && extremes_[d].stem_dir_ == dir_) { - if (dir == -d - && extremes[d].stem_extent_[Y_AXIS].contains (os[d][Y_AXIS])) + Interval stem_y = extremes_[d].stem_extent_[Y_AXIS]; + stem_y.widen (0.25 * staff_space_); + if (stem_y.contains (os[d][Y_AXIS])) { - os[d][X_AXIS] = extremes[d].slur_head_extent_[-d] + os[d][X_AXIS] = extremes_[d].stem_extent_[X_AXIS][-d] - d * 0.3; attach_to_stem[d] = true; } - else if (dir *extremes[d].stem_extent_[Y_AXIS][dir] - < dir * os[d][Y_AXIS] - && !extremes[d].stem_extent_[X_AXIS].is_empty() + else if (dir_ * extremes_[d].stem_extent_[Y_AXIS][dir_] + < dir_ * os[d][Y_AXIS] + && !extremes_[d].stem_extent_[X_AXIS].is_empty () ) - - os[d][X_AXIS] = extremes[d].stem_extent_[X_AXIS].center(); + + os[d][X_AXIS] = extremes_[d].stem_extent_[X_AXIS].center (); } } while (flip (&d) != LEFT); @@ -809,14 +654,14 @@ enumerate_attachments (Grob *me, Grob *common[], Offset dz; dz = os[RIGHT] - os[LEFT]; if (dz[X_AXIS] < minimum_length - || fabs (dz[Y_AXIS] / dz[X_AXIS]) > score_param->max_slope_ + || fabs (dz[Y_AXIS] / dz[X_AXIS]) > parameters_.max_slope_ ) { do { - if (extremes[d].slur_head_) + if (extremes_[d].slur_head_) { - os[d][X_AXIS] = extremes[d].slur_head_extent_.center (); + os[d][X_AXIS] = extremes_[d].slur_head_extent_.center (); attach_to_stem[d] = false; } } @@ -826,244 +671,42 @@ enumerate_attachments (Grob *me, Grob *common[], dz = os[RIGHT] - os[LEFT]; do { - if (extremes[d].slur_head_ + if (extremes_[d].slur_head_ && !attach_to_stem[d]) { /* Horizontally move tilted slurs a little. Move more for bigger tilts. - + TODO: parameter */ os[d][X_AXIS] - -= dir * extremes[d].slur_head_extent_.length () - * sin (dz.arg ()) / 3; + -= dir_ * extremes_[d].slur_head_extent_.length () + * sin (dz.arg ()) / 3; } } while (flip (&d) != LEFT); - + s.attachment_ = os; - scores.push (s); - - os[RIGHT][Y_AXIS] += dir * staff_space / 2; - } - - os[LEFT][Y_AXIS] += dir * staff_space / 2; - } - - assert (scores.size() > 0); - return scores; -} - -inline Real -linear_interpolate (Real x, Real x1, Real x2, Real y1, Real y2) -{ - return (x2 - x) / (x2 - x1) * y1 + - (x - x1) / (x2 - x1) * y2 ; -} - + s.index_ = scores.size (); -void -score_encompass (Grob *me, Grob *common[], - Slur_score_parameters *score_param, - Drul_array extremes, - Drul_array base_attach, - Array *scores) -{ - (void) extremes; - (void) base_attach; - - Link_array encompasses - = Pointer_group_interface__extract_grobs (me, (Grob *)0, "note-columns"); - Direction dir = get_grob_direction (me); - - Array infos; - - 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++) - { - Slur_score &configuration = scores->elem_ref (i); - Bezier const &bez (configuration.curve_); - Real demerit = 0.0; - - /* - Distances for heads that are between slur and line between - attachment points. - */ - Array convex_head_distances; - Array edge_distances; - for (int j = 0; j < infos.size(); j++) - { - Real x = infos[j].x_; - - bool l_edge = j==0; - bool r_edge = j==infos.size()-1; - bool edge = l_edge || r_edge; - - - if (edge) - { - edge_distances.push (fabs (configuration.attachment_[l_edge ? LEFT : RIGHT][Y_AXIS] - - infos[j].get_point (dir))); - } + scores.push (new Slur_configuration (s)); - - if (!(x < configuration.attachment_[RIGHT][X_AXIS] - && x > configuration.attachment_[LEFT][X_AXIS])) - continue; - - Real y = bez.get_other_coordinate (X_AXIS, x); - if (!edge) - { - Real head_dy = (y - infos[j].head_); - if (dir * head_dy < 0) - { - demerit += score_param->head_encompass_penalty_; - convex_head_distances.push (0.0); - } - else - { - Real hd = (head_dy) - ? (1 / fabs (head_dy) - 1 / score_param->free_head_distance_) - : score_param->head_encompass_penalty_; - hd = (hd >? 0)head_encompass_penalty_; - - demerit += hd; - } - - Real line_y = linear_interpolate (x, - configuration.attachment_[RIGHT][X_AXIS], - configuration.attachment_[LEFT][X_AXIS], - configuration.attachment_[RIGHT][Y_AXIS], - configuration.attachment_[LEFT][Y_AXIS]); - - if ( 1 ) // dir * infos[j].get_point (dir) > dir *line_y ) - { - - Real closest = - dir * (dir * infos[j].get_point (dir) - >? dir *line_y - ); - Real d = fabs(closest - y); - - convex_head_distances.push (d); - } - } - - - - if (dir * (y - infos[j].stem_) < 0) - { - Real stem_dem =score_param->stem_encompass_penalty_ ; - if ((l_edge && dir == UP) - || (r_edge && dir == DOWN)) - stem_dem /= 5; - - demerit += stem_dem; - } - else if (!edge) - { - Interval ext; - ext.add_point (infos[j].stem_); - ext.add_point (infos[j].head_); - - // ? - demerit += -score_param->closeness_factor_ - * (dir - * (y - (ext[dir] + dir * score_param->free_head_distance_)) - head_slur_distance_max_ratio_; - if (min_dist > 0.0) - variance_penalty = ((avg_distance / (min_dist +score_param->free_head_distance_)) - 1.0) - head_slur_distance_factor_; + os[RIGHT][Y_AXIS] += dir_ * staff_space_ / 2; } -#if DEBUG_SLUR_QUANTING - (*scores)[i].score_card_ += to_string ("C%.2f", demerit); - (*scores)[i].score_card_ += to_string ("D%.2f", variance_penalty); -#endif - (*scores)[i].score_ += demerit + variance_penalty; + os[LEFT][Y_AXIS] += dir_ * staff_space_ / 2; } + + assert (scores.size () > 0); + return scores; } -struct Extra_collision_info -{ - Real idx_; - Box extents_; - Real penalty_; - - Extra_collision_info (Real idx, Interval x, Interval y, Real p) - { - idx_ = idx; - extents_[X_AXIS] = x; - extents_[Y_AXIS] = y; - penalty_ = p; - } - Extra_collision_info () - { - idx_ = 0.0; - penalty_ = 0.; - } -}; -void -score_extra_encompass (Grob *me, Grob *common[], - Slur_score_parameters *score_param, - Drul_array extremes, - Drul_array base_attach, - Array *scores) +Array +Slur_score_state::get_extra_encompass_infos () const { - (void) base_attach; - (void) extremes; - - Spanner *me_spanner = dynamic_cast (me); - Link_array encompasses - = Pointer_group_interface__extract_grobs (me, (Grob *)0, + = Pointer_group_interface__extract_grobs (slur_, (Grob *)0, "encompass-objects"); - Direction dir = get_grob_direction (me); - Real lt = me->get_paper ()->get_dimension (ly_symbol2scm ("linethickness")); - Real thick = robust_scm2double (me->get_property ("thickness"), 1.0) * lt; - Array collision_infos; for (int i = encompasses.size (); i--; ) { @@ -1072,48 +715,48 @@ score_extra_encompass (Grob *me, Grob *common[], Spanner * small_slur = dynamic_cast (encompasses[i]); Bezier b = Slur::get_curve (small_slur); - Offset relative (small_slur->relative_coordinate (common[X_AXIS], X_AXIS), - small_slur->relative_coordinate (common[Y_AXIS], Y_AXIS)); + Offset relative (small_slur->relative_coordinate (common_[X_AXIS], X_AXIS), + small_slur->relative_coordinate (common_[Y_AXIS], Y_AXIS)); for (int k = 0; k < 3; k++) - { - Direction hdir = Direction (k /2 - 1); - - /* - Only take bound into account if small slur starts - together with big slur. - */ - if (hdir && small_slur->get_bound (hdir) != me_spanner->get_bound (hdir)) - continue; - + { + Direction hdir = Direction (k /2 - 1); - Offset z = b.curve_point ( k / 2.0); - z += relative; - - Interval yext; - yext.set_full(); - yext[dir] = z[Y_AXIS] + dir * thick * 1.0; - - Interval xext(-1, 1); - xext = xext *(thick*2) + z[X_AXIS]; - Extra_collision_info info (k - 1.0, - xext, - yext, - score_param->extra_object_collision_); - collision_infos.push (info); - } + /* + Only take bound into account if small slur starts + together with big slur. + */ + if (hdir && small_slur->get_bound (hdir) != slur_->get_bound (hdir)) + continue; + + Offset z = b.curve_point (k / 2.0); + z += relative; + + Interval yext; + yext.set_full (); + yext[dir_] = z[Y_AXIS] + dir_ * thickness_ * 1.0; + + Interval xext (-1, 1); + xext = xext * (thickness_*2) + z[X_AXIS]; + Extra_collision_info info (small_slur, + k - 1.0, + xext, + yext, + parameters_.extra_object_collision_); + collision_infos.push (info); + } } else { Grob *g = encompasses [i]; - Interval xe = g->extent (common[X_AXIS], X_AXIS); - Interval ye = g->extent (common[Y_AXIS], Y_AXIS); + Interval xe = g->extent (common_[X_AXIS], X_AXIS); + Interval ye = g->extent (common_[Y_AXIS], Y_AXIS); Real xp = 0.0; - Real penalty = score_param->extra_object_collision_; + Real penalty = parameters_.extra_object_collision_; if (Accidental_interface::has_interface (g)) { - penalty = score_param->accidental_collision_; + penalty = parameters_.accidental_collision_; /* Begin copy accidental.cc */ bool parens = false; if (to_boolean (g->get_property ("cautionary"))) @@ -1129,313 +772,29 @@ score_extra_encompass (Grob *me, Grob *common[], && scm_ilength (accs) == 1) { /* End copy accidental.cc */ - switch (scm_to_int (ly_car (accs))) + switch (scm_to_int (scm_car (accs))) { case FLAT: case DOUBLE_FLAT: xp = LEFT; break ; case SHARP: - xp = 0.5 * dir; + xp = 0.5 * dir_; break ; case NATURAL: - xp = -dir; - break; + xp = -dir_; + break; } } } - ye.widen (thick * 0.5); - xe.widen (thick * 1.0); - Extra_collision_info info (xp, xe, ye, penalty); + ye.widen (thickness_ * 0.5); + xe.widen (thickness_ * 1.0); + Extra_collision_info info (g, xp, xe, ye, penalty); collision_infos.push (info); } } - for (int i = 0; i < scores->size (); i++) - { - Real demerit = 0.0; - for (int j = 0; j < collision_infos.size(); j++) - { - Drul_array attachment = scores->elem (i).attachment_; - Interval slur_wid (attachment[LEFT][X_AXIS], attachment[RIGHT][X_AXIS]); - - /* - to prevent numerical inaccuracies in - Bezier::get_other_coordinate(). - */ - Direction d = LEFT; - bool found = false; - Real y = 0.0; - - do - { - if (collision_infos[j].extents_[X_AXIS].contains (attachment[d][X_AXIS])) - { - y = attachment[d][Y_AXIS]; - found = true; - } - } - while (flip (&d) != LEFT); - - if (!found) - { - - Real x = collision_infos[j].extents_[X_AXIS] - .linear_combination (collision_infos[j].idx_); - - if (!slur_wid.contains (x)) - continue; - - y = scores->elem (i).curve_.get_other_coordinate (X_AXIS, x); - } - - Real dist = collision_infos[j].extents_[Y_AXIS].distance (y); - demerit += - fabs (0 >? (score_param->extra_encompass_free_distance_ - dist)) / - score_param->extra_encompass_free_distance_ - * collision_infos[j].penalty_; - } -#if DEBUG_SLUR_QUANTING - (*scores)[i].score_card_ += to_string ("X%.2f", demerit); -#endif - (*scores)[i].score_ += demerit; - } -} - -/* - TODO: should make edge penalties dependent on the direction that the - slur-end is pointing. - */ -void -score_edges (Grob *me, Grob *common[], - Slur_score_parameters * score_param, - Drul_array extremes, - Drul_array base_attach, - Array *scores) -{ - (void) common; - Direction dir = get_grob_direction (me); - for (int i = 0; i < scores->size (); i++) - { - Direction d = LEFT; - Slur_score &config = scores->elem_ref (i); - Offset dz = config.attachment_[RIGHT] - config.attachment_[LEFT]; - Real slope = dz[Y_AXIS] / dz[X_AXIS]; - do - { - Real y = config.attachment_[d][Y_AXIS]; - Real dy = fabs (y - base_attach[d][Y_AXIS]); - - Real factor = score_param->edge_attraction_factor_; - Real demerit = factor * dy; - if (extremes[d].stem_ - && extremes[d].stem_dir_ == dir - && !Stem::get_beaming (extremes[d].stem_, -d) - ) - demerit /= 5; - - demerit *= exp (dir * d * slope - * score_param->edge_slope_exponent_ ); - - (*scores)[i].score_ += demerit; -#if DEBUG_SLUR_QUANTING - (*scores)[i].score_card_ += to_string ("E%.2f", demerit); -#endif - } - while (flip (&d) != LEFT); - } + return collision_infos; } -void -score_slopes (Grob *me, Grob *common[], - Slur_score_parameters *score_param, - Drul_array extremes, - Drul_array base_attach, - Array * scores) -{ - (void) me; - (void) base_attach; - - Drul_array ys; - Direction d = LEFT; - do - { - 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++) - { - Offset slur_dz = (*scores)[i].attachment_[RIGHT] - - (*scores)[i].attachment_[LEFT]; - Real slur_dy = slur_dz[Y_AXIS]; - Real demerit = 0.0; - - demerit += ((fabs (slur_dy / slur_dz[X_AXIS]) - - score_param->max_slope_) >? 0) - * score_param->max_slope_factor_; - - /* 0.2: account for staffline offset. */ - Real max_dy = (fabs (dy) + 0.2); - if (has_beams) - max_dy += 1.0; - - demerit += score_param->steeper_slope_factor_ - * ((fabs (slur_dy) -max_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 += score_param->non_horizontal_penalty_; - - if (sign (dy) - && sign (slur_dy) - && sign (slur_dy) != sign (dy)) - demerit += 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); -#endif - (*scores)[i].score_ += demerit; - } - - - -} - - -Real -fit_factor (Offset dz_unit, Offset dz_perp, - Bezier curve, Direction d, Array const &avoid) -{ - Real fit_factor = 0.0; - Offset x0 = curve.control_[0]; - curve.translate (-x0); - curve.rotate (-dz_unit.arg ()); - curve.scale (1, d); - - Interval curve_xext; - curve_xext.add_point (curve.control_[0][X_AXIS]); - curve_xext.add_point (curve.control_[3][X_AXIS]); - - for (int i = 0; i < avoid.size (); i++) - { - Offset z = (avoid[i] - x0) ; - Offset p (dot_product (z, dz_unit), - d* dot_product (z, dz_perp)); - if (!curve_xext.contains (p[X_AXIS])) - continue; - - Real y = curve.get_other_coordinate (X_AXIS, p[X_AXIS]); - if (y) - { - fit_factor = fit_factor >? (p[Y_AXIS] / y); - } - } - return fit_factor; -} - - -Bezier -get_bezier (Grob *me, - Grob **common, - Slur_score_parameters *score_param, - Drul_array extremes, - Drul_array attachments, - Real r_0, Real h_inf - ) -{ - Link_array encompasses - = Pointer_group_interface__extract_grobs (me, (Grob *)0, "note-columns"); - Direction dir = get_grob_direction (me); - - Array avoid; - for (int i = 0; i < encompasses.size(); i++) - { - if (extremes[LEFT].note_column_ == encompasses[i] - ||extremes[RIGHT].note_column_ == encompasses[i]) - continue; - - Encompass_info inf (get_encompass_info (me, encompasses[i], common)); - - Real y = dir*((dir * inf.head_) >? (dir *inf.stem_)); - - avoid.push (Offset (inf.x_, y + dir * score_param->free_head_distance_)); - } - - Link_array extra_encompasses - = Pointer_group_interface__extract_grobs (me, (Grob *)0, "encompass-objects"); - for (int i = 0; i < extra_encompasses.size (); i++) - if (Slur::has_interface (extra_encompasses[i])) - { - Grob * small_slur = extra_encompasses[i]; - Bezier b = Slur::get_curve (small_slur); - - Offset z = b.curve_point (0.5); - z += Offset (small_slur->relative_coordinate (common[X_AXIS], X_AXIS), - small_slur->relative_coordinate (common[Y_AXIS], Y_AXIS)); - - z[Y_AXIS] += dir * score_param->free_slur_distance_; - avoid.push (z); - } - - Offset dz = attachments[RIGHT]- attachments[LEFT];; - Offset dz_unit = dz; - dz_unit *= 1 / dz.length(); - Offset dz_perp = dz_unit * Offset(0,1); - - Real indent, height; - get_slur_indent_height (&indent, &height, dz.length (), h_inf, r_0); - - Real excentricity = robust_scm2double (me->get_property ("excentricity"), 0.0); - Bezier curve; - - Real x1 = (excentricity + indent); - Real x2 = (excentricity - indent); - curve.control_[0] = attachments[LEFT]; - curve.control_[1] = attachments[LEFT] + dz_perp * height * dir + dz_unit * x1; - curve.control_[2] = attachments[RIGHT] + dz_perp * height * dir + dz_unit * x2; - curve.control_[3] = attachments[RIGHT]; - - - Real ff = fit_factor (dz_unit, dz_perp, curve, dir, avoid); - Real l = dz.length (); - - /* - This condition, - - l^2 > 4h^2 + 3(i 1/3l)^2 - 1/3 l^2 - - is equivalent to: - - |bez'(0)| < | bez'(.5)| - - when (control2-control1) has the same direction as (control3 - - control0). - - */ - Real max_h = sqrt (sqr (l)/3 - .75 * sqr (indent + l / 3)); - height = height >? ((height * ff)