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