lilypond-1.3.69
[lilypond.git] / lily / spanner.cc
blobb272827ba4e22d758828e88ede2b942f89a89890
1 /*
2 spanner.cc -- implement Spanner
4 source file of the GNU LilyPond music typesetter
6 (c) 1996--2000 Han-Wen Nienhuys <hanwen@cs.uu.nl>
7 */
8 #include <math.h>
9 #include <libc-extension.hh>
12 #include "debug.hh"
13 #include "spanner.hh"
14 #include "paper-column.hh"
15 #include "paper-score.hh"
16 #include "molecule.hh"
17 #include "paper-outputter.hh"
18 #include "paper-column.hh"
19 #include "line-of-score.hh"
20 #include "break-align-item.hh"
23 void
24 Spanner::do_break_processing ()
26 //break_into_pieces
27 Item * left = spanned_drul_[LEFT];
28 Item * right = spanned_drul_[RIGHT];
30 if (!left || !right)
31 return;
34 Check if our parent in X-direction spans equally wide
35 or wider than we do.
37 for (int a = X_AXIS; a < NO_AXES; a ++)
39 if (Spanner* parent = dynamic_cast<Spanner*> (parent_l ((Axis)a)))
41 if (!parent->spanned_rank_iv ().contains_b (this->spanned_rank_iv ()))
43 programming_error (to_str ("Spanner `%s' is not fully contained in parent spanner `%s'.",
44 classname (this),
45 classname (parent)));
50 if (line_l () || broken_b ())
51 return;
53 if (left == right)
56 If we have a spanner spanning one column, we must break it
57 anyway because it might provide a parent for another item. */
58 Direction d = LEFT;
61 Item* bound = left->find_prebroken_piece (d);
62 if (!bound)
63 programming_error ("no broken bound");
64 else if (bound->line_l ())
66 Spanner * span_p = dynamic_cast<Spanner*>( clone ());
67 span_p->set_bound (LEFT, bound);
68 span_p->set_bound (RIGHT, bound);
70 assert (span_p->line_l ());
71 span_p->line_l ()->typeset_element (span_p);
72 broken_into_l_arr_.push (span_p);
75 while ((flip(&d))!= LEFT);
77 else
79 Link_array<Item> break_points = pscore_l_->line_l_->broken_col_range (left,right);
81 break_points.insert (left,0);
82 break_points.push (right);
84 for (int i=1; i < break_points.size(); i++)
86 Drul_array<Item*> bounds;
87 bounds[LEFT] = break_points[i-1];
88 bounds[RIGHT] = break_points[i];
89 Direction d = LEFT;
92 if (!bounds[d]->line_l())
93 bounds[d] = bounds[d]->find_prebroken_piece(- d);
95 while ((flip(&d))!= LEFT);
97 if (!bounds[LEFT] || ! bounds[RIGHT])
99 programming_error ("bounds of this piece aren't breakable. ");
100 continue;
103 Spanner *span_p = dynamic_cast<Spanner*>(clone ());
104 span_p->set_bound(LEFT,bounds[LEFT]);
105 span_p->set_bound(RIGHT,bounds[RIGHT]);
108 assert (bounds[LEFT]->line_l () ==
109 bounds[RIGHT]->line_l ());
111 bounds[LEFT]->line_l ()->typeset_element (span_p);
112 broken_into_l_arr_.push (span_p);
115 broken_into_l_arr_.sort (Spanner::compare);
118 void
119 Spanner::set_my_columns()
121 Direction i = (Direction) LEFT;
124 if (!spanned_drul_[i]->line_l())
125 set_bound(i,spanned_drul_[i]->find_prebroken_piece((Direction) -i));
127 while (flip(&i) != LEFT);
130 Interval_t<int>
131 Spanner::spanned_rank_iv ()
133 Interval_t<int> iv (0, 0);
135 if (spanned_drul_[LEFT])
137 iv[LEFT] = Paper_column::rank_i (spanned_drul_[LEFT]->column_l ());
139 if (spanned_drul_[RIGHT])
141 iv[RIGHT] = Paper_column::rank_i (spanned_drul_[RIGHT]->column_l ());
143 return iv;
146 Item*
147 Spanner::get_bound (Direction d) const
149 return spanned_drul_ [d];
152 void
153 Spanner::set_bound(Direction d, Score_element*s)
155 Item * i = dynamic_cast<Item*> (s);
156 if (!i)
158 programming_error ("Must have Item for spanner bound.");
159 return;
162 spanned_drul_[d] =i;
165 We check for Line_of_score to prevent the column -> line_of_score
166 -> column -> line_of_score -> etc situation */
167 if (d== LEFT && !dynamic_cast<Line_of_score*> (this))
169 set_parent (i, X_AXIS);
174 Spanner::Spanner (SCM s)
175 : Score_element (s)
177 spanned_drul_[LEFT]=0;
178 spanned_drul_[RIGHT]=0;
181 Spanner::Spanner (Spanner const &s)
182 : Score_element (s)
184 spanned_drul_[LEFT] = spanned_drul_[RIGHT] =0;
188 Real
189 Spanner::spanner_length() const
191 Real l = spanned_drul_[LEFT]->relative_coordinate (0, X_AXIS);
192 Real r = spanned_drul_[RIGHT]->relative_coordinate (0, X_AXIS);
194 if (r< l)
195 programming_error ("spanner with negative length");
197 return r-l;
200 Line_of_score *
201 Spanner::line_l() const
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();
211 Score_element*
212 Spanner::find_broken_piece (Line_of_score*l) const
214 int idx = binsearch_link_array (broken_into_l_arr_, (Spanner*)l, Spanner::compare);
216 if (idx < 0)
217 return 0;
218 else
219 return broken_into_l_arr_ [idx];
224 Spanner::compare (Spanner * const &p1, Spanner * const &p2)
226 return p1->line_l ()->rank_i_ - p2->line_l ()->rank_i_;
229 bool
230 Spanner::broken_b() const
232 return broken_into_l_arr_.size();
235 Array<Rod>
236 Spanner::get_rods () const
238 Array<Rod> r;
239 return r;
242 Array<Spring>
243 Spanner::get_springs () const
245 Array<Spring> s;
246 return s;
249 void
250 Spanner::do_space_processing ()
252 Array<Rod> rs (get_rods ());
253 for (int i=0; i < rs.size (); i++)
255 rs[i].add_to_cols ();
258 Array<Spring> ss (get_springs ());
259 for (int i=0; i < ss.size (); i++)
261 if (isinf (ss[i].distance_f_))
262 programming_error ("weird spring");
263 else
264 ss[i].add_to_cols ();
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.
274 Real
275 Spanner::get_broken_left_end_align () const
277 Paper_column *sc = dynamic_cast<Paper_column*> (spanned_drul_[LEFT]->column_l());
279 // Relevant only if left span point is first column in line
280 if(sc != NULL &&
281 sc->break_status_dir () == RIGHT)
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.
289 return sc->extent (X_AXIS)[RIGHT];
292 return 0.0;
295 void
296 Spanner::do_derived_mark ()
298 Direction d = LEFT;
300 if (spanned_drul_[d])
301 scm_gc_mark (spanned_drul_[d]->self_scm_);
302 while (flip (&d) != LEFT);
304 for (int i= broken_into_l_arr_.size () ; i--;)
305 scm_gc_mark (broken_into_l_arr_[i]->self_scm_);
308 void
309 add_bound_item (Spanner* sp, Item*it)
311 if (!sp->get_bound (LEFT))
312 sp->set_bound (LEFT, it);
313 else
314 sp->set_bound (RIGHT, it);