]> git.donarmstrong.com Git - lilypond.git/blob - lily/spanner.cc
patch::: 1.3.33.jcn3
[lilypond.git] / lily / spanner.cc
1 /*
2   spanner.cc -- implement Spanner
3
4   source file of the GNU LilyPond music typesetter
5
6   (c) 1996--2000 Han-Wen Nienhuys <hanwen@cs.uu.nl>
7 */
8 #include <math.h>
9
10 #include "dimension-cache.hh"
11 #include "debug.hh"
12 #include "spanner.hh"
13 #include "paper-column.hh"
14 #include "paper-score.hh"
15 #include "molecule.hh"
16 #include "paper-outputter.hh"
17 #include "paper-column.hh"
18 #include "line-of-score.hh"
19 #include "break-align-item.hh"
20
21 void
22 Spanner::do_break_processing()
23 {
24   //break_into_pieces
25   
26   if (line_l () || broken_b ())
27     return;
28   
29   Item * left = spanned_drul_[LEFT];
30   Item * right = spanned_drul_[RIGHT];
31
32   if  (left == right)
33     {
34       warning (_ ("Left spanpoint is right spanpoint"));
35
36       /*
37         FIXME: this is broken.
38        */
39       /*
40         If we have a spanner spanning one column, we must break it
41         anyway because it might provide a parent for another item.  */
42       Direction d = LEFT;
43       do
44         {
45           Item* bound = left->find_broken_piece (d);
46           Spanner * span_p = dynamic_cast<Spanner*>( clone ());
47           span_p->set_bound (LEFT, bound);
48           span_p->set_bound (RIGHT, bound);
49
50           assert (span_p->line_l ()); 
51           pscore_l_->typeset_element (span_p);
52           broken_into_l_arr_.push (span_p);
53         }
54       while ((flip(&d))!= LEFT);
55     }
56   else
57     {
58       Link_array<Item> break_points = pscore_l_->broken_col_range (left,right);
59
60       break_points.insert (left,0);
61       break_points.push (right);
62
63       for (int i=1; i < break_points.size(); i++) 
64         {
65           Drul_array<Item*> bounds;
66           bounds[LEFT] = break_points[i-1];
67           bounds[RIGHT] = break_points[i];
68           Direction d = LEFT;
69           do
70             {
71               Item *&pc_l = bounds[d] ;
72               if (!pc_l->line_l())
73                 pc_l =  pc_l->find_broken_piece(- d);
74           
75               assert (pc_l);
76             }
77           while ((flip(&d))!= LEFT);
78
79           Spanner *span_p = dynamic_cast<Spanner*>(clone ());
80           span_p->set_bound(LEFT,bounds[LEFT]);
81           span_p->set_bound(RIGHT,bounds[RIGHT]);
82       
83           pscore_l_->typeset_element (span_p);
84           broken_into_l_arr_.push (span_p);
85         }
86     }
87   broken_into_l_arr_.sort (Spanner::compare);
88 }
89
90 void
91 Spanner::set_my_columns()
92 {
93   Direction i = (Direction) LEFT;
94   do 
95     {
96       if (!spanned_drul_[i]->line_l())
97         set_bound(i,spanned_drul_[i]->find_broken_piece((Direction) -i));
98     } 
99   while (flip(&i) != LEFT);
100 }       
101
102
103 Item*
104 Spanner::get_bound (Direction d) const
105 {
106   return spanned_drul_ [d];
107 }
108
109 void
110 Spanner::set_bound(Direction d, Item*i)
111 {
112   spanned_drul_[d] =i;
113   if (i)
114     {
115       i->used_b_ = true;
116     }
117
118   /**
119      Prevent the column -> line_of_score -> column -> line_of_score -> etc situation
120   */
121   if (d== LEFT && !dynamic_cast<Line_of_score*> (this))
122     {
123       set_parent (i, X_AXIS);
124     }
125   
126   if (spanned_drul_[Direction(-d)] == spanned_drul_[d]
127        && i)
128     warning (_f ("Spanner `%s' has equal left and right spanpoints", classname (this)));
129 }
130
131
132 Spanner::Spanner ()
133 {
134   spanned_drul_[LEFT]=0;
135   spanned_drul_[RIGHT]=0;
136 }
137
138 Spanner::Spanner (Spanner const &s)
139   : Score_element (s)
140 {
141   spanned_drul_[LEFT] = spanned_drul_[RIGHT] =0;
142 }
143
144
145 Real
146 Spanner::spanner_length() const
147 {  
148   Real l = spanned_drul_[LEFT]->relative_coordinate (0, X_AXIS);
149   Real r = spanned_drul_[RIGHT]->relative_coordinate (0, X_AXIS);
150
151   if (r< l)
152     programming_error ("spanner with negative length");
153
154   return r-l;
155 }
156
157 Line_of_score *
158 Spanner::line_l() const
159 {
160   if (!spanned_drul_[LEFT] || !spanned_drul_[RIGHT])
161     return 0;
162   if (spanned_drul_[LEFT]->line_l () != spanned_drul_[RIGHT]->line_l ())
163     return 0;
164   return spanned_drul_[LEFT]->line_l();
165 }
166
167
168 Score_element*
169 Spanner::find_broken_piece (Line_of_score*l) const
170 {
171   int idx = binsearch_link_array (broken_into_l_arr_,  (Spanner*)l, Spanner::compare);
172   
173   if (idx < 0)
174     return 0;
175   else
176     return broken_into_l_arr_ [idx];
177 }
178
179
180 int
181 Spanner::compare (Spanner * const &p1, Spanner * const &p2)
182 {
183   return p1->line_l ()->rank_i_ - p2->line_l ()->rank_i_;
184 }
185
186 bool
187 Spanner::broken_b() const
188 {
189   return broken_into_l_arr_.size();
190 }
191
192 Array<Rod>
193 Spanner::get_rods () const
194 {
195   Array<Rod> r;
196   return r;
197 }
198
199 Array<Spring>
200 Spanner::get_springs () const
201 {
202   Array<Spring> s;
203   return s;    
204 }
205
206 void
207 Spanner::do_space_processing ()
208 {
209   Array<Rod> rs (get_rods ());
210   for (int i=0; i < rs.size (); i++)
211     {
212       rs[i].add_to_cols ();
213     }
214
215   Array<Spring> ss (get_springs ());
216   for (int i=0; i < ss.size (); i++)
217     {
218       if (isinf (ss[i].distance_f_))
219         programming_error ("weird spring");
220       else
221         ss[i].add_to_cols ();
222     }
223 }
224
225 /*
226   If this is a broken spanner, return the amount the left end is to be
227   shifted horizontally so that the spanner starts after the initial
228   clef and key on the staves. This is necessary for ties, slurs,
229   crescendo and decrescendo signs, for example.
230 */
231 Real
232 Spanner::get_broken_left_end_align () const
233 {
234   Paper_column *sc = dynamic_cast<Paper_column*> (spanned_drul_[LEFT]->column_l());
235
236   // Relevant only if left span point is first column in line
237   if(sc != NULL &&
238      sc->break_status_dir () == RIGHT)
239     {
240       /*
241         
242         We used to do a full search for the Break_align_item.
243         But that doesn't make a difference, since the Paper_column
244         is likely to contain only a Break_align_item.
245       */
246       return sc->extent (X_AXIS)[RIGHT];
247     }
248
249   return 0.0;
250 }