]> git.donarmstrong.com Git - lilypond.git/blob - lily/beam-collision-engraver.cc
5e9006f9b6f62ee1a2420d0e950caaaf5682593b
[lilypond.git] / lily / beam-collision-engraver.cc
1 /*
2   This file is part of LilyPond, the GNU music typesetter.
3
4   Copyright (C) 2011 Mike Solomon <mike@apollinemike.com>
5
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.
10
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.
15
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/>.
18 */
19
20 #include "beam.hh"
21 #include "engraver.hh"
22 #include "item.hh"
23 #include "note-head.hh"
24 #include "pointer-group-interface.hh"
25
26 class Beam_collision_engraver : public Engraver
27 {
28 protected:
29   vector<Grob *> beams_;
30   vector<Grob *> covered_grobs_;
31
32   DECLARE_ACKNOWLEDGER (note_head);
33   DECLARE_ACKNOWLEDGER (accidental);
34   DECLARE_ACKNOWLEDGER (clef);
35   DECLARE_ACKNOWLEDGER (key_signature);
36   DECLARE_ACKNOWLEDGER (time_signature);
37   DECLARE_ACKNOWLEDGER (beam);
38
39   virtual void finalize ();
40
41 private:
42   bool covered_grob_has_interface (Grob *covered_grob, Grob *beam);
43
44 public:
45   TRANSLATOR_DECLARATIONS (Beam_collision_engraver);
46 };
47
48 Beam_collision_engraver::Beam_collision_engraver () {}
49
50 bool
51 Beam_collision_engraver::covered_grob_has_interface (Grob *covered_grob, Grob *beam)
52 {
53   SCM interfaces = beam->get_property ("collision-interfaces");
54
55   for (SCM l = interfaces; scm_is_pair (l); l = scm_cdr (l))
56     {
57       if (covered_grob->internal_has_interface (scm_car (l)));
58         return true;
59     }
60
61   return false;
62 }
63
64 void
65 Beam_collision_engraver::finalize ()
66 {
67   if (!covered_grobs_.size ())
68     return;
69
70   vector_sort (covered_grobs_, Grob::less);
71   vector_sort (beams_, Grob::less);
72   vsize start = 0;
73
74   for (vsize i = 0; i < beams_.size (); i++)
75     {
76       Interval_t<int> beam_spanned_rank_ = beams_[i]->spanned_rank_interval ();
77       // Start considering grobs at the first grob whose end falls at or after the beam's beginning.
78       while (covered_grobs_[start]->spanned_rank_interval ()[RIGHT] < beam_spanned_rank_[LEFT])
79         start++;
80
81       // Stop when the grob's beginning comes after the beam's end.
82       for (vsize j = start; j < covered_grobs_.size (); j++)
83         {
84           Interval_t<int> covered_grob_spanned_rank = covered_grobs_[j]->spanned_rank_interval ();
85           if ((covered_grob_spanned_rank[LEFT] > beam_spanned_rank_[RIGHT]
86               || !covered_grob_has_interface (covered_grobs_[j], beams_[i])))
87             break;
88           /*
89              Only consider grobs whose end falls at or after the beam's beginning.
90              If the grob is a beam, it cannot start before beams_[i]
91           */
92           if ((covered_grob_spanned_rank[RIGHT] >= beam_spanned_rank_[LEFT])
93               && !(Beam::has_interface (covered_grobs_[j])
94                    && (covered_grob_spanned_rank[LEFT] <= beam_spanned_rank_[LEFT])))
95             {
96               // Do not consider note heads attached to the beam.
97               bool my_beam = false;
98               if (Grob *stem = unsmob_grob (covered_grobs_[j]->get_object ("stem")))
99                 if (Grob *beam = unsmob_grob (stem->get_object ("beam")))
100                   if (beam == beams_[i])
101                     my_beam = true;
102
103               if (!my_beam)
104                 Pointer_group_interface::add_grob (beams_[i], ly_symbol2scm ("covered-grobs"), covered_grobs_[j]);
105             }
106         }
107     }
108 }
109
110 void
111 Beam_collision_engraver::acknowledge_note_head (Grob_info i)
112 {
113   covered_grobs_.push_back (i.grob ());
114 }
115
116 void
117 Beam_collision_engraver::acknowledge_accidental (Grob_info i)
118 {
119   if (i.grob ()->internal_has_interface (ly_symbol2scm ("inline-accidental-interface")))
120     covered_grobs_.push_back (i.grob ());
121 }
122
123 void
124 Beam_collision_engraver::acknowledge_clef (Grob_info i)
125 {
126   covered_grobs_.push_back (i.grob ());
127 }
128
129 void
130 Beam_collision_engraver::acknowledge_key_signature (Grob_info i)
131 {
132   covered_grobs_.push_back (i.grob ());
133 }
134
135 void
136 Beam_collision_engraver::acknowledge_time_signature (Grob_info i)
137 {
138   covered_grobs_.push_back (i.grob ());
139 }
140
141 void
142 Beam_collision_engraver::acknowledge_beam (Grob_info i)
143 {
144   beams_.push_back (i.grob ());
145   covered_grobs_.push_back (i.grob ());
146 }
147
148 #include "translator.icc"
149
150 ADD_ACKNOWLEDGER (Beam_collision_engraver, note_head);
151 ADD_ACKNOWLEDGER (Beam_collision_engraver, accidental);
152 ADD_ACKNOWLEDGER (Beam_collision_engraver, clef);
153 ADD_ACKNOWLEDGER (Beam_collision_engraver, key_signature);
154 ADD_ACKNOWLEDGER (Beam_collision_engraver, time_signature);
155 ADD_ACKNOWLEDGER (Beam_collision_engraver, beam);
156
157 ADD_TRANSLATOR (Beam_collision_engraver,
158                 /* doc */
159                 "Help beams avoid colliding with notes and clefs in other voices.",
160
161                 /* create */
162                 "",
163
164                 /* read */
165                 "",
166
167                 /* write */
168                 ""
169                 );