From f0fbdb3f07ef9028c6a256b9e1fd1db217ef8799 Mon Sep 17 00:00:00 2001 From: Werner Lemberg Date: Mon, 25 Feb 2013 22:15:37 +0100 Subject: [PATCH] Avoid excessive number of dots in chords (#3179). --- input/regression/chord-dots.ly | 21 ++++++++++ lily/dot-column.cc | 75 ++++++++++++++++++++++++++++++++-- scm/define-grob-properties.scm | 3 ++ scm/define-grobs.scm | 1 + 4 files changed, 97 insertions(+), 3 deletions(-) create mode 100644 input/regression/chord-dots.ly diff --git a/input/regression/chord-dots.ly b/input/regression/chord-dots.ly new file mode 100644 index 0000000000..56de7a59c6 --- /dev/null +++ b/input/regression/chord-dots.ly @@ -0,0 +1,21 @@ +\version "2.17.13" + +\header { + texidoc = +"Property @code{chord-dots}: If set, remove dots which the +@code{DotColumn} algorithm would vertically position too far away from +note heads." +} + +\layout{ ragged-right = ##t } + + +\relative c'' { + \override Score.DotColumn.chord-dots = ##f + << { 4. } \\ + { 4. } >> + + \override Score.DotColumn.chord-dots = ##t + << { 4. } \\ + { 4. } >> +} diff --git a/lily/dot-column.cc b/lily/dot-column.cc index 6cba432639..012808f289 100644 --- a/lily/dot-column.cc +++ b/lily/dot-column.cc @@ -60,6 +60,7 @@ Dot_column::calc_positioning_done (SCM smob) = extract_grob_array (me, "dots"); vector main_heads; + vector allowed_y_positions; Real ss = 0; Grob *commonx = me; @@ -73,7 +74,35 @@ Dot_column::calc_positioning_done (SCM smob) commonx = stem->common_refpoint (commonx, X_AXIS); if (Stem::first_head (stem) == n) - main_heads.push_back (n); + { + main_heads.push_back (n); + + // Get vertical interval of the chord's notehead positions. + // We widen this interval since dots always sit between staff + // lines. Be careful to make it work also for unusual + // overrides of `NoteHead.Y-offset'. + // + // Possible solutions to improve this code (namely, to handle + // the `staff-position' property also) -- in case there is + // ever the desire or necessity to do so -- can be found in + // the Rietveld comments at + // + // https://codereview.appspot.com/7319049 + + Interval hp = Stem::head_positions (stem); + + int top = int (ceil (hp[UP])); + if (Staff_symbol_referencer::on_line (stem, top)) + top += 1; + hp[UP] = top; + + int bottom = int (floor (hp[DOWN])); + if (Staff_symbol_referencer::on_line (stem, bottom)) + bottom -= 1; + hp[DOWN] = bottom; + + allowed_y_positions.push_back (hp); + } } } @@ -194,6 +223,45 @@ Dot_column::calc_positioning_done (SCM smob) problem.register_configuration (cfg); + // If in a chord, remove dots which have vertical positions above or below + // the topmost or bottommost note, respectively ([Gould], p. 56). + // Note that a dot configuration can contain more than a single chord or + // rest (the latter gets ignored). + // + // The dot positioning algorithm vertically shifts dots; it thus can + // happen that, say, a dot of the upper voice's chord is positioned + // beneath a note head of the lower voice's chord, while the dots of the + // lower voice's chord are shifted down even more. We thus check all + // vertical ranges for valid positions and not only the range of the dot's + // parent chord. + // + // Do nothing if there is either no staff line, or no note head, or the + // `chord-dots' property not set. + Grob *st = Staff_symbol_referencer::get_staff_symbol (me); + vsize num_positions = allowed_y_positions.size (); + bool chord_dots = to_boolean (me->get_property ("chord-dots")); + + if (st && num_positions && chord_dots) + { + for (Dot_configuration::const_iterator i (cfg.begin ()); + i != cfg.end (); i++) + { + vsize j; + + for (j = 0; j < num_positions; j++) + if (allowed_y_positions[j].contains (i->first)) + break; + + if (j == num_positions) + { + Grob *dot = i->second.dot_; + Grob *n = dot->get_parent (Y_AXIS); + if (n && Note_head::has_interface (n)) + dot->suicide (); + } + } + } + for (Dot_configuration::const_iterator i (cfg.begin ()); i != cfg.end (); i++) { @@ -236,9 +304,10 @@ ADD_INTERFACE (Dot_column, " dots so they do not clash with staff lines.", /* properties */ - "dots " - "positioning-done " + "chord-dots " "direction " + "dots " "note-collision " + "positioning-done " ); diff --git a/scm/define-grob-properties.scm b/scm/define-grob-properties.scm index c1a3a723cb..9afb49a0a3 100644 --- a/scm/define-grob-properties.scm +++ b/scm/define-grob-properties.scm @@ -173,6 +173,9 @@ when a spanner is broken at a line break.") ;; (c0-position ,integer? "An integer indicating the position of middle@tie{}C.") + (chord-dots ,boolean? "If set, remove dots which the +@code{DotColumn} algorithm would vertically position too far away from +note heads.") (circled-tip ,boolean? "Put a circle at start/@/end of hairpins (al/@/del niente).") (clip-edges ,boolean? "Allow outward pointing beamlets at the diff --git a/scm/define-grobs.scm b/scm/define-grobs.scm index ad014bce44..ff02523046 100644 --- a/scm/define-grobs.scm +++ b/scm/define-grobs.scm @@ -686,6 +686,7 @@ (DotColumn . ( (axes . (,X)) + (chord-dots . #t) (direction . ,RIGHT) (positioning-done . ,ly:dot-column::calc-positioning-done) (X-extent . ,ly:axis-group-interface::width) -- 2.39.2