]> git.donarmstrong.com Git - lilypond.git/blob - lily/collision.cc
release: 0.1.7
[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_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];
57     
58     for (int i=0; i < clash_l_arr_.size(); i++) {
59         Note_column* c_l = clash_l_arr_[i];
60         if (! c_l->dir_i_) {
61             warning ("No stem direction set. Ignoring column in clash. ");
62             continue;
63         }
64         int d = (c_l->dir_i_);
65         
66         clash_group_arr_a[idx(d, c_l->h_shift_b_)].push(c_l);
67     }
68     
69     
70     for (int j=0; j < 4; j++) {
71         if (clash_group_arr_a[j].size() > 1) {
72             warning("Too many clashing notecolumns. Ignoring them.");
73             return;
74         }
75     }
76     int d = 1;
77     do {
78         if (!clash_group_arr_a[idx(d, false)].size()){
79             clash_group_arr_a[idx(d,  false)] = clash_group_arr_a[idx(d, true)];
80             clash_group_arr_a[idx(d, true)].clear();
81         }
82     } while ((d *= -1) != 1);
83                                   
84
85     Interval_t<int> y_extent[4];
86     Note_column * col_l_a[4];
87     Real x_off [4];
88     int y_off[4];
89     
90     for (int j =0 ; j < 4; j++) {
91         if (clash_group_arr_a[j].size()) 
92             col_l_a[j] = clash_group_arr_a[j][0];
93         else
94             col_l_a[j] = 0;
95         
96         if (col_l_a[j]) {
97             y_extent[j] = col_l_a[j]->head_positions_interval();
98         }
99
100
101         x_off [j] = 0.0;
102         y_off[j] = 0;
103     }
104     
105     do {
106         x_off[idx(d, true)] = d*0.5;
107     } while ((d *= -1) != 1);
108
109   
110     // y_extent: smallest y-pos noteball interval containing all balls
111     // 4 (0..3) groups: stem up/down; shift on/off; 
112     Interval_t<int> middle( y_extent[idx(-1,0)].max(),
113                             y_extent[idx(1,0)].min() );
114     Interval_t<int> open_middle( y_extent[idx(-1,0)].max()+1, y_extent[idx(1,0)].min()-1);
115     do{
116         if (!open_middle.contains_b(y_extent[idx(d,true)]))
117             x_off[idx(d, true)] = d *1.0 ;
118     } while ((d *= -1) != 1);
119    
120     if (!middle.empty_b() 
121         && middle.length() < 2 && col_l_a[idx(1,0)] && col_l_a[idx(-1,0)]) {    
122 // reproduction of bugfix at 3am ?
123         Note_head * nu_l= col_l_a[idx(1,0)]->head_l_arr_[0];
124         Note_head * nd_l = col_l_a[idx(-1,0)]->head_l_arr_.top();
125         if (! (nu_l->balltype_i_ == nd_l->balltype_i_ 
126                && nu_l->dots_i_ == nd_l->dots_i_  && middle.length() == 0 )) {
127             x_off[idx(1,0)] -= 0.5;
128             x_off[idx(1,1)] -= 0.5;
129             x_off[idx(-1,1)] += 0.5;
130             x_off[idx(-1,0)] += 0.5;
131         }
132         
133     }    
134     Real inter_f = paper()->internote_f();
135     Real wid_f = paper()->note_width();
136     for (int j=0; j < 4; j++) {
137         if (col_l_a[j]) {
138             /* collision.cc:138: request for method `translate' is ambiguous 
139                
140                (shaddup)
141              */
142             Offset o(x_off[j] * wid_f, y_off[j] * inter_f);
143             ((Score_elem*)col_l_a[j])->translate(o);
144         }
145     }
146 }
147
148
149 IMPLEMENT_IS_TYPE_B1(Collision, Item);
150
151 void
152 Collision::do_substitute_dependency(Score_elem*o_l,Score_elem*n_l)
153 {
154     clash_l_arr_.substitute((Note_column*)o_l->item(), 
155                             (Note_column*)(n_l?n_l->item():0));
156 }