2 Determine whether a beam is concave.
5 #include "pointer-group-interface.hh"
9 #include "staff-symbol-referencer.hh"
12 is_concave_single_notes (Array<int> const &positions, Direction beam_dir)
15 covering.add_point (positions[0]);
16 covering.add_point (positions.top ());
23 notes above and below the interval covered by 1st and last note.
25 for (int i = 1; i < positions.size () - 1; i++)
27 above = above || (positions[i] > covering[UP]);
28 below = below || (positions[i] < covering[DOWN]);
31 concave = concave || (above && below);
33 A note as close or closer to the beam than begin and end, but the
34 note is reached in the opposite direction as the last-first dy
36 int dy = positions.top () - positions[0];
37 int closest = max (beam_dir * positions.top (), beam_dir * positions[0]);
38 for (int i = 2; !concave && i < positions.size () - 1; i++)
40 int inner_dy = positions[i] - positions[i - 1];
41 if (sign (inner_dy) != sign (dy)
42 && (beam_dir * positions[i] >= closest
43 || beam_dir * positions[i - 1] >= closest))
47 bool all_closer = true;
48 for (int i = 1; all_closer && i < positions.size () - 1; i++)
50 all_closer = all_closer
51 && (beam_dir * positions[i] > closest);
54 concave = concave || all_closer;
59 calc_concaveness (Array<int> const &positions, Direction beam_dir)
61 Real dy = positions.top () - positions[0];
62 Real slope = dy / Real (positions.size () - 1);
63 Real concaveness = 0.0;
64 for (int i = 1; i < positions.size () - 1; i++)
66 Real line_y = slope * i + positions[0];
68 concaveness += max (beam_dir * (positions[i] - line_y), 0.0);
71 concaveness /= positions.size ();
74 Normalize. For dy = 0, the slope ends up as 0 anyway, so the
75 scaling of concaveness doesn't matter much.
78 concaveness /= fabs (dy);
82 MAKE_SCHEME_CALLBACK (Beam, check_concave, 1);
84 Beam::check_concave (SCM smob)
86 Grob *me = unsmob_grob (smob);
88 Link_array<Grob> stems
89 = extract_grob_array (me, "stems");
92 return SCM_UNSPECIFIED;
94 Direction beam_dir = CENTER;
95 for (int i = stems.size (); i--;)
97 if (Stem::is_invisible (stems[i]))
101 if (Direction dir = Stem::get_direction (stems[i]))
106 if (stems.size () <= 2)
107 return SCM_UNSPECIFIED;
109 Array<int> close_positions;
110 Array<int> far_positions;
111 for (int i = 0; i < stems.size (); i++)
114 For chords, we take the note head that is closest to the beam.
116 Hmmm.. wait, for the beams in the last measure of morgenlied,
117 this doesn't look so good. Let's try the heads farthest from
121 Interval posns = Stem::head_positions (stems[i]);
123 close_positions.push ((int) rint (posns[beam_dir]));
124 far_positions.push ((int) rint (posns[-beam_dir]));
127 if (is_concave_single_notes (far_positions, beam_dir))
129 Drul_array<Real> pos = ly_scm2interval (me->get_property ("positions"));
130 Real r = linear_combination (pos, 0.0);
132 r /= Staff_symbol_referencer::staff_space (me);
133 me->set_property ("positions", ly_interval2scm (Drul_array<Real> (r, r)));
134 me->set_property ("least-squares-dy", scm_from_double (0));
138 Real concaveness = (calc_concaveness (far_positions, beam_dir)
139 + calc_concaveness (close_positions, beam_dir)) / 2;
141 me->set_property ("concaveness", scm_from_double (concaveness));
144 return SCM_UNSPECIFIED;