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