--- /dev/null
+/*
+ This file is part of LilyPond, the GNU music typesetter.
+
+ Copyright (C) 2011 Mike Solomon <mike@apollinemike.com>
+
+ 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 <http://www.gnu.org/licenses/>.
+*/
+
+#include <cstdio>
+
+#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<Grob *> 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<Grob *> const &cols, vsize col_index, bool line_starter)
+{
+ Grob *col = cols[col_index];
+ if (line_starter)
+ col = Item::maybe_find_prebroken_piece (dynamic_cast<Item *> (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<Item *> (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
breaks_ = pscore_->get_break_indices ();
all_ = pscore_->root_system ()->used_columns ();
lines_.resize (breaks_.size (), breaks_.size (), Line_details ());
- vector<Real> forces = get_line_forces (all_,
- other_lines.length (),
- other_lines.length () - first_line.length (),
- ragged_right_);
+ vector<Simple_spacer> 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++)
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;
--- /dev/null
+/*
+ This file is part of LilyPond, the GNU music typesetter.
+
+ Copyright (C) 2011 Mike Solomon <mike@apollinemike.com>
+
+ 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 <http://www.gnu.org/licenses/>.
+*/
+
+#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<Rod_description> rods_;
+ vector<Rod_description> 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<Grob *> const &cols, vsize col_index, bool line_starter);
+};
+
+#endif /* COLUMN_DESCRIPTION_HH */
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;
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 *);
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 &);
vector<Real> 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);
bool fits_;
};
-/* returns a vector of dimensions breaks.size () * breaks.size () */
-vector<Real> get_line_forces (vector<Grob *> const &columns,
- Real line_len,
- Real indent,
- bool ragged);
-
Column_x_positions get_line_configuration (vector<Grob *> const &columns,
Real line_len,
Real indent,
class System : public Spanner
{
int rank_;
+ vector<Simple_spacer> simple_spacers_;
Grob_array *all_elements_;
void init_elements ();
friend class Paper_score; // ugh.
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<Simple_spacer> get_simple_spacers (Real line_len, Real indent, bool ragged);
+ void gen_simple_spacers (Real line_len, Real indent, bool ragged);
vector<Real> get_footnote_heights_in_range (vsize st, vsize end);
vector<Real> get_in_note_heights_in_range (vsize st, vsize end);
vector<Real> internal_get_note_heights_in_range (vsize st, vsize end, bool foot);
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
{
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)
{
#include <cstdio>
+#include "column-description.hh"
#include "column-x-positions.hh"
#include "dimensions.hh"
#include "international.hh"
return force_;
}
+Real
+Simple_spacer::line_len () const
+{
+ return line_len_;
+}
+
bool
Simple_spacer::fits () 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<Rod_description> rods_;
- vector<Rod_description> 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<Item *> (g)->find_prebroken_piece (d);
- if (ret)
- return ret;
- return g;
-}
-
-static Grob *
-next_spaceable_column (vector<Grob *> 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<Grob *> 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<Item *> (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<Real>
-get_line_forces (vector<Grob *> const &columns,
- Real line_len, Real indent, bool ragged)
-{
- vector<vsize> breaks;
- vector<Real> force;
- vector<Grob *> non_loose;
- vector<Column_description> 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<Grob *> const &columns,
Real line_len,
ret.cols_.push_back (dynamic_cast<Item *> (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]);
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++)
return ret;
}
-
#include "ly-smobs.icc"
IMPLEMENT_SIMPLE_SMOBS (Simple_spacer);
#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"
return 0;
}
+vector<Simple_spacer>
+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<vsize> breaks;
+ vector<Grob *> non_loose;
+ vector<Column_description> cols;
+ SCM force_break = ly_symbol2scm ("force");
+ vector<Grob *> 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)
{