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