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