-MAKE_SCHEME_CALLBACK (Beam, check_concave, 1);
-SCM
-Beam::check_concave (SCM smob)
-{
- Grob *me = unsmob_grob (smob);
-
- Link_array<Grob> stems =
- Pointer_group_interface__extract_grobs (me, (Grob*) 0, "stems");
-
- Direction beam_dir = CENTER;
- for (int i = 0; i < stems.size ();)
- {
- if (Stem::is_invisible (stems[i]))
- stems.del (i);
- else
- {
- if (Direction sd = Stem::get_direction (stems[i]))
- {
- /*
- Don't do knee beams.
- */
- if (beam_dir && sd && sd != beam_dir)
- return SCM_UNSPECIFIED;
-
- beam_dir = sd;
- }
- i++;
- }
- }
-
- if (stems.size () < 3)
- return SCM_UNSPECIFIED;
-
-
- /* Concaveness #1: If distance of an inner notehead to line between
- two outer noteheads is bigger than CONCAVENESS-GAP (2.0ss),
- beam is concave (Heinz Stolba).
-
- In the case of knees, the line connecting outer heads is often
- not related to the beam slope (it may even go in the other
- direction). Skip the check when the outer stems point in
- different directions. --hwn
-
- */
- bool is_concave1 = false;
- SCM gap = me->get_property ("concaveness-gap");
- if (is_number (gap))
- {
- Real r1 = ly_scm2double (gap);
- Real dy = Stem::chord_start_y (stems.top ())
- - Stem::chord_start_y (stems[0]);
-
-
- Real slope = dy / (stems.size () - 1);
-
- Real y0 = Stem::chord_start_y (stems[0]);
- for (int i = 1; i < stems.size () - 1; i++)
- {
- Real c =
- beam_dir *((Stem::chord_start_y (stems[i]) - y0) - i * slope);
- if (c - r1 > 0)
- {
- is_concave1 = true;
- break;
- }
- }
- }
-
-
- /* Concaveness #2: Sum distances of inner noteheads that fall
- outside the interval of the two outer noteheads.
-
- We only do this for beams where first and last stem have the same
- direction. --hwn.
-
-
- Note that "convex" stems compensate for "concave" stems.
- (is that intentional?) --hwn.
- */
-
- Real concaveness2 = 0;
- SCM thresh = me->get_property ("concaveness-threshold");
- Real r2 = infinity_f;
- if (!is_concave1 && is_number (thresh))
- {
- r2 = ly_scm2double (thresh);
-
- Interval iv;
- iv.add_point (Stem::chord_start_y (stems[0]));
- iv.add_point (Stem::chord_start_y (stems.top ()));
-
- for (int i = 1; i < stems.size () - 1; i++)
- {
- Real f = Stem::chord_start_y (stems[i]);
- concaveness2 += ( (f - iv[MAX] ) >? 0) +
- ( (f - iv[MIN] ) <? 0);
- }
-
- concaveness2 *= beam_dir / (stems.size () - 2);
- }
-
- /* TODO: some sort of damping iso -> plain horizontal */
- if (is_concave1 || concaveness2 > r2)
- {
- Drul_array<Real> pos = ly_scm2interval (me->get_property ("positions"));
- Real r = linear_combination (pos, 0);
-
- r /= Staff_symbol_referencer::staff_space (me);
- me->set_property ("positions", ly_interval2scm (Drul_array<Real> (r, r)));
- me->set_property ("least-squares-dy", scm_make_real (0));
- }
-
- return SCM_UNSPECIFIED;
-}
-