Fixes Issue 1504, allowing feather beam line breaking.
[lilypond/patrick.git] / lily / beam-concave.cc
blob7ca626b60907f75aceeac1a81542adb7b0d1c372
1 /*
2 This file is part of LilyPond, the GNU music typesetter.
4 Copyright (C) 2004 Han-Wen Nienhuys <hanwen@lilypond.org>
6 LilyPond is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
11 LilyPond is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with LilyPond. If not, see <http://www.gnu.org/licenses/>.
21 Determine whether a beam is concave.
23 A beam is concave when the middle notes get closer to the
24 beam than the left and right edge notes.
26 This is determined in two ways: by looking at the positions of the
27 middle notes, or by looking at the deviation of the inside notes
28 compared to the line connecting first and last.
30 The tricky thing is what to do with beams with chords. There are no
31 real guidelines in this case.
34 #include "pointer-group-interface.hh"
35 #include "stem.hh"
36 #include "beam.hh"
37 #include "grob.hh"
38 #include "staff-symbol-referencer.hh"
39 #include "directional-element-interface.hh"
41 bool
42 is_concave_single_notes (vector<int> const &positions, Direction beam_dir)
44 Interval covering;
45 covering.add_point (positions[0]);
46 covering.add_point (positions.back ());
48 bool above = false;
49 bool below = false;
50 bool concave = false;
53 notes above and below the interval covered by 1st and last note.
55 for (vsize i = 1; i + 1 < positions.size (); i++)
57 above = above || (positions[i] > covering[UP]);
58 below = below || (positions[i] < covering[DOWN]);
61 concave = concave || (above && below);
63 A note as close or closer to the beam than begin and end, but the
64 note is reached in the opposite direction as the last-first dy
66 int dy = positions.back () - positions[0];
67 int closest = max (beam_dir * positions.back (), beam_dir * positions[0]);
68 for (vsize i = 2; !concave && i + 1 < positions.size (); i++)
70 int inner_dy = positions[i] - positions[i - 1];
71 if (sign (inner_dy) != sign (dy)
72 && (beam_dir * positions[i] >= closest
73 || beam_dir * positions[i - 1] >= closest))
74 concave = true;
77 bool all_closer = true;
78 for (vsize i = 1; all_closer && i + 1 < positions.size (); i++)
80 all_closer = all_closer
81 && (beam_dir * positions[i] > closest);
84 concave = concave || all_closer;
85 return concave;
88 Real
89 calc_positions_concaveness (vector<int> const &positions, Direction beam_dir)
91 Real dy = positions.back () - positions[0];
92 Real slope = dy / Real (positions.size () - 1);
93 Real concaveness = 0.0;
94 for (vsize i = 1; i + 1 < positions.size (); i++)
96 Real line_y = slope * i + positions[0];
98 concaveness += max (beam_dir * (positions[i] - line_y), 0.0);
101 concaveness /= positions.size ();
104 Normalize. For dy = 0, the slope ends up as 0 anyway, so the
105 scaling of concaveness doesn't matter much.
107 if (dy)
108 concaveness /= fabs (dy);
109 return concaveness;
113 MAKE_SCHEME_CALLBACK (Beam, calc_concaveness, 1);
115 Beam::calc_concaveness (SCM smob)
117 Grob *me = unsmob_grob (smob);
119 vector<Grob*> stems
120 = extract_grob_array (me, "stems");
122 if (is_knee (me))
123 return scm_from_double (0.0);
125 Direction beam_dir = CENTER;
126 for (vsize i = stems.size (); i--;)
128 if (Stem::is_normal_stem (stems[i]))
130 if (Direction dir = get_grob_direction (stems[i]))
131 beam_dir = dir;
133 else
134 stems.erase (stems.begin () + i);
137 if (stems.size () <= 2)
138 return scm_from_int (0);
140 vector<int> close_positions;
141 vector<int> far_positions;
142 for (vsize i = 0; i < stems.size (); i++)
145 For chords, we take the note head that is closest to the beam.
147 Hmmm.. wait, for the beams in the last measure of morgenlied,
148 this doesn't look so good. Let's try the heads farthest from
149 the beam.
151 Interval posns = Stem::head_positions (stems[i]);
153 close_positions.push_back ((int) rint (posns[beam_dir]));
154 far_positions.push_back ((int) rint (posns[-beam_dir]));
157 Real concaveness = 0.0;
159 if (is_concave_single_notes (beam_dir == UP ? close_positions : far_positions, beam_dir))
161 concaveness = 10000;
163 else
165 concaveness = (calc_positions_concaveness (far_positions, beam_dir)
166 + calc_positions_concaveness (close_positions, beam_dir)) / 2;
169 return scm_from_double (concaveness);