+ if (segments_[j].horizontal_.contains (x))
+ c.beam_y_.add_point (segments_[j].vertical_count_ * beam_translation_);
+ if (segments_[j].horizontal_[LEFT] > x)
+ break;
+ }
+ c.beam_y_.widen (0.5 * beam_thickness_);
+
+ c.x_ = x;
+
+ y *= 1 / staff_space_;
+ c.y_ = y;
+ c.base_penalty_ = score_factor;
+ collisions_.push_back (c);
+}
+
+void Beam_scoring_problem::init_instance_variables (Grob *me, Drul_array<Real> ys, bool align_broken_intos)
+{
+ beam_ = dynamic_cast<Spanner *> (me);
+ unquanted_y_ = ys;
+
+ /*
+ If 'ys' are finite, use them as starting points for y-positions of the
+ ends of the beam, instead of the best-fit through the natural ends of
+ the stems. Otherwise, we want to do initial slope calculations.
+ */
+ do_initial_slope_calculations_ = false;
+ for (LEFT_and_RIGHT (d))
+ do_initial_slope_calculations_ |= isinf (unquanted_y_[d]) || isnan (unquanted_y_[d]);
+
+ /*
+ Calculations are relative to a unit-scaled staff, i.e. the quants are
+ divided by the current staff_space_.
+ */
+ staff_space_ = Staff_symbol_referencer::staff_space (beam_);
+ beam_thickness_ = Beam::get_beam_thickness (beam_) / staff_space_;
+ line_thickness_ = Staff_symbol_referencer::line_thickness (beam_) / staff_space_;
+
+ // This is the least-squares DY, corrected for concave beams.
+ musical_dy_ = robust_scm2double (beam_->get_property ("least-squares-dy"), 0);
+
+ vector<Spanner *> beams;
+ align_broken_intos_ = align_broken_intos;
+ if (align_broken_intos_)
+ {
+ Spanner *orig = dynamic_cast<Spanner *> (beam_->original ());
+ if (!orig)
+ align_broken_intos_ = false;
+ else if (!orig->broken_intos_.size ())
+ align_broken_intos_ = false;
+ else
+ beams.insert (beams.end (), orig->broken_intos_.begin (), orig->broken_intos_.end ());
+ }
+ if (!align_broken_intos_)
+ beams.push_back (beam_);
+
+ /*
+ x_span_ is a single scalar, cumulatively summing the length of all the
+ segments the parent beam was broken-into.
+ */
+ x_span_ = 0.0;
+ is_knee_ = false;
+ normal_stem_count_ = 0;
+ for (vsize i = 0; i < beams.size (); i++)
+ {
+ extract_grob_set (beams[i], "stems", stems);
+ extract_grob_set (beams[i], "covered-grobs", fake_collisions);
+ vector<Grob *> collisions;
+
+ for (vsize j = 0; j < fake_collisions.size (); j++)
+ if (fake_collisions[j]->get_system () == beams[i]->get_system ())
+ collisions.push_back (fake_collisions[j]);
+
+ Grob *common[2];
+ for (int a = 2; a--;)
+ common[a] = common_refpoint_of_array (stems, beams[i], Axis (a));
+
+ for (LEFT_and_RIGHT (d))
+ common[X_AXIS] = beams[i]->get_bound (d)->common_refpoint (common[X_AXIS], X_AXIS);
+
+ // positions of the endpoints of this beam segment, including any overhangs
+ const Interval x_pos = robust_scm2interval (beams[i]->get_property ("X-positions"),
+ Interval (0.0, 0.0));
+
+ Drul_array<Grob *> edge_stems (Beam::first_normal_stem (beams[i]),
+ Beam::last_normal_stem (beams[i]));
+
+ Drul_array<bool> dirs_found (0, 0);
+
+ Real my_y = beams[i]->relative_coordinate (common[Y_AXIS], Y_AXIS);
+
+ Interval beam_width (-1.0, -1.0);
+ for (vsize j = 0; j < stems.size (); j++)
+ {
+ Grob *s = stems[j];
+ beam_multiplicity_.push_back (Stem::beam_multiplicity (stems[j]));
+ head_positions_.push_back (Stem::head_positions (stems[j]));
+ is_normal_.push_back (Stem::is_normal_stem (stems[j]));
+
+ Stem_info si (Stem::get_stem_info (s));
+ si.scale (1 / staff_space_);
+ stem_infos_.push_back (si);
+ chord_start_y_.push_back (Stem::chord_start_y (s));
+ dirs_found[si.dir_] = true;
+
+ bool f = to_boolean (s->get_property ("french-beaming"))
+ && s != edge_stems[LEFT] && s != edge_stems[RIGHT];
+
+ Real y = Beam::calc_stem_y (beams[i], s, common, x_pos[LEFT], x_pos[RIGHT], CENTER,
+ Interval (0, 0), f);
+ base_lengths_.push_back (y / staff_space_);
+ stem_xpositions_.push_back (s->relative_coordinate (common[X_AXIS], X_AXIS) - x_pos[LEFT] + x_span_);
+ stem_ypositions_.push_back (s->relative_coordinate (common[Y_AXIS], Y_AXIS) - my_y);
+
+ if (is_normal_.back ())
+ {
+ if (beam_width[LEFT] == -1.0)
+ beam_width[LEFT] = stem_xpositions_.back ();
+ beam_width[RIGHT] = stem_xpositions_.back ();
+ }
+ }
+
+ edge_dirs_ = Drul_array<Direction> (CENTER, CENTER);
+ normal_stem_count_ += Beam::normal_stem_count (beams[i]);
+ if (normal_stem_count_)
+ edge_dirs_ = Drul_array<Direction> (stem_infos_[0].dir_,
+ stem_infos_.back ().dir_);
+
+ is_xstaff_ = has_interface<Align_interface> (common[Y_AXIS]);
+ is_knee_ |= dirs_found[DOWN] && dirs_found[UP];
+
+ staff_radius_ = Staff_symbol_referencer::staff_radius (beams[i]);
+ edge_beam_counts_ = Drul_array<int>
+ (Stem::beam_multiplicity (stems[0]).length () + 1,
+ Stem::beam_multiplicity (stems.back ()).length () + 1);
+
+ // TODO - why are we dividing by staff_space_?
+ beam_translation_ = Beam::get_beam_translation (beams[i]) / staff_space_;