From e4be20302c832985b7faac6fc0daf1f45f382391 Mon Sep 17 00:00:00 2001 From: Mike Solomon Date: Wed, 30 Mar 2011 11:15:39 -0400 Subject: [PATCH] Modifies the Beam_collision_engraver to accommodate auto beaming. This is a major rewrite of the engraver, moving all of its logic to the finalize method and iterating through a vector of acknowledged beams to find the grobs that any given beam covers. --- lily/beam-collision-engraver.cc | 168 ++++++++++---------------------- 1 file changed, 50 insertions(+), 118 deletions(-) diff --git a/lily/beam-collision-engraver.cc b/lily/beam-collision-engraver.cc index 367570ff6d..a12311602c 100644 --- a/lily/beam-collision-engraver.cc +++ b/lily/beam-collision-engraver.cc @@ -26,11 +26,8 @@ class Beam_collision_engraver : public Engraver { protected: - vector active_beams_; - vector signaled_beams_; - vector end_beams_; + vector beams_; vector covered_grobs_; - vector covered_interior_grobs_; DECLARE_ACKNOWLEDGER (note_head); DECLARE_ACKNOWLEDGER (accidental); @@ -38,119 +35,60 @@ protected: DECLARE_ACKNOWLEDGER (key_signature); DECLARE_ACKNOWLEDGER (time_signature); DECLARE_ACKNOWLEDGER (beam); - DECLARE_END_ACKNOWLEDGER (beam); - void stop_translation_timestep (); + + virtual void finalize (); + public: TRANSLATOR_DECLARATIONS (Beam_collision_engraver); }; +Beam_collision_engraver::Beam_collision_engraver () {} + void -Beam_collision_engraver::stop_translation_timestep () +Beam_collision_engraver::finalize () { - /* - First, for all grobs that fall to the left of a beam during - a timestep (i.e. clefs, time signatures), add these to - the beams that are currently active. - */ - for (vsize i = 0; i < covered_interior_grobs_.size (); i++) - for (vsize j = 0; j < active_beams_.size (); j++) - Pointer_group_interface::add_grob (active_beams_[j], ly_symbol2scm ("covered-grobs"), covered_interior_grobs_[i]); - - covered_interior_grobs_.clear (); - - /* - If a signaled beam is already in active_beams_, we erase it so as - not to have a beam represented in active_beams_ more than once. - */ - - for (vsize i = 0; i < active_beams_.size (); i++) - for (vsize j = 0; j < signaled_beams_.size (); j++) - if (active_beams_[i] == signaled_beams_[j]) + if (!covered_grobs_.size ()) + return; + + vector_sort (covered_grobs_, Grob::less); + vector_sort (beams_, Grob::less); + vsize start = 0; + + for (vsize i = 0; i < beams_.size (); i++) + { + Interval_t beam_spanned_rank_ = beams_[i]->spanned_rank_interval (); + // Start considering grobs at the first grob whose end falls at or after the beam's beginning. + while (covered_grobs_[start]->spanned_rank_interval ()[RIGHT] < beam_spanned_rank_[LEFT]) + start++; + + // Stop when the grob's beginning comes after the beam's end. + for (vsize j = start; j < covered_grobs_.size (); j++) { - signaled_beams_.erase (signaled_beams_.begin () + j); - break; + Interval_t covered_grob_spanned_rank = covered_grobs_[j]->spanned_rank_interval (); + if (covered_grob_spanned_rank[LEFT] > beam_spanned_rank_[RIGHT]) + break; + /* + Only consider grobs whose end falls at or after the beam's beginning. + If the grob is a beam, it cannot start before beams_[i] + */ + if ((covered_grob_spanned_rank[RIGHT] >= beam_spanned_rank_[LEFT]) + && !(Beam::has_interface (covered_grobs_[j]) + && (covered_grob_spanned_rank[LEFT] <= beam_spanned_rank_[LEFT]))) + { + // Do not consider note heads attached to the beam. + bool my_beam = false; + if (Grob *stem = unsmob_grob (covered_grobs_[j]->get_object ("stem"))) + if (Grob *beam = unsmob_grob (stem->get_object ("beam"))) + if (beam == beams_[i]) + my_beam = true; + + if (!my_beam) + Pointer_group_interface::add_grob (beams_[i], ly_symbol2scm ("covered-grobs"), covered_grobs_[j]); + } } - - /* - In auto beaming, beams both begin and end during the same timestep. - This means that if there is a beam that is both in signaled_beams_ and - end_beams_, it must either be an auto beam (likely) or a beam that - has no notes under it (highly unlikely). In either case, we cannot account - for the grobs under this beam, and we erase it from signaled beams. - */ - for (vsize i = 0; i < end_beams_.size (); i++) - for (vsize j = 0; j < signaled_beams_.size (); j++) - if (end_beams_[i] == signaled_beams_[j]) - { - signaled_beams_.erase (signaled_beams_.begin () + j); - break; - } - - /* - We want to know how big active beams was originally so that we do not - get any cyclical dependencies (see below). - */ - vsize orig_size = active_beams_.size (); - - /* - All signaled beams that are left now become active beams that are fair - game to collect covered grobs. - */ - for (vsize i=0; i < signaled_beams_.size (); i++) - active_beams_.push_back (signaled_beams_[i]); - - /* - Add all covered grobs that fall to the right of a beam (like noteheads) - as to covered-grobs of the beam. Note that noteheads that part of a beam - are not added to that list, as note heads should not never collide with - their own beams due to minimum stem length penalties in beam-quanting.cc. - */ - for (vsize i = 0; i < covered_grobs_.size (); i++) - for (vsize j = 0; j < active_beams_.size (); j++) - { - bool my_beam = false; - if (Grob *stem = unsmob_grob (covered_grobs_[i]->get_object ("stem"))) - if (Grob *beam = unsmob_grob (stem->get_object ("beam"))) - if (beam == active_beams_.at (j)) - my_beam = true; - if (!my_beam) - Pointer_group_interface::add_grob (active_beams_.at (j), ly_symbol2scm ("covered-grobs"), covered_grobs_[i]); - } - - covered_grobs_.clear (); - - /* - This is where cyclical dependencies are avoided. In beam collision avoidance, - beams often need to avoid other beams. To do this, they need to know the beam's - position. But, if that second beam needs to know the first beam's position, we - have a cyclical dependency. So, we only ever add signaled beams to active_beams_ - that existed BEFORE this time step. This is controlled by the orig_size variable. - The for loop stops before it gets to the signaled beams added above so that beams - added during this timestep are never dependent on each other for positioning. - */ - for (vsize i = 0; i < signaled_beams_.size (); i++) - for (vsize j = 0; j < orig_size; j++) - Pointer_group_interface::add_grob (active_beams_[j], ly_symbol2scm ("covered-grobs"), signaled_beams_[i]); - - signaled_beams_.clear (); - - /* - If the end of a beam has been announced, it is no longer active. So, remove this beam - from active_beams_. - */ - for (vsize i = 0; i < end_beams_.size (); i++) - for (vsize j = 0; j < active_beams_.size (); j++) - if (end_beams_[i] == active_beams_[j]) - { - active_beams_.erase (active_beams_.begin () + j); - break; - } - - end_beams_.clear (); + } } -Beam_collision_engraver::Beam_collision_engraver () {} - void Beam_collision_engraver::acknowledge_note_head (Grob_info i) { @@ -167,31 +105,26 @@ Beam_collision_engraver::acknowledge_accidental (Grob_info i) void Beam_collision_engraver::acknowledge_clef (Grob_info i) { - covered_interior_grobs_.push_back (i.grob ()); + covered_grobs_.push_back (i.grob ()); } void Beam_collision_engraver::acknowledge_key_signature (Grob_info i) { - covered_interior_grobs_.push_back (i.grob ()); + covered_grobs_.push_back (i.grob ()); } void Beam_collision_engraver::acknowledge_time_signature (Grob_info i) { - covered_interior_grobs_.push_back (i.grob ()); + covered_grobs_.push_back (i.grob ()); } void Beam_collision_engraver::acknowledge_beam (Grob_info i) { - signaled_beams_.push_back (i.grob ()); -} - -void -Beam_collision_engraver::acknowledge_end_beam (Grob_info i) -{ - end_beams_.push_back (i.grob ()); + beams_.push_back (i.grob ()); + covered_grobs_.push_back (i.grob ()); } #include "translator.icc" @@ -202,7 +135,6 @@ ADD_ACKNOWLEDGER (Beam_collision_engraver, clef); ADD_ACKNOWLEDGER (Beam_collision_engraver, key_signature); ADD_ACKNOWLEDGER (Beam_collision_engraver, time_signature); ADD_ACKNOWLEDGER (Beam_collision_engraver, beam); -ADD_END_ACKNOWLEDGER (Beam_collision_engraver, beam); ADD_TRANSLATOR (Beam_collision_engraver, /* doc */ -- 2.39.2