]> git.donarmstrong.com Git - lilypond.git/blob - lily/spanner.cc
release: 1.3.22
[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, 1997--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 void
22 Spanner::do_break_processing()
23 {
24   //break_into_pieces
25   
26   if (line_l () || broken_b ())
27     return;
28   
29   Item * left = spanned_drul_[LEFT];
30   Item * right = spanned_drul_[RIGHT];
31
32   if  (left == right)
33     {
34       warning (_ ("Left spanpoint is right spanpoint"));
35       return;
36     }
37   
38   Link_array<Item> break_points = pscore_l_->broken_col_range (left,right);
39
40   break_points.insert (left,0);
41   break_points.push (right);
42
43   for (int i=1; i < break_points.size(); i++) 
44     {
45       Drul_array<Item*> bounds;
46       bounds[LEFT] = break_points[i-1];
47       bounds[RIGHT] = break_points[i];
48       Direction d = LEFT;
49       do
50         {
51           Item *&pc_l = bounds[d] ;
52           if (!pc_l->line_l())
53             pc_l =  pc_l->find_broken_piece(- d);
54           
55           assert (pc_l);
56         }
57       while ((flip(&d))!= LEFT);
58
59       Spanner *span_p = dynamic_cast<Spanner*>(clone ());
60       span_p->set_bounds(LEFT,bounds[LEFT]);
61       span_p->set_bounds(RIGHT,bounds[RIGHT]);
62       
63       pscore_l_->typeset_element (span_p);
64       broken_into_l_arr_.push (span_p);
65     }
66
67   broken_into_l_arr_.sort (Spanner::compare);
68 }
69
70 void
71 Spanner::set_my_columns()
72 {
73   Direction i = (Direction) LEFT;
74   do 
75     {
76       if (!spanned_drul_[i]->line_l())
77         set_bounds(i,spanned_drul_[i]->find_broken_piece((Direction) -i));
78     } 
79   while (flip(&i) != LEFT);
80 }       
81
82 void
83 Spanner::set_bounds(Direction d, Item*i)
84 {
85   spanned_drul_[d] =i;
86   if (i)
87     {
88       i->used_b_ = true;
89     }
90
91   /**
92      Prevent the column -> line_of_score -> column -> line_of_score -> etc situation
93   */
94   if (d== LEFT && !dynamic_cast<Line_of_score*> (this))
95     {
96       set_parent (i, X_AXIS);
97     }
98   
99   if (spanned_drul_[Direction(-d)] == spanned_drul_[d]
100        && i)
101     warning (_f ("Spanner `%s' has equal left and right spanpoints", classname (this)));
102 }
103
104
105 Spanner::Spanner ()
106 {
107   spanned_drul_[LEFT]=0;
108   spanned_drul_[RIGHT]=0;
109 }
110
111 Spanner::Spanner (Spanner const &s)
112   : Score_element (s)
113 {
114   spanned_drul_[LEFT] = spanned_drul_[RIGHT] =0;
115 }
116
117
118 Real
119 Spanner::spanner_length() const
120 {  
121   Real l = spanned_drul_[LEFT]->relative_coordinate (0, X_AXIS);
122   Real r = spanned_drul_[RIGHT]->relative_coordinate (0, X_AXIS);
123
124   if (r< l)
125     programming_error ("spanner with negative length");
126
127   return r-l;
128 }
129
130 Line_of_score *
131 Spanner::line_l() const
132 {
133   if (!spanned_drul_[LEFT] || !spanned_drul_[RIGHT])
134     return 0;
135   if (spanned_drul_[LEFT]->line_l () != spanned_drul_[RIGHT]->line_l ())
136     return 0;
137   return spanned_drul_[LEFT]->line_l();
138 }
139
140
141 Score_element*
142 Spanner::find_broken_piece (Line_of_score*l) const
143 {
144   int idx = binsearch_link_array (broken_into_l_arr_,  (Spanner*)l, Spanner::compare);
145   
146   if (idx < 0)
147     return 0;
148   else
149     return broken_into_l_arr_ [idx];
150 }
151
152
153 int
154 Spanner::compare (Spanner * const &p1, Spanner * const &p2)
155 {
156   return p1->line_l ()->rank_i_ - p2->line_l ()->rank_i_;
157 }
158
159 bool
160 Spanner::broken_b() const
161 {
162   return broken_into_l_arr_.size();
163 }
164
165 Array<Rod>
166 Spanner::get_rods () const
167 {
168   Array<Rod> r;
169   return r;
170 }
171
172 Array<Spring>
173 Spanner::get_springs () const
174 {
175   Array<Spring> s;
176   return s;    
177 }
178
179 void
180 Spanner::do_space_processing ()
181 {
182   Array<Rod> rs (get_rods ());
183   for (int i=0; i < rs.size (); i++)
184     {
185       rs[i].add_to_cols ();
186     }
187
188   Array<Spring> ss (get_springs ());
189   for (int i=0; i < ss.size (); i++)
190     {
191       if (isinf (ss[i].distance_f_))
192         programming_error ("weird spring");
193       else
194         ss[i].add_to_cols ();
195     }
196 }
197
198 /*
199   If this is a broken spanner, return the amount the left end is to be
200   shifted horizontally so that the spanner starts after the initial
201   clef and key on the staves. This is necessary for ties, slurs,
202   crescendo and decrescendo signs, for example.
203 */
204 Real
205 Spanner::get_broken_left_end_align () const
206 {
207   Paper_column *sc = dynamic_cast<Paper_column*> (spanned_drul_[LEFT]->column_l());
208
209   // Relevant only if left span point is first column in line
210   if(sc != NULL &&
211      sc->break_status_dir () == RIGHT)
212     {
213       /*
214         
215         We used to do a full search for the Break_align_item.
216         But that doesn't make a difference, since the Paper_column
217         is likely to contain only a Break_align_item.
218       */
219       return sc->extent (X_AXIS)[RIGHT];
220     }
221
222   return 0.0;
223 }