+
+Tie_configuration*
+Tie_formatting_problem::get_configuration (int pos, Direction dir)
+{
+ pair<int,int> key (pos, dir);
+ Tie_configuration_map::const_iterator f = possibilities_.find (key);
+
+ if (f != possibilities_.end ())
+ {
+ return (*f).second;
+ }
+
+
+ Tie_configuration *conf = generate_configuration (pos,dir);
+ possibilities_[key] = conf;
+ return conf;
+}
+
+Tie_configuration*
+Tie_formatting_problem::generate_configuration (int pos, Direction dir)
+{
+ Tie_configuration *conf = new Tie_configuration;
+ conf->position_ = pos;
+ conf->dir_ = dir;
+ Real y = conf->position_ * 0.5 * details_.staff_space_;
+
+ if (dot_positions_.find (pos) != dot_positions_.end ())
+ {
+ conf->delta_y_ += 0.25 * details_.staff_space_;
+ }
+ conf->attachment_x_ = get_attachment (y + conf->delta_y_);
+
+ Real h = conf->height (details_);
+ if (!conf->delta_y_)
+ {
+ if (h < 0.5 * details_.staff_space_
+ && !Staff_symbol_referencer::on_staffline (details_.staff_symbol_referencer_, pos))
+ {
+ conf->center_tie_vertically (details_);
+ }
+ else if (h < 0.5 * details_.staff_space_
+ && Staff_symbol_referencer::on_staffline (details_.staff_symbol_referencer_, pos))
+ {
+ conf->delta_y_ += dir * 0.2 * details_.staff_space_;
+ }
+ }
+
+ conf->attachment_x_.widen ( - details_.x_gap_);
+ return conf;
+}
+
+Real
+Tie_formatting_problem::score_aptitude (Tie_configuration const &conf,
+ int tie_position)
+{
+ Real wrong_direction_offset_penalty_;
+ Real distance_penalty_factor_;
+
+ wrong_direction_offset_penalty_ = 10;
+ distance_penalty_factor_ = 5;
+
+ Real penalty = 0.0;
+ Real curve_y = conf.position_ * details_.staff_space_ * 0.5 + conf.delta_y_;
+ Real tie_y = tie_position * details_.staff_space_ * 0.5;
+ if (sign (curve_y - tie_y) != conf.dir_)
+ penalty += wrong_direction_offset_penalty_;
+
+ penalty += distance_penalty_factor_ * fabs (curve_y - tie_y);
+ return penalty;
+}
+
+
+Real
+Tie_formatting_problem::score_configuration (Tie_configuration const &conf)
+{
+ Real length_penalty_factor = 1.0;
+ Real min_length = 0.333;
+ Real staff_line_clearance = 0.1;
+ Real staff_line_collision_penalty = 5;
+
+ Real penalty = 0.0;
+ Real length = conf.attachment_x_.length ();
+ if (length < min_length)
+ penalty += length_penalty_factor / max (0.01, length);
+
+ Real tip_pos = conf.position_ + conf.delta_y_ / 0.5 * details_.staff_space_;
+ Real tip_y = tip_pos * details_.staff_space_ * 0.5;
+ Real height = conf.height (details_);
+
+ Real top_y = tip_y + conf.dir_ * height;
+ Real top_pos = 2 * top_y / details_.staff_space_;
+ Real round_top_pos = rint (top_pos);
+ if (fabs (top_pos - round_top_pos) < staff_line_clearance
+ && Staff_symbol_referencer::on_staffline (details_.staff_symbol_referencer_,
+ int (round_top_pos))
+ && Staff_symbol_referencer::staff_radius (details_.staff_symbol_referencer_) > top_y)
+ {
+ penalty += staff_line_collision_penalty;
+ }
+
+ if (fabs (tip_pos - rint (tip_pos)) < staff_line_clearance
+ && Staff_symbol_referencer::on_staffline (details_.staff_symbol_referencer_,
+ int (rint (tip_pos))))
+ {
+ penalty += staff_line_collision_penalty;
+ }
+
+ return penalty;
+}
+
+Tie_configuration
+Tie_formatting_problem::find_optimal_tie_configuration (int pos, Direction dir)
+{
+ Link_array<Tie_configuration> confs;
+
+ int region_size = 3;
+ for (int i = 0; i < region_size; i ++)
+ {
+ confs.push (generate_configuration (pos + i * dir, dir));
+ }
+
+ Array<Real> scores;
+
+ int best_idx = -1;
+ Real best_score = 1e6;
+ for (int i = 0; i < confs.size (); i ++)
+ {
+ Real score = 0.0;
+ score += score_configuration (*confs[i]);
+ score += score_aptitude (*confs[i], pos);
+
+ if (score < best_score)
+ {
+ best_score = score;
+ best_idx = i;
+ }
+ }
+
+ Tie_configuration best = *confs[best_idx];
+ for (int i = 0; i < confs.size (); i++)
+ delete confs[i];
+
+ return best;
+}