]> git.donarmstrong.com Git - lilypond.git/blob - lily/beam-quanting.cc
Standardizes X extents of beams across beam calculations.
[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 "spanner.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 * p->y.delta () / x_span_;
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   // We used to screen for quant range, but no more.
163
164   Beam_collision c;
165   c.beam_y_.set_empty ();
166
167   for (vsize j = 0; j < segments_.size (); j++)
168     {
169       if (segments_[j].horizontal_.contains (x))
170         c.beam_y_.add_point (segments_[j].vertical_count_ * beam_translation_);
171       if (segments_[j].horizontal_[LEFT] > x)
172         break;
173     }
174   c.beam_y_.widen (0.5 * beam_thickness_);
175
176   c.x_ = x;
177
178   y *= 1 / staff_space_;
179   c.y_ = y;
180   c.base_penalty_ = score_factor;
181   collisions_.push_back (c);
182 }
183
184 void Beam_scoring_problem::init_instance_variables (Grob *me, Drul_array<Real> ys, bool align_broken_intos)
185 {
186   beam_ = dynamic_cast<Spanner *> (me);
187   unquanted_y_ = ys;
188
189   /*
190     If 'ys' are finite, use them as starting points for y-positions of the
191     ends of the beam, instead of the best-fit through the natural ends of
192     the stems.  Otherwise, we want to do initial slope calculations.
193   */
194   do_initial_slope_calculations_ = false;
195   Direction d = LEFT;
196   do
197     do_initial_slope_calculations_ |= isinf (unquanted_y_[d]) || isnan (unquanted_y_[d]);
198   while (flip (&d) != LEFT);
199
200   /*
201     Calculations are relative to a unit-scaled staff, i.e. the quants are
202     divided by the current staff_space_.
203   */
204   staff_space_ = Staff_symbol_referencer::staff_space (beam_);
205   beam_thickness_ = Beam::get_beam_thickness (beam_) / staff_space_;
206   line_thickness_ = Staff_symbol_referencer::line_thickness (beam_) / staff_space_;
207
208   // This is the least-squares DY, corrected for concave beams.
209   musical_dy_ = robust_scm2double (beam_->get_property ("least-squares-dy"), 0);
210
211   vector<Spanner *> beams;
212   align_broken_intos_ = align_broken_intos;
213   if (align_broken_intos_)
214     {
215       Spanner *orig = dynamic_cast<Spanner *> (beam_->original ());
216       if (!orig)
217         align_broken_intos_ = false;
218       else if (!orig->broken_intos_.size ())
219         align_broken_intos_ = false;
220       else
221         beams.insert (beams.end (), orig->broken_intos_.begin (), orig->broken_intos_.end ());
222     }
223   if (!align_broken_intos_)
224     beams.push_back (beam_);
225
226   /*
227     x_span_ is a single scalar, cumulatively summing the length of all the
228     segments the parent beam was broken-into.
229   */
230   x_span_ = 0.0;
231   is_knee_ = false;
232   normal_stem_count_ = 0;
233   for (vsize i = 0; i < beams.size (); i++)
234     {
235       extract_grob_set (beams[i], "stems", stems);
236       extract_grob_set (beams[i], "covered-grobs", fake_collisions);
237       vector<Grob *> collisions;
238
239       for (vsize j = 0; j < fake_collisions.size (); j++)
240         if (fake_collisions[j]->get_system () == beams[i]->get_system ())
241           collisions.push_back (fake_collisions[j]);
242
243       Grob *common[2];
244       for (int a = 2; a--;)
245         common[a] = common_refpoint_of_array (stems, beams[i], Axis (a));
246
247       Direction d = LEFT;
248       do
249         common[X_AXIS] = beams[i]->get_bound (d)->common_refpoint (common[X_AXIS], X_AXIS);
250       while (flip (&d) != LEFT);
251
252       // positions of the endpoints of this beam segment, including any overhangs
253       const Interval x_pos = robust_scm2interval (beams[i]->get_property ("X-positions"),
254                                                   Interval (0.0, 0.0));
255
256       Drul_array<Grob *> edge_stems (Beam::first_normal_stem (beams[i]),
257                                      Beam::last_normal_stem (beams[i]));
258
259       Drul_array<bool> dirs_found (0, 0);
260
261       Real my_y = beams[i]->relative_coordinate (common[Y_AXIS], Y_AXIS);
262
263       Interval beam_width (-1.0,-1.0);
264       for (vsize j = 0; j < stems.size (); j++)
265         {
266           Grob *s = stems[j];
267           beam_multiplicity_.push_back (Stem::beam_multiplicity (stems[j]));
268           head_positions_.push_back (Stem::head_positions (stems[j]));
269           is_normal_.push_back (Stem::is_normal_stem (stems[j]));
270
271           Stem_info si (Stem::get_stem_info (s));
272           si.scale (1 / staff_space_);
273           stem_infos_.push_back (si);
274           chord_start_y_.push_back (Stem::chord_start_y (s));
275           dirs_found[si.dir_] = true;
276
277           bool f = to_boolean (s->get_property ("french-beaming"))
278                    && s != edge_stems[LEFT] && s != edge_stems[RIGHT];
279
280           Real y = Beam::calc_stem_y (beams[i], s, common, x_pos[LEFT], x_pos[RIGHT], CENTER,
281                                       Interval (0, 0), f);
282           base_lengths_.push_back (y / staff_space_);
283           stem_xpositions_.push_back (s->relative_coordinate (common[X_AXIS], X_AXIS) - x_pos[LEFT] + x_span_);
284           stem_ypositions_.push_back (s->relative_coordinate (common[Y_AXIS], Y_AXIS) - my_y);
285           if (is_normal_.back ())
286             {
287               if (beam_width[LEFT] == -1.0)
288                 beam_width[LEFT] = stem_xpositions_.back ();
289               beam_width[RIGHT] = stem_xpositions_.back ();
290             }
291         }
292
293       edge_dirs_ = Drul_array<Direction> (CENTER, CENTER);
294       normal_stem_count_ += Beam::normal_stem_count (beams[i]);
295       if (normal_stem_count_)
296         edge_dirs_ = Drul_array<Direction> (stem_infos_[0].dir_,
297                                             stem_infos_.back ().dir_);
298
299       is_xstaff_ = Align_interface::has_interface (common[Y_AXIS]);
300       is_knee_ |= dirs_found[DOWN] && dirs_found[UP];
301
302       staff_radius_ = Staff_symbol_referencer::staff_radius (beams[i]);
303       edge_beam_counts_ = Drul_array<int>
304                          (Stem::beam_multiplicity (stems[0]).length () + 1,
305                           Stem::beam_multiplicity (stems.back ()).length () + 1);
306
307       // TODO - why are we dividing by staff_space_?
308       beam_translation_ = Beam::get_beam_translation (beams[i]) / staff_space_;
309
310       d = LEFT;
311       do
312         {
313           quant_range_[d].set_full ();
314           if (!edge_stems[d])
315             continue;
316
317           Real stem_offset = edge_stems[d]->relative_coordinate (common[Y_AXIS], Y_AXIS)
318                              - beams[i]->relative_coordinate (common[Y_AXIS], Y_AXIS);
319           Interval heads = Stem::head_positions (edge_stems[d]) * 0.5 * staff_space_;
320
321           Direction ed = edge_dirs_[d];
322           heads.widen (0.5 * staff_space_
323                        + (edge_beam_counts_[d] - 1) * beam_translation_ + beam_thickness_ * .5);
324           quant_range_[d][-ed] = heads[ed] + stem_offset;
325         }
326       while (flip (&d) != LEFT);
327
328       segments_ = Beam::get_beam_segments (beams[i]);
329       vector_sort (segments_, beam_segment_less);
330       for (vsize j = 0; j < segments_.size (); j++)
331         segments_[j].horizontal_ += (x_span_ - x_pos[LEFT]);
332
333       set<Grob *> colliding_stems;
334       for (vsize j = 0; j < collisions.size (); j++)
335         {
336           if (!collisions[j]->is_live ())
337             continue;
338
339           if (Beam::has_interface (collisions[j]) && Beam::is_cross_staff (collisions[j]))
340             continue;
341
342           Box b;
343           for (Axis a = X_AXIS; a < NO_AXES; incr (a))
344             b[a] = collisions[j]->extent (common[a], a);
345
346           if (b[X_AXIS][RIGHT] < x_pos[LEFT] || b[X_AXIS][LEFT] > x_pos[RIGHT])
347             continue;
348           if (b[X_AXIS].is_empty () || b[Y_AXIS].is_empty ())
349             continue;
350
351           b[X_AXIS] += (x_span_ - x_pos[LEFT]);
352           Real width = b[X_AXIS].length ();
353           Real width_factor = sqrt (width / staff_space_);
354
355           Direction d = LEFT;
356           do
357             add_collision (b[X_AXIS][d], b[Y_AXIS], width_factor);
358           while (flip (&d) != LEFT);
359
360           Grob *stem = unsmob_grob (collisions[j]->get_object ("stem"));
361           if (stem && Stem::has_interface (stem) && Stem::is_normal_stem (stem))
362             {
363               colliding_stems.insert (stem);
364             }
365         }
366
367       for (set<Grob *>::const_iterator it (colliding_stems.begin ()); it != colliding_stems.end (); it++)
368         {
369           Grob *s = *it;
370           Real x = (s->extent (common[X_AXIS], X_AXIS) - x_pos[LEFT] + x_span_).center ();
371
372           Direction stem_dir = get_grob_direction (*it);
373           Interval y;
374           y.set_full ();
375           y[-stem_dir] = Stem::chord_start_y (*it) + (*it)->relative_coordinate (common[Y_AXIS], Y_AXIS)
376                          - beams[i]->relative_coordinate (common[Y_AXIS], Y_AXIS);
377
378           Real factor = parameters_.STEM_COLLISION_FACTOR;
379           if (!unsmob_grob (s->get_object ("beam")))
380             factor = 1.0;
381           add_collision (x, y, factor);
382         }
383       x_span_ += beams[i]->spanner_length ();
384     }
385 }
386
387 Beam_scoring_problem::Beam_scoring_problem (Grob *me, Drul_array<Real> ys, bool align_broken_intos)
388 {
389   beam_ = dynamic_cast<Spanner *> (me);
390   unquanted_y_ = ys;
391   align_broken_intos_ = align_broken_intos;
392
393   parameters_.fill (me);
394   init_instance_variables (me, ys, align_broken_intos);
395   if (do_initial_slope_calculations_)
396     {
397       least_squares_positions ();
398       slope_damping ();
399       shift_region_to_valid ();
400     }
401 }
402
403 // Assuming V is not empty, pick a 'reasonable' point inside V.
404 static Real
405 point_in_interval (Interval v, Real dist)
406 {
407   if (isinf (v[DOWN]))
408     return v[UP] - dist;
409   else if (isinf (v[UP]))
410     return v[DOWN] + dist;
411   else
412     return v.center ();
413 }
414
415 /* Set stem's shorten property if unset.
416
417 TODO:
418 take some y-position (chord/beam/nearest?) into account
419 scmify forced-fraction
420
421 This is done in beam because the shorten has to be uniform over the
422 entire beam.
423 */
424
425 void
426 set_minimum_dy (Grob *me, Real *dy)
427 {
428   if (*dy)
429     {
430       /*
431         If dy is smaller than the smallest quant, we
432         get absurd direction-sign penalties.
433       */
434
435       Real ss = Staff_symbol_referencer::staff_space (me);
436       Real beam_thickness = Beam::get_beam_thickness (me) / ss;
437       Real slt = Staff_symbol_referencer::line_thickness (me) / ss;
438       Real sit = (beam_thickness - slt) / 2;
439       Real inter = 0.5;
440       Real hang = 1.0 - (beam_thickness - slt) / 2;
441
442       *dy = sign (*dy) * max (fabs (*dy),
443                               min (min (sit, inter), hang));
444     }
445 }
446
447 void
448 Beam_scoring_problem::no_visible_stem_positions ()
449 {
450   if (!head_positions_.size ())
451     {
452       unquanted_y_ = Interval (0, 0);
453       return;
454     }
455
456   Interval head_positions;
457   Slice multiplicity;
458   for (vsize i = 0; i < head_positions_.size (); i++)
459     {
460       head_positions.unite (head_positions_[i]);
461       multiplicity.unite (beam_multiplicity_[i]);
462     }
463
464   Direction dir = get_grob_direction (beam_);
465
466   if (!dir)
467     programming_error ("The beam should have a direction by now.");
468
469   Real y = head_positions.linear_combination (dir)
470            * 0.5 * staff_space_
471            + dir * beam_translation_ * (multiplicity.length () + 1);
472
473   unquanted_y_ = Interval (y, y);
474 }
475
476 vsize
477 Beam_scoring_problem::first_normal_index ()
478 {
479   for (vsize i = 0; i < is_normal_.size (); i++)
480     if (is_normal_[i])
481       return i;
482
483   beam_->programming_error ("No normal stems, but asking for first normal stem index.");
484   return 0;
485 }
486
487 vsize
488 Beam_scoring_problem::last_normal_index ()
489 {
490   for (vsize i = is_normal_.size (); i--;)
491     if (is_normal_[i])
492       return i;
493
494   beam_->programming_error ("No normal stems, but asking for first normal stem index.");
495   return 0;
496 }
497
498 void
499 Beam_scoring_problem::least_squares_positions ()
500 {
501   if (!normal_stem_count_)
502     {
503       no_visible_stem_positions ();
504       return;
505     }
506
507   if (stem_infos_.size () < 1)
508     return;
509
510   vsize fnx = first_normal_index ();
511   vsize lnx = last_normal_index ();
512
513   Interval ideal (stem_infos_[fnx].ideal_y_ + stem_ypositions_[fnx],
514                   stem_infos_[lnx].ideal_y_ + stem_ypositions_[lnx]);
515
516   Real y = 0;
517   Real slope = 0;
518   Real dy = 0;
519   Real ldy = 0.0;
520   if (!ideal.delta ())
521     {
522       Interval chord (chord_start_y_[0],
523                       chord_start_y_.back ());
524
525       /* Simple beams (2 stems) on middle line should be allowed to be
526          slightly sloped.
527
528          However, if both stems reach middle line,
529          ideal[LEFT] == ideal[RIGHT] and ideal.delta () == 0.
530
531          For that case, we apply artificial slope */
532       if (!ideal[LEFT] && chord.delta () && stem_infos_.size () == 2)
533         {
534           /* FIXME. -> UP */
535           Direction d = (Direction) (sign (chord.delta ()) * UP);
536           unquanted_y_[d] = Beam::get_beam_thickness (beam_) / 2;
537           unquanted_y_[-d] = -unquanted_y_[d];
538         }
539       else
540         unquanted_y_ = ideal;
541
542       ldy = unquanted_y_[RIGHT] - unquanted_y_[LEFT];
543     }
544   else
545     {
546       vector<Offset> ideals;
547       for (vsize i = 0; i < stem_infos_.size (); i++)
548         if (is_normal_[i])
549           ideals.push_back (Offset (stem_xpositions_[i],
550                                     stem_infos_[i].ideal_y_
551                                     + stem_ypositions_[i]));
552
553       minimise_least_squares (&slope, &y, ideals);
554
555       dy = slope * x_span_;
556
557       set_minimum_dy (beam_, &dy);
558
559       ldy = dy;
560       unquanted_y_ = Interval (y, (y + dy));
561     }
562
563   musical_dy_ = ldy;
564   beam_->set_property ("least-squares-dy", scm_from_double (musical_dy_));
565 }
566
567 /*
568   Determine whether a beam is concave.
569
570   A beam is concave when the middle notes get closer to the
571   beam than the left and right edge notes.
572
573   This is determined in two ways: by looking at the positions of the
574   middle notes, or by looking at the deviation of the inside notes
575   compared to the line connecting first and last.
576
577   The tricky thing is what to do with beams with chords. There are no
578   real guidelines in this case.
579 */
580
581 bool
582 is_concave_single_notes (vector<int> const &positions, Direction beam_dir)
583 {
584   Interval covering;
585   covering.add_point (positions[0]);
586   covering.add_point (positions.back ());
587
588   bool above = false;
589   bool below = false;
590   bool concave = false;
591
592   /*
593     notes above and below the interval covered by 1st and last note.
594   */
595   for (vsize i = 1; i + 1 < positions.size (); i++)
596     {
597       above = above || (positions[i] > covering[UP]);
598       below = below || (positions[i] < covering[DOWN]);
599     }
600
601   concave = concave || (above && below);
602   /*
603     A note as close or closer to the beam than begin and end, but the
604     note is reached in the opposite direction as the last-first dy
605   */
606   int dy = positions.back () - positions[0];
607   int closest = max (beam_dir * positions.back (), beam_dir * positions[0]);
608   for (vsize i = 2; !concave && i + 1 < positions.size (); i++)
609     {
610       int inner_dy = positions[i] - positions[i - 1];
611       if (sign (inner_dy) != sign (dy)
612           && (beam_dir * positions[i] >= closest
613               || beam_dir * positions[i - 1] >= closest))
614         concave = true;
615     }
616
617   bool all_closer = true;
618   for (vsize i = 1; all_closer && i + 1 < positions.size (); i++)
619     {
620       all_closer = all_closer
621                    && (beam_dir * positions[i] > closest);
622     }
623
624   concave = concave || all_closer;
625   return concave;
626 }
627
628 Real
629 calc_positions_concaveness (vector<int> const &positions, Direction beam_dir)
630 {
631   Real dy = positions.back () - positions[0];
632   Real slope = dy / Real (positions.size () - 1);
633   Real concaveness = 0.0;
634   for (vsize i = 1; i + 1 < positions.size (); i++)
635     {
636       Real line_y = slope * i + positions[0];
637
638       concaveness += max (beam_dir * (positions[i] - line_y), 0.0);
639     }
640
641   concaveness /= positions.size ();
642
643   /*
644     Normalize. For dy = 0, the slope ends up as 0 anyway, so the
645     scaling of concaveness doesn't matter much.
646   */
647   if (dy)
648     concaveness /= fabs (dy);
649   return concaveness;
650 }
651
652 Real
653 Beam_scoring_problem::calc_concaveness ()
654 {
655   SCM conc = beam_->get_property ("concaveness");
656   if (scm_is_number (conc))
657     return scm_to_double (conc);
658
659   if (is_knee_)
660     return 0.0;
661
662   Direction beam_dir = CENTER;
663   for (vsize i = is_normal_.size (); i--;)
664     if (is_normal_[i] && stem_infos_[i].dir_)
665       beam_dir = stem_infos_[i].dir_;
666
667   if (normal_stem_count_ <= 2)
668     return 0.0;
669
670   vector<int> close_positions;
671   vector<int> far_positions;
672   for (vsize i = 0; i < is_normal_.size (); i++)
673     if (is_normal_[i])
674       {
675         /*
676           For chords, we take the note head that is closest to the beam.
677
678           Hmmm.. wait, for the beams in the last measure of morgenlied,
679           this doesn't look so good. Let's try the heads farthest from
680           the beam.
681         */
682
683         close_positions.push_back ((int) rint (head_positions_[i][beam_dir]));
684         far_positions.push_back ((int) rint (head_positions_[i][-beam_dir]));
685     }
686
687   Real concaveness = 0.0;
688
689   if (is_concave_single_notes (beam_dir == UP ? close_positions : far_positions, beam_dir))
690     {
691       concaveness = 10000;
692     }
693   else
694     {
695       concaveness = (calc_positions_concaveness (far_positions, beam_dir)
696                      + calc_positions_concaveness (close_positions, beam_dir)) / 2;
697     }
698
699   return concaveness;
700 }
701
702 void
703 Beam_scoring_problem::slope_damping ()
704 {
705   if (normal_stem_count_ <= 1)
706     return;
707
708   SCM s = beam_->get_property ("damping");
709   Real damping = scm_to_double (s);
710   Real concaveness = calc_concaveness ();
711   if (concaveness >= 10000)
712     {
713       unquanted_y_[LEFT] = unquanted_y_[RIGHT];
714       musical_dy_ = 0;
715       damping = 0;
716     }
717
718   if (damping)
719     {
720       Real dy = unquanted_y_[RIGHT] - unquanted_y_[LEFT];
721
722       Real slope = dy && x_span_ ? dy / x_span_ : 0;
723
724       slope = 0.6 * tanh (slope) / (damping + concaveness);
725
726       Real damped_dy = slope * x_span_;
727
728       set_minimum_dy (beam_, &damped_dy);
729
730       unquanted_y_[LEFT] += (dy - damped_dy) / 2;
731       unquanted_y_[RIGHT] -= (dy - damped_dy) / 2;
732     }
733 }
734
735 void
736 Beam_scoring_problem::shift_region_to_valid ()
737 {
738   if (!normal_stem_count_)
739     return;
740
741   Real beam_dy = unquanted_y_[RIGHT] - unquanted_y_[LEFT];
742   Real slope = x_span_ ? beam_dy / x_span_ : 0.0;
743
744   /*
745     Shift the positions so that we have a chance of finding good
746     quants (i.e. no short stem failures.)
747   */
748   Interval feasible_left_point;
749   feasible_left_point.set_full ();
750
751   for (vsize i = 0; i < stem_infos_.size (); i++)
752     {
753       // TODO - check for invisible here...
754       Real left_y
755         = stem_infos_[i].shortest_y_
756           - slope * stem_xpositions_ [i];
757
758       /*
759         left_y is now relative to the stem S. We want relative to
760         ourselves, so translate:
761       */
762       left_y += stem_ypositions_[i];
763       Interval flp;
764       flp.set_full ();
765       flp[-stem_infos_[i].dir_] = left_y;
766
767       feasible_left_point.intersect (flp);
768     }
769
770   vector<Grob *> filtered;
771   /*
772     We only update these for objects that are too large for quanting
773     to find a workaround.  Typically, these are notes with
774     stems, and timesig/keysig/clef, which take out the entire area
775     inside the staff as feasible.
776
777     The code below disregards the thickness and multiplicity of the
778     beam.  This should not be a problem, as the beam quanting will
779     take care of computing the impact those exactly.
780   */
781   Real min_y_size = 2.0;
782
783   // A list of intervals into which beams may not fall
784   vector<Interval> forbidden_intervals;
785
786   for (vsize i = 0; i < collisions_.size (); i++)
787     {
788       if (collisions_[i].x_ < 0 || collisions_[i].x_ > x_span_)
789         continue;
790
791       if (collisions_[i].y_.length () < min_y_size)
792         continue;
793
794       Direction d = LEFT;
795       do
796         {
797           Real dy = slope * collisions_[i].x_;
798
799           Direction yd = DOWN;
800           Interval disallowed;
801           do
802             {
803               Real left_y = collisions_[i].y_[yd] - dy;
804               disallowed[yd] = left_y;
805             }
806           while (flip (&yd) != DOWN);
807
808           forbidden_intervals.push_back (disallowed);
809         }
810       while (flip (&d) != LEFT);
811     }
812
813   vector_sort (forbidden_intervals, Interval::left_less);
814   Real epsilon = 1.0e-10;
815   Real beam_left_y = unquanted_y_[LEFT];
816   Interval feasible_beam_placements (beam_left_y, beam_left_y);
817
818   /*
819     forbidden_intervals contains a vector of intervals in which
820     the beam cannot start.  it iterates through these intervals,
821     pushing feasible_beam_placements epsilon over or epsilon under a
822     collision.  when this type of change happens, the loop is marked
823     as "dirty" and re-iterated.
824
825     TODO: figure out a faster ways that this loop can happen via
826     a better search algorithm and/or OOP.
827   */
828
829   bool dirty = false;
830   do
831     {
832       dirty = false;
833       for (vsize i = 0; i < forbidden_intervals.size (); i++)
834         {
835           Direction d = DOWN;
836           do
837             {
838               if (forbidden_intervals[i][d] == d * infinity_f)
839                 feasible_beam_placements[d] = d * infinity_f;
840               else if (forbidden_intervals[i].contains (feasible_beam_placements[d]))
841                 {
842                   feasible_beam_placements[d] = d * epsilon + forbidden_intervals[i][d];
843                   dirty = true;
844                 }
845             }
846           while (flip (&d) != DOWN);
847         }
848     }
849   while (dirty);
850
851   // if the beam placement falls out of the feasible region, we push it
852   // to infinity so that it can never be a feasible candidate below
853   Direction d = DOWN;
854   do
855     {
856       if (!feasible_left_point.contains (feasible_beam_placements[d]))
857         feasible_beam_placements[d] = d * infinity_f;
858     }
859   while (flip (&d) != DOWN);
860
861   if ((feasible_beam_placements[UP] == infinity_f && feasible_beam_placements[DOWN] == -infinity_f) && !feasible_left_point.is_empty ())
862     {
863       // We are somewhat screwed: we have a collision, but at least
864       // there is a way to satisfy stem length constraints.
865       beam_left_y = point_in_interval (feasible_left_point, 2.0);
866     }
867   else if (!feasible_left_point.is_empty ())
868     {
869       // Only one of them offers is feasible solution. Pick that one.
870       if (abs (beam_left_y - feasible_beam_placements[DOWN]) > abs (beam_left_y - feasible_beam_placements[UP]))
871         beam_left_y = feasible_beam_placements[UP];
872       else
873         beam_left_y = feasible_beam_placements[DOWN];
874     }
875   else
876     {
877       // We are completely screwed.
878       beam_->warning (_ ("no viable initial configuration found: may not find good beam slope"));
879     }
880
881   unquanted_y_ = Drul_array<Real> (beam_left_y, (beam_left_y + beam_dy));
882 }
883
884 void
885 Beam_scoring_problem::generate_quants (vector<Beam_configuration *> *scores) const
886 {
887   int region_size = (int) parameters_.REGION_SIZE;
888
889   // Knees and collisions are harder, lets try some more possibilities
890   if (is_knee_)
891     region_size += 2;
892   if (collisions_.size ())
893     region_size += 2;
894
895   Real straddle = 0.0;
896   Real sit = (beam_thickness_ - line_thickness_) / 2;
897   Real inter = 0.5;
898   Real hang = 1.0 - (beam_thickness_ - line_thickness_) / 2;
899   Real base_quants [] = {straddle, sit, inter, hang};
900   int num_base_quants = int (sizeof (base_quants) / sizeof (Real));
901
902   /*
903     Asymetry ? should run to <= region_size ?
904   */
905   vector<Real> unshifted_quants;
906   for (int i = -region_size; i < region_size; i++)
907     for (int j = 0; j < num_base_quants; j++)
908       {
909         unshifted_quants.push_back (i + base_quants[j]);
910       }
911
912   for (vsize i = 0; i < unshifted_quants.size (); i++)
913     for (vsize j = 0; j < unshifted_quants.size (); j++)
914       {
915         Beam_configuration *c
916           = Beam_configuration::new_config (unquanted_y_,
917                                             Interval (unshifted_quants[i],
918                                                       unshifted_quants[j]));
919
920         Direction d = LEFT;
921         do
922           {
923             if (!quant_range_[d].contains (c->y[d]))
924               {
925                 delete c;
926                 c = NULL;
927                 break;
928               }
929           }
930         while (flip (&d) != LEFT);
931         if (c)
932           scores->push_back (c);
933       }
934
935 }
936
937 void Beam_scoring_problem::one_scorer (Beam_configuration *config) const
938 {
939   score_count++;
940   switch (config->next_scorer_todo)
941     {
942     case SLOPE_IDEAL:
943       score_slope_ideal (config);
944       break;
945     case SLOPE_DIRECTION:
946       score_slope_direction (config);
947       break;
948     case SLOPE_MUSICAL:
949       score_slope_musical (config);
950       break;
951     case FORBIDDEN:
952       score_forbidden_quants (config);
953       break;
954     case STEM_LENGTHS:
955       score_stem_lengths (config);
956       break;
957     case COLLISIONS:
958       score_collisions (config);
959       break;
960     case HORIZONTAL_INTER:
961       score_horizontal_inter_quants (config);
962       break;
963
964     case NUM_SCORERS:
965     case ORIGINAL_DISTANCE:
966     default:
967       assert (false);
968     }
969   config->next_scorer_todo++;
970 }
971
972 Beam_configuration *
973 Beam_scoring_problem::force_score (SCM inspect_quants, const vector<Beam_configuration *> &configs) const
974 {
975   Drul_array<Real> ins = ly_scm2interval (inspect_quants);
976   Real mindist = 1e6;
977   Beam_configuration *best = NULL;
978   for (vsize i = 0; i < configs.size (); i++)
979     {
980       Real d = fabs (configs[i]->y[LEFT] - ins[LEFT]) + fabs (configs[i]->y[RIGHT] - ins[RIGHT]);
981       if (d < mindist)
982         {
983           best = configs[i];
984           mindist = d;
985         }
986     }
987   if (mindist > 1e5)
988     programming_error ("cannot find quant");
989
990   while (!best->done ())
991     one_scorer (best);
992
993   return best;
994 }
995
996 Drul_array<Real>
997 Beam_scoring_problem::solve () const
998 {
999   vector<Beam_configuration *> configs;
1000   generate_quants (&configs);
1001
1002   if (configs.empty ())
1003     {
1004       programming_error ("No viable beam quanting found.  Using unquanted y value.");
1005       return unquanted_y_;
1006     }
1007
1008   if (to_boolean (beam_->get_property ("skip-quanting")))
1009     return unquanted_y_;
1010
1011   Beam_configuration *best = NULL;
1012
1013   bool debug
1014     = to_boolean (beam_->layout ()->lookup_variable (ly_symbol2scm ("debug-beam-scoring")));
1015   SCM inspect_quants = beam_->get_property ("inspect-quants");
1016   if (scm_is_pair (inspect_quants))
1017     {
1018       debug = true;
1019       best = force_score (inspect_quants, configs);
1020     }
1021   else
1022     {
1023       std::priority_queue < Beam_configuration *, std::vector<Beam_configuration *>,
1024           Beam_configuration_less > queue;
1025       for (vsize i = 0; i < configs.size (); i++)
1026         queue.push (configs[i]);
1027
1028       /*
1029         TODO
1030
1031         It would be neat if we generated new configurations on the
1032         fly, depending on the best complete score so far, eg.
1033
1034         if (best->done()) {
1035           if (best->demerits < sqrt(queue.size())
1036             break;
1037           while (best->demerits > sqrt(queue.size()) {
1038             generate and insert new configuration
1039           }
1040         }
1041
1042         that would allow us to do away with region_size altogether.
1043       */
1044       while (true)
1045         {
1046           best = queue.top ();
1047           if (best->done ())
1048             break;
1049
1050           queue.pop ();
1051           one_scorer (best);
1052           queue.push (best);
1053         }
1054     }
1055
1056   Interval final_positions = best->y;
1057
1058 #if DEBUG_BEAM_SCORING
1059   if (debug)
1060     {
1061       // debug quanting
1062       int completed = 0;
1063       for (vsize i = 0; i < configs.size (); i++)
1064         {
1065           if (configs[i]->done ())
1066             completed++;
1067         }
1068
1069       string card = best->score_card_ + to_string (" c%d/%d", completed, configs.size ());
1070       beam_->set_property ("annotation", ly_string2scm (card));
1071     }
1072 #endif
1073
1074   junk_pointers (configs);
1075   if (align_broken_intos_)
1076     {
1077       Interval normalized_endpoints = robust_scm2interval (beam_->get_property ("normalized-endpoints"), Interval (0, 1));
1078       Real y_length = final_positions[RIGHT] - final_positions[LEFT];
1079
1080       final_positions[LEFT] += normalized_endpoints[LEFT] * y_length;
1081       final_positions[RIGHT] -= (1 - normalized_endpoints[RIGHT]) * y_length;
1082     }
1083
1084   return final_positions;
1085 }
1086
1087 void
1088 Beam_scoring_problem::score_stem_lengths (Beam_configuration *config) const
1089 {
1090   Real limit_penalty = parameters_.STEM_LENGTH_LIMIT_PENALTY;
1091   Drul_array<Real> score (0, 0);
1092   Drul_array<int> count (0, 0);
1093
1094   for (vsize i = 0; i < stem_xpositions_.size (); i++)
1095     {
1096       if (!is_normal_[i])
1097         continue;
1098
1099       Real x = stem_xpositions_[i];
1100       Real dx = x_span_;
1101       Real beam_y = dx
1102                     ? config->y[RIGHT] * x / dx + config->y[LEFT] * (x_span_ - x) / dx
1103                     : (config->y[RIGHT] + config->y[LEFT]) / 2;
1104       Real current_y = beam_y + base_lengths_[i];
1105       Real length_pen = parameters_.STEM_LENGTH_DEMERIT_FACTOR;
1106
1107       Stem_info info = stem_infos_[i];
1108       Direction d = info.dir_;
1109
1110       score[d] += limit_penalty * max (0.0, (d * (info.shortest_y_ - current_y)));
1111
1112       Real ideal_diff = d * (current_y - info.ideal_y_);
1113       Real ideal_score = shrink_extra_weight (ideal_diff, 1.5);
1114
1115       /* We introduce a power, to make the scoring strictly
1116          convex. Otherwise a symmetric knee beam (up/down/up/down)
1117          does not have an optimum in the middle. */
1118       if (is_knee_)
1119         ideal_score = pow (ideal_score, 1.1);
1120
1121       score[d] += length_pen * ideal_score;
1122       count[d]++;
1123     }
1124
1125   /* Divide by number of stems, to make the measure scale-free. */
1126   Direction d = DOWN;
1127   do
1128     score[d] /= max (count[d], 1);
1129   while (flip (&d) != DOWN);
1130
1131   /*
1132     sometimes, two perfectly symmetric kneed beams will have the same score
1133     and can either be quanted up or down.
1134
1135     we choose the quanting in the direction of the slope so that the first stem
1136     always seems longer, reaching to the second, rather than squashed.
1137   */
1138   if (is_knee_ && count[LEFT] == count[RIGHT] && count[LEFT] == 1 && unquanted_y_.delta ())
1139     score[Direction (sign (unquanted_y_.delta ()))] += score[Direction (sign (unquanted_y_.delta ()))] < 1.0 ? 0.01 : 0.0;
1140
1141   config->add (score[LEFT] + score[RIGHT], "L");
1142 }
1143
1144 void
1145 Beam_scoring_problem::score_slope_direction (Beam_configuration *config) const
1146 {
1147   Real dy = config->y.delta ();
1148   Real damped_dy = unquanted_y_.delta ();
1149   Real dem = 0.0;
1150   /*
1151     DAMPING_DIRECTION_PENALTY is a very harsh measure, while for
1152     complex beaming patterns, horizontal is often a good choice.
1153
1154     TODO: find a way to incorporate the complexity of the beam in this
1155     penalty.
1156   */
1157   if (sign (damped_dy) != sign (dy))
1158     {
1159       if (!dy)
1160         {
1161           if (fabs (damped_dy / x_span_) > parameters_.ROUND_TO_ZERO_SLOPE)
1162             dem += parameters_.DAMPING_DIRECTION_PENALTY;
1163           else
1164             dem += parameters_.HINT_DIRECTION_PENALTY;
1165         }
1166       else
1167         dem += parameters_.DAMPING_DIRECTION_PENALTY;
1168     }
1169
1170   config->add (dem, "Sd");
1171 }
1172
1173 // Score for going against the direction of the musical pattern
1174 void
1175 Beam_scoring_problem::score_slope_musical (Beam_configuration *config) const
1176 {
1177   Real dy = config->y.delta ();
1178   Real dem = parameters_.MUSICAL_DIRECTION_FACTOR
1179              * max (0.0, (fabs (dy) - fabs (musical_dy_)));
1180   config->add (dem, "Sm");
1181 }
1182
1183 // Score deviation from calculated ideal slope.
1184 void
1185 Beam_scoring_problem::score_slope_ideal (Beam_configuration *config) const
1186 {
1187   Real dy = config->y.delta ();
1188   Real damped_dy = unquanted_y_.delta ();
1189   Real dem = 0.0;
1190
1191   Real slope_penalty = parameters_.IDEAL_SLOPE_FACTOR;
1192
1193   /* Xstaff beams tend to use extreme slopes to get short stems. We
1194      put in a penalty here. */
1195   if (is_xstaff_)
1196     slope_penalty *= 10;
1197
1198   /* Huh, why would a too steep beam be better than a too flat one ? */
1199   dem += shrink_extra_weight (fabs (damped_dy) - fabs (dy), 1.5)
1200          * slope_penalty;
1201
1202   config->add (dem, "Si");
1203 }
1204
1205 static Real
1206 my_modf (Real x)
1207 {
1208   return x - floor (x);
1209 }
1210
1211 // TODO - there is some overlap with forbidden quants, but for
1212 // horizontal beams, it is much more serious to have stafflines
1213 // appearing in the wrong place, so we have a separate scorer.
1214 void
1215 Beam_scoring_problem::score_horizontal_inter_quants (Beam_configuration *config) const
1216 {
1217   if (config->y.delta () == 0.0
1218       && abs (config->y[LEFT]) < staff_radius_ * staff_space_)
1219     {
1220       Real yshift = config->y[LEFT] - 0.5 * staff_space_;
1221       if (fabs (my_round (yshift) - yshift) < 0.01 * staff_space_)
1222         config->add (parameters_.HORIZONTAL_INTER_QUANT_PENALTY, "H");
1223     }
1224 }
1225
1226 /*
1227   TODO: The fixed value SECONDARY_BEAM_DEMERIT is probably flawed:
1228   because for 32nd and 64th beams the forbidden quants are relatively
1229   more important than stem lengths.
1230 */
1231 void
1232 Beam_scoring_problem::score_forbidden_quants (Beam_configuration *config) const
1233 {
1234   Real dy = config->y.delta ();
1235
1236   Real extra_demerit = parameters_.SECONDARY_BEAM_DEMERIT
1237                        / max (edge_beam_counts_[LEFT], edge_beam_counts_[RIGHT]);
1238
1239   Direction d = LEFT;
1240   Real dem = 0.0;
1241   Real eps = parameters_.BEAM_EPS;
1242
1243   do
1244     {
1245       for (int j = 1; j <= edge_beam_counts_[d]; j++)
1246         {
1247           Direction stem_dir = edge_dirs_[d];
1248
1249           /*
1250             The 2.2 factor is to provide a little leniency for
1251             borderline cases. If we do 2.0, then the upper outer line
1252             will be in the gap of the (2, sit) quant, leading to a
1253             false demerit.
1254           */
1255           Real gap1 = config->y[d] - stem_dir * ((j - 1) * beam_translation_ + beam_thickness_ / 2 - line_thickness_ / 2.2);
1256           Real gap2 = config->y[d] - stem_dir * (j * beam_translation_ - beam_thickness_ / 2 + line_thickness_ / 2.2);
1257
1258           Interval gap;
1259           gap.add_point (gap1);
1260           gap.add_point (gap2);
1261
1262           for (Real k = -staff_radius_;
1263                k <= staff_radius_ + eps; k += 1.0)
1264             if (gap.contains (k))
1265               {
1266                 Real dist = min (fabs (gap[UP] - k), fabs (gap[DOWN] - k));
1267
1268                 /*
1269                   this parameter is tuned to grace-stem-length.ly
1270                   retuned from 0.40 to 0.39 by MS because of slight increases
1271                   in gap.length () resulting from measuring beams at real ends
1272                   instead of from the middle of stems.
1273
1274                   TODO:
1275                   This function needs better comments so we know what is forbidden
1276                   and why.
1277                 */
1278                 Real fixed_demerit = 0.39;
1279
1280                 dem += extra_demerit
1281                        * (fixed_demerit
1282                           + (1 - fixed_demerit) * (dist / gap.length ()) * 2);
1283               }
1284         }
1285     }
1286   while ((flip (&d)) != LEFT);
1287
1288   if (max (edge_beam_counts_[LEFT], edge_beam_counts_[RIGHT]) >= 2)
1289     {
1290       Real straddle = 0.0;
1291       Real sit = (beam_thickness_ - line_thickness_) / 2;
1292       Real inter = 0.5;
1293       Real hang = 1.0 - (beam_thickness_ - line_thickness_) / 2;
1294
1295       Direction d = LEFT;
1296       do
1297         {
1298           if (edge_beam_counts_[d] >= 2
1299               && fabs (config->y[d] - edge_dirs_[d] * beam_translation_) < staff_radius_ + inter)
1300             {
1301               // TODO up/down symmetry.
1302               if (edge_dirs_[d] == UP && dy <= eps
1303                   && fabs (my_modf (config->y[d]) - sit) < eps)
1304                 dem += extra_demerit;
1305
1306               if (edge_dirs_[d] == DOWN && dy >= eps
1307                   && fabs (my_modf (config->y[d]) - hang) < eps)
1308                 dem += extra_demerit;
1309             }
1310
1311           if (edge_beam_counts_[d] >= 3
1312               && fabs (config->y[d] - 2 * edge_dirs_[d] * beam_translation_) < staff_radius_ + inter)
1313             {
1314               // TODO up/down symmetry.
1315               if (edge_dirs_[d] == UP && dy <= eps
1316                   && fabs (my_modf (config->y[d]) - straddle) < eps)
1317                 dem += extra_demerit;
1318
1319               if (edge_dirs_[d] == DOWN && dy >= eps
1320                   && fabs (my_modf (config->y[d]) - straddle) < eps)
1321                 dem += extra_demerit;
1322             }
1323         }
1324       while (flip (&d) != LEFT);
1325     }
1326
1327   config->add (dem, "F");
1328 }
1329
1330 void
1331 Beam_scoring_problem::score_collisions (Beam_configuration *config) const
1332 {
1333   Real demerits = 0.0;
1334   for (vsize i = 0; i < collisions_.size (); i++)
1335     {
1336       Interval collision_y = collisions_[i].y_;
1337       Real x = collisions_[i].x_;
1338
1339       Real center_beam_y = y_at (x, config);
1340       Interval beam_y = center_beam_y + collisions_[i].beam_y_;
1341
1342       Real dist = infinity_f;
1343       if (!intersection (beam_y, collision_y).is_empty ())
1344         dist = 0.0;
1345       else
1346         dist = min (beam_y.distance (collision_y[DOWN]),
1347                     beam_y.distance (collision_y[UP]));
1348
1349       Real scale_free
1350         = max (parameters_.COLLISION_PADDING - dist, 0.0) /
1351           parameters_.COLLISION_PADDING;
1352       demerits
1353       += collisions_[i].base_penalty_ *
1354          pow (scale_free, 3) * parameters_.COLLISION_PENALTY;
1355     }
1356
1357   config->add (demerits, "C");
1358 }