page_penalty_ = 0;
turn_penalty_ = 0;
title_ = false;
- compressed_lines_count_ = 0;
- compressed_nontitle_lines_count_ = 0;
+ compressed_lines_count_ = 1;
+ compressed_nontitle_lines_count_ = 1;
}
Line_details (Prob *pb)
page_penalty_ = robust_scm2double (pb->get_property ("page-break-penalty"), 0);
turn_penalty_ = robust_scm2double (pb->get_property ("page-turn-penalty"), 0);
title_ = to_boolean (pb->get_property ("is-title"));
- compressed_lines_count_ = 0;
- compressed_nontitle_lines_count_ = 0;
+ compressed_lines_count_ = 1;
+ compressed_nontitle_lines_count_ = title_ ? 0 : 1;
}
};
vsize current_configuration_count () const;
Line_division current_configuration (vsize configuration_index) const;
Page_spacing_result space_systems_on_n_pages (vsize configuration_index,
- vsize n, vsize first_page_num);
+ vsize n, vsize first_page_num,
+ int systems_per_page=0);
Page_spacing_result space_systems_on_n_or_one_more_pages (vsize configuration_index, vsize n,
- vsize first_page_num);
+ vsize first_page_num,
+ int systems_per_page=0);
Page_spacing_result space_systems_on_best_pages (vsize configuration_index,
vsize first_page_num);
Page_spacing_result space_systems_with_fixed_number_per_page (vsize configuration_index,
- int systems_per_page,
- vsize first_page_num);
+ vsize first_page_num,
+ int systems_per_page);
Page_spacing_result pack_systems_on_least_pages (vsize configuration_index,
vsize first_page_num);
vsize min_page_count (vsize configuration_index, vsize first_page_num);
#include "constrained-breaking.hh"
#include "page-spacing-result.hh"
+/* This is a penalty that we add whenever a page breaking solution
+ is not bad enough to completely discard, but bad enough that
+ it is worse than any "proper" solution. For example, if we didn't
+ manage to fit systems on the desired number of pages or if there was
+ too big for a page.
+
+ This constant is large enough that it dominates any reasonable penalty,
+ but small enough that nothing will overflow to infinity (so that we
+ can still distinguish bad spacings by the number of BAD_SPACING_PENALTYs
+ that they incur.
+*/
+const Real BAD_SPACING_PENALTY = 200000;
+
/* for page_count > 2, we use a dynamic algorithm similar to
constrained-breaking -- we have a class that stores the intermediate
vsize max_sys_count = max_system_count (0, end);
vsize first_page_num = robust_scm2int (book_->paper_->c_variable ("first-page-number"), 1);
SCM forced_page_count = book_->paper_->c_variable ("page-count");
+ int systems_per_page = robust_scm2int (book_->paper_->c_variable ("systems-per-page"), 0);
set_to_ideal_line_configuration (0, end);
/* find out the ideal number of pages */
message (_ ("Finding the ideal number of pages..."));
- best = space_systems_on_best_pages (0, first_page_num);
- page_count = best.systems_per_page_.size ();
+ if (systems_per_page > 0)
+ best = space_systems_with_fixed_number_per_page (0, first_page_num, systems_per_page);
+ else
+ best = space_systems_on_best_pages (0, first_page_num);
+ page_count = best.systems_per_page_.size ();
ideal_sys_count = best.system_count ();
min_sys_count = ideal_sys_count - best.systems_per_page_.back ();
}
else
{
- /* todo: the following line will spit out programming errors if the
+ /* TODO: the following line will spit out programming errors if the
ideal line spacing doesn't fit on PAGE_COUNT pages */
- best = space_systems_on_n_pages (0, page_count, first_page_num);
+ /* TODO: the interaction between systems_per_page and page_count needs to
+ be considered. */
+ best = space_systems_on_n_pages (0, page_count, first_page_num, systems_per_page);
min_sys_count = page_count;
}
Page_spacing_result cur;
if (min_p_count == page_count || scm_is_integer (forced_page_count))
- cur = space_systems_on_n_pages (i, page_count, first_page_num);
+ cur = space_systems_on_n_pages (i, page_count, first_page_num, systems_per_page);
else
- cur = space_systems_on_n_or_one_more_pages (i, page_count-1, first_page_num);
+ cur = space_systems_on_n_or_one_more_pages (i, page_count-1, first_page_num, systems_per_page);
if (cur.demerits_ < best_for_this_sys_count.demerits_ || isinf (best_for_this_sys_count.demerits_))
{
if (min_p_count > page_count)
continue;
else
- cur = space_systems_on_n_pages (i, page_count, first_page_num);
+ cur = space_systems_on_n_pages (i, page_count, first_page_num, systems_per_page);
if (cur.demerits_ < best.demerits_ || isinf (best.demerits_))
{
{
int compressed_count = 0;
for (vsize j = start_sys; j < start_sys + systems_per_page[i]; j++)
- compressed_count += compressed[j].compressed_lines_count_;
+ compressed_count += compressed[j].compressed_lines_count_ - 1;
ret.push_back (systems_per_page[i] + compressed_count);
start_sys += systems_per_page[i];
return ret;
}
+// If systems_per_page is positive, we don't really try to space on N pages;
+// we just put the requested number of systems on each page and penalize
+// if the result doesn't have N pages.
Page_spacing_result
-Page_breaking::space_systems_on_n_pages (vsize configuration, vsize n, vsize first_page_num)
+Page_breaking::space_systems_on_n_pages (vsize configuration, vsize n, vsize first_page_num,
+ int systems_per_page)
{
Page_spacing_result ret;
+ if (systems_per_page > 0)
+ {
+ Page_spacing_result ret = space_systems_with_fixed_number_per_page (configuration, first_page_num,
+ systems_per_page);
+ ret.demerits_ += (ret.force_.size () == n) ? 0 : BAD_SPACING_PENALTY;
+ return ret;
+ }
+
cache_line_details (configuration);
bool valid_n = (n >= min_page_count (configuration, first_page_num)
&& n <= cached_line_details_.size ());
return robust_scm2double (book_->paper_->lookup_variable (penalty_sym), 0.0);
}
+// If systems_per_page is positive, we don't really try to space on N
+// or N+1 pages; see the comment to space_systems_on_n_pages.
Page_spacing_result
-Page_breaking::space_systems_on_n_or_one_more_pages (vsize configuration, vsize n, vsize first_page_num)
+Page_breaking::space_systems_on_n_or_one_more_pages (vsize configuration, vsize n, vsize first_page_num,
+ int systems_per_page)
{
Page_spacing_result n_res;
Page_spacing_result m_res;
+ if (systems_per_page > 0)
+ {
+ Page_spacing_result ret = space_systems_with_fixed_number_per_page (configuration, first_page_num,
+ systems_per_page);
+ ret.demerits_ += (ret.force_.size () == n || ret.force_.size () == (n-1)) ? 0 : BAD_SPACING_PENALTY;
+ return ret;
+ }
+
cache_line_details (configuration);
vsize min_p_count = min_page_count (configuration, first_page_num);
bool valid_n = n >= min_p_count || n <= cached_line_details_.size ();
Page_spacing_result
Page_breaking::space_systems_with_fixed_number_per_page (vsize configuration,
- int systems_per_page,
- vsize first_page_num)
+ vsize first_page_num,
+ int systems_per_page)
{
Page_spacing_result res;
Page_spacing space (page_height (first_page_num, false), page_top_space_);
while (system_count_on_this_page < systems_per_page
&& line < cached_line_details_.size ())
{
- space.append_system (cached_line_details_[line]);
- system_count_on_this_page += cached_line_details_[line].compressed_nontitle_lines_count_;
+ Line_details const &cur_line = cached_line_details_[line];
+ space.append_system (cur_line);
+ system_count_on_this_page += cur_line.compressed_nontitle_lines_count_;
line++;
+
+ if (cur_line.page_permission_ == ly_symbol2scm ("force"))
+ break;
}
res.systems_per_page_.push_back (line - page_first_line);
if (extra_systems)
{
ret.systems_per_page_.back () += extra_systems;
- ret.demerits_ += 200000;
+ ret.demerits_ += BAD_SPACING_PENALTY;
}
if (extra_pages)
{
- ret.force_.insert (ret.force_.end (), extra_pages, 200000);
+ ret.force_.insert (ret.force_.end (), extra_pages, BAD_SPACING_PENALTY);
ret.systems_per_page_.insert (ret.systems_per_page_.end (), extra_pages, 0);
- ret.demerits_ += 200000;
+ ret.demerits_ += BAD_SPACING_PENALTY;
}
/* we may have to deal with single lines that are taller than a page */
if (isinf (space.force_) && page_start == line)
- space.force_ = -200000;
+ space.force_ = -BAD_SPACING_PENALTY;
Real dem = fabs (space.force_) + (prev ? prev->demerits_ : 0);
Real penalty = 0;