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