Nitpick: ly:spanner-bound grob name slur -> spanner.
[lilypond.git] / lily / beam-concave.cc
blob48d45c859945eaa87ded018191bb9ab421b7b640
1 /*
2 beam-concave.cc -- implement Concaveness for beams.
4 source file of the GNU LilyPond music typesetter
6 (c) 2004 Han-Wen Nienhuys <hanwen@lilypond.org>
8 */
11 Determine whether a beam is concave.
13 A beam is concave when the middle notes get closer to the
14 beam than the left and right edge notes.
16 This is determined in two ways: by looking at the positions of the
17 middle notes, or by looking at the deviation of the inside notes
18 compared to the line connecting first and last.
20 The tricky thing is what to do with beams with chords. There are no
21 real guidelines in this case.
24 #include "pointer-group-interface.hh"
25 #include "stem.hh"
26 #include "beam.hh"
27 #include "grob.hh"
28 #include "staff-symbol-referencer.hh"
29 #include "directional-element-interface.hh"
31 bool
32 is_concave_single_notes (vector<int> const &positions, Direction beam_dir)
34 Interval covering;
35 covering.add_point (positions[0]);
36 covering.add_point (positions.back ());
38 bool above = false;
39 bool below = false;
40 bool concave = false;
43 notes above and below the interval covered by 1st and last note.
45 for (vsize i = 1; i + 1 < positions.size (); i++)
47 above = above || (positions[i] > covering[UP]);
48 below = below || (positions[i] < covering[DOWN]);
51 concave = concave || (above && below);
53 A note as close or closer to the beam than begin and end, but the
54 note is reached in the opposite direction as the last-first dy
56 int dy = positions.back () - positions[0];
57 int closest = max (beam_dir * positions.back (), beam_dir * positions[0]);
58 for (vsize i = 2; !concave && i + 1 < positions.size (); i++)
60 int inner_dy = positions[i] - positions[i - 1];
61 if (sign (inner_dy) != sign (dy)
62 && (beam_dir * positions[i] >= closest
63 || beam_dir * positions[i - 1] >= closest))
64 concave = true;
67 bool all_closer = true;
68 for (vsize i = 1; all_closer && i + 1 < positions.size (); i++)
70 all_closer = all_closer
71 && (beam_dir * positions[i] > closest);
74 concave = concave || all_closer;
75 return concave;
78 Real
79 calc_positions_concaveness (vector<int> const &positions, Direction beam_dir)
81 Real dy = positions.back () - positions[0];
82 Real slope = dy / Real (positions.size () - 1);
83 Real concaveness = 0.0;
84 for (vsize i = 1; i + 1 < positions.size (); i++)
86 Real line_y = slope * i + positions[0];
88 concaveness += max (beam_dir * (positions[i] - line_y), 0.0);
91 concaveness /= positions.size ();
94 Normalize. For dy = 0, the slope ends up as 0 anyway, so the
95 scaling of concaveness doesn't matter much.
97 if (dy)
98 concaveness /= fabs (dy);
99 return concaveness;
103 MAKE_SCHEME_CALLBACK (Beam, calc_concaveness, 1);
105 Beam::calc_concaveness (SCM smob)
107 Grob *me = unsmob_grob (smob);
109 vector<Grob*> stems
110 = extract_grob_array (me, "stems");
112 if (is_knee (me))
113 return scm_from_double (0.0);
115 Direction beam_dir = CENTER;
116 for (vsize i = stems.size (); i--;)
118 if (Stem::is_normal_stem (stems[i]))
120 if (Direction dir = get_grob_direction (stems[i]))
121 beam_dir = dir;
123 else
124 stems.erase (stems.begin () + i);
127 if (stems.size () <= 2)
128 return scm_from_int (0);
130 vector<int> close_positions;
131 vector<int> far_positions;
132 for (vsize i = 0; i < stems.size (); i++)
135 For chords, we take the note head that is closest to the beam.
137 Hmmm.. wait, for the beams in the last measure of morgenlied,
138 this doesn't look so good. Let's try the heads farthest from
139 the beam.
141 Interval posns = Stem::head_positions (stems[i]);
143 close_positions.push_back ((int) rint (posns[beam_dir]));
144 far_positions.push_back ((int) rint (posns[-beam_dir]));
147 Real concaveness = 0.0;
149 if (is_concave_single_notes (beam_dir == UP ? close_positions : far_positions, beam_dir))
151 concaveness = 10000;
153 else
155 concaveness = (calc_positions_concaveness (far_positions, beam_dir)
156 + calc_positions_concaveness (close_positions, beam_dir)) / 2;
159 return scm_from_double (concaveness);