X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=lily%2Fbeam.cc;h=2e223aaecc0a235052567044b9351b83b93c93fc;hb=9fe1f948145ed4ae347b2a2cc50b0594c7b15a64;hp=47e156a3a92b754dc2d706a3653873981ab4b020;hpb=2fe8400cb548432897a522351ee0f300a4f34501;p=lilypond.git diff --git a/lily/beam.cc b/lily/beam.cc index 47e156a3a9..2e223aaecc 100644 --- a/lily/beam.cc +++ b/lily/beam.cc @@ -21,12 +21,11 @@ * Rewrite stem_beams. * Use Number_pair i.s.o Interval to represent (yl, yr). + */ - - #include // tanh. #include "molecule.hh" @@ -57,10 +56,12 @@ const int INTER_QUANT_PENALTY = 1000; const int SECONDARY_BEAM_DEMERIT = 15; const int STEM_LENGTH_DEMERIT_FACTOR = 5; -const int STEM_LENGTH_LIMIT_PENALTY = 500; +// possibly ridiculous, but too short stems just won't do +const int STEM_LENGTH_LIMIT_PENALTY = 5000; const int DAMPING_DIRECTIION_PENALTY = 800; const int MUSICAL_DIRECTION_FACTOR = 400; const int IDEAL_SLOPE_FACTOR = 10; +const int REGION_SIZE = 2; static Real @@ -346,13 +347,9 @@ Beam::set_stem_shorten (Grob *m) } /* Call list of y-dy-callbacks, that handle setting of - grob-properties y, dy. - - User may set grob-properties: y-position-hs and height-hs - (to be fixed) that override the calculated y and dy. - - Because y and dy cannot be calculated and quanted separately, we - always calculate both, then check for user override. */ + grob-properties + +*/ MAKE_SCHEME_CALLBACK (Beam, after_line_breaking, 1); SCM Beam::after_line_breaking (SCM smob) @@ -447,31 +444,29 @@ Beam::quanting (SCM smob) for (int i= 0; i < stems.size(); i++) { Grob*s = stems[i]; - stem_infos.push( Stem::calc_stem_info (s)); + stem_infos.push (Stem::calc_stem_info (s)); + dirs_found[stem_infos.top ().dir_] = true; - Real b = calc_stem_y (me, s, Interval (1,0)); + Real b = calc_stem_y (me, s, Interval (1,0), false); lbase_lengths.push (b); - b = calc_stem_y (me, s, Interval (0,1)); - rbase_lengths.push (b); - - dirs_found [stem_infos.top().dir_] = true; + Real a = calc_stem_y (me, s, Interval (0,1), false); + rbase_lengths.push (a); } Direction ldir = Direction (stem_infos[0].dir_); Direction rdir = Direction (stem_infos.top ().dir_); bool knee_b = dirs_found[LEFT] && dirs_found[RIGHT]; - - int REGION_SIZE = 2; + int region_size = REGION_SIZE; /* Knees are harder, lets try some more possibilities for knees. */ if (knee_b) - REGION_SIZE += 2 ; + region_size += 2; - for (int i = -REGION_SIZE ; i < REGION_SIZE; i++) + for (int i = -region_size ; i < region_size; i++) for (int j = 0; j < num_quants; j++) { quantsl.push (i + quants[j] + int (yl)); @@ -573,9 +568,7 @@ Beam::score_stem_lengths (Link_arraystems, { Real demerit_score = 0.0 ; Real pen = STEM_LENGTH_LIMIT_PENALTY; - if (knee) - pen = sqrt(pen); - + for (int i=0; i < stems.size (); i++) { Grob* s = stems[i]; @@ -588,7 +581,9 @@ Beam::score_stem_lengths (Link_arraystems, Stem_info info = stem_infos[i]; Direction d = info.dir_; - demerit_score += pen * ( 0 >? (info.dir_ *(info.shortest_y_ - current_y))); + demerit_score += pen + * ( 0 >? (info.dir_ * (info.shortest_y_ - current_y))); + demerit_score += STEM_LENGTH_DEMERIT_FACTOR * shrink_extra_weight (d * current_y - info.dir_ * info.ideal_y_); } @@ -740,6 +735,29 @@ Beam::least_squares (SCM smob) Interval ideal (Stem::calc_stem_info (first_visible_stem (me)).ideal_y_, Stem::calc_stem_info (last_visible_stem (me)).ideal_y_); + + + + Array x_posns ; + Link_array stems= + Pointer_group_interface__extract_grobs (me, (Item*)0, "stems"); + Grob *common = stems[0]; + for (int i=1; i < stems.size (); i++) + common = stems[i]->common_refpoint (common, X_AXIS); + + Real x0 = first_visible_stem (me)->relative_coordinate (common, X_AXIS); + for (int i=0; i < stems.size (); i++) + { + Item* s = stems[i]; + + Real x = s->relative_coordinate (common, X_AXIS) - x0; + x_posns.push (x); + } + Real dx = last_visible_stem (me)->relative_coordinate (common, X_AXIS) - x0; + + Real y =0; + Real dydx = 0; + Real dy = 0; if (!ideal.delta ()) { @@ -748,11 +766,10 @@ Beam::least_squares (SCM smob) /* - TODO : use scoring for this. + TODO -- use scoring for this. complicated, because we take stem-info.ideal for determining beam slopes. - */ /* Make simple beam on middle line have small tilt */ if (!ideal[LEFT] && chord.delta () && count == 2) @@ -770,39 +787,125 @@ Beam::least_squares (SCM smob) { pos = ideal; } + + y = pos[LEFT]; + dy = pos[RIGHT]- y; + dydx = dy/dx; } else { Array ideals; - - // ugh -> use commonx - Real x0 = first_visible_stem (me)->relative_coordinate (0, X_AXIS); - Link_array stems= - Pointer_group_interface__extract_grobs (me, (Item*)0, "stems"); - for (int i=0; i < stems.size (); i++) { Item* s = stems[i]; if (Stem::invisible_b (s)) continue; - ideals.push (Offset (s->relative_coordinate (0, X_AXIS) - x0, + ideals.push (Offset (x_posns[i], Stem::calc_stem_info (s).ideal_y_)); } - Real y; - Real dydx; minimise_least_squares (&dydx, &y, ideals); - Real dx = last_visible_stem (me)->relative_coordinate (0, X_AXIS) - x0; - Real dy = dydx * dx; + dy = dydx * dx; me->set_grob_property ("least-squares-dy", gh_double2scm (dy)); - pos = Interval (y, (y+dy)); } me->set_grob_property ("positions", ly_interval2scm (pos)); + return SCM_UNSPECIFIED; } + +/* + We can't combine with previous function, since check concave and + slope damping comes first. + */ +MAKE_SCHEME_CALLBACK (Beam, shift_region_to_valid, 1); +SCM +Beam::shift_region_to_valid (SCM grob) +{ + Grob *me = unsmob_grob (grob); + /* + Code dup. + */ + Array x_posns ; + Link_array stems= + Pointer_group_interface__extract_grobs (me, (Item*)0, "stems"); + Grob *common = stems[0]; + for (int i=1; i < stems.size (); i++) + common = stems[i]->common_refpoint (common, X_AXIS); + + Grob *fvs = first_visible_stem (me); + + if (!fvs) + return SCM_UNSPECIFIED; + + Real x0 =fvs->relative_coordinate (common, X_AXIS); + for (int i=0; i < stems.size (); i++) + { + Item* s = stems[i]; + + Real x = s->relative_coordinate (common, X_AXIS) - x0; + x_posns.push (x); + } + + Grob *lvs = last_visible_stem (me); + if (!lvs) + return SCM_UNSPECIFIED; + + Real dx = lvs->relative_coordinate (common, X_AXIS) - x0; + + Interval pos = ly_scm2interval ( me->get_grob_property ("positions")); + Real dy = pos.delta(); + Real y = pos[LEFT]; + Real dydx =dy/dx; + + + /* + Shift the positions so that we have a chance of finding good + quants (i.e. no short stem failures.) + */ + Interval feasible_left_point; + feasible_left_point.set_full (); + for (int i=0; i < stems.size (); i++) + { + Item* s = stems[i]; + if (Stem::invisible_b (s)) + continue; + + + Direction d = Stem::get_direction (s); + + + Real left_y = Stem::calc_stem_info (s).shortest_y_ + - dydx * x_posns [i]; + + Interval flp ; + flp.set_full (); + flp[-d] = left_y; + + feasible_left_point.intersect (flp); + } + + if (feasible_left_point.empty_b()) + { + warning (_("Not sure that we can find a nice beam slope (no viable initial configuration found).")); + } + else if (!feasible_left_point.elem_b(y)) + { + if (isinf (feasible_left_point[DOWN])) + y = feasible_left_point[UP] - REGION_SIZE; + else if (isinf (feasible_left_point[UP])) + y = feasible_left_point[DOWN]+ REGION_SIZE; + else + y = feasible_left_point.center (); + } + pos = Interval (y, (y+dy)); + me->set_grob_property ("positions", ly_interval2scm (pos)); + return SCM_UNSPECIFIED; +} + + MAKE_SCHEME_CALLBACK (Beam, check_concave, 1); SCM Beam::check_concave (SCM smob) @@ -962,30 +1065,39 @@ Beam::slope_damping (SCM smob) /* Calculate the Y position of the stem-end, given the Y-left, Y-right in POS, and for stem S. + + If CORRECT, correct for multiplicity of beam in case of knees. + + + TODO: junk CORRECT from this. */ Real -Beam::calc_stem_y (Grob *me, Grob* s, Interval pos) +Beam::calc_stem_y (Grob *me, Grob* s, Interval pos, bool correct) { int beam_multiplicity = get_multiplicity (me); int stem_multiplicity = (Stem::duration_log (s) - 2) >? 0; + Real thick = gh_scm2double (me->get_grob_property ("thickness")); Real interbeam = get_interbeam (me); // ugh -> use commonx - Real x0 = first_visible_stem (me)->relative_coordinate (0, X_AXIS); - Real dx = last_visible_stem (me)->relative_coordinate (0, X_AXIS) - x0; + Grob * fvs = first_visible_stem (me); + Grob *lvs = last_visible_stem (me); + + Real x0 = fvs ? fvs->relative_coordinate (0, X_AXIS) : 0.0; + Real dx = fvs ? lvs->relative_coordinate (0, X_AXIS) - x0 : 0.0; + Real r = s->relative_coordinate (0, X_AXIS) - x0; Real dy = pos.delta (); Real stem_y = (dy && dx - ? (s->relative_coordinate (0, X_AXIS) - x0) / dx + ? r / dx * dy : 0) + pos[LEFT]; - - Direction first_dir = Directional_element_interface::get (first_visible_stem (me)); Direction my_dir = Directional_element_interface::get (s); + Direction first_dir = fvs? Directional_element_interface::get (fvs) : my_dir; - if (my_dir != first_dir) + if (correct && my_dir != first_dir) { /* WTF is happening here ? @@ -1009,6 +1121,8 @@ Beam::calc_stem_y (Grob *me, Grob* s, Interval pos) --hwn. */ + + // FIXME, hairy stuff stem_y += my_dir * (thick / 2 + (beam_multiplicity - 1) * interbeam); // huh, why not for first visible? @@ -1027,7 +1141,6 @@ Beam::calc_stem_y (Grob *me, Grob* s, Interval pos) else programming_error ("No last visible stem"); } - return stem_y; } @@ -1067,7 +1180,7 @@ Beam::set_stem_lengths (Grob *me) if (Stem::invisible_b (s)) continue; - Real stem_y = calc_stem_y (me, s, pos); + Real stem_y = calc_stem_y (me, s, pos, true); #if 0 // doesn't play well with dvips @@ -1293,8 +1406,6 @@ Beam::brew_molecule (SCM smob) Real dydx = dy && dx ? dy/dx : 0; - Direction firstdir = Directional_element_interface::get ( Beam::first_visible_stem (me) ); - for (int i=0; i < stems.size (); i++) { Item *item = stems[i]; @@ -1307,7 +1418,7 @@ Beam::brew_molecule (SCM smob) Real x = item->relative_coordinate (0, X_AXIS) - x0; sb.translate (Offset (x, x * dydx + pos[LEFT])); - Direction sd = Stem::get_direction (item); + mol.add_molecule (sb); }