]> git.donarmstrong.com Git - lilypond.git/blob - lily/spanner.cc
release: 1.3.58
[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, Item*i)
161 {
162   spanned_drul_[d] =i;
163
164   /**
165      We check for Line_of_score to prevent the column -> line_of_score
166      -> column -> line_of_score -> etc situation */
167   if (d== LEFT && !dynamic_cast<Line_of_score*> (this))
168     {
169       set_parent (i, X_AXIS);
170     }
171   
172   if (spanned_drul_[Direction(-d)] == spanned_drul_[d]
173        && i)
174     warning (_f ("Spanner `%s' has equal left and right spanpoints",
175                  classname (this)));
176 }
177
178
179 Spanner::Spanner (SCM s)
180   : Score_element (s)
181 {
182   spanned_drul_[LEFT]=0;
183   spanned_drul_[RIGHT]=0;
184 }
185
186 Spanner::Spanner (Spanner const &s)
187   : Score_element (s)
188 {
189   spanned_drul_[LEFT] = spanned_drul_[RIGHT] =0;
190 }
191
192
193 Real
194 Spanner::spanner_length() const
195 {  
196   Real l = spanned_drul_[LEFT]->relative_coordinate (0, X_AXIS);
197   Real r = spanned_drul_[RIGHT]->relative_coordinate (0, X_AXIS);
198
199   if (r< l)
200     programming_error ("spanner with negative length");
201
202   return r-l;
203 }
204
205 Line_of_score *
206 Spanner::line_l() const
207 {
208   if (!spanned_drul_[LEFT] || !spanned_drul_[RIGHT])
209     return 0;
210   if (spanned_drul_[LEFT]->line_l () != spanned_drul_[RIGHT]->line_l ())
211     return 0;
212   return spanned_drul_[LEFT]->line_l();
213 }
214
215
216 Score_element*
217 Spanner::find_broken_piece (Line_of_score*l) const
218 {
219   int idx = binsearch_link_array (broken_into_l_arr_,  (Spanner*)l, Spanner::compare);
220   
221   if (idx < 0)
222     return 0;
223   else
224     return broken_into_l_arr_ [idx];
225 }
226
227
228 int
229 Spanner::compare (Spanner * const &p1, Spanner * const &p2)
230 {
231   return p1->line_l ()->rank_i_ - p2->line_l ()->rank_i_;
232 }
233
234 bool
235 Spanner::broken_b() const
236 {
237   return broken_into_l_arr_.size();
238 }
239
240 Array<Rod>
241 Spanner::get_rods () const
242 {
243   Array<Rod> r;
244   return r;
245 }
246
247 Array<Spring>
248 Spanner::get_springs () const
249 {
250   Array<Spring> s;
251   return s;    
252 }
253
254 void
255 Spanner::do_space_processing ()
256 {
257   Array<Rod> rs (get_rods ());
258   for (int i=0; i < rs.size (); i++)
259     {
260       rs[i].add_to_cols ();
261     }
262
263   Array<Spring> ss (get_springs ());
264   for (int i=0; i < ss.size (); i++)
265     {
266       if (isinf (ss[i].distance_f_))
267         programming_error ("weird spring");
268       else
269         ss[i].add_to_cols ();
270     }
271 }
272
273 /*
274   If this is a broken spanner, return the amount the left end is to be
275   shifted horizontally so that the spanner starts after the initial
276   clef and key on the staves. This is necessary for ties, slurs,
277   crescendo and decrescendo signs, for example.
278 */
279 Real
280 Spanner::get_broken_left_end_align () const
281 {
282   Paper_column *sc = dynamic_cast<Paper_column*> (spanned_drul_[LEFT]->column_l());
283
284   // Relevant only if left span point is first column in line
285   if(sc != NULL &&
286      sc->break_status_dir () == RIGHT)
287     {
288       /*
289         
290         We used to do a full search for the Break_align_item.
291         But that doesn't make a difference, since the Paper_column
292         is likely to contain only a Break_align_item.
293       */
294       return sc->extent (X_AXIS)[RIGHT];
295     }
296
297   return 0.0;
298 }
299
300 void
301 Spanner::do_derived_mark ()
302 {
303   Direction d = LEFT;
304   do
305     if (spanned_drul_[d])
306       scm_gc_mark (spanned_drul_[d]->self_scm_);
307   while (flip (&d) != LEFT);
308 }
309