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