Here is the patch for the "begin/rest-of-line" problem.
(Sorry, couldn't upload to appspot for various reasons).
I have also attached two score examples illustrating the bug.
We should probably augment the test suite, too, for the bug
to be considered done done.
Btw, how does one file a proper file report?
The bug tracker says scary things to the effect of "never create
a bug report directly in this tracker, or risk being permanently
killed; instead, write to the -bug maillist." Well at least this is
my (mis-?)understanding of it. I have written numeruos reports
here, but never actually saw it result in a tracked report.
What is the correct procedure?
--
Boris Shingarov
Work on Lilypond under grant from Sonus Paradisi / Jiri Zurek (Prague),
Czech Science Foundation, Project No. 401/09/0419
diff --git a/lily/constrained-breaking.cc b/lily/constrained-breaking.cc
index 0db98cc..78079ef 100644
--- a/lily/constrained-breaking.cc
+++ b/lily/constrained-breaking.cc
@@ -458,7 +471,8 @@ Constrained_breaking::fill_line_details (Line_details *const out, vsize start, v
int start_rank = Paper_column::get_rank (all_[breaks_[start]]);
int end_rank = Paper_column::get_rank (all_[breaks_[end]]);
System *sys = pscore_->root_system ();
- Interval extent = sys->pure_height (sys, start_rank, end_rank);
+ Interval begin_of_line_extent = sys->begin_of_line_pure_height (start_rank, end_rank);
+ Interval rest_of_line_extent = sys->rest_of_line_pure_height (start_rank, end_rank);
Grob *c = all_[breaks_[end]];
out->last_column_ = c;
@@ -476,20 +490,18 @@ Constrained_breaking::fill_line_details (Line_details *const out, vsize start, v
out->turn_permission_ = min_permission (out->page_permission_,
out->turn_permission_);
- // TODO: see the hack regarding begin_of_line and
- // rest_of_line extents in align-interface. Perhaps we
- // should do the same thing here so that the effect extends
- // between systems as well as within systems. It isn't as
- // crucial here, however, because the effect is largest when
- // dealing with large systems.
- out->extent_ = (extent.is_empty ()
- || isnan (extent[LEFT])
- || isnan (extent[RIGHT]))
- ? Interval (0, 0) : extent;
+ out->begin_of_line_extent_ = (begin_of_line_extent.is_empty ()
+ || isnan (begin_of_line_extent[LEFT])
+ || isnan (begin_of_line_extent[RIGHT]))
+ ? Interval (0, 0) : begin_of_line_extent;
+ out->rest_of_line_extent_ = (rest_of_line_extent.is_empty ()
+ || isnan (rest_of_line_extent[LEFT])
+ || isnan (rest_of_line_extent[RIGHT]))
+ ? Interval (0, 0) : rest_of_line_extent;
out->padding_ = between_system_padding_;
out->title_padding_ = before_title_padding_;
out->space_ = between_system_space_;
- out->inverse_hooke_ = extent.length () + between_system_space_;
+ out->inverse_hooke_ = out->full_height () + between_system_space_;
}
Real
@@ -512,7 +524,6 @@ Line_details::Line_details (Prob *pb, Output_def *paper)
last_column_ = 0;
force_ = 0;
- extent_ = unsmob_stencil (pb->get_property ("stencil")) ->extent (Y_AXIS);
bottom_padding_ = 0;
space_ = 0.0;
inverse_hooke_ = 1.0;
@@ -530,3 +541,33 @@ Line_details::Line_details (Prob *pb, Output_def *paper)
SCM first_scm = pb->get_property ("first-markup-line");
first_markup_line_ = to_boolean (first_scm);
}
+
+/*
+ * I measure hanging from top of page. It is positive for everything
+ * below the top of page. Lower things have bigger hanging.
+ * NB!!! These hangings are artificial in that they do not take into
+ * account any padding/spacing. They are as if systems were stacked
+ * on top of each other; as such, hangings are only used/useful for the
+ * calculation of ext_len in Page_breaking.
+ */
+void Line_details::compute_hangings (double previous_begin, double previous_rest)
+{
+ double a = begin_of_line_extent_[UP];
+ double b = rest_of_line_extent_[UP];
+ double midline_hanging = max (previous_begin + a, previous_rest + b);
+ hanging_begin_ = midline_hanging - begin_of_line_extent_[DOWN];
+ hanging_rest_ = midline_hanging - rest_of_line_extent_[DOWN];
+}
+
+double Line_details::hanging ()
+{
+ return max (hanging_begin_, hanging_rest_);
+}
+
+double Line_details::full_height ()
+{
+ Interval ret;
+ ret.unite(begin_of_line_extent_);
+ ret.unite(rest_of_line_extent_);
+ return ret.length();
+}
diff --git a/lily/include/constrained-breaking.hh b/lily/include/constrained-breaking.hh
index e6d898e..1f0e952 100644
--- a/lily/include/constrained-breaking.hh
+++ b/lily/include/constrained-breaking.hh
@@ -27,7 +27,11 @@
struct Line_details {
Grob *last_column_;
Real force_;
- Interval extent_; /* Y-extent of the system */
+ Interval begin_of_line_extent_;
+ Interval rest_of_line_extent_;
+ double hanging_begin_;
+ double hanging_rest_;
+ double y_extent_; /* Y-extent, adjusted according to begin/rest-of-line*/
Real padding_; /* compulsory space after this system (if we're not
last on a page) */
@@ -78,6 +82,16 @@ struct Line_details {
}
Line_details (Prob *pb, Output_def *paper);
+
+ /*
+ * Pure procedure.
+ * Based on the arguments which indicate how low the previous system
+ * hangs, and on the internal state (*_of_line_extents), store into
+ * internal state (hanging_*) how low our own low margin hangs.
+ */
+ void compute_hangings (double previous_begin, double previous_rest);
+ double hanging ();
+ double full_height ();
};
/*
diff --git a/lily/include/system.hh b/lily/include/system.hh
index 509a65d..b8fa664 100644
--- a/lily/include/system.hh
+++ b/lily/include/system.hh
@@ -65,9 +65,15 @@ public:
void typeset_grob (Grob *);
void pre_processing ();
+ Interval begin_of_line_pure_height (vsize start, vsize end);
+ Interval rest_of_line_pure_height (vsize start, vsize end);
+
protected:
virtual void derived_mark () const;
virtual Grob *clone () const;
+
+private:
+ Interval part_of_line_pure_height (vsize start, vsize end, bool begin);
};
void set_loose_columns (System *which, Column_x_positions const *posns);
diff --git a/lily/page-breaking.cc b/lily/page-breaking.cc
index 7dbac44..1741f5c 100644
--- a/lily/page-breaking.cc
+++ b/lily/page-breaking.cc
@@ -101,8 +101,6 @@ compress_lines (const vector<Line_details> &orig)
Line_details compressed = orig[i];
Real padding = orig[i].title_ ? old.title_padding_ : old.padding_;
- compressed.extent_[DOWN] = old.extent_[DOWN];
- compressed.extent_[UP] = old.extent_[UP] + orig[i].extent_.length () + padding;
compressed.space_ += old.space_;
compressed.inverse_hooke_ += old.inverse_hooke_;
@@ -853,11 +851,27 @@ Page_breaking::min_page_count (vsize configuration, vsize first_page_num)
for (vsize i = 0; i < cached_line_details_.size (); i++)
{
- Real ext_len = cached_line_details_[i].extent_.length ();
+ double previous_hanging_begin = 0;
+ double previous_hanging_rest = 0;
+ if (i > 0)
+ {
+ previous_hanging_begin = cached_line_details_[i-1].hanging_begin_;
+ previous_hanging_rest = cached_line_details_[i-1].hanging_rest_;
+ }
+ cached_line_details_[i].compute_hangings (previous_hanging_begin, previous_hanging_rest);
+ double prev_hanging = 0;
+ if (i > 0)
+ {
+ prev_hanging = cached_line_details_[i-1].hanging ();
+ }
+ Real ext_len = cached_line_details_[i].hanging () - prev_hanging;
+ cached_line_details_[i].y_extent_ = ext_len;
+
Real padding = 0;
if (cur_rod_height > 0)
- padding = cached_line_details_[i].title_ ?
- cached_line_details_[i-1].title_padding_ : cached_line_details_[i-1].padding_;
+ padding = cached_line_details_[i].title_ ?
+ cached_line_details_[i-1].title_padding_ :
+ cached_line_details_[i-1].padding_;
Real next_rod_height = cur_rod_height + ext_len + padding;
Real next_spring_height = cur_spring_height + cached_line_details_[i].space_;
@@ -870,6 +884,8 @@ Page_breaking::min_page_count (vsize configuration, vsize first_page_num)
|| (i > 0
&& cached_line_details_[i-1].page_permission_ == ly_symbol2scm ("force")))
{
+ // ok, this page is filled, move to the beginning of next page
+ cached_line_details_[i].compute_hangings (0, 0);
line_count = cached_line_details_[i].compressed_nontitle_lines_count_;
cur_rod_height = ext_len;
cur_spring_height = cached_line_details_[i].space_;
@@ -909,7 +925,7 @@ Page_breaking::min_page_count (vsize configuration, vsize first_page_num)
if (!too_few_lines (line_count - cached_line_details_.back ().compressed_nontitle_lines_count_)
&& cur_height > cur_page_height
/* don't increase the page count if the last page had only one system */
- && cur_rod_height > cached_line_details_.back ().extent_.length ())
+ && cur_rod_height > cached_line_details_.back ().full_height ())
ret++;
assert (ret <= cached_line_details_.size ());
@@ -1388,7 +1404,8 @@ Page_breaking::min_whitespace_at_top_of_page (Line_details const &line) const
ly_symbol2scm ("padding"));
// FIXME: take into account the height of the header
- return max (0.0, max (padding, min_distance - line.extent_[UP]));
+ double translate = max (line.begin_of_line_extent_[UP], line.rest_of_line_extent_[UP]);
+ return max (0.0, max (padding, min_distance - translate));
}
Real
@@ -1406,7 +1423,8 @@ Page_breaking::min_whitespace_at_bottom_of_page (Line_details const &line) const
ly_symbol2scm ("padding"));
// FIXME: take into account the height of the footer
- return max (0.0, max (padding, min_distance + line.extent_[DOWN]));
+ double translate = min (line.begin_of_line_extent_[DOWN], line.rest_of_line_extent_[DOWN]);
+ return max (0.0, max (padding, min_distance + translate));
}
int
diff --git a/lily/page-spacing.cc b/lily/page-spacing.cc
index f78cc17..3f2bf45 100644
--- a/lily/page-spacing.cc
+++ b/lily/page-spacing.cc
@@ -52,7 +52,7 @@ Page_spacing::append_system (const Line_details &line)
rod_height_ += line.title_ ? last_line_.title_padding_ : last_line_.padding_;
- rod_height_ += line.extent_.length ();
+ rod_height_ += line.y_extent_;
spring_len_ += line.space_;
inverse_spring_k_ += line.inverse_hooke_;
@@ -69,7 +69,7 @@ Page_spacing::prepend_system (const Line_details &line)
else
last_line_ = line;
- rod_height_ += line.extent_.length ();
+ rod_height_ += line.y_extent_;
spring_len_ += line.space_;
inverse_spring_k_ += line.inverse_hooke_;
diff --git a/lily/system.cc b/lily/system.cc
index 1be38ea..5d370fe 100644
--- a/lily/system.cc
+++ b/lily/system.cc
@@ -570,6 +570,37 @@ System::get_extremal_staff (Direction dir, Interval const &iv)
return 0;
}
+Interval
+System::part_of_line_pure_height (vsize start, vsize end, bool begin)
+{
+ Grob *alignment = get_vertical_alignment (); //TODO check for null
+ extract_grob_set (alignment, "elements", staves);
+ vector<Real> offsets = Align_interface::get_minimum_translations (alignment, staves, Y_AXIS, true, start, end);
+
+Interval ret;
+ for (vsize i = 0; i < staves.size(); ++i)
+ {
+ Interval iv = begin?
+ Axis_group_interface::begin_of_line_pure_height (staves[i], start) :
+ Axis_group_interface::rest_of_line_pure_height (staves[i], start, end);
+ iv.translate (offsets[i]);
+ ret.unite (iv);
+ }
+ return ret;
+}
+
+Interval
+System::begin_of_line_pure_height (vsize start, vsize end)
+{
+ return part_of_line_pure_height (start, end, true);
+}
+
+Interval
+System::rest_of_line_pure_height (vsize start, vsize end)
+{
+ return part_of_line_pure_height (start, end, false);
+}
+
ADD_INTERFACE (System,
"This is the top-level object: Each object in a score"
" ultimately has a @code{System} object as its X and"
% Example of Lilypond score illustrating the problem
% with begin/rest of system height estimation.
% Copyright (c) Boris Shingarov, 2010
\version "2.13.14"
\paper {
#(set-paper-size "b5")
indent = 0.0
tagline = ##f
between-system-spacing = #'((space . 1.20) (padding . 1.20) (minimum-distance . 1.20))
% between-system-space = 1.20
ragged-bottom=##t
ragged-last-bottom=##t
}
\book {
\score {
<<
\new Voice = "cantus" {
d' e' d' e' d' e' d' e'
d' e' d' e' d' e' d' e'
d' e' d' e' d' e' d' e'
d' e' d' e' d' e' d' e'
d' e' d' e' d' e' d' e'
d' e' d' e' d' e' d' e'
d' e' d' e' d' e' d' e'
d' e' d' e' d' e' d' e'
d' e' d' e' d' e' d' e'
d' e' d' e' d' e' d' e'
d' e' d' e' d' e' d' e'
d' e' d' e' d' e' d' e'
d' e' d' e' d' e' d' e'
d' e' d' e' d' e' d' e'
d' e' d' e' d' e' d' e'
d' e' d' e' d' e' d' e'
d' e' d' e' d' e' d' e'
d' e' d' e' d' e' d' e'
d' e' d' e' d' e' d' e'
d' e' d' e' d' e' d' e'
d' e' d' e' d' e' d' e'
d' e' d' e' d' e' d' e'
d' e' d' e' d' e' d' e'
d' e' d' e' d' e' d' e'
d' e' d' e' d' e' d' e'
d' e' d' e' d' e' d' e'
d' e' d' e' d' e' d' e'
d' e' d' e' d' e' d' e'
d' e' d' e' d' e' d' e'
d' e' d' e' d' e' d' e'
d' e' d' e' d' e' d' e'
d' e' d' e' d' e' d' e'
d' e' d' e' d' e' d' e'
d' e' d' e' d' e' d' e'
d' e' d' e' d' e' d' e'
d' e' d' e' d' e' d' e'
d' e' d' e' d' e' d' e'
d' e' d' e' d' e' d' e'
d' e' d' e' d' e' d' e'
d' e' d' e' d' e' d' e'
d' e' d' e' d' e' d' e'
d' e' d' e' d' e' d' e'
d' e' d' e' d' e' d' e'
d' e' d' e' d' e' d' e'
d' e' d' e' d' e' d' e'
d' e' d' e' d' e' d' e'
d' e' d' e' d' e' d' e'
d' e' d' e' d' e' d' e'
d' e' d' e' d' e' d' e'
d' e' d' e' d' e' d' e'
}
\new Lyrics
\lyricsto "cantus" {
\lyricmode {
Q Q Q Q Q Q Q Q
Q Q Q Q Q Q Q Q
Q Q Q Q Q Q Q Q
Q Q Q Q Q Q Q Q
Q Q Q Q Q Q Q Q
Q Q Q Q Q Q Q Q
Q Q Q Q Q Q Q Q
Q Q Q Q Q Q Q Q
Q Q Q Q Q Q Q Q
Q Q Q Q Q Q Q Q
Q Q Q Q Q Q Q Q
Q Q Q Q Q Q Q Q
Q Q Q Q Q Q Q Q
Q Q Q Q Q Q Q Q
Q Q Q Q Q Q Q Q
Q Q Q Q Q Q Q Q
Q Q Q Q Q Q Q Q
Q Q Q Q Q Q Q Q
Q Q Q Q Q Q Q Q
Q Q Q Q Q Q Q Q
Q Q Q Q Q Q Q Q
Q Q Q Q Q Q Q Q
Q Q Q Q Q Q Q Q
Q Q Q Q Q Q Q Q
Q Q Q Q Q Q Q Q
Q Q Q Q Q Q Q Q
Q Q Q Q Q Q Q Q
Q Q Q Q Q Q Q Q
Q Q Q Q Q Q Q Q
Q Q Q Q Q Q Q Q
Q Q Q Q Q Q Q Q
Q Q Q Q Q Q Q Q
Q Q Q Q Q Q Q Q
Q Q Q Q Q Q Q Q
Q Q Q Q Q Q Q Q
Q Q Q Q Q Q Q Q
Q Q Q Q Q Q Q Q
Q Q Q Q Q Q Q Q
Q Q Q Q Q Q Q Q
Q Q Q Q Q Q Q Q
Q Q Q Q Q Q Q Q
Q Q Q Q Q Q Q Q
Q Q Q Q Q Q Q Q
Q Q Q Q Q Q Q Q
Q Q Q Q Q Q Q Q
Q Q Q Q Q Q Q Q
Q Q Q Q Q Q Q Q
Q Q Q Q Q Q Q Q
Q Q Q Q Q Q Q Q
Q Q Q Q Q Q Q Q
} %lyricmode
} %lyricsto
>>
\layout {
\context {
\Score
\remove "Bar_number_engraver"
}
} %layout
} %score
} %book
% Example of Lilypond score illustrating the problem
% with begin/rest of system height estimation.
% Copyright (c) Boris Shingarov, 2010
\version "2.13.14"
\paper {
#(set-paper-size "b5")
indent = 0.0
tagline = ##f
between-system-spacing = #'((space . 1.20) (padding . 1.20) (minimum-distance . 1.20))
ragged-bottom=##t
ragged-last-bottom=##t
%min-systems-per-page=12
}
\book {
\score {
<<
\new Voice = "cantus" {
f e f e f e f e
f e f e f e f e
f e f e f e f e
f e f e f e f e
f e f e f e f e
f e f e f e f e
f e f e f e f e
f e f e f e f e
f e f e f e f e
f e f e f e f e
f e f e f e f e
f e f e f e f e
f e f e f e f e
f e f e f e f e
f e f e f e f e
f e f e f e f e
f e f e f e f e
f e f e f e f e
f e f e f e f e
f e f e f e f e
f e f e f e f e
f e f e f e f e
f e f e f e f e
f e f e f e f e
f e f e f e f e
f e f e f e f e
f e f e f e f e
f e f e f e f e
f e f e f e f e
f e f e f e f e
f e f e f e f e
f e f e f e f e
f e f e f e f e
f e f e f e f e
f e f e f e f e
f e f e f e f e
f e f e f e f e
f e f e f e f e
f e f e f e f e
f e f e f e f e
f e f e f e f e
f e f e f e f e
f e f e f e f e
f e f e f e f e
f e f e f e f e
f e f e f e f e
f e f e f e f e
f e f e f e f e
f e f e f e f e
f e f e f e f e
f e f e f e f e
f e f e f e f e
f e f e f e f e
f e f e f e f e
f e f e f e f e
f e f e f e f e
f e f e f e f e
f e f e f e f e
f e f e f e f e
f e f e f e f e
f e f e f e f e
f e f e f e f e
f e f e f e f e
f e f e f e f e
f e f e f e f e
f e f e f e f e
f e f e f e f e
f e f e f e f e
f e f e f e f e
f e f e f e f e
f e f e f e f e
f e f e f e f e
f e f e f e f e
f e f e f e f e
f e f e f e f e
f e f e f e f e
f e f e f e f e
f e f e f e f e
f e f e f e f e
f e f e f e f e
f e f e f e f e
f e f e f e f e
f e f e f e f e
f e f e f e f e
f e f e f e f e
f e f e f e f e
f e f e f e f e
f e f e f e f e
f e f e f e f e
f e f e f e f e
f e f e f e f e
f e f e f e f e
f e f e f e f e
f e f e f e f e
f e f e f e f e
f e f e f e f e
f e f e f e f e
f e f e f e f e
}
>>
} %score
} %book
_______________________________________________
bug-lilypond mailing list
[email protected]
http://lists.gnu.org/mailman/listinfo/bug-lilypond