+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;
+ 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))
+ {
+ 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"))
+ && !Stem::flag (s).is_empty ())
+ factor = 1.0;
+ add_collision (x, y, factor);
+ }
+}
+