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