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