#include "grob-interface.hh"
#include "lily-proto.hh"
+#include "spring.hh"
class Note_spacing
{
public:
DECLARE_GROB_INTERFACE();
- static void get_spacing (Grob *me, Item *, Real, Real, Real *, Real *);
+ static Spring get_spacing (Grob *me, Item *, Real, Real);
static void stem_dir_correction (Grob *me, Item *next_col, Real incr,
Real *, Real *);
};
#include "lily-proto.hh"
#include "grob-interface.hh"
+#include "spring.hh"
struct Spaceable_grob
{
/// 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);
DECLARE_GROB_INTERFACE();
/*
- spring.hh -- declare Spring, Column_spring
+ spring.hh -- declare Spring
source file of the GNU LilyPond music typesetter
#include "lily-proto.hh"
#include "smobs.hh"
-struct Spring
+class Spring
{
- Grob *other_;
Real distance_;
Real min_distance_;
DECLARE_SIMPLE_SMOBS (Spring);
public:
Spring ();
+ Spring (Real distance, Real min_distance);
+
+ Real distance () const {return distance_;}
+ 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_;}
+
+ void set_distance (Real);
+ void set_min_distance (Real);
+ void set_inverse_stretch_strength (Real);
+ void set_inverse_compress_strength (Real);
+
+ void operator*= (Real);
+ Grob *other_;
};
DECLARE_UNSMOB (Spring, spring);
+Spring merge_springs (vector<Spring> const &springs);
+
#endif /* SPRING_HH */
public:
DECLARE_GROB_INTERFACE();
- static Spring get_spacing_params (Grob *);
+ static Spring get_spacing (Grob *);
static Interval bar_y_positions (Grob *);
};
spacing?
*/
-void
+Spring
Note_spacing::get_spacing (Grob *me, Item *right_col,
- Real base_space, Real increment, Real *space, Real *fixed)
+ Real base_space, Real increment)
{
vector<Item*> note_columns = Spacing_interface::left_note_columns (me);
Real left_head_end = 0;
the full amount of space.
*/
Real min_dist = Spacing_interface::minimum_distance (me);
+ 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;
- *fixed = max (left_head_end + (min_dist - left_head_end) / 2,
- min_dist - (base_space - increment) / 2);
-
- /*
- We don't do complicated stuff: (base_space - increment) is the
- normal amount of white, which also determines the amount of
- stretch. Upon (extreme) stretching, notes with accidentals should
- stretch as much as notes without accidentals.
- */
- *space = (base_space - increment) + *fixed;
+ stem_dir_correction (me, right_col, increment, &ideal, &min_desired_space);
- stem_dir_correction (me, right_col, increment, space, fixed);
+ Spring ret (ideal, min_dist);
+ ret.set_inverse_compress_strength (ideal - max (min_dist, min_desired_space));
+ return ret;
}
vector<Offset> pts;
pts.push_back (Offset (0, y));
- Offset p2 (sp->distance_, y);
+ Offset p2 (sp->distance (), y);
pts.push_back (p2);
Stencil id_stencil = Lookup::points_to_line_stencil (0.1, pts);
SCM distance_stc = Text_interface::interpret_markup (me->layout ()->self_scm (),
small_letters,
- ly_string2scm (String_convert::form_string ("%5.2lf", sp->distance_)));
+ ly_string2scm (String_convert::form_string ("%5.2lf", sp->distance ())));
- id_stencil.add_stencil (unsmob_stencil (distance_stc)->translated (Offset (sp->distance_/3, y+1)));
+ id_stencil.add_stencil (unsmob_stencil (distance_stc)->translated (Offset (sp->distance ()/3, y+1)));
id_stencil.add_stencil (head.translated (p2));
id_stencil = id_stencil.in_color (0,0,1);
l.add_stencil (id_stencil);
Spaceable_grob::add_spring (Grob *me, Grob *other,
Real distance, Real inverse_strength)
{
- if (distance < 0.0 || inverse_strength < 0.0)
- {
- programming_error ("adding reverse spring, setting to unit");
- distance = 1.0;
- inverse_strength = 1.0;
- }
-
- if (isinf (distance) || isnan (distance)
- || isnan (inverse_strength))
- {
- /* strength == INF is possible. It means fixed distance. */
- programming_error ("insane distance found");
- distance = 1.0;
- inverse_strength = 1.0;
- }
-
#ifndef NDEBUG
SCM mins = me->get_object ("ideal-distances");
for (SCM s = mins; scm_is_pair (s); s = scm_cdr (s))
#endif
Spring spring;
- spring.inverse_stretch_strength_ = inverse_strength;
- spring.inverse_compress_strength_ = inverse_strength;
- spring.distance_ = distance;
+ 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");
me->set_object ("ideal-distances", ideal);
}
+void
+Spaceable_grob::add_spring (Grob *me, Grob *other, Spring sp)
+{
+ SCM ideal = me->get_object ("ideal-distances");
+ sp.other_ = other;
+ ideal = scm_cons (sp.smobbed_copy (), ideal);
+ me->set_object ("ideal-distances", ideal);
+}
+
void
Spaceable_grob::get_spring (Grob *this_col, Grob *next_col, Real *dist, Real *inv_strength)
{
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;
+ *dist = (spring) ? spring->distance () : 5.0;
+ *inv_strength = (spring) ? spring->inverse_stretch_strength () : 1.0;
}
The note spacing should be taken from the musical
columns.
*/
- Real space = 0.0;
- Real fixed = 0.0;
-
Real base = note_spacing (me, lc, rc, options);
- Note_spacing::get_spacing (sp, rc, base, options->increment_,
- &space, &fixed);
+ Spring spring = Note_spacing::get_spacing (sp, rc, base, options->increment_);
- space -= options->increment_;
-
- dists[d] = max (dists[d], space);
+ dists[d] = max (dists[d], spring.distance () - options->increment_);
}
else if (Staff_spacing::has_interface (sp))
{
- Spring spring = Staff_spacing::get_spacing_params (sp);
- Real fixed = spring.distance_ - spring.inverse_compress_strength_;
+ Spring spring = Staff_spacing::get_spacing (sp);
- dists[d] = max (dists[d], fixed);
+ dists[d] = max (dists[d], spring.min_distance ());
}
else
programming_error ("Subversive spacing wish");
}
while (flip (&d) != LEFT);
- return skylines[LEFT].distance (skylines[RIGHT]);
+ return max (0.0, skylines[LEFT].distance (skylines[RIGHT]));
}
/*
Spacing_options const *options)
{
Real base_note_space = note_spacing (me, left_col, right_col, options);
-
- Real max_fixed = 0;
- Real max_space = 0;
- Real compound_note_space = 0.0;
- Real compound_fixed_note_space = 0.0;
+ Spring spring;
if (options->stretch_uniformly_)
- {
- compound_note_space = base_note_space;
-
- if (!Paper_column::is_musical (right_col))
- {
- /*
- Crude fix for notes that lead up to barlines and time sigs.
- */
- Interval lext = right_col->extent (right_col, X_AXIS);
- if (!lext.is_empty ())
- compound_note_space += -lext[LEFT];
- }
- }
+ spring = Spring (base_note_space, 0.0);
else
{
- int wish_count = 0;
-
+ vector<Spring> springs;
extract_grob_set (left_col, "right-neighbors", neighbors);
- /*
- We adjust the space following a note only if the next note
- happens after the current note (this is set in the grob
- property SPACING-SEQUENCE.
- */
for (vsize i = 0; i < neighbors.size (); i++)
{
Grob *wish = neighbors[i];
This is probably a waste of time in the case of polyphonic
music. */
if (Note_spacing::has_interface (wish))
- {
- Real space = 0.0;
- Real fixed = 0.0;
-
- Note_spacing::get_spacing (wish, right_col, base_note_space, options->increment_, &space, &fixed);
-
-
- max_space = max (max_space, space);
- max_fixed = max (max_fixed, fixed);
-
- compound_note_space += space;
- compound_fixed_note_space += fixed;
- wish_count++;
- }
- }
-
- if (Paper_column::when_mom (right_col).grace_part_
- && !Paper_column::when_mom (left_col).grace_part_)
- {
- /*
- Ugh. 0.8 is arbitrary.
- */
- compound_note_space *= 0.8;
+ springs.push_back (Note_spacing::get_spacing (wish, right_col, base_note_space, options->increment_));
}
- if (compound_note_space < 0 || wish_count == 0)
+ if (springs.empty ())
{
if (!Paper_column::is_musical (right_col))
spacing, because the width of s^"text" output is also
taken into account here.
*/
- compound_fixed_note_space = options->increment_;
- compound_note_space = max (base_note_space,
- options->increment_);
+ spring = Spring (max (base_note_space, options->increment_),
+ options->increment_);
}
else
{
Fixed should be 0.0. If there are no spacing wishes, we're
likely dealing with polyphonic spacing of hemiolas.
- We used to have compound_fixed_note_space = options->increment_
+ We used to have min_distance_ = options->increment_
but this can lead to numeric instability problems when we
do
- inverse_strength = (compound_note_space - compound_fixed_note_space)
+ inverse_strength = (distance_ - min_distance_)
*/
-
- compound_note_space = base_note_space;
- compound_fixed_note_space = 0.0;
+ spring = Spring (base_note_space, 0.0);
}
}
- else if (to_boolean (me->get_property ("average-spacing-wishes")))
- {
- compound_note_space /= wish_count;
- compound_fixed_note_space /= wish_count;
- }
else
- {
- compound_fixed_note_space = max_fixed;
- compound_note_space = max_space;
- }
+ spring = merge_springs (springs);
+ }
+ if (Paper_column::when_mom (right_col).grace_part_
+ && !Paper_column::when_mom (left_col).grace_part_)
+ {
/*
- Whatever we do, the fixed space is smaller than the real
- space.
-
- TODO: this criterion is discontinuous in the derivative.
- Maybe it should be continuous?
+ Ugh. 0.8 is arbitrary.
*/
- compound_fixed_note_space = min (compound_fixed_note_space,
- compound_note_space);
+ spring *= 0.8;
}
- Real inverse_strength = 1.0;
- Real distance = 1.0;
-
/*
TODO: make sure that the space doesn't exceed the right margin.
*/
pack as much bars of music as possible into a line, but the
line will then be stretched to fill the whole linewidth.
*/
- inverse_strength = 1.0;
- distance = compound_fixed_note_space;
- }
- else
- {
- inverse_strength = (compound_note_space - compound_fixed_note_space);
- distance = compound_note_space;
+ spring.set_distance (spring.min_distance ());
+ spring.set_inverse_stretch_strength (1.0);
}
- Spaceable_grob::add_spring (left_col, right_col, distance, inverse_strength);
+ Spaceable_grob::add_spring (left_col, right_col, spring);
}
/*
*/
assert (spacing_grob->get_column () == l);
- Spring sp = Staff_spacing::get_spacing_params (spacing_grob);
- Real space = sp.distance_;
- Real fixed = sp.distance_ - sp.inverse_compress_strength_;
+ Spring sp = Staff_spacing::get_spacing (spacing_grob);
+ Real space = sp.distance ();
+ Real fixed = sp.min_distance ();
if (Paper_column::when_mom (r).grace_part_)
{
#include "warn.hh"
#include "ly-smobs.icc"
-Spring::Spring ()
-{
- distance_ = 1.0;
- min_distance_ = 1.0;
- inverse_stretch_strength_ = 1.0;
- inverse_compress_strength_ = 1.0;
- other_ = 0;
-}
-
IMPLEMENT_SIMPLE_SMOBS (Spring);
SCM
will be the distance between columns if there is a compression force of 1.0
applied to the line. */
Spring
-Staff_spacing::get_spacing_params (Grob *me)
+Staff_spacing::get_spacing (Grob *me)
{
Grob *separation_item = 0;
Item *me_item = dynamic_cast<Item *> (me);
fixed += correction;
ideal += correction;
- Spring ret;
- ret.min_distance_ = max (min_dist, fixed);
- ret.distance_ = ideal;
- ret.inverse_stretch_strength_ = ret.inverse_compress_strength_ = ideal - fixed;
+ Spring ret (ideal, min_dist);
+ ret.set_inverse_stretch_strength (ideal - fixed);
return ret;
}