]> git.donarmstrong.com Git - lilypond.git/blob - lily/slur-bezier-bow.cc
0240e99f87a2dbc45c1aa0c560e481788f45ce34
[lilypond.git] / lily / slur-bezier-bow.cc
1 /*
2   slur-bezier-bow.cc -- implement Slur_bezier_bow
3
4   source file of the GNU LilyPond music typesetter
5
6   (c) 2000  Jan Nieuwenhuizen <janneke@gnu.org>
7 */
8
9 #include "debug.hh"
10 #include "paper-def.hh"
11 #include "slur-bezier-bow.hh"
12 #include "main.hh"
13
14 Slur_bezier_bow::Slur_bezier_bow (Array<Offset> encompass, Direction dir,
15                                   Real h_inf, Real r_0)
16 {
17   h_inf_ = h_inf;
18   r_0_ = r_0;
19   alpha_ = 0;
20   dir_ = dir;
21   encompass_ = encompass;
22   to_canonical_form ();
23
24   Real w = encompass_.top ()[X_AXIS] - encompass_[0][X_AXIS];
25   curve_ = slur_shape (w, h_inf, r_0);
26 }
27
28 Bezier
29 Slur_bezier_bow::get_bezier () const
30 {
31   Bezier rv = curve_;
32   if (dir_ == DOWN)
33     {
34       rv.scale (1, -1);
35     }
36
37   rv.rotate (alpha_);
38   rv.translate (origin_);
39   
40   return rv;
41 }
42
43 void
44 Slur_bezier_bow::to_canonical_form ()
45 {
46   origin_ = encompass_[0];
47   translate (&encompass_, -origin_);
48
49   Offset delta = encompass_.top () - encompass_[0];
50   alpha_ = delta.arg ();
51
52   rotate (&encompass_, -alpha_);
53   if (dir_ == DOWN)
54     {
55       scale (&encompass_, 1, -1);
56     }
57
58   while (encompass_.size () > 1 && encompass_[1][X_AXIS] <= 0.0)
59     {
60       programming_error ("Degenerate bow: infinite steepness reqd");
61       encompass_.del (1);
62     }
63
64   Real l = encompass_.top ()[X_AXIS];
65   while (encompass_.size () > 1 && encompass_.top (1)[X_AXIS] >= l)
66     {
67       programming_error ("Degenerate bow: infinite steepness reqd");
68       encompass_.del (encompass_.size ()-2);
69     }
70 }
71
72
73
74 void
75 Slur_bezier_bow::blow_fit ()
76 {
77   Real len = curve_.control_[3][X_AXIS]; 
78   Real h = curve_.control_[1][Y_AXIS] * fit_factor () / len;
79   curve_.control_[1][Y_AXIS] = h * len;
80   curve_.control_[2][Y_AXIS] = h * len;  
81   curve_.assert_sanity ();
82 }
83
84
85 Real
86 Slur_bezier_bow::enclosed_area_f () const
87 {
88   Real a = 0;
89   for (int i=0; i < encompass_.size (); i++)
90     {
91       Interval x;
92       Interval y;
93       if (i == 0)
94         {
95           x = Interval (0, encompass_[1][X_AXIS] / 2);
96           y = Interval (0,
97                         curve_.get_other_coordinate (X_AXIS,
98                                                      encompass_[1][X_AXIS]
99                                                      / 2));
100         }
101       else if (i == encompass_.size () - 1)
102         {
103           x = Interval ((encompass_[i-1][X_AXIS] + encompass_[i][X_AXIS])/2, 
104                         encompass_[i][X_AXIS]);
105           y = Interval (0,
106                         (curve_.get_other_coordinate (X_AXIS,
107                                                       (x[MIN] + x[MAX]) / 2)));
108         }
109       else
110         {
111           x = Interval ((encompass_[i-1][X_AXIS] + encompass_[i][X_AXIS]) / 2, 
112                         (encompass_[i][X_AXIS] + encompass_[i+1][X_AXIS]) / 2);
113           y = Interval (encompass_[i][Y_AXIS],
114                         (curve_.get_other_coordinate (X_AXIS, x[MIN])
115                          + curve_.get_other_coordinate (X_AXIS,
116                                                         (x[MIN] + x[MAX]) / 2)
117                          + curve_.get_other_coordinate (X_AXIS, x[MAX])) / 3);
118         }
119       
120       Real da = x.length () * y.length ();
121       a += da;
122     }
123   return a;
124 }
125
126 Array<Real>
127 Slur_bezier_bow::area_x_gradients_array (Real area)
128 {
129   Real len = curve_.control_[3][X_AXIS]; 
130   Real grow = len / 10.0;
131   Array<Real> da (2);
132   for (int i=0; i < 2; i++)
133     {
134       Real r = curve_.control_[i+1][X_AXIS];
135       curve_.control_[i+1][X_AXIS] += grow;
136       da[i] = (enclosed_area_f () - area) / grow;
137       curve_.control_[i+1][X_AXIS] = r; 
138     }
139   return da;
140 }
141
142 /*
143   ugh, should have another look, and use a regular optimization
144   algorithm, instead of this homebrew.
145 */
146 void
147 Slur_bezier_bow::minimise_enclosed_area (Paper_def* paper_l, Real beauty)
148 {
149   Real length = curve_.control_[3][X_AXIS]; 
150   Real beautiful = beauty * length * slur_height (length, h_inf_, r_0_);
151
152   DEBUG_OUT << to_str ("Beautiful: %f\n", beautiful);
153   DEBUG_OUT << to_str ("Length: %f\n", length);
154   //  DEBUG_OUT << to_str ("D-height: %f\n", default_height);
155   DEBUG_OUT << to_str ("FitFac: %f\n", fit_factor ());
156
157   if (fit_factor () > 1.0)
158     blow_fit ();
159   
160   Real pct_c0 = paper_l->get_var ("bezier_pct_c0");
161   Real pct_c3 = paper_l->get_var ("bezier_pct_c3");
162   Real pct_in_max = paper_l->get_var ("bezier_pct_in_max");
163   Real pct_out_max = paper_l->get_var ("bezier_pct_out_max");
164   Real steps = paper_l->get_var ("bezier_area_steps");
165
166   for (int i=0; i < steps; i++)
167     {
168       Real area = enclosed_area_f ();
169       if (!i)
170         DEBUG_OUT << to_str ("Init area: %f\n", area);
171
172       if (area <= beautiful)
173         break;
174
175       Array<Real> da = area_x_gradients_array (area);
176
177       // urg
178       Real pct = pct_c0 + pct_c3 * length * length * length;
179       pct *= (steps - i) / steps;
180       if (da[0] > 0 || da[1] < 0)
181         pct = pct <? pct_out_max;
182       else
183         pct = pct <? pct_in_max;
184
185       Real u = (abs (curve_.control_[1][X_AXIS] / da[0])
186                 <? abs ((curve_.control_[3][X_AXIS]
187                          - curve_.control_[2][X_AXIS]) / da[1]));
188
189       DEBUG_OUT << to_str ("pct: %f\n", pct);
190       DEBUG_OUT << to_str ("u: %f\n", u);
191
192       DEBUG_OUT << to_str ("da: (%f, %f)\n", da[0], da[1]);
193       DEBUG_OUT << to_str ("da*u: (%f, %f)\n", da[0]*u*pct, da[1]*u*pct);
194       DEBUG_OUT << to_str ("cx: (%f, %f)\n", curve_.control_[1][X_AXIS],
195                            curve_.control_[2][X_AXIS]);
196
197       curve_.control_[1][X_AXIS] -= da[0] * u * pct;
198       curve_.control_[2][X_AXIS] -= da[1] * u * pct;
199     }
200
201   Real area = enclosed_area_f ();
202   DEBUG_OUT << to_str ("Exarea: %f\n", area);
203 }
204
205
206
207 /*
208   max ( encompass.y / curve.y )
209   
210  */
211 Real
212 Slur_bezier_bow::fit_factor () const
213 {
214   Real x1 = encompass_[0][X_AXIS];
215   Real x2 = encompass_.top ()[X_AXIS];
216
217   Real factor = 0.0;
218   for (int i=1; i < encompass_.size ()-1; i++)
219     {
220       if (encompass_[i][X_AXIS] > x1 && encompass_[i][X_AXIS] < x2)
221         {
222          Real y = curve_.get_other_coordinate (X_AXIS, encompass_[i][X_AXIS]);
223          if (y>0)
224            {
225              Real f = encompass_[i][Y_AXIS] / y;
226              factor = factor >? f;
227            }
228         }
229     }
230
231
232   return factor;
233 }
234
235
236
237