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 (vector<int> const &positions, Direction beam_dir)
16 covering.add_point (positions[0]);
17 covering.add_point (positions.back ());
24 notes above and below the interval covered by 1st and last note.
26 for (vsize i = 1; i + 1 < positions.size (); 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.back () - positions[0];
38 int closest = max (beam_dir * positions.back (), beam_dir * positions[0]);
39 for (vsize i = 2; !concave && i + 1 < positions.size (); 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 (vsize i = 1; all_closer && i + 1 < positions.size (); i++)
51 all_closer = all_closer
52 && (beam_dir * positions[i] > closest);
55 concave = concave || all_closer;
60 calc_positions_concaveness (vector<int> const &positions, Direction beam_dir)
62 Real dy = positions.back () - positions[0];
63 Real slope = dy / Real (positions.size () - 1);
64 Real concaveness = 0.0;
65 for (vsize i = 1; i + 1 < positions.size (); 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);
84 MAKE_SCHEME_CALLBACK (Beam, calc_concaveness, 1);
86 Beam::calc_concaveness (SCM smob)
88 Grob *me = unsmob_grob (smob);
91 = extract_grob_array (me, "stems");
94 return scm_from_double (0.0);
96 Direction beam_dir = CENTER;
97 for (vsize i = stems.size (); i--;)
99 if (Stem::is_normal_stem (stems[i]))
101 if (Direction dir = get_grob_direction (stems[i]))
105 stems.erase (stems.begin () + i);
108 if (stems.size () <= 2)
109 return scm_from_int (0);
111 vector<int> close_positions;
112 vector<int> far_positions;
113 for (vsize 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_back ((int) rint (posns[beam_dir]));
126 far_positions.push_back ((int) rint (posns[-beam_dir]));
129 Real concaveness = 0.0;
131 if (is_concave_single_notes (far_positions, beam_dir))
137 concaveness = (calc_positions_concaveness (far_positions, beam_dir)
138 + calc_positions_concaveness (close_positions, beam_dir)) / 2;
141 return scm_from_double (concaveness);