2 Determine whether a beam is concave.
7 #include "pointer-group-interface.hh"
11 #include "staff-symbol-referencer.hh"
14 is_concave_single_notes (Array<int> const &positions, Direction beam_dir)
17 covering.add_point (positions[0]);
18 covering.add_point (positions.top ());
25 notes above and below the interval covered by 1st and last note.
27 for (int i = 1; i < positions.size () - 1; i++)
29 above = above || (positions[i] > covering[UP]);
30 below = below || (positions[i] < covering[DOWN]);
33 concave = concave || (above && below);
35 A note as close or closer to the beam than begin and end, but the
36 note is reached in the opposite direction as the last-first dy
38 int dy = positions.top () - positions[0];
39 int closest = max (beam_dir * positions.top (), beam_dir * positions[0]);
40 for (int i = 2; !concave && i < positions.size () - 1; i++)
42 int inner_dy = positions[i] - positions[i - 1];
43 if (sign (inner_dy) != sign (dy)
44 && (beam_dir * positions[i] >= closest
45 || beam_dir * positions[i - 1] >= closest))
49 bool all_closer = true;
50 for (int i = 1; all_closer && i < positions.size () - 1; i++)
52 all_closer = all_closer
53 && (beam_dir * positions[i] > closest);
56 concave = concave || all_closer;
61 calc_concaveness (Array<int> const &positions, Direction beam_dir)
63 Real dy = positions.top () - positions[0];
64 Real slope = dy / Real (positions.size () - 1);
65 Real concaveness = 0.0;
66 for (int i = 1; i < positions.size () - 1; i++)
68 Real line_y = slope * i + positions[0];
70 concaveness += max (beam_dir * (positions[i] - line_y), 0.0);
73 concaveness /= positions.size ();
76 Normalize. For dy = 0, the slope ends up as 0 anyway, so the
77 scaling of concaveness doesn't matter much.
80 concaveness /= fabs (dy);
84 MAKE_SCHEME_CALLBACK (Beam, check_concave, 1);
86 Beam::check_concave (SCM smob)
88 Grob *me = unsmob_grob (smob);
90 Link_array<Grob> stems
91 = extract_grob_array (me, "stems");
94 return SCM_UNSPECIFIED;
96 Direction beam_dir = CENTER;
97 for (int i = stems.size (); i--;)
99 if (Stem::is_invisible (stems[i]))
103 if (Direction dir = Stem::get_direction (stems[i]))
108 if (stems.size () <= 2)
109 return SCM_UNSPECIFIED;
111 Array<int> close_positions;
112 Array<int> far_positions;
113 for (int i = 0; i < stems.size (); i++)
116 For chords, we take the note head that is closest to the beam.
118 Hmmm.. wait, for the beams in the last measure of morgenlied,
119 this doesn't look so good. Let's try the heads farthest from
123 Interval posns = Stem::head_positions (stems[i]);
125 close_positions.push ((int) rint (posns[beam_dir]));
126 far_positions.push ((int) rint (posns[-beam_dir]));
129 if (is_concave_single_notes (far_positions, beam_dir))
131 Drul_array<Real> pos = ly_scm2interval (me->get_property ("positions"));
132 Real r = linear_combination (pos, 0.0);
134 r /= Staff_symbol_referencer::staff_space (me);
135 me->set_property ("positions", ly_interval2scm (Drul_array<Real> (r, r)));
136 me->set_property ("least-squares-dy", scm_from_double (0));
140 Real concaveness = (calc_concaveness (far_positions, beam_dir)
141 + calc_concaveness (close_positions, beam_dir)) / 2;
143 me->set_property ("concaveness", scm_from_double (concaveness));
146 return SCM_UNSPECIFIED;