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