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