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
bug-lilypond@gnu.org
http://lists.gnu.org/mailman/listinfo/bug-lilypond

Reply via email to