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