Fixes Issue 1504, allowing feather beam line breaking.
[lilypond/patrick.git] / lily / spanner.cc
blobd3fd5a0955dd00df7cf78215f0452623748447c8
1 /*
2 This file is part of LilyPond, the GNU music typesetter.
4 Copyright (C) 1996--2011 Han-Wen Nienhuys <hanwen@xs4all.nl>
6 LilyPond is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
11 LilyPond is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with LilyPond. If not, see <http://www.gnu.org/licenses/>.
20 #include "libc-extension.hh"
21 #include "moment.hh"
22 #include "paper-column.hh"
23 #include "paper-score.hh"
24 #include "pointer-group-interface.hh"
25 #include "stencil.hh"
26 #include "system.hh"
27 #include "warn.hh"
29 Grob *
30 Spanner::clone () const
32 return new Spanner (*this);
35 void
36 Spanner::do_break_processing ()
38 //break_into_pieces
39 Item *left = spanned_drul_[LEFT];
40 Item *right = spanned_drul_[RIGHT];
42 if (!left || !right)
43 return;
46 if (get_system () || is_broken ())
47 return;
49 if (left == right)
52 If we have a spanner spanning one column, we must break it
53 anyway because it might provide a parent for another item. */
54 Direction d = LEFT;
57 Item *bound = left->find_prebroken_piece (d);
58 if (!bound)
59 programming_error ("no broken bound");
60 else if (bound->get_system ())
62 Spanner *span = dynamic_cast<Spanner *> (clone ());
63 span->set_bound (LEFT, bound);
64 span->set_bound (RIGHT, bound);
66 assert (span->get_system ());
67 span->get_system ()->typeset_grob (span);
68 broken_intos_.push_back (span);
71 while ((flip (&d)) != LEFT);
73 else
75 System *root = get_root_system (this);
76 vector<Item*> break_points = root->broken_col_range (left, right);
78 break_points.insert (break_points.begin () + 0, left);
79 break_points.push_back (right);
81 Slice parent_rank_slice;
82 parent_rank_slice.set_full ();
85 Check if our parent in X-direction spans equally wide
86 or wider than we do.
88 for (int a = X_AXIS; a < NO_AXES; a++)
90 if (Spanner *parent = dynamic_cast<Spanner *> (get_parent ((Axis)a)))
91 parent_rank_slice.intersect (parent->spanned_rank_interval ());
94 for (vsize i = 1; i < break_points.size (); i++)
96 Drul_array<Item *> bounds;
97 bounds[LEFT] = break_points[i - 1];
98 bounds[RIGHT] = break_points[i];
99 Direction d = LEFT;
102 if (!bounds[d]->get_system ())
103 bounds[d] = bounds[d]->find_prebroken_piece (- d);
105 while ((flip (&d)) != LEFT);
107 if (!bounds[LEFT] || ! bounds[RIGHT])
109 programming_error ("bounds of this piece aren't breakable. ");
110 continue;
113 bool ok = parent_rank_slice.contains (bounds[LEFT]->get_column ()->get_rank ());
114 ok = ok && parent_rank_slice.contains (bounds[RIGHT]->get_column ()->get_rank ());
116 if (!ok)
118 programming_error (to_string ("Spanner `%s' is not fully contained in parent spanner. Ignoring orphaned part",
119 name ().c_str ()));
120 continue;
124 Spanner *span = dynamic_cast<Spanner *> (clone ());
125 span->set_bound (LEFT, bounds[LEFT]);
126 span->set_bound (RIGHT, bounds[RIGHT]);
128 if (!bounds[LEFT]->get_system ()
129 || !bounds[RIGHT]->get_system ()
130 || bounds[LEFT]->get_system () != bounds[RIGHT]->get_system ())
132 programming_error ("bounds of spanner are invalid");
133 span->suicide ();
135 else
137 bounds[LEFT]->get_system ()->typeset_grob (span);
138 broken_intos_.push_back (span);
142 vector_sort (broken_intos_, Spanner::less);
143 for (vsize i = broken_intos_.size (); i--;)
144 broken_intos_[i]->break_index_ = i;
147 vsize
148 Spanner::get_break_index () const
150 return break_index_;
153 void
154 Spanner::set_my_columns ()
156 Direction i = (Direction) LEFT;
159 if (!spanned_drul_[i]->get_system ())
160 set_bound (i, spanned_drul_[i]->find_prebroken_piece ((Direction) -i));
162 while (flip (&i) != LEFT);
165 Interval_t<int>
166 Spanner::spanned_rank_interval () const
168 Interval_t<int> iv (0, 0);
170 if (spanned_drul_[LEFT] && spanned_drul_[LEFT]->get_column ())
171 iv[LEFT] = spanned_drul_[LEFT]->get_column ()->get_rank ();
172 if (spanned_drul_[RIGHT] && spanned_drul_[RIGHT]->get_column ())
173 iv[RIGHT] = spanned_drul_[RIGHT]->get_column ()->get_rank ();
174 return iv;
177 Interval_t<Moment>
178 Spanner::spanned_time () const
180 return spanned_time_interval (spanned_drul_[LEFT],
181 spanned_drul_[RIGHT]);
185 Item *
186 Spanner::get_bound (Direction d) const
188 return spanned_drul_[d];
192 Set the items that this spanner spans. If D == LEFT, we also set the
193 X-axis parent of THIS to S.
195 void
196 Spanner::set_bound (Direction d, Grob *s)
198 Item *i = dynamic_cast<Item *> (s);
199 if (!i)
201 programming_error ("must have Item for spanner bound of " + name());
202 return;
205 spanned_drul_[d] = i;
208 We check for System to prevent the column -> line_of_score
209 -> column -> line_of_score -> etc situation */
210 if (d == LEFT && !dynamic_cast<System *> (this))
211 set_parent (i, X_AXIS);
214 Signal that this column needs to be kept alive. They need to be
215 kept alive to have meaningful position and linebreaking.
217 [maybe we should try keeping all columns alive?, and perhaps
218 inherit position from their (non-)musical brother]
220 if (dynamic_cast<Paper_column *> (i))
221 Pointer_group_interface::add_grob (i, ly_symbol2scm ("bounded-by-me"), this);
224 Spanner::Spanner (SCM s)
225 : Grob (s)
227 break_index_ = 0;
228 spanned_drul_.set (0, 0);
229 pure_property_cache_ = SCM_UNDEFINED;
232 Spanner::Spanner (Spanner const &s)
233 : Grob (s)
235 spanned_drul_.set (0, 0);
236 pure_property_cache_ = SCM_UNDEFINED;
239 Real
240 Spanner::spanner_length () const
242 Real l = spanned_drul_[LEFT]->relative_coordinate (0, X_AXIS);
243 Real r = spanned_drul_[RIGHT]->relative_coordinate (0, X_AXIS);
245 if (r < l)
246 programming_error ("spanner with negative length");
248 return r - l;
251 System *
252 Spanner::get_system () const
254 if (!spanned_drul_[LEFT] || !spanned_drul_[RIGHT])
255 return 0;
256 if (spanned_drul_[LEFT]->get_system () != spanned_drul_[RIGHT]->get_system ())
257 return 0;
258 return spanned_drul_[LEFT]->get_system ();
261 Grob *
262 Spanner::find_broken_piece (System *l) const
264 vsize idx = binary_search (broken_intos_, (Spanner *) l, Spanner::less);
265 if (idx != VPOS)
266 return broken_intos_ [idx];
267 return 0;
270 Spanner *
271 Spanner::broken_neighbor (Direction d) const
273 if (!original_)
274 return 0;
276 vsize k = get_break_index ();
277 Spanner *orig = dynamic_cast<Spanner*> (original_);
278 int j = int (k) + d;
279 if (j < 0 || vsize (j) >= orig->broken_intos_.size ())
280 return 0;
282 return orig->broken_intos_[j];
286 Spanner::compare (Spanner *const &p1, Spanner *const &p2)
288 return p1->get_system ()->get_rank () - p2->get_system ()->get_rank ();
291 bool
292 Spanner::less (Spanner *const &a, Spanner *const &b)
294 return a->get_system ()->get_rank () < b->get_system ()->get_rank ();
297 bool
298 Spanner::is_broken () const
300 return broken_intos_.size ();
304 If this is a broken spanner, return the amount the left end is to be
305 shifted horizontally so that the spanner starts after the initial
306 clef and key on the staves. This is necessary for ties, slurs,
307 crescendo and decrescendo signs, for example.
309 Real
310 Spanner::get_broken_left_end_align () const
312 Paper_column *sc = dynamic_cast<Paper_column *> (spanned_drul_[LEFT]->get_column ());
314 // Relevant only if left span point is first column in line
315 if (sc != NULL
316 && sc->break_status_dir () == RIGHT)
319 We used to do a full search for the Break_align_item.
320 But that doesn't make a difference, since the Paper_column
321 is likely to contain only a Break_align_item.
323 return sc->extent (sc, X_AXIS)[RIGHT];
326 return 0.0;
329 void
330 Spanner::derived_mark () const
332 scm_gc_mark (pure_property_cache_);
334 Direction d = LEFT;
336 if (spanned_drul_[d])
337 scm_gc_mark (spanned_drul_[d]->self_scm ());
338 while (flip (&d) != LEFT)
341 for (vsize i = broken_intos_.size (); i--;)
342 scm_gc_mark (broken_intos_[i]->self_scm ());
346 Set left or right bound to IT.
348 Warning: caller should ensure that subsequent calls put in ITems
349 that are left-to-right ordered.
351 void
352 add_bound_item (Spanner *sp, Grob *it)
354 if (!sp->get_bound (LEFT))
355 sp->set_bound (LEFT, it);
356 else
357 sp->set_bound (RIGHT, it);
360 MAKE_SCHEME_CALLBACK (Spanner, set_spacing_rods, 1);
362 Spanner::set_spacing_rods (SCM smob)
364 Grob *me = unsmob_grob (smob);
365 SCM num_length = me->get_property ("minimum-length");
366 if (scm_is_number (num_length))
368 Rod r;
369 Spanner *sp = dynamic_cast<Spanner *> (me);
370 System *root = get_root_system (me);
371 Drul_array<Item*> bounds (sp->get_bound (LEFT),
372 sp->get_bound (RIGHT));
373 if (!bounds[LEFT] || !bounds[RIGHT])
374 return SCM_UNSPECIFIED;
376 vector<Item*> cols (root->broken_col_range (bounds[LEFT]->get_column (),
377 bounds[RIGHT]->get_column ()));
379 if (cols.size ())
381 Rod r ;
382 r.item_drul_[LEFT] = sp->get_bound (LEFT);
383 r.item_drul_[RIGHT] = cols[0]->find_prebroken_piece (LEFT);
384 r.distance_ = robust_scm2double (num_length, 0);
385 r.add_to_cols ();
387 r.item_drul_[LEFT] = cols.back ()->find_prebroken_piece (RIGHT);
388 r.item_drul_[RIGHT] = sp->get_bound (RIGHT);
389 r.add_to_cols ();
392 r.distance_ = robust_scm2double (num_length, 0);
393 r.item_drul_[LEFT] = sp->get_bound (LEFT);
394 r.item_drul_[RIGHT] = sp->get_bound (RIGHT);
395 r.add_to_cols ();
398 return SCM_UNSPECIFIED;
401 MAKE_SCHEME_CALLBACK (Spanner, calc_normalized_endpoints, 1);
403 Spanner::calc_normalized_endpoints (SCM smob)
405 Spanner *me = unsmob_spanner (smob);
406 SCM result = SCM_EOL;
408 Spanner *orig = dynamic_cast<Spanner *> (me->original ());
410 orig = orig ? orig : me;
412 if (orig->is_broken ())
414 Real total_width = 0.0;
415 vector<Real> span_data;
417 if (!orig->is_broken ())
418 span_data.push_back (orig->spanner_length ());
419 else
420 for (vsize i = 0; i < orig->broken_intos_.size (); i++)
421 span_data.push_back (orig->broken_intos_[i]->spanner_length ());
423 vector<Interval> unnormalized_endpoints;
425 for (vsize i = 0; i < span_data.size (); i++)
427 unnormalized_endpoints.push_back (Interval (total_width, total_width + span_data[i]));
428 total_width += span_data[i];
431 for (vsize i = 0; i < unnormalized_endpoints.size (); i++)
433 SCM t = ly_interval2scm (1 / total_width * unnormalized_endpoints[i]);
434 orig->broken_intos_[i]->set_property ("normalized-endpoints", t);
435 if (me->get_break_index () == i)
436 result = t;
439 else
441 result = scm_cons (scm_from_double (0.0), scm_from_double (1.0));
442 orig->set_property ("normalized-endpoints", result);
445 return result;
448 Spanner *
449 unsmob_spanner (SCM s)
451 return dynamic_cast<Spanner *> (unsmob_grob (s));
454 MAKE_SCHEME_CALLBACK (Spanner, bounds_width, 1);
456 Spanner::bounds_width (SCM grob)
458 Spanner *me = unsmob_spanner (grob);
460 Grob *common = me->get_bound (LEFT)->common_refpoint (me->get_bound (RIGHT), X_AXIS);
462 Interval w (me->get_bound (LEFT)->relative_coordinate (common, X_AXIS),
463 me->get_bound (RIGHT)->relative_coordinate (common, X_AXIS));
465 w -= me->relative_coordinate (common, X_AXIS);
467 return ly_interval2scm (w);
470 MAKE_SCHEME_CALLBACK (Spanner, kill_zero_spanned_time, 1);
472 Spanner::kill_zero_spanned_time (SCM grob)
474 Spanner *me = unsmob_spanner (grob);
475 Interval_t<Moment> moments = me->spanned_time ();
477 Remove the line or hairpin at the start of the line. For
478 piano voice indicators, it makes no sense to have them at
479 the start of the line.
481 I'm not sure what the official rules for glissandi are, but
482 usually the 2nd note of the glissando is "exact", so when playing
483 from the start of the line, there is no need to glide.
485 From a typographical p.o.v. this makes sense, since the amount of
486 space left of a note at the start of a line is very small.
488 --hwn.
491 if (moments.length () == Moment (0, 0))
492 me->suicide ();
494 return SCM_UNSPECIFIED;
498 Spanner::get_cached_pure_property (SCM sym, int start, int end)
500 // The pure property cache is indexed by (name start . end), where name is
501 // a symbol, and start and end are numbers referring to the starting and
502 // ending column ranks of the current line.
503 if (scm_hash_table_p (pure_property_cache_) == SCM_BOOL_F)
504 return SCM_UNDEFINED;
506 SCM key = scm_cons (sym, scm_cons (scm_from_int (start), scm_from_int (end)));
507 return scm_hash_ref (pure_property_cache_, key, SCM_UNDEFINED);
510 void
511 Spanner::cache_pure_property (SCM sym, int start, int end, SCM val)
513 if (scm_hash_table_p (pure_property_cache_) == SCM_BOOL_F)
514 pure_property_cache_ = scm_c_make_hash_table (17);
516 SCM key = scm_cons (sym, scm_cons (scm_from_int (start), scm_from_int (end)));
517 scm_hash_set_x (pure_property_cache_, key, val);
520 ADD_INTERFACE (Spanner,
521 "Some objects are horizontally spanned between objects. For"
522 " example, slurs, beams, ties, etc. These grobs form a subtype"
523 " called @code{Spanner}. All spanners have two span points"
524 " (these must be @code{Item} objects), one on the left and one"
525 " on the right. The left bound is also the X@tie{}reference"
526 " point of the spanner.",
528 /* properties */
529 "normalized-endpoints "
530 "minimum-length "
531 "to-barline "