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