+/*
+ Read hints from L and generate springs.
+ */
+void
+Spacing_spanner::breakable_column_spacing (Grob*me, Item* l, Item *r,Moment shortest)
+{
+ Real max_fixed = -infinity_f;
+ Real max_space = -infinity_f;
+
+ standard_breakable_column_spacing (me, l, r, &max_fixed, &max_space ,
+ shortest);
+
+ for (SCM s = l->get_grob_property ("spacing-wishes");
+ gh_pair_p (s); s = gh_cdr (s))
+ {
+ Item * spacing_grob = dynamic_cast<Item*> (unsmob_grob (gh_car (s)));
+
+ if (!spacing_grob || !Staff_spacing::has_interface (spacing_grob))
+ continue;
+
+ Real space;
+ Real fixed_space;
+
+ /*
+ column for the left one settings should be ok due automatic
+ pointer munging.
+
+ */
+ assert (spacing_grob-> get_column () == l);
+
+ Staff_spacing::get_spacing_params (spacing_grob,
+ &space, &fixed_space);
+ if (space > max_space)
+ {
+ max_space = space;
+ max_fixed = fixed_space;
+ }
+ }
+
+
+
+
+ if (isinf (max_space))
+ {
+ /*
+ One situation where this can happen is when there is a column
+ that only serves as a spanning point for a short staff-symbol.
+
+ ===============X===
+
+ |=======Y
+
+
+ (here no StaffSpacing from Y to X is found.)
+ */
+ programming_error ("No StaffSpacing wishes found");
+ max_space = 2.0;
+ max_fixed = 1.0;
+ }
+
+
+ if (l->break_status_dir() == RIGHT
+ && Paper_column::when_mom (l) == Paper_column::when_mom (r))
+ {
+ /* Start of line: this space is not stretchable */
+ max_fixed = max_space;
+ }
+
+ /*
+ Hmm. we do 1/0 in the next thing. Perhaps we should check if this
+ works on all architectures.
+ */
+
+ bool ragged = to_boolean (me->get_paper ()->get_scmvar ("raggedright"));
+ Real strength = (ragged) ? 1.0 : 1 / (max_space - max_fixed);
+ Real distance = (ragged) ? max_fixed : max_space;
+ Spaceable_grob::add_spring (l, r, distance, strength, false);
+}
+
+
+/**
+ Get the measure wide ant for arithmetic spacing.
+ */
+Real
+Spacing_spanner::get_duration_space (Grob*me, Moment d, Rational shortest, bool * expand_only)
+{
+ Real k = gh_scm2double (me->get_grob_property ("shortest-duration-space"));
+ Real incr = gh_scm2double (me->get_grob_property ("spacing-increment"));
+
+ if (d < shortest)
+ {
+ /*
+ We don't space really short notes using the log of the
+ duration, since it would disproportionally stretches the long
+ notes in a piece. In stead, we use geometric spacing with constant 0.5
+ (i.e. linear.)
+
+ This should probably be tunable, to use other base numbers.
+
+ In Mozart hrn3 by EB., we have 8th note = 3.9 mm (total), 16th note =
+ 3.6 mm (total). head-width = 2.4, so we 1.2mm for 16th, 1.5
+ mm for 8th. (white space), suggesting that we use
+
+ (1.2 / 1.5)^{-log2(duration ratio)}
+
+
+ */
+ Rational ratio = d.main_part_ / shortest;
+
+#if 0
+ *expand_only = true;
+#endif
+ return ((k-1) + double (ratio)) * incr;
+ }
+ else
+ {
+ /*
+ John S. Gourlay. ``Spacing a Line of Music,'' Technical
+ Report OSU-CISRC-10/87-TR35, Department of Computer and
+ Information Science, The Ohio State University, 1987.
+ */
+ Real log = log_2 (shortest);
+ k -= log;
+ Rational compdur = d.main_part_ + d.grace_part_ /Rational (3);
+ *expand_only = false;
+
+ return (log_2 (compdur) + k) * incr;
+ }
+}
+
+Real
+Spacing_spanner::note_spacing (Grob*me, Grob *lc, Grob *rc,
+ Moment shortest, bool * expand_only)
+{
+ Moment shortest_playing_len = 0;
+ SCM s = lc->get_grob_property ("shortest-playing-duration");
+
+ if (unsmob_moment (s))
+ shortest_playing_len = *unsmob_moment (s);
+
+ if (! shortest_playing_len.to_bool ())
+ {
+ programming_error ("can't find a ruling note at " + Paper_column::when_mom (lc).string ());
+ shortest_playing_len = 1;
+ }
+
+ Moment lwhen = Paper_column::when_mom (lc);
+ Moment rwhen = Paper_column::when_mom (rc);
+
+ Moment delta_t = rwhen - lwhen;
+ Real dist = 0.0;
+
+ /*
+ In normal situations, the next column is at most
+ SHORTEST_PLAYING_LEN away. However chord-tremolos do funky faking stuff
+ with durations, invalidating this assumption. Here we kludge
+ around to get chord tremolos to behave properly.
+
+ */
+ shortest_playing_len = shortest_playing_len >? delta_t;
+ if (delta_t.main_part_ && !lwhen.grace_part_)
+ {
+ dist = get_duration_space (me, shortest_playing_len, shortest.main_part_, expand_only);
+ dist *= (double) (delta_t.main_part_ / shortest_playing_len.main_part_);
+ }
+ else if (delta_t.grace_part_)
+ {
+ /*
+ TODO: figure out how to space grace notes.
+ */
+ dist = get_duration_space (me, shortest, shortest.main_part_, expand_only);
+
+ Real grace_fact = 1.0;
+ SCM gf = me->get_grob_property ("grace-space-factor");
+ if (gh_number_p (gf))
+ grace_fact = gh_scm2double (gf);
+
+ dist *= grace_fact;
+ }
+
+
+ return dist;
+}
+
+
+
+ADD_INTERFACE (Spacing_spanner,"spacing-spanner-interface",
+ "
+The space taken by a note is dependent on its duration. Doubling a
+duration adds spacing-increment to the space. The most common shortest
+note gets shortest-duration-space. Notes that are even shorter are
+spaced proportonial to their duration.
+
+Typically, the increment is the width of a black note head. In a
+piece with lots of 8th notes, and some 16th notes, the eighth note
+gets 2 note heads width (i.e. the space following a note is 1 note
+head width) A 16th note is followed by 0.5 note head width. The
+quarter note is followed by 3 NHW, the half by 4 NHW, etc.
+",
+ "grace-space-factor spacing-increment base-shortest-duration shortest-duration-space common-shortest-duration");
+
+
+
+ADD_INTERFACE (Spacing_interface,"spacing-interface",
+ "Something to do with line breaking and spacing. Kill this one after determining line breaks.",
+ "");
+