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