]> git.donarmstrong.com Git - lilypond.git/blob - src/beam.cc
release: 0.0.13
[lilypond.git] / src / beam.cc
1 #include "beam.hh"
2 #include "debug.hh"
3 #include "symbol.hh"
4 #include "molecule.hh"
5 #include "leastsquares.hh"
6 #include "pcol.hh"
7 #include "stem.hh"
8 #include "paper.hh"
9 #include "lookup.hh"
10
11
12 struct Stem_info {
13     Real x;
14     Real idealy;
15     Real miny;
16     int no_beams;
17
18     ///////////////
19     
20     Stem_info(){}
21     Stem_info(const Stem*);
22 };
23 Stem_info::Stem_info(const Stem*s)
24 {
25     x = s->hpos();
26     int dir = s->dir;
27     idealy  = MAX(dir*s->top, dir*s->bot);
28     miny = MAX(dir*s->minnote, dir*s-> maxnote);
29     assert(miny <= idealy);
30     no_beams = s->flag;
31 }
32
33 /****************/
34
35 Beam::Beam()
36 {
37     slope = 0;
38     left_pos = 0.0;
39     dir =0;
40 }
41
42 void
43 Beam::add(Stem*s)
44 {
45     stems.bottom().add(s);
46     s->print_flag = false;
47 }
48
49 void
50 Beam::set_default_dir()
51 {
52     int dirs[2];
53     dirs[0]=0; dirs[1] =0;
54     for (PCursor<Stem*> sc(stems); sc.ok(); sc++) {
55         sc->set_default_dir();
56         dirs[(sc->dir+1)/2] ++;
57     }
58     dir =  (dirs[0] > dirs[1]) ? -1 : 1;
59     for (PCursor<Stem*> sc(stems); sc.ok(); sc++) {
60         sc->dir = dir;
61     }
62 }
63 /*
64   should use minimum energy formulation (cf linespacing)
65   */
66 void
67 Beam::solve_slope()
68 {
69     svec<Stem_info> sinfo;
70     for (PCursor<Stem* >sc(stems); sc.ok(); sc++) {
71         sc->set_default_extents();
72         Stem_info i(sc);
73         sinfo.add(i);
74     }
75     Real leftx = sinfo[0].x;
76     Least_squares l;
77     for (int i=0; i < sinfo.sz(); i++) {
78         sinfo[i].x -= leftx;
79         l.input.add(Offset(sinfo[i].x, sinfo[i].idealy));
80     }
81
82     l.minimise(slope, left_pos);
83     Real dy = 0.0;
84     for (int i=0; i < sinfo.sz(); i++) {
85         Real y = sinfo[i].x * slope + left_pos;
86         Real my = sinfo[i].miny;
87
88         if (my - y > dy)
89             dy = my -y; 
90     }
91     left_pos += dy;
92     left_pos *= dir;    
93     slope *= dir;
94     
95 }
96
97 void
98 Beam::set_stemlens()
99 {
100     PCursor<Stem*> s(stems);
101     Real x0 = s->hpos();    
102     for (; s.ok() ; s++) {
103         Real x =  s->hpos()-x0;
104         s->set_stemend(left_pos + slope * x);   
105     }
106 }
107
108 void
109 Beam::calculate()
110 {
111     assert(stems.size()>1);
112     if (!dir)
113         set_default_dir();
114
115     solve_slope();
116 }
117
118 void
119 Beam::process()
120 {
121     calculate();
122     brew_molecule();
123     set_stemlens();
124 }
125
126
127 // todo.
128 Spanner *
129 Beam::broken_at(const PCol *, const PCol *) const
130 {
131     return new Beam(*this);
132 }
133
134 void
135 Beam::preprocess()
136 {
137     left  = (*stems.top())   ->pcol_;
138     right = (*stems.bottom())->pcol_;    
139 }
140
141 Interval
142 Beam::height() const
143 {
144     return output->extent().y;
145 }
146
147 Interval
148 Beam::width() const
149 {
150     Beam * me = (Beam*) this;   // ugh
151     return Interval( (*me->stems.top()) ->hpos(),
152                      (*me->stems.bottom()) ->hpos() );
153 }
154
155 void
156 Beam::brew_molecule()
157 {
158     assert(left->line == right->line);
159     Real inter=paper()->internote();
160     Real sl = slope*inter;
161     Real w =  width().length() + paper()->rule_thickness();
162     Symbol s = paper()->lookup_->beam(sl,w);
163     slope = sl / inter;
164     
165     Atom a(s);
166     
167     Real dx = width().min -left->hpos;
168     a.translate(Offset(dx,left_pos*inter));
169     output = new Molecule(a);
170 }
171
172 void
173 Beam::print()const
174 {
175     mtor << "Beam, slope " <<slope << "left ypos " << left_pos<<'\n';    
176 }
177