]> git.donarmstrong.com Git - lilypond.git/blob - lily/beam-concave.cc
0f2cb2fb9c896174f4e3f2fa259d36dc310deef5
[lilypond.git] / lily / beam-concave.cc
1 /*
2    Determine whether a beam is concave.
3  */
4
5 #include <math.h>
6
7 #include "group-interface.hh"
8 #include "array.hh"
9 #include "stem.hh"
10 #include "beam.hh"
11 #include "staff-symbol-referencer.hh"
12
13 bool
14 is_concave_single_notes (Array<int> const &positions, Direction beam_dir)
15 {
16   Interval covering;
17   covering.add_point (positions[0]);
18   covering.add_point (positions.top ());
19
20   bool above = false;
21   bool below = false;
22   bool concave = false;
23   
24   /*
25     notes above and below the interval covered by 1st and last note.
26    */
27   for (int i = 1; i < positions.size () - 1; i++)
28     {
29       above = above || (positions[i] > covering[UP]);
30       below = below || (positions[i] < covering[DOWN]);
31     }
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 = (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 += (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, ly_symbol2scm ("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
113   Array<int> close_positions;
114   Array<int> far_positions;
115   for (int i = 0; i < stems.size (); i++)
116     {
117       /*
118         For chords, we take the note head that is closest to the beam.
119
120         Hmmm.. wait, for the beams in the last measure of morgenlied,
121         this doesn't look so good. Let's try the heads farthest from
122         the beam.
123         
124        */
125       Interval posns = Stem::head_positions (stems[i]);
126       
127       close_positions.push ((int) rint (posns[beam_dir]));
128       far_positions.push ((int) rint (posns[-beam_dir]));
129     }
130
131   if (is_concave_single_notes (far_positions, beam_dir)) 
132     {
133       Drul_array<Real> pos = ly_scm2interval (me->get_property ("positions"));
134       Real r = linear_combination (pos, 0.0);
135
136       r /= Staff_symbol_referencer::staff_space (me);
137       me->set_property ("positions", ly_interval2scm (Drul_array<Real> (r, r)));
138       me->set_property ("least-squares-dy", scm_make_real (0));
139     }
140   else
141     {
142       Real concaveness = (calc_concaveness (far_positions, beam_dir)
143                           + calc_concaveness (close_positions, beam_dir))/2;
144       
145
146       me->set_property ("concaveness", scm_from_double (concaveness));
147     }
148   
149   return SCM_UNSPECIFIED;
150 }