]> git.donarmstrong.com Git - lilypond.git/commitdiff
Add support for max-systems-per-page.
authorJoe Neeman <joeneeman@gmail.com>
Tue, 11 Nov 2008 21:25:28 +0000 (13:25 -0800)
committerJoe Neeman <joeneeman@gmail.com>
Tue, 11 Nov 2008 21:25:28 +0000 (13:25 -0800)
lily/include/page-breaking.hh
lily/page-breaking.cc
lily/page-spacing.cc

index 5768e4b1098af965a87f67d5efc22c44dc8f65e6..d69fe1ce5f42af1fb7a73348c3138dbef579a604 100644 (file)
@@ -103,9 +103,13 @@ public:
   bool ends_score () const;
   int systems_per_page () const;
   int max_systems_per_page () const;
+  int min_systems_per_page () const;
   Real page_height (int page_number, bool last) const;
   Real page_top_space () const;
   vsize system_count () const;
+  Real line_count_penalty (int line_count) const;
+  bool too_many_lines (int line_count) const;
+  bool too_few_lines (int line_count) const;
 
 protected:
   Paper_book *book_;
@@ -156,6 +160,7 @@ private:
   bool ragged_last_;
   int systems_per_page_;
   int max_systems_per_page_;
+  int min_systems_per_page_;
   Real page_top_space_;
   vsize system_count_;
 
index c8adcf64adaf278836390508b0990b9369832961..12372c1e49874cd66990e98d0d467be5f6dbbab7 100644 (file)
@@ -103,6 +103,7 @@ Page_breaking::Page_breaking (Paper_book *pb, Break_predicate is_break)
   page_top_space_ = robust_scm2double (pb->paper_->c_variable ("page-top-space"), 0);
   systems_per_page_ = robust_scm2int (pb->paper_->c_variable ("systems-per-page"), 0);
   max_systems_per_page_ = robust_scm2int (pb->paper_->c_variable ("max-systems-per-page"), 0);
+  min_systems_per_page_ = robust_scm2int (pb->paper_->c_variable ("min-systems-per-page"), 0);
 
   create_system_list ();
   find_chunks_and_breaks (is_break);
@@ -136,6 +137,12 @@ Page_breaking::max_systems_per_page () const
   return max_systems_per_page_;
 }
 
+int
+Page_breaking::min_systems_per_page () const
+{
+  return min_systems_per_page_;
+}
+
 Real
 Page_breaking::page_top_space () const
 {
@@ -148,6 +155,25 @@ Page_breaking::system_count () const
   return system_count_;
 }
 
+bool
+Page_breaking::too_many_lines (int line_count) const
+{
+  return max_systems_per_page () > 0 && line_count > max_systems_per_page ();
+}
+
+bool
+Page_breaking::too_few_lines (int line_count) const
+{
+  return line_count < min_systems_per_page ();
+}
+
+Real
+Page_breaking::line_count_penalty (int line_count) const
+{
+  // TODO: also check min_systems_per_page (once we support it in Page_spacer)
+  return too_many_lines (line_count) ? BAD_SPACING_PENALTY : 0;
+}
+
 /* translate indices into breaks_ into start-end parameters for the line breaker */
 void
 Page_breaking::line_breaker_args (vsize sys,
@@ -646,6 +672,7 @@ Page_breaking::min_page_count (vsize configuration, vsize first_page_num)
   Real cur_rod_height = 0;
   Real cur_spring_height = 0;
   Real cur_page_height = page_height (first_page_num, false);
+  int line_count = 0;
 
   cache_line_details (configuration);
   for (vsize i = 0; i < cached_line_details_.size (); i++)
@@ -656,11 +683,14 @@ Page_breaking::min_page_count (vsize configuration, vsize first_page_num)
       Real next_spring_height = cur_spring_height + cached_line_details_[i].space_;
       Real next_height = next_rod_height + (ragged () ? next_spring_height : 0);
 
+      line_count += cached_line_details_[i].compressed_nontitle_lines_count_;
 
       if ((next_height > cur_page_height && cur_rod_height > 0)
+         || too_many_lines (line_count)
          || (i > 0
              && cached_line_details_[i-1].page_permission_ == ly_symbol2scm ("force")))
        {
+         line_count = cached_line_details_[i].compressed_nontitle_lines_count_;
          cur_rod_height = ext_len;
          cur_spring_height = cached_line_details_[i].space_;
          cur_page_height = page_height (first_page_num + ret, false);
@@ -1028,6 +1058,8 @@ Page_breaking::space_systems_on_2_pages (vsize configuration, vsize first_page_n
   vector<Real> page2_force;
   Page_spacing page1 (page1_height, page_top_space_);
   Page_spacing page2 (page2_height, page_top_space_);
+  int page1_line_count = 0;
+  int page2_line_count = 0;
 
   page1_force.resize (cached_line_details_.size () - 1, infinity_f);
   page2_force.resize (cached_line_details_.size () - 1, infinity_f);
@@ -1037,13 +1069,22 @@ Page_breaking::space_systems_on_2_pages (vsize configuration, vsize first_page_n
     {
       page1.append_system (cached_line_details_[i]);
       page2.prepend_system (cached_line_details_[cached_line_details_.size () - 1 - i]);
-      page1_force[i] = (ragged1 && page1.force_ < 0 && i > 0) ? infinity_f : page1.force_;
+      page1_line_count += cached_line_details_[i].compressed_nontitle_lines_count_;
+      page2_line_count += cached_line_details_[cached_line_details_.size () - 1 - i].compressed_nontitle_lines_count_;
+
+      // NOTE: we treat max-systems-per-page and min-systems-per-page as soft
+      // constraints. That is, we penalize harshly when they don't happen
+      // but we don't completely reject.
+      page1_force[i] = line_count_penalty (page1_line_count) 
+       + (ragged1 && page1.force_ < 0 && i > 0) ? infinity_f : page1.force_;
 
       if (ragged2)
        page2_force[page2_force.size () - 1 - i] =
          (page2.force_ < 0 && i + 1 < page1_force.size ()) ? infinity_f : 0;
       else
        page2_force[page2_force.size () - 1 - i] = page2.force_;
+
+      page2_force[page2_force.size () - 1 - i] += line_count_penalty (page2_line_count);
     }
 
   /* find the position that minimises the sum of the page forces */
index a6d98d82ef32d0c99cbf7d79e9d3a8c743b859e8..c4266935cea4686966edce2eee60746b7dfcd049 100644 (file)
@@ -193,10 +193,15 @@ Page_spacer::calc_subproblem (vsize page, vsize line)
                      breaker_->page_top_space ());
   Page_spacing_node &cur = state_.at (line, page);
   bool ragged = ragged_ || (ragged_last_ && last);
+  int line_count = 0;
 
   for (vsize page_start = line+1; page_start > page && page_start--;)
     {
       Page_spacing_node const *prev = page > 0 ? &state_.at (page_start-1, page-1) : 0;
+      line_count += lines_[page_start].compressed_nontitle_lines_count_;
+
+      if (breaker_->too_many_lines (line_count))
+       break;
 
       space.prepend_system (lines_[page_start]);
       if (page_start < line && (isinf (space.force_) || (space.force_ < 0 && ragged)))
@@ -207,7 +212,9 @@ 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 */
+         /* we may have to deal with single lines that are taller than a page, in
+            which case we can't make the force infinite, but we should make
+            it very large. */
          if (isinf (space.force_) && page_start == line)
            space.force_ = -BAD_SPACING_PENALTY;