X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=lily%2Fsimple-spacer.cc;h=cf4fd5849e35601ad8cf839394d7f6d6ba407c8e;hb=97a0169312a260933246ab224e4f8b0969871dd5;hp=c6b3c06f5d3a710fdb2c875aa6e27f8aaaf33ed6;hpb=968e4722ea19df8485b5fec506c3b2dc9a29c664;p=lilypond.git diff --git a/lily/simple-spacer.cc b/lily/simple-spacer.cc index c6b3c06f5d..cf4fd5849e 100644 --- a/lily/simple-spacer.cc +++ b/lily/simple-spacer.cc @@ -1,7 +1,7 @@ /* This file is part of LilyPond, the GNU music typesetter. - Copyright (C) 1999--2011 Han-Wen Nienhuys + Copyright (C) 1999--2015 Han-Wen Nienhuys TODO: - add support for different stretch/shrink constants? @@ -22,7 +22,6 @@ #include -#include "column-description.hh" #include "column-x-positions.hh" #include "dimensions.hh" #include "international.hh" @@ -83,12 +82,6 @@ Simple_spacer::force () const return force_; } -Real -Simple_spacer::line_len () const -{ - return line_len_; -} - bool Simple_spacer::fits () const { @@ -200,9 +193,10 @@ Simple_spacer::expand_line () inv_hooke += springs_[i].inverse_stretch_strength (); if (inv_hooke == 0.0) /* avoid division by zero. If springs are infinitely stiff */ - return 0.0; /* anyway, then it makes no difference what the force is */ + inv_hooke = 1e-6; /* then report a very large stretching force */ - assert (cur_len <= line_len_); + if (cur_len > (1 + 1e-6) * line_len_) + programming_error ("misuse of expand_line"); return (line_len_ - cur_len) / inv_hooke + force_; } @@ -226,8 +220,8 @@ Simple_spacer::compress_line () fits_ = true; - assert (line_len_ <= cur_len); - + if (line_len_ > (1 + 1e-6) * cur_len) + programming_error ("misuse of compress_line"); vector sorted_springs = springs_; sort (sorted_springs.begin (), sorted_springs.end (), greater ()); @@ -255,7 +249,9 @@ Simple_spacer::compress_line () /* Paranoia check. */ - assert (fabs (configuration_length (cur_force) - cur_len) < 1e-6); + if (fabs (configuration_length (cur_force) - cur_len) > 1e-6 * cur_len) + programming_error (to_string ("mis-predicted force, %.6f ~= %.6f", + cur_len, configuration_length(cur_force))); return cur_force; } @@ -302,6 +298,185 @@ 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); + + if (col_index + 1 < cols.size ()) + { + 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 (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 */ + /* see Spanner::set_spacing_rods for more comments on how + to deal with situations where we don't know if we're + ending yet on 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 () && scm_is_eq (cols[end].break_permission_, force_break)) + break; + } + } + return force; +} + Column_x_positions get_line_configuration (vector const &columns, Real line_len, @@ -315,7 +490,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 (Paper_column::is_loose (columns[i])) + if (is_loose (columns[i])) ret.loose_cols_.push_back (columns[i]); else ret.cols_.push_back (columns[i]); @@ -326,7 +501,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 (Column_description::get_column_description (ret.cols_, i, i == 0)); + cols.push_back (get_column_description (ret.cols_, i, i == 0)); spacer.add_spring (cols[i].spring_); } for (vsize i = 0; i < cols.size (); i++) @@ -356,28 +531,9 @@ get_line_configuration (vector const &columns, for (vsize i = 1; i + 1 < ret.cols_.size (); i++) { SCM p = ret.cols_[i]->get_property ("line-break-permission"); - if (p == ly_symbol2scm ("force")) + if (scm_is_eq (p, ly_symbol2scm ("force"))) ret.satisfies_constraints_ = false; } return ret; } - -#include "ly-smobs.icc" - -IMPLEMENT_SIMPLE_SMOBS (Simple_spacer); -IMPLEMENT_DEFAULT_EQUAL_P (Simple_spacer); - -SCM -Simple_spacer::mark_smob (SCM /* x */) -{ - return SCM_EOL; -} - -int -Simple_spacer::print_smob (SCM /* x */, SCM p, scm_print_state *) -{ - scm_puts ("#", p); - return 1; -} -