]> git.donarmstrong.com Git - lilypond.git/blob - lily/beam-quanting.cc
Merge branch 'master' into lilypond/translation
[lilypond.git] / lily / beam-quanting.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 #include "beam-scoring-problem.hh"
22
23 #include <algorithm>
24 #include <queue>
25 #include <set>
26 using namespace std;
27
28 #include "align-interface.hh"
29 #include "beam.hh"
30 #include "direction.hh"
31 #include "directional-element-interface.hh"
32 #include "grob.hh"
33 #include "grob-array.hh"
34 #include "item.hh"
35 #include "international.hh"
36 #include "least-squares.hh"
37 #include "libc-extension.hh"
38 #include "main.hh"
39 #include "note-head.hh"
40 #include "output-def.hh"
41 #include "pointer-group-interface.hh"
42 #include "rhythmic-head.hh"
43 #include "staff-symbol-referencer.hh"
44 #include "stencil.hh"
45 #include "stem.hh"
46 #include "warn.hh"
47
48 Real
49 get_detail (SCM alist, SCM sym, Real def)
50 {
51   SCM entry = scm_assq (sym, alist);
52
53   if (scm_is_pair (entry))
54     return robust_scm2double (scm_cdr (entry), def);
55   return def;
56 }
57
58 void
59 Beam_quant_parameters::fill (Grob *him)
60 {
61   SCM details = him->get_property ("details");
62
63   // General
64   BEAM_EPS = get_detail (details, ly_symbol2scm ("beam-eps"), 1e-3);
65   REGION_SIZE = get_detail (details, ly_symbol2scm ("region-size"), 2);
66
67   // forbidden quants
68   SECONDARY_BEAM_DEMERIT = get_detail (details, ly_symbol2scm ("secondary-beam-demerit"), 10.0);
69   STEM_LENGTH_DEMERIT_FACTOR = get_detail (details, ly_symbol2scm ("stem-length-demerit-factor"), 5);
70   HORIZONTAL_INTER_QUANT_PENALTY = get_detail (details, ly_symbol2scm ("horizontal-inter-quant"), 500);
71
72   STEM_LENGTH_LIMIT_PENALTY = get_detail (details, ly_symbol2scm ("stem-length-limit-penalty"), 5000);
73   DAMPING_DIRECTION_PENALTY = get_detail (details, ly_symbol2scm ("damping-direction-penalty"), 800);
74   HINT_DIRECTION_PENALTY = get_detail (details, ly_symbol2scm ("hint-direction-penalty"), 20);
75   MUSICAL_DIRECTION_FACTOR = get_detail (details, ly_symbol2scm ("musical-direction-factor"), 400);
76   IDEAL_SLOPE_FACTOR = get_detail (details, ly_symbol2scm ("ideal-slope-factor"), 10);
77   ROUND_TO_ZERO_SLOPE = get_detail (details, ly_symbol2scm ("round-to-zero-slope"), 0.02);
78
79   // Collisions
80   COLLISION_PENALTY = get_detail (details, ly_symbol2scm ("collision-penalty"), 500);
81   COLLISION_PADDING = get_detail (details, ly_symbol2scm ("collision-padding"), 0.5);
82   STEM_COLLISION_FACTOR = get_detail (details, ly_symbol2scm ("stem-collision-factor"), 0.1);
83 }
84
85 // Add x if x is positive, add |x|*fac if x is negative.
86 static Real
87 shrink_extra_weight (Real x, Real fac)
88 {
89   return fabs (x) * ((x < 0) ? fac : 1.0);
90 }
91
92 /****************************************************************/
93
94 Beam_configuration::Beam_configuration ()
95 {
96   y = Interval (0.0, 0.0);
97   demerits = 0.0;
98   next_scorer_todo = ORIGINAL_DISTANCE;
99 }
100
101 bool Beam_configuration::done () const
102 {
103   return next_scorer_todo >= NUM_SCORERS;
104 }
105
106 void Beam_configuration::add (Real demerit, const string &reason)
107 {
108   demerits += demerit;
109
110 #if DEBUG_BEAM_SCORING
111   if (demerit)
112     score_card_ += to_string (" %s %.2f", reason.c_str (), demerit);
113 #endif
114 }
115
116 Beam_configuration *Beam_configuration::new_config (Interval start,
117                                                     Interval offset)
118 {
119   Beam_configuration *qs = new Beam_configuration;
120   qs->y = Interval (int (start[LEFT]) + offset[LEFT],
121                     int (start[RIGHT]) + offset[RIGHT]);
122
123   // This orders the sequence so we try combinations closest to the
124   // the ideal offset first.
125   Real start_score = abs (offset[RIGHT]) + abs (offset[LEFT]);
126   qs->demerits = start_score / 1000.0;
127   qs->next_scorer_todo = ORIGINAL_DISTANCE + 1;
128
129   return qs;
130 }
131
132 Real
133 Beam_scoring_problem::y_at (Real x, Beam_configuration const *p) const
134 {
135   return p->y[LEFT] + (x - x_span_[LEFT]) * p->y.delta () / x_span_.delta ();
136 }
137
138 /****************************************************************/
139
140 /*
141   TODO:
142
143   - Make all demerits customisable
144
145   - Add demerits for quants per se, as to forbid a specific quant
146   entirely
147 */
148
149 // This is a temporary hack to see how much we can gain by using a
150 // priority queue on the beams to score.
151 static int score_count = 0;
152 LY_DEFINE (ly_beam_score_count, "ly:beam-score-count", 0, 0, 0,
153            (),
154            "count number of beam scores.")
155 {
156   return scm_from_int (score_count);
157 }
158
159 void Beam_scoring_problem::add_collision (Real x, Interval y,
160                                           Real score_factor)
161 {
162   if (edge_dirs_[LEFT] == edge_dirs_[RIGHT])
163     {
164       Direction d = edge_dirs_[LEFT];
165
166       Real quant_range_y = quant_range_[LEFT][-d]
167                            + (x - x_span_[LEFT]) * (quant_range_[RIGHT][-d] - quant_range_[LEFT][-d]) / x_span_.delta ();
168
169       if (d * (quant_range_y - minmax (d, y[UP], y[DOWN])) > 0)
170         {
171           return;
172         }
173     }
174
175   Beam_collision c;
176   c.beam_y_.set_empty ();
177
178   for (vsize j = 0; j < segments_.size (); j++)
179     {
180       if (segments_[j].horizontal_.contains (x))
181         c.beam_y_.add_point (segments_[j].vertical_count_ * beam_translation_);
182       if (segments_[j].horizontal_[LEFT] > x)
183         break;
184     }
185   c.beam_y_.widen (0.5 * beam_thickness_);
186
187   c.x_ = x;
188
189   y *= 1 / staff_space_;
190   c.y_ = y;
191   c.base_penalty_ = score_factor;
192   collisions_.push_back (c);
193 }
194
195 void Beam_scoring_problem::init_collisions (vector<Grob *> grobs)
196 {
197   Grob *common_x = NULL;
198   segments_ = Beam::get_beam_segments (beam_, &common_x);
199   vector_sort (segments_, beam_segment_less);
200   if (common_[X_AXIS] != common_x)
201     {
202       programming_error ("Disagree on common x. Skipping collisions in beam scoring.");
203       return;
204     }
205
206   set<Grob *> stems;
207   for (vsize i = 0; i < grobs.size (); i++)
208     {
209       Box b;
210       for (Axis a = X_AXIS; a < NO_AXES; incr (a))
211         b[a] = grobs[i]->extent (common_[a], a);
212
213       Real width = b[X_AXIS].length ();
214       Real width_factor = sqrt (width / staff_space_);
215
216       Direction d = LEFT;
217       do
218         add_collision (b[X_AXIS][d], b[Y_AXIS], width_factor);
219       while (flip (&d) != LEFT);
220
221       Grob *stem = unsmob_grob (grobs[i]->get_object ("stem"));
222       if (stem && Stem::has_interface (stem) && Stem::is_normal_stem (stem))
223         {
224           stems.insert (stem);
225         }
226     }
227
228   for (set<Grob *>::const_iterator it (stems.begin ()); it != stems.end (); it++)
229     {
230       Grob *s = *it;
231       Real x = s->extent (common_[X_AXIS], X_AXIS).center ();
232
233       Direction stem_dir = get_grob_direction (*it);
234       Interval y;
235       y.set_full ();
236       y[-stem_dir] = Stem::chord_start_y (*it) + (*it)->relative_coordinate (common_[Y_AXIS], Y_AXIS)
237                      - beam_->relative_coordinate (common_[Y_AXIS], Y_AXIS);
238
239       Real factor = parameters_.STEM_COLLISION_FACTOR;
240       if (!unsmob_grob (s->get_object ("beam")))
241         factor = 1.0;
242       add_collision (x, y, factor);
243     }
244 }
245
246 void Beam_scoring_problem::init_stems ()
247 {
248   extract_grob_set (beam_, "covered-grobs", collisions);
249   extract_grob_set (beam_, "stems", stems);
250   for (int a = 2; a--;)
251     {
252       common_[a] = common_refpoint_of_array (stems, beam_, Axis (a));
253       common_[a] = common_refpoint_of_array (collisions, common_[a], Axis (a));
254     }
255
256   Drul_array<Grob *> edge_stems (Beam::first_normal_stem (beam_),
257                                  Beam::last_normal_stem (beam_));
258   Direction d = LEFT;
259   do
260     x_span_[d] = edge_stems[d] ? edge_stems[d]->relative_coordinate (common_[X_AXIS], X_AXIS) : 0.0;
261   while (flip (&d) != LEFT);
262
263   Drul_array<bool> dirs_found (0, 0);
264   for (vsize i = 0; i < stems.size (); i++)
265     {
266       Grob *s = stems[i];
267       if (!Stem::is_normal_stem (s))
268         continue;
269
270       Stem_info si (Stem::get_stem_info (s));
271       si.scale (1 / staff_space_);
272       stem_infos_.push_back (si);
273       dirs_found[si.dir_] = true;
274
275       bool f = to_boolean (s->get_property ("french-beaming"))
276                && s != edge_stems[LEFT] && s != edge_stems[RIGHT];
277
278       Real y = Beam::calc_stem_y (beam_, s, common_, x_span_[LEFT], x_span_[RIGHT], CENTER,
279                                   Interval (0, 0), f);
280       base_lengths_.push_back (y / staff_space_);
281       stem_xpositions_.push_back (s->relative_coordinate (common_[X_AXIS], X_AXIS));
282     }
283
284   edge_dirs_ = Drul_array<Direction> (CENTER, CENTER);
285   if (stem_infos_.size ())
286     {
287       edge_dirs_ = Drul_array<Direction> (stem_infos_[0].dir_,
288                                          stem_infos_.back ().dir_);
289     }
290
291   is_xstaff_ = Align_interface::has_interface (common_[Y_AXIS]);
292   is_knee_ = dirs_found[LEFT] && dirs_found[RIGHT];
293
294   staff_radius_ = Staff_symbol_referencer::staff_radius (beam_);
295   edge_beam_counts_ = Drul_array<int>
296                      (Stem::beam_multiplicity (stems[0]).length () + 1,
297                       Stem::beam_multiplicity (stems.back ()).length () + 1);
298
299   // TODO - why are we dividing by staff_space_?
300   beam_translation_ = Beam::get_beam_translation (beam_) / staff_space_;
301
302   d = LEFT;
303   do
304     {
305       quant_range_[d].set_full ();
306       if (!edge_stems[d])
307         continue;
308
309       Real stem_offset = edge_stems[d]->relative_coordinate (common_[Y_AXIS], Y_AXIS)
310                          - beam_->relative_coordinate (common_[Y_AXIS], Y_AXIS);
311       Interval heads = Stem::head_positions (edge_stems[d]) * 0.5 * staff_space_;
312
313       Direction ed = edge_dirs_[d];
314       heads.widen (0.5 * staff_space_
315                    + (edge_beam_counts_[d] - 1) * beam_translation_ + beam_thickness_ * .5);
316       quant_range_[d][-ed] = heads[ed] + stem_offset;
317     }
318   while (flip (&d) != LEFT);
319
320   init_collisions (collisions);
321 }
322
323 Beam_scoring_problem::Beam_scoring_problem (Grob *me, Drul_array<Real> ys)
324 {
325   beam_ = me;
326   unquanted_y_ = ys;
327
328   /*
329     Calculations are relative to a unit-scaled staff, i.e. the quants are
330     divided by the current staff_space_.
331   */
332   staff_space_ = Staff_symbol_referencer::staff_space (me);
333   beam_thickness_ = Beam::get_beam_thickness (me) / staff_space_;
334   line_thickness_ = Staff_symbol_referencer::line_thickness (me) / staff_space_;
335
336   // This is the least-squares DY, corrected for concave beams.
337   musical_dy_ = robust_scm2double (me->get_property ("least-squares-dy"), 0);
338
339   parameters_.fill (me);
340   init_stems ();
341 }
342
343 // Assuming V is not empty, pick a 'reasonable' point inside V.
344 static Real
345 point_in_interval (Interval v, Real dist)
346 {
347   if (isinf (v[DOWN]))
348     return v[UP] - dist;
349   else if (isinf (v[UP]))
350     return v[DOWN] + dist;
351   else
352     return v.center ();
353 }
354
355 /* Set stem's shorten property if unset.
356
357 TODO:
358 take some y-position (chord/beam/nearest?) into account
359 scmify forced-fraction
360
361 This is done in beam because the shorten has to be uniform over the
362 entire beam.
363 */
364
365 void
366 set_minimum_dy (Grob *me, Real *dy)
367 {
368   if (*dy)
369     {
370       /*
371         If dy is smaller than the smallest quant, we
372         get absurd direction-sign penalties.
373       */
374
375       Real ss = Staff_symbol_referencer::staff_space (me);
376       Real beam_thickness = Beam::get_beam_thickness (me) / ss;
377       Real slt = Staff_symbol_referencer::line_thickness (me) / ss;
378       Real sit = (beam_thickness - slt) / 2;
379       Real inter = 0.5;
380       Real hang = 1.0 - (beam_thickness - slt) / 2;
381
382       *dy = sign (*dy) * max (fabs (*dy),
383                               min (min (sit, inter), hang));
384     }
385 }
386
387 Interval
388 Beam::no_visible_stem_positions (Grob *me, Interval default_value)
389 {
390   extract_grob_set (me, "stems", stems);
391   if (stems.empty ())
392     return default_value;
393
394   Interval head_positions;
395   Slice multiplicity;
396   for (vsize i = 0; i < stems.size (); i++)
397     {
398       head_positions.unite (Stem::head_positions (stems[i]));
399       multiplicity.unite (Stem::beam_multiplicity (stems[i]));
400     }
401
402   Direction dir = get_grob_direction (me);
403
404   if (!dir)
405     programming_error ("The beam should have a direction by now.");
406
407   Real y = head_positions.linear_combination (dir)
408            * 0.5 * Staff_symbol_referencer::staff_space (me)
409            + dir * get_beam_translation (me) * (multiplicity.length () + 1);
410
411   y /= Staff_symbol_referencer::staff_space (me);
412   return Interval (y, y);
413 }
414
415 /*
416   Compute a first approximation to the beam slope.
417 */
418 MAKE_SCHEME_CALLBACK (Beam, calc_least_squares_positions, 2);
419 SCM
420 Beam::calc_least_squares_positions (SCM smob, SCM /* posns */)
421 {
422   Grob *me = unsmob_grob (smob);
423
424   int count = normal_stem_count (me);
425   Interval pos (0, 0);
426   if (count < 1)
427     return ly_interval2scm (no_visible_stem_positions (me, pos));
428
429   vector<Real> x_posns;
430   extract_grob_set (me, "normal-stems", stems);
431   Grob *commonx = common_refpoint_of_array (stems, me, X_AXIS);
432   Grob *commony = common_refpoint_of_array (stems, me, Y_AXIS);
433
434   Real my_y = me->relative_coordinate (commony, Y_AXIS);
435
436   Grob *fvs = first_normal_stem (me);
437   Grob *lvs = last_normal_stem (me);
438
439   Interval ideal (Stem::get_stem_info (fvs).ideal_y_
440                   + fvs->relative_coordinate (commony, Y_AXIS) - my_y,
441                   Stem::get_stem_info (lvs).ideal_y_
442                   + lvs->relative_coordinate (commony, Y_AXIS) - my_y);
443
444   Real x0 = first_normal_stem (me)->relative_coordinate (commonx, X_AXIS);
445   for (vsize i = 0; i < stems.size (); i++)
446     {
447       Grob *s = stems[i];
448
449       Real x = s->relative_coordinate (commonx, X_AXIS) - x0;
450       x_posns.push_back (x);
451     }
452   Real dx = last_normal_stem (me)->relative_coordinate (commonx, X_AXIS) - x0;
453
454   Real y = 0;
455   Real slope = 0;
456   Real dy = 0;
457   Real ldy = 0.0;
458   if (!ideal.delta ())
459     {
460       Interval chord (Stem::chord_start_y (stems[0]),
461                       Stem::chord_start_y (stems.back ()));
462
463       /* Simple beams (2 stems) on middle line should be allowed to be
464          slightly sloped.
465
466          However, if both stems reach middle line,
467          ideal[LEFT] == ideal[RIGHT] and ideal.delta () == 0.
468
469          For that case, we apply artificial slope */
470       if (!ideal[LEFT] && chord.delta () && count == 2)
471         {
472           /* FIXME. -> UP */
473           Direction d = (Direction) (sign (chord.delta ()) * UP);
474           pos[d] = get_beam_thickness (me) / 2;
475           pos[-d] = -pos[d];
476         }
477       else
478         pos = ideal;
479
480       /*
481         For broken beams this doesn't work well. In this case, the
482         slope esp. of the first part of a broken beam should predict
483         where the second part goes.
484       */
485       ldy = pos[RIGHT] - pos[LEFT];
486     }
487   else
488     {
489       vector<Offset> ideals;
490       for (vsize i = 0; i < stems.size (); i++)
491         {
492           Grob *s = stems[i];
493           ideals.push_back (Offset (x_posns[i],
494                                     Stem::get_stem_info (s).ideal_y_
495                                     + s->relative_coordinate (commony, Y_AXIS)
496                                     - my_y));
497         }
498
499       minimise_least_squares (&slope, &y, ideals);
500
501       dy = slope * dx;
502
503       set_minimum_dy (me, &dy);
504
505       ldy = dy;
506       pos = Interval (y, (y + dy));
507     }
508
509   /*
510     "position" is relative to the staff.
511   */
512   scale_drul (&pos, 1 / Staff_symbol_referencer::staff_space (me));
513
514   me->set_property ("least-squares-dy", scm_from_double (ldy));
515   return ly_interval2scm (pos);
516 }
517
518 /* This neat trick is by Werner Lemberg,
519    damped = tanh (slope)
520    corresponds with some tables in [Wanske] CHECKME */
521 MAKE_SCHEME_CALLBACK (Beam, slope_damping, 2);
522 SCM
523 Beam::slope_damping (SCM smob, SCM posns)
524 {
525   Grob *me = unsmob_grob (smob);
526   Drul_array<Real> pos = ly_scm2interval (posns);
527
528   if (normal_stem_count (me) <= 1)
529     return posns;
530
531   SCM s = me->get_property ("damping");
532   Real damping = scm_to_double (s);
533   Real concaveness = robust_scm2double (me->get_property ("concaveness"), 0.0);
534   if (concaveness >= 10000)
535     {
536       pos[LEFT] = pos[RIGHT];
537       me->set_property ("least-squares-dy", scm_from_double (0));
538       damping = 0;
539     }
540
541   if (damping)
542     {
543       scale_drul (&pos, Staff_symbol_referencer::staff_space (me));
544
545       Real dy = pos[RIGHT] - pos[LEFT];
546
547       Grob *fvs = first_normal_stem (me);
548       Grob *lvs = last_normal_stem (me);
549
550       Grob *commonx = fvs->common_refpoint (lvs, X_AXIS);
551
552       Real dx = last_normal_stem (me)->relative_coordinate (commonx, X_AXIS)
553                 - first_normal_stem (me)->relative_coordinate (commonx, X_AXIS);
554
555       Real slope = dy && dx ? dy / dx : 0;
556
557       slope = 0.6 * tanh (slope) / (damping + concaveness);
558
559       Real damped_dy = slope * dx;
560
561       set_minimum_dy (me, &damped_dy);
562
563       pos[LEFT] += (dy - damped_dy) / 2;
564       pos[RIGHT] -= (dy - damped_dy) / 2;
565
566       scale_drul (&pos, 1 / Staff_symbol_referencer::staff_space (me));
567     }
568
569   return ly_interval2scm (pos);
570 }
571
572 /*
573   We can't combine with previous function, since check concave and
574   slope damping comes first.
575
576   TODO: we should use the concaveness to control the amount of damping
577   applied.
578 */
579 MAKE_SCHEME_CALLBACK (Beam, shift_region_to_valid, 2);
580 SCM
581 Beam::shift_region_to_valid (SCM grob, SCM posns)
582 {
583   Grob *me = unsmob_grob (grob);
584
585   /*
586     Code dup.
587   */
588   vector<Real> x_posns;
589   extract_grob_set (me, "stems", stems);
590   extract_grob_set (me, "covered-grobs", covered);
591
592   Grob *common[NO_AXES] = { me, me };
593   for (Axis a = X_AXIS; a < NO_AXES; incr (a))
594     {
595       common[a] = common_refpoint_of_array (stems, me, a);
596       common[a] = common_refpoint_of_array (covered, common[a], a);
597     }
598   Grob *fvs = first_normal_stem (me);
599
600   if (!fvs)
601     return posns;
602   Interval x_span;
603   x_span[LEFT] = fvs->relative_coordinate (common[X_AXIS], X_AXIS);
604   for (vsize i = 0; i < stems.size (); i++)
605     {
606       Grob *s = stems[i];
607
608       Real x = s->relative_coordinate (common[X_AXIS], X_AXIS) - x_span[LEFT];
609       x_posns.push_back (x);
610     }
611
612   Grob *lvs = last_normal_stem (me);
613   x_span[RIGHT] = lvs->relative_coordinate (common[X_AXIS], X_AXIS);
614
615   Drul_array<Real> pos = ly_scm2interval (posns);
616
617   scale_drul (&pos, Staff_symbol_referencer::staff_space (me));
618
619   Real beam_dy = pos[RIGHT] - pos[LEFT];
620   Real beam_left_y = pos[LEFT];
621   Real slope = x_span.delta () ? (beam_dy / x_span.delta ()) : 0.0;
622
623   /*
624     Shift the positions so that we have a chance of finding good
625     quants (i.e. no short stem failures.)
626   */
627   Interval feasible_left_point;
628   feasible_left_point.set_full ();
629
630   for (vsize i = 0; i < stems.size (); i++)
631     {
632       Grob *s = stems[i];
633       if (Stem::is_invisible (s))
634         continue;
635
636       Direction d = get_grob_direction (s);
637       Real left_y
638         = Stem::get_stem_info (s).shortest_y_
639           - slope * x_posns [i];
640
641       /*
642         left_y is now relative to the stem S. We want relative to
643         ourselves, so translate:
644       */
645       left_y
646       += + s->relative_coordinate (common[Y_AXIS], Y_AXIS)
647          - me->relative_coordinate (common[Y_AXIS], Y_AXIS);
648
649       Interval flp;
650       flp.set_full ();
651       flp[-d] = left_y;
652
653       feasible_left_point.intersect (flp);
654     }
655
656   vector<Grob *> filtered;
657   /*
658     We only update these for objects that are too large for quanting
659     to find a workaround.  Typically, these are notes with
660     stems, and timesig/keysig/clef, which take out the entire area
661     inside the staff as feasible.
662
663     The code below disregards the thickness and multiplicity of the
664     beam.  This should not be a problem, as the beam quanting will
665     take care of computing the impact those exactly.
666   */
667   Real min_y_size = 2.0;
668
669   // A list of intervals into which beams may not fall
670   vector<Interval> forbidden_intervals;
671
672   for (vsize i = 0; i < covered.size (); i++)
673     {
674       if (!covered[i]->is_live ())
675         continue;
676
677       if (Beam::has_interface (covered[i]) && is_cross_staff (covered[i]))
678         continue;
679
680       Box b;
681       for (Axis a = X_AXIS; a < NO_AXES; incr (a))
682         b[a] = covered[i]->extent (common[a], a);
683
684       if (b[X_AXIS].is_empty () || b[Y_AXIS].is_empty ())
685         continue;
686
687       if (intersection (b[X_AXIS], x_span).is_empty ())
688         continue;
689
690       filtered.push_back (covered[i]);
691       Grob *head_stem = Rhythmic_head::get_stem (covered[i]);
692       if (head_stem && Stem::is_normal_stem (head_stem)
693           && Note_head::has_interface (covered[i]))
694         {
695           if (Stem::get_beam (head_stem))
696             {
697               /*
698                 We must assume that stems are infinitely long in this
699                 case, as asking for the length of the stem typically
700                 leads to circular dependencies.
701
702                 This strategy assumes that we don't want to handle the
703                 collision of beams in opposite non-forced directions
704                 with this code, where shortening the stems of both
705                 would resolve the problem, eg.
706
707                  x    x
708                 |    |
709                 =====
710
711                 =====
712                 |   |
713                 x   x
714
715                 Such beams would need a coordinating grob to resolve
716                 the collision, since both will likely want to occupy
717                 the centerline.
718               */
719               Direction stemdir = get_grob_direction (head_stem);
720               b[Y_AXIS][stemdir] = stemdir * infinity_f;
721             }
722           else
723             {
724               // TODO - should we include the extent of the stem here?
725             }
726         }
727
728       if (b[Y_AXIS].length () < min_y_size)
729         continue;
730
731       Direction d = LEFT;
732       do
733         {
734           Real x = b[X_AXIS][d] - x_span[LEFT];
735           Real dy = slope * x;
736
737           Direction yd = DOWN;
738           Interval disallowed;
739           do
740             {
741               Real left_y = b[Y_AXIS][yd];
742
743               left_y -= dy;
744
745               // Translate back to beam as ref point.
746               left_y -= me->relative_coordinate (common[Y_AXIS], Y_AXIS);
747
748               disallowed[yd] = left_y;
749             }
750           while (flip (&yd) != DOWN);
751
752           forbidden_intervals.push_back (disallowed);
753         }
754       while (flip (&d) != LEFT);
755     }
756
757   Grob_array *arr
758     = Pointer_group_interface::get_grob_array (me,
759                                                ly_symbol2scm ("covered-grobs"));
760   arr->set_array (filtered);
761
762   vector_sort (forbidden_intervals, Interval::left_less);
763   Real epsilon = 1.0e-10;
764   Interval feasible_beam_placements (beam_left_y, beam_left_y);
765
766   /*
767     forbidden_intervals contains a vector of intervals in which
768     the beam cannot start.  it iterates through these intervals,
769     pushing feasible_beam_placements epsilon over or epsilon under a
770     collision.  when this type of change happens, the loop is marked
771     as "dirty" and re-iterated.
772
773     TODO: figure out a faster ways that this loop can happen via
774     a better search algorithm and/or OOP.
775   */
776
777   bool dirty = false;
778   do
779     {
780       dirty = false;
781       for (vsize i = 0; i < forbidden_intervals.size (); i++)
782         {
783           Direction d = DOWN;
784           do
785             {
786               if (forbidden_intervals[i][d] == d * infinity_f)
787                 feasible_beam_placements[d] = d * infinity_f;
788               else if (forbidden_intervals[i].contains (feasible_beam_placements[d]))
789                 {
790                   feasible_beam_placements[d] = d * epsilon + forbidden_intervals[i][d];
791                   dirty = true;
792                 }
793             }
794           while (flip (&d) != DOWN);
795         }
796     }
797   while (dirty);
798
799   // if the beam placement falls out of the feasible region, we push it
800   // to infinity so that it can never be a feasible candidate below
801   Direction d = DOWN;
802   do
803     {
804       if (!feasible_left_point.contains (feasible_beam_placements[d]))
805         feasible_beam_placements[d] = d * infinity_f;
806     }
807   while (flip (&d) != DOWN);
808
809   if ((feasible_beam_placements[UP] == infinity_f && feasible_beam_placements[DOWN] == -infinity_f) && !feasible_left_point.is_empty ())
810     {
811       // We are somewhat screwed: we have a collision, but at least
812       // there is a way to satisfy stem length constraints.
813       beam_left_y = point_in_interval (feasible_left_point, 2.0);
814     }
815   else if (!feasible_left_point.is_empty ())
816     {
817       // Only one of them offers is feasible solution. Pick that one.
818       if (abs (beam_left_y - feasible_beam_placements[DOWN]) > abs (beam_left_y - feasible_beam_placements[UP]))
819         beam_left_y = feasible_beam_placements[UP];
820       else
821         beam_left_y = feasible_beam_placements[DOWN];
822     }
823   else
824     {
825       // We are completely screwed.
826       me->warning (_ ("no viable initial configuration found: may not find good beam slope"));
827     }
828
829   pos = Drul_array<Real> (beam_left_y, (beam_left_y + beam_dy));
830   scale_drul (&pos, 1 / Staff_symbol_referencer::staff_space (me));
831
832   return ly_interval2scm (pos);
833 }
834
835 void
836 Beam_scoring_problem::generate_quants (vector<Beam_configuration *> *scores) const
837 {
838   int region_size = (int) parameters_.REGION_SIZE;
839
840   // Knees and collisions are harder, lets try some more possibilities
841   if (is_knee_)
842     region_size += 2;
843   if (collisions_.size ())
844     region_size += 2;
845
846   Real straddle = 0.0;
847   Real sit = (beam_thickness_ - line_thickness_) / 2;
848   Real inter = 0.5;
849   Real hang = 1.0 - (beam_thickness_ - line_thickness_) / 2;
850   Real base_quants [] = {straddle, sit, inter, hang};
851   int num_base_quants = int (sizeof (base_quants) / sizeof (Real));
852
853   /*
854     Asymetry ? should run to <= region_size ?
855   */
856   vector<Real> unshifted_quants;
857   for (int i = -region_size; i < region_size; i++)
858     for (int j = 0; j < num_base_quants; j++)
859       {
860         unshifted_quants.push_back (i + base_quants[j]);
861       }
862
863   for (vsize i = 0; i < unshifted_quants.size (); i++)
864     for (vsize j = 0; j < unshifted_quants.size (); j++)
865       {
866         Beam_configuration *c
867           = Beam_configuration::new_config (unquanted_y_,
868                                             Interval (unshifted_quants[i],
869                                                       unshifted_quants[j]));
870
871         Direction d = LEFT;
872         do
873           {
874             if (!quant_range_[d].contains (c->y[d]))
875               {
876                 delete c;
877                 c = NULL;
878                 break;
879               }
880           }
881         while (flip (&d) != LEFT);
882         if (c)
883           scores->push_back (c);
884       }
885
886 }
887
888 void Beam_scoring_problem::one_scorer (Beam_configuration *config) const
889 {
890   score_count++;
891   switch (config->next_scorer_todo)
892     {
893     case SLOPE_IDEAL:
894       score_slope_ideal (config);
895       break;
896     case SLOPE_DIRECTION:
897       score_slope_direction (config);
898       break;
899     case SLOPE_MUSICAL:
900       score_slope_musical (config);
901       break;
902     case FORBIDDEN:
903       score_forbidden_quants (config);
904       break;
905     case STEM_LENGTHS:
906       score_stem_lengths (config);
907       break;
908     case COLLISIONS:
909       score_collisions (config);
910       break;
911     case HORIZONTAL_INTER:
912       score_horizontal_inter_quants (config);
913       break;
914
915     case NUM_SCORERS:
916     case ORIGINAL_DISTANCE:
917     default:
918       assert (false);
919     }
920   config->next_scorer_todo++;
921 }
922
923 Beam_configuration *
924 Beam_scoring_problem::force_score (SCM inspect_quants, const vector<Beam_configuration *> &configs) const
925 {
926   Drul_array<Real> ins = ly_scm2interval (inspect_quants);
927   Real mindist = 1e6;
928   Beam_configuration *best = NULL;
929   for (vsize i = 0; i < configs.size (); i++)
930     {
931       Real d = fabs (configs[i]->y[LEFT] - ins[LEFT]) + fabs (configs[i]->y[RIGHT] - ins[RIGHT]);
932       if (d < mindist)
933         {
934           best = configs[i];
935           mindist = d;
936         }
937     }
938   if (mindist > 1e5)
939     programming_error ("cannot find quant");
940
941   while (!best->done ())
942     one_scorer (best);
943
944   return best;
945 }
946
947 Drul_array<Real>
948 Beam_scoring_problem::solve () const
949 {
950   vector<Beam_configuration *> configs;
951   generate_quants (&configs);
952
953   if (configs.empty ())
954     {
955       programming_error ("No viable beam quanting found.  Using unquanted y value.");
956       return unquanted_y_;
957     }
958
959   Beam_configuration *best = NULL;
960
961   bool debug
962     = to_boolean (beam_->layout ()->lookup_variable (ly_symbol2scm ("debug-beam-scoring")));
963   SCM inspect_quants = beam_->get_property ("inspect-quants");
964   if (scm_is_pair (inspect_quants))
965     {
966       debug = true;
967       best = force_score (inspect_quants, configs);
968     }
969   else
970     {
971       std::priority_queue < Beam_configuration *, std::vector<Beam_configuration *>,
972           Beam_configuration_less > queue;
973       for (vsize i = 0; i < configs.size (); i++)
974         queue.push (configs[i]);
975
976       /*
977         TODO
978
979         It would be neat if we generated new configurations on the
980         fly, depending on the best complete score so far, eg.
981
982         if (best->done()) {
983           if (best->demerits < sqrt(queue.size())
984             break;
985           while (best->demerits > sqrt(queue.size()) {
986             generate and insert new configuration
987           }
988         }
989
990         that would allow us to do away with region_size altogether.
991       */
992       while (true)
993         {
994           best = queue.top ();
995           if (best->done ())
996             break;
997
998           queue.pop ();
999           one_scorer (best);
1000           queue.push (best);
1001         }
1002     }
1003
1004   Interval final_positions = best->y;
1005
1006 #if DEBUG_BEAM_SCORING
1007   if (debug)
1008     {
1009       // debug quanting
1010       int completed = 0;
1011       for (vsize i = 0; i < configs.size (); i++)
1012         {
1013           if (configs[i]->done ())
1014             completed++;
1015         }
1016
1017       string card = best->score_card_ + to_string (" c%d/%d", completed, configs.size ());
1018       beam_->set_property ("annotation", ly_string2scm (card));
1019     }
1020 #endif
1021
1022   junk_pointers (configs);
1023   return final_positions;
1024 }
1025
1026 void
1027 Beam_scoring_problem::score_stem_lengths (Beam_configuration *config) const
1028 {
1029   Real limit_penalty = parameters_.STEM_LENGTH_LIMIT_PENALTY;
1030   Drul_array<Real> score (0, 0);
1031   Drul_array<int> count (0, 0);
1032
1033   for (vsize i = 0; i < stem_xpositions_.size (); i++)
1034     {
1035       Real x = stem_xpositions_[i];
1036       Real dx = x_span_.delta ();
1037       Real beam_y = dx
1038                     ? config->y[RIGHT] * (x - x_span_[LEFT]) / dx + config->y[LEFT] * (x_span_[RIGHT] - x) / dx
1039                     : (config->y[RIGHT] + config->y[LEFT]) / 2;
1040       Real current_y = beam_y + base_lengths_[i];
1041       Real length_pen = parameters_.STEM_LENGTH_DEMERIT_FACTOR;
1042
1043       Stem_info info = stem_infos_[i];
1044       Direction d = info.dir_;
1045
1046       score[d] += limit_penalty * max (0.0, (d * (info.shortest_y_ - current_y)));
1047
1048       Real ideal_diff = d * (current_y - info.ideal_y_);
1049       Real ideal_score = shrink_extra_weight (ideal_diff, 1.5);
1050
1051       /* We introduce a power, to make the scoring strictly
1052          convex. Otherwise a symmetric knee beam (up/down/up/down)
1053          does not have an optimum in the middle. */
1054       if (is_knee_)
1055         ideal_score = pow (ideal_score, 1.1);
1056
1057       score[d] += length_pen * ideal_score;
1058       count[d]++;
1059     }
1060
1061   /* Divide by number of stems, to make the measure scale-free. */
1062   Direction d = DOWN;
1063   do
1064     score[d] /= max (count[d], 1);
1065   while (flip (&d) != DOWN);
1066
1067   config->add (score[LEFT] + score[RIGHT], "L");
1068 }
1069
1070 void
1071 Beam_scoring_problem::score_slope_direction (Beam_configuration *config) const
1072 {
1073   Real dy = config->y.delta ();
1074   Real damped_dy = unquanted_y_.delta ();
1075   Real dem = 0.0;
1076   /*
1077     DAMPING_DIRECTION_PENALTY is a very harsh measure, while for
1078     complex beaming patterns, horizontal is often a good choice.
1079
1080     TODO: find a way to incorporate the complexity of the beam in this
1081     penalty.
1082   */
1083   if (sign (damped_dy) != sign (dy))
1084     {
1085       if (!dy)
1086         {
1087           if (fabs (damped_dy / x_span_.delta ()) > parameters_.ROUND_TO_ZERO_SLOPE)
1088             dem += parameters_.DAMPING_DIRECTION_PENALTY;
1089           else
1090             dem += parameters_.HINT_DIRECTION_PENALTY;
1091         }
1092       else
1093         dem += parameters_.DAMPING_DIRECTION_PENALTY;
1094     }
1095
1096   config->add (dem, "Sd");
1097 }
1098
1099 // Score for going against the direction of the musical pattern
1100 void
1101 Beam_scoring_problem::score_slope_musical (Beam_configuration *config) const
1102 {
1103   Real dy = config->y.delta ();
1104   Real dem = parameters_.MUSICAL_DIRECTION_FACTOR
1105              * max (0.0, (fabs (dy) - fabs (musical_dy_)));
1106   config->add (dem, "Sm");
1107 }
1108
1109 // Score deviation from calculated ideal slope.
1110 void
1111 Beam_scoring_problem::score_slope_ideal (Beam_configuration *config) const
1112 {
1113   Real dy = config->y.delta ();
1114   Real damped_dy = unquanted_y_.delta ();
1115   Real dem = 0.0;
1116
1117   Real slope_penalty = parameters_.IDEAL_SLOPE_FACTOR;
1118
1119   /* Xstaff beams tend to use extreme slopes to get short stems. We
1120      put in a penalty here. */
1121   if (is_xstaff_)
1122     slope_penalty *= 10;
1123
1124   /* Huh, why would a too steep beam be better than a too flat one ? */
1125   dem += shrink_extra_weight (fabs (damped_dy) - fabs (dy), 1.5)
1126          * slope_penalty;
1127
1128   config->add (dem, "Si");
1129 }
1130
1131 static Real
1132 my_modf (Real x)
1133 {
1134   return x - floor (x);
1135 }
1136
1137 // TODO - there is some overlap with forbidden quants, but for
1138 // horizontal beams, it is much more serious to have stafflines
1139 // appearing in the wrong place, so we have a separate scorer.
1140 void
1141 Beam_scoring_problem::score_horizontal_inter_quants (Beam_configuration *config) const
1142 {
1143   if (config->y.delta () == 0.0
1144       && abs (config->y[LEFT]) < staff_radius_ * staff_space_)
1145     {
1146       Real yshift = config->y[LEFT] - 0.5 * staff_space_;
1147       if (fabs (my_round (yshift) - yshift) < 0.01 * staff_space_)
1148         config->add (parameters_.HORIZONTAL_INTER_QUANT_PENALTY, "H");
1149     }
1150 }
1151
1152 /*
1153   TODO: The fixed value SECONDARY_BEAM_DEMERIT is probably flawed:
1154   because for 32nd and 64th beams the forbidden quants are relatively
1155   more important than stem lengths.
1156 */
1157 void
1158 Beam_scoring_problem::score_forbidden_quants (Beam_configuration *config) const
1159 {
1160   Real dy = config->y.delta ();
1161
1162   Real extra_demerit = parameters_.SECONDARY_BEAM_DEMERIT
1163                        / max (edge_beam_counts_[LEFT], edge_beam_counts_[RIGHT]);
1164
1165   Direction d = LEFT;
1166   Real dem = 0.0;
1167   Real eps = parameters_.BEAM_EPS;
1168
1169   do
1170     {
1171       for (int j = 1; j <= edge_beam_counts_[d]; j++)
1172         {
1173           Direction stem_dir = edge_dirs_[d];
1174
1175           /*
1176             The 2.2 factor is to provide a little leniency for
1177             borderline cases. If we do 2.0, then the upper outer line
1178             will be in the gap of the (2, sit) quant, leading to a
1179             false demerit.
1180           */
1181           Real gap1 = config->y[d] - stem_dir * ((j - 1) * beam_translation_ + beam_thickness_ / 2 - line_thickness_ / 2.2);
1182           Real gap2 = config->y[d] - stem_dir * (j * beam_translation_ - beam_thickness_ / 2 + line_thickness_ / 2.2);
1183
1184           Interval gap;
1185           gap.add_point (gap1);
1186           gap.add_point (gap2);
1187
1188           for (Real k = -staff_radius_;
1189                k <= staff_radius_ + eps; k += 1.0)
1190             if (gap.contains (k))
1191               {
1192                 Real dist = min (fabs (gap[UP] - k), fabs (gap[DOWN] - k));
1193
1194                 /*
1195                   this parameter is tuned to grace-stem-length.ly
1196                 */
1197                 Real fixed_demerit = 0.4;
1198
1199                 dem += extra_demerit
1200                        * (fixed_demerit
1201                           + (1 - fixed_demerit) * (dist / gap.length ()) * 2);
1202               }
1203         }
1204     }
1205   while ((flip (&d)) != LEFT);
1206
1207   if (max (edge_beam_counts_[LEFT], edge_beam_counts_[RIGHT]) >= 2)
1208     {
1209       Real straddle = 0.0;
1210       Real sit = (beam_thickness_ - line_thickness_) / 2;
1211       Real inter = 0.5;
1212       Real hang = 1.0 - (beam_thickness_ - line_thickness_) / 2;
1213
1214       Direction d = LEFT;
1215       do
1216         {
1217           if (edge_beam_counts_[d] >= 2
1218               && fabs (config->y[d] - edge_dirs_[d] * beam_translation_) < staff_radius_ + inter)
1219             {
1220               // TODO up/down symmetry.
1221               if (edge_dirs_[d] == UP && dy <= eps
1222                   && fabs (my_modf (config->y[d]) - sit) < eps)
1223                 dem += extra_demerit;
1224
1225               if (edge_dirs_[d] == DOWN && dy >= eps
1226                   && fabs (my_modf (config->y[d]) - hang) < eps)
1227                 dem += extra_demerit;
1228             }
1229
1230           if (edge_beam_counts_[d] >= 3
1231               && fabs (config->y[d] - 2 * edge_dirs_[d] * beam_translation_) < staff_radius_ + inter)
1232             {
1233               // TODO up/down symmetry.
1234               if (edge_dirs_[d] == UP && dy <= eps
1235                   && fabs (my_modf (config->y[d]) - straddle) < eps)
1236                 dem += extra_demerit;
1237
1238               if (edge_dirs_[d] == DOWN && dy >= eps
1239                   && fabs (my_modf (config->y[d]) - straddle) < eps)
1240                 dem += extra_demerit;
1241             }
1242         }
1243       while (flip (&d) != LEFT);
1244     }
1245
1246   config->add (dem, "F");
1247 }
1248
1249 void
1250 Beam_scoring_problem::score_collisions (Beam_configuration *config) const
1251 {
1252   Real demerits = 0.0;
1253   for (vsize i = 0; i < collisions_.size (); i++)
1254     {
1255       Interval collision_y = collisions_[i].y_;
1256       Real x = collisions_[i].x_;
1257
1258       Real center_beam_y = y_at (x, config);
1259       Interval beam_y = center_beam_y + collisions_[i].beam_y_;
1260
1261       Real dist = infinity_f;
1262       if (!intersection (beam_y, collision_y).is_empty ())
1263         dist = 0.0;
1264       else
1265         dist = min (beam_y.distance (collision_y[DOWN]),
1266                     beam_y.distance (collision_y[UP]));
1267
1268       Real scale_free
1269         = max (parameters_.COLLISION_PADDING - dist, 0.0) /
1270           parameters_.COLLISION_PADDING;
1271       demerits
1272       += collisions_[i].base_penalty_ *
1273          pow (scale_free, 3) * parameters_.COLLISION_PENALTY;
1274     }
1275
1276   config->add (demerits, "C");
1277 }