]> git.donarmstrong.com Git - lilypond.git/blob - lily/collision.cc
f9a15bc4fa4a11615a42c022e713fa9c8dc1e197
[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 Han-Wen Nienhuys <hanwen@stack.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     empty_b_ = transparent_b_ =true;
17 }
18
19 void
20 Collision::add(Note_column* ncol_l)
21 {
22     clash_l_arr_.push(ncol_l);
23     add_dependency(ncol_l);
24 }
25 /**
26   should derive of Array.
27  */
28 static 
29 int idx(int dir, bool h_shift_b)
30 {
31     assert(abs (dir) == 1);
32     int j = dir > 0 ? 0 : 3;
33     if ( h_shift_b ) 
34         j += dir;
35     return j;
36 }
37
38 /** This complicated routine moves note columns around horizontally
39   (and rests vertically) to ensure that notes don't clash. 
40
41   This should be done better, probably.  
42
43   This routine is dedicated to Stine Randmael :-)
44
45   */
46 void
47 Collision::do_pre_processing()
48 {
49     if (clash_l_arr_.size() <= 1)
50         return;
51     
52     /*
53       [stem up, stem up shifted, stem down shifted, stem down]
54      */
55     Array<Note_column*> clash_group_arr_a[4];
56     
57     for (int i=0; i < clash_l_arr_.size(); i++) {
58         Note_column* c_l = clash_l_arr_[i];
59         if (! c_l->dir_i_) {
60             warning ("No stem direction set. Ignoring column in clash. ");
61             continue;
62         }
63         int d = (c_l->dir_i_);
64         
65         clash_group_arr_a[idx(d, c_l->h_shift_b_)].push(c_l);
66     }
67     
68     
69     for (int j=0; j < 4; j++) {
70         if (clash_group_arr_a[j].size() > 1) {
71             warning("Too many clashing notecolumns. Ignoring them.");
72             return;
73         }
74     }
75     int d = 1;
76     do {
77         if (!clash_group_arr_a[idx(d, false)].size()){
78             clash_group_arr_a[idx(d,  false)] = clash_group_arr_a[idx(d, true)];
79             clash_group_arr_a[idx(d, true)].set_size(0);
80         }
81     } while ((d *= -1) != 1);
82                                   
83
84     Interval_t<int> y_extent[4];
85     Note_column * col_l_a[4];
86     Real x_off [4];
87     int y_off[4];
88     
89     for (int j =0 ; j < 4; j++) {
90         if (clash_group_arr_a[j].size()) 
91             col_l_a[j] = clash_group_arr_a[j][0];
92         else
93             col_l_a[j] = 0;
94         
95         if (col_l_a[j]) {
96             y_extent[j] = col_l_a[j]->head_positions_interval();
97         }
98
99
100         x_off [j] = 0.0;
101         y_off[j] = 0;
102     }
103     
104     do {
105         x_off[idx(d, true)] = d*0.5;
106     } while ((d *= -1) != 1);
107
108   
109     // y_extent: smallest y-pos noteball interval containing all balls
110     // 4 (0..3) groups: stem up/down; shift on/off; 
111     Interval_t<int> middle( y_extent[idx(-1,0)].max(),
112                             y_extent[idx(1,0)].min() );
113     Interval_t<int> open_middle( y_extent[idx(-1,0)].max()+1, y_extent[idx(1,0)].min()-1);
114     do{
115         if (!open_middle.contains_b(y_extent[idx(d,true)]))
116             x_off[idx(d, true)] = d *1.0 ;
117     } while ((d *= -1) != 1);
118    
119     if (!middle.empty_b() 
120         && middle.length() < 2 && col_l_a[idx(1,0)] && col_l_a[idx(-1,0)]) {    
121 // reproduction of bugfix at 3am ?
122         Note_head * nu_l= col_l_a[idx(1,0)]->head_l_arr_[0];
123         Note_head * nd_l = col_l_a[idx(-1,0)]->head_l_arr_.top();
124         if (! (nu_l->balltype_i_ == nd_l->balltype_i_ 
125                && nu_l->dots_i_ == nd_l->dots_i_  && middle.length() == 0 )) {
126             x_off[idx(1,0)] -= 0.5;
127             x_off[idx(1,1)] -= 0.5;
128             x_off[idx(-1,1)] += 0.5;
129             x_off[idx(-1,0)] += 0.5;
130         }
131         
132     }    
133     Real inter_f = paper()->internote_f();
134     Real wid_f = paper()->note_width();
135     for (int j=0; j < 4; j++) {
136         if (col_l_a[j])
137             col_l_a[j]->translate(Offset(x_off[j] * wid_f,
138                                          y_off[j] * inter_f));
139         
140     }
141 }
142
143
144 IMPLEMENT_IS_TYPE_B1(Collision, Item);
145
146 void
147 Collision::do_substitute_dependency(Score_elem*o_l,Score_elem*n_l)
148 {
149     clash_l_arr_.substitute((Note_column*)o_l->item(), 
150                             (Note_column*)(n_l?n_l->item():0));
151 }