2 optimal-page-breaking.cc -- implement a page-breaker that
3 will break pages in such a way that both horizontal and
4 vertical spacing will be acceptable
6 source file of the GNU LilyPond music typesetter
8 (c) 2006--2007 Joe Neeman <joeneeman@gmail.com>
11 #include "optimal-page-breaking.hh"
12 #include "output-def.hh"
13 #include "page-spacing.hh"
14 #include "paper-book.hh"
15 #include "paper-score.hh"
22 (void) g; /* shutup warning */
26 Optimal_page_breaking::Optimal_page_breaking (Paper_book *pb)
27 : Page_breaking (pb, is_break)
31 Optimal_page_breaking::~Optimal_page_breaking ()
36 Optimal_page_breaking::try_page_spacing (Line_division const &line_count)
38 vector<Line_details> lines = line_details (0, breaks_.size () - 1, line_count);
39 Real page_h = page_height (1, false); // FIXME
40 SCM force_sym = ly_symbol2scm ("blank-last-page-force");
41 Real blank_force = robust_scm2double (book_->paper_->lookup_variable (force_sym), 0);
42 bool ragged_all = to_boolean (book_->paper_->c_variable ("ragged-bottom"));
43 bool ragged_last = to_boolean (book_->paper_->c_variable ("ragged-last-bottom"));
44 Spacing_result ret = space_systems_on_best_pages (lines,
50 /* add in the line penalties */
52 Real line_penalty = 0;
53 Real page_weighting = robust_scm2double (book_->paper_->c_variable ("page-spacing-weight"), 10);
55 for (vsize i = 0; i < lines.size (); i++)
57 line_force += lines[i].force_ * lines[i].force_;
58 line_penalty += lines[i].break_penalty_;
61 ret.demerits_ = ret.force_[0] * ret.force_[0] * page_weighting;
62 for (vsize i = 1; i < ret.force_.size (); i++)
63 ret.demerits_ += ret.force_[i] * ret.force_[i] * page_weighting;
65 /* for a while we tried averaging page and line forces instead of summing
66 them, but it caused the following problem. If there is a single page
67 with a very bad page force (for example because of a forced page break),
68 the page breaker will put in a _lot_ of pages so that the bad force
69 becomes averaged out over many pages. */
70 ret.demerits_ += line_force + line_penalty;
75 Optimal_page_breaking::solve ()
77 vsize end = breaks_.size () - 1;
78 vsize min_sys_count = min_system_count (0, end);
79 vsize max_sys_count = max_system_count (0, end);
80 vsize max_page_count = INT_MAX;
81 vsize cur_page_count = 0;
83 Line_division best_division;
84 Line_division lower_bound;
86 for (vsize sys_count = min_sys_count;
87 cur_page_count <= max_page_count && sys_count <= max_sys_count;
90 Real this_best_demerits = infinity_f;
91 vector<Line_division> div = line_divisions (0, end, sys_count, lower_bound);
92 for (vsize d = 0; d < div.size (); d++)
94 Spacing_result cur = try_page_spacing (div[d]);
95 cur_page_count = cur.systems_per_page_.size ();
96 if (cur.demerits_ < best.demerits_ || isinf (best.demerits_))
99 best_division = div[d];
102 if (cur.demerits_ < this_best_demerits || isinf (best.demerits_))
104 this_best_demerits = cur.demerits_;
105 lower_bound = div[d];
108 vector<Line_details> det = line_details (0, end, div[d]);
109 bool all_lines_stretched = true;
110 for (vsize i = 0; i < det.size (); i++)
111 if (det[i].force_ < 0)
112 all_lines_stretched = false;
114 if (all_lines_stretched)
115 max_page_count = min (max_page_count, cur_page_count + 1);
119 break_into_pieces (0, end, best_division);
120 SCM lines = systems ();
121 return make_pages (best.systems_per_page_, lines);