#include "std-vector.hh"
#include "lily-proto.hh"
+#include "spring.hh"
#include "smobs.hh"
-struct Spring_description
-{
- Real ideal_;
- Real inverse_hooke_;
- Real block_force_;
-
- Real length (Real force) const;
- Spring_description ();
-
- bool is_sane () const;
-
- bool operator> (const Spring_description &s) const
- {
- return block_force_ > s.block_force_;
- }
-
- bool operator< (const Spring_description &s) const
- {
- return block_force_ < s.block_force_;
- }
-};
-
class Simple_spacer
{
public:
void solve (Real line_len, bool ragged);
void add_rod (int l, int r, Real dist);
- void add_spring (Real, Real);
+ void add_spring (Spring const&);
Real range_ideal_len (int l, int r) const;
- Real range_stiffness (int l, int r) const;
+ Real range_stiffness (int l, int r, bool stretch) const;
Real configuration_length (Real) const;
vector<Real> spring_positions () const;
Real compress_line ();
Real rod_force (int l, int r, Real dist);
- vector<Spring_description> springs_;
+ vector<Spring> springs_;
Real line_len_;
Real force_;
bool ragged_;
{
/// set a minimum distance
static void add_rod (Grob *me, Grob *to, Real distance);
- static void add_spring (Grob *me, Grob *to, Real dist, Real strength);
static void add_spring (Grob *me, Grob *to, Spring sp);
- static void get_spring (Grob *me, Grob *other, Real *dist, Real *inv_strength);
+ static Spring get_spring (Grob *me, Grob *other);
DECLARE_GROB_INTERFACE();
static SCM get_minimum_distances (Grob *);
struct Spacing_interface
{
- static Real minimum_distance (Grob *me);
+ static Real minimum_distance (Grob *me, Grob *right_col);
static vector<Item*> right_note_columns (Grob *me);
static vector<Item*> left_note_columns (Grob *me);
static Item* right_column (Grob *me);
Real inverse_stretch_strength_;
Real inverse_compress_strength_;
+ Real blocking_force_;
+
+ void update_blocking_force ();
+
DECLARE_SIMPLE_SMOBS (Spring);
public:
Spring ();
Real min_distance () const {return min_distance_;}
Real inverse_stretch_strength () const {return inverse_stretch_strength_;}
Real inverse_compress_strength () const {return inverse_compress_strength_;}
+ Real blocking_force () const {return blocking_force_;}
+
+ Real length (Real f) const;
void set_distance (Real);
void set_min_distance (Real);
void set_inverse_stretch_strength (Real);
void set_inverse_compress_strength (Real);
+ void set_blocking_force (Real);
void set_default_strength ();
void operator*= (Real);
+ bool operator> (Spring const&) const;
Grob *other_;
};
DECLARE_UNSMOB (Spring, spring);
public:
DECLARE_GROB_INTERFACE();
- static Spring get_spacing (Grob *);
+ static Spring get_spacing (Grob *, Grob *right_col);
static Interval bar_y_positions (Grob *);
};
What is sticking out of the note head (eg. a flag), doesn't get
the full amount of space.
*/
- Real min_dist = Spacing_interface::minimum_distance (me);
+ Real min_dist = Spacing_interface::minimum_distance (me, right_col);
Real min_desired_space = max (left_head_end + (min_dist - left_head_end) / 2,
min_dist - (base_space - increment) / 2);
Real ideal = base_space - increment + min_desired_space;
+++ /dev/null
-/*
- separating-group-spanner.cc -- implement Separating_group_spanner
-
- source file of the GNU LilyPond music typesetter
-
- (c) 1998--2007 Han-Wen Nienhuys <hanwen@xs4all.nl>
-*/
-
-#include "separating-group-spanner.hh"
-
-#include "separation-item.hh"
-#include "paper-column.hh"
-#include "output-def.hh"
-#include "dimensions.hh"
-#include "pointer-group-interface.hh"
-#include "moment.hh"
-
-void
-Separating_group_spanner::find_rods (Item *r,
- vector<Grob*> const &separators,
- vsize idx,
- Real padding)
-{
-
- /*
- This is an inner loop: look for the first normal (unbroken) Left
- grob. This looks like an inner loop (ie. quadratic total), but in
- most cases, the interesting L will just be the first entry of
- NEXT, making it linear in most of the cases.
- */
- for (; idx != VPOS; idx--)
- {
- Item *l = dynamic_cast<Item *> (separators[idx]);
- Item *lb = l->find_prebroken_piece (RIGHT);
-
- if (lb)
- {
- Separation_item::set_distance (Drul_array<Item*> (lb, r), padding);
- }
-
- if (Separation_item::set_distance (Drul_array<Item *> (l, r), padding)
- /*
- This check is because grace notes are set very tight, and
- the accidentals of main note may stick out so far to cover
- a barline preceding the grace note.
- */
- && spanned_time_interval (l, r).length ().main_part_ > Rational (0))
- break;
-
- /*
- this grob doesn't cause a constraint. We look further until we
- find one that does.
- */
- }
-}
-
-MAKE_SCHEME_CALLBACK (Separating_group_spanner, set_spacing_rods, 1);
-SCM
-Separating_group_spanner::set_spacing_rods (SCM smob)
-{
- Grob *me = unsmob_grob (smob);
-
- /*
- Ugh: padding is added doubly, also for SeparationItem
- */
- Real padding = robust_scm2double (me->get_property ("padding"), 0.1);
-
- extract_grob_set (me, "elements", elts);
- for (vsize i = elts.size (); i-- > 1;)
- {
- Item *r = dynamic_cast<Item *> (elts[i]);
- if (!r)
- continue;
-
- if (Separation_item::width (r).is_empty ())
- continue;
-
- Item *rb
- = dynamic_cast<Item *> (r->find_prebroken_piece (LEFT));
-
- find_rods (r, elts, i - 1, padding);
- if (rb)
- find_rods (rb, elts, i - 1, padding);
- }
-
- return SCM_UNSPECIFIED;
-}
-
-void
-Separating_group_spanner::add_spacing_unit (Grob *me, Item *i)
-{
- Pointer_group_interface::add_unordered_grob (me, ly_symbol2scm ("elements"), i);
-}
-
-ADD_INTERFACE (Separating_group_spanner,
- "A spanner that calculates spacing constraints (\"rods\") "
- "using the @code{separation-item-interface} grobs in @code{elements}.",
-
- /* properties */
- "elements "
- "padding ");
Spacings current_spacings_;
Spacings last_spacings_;
- Spanner *sep_span_;
-
DECLARE_ACKNOWLEDGER (item);
- void process_music ();
- virtual void finalize ();
void stop_translation_timestep ();
void start_translation_timestep ();
public:
Separating_line_group_engraver::Separating_line_group_engraver ()
{
- sep_span_ = 0;
break_item_ = 0;
musical_item_ = 0;
}
-void
-Separating_line_group_engraver::process_music ()
-{
- if (!sep_span_)
- {
- sep_span_ = make_spanner ("SeparatingGroupSpanner", SCM_EOL);
-
- sep_span_->set_bound (LEFT, unsmob_grob (get_property ("currentCommandColumn")));
- }
-}
-void
-Separating_line_group_engraver::finalize ()
-{
- if (!sep_span_)
- return;
-
- SCM ccol = get_property ("currentCommandColumn");
- Grob *column = unsmob_grob (ccol);
-
- sep_span_->set_bound (RIGHT, unsmob_grob (ccol));
- sep_span_ = 0;
-
- if (last_spacings_.staff_spacing_
- && last_spacings_.staff_spacing_->get_column () == column)
- last_spacings_.staff_spacing_->suicide ();
-}
-
void
Separating_line_group_engraver::acknowledge_item (Grob_info i)
{
void
Separating_line_group_engraver::stop_translation_timestep ()
{
- if (break_item_)
- Separating_group_spanner::add_spacing_unit (sep_span_, break_item_);
-
if (Item *sp = current_spacings_.staff_spacing_)
{
/*
current_spacings_.clear ();
- if (musical_item_)
- Separating_group_spanner::add_spacing_unit (sep_span_, musical_item_);
-
musical_item_ = 0;
}
Real ideal = scm_to_double (scm_caar (s));
Real inv_hooke = scm_to_double (scm_cadar (s));
- spacer.add_spring (ideal, inv_hooke);
+ Spring sp (ideal, 0.0);
+ sp.set_inverse_compress_strength (inv_hooke);
+ sp.set_inverse_stretch_strength (inv_hooke);
+
+ spacer.add_spring (sp);
}
for (SCM s = rods; scm_is_pair (s); s = scm_cdr (s))
Real
Simple_spacer::rod_force (int l, int r, Real dist)
{
- Real c = range_stiffness (l, r);
Real d = range_ideal_len (l, r);
+ Real c = range_stiffness (l, r, d > dist);
Real block_stretch = dist - d;
return c * block_stretch;
}
Real spring_dist = range_ideal_len (l, r);
if (spring_dist < dist)
for (int i = l; i < r; i++)
- springs_[i].ideal_ *= dist / spring_dist;
+ springs_[i].set_distance (springs_[i].distance () * dist / spring_dist);
return;
}
force_ = max (force_, block_force);
for (int i = l; i < r; i++)
- springs_[i].block_force_ = max (block_force, springs_[i].block_force_);
+ springs_[i].set_blocking_force (max (block_force, springs_[i].blocking_force ()));
}
Real
{
Real d = 0.;
for (int i = l; i < r; i++)
- d += springs_[i].ideal_;
+ d += springs_[i].distance ();
return d;
}
Real
-Simple_spacer::range_stiffness (int l, int r) const
+Simple_spacer::range_stiffness (int l, int r, bool stretch) const
{
Real den = 0.0;
for (int i = l; i < r; i++)
- den += springs_[i].inverse_hooke_;
+ den += stretch ? springs_[i].inverse_stretch_strength ()
+ : springs_[i].inverse_compress_strength ();
return 1 / den;
}
Simple_spacer::solve (Real line_len, bool ragged)
{
Real conf = configuration_length (force_);
- double inv_hooke = 0;
- for (vsize i=0; i < springs_.size (); i++)
- inv_hooke += springs_[i].inverse_hooke_;
ragged_ = ragged;
line_len_ = line_len;
- if ((inv_hooke > 0) && (conf < line_len_))
+ if (conf < line_len_)
force_ = expand_line ();
else if (conf > line_len_)
force_ = compress_line ();
fits_ = true;
for (vsize i=0; i < springs_.size (); i++)
- inv_hooke += springs_[i].inverse_hooke_;
+ inv_hooke += springs_[i].inverse_stretch_strength ();
assert (cur_len <= line_len_);
return (line_len_ - cur_len) / inv_hooke + force_;
double inv_hooke = 0;
double cur_len = configuration_length (force_);
double cur_force = force_;
+ bool compressed = false;
+
+ /* just because we are in compress_line () doesn't mean that the line
+ will actually be compressed (as in, a negative force) because
+ we start out with a stretched line. Here, we check whether we
+ will be compressed or stretched (so we know which spring constant to use) */
+ if (configuration_length (0.0) > line_len_)
+ {
+ cur_force = 0.0;
+ cur_len = configuration_length (0.0);
+ compressed = true;
+ }
fits_ = true;
for (vsize i=0; i < springs_.size (); i++)
- inv_hooke += springs_[i].inverse_hooke_;
+ inv_hooke += compressed
+ ? springs_[i].inverse_compress_strength ()
+ : springs_[i].inverse_stretch_strength ();
assert (line_len_ <= cur_len);
- vector<Spring_description> sorted_springs = springs_;
- sort (sorted_springs.begin (), sorted_springs.end (), greater<Spring_description> ());
+ vector<Spring> sorted_springs = springs_;
+ sort (sorted_springs.begin (), sorted_springs.end (), greater<Spring> ());
for (vsize i = 0; i < sorted_springs.size (); i++)
{
- Spring_description sp = sorted_springs[i];
+ Spring sp = sorted_springs[i];
- assert (sp.block_force_ <= cur_force);
- if (isinf (sp.block_force_))
+ assert (sp.blocking_force () <= cur_force);
+ if (isinf (sp.blocking_force ()))
break;
- double block_dist = (cur_force - sp.block_force_) * inv_hooke;
+ double block_dist = (cur_force - sp.blocking_force ()) * inv_hooke;
if (cur_len - block_dist < line_len_)
{
- cur_force += (line_len_ - cur_len) / inv_hooke;
- cur_len = line_len_;
+ cur_force += (line_len_ - cur_len) / inv_hooke;
+ cur_len = line_len_;
- /*
- Paranoia check.
+ /*
+ Paranoia check.
*/
- assert (fabs (configuration_length (cur_force) - cur_len) < 1e-6);
- return cur_force;
+ assert (fabs (configuration_length (cur_force) - cur_len) < 1e-6);
+ return cur_force;
}
cur_len -= block_dist;
- inv_hooke -= sp.inverse_hooke_;
- cur_force = sp.block_force_;
+ inv_hooke -= sp.inverse_compress_strength ();
+ cur_force = sp.blocking_force ();
}
fits_ = false;
}
void
-Simple_spacer::add_spring (Real ideal, Real inverse_hooke)
+Simple_spacer::add_spring (Spring const &sp)
{
- Spring_description description;
-
- description.ideal_ = ideal;
- description.inverse_hooke_ = inverse_hooke;
- if (!description.is_sane ())
- {
- programming_error ("insane spring found, setting to unit");
-
- description.inverse_hooke_ = 1.0;
- description.ideal_ = 1.0;
- }
-
- description.block_force_ = -description.ideal_ / description.inverse_hooke_;
- // block at distance 0
-
- springs_.push_back (description);
+ force_ = max (force_, sp.blocking_force ());
+ springs_.push_back (sp);
}
vector<Real>
/****************************************************************/
-Spring_description::Spring_description ()
-{
- ideal_ = 0.0;
- inverse_hooke_ = 0.0;
- block_force_ = 0.0;
-}
-
-bool
-Spring_description::is_sane () const
-{
- return (inverse_hooke_ >= 0)
- && ideal_ >= 0
- && !isinf (ideal_) && !isnan (ideal_)
- && (inverse_hooke_ == 0.0 || fabs (inverse_hooke_) > 1e-8)
- ;
-}
-
-Real
-Spring_description::length (Real f) const
-{
- return ideal_ + max (f, block_force_) * inverse_hooke_;
-}
-
-/****************************************************************/
-
/*
TODO: should a add penalty for widely varying spring forces (caused
by constraints, eg.
{
vector<Rod_description> rods_;
vector<Rod_description> end_rods_; /* use these if they end at the last column of the line */
- Real ideal_;
- Real inverse_hooke_;
- Real end_ideal_;
- Real end_inverse_hooke_;
+ Spring spring_;
+ Spring end_spring_;
+
SCM break_permission_;
Interval keep_inside_line_;
Column_description ()
{
- ideal_ = 0;
- inverse_hooke_ = 0;
- end_ideal_ = 0;
- end_inverse_hooke_ = 0;
break_permission_ = SCM_EOL;
}
};
Column_description description;
Grob *next_col = next_spaceable_column (cols, col_index);
if (next_col)
- Spaceable_grob::get_spring (col, next_col, &description.ideal_, &description.inverse_hooke_);
+ 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)
- Spaceable_grob::get_spring (col, end_col, &description.end_ideal_, &description.end_inverse_hooke_);
+ 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))
Simple_spacer spacer;
for (vsize i = breaks[b]; i < end - 1; i++)
- spacer.add_spring (cols[i].ideal_, cols[i].inverse_hooke_);
- spacer.add_spring (cols[end-1].end_ideal_, cols[end-1].end_inverse_hooke_);
+ spacer.add_spring (cols[i].spring_);
+ spacer.add_spring (cols[end-1].end_spring_);
for (vsize i = breaks[b]; i < end; i++)
for (vsize i = 0; i + 1 < ret.cols_.size (); i++)
{
cols.push_back (get_column_description (ret.cols_, i, i == 0));
- spacer.add_spring (cols[i].ideal_, cols[i].inverse_hooke_);
+ spacer.add_spring (cols[i].spring_);
}
for (vsize i = 0; i < cols.size (); i++)
{
me->set_object ("minimum-distances", mins);
}
-void
-Spaceable_grob::add_spring (Grob *me, Grob *other,
- Real distance, Real inverse_strength)
-{
-#ifndef NDEBUG
- SCM mins = me->get_object ("ideal-distances");
- for (SCM s = mins; scm_is_pair (s); s = scm_cdr (s))
- {
- Spring *sp = unsmob_spring (scm_car (s));
- if (sp->other_ == other)
- {
- programming_error ("already have that spring");
- return;
- }
- }
-#endif
-
- Spring spring;
- spring.set_inverse_stretch_strength (inverse_strength);
- spring.set_inverse_compress_strength (inverse_strength);
- spring.set_distance (distance);
- spring.other_ = other;
-
- SCM ideal = me->get_object ("ideal-distances");
- ideal = scm_cons (spring.smobbed_copy (), ideal);
- me->set_object ("ideal-distances", ideal);
-}
-
void
Spaceable_grob::add_spring (Grob *me, Grob *other, Spring sp)
{
me->set_object ("ideal-distances", ideal);
}
-void
-Spaceable_grob::get_spring (Grob *this_col, Grob *next_col, Real *dist, Real *inv_strength)
+Spring
+Spaceable_grob::get_spring (Grob *this_col, Grob *next_col)
{
Spring *spring = 0;
programming_error (_f ("No spring between column %d and next one",
Paper_column::get_rank (this_col)));
- *dist = (spring) ? spring->distance () : 5.0;
- *inv_strength = (spring) ? spring->inverse_stretch_strength () : 1.0;
+ return spring ? *spring : Spring ();
}
}
else if (Staff_spacing::has_interface (sp))
{
- Spring spring = Staff_spacing::get_spacing (sp);
+ Spring spring = Staff_spacing::get_spacing (sp, rc);
dists[d] = max (dists[d], spring.min_distance ());
}
/* return the minimum distance between the left-items and the right-items of
this spacing object */
Real
-Spacing_interface::minimum_distance (Grob *me)
+Spacing_interface::minimum_distance (Grob *me, Grob *right_col)
{
/* the logic here is a little convoluted.
- A {Staff,Note}_spacing doesn't copy {left-,right-}items when it clones,
+ A {Staff,Note}_spacing doesn't copy left-items when it clones,
so in order to find the separation items, we need to use the original
spacing grob. But once we find the separation items, we need to get back
the broken piece.
-
- FIXME: this only works for the left column. There is only one spacing
- grob for both the original and non-original right columns and we have no way
- to tell which one we need */
+ */
Grob *orig = me->original () ? me->original () : me;
- Direction break_dir = dynamic_cast<Item*> (me)->break_status_dir ();
+ Drul_array<Direction> break_dirs (dynamic_cast<Item*> (me)->break_status_dir (),
+ dynamic_cast<Item*> (right_col)->break_status_dir ());
Drul_array<Skyline> skylines = Drul_array<Skyline> (Skyline (RIGHT), Skyline (LEFT));
Drul_array<vector<Grob*> > items (ly_scm2link_array (orig->get_object ("left-items")),
ly_scm2link_array (orig->get_object ("right-items")));
for (vsize i = 0; i < items[d].size (); i++)
{
Grob *g = items[d][i];
- if (d == LEFT)
- if (Item *it = dynamic_cast<Item*> (g))
- if (Grob *piece = it->find_prebroken_piece (break_dir))
- g = piece;
+ if (Item *it = dynamic_cast<Item*> (g))
+ if (Grob *piece = it->find_prebroken_piece (break_dirs[d]))
+ g = piece;
if (Separation_item::has_interface (g))
{
*/
assert (spacing_grob->get_column () == l);
- springs.push_back (Staff_spacing::get_spacing (spacing_grob));
+ springs.push_back (Staff_spacing::get_spacing (spacing_grob, r));
}
}
will be the distance between columns if there is a compression force of 1.0
applied to the line. */
Spring
-Staff_spacing::get_spacing (Grob *me)
+Staff_spacing::get_spacing (Grob *me, Grob *right_col)
{
Grob *separation_item = 0;
Item *me_item = dynamic_cast<Item *> (me);
}
Real optical_correction = next_notes_correction (me, last_grob);
- Real min_dist = Spacing_interface::minimum_distance (me);
+ Real min_dist = Spacing_interface::minimum_distance (me, right_col);
Real min_dist_correction = max (0.0, 0.3 + min_dist - fixed);
Real correction = max (optical_correction, min_dist_correction);
(interfaces . (
separation-item-interface))))))
- (SeparatingGroupSpanner
- . (
- (springs-and-rods . ,ly:separating-group-spanner::set-spacing-rods)
- (meta . ((class . Spanner)
- (interfaces . (only-prebreak-interface
-
- separating-group-spanner-interface))))))
-
(Slur
. ((details . ,default-slur-details)
(control-points . ,ly:slur::calc-control-points)
ly:piano-pedal-bracket::print
ly:rest::print
ly:script-interface::print
- ly:separating-group-spanner::set-spacing-rods
ly:slur::height
ly:slur::print
ly:spacing-spanner::set-springs