]> git.donarmstrong.com Git - lilypond.git/blob - lily/optimal-page-breaking.cc
page breaking coding style fixes.
[lilypond.git] / lily / optimal-page-breaking.cc
1 /*
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
5
6   source file of the GNU LilyPond music typesetter
7
8   (c) 2006--2007 Joe Neeman <joeneeman@gmail.com>
9 */
10
11 #include "international.hh"
12 #include "optimal-page-breaking.hh"
13 #include "output-def.hh"
14 #include "page-spacing.hh"
15 #include "paper-book.hh"
16 #include "paper-score.hh"
17 #include "prob.hh"
18 #include "system.hh"
19
20 static bool
21 is_break (Grob *g)
22 {
23   (void) g; /* shutup warning */
24   return false;
25 }
26
27 Optimal_page_breaking::Optimal_page_breaking (Paper_book *pb)
28   : Page_breaking (pb, is_break)
29 {
30 }
31
32 Optimal_page_breaking::~Optimal_page_breaking ()
33 {
34 }
35
36 SCM
37 Optimal_page_breaking::solve ()
38 {
39   vsize end = last_break_position ();
40   vsize min_sys_count = 0;
41   vsize ideal_sys_count = 0;
42   vsize max_sys_count = max_system_count (0, end);
43   vsize page_count = 0;
44   
45   Line_division ideal_line_division;
46   Line_division best_division;
47   Line_division bound;
48   vsize first_page_num = robust_scm2int (book_->paper_->c_variable ("first-page-number"), 1);
49
50   /* find out the ideal number of pages */
51   message (_ ("Finding the ideal number of pages..."));
52   set_to_ideal_line_configuration (0, end);
53   ideal_line_division = current_configuration (0);
54
55   Spacing_result best = space_systems_on_best_pages (0, first_page_num);
56   page_count = best.systems_per_page_.size ();
57   best_division = ideal_line_division;
58
59   for (vsize i = 0; i < page_count; i++)
60     ideal_sys_count += best.systems_per_page_[i];
61
62   min_sys_count = ideal_sys_count - best.systems_per_page_.back ();
63   if (page_count > 1)
64     min_sys_count -= best.systems_per_page_[page_count - 2];
65
66   if (page_count == 1)
67     message (_ ("Fitting music on 1 page..."));
68   else
69     message (_f ("Fitting music on %d or %d pages...", (int)page_count-1, (int)page_count));
70
71   /* try a smaller number of systems than the ideal number for line breaking */
72   bound = ideal_line_division;
73   for (vsize sys_count = ideal_sys_count; --sys_count >= min_sys_count;)
74     {
75       Spacing_result best_for_this_sys_count;
76       set_current_breakpoints (0, end, sys_count, Line_division (), bound);
77
78       for (vsize i = 0; i < current_configuration_count (); i++)
79         {
80           vsize min_p_count = min_page_count (i, first_page_num);
81           Spacing_result cur;
82
83           if (min_p_count > page_count)
84             continue;
85           else if (min_p_count == page_count)
86             cur = space_systems_on_n_pages (i, page_count, first_page_num);
87           else
88             cur = space_systems_on_n_or_one_more_pages (i, page_count-1, first_page_num);
89
90           if (cur.demerits_ < best_for_this_sys_count.demerits_ || isinf (best_for_this_sys_count.demerits_))
91             {
92               best_for_this_sys_count = cur;
93               bound = current_configuration (i);
94             }
95         }
96
97       if (best_for_this_sys_count.demerits_ < best.demerits_ || isinf (best.demerits_))
98         {
99           best = best_for_this_sys_count;
100           best_division = bound;
101         }
102
103       if (best_for_this_sys_count.systems_per_page_.size () < page_count)
104         {
105           /* if the pages are stretched on average, stop trying to reduce sys_count */
106           Real avg_f = 0;
107           for (vsize i = 0; i < best_for_this_sys_count.systems_per_page_.size (); i++)
108             avg_f += best_for_this_sys_count.systems_per_page_[i];
109           if (avg_f > 0)
110             break;
111         }
112
113       if (isinf (best_for_this_sys_count.demerits_))
114         break;
115     }
116
117   /* try a larger number of systems than the ideal line breaking number. This
118      is more or less C&P, but the loop bounds make it difficult to try something
119      like do {...} while (flip(&d) != UP). */
120   bound = ideal_line_division;
121   for (vsize sys_count = ideal_sys_count+1; sys_count <= max_sys_count; sys_count++)
122     {
123       Real best_demerits_for_this_sys_count = infinity_f;
124       set_current_breakpoints (0, end, sys_count, bound);
125
126       for (vsize i = 0; i < current_configuration_count (); i++)
127         {
128           vsize min_p_count = min_page_count (i, first_page_num);
129           Spacing_result cur;
130
131           if (min_p_count > page_count)
132             continue;
133           else
134             cur = space_systems_on_n_pages (i, page_count, first_page_num);
135
136           if (cur.demerits_ < best.demerits_ || isinf (best.demerits_))
137             {
138               best = cur;
139               best_division = current_configuration (i);
140             }
141
142           if (cur.demerits_ < best_demerits_for_this_sys_count || isinf (best_demerits_for_this_sys_count))
143             {
144               best_demerits_for_this_sys_count = cur.demerits_;
145               bound = current_configuration (i);
146             }
147         }
148       if (isinf (best_demerits_for_this_sys_count))
149         break;
150     }
151
152   message ("Drawing systems...");
153   break_into_pieces (0, end, best_division);
154   SCM lines = systems ();
155   return make_pages (best.systems_per_page_, lines);
156 }
157