X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=lily%2Fbeam.cc;h=1bb0a209a859666c271dfed1c955d556723ecfa0;hb=54b02666750062788185bd3f99e644d621e348c2;hp=6fbd71d7d6a6d4ddcda0a7fbd7782f8e6eef43c4;hpb=4bd29f98794235cbe90875a6d73ad6cf4ffeaf5b;p=lilypond.git diff --git a/lily/beam.cc b/lily/beam.cc index 6fbd71d7d6..1bb0a209a8 100644 --- a/lily/beam.cc +++ b/lily/beam.cc @@ -37,6 +37,7 @@ #include "beam.hh" +#include "align-interface.hh" #include "beam-scoring-problem.hh" #include "beaming-pattern.hh" #include "directional-element-interface.hh" @@ -554,6 +555,8 @@ Beam::print (SCM grob) Spanner *me = unsmob_spanner (grob); Grob *commonx = 0; vector segments = get_beam_segments (me, &commonx); + if (!segments.size ()) + return SCM_EOL; Interval span; if (normal_stem_count (me)) @@ -973,7 +976,11 @@ Beam::no_visible_stem_positions (Grob *me, Interval default_value) } Direction dir = get_grob_direction (me); - Real y = head_positions[dir] + + if (!dir) + programming_error ("The beam should have a direction by now."); + + Real y = head_positions.linear_combination (dir) * 0.5 * Staff_symbol_referencer::staff_space (me) + dir * get_beam_translation (me) * (multiplicity.length () + 1); @@ -1181,13 +1188,6 @@ Beam::shift_region_to_valid (SCM grob, SCM posns) feasible_left_point.intersect (flp); } - /* - We have two intervals here, one for the up variant (beams goes - over the collision) one for the down. - */ - Drul_array collision_free (feasible_left_point, - feasible_left_point); - vector filtered; /* We only update these for objects that are too large for quanting @@ -1200,11 +1200,18 @@ Beam::shift_region_to_valid (SCM grob, SCM posns) take care of computing the impact those exactly. */ Real min_y_size = 2.0; + + // A list of intervals into which beams may not fall + vector forbidden_intervals; + for (vsize i = 0; i < covered.size(); i++) { if (!covered[i]->is_live()) continue; - + + if (Beam::has_interface (covered[i]) && is_cross_staff (covered[i])) + continue; + Box b; for (Axis a = X_AXIS; a < NO_AXES; incr (a)) b[a] = covered[i]->extent (common[a], a); @@ -1245,7 +1252,7 @@ Beam::shift_region_to_valid (SCM grob, SCM posns) the centerline. */ Direction stemdir = get_grob_direction (head_stem); - b[Y_AXIS][stemdir] = stemdir * infinity_f; + b[Y_AXIS][stemdir] = stemdir * infinity_f; } else { @@ -1263,65 +1270,97 @@ Beam::shift_region_to_valid (SCM grob, SCM posns) Real dy = slope * x; Direction yd = DOWN; + Interval disallowed; do { Real left_y = b[Y_AXIS][yd]; - if (left_y == yd * infinity_f) - { - collision_free[yd].set_empty (); - continue; - } - left_y -= dy; // Translate back to beam as ref point. left_y -= me->relative_coordinate (common[Y_AXIS], Y_AXIS); - - Interval allowed; - allowed.set_full (); - allowed[-yd] = left_y; - collision_free[yd].intersect (allowed); + disallowed[yd] = left_y; } while (flip (&yd) != DOWN); + + forbidden_intervals.push_back (disallowed); } while (flip (&d) != LEFT); } - Grob_array *arr = + Grob_array *arr = Pointer_group_interface::get_grob_array (me, ly_symbol2scm ("covered-grobs")); arr->set_array (filtered); - if (collision_free[DOWN].contains (beam_left_y) - || collision_free[UP].contains (beam_left_y)) + vector_sort (forbidden_intervals, Interval::left_less); + Real epsilon = 1.0e-10; + Interval feasible_beam_placements (beam_left_y, beam_left_y); + + /* + forbidden_intervals contains a vector of intervals in which + the beam cannot start. it iterates through these intervals, + pushing feasible_beam_placements epsilon over or epsilon under a + collision. when this type of change happens, the loop is marked + as "dirty" and re-iterated. + + TODO: figure out a faster ways that this loop can happen via + a better search algorithm and/or OOP. + */ + + bool dirty = false; + do { - // We're good to go. Do nothing. + dirty = false; + for (vsize i = 0; i < forbidden_intervals.size (); i++) + { + Direction d = DOWN; + do + { + if (forbidden_intervals[i][d] == d * infinity_f) + feasible_beam_placements[d] = d * infinity_f; + else if (forbidden_intervals[i].contains (feasible_beam_placements[d])) + { + feasible_beam_placements[d] = d * epsilon + forbidden_intervals[i][d]; + dirty = true; + } + } + while (flip (&d) != DOWN); + } } - else if (!collision_free[DOWN].is_empty () - || !collision_free[UP].is_empty ()) - { - // We have space above or below collisions (or, no collisions at - // all). - Interval best = - (collision_free[DOWN].length () > collision_free[UP].length ()) ? - collision_free[DOWN] : collision_free[UP]; + while (dirty); - beam_left_y = point_in_interval (best, 2.0); + // if the beam placement falls out of the feasible region, we push it + // to infinity so that it can never be a feasible candidate below + Direction d = DOWN; + do + { + if (!feasible_left_point.contains (feasible_beam_placements[d])) + feasible_beam_placements[d] = d*infinity_f; } - else if (!feasible_left_point.is_empty ()) + while (flip (&d) != DOWN); + + if ((feasible_beam_placements[UP] == infinity_f && feasible_beam_placements[DOWN] == -infinity_f) && !feasible_left_point.is_empty ()) { // We are somewhat screwed: we have a collision, but at least // there is a way to satisfy stem length constraints. beam_left_y = point_in_interval (feasible_left_point, 2.0); } + else if (!feasible_left_point.is_empty ()) + { + // Only one of them offers is feasible solution. Pick that one. + if (abs (beam_left_y - feasible_beam_placements[DOWN]) > abs (beam_left_y - feasible_beam_placements[UP])) + beam_left_y = feasible_beam_placements[UP]; + else + beam_left_y = feasible_beam_placements[DOWN]; + } else { // We are completely screwed. - warning (_ ("no viable initial configuration found: may not find good beam slope")); + me->warning (_ ("no viable initial configuration found: may not find good beam slope")); } - + pos = Drul_array (beam_left_y, (beam_left_y + beam_dy)); scale_drul (&pos, 1 / Staff_symbol_referencer::staff_space (me)); @@ -1818,6 +1857,8 @@ ADD_INTERFACE (Beam, "break-overshoot " "clip-edges " "concaveness " + "collision-interfaces " + "collision-voice-only " "covered-grobs " "damping " "details "