From: Mike Solomon Date: Wed, 4 May 2011 14:51:04 +0000 (-0700) Subject: Fixes issue 1613. X-Git-Tag: release/2.15.0-1~51 X-Git-Url: https://git.donarmstrong.com/?a=commitdiff_plain;h=e0679ba2d5af0f480a67e6108760ef3ee9bcdb80;p=lilypond.git Fixes issue 1613. Beams' left extrema are now placed outside of zones that would cause an intersection. --- diff --git a/lily/beam.cc b/lily/beam.cc index 938567984e..288eb226bc 100644 --- a/lily/beam.cc +++ b/lily/beam.cc @@ -1182,13 +1182,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 @@ -1201,6 +1194,10 @@ 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()) @@ -1254,7 +1251,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 { @@ -1272,76 +1269,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()) - { - // Only one of them offers is feasible solution. Pick that one. - Interval v = - (!collision_free[DOWN].is_empty()) ? - collision_free[DOWN] : - collision_free[UP]; + while (dirty); - beam_left_y = point_in_interval (v, 2.0); - } - else if (!collision_free[DOWN].is_empty () - && !collision_free[UP].is_empty ()) + // 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 { - // Above and below are candidates, take the one closest to the - // starting solution. - Interval best = - (collision_free[DOWN].distance (beam_left_y) - < collision_free[UP].distance (beam_left_y)) ? - collision_free[DOWN] : collision_free[UP]; - - beam_left_y = point_in_interval (best, 2.0); + 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. 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));