(process_acknowledged_grobs):
[lilypond.git] / lily / gourlay-breaking.cc
blobb4657f893ada1c0ea373e93032056f45f534500a
1 /*
2 gourlay-breaking.cc -- implement Gourlay_breaking
4 source file of the GNU LilyPond music typesetter
6 (c) 1997--2003 Han-Wen Nienhuys <hanwen@cs.uu.nl>
7 */
8 #include <math.h> // rint
9 #include <stdio.h>
11 #include "gourlay-breaking.hh"
12 #include "column-x-positions.hh"
13 #include "warn.hh"
14 #include "main.hh"
15 #include "paper-column.hh"
16 #include "paper-score.hh"
17 #include "paper-def.hh"
18 #include "simple-spacer.hh"
19 #include "system.hh"
21 /// How often to print operator pacification marks?
22 const int HAPPY_DOTS_I = 3;
24 /**
25 Helper to trace back an optimal path
27 struct Break_node {
28 /** this was the previous. If negative, this break should not be
29 considered: this path has infinite energy
32 int prev_break_;
33 /**
34 Which system number so far?
36 int line_;
38 Real demerits_;
39 Column_x_positions line_config_;
41 Break_node ()
43 prev_break_ = -1;
44 line_ = 0;
45 demerits_ = 0;
48 void print () const
50 printf ("prev break %d, line %d, demerits %f\n",
51 prev_break_, line_, demerits_);
55 void
56 print_break_nodes (Array<Break_node> const & arr)
58 for (int i =0; i < arr.size (); i++)
60 printf ( "node %d: ", i);
61 arr[i].print ();
65 /**
66 This algorithms is adapted from the OSU Tech report on breaking lines.
68 this function is longish, but not very complicated.
71 Array<Column_x_positions>
72 Gourlay_breaking::do_solve () const
74 Array<Break_node> optimal_paths;
75 Link_array<Grob> all =
76 pscore_->system_->columns ();
78 Array<int> breaks = find_break_indices ();
80 Break_node first_node ;
81 optimal_paths.push (first_node);
83 Real worst_force = 0.0;
85 for (int break_idx=1; break_idx< breaks.size (); break_idx++)
88 start with a short line, add measures. At some point
89 the line becomes infeasible. Then we don't try to add more
91 int minimal_start_idx = -1;
92 Column_x_positions minimal_sol;
93 Column_x_positions backup_sol;
95 Real minimal_demerits = infinity_f;
97 bool ragged = to_boolean (pscore_->paper_->get_scmvar ("raggedright"));
99 for (int start_idx = break_idx; start_idx--;)
101 Link_array<Grob> line = all.slice (breaks[start_idx], breaks[break_idx]+1);
103 line[0] = dynamic_cast<Item*> (line[0]) ->find_prebroken_piece (RIGHT);
104 line.top () = dynamic_cast<Item*> (line.top ())->find_prebroken_piece (LEFT);
106 Column_x_positions cp;
107 cp.cols_ = line;
109 Interval line_dims
110 = pscore_->paper_->line_dimensions_int (optimal_paths[start_idx].line_);
111 Simple_spacer * sp = generate_spacing_problem (line, line_dims);
112 sp->solve (&cp, ragged);
113 delete sp;
115 if (fabs (cp.force_) > worst_force)
116 worst_force = fabs (cp.force_);
119 We remember this solution as a "should always work
120 solution", in case everything fucks up. */
121 if (start_idx == break_idx - 1)
122 backup_sol = cp;
124 Real this_demerits;
126 if (optimal_paths[start_idx].demerits_ >= infinity_f)
127 this_demerits = infinity_f;
128 else
129 this_demerits = combine_demerits (optimal_paths[start_idx].line_config_, cp)
130 + optimal_paths[start_idx].demerits_;
132 if (this_demerits < minimal_demerits)
134 minimal_start_idx = start_idx;
135 minimal_sol = cp;
136 minimal_demerits = this_demerits;
140 we couldn't satisfy the constraints, this won't get better
141 if we add more columns, so we get on with the next one
143 if (!cp.satisfies_constraints_b_)
144 break ;
148 Break_node bnod;
149 if (minimal_start_idx < 0)
151 bnod.demerits_ = infinity_f;
152 bnod.line_config_ = backup_sol;
153 bnod.prev_break_ = break_idx - 1;
155 else
157 bnod.prev_break_ = minimal_start_idx;
158 bnod.demerits_ = minimal_demerits;
159 bnod.line_config_ = minimal_sol;
161 bnod.line_ = optimal_paths[bnod.prev_break_].line_ + 1;
162 optimal_paths.push (bnod);
164 if (! (break_idx % HAPPY_DOTS_I))
165 progress_indication (String ("[") + to_string (break_idx) + "]");
168 /* do the last one */
169 if (breaks.size () % HAPPY_DOTS_I)
170 progress_indication (String ("[") + to_string (breaks.size()) + "]");
172 progress_indication ("\n");
174 Array<int> final_breaks;
175 Array<Column_x_positions> lines;
177 /* skip 0-th element, since it is a "dummy" elt*/
178 for (int i = optimal_paths.size ()-1; i> 0;)
180 final_breaks.push (i);
181 int prev = optimal_paths[i].prev_break_;
182 assert (i > prev);
183 i = prev;
186 if (verbose_global_b)
188 progress_indication (_f ("Optimal demerits: %f",
189 optimal_paths.top ().demerits_) + "\n");
192 if (optimal_paths.top ().demerits_ >= infinity_f)
193 warning (_ ("No feasible line breaking found"));
195 for (int i= final_breaks.size (); i--;)
197 Column_x_positions cp (optimal_paths[final_breaks[i]].line_config_);
199 lines.push (cp);
200 if(!cp.satisfies_constraints_b_)
201 warning ("Could not find line breaking that satisfies constraints.");
203 return lines;
207 Gourlay_breaking::Gourlay_breaking ()
214 TODO: uniformity parameter to control rel. importance of spacing differences.
216 TODO:
218 mixing break penalties and constraint-failing solutions is confusing.
220 Real
221 Gourlay_breaking::combine_demerits (Column_x_positions const &prev,
222 Column_x_positions const &this_one) const
224 Real break_penalties = 0.0;
225 Grob * pc = this_one.cols_.top ();
226 if (pc->original_)
228 SCM pen = pc->get_grob_property ("penalty");
229 if (gh_number_p (pen) && fabs (gh_scm2double (pen)) < 10000)
231 break_penalties += gh_scm2double (pen);
236 Q: do we want globally non-cramped lines, or locally equally
237 cramped lines?
239 There used to be an example file input/test/uniform-breaking to
240 demonstrate problems with this approach. When music is gradually
241 becoming denser, the uniformity requirement makes lines go from
242 cramped to even more cramped (because going from cramped
243 3meas/line to relatively loose 2meas/line is such a big step.
247 Real demerit = abs (this_one.force_) + abs (prev.force_ - this_one.force_)
248 + break_penalties;
250 if (!this_one.satisfies_constraints_b_)
253 If it doesn't satisfy constraints, we make this one
254 really unattractive.
256 add 20000 to the demerits, so that a break penalty
257 of -10000 won't change the result */
258 demerit = (demerit + 20000) >? 2000;
260 demerit *= 10;
263 return demerit;