From: Mike Solomon Date: Wed, 9 Nov 2011 14:02:35 +0000 (+0100) Subject: Makes line breaking options more accessible to grobs. X-Git-Tag: release/2.15.17-1~2^2~1 X-Git-Url: https://git.donarmstrong.com/?a=commitdiff_plain;h=408475516f7db93450e45c7e1b4a2660a4fa96c0;p=lilypond.git Makes line breaking options more accessible to grobs. --- diff --git a/lily/column-description.cc b/lily/column-description.cc new file mode 100644 index 0000000000..d7a198734a --- /dev/null +++ b/lily/column-description.cc @@ -0,0 +1,72 @@ +/* + This file is part of LilyPond, the GNU music typesetter. + + Copyright (C) 2011 Mike Solomon + + LilyPond is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + LilyPond is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with LilyPond. If not, see . +*/ + +#include + +#include "column-description.hh" +#include "paper-column.hh" +#include "simple-spacer.hh" +#include "spaceable-grob.hh" +#include "spring.hh" + +static Grob * +next_spaceable_column (vector const &list, vsize starting) +{ + for (vsize i = starting + 1; i < list.size (); i++) + if (!Paper_column::is_loose (list[i])) + return list[i]; + return 0; +} + +Column_description +Column_description::get_column_description (vector const &cols, vsize col_index, bool line_starter) +{ + Grob *col = cols[col_index]; + if (line_starter) + col = Item::maybe_find_prebroken_piece (dynamic_cast (col), RIGHT); + + Column_description description; + Grob *next_col = next_spaceable_column (cols, col_index); + if (next_col) + description.spring_ = Spaceable_grob::get_spring (col, next_col); + + Grob *end_col = dynamic_cast (cols[col_index + 1])->find_prebroken_piece (LEFT); + if (end_col) + description.end_spring_ = Spaceable_grob::get_spring (col, end_col); + + for (SCM s = Spaceable_grob::get_minimum_distances (col); + scm_is_pair (s); s = scm_cdr (s)) + { + Grob *other = unsmob_grob (scm_caar (s)); + vsize j = binary_search (cols, other, Paper_column::less_than, col_index); + if (j != VPOS) + { + if (cols[j] == other) + description.rods_.push_back (Rod_description (j, scm_to_double (scm_cdar (s)))); + else /* it must end at the LEFT prebroken_piece */ + description.end_rods_.push_back (Rod_description (j, scm_to_double (scm_cdar (s)))); + } + } + + if (!line_starter && to_boolean (col->get_property ("keep-inside-line"))) + description.keep_inside_line_ = col->extent (col, X_AXIS); + + description.break_permission_ = col->get_property ("line-break-permission"); + return description; +} \ No newline at end of file diff --git a/lily/constrained-breaking.cc b/lily/constrained-breaking.cc index 1e7fe96c51..7e5bfadd50 100644 --- a/lily/constrained-breaking.cc +++ b/lily/constrained-breaking.cc @@ -436,10 +436,10 @@ Constrained_breaking::initialize () breaks_ = pscore_->get_break_indices (); all_ = pscore_->root_system ()->used_columns (); lines_.resize (breaks_.size (), breaks_.size (), Line_details ()); - vector forces = get_line_forces (all_, - other_lines.length (), - other_lines.length () - first_line.length (), - ragged_right_); + vector spacers = + pscore_->root_system ()->get_simple_spacers(other_lines.length (), + other_lines.length () - first_line.length (), + ragged_right_); for (vsize i = 0; i + 1 < breaks_.size (); i++) { for (vsize j = i + 1; j < breaks_.size (); j++) @@ -448,9 +448,18 @@ Constrained_breaking::initialize () bool ragged = ragged_right_ || (last && ragged_last_); Line_details &line = lines_.at (j, i); - line.force_ = forces[i * breaks_.size () + j]; + line.force_ = spacers[i * breaks_.size () + j].force_penalty (ragged_right_); + if (!spacers[i * breaks_.size () + j].fits ()) + { + if (spacers[i * breaks_.size () + j].minimal_) + line.force_ = -200000; + else + line.force_ = infinity_f; + } if (ragged && last && !isinf (line.force_)) line.force_ = (line.force_ < 0 && j > i + 1) ? infinity_f : 0; + if (!line.force_ && !spacers[i * breaks_.size () + j].line_len ()) + line.force_ = infinity_f; if (isinf (line.force_)) break; diff --git a/lily/include/column-description.hh b/lily/include/column-description.hh new file mode 100644 index 0000000000..0c252149de --- /dev/null +++ b/lily/include/column-description.hh @@ -0,0 +1,67 @@ +/* + This file is part of LilyPond, the GNU music typesetter. + + Copyright (C) 2011 Mike Solomon + + LilyPond is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + LilyPond is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with LilyPond. If not, see . +*/ + +#ifndef COLUMN_DESCRIPTION_HH +#define COLUMN_DESCRIPTION_HH + +#include "lily-proto.hh" +#include "smobs.hh" +#include "spring.hh" + +struct Rod_description +{ + vsize r_; + Real dist_; + + bool operator < (const Rod_description r) + { + return r_ < r.r_; + } + + Rod_description () + { + r_ = 0; + dist_ = 0; + } + + Rod_description (vsize r, Real d) + { + r_ = r; + dist_ = d; + } +}; + +struct Column_description +{ + vector rods_; + vector end_rods_; /* use these if they end at the last column of the line */ + Spring spring_; + Spring end_spring_; + + SCM break_permission_; + Interval keep_inside_line_; + + Column_description () + { + break_permission_ = SCM_EOL; + } + static Column_description get_column_description (vector const &cols, vsize col_index, bool line_starter); +}; + +#endif /* COLUMN_DESCRIPTION_HH */ diff --git a/lily/include/item.hh b/lily/include/item.hh index 945866632e..73b3bc7b3f 100644 --- a/lily/include/item.hh +++ b/lily/include/item.hh @@ -40,6 +40,7 @@ public: static bool is_non_musical (Grob *); static bool break_visible (Grob *); + static Item * maybe_find_prebroken_piece (Item *g, Direction d); bool is_broken () const; virtual bool pure_is_visible (int start, int end) const; diff --git a/lily/include/paper-column.hh b/lily/include/paper-column.hh index acfd84668a..c91f66b3c9 100644 --- a/lily/include/paper-column.hh +++ b/lily/include/paper-column.hh @@ -52,6 +52,7 @@ public: DECLARE_GROB_INTERFACE (); static int get_rank (Grob const *); + static bool is_loose (Grob *); static bool is_musical (Grob *); static Moment when_mom (Grob *); static bool is_used (Grob *); diff --git a/lily/include/simple-spacer.hh b/lily/include/simple-spacer.hh index 620921fe9a..b5aeeb200d 100644 --- a/lily/include/simple-spacer.hh +++ b/lily/include/simple-spacer.hh @@ -30,6 +30,8 @@ class Simple_spacer public: Simple_spacer (); + bool minimal_; + void solve (Real line_len, bool ragged); void add_rod (int l, int r, Real dist); void add_spring (Spring const &); @@ -39,12 +41,14 @@ public: vector spring_positions () const; Real force () const; + Real line_len () const; Real force_penalty (bool ragged) const; bool fits () const; DECLARE_SIMPLE_SMOBS (Simple_spacer); private: + Real expand_line (); Real compress_line (); Real rod_force (int l, int r, Real dist); @@ -56,12 +60,6 @@ private: bool fits_; }; -/* returns a vector of dimensions breaks.size () * breaks.size () */ -vector get_line_forces (vector const &columns, - Real line_len, - Real indent, - bool ragged); - Column_x_positions get_line_configuration (vector const &columns, Real line_len, Real indent, diff --git a/lily/include/system.hh b/lily/include/system.hh index f002d72c0f..165b589c37 100644 --- a/lily/include/system.hh +++ b/lily/include/system.hh @@ -32,6 +32,7 @@ class System : public Spanner { int rank_; + vector simple_spacers_; Grob_array *all_elements_; void init_elements (); friend class Paper_score; // ugh. @@ -46,6 +47,8 @@ public: Grob *get_pure_bound (Direction dir, int start, int end); Grob *get_maybe_pure_bound (Direction dir, bool pure, int start, int end); int get_rank () const; + vector get_simple_spacers (Real line_len, Real indent, bool ragged); + void gen_simple_spacers (Real line_len, Real indent, bool ragged); vector get_footnote_heights_in_range (vsize st, vsize end); vector get_in_note_heights_in_range (vsize st, vsize end); vector internal_get_note_heights_in_range (vsize st, vsize end, bool foot); diff --git a/lily/item.cc b/lily/item.cc index 6a468a6830..c3718796e0 100644 --- a/lily/item.cc +++ b/lily/item.cc @@ -130,6 +130,15 @@ Item::find_broken_piece (System *l) const return 0; } +Item * +Item::maybe_find_prebroken_piece (Item *g, Direction d) +{ + Item *ret = g->find_prebroken_piece (d); + if (ret) + return ret; + return g; +} + Item * Item::find_prebroken_piece (Direction d) const { diff --git a/lily/paper-column.cc b/lily/paper-column.cc index 271a752a26..8f392bb930 100644 --- a/lily/paper-column.cc +++ b/lily/paper-column.cc @@ -123,6 +123,12 @@ Paper_column::when_mom (Grob *me) return Moment (0); } +bool +Paper_column::is_loose (Grob *g) +{ + return (scm_is_pair (g->get_object ("between-cols"))); +} + bool Paper_column::is_musical (Grob *me) { diff --git a/lily/simple-spacer.cc b/lily/simple-spacer.cc index 4644ad7c4b..a870ee3dcc 100644 --- a/lily/simple-spacer.cc +++ b/lily/simple-spacer.cc @@ -22,6 +22,7 @@ #include +#include "column-description.hh" #include "column-x-positions.hh" #include "dimensions.hh" #include "international.hh" @@ -82,6 +83,12 @@ Simple_spacer::force () const return force_; } +Real +Simple_spacer::line_len () const +{ + return line_len_; +} + bool Simple_spacer::fits () const { @@ -289,179 +296,6 @@ Simple_spacer::force_penalty (bool ragged) const /****************************************************************/ -struct Rod_description -{ - vsize r_; - Real dist_; - - bool operator < (const Rod_description r) - { - return r_ < r.r_; - } - - Rod_description () - { - r_ = 0; - dist_ = 0; - } - - Rod_description (vsize r, Real d) - { - r_ = r; - dist_ = d; - } -}; - -struct Column_description -{ - vector rods_; - vector end_rods_; /* use these if they end at the last column of the line */ - Spring spring_; - Spring end_spring_; - - SCM break_permission_; - Interval keep_inside_line_; - - Column_description () - { - break_permission_ = SCM_EOL; - } -}; - -static bool -is_loose (Grob *g) -{ - return (scm_is_pair (g->get_object ("between-cols"))); -} - -static Grob * -maybe_find_prebroken_piece (Grob *g, Direction d) -{ - Grob *ret = dynamic_cast (g)->find_prebroken_piece (d); - if (ret) - return ret; - return g; -} - -static Grob * -next_spaceable_column (vector const &list, vsize starting) -{ - for (vsize i = starting + 1; i < list.size (); i++) - if (!is_loose (list[i])) - return list[i]; - return 0; -} - -static Column_description -get_column_description (vector const &cols, vsize col_index, bool line_starter) -{ - Grob *col = cols[col_index]; - if (line_starter) - col = maybe_find_prebroken_piece (col, RIGHT); - - Column_description description; - Grob *next_col = next_spaceable_column (cols, col_index); - if (next_col) - description.spring_ = Spaceable_grob::get_spring (col, next_col); - - Grob *end_col = dynamic_cast (cols[col_index + 1])->find_prebroken_piece (LEFT); - if (end_col) - description.end_spring_ = Spaceable_grob::get_spring (col, end_col); - - for (SCM s = Spaceable_grob::get_minimum_distances (col); - scm_is_pair (s); s = scm_cdr (s)) - { - Grob *other = unsmob_grob (scm_caar (s)); - vsize j = binary_search (cols, other, Paper_column::less_than, col_index); - if (j != VPOS) - { - if (cols[j] == other) - description.rods_.push_back (Rod_description (j, scm_to_double (scm_cdar (s)))); - else /* it must end at the LEFT prebroken_piece */ - description.end_rods_.push_back (Rod_description (j, scm_to_double (scm_cdar (s)))); - } - } - - if (!line_starter && to_boolean (col->get_property ("keep-inside-line"))) - description.keep_inside_line_ = col->extent (col, X_AXIS); - - description.break_permission_ = col->get_property ("line-break-permission"); - return description; -} - -vector -get_line_forces (vector const &columns, - Real line_len, Real indent, bool ragged) -{ - vector breaks; - vector force; - vector non_loose; - vector cols; - SCM force_break = ly_symbol2scm ("force"); - - for (vsize i = 0; i < columns.size (); i++) - if (!is_loose (columns[i]) || Paper_column::is_breakable (columns[i])) - non_loose.push_back (columns[i]); - - breaks.clear (); - breaks.push_back (0); - cols.push_back (Column_description ()); - for (vsize i = 1; i + 1 < non_loose.size (); i++) - { - if (Paper_column::is_breakable (non_loose[i])) - breaks.push_back (cols.size ()); - - cols.push_back (get_column_description (non_loose, i, false)); - } - breaks.push_back (cols.size ()); - force.resize (breaks.size () * breaks.size (), infinity_f); - - for (vsize b = 0; b + 1 < breaks.size (); b++) - { - cols[breaks[b]] = get_column_description (non_loose, breaks[b], true); - vsize st = breaks[b]; - - for (vsize c = b + 1; c < breaks.size (); c++) - { - vsize end = breaks[c]; - Simple_spacer spacer; - - for (vsize i = breaks[b]; i < end - 1; i++) - spacer.add_spring (cols[i].spring_); - spacer.add_spring (cols[end - 1].end_spring_); - - for (vsize i = breaks[b]; i < end; i++) - { - for (vsize r = 0; r < cols[i].rods_.size (); r++) - if (cols[i].rods_[r].r_ < end) - spacer.add_rod (i - st, cols[i].rods_[r].r_ - st, cols[i].rods_[r].dist_); - for (vsize r = 0; r < cols[i].end_rods_.size (); r++) - if (cols[i].end_rods_[r].r_ == end) - spacer.add_rod (i - st, end - st, cols[i].end_rods_[r].dist_); - if (!cols[i].keep_inside_line_.is_empty ()) - { - spacer.add_rod (i - st, end - st, cols[i].keep_inside_line_[RIGHT]); - spacer.add_rod (0, i - st, -cols[i].keep_inside_line_[LEFT]); - } - } - spacer.solve ((b == 0) ? line_len - indent : line_len, ragged); - force[b * breaks.size () + c] = spacer.force_penalty (ragged); - - if (!spacer.fits ()) - { - if (c == b + 1) - force[b * breaks.size () + c] = -200000; - else - force[b * breaks.size () + c] = infinity_f; - break; - } - if (end < cols.size () && cols[end].break_permission_ == force_break) - break; - } - } - return force; -} - Column_x_positions get_line_configuration (vector const &columns, Real line_len, @@ -475,7 +309,7 @@ get_line_configuration (vector const &columns, ret.cols_.push_back (dynamic_cast (columns[0])->find_prebroken_piece (RIGHT)); for (vsize i = 1; i + 1 < columns.size (); i++) { - if (is_loose (columns[i])) + if (Paper_column::is_loose (columns[i])) ret.loose_cols_.push_back (columns[i]); else ret.cols_.push_back (columns[i]); @@ -486,7 +320,7 @@ get_line_configuration (vector const &columns, the end_XXX_ fields of our column_description */ for (vsize i = 0; i + 1 < ret.cols_.size (); i++) { - cols.push_back (get_column_description (ret.cols_, i, i == 0)); + cols.push_back (Column_description::get_column_description (ret.cols_, i, i == 0)); spacer.add_spring (cols[i].spring_); } for (vsize i = 0; i < cols.size (); i++) @@ -523,7 +357,6 @@ get_line_configuration (vector const &columns, return ret; } - #include "ly-smobs.icc" IMPLEMENT_SIMPLE_SMOBS (Simple_spacer); diff --git a/lily/system.cc b/lily/system.cc index e3b48bda71..176e338a54 100644 --- a/lily/system.cc +++ b/lily/system.cc @@ -23,6 +23,7 @@ #include "all-font-metrics.hh" #include "axis-group-interface.hh" #include "break-align-interface.hh" +#include "column-description.hh" #include "grob-array.hh" #include "hara-kiri-group-spanner.hh" #include "international.hh" @@ -703,6 +704,82 @@ System::get_extremal_staff (Direction dir, Interval const &iv) return 0; } +vector +System::get_simple_spacers (Real line_len, Real indent, bool ragged) +{ + if (!simple_spacers_.size ()) + gen_simple_spacers (line_len, indent, ragged); + + return simple_spacers_; +} + +void +System::gen_simple_spacers (Real line_len, Real indent, bool ragged) +{ + vector breaks; + vector non_loose; + vector cols; + SCM force_break = ly_symbol2scm ("force"); + vector columns = used_columns (); + + for (vsize i = 0; i < columns.size (); i++) + if (!Paper_column::is_loose (columns[i]) + || Paper_column::is_breakable (columns[i])) + non_loose.push_back (columns[i]); + + breaks.clear (); + breaks.push_back (0); + cols.push_back (Column_description ()); + for (vsize i = 1; i + 1 < non_loose.size (); i++) + { + if (Paper_column::is_breakable (non_loose[i])) + breaks.push_back (cols.size ()); + + cols.push_back (Column_description::get_column_description (non_loose, i, false)); + } + breaks.push_back (cols.size ()); + simple_spacers_.resize (breaks.size () * breaks.size (), Simple_spacer ()); + + for (vsize b = 0; b + 1 < breaks.size (); b++) + { + cols[breaks[b]] = Column_description::get_column_description (non_loose, breaks[b], true); + vsize st = breaks[b]; + + for (vsize c = b + 1; c < breaks.size (); c++) + { + vsize end = breaks[c]; + Simple_spacer spacer; + + for (vsize i = breaks[b]; i < end - 1; i++) + spacer.add_spring (cols[i].spring_); + spacer.add_spring (cols[end - 1].end_spring_); + + for (vsize i = breaks[b]; i < end; i++) + { + for (vsize r = 0; r < cols[i].rods_.size (); r++) + if (cols[i].rods_[r].r_ < end) + spacer.add_rod (i - st, cols[i].rods_[r].r_ - st, cols[i].rods_[r].dist_); + for (vsize r = 0; r < cols[i].end_rods_.size (); r++) + if (cols[i].end_rods_[r].r_ == end) + spacer.add_rod (i - st, end - st, cols[i].end_rods_[r].dist_); + if (!cols[i].keep_inside_line_.is_empty ()) + { + spacer.add_rod (i - st, end - st, cols[i].keep_inside_line_[RIGHT]); + spacer.add_rod (0, i - st, -cols[i].keep_inside_line_[LEFT]); + } + } + spacer.solve ((b == 0) ? line_len - indent : line_len, ragged); + spacer.minimal_ = c == b + 1; + simple_spacers_[b * breaks.size () + c] = spacer; + + if (!spacer.fits () + || (end < cols.size () + && cols[end].break_permission_ == force_break)) + break; + } + } +} + Interval System::pure_refpoint_extent (vsize start, vsize end) {