+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
d'[ cis] |
%% d4 d,,2 |
d4
- #(assert-system-count-override 6)
+% #(assert-system-count-override 6)
d,,2 |
}
line-width =183.5 \mm
between-system-space = 25\mm
between-system-padding = 0\mm
+ system-count = 6
%% annotatespacing = ##t
}
{
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;
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);
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);
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;
}
}
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);
}
+++ /dev/null
-/*
- 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;
-}
-
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
+++ /dev/null
-/*
- 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
/*
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 ();
/* 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);
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 *);
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)
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,
{
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];
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);
}
}
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"));
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
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));
*/
#include "page-spacing.hh"
+
#include "matrix.hh"
+#include "warn.hh"
/*
A much simplified rods-and-springs problem.
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_;
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)
+ (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_;
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;
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;
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);
}
#include "all-font-metrics.hh"
#include "book.hh"
-#include "gourlay-breaking.hh"
#include "international.hh"
#include "main.hh"
#include "misc.hh"
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;
}
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)
{
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_);
}
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++)
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++)
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;
}
}
{
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]);
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)
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")))
{
(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 )
(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)
`(,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
(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))
(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))))
(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
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)))
(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))
(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)))
(- (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
(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))
(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
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)))
(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)