Fixes Issue 1504, allowing feather beam line breaking.
[lilypond/patrick.git] / lily / beam-collision-engraver.cc
blob39e614c2a15dea10f3b72f88110959c35dc389a1
1 /*
2 This file is part of LilyPond, the GNU music typesetter.
4 Copyright (C) 2011 Mike Solomon <mike@apollinemike.com>
6 LilyPond is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
11 LilyPond is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with LilyPond. If not, see <http://www.gnu.org/licenses/>.
20 #include "beam.hh"
21 #include "engraver.hh"
22 #include "item.hh"
23 #include "note-head.hh"
24 #include "pointer-group-interface.hh"
26 class Beam_collision_engraver : public Engraver
28 protected:
29 vector<Grob *> active_beams_;
30 vector<Grob *> signaled_beams_;
31 vector<Grob *> end_beams_;
32 vector<Grob *> covered_grobs_;
33 vector<Grob *> covered_interior_grobs_;
35 DECLARE_ACKNOWLEDGER (note_head);
36 DECLARE_ACKNOWLEDGER (accidental);
37 DECLARE_ACKNOWLEDGER (clef);
38 DECLARE_ACKNOWLEDGER (key_signature);
39 DECLARE_ACKNOWLEDGER (time_signature);
40 DECLARE_ACKNOWLEDGER (beam);
41 DECLARE_END_ACKNOWLEDGER (beam);
42 void stop_translation_timestep ();
43 public:
44 TRANSLATOR_DECLARATIONS (Beam_collision_engraver);
47 void
48 Beam_collision_engraver::stop_translation_timestep ()
50 /*
51 First, for all grobs that fall to the left of a beam during
52 a timestep (i.e. clefs, time signatures), add these to
53 the beams that are currently active.
55 for (vsize i = 0; i < covered_interior_grobs_.size (); i++)
56 for (vsize j = 0; j < active_beams_.size (); j++)
57 Pointer_group_interface::add_grob (active_beams_[j], ly_symbol2scm ("covered-grobs"), covered_interior_grobs_[i]);
59 covered_interior_grobs_.clear ();
62 If a signaled beam is already in active_beams_, we erase it so as
63 not to have a beam represented in active_beams_ more than once.
66 for (vsize i = 0; i < active_beams_.size (); i++)
67 for (vsize j = 0; j < signaled_beams_.size (); j++)
68 if (active_beams_[i] == signaled_beams_[j])
70 signaled_beams_.erase (signaled_beams_.begin () + j);
71 break;
75 In auto beaming, beams both begin and end during the same timestep.
76 This means that if there is a beam that is both in signaled_beams_ and
77 end_beams_, it must either be an auto beam (likely) or a beam that
78 has no notes under it (highly unlikely). In either case, we cannot account
79 for the grobs under this beam, and we erase it from signaled beams.
81 for (vsize i = 0; i < end_beams_.size (); i++)
82 for (vsize j = 0; j < signaled_beams_.size (); j++)
83 if (end_beams_[i] == signaled_beams_[j])
85 signaled_beams_.erase (signaled_beams_.begin () + j);
86 break;
90 We want to know how big active beams was originally so that we do not
91 get any cyclical dependencies (see below).
93 vsize orig_size = active_beams_.size ();
96 All signaled beams that are left now become active beams that are fair
97 game to collect covered grobs.
99 for (vsize i=0; i < signaled_beams_.size (); i++)
100 active_beams_.push_back (signaled_beams_[i]);
103 Add all covered grobs that fall to the right of a beam (like noteheads)
104 as to covered-grobs of the beam. Note that noteheads that part of a beam
105 are not added to that list, as note heads should not never collide with
106 their own beams due to minimum stem length penalties in beam-quanting.cc.
108 for (vsize i = 0; i < covered_grobs_.size (); i++)
109 for (vsize j = 0; j < active_beams_.size (); j++)
111 bool my_beam = false;
112 if (Grob *stem = unsmob_grob (covered_grobs_[i]->get_object ("stem")))
113 if (Grob *beam = unsmob_grob (stem->get_object ("beam")))
114 if (beam == active_beams_.at (j))
115 my_beam = true;
116 if (!my_beam)
117 Pointer_group_interface::add_grob (active_beams_.at (j), ly_symbol2scm ("covered-grobs"), covered_grobs_[i]);
120 covered_grobs_.clear ();
123 This is where cyclical dependencies are avoided. In beam collision avoidance,
124 beams often need to avoid other beams. To do this, they need to know the beam's
125 position. But, if that second beam needs to know the first beam's position, we
126 have a cyclical dependency. So, we only ever add signaled beams to active_beams_
127 that existed BEFORE this time step. This is controlled by the orig_size variable.
128 The for loop stops before it gets to the signaled beams added above so that beams
129 added during this timestep are never dependent on each other for positioning.
131 for (vsize i = 0; i < signaled_beams_.size (); i++)
132 for (vsize j = 0; j < orig_size; j++)
133 Pointer_group_interface::add_grob (active_beams_[j], ly_symbol2scm ("covered-grobs"), signaled_beams_[i]);
135 signaled_beams_.clear ();
138 If the end of a beam has been announced, it is no longer active. So, remove this beam
139 from active_beams_.
141 for (vsize i = 0; i < end_beams_.size (); i++)
142 for (vsize j = 0; j < active_beams_.size (); j++)
143 if (end_beams_[i] == active_beams_[j])
145 active_beams_.erase (active_beams_.begin () + j);
146 break;
149 end_beams_.clear ();
152 Beam_collision_engraver::Beam_collision_engraver () {}
154 void
155 Beam_collision_engraver::acknowledge_note_head (Grob_info i)
157 covered_grobs_.push_back (i.grob ());
160 void
161 Beam_collision_engraver::acknowledge_accidental (Grob_info i)
163 covered_grobs_.push_back (i.grob ());
166 void
167 Beam_collision_engraver::acknowledge_clef (Grob_info i)
169 covered_interior_grobs_.push_back (i.grob ());
172 void
173 Beam_collision_engraver::acknowledge_key_signature (Grob_info i)
175 covered_interior_grobs_.push_back (i.grob ());
178 void
179 Beam_collision_engraver::acknowledge_time_signature (Grob_info i)
181 covered_interior_grobs_.push_back (i.grob ());
184 void
185 Beam_collision_engraver::acknowledge_beam (Grob_info i)
187 signaled_beams_.push_back (i.grob ());
190 void
191 Beam_collision_engraver::acknowledge_end_beam (Grob_info i)
193 end_beams_.push_back (i.grob ());
196 #include "translator.icc"
198 ADD_ACKNOWLEDGER (Beam_collision_engraver, note_head);
199 ADD_ACKNOWLEDGER (Beam_collision_engraver, accidental);
200 ADD_ACKNOWLEDGER (Beam_collision_engraver, clef);
201 ADD_ACKNOWLEDGER (Beam_collision_engraver, key_signature);
202 ADD_ACKNOWLEDGER (Beam_collision_engraver, time_signature);
203 ADD_ACKNOWLEDGER (Beam_collision_engraver, beam);
204 ADD_END_ACKNOWLEDGER (Beam_collision_engraver, beam);
206 ADD_TRANSLATOR (Beam_collision_engraver,
207 /* doc */
208 "Help beams avoid colliding with notes and clefs in other voices.",
210 /* create */
213 /* read */
216 /* write */