summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog52
-rw-r--r--input/mutopia/J.S.Bach/baerenreiter-sarabande.ly3
-rw-r--r--lily/axis-group-interface.cc9
-rw-r--r--lily/constrained-breaking.cc15
-rw-r--r--lily/gourlay-breaking.cc265
-rw-r--r--lily/grob.cc8
-rw-r--r--lily/include/gourlay-breaking.hh23
-rw-r--r--lily/include/lily-guile.hh4
-rw-r--r--lily/include/simple-spacer.hh1
-rw-r--r--lily/include/slur.hh1
-rw-r--r--lily/lily-guile.cc15
-rw-r--r--lily/optimal-page-breaking.cc10
-rw-r--r--lily/page-breaking.cc30
-rw-r--r--lily/page-spacing.cc24
-rw-r--r--lily/page-turn-page-breaking.cc5
-rw-r--r--lily/paper-score.cc16
-rw-r--r--lily/simple-spacer.cc57
-rw-r--r--lily/slur.cc29
-rw-r--r--lily/system.cc14
-rw-r--r--ly/paper-defaults.ly2
-rw-r--r--scm/define-grobs.scm7
-rw-r--r--scm/layout-page-layout.scm58
22 files changed, 235 insertions, 413 deletions
diff --git a/ChangeLog b/ChangeLog
index 94f62b8cce..ff27e6840b 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,55 @@
+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
diff --git a/input/mutopia/J.S.Bach/baerenreiter-sarabande.ly b/input/mutopia/J.S.Bach/baerenreiter-sarabande.ly
index bc4ce8a241..a61a1ff8a6 100644
--- a/input/mutopia/J.S.Bach/baerenreiter-sarabande.ly
+++ b/input/mutopia/J.S.Bach/baerenreiter-sarabande.ly
@@ -126,7 +126,7 @@ sarabandeA = \context Voice \relative c {
d'[ cis] |
%% d4 d,,2 |
d4
- #(assert-system-count-override 6)
+% #(assert-system-count-override 6)
d,,2 |
}
@@ -173,6 +173,7 @@ smallerPaper = \layout {
line-width =183.5 \mm
between-system-space = 25\mm
between-system-padding = 0\mm
+ system-count = 6
%% annotatespacing = ##t
}
diff --git a/lily/axis-group-interface.cc b/lily/axis-group-interface.cc
index 1d509f04d1..8700da3e54 100644
--- a/lily/axis-group-interface.cc
+++ b/lily/axis-group-interface.cc
@@ -145,7 +145,14 @@ Axis_group_interface::relative_pure_height (Grob *me,
{
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;
diff --git a/lily/constrained-breaking.cc b/lily/constrained-breaking.cc
index e3b07fab3b..4d9c5795ee 100644
--- a/lily/constrained-breaking.cc
+++ b/lily/constrained-breaking.cc
@@ -156,7 +156,6 @@ Constrained_breaking::resize (vsize systems)
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);
@@ -172,6 +171,12 @@ Constrained_breaking::resize (vsize systems)
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);
@@ -181,15 +186,10 @@ Constrained_breaking::resize (vsize systems)
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;
}
}
@@ -374,6 +374,9 @@ Constrained_breaking::Constrained_breaking (vector<vsize> const &start)
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);
}
diff --git a/lily/gourlay-breaking.cc b/lily/gourlay-breaking.cc
deleted file mode 100644
index f5e29ad18d..0000000000
--- a/lily/gourlay-breaking.cc
+++ /dev/null
@@ -1,265 +0,0 @@
-/*
- 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;
-}
-
diff --git a/lily/grob.cc b/lily/grob.cc
index 4b44231e61..72b46376c6 100644
--- a/lily/grob.cc
+++ b/lily/grob.cc
@@ -302,10 +302,14 @@ Grob::pure_relative_y_coordinate (Grob const *refp, int start, int end)
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
diff --git a/lily/include/gourlay-breaking.hh b/lily/include/gourlay-breaking.hh
deleted file mode 100644
index 34a92f8dea..0000000000
--- a/lily/include/gourlay-breaking.hh
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- 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
diff --git a/lily/include/lily-guile.hh b/lily/include/lily-guile.hh
index 23b3c64785..a0ac54bda7 100644
--- a/lily/include/lily-guile.hh
+++ b/lily/include/lily-guile.hh
@@ -117,9 +117,7 @@ inline SCM ly_append4 (SCM x1, SCM x2, SCM x3, SCM x4)
/*
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 ();
diff --git a/lily/include/simple-spacer.hh b/lily/include/simple-spacer.hh
index 39d9a3f853..758cd65b32 100644
--- a/lily/include/simple-spacer.hh
+++ b/lily/include/simple-spacer.hh
@@ -67,7 +67,6 @@ private:
/* 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);
diff --git a/lily/include/slur.hh b/lily/include/slur.hh
index 2c797239ce..f0213372bc 100644
--- a/lily/include/slur.hh
+++ b/lily/include/slur.hh
@@ -23,6 +23,7 @@ public:
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 *);
diff --git a/lily/lily-guile.cc b/lily/lily-guile.cc
index 971063e54e..064ed54fab 100644
--- a/lily/lily-guile.cc
+++ b/lily/lily-guile.cc
@@ -114,15 +114,12 @@ gulp_file_to_string (string fn, bool must_exist, int size)
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)
diff --git a/lily/optimal-page-breaking.cc b/lily/optimal-page-breaking.cc
index 6f3fcc5683..03d72629a0 100644
--- a/lily/optimal-page-breaking.cc
+++ b/lily/optimal-page-breaking.cc
@@ -39,8 +39,8 @@ Optimal_page_breaking::try_page_spacing (Line_division const &line_count)
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,
@@ -91,13 +91,13 @@ Optimal_page_breaking::solve ()
{
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];
@@ -110,7 +110,7 @@ Optimal_page_breaking::solve ()
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);
}
}
diff --git a/lily/page-breaking.cc b/lily/page-breaking.cc
index 1a32d7e7f1..b1fd686e2b 100644
--- a/lily/page-breaking.cc
+++ b/lily/page-breaking.cc
@@ -175,9 +175,17 @@ Page_breaking::breakpoint_property (vsize breakpoint, char const *str)
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"));
@@ -193,10 +201,15 @@ Page_breaking::make_pages (vector<vsize> lines_per_page, SCM systems)
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
@@ -214,7 +227,16 @@ Page_breaking::create_system_list ()
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));
diff --git a/lily/page-spacing.cc b/lily/page-spacing.cc
index fc6c5b3ddf..4d11f0c865 100644
--- a/lily/page-spacing.cc
+++ b/lily/page-spacing.cc
@@ -8,7 +8,9 @@
*/
#include "page-spacing.hh"
+
#include "matrix.hh"
+#include "warn.hh"
/*
A much simplified rods-and-springs problem.
@@ -249,10 +251,10 @@ Page_spacer::solve (vsize page_count)
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_;
@@ -311,6 +313,10 @@ Page_spacer::calc_subproblem (vsize page, vsize line)
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)
@@ -318,7 +324,7 @@ Page_spacer::calc_subproblem (vsize page, vsize line)
+ (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_;
@@ -343,15 +349,15 @@ min_page_count (vector<Line_details> const &lines, Real page_height, bool ragged
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;
diff --git a/lily/page-turn-page-breaking.cc b/lily/page-turn-page-breaking.cc
index 6171adca4d..7db8831905 100644
--- a/lily/page-turn-page-breaking.cc
+++ b/lily/page-turn-page-breaking.cc
@@ -149,7 +149,7 @@ Page_turn_page_breaking::calc_subproblem (vsize ending_breakpoint)
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;
@@ -175,8 +175,9 @@ Page_turn_page_breaking::calc_subproblem (vsize ending_breakpoint)
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);
}
diff --git a/lily/paper-score.cc b/lily/paper-score.cc
index ffad13c38b..e7a5f51247 100644
--- a/lily/paper-score.cc
+++ b/lily/paper-score.cc
@@ -10,7 +10,6 @@
#include "all-font-metrics.hh"
#include "book.hh"
-#include "gourlay-breaking.hh"
#include "international.hh"
#include "main.hh"
#include "misc.hh"
@@ -100,24 +99,17 @@ Paper_score::get_columns () const
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;
}
diff --git a/lily/simple-spacer.cc b/lily/simple-spacer.cc
index 3b3eaed3ba..560dfecacd 100644
--- a/lily/simple-spacer.cc
+++ b/lily/simple-spacer.cc
@@ -358,20 +358,6 @@ next_spaceable_column (vector<Grob*> const &list, vsize starting)
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)
{
@@ -406,7 +392,7 @@ get_column_description (vector<Grob*> const &cols, vsize col_index, bool line_st
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_);
@@ -430,32 +416,35 @@ get_column_description (vector<Grob*> const &cols, vsize col_index, bool line_st
}
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++)
@@ -465,7 +454,7 @@ get_line_forces (vector<Grob*> const &icols, vector<vsize> breaks,
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++)
@@ -490,13 +479,16 @@ get_line_forces (vector<Grob*> const &icols, vector<vsize> breaks,
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;
}
}
@@ -535,6 +527,7 @@ get_line_configuration (vector<Grob*> const &columns,
{
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]);
diff --git a/lily/slur.cc b/lily/slur.cc
index 557200b239..0c68a6137e 100644
--- a/lily/slur.cc
+++ b/lily/slur.cc
@@ -57,6 +57,35 @@ Slur::calc_direction (SCM smob)
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)
diff --git a/lily/system.cc b/lily/system.cc
index 2fba41a49e..54562cdc04 100644
--- a/lily/system.cc
+++ b/lily/system.cc
@@ -397,14 +397,12 @@ System::get_paper_system ()
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")))
{
diff --git a/ly/paper-defaults.ly b/ly/paper-defaults.ly
index 9fae0cabd5..2e265c7ab1 100644
--- a/ly/paper-defaults.ly
+++ b/ly/paper-defaults.ly
@@ -96,7 +96,7 @@
(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 )
diff --git a/scm/define-grobs.scm b/scm/define-grobs.scm
index bc3aee5e93..07971e2f91 100644
--- a/scm/define-grobs.scm
+++ b/scm/define-grobs.scm
@@ -1983,7 +1983,8 @@
(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)
@@ -2004,7 +2005,8 @@
`(,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
@@ -2017,6 +2019,7 @@
(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))
diff --git a/scm/layout-page-layout.scm b/scm/layout-page-layout.scm
index 215b5003d0..fabe89f97b 100644
--- a/scm/layout-page-layout.scm
+++ b/scm/layout-page-layout.scm
@@ -46,20 +46,20 @@
(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))))
@@ -69,24 +69,24 @@
(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
@@ -124,7 +124,7 @@ is what have collected so far, and has ascending page numbers."
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)))
@@ -134,7 +134,7 @@ is what have collected so far, and has ascending page numbers."
(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))
@@ -142,7 +142,7 @@ is what have collected so far, and has ascending page numbers."
(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)))
@@ -154,27 +154,31 @@ is what have collected so far, and has ascending page numbers."
(- (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
@@ -185,18 +189,18 @@ CURRENT-BEST is the best result sofar, or #f."
(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))
@@ -234,7 +238,7 @@ CURRENT-BEST is the best result sofar, or #f."
(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
@@ -250,7 +254,7 @@ CURRENT-BEST is the best result sofar, or #f."
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)))
@@ -262,8 +266,8 @@ DONE."
(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)