2 Determine whether a beam is concave.
5 #include "pointer-group-interface.hh"
9 #include "staff-symbol-referencer.hh"
10 #include "directional-element-interface.hh"
13 is_concave_single_notes (Array<int> const &positions, Direction beam_dir)
16 covering.add_point (positions[0]);
17 covering.add_point (positions.top ());
24 notes above and below the interval covered by 1st and last note.
26 for (int i = 1; i < positions.size () - 1; i++)
28 above = above || (positions[i] > covering[UP]);
29 below = below || (positions[i] < covering[DOWN]);
32 concave = concave || (above && below);
34 A note as close or closer to the beam than begin and end, but the
35 note is reached in the opposite direction as the last-first dy
37 int dy = positions.top () - positions[0];
38 int closest = max (beam_dir * positions.top (), beam_dir * positions[0]);
39 for (int i = 2; !concave && i < positions.size () - 1; i++)
41 int inner_dy = positions[i] - positions[i - 1];
42 if (sign (inner_dy) != sign (dy)
43 && (beam_dir * positions[i] >= closest
44 || beam_dir * positions[i - 1] >= closest))
48 bool all_closer = true;
49 for (int i = 1; all_closer && i < positions.size () - 1; i++)
51 all_closer = all_closer
52 && (beam_dir * positions[i] > closest);
55 concave = concave || all_closer;
60 calc_concaveness (Array<int> const &positions, Direction beam_dir)
62 Real dy = positions.top () - positions[0];
63 Real slope = dy / Real (positions.size () - 1);
64 Real concaveness = 0.0;
65 for (int i = 1; i < positions.size () - 1; i++)
67 Real line_y = slope * i + positions[0];
69 concaveness += max (beam_dir * (positions[i] - line_y), 0.0);
72 concaveness /= positions.size ();
75 Normalize. For dy = 0, the slope ends up as 0 anyway, so the
76 scaling of concaveness doesn't matter much.
79 concaveness /= fabs (dy);
83 MAKE_SCHEME_CALLBACK (Beam, check_concave, 1);
85 Beam::check_concave (SCM smob)
87 Grob *me = unsmob_grob (smob);
89 Link_array<Grob> stems
90 = extract_grob_array (me, "stems");
93 return SCM_UNSPECIFIED;
95 Direction beam_dir = CENTER;
96 for (int i = stems.size (); i--;)
98 if (Stem::is_invisible (stems[i]))
102 if (Direction dir = get_grob_direction (stems[i]))
107 if (stems.size () <= 2)
108 return SCM_UNSPECIFIED;
110 Array<int> close_positions;
111 Array<int> far_positions;
112 for (int i = 0; i < stems.size (); i++)
115 For chords, we take the note head that is closest to the beam.
117 Hmmm.. wait, for the beams in the last measure of morgenlied,
118 this doesn't look so good. Let's try the heads farthest from
122 Interval posns = Stem::head_positions (stems[i]);
124 close_positions.push ((int) rint (posns[beam_dir]));
125 far_positions.push ((int) rint (posns[-beam_dir]));
128 if (is_concave_single_notes (far_positions, beam_dir))
130 Drul_array<Real> pos = ly_scm2interval (me->get_property ("positions"));
131 Real r = linear_combination (pos, 0.0);
133 r /= Staff_symbol_referencer::staff_space (me);
134 me->set_property ("positions", ly_interval2scm (Drul_array<Real> (r, r)));
135 me->set_property ("least-squares-dy", scm_from_double (0));
139 Real concaveness = (calc_concaveness (far_positions, beam_dir)
140 + calc_concaveness (close_positions, beam_dir)) / 2;
142 me->set_property ("concaveness", scm_from_double (concaveness));
145 return SCM_UNSPECIFIED;