2 Determine whether a beam is concave.
7 #include "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]);
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 = (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 += (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 Pointer_group_interface__extract_grobs (me, (Grob*) 0, "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;
113 Array<int> close_positions;
114 Array<int> far_positions;
115 for (int i = 0; i < stems.size (); i++)
118 For chords, we take the note head that is closest to the beam.
120 Hmmm.. wait, for the beams in the last measure of morgenlied,
121 this doesn't look so good. Let's try the heads farthest from
125 Interval posns = Stem::head_positions (stems[i]);
127 close_positions.push ((int) rint (posns[beam_dir]));
128 far_positions.push ((int) rint (posns[-beam_dir]));
131 if (is_concave_single_notes (far_positions, beam_dir))
133 Drul_array<Real> pos = ly_scm2interval (me->get_property ("positions"));
134 Real r = linear_combination (pos, 0.0);
136 r /= Staff_symbol_referencer::staff_space (me);
137 me->set_property ("positions", ly_interval2scm (Drul_array<Real> (r, r)));
138 me->set_property ("least-squares-dy", scm_make_real (0));
142 Real concaveness = (calc_concaveness (far_positions, beam_dir)
143 + calc_concaveness (close_positions, beam_dir))/2;
146 me->set_property ("concaveness", scm_from_double (concaveness));
149 return SCM_UNSPECIFIED;