2 This file is part of LilyPond, the GNU music typesetter.
4 Copyright (C) 2006--2010 Joe Neeman <joeneeman@gmail.com>
6 LilyPond is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
11 LilyPond is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with LilyPond. If not, see <http://www.gnu.org/licenses/>.
20 #include "international.hh"
21 #include "optimal-page-breaking.hh"
22 #include "output-def.hh"
23 #include "page-spacing.hh"
24 #include "paper-book.hh"
25 #include "paper-score.hh"
32 return g->get_property ("page-break-permission") == ly_symbol2scm ("force");
35 Optimal_page_breaking::Optimal_page_breaking (Paper_book *pb)
36 : Page_breaking (pb, is_break)
40 Optimal_page_breaking::~Optimal_page_breaking ()
44 extern bool debug_page_breaking_scoring;
46 // Solves the subproblem betwen the (END-1)th \pageBreak and the
48 // Returns a vector of systems per page for the pages within this chunk.
50 Optimal_page_breaking::solve_chunk (vsize end, SCM forced_page_count)
52 vsize max_sys_count = max_system_count (end-1, end);
53 vsize first_page_num = robust_scm2int (book_->paper_->c_variable ("first-page-number"), 1);
55 set_to_ideal_line_configuration (end-1, end);
57 Page_spacing_result best;
58 vsize page_count = robust_scm2int (forced_page_count, 1);
59 Line_division ideal_line_division = current_configuration (0);
60 Line_division best_division = ideal_line_division;
61 vsize min_sys_count = 1;
62 vsize ideal_sys_count = system_count ();
64 if (!scm_is_integer (forced_page_count))
66 if (systems_per_page () > 0)
67 best = space_systems_with_fixed_number_per_page (0, first_page_num);
69 best = space_systems_on_best_pages (0, first_page_num);
71 page_count = best.systems_per_page_.size ();
72 ideal_sys_count = best.system_count ();
73 min_sys_count = ideal_sys_count - best.systems_per_page_.back ();
75 if (page_count > 1 && best.systems_per_page_[page_count - 2] > 1)
76 min_sys_count -= best.systems_per_page_[page_count - 2];
78 min_sys_count = max (min_sys_count, (vsize)1);
82 /* TODO: the following line will spit out programming errors if the
83 ideal line spacing doesn't fit on PAGE_COUNT pages */
84 /* TODO: the interaction between systems_per_page and page_count needs to
86 best = space_systems_on_n_pages (0, page_count, first_page_num);
87 min_sys_count = page_count;
90 if (page_count == 1 || scm_is_integer (forced_page_count))
91 progress_indication (_f ("[%d: %d pages]", (int) end, (int) page_count));
93 progress_indication (_f ("[%d: %d or %d pages]", (int) end, (int) page_count-1, (int)page_count));
95 /* try a smaller number of systems than the ideal number for line breaking */
96 Line_division bound = ideal_line_division;
97 for (vsize sys_count = ideal_sys_count; --sys_count >= min_sys_count;)
99 Page_spacing_result best_for_this_sys_count;
100 set_current_breakpoints (end-1, end, sys_count, Line_division (), bound);
102 if (debug_page_breaking_scoring)
103 message (_f ("trying %d systems", (int)sys_count));
105 for (vsize i = 0; i < current_configuration_count (); i++)
107 vsize min_p_count = min_page_count (i, first_page_num);
108 Page_spacing_result cur;
110 if (min_p_count == page_count || scm_is_integer (forced_page_count))
111 cur = space_systems_on_n_pages (i, page_count, first_page_num);
113 cur = space_systems_on_n_or_one_more_pages (i, page_count-1, first_page_num, 0);
115 if (cur.demerits_ < best_for_this_sys_count.demerits_)
117 best_for_this_sys_count = cur;
118 bound = current_configuration (i);
122 if (debug_page_breaking_scoring)
123 message (_f ("best score for this sys-count: %f", best_for_this_sys_count.demerits_));
125 if (best_for_this_sys_count.demerits_ < best.demerits_)
127 best = best_for_this_sys_count;
128 best_division = bound;
131 /* Check to see if we already have too few systems. There are two ways
132 we check this: if we are trying one less than the ideal number of pages
133 and the pages are stretched on average then we have too
134 few systems. If the spacing is worse than BAD_SPACING_PENALTY, then we
135 have too few systems. In either case, though, we need to continue reducing
136 the number of systems if max-systems-per-page requires it. */
137 if (!(best.system_count_status_ & SYSTEM_COUNT_TOO_MANY))
139 if (best_for_this_sys_count.page_count () < page_count
140 && best_for_this_sys_count.average_force () > 0)
143 if (best_for_this_sys_count.demerits_ >= BAD_SPACING_PENALTY)
148 /* try a larger number of systems than the ideal line breaking number. This
149 is more or less C&P, but the loop bounds make it difficult to try something
150 like do {...} while (flip(&d) != UP). */
151 bound = ideal_line_division;
152 for (vsize sys_count = ideal_sys_count+1; sys_count <= max_sys_count; sys_count++)
154 Real best_demerits_for_this_sys_count = infinity_f;
155 set_current_breakpoints (end-1, end, sys_count, bound);
157 if (debug_page_breaking_scoring)
158 message (_f ("trying %d systems", (int)sys_count));
160 for (vsize i = 0; i < current_configuration_count (); i++)
162 vsize min_p_count = min_page_count (i, first_page_num);
163 Page_spacing_result cur;
165 if (min_p_count > page_count)
168 cur = space_systems_on_n_pages (i, page_count, first_page_num);
170 if (cur.demerits_ < best.demerits_)
173 best_division = current_configuration (i);
176 if (cur.demerits_ < best_demerits_for_this_sys_count)
178 best_demerits_for_this_sys_count = cur.demerits_;
179 bound = current_configuration (i);
183 if (debug_page_breaking_scoring)
184 message (_f ("best score for this sys-count: %f", best_demerits_for_this_sys_count));
186 if (best_demerits_for_this_sys_count >= BAD_SPACING_PENALTY
187 && !(best.system_count_status_ & SYSTEM_COUNT_TOO_FEW))
190 break_into_pieces (end-1, end, best_division);
192 return best.systems_per_page_;
196 Optimal_page_breaking::solve ()
198 vector<vsize> systems_per_page;
200 SCM forced_page_counts = book_->paper_->c_variable ("page-count");
201 if (scm_is_integer (forced_page_counts))
202 forced_page_counts = scm_list_1 (forced_page_counts);
204 bool is_forced_page_counts = false;
205 if (scm_to_bool (scm_list_p (forced_page_counts)))
207 int len = scm_to_int (scm_length (forced_page_counts));
208 if (len != (int)last_break_position ())
210 warning (_f ("page-count has length %d, but it should have length %d "
211 "(one more than the number of forced page breaks)",
212 len, (int)last_break_position ()));
215 is_forced_page_counts = true;
219 message (_f ("Solving %d page-breaking chunks...", last_break_position ()));
220 for (vsize end = 1; end <= last_break_position (); ++end)
222 SCM page_count = SCM_EOL;
223 if (is_forced_page_counts)
225 page_count = scm_car (forced_page_counts);
226 forced_page_counts = scm_cdr (forced_page_counts);
229 vector<vsize> chunk_systems = solve_chunk (end, page_count);
230 systems_per_page.insert (systems_per_page.end (), chunk_systems.begin (), chunk_systems.end ());
233 message (_ ("Drawing systems..."));
234 SCM lines = systems ();
235 return make_pages (systems_per_page, lines);