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;
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;
+ 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;
+ 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->shape_ = Line_shape (begin_of_line_extent, 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
last_column_ = 0;
force_ = 0;
- extent_ = unsmob_stencil (pb->get_property ("stencil")) ->extent (Y_AXIS);
+ Interval stencil_extent = unsmob_stencil (pb->get_property ("stencil"))->extent (Y_AXIS);
+ shape_ = Line_shape (stencil_extent, stencil_extent); // pretend it goes all the way across
+ tallness_ = 0;
bottom_padding_ = 0;
space_ = 0.0;
inverse_hooke_ = 1.0;
SCM first_scm = pb->get_property ("first-markup-line");
first_markup_line_ = to_boolean (first_scm);
}
+
+Real
+Line_details::full_height () const
+{
+ Interval ret;
+ ret.unite(shape_.begin_);
+ ret.unite(shape_.rest_);
+ return ret.length();
+}
+
+Real
+Line_details::tallness () const
+{
+ return tallness_;
+}
+
+Line_shape::Line_shape (Interval begin, Interval rest)
+{
+ begin_ = begin;
+ rest_ = rest;
+}
+
+Line_shape
+Line_shape::piggyback (Line_shape mount, Real padding) const
+{
+ Real elevation = max (begin_[UP]-mount.begin_[DOWN], rest_[UP]-mount.rest_[DOWN]);
+ Interval begin = Interval (begin_[DOWN], elevation + mount.begin_[UP] + padding);
+ Interval rest = Interval (rest_[DOWN], elevation + mount.rest_[UP] + padding);
+ return Line_shape (begin, rest);
+}
#include "matrix.hh"
#include "prob.hh"
+/*
+ * Begin/rest-of-line hack. This geometrical shape is a crude approximation
+ * of Skyline, but it is better than a rectangle.
+ */
+struct Line_shape
+{
+ Interval begin_;
+ Interval rest_;
+
+ Line_shape ()
+ {
+ }
+ Line_shape (Interval begin, Interval rest);
+ Line_shape piggyback (Line_shape mount, Real padding) const;
+};
+
struct Line_details {
Grob *last_column_;
Real force_;
- Interval extent_; /* Y-extent of the system */
+ Line_shape shape_;
+ Real tallness_; /* Y-extent, adjusted according to begin/rest-of-line*/
Real padding_; /* compulsory space after this system (if we're not
last on a page) */
compressed_nontitle_lines_count_ = 1;
last_markup_line_ = false;
first_markup_line_ = false;
+ tallness_ = 0;
}
Line_details (Prob *pb, Output_def *paper);
+ Real full_height () const;
+ Real tallness () const;
};
/*
vsize current_end_breakpoint_;
void cache_line_details (vsize configuration_index);
+ void compute_line_heights ();
void clear_line_details_cache ();
vsize cached_configuration_index_;
vector<Line_details> cached_line_details_;
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);
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.shape_ = old.shape_.piggyback (orig[i].shape_, padding);
compressed.space_ += old.space_;
compressed.inverse_hooke_ += old.inverse_hooke_;
}
}
+void
+Page_breaking::compute_line_heights ()
+{
+ Real prev_hanging = 0;
+ Real prev_hanging_begin = 0;
+ Real prev_hanging_rest = 0;
+ for (vsize i = 0; i < cached_line_details_.size (); i++)
+ {
+ Line_shape shape = cached_line_details_[i].shape_;
+ Real a = shape.begin_[UP];
+ Real b = shape.rest_[UP];
+ Real midline_hanging = max (prev_hanging_begin + a, prev_hanging_rest + b);
+ Real hanging_begin = midline_hanging - shape.begin_[DOWN];
+ Real hanging_rest = midline_hanging - shape.rest_[DOWN];
+ Real hanging = max (hanging_begin, hanging_rest);
+ cached_line_details_[i].tallness_ = hanging - prev_hanging;
+ prev_hanging = hanging;
+ prev_hanging_begin = hanging_begin;
+ prev_hanging_rest = hanging_rest;
+ }
+}
+
vsize
Page_breaking::min_page_count (vsize configuration, vsize first_page_num)
{
int line_count = 0;
cache_line_details (configuration);
+ compute_line_heights ();
if (cached_line_details_.size ())
cur_page_height -= min_whitespace_at_top_of_page (cached_line_details_[0]);
for (vsize i = 0; i < cached_line_details_.size (); i++)
{
- Real ext_len = cached_line_details_[i].extent_.length ();
Real padding = 0;
+ Real ext_len;
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_;
+ ext_len = cached_line_details_[i].tallness_;
+ }
+ else
+ {
+ ext_len = cached_line_details_[i].full_height();
+ }
Real next_rod_height = cur_rod_height + ext_len + padding;
Real next_spring_height = cur_spring_height + cached_line_details_[i].space_;
Real next_height = next_rod_height + (ragged () ? next_spring_height : 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_rod_height = cached_line_details_[i].full_height();
cur_spring_height = cached_line_details_[i].space_;
page_starter = i;
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 ());
ly_symbol2scm ("padding"));
// FIXME: take into account the height of the header
- return max (0.0, max (padding, min_distance - line.extent_[UP]));
+ Real translate = max (line.shape_.begin_[UP], line.shape_.rest_[UP]);
+ return max (0.0, max (padding, min_distance - translate));
}
Real
ly_symbol2scm ("padding"));
// FIXME: take into account the height of the footer
- return max (0.0, max (padding, min_distance + line.extent_[DOWN]));
+ Real translate = min (line.shape_.begin_[DOWN], line.shape_.rest_[DOWN]);
+ return max (0.0, max (padding, min_distance + translate));
}
int
void
Page_spacing::append_system (const Line_details &line)
{
- if (!rod_height_)
- first_line_ = line;
-
+ if (rod_height_)
+ {
+ rod_height_ += line.tallness_;
+ }
+ else
+ {
+ rod_height_ += line.full_height ();
+ first_line_ = line;
+ }
rod_height_ += line.title_ ? last_line_.title_padding_ : last_line_.padding_;
-
- rod_height_ += line.extent_.length ();
spring_len_ += line.space_;
inverse_spring_k_ += line.inverse_hooke_;
else
last_line_ = line;
- rod_height_ += line.extent_.length ();
+ rod_height_ -= first_line_.full_height ();
+ rod_height_ += first_line_.tallness_;
+ rod_height_ += line.full_height();
spring_len_ += line.space_;
inverse_spring_k_ += line.inverse_hooke_;
return 0;
}
+Interval
+System::part_of_line_pure_height (vsize start, vsize end, bool begin)
+{
+ Grob *alignment = get_vertical_alignment ();
+ if (!alignment)
+ {
+ programming_error("system does not have a vertical alignment");
+ return Interval();
+ }
+ 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);
+ if (i<offsets.size())
+ 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"