diff options
-rw-r--r-- | ChangeLog | 52 | ||||
-rw-r--r-- | input/mutopia/J.S.Bach/baerenreiter-sarabande.ly | 3 | ||||
-rw-r--r-- | lily/axis-group-interface.cc | 9 | ||||
-rw-r--r-- | lily/constrained-breaking.cc | 15 | ||||
-rw-r--r-- | lily/gourlay-breaking.cc | 265 | ||||
-rw-r--r-- | lily/grob.cc | 8 | ||||
-rw-r--r-- | lily/include/gourlay-breaking.hh | 23 | ||||
-rw-r--r-- | lily/include/lily-guile.hh | 4 | ||||
-rw-r--r-- | lily/include/simple-spacer.hh | 1 | ||||
-rw-r--r-- | lily/include/slur.hh | 1 | ||||
-rw-r--r-- | lily/lily-guile.cc | 15 | ||||
-rw-r--r-- | lily/optimal-page-breaking.cc | 10 | ||||
-rw-r--r-- | lily/page-breaking.cc | 30 | ||||
-rw-r--r-- | lily/page-spacing.cc | 24 | ||||
-rw-r--r-- | lily/page-turn-page-breaking.cc | 5 | ||||
-rw-r--r-- | lily/paper-score.cc | 16 | ||||
-rw-r--r-- | lily/simple-spacer.cc | 57 | ||||
-rw-r--r-- | lily/slur.cc | 29 | ||||
-rw-r--r-- | lily/system.cc | 14 | ||||
-rw-r--r-- | ly/paper-defaults.ly | 2 | ||||
-rw-r--r-- | scm/define-grobs.scm | 7 | ||||
-rw-r--r-- | scm/layout-page-layout.scm | 58 |
22 files changed, 235 insertions, 413 deletions
@@ -1,3 +1,55 @@ +2006-09-02 Joe Neeman <joeneeman@gmail.com> + + * lily/simple-spacer.cc (get_line_forces): Ignore loose columns + unless they are breakable. This fixes discrepancies between the forces + calculated here and the forces calculated in get_line_configuration. + + * lily/grob.cc (pure_relative_y_coordinate): fix some + mis-estimation that was happening with piano staves. + + * lily/constrained-breaking.cc (resize): don't choke if we get a + measure that won't fit on a line. + (combine_demerits): don't consider uniformity when ragged + + * lily/page-spacing.cc (solve): why the f* were there two of these? + (calc_subproblem): properly handle the case where a system is taller + than the page. + + * lily/system.cc (get_paper_system): ensure that all the permissions + and penalties are passed to the paper systems. + + * lily/page-breaking.cc (create_system_list): support system-count. + + * scm/define-grobs.scm (pure-print-callbacks): add + ly:script-interface::print + + * lily/page-spacing.cc (min_page_count): fix calculation of min + pages if we are ragged and there are non-zero springs. + + * scm/layout-page-layout.scm: if the pure-height estimates are under + the real height, allow space-systems to ignore padding if it is + needed in order to fit the systems on one page + + * lily/optimal-page-breaking.cc (try_page_spacing): fix reading + ragged properties + (solve): fix performance problem. Make sure we always get at least + one solution + + * lily/page-breaking.cc (make_pages): include write-page-breaks + and page-stencil + + * lily/paper-score.cc (calc_breaking): remove Gourlay breaker + + * scm/define-grobs.scm: add the new slur-callback + fix pure-relevant to not exclude grobs whose extent is already + calculated + + * ly/paper-defaults.ly: make ly:optimal-breaking the new default + page breaker + + * lily/slur.cc (pure_height): new callback to estimate the height + of a slur + 2006-09-02 Graham Percival <gpermus@gmail.com> * Documentation/user/invoking.itely: small update on diff --git a/input/mutopia/J.S.Bach/baerenreiter-sarabande.ly b/input/mutopia/J.S.Bach/baerenreiter-sarabande.ly index bc4ce8a241..a61a1ff8a6 100644 --- a/input/mutopia/J.S.Bach/baerenreiter-sarabande.ly +++ b/input/mutopia/J.S.Bach/baerenreiter-sarabande.ly @@ -126,7 +126,7 @@ sarabandeA = \context Voice \relative c { d'[ cis] | %% d4 d,,2 | d4 - #(assert-system-count-override 6) +% #(assert-system-count-override 6) d,,2 | } @@ -173,6 +173,7 @@ smallerPaper = \layout { line-width =183.5 \mm between-system-space = 25\mm between-system-padding = 0\mm + system-count = 6 %% annotatespacing = ##t } diff --git a/lily/axis-group-interface.cc b/lily/axis-group-interface.cc index 1d509f04d1..8700da3e54 100644 --- a/lily/axis-group-interface.cc +++ b/lily/axis-group-interface.cc @@ -145,7 +145,14 @@ Axis_group_interface::relative_pure_height (Grob *me, { Interval dims = elts[i]->pure_height (common, start, end); if (!dims.is_empty ()) - r.unite (dims); + { + r.unite (dims); + /* + message (_f ("axis-group (%d-%d) %s has child %s with height (%.2f,%.2f), my height is now (%.2f,%.2f)", + start, end, + me->name ().c_str (), elts[i]->name ().c_str (), dims[DOWN], dims[UP], r[DOWN], r[UP])); + */ + } } } return r; diff --git a/lily/constrained-breaking.cc b/lily/constrained-breaking.cc index e3b07fab3b..4d9c5795ee 100644 --- a/lily/constrained-breaking.cc +++ b/lily/constrained-breaking.cc @@ -156,7 +156,6 @@ Constrained_breaking::resize (vsize systems) all_ = pscore_->root_system ()->columns (); lines_.resize (breaks_.size (), breaks_.size (), Line_details ()); vector<Real> forces = get_line_forces (all_, - breaks_, other_lines.length (), other_lines.length () - first_line.length (), ragged_right); @@ -172,6 +171,12 @@ Constrained_breaking::resize (vsize systems) bool ragged = ragged_right || (last && ragged_last); Line_details &line = lines_.at (j, i); + line.force_ = forces[i*breaks_.size () + j]; + if (ragged && last && !isinf (line.force_)) + line.force_ = 0; + if (isinf (line.force_)) + break; + Grob *c = all_[breaks_[j]]; line.break_penalty_ = robust_scm2double (c->get_property ("line-break-penalty"), 0); line.page_penalty_ = robust_scm2double (c->get_property ("page-break-penalty"), 0); @@ -181,15 +186,10 @@ Constrained_breaking::resize (vsize systems) line.turn_permission_ = c->get_property ("page-turn-permission"); max_ext = max (max_ext, extent.length ()); - line.force_ = forces[i*breaks_.size () + j]; line.extent_ = extent; line.padding_ = padding; line.space_ = space; line.inverse_hooke_ = 1; - if (ragged && line.force_ < 0) - line.force_ = infinity_f; - if (isinf (line.force_)) - break; } } @@ -374,6 +374,9 @@ Constrained_breaking::Constrained_breaking (vector<vsize> const &start) Real Constrained_breaking::combine_demerits (Real force, Real prev_force) { + if (to_boolean (pscore_->layout ()->c_variable ("ragged-right"))) + return force * force; + return force * force + (prev_force - force) * (prev_force - force); } diff --git a/lily/gourlay-breaking.cc b/lily/gourlay-breaking.cc deleted file mode 100644 index f5e29ad18d..0000000000 --- a/lily/gourlay-breaking.cc +++ /dev/null @@ -1,265 +0,0 @@ -/* - gourlay-breaking.cc -- implement Gourlay_breaking - - source file of the GNU LilyPond music typesetter - - (c) 1997--2006 Han-Wen Nienhuys <hanwen@xs4all.nl> -*/ - -#include "gourlay-breaking.hh" - -#include <cmath> // rint -#include <cstdio> -using namespace std; - -#include "international.hh" -#include "main.hh" -#include "output-def.hh" -#include "paper-column.hh" -#include "paper-score.hh" -#include "simple-spacer.hh" -#include "system.hh" -#include "warn.hh" - -/// How often to print operator pacification marks? -const int HAPPY_DOTS = 3; - -/** - Helper to trace back an optimal path -*/ -struct Break_node -{ - /** this was the previous. If negative, this break should not be - considered: this path has infinite energy - - */ - int prev_break_; - /** - Which system number so far? - */ - int line_; - - Real demerits_; - Column_x_positions line_config_; - - Break_node () - { - prev_break_ = -1; - line_ = 0; - demerits_ = 0; - } - - void print () const - { - printf ("prev break %d, line %d, demerits %f\n", - prev_break_, line_, demerits_); - } -}; - -void -print_break_nodes (vector<Break_node> const &arr) -{ - for (vsize i = 0; i < arr.size (); i++) - { - printf ("node %d: ", i); - arr[i].print (); - } -} - -/** - This algorithms is adapted from the OSU Tech report on breaking lines. - - this function is longish, but not very complicated. - - TODO: should rewrite. See the function in scm/page-layout.scm for - inspiration. -*/ -vector<Column_x_positions> -Gourlay_breaking::solve () -{ - vector<Break_node> optimal_paths; - vector<Grob*> all - = pscore_->root_system ()->columns (); - - vector<vsize> breaks = pscore_->find_break_indices (); - - Break_node first_node; - optimal_paths.push_back (first_node); - - bool ragged_right = to_boolean (pscore_->layout ()->c_variable ("ragged-right")); - bool ragged_last = to_boolean (pscore_->layout ()->c_variable ("ragged-last")); - - Real worst_force = 0.0; - for (vsize break_idx = 1; break_idx < breaks.size (); break_idx++) - { - /* - start with a short line, add measures. At some point - the line becomes infeasible. Then we don't try to add more - */ - int minimal_start_idx = -1; - Column_x_positions minimal_sol; - Column_x_positions backup_sol; - - Real minimal_demerits = infinity_f; - - for (vsize start_idx = break_idx; start_idx--;) - { - vector<Grob*> line (all.begin () + breaks[start_idx], - all.begin () + breaks[break_idx] + 1); - - Interval line_dims - = line_dimensions_int (pscore_->layout (), optimal_paths[start_idx].line_); - bool last_line = break_idx == breaks.size () - 1; - bool ragged = ragged_right || (last_line && ragged_last); - - Column_x_positions cp = get_line_configuration (line, line_dims[RIGHT] - line_dims[LEFT], - line_dims[LEFT], ragged); - - if (ragged && last_line) - cp.force_ = min (cp.force_, 0.0); - - if (fabs (cp.force_) > worst_force) - worst_force = fabs (cp.force_); - - /* - We remember this solution as a "should always work - solution", in case everything fucks up. */ - if (start_idx == break_idx - 1) - backup_sol = cp; - - Real this_demerits; - - if (optimal_paths[start_idx].demerits_ >= infinity_f) - this_demerits = infinity_f; - else - this_demerits = combine_demerits (optimal_paths[start_idx].line_config_, cp) - + optimal_paths[start_idx].demerits_; - - if (this_demerits < minimal_demerits) - { - minimal_start_idx = start_idx; - minimal_sol = cp; - minimal_demerits = this_demerits; - } - - /* - we couldn't satisfy the constraints, this won't get better - if we add more columns, so we get on with the next one - */ - if (!cp.satisfies_constraints_) - break; - } - - Break_node bnod; - if (minimal_start_idx < 0) - { - bnod.demerits_ = infinity_f; - bnod.line_config_ = backup_sol; - bnod.prev_break_ = break_idx - 1; - } - else - { - bnod.prev_break_ = minimal_start_idx; - bnod.demerits_ = minimal_demerits; - bnod.line_config_ = minimal_sol; - } - bnod.line_ = optimal_paths[bnod.prev_break_].line_ + 1; - optimal_paths.push_back (bnod); - - if (! (break_idx % HAPPY_DOTS)) - progress_indication (string ("[") + to_string (break_idx) + "]"); - } - - /* do the last one */ - if (breaks.size () % HAPPY_DOTS) - progress_indication (string ("[") + to_string (breaks.size ()) + "]"); - - progress_indication ("\n"); - - vector<int> final_breaks; - vector<Column_x_positions> lines; - - /* skip 0-th element, since it is a "dummy" elt*/ - for (vsize i = optimal_paths.size () - 1; i > 0;) - { - final_breaks.push_back (i); - vsize prev = optimal_paths[i].prev_break_; - assert (i > prev); - i = prev; - } - - if (be_verbose_global) - { - message (_f ("Optimal demerits: %f", - optimal_paths.back ().demerits_) + "\n"); - } - - if (optimal_paths.back ().demerits_ >= infinity_f) - warning (_ ("no feasible line breaking found")); - - for (vsize i = final_breaks.size (); i--;) - { - Column_x_positions cp (optimal_paths[final_breaks[i]].line_config_); - - lines.push_back (cp); - if (!cp.satisfies_constraints_) - warning (_ ("can't find line breaking that satisfies constraints")); - } - return lines; -} - -Gourlay_breaking::Gourlay_breaking () -{ -} - -/* - TODO: uniformity parameter to control rel. importance of spacing differences. - - TODO: - - mixing break penalties and constraint-failing solutions is confusing. -*/ -Real -Gourlay_breaking::combine_demerits (Column_x_positions const &prev, - Column_x_positions const &this_one) const -{ - Real break_penalties = 0.0; - Grob *pc = this_one.cols_.back (); - if (pc->original ()) - { - SCM pen = pc->get_property ("line-break-penalty"); - if (scm_is_number (pen) && fabs (scm_to_double (pen)) < 10000) - break_penalties += scm_to_double (pen); - } - - /* - Q: do we want globally non-cramped lines, or locally equally - cramped lines? - - There used to be an example file input/test/uniform-breaking to - demonstrate problems with this approach. When music is gradually - becoming denser, the uniformity requirement makes lines go from - cramped to even more cramped (because going from cramped - 3meas/line to relatively loose 2meas/line is such a big step. - - */ - - Real demerit = abs (this_one.force_) + abs (prev.force_ - this_one.force_) - + break_penalties; - - if (!this_one.satisfies_constraints_) - { - /* - If it doesn't satisfy constraints, we make this one - really unattractive. - - add 20000 to the demerits, so that a break penalty - of -10000 won't change the result */ - demerit = max ((demerit + 20000), 2000.0); - - demerit *= 10; - } - - return demerit; -} - diff --git a/lily/grob.cc b/lily/grob.cc index 4b44231e61..72b46376c6 100644 --- a/lily/grob.cc +++ b/lily/grob.cc @@ -302,10 +302,14 @@ Grob::pure_relative_y_coordinate (Grob const *refp, int start, int end) dim_cache_[Y_AXIS].offset_ = 0; } - /* we simulate positioning-done if we are the child of a VerticalAlignment */ + /* we simulate positioning-done if we are the child of a VerticalAlignment, + but only if we don't have a cached offset. If we do have a cached offset, + it probably means that the Alignment was fixed and it has already been + calculated. + */ Grob *p = get_parent (Y_AXIS); Real trans = 0; - if (Align_interface::has_interface (p)) + if (Align_interface::has_interface (p) && !dim_cache_[Y_AXIS].offset_) trans = Align_interface::get_pure_child_y_translation (p, this, start, end); return off + trans diff --git a/lily/include/gourlay-breaking.hh b/lily/include/gourlay-breaking.hh deleted file mode 100644 index 34a92f8dea..0000000000 --- a/lily/include/gourlay-breaking.hh +++ /dev/null @@ -1,23 +0,0 @@ -/* - gourlay-breaking.hh -- declare Gourlay_breaking - - source file of the GNU LilyPond music typesetter - - (c) 1997--2006 Han-Wen Nienhuys <hanwen@xs4all.nl> -*/ - -#ifndef GOURLAY_BREAKING_HH -#define GOURLAY_BREAKING_HH - -#include "break-algorithm.hh" - -/** - A dynamic programming solution to breaking scores into lines -*/ -struct Gourlay_breaking : public Break_algorithm -{ - vector<Column_x_positions> solve (); - Gourlay_breaking (); - Real combine_demerits (Column_x_positions const &, Column_x_positions const &) const; -}; -#endif // GOURLAY_BREAKING_HH diff --git a/lily/include/lily-guile.hh b/lily/include/lily-guile.hh index 23b3c64785..a0ac54bda7 100644 --- a/lily/include/lily-guile.hh +++ b/lily/include/lily-guile.hh @@ -117,9 +117,7 @@ inline SCM ly_append4 (SCM x1, SCM x2, SCM x3, SCM x4) /* display and print newline. */ -extern "C" { - void ly_display_scm (SCM s); -} +void ly_display_scm (void *s); void read_lily_scm_file (string); void ly_c_init_guile (); diff --git a/lily/include/simple-spacer.hh b/lily/include/simple-spacer.hh index 39d9a3f853..758cd65b32 100644 --- a/lily/include/simple-spacer.hh +++ b/lily/include/simple-spacer.hh @@ -67,7 +67,6 @@ private: /* returns a vector of dimensions breaks.size () * breaks.size () */ vector<Real> get_line_forces (vector<Grob*> const &columns, - vector<vsize> breaks, Real line_len, Real indent, bool ragged); diff --git a/lily/include/slur.hh b/lily/include/slur.hh index 2c797239ce..f0213372bc 100644 --- a/lily/include/slur.hh +++ b/lily/include/slur.hh @@ -23,6 +23,7 @@ public: DECLARE_SCHEME_CALLBACK (print, (SCM)); DECLARE_SCHEME_CALLBACK (calc_control_points, (SCM)); DECLARE_SCHEME_CALLBACK (calc_direction, (SCM)); + DECLARE_SCHEME_CALLBACK (pure_height, (SCM, SCM, SCM)); DECLARE_SCHEME_CALLBACK (height, (SCM)); DECLARE_SCHEME_CALLBACK (outside_slur_callback, (SCM, SCM)); static bool has_interface (Grob *); diff --git a/lily/lily-guile.cc b/lily/lily-guile.cc index 971063e54e..064ed54fab 100644 --- a/lily/lily-guile.cc +++ b/lily/lily-guile.cc @@ -114,15 +114,12 @@ gulp_file_to_string (string fn, bool must_exist, int size) return result; } -extern "C" { - // maybe gdb 5.0 becomes quicker if it doesn't do fancy C++ typing? - void - ly_display_scm (SCM s) - { - scm_display (s, scm_current_output_port ()); - scm_newline (scm_current_output_port ()); - } -}; +void +ly_display_scm (void *s) +{ + scm_display ((SCM)s, scm_current_output_port ()); + scm_newline (scm_current_output_port ()); +} string ly_scm2string (SCM str) diff --git a/lily/optimal-page-breaking.cc b/lily/optimal-page-breaking.cc index 6f3fcc5683..03d72629a0 100644 --- a/lily/optimal-page-breaking.cc +++ b/lily/optimal-page-breaking.cc @@ -39,8 +39,8 @@ Optimal_page_breaking::try_page_spacing (Line_division const &line_count) Real page_h = page_height (1, false); // FIXME SCM force_sym = ly_symbol2scm ("blank-last-page-force"); Real blank_force = robust_scm2double (book_->paper_->lookup_variable (force_sym), 0); - bool ragged_all = book_->paper_->c_variable ("ragged-bottom"); - bool ragged_last = book_->paper_->c_variable ("ragged-last-bottom"); + bool ragged_all = to_boolean (book_->paper_->c_variable ("ragged-bottom")); + bool ragged_last = to_boolean (book_->paper_->c_variable ("ragged-last-bottom")); Spacing_result ret = space_systems_on_best_pages (lines, page_h, blank_force, @@ -91,13 +91,13 @@ Optimal_page_breaking::solve () { Spacing_result cur = try_page_spacing (div[d]); cur_page_count = cur.systems_per_page_.size (); - if (cur.demerits_ < best.demerits_) + if (cur.demerits_ < best.demerits_ || isinf (best.demerits_)) { best = cur; best_division = div[d]; } - if (cur.demerits_ < this_best_demerits) + if (cur.demerits_ < this_best_demerits || isinf (best.demerits_)) { this_best_demerits = cur.demerits_; lower_bound = div[d]; @@ -110,7 +110,7 @@ Optimal_page_breaking::solve () all_lines_stretched = false; if (all_lines_stretched) - max_page_count = cur_page_count + 1; + max_page_count = min (max_page_count, cur_page_count + 1); } } diff --git a/lily/page-breaking.cc b/lily/page-breaking.cc index 1a32d7e7f1..b1fd686e2b 100644 --- a/lily/page-breaking.cc +++ b/lily/page-breaking.cc @@ -175,9 +175,17 @@ Page_breaking::breakpoint_property (vsize breakpoint, char const *str) SCM Page_breaking::make_pages (vector<vsize> lines_per_page, SCM systems) { - SCM module = scm_c_resolve_module ("scm layout-page-layout"); - SCM make_page = scm_c_module_lookup (module, "make-page-from-systems"); + SCM layout_module = scm_c_resolve_module ("scm layout-page-layout"); + SCM dump_module = scm_c_resolve_module ("scm layout-page-dump"); + SCM page_module = scm_c_resolve_module ("scm page"); + + SCM make_page = scm_c_module_lookup (layout_module, "make-page-from-systems"); + SCM write_page_breaks = scm_c_module_lookup (dump_module, "write-page-breaks"); + SCM page_stencil = scm_c_module_lookup (page_module, "page-stencil"); make_page = scm_variable_ref (make_page); + write_page_breaks = scm_variable_ref (write_page_breaks); + page_stencil = scm_variable_ref (page_stencil); + SCM book = book_->self_scm (); bool ragged_all = to_boolean (book_->paper_->c_variable ("ragged-bottom")); bool ragged_last = to_boolean (book_->paper_->c_variable ("ragged-last-bottom")); @@ -193,10 +201,15 @@ Page_breaking::make_pages (vector<vsize> lines_per_page, SCM systems) SCM page = scm_apply_0 (make_page, scm_list_n (book, lines, page_num, ragged, last, SCM_UNDEFINED)); + scm_apply_1 (page_stencil, page, SCM_EOL); ret = scm_cons (page, ret); systems = scm_list_tail (systems, line_count); } - return scm_reverse (ret); + ret = scm_reverse (ret); + + if (to_boolean (book_->paper_->c_variable ("write-page-layout"))) + scm_apply_1 (write_page_breaks, ret, SCM_EOL); + return ret; } /* The page-turn-page-breaker needs to have a line-breaker between any two @@ -214,7 +227,16 @@ Page_breaking::create_system_list () for (SCM s = specs; s != SCM_EOL; s = scm_cdr (s)) { if (Paper_score *ps = dynamic_cast<Paper_score*> (unsmob_music_output (scm_car (s)))) - all_.push_back (System_spec (ps)); + { + SCM system_count = ps->layout ()->c_variable ("system-count"); + + if (scm_is_number (system_count)) + s = scm_append (scm_list_3 (scm_list_1 (scm_car (s)), + scm_vector_to_list (ps->get_paper_systems ()), + scm_cdr (s))); + else + all_.push_back (System_spec (ps)); + } else { Prob *pb = unsmob_prob (scm_car (s)); diff --git a/lily/page-spacing.cc b/lily/page-spacing.cc index fc6c5b3ddf..4d11f0c865 100644 --- a/lily/page-spacing.cc +++ b/lily/page-spacing.cc @@ -8,7 +8,9 @@ */ #include "page-spacing.hh" + #include "matrix.hh" +#include "warn.hh" /* A much simplified rods-and-springs problem. @@ -249,10 +251,10 @@ Page_spacer::solve (vsize page_count) vsize system = lines_.size () - 1; if (isinf (state_.at (system, page_count-1).demerits_)) - return Spacing_result (); /* bad number of pages */ - - if (isinf (state_.at (system, page_count-1).demerits_)) - return Spacing_result (); /* bad number of pages */ + { + programming_error ("tried to space systems on a bad number of pages"); + return Spacing_result (); /* bad number of pages */ + } ret.penalty_ = state_.at (system, page_count-1).penalty_ + lines_.back ().page_penalty_ + lines_.back ().turn_penalty_; @@ -311,6 +313,10 @@ Page_spacer::calc_subproblem (vsize page, vsize line) if (line == lines_.size () - 1 && ragged_last_ && space.force_ > 0) space.force_ = 0; + /* we may have to deal with single lines that are taller than a page */ + if (isinf (space.force_) && page_start == line) + space.force_ = -200000; + Real dem = fabs (space.force_) + (prev ? prev->demerits_ : 0); Real penalty = 0; if (page_start > 0) @@ -318,7 +324,7 @@ Page_spacer::calc_subproblem (vsize page, vsize line) + (page % 2 == 0) ? lines_[page_start-1].turn_penalty_ : 0; dem += penalty; - if (dem < cur.demerits_) + if (dem < cur.demerits_ || page_start == line) { cur.demerits_ = dem; cur.force_ = space.force_; @@ -343,15 +349,15 @@ min_page_count (vector<Line_details> const &lines, Real page_height, bool ragged for (vsize i = 0; i < lines.size (); i++) { Real ext_len = lines[i].extent_.length (); - Real next_height = cur_rod_height - + (ragged ? max (ext_len, lines[i].space_) : ext_len) - + ((i > 0 && cur_rod_height > 0) ? lines[i-1].padding_: 0); + Real next_height = cur_rod_height + ext_len + + (ragged ? lines[i].space_ : 0) + + ((cur_rod_height > 0) ? lines[i-1].padding_: 0); if ((next_height > page_height && cur_rod_height > 0) || (i > 0 && lines[i-1].page_permission_ == ly_symbol2scm ("force"))) { ret++; - cur_rod_height = ragged ? max (ext_len, lines[i].space_) : ext_len; + cur_rod_height = ext_len + (ragged ? lines[i].space_ : 0); } else cur_rod_height = next_height; diff --git a/lily/page-turn-page-breaking.cc b/lily/page-turn-page-breaking.cc index 6171adca4d..7db8831905 100644 --- a/lily/page-turn-page-breaking.cc +++ b/lily/page-turn-page-breaking.cc @@ -149,7 +149,7 @@ Page_turn_page_breaking::calc_subproblem (vsize ending_breakpoint) if (cur.page_count_ > 2 && (start < end - 1 || (!isinf (this_start_best.demerits_) && cur.page_count_ + cur.page_count_ % 2 - > this_start_best.page_count_ + this_start_best.page_count_ % 2))) + > this_start_best.page_count_ + this_start_best.page_count_ % 2))) { ok_page = false; break; @@ -175,8 +175,9 @@ Page_turn_page_breaking::calc_subproblem (vsize ending_breakpoint) assert (!isinf (best.demerits_) && start < end - 1); break; } + if (this_start_best.demerits_ < best.demerits_) - best = this_start_best; + best = this_start_best; } state_.push_back (best); } diff --git a/lily/paper-score.cc b/lily/paper-score.cc index ffad13c38b..e7a5f51247 100644 --- a/lily/paper-score.cc +++ b/lily/paper-score.cc @@ -10,7 +10,6 @@ #include "all-font-metrics.hh" #include "book.hh" -#include "gourlay-breaking.hh" #include "international.hh" #include "main.hh" #include "misc.hh" @@ -100,24 +99,17 @@ Paper_score::get_columns () const vector<Column_x_positions> Paper_score::calc_breaking () { - Break_algorithm *algorithm = 0; + Constrained_breaking algorithm; vector<Column_x_positions> sol; message (_ ("Calculating line breaks...") + " "); int system_count = robust_scm2int (layout ()->c_variable ("system-count"), 0); if (system_count) - { - Constrained_breaking *b = new Constrained_breaking; - b->resize (system_count); - algorithm = b; - } - else - algorithm = new Gourlay_breaking; + algorithm.resize (system_count); - algorithm->set_pscore (this); - sol = algorithm->solve (); - delete algorithm; + algorithm.set_pscore (this); + sol = algorithm.solve (); return sol; } diff --git a/lily/simple-spacer.cc b/lily/simple-spacer.cc index 3b3eaed3ba..560dfecacd 100644 --- a/lily/simple-spacer.cc +++ b/lily/simple-spacer.cc @@ -358,20 +358,6 @@ next_spaceable_column (vector<Grob*> const &list, vsize starting) return 0; } -/* this only returns non-NULL if the line-ending column is the next - spaceable-or-breakable column */ -static Grob* -next_line_ending_column (vector<Grob*> const &list, vsize starting) -{ - vsize i = starting + 1; - for (; i < list.size () - && is_loose (list[i]) - && !Paper_column::is_breakable (list[i]); - i++) - ; - return dynamic_cast<Item*> (list[i])->find_prebroken_piece (LEFT); -} - static void get_column_spring (Grob *this_col, Grob *next_col, Real *ideal, Real *inv_hooke) { @@ -406,7 +392,7 @@ get_column_description (vector<Grob*> const &cols, vsize col_index, bool line_st Grob *next_col = next_spaceable_column (cols, col_index); if (next_col) get_column_spring (col, next_col, &description.ideal_, &description.inverse_hooke_); - Grob *end_col = next_line_ending_column (cols, col_index); + Grob *end_col = dynamic_cast<Item*> (cols[col_index+1])->find_prebroken_piece (LEFT); if (end_col) get_column_spring (col, end_col, &description.end_ideal_, &description.end_inverse_hooke_); @@ -430,32 +416,35 @@ get_column_description (vector<Grob*> const &cols, vsize col_index, bool line_st } vector<Real> -get_line_forces (vector<Grob*> const &icols, vector<vsize> breaks, +get_line_forces (vector<Grob*> const &columns, Real line_len, Real indent, bool ragged) { + vector<vsize> breaks; vector<Real> force; - force.resize (breaks.size () * breaks.size (), infinity_f); - + vector<Grob*> non_loose; vector<Column_description> cols; - vsize b = 1; SCM force_break = ly_symbol2scm ("force"); + for (vsize i = 0; i < columns.size (); i++) + if (!is_loose (columns[i]) || Paper_column::is_breakable (columns[i])) + non_loose.push_back (columns[i]); + + breaks.clear (); + breaks.push_back (0); cols.push_back (Column_description ()); - for (vsize i = 1; i < icols.size () - 1; i++) + for (vsize i = 1; i < non_loose.size () - 1; i++) { - if (b < breaks.size () && breaks[b] == i) - { - breaks[b] = cols.size (); - b++; - } - if (!is_loose (icols[i])) - cols.push_back (get_column_description (icols, i, false)); + if (Paper_column::is_breakable (non_loose[i])) + breaks.push_back (cols.size ()); + + cols.push_back (get_column_description (non_loose, i, false)); } - breaks.back () = cols.size (); + breaks.push_back (cols.size ()); + force.resize (breaks.size () * breaks.size (), infinity_f); for (vsize b = 0; b < breaks.size () - 1; b++) { - cols[breaks[b]] = get_column_description (icols, breaks[b], true); + cols[breaks[b]] = get_column_description (non_loose, breaks[b], true); vsize st = breaks[b]; for (vsize c = b+1; c < breaks.size (); c++) @@ -465,7 +454,7 @@ get_line_forces (vector<Grob*> const &icols, vector<vsize> breaks, for (vsize i = breaks[b]; i < end - 1; i++) spacer.add_spring (cols[i].ideal_, cols[i].inverse_hooke_); - spacer.add_spring (cols[end-1].end_ideal_, cols[end-1].inverse_hooke_); + spacer.add_spring (cols[end-1].end_ideal_, cols[end-1].end_inverse_hooke_); for (vsize i = breaks[b]; i < end; i++) @@ -490,13 +479,16 @@ get_line_forces (vector<Grob*> const &icols, vector<vsize> breaks, breaks, so compression penalties can result in scores (eg. wtk-fugue) blowing up to too many pages. */ Real f = spacer.force (); - force[b * breaks.size () + c] = f - (f < 0 ? f*f*6 : 0); + force[b * breaks.size () + c] = f - (f < 0 ? f*f*f*f*4 : 0); if (end < cols.size () && cols[end].break_permission_ == force_break) break; if (!spacer.fits ()) { - force[b * breaks.size () + c] = infinity_f; + if (c == b + 1) + force[b * breaks.size () + c] = -200000; + else + force[b * breaks.size () + c] = infinity_f; break; } } @@ -535,6 +527,7 @@ get_line_configuration (vector<Grob*> const &columns, { for (vsize r = 0; r < cols[i].rods_.size (); r++) spacer.add_rod (i, cols[i].rods_[r].r_, cols[i].rods_[r].dist_); + if (!cols[i].keep_inside_line_.is_empty ()) { spacer.add_rod (i, cols.size (), cols[i].keep_inside_line_[RIGHT]); diff --git a/lily/slur.cc b/lily/slur.cc index 557200b239..0c68a6137e 100644 --- a/lily/slur.cc +++ b/lily/slur.cc @@ -57,6 +57,35 @@ Slur::calc_direction (SCM smob) return scm_from_int (d); } +MAKE_SCHEME_CALLBACK (Slur, pure_height, 3); +SCM +Slur::pure_height (SCM smob, SCM start_scm, SCM end_scm) +{ + Grob *me = unsmob_grob (smob); + int start = scm_to_int (start_scm); + int end = scm_to_int (end_scm); + Real height = robust_scm2double (me->get_property ("height-limit"), 2.0); + + extract_grob_set (me, "note-columns", encompasses); + Interval ret; + + Grob *parent = me->get_parent (Y_AXIS); + if (common_refpoint_of_array (encompasses, me, Y_AXIS) != parent) + /* this could happen if, for example, we are a cross-staff slur. + in this case, we want to be ignored */ + return ly_interval2scm (Interval ()); + + for (vsize i = 0; i < encompasses.size (); i++) + { + Interval d = encompasses[i]->pure_height (parent, start, end); + if (!d.is_empty ()) + ret.unite (d); + } + + ret.widen (height * 0.5); + return ly_interval2scm (ret); +} + MAKE_SCHEME_CALLBACK (Slur, height, 1); SCM Slur::height (SCM smob) diff --git a/lily/system.cc b/lily/system.cc index 2fba41a49e..54562cdc04 100644 --- a/lily/system.cc +++ b/lily/system.cc @@ -397,14 +397,12 @@ System::get_paper_system () Prob *pl = make_paper_system (prop_init); paper_system_set_stencil (pl, sys_stencil); - /* backwards-compatibility hack for the old page-breaker */ - SCM turn_perm = left_bound->get_property ("page-break-permission"); - if (!scm_is_symbol (turn_perm)) - pl->set_property ("penalty", scm_from_double (10001.0)); - else if (turn_perm == ly_symbol2scm ("force")) - pl->set_property ("penalty", scm_from_double (-10001.0)); - else - pl->set_property ("penalty", scm_from_double (0.0)); + /* information that the page breaker might need */ + Grob *right_bound = this->get_bound (RIGHT); + pl->set_property ("page-break-permission", right_bound->get_property ("page-break-permission")); + pl->set_property ("page-turn-permission", right_bound->get_property ("page-turn-permission")); + pl->set_property ("page-break-penalty", right_bound->get_property ("page-break-penalty")); + pl->set_property ("page-turn-penalty", right_bound->get_property ("page-turn-penalty")); if (!scm_is_pair (pl->get_property ("refpoint-Y-extent"))) { diff --git a/ly/paper-defaults.ly b/ly/paper-defaults.ly index 9fae0cabd5..2e265c7ab1 100644 --- a/ly/paper-defaults.ly +++ b/ly/paper-defaults.ly @@ -96,7 +96,7 @@ (baseline-skip . 3) (word-space . 0.6))) - #(define page-breaking optimal-page-breaks) + #(define page-breaking ly:optimal-breaking) % #(define page-music-height default-page-music-height ) % #(define page-make-stencil default-page-make-stencil ) diff --git a/scm/define-grobs.scm b/scm/define-grobs.scm index bc3aee5e93..07971e2f91 100644 --- a/scm/define-grobs.scm +++ b/scm/define-grobs.scm @@ -1983,7 +1983,8 @@ (list `(,ly:note-head::print . '()) `(,ly:clef::print . '()) - `(,ly:text-interface::print . '()))) + `(,ly:text-interface::print . '()) + `(,ly:script-interface::print . '()))) ;; ly:grob::stencil-extent is safe iff the print callback is safe too (define (pure-stencil-height grob start stop) @@ -2004,7 +2005,8 @@ `(,ly:grob::stencil-height . ,pure-stencil-height) `(,ly:side-position-interface::y-aligned-side . ,ly:side-position-interface::pure-y-aligned-side) `(,ly:axis-group-interface::height . ,ly:axis-group-interface::pure-height) - `(,ly:hara-kiri-group-spanner::y-extent . ,ly:hara-kiri-group-spanner::pure-height))) + `(,ly:hara-kiri-group-spanner::y-extent . ,ly:hara-kiri-group-spanner::pure-height) + `(,ly:slur::height . ,ly:slur::pure-height))) (define pure-Y-offsets (list @@ -2017,6 +2019,7 @@ (define-public (pure-relevant grob) (let ((extent-callback (ly:grob-property-data grob 'Y-extent))) (or + (pair? extent-callback) (pair? (assq extent-callback pure-Y-extents)) (and (pair? (assq extent-callback Y-extent-conversions)) diff --git a/scm/layout-page-layout.scm b/scm/layout-page-layout.scm index 215b5003d0..fabe89f97b 100644 --- a/scm/layout-page-layout.scm +++ b/scm/layout-page-layout.scm @@ -46,20 +46,20 @@ (ly:output-def-lookup layout 'between-system-padding))) -(define (line-minimum-distance line next-line layout) +(define (line-minimum-distance line next-line layout ignore-padding) "Minimum distance between `line' reference position and `next-line' reference position. If next-line is #f, return #f." (and next-line (max 0 (- (+ (interval-end (paper-system-extent next-line Y)) - (line-next-padding line next-line layout)) + (if ignore-padding 0 (line-next-padding line next-line layout))) (interval-start (paper-system-extent line Y)))))) -(define (line-ideal-distance line next-line layout) +(define (line-ideal-distance line next-line layout ignore-padding) "Ideal distance between `line' reference position and `next-line' reference position. If next-line is #f, return #f." (and next-line (+ (max 0 (- (+ (interval-end (paper-system-staff-extents next-line)) - (line-next-padding line next-line layout)) + (if ignore-padding 0 (line-next-padding line next-line layout))) (interval-start (paper-system-staff-extents line)))) (line-next-space line next-line layout)))) @@ -69,24 +69,24 @@ (interval-end (paper-system-staff-extents line))) (interval-end (paper-system-extent line Y)))) -(define (line-ideal-relative-position line prev-line layout) +(define (line-ideal-relative-position line prev-line layout ignore-padding) "Return ideal position of `line', relative to `prev-line' position. `prev-line' can be #f, meaning that `line' is the first line." (if (not prev-line) ;; first line on page (first-line-position line layout) ;; not the first line on page - (max (line-minimum-distance prev-line line layout) - (line-ideal-distance prev-line line layout)))) + (max (line-minimum-distance prev-line line layout ignore-padding) + (line-ideal-distance prev-line line layout ignore-padding)))) -(define (line-minimum-relative-position line prev-line layout) +(define (line-minimum-relative-position line prev-line layout ignore-padding) "Return position of `line', relative to `prev-line' position. `prev-line' can be #f, meaning that `line' is the first line." (if (not prev-line) ;; first line on page (first-line-position line layout) ;; not the first line on page - (line-minimum-distance prev-line line layout))) + (line-minimum-distance prev-line line layout ignore-padding))) ;;; ;;; Page breaking functions @@ -124,7 +124,7 @@ is what have collected so far, and has ascending page numbers." inter-system-space)) user))) -(define (space-systems page-height lines ragged? paper) +(define (space-systems page-height lines ragged paper ignore-padding) "Compute lines positions on page: return force and line positions as a pair. force is #f if lines do not fit on page." (let* ((empty-stencil (ly:make-stencil '() '(0 . 0) '(0 . 0))) @@ -134,7 +134,7 @@ is what have collected so far, and has ascending page numbers." (list empty-prob) '()))) (springs (map (lambda (prev-line line) - (list (line-ideal-distance prev-line line paper) + (list (line-ideal-distance prev-line line paper ignore-padding) (/ 1.0 (line-next-space prev-line line paper)))) lines cdr-lines)) @@ -142,7 +142,7 @@ is what have collected so far, and has ascending page numbers." (lambda (prev-line line) (set! i (1+ i)) (list i (1+ i) - (line-minimum-distance prev-line line paper)))) + (line-minimum-distance prev-line line paper ignore-padding)))) lines cdr-lines)) (last-line (car (last-pair lines))) @@ -154,27 +154,31 @@ is what have collected so far, and has ascending page numbers." (- (interval-start (paper-system-extent last-line Y))))) (space-result - (ly:solve-spring-rod-problem springs rods space-to-fill ragged?))) + (ly:solve-spring-rod-problem springs rods space-to-fill ragged))) (cons (car space-result) (map (lambda (y) (+ y topskip)) (cdr space-result))))) -(define (make-page-from-systems paper-book lines page-number ragged? last?) +(define (make-page-from-systems paper-book lines page-number ragged last) (let* ((page (make-page paper-book 'lines lines 'page-number page-number - 'is-last last?)) + 'is-last last)) (height (page-printable-height page)) (posns (if (> (length lines) 0) - (cdr (space-systems height lines ragged? (ly:paper-book-paper paper-book))) + (let* ((paper (ly:paper-book-paper paper-book)) + (spacing (space-systems height lines ragged paper #f))) + (if (inf? (car spacing)) + (cdr (space-systems height lines ragged paper #t)) + (cdr spacing))) '()))) (page-set-property! page 'configuration posns) page)) -(define (walk-paths done-lines best-paths current-lines last? current-best +(define (walk-paths done-lines best-paths current-lines last current-best paper-book page-alist) "Return the best optimal-page-break-node that contains CURRENT-LINES. DONE-LINES.reversed ++ CURRENT-LINES is a consecutive @@ -185,18 +189,18 @@ CURRENT-BEST is the best result sofar, or #f." (let* ((paper (ly:paper-book-paper paper-book)) (this-page (make-page paper-book - 'is-last last? + 'is-last last 'page-number (if (null? best-paths) (ly:output-def-lookup paper 'first-page-number) (1+ (page-page-number (first best-paths)))))) - (ragged-all? (eq? #t (ly:output-def-lookup paper 'ragged-bottom))) - (ragged-last? (eq? #t (ly:output-def-lookup paper 'ragged-last-bottom))) - (ragged? (or ragged-all? (and ragged-last? last?))) + (ragged-all (eq? #t (ly:output-def-lookup paper 'ragged-bottom))) + (ragged-last (eq? #t (ly:output-def-lookup paper 'ragged-last-bottom))) + (ragged (or ragged-all (and ragged-last last))) (height (page-printable-height this-page)) - (vertical-spacing (space-systems height current-lines ragged? paper)) + (vertical-spacing (space-systems height current-lines ragged paper #f)) (satisfied-constraints (car vertical-spacing)) (force (if satisfied-constraints - (if (and last? ragged-last?) + (if (and last ragged-last) 0.0 satisfied-constraints) 10000)) @@ -234,7 +238,7 @@ CURRENT-BEST is the best result sofar, or #f." (list "\nuser pen " user-penalty "\nsatisfied-constraints" satisfied-constraints - "\nlast? " last? "ragged?" ragged? + "\nlast? " last "ragged?" ragged "\nis-better " is-better " total-penalty " total-penalty "\n" "\nconfig " positions "\nforce " force @@ -250,7 +254,7 @@ CURRENT-BEST is the best result sofar, or #f." satisfied-constraints) (walk-paths (cdr done-lines) (cdr best-paths) (cons (car done-lines) current-lines) - last? new-best + last new-best paper-book page-alist) new-best))) @@ -262,8 +266,8 @@ DONE." (if (null? todo) (car best-paths) (let* ((this-line (car todo)) - (last? (null? (cdr todo))) - (next (walk-paths done best-paths (list this-line) last? #f + (last (null? (cdr todo))) + (next (walk-paths done best-paths (list this-line) last #f paper-book page-alist))) (walk-lines (cons this-line done) (cons next best-paths) |