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_;
bool ragged_last_;
int systems_per_page_;
int max_systems_per_page_;
+ int min_systems_per_page_;
Real page_top_space_;
vsize system_count_;
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);
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
{
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,
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++)
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);
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);
{
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 */
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)))
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;