+/*
+ Quantise dy (height) of beam.
+ Generalisation of [Ross].
+ */
+MAKE_SCHEME_CALLBACK (Beam, quantise_dy, 1);
+SCM
+Beam::quantise_dy (SCM smob)
+{
+ Grob *me = unsmob_grob (smob);
+
+ if (visible_stem_count (me) <= 1)
+ return SCM_UNSPECIFIED;
+
+ Array<Real> a;
+ SCM proc = me->get_grob_property ("height-quants");
+ SCM quants = gh_call2 (proc, me->self_scm (),
+ gh_double2scm (me->paper_l ()->get_var ("stafflinethickness")
+ / 1.0));
+
+ for (SCM s = quants; gh_pair_p (s); s = ly_cdr (s))
+ a.push (gh_scm2double (ly_car (s)));
+
+ if (a.size () > 1)
+ {
+ /* y,dy in this function are corrected for beam-dir */
+ Direction dir = Directional_element_interface::get (me);
+ Real y = gh_scm2double (me->get_grob_property ("y")) * dir;
+ Real dy = gh_scm2double (me->get_grob_property ("dy")) * dir;
+
+ Real staff_space = Staff_symbol_referencer::staff_space (me);
+
+ Interval iv = quantise_iv (a, abs (dy)/staff_space) * staff_space;
+ Real q = (abs (dy) - iv[SMALLER] <= iv[BIGGER] - abs (dy))
+ ? iv[SMALLER]
+ : iv[BIGGER];
+
+ Real quantised_dy = q * sign (dy);
+ Real adjusted_y = y + (dy - quantised_dy) / 2;
+ /* Store true, not dir-corrected values */
+ me->set_grob_property ("y", gh_double2scm (adjusted_y * dir));
+ me->set_grob_property ("dy", gh_double2scm (quantised_dy * dir));
+ }
+ return SCM_UNSPECIFIED;
+}
+
+/* It's tricky to have the user override y,dy directly, so we use this
+ translation func. Also, if our staff_space != 1 (smaller staff, eg),
+ user will expect staff-position to be discrete values. */
+MAKE_SCHEME_CALLBACK (Beam, user_override, 1);
+SCM
+Beam::user_override (SCM smob)
+{
+ Grob *me = unsmob_grob (smob);
+ Real staff_space = Staff_symbol_referencer::staff_space (me);
+
+ SCM s = me->get_grob_property ("staff-position");
+ if (gh_number_p (s))
+ {
+ Real y = gh_scm2double (s) * staff_space * 0.5;
+ me->set_grob_property ("y", gh_double2scm (y));
+ }
+
+ /* Name suggestions? Tilt, slope, vertical-* ? */
+ s = me->get_grob_property ("height");
+ if (gh_number_p (s))
+ {
+ Real dy = gh_scm2double (s) * staff_space * 0.5;
+ me->set_grob_property ("dy", gh_double2scm (dy));
+ }
+
+ return SCM_UNSPECIFIED;
+}
+
+/*
+ Ugh, this must be last, after user_override
+ Assumes directionised y/dy.
+ */
+MAKE_SCHEME_CALLBACK (Beam, do_quantise_y, 1);
+SCM
+Beam::do_quantise_y (SCM smob)
+{
+ Grob *me = unsmob_grob (smob);
+
+ /*
+ If the user set y-position, we shouldn't do quanting.
+ */
+ if (gh_number_p (me->get_grob_property ("y-position-hs")))
+ return SCM_UNSPECIFIED;
+
+ Real y = gh_scm2double (me->get_grob_property ("y"));
+ Real dy = gh_scm2double (me->get_grob_property ("dy"));
+
+ /* we can modify y, so we should quantise y */
+ Real half_space = Staff_symbol_referencer::staff_space (me) / 2;
+ Real y_shift = check_stem_length_f (me, y, dy);
+ y += y_shift;
+ y = quantise_y_f (me, y, dy, 0);
+
+ /*
+ Hmm, this is a bit keyhole operation: we're passing `this' as a
+ parameter, and member vars as SCM properties. We should decide on
+ SCM/C/C++ boundary */
+ me->set_grob_property ("y", gh_double2scm (y));
+ set_stem_lengths (me);
+ y = gh_scm2double (me->get_grob_property ("y"));
+
+ y_shift = check_stem_length_f (me, y, dy);
+
+ if (y_shift > half_space / 4)
+ {
+ y += y_shift;
+
+ /*
+ for significantly lengthened or shortened stems,
+ request quanting the other way.
+ */
+ int quant_dir = 0;
+ if (abs (y_shift) > half_space / 2)
+ quant_dir = sign (y_shift) * Directional_element_interface::get (me);
+ y = quantise_y_f (me, y, dy, quant_dir);
+ }
+
+ me->set_grob_property ("y", gh_double2scm (y));
+ // me->set_grob_property ("dy", gh_double2scm (dy));
+ return SCM_UNSPECIFIED;
+}
+
+