]> git.donarmstrong.com Git - lilypond.git/blob - lily/collision.cc
b4136ae520efe85490c286bde43bad70aebd5b11
[lilypond.git] / lily / collision.cc
1 /*
2   collision.cc -- implement Collision
3
4   source file of the GNU LilyPond music typesetter
5
6   (c)  1997--1999 Han-Wen Nienhuys <hanwen@cs.uu.nl>
7 */
8 #include "debug.hh"
9 #include "collision.hh"
10 #include "note-column.hh"
11 #include "note-head.hh"
12 #include "paper-def.hh"
13
14 Collision::Collision()
15 {
16   set_axes (X_AXIS, Y_AXIS);
17 }
18
19 void
20 Collision::add_column (Note_column* ncol_l)
21 {
22   clash_l_arr_.push (ncol_l);
23   add_element (ncol_l);
24   add_dependency (ncol_l);
25 }
26 /**
27   should derive of Array.
28  */
29 static
30 int idx (int dir, bool h_shift_b)
31 {
32   assert (abs (dir) == 1);
33   int j = dir > 0 ? 0 : 3;
34   if (h_shift_b)
35     j += dir;
36   return j;
37 }
38
39 /** This complicated routine moves note columns around horizontally
40   (and rests vertically) to ensure that notes don't clash.
41
42   This should be done better, probably.
43
44   This routine is dedicated to Stine Randmael :-)
45
46   */
47 void
48 Collision::do_pre_processing()
49 {
50   if (clash_l_arr_.size() <= 1)
51     return;
52
53   /*
54     [stem up, stem up shifted, stem down shifted, stem down]
55   */ 
56   Array<Note_column*> clash_group_arr_a[4]; // TODO: use drul.
57
58   for (int i=0; i < clash_l_arr_.size(); i++)
59     {
60       Note_column* c_l = clash_l_arr_[i];
61       Direction d = c_l->dir ();
62       if (!d)
63         {
64           warning (_ ("No stem direction set. Ignoring column in clash."));
65           continue;
66         }
67
68       SCM shift = c_l->remove_elt_property (horizontal_shift_scm_sym);
69       bool shift_b  = (shift != SCM_BOOL_F);
70       clash_group_arr_a[idx (d, shift_b)].push (c_l);
71     }
72
73
74   for (int j=0; j < 4; j++)
75     {
76       if (clash_group_arr_a[j].size() > 1)
77         {
78           warning (_ ("Too many clashing notecolumns. Ignoring them."));
79           return;
80         }
81     }
82   Direction d = UP;
83   do
84     {
85       if (!clash_group_arr_a[idx (d, false)].size())
86         {
87           clash_group_arr_a[idx (d,  false)] = clash_group_arr_a[idx (d, true)];
88           clash_group_arr_a[idx (d, true)].clear();
89         }
90     }
91   while (flip (&d) != UP);
92
93
94   Interval_t<int> y_extent[4];
95   Note_column * col_l_a[4];
96   Real x_off [4];
97
98   for (int j =0 ; j < 4; j++)
99     {
100       if (clash_group_arr_a[j].size())
101         col_l_a[j] = clash_group_arr_a[j][0];
102       else
103         col_l_a[j] = 0;
104
105       if (col_l_a[j])
106         {
107           y_extent[j] = col_l_a[j]->head_positions_interval();
108         }
109
110
111       x_off [j] = 0.0;
112     }
113
114   do
115     {
116       x_off[idx (d, true)] = d*0.5;
117     }
118   while (flip (&d) != UP);
119
120
121   // y_extent: smallest y-pos noteball interval containing all balls
122   // 4 (0..3) groups: stem up/down; shift on/off;
123   Interval_t<int> middle (y_extent[idx (-1,0)][BIGGER],
124                           y_extent[idx (1,0)][SMALLER]);
125   Interval_t<int> open_middle (y_extent[idx (-1,0)][BIGGER]+1, y_extent[idx (1,0)][SMALLER]-1);
126   do
127     {
128       if (!open_middle.contains_b (y_extent[idx (d,true)]))
129         x_off[idx (d, true)] = d *1.0 ;
130     } while ((d *= -1) != 1);
131
132
133   if (!middle.empty_b()
134       && middle.length() < 2 && col_l_a[idx (1,0)] && col_l_a[idx (-1,0)])
135     {
136       // reproduction of bugfix at 3am ?
137       Note_head * nu_l= col_l_a[idx (1,0)]->head_l_arr_[0];
138       Note_head * nd_l = col_l_a[idx (-1,0)]->head_l_arr_.top();
139       if (! (nu_l->balltype_i_ == nd_l->balltype_i_
140              && nu_l->dots_i_ == nd_l->dots_i_  && middle.length() == 0))
141         {
142           do
143             {
144               x_off[idx (d, false)] -= d*0.5;
145               x_off[idx (d, true)] -= d*0.5;
146             }
147           while (flip (&d) != UP);
148         }
149     }
150
151   Real wid_f = paper_l ()->note_width ();
152   for (int j=0; j < 4; j++)
153     {
154       if (col_l_a[j])
155         {
156           Offset o (x_off[j] * wid_f, 0);
157           col_l_a[j]->translate (o);
158         }
159     }
160 }
161
162
163
164
165 void
166 Collision::do_substitute_element_pointer (Score_element*o_l,Score_element*n_l)
167 {
168   if (o_l)
169     {
170       clash_l_arr_.substitute (dynamic_cast<Note_column *> (o_l),
171                                dynamic_cast <Note_column *> (n_l));
172
173     }
174 }