]> git.donarmstrong.com Git - lilypond.git/blob - lily/slur-bezier-bow.cc
release: 1.3.72
[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)
148 {
149   Real length = curve_.control_[3][X_AXIS]; 
150
151   Real sb = paper_l->get_var ("slur_beautiful");
152   Real beautiful = sb * length * slur_height (length, h_inf_, r_0_);
153
154   DEBUG_OUT << to_str ("Beautiful: %f\n", beautiful);
155   DEBUG_OUT << to_str ("Length: %f\n", length);
156   //  DEBUG_OUT << to_str ("D-height: %f\n", default_height);
157   DEBUG_OUT << to_str ("FitFac: %f\n", fit_factor ());
158
159   if (fit_factor () > 1.0)
160     blow_fit ();
161   
162   Real pct_c0 = paper_l->get_var ("bezier_pct_c0");
163   Real pct_c3 = paper_l->get_var ("bezier_pct_c3");
164   Real pct_in_max = paper_l->get_var ("bezier_pct_in_max");
165   Real pct_out_max = paper_l->get_var ("bezier_pct_out_max");
166   Real steps = paper_l->get_var ("bezier_area_steps");
167
168   for (int i=0; i < steps; i++)
169     {
170       Real area = enclosed_area_f ();
171       if (!i)
172         DEBUG_OUT << to_str ("Init area: %f\n", area);
173
174       if (area <= beautiful)
175         break;
176
177       Array<Real> da = area_x_gradients_array (area);
178
179       // urg
180       Real pct = pct_c0 + pct_c3 * length * length * length;
181       pct *= (steps - i) / steps;
182       if (da[0] > 0 || da[1] < 0)
183         pct = pct <? pct_out_max;
184       else
185         pct = pct <? pct_in_max;
186
187       Real u = (abs (curve_.control_[1][X_AXIS] / da[0])
188                 <? abs ((curve_.control_[3][X_AXIS]
189                          - curve_.control_[2][X_AXIS]) / da[1]));
190
191       DEBUG_OUT << to_str ("pct: %f\n", pct);
192       DEBUG_OUT << to_str ("u: %f\n", u);
193
194       DEBUG_OUT << to_str ("da: (%f, %f)\n", da[0], da[1]);
195       DEBUG_OUT << to_str ("da*u: (%f, %f)\n", da[0]*u*pct, da[1]*u*pct);
196       DEBUG_OUT << to_str ("cx: (%f, %f)\n", curve_.control_[1][X_AXIS],
197                            curve_.control_[2][X_AXIS]);
198
199       curve_.control_[1][X_AXIS] -= da[0] * u * pct;
200       curve_.control_[2][X_AXIS] -= da[1] * u * pct;
201     }
202
203   Real area = enclosed_area_f ();
204   DEBUG_OUT << to_str ("Exarea: %f\n", area);
205 }
206
207
208
209 /*
210   max ( encompass.y / curve.y )
211   
212  */
213 Real
214 Slur_bezier_bow::fit_factor () const
215 {
216   Real x1 = encompass_[0][X_AXIS];
217   Real x2 = encompass_.top ()[X_AXIS];
218
219   Real factor = 0.0;
220   for (int i=1; i < encompass_.size ()-1; i++)
221     {
222       if (encompass_[i][X_AXIS] > x1 && encompass_[i][X_AXIS] < x2)
223         {
224          Real y = curve_.get_other_coordinate (X_AXIS, encompass_[i][X_AXIS]);
225          if (y>0)
226            {
227              Real f = encompass_[i][Y_AXIS] / y;
228              factor = factor >? f;
229            }
230         }
231     }
232
233
234   return factor;
235 }
236
237
238
239