]> git.donarmstrong.com Git - lilypond.git/blob - lily/beam.cc
Merge branch 'lilypond/translation' of ssh://git.sv.gnu.org/srv/git/lilypond into...
[lilypond.git] / lily / beam.cc
1 /*
2   This file is part of LilyPond, the GNU music typesetter.
3
4   Copyright (C) 1997--2011 Han-Wen Nienhuys <hanwen@xs4all.nl>
5   Jan Nieuwenhuizen <janneke@gnu.org>
6
7   LilyPond is free software: you can redistribute it and/or modify
8   it under the terms of the GNU General Public License as published by
9   the Free Software Foundation, either version 3 of the License, or
10   (at your option) any later version.
11
12   LilyPond is distributed in the hope that it will be useful,
13   but WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   GNU General Public License for more details.
16
17   You should have received a copy of the GNU General Public License
18   along with LilyPond.  If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 /*
22   TODO:
23
24   - Determine auto knees based on positions if it's set by the user.
25
26   - the code is littered with * and / staff_space calls for
27   #'positions. Consider moving to real-world coordinates?
28
29   Problematic issue is user tweaks (user tweaks are in staff-coordinates.)
30
31   Notes:
32
33   - Stems run to the Y-center of the beam.
34
35   - beam_translation is the offset between Y centers of the beam.
36 */
37
38 #include "beam.hh"
39
40 #include "align-interface.hh"
41 #include "beam-scoring-problem.hh"
42 #include "beaming-pattern.hh"
43 #include "directional-element-interface.hh"
44 #include "grob-array.hh"
45 #include "international.hh"
46 #include "interval-set.hh"
47 #include "item.hh"
48 #include "least-squares.hh"
49 #include "lookup.hh"
50 #include "main.hh"
51 #include "misc.hh"
52 #include "note-head.hh"
53 #include "output-def.hh"
54 #include "pointer-group-interface.hh"
55 #include "rhythmic-head.hh"
56 #include "spanner.hh"
57 #include "staff-symbol.hh"
58 #include "staff-symbol-referencer.hh"
59 #include "stem.hh"
60 #include "warn.hh"
61
62 #if DEBUG_BEAM_SCORING
63 #include "text-interface.hh" // debug output.
64 #include "font-interface.hh" // debug output.
65 #endif
66
67 #include <map>
68
69 Beam_stem_segment::Beam_stem_segment ()
70 {
71   max_connect_ = 1000;          // infinity
72   stem_ = 0;
73   width_ = 0.0;
74   stem_x_ = 0.0;
75   rank_ = 0;
76   stem_index_ = 0;
77   dir_ = CENTER;
78 }
79
80 bool
81 beam_segment_less (Beam_segment const &a, Beam_segment const &b)
82 {
83   return a.horizontal_[LEFT] < b.horizontal_[LEFT];
84 }
85
86 Beam_segment::Beam_segment ()
87 {
88   vertical_count_ = 0;
89 }
90
91 void
92 Beam::add_stem (Grob *me, Grob *s)
93 {
94   if (Stem::get_beam (s))
95     {
96       programming_error ("Stem already has beam");
97       return;
98     }
99
100   Pointer_group_interface::add_grob (me, ly_symbol2scm ("stems"), s);
101   s->set_object ("beam", me->self_scm ());
102   add_bound_item (dynamic_cast<Spanner *> (me), dynamic_cast<Item *> (s));
103 }
104
105 Real
106 Beam::get_beam_thickness (Grob *me)
107 {
108   return robust_scm2double (me->get_property ("beam-thickness"), 0)
109          * Staff_symbol_referencer::staff_space (me);
110 }
111
112 /* Return the translation between 2 adjoining beams. */
113 Real
114 Beam::get_beam_translation (Grob *me)
115 {
116   int beam_count = get_beam_count (me);
117   Real staff_space = Staff_symbol_referencer::staff_space (me);
118   Real line = Staff_symbol_referencer::line_thickness (me);
119   Real beam_thickness = get_beam_thickness (me);
120   Real fract = robust_scm2double (me->get_property ("length-fraction"), 1.0);
121
122   Real beam_translation = beam_count < 4
123                           ? (2 * staff_space + line - beam_thickness) / 2.0
124                           : (3 * staff_space + line - beam_thickness) / 3.0;
125
126   return fract * beam_translation;
127 }
128
129 /* Maximum beam_count. */
130 int
131 Beam::get_beam_count (Grob *me)
132 {
133   int m = 0;
134
135   extract_grob_set (me, "stems", stems);
136   for (vsize i = 0; i < stems.size (); i++)
137     {
138       Grob *stem = stems[i];
139       m = max (m, (Stem::beam_multiplicity (stem).length () + 1));
140     }
141   return m;
142 }
143
144 MAKE_SCHEME_CALLBACK (Beam, calc_normal_stems, 1);
145 SCM
146 Beam::calc_normal_stems (SCM smob)
147 {
148   Grob *me = unsmob_grob (smob);
149
150   extract_grob_set (me, "stems", stems);
151   SCM val = Grob_array::make_array ();
152   Grob_array *ga = unsmob_grob_array (val);
153   for (vsize i = 0; i < stems.size (); i++)
154     if (Stem::is_normal_stem (stems[i]))
155       ga->add (stems[i]);
156
157   return val;
158 }
159
160 MAKE_SCHEME_CALLBACK (Beam, calc_direction, 1);
161 SCM
162 Beam::calc_direction (SCM smob)
163 {
164   Grob *me = unsmob_grob (smob);
165
166   /* Beams with less than 2 two stems don't make much sense, but could happen
167      when you do
168
169      r8[ c8 r8]
170
171   */
172
173   Direction dir = CENTER;
174
175   int count = normal_stem_count (me);
176   if (count < 2)
177     {
178       extract_grob_set (me, "stems", stems);
179       if (stems.size () == 0)
180         {
181           me->warning (_ ("removing beam with no stems"));
182           me->suicide ();
183
184           return SCM_UNSPECIFIED;
185         }
186       else
187         {
188           Grob *stem = first_normal_stem (me);
189
190           /*
191             This happens for chord tremolos.
192           */
193           if (!stem)
194             stem = stems[0];
195
196           if (is_direction (stem->get_property_data ("direction")))
197             dir = to_dir (stem->get_property_data ("direction"));
198           else
199             dir = to_dir (stem->get_property ("default-direction"));
200         }
201     }
202
203   if (count >= 1)
204     {
205       if (!dir)
206         dir = get_default_dir (me);
207
208       consider_auto_knees (me);
209     }
210
211   if (dir)
212     {
213       set_stem_directions (me, dir);
214     }
215
216   return scm_from_int (dir);
217 }
218
219 /* We want a maximal number of shared beams, but if there is choice, we
220  * take the one that is closest to the end of the stem. This is for
221  * situations like
222  *
223  *        x
224  *       |
225  *       |
226  *   |===|
227  *   |=
228  *   |
229  *  x
230  */
231 int
232 position_with_maximal_common_beams (SCM left_beaming, SCM right_beaming,
233                                     Direction left_dir,
234                                     Direction right_dir)
235 {
236   Slice lslice = int_list_to_slice (scm_cdr (left_beaming));
237
238   int best_count = 0;
239   int best_start = 0;
240   for (int i = lslice[-left_dir];
241        (i - lslice[left_dir]) * left_dir <= 0; i += left_dir)
242     {
243       int count = 0;
244       for (SCM s = scm_car (right_beaming); scm_is_pair (s); s = scm_cdr (s))
245         {
246           int k = -right_dir * scm_to_int (scm_car (s)) + i;
247           if (scm_c_memq (scm_from_int (k), left_beaming) != SCM_BOOL_F)
248             count++;
249         }
250
251       if (count >= best_count)
252         {
253           best_count = count;
254           best_start = i;
255         }
256     }
257
258   return best_start;
259 }
260
261 MAKE_SCHEME_CALLBACK (Beam, calc_beaming, 1)
262 SCM
263 Beam::calc_beaming (SCM smob)
264 {
265   Grob *me = unsmob_grob (smob);
266
267   extract_grob_set (me, "stems", stems);
268
269   Slice last_int;
270   last_int.set_empty ();
271
272   SCM last_beaming = scm_cons (SCM_EOL, scm_list_1 (scm_from_int (0)));
273   Direction last_dir = CENTER;
274   for (vsize i = 0; i < stems.size (); i++)
275     {
276       Grob *this_stem = stems[i];
277       SCM this_beaming = this_stem->get_property ("beaming");
278
279       Direction this_dir = get_grob_direction (this_stem);
280       if (scm_is_pair (last_beaming) && scm_is_pair (this_beaming))
281         {
282           int start_point = position_with_maximal_common_beams
283                             (last_beaming, this_beaming,
284                              last_dir ? last_dir : this_dir,
285                              this_dir);
286
287           Direction d = LEFT;
288           Slice new_slice;
289           do
290             {
291               new_slice.set_empty ();
292               SCM s = index_get_cell (this_beaming, d);
293               for (; scm_is_pair (s); s = scm_cdr (s))
294                 {
295                   int new_beam_pos
296                     = start_point - this_dir * scm_to_int (scm_car (s));
297
298                   new_slice.add_point (new_beam_pos);
299                   scm_set_car_x (s, scm_from_int (new_beam_pos));
300                 }
301             }
302           while (flip (&d) != LEFT);
303
304           if (!new_slice.is_empty ())
305             last_int = new_slice;
306         }
307       else
308         {
309           /*
310             FIXME: what's this for?
311            */
312           SCM s = scm_cdr (this_beaming);
313           for (; scm_is_pair (s); s = scm_cdr (s))
314             {
315               int np = -this_dir * scm_to_int (scm_car (s));
316               scm_set_car_x (s, scm_from_int (np));
317               last_int.add_point (np);
318             }
319         }
320
321       if (scm_ilength (scm_cdr (this_beaming)) > 0)
322         {
323           last_beaming = this_beaming;
324           last_dir = this_dir;
325         }
326     }
327
328   return SCM_EOL;
329 }
330
331 bool
332 operator <(Beam_stem_segment const &a,
333            Beam_stem_segment const &b)
334 {
335   return a.rank_ < b.rank_;
336 }
337
338 typedef map<int, vector<Beam_stem_segment> > Position_stem_segments_map;
339
340 // TODO - should store result in a property?
341 vector<Beam_segment>
342 Beam::get_beam_segments (Grob *me_grob, Grob **common)
343 {
344   /* ugh, this has a side-effect that we need to ensure that
345      Stem #'beaming is correct */
346   (void) me_grob->get_property ("beaming");
347
348   Spanner *me = dynamic_cast<Spanner *> (me_grob);
349
350   extract_grob_set (me, "stems", stems);
351   Grob *commonx = common_refpoint_of_array (stems, me, X_AXIS);
352
353   commonx = me->get_bound (LEFT)->common_refpoint (commonx, X_AXIS);
354   commonx = me->get_bound (RIGHT)->common_refpoint (commonx, X_AXIS);
355
356   *common = commonx;
357
358   int gap_count = robust_scm2int (me->get_property ("gap-count"), 0);
359   Real gap_length = robust_scm2double (me->get_property ("gap"), 0.0);
360
361   Position_stem_segments_map stem_segments;
362   Real lt = me->layout ()->get_dimension (ly_symbol2scm ("line-thickness"));
363
364   /* There are two concepts of "rank" that are used in the following code.
365      The beam_rank is the vertical position of the beam (larger numbers are
366      closer to the noteheads). Beam_stem_segment.rank_, on the other hand,
367      is the horizontal position of the segment (this is incremented by two
368      for each stem; the beam segment on the right side of the stem has
369      a higher rank (by one) than its neighbour to the left). */
370   Slice ranks;
371   for (vsize i = 0; i < stems.size (); i++)
372     {
373       Grob *stem = stems[i];
374       Real stem_width = robust_scm2double (stem->get_property ("thickness"), 1.0) * lt;
375       Real stem_x = stem->relative_coordinate (commonx, X_AXIS);
376       SCM beaming = stem->get_property ("beaming");
377       Direction d = LEFT;
378       do
379         {
380           // Find the maximum and minimum beam ranks.
381           // Given that RANKS is never reset to empty, the interval will always be
382           // smallest for the left beamlet of the first stem, and then it might grow.
383           // Do we really want this? (It only affects the tremolo gaps) --jneem
384           for (SCM s = index_get_cell (beaming, d);
385                scm_is_pair (s); s = scm_cdr (s))
386             {
387               if (!scm_is_integer (scm_car (s)))
388                 continue;
389
390               int beam_rank = scm_to_int (scm_car (s));
391               ranks.add_point (beam_rank);
392             }
393
394           for (SCM s = index_get_cell (beaming, d);
395                scm_is_pair (s); s = scm_cdr (s))
396             {
397               if (!scm_is_integer (scm_car (s)))
398                 continue;
399
400               int beam_rank = scm_to_int (scm_car (s));
401               Beam_stem_segment seg;
402               seg.stem_ = stem;
403               seg.stem_x_ = stem_x;
404               seg.rank_ = 2 * i + (d + 1) / 2;
405               seg.width_ = stem_width;
406               seg.stem_index_ = i;
407               seg.dir_ = d;
408               seg.max_connect_ = robust_scm2int (stem->get_property ("max-beam-connect"), 1000);
409
410               Direction stem_dir = get_grob_direction (stem);
411
412               seg.gapped_
413                 = (stem_dir * beam_rank < (stem_dir * ranks[-stem_dir] + gap_count));
414               stem_segments[beam_rank].push_back (seg);
415             }
416         }
417       while (flip (&d) != LEFT);
418     }
419
420   Drul_array<Real> break_overshoot
421     = robust_scm2drul (me->get_property ("break-overshoot"),
422                        Drul_array<Real> (-0.5, 0.0));
423
424   vector<Beam_segment> segments;
425   for (Position_stem_segments_map::const_iterator i (stem_segments.begin ());
426        i != stem_segments.end (); i++)
427     {
428       vector<Beam_stem_segment> segs = (*i).second;
429       vector_sort (segs, less<Beam_stem_segment> ());
430
431       Beam_segment current;
432
433       // Iterate over all of the segments of the current beam rank,
434       // merging the adjacent Beam_stem_segments into one Beam_segment
435       // when appropriate.
436       int vertical_count = (*i).first;
437       for (vsize j = 0; j < segs.size (); j++)
438         {
439           // Keeping track of the different directions here is a little tricky.
440           // segs[j].dir_ is the direction of the beam segment relative to the stem
441           // (ie. segs[j].dir_ == LEFT if the beam segment sticks out to the left of
442           // its stem) whereas event_dir refers to the edge of the beam segment that
443           // we are currently looking at (ie. if segs[j].dir_ == event_dir then we
444           // are looking at that edge of the beam segment that is furthest from its
445           // stem).
446           Direction event_dir = LEFT;
447           Beam_stem_segment const &seg = segs[j];
448           do
449             {
450               Beam_stem_segment const &neighbor_seg = segs[j + event_dir];
451               // TODO: make names clearer? --jneem
452               // on_line_bound: whether the current segment is on the boundary of the WHOLE beam
453               // on_beam_bound: whether the current segment is on the boundary of just that part
454               //   of the beam with the current beam_rank
455               bool on_line_bound = (seg.dir_ == LEFT) ? seg.stem_index_ == 0
456                                    : seg.stem_index_ == stems.size () - 1;
457               bool on_beam_bound = (event_dir == LEFT) ? j == 0
458                                    : j == segs.size () - 1;
459               bool inside_stem = (event_dir == LEFT)
460                                  ? seg.stem_index_ > 0
461                                  : seg.stem_index_ + 1 < stems.size ();
462
463               bool event = on_beam_bound
464                            || abs (seg.rank_ - neighbor_seg.rank_) > 1
465                            || (abs (vertical_count) >= seg.max_connect_
466                                || abs (vertical_count) >= neighbor_seg.max_connect_);
467
468               if (!event)
469                 // Then this edge of the current segment is irrelevent because it will
470                 // be connected with the next segment in the event_dir direction.
471                 continue;
472
473               current.vertical_count_ = vertical_count;
474               current.horizontal_[event_dir] = seg.stem_x_;
475               if (seg.dir_ == event_dir)
476                 // then we are examining the edge of a beam segment that is furthest
477                 // from its stem.
478                 {
479                   if (on_line_bound
480                       && me->get_bound (event_dir)->break_status_dir ())
481                     {
482                       current.horizontal_[event_dir]
483                         = (robust_relative_extent (me->get_bound (event_dir),
484                                                    commonx, X_AXIS)[RIGHT]
485                            + event_dir * break_overshoot[event_dir]);
486                     }
487                   else
488                     {
489                       Grob *stem = stems[seg.stem_index_];
490                       Drul_array<Real> beamlet_length
491                         = robust_scm2interval (stem->get_property ("beamlet-default-length"), Interval (1.1, 1.1));
492                       Drul_array<Real> max_proportion
493                         = robust_scm2interval (stem->get_property ("beamlet-max-length-proportion"), Interval (0.75, 0.75));
494                       Real length = beamlet_length[seg.dir_];
495
496                       if (inside_stem)
497                         {
498                           Grob *neighbor_stem = stems[seg.stem_index_ + event_dir];
499                           Real neighbor_stem_x = neighbor_stem->relative_coordinate (commonx, X_AXIS);
500
501                           length = min (length,
502                                         fabs (neighbor_stem_x - seg.stem_x_) * max_proportion[seg.dir_]);
503                         }
504                       current.horizontal_[event_dir] += event_dir * length;
505                     }
506                 }
507               else
508                 // we are examining the edge of a beam segment that is closest
509                 // (ie. touching, unless there is a gap) its stem.
510                 {
511                   current.horizontal_[event_dir] += event_dir * seg.width_ / 2;
512                   if (seg.gapped_)
513                     {
514                       current.horizontal_[event_dir] -= event_dir * gap_length;
515
516                       if (Stem::is_invisible (seg.stem_))
517                         {
518                           /*
519                             Need to do this in case of whole notes. We don't want the
520                             heads to collide with the beams.
521                            */
522                           extract_grob_set (seg.stem_, "note-heads", heads);
523
524                           for (vsize k = 0; k < heads.size (); k++)
525                             current.horizontal_[event_dir]
526                               = event_dir * min (event_dir * current.horizontal_[event_dir],
527                                                  - gap_length / 2
528                                                  + event_dir
529                                                  * heads[k]->extent (commonx,
530                                                                      X_AXIS)[-event_dir]);
531                         }
532                     }
533                 }
534
535               if (event_dir == RIGHT)
536                 {
537                   segments.push_back (current);
538                   current = Beam_segment ();
539                 }
540             }
541           while (flip (&event_dir) != LEFT);
542         }
543
544     }
545
546   return segments;
547 }
548
549 MAKE_SCHEME_CALLBACK (Beam, print, 1);
550 SCM
551 Beam::print (SCM grob)
552 {
553   Spanner *me = unsmob_spanner (grob);
554   Grob *commonx = 0;
555   vector<Beam_segment> segments = get_beam_segments (me, &commonx);
556   if (!segments.size ())
557     return SCM_EOL;
558
559   Interval span;
560   if (normal_stem_count (me))
561     {
562       span[LEFT] = first_normal_stem (me)->relative_coordinate (commonx, X_AXIS);
563       span[RIGHT] = last_normal_stem (me)->relative_coordinate (commonx, X_AXIS);
564     }
565   else
566     {
567       extract_grob_set (me, "stems", stems);
568       span[LEFT] = stems[0]->relative_coordinate (commonx, X_AXIS);
569       span[RIGHT] = stems.back ()->relative_coordinate (commonx, X_AXIS);
570     }
571
572   Real blot = me->layout ()->get_dimension (ly_symbol2scm ("blot-diameter"));
573
574   SCM posns = me->get_property ("quantized-positions");
575   Interval pos;
576   if (!is_number_pair (posns))
577     {
578       programming_error ("no beam positions?");
579       pos = Interval (0, 0);
580     }
581   else
582     pos = ly_scm2realdrul (posns);
583
584   scale_drul (&pos, Staff_symbol_referencer::staff_space (me));
585
586   Real dy = pos[RIGHT] - pos[LEFT];
587   Real slope = (dy && span.length ()) ? dy / span.length () : 0;
588
589   Real beam_thickness = get_beam_thickness (me);
590   Real beam_dy = get_beam_translation (me);
591
592   Direction feather_dir = to_dir (me->get_property ("grow-direction"));
593
594   Interval placements = robust_scm2interval (me->get_property ("normalized-endpoints"), Interval (0.0, 0.0));
595
596   Stencil the_beam;
597
598   int extreme = (segments[0].vertical_count_ == 0
599                  ? segments[0].vertical_count_
600                  : segments.back ().vertical_count_);
601
602   for (vsize i = 0; i < segments.size (); i++)
603     {
604       Real local_slope = slope;
605       /*
606         Makes local slope proportional to the ratio of the length of this beam
607         to the total length.
608       */
609       if (feather_dir)
610         local_slope += (feather_dir * segments[i].vertical_count_
611                         * beam_dy
612                         * placements.length ()
613                         / span.length ());
614
615       Stencil b = Lookup::beam (local_slope, segments[i].horizontal_.length (), beam_thickness, blot);
616
617       b.translate_axis (segments[i].horizontal_[LEFT], X_AXIS);
618       Real multiplier = feather_dir ? placements[LEFT] : 1.0;
619
620       Interval weights (1 - multiplier, multiplier);
621
622       if (feather_dir != LEFT)
623         weights.swap ();
624
625       // we need two translations: the normal one and
626       // the one of the lowest segment
627       int idx[] = {i, extreme};
628       Real translations[2];
629
630       for (int j = 0; j < 2; j++)
631         translations[j] = slope
632                           * (segments[idx[j]].horizontal_[LEFT] - span.linear_combination (CENTER))
633                           + pos.linear_combination (CENTER)
634                           + beam_dy * segments[idx[j]].vertical_count_;
635
636       Real weighted_average = translations[0] * weights[LEFT] + translations[1] * weights[RIGHT];
637
638       /*
639         Tricky.  The manipulation of the variable `weighted_average' below ensures
640         that beams with a RIGHT grow direction will start from the position of the
641         lowest segment at 0, and this error will decrease and decrease over the
642         course of the beam.  Something with a LEFT grow direction, on the other
643         hand, will always start in the correct place but progressively accrue
644         error at broken places.  This code shifts beams up given where they are
645         in the total span length (controlled by the variable `multiplier').  To
646         better understand what it does, try commenting it out: you'll see that
647         all of the RIGHT growing beams immediately start too low and get better
648         over line breaks, whereas all of the LEFT growing beams start just right
649         and get worse over line breaks.
650       */
651       Real factor = Interval (multiplier, 1 - multiplier).linear_combination (feather_dir);
652
653       if (segments[0].vertical_count_ < 0 && feather_dir)
654         weighted_average += beam_dy * (segments.size () - 1) * factor;
655
656       b.translate_axis (weighted_average, Y_AXIS);
657
658       the_beam.add_stencil (b);
659
660     }
661
662 #if (DEBUG_BEAM_SCORING)
663   SCM annotation = me->get_property ("annotation");
664   if (scm_is_string (annotation))
665     {
666       extract_grob_set (me, "stems", stems);
667
668       /*
669         This code prints the demerits for each beam. Perhaps this
670         should be switchable for those who want to twiddle with the
671         parameters.
672       */
673       string str;
674       SCM properties = Font_interface::text_font_alist_chain (me);
675
676       properties = scm_cons (scm_acons (ly_symbol2scm ("font-size"), scm_from_int (-5), SCM_EOL),
677                              properties);
678
679       Direction stem_dir = stems.size () ? to_dir (stems[0]->get_property ("direction")) : UP;
680
681       Stencil score = *unsmob_stencil (Text_interface::interpret_markup
682                                        (me->layout ()->self_scm (), properties, annotation));
683
684       if (!score.is_empty ())
685         {
686           score.translate_axis (me->relative_coordinate (commonx, X_AXIS), X_AXIS);
687           the_beam.add_at_edge (Y_AXIS, stem_dir, score, 1.0);
688         }
689     }
690 #endif
691
692   the_beam.translate_axis (-me->relative_coordinate (commonx, X_AXIS), X_AXIS);
693   return the_beam.smobbed_copy ();
694 }
695
696 Direction
697 Beam::get_default_dir (Grob *me)
698 {
699   extract_grob_set (me, "stems", stems);
700
701   Drul_array<Real> extremes (0.0, 0.0);
702   for (iterof (s, stems); s != stems.end (); s++)
703     {
704       Interval positions = Stem::head_positions (*s);
705       Direction d = DOWN;
706       do
707         {
708           if (sign (positions[d]) == d)
709             extremes[d] = d * max (d * positions[d], d * extremes[d]);
710         }
711       while (flip (&d) != DOWN);
712     }
713
714   Drul_array<int> total (0, 0);
715   Drul_array<int> count (0, 0);
716
717   bool force_dir = false;
718   for (vsize i = 0; i < stems.size (); i++)
719     {
720       Grob *s = stems[i];
721       Direction stem_dir = CENTER;
722       SCM stem_dir_scm = s->get_property_data ("direction");
723       if (is_direction (stem_dir_scm))
724         {
725           stem_dir = to_dir (stem_dir_scm);
726           force_dir = true;
727         }
728       else
729         stem_dir = to_dir (s->get_property ("default-direction"));
730
731       if (!stem_dir)
732         stem_dir = to_dir (s->get_property ("neutral-direction"));
733
734       if (stem_dir)
735         {
736           count[stem_dir]++;
737           total[stem_dir] += max (int (- stem_dir * Stem::head_positions (s) [-stem_dir]), 0);
738         }
739     }
740
741   if (!force_dir)
742     {
743       if (abs (extremes[UP]) > -extremes[DOWN])
744         return DOWN;
745       else if (extremes[UP] < -extremes[DOWN])
746         return UP;
747     }
748
749   Direction dir = CENTER;
750   Direction d = CENTER;
751   if ((d = (Direction) sign (count[UP] - count[DOWN])))
752     dir = d;
753   else if (count[UP]
754            && count[DOWN]
755            && (d = (Direction) sign (total[UP] / count[UP] - total[DOWN] / count[DOWN])))
756     dir = d;
757   else if ((d = (Direction) sign (total[UP] - total[DOWN])))
758     dir = d;
759   else
760     dir = to_dir (me->get_property ("neutral-direction"));
761
762   return dir;
763 }
764
765 /* Set all stems with non-forced direction to beam direction.
766    Urg: non-forced should become `without/with unforced' direction,
767    once stem gets cleaned-up. */
768 void
769 Beam::set_stem_directions (Grob *me, Direction d)
770 {
771   extract_grob_set (me, "stems", stems);
772
773   for (vsize i = 0; i < stems.size (); i++)
774     {
775       Grob *s = stems[i];
776
777       SCM forcedir = s->get_property_data ("direction");
778       if (!to_dir (forcedir))
779         set_grob_direction (s, d);
780     }
781 }
782
783 /*
784   Only try horizontal beams for knees.  No reliable detection of
785   anything else is possible here, since we don't know funky-beaming
786   settings, or X-distances (slopes!)  People that want sloped
787   knee-beams, should set the directions manually.
788
789
790   TODO:
791
792   this routine should take into account the stemlength scoring
793   of a possible knee/nonknee beam.
794 */
795 void
796 Beam::consider_auto_knees (Grob *me)
797 {
798   SCM scm = me->get_property ("auto-knee-gap");
799   if (!scm_is_number (scm))
800     return;
801
802   Interval_set gaps;
803
804   gaps.set_full ();
805
806   extract_grob_set (me, "normal-stems", stems);
807
808   Grob *common = common_refpoint_of_array (stems, me, Y_AXIS);
809   Real staff_space = Staff_symbol_referencer::staff_space (me);
810
811   vector<Interval> head_extents_array;
812   for (vsize i = 0; i < stems.size (); i++)
813     {
814       Grob *stem = stems[i];
815
816       Interval head_extents = Stem::head_positions (stem);
817       if (!head_extents.is_empty ())
818         {
819           head_extents[LEFT] += -1;
820           head_extents[RIGHT] += 1;
821           head_extents *= staff_space * 0.5;
822
823           /*
824             We could subtract beam Y position, but this routine only
825             sets stem directions, a constant shift does not have an
826             influence.
827           */
828           head_extents += stem->pure_relative_y_coordinate (common, 0, INT_MAX);
829
830           if (to_dir (stem->get_property_data ("direction")))
831             {
832               Direction stemdir = to_dir (stem->get_property ("direction"));
833               head_extents[-stemdir] = -stemdir * infinity_f;
834             }
835         }
836       head_extents_array.push_back (head_extents);
837
838       gaps.remove_interval (head_extents);
839     }
840
841   Interval max_gap;
842   Real max_gap_len = 0.0;
843
844   for (vsize i = gaps.allowed_regions_.size () - 1; i != VPOS; i--)
845     {
846       Interval gap = gaps.allowed_regions_[i];
847
848       /*
849         the outer gaps are not knees.
850       */
851       if (isinf (gap[LEFT]) || isinf (gap[RIGHT]))
852         continue;
853
854       if (gap.length () >= max_gap_len)
855         {
856           max_gap_len = gap.length ();
857           max_gap = gap;
858         }
859     }
860
861   Real beam_translation = get_beam_translation (me);
862   Real beam_thickness = Beam::get_beam_thickness (me);
863   int beam_count = Beam::get_beam_count (me);
864   Real height_of_beams = beam_thickness / 2
865                          + (beam_count - 1) * beam_translation;
866   Real threshold = scm_to_double (scm) + height_of_beams;
867
868   if (max_gap_len > threshold)
869     {
870       int j = 0;
871       for (vsize i = 0; i < stems.size (); i++)
872         {
873           Grob *stem = stems[i];
874           Interval head_extents = head_extents_array[j++];
875
876           Direction d = (head_extents.center () < max_gap.center ())
877                         ? UP : DOWN;
878
879           stem->set_property ("direction", scm_from_int (d));
880
881           head_extents.intersect (max_gap);
882           assert (head_extents.is_empty () || head_extents.length () < 1e-6);
883         }
884     }
885 }
886
887 /* Set stem's shorten property if unset.
888
889 TODO:
890 take some y-position (chord/beam/nearest?) into account
891 scmify forced-fraction
892
893 This is done in beam because the shorten has to be uniform over the
894 entire beam.
895 */
896
897 void
898 set_minimum_dy (Grob *me, Real *dy)
899 {
900   if (*dy)
901     {
902       /*
903         If dy is smaller than the smallest quant, we
904         get absurd direction-sign penalties.
905       */
906
907       Real ss = Staff_symbol_referencer::staff_space (me);
908       Real beam_thickness = Beam::get_beam_thickness (me) / ss;
909       Real slt = Staff_symbol_referencer::line_thickness (me) / ss;
910       Real sit = (beam_thickness - slt) / 2;
911       Real inter = 0.5;
912       Real hang = 1.0 - (beam_thickness - slt) / 2;
913
914       *dy = sign (*dy) * max (fabs (*dy),
915                               min (min (sit, inter), hang));
916     }
917 }
918
919 MAKE_SCHEME_CALLBACK (Beam, calc_stem_shorten, 1)
920 SCM
921 Beam::calc_stem_shorten (SCM smob)
922 {
923   Grob *me = unsmob_grob (smob);
924
925   /*
926     shortening looks silly for x staff beams
927   */
928   if (is_knee (me))
929     return scm_from_int (0);
930
931   Real forced_fraction = 1.0 * forced_stem_count (me)
932                          / normal_stem_count (me);
933
934   int beam_count = get_beam_count (me);
935
936   SCM shorten_list = me->get_property ("beamed-stem-shorten");
937   if (shorten_list == SCM_EOL)
938     return scm_from_int (0);
939
940   Real staff_space = Staff_symbol_referencer::staff_space (me);
941
942   SCM shorten_elt
943     = robust_list_ref (beam_count - 1, shorten_list);
944   Real shorten = scm_to_double (shorten_elt) * staff_space;
945
946   shorten *= forced_fraction;
947
948   if (shorten)
949     return scm_from_double (shorten);
950
951   return scm_from_double (0.0);
952 }
953
954 Interval
955 Beam::no_visible_stem_positions (Grob *me, Interval default_value)
956 {
957   extract_grob_set (me, "stems", stems);
958   if (stems.empty ())
959     return default_value;
960
961   Interval head_positions;
962   Slice multiplicity;
963   for (vsize i = 0; i < stems.size (); i++)
964     {
965       head_positions.unite (Stem::head_positions (stems[i]));
966       multiplicity.unite (Stem::beam_multiplicity (stems[i]));
967     }
968
969   Direction dir = get_grob_direction (me);
970
971   if (!dir)
972     programming_error ("The beam should have a direction by now.");
973
974   Real y = head_positions.linear_combination (dir)
975            * 0.5 * Staff_symbol_referencer::staff_space (me)
976            + dir * get_beam_translation (me) * (multiplicity.length () + 1);
977
978   y /= Staff_symbol_referencer::staff_space (me);
979   return Interval (y, y);
980 }
981
982 /*
983   Compute a first approximation to the beam slope.
984 */
985 MAKE_SCHEME_CALLBACK (Beam, calc_least_squares_positions, 2);
986 SCM
987 Beam::calc_least_squares_positions (SCM smob, SCM /* posns */)
988 {
989   Grob *me = unsmob_grob (smob);
990
991   int count = normal_stem_count (me);
992   Interval pos (0, 0);
993   if (count < 1)
994     return ly_interval2scm (no_visible_stem_positions (me, pos));
995
996   vector<Real> x_posns;
997   extract_grob_set (me, "normal-stems", stems);
998   Grob *commonx = common_refpoint_of_array (stems, me, X_AXIS);
999   Grob *commony = common_refpoint_of_array (stems, me, Y_AXIS);
1000
1001   Real my_y = me->relative_coordinate (commony, Y_AXIS);
1002
1003   Grob *fvs = first_normal_stem (me);
1004   Grob *lvs = last_normal_stem (me);
1005
1006   Interval ideal (Stem::get_stem_info (fvs).ideal_y_
1007                   + fvs->relative_coordinate (commony, Y_AXIS) - my_y,
1008                   Stem::get_stem_info (lvs).ideal_y_
1009                   + lvs->relative_coordinate (commony, Y_AXIS) - my_y);
1010
1011   Real x0 = first_normal_stem (me)->relative_coordinate (commonx, X_AXIS);
1012   for (vsize i = 0; i < stems.size (); i++)
1013     {
1014       Grob *s = stems[i];
1015
1016       Real x = s->relative_coordinate (commonx, X_AXIS) - x0;
1017       x_posns.push_back (x);
1018     }
1019   Real dx = last_normal_stem (me)->relative_coordinate (commonx, X_AXIS) - x0;
1020
1021   Real y = 0;
1022   Real slope = 0;
1023   Real dy = 0;
1024   Real ldy = 0.0;
1025   if (!ideal.delta ())
1026     {
1027       Interval chord (Stem::chord_start_y (stems[0]),
1028                       Stem::chord_start_y (stems.back ()));
1029
1030       /* Simple beams (2 stems) on middle line should be allowed to be
1031          slightly sloped.
1032
1033          However, if both stems reach middle line,
1034          ideal[LEFT] == ideal[RIGHT] and ideal.delta () == 0.
1035
1036          For that case, we apply artificial slope */
1037       if (!ideal[LEFT] && chord.delta () && count == 2)
1038         {
1039           /* FIXME. -> UP */
1040           Direction d = (Direction) (sign (chord.delta ()) * UP);
1041           pos[d] = get_beam_thickness (me) / 2;
1042           pos[-d] = -pos[d];
1043         }
1044       else
1045         pos = ideal;
1046
1047       /*
1048         For broken beams this doesn't work well. In this case, the
1049         slope esp. of the first part of a broken beam should predict
1050         where the second part goes.
1051       */
1052       ldy = pos[RIGHT] - pos[LEFT];
1053     }
1054   else
1055     {
1056       vector<Offset> ideals;
1057       for (vsize i = 0; i < stems.size (); i++)
1058         {
1059           Grob *s = stems[i];
1060           ideals.push_back (Offset (x_posns[i],
1061                                     Stem::get_stem_info (s).ideal_y_
1062                                     + s->relative_coordinate (commony, Y_AXIS)
1063                                     - my_y));
1064         }
1065
1066       minimise_least_squares (&slope, &y, ideals);
1067
1068       dy = slope * dx;
1069
1070       set_minimum_dy (me, &dy);
1071
1072       ldy = dy;
1073       pos = Interval (y, (y + dy));
1074     }
1075
1076   /*
1077     "position" is relative to the staff.
1078   */
1079   scale_drul (&pos, 1 / Staff_symbol_referencer::staff_space (me));
1080
1081   me->set_property ("least-squares-dy", scm_from_double (ldy));
1082   return ly_interval2scm (pos);
1083 }
1084
1085 // Assuming V is not empty, pick a 'reasonable' point inside V.
1086 static Real
1087 point_in_interval (Interval v, Real dist)
1088 {
1089   if (isinf (v[DOWN]))
1090     return v[UP] - dist;
1091   else if (isinf (v[UP]))
1092     return v[DOWN] + dist;
1093   else
1094     return v.center ();
1095 }
1096
1097 /*
1098   We can't combine with previous function, since check concave and
1099   slope damping comes first.
1100
1101   TODO: we should use the concaveness to control the amount of damping
1102   applied.
1103 */
1104 MAKE_SCHEME_CALLBACK (Beam, shift_region_to_valid, 2);
1105 SCM
1106 Beam::shift_region_to_valid (SCM grob, SCM posns)
1107 {
1108   Grob *me = unsmob_grob (grob);
1109
1110   /*
1111     Code dup.
1112   */
1113   vector<Real> x_posns;
1114   extract_grob_set (me, "stems", stems);
1115   extract_grob_set (me, "covered-grobs", covered);
1116
1117   Grob *common[NO_AXES] = { me, me };
1118   for (Axis a = X_AXIS; a < NO_AXES; incr (a))
1119     {
1120       common[a] = common_refpoint_of_array (stems, me, a);
1121       common[a] = common_refpoint_of_array (covered, common[a], a);
1122     }
1123   Grob *fvs = first_normal_stem (me);
1124
1125   if (!fvs)
1126     return posns;
1127   Interval x_span;
1128   x_span[LEFT] = fvs->relative_coordinate (common[X_AXIS], X_AXIS);
1129   for (vsize i = 0; i < stems.size (); i++)
1130     {
1131       Grob *s = stems[i];
1132
1133       Real x = s->relative_coordinate (common[X_AXIS], X_AXIS) - x_span[LEFT];
1134       x_posns.push_back (x);
1135     }
1136
1137   Grob *lvs = last_normal_stem (me);
1138   x_span[RIGHT] = lvs->relative_coordinate (common[X_AXIS], X_AXIS);
1139
1140   Drul_array<Real> pos = ly_scm2interval (posns);
1141
1142   scale_drul (&pos, Staff_symbol_referencer::staff_space (me));
1143
1144   Real beam_dy = pos[RIGHT] - pos[LEFT];
1145   Real beam_left_y = pos[LEFT];
1146   Real slope = x_span.delta () ? (beam_dy / x_span.delta ()) : 0.0;
1147
1148   /*
1149     Shift the positions so that we have a chance of finding good
1150     quants (i.e. no short stem failures.)
1151   */
1152   Interval feasible_left_point;
1153   feasible_left_point.set_full ();
1154
1155   for (vsize i = 0; i < stems.size (); i++)
1156     {
1157       Grob *s = stems[i];
1158       if (Stem::is_invisible (s))
1159         continue;
1160
1161       Direction d = get_grob_direction (s);
1162       Real left_y
1163         = Stem::get_stem_info (s).shortest_y_
1164           - slope * x_posns [i];
1165
1166       /*
1167         left_y is now relative to the stem S. We want relative to
1168         ourselves, so translate:
1169       */
1170       left_y
1171       += + s->relative_coordinate (common[Y_AXIS], Y_AXIS)
1172          - me->relative_coordinate (common[Y_AXIS], Y_AXIS);
1173
1174       Interval flp;
1175       flp.set_full ();
1176       flp[-d] = left_y;
1177
1178       feasible_left_point.intersect (flp);
1179     }
1180
1181   vector<Grob *> filtered;
1182   /*
1183     We only update these for objects that are too large for quanting
1184     to find a workaround.  Typically, these are notes with
1185     stems, and timesig/keysig/clef, which take out the entire area
1186     inside the staff as feasible.
1187
1188     The code below disregards the thickness and multiplicity of the
1189     beam.  This should not be a problem, as the beam quanting will
1190     take care of computing the impact those exactly.
1191   */
1192   Real min_y_size = 2.0;
1193
1194   // A list of intervals into which beams may not fall
1195   vector<Interval> forbidden_intervals;
1196
1197   for (vsize i = 0; i < covered.size (); i++)
1198     {
1199       if (!covered[i]->is_live ())
1200         continue;
1201
1202       if (Beam::has_interface (covered[i]) && is_cross_staff (covered[i]))
1203         continue;
1204
1205       Box b;
1206       for (Axis a = X_AXIS; a < NO_AXES; incr (a))
1207         b[a] = covered[i]->extent (common[a], a);
1208
1209       if (b[X_AXIS].is_empty () || b[Y_AXIS].is_empty ())
1210         continue;
1211
1212       if (intersection (b[X_AXIS], x_span).is_empty ())
1213         continue;
1214
1215       filtered.push_back (covered[i]);
1216       Grob *head_stem = Rhythmic_head::get_stem (covered[i]);
1217       if (head_stem && Stem::is_normal_stem (head_stem)
1218           && Note_head::has_interface (covered[i]))
1219         {
1220           if (Stem::get_beam (head_stem))
1221             {
1222               /*
1223                 We must assume that stems are infinitely long in this
1224                 case, as asking for the length of the stem typically
1225                 leads to circular dependencies.
1226
1227                 This strategy assumes that we don't want to handle the
1228                 collision of beams in opposite non-forced directions
1229                 with this code, where shortening the stems of both
1230                 would resolve the problem, eg.
1231
1232                  x    x
1233                 |    |
1234                 =====
1235
1236                 =====
1237                 |   |
1238                 x   x
1239
1240                 Such beams would need a coordinating grob to resolve
1241                 the collision, since both will likely want to occupy
1242                 the centerline.
1243               */
1244               Direction stemdir = get_grob_direction (head_stem);
1245               b[Y_AXIS][stemdir] = stemdir * infinity_f;
1246             }
1247           else
1248             {
1249               // TODO - should we include the extent of the stem here?
1250             }
1251         }
1252
1253       if (b[Y_AXIS].length () < min_y_size)
1254         continue;
1255
1256       Direction d = LEFT;
1257       do
1258         {
1259           Real x = b[X_AXIS][d] - x_span[LEFT];
1260           Real dy = slope * x;
1261
1262           Direction yd = DOWN;
1263           Interval disallowed;
1264           do
1265             {
1266               Real left_y = b[Y_AXIS][yd];
1267
1268               left_y -= dy;
1269
1270               // Translate back to beam as ref point.
1271               left_y -= me->relative_coordinate (common[Y_AXIS], Y_AXIS);
1272
1273               disallowed[yd] = left_y;
1274             }
1275           while (flip (&yd) != DOWN);
1276
1277           forbidden_intervals.push_back (disallowed);
1278         }
1279       while (flip (&d) != LEFT);
1280     }
1281
1282   Grob_array *arr
1283     = Pointer_group_interface::get_grob_array (me,
1284                                                ly_symbol2scm ("covered-grobs"));
1285   arr->set_array (filtered);
1286
1287   vector_sort (forbidden_intervals, Interval::left_less);
1288   Real epsilon = 1.0e-10;
1289   Interval feasible_beam_placements (beam_left_y, beam_left_y);
1290
1291   /*
1292     forbidden_intervals contains a vector of intervals in which
1293     the beam cannot start.  it iterates through these intervals,
1294     pushing feasible_beam_placements epsilon over or epsilon under a
1295     collision.  when this type of change happens, the loop is marked
1296     as "dirty" and re-iterated.
1297
1298     TODO: figure out a faster ways that this loop can happen via
1299     a better search algorithm and/or OOP.
1300   */
1301
1302   bool dirty = false;
1303   do
1304     {
1305       dirty = false;
1306       for (vsize i = 0; i < forbidden_intervals.size (); i++)
1307         {
1308           Direction d = DOWN;
1309           do
1310             {
1311               if (forbidden_intervals[i][d] == d * infinity_f)
1312                 feasible_beam_placements[d] = d * infinity_f;
1313               else if (forbidden_intervals[i].contains (feasible_beam_placements[d]))
1314                 {
1315                   feasible_beam_placements[d] = d * epsilon + forbidden_intervals[i][d];
1316                   dirty = true;
1317                 }
1318             }
1319           while (flip (&d) != DOWN);
1320         }
1321     }
1322   while (dirty);
1323
1324   // if the beam placement falls out of the feasible region, we push it
1325   // to infinity so that it can never be a feasible candidate below
1326   Direction d = DOWN;
1327   do
1328     {
1329       if (!feasible_left_point.contains (feasible_beam_placements[d]))
1330         feasible_beam_placements[d] = d * infinity_f;
1331     }
1332   while (flip (&d) != DOWN);
1333
1334   if ((feasible_beam_placements[UP] == infinity_f && feasible_beam_placements[DOWN] == -infinity_f) && !feasible_left_point.is_empty ())
1335     {
1336       // We are somewhat screwed: we have a collision, but at least
1337       // there is a way to satisfy stem length constraints.
1338       beam_left_y = point_in_interval (feasible_left_point, 2.0);
1339     }
1340   else if (!feasible_left_point.is_empty ())
1341     {
1342       // Only one of them offers is feasible solution. Pick that one.
1343       if (abs (beam_left_y - feasible_beam_placements[DOWN]) > abs (beam_left_y - feasible_beam_placements[UP]))
1344         beam_left_y = feasible_beam_placements[UP];
1345       else
1346         beam_left_y = feasible_beam_placements[DOWN];
1347     }
1348   else
1349     {
1350       // We are completely screwed.
1351       me->warning (_ ("no viable initial configuration found: may not find good beam slope"));
1352     }
1353
1354   pos = Drul_array<Real> (beam_left_y, (beam_left_y + beam_dy));
1355   scale_drul (&pos, 1 / Staff_symbol_referencer::staff_space (me));
1356
1357   return ly_interval2scm (pos);
1358 }
1359
1360 /* This neat trick is by Werner Lemberg,
1361    damped = tanh (slope)
1362    corresponds with some tables in [Wanske] CHECKME */
1363 MAKE_SCHEME_CALLBACK (Beam, slope_damping, 2);
1364 SCM
1365 Beam::slope_damping (SCM smob, SCM posns)
1366 {
1367   Grob *me = unsmob_grob (smob);
1368   Drul_array<Real> pos = ly_scm2interval (posns);
1369
1370   if (normal_stem_count (me) <= 1)
1371     return posns;
1372
1373   SCM s = me->get_property ("damping");
1374   Real damping = scm_to_double (s);
1375   Real concaveness = robust_scm2double (me->get_property ("concaveness"), 0.0);
1376   if (concaveness >= 10000)
1377     {
1378       pos[LEFT] = pos[RIGHT];
1379       me->set_property ("least-squares-dy", scm_from_double (0));
1380       damping = 0;
1381     }
1382
1383   if (damping)
1384     {
1385       scale_drul (&pos, Staff_symbol_referencer::staff_space (me));
1386
1387       Real dy = pos[RIGHT] - pos[LEFT];
1388
1389       Grob *fvs = first_normal_stem (me);
1390       Grob *lvs = last_normal_stem (me);
1391
1392       Grob *commonx = fvs->common_refpoint (lvs, X_AXIS);
1393
1394       Real dx = last_normal_stem (me)->relative_coordinate (commonx, X_AXIS)
1395                 - first_normal_stem (me)->relative_coordinate (commonx, X_AXIS);
1396
1397       Real slope = dy && dx ? dy / dx : 0;
1398
1399       slope = 0.6 * tanh (slope) / (damping + concaveness);
1400
1401       Real damped_dy = slope * dx;
1402
1403       set_minimum_dy (me, &damped_dy);
1404
1405       pos[LEFT] += (dy - damped_dy) / 2;
1406       pos[RIGHT] -= (dy - damped_dy) / 2;
1407
1408       scale_drul (&pos, 1 / Staff_symbol_referencer::staff_space (me));
1409     }
1410
1411   return ly_interval2scm (pos);
1412 }
1413
1414 MAKE_SCHEME_CALLBACK (Beam, quanting, 2);
1415 SCM
1416 Beam::quanting (SCM smob, SCM posns)
1417 {
1418   Grob *me = unsmob_grob (smob);
1419   Drul_array<Real> ys (0, 0);
1420   ys = robust_scm2drul (posns, ys);
1421   Beam_scoring_problem problem (me, ys);
1422
1423   ys = problem.solve ();
1424   return ly_interval2scm (ys);
1425 }
1426
1427 /*
1428   Report slice containing the numbers that are both in (car BEAMING)
1429   and (cdr BEAMING)
1430 */
1431 Slice
1432 where_are_the_whole_beams (SCM beaming)
1433 {
1434   Slice l;
1435
1436   for (SCM s = scm_car (beaming); scm_is_pair (s); s = scm_cdr (s))
1437     {
1438       if (scm_c_memq (scm_car (s), scm_cdr (beaming)) != SCM_BOOL_F)
1439
1440         l.add_point (scm_to_int (scm_car (s)));
1441     }
1442
1443   return l;
1444 }
1445
1446 /* Return the Y position of the stem-end, given the Y-left, Y-right
1447    in POS for stem S.  This Y position is relative to S. */
1448 Real
1449 Beam::calc_stem_y (Grob *me, Grob *stem, Grob **common,
1450                    Real xl, Real xr, Direction feather_dir,
1451                    Drul_array<Real> pos, bool french)
1452 {
1453   Real beam_translation = get_beam_translation (me);
1454   Direction stem_dir = get_grob_direction (stem);
1455
1456   Real dx = xr - xl;
1457   Real relx = dx ? (stem->relative_coordinate (common[X_AXIS], X_AXIS) - xl) / dx : 0;
1458   Real xdir = 2 * relx - 1;
1459
1460   Real stem_y = linear_combination (pos, xdir);
1461
1462   SCM beaming = stem->get_property ("beaming");
1463
1464   Slice beam_slice (french
1465                     ? where_are_the_whole_beams (beaming)
1466                     : Stem::beam_multiplicity (stem));
1467   if (beam_slice.is_empty ())
1468     beam_slice = Slice (0, 0);
1469   Interval beam_multiplicity (beam_slice[LEFT],
1470                               beam_slice[RIGHT]);
1471
1472   /*
1473     feather dir = 1 , relx 0->1 : factor 0 -> 1
1474     feather dir = 0 , relx 0->1 : factor 1 -> 1
1475     feather dir = -1, relx 0->1 : factor 1 -> 0
1476    */
1477   Real feather_factor = 1;
1478   if (feather_dir > 0)
1479     feather_factor = relx;
1480   else if (feather_dir < 0)
1481     feather_factor = 1 - relx;
1482
1483   stem_y += feather_factor * beam_translation
1484             * beam_multiplicity[Direction (((french) ? DOWN : UP) * stem_dir)];
1485   Real id = me->relative_coordinate (common[Y_AXIS], Y_AXIS)
1486             - stem->relative_coordinate (common[Y_AXIS], Y_AXIS);
1487
1488   return stem_y + id;
1489 }
1490
1491 /*
1492   Hmm.  At this time, beam position and slope are determined.  Maybe,
1493   stem directions and length should set to relative to the chord's
1494   position of the beam.  */
1495 MAKE_SCHEME_CALLBACK (Beam, set_stem_lengths, 1);
1496 SCM
1497 Beam::set_stem_lengths (SCM smob)
1498 {
1499   Grob *me = unsmob_grob (smob);
1500
1501   /* trigger callbacks. */
1502   (void) me->get_property ("direction");
1503   (void) me->get_property ("beaming");
1504
1505   SCM posns = me->get_property ("positions");
1506
1507   extract_grob_set (me, "stems", stems);
1508   if (!stems.size ())
1509     return posns;
1510
1511   Grob *common[2];
1512   for (int a = 2; a--;)
1513     common[a] = common_refpoint_of_array (stems, me, Axis (a));
1514
1515   Drul_array<Real> pos = ly_scm2realdrul (posns);
1516   Real staff_space = Staff_symbol_referencer::staff_space (me);
1517   scale_drul (&pos, staff_space);
1518
1519   bool gap = false;
1520   Real thick = 0.0;
1521   if (robust_scm2int (me->get_property ("gap-count"), 0))
1522     {
1523       gap = true;
1524       thick = get_beam_thickness (me);
1525     }
1526
1527   Grob *fvs = first_normal_stem (me);
1528   Grob *lvs = last_normal_stem (me);
1529
1530   Real xl = fvs ? fvs->relative_coordinate (common[X_AXIS], X_AXIS) : 0.0;
1531   Real xr = lvs ? lvs->relative_coordinate (common[X_AXIS], X_AXIS) : 0.0;
1532   Direction feather_dir = to_dir (me->get_property ("grow-direction"));
1533
1534   for (vsize i = 0; i < stems.size (); i++)
1535     {
1536       Grob *s = stems[i];
1537
1538       bool french = to_boolean (s->get_property ("french-beaming"));
1539       Real stem_y = calc_stem_y (me, s, common,
1540                                  xl, xr, feather_dir,
1541                                  pos, french && s != lvs && s != fvs);
1542
1543       /*
1544         Make the stems go up to the end of the beam. This doesn't matter
1545         for normal beams, but for tremolo beams it looks silly otherwise.
1546       */
1547       if (gap
1548           && !Stem::is_invisible (s))
1549         stem_y += thick * 0.5 * get_grob_direction (s);
1550
1551       /*
1552         Do set_stem_positions for invisible stems too, so tuplet brackets
1553         have a reference point for sloping
1554        */
1555       Stem::set_stem_positions (s, 2 * stem_y / staff_space);
1556     }
1557
1558   return posns;
1559 }
1560
1561 void
1562 Beam::set_beaming (Grob *me, Beaming_pattern const *beaming)
1563 {
1564   extract_grob_set (me, "stems", stems);
1565
1566   Direction d = LEFT;
1567   for (vsize i = 0; i < stems.size (); i++)
1568     {
1569       /*
1570         Don't overwrite user settings.
1571       */
1572       do
1573         {
1574           Grob *stem = stems[i];
1575           SCM beaming_prop = stem->get_property ("beaming");
1576           if (beaming_prop == SCM_EOL
1577               || index_get_cell (beaming_prop, d) == SCM_EOL)
1578             {
1579               int count = beaming->beamlet_count (i, d);
1580               if (i > 0
1581                   && i + 1 < stems.size ()
1582                   && Stem::is_invisible (stem))
1583                 count = min (count, beaming->beamlet_count (i, -d));
1584
1585               if ( ((i == 0 && d == LEFT)
1586                     || (i == stems.size () - 1 && d == RIGHT))
1587                    && stems.size () > 1
1588                    && to_boolean (me->get_property ("clip-edges")))
1589                 count = 0;
1590
1591               Stem::set_beaming (stem, count, d);
1592             }
1593         }
1594       while (flip (&d) != LEFT);
1595     }
1596 }
1597
1598 int
1599 Beam::forced_stem_count (Grob *me)
1600 {
1601   extract_grob_set (me, "normal-stems", stems);
1602
1603   int f = 0;
1604   for (vsize i = 0; i < stems.size (); i++)
1605     {
1606       Grob *s = stems[i];
1607
1608       /* I can imagine counting those boundaries as a half forced stem,
1609          but let's count them full for now. */
1610       Direction defdir = to_dir (s->get_property ("default-direction"));
1611
1612       if (abs (Stem::chord_start_y (s)) > 0.1
1613           && defdir
1614           && get_grob_direction (s) != defdir)
1615         f++;
1616     }
1617   return f;
1618 }
1619
1620 int
1621 Beam::normal_stem_count (Grob *me)
1622 {
1623   extract_grob_set (me, "normal-stems", stems);
1624   return stems.size ();
1625 }
1626
1627 Grob *
1628 Beam::first_normal_stem (Grob *me)
1629 {
1630   extract_grob_set (me, "normal-stems", stems);
1631   return stems.size () ? stems[0] : 0;
1632 }
1633
1634 Grob *
1635 Beam::last_normal_stem (Grob *me)
1636 {
1637   extract_grob_set (me, "normal-stems", stems);
1638   return stems.size () ? stems.back () : 0;
1639 }
1640
1641 /*
1642   [TODO]
1643
1644   handle rest under beam (do_post: beams are calculated now)
1645   what about combination of collisions and rest under beam.
1646
1647   Should lookup
1648
1649   rest -> stem -> beam -> interpolate_y_position ()
1650 */
1651 MAKE_SCHEME_CALLBACK_WITH_OPTARGS (Beam, rest_collision_callback, 2, 1, "");
1652 SCM
1653 Beam::rest_collision_callback (SCM smob, SCM prev_offset)
1654 {
1655   Grob *rest = unsmob_grob (smob);
1656   if (scm_is_number (rest->get_property ("staff-position")))
1657     return scm_from_int (0);
1658
1659   Real offset = robust_scm2double (prev_offset, 0.0);
1660
1661   Grob *st = unsmob_grob (rest->get_object ("stem"));
1662   Grob *stem = st;
1663   if (!stem)
1664     return scm_from_double (0.0);
1665   Grob *beam = unsmob_grob (stem->get_object ("beam"));
1666   if (!beam
1667       || !Beam::has_interface (beam)
1668       || !Beam::normal_stem_count (beam))
1669     return scm_from_double (0.0);
1670
1671   Drul_array<Real> pos (robust_scm2drul (beam->get_property ("positions"),
1672                                          Drul_array<Real> (0, 0)));
1673
1674   Real staff_space = Staff_symbol_referencer::staff_space (rest);
1675
1676   scale_drul (&pos, staff_space);
1677
1678   Real dy = pos[RIGHT] - pos[LEFT];
1679
1680   Drul_array<Grob *> visible_stems (first_normal_stem (beam),
1681                                     last_normal_stem (beam));
1682   extract_grob_set (beam, "stems", stems);
1683
1684   Grob *common = common_refpoint_of_array (stems, beam, X_AXIS);
1685
1686   Real x0 = visible_stems[LEFT]->relative_coordinate (common, X_AXIS);
1687   Real dx = visible_stems[RIGHT]->relative_coordinate (common, X_AXIS) - x0;
1688   Real slope = dy && dx ? dy / dx : 0;
1689
1690   Direction d = get_grob_direction (stem);
1691   Real stem_y = pos[LEFT]
1692                 + (stem->relative_coordinate (common, X_AXIS) - x0) * slope;
1693
1694   Real beam_translation = get_beam_translation (beam);
1695   Real beam_thickness = Beam::get_beam_thickness (beam);
1696
1697   /*
1698     TODO: this is not strictly correct for 16th knee beams.
1699   */
1700   int beam_count
1701     = Stem::beam_multiplicity (stem).length () + 1;
1702
1703   Real height_of_my_beams = beam_thickness / 2
1704                             + (beam_count - 1) * beam_translation;
1705   Real beam_y = stem_y - d * height_of_my_beams;
1706
1707   Grob *common_y = rest->common_refpoint (beam, Y_AXIS);
1708
1709   Interval rest_extent = rest->extent (rest, Y_AXIS);
1710   rest_extent.translate (offset + rest->get_parent (Y_AXIS)->relative_coordinate (common_y, Y_AXIS));
1711
1712   Real rest_dim = rest_extent[d];
1713   Real minimum_distance
1714     = staff_space * (robust_scm2double (stem->get_property ("stemlet-length"), 0.0)
1715                      + robust_scm2double (rest->get_property ("minimum-distance"), 0.0));
1716
1717   Real shift = d * min (d * (beam_y - d * minimum_distance - rest_dim), 0.0);
1718
1719   shift /= staff_space;
1720   Real rad = Staff_symbol_referencer::line_count (rest) * staff_space / 2;
1721
1722   /* Always move discretely by half spaces */
1723   shift = ceil (fabs (shift * 2.0)) / 2.0 * sign (shift);
1724
1725   /* Inside staff, move by whole spaces*/
1726   if ((rest_extent[d] + staff_space * shift) * d
1727       < rad
1728       || (rest_extent[-d] + staff_space * shift) * -d
1729       < rad)
1730     shift = ceil (fabs (shift)) * sign (shift);
1731
1732   return scm_from_double (offset + staff_space * shift);
1733 }
1734
1735 MAKE_SCHEME_CALLBACK_WITH_OPTARGS (Beam, pure_rest_collision_callback, 4, 1, "");
1736 SCM
1737 Beam::pure_rest_collision_callback (SCM smob,
1738                                     SCM, /* prev_offset */
1739                                     SCM, /* start */
1740                                     SCM /* end */)
1741 {
1742   Real amount = 0.0;
1743
1744   Grob *me = unsmob_grob (smob);
1745   Grob *stem = unsmob_grob (me->get_object ("stem"));
1746   if (!stem)
1747     return scm_from_double (amount);
1748   Grob *beam = unsmob_grob (stem->get_object ("beam"));
1749   if (!beam
1750       || !Beam::normal_stem_count (beam))
1751     return scm_from_double (amount);
1752
1753   Real ss = Staff_symbol_referencer::staff_space (me);
1754
1755   /*
1756     This gives the extrema of rest positions.
1757     In general, beams are never typeset more than one staff space away
1758     from the staff in either direction.
1759   */
1760   Grob *staff = Staff_symbol_referencer::get_staff_symbol (me);
1761   Interval rest_max_pos = staff ? Staff_symbol::line_span (staff) : Interval (0.0, 0.0);
1762   rest_max_pos.widen (1);
1763   rest_max_pos *= ss / 2;
1764
1765   extract_grob_set (beam, "stems", stems);
1766   vector<Grob *> my_stems;
1767
1768   for (vsize i = 0; i < stems.size (); i++)
1769     if (Stem::head_count (stems[i]) || stems[i] == stem)
1770       my_stems.push_back (stems[i]);
1771
1772   vsize idx = -1;
1773
1774   for (vsize i = 0; i < my_stems.size (); i++)
1775     if (my_stems[i] == stem)
1776       {
1777         idx = i;
1778         break;
1779       }
1780   Grob *left;
1781   Grob *right;
1782
1783   if (idx == (vsize)-1 || my_stems.size () == 1)
1784     return scm_from_double (amount);
1785   else if (idx == 0)
1786     left = right = my_stems[1];
1787   else if (idx == my_stems.size () - 1)
1788     left = right = my_stems[idx - 1];
1789   else
1790     {
1791       left = my_stems[idx - 1];
1792       right = my_stems[idx + 1];
1793     }
1794   Direction beamdir = get_grob_direction (beam);
1795   /*
1796     Take the position between the two bounding head_positions,
1797     then bound it by the minimum and maximum positions outside the staff.
1798     4.0 = 2.0 to get out of staff space * 2.0 for the average
1799   */
1800   amount = min (max ((Stem::head_positions (left)[beamdir] + Stem::head_positions (right)[beamdir]) / 4.0, rest_max_pos[DOWN]), rest_max_pos[UP]);
1801
1802   return scm_from_double (amount);
1803 }
1804
1805
1806 bool
1807 Beam::is_knee (Grob *me)
1808 {
1809   SCM k = me->get_property ("knee");
1810   if (scm_is_bool (k))
1811     return ly_scm2bool (k);
1812
1813   bool knee = false;
1814   int d = 0;
1815   extract_grob_set (me, "stems", stems);
1816   for (vsize i = stems.size (); i--;)
1817     {
1818       Direction dir = get_grob_direction (stems[i]);
1819       if (d && d != dir)
1820         {
1821           knee = true;
1822           break;
1823         }
1824       d = dir;
1825     }
1826
1827   me->set_property ("knee", ly_bool2scm (knee));
1828
1829   return knee;
1830 }
1831
1832 bool
1833 Beam::is_cross_staff (Grob *me)
1834 {
1835   extract_grob_set (me, "stems", stems);
1836   Grob *staff_symbol = Staff_symbol_referencer::get_staff_symbol (me);
1837   for (vsize i = 0; i < stems.size (); i++)
1838     if (Staff_symbol_referencer::get_staff_symbol (stems[i]) != staff_symbol)
1839       return true;
1840   return false;
1841 }
1842
1843 MAKE_SCHEME_CALLBACK (Beam, calc_cross_staff, 1)
1844 SCM
1845 Beam::calc_cross_staff (SCM smob)
1846 {
1847   return scm_from_bool (is_cross_staff (unsmob_grob (smob)));
1848 }
1849
1850 int
1851 Beam::get_direction_beam_count (Grob *me, Direction d)
1852 {
1853   extract_grob_set (me, "stems", stems);
1854   int bc = 0;
1855
1856   for (vsize i = stems.size (); i--;)
1857     {
1858       /*
1859         Should we take invisible stems into account?
1860       */
1861       if (get_grob_direction (stems[i]) == d)
1862         bc = max (bc, (Stem::beam_multiplicity (stems[i]).length () + 1));
1863     }
1864
1865   return bc;
1866 }
1867
1868 ADD_INTERFACE (Beam,
1869                "A beam.\n"
1870                "\n"
1871                "The @code{beam-thickness} property is the weight of beams,"
1872                " measured in staffspace.  The @code{direction} property is"
1873                " not user-serviceable.  Use the @code{direction} property"
1874                " of @code{Stem} instead.\n"
1875                "\n"
1876                "The following properties may be set in the @code{details}"
1877                " list.\n"
1878                "\n"
1879                "@table @code\n"
1880                "@item stem-length-demerit-factor\n"
1881                "Demerit factor used for inappropriate stem lengths.\n"
1882                "@item secondary-beam-demerit\n"
1883                "Demerit used in quanting calculations for multiple"
1884                " beams.\n"
1885                "@item region-size\n"
1886                "Size of region for checking quant scores.\n"
1887                "@item beam-eps\n"
1888                "Epsilon for beam quant code to check for presence"
1889                " in gap.\n"
1890                "@item stem-length-limit-penalty\n"
1891                "Penalty for differences in stem lengths on a beam.\n"
1892                "@item damping-direction-penalty\n"
1893                "Demerit penalty applied when beam direction is different"
1894                " from damping direction.\n"
1895                "@item hint-direction-penalty\n"
1896                "Demerit penalty applied when beam direction is different"
1897                " from damping direction, but damping slope is"
1898                " <= @code{round-to-zero-slope}.\n"
1899                "@item musical-direction-factor\n"
1900                "Demerit scaling factor for difference between"
1901                " beam slope and music slope.\n"
1902                "@item ideal-slope-factor\n"
1903                "Demerit scaling factor for difference between"
1904                " beam slope and damping slope.\n"
1905                "@item round-to-zero-slope\n"
1906                "Damping slope which is considered zero for purposes of"
1907                " calculating direction penalties.\n"
1908                "@end table\n",
1909
1910                /* properties */
1911                "annotation "
1912                "auto-knee-gap "
1913                "beamed-stem-shorten "
1914                "beaming "
1915                "beam-thickness "
1916                "break-overshoot "
1917                "clip-edges "
1918                "concaveness "
1919                "collision-interfaces "
1920                "collision-voice-only "
1921                "covered-grobs "
1922                "damping "
1923                "details "
1924                "direction "
1925                "gap "
1926                "gap-count "
1927                "grow-direction "
1928                "inspect-quants "
1929                "knee "
1930                "length-fraction "
1931                "least-squares-dy "
1932                "neutral-direction "
1933                "normal-stems "
1934                "positions "
1935                "quantized-positions "
1936                "shorten "
1937                "stems "
1938               );