]> git.donarmstrong.com Git - lilypond.git/blob - lily/beam-concave.cc
Merge commit 'origin' into includes
[lilypond.git] / lily / beam-concave.cc
1 /* 
2   beam-concave.cc -- implement Concaveness for beams.
3   
4   source file of the GNU LilyPond music typesetter
5   
6   (c) 2004 Han-Wen Nienhuys <hanwen@lilypond.org>
7   
8 */
9
10 /*
11   Determine whether a beam is concave.
12
13   A beam is concave when the middle notes get closer to the
14   beam than the left and right edge notes.
15
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.
19
20   The tricky thing is what to do with beams with chords. There are no
21   real guidelines in this case.
22 */
23
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"
30
31 bool
32 is_concave_single_notes (vector<int> const &positions, Direction beam_dir)
33 {
34   Interval covering;
35   covering.add_point (positions[0]);
36   covering.add_point (positions.back ());
37
38   bool above = false;
39   bool below = false;
40   bool concave = false;
41
42   /*
43     notes above and below the interval covered by 1st and last note.
44   */
45   for (vsize i = 1; i + 1 < positions.size (); i++)
46     {
47       above = above || (positions[i] > covering[UP]);
48       below = below || (positions[i] < covering[DOWN]);
49     }
50
51   concave = concave || (above && below);
52   /*
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
55   */
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++)
59     {
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;
65     }
66
67   bool all_closer = true;
68   for (vsize i = 1; all_closer && i + 1 < positions.size (); i++)
69     {
70       all_closer = all_closer
71         && (beam_dir * positions[i] > closest);
72     }
73
74   concave = concave || all_closer;
75   return concave;
76 }
77
78 Real
79 calc_positions_concaveness (vector<int> const &positions, Direction beam_dir)
80 {
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++)
85     {
86       Real line_y = slope * i + positions[0];
87
88       concaveness += max (beam_dir * (positions[i] - line_y), 0.0);
89     }
90
91   concaveness /= positions.size ();
92
93   /*
94     Normalize. For dy = 0, the slope ends up as 0 anyway, so the
95     scaling of concaveness doesn't matter much.
96   */
97   if (dy)
98     concaveness /= fabs (dy);
99   return concaveness;
100 }
101
102
103 MAKE_SCHEME_CALLBACK (Beam, calc_concaveness, 1);
104 SCM
105 Beam::calc_concaveness (SCM smob)
106 {
107   Grob *me = unsmob_grob (smob);
108
109   vector<Grob*> stems
110     = extract_grob_array (me, "stems");
111
112   if (is_knee (me))
113     return scm_from_double (0.0);
114
115   Direction beam_dir = CENTER;
116   for (vsize i = stems.size (); i--;)
117     {
118       if (Stem::is_normal_stem (stems[i]))
119         {
120           if (Direction dir = get_grob_direction (stems[i]))
121             beam_dir = dir;
122         }
123       else
124         stems.erase (stems.begin () + i);
125     }
126
127   if (stems.size () <= 2)
128     return scm_from_int (0);
129
130   vector<int> close_positions;
131   vector<int> far_positions;
132   for (vsize i = 0; i < stems.size (); i++)
133     {
134       /*
135         For chords, we take the note head that is closest to the beam.
136
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.
140       */
141       Interval posns = Stem::head_positions (stems[i]);
142
143       close_positions.push_back ((int) rint (posns[beam_dir]));
144       far_positions.push_back ((int) rint (posns[-beam_dir]));
145     }
146
147   Real concaveness = 0.0;
148
149   if (is_concave_single_notes (beam_dir == UP ? close_positions : far_positions, beam_dir))
150     {
151       concaveness = 10000;
152     }
153   else
154     {
155       concaveness = (calc_positions_concaveness (far_positions, beam_dir)
156                      + calc_positions_concaveness (close_positions, beam_dir)) / 2;
157     }
158
159   return scm_from_double (concaveness);
160 }
161
162
163