2 tie-formatting-problem.cc -- implement Tie_formatting_problem
4 source file of the GNU LilyPond music typesetter
6 (c) 2005--2006 Han-Wen Nienhuys <hanwen@xs4all.nl>
10 #include "tie-formatting-problem.hh"
12 #include "paper-column.hh"
14 #include "directional-element-interface.hh"
16 #include "libc-extension.hh"
18 #include "note-head.hh"
19 #include "rhythmic-head.hh"
21 #include "staff-symbol-referencer.hh"
23 #include "tie-configuration.hh"
29 Tie_formatting_problem::print_ties_configuration (Ties_configuration
const *ties
)
31 for (vsize i
= 0; i
< ties
->size (); i
++)
33 char const *man_pos
= (specifications_
[i
].has_manual_position_
) ? "(M)" : "";
34 char const *man_dir
= (specifications_
[i
].has_manual_dir_
) ? "(M)" : "";
35 char const *dir
= (ties
->at (i
).dir_
== UP
) ? "up" : "dn";
37 printf ("(P%d%s, %s%s) ", ties
->at (i
).position_
, man_pos
, dir
, man_dir
);
43 Tie_formatting_problem::get_attachment (Real y
, Drul_array
<int> columns
) const
45 Interval
attachments (0,0);
49 Tuple2
<int> key (columns
[d
], int (d
));
50 Chord_outline_map::const_iterator
i (chord_outlines_
.find (key
));
51 if (i
== chord_outlines_
.end ())
52 programming_error ("Can't find chord outline");
54 attachments
[d
] = skyline_height ((*i
).second
, y
, -d
);
56 while (flip (&d
) != LEFT
);
61 Tie_formatting_problem::Tie_formatting_problem()
66 Tie_formatting_problem::~Tie_formatting_problem ()
68 for (Tie_configuration_map::const_iterator
i (possibilities_
.begin ());
69 i
!= possibilities_
.end (); i
++)
74 Tie_formatting_problem::set_column_chord_outline (vector
<Item
*> bounds
,
78 Real staff_space
= Staff_symbol_referencer::staff_space (bounds
[0]);
81 vector
<Box
> head_boxes
;
84 for (vsize i
= 0; i
< bounds
.size (); i
++)
86 Grob
*head
= bounds
[i
];
87 if (!Note_head::has_interface (head
))
91 stem
= unsmob_grob (head
->get_object ("stem"));
93 Real p
= Staff_symbol_referencer::get_position (head
);
94 Interval
y ((p
-1) * 0.5 * staff_space
,
95 (p
+1) * 0.5 * staff_space
);
97 Interval x
= head
->extent (x_refpoint_
, X_AXIS
);
98 head_boxes
.push_back (Box (x
, y
));
99 boxes
.push_back (Box (x
, y
));
101 Grob
*dots
= Rhythmic_head::get_dots (head
);
102 if (dir
== LEFT
&& dots
)
104 Interval x
= dots
->extent (x_refpoint_
, X_AXIS
);
105 int p
= int (Staff_symbol_referencer::get_position (dots
));
107 dot_positions_
.insert (p
);
110 Interval
y (dots
->extent (dots
, Y_AXIS
));
111 y
.translate (p
* staff_space
* 0.5);
113 boxes
.push_back (Box (x
, y
));
117 Tuple2
<int> key (column_rank
, int (dir
));
119 chord_outlines_
[key
] = empty_skyline (-dir
);
121 if (bounds
[0]->break_status_dir ())
123 Real x
= robust_relative_extent (bounds
[0], x_refpoint_
, X_AXIS
)[-dir
];
124 chord_outlines_
[key
].at (0).height_
= x
;
129 for (vsize j
= 0; j
< head_boxes
.size (); j
++)
131 x
.unite (head_boxes
[j
][X_AXIS
]);
134 chord_outlines_
[key
].at (0).height_
= x
[dir
];
137 for (vsize i
= 0; i
< boxes
.size (); i
++)
138 insert_extent_into_skyline (&chord_outlines_
[key
] ,
139 boxes
[i
], Y_AXIS
, -dir
);
142 && !Stem::is_invisible (stem
))
145 x
.add_point (stem
->relative_coordinate (x_refpoint_
, X_AXIS
));
146 x
.widen (staff_space
/ 20); // ugh.
148 y
.add_point (Stem::stem_end_position (stem
) * staff_space
* .5);
150 Direction stemdir
= get_grob_direction (stem
);
151 y
.add_point (Stem::head_positions (stem
)[-stemdir
]
154 insert_extent_into_skyline (&chord_outlines_
[key
], Box (x
,y
), Y_AXIS
, -dir
);
156 stem_extents_
[key
].unite (Box (x
,y
));
160 Box flag_box
= Stem::get_translated_flag (stem
).extent_box ();
161 flag_box
.translate( Offset (x
[RIGHT
], X_AXIS
));
162 insert_extent_into_skyline (&chord_outlines_
[key
], flag_box
,
168 Grob
*head
= Stem::support_head (stem
);
171 In case of invisible stem, don't pass x-center of heads.
173 Real x_center
= head
->extent (x_refpoint_
, X_AXIS
).center ();
175 x_ext
[-dir
] = x_center
;
177 for (vsize j
= 0; j
< head_boxes
.size (); j
++)
178 y_ext
.unite (head_boxes
[j
][Y_AXIS
]);
180 insert_extent_into_skyline (&chord_outlines_
[key
],
185 Direction updowndir
= DOWN
;
190 if (head_boxes
.size())
192 Box b
= boundary (head_boxes
, updowndir
, 0);
194 x
[-dir
] = b
[X_AXIS
].linear_combination (-dir
/ 2);
195 y
[-updowndir
] = b
[Y_AXIS
][updowndir
];
196 y
[updowndir
] = updowndir
* infinity_f
;
200 insert_extent_into_skyline (&chord_outlines_
[key
],
204 while (flip (&updowndir
) != DOWN
);
206 head_extents_
[key
].set_empty ();
207 for (vsize i
= 0; i
< head_boxes
.size (); i
++)
209 head_extents_
[key
].unite (head_boxes
[i
]);
214 Tie_formatting_problem::set_chord_outline (vector
<Item
*> bounds
,
219 for (vsize i
= 0; i
< bounds
.size (); i
++)
220 ranks
.push_back (bounds
[i
]->get_column ()->get_rank ());
222 vector_sort (ranks
, less
<int> ());
225 for (vsize i
= 0; i
< ranks
.size (); i
++)
227 vector
<Item
*> col_items
;
228 for (vsize j
= 0; j
< bounds
.size (); j
++)
230 if (bounds
[j
]->get_column ()->get_rank () == ranks
[i
])
231 col_items
.push_back (bounds
[j
]);
234 set_column_chord_outline (col_items
, dir
, ranks
[i
]);
241 Tie_formatting_problem::from_tie (Grob
*tie
)
244 ties
.push_back (tie
);
247 details_
.from_grob (tie
);
251 Tie_formatting_problem::common_x_refpoint () const
257 Tie_formatting_problem::from_ties (vector
<Grob
*> const &ties
)
262 x_refpoint_
= ties
[0];
263 for (vsize i
= 0; i
< ties
.size (); i
++)
265 x_refpoint_
= dynamic_cast<Spanner
*> (ties
[i
])->get_bound (LEFT
)->common_refpoint (x_refpoint_
, X_AXIS
);
266 x_refpoint_
= dynamic_cast<Spanner
*> (ties
[i
])->get_bound (RIGHT
)->common_refpoint (x_refpoint_
, X_AXIS
);
269 details_
.from_grob (ties
[0]);
274 vector
<Item
*> bounds
;
276 for (vsize i
= 0; i
< ties
.size (); i
++)
278 Item
*it
= dynamic_cast<Spanner
*> (ties
[i
])->get_bound (d
);
280 bounds
.push_back (it
);
283 set_chord_outline (bounds
, d
);
285 while (flip (&d
) != LEFT
);
288 for (vsize i
= 0; i
< ties
.size (); i
++)
290 Tie_specification spec
;
292 if (scm_is_number (ties
[i
]->get_property_data (ly_symbol2scm ("direction"))))
294 spec
.manual_dir_
= to_dir (ties
[i
]->get_property ("direction"));
295 spec
.has_manual_dir_
= true;
298 spec
.position_
= Tie::get_position (ties
[i
]);
299 if (scm_is_number (ties
[i
]->get_property ("staff-position")))
301 spec
.manual_position_
= scm_to_double (ties
[i
]->get_property ("staff-position"));
302 spec
.has_manual_position_
= true;
303 spec
.position_
= int (my_round (spec
.manual_position_
));
308 spec
.note_head_drul_
[d
] = Tie::head (ties
[i
], d
);
309 spec
.column_ranks_
[d
] =
310 dynamic_cast<Spanner
*> (ties
[i
])->get_bound (d
)->get_column ()->get_rank ();
312 while (flip (&d
) != LEFT
);
313 specifications_
.push_back (spec
);
318 Tie_formatting_problem::from_semi_ties (vector
<Grob
*> const &lv_ties
, Direction head_dir
)
320 if (lv_ties
.empty ())
323 details_
.from_grob (lv_ties
[0]);
326 int column_rank
= -1;
327 for (vsize i
= 0; i
< lv_ties
.size (); i
++)
329 Tie_specification spec
;
330 Item
*head
= unsmob_item (lv_ties
[i
]->get_object ("note-head"));
333 programming_error ("LV tie without head?!");
337 spec
.position_
= int (Staff_symbol_referencer::get_position (head
));
341 spec
.note_head_drul_
[head_dir
] = head
;
342 column_rank
= dynamic_cast<Item
*> (head
)->get_column ()->get_rank ();
343 spec
.column_ranks_
= Drul_array
<int> (column_rank
, column_rank
);
344 heads
.push_back (head
);
345 specifications_
.push_back (spec
);
348 x_refpoint_
= lv_ties
[0];
349 for (vsize i
= 0; i
< lv_ties
.size (); i
++)
350 x_refpoint_
= lv_ties
[i
]->common_refpoint (x_refpoint_
, X_AXIS
);
351 for (vsize i
= 0; i
< heads
.size (); i
++)
352 x_refpoint_
= heads
[i
]->common_refpoint (x_refpoint_
, X_AXIS
);
354 set_chord_outline (heads
, head_dir
);
356 Real extremal
= head_dir
* infinity_f
;
358 Tuple2
<int> head_key (column_rank
, head_dir
);
359 Tuple2
<int> open_key (column_rank
, -head_dir
);
361 for (vsize i
= 0; i
< chord_outlines_
[head_key
].size (); i
++)
363 extremal
= head_dir
* min (head_dir
* extremal
,
364 head_dir
* chord_outlines_
[head_key
][i
].height_
);
367 Skyline_entry right_entry
;
368 right_entry
.width_
.set_full ();
369 right_entry
.height_
= extremal
- head_dir
* 1.5;
371 chord_outlines_
[open_key
].push_back (right_entry
);
376 Tie_formatting_problem::get_tie_specification (int i
) const
378 return specifications_
[i
];
383 Return configuration, create it if necessary.
386 Tie_formatting_problem::get_configuration (int pos
, Direction dir
, Drul_array
<int> columns
) const
388 int key_components
[] = {
389 pos
, dir
, columns
[LEFT
], columns
[RIGHT
]
391 Tuple
<int,4> key (key_components
);
393 Tie_configuration_map::const_iterator f
= possibilities_
.find (key
);
394 if (f
!= possibilities_
.end ())
400 Tie_configuration
*conf
= generate_configuration (pos
, dir
, columns
);
401 ((Tie_formatting_problem
*) this)->possibilities_
[key
] = conf
;
406 Tie_formatting_problem::generate_configuration (int pos
, Direction dir
,
407 Drul_array
<int> columns
) const
409 Tie_configuration
*conf
= new Tie_configuration
;
410 conf
->position_
= pos
;
413 conf
->column_ranks_
= columns
;
415 Real y
= conf
->position_
* 0.5 * details_
.staff_space_
;
418 if (dot_positions_
.find (pos
) != dot_positions_
.end ())
420 conf
->delta_y_
+= dir
* 0.25 * details_
.staff_space_
;
425 && max (fabs (get_head_extent (columns
[LEFT
], LEFT
, Y_AXIS
)[dir
] - y
),
426 fabs (get_head_extent (columns
[RIGHT
], RIGHT
, Y_AXIS
)[dir
] - y
)) < 0.25
427 && !Staff_symbol_referencer::on_line (details_
.staff_symbol_referencer_
, pos
))
430 (get_head_extent (columns
[LEFT
], LEFT
, Y_AXIS
)[dir
] - y
)
431 + dir
* details_
.outer_tie_vertical_gap_
;
436 conf
->attachment_x_
= get_attachment (y
+ conf
->delta_y_
, conf
->column_ranks_
);
437 Real h
= conf
->height (details_
);
442 - should make sliding criterion, should flatten ties if
444 - they're just the wrong (ie. touching line at top & bottom)
448 if (h
< details_
.intra_space_threshold_
* 0.5 * details_
.staff_space_
)
450 if (!Staff_symbol_referencer::on_line (details_
.staff_symbol_referencer_
, pos
)
451 && abs (pos
) < 2 * Staff_symbol_referencer::staff_radius (details_
.staff_symbol_referencer_
))
453 conf
->center_tie_vertically (details_
);
455 else if (Staff_symbol_referencer::on_line (details_
.staff_symbol_referencer_
, pos
))
457 conf
->delta_y_
+= dir
*
458 details_
.tip_staff_line_clearance_
* 0.5 * details_
.staff_space_
;
463 Real top_y
= y
+ conf
->delta_y_
+ conf
->dir_
* h
;
464 Real top_pos
= top_y
/ (0.5*details_
.staff_space_
);
465 int round_pos
= int (my_round (top_pos
));
467 /* TODO: should use other variable? */
468 Real clearance
= details_
.center_staff_line_clearance_
;
469 if (fabs (top_pos
- round_pos
) < clearance
470 && Staff_symbol_referencer::on_staff_line (details_
.staff_symbol_referencer_
,
473 Real new_y
= (round_pos
+ clearance
* conf
->dir_
) * 0.5 * details_
.staff_space_
;
474 conf
->delta_y_
= (new_y
- top_y
);
479 conf
->attachment_x_
= get_attachment (y
+ conf
->delta_y_
, conf
->column_ranks_
);
480 if (conf
->height (details_
) < details_
.intra_space_threshold_
* 0.5 * details_
.staff_space_
)
483 This is less sensible for long ties, since those are more
486 Interval close_by
= get_attachment (y
488 + (dir
* details_
.intra_space_threshold_
* 0.25
489 * details_
.staff_space_
),
490 conf
->column_ranks_
);
492 conf
->attachment_x_
.intersect (close_by
);
495 conf
->attachment_x_
.widen ( - details_
.x_gap_
);
500 Real y
= conf
->position_
* details_
.staff_space_
* 0.5 + conf
->delta_y_
;
501 if (get_stem_extent (conf
->column_ranks_
[d
], d
, X_AXIS
).is_empty ()
502 || !get_stem_extent (conf
->column_ranks_
[d
], d
, Y_AXIS
).contains (y
))
505 conf
->attachment_x_
[d
] =
506 d
* min (d
* conf
->attachment_x_
[d
],
507 d
* (get_stem_extent (conf
->column_ranks_
[d
], d
, X_AXIS
)[-d
] - d
* details_
.stem_gap_
));
509 while (flip (&d
) != LEFT
);
515 Tie_formatting_problem::get_head_extent (int col
, Direction d
, Axis a
) const
517 return (*head_extents_
.find (Tuple2
<int> (col
, int (d
)))).second
[a
];
521 Tie_formatting_problem::get_stem_extent (int col
, Direction d
, Axis a
) const
523 return (*stem_extents_
.find (Tuple2
<int> (col
, int (d
)))).second
[a
];
527 TIE_IDX and TIES_CONF are optional.
530 Tie_formatting_problem::score_aptitude (Tie_configuration
*conf
,
531 Tie_specification
const &spec
,
532 Ties_configuration
*ties_conf
, int tie_idx
) const
535 Real curve_y
= conf
->position_
* details_
.staff_space_
* 0.5 + conf
->delta_y_
;
536 Real tie_y
= spec
.position_
* details_
.staff_space_
* 0.5;
537 if (sign (curve_y
- tie_y
) != conf
->dir_
)
539 Real p
= details_
.wrong_direction_offset_penalty_
;
541 ties_conf
->add_tie_score (p
, tie_idx
, "wrong dir");
547 Real p
= details_
.vertical_distance_penalty_factor_
* fabs (curve_y
- tie_y
);
549 ties_conf
->add_tie_score (p
, tie_idx
, "vdist");
557 if (!spec
.note_head_drul_
[d
])
560 Interval head_x
= spec
.note_head_drul_
[d
]->extent (x_refpoint_
, X_AXIS
);
561 Real dist
= head_x
.distance (conf
->attachment_x_
[d
]);
564 TODO: flatten with log or sqrt.
566 Real p
= details_
.horizontal_distance_penalty_factor_
* dist
;
568 ties_conf
->add_tie_score (p
, tie_idx
,
569 (d
== LEFT
) ? "lhdist" : "rhdist");
573 while (flip (&d
) != LEFT
);
579 Tie_formatting_problem::score_configuration (Tie_configuration
*conf
) const
586 Real length
= conf
->attachment_x_
.length ();
588 conf
->add_score (details_
.min_length_penalty_factor_
589 * peak_around (0.33 * details_
.min_length_
, details_
.min_length_
, length
),
592 Real tip_pos
= conf
->position_
+ conf
->delta_y_
/ 0.5 * details_
.staff_space_
;
593 Real tip_y
= tip_pos
* details_
.staff_space_
* 0.5;
594 Real height
= conf
->height (details_
);
596 Real top_y
= tip_y
+ conf
->dir_
* height
;
597 Real top_pos
= 2 * top_y
/ details_
.staff_space_
;
598 Real round_top_pos
= rint (top_pos
);
599 if (Staff_symbol_referencer::on_line (details_
.staff_symbol_referencer_
,
601 && Staff_symbol_referencer::staff_radius (details_
.staff_symbol_referencer_
) > top_y
)
604 details_
.staff_line_collision_penalty_
605 * peak_around (0.1 * details_
.center_staff_line_clearance_
,
606 details_
.center_staff_line_clearance_
,
607 fabs (top_pos
- round_top_pos
)),
611 if (Staff_symbol_referencer::on_line (details_
.staff_symbol_referencer_
,
612 int (rint (tip_pos
))))
614 conf
->add_score (details_
.staff_line_collision_penalty_
615 * peak_around (0.1 * details_
.tip_staff_line_clearance_
,
616 details_
.tip_staff_line_clearance_
,
617 fabs (tip_pos
- rint (tip_pos
))),
621 if (!dot_x_
.is_empty ())
624 Real x
= dot_x_
.center ();
626 Bezier b
= conf
->get_transformed_bezier (details_
);
627 if (b
.control_point_extent (X_AXIS
).contains (x
))
629 Real y
= b
.get_other_coordinate (X_AXIS
, x
);
631 for (set
<int>::const_iterator
i (dot_positions_
.begin ());
632 i
!= dot_positions_
.end (); i
++)
635 conf
->add_score (details_
.dot_collision_penalty_
636 * peak_around (.1 * details_
.dot_collision_clearance_
,
637 details_
.dot_collision_clearance_
,
638 fabs (dot_pos
* details_
.staff_space_
* 0.5 - y
)),
644 conf
->scored_
= true;
648 Tie_formatting_problem::find_optimal_tie_configuration (Tie_specification
const &spec
) const
650 vector
<Tie_configuration
*> confs
;
652 int pos
= spec
.position_
;
653 Direction dir
= spec
.manual_dir_
;
655 for (int i
= 0; i
< details_
.single_tie_region_size_
; i
++)
657 confs
.push_back (generate_configuration (pos
+ i
* dir
, dir
,
658 spec
.column_ranks_
));
660 if (spec
.has_manual_position_
)
662 confs
.back ()->delta_y_
663 = (spec
.manual_position_
- spec
.position_
)
664 * 0.5 * details_
.staff_space_
;
673 Real best_score
= 1e6
;
674 for (vsize i
= 0; i
< confs
.size (); i
++)
676 score_configuration (confs
[i
]);
677 Real score
= score_aptitude (confs
[i
], spec
, 0, 0)
678 + confs
[i
]->score ();
680 if (score
< best_score
)
688 programming_error ("No best tie configuration found.");
690 Tie_configuration best
691 = (best_idx
>= 0) ? *confs
[best_idx
] : *confs
[0];
693 for (vsize i
= 0; i
< confs
.size (); i
++)
699 Tie_specification::Tie_specification ()
701 has_manual_position_
= false;
702 has_manual_dir_
= false;
704 manual_position_
= 0;
705 manual_dir_
= CENTER
;
706 note_head_drul_
[LEFT
] =
707 note_head_drul_
[RIGHT
] = 0;
708 column_ranks_
[RIGHT
] =
709 column_ranks_
[LEFT
] = 0;
713 Tie_specification::column_span () const
715 return column_ranks_
[RIGHT
] - column_ranks_
[LEFT
];
719 Tie_formatting_problem::score_ties_aptitude (Ties_configuration
*ties
) const
721 if (ties
->size () != specifications_
.size ())
723 programming_error ("Huh? Mismatch between sizes.");
727 for (vsize i
= 0; i
< ties
->size (); i
++)
728 score_aptitude (&ties
->at (i
), specifications_
[i
],
733 Tie_formatting_problem::score_ties (Ties_configuration
*ties
) const
738 score_ties_configuration (ties
);
739 score_ties_aptitude (ties
);
740 ties
->scored_
= true;
744 Tie_formatting_problem::score_ties_configuration (Ties_configuration
*ties
) const
746 for (vsize i
= 0; i
< ties
->size (); i
++)
748 score_configuration (&ties
->at (i
));
749 ties
->add_tie_score (ties
->at (i
).score (), i
, "conf");
752 Real last_edge
= 0.0;
753 Real last_center
= 0.0;
754 for (vsize i
= 0; i
< ties
->size (); i
++)
756 Bezier
b (ties
->at (i
).get_transformed_bezier (details_
));
758 Real center
= b
.curve_point (0.5)[Y_AXIS
];
759 Real edge
= b
.curve_point (0.0)[Y_AXIS
];
763 if (edge
<= last_edge
)
764 ties
->add_score (details_
.tie_column_monotonicity_penalty_
, "monoton edge");
765 if (center
<= last_center
)
766 ties
->add_score (details_
.tie_column_monotonicity_penalty_
, "monoton cent");
768 ties
->add_score (details_
.tie_tie_collision_penalty_
*
769 peak_around (0.1 * details_
.tie_tie_collision_distance_
,
770 details_
.tie_tie_collision_distance_
,
771 fabs (center
- last_center
)),
773 ties
->add_score (details_
.tie_tie_collision_penalty_
*
774 peak_around (0.1 * details_
.tie_tie_collision_distance_
,
775 details_
.tie_tie_collision_distance_
,
776 fabs (edge
- last_edge
)), "tietie edge");
780 last_center
= center
;
783 ties
->add_score (details_
.outer_tie_length_symmetry_penalty_factor_
784 * fabs (ties
->at (0).attachment_x_
.length () - ties
->back ().attachment_x_
.length ()),
787 ties
->add_score (details_
.outer_tie_vertical_distance_symmetry_penalty_factor_
788 * fabs (fabs (specifications_
[0].position_
* 0.5 * details_
.staff_space_
789 - (ties
->at (0).position_
* 0.5 * details_
.staff_space_
790 + ties
->at (0).delta_y_
))
792 fabs (specifications_
.back ().position_
* 0.5 * details_
.staff_space_
793 - (ties
->back ().position_
* 0.5 * details_
.staff_space_
794 + ties
->back ().delta_y_
))),
799 Generate with correct X-attachments and beziers, copying delta_y_
800 from TIES_CONFIG if necessary.
803 Tie_formatting_problem::generate_ties_configuration (Ties_configuration
const &ties_config
)
805 Ties_configuration copy
;
806 for (vsize i
= 0; i
< ties_config
.size (); i
++)
808 Tie_configuration
* ptr
= get_configuration (ties_config
[i
].position_
, ties_config
[i
].dir_
,
809 ties_config
[i
].column_ranks_
);
810 if (specifications_
[i
].has_manual_position_
)
813 = (specifications_
[i
].manual_position_
- ties_config
[i
].position_
)
814 * 0.5 * details_
.staff_space_
;
816 copy
.push_back (*ptr
);
823 Tie_formatting_problem::generate_base_chord_configuration ()
825 Ties_configuration ties_config
;
826 for (vsize i
= 0; i
< specifications_
.size (); i
++)
828 Tie_configuration conf
;
829 if (specifications_
[i
].has_manual_dir_
)
830 conf
.dir_
= specifications_
[i
].manual_dir_
;
831 if (specifications_
[i
].has_manual_position_
)
833 conf
.position_
= (int) my_round (specifications_
[i
].manual_position_
);
834 conf
.delta_y_
= (specifications_
[i
].manual_position_
- conf
.position_
)
835 * 0.5 * details_
.staff_space_
;
839 conf
.position_
= specifications_
[i
].position_
;
842 conf
.column_ranks_
= specifications_
[i
].column_ranks_
;
843 ties_config
.push_back (conf
);
846 set_ties_config_standard_directions (&ties_config
);
847 for (vsize i
= 0; i
< ties_config
.size (); i
++)
848 if (!specifications_
[i
].manual_position_
)
849 ties_config
[i
].position_
+= ties_config
[i
].dir_
;
851 ties_config
= generate_ties_configuration (ties_config
);
857 Tie_formatting_problem::find_best_variation (Ties_configuration
const &base
,
858 vector
<Tie_configuration_variation
> vars
)
860 Ties_configuration best
= base
;
863 This simply is 1-opt: we have K substitions, and we try applying
864 exactly every one for each.
866 for (vsize i
= 0; i
< vars
.size (); i
++)
868 Ties_configuration
variant (base
);
869 variant
[vars
[i
].index_
] = *vars
[i
].suggestion_
;
871 variant
.reset_score ();
872 score_ties (&variant
);
874 if (variant
.score () < best
.score ())
886 Tie_formatting_problem::generate_optimal_chord_configuration ()
888 Ties_configuration base
= generate_base_chord_configuration ();
889 vector
<Tie_configuration_variation
> vars
= generate_collision_variations (base
);
892 Ties_configuration best
= find_best_variation (base
, vars
);
893 vars
= generate_extremal_tie_variations (best
);
894 best
= find_best_variation (best
, vars
);
900 Tie_formatting_problem::set_ties_config_standard_directions (Ties_configuration
*tie_configs
)
902 if (tie_configs
->empty ())
905 if (!tie_configs
->at (0).dir_
)
906 tie_configs
->at (0).dir_
= DOWN
;
907 if (!tie_configs
->back ().dir_
)
908 tie_configs
->back ().dir_
= UP
;
913 for (vsize i
= 1; i
< tie_configs
->size (); i
++)
915 Real diff
= (tie_configs
->at (i
).position_
916 -tie_configs
->at (i
-1).position_
);
919 = specifications_
[i
].column_span () - specifications_
[i
-1].column_span ();
920 if (span_diff
&& fabs (diff
) <= 2)
923 tie_configs
->at (i
).dir_
= UP
;
924 else if (span_diff
< 0)
925 tie_configs
->at (i
-1).dir_
= DOWN
;
927 else if (fabs (diff
) <= 1)
929 if (!tie_configs
->at (i
-1).dir_
)
930 tie_configs
->at (i
-1).dir_
= DOWN
;
931 if (!tie_configs
->at (i
).dir_
)
932 tie_configs
->at (i
).dir_
= UP
;
936 for (vsize i
= 1; i
< tie_configs
->size() - 1; i
++)
938 Tie_configuration
&conf
= tie_configs
->at (i
);
942 Direction position_dir
=
943 Direction (sign (conf
.position_
));
947 conf
.dir_
= position_dir
;
951 Tie_configuration_variation::Tie_configuration_variation ()
957 vector
<Tie_configuration_variation
>
958 Tie_formatting_problem::generate_extremal_tie_variations (Ties_configuration
const &ties
) const
960 vector
<Tie_configuration_variation
> vars
;
964 if (boundary (ties
, d
, 0).dir_
== d
965 && !boundary (specifications_
, d
, 0).has_manual_position_
)
966 for (int i
= 1; i
<= details_
.multi_tie_region_size_
; i
++)
968 Tie_configuration_variation var
;
969 var
.index_
= (d
== DOWN
) ? 0 : ties
.size () - 1;
970 var
.suggestion_
= get_configuration (boundary (ties
, d
, 0).position_
972 boundary (ties
, d
, 0).column_ranks_
);
973 vars
.push_back (var
);
976 while (flip (&d
) != DOWN
);
982 vector
<Tie_configuration_variation
>
983 Tie_formatting_problem::generate_collision_variations (Ties_configuration
const &ties
) const
985 Real center_distance_tolerance
= 0.25;
987 vector
<Tie_configuration_variation
> vars
;
988 Real last_center
= 0.0;
989 for (vsize i
= 0; i
< ties
.size (); i
++)
991 Bezier
b (ties
[i
].get_transformed_bezier (details_
));
993 Real center
= b
.curve_point (0.5)[Y_AXIS
];
997 if (center
<= last_center
+ center_distance_tolerance
)
999 if (!specifications_
[i
].has_manual_dir_
)
1001 Tie_configuration_variation var
;
1003 var
.suggestion_
= get_configuration (specifications_
[i
].position_
1007 ties
[i
].column_ranks_
1010 vars
.push_back (var
);
1013 if (!specifications_
[i
-1].has_manual_dir_
)
1015 Tie_configuration_variation var
;
1017 var
.suggestion_
= get_configuration (specifications_
[i
-1].position_
1020 specifications_
[i
-1].column_ranks_
);
1022 vars
.push_back (var
);
1025 if (i
== 1 && !specifications_
[i
-1].has_manual_position_
1026 && ties
[i
-1].dir_
== DOWN
)
1028 Tie_configuration_variation var
;
1030 var
.suggestion_
= get_configuration (specifications_
[i
-1].position_
- 1, DOWN
,
1031 specifications_
[i
-1].column_ranks_
);
1032 vars
.push_back (var
);
1034 if (i
== ties
.size() && !specifications_
[i
].has_manual_position_
1035 && ties
[i
].dir_
== UP
)
1037 Tie_configuration_variation var
;
1039 var
.suggestion_
= get_configuration (specifications_
[i
].position_
1041 specifications_
[i
].column_ranks_
);
1042 vars
.push_back (var
);
1045 else if (dot_positions_
.find (ties
[i
].position_
) != dot_positions_
.end ()
1046 && !specifications_
[i
].has_manual_position_
)
1048 Tie_configuration_variation var
;
1050 var
.suggestion_
= get_configuration (ties
[i
].position_
+ ties
[i
].dir_
,
1052 ties
[i
].column_ranks_
);
1053 vars
.push_back (var
);
1058 last_center
= center
;
1066 Tie_formatting_problem::set_manual_tie_configuration (SCM manual_configs
)
1069 for (SCM s
= manual_configs
;
1070 scm_is_pair (s
) && k
< specifications_
.size (); s
= scm_cdr (s
))
1072 SCM entry
= scm_car (s
);
1073 if (scm_is_pair (entry
))
1075 Tie_specification
&spec
= specifications_
[k
];
1077 if (scm_is_number (scm_car (entry
)))
1079 spec
.has_manual_position_
= true;
1080 spec
.manual_position_
= scm_to_double (scm_car (entry
));
1082 if (scm_is_number (scm_cdr (entry
)))
1084 spec
.has_manual_dir_
= true;
1085 spec
.manual_dir_
= Direction (scm_to_int (scm_cdr (entry
)));