+void Beam_scoring_problem::add_collision (Real x, Interval y,
+ Real score_factor)
+{
+ if (edge_dirs[LEFT] == edge_dirs[RIGHT])
+ {
+ Direction d = edge_dirs[LEFT];
+
+ Real quant_range_y = quant_range[LEFT][-d]
+ + (x - x_span[LEFT]) * (quant_range[RIGHT][-d] - quant_range[LEFT][-d]) / x_span.delta ();
+
+ if (d * (quant_range_y - minmax (d, y[UP], y[DOWN])) > 0)
+ {
+ return;
+ }
+ }
+
+ Beam_collision c;
+ c.beam_y_.set_empty ();
+
+ for (vsize j = 0; j < segments_.size (); j++)
+ {
+ 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_collisions (vector<Grob *> grobs)
+{
+ Grob *common_x = NULL;
+ segments_ = Beam::get_beam_segments (beam, &common_x);
+ vector_sort (segments_, beam_segment_less);
+ if (common[X_AXIS] != common_x)
+ {
+ programming_error ("Disagree on common x. Skipping collisions in beam scoring.");
+ return;
+ }
+
+ set<Grob *> stems;
+ for (vsize i = 0; i < grobs.size (); i++)
+ {
+ Box b;
+ for (Axis a = X_AXIS; a < NO_AXES; incr (a))
+ b[a] = grobs[i]->extent (common[a], a);
+
+ Real width = b[X_AXIS].length ();
+ Real width_factor = sqrt (width / staff_space);
+
+ Direction d = LEFT;
+ do
+ add_collision (b[X_AXIS][d], b[Y_AXIS], width_factor);
+ while (flip (&d) != LEFT);
+
+ Grob *stem = unsmob_grob (grobs[i]->get_object ("stem"));
+ if (stem && Stem::has_interface (stem) && Stem::is_normal_stem (stem))
+ {
+ stems.insert (stem);
+ }
+ }
+
+ for (set<Grob *>::const_iterator it (stems.begin ()); it != stems.end (); it++)
+ {
+ Grob *s = *it;
+ Real x = s->extent (common[X_AXIS], X_AXIS).center ();
+
+ Direction stem_dir = get_grob_direction (*it);
+ Interval y;
+ y.set_full ();
+ y[-stem_dir] = Stem::chord_start_y (*it) + (*it)->relative_coordinate (common[Y_AXIS], Y_AXIS)
+ - beam->relative_coordinate (common[Y_AXIS], Y_AXIS);
+
+ Real factor = parameters.STEM_COLLISION_FACTOR;
+ if (!unsmob_grob (s->get_object ("beam")))
+ factor = 1.0;
+ add_collision (x, y, factor);
+ }
+}
+