]> git.donarmstrong.com Git - lilypond.git/blob - lily/beam-concave.cc
* lily/grob-property.cc (get_interfaces): new function.
[lilypond.git] / lily / beam-concave.cc
1 /*
2   Determine whether a beam is concave.
3 */
4
5 #include "pointer-group-interface.hh"
6 #include "array.hh"
7 #include "stem.hh"
8 #include "beam.hh"
9 #include "staff-symbol-referencer.hh"
10 #include "directional-element-interface.hh"
11
12 bool
13 is_concave_single_notes (Array<int> const &positions, Direction beam_dir)
14 {
15   Interval covering;
16   covering.add_point (positions[0]);
17   covering.add_point (positions.top ());
18
19   bool above = false;
20   bool below = false;
21   bool concave = false;
22
23   /*
24     notes above and below the interval covered by 1st and last note.
25   */
26   for (int i = 1; i < positions.size () - 1; i++)
27     {
28       above = above || (positions[i] > covering[UP]);
29       below = below || (positions[i] < covering[DOWN]);
30     }
31
32   concave = concave || (above && below);
33   /*
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
36   */
37   int dy = positions.top () - positions[0];
38   int closest = max (beam_dir * positions.top (), beam_dir * positions[0]);
39   for (int i = 2; !concave && i < positions.size () - 1; i++)
40     {
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))
45         concave = true;
46     }
47
48   bool all_closer = true;
49   for (int i = 1; all_closer && i < positions.size () - 1; i++)
50     {
51       all_closer = all_closer
52         && (beam_dir * positions[i] > closest);
53     }
54
55   concave = concave || all_closer;
56   return concave;
57 }
58
59 Real
60 calc_concaveness (Array<int> const &positions, Direction beam_dir)
61 {
62   Real dy = positions.top () - positions[0];
63   Real slope = dy / Real (positions.size () - 1);
64   Real concaveness = 0.0;
65   for (int i = 1; i < positions.size () - 1; i++)
66     {
67       Real line_y = slope * i + positions[0];
68
69       concaveness += max (beam_dir * (positions[i] - line_y), 0.0);
70     }
71
72   concaveness /= positions.size ();
73
74   /*
75     Normalize. For dy = 0, the slope ends up as 0 anyway, so the
76     scaling of concaveness doesn't matter much.
77   */
78   if (dy)
79     concaveness /= fabs (dy);
80   return concaveness;
81 }
82
83 MAKE_SCHEME_CALLBACK (Beam, check_concave, 1);
84 SCM
85 Beam::check_concave (SCM smob)
86 {
87   Grob *me = unsmob_grob (smob);
88
89   Link_array<Grob> stems
90     = extract_grob_array (me, "stems");
91
92   if (is_knee (me))
93     return SCM_UNSPECIFIED;
94
95   Direction beam_dir = CENTER;
96   for (int i = stems.size (); i--;)
97     {
98       if (Stem::is_invisible (stems[i]))
99         stems.del (i);
100       else
101         {
102           if (Direction dir = get_grob_direction (stems[i]))
103             beam_dir = dir;
104         }
105     }
106
107   if (stems.size () <= 2)
108     return SCM_UNSPECIFIED;
109
110   Array<int> close_positions;
111   Array<int> far_positions;
112   for (int i = 0; i < stems.size (); i++)
113     {
114       /*
115         For chords, we take the note head that is closest to the beam.
116
117         Hmmm.. wait, for the beams in the last measure of morgenlied,
118         this doesn't look so good. Let's try the heads farthest from
119         the beam.
120
121       */
122       Interval posns = Stem::head_positions (stems[i]);
123
124       close_positions.push ((int) rint (posns[beam_dir]));
125       far_positions.push ((int) rint (posns[-beam_dir]));
126     }
127
128   if (is_concave_single_notes (far_positions, beam_dir))
129     {
130       Drul_array<Real> pos = ly_scm2interval (me->get_property ("positions"));
131       Real r = linear_combination (pos, 0.0);
132
133       r /= Staff_symbol_referencer::staff_space (me);
134       me->set_property ("positions", ly_interval2scm (Drul_array<Real> (r, r)));
135       me->set_property ("least-squares-dy", scm_from_double (0));
136     }
137   else
138     {
139       Real concaveness = (calc_concaveness (far_positions, beam_dir)
140                           + calc_concaveness (close_positions, beam_dir)) / 2;
141
142       me->set_property ("concaveness", scm_from_double (concaveness));
143     }
144
145   return SCM_UNSPECIFIED;
146 }