X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=lily%2Ftie-formatting-problem.cc;h=a55f31373519f6519131a5c5fd76bb8724c55cdd;hb=424dee2dd114c4b69c3b58d2ef61e310e5d492f8;hp=f1fc92244123ee8c64f8e00dbf32f8c9caa69b1e;hpb=849ed54c1a272dac222d975e3c8d3e532aaa8f27;p=lilypond.git diff --git a/lily/tie-formatting-problem.cc b/lily/tie-formatting-problem.cc index f1fc922441..a55f313735 100644 --- a/lily/tie-formatting-problem.cc +++ b/lily/tie-formatting-problem.cc @@ -9,10 +9,11 @@ #include "tie-formatting-problem.hh" +#include "paper-column.hh" #include "bezier.hh" #include "directional-element-interface.hh" -#include "item.hh" #include "libc-extension.hh" +#include "misc.hh" #include "note-head.hh" #include "rhythmic-head.hh" #include "spanner.hh" @@ -22,15 +23,6 @@ #include "tie.hh" #include "warn.hh" -/* - 0 at threshold, 1 at 0, with 1/x falloff. - */ -Real peak_around (Real epsilon, Real threshold, Real x) -{ - if (x < 0) - return 1.0; - return max (- epsilon * (x - threshold) / ((x + epsilon) * threshold), 0.0); -} void Tie_formatting_problem::print_ties_configuration (Ties_configuration const *ties) @@ -47,13 +39,18 @@ Tie_formatting_problem::print_ties_configuration (Ties_configuration const *ties } Interval -Tie_formatting_problem::get_attachment (Real y) const +Tie_formatting_problem::get_attachment (Real y, Drul_array columns) const { - Interval attachments; + Interval attachments (0,0); Direction d = LEFT; do { - attachments[d] = skyline_height (chord_outlines_[d], y, -d); + Tuple2 key (columns[d], int (d)); + Chord_outline_map::const_iterator i (chord_outlines_.find (key)); + if (i == chord_outlines_.end ()) + programming_error ("Can't find chord outline"); + else + attachments[d] = i->second.height (y); } while (flip (&d) != LEFT); @@ -73,8 +70,9 @@ Tie_formatting_problem::~Tie_formatting_problem () } void -Tie_formatting_problem::set_chord_outline (vector bounds, - Direction dir) +Tie_formatting_problem::set_column_chord_outline (vector bounds, + Direction dir, + int column_rank) { Real staff_space = Staff_symbol_referencer::staff_space (bounds[0]); @@ -87,7 +85,7 @@ Tie_formatting_problem::set_chord_outline (vector bounds, Grob *head = bounds[i]; if (!Note_head::has_interface (head)) continue; - + if (!stem) stem = unsmob_grob (head->get_object ("stem")); @@ -115,16 +113,7 @@ Tie_formatting_problem::set_chord_outline (vector bounds, } } - chord_outlines_[dir] = empty_skyline (-dir); - if (bounds[0]->break_status_dir ()) - { - Real x = robust_relative_extent (bounds[0], x_refpoint_, X_AXIS)[-dir]; - chord_outlines_[dir].at (0).height_ = x; - } - - for (vsize i = 0; i < boxes.size (); i++) - insert_extent_into_skyline (&chord_outlines_[dir] , - boxes[i], Y_AXIS, -dir); + Tuple2 key (column_rank, int (dir)); if (stem && !Stem::is_invisible (stem)) @@ -138,19 +127,34 @@ Tie_formatting_problem::set_chord_outline (vector bounds, Direction stemdir = get_grob_direction (stem); y.add_point (Stem::head_positions (stem)[-stemdir] * staff_space * .5); - - insert_extent_into_skyline (&chord_outlines_[dir], Box (x,y), Y_AXIS, -dir); - stem_extents_[dir].unite (Box (x,y)); + boxes.push_back (Box (x, y)); + + stem_extents_[key].unite (Box (x,y)); if (dir == LEFT) { Box flag_box = Stem::get_translated_flag (stem).extent_box (); flag_box.translate( Offset (x[RIGHT], X_AXIS)); - insert_extent_into_skyline (&chord_outlines_[dir], flag_box, - Y_AXIS, -dir); + boxes.push_back (flag_box); } } + else if (stem) + { + Grob *head = Stem::support_head (stem); + + /* + In case of invisible stem, don't pass x-center of heads. + */ + Real x_center = head->extent (x_refpoint_, X_AXIS).center (); + Interval x_ext; + x_ext[-dir] = x_center; + Interval y_ext; + for (vsize j = 0; j < head_boxes.size (); j++) + y_ext.unite (head_boxes[j][Y_AXIS]); + + boxes.push_back (Box (x_ext, y_ext)); + } Direction updowndir = DOWN; do @@ -167,19 +171,61 @@ Tie_formatting_problem::set_chord_outline (vector bounds, } if (!x.is_empty ()) - insert_extent_into_skyline (&chord_outlines_[dir], - Box (x,y), - Y_AXIS, -dir); + boxes.push_back (Box (x, y)); } while (flip (&updowndir) != DOWN); - - head_extents_[dir].set_empty (); + + /* todo: the horizon_padding is somewhat arbitrary */ + chord_outlines_[key] = Skyline (boxes, 0.1, Y_AXIS, -dir); + if (bounds[0]->break_status_dir ()) + { + Real x = robust_relative_extent (bounds[0], x_refpoint_, X_AXIS)[-dir]; + chord_outlines_[key].set_minimum_height (x); + } + else + { + Interval x; + for (vsize j = 0; j < head_boxes.size (); j++) + { + x.unite (head_boxes[j][X_AXIS]); + } + + chord_outlines_[key].set_minimum_height (x[dir]); + } + + head_extents_[key].set_empty (); for (vsize i = 0; i < head_boxes.size (); i++) { - head_extents_[dir].unite (head_boxes[i]); + head_extents_[key].unite (head_boxes[i]); } } +void +Tie_formatting_problem::set_chord_outline (vector bounds, + Direction dir) + +{ + vector ranks; + for (vsize i = 0; i < bounds.size (); i++) + ranks.push_back (bounds[i]->get_column ()->get_rank ()); + + vector_sort (ranks, less ()); + uniq (ranks); + + for (vsize i = 0; i < ranks.size (); i++) + { + vector col_items; + for (vsize j = 0; j < bounds.size (); j ++) + { + if (bounds[j]->get_column ()->get_rank () == ranks[i]) + col_items.push_back (bounds[j]); + } + + set_column_chord_outline (col_items, dir, ranks[i]); + } +} + + void Tie_formatting_problem::from_tie (Grob *tie) @@ -232,38 +278,36 @@ Tie_formatting_problem::from_ties (vector const &ties) for (vsize i = 0; i < ties.size (); i++) { Tie_specification spec; + + spec.get_tie_manual_settings (ties[i]); - if (scm_is_number (ties[i]->get_property_data (ly_symbol2scm ("direction")))) - { - spec.manual_dir_ = to_dir (ties[i]->get_property ("direction")); - spec.has_manual_dir_ = true; - } - - spec.position_ = Tie::get_position (ties[i]); + do { spec.note_head_drul_[d] = Tie::head (ties[i], d); + spec.column_ranks_[d] = + dynamic_cast (ties[i])->get_bound (d)->get_column ()->get_rank (); } while (flip (&d) != LEFT); - specifications_.push_back (spec); } } void -Tie_formatting_problem::from_lv_ties (vector const &lv_ties) +Tie_formatting_problem::from_semi_ties (vector const &semi_ties, Direction head_dir) { - if (lv_ties.empty ()) + if (semi_ties.empty ()) return; - details_.from_grob (lv_ties[0]); + details_.from_grob (semi_ties[0]); vector heads; - - for (vsize i = 0; i < lv_ties.size (); i++) + + int column_rank = -1; + for (vsize i = 0; i < semi_ties.size (); i++) { Tie_specification spec; - Item *head = unsmob_item (lv_ties[i]->get_object ("note-head")); + Item *head = unsmob_item (semi_ties[i]->get_object ("note-head")); if (!head) programming_error ("LV tie without head?!"); @@ -273,31 +317,29 @@ Tie_formatting_problem::from_lv_ties (vector const &lv_ties) spec.position_ = int (Staff_symbol_referencer::get_position (head)); } - spec.note_head_drul_[LEFT] = head; + spec.get_tie_manual_settings (semi_ties[i]); + + spec.note_head_drul_[head_dir] = head; + column_rank = dynamic_cast (head)->get_column ()->get_rank (); + spec.column_ranks_ = Drul_array (column_rank, column_rank); heads.push_back (head); specifications_.push_back (spec); } - x_refpoint_ = lv_ties [0]; - for (vsize i = 0; i < lv_ties.size (); i++) - x_refpoint_ = lv_ties[i]->common_refpoint (x_refpoint_, X_AXIS); + x_refpoint_ = semi_ties [0]; + for (vsize i = 0; i < semi_ties.size (); i++) + x_refpoint_ = semi_ties[i]->common_refpoint (x_refpoint_, X_AXIS); for (vsize i = 0; i < heads.size (); i++) x_refpoint_ = heads[i]->common_refpoint (x_refpoint_, X_AXIS); - set_chord_outline (heads, LEFT); + set_chord_outline (heads, head_dir); - Real right_most = - infinity_f; + Tuple2 head_key (column_rank, head_dir); + Tuple2 open_key (column_rank, -head_dir); + Real extremal = chord_outlines_[head_key].max_height (); - for (vsize i = 0; i < chord_outlines_[LEFT].size (); i++) - { - right_most = max (right_most, chord_outlines_[LEFT][i].height_); - } - - Skyline_entry right_entry; - right_entry.width_.set_full (); - right_entry.height_ = right_most + 1.5; - - chord_outlines_[RIGHT].push_back (right_entry); + chord_outlines_[open_key] = Skyline (head_dir); + chord_outlines_[open_key].set_minimum_height (extremal - head_dir * 1.5); } @@ -308,54 +350,61 @@ Tie_formatting_problem::get_tie_specification (int i) const } +/* + Return configuration, create it if necessary. +*/ Tie_configuration* -Tie_formatting_problem::get_configuration (int pos, Direction dir) const +Tie_formatting_problem::get_configuration (int pos, Direction dir, Drul_array columns) const { - pair key (pos, dir); + int key_components[] = { + pos, dir, columns[LEFT], columns[RIGHT] + }; + Tuple key (key_components); + Tie_configuration_map::const_iterator f = possibilities_.find (key); - if (f != possibilities_.end ()) { return (*f).second; } - Tie_configuration *conf = generate_configuration (pos, dir); + Tie_configuration *conf = generate_configuration (pos, dir, columns); ((Tie_formatting_problem*) this)->possibilities_[key] = conf; return conf; } Tie_configuration* -Tie_formatting_problem::generate_configuration (int pos, Direction dir) const +Tie_formatting_problem::generate_configuration (int pos, Direction dir, + Drul_array columns) const { Tie_configuration *conf = new Tie_configuration; conf->position_ = pos; conf->dir_ = dir; + + conf->column_ranks_ = columns; + Real y = conf->position_ * 0.5 * details_.staff_space_; - bool y_tune = true; if (dot_positions_.find (pos) != dot_positions_.end ()) { - conf->delta_y_ += 0.25 * details_.staff_space_; + conf->delta_y_ += dir * 0.25 * details_.staff_space_; y_tune = false; } - - if (y_tune - && max (fabs (head_extents_[LEFT][Y_AXIS][dir] - y), - fabs (head_extents_[RIGHT][Y_AXIS][dir] - y)) < 0.25 + && max (fabs (get_head_extent (columns[LEFT], LEFT, Y_AXIS)[dir] - y), + fabs (get_head_extent (columns[RIGHT], RIGHT, Y_AXIS)[dir] - y)) < 0.25 && !Staff_symbol_referencer::on_line (details_.staff_symbol_referencer_, pos)) { conf->delta_y_ = - (head_extents_[LEFT][Y_AXIS][dir] - y) + (get_head_extent (columns[LEFT], LEFT, Y_AXIS)[dir] - y) + dir * details_.outer_tie_vertical_gap_; } if (y_tune) { - conf->attachment_x_ = get_attachment (y + conf->delta_y_); + conf->attachment_x_ = get_attachment (y + conf->delta_y_, conf->column_ranks_); Real h = conf->height (details_); /* @@ -398,7 +447,7 @@ Tie_formatting_problem::generate_configuration (int pos, Direction dir) const } } - conf->attachment_x_ = get_attachment (y + conf->delta_y_); + conf->attachment_x_ = get_attachment (y + conf->delta_y_, conf->column_ranks_); if (conf->height (details_) < details_.intra_space_threshold_ * 0.5 * details_.staff_space_) { /* @@ -408,29 +457,60 @@ Tie_formatting_problem::generate_configuration (int pos, Direction dir) const Interval close_by = get_attachment (y + conf->delta_y_ + (dir * details_.intra_space_threshold_ * 0.25 - * details_.staff_space_)); + * details_.staff_space_), + conf->column_ranks_); conf->attachment_x_.intersect (close_by); } conf->attachment_x_.widen ( - details_.x_gap_); - Direction d = LEFT; - do + if (conf->column_span_length ()) { - Real y = conf->position_ * details_.staff_space_ * 0.5 + conf->delta_y_; - if (stem_extents_[d][X_AXIS].is_empty () - || !stem_extents_[d][Y_AXIS].contains (y)) - continue; + /* + avoid the stems that we attach to as well. We don't do this + for semities (span length = 0) - conf->attachment_x_[d] = - d* min (d * conf->attachment_x_[d], - d * (stem_extents_[d][X_AXIS][-d] - d * details_.stem_gap_)); - } - while (flip (&d) != LEFT); + It would be better to check D against HEAD-DIRECTION if + applicable. + */ + Direction d = LEFT; + do + { + Real y = conf->position_ * details_.staff_space_ * 0.5 + conf->delta_y_; + if (get_stem_extent (conf->column_ranks_[d], d, X_AXIS).is_empty () + || !get_stem_extent (conf->column_ranks_[d], d, Y_AXIS).contains (y)) + continue; + + conf->attachment_x_[d] = + d * min (d * conf->attachment_x_[d], + d * (get_stem_extent (conf->column_ranks_[d], d, X_AXIS)[-d] - d * details_.stem_gap_)); + } + while (flip (&d) != LEFT); + } return conf; } +Interval +Tie_formatting_problem::get_head_extent (int col, Direction d, Axis a) const +{ + Column_extent_map::const_iterator i = head_extents_.find (Tuple2 (col, int (d))); + if (i != head_extents_.end ()) + return (*i).second[a]; + else + return Interval (); +} + +Interval +Tie_formatting_problem::get_stem_extent (int col, Direction d, Axis a) const +{ + Column_extent_map::const_iterator i = stem_extents_.find (Tuple2 (col, int (d))); + if (i != stem_extents_.end ()) + return (*i).second[a]; + else + return Interval (); +} + /** TIE_IDX and TIES_CONF are optional. */ @@ -562,7 +642,17 @@ Tie_formatting_problem::find_optimal_tie_configuration (Tie_specification const for (int i = 0; i < details_.single_tie_region_size_; i ++) { - confs.push_back (generate_configuration (pos + i * dir, dir)); + confs.push_back (generate_configuration (pos + i * dir, dir, + spec.column_ranks_)); + + if (spec.has_manual_position_) + { + confs.back ()->delta_y_ + = (spec.manual_position_ - spec.position_) + * 0.5 * details_.staff_space_; + + break; + } } vector scores; @@ -582,7 +672,12 @@ Tie_formatting_problem::find_optimal_tie_configuration (Tie_specification const } } - Tie_configuration best = *confs[best_idx]; + if (best_idx < 0) + programming_error ("No best tie configuration found."); + + Tie_configuration best + = (best_idx >= 0) ? *confs[best_idx] : *confs[0]; + for (vsize i = 0; i < confs.size (); i++) delete confs[i]; @@ -598,9 +693,35 @@ Tie_specification::Tie_specification () manual_dir_ = CENTER; note_head_drul_[LEFT] = note_head_drul_[RIGHT] = 0; + column_ranks_[RIGHT] = + column_ranks_[LEFT] = 0; } +void +Tie_specification::get_tie_manual_settings (Grob *tie) +{ + if (scm_is_number (tie->get_property_data ("direction"))) + { + manual_dir_ = to_dir (tie->get_property ("direction")); + has_manual_dir_ = true; + } + + position_ = Tie::get_position (tie); + if (scm_is_number (tie->get_property ("staff-position"))) + { + manual_position_ = scm_to_double (tie->get_property ("staff-position")); + has_manual_position_ = true; + position_ = int (my_round (manual_position_)); + } +} + +int +Tie_specification::column_span () const +{ + return column_ranks_[RIGHT] - column_ranks_[LEFT]; +} + void Tie_formatting_problem::score_ties_aptitude (Ties_configuration *ties) const { @@ -691,7 +812,8 @@ Tie_formatting_problem::generate_ties_configuration (Ties_configuration const &t Ties_configuration copy; for (vsize i = 0; i < ties_config.size (); i++) { - Tie_configuration * ptr = get_configuration (ties_config[i].position_, ties_config[i].dir_); + Tie_configuration * ptr = get_configuration (ties_config[i].position_, ties_config[i].dir_, + ties_config[i].column_ranks_); if (specifications_[i].has_manual_position_) { ptr->delta_y_ @@ -723,6 +845,8 @@ Tie_formatting_problem::generate_base_chord_configuration () { conf.position_ = specifications_[i].position_; } + + conf.column_ranks_ = specifications_[i].column_ranks_; ties_config.push_back (conf); } @@ -768,7 +892,6 @@ Tie_formatting_problem::find_best_variation (Ties_configuration const &base, Ties_configuration Tie_formatting_problem::generate_optimal_chord_configuration () { - Ties_configuration base = generate_base_chord_configuration (); vector vars = generate_collision_variations (base); @@ -785,9 +908,16 @@ Tie_formatting_problem::set_ties_config_standard_directions (Ties_configuration { if (tie_configs->empty ()) return ; - + if (!tie_configs->at (0).dir_) - tie_configs->at (0).dir_ = DOWN; + { + if (tie_configs->size () == 1) + tie_configs->at (0).dir_ = Direction (sign (tie_configs->at (0).position_)); + + if (!tie_configs->at (0).dir_) + tie_configs->at (0).dir_ = DOWN; + } + if (!tie_configs->back ().dir_) tie_configs->back ().dir_ = UP; @@ -796,10 +926,19 @@ Tie_formatting_problem::set_ties_config_standard_directions (Ties_configuration */ for (vsize i = 1; i < tie_configs->size (); i++) { - Real diff = (tie_configs->at (i-1).position_ - - tie_configs->at (i).position_); - - if (fabs (diff) <= 1) + Real diff = (tie_configs->at (i).position_ + -tie_configs->at (i-1).position_); + + Real span_diff + = specifications_[i].column_span () - specifications_[i-1].column_span (); + if (span_diff && fabs (diff) <= 2) + { + if (span_diff > 0) + tie_configs->at (i).dir_ = UP; + else if (span_diff < 0) + tie_configs->at (i-1).dir_ = DOWN; + } + else if (fabs (diff) <= 1) { if (!tie_configs->at (i-1).dir_) tie_configs->at (i-1).dir_ = DOWN; @@ -843,7 +982,8 @@ Tie_formatting_problem::generate_extremal_tie_variations (Ties_configuration con Tie_configuration_variation var; var.index_ = (d == DOWN) ? 0 : ties.size () - 1; var.suggestion_ = get_configuration (boundary (ties, d, 0).position_ - + d * i, d); + + d * i, d, + boundary (ties, d, 0).column_ranks_); vars.push_back (var); } } @@ -876,7 +1016,10 @@ Tie_formatting_problem::generate_collision_variations (Ties_configuration const var.index_ = i; var.suggestion_ = get_configuration (specifications_[i].position_ - ties[i].dir_, - -ties[i].dir_); + - ties[i].dir_, + + ties[i].column_ranks_ + ); vars.push_back (var); } @@ -887,7 +1030,8 @@ Tie_formatting_problem::generate_collision_variations (Ties_configuration const var.index_ = i-1; var.suggestion_ = get_configuration (specifications_[i-1].position_ - ties[i-1].dir_, - - ties[i-1].dir_); + - ties[i-1].dir_, + specifications_[i-1].column_ranks_); vars.push_back (var); } @@ -897,8 +1041,8 @@ Tie_formatting_problem::generate_collision_variations (Ties_configuration const { Tie_configuration_variation var; var.index_ = i-1; - var.suggestion_ = get_configuration (specifications_[i-1].position_ - - 1, DOWN); + var.suggestion_ = get_configuration (specifications_[i-1].position_ - 1, DOWN, + specifications_[i-1].column_ranks_); vars.push_back (var); } if (i == ties.size() && !specifications_[i].has_manual_position_ @@ -907,7 +1051,8 @@ Tie_formatting_problem::generate_collision_variations (Ties_configuration const Tie_configuration_variation var; var.index_ = i; var.suggestion_ = get_configuration (specifications_[i].position_ - + 1, UP); + + 1, UP, + specifications_[i].column_ranks_); vars.push_back (var); } } @@ -917,7 +1062,8 @@ Tie_formatting_problem::generate_collision_variations (Ties_configuration const Tie_configuration_variation var; var.index_ = i; var.suggestion_ = get_configuration (ties[i].position_ + ties[i].dir_, - ties[i].dir_); + ties[i].dir_, + ties[i].column_ranks_); vars.push_back (var); }