]> git.donarmstrong.com Git - lilypond.git/blob - lily/spanner.cc
patch::: 1.3.63.uu1: Re: Lilypond?
[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 #include <libc-extension.hh>
10
11 #include "dimension-cache.hh"
12 #include "debug.hh"
13 #include "spanner.hh"
14 #include "paper-column.hh"
15 #include "paper-score.hh"
16 #include "molecule.hh"
17 #include "paper-outputter.hh"
18 #include "paper-column.hh"
19 #include "line-of-score.hh"
20 #include "break-align-item.hh"
21
22
23 void
24 Spanner::do_break_processing ()
25 {
26   //break_into_pieces
27   Item * left = spanned_drul_[LEFT];
28   Item * right = spanned_drul_[RIGHT];
29
30   if (!left || !right)
31     return;
32   
33   if  (left == right)
34     {
35       warning (_f ("Spanner `%s' has equal left and right spanpoints",
36                    classname (this)));
37     }
38
39   /*
40     Check if our parent in X-direction spans equally wide
41     or wider than we do.
42    */
43   for (int a = X_AXIS; a < NO_AXES; a ++)
44     {
45       if (Spanner* parent = dynamic_cast<Spanner*> (parent_l ((Axis)a)))
46         {
47           if (!parent->spanned_rank_iv ().contains_b (this->spanned_rank_iv ()))
48             {
49               programming_error (to_str ("Spanner `%s' is not fully contained in parent spanner `%s'.",
50                                          classname (this),
51                                          classname (parent)));
52             }
53         }
54     }
55   
56   if (line_l () || broken_b ())
57     return;
58
59   if  (left == right)
60     {
61       /*
62         FIXME: this is broken.
63        */
64       /*
65         If we have a spanner spanning one column, we must break it
66         anyway because it might provide a parent for another item.  */
67       Direction d = LEFT;
68       do
69         {
70           Item* bound = left->find_prebroken_piece (d);
71           if (bound->line_l ())
72             {
73               Spanner * span_p = dynamic_cast<Spanner*>( clone ());
74               span_p->set_bound (LEFT, bound);
75               span_p->set_bound (RIGHT, bound);
76
77               assert (span_p->line_l ()); 
78               span_p->line_l ()->typeset_element (span_p);
79               broken_into_l_arr_.push (span_p);
80             }
81         }
82       while ((flip(&d))!= LEFT);
83     }
84   else
85     {
86       Link_array<Item> break_points = pscore_l_->line_l_->broken_col_range (left,right);
87
88       break_points.insert (left,0);
89       break_points.push (right);
90
91       for (int i=1; i < break_points.size(); i++) 
92         {
93           Drul_array<Item*> bounds;
94           bounds[LEFT] = break_points[i-1];
95           bounds[RIGHT] = break_points[i];
96           Direction d = LEFT;
97           do
98             {
99               if (!bounds[d]->line_l())
100                 bounds[d] = bounds[d]->find_prebroken_piece(- d);
101             }
102           while ((flip(&d))!= LEFT);
103
104           if (!bounds[LEFT] ||  ! bounds[RIGHT])
105             {
106               programming_error ("bounds of this piece aren't breakable. ");
107               continue; 
108             }
109
110           Spanner *span_p = dynamic_cast<Spanner*>(clone ());
111           span_p->set_bound(LEFT,bounds[LEFT]);
112           span_p->set_bound(RIGHT,bounds[RIGHT]);
113
114
115           assert (bounds[LEFT]->line_l () ==
116                   bounds[RIGHT]->line_l ());
117
118           bounds[LEFT]->line_l ()->typeset_element (span_p);
119           broken_into_l_arr_.push (span_p);
120         }
121     }
122   broken_into_l_arr_.sort (Spanner::compare);
123 }
124
125 void
126 Spanner::set_my_columns()
127 {
128   Direction i = (Direction) LEFT;
129   do 
130     {
131       if (!spanned_drul_[i]->line_l())
132         set_bound(i,spanned_drul_[i]->find_prebroken_piece((Direction) -i));
133     } 
134   while (flip(&i) != LEFT);
135 }       
136
137 Interval_t<int>
138 Spanner::spanned_rank_iv ()
139 {
140   Interval_t<int> iv (0, 0);
141
142   if (spanned_drul_[LEFT])
143     {
144       iv[LEFT] = spanned_drul_[LEFT]->column_l ()->rank_i ();
145     }
146   if (spanned_drul_[RIGHT])
147     {
148       iv[RIGHT] = spanned_drul_[RIGHT]->column_l ()->rank_i ();
149     }
150   return iv;
151 }
152
153 Item*
154 Spanner::get_bound (Direction d) const
155 {
156   return spanned_drul_ [d];
157 }
158
159 void
160 Spanner::set_bound(Direction d, Score_element*s)
161 {
162   Item * i = dynamic_cast<Item*> (s);
163   if (!i)
164     {
165       programming_error ("Must have Item for spanner bound.");
166       return;
167     }
168   
169   spanned_drul_[d] =i;
170
171   /**
172      We check for Line_of_score to prevent the column -> line_of_score
173      -> column -> line_of_score -> etc situation */
174   if (d== LEFT && !dynamic_cast<Line_of_score*> (this))
175     {
176       set_parent (i, X_AXIS);
177     }
178   
179   if (spanned_drul_[Direction(-d)] == spanned_drul_[d]
180        && i)
181     warning (_f ("Spanner `%s' has equal left and right spanpoints",
182                  classname (this)));
183 }
184
185
186 Spanner::Spanner (SCM s)
187   : Score_element (s)
188 {
189   spanned_drul_[LEFT]=0;
190   spanned_drul_[RIGHT]=0;
191 }
192
193 Spanner::Spanner (Spanner const &s)
194   : Score_element (s)
195 {
196   spanned_drul_[LEFT] = spanned_drul_[RIGHT] =0;
197 }
198
199
200 Real
201 Spanner::spanner_length() const
202 {  
203   Real l = spanned_drul_[LEFT]->relative_coordinate (0, X_AXIS);
204   Real r = spanned_drul_[RIGHT]->relative_coordinate (0, X_AXIS);
205
206   if (r< l)
207     programming_error ("spanner with negative length");
208
209   return r-l;
210 }
211
212 Line_of_score *
213 Spanner::line_l() const
214 {
215   if (!spanned_drul_[LEFT] || !spanned_drul_[RIGHT])
216     return 0;
217   if (spanned_drul_[LEFT]->line_l () != spanned_drul_[RIGHT]->line_l ())
218     return 0;
219   return spanned_drul_[LEFT]->line_l();
220 }
221
222
223 Score_element*
224 Spanner::find_broken_piece (Line_of_score*l) const
225 {
226   int idx = binsearch_link_array (broken_into_l_arr_,  (Spanner*)l, Spanner::compare);
227   
228   if (idx < 0)
229     return 0;
230   else
231     return broken_into_l_arr_ [idx];
232 }
233
234
235 int
236 Spanner::compare (Spanner * const &p1, Spanner * const &p2)
237 {
238   return p1->line_l ()->rank_i_ - p2->line_l ()->rank_i_;
239 }
240
241 bool
242 Spanner::broken_b() const
243 {
244   return broken_into_l_arr_.size();
245 }
246
247 Array<Rod>
248 Spanner::get_rods () const
249 {
250   Array<Rod> r;
251   return r;
252 }
253
254 Array<Spring>
255 Spanner::get_springs () const
256 {
257   Array<Spring> s;
258   return s;    
259 }
260
261 void
262 Spanner::do_space_processing ()
263 {
264   Array<Rod> rs (get_rods ());
265   for (int i=0; i < rs.size (); i++)
266     {
267       rs[i].add_to_cols ();
268     }
269
270   Array<Spring> ss (get_springs ());
271   for (int i=0; i < ss.size (); i++)
272     {
273       if (isinf (ss[i].distance_f_))
274         programming_error ("weird spring");
275       else
276         ss[i].add_to_cols ();
277     }
278 }
279
280 /*
281   If this is a broken spanner, return the amount the left end is to be
282   shifted horizontally so that the spanner starts after the initial
283   clef and key on the staves. This is necessary for ties, slurs,
284   crescendo and decrescendo signs, for example.
285 */
286 Real
287 Spanner::get_broken_left_end_align () const
288 {
289   Paper_column *sc = dynamic_cast<Paper_column*> (spanned_drul_[LEFT]->column_l());
290
291   // Relevant only if left span point is first column in line
292   if(sc != NULL &&
293      sc->break_status_dir () == RIGHT)
294     {
295       /*
296         
297         We used to do a full search for the Break_align_item.
298         But that doesn't make a difference, since the Paper_column
299         is likely to contain only a Break_align_item.
300       */
301       return sc->extent (X_AXIS)[RIGHT];
302     }
303
304   return 0.0;
305 }
306
307 void
308 Spanner::do_derived_mark ()
309 {
310   Direction d = LEFT;
311   do
312     if (spanned_drul_[d])
313       scm_gc_mark (spanned_drul_[d]->self_scm_);
314   while (flip (&d) != LEFT);
315 }
316