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