]> git.donarmstrong.com Git - lilypond.git/blob - lily/beam-concave.cc
* ly/a4-init.ly (vsize): remove papersize init files.
[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> 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
64 MAKE_SCHEME_CALLBACK (Beam, check_concave, 1);
65 SCM
66 Beam::check_concave (SCM smob)
67 {
68   Grob *me = unsmob_grob (smob);
69
70   Link_array<Grob> stems = 
71     Pointer_group_interface__extract_grobs (me, (Grob*) 0, "stems");
72
73   if (is_knee (me))
74     return SCM_UNSPECIFIED;
75   
76   Direction beam_dir = CENTER;
77   for (int i = stems.size (); i--; )
78     {
79       if (Stem::is_invisible (stems[i]))
80         stems.del (i);
81       else
82         {
83           if (Direction dir = Stem::get_direction (stems[i]))
84             beam_dir = dir;
85         }
86     }
87   
88   if (stems.size () <= 2)
89     return SCM_UNSPECIFIED;
90
91
92   Array<int> positions;
93   for (int i= 0; i < stems.size (); i++)
94     {
95       /*
96         For chords, we take the note head that is closest to the beam.
97
98         Hmmm.. wait, for the beams in the last measure of morgenlied,
99         this doesn't look so good. Let's try the heads farthest from
100         the beam.
101         
102        */
103       Real pos = Stem::head_positions (stems[i])[-beam_dir];
104       
105       positions.push ((int) rint (pos));
106     }
107
108   if (is_concave_single_notes (positions, beam_dir)) 
109     {
110       Drul_array<Real> pos = ly_scm2interval (me->get_property ("positions"));
111       Real r = linear_combination (pos, 0.0);
112
113       r /= Staff_symbol_referencer::staff_space (me);
114       me->set_property ("positions", ly_interval2scm (Drul_array<Real> (r, r)));
115       me->set_property ("least-squares-dy", scm_make_real (0));
116     }
117   else
118     {
119       Real dy = positions.top () - positions[0];
120       Real slope = dy / Real (positions.size() - 1);
121       Real concaveness = 0.0;
122       for (int i = 1; i < positions.size() - 1; i++)
123         {
124           Real line_y = slope * i + positions[0];
125
126           concaveness += (beam_dir * (positions[i] - line_y)) >? 0.0;
127         }
128
129       concaveness /= positions.size () ;
130
131       /*
132         Normalize. For dy = 0, the slope ends up as 0 anyway, so the
133         scaling of concaveness doesn't matter much.
134        */
135       if (dy)
136         concaveness /= dy; 
137
138       me->set_property ("concaveness", scm_from_double (concaveness));
139     }
140   
141   return SCM_UNSPECIFIED;
142 }