X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=lily%2Fbeam-collision-engraver.cc;h=364d725c9afab0383163eb3de61ac72e135230e2;hb=21f6ea846dc1930cb41f185485ce6e1c8d9b30bd;hp=67106cb8e7f69ff7e0126663c0531cb8a0f762a1;hpb=5619b5ab2e011ce829cb072b20ee2b49e535076d;p=lilypond.git diff --git a/lily/beam-collision-engraver.cc b/lily/beam-collision-engraver.cc index 67106cb8e7..364d725c9a 100644 --- a/lily/beam-collision-engraver.cc +++ b/lily/beam-collision-engraver.cc @@ -1,7 +1,7 @@ /* This file is part of LilyPond, the GNU music typesetter. - Copyright (C) 2011 Mike Solomon + Copyright (C) 2011--2012 Mike Solomon LilyPond is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -22,158 +22,197 @@ #include "item.hh" #include "note-head.hh" #include "pointer-group-interface.hh" +#include "stem.hh" class Beam_collision_engraver : public Engraver { protected: - vector active_beams_; - vector signaled_beams_; - vector end_beams_; - vector covered_grobs_; - vector covered_interior_grobs_; + vector beams_; + vector covered_grobs_; DECLARE_ACKNOWLEDGER (note_head); + DECLARE_ACKNOWLEDGER (stem); DECLARE_ACKNOWLEDGER (accidental); DECLARE_ACKNOWLEDGER (clef); + DECLARE_ACKNOWLEDGER (octavate_eight); DECLARE_ACKNOWLEDGER (key_signature); DECLARE_ACKNOWLEDGER (time_signature); DECLARE_ACKNOWLEDGER (beam); - DECLARE_END_ACKNOWLEDGER (beam); - void stop_translation_timestep (); + DECLARE_ACKNOWLEDGER (flag); + + virtual void finalize (); + +private: + bool covered_grob_has_interface (Grob *covered_grob, Grob *beam); + public: TRANSLATOR_DECLARATIONS (Beam_collision_engraver); }; -void -Beam_collision_engraver::stop_translation_timestep () -{ - 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 (); +Beam_collision_engraver::Beam_collision_engraver () {} - 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]) - { - signaled_beams_.erase (signaled_beams_.begin () + j); - break; - } +bool +Beam_collision_engraver::covered_grob_has_interface (Grob *covered_grob, Grob *beam) +{ + SCM interfaces = beam->get_property ("collision-interfaces"); - /* - hack. - in auto beaming, end beams are signaled with their beams at a later timestep. - we need to scrub these. - */ - 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; - } + for (SCM l = interfaces; scm_is_pair (l); l = scm_cdr (l)) + { + if (covered_grob->internal_has_interface (scm_car (l))) + return true; + } - vsize orig_size = active_beams_.size (); + return false; +} - for (vsize i=0; i < signaled_beams_.size (); i++) - active_beams_.push_back (signaled_beams_[i]); +void +Beam_collision_engraver::finalize () +{ + if (!covered_grobs_.size ()) + return; - 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]); - } + vector_sort (covered_grobs_, Grob_info::less); + vector_sort (beams_, Grob_info::less); + vsize start = 0; - covered_grobs_.clear (); + for (vsize i = 0; i < beams_.size (); i++) + { + Grob *beam_grob = beams_[i].grob (); - 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]); + extract_grob_set (beam_grob, "normal-stems", stems); + Interval_t vertical_span; + for (vsize j = 0; j < stems.size (); j++) + { + int vag = Grob::get_vertical_axis_group_index (stems[j]); + if (vag >= 0) + vertical_span.add_point (vag); + } + Context *beam_context = beams_[i].context (); - signaled_beams_.clear (); + Interval_t beam_spanned_rank_ = beam_grob->spanned_rank_interval (); + // Start considering grobs at the first grob whose end falls at or after the beam's beginning. + while (covered_grobs_[start].grob ()->spanned_rank_interval ()[RIGHT] < beam_spanned_rank_[LEFT]) + start++; - 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]) + // Stop when the grob's beginning comes after the beam's end. + for (vsize j = start; j < covered_grobs_.size (); j++) { - active_beams_.erase (active_beams_.begin () + j); - break; + Grob *covered_grob = covered_grobs_[j].grob (); + int vag = Grob::get_vertical_axis_group_index (covered_grob); + if (!vertical_span.contains (vag)) + continue; + Context *covered_grob_context = covered_grobs_[j].context (); + + Interval_t covered_grob_spanned_rank = covered_grob->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]. + Also, if the user wants to check for collisions only in the beam's voice, + then make sure the beam and the covered_grob are in the same voice. + */ + if ((covered_grob_spanned_rank[RIGHT] >= beam_spanned_rank_[LEFT]) + && !(to_boolean (beam_grob->get_property ("collision-voice-only")) + && (covered_grob_context != beam_context)) + && !(Beam::has_interface (covered_grob) + && (covered_grob_spanned_rank[LEFT] <= beam_spanned_rank_[LEFT])) + && covered_grob_has_interface (covered_grob, beam_grob)) + { + // Do not consider note heads attached to the beam. + if (Stem::has_interface (covered_grob)) + if (unsmob_grob (covered_grob->get_object ("beam"))) + continue; + + if (Grob *stem = unsmob_grob (covered_grob->get_object ("stem"))) + if (Grob *beam = unsmob_grob (stem->get_object ("beam"))) + if (beam == beam_grob) + continue; + + Pointer_group_interface::add_grob (beam_grob, ly_symbol2scm ("covered-grobs"), covered_grob); + } } - - end_beams_.clear (); + } } -Beam_collision_engraver::Beam_collision_engraver () {} - void Beam_collision_engraver::acknowledge_note_head (Grob_info i) { - covered_grobs_.push_back (i.grob ()); + covered_grobs_.push_back (i); +} + +void +Beam_collision_engraver::acknowledge_stem (Grob_info i) +{ + covered_grobs_.push_back (i); } void Beam_collision_engraver::acknowledge_accidental (Grob_info i) { - covered_grobs_.push_back (i.grob ()); + if (i.grob ()->internal_has_interface (ly_symbol2scm ("inline-accidental-interface"))) + covered_grobs_.push_back (i); } void Beam_collision_engraver::acknowledge_clef (Grob_info i) { - covered_interior_grobs_.push_back (i.grob ()); + covered_grobs_.push_back (i); } void Beam_collision_engraver::acknowledge_key_signature (Grob_info i) { - covered_interior_grobs_.push_back (i.grob ()); + covered_grobs_.push_back (i); +} + +void +Beam_collision_engraver::acknowledge_octavate_eight (Grob_info i) +{ + covered_grobs_.push_back (i); } void Beam_collision_engraver::acknowledge_time_signature (Grob_info i) { - covered_interior_grobs_.push_back (i.grob ()); + covered_grobs_.push_back (i); } void -Beam_collision_engraver::acknowledge_beam (Grob_info i) +Beam_collision_engraver::acknowledge_flag (Grob_info i) { - signaled_beams_.push_back (i.grob ()); + covered_grobs_.push_back (i); } void -Beam_collision_engraver::acknowledge_end_beam (Grob_info i) +Beam_collision_engraver::acknowledge_beam (Grob_info i) { - end_beams_.push_back (i.grob ()); + beams_.push_back (i); + covered_grobs_.push_back (i); } #include "translator.icc" ADD_ACKNOWLEDGER (Beam_collision_engraver, note_head); +ADD_ACKNOWLEDGER (Beam_collision_engraver, stem); ADD_ACKNOWLEDGER (Beam_collision_engraver, accidental); 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, octavate_eight); +ADD_ACKNOWLEDGER (Beam_collision_engraver, flag); ADD_ACKNOWLEDGER (Beam_collision_engraver, beam); -ADD_END_ACKNOWLEDGER (Beam_collision_engraver, beam); ADD_TRANSLATOR (Beam_collision_engraver, - /* doc */ - "Help beams avoid colliding with notes and clefs in other voices.", + /* doc */ + "Help beams avoid colliding with notes and clefs in other voices.", - /* create */ - "", + /* create */ + "", - /* read */ - "", + /* read */ + "", - /* write */ - "" - ); + /* write */ + "" + );