2 Determine whether a beam is concave.
8 #include "pointer-group-interface.hh"
12 #include "staff-symbol-referencer.hh"
15 is_concave_single_notes (Array<int> const &positions, Direction beam_dir)
18 covering.add_point (positions[0]);
19 covering.add_point (positions.top ());
26 notes above and below the interval covered by 1st and last note.
28 for (int i = 1; i < positions.size () - 1; i++)
30 above = above || (positions[i] > covering[UP]);
31 below = below || (positions[i] < covering[DOWN]);
34 concave = concave || (above && below);
36 A note as close or closer to the beam than begin and end, but the
37 note is reached in the opposite direction as the last-first dy
39 int dy = positions.top () - positions[0];
40 int closest = max (beam_dir * positions.top (), beam_dir * positions[0]);
41 for (int i = 2; !concave && i < positions.size () - 1; i++)
43 int inner_dy = positions[i] - positions[i - 1];
44 if (sign (inner_dy) != sign (dy)
45 && (beam_dir * positions[i] >= closest
46 || beam_dir * positions[i - 1] >= closest))
50 bool all_closer = true;
51 for (int i = 1; all_closer && i < positions.size () - 1; i++)
53 all_closer = all_closer
54 && (beam_dir * positions[i] > closest);
57 concave = concave || all_closer;
62 calc_concaveness (Array<int> const &positions, Direction beam_dir)
64 Real dy = positions.top () - positions[0];
65 Real slope = dy / Real (positions.size () - 1);
66 Real concaveness = 0.0;
67 for (int i = 1; i < positions.size () - 1; i++)
69 Real line_y = slope * i + positions[0];
71 concaveness += max (beam_dir * (positions[i] - line_y), 0.0);
74 concaveness /= positions.size ();
77 Normalize. For dy = 0, the slope ends up as 0 anyway, so the
78 scaling of concaveness doesn't matter much.
81 concaveness /= fabs (dy);
85 MAKE_SCHEME_CALLBACK (Beam, check_concave, 1);
87 Beam::check_concave (SCM smob)
89 Grob *me = unsmob_grob (smob);
91 Link_array<Grob> stems
92 = extract_grob_array (me, "stems");
95 return SCM_UNSPECIFIED;
97 Direction beam_dir = CENTER;
98 for (int i = stems.size (); i--;)
100 if (Stem::is_invisible (stems[i]))
104 if (Direction dir = Stem::get_direction (stems[i]))
109 if (stems.size () <= 2)
110 return SCM_UNSPECIFIED;
112 Array<int> close_positions;
113 Array<int> far_positions;
114 for (int i = 0; i < stems.size (); i++)
117 For chords, we take the note head that is closest to the beam.
119 Hmmm.. wait, for the beams in the last measure of morgenlied,
120 this doesn't look so good. Let's try the heads farthest from
124 Interval posns = Stem::head_positions (stems[i]);
126 close_positions.push ((int) rint (posns[beam_dir]));
127 far_positions.push ((int) rint (posns[-beam_dir]));
130 if (is_concave_single_notes (far_positions, beam_dir))
132 Drul_array<Real> pos = ly_scm2interval (me->get_property ("positions"));
133 Real r = linear_combination (pos, 0.0);
135 r /= Staff_symbol_referencer::staff_space (me);
136 me->set_property ("positions", ly_interval2scm (Drul_array<Real> (r, r)));
137 me->set_property ("least-squares-dy", scm_from_double (0));
141 Real concaveness = (calc_concaveness (far_positions, beam_dir)
142 + calc_concaveness (close_positions, beam_dir)) / 2;
144 me->set_property ("concaveness", scm_from_double (concaveness));
147 return SCM_UNSPECIFIED;