X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=lily%2Fnote-spacing.cc;h=9f767ab54c0501c3b5b0fd9483f6e78c089ccefd;hb=15551c56a17c10f2e1eae0766ddc87a62da119a8;hp=a002d50dc25ed0f8922768ab1beffbea12bffb10;hpb=c380a7abde14a60ebd6d8a6eab91ae4e13677a23;p=lilypond.git diff --git a/lily/note-spacing.cc b/lily/note-spacing.cc index a002d50dc2..9f767ab54c 100644 --- a/lily/note-spacing.cc +++ b/lily/note-spacing.cc @@ -3,7 +3,7 @@ source file of the GNU LilyPond music typesetter - (c) 2001--2002 Han-Wen Nienhuys + (c) 2001--2004 Han-Wen Nienhuys */ @@ -17,34 +17,40 @@ #include "stem.hh" #include "separation-item.hh" #include "staff-spacing.hh" +#include "accidental-placement.hh" +#include "paper-def.hh" -bool -Note_spacing::has_interface (Grob* g) -{ - return g && g->has_interface (ly_symbol2scm ("note-spacing-interface")); -} + +/* + +TODO: detect hshifts due to collisions, and account for them in +spacing? + +*/ void Note_spacing::get_spacing (Grob *me, Item* right_col, Real base_space, Real increment, Real *space, Real *fixed) { - Drul_array props(me->get_grob_property ("left-items"), - me->get_grob_property ("right-items")); + Drul_array props (me->get_property ("left-items"), + me->get_property ("right-items")); Direction d = LEFT; Direction col_dir = right_col->break_status_dir (); Drul_array extents; + + Interval left_head_wid; do { for (SCM s = props[d]; gh_pair_p (s); s = gh_cdr (s)) { - Item * it= dynamic_cast (unsmob_grob (gh_car(s))); - + Item * it= dynamic_cast (unsmob_grob (gh_car (s))); + if (d == RIGHT && it->break_status_dir () != col_dir) { it = it -> find_prebroken_piece (col_dir); - } + } /* some kind of mismatch, eg. a note column, that is behind a linebreak. @@ -52,16 +58,32 @@ Note_spacing::get_spacing (Grob *me, Item* right_col, if (!it) continue; - if (d == RIGHT && right_col != it->column_l ()) + Item *it_col = it->get_column (); + if (d == RIGHT && right_col != it_col) continue; if (Separation_item::has_interface (it)) { - extents[d].unite (Separation_item::my_width (it)); + extents[d].unite (Separation_item::width (it)); continue; } + + if (d == LEFT) + { + SCM r = it->get_property ("rest"); + Grob * g = unsmob_grob (r); + if (!g) + g = Note_column::first_head (it); + + /* + Ugh. If Stem is switched off, we don't know what the + first note head will be. + */ + if (g) + left_head_wid = g->extent (it_col, X_AXIS); + } - extents[d].unite (it->extent (it->column_l (), X_AXIS)); + extents[d].unite (it->extent (it_col, X_AXIS)); if (d == RIGHT) { Grob * accs = Note_column::accidentals (it); @@ -69,41 +91,83 @@ Note_spacing::get_spacing (Grob *me, Item* right_col, accs = Note_column::accidentals (it->get_parent (X_AXIS)); if (accs) - extents[d].unite (accs->extent (it->column_l (), X_AXIS)); + { + Interval v = + Accidental_placement::get_relevant_accidental_extent (accs, it_col, me); + + extents[d].unite (v); + } } } - if (extents[d].empty_b ()) + if (extents[d].is_empty ()) extents[d] = Interval (0,0); } while (flip (&d) != LEFT); - *fixed = (extents[LEFT][RIGHT] >? increment); + + /* + We look at the width of the note head, since smaller heads get less space + eg. a quarter rest gets almost 0.5 ss less horizontal space than a note. + + What is sticking out of the note head (eg. a flag), doesn't get + the full amount of space. + + FIXED also includes the left part of the right object. + */ + *fixed = + (left_head_wid.is_empty () ? increment : + /* + Size of the head: + */ + (left_head_wid[RIGHT]+ + + /* + What's sticking out of the head, eg. a flag: + */ + (extents[LEFT][RIGHT] - left_head_wid[RIGHT])/2)) + + /* + What is sticking out of the right note: + */ + + (extents[RIGHT].is_empty () ? 0.0 : - extents[RIGHT][LEFT] / 2); + + /* + We don't do complicated stuff: (base_space - increment) is the + normal amount of white, which also determines the amount of + stretch. Upon (extreme) stretching, notes with accidentals should + stretch as much as notes without accidentals. + */ *space = (base_space - increment) + *fixed ; - if (*space - *fixed < 2 * ((- extents[RIGHT][LEFT]) >? 0)) + if (!extents[RIGHT].is_empty () + && (Item::is_breakable (right_col) + || right_col->original_)) { /* - - What's sticking out at the left of the right side has less - influence. We only take it into account if there is not enough - space. + This is for the situation - this sucks: this criterion is discontinuous; FIXME. - */ - *space += 0.5 * (( -extents[RIGHT][LEFT]) >? 0); - } + rest | 3/4 (eol) - *space += stem_dir_correction (me, right_col, increment); + Since we only take half of the right-object space above, the + barline will bump into the notes preceding it, if the right + thing is big. We add the rest of the extents here: + */ + + *space += -extents[RIGHT][LEFT] / 2; + *fixed += -extents[RIGHT][LEFT] / 2; + } + + stem_dir_correction (me, right_col, increment, space, fixed); } Item * Note_spacing::left_column (Grob *me) { - if (me->immutable_property_alist_ == SCM_EOL) + if (!me->live ()) return 0; - return dynamic_cast (me)->column_l (); + return dynamic_cast (me)->get_column (); } /* @@ -117,13 +181,10 @@ prune RIGHT-ITEMS. Item * Note_spacing::right_column (Grob*me) { - /* - ugh. should have generic is_live() method? - */ - if (me->immutable_property_alist_ == SCM_EOL) + if (!me->live ()) return 0; - SCM right = me->get_grob_property ("right-items"); + SCM right = me->get_property ("right-items"); Item *mincol = 0; int min_rank = INT_MAX; bool prune = false; @@ -131,8 +192,8 @@ Note_spacing::right_column (Grob*me) { Item * ri = unsmob_item (gh_car (s)); - Item * col = ri->column_l (); - int rank = Paper_column::rank_i (col); + Item * col = ri->get_column (); + int rank = Paper_column::get_rank (col); if (rank < min_rank) { @@ -150,18 +211,18 @@ Note_spacing::right_column (Grob*me) SCM newright = SCM_EOL; for (SCM s = right ; gh_pair_p (s) ; s =gh_cdr (s)) { - if (unsmob_item (gh_car (s))->column_l () == mincol) + if (unsmob_item (gh_car (s))->get_column () == mincol) newright = gh_cons (gh_car (s), newright); } - me->set_grob_property ("right-items", newright); + me->set_property ("right-items", newright); } if (!mincol) { /* - int r = Paper_column::rank_i (dynamic_cast(me)->column_l ()); - programming_error (_f("Spacing wish column %d has no right item.", r)); + int r = Paper_column::get_rank (dynamic_cast(me)->get_column ()); + programming_error (_f ("Spacing wish column %d has no right item.", r)); */ return 0; @@ -178,25 +239,26 @@ Note_spacing::right_column (Grob*me) TODO: have to check wether the stems are in the same staff. */ -Real +void Note_spacing::stem_dir_correction (Grob*me, Item * rcolumn, - Real increment) + Real increment, + Real * space, Real *fixed) { - Drul_array stem_dirs(CENTER,CENTER); + Drul_array stem_dirs (CENTER,CENTER); Drul_array stem_posns; Drul_array head_posns; - Drul_array props(me->get_grob_property ("left-items"), - me->get_grob_property ("right-items")); + Drul_array props (me->get_property ("left-items"), + me->get_property ("right-items")); - Drul_array beams_drul(0,0); - Real correction = 0.0; + Drul_array beams_drul (0,0); + Drul_array stems_drul (0,0); stem_dirs[LEFT] = stem_dirs[RIGHT] = CENTER; Interval intersect; Interval bar_xextent; Interval bar_yextent; - bool correct = true; + bool correct_stem_dirs = true; Direction d = LEFT; bool acc_right = false; @@ -204,23 +266,23 @@ Note_spacing::stem_dir_correction (Grob*me, Item * rcolumn, { for (SCM s = props[d]; gh_pair_p (s); s = gh_cdr (s)) { - Item * it= dynamic_cast (unsmob_grob (gh_car(s))); + Item * it= dynamic_cast (unsmob_grob (gh_car (s))); if (d == RIGHT) acc_right = acc_right || Note_column::accidentals (it); - Grob *stem = Note_column::stem_l (it); + Grob *stem = Note_column::get_stem (it); - if (!stem) + if (!stem || !stem->live ()) { if (d == RIGHT && Separation_item::has_interface (it)) { - if (it->column_l () != rcolumn) + if (it->get_column () != rcolumn) { it = it->find_prebroken_piece (rcolumn->break_status_dir ()); } - Grob *last = Staff_spacing::extremal_break_aligned_grob (it, LEFT, &bar_xextent); + Grob *last = Separation_item::extremal_break_aligned_grob (it, LEFT, &bar_xextent); if (last) bar_yextent = Staff_spacing::bar_y_positions (last); @@ -228,31 +290,42 @@ Note_spacing::stem_dir_correction (Grob*me, Item * rcolumn, break; } - goto exit_func; + return ; } - if(Stem::invisible_b (stem)) + if (Stem::is_invisible (stem)) { - correct = false; - goto exit_func ; + correct_stem_dirs = false; + continue; } - beams_drul[d] = Stem::beam_l (stem); + stems_drul[d] = stem; + beams_drul[d] = Stem::get_beam (stem); Direction sd = Stem::get_direction (stem); if (stem_dirs[d] && stem_dirs[d] != sd) { - correct = false; - goto exit_func; + correct_stem_dirs = false; + continue; } stem_dirs[d] = sd; + /* + Correction doesn't seem appropriate when there is a large flag + hanging from the note. + */ + if (d == LEFT + && Stem::duration_log (stem) > 2 && !Stem::get_beam (stem)) + { + correct_stem_dirs = false; + } + Interval hp = Stem::head_positions (stem); Real chord_start = hp[sd]; Real stem_end = Stem::stem_end_position (stem); - stem_posns[d] = Interval(chord_start? stem_end); + stem_posns[d] = Interval (chord_start? stem_end); head_posns[d].unite (hp); } } @@ -261,53 +334,77 @@ Note_spacing::stem_dir_correction (Grob*me, Item * rcolumn, /* don't correct if accidentals are sticking out of the right side. - */ if (acc_right) - return 0.0; + return ; - if (!bar_yextent.empty_b()) + Real correction = 0.0; + + if (!bar_yextent.is_empty ()) { stem_dirs[RIGHT] = - stem_dirs[LEFT]; stem_posns[RIGHT] = bar_yextent; } - if (correct &&stem_dirs[LEFT] *stem_dirs[RIGHT] == -1) + if (correct_stem_dirs && stem_dirs[LEFT] *stem_dirs[RIGHT] == -1) { - if (beams_drul[LEFT] == beams_drul[RIGHT]) + if (beams_drul[LEFT] && beams_drul[LEFT] == beams_drul[RIGHT]) { + /* this is a knee: maximal correction. */ - - correction = increment* stem_dirs[LEFT]; + Real note_head_width = increment; + Grob * st = stems_drul[RIGHT]; + Grob * head = st ? Stem::support_head (st) : 0; + + Interval head_extent; + if (head) + { + head_extent = head->extent (rcolumn, X_AXIS); + + if (!head_extent.is_empty ()) + note_head_width = head_extent[RIGHT]; + + if (st) + { + Real thick = Stem::thickness (st); + + note_head_width -= thick; + } + } + + correction = note_head_width* stem_dirs[LEFT]; + correction *= robust_scm2double (me->get_property ("knee-spacing-correction"), 0); + *fixed += correction; } else { intersect = stem_posns[LEFT]; - intersect.intersect(stem_posns[RIGHT]); - correct = correct && !intersect.empty_b (); + intersect.intersect (stem_posns[RIGHT]); + correct_stem_dirs = correct_stem_dirs && !intersect.is_empty (); - if (!correct) - return 0.0; - - correction = abs (intersect.length ()); + if (correct_stem_dirs) + { + correction =abs (intersect.length ()); - /* - Ugh. 7 is hardcoded. - */ - correction = (correction/7) get_grob_property ("stem-spacing-correction")); - - if (!bar_yextent.empty_b()) + /* + Ugh. 7 is hardcoded. + */ + correction = (correction/7) get_property ("stem-spacing-correction"), 0); + } + + if (!bar_yextent.is_empty ()) { correction *= 0.5; } } } - else if (correct && stem_dirs[LEFT] *stem_dirs[RIGHT] == UP) + else if (correct_stem_dirs && stem_dirs[LEFT] *stem_dirs[RIGHT] == UP) { /* Correct for the following situation: @@ -331,30 +428,31 @@ Note_spacing::stem_dir_correction (Grob*me, Item * rcolumn, Interval hp = head_posns[LEFT]; hp.intersect (head_posns[RIGHT]); - if (!hp.empty_b()) - return 0.0; + if (!hp.is_empty ()) + return ; Direction lowest = (head_posns[LEFT][DOWN] > head_posns[RIGHT][UP]) ? RIGHT : LEFT; Real delta = head_posns[-lowest][DOWN] - head_posns[lowest][UP] ; - Real corr = gh_scm2double (me->get_grob_property ("stem-spacing-correction")); + Real corr = robust_scm2double (me->get_property ("stem-spacing-correction"), 0); corr = (delta <= 1) ? 0.0 : 0.25; correction= -lowest * corr ; } - if (!bar_xextent.empty_b()) - correction += - bar_xextent[LEFT]; - - exit_func: - return correction; + *space += correction; + + /* there used to be a correction for bar_xextent () here, but + it's unclear what that was good for ? + */ + } ADD_INTERFACE (Note_spacing,"note-spacing-interface", - "", - "left-items right-items stem-spacing-correction"); + "This object calculates spacing wishes for individual voices.", + "left-items right-items stem-spacing-correction knee-spacing-correction");