]> git.donarmstrong.com Git - lilypond.git/blob - lily/collision.cc
1ddff7d2f7cc3f880b3edcc1dc967453e8b52dbf
[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
28 /** This complicated routine moves note columns around horizontally to
29   ensure that notes don't clash.
30
31   This should be done better, probably.
32
33   TODO: forced hshift
34   
35   */
36 void
37 Collision::do_pre_processing()
38 {
39   Drul_array<Link_array<Note_column> > clash_groups;
40   Drul_array<Array<int> > shifts;
41   
42   for (int i=0; i < clash_l_arr_.size(); i++)
43     {
44       clash_groups[clash_l_arr_[i]->dir ()].push (clash_l_arr_[i]);
45     }
46
47   
48   Direction d = UP;
49   do
50     {
51       Array<int> & shift (shifts[d]);
52       Link_array<Note_column> & clashes (clash_groups[d]);
53
54       clashes.sort (Note_column::shift_compare);
55
56       for (int i=0; i < clashes.size (); i++)
57         {
58           SCM sh
59             = clashes[i]->remove_elt_property (horizontal_shift_scm_sym);
60
61           if (sh == SCM_BOOL_F)
62             shift.push (0);
63           else
64             shift.push (gh_scm2int (SCM_CDR (sh)));
65         }
66       
67       for (int i=1; i < shift.size (); i++)
68         {
69           if (shift[i-1] == shift[i])
70             {
71               warning (_ ("Too many clashing notecolumns. Ignoring them."));
72               return;
73             }
74         }
75     }
76   while ((flip (&d))!= UP);
77
78   Drul_array< Array < Slice > > extents;
79   Drul_array< Array < Real > > offsets;
80   d = UP;
81   do
82     {
83       for (int i=0; i < clash_groups[d].size (); i++)
84         {
85           Slice s(clash_groups[d][i]->head_positions_interval ());
86           s[LEFT] --;
87           s[RIGHT]++;
88           extents[d].push (s);
89           offsets[d].push (d * 0.5 * i);
90         }
91     }
92   while ((flip (&d))!= UP);
93   
94   do
95     {
96       for (int i=1; i < clash_groups[d].size (); i++)
97         {
98           Slice prev =extents[d][i-1];
99           prev.intersect (extents[d][i]);
100           if (prev.length ()> 0 ||
101               (extents[-d].size () && d * (extents[d][i][-d] - extents[-d][0][d]) < 0))
102             for (int j = i; j <  clash_groups[d].size (); j++)
103               offsets[d][j] += d * 0.5;
104         }
105     }   
106   while ((flip (&d))!= UP);
107
108   /*
109     if the up and down version are close, and can not be merged, move
110     all of them again. */
111   if (extents[UP].size () && extents[DOWN].size ())
112     {
113       Note_column *cu_l =clash_groups[UP][0];
114       Note_column *cd_l =clash_groups[DOWN][0];
115       Note_head * nu_l= cu_l->head_l_arr_[0];
116       Note_head * nd_l = cd_l->head_l_arr_.top();
117       int downpos =     cd_l->head_positions_interval ()[SMALLER];
118       int uppos =       cu_l->head_positions_interval ()[BIGGER];      
119       
120       bool merge  =
121         downpos == uppos
122         && nu_l->balltype_i_ == nd_l->balltype_i_
123         && nu_l->dots_i_ == nd_l->dots_i_;
124
125       /*
126         notes are close, but can not be merged.  Shift
127        */
128       if (abs(uppos - downpos) < 2 && !merge)
129           do
130           {
131             for (int i=0; i < clash_groups[d].size (); i++)
132               {
133                 offsets[d][i] -= d * 0.5;
134               }
135           }
136           while ((flip (&d))!= UP);
137     }
138
139   Real wid_f = paper_l ()->note_width ();
140   do
141     {
142       for (int i=0; i < clash_groups[d].size (); i++)
143         {
144           clash_groups[d][i]->translate_axis (offsets[d][i]*wid_f, X_AXIS);
145         }
146     }
147   while (flip (&d) != UP);
148 }
149
150
151 void
152 Collision::do_substitute_element_pointer (Score_element*o_l,Score_element*n_l)
153 {
154   if (o_l)
155     {
156       clash_l_arr_.substitute (dynamic_cast<Note_column *> (o_l),
157                                dynamic_cast <Note_column *> (n_l));
158
159     }
160 }