*** empty log message ***
[lilypond.git] / lily / slur-bezier-bow.cc
blobf007d58dae10927ce8e65bb0e70c67f8eb388b0a
1 /*
2 slur-bezier-bow.cc -- implement Slur_bezier_bow
4 source file of the GNU LilyPond music typesetter
6 (c) 2000--2004 Jan Nieuwenhuizen <janneke@gnu.org>
7 */
9 #include "warn.hh"
10 #include "paper-def.hh"
11 #include "slur-bezier-bow.hh"
13 Slur_bezier_bow::Slur_bezier_bow (Array<Offset> encompass, Direction dir,
14 Real h_inf, Real r_0)
16 h_inf_ = h_inf;
17 r_0_ = r_0;
18 alpha_ = 0;
19 dir_ = dir;
20 encompass_ = encompass;
21 to_canonical_form ();
23 Real w = encompass_.top ()[X_AXIS] - encompass_[0][X_AXIS];
24 curve_ = slur_shape (w, h_inf, r_0);
27 Bezier
28 Slur_bezier_bow::get_bezier () const
30 Bezier rv = curve_;
31 if (dir_ == DOWN)
33 rv.scale (1, -1);
36 rv.rotate (alpha_);
37 rv.translate (origin_);
39 return rv;
42 void
43 Slur_bezier_bow::to_canonical_form ()
45 origin_ = encompass_[0];
46 translate (&encompass_, -origin_);
48 Offset delta = encompass_.top () - encompass_[0];
49 alpha_ = delta.arg ();
51 rotate (&encompass_, -alpha_);
52 if (dir_ == DOWN)
54 scale (&encompass_, 1, -1);
57 while (encompass_.size () > 1 && encompass_[1][X_AXIS] <= 0.0)
59 programming_error ("Degenerate bow: infinite steepness reqd");
60 encompass_.del (1);
63 Real l = encompass_.top ()[X_AXIS];
64 while (encompass_.size () > 1 && encompass_.top (1)[X_AXIS] >= l)
66 programming_error ("Degenerate bow: infinite steepness reqd");
67 encompass_.del (encompass_.size ()-2);
73 void
74 Slur_bezier_bow::blow_fit ()
76 Real len = curve_.control_[3][X_AXIS];
77 Real h = curve_.control_[1][Y_AXIS] * fit_factor () / len;
78 curve_.control_[1][Y_AXIS] = h * len;
79 curve_.control_[2][Y_AXIS] = h * len;
80 curve_.assert_sanity ();
84 Real
85 Slur_bezier_bow::get_enclosed_area () const
87 Real a = 0;
88 for (int i=0; i < encompass_.size (); i++)
90 Interval x;
91 Interval y;
92 if (i == 0)
94 x = Interval (0, encompass_[1][X_AXIS] / 2);
95 y = Interval (0,
96 curve_.get_other_coordinate (X_AXIS,
97 encompass_[1][X_AXIS]
98 / 2));
100 else if (i == encompass_.size () - 1)
102 x = Interval ((encompass_[i-1][X_AXIS] + encompass_[i][X_AXIS])/2,
103 encompass_[i][X_AXIS]);
104 y = Interval (0,
105 (curve_.get_other_coordinate (X_AXIS,
106 (x[MIN] + x[MAX]) / 2)));
108 else
110 x = Interval ((encompass_[i-1][X_AXIS] + encompass_[i][X_AXIS]) / 2,
111 (encompass_[i][X_AXIS] + encompass_[i+1][X_AXIS]) / 2);
112 y = Interval (encompass_[i][Y_AXIS],
113 (curve_.get_other_coordinate (X_AXIS, x[MIN])
114 + curve_.get_other_coordinate (X_AXIS,
115 (x[MIN] + x[MAX]) / 2)
116 + curve_.get_other_coordinate (X_AXIS, x[MAX])) / 3);
119 Real da = x.length () * y.length ();
120 a += da;
122 return a;
125 Array<Real>
126 Slur_bezier_bow::area_x_gradientses (Real area)
128 Real len = curve_.control_[3][X_AXIS];
129 Real grow = len / 10.0;
130 Array<Real> da (2);
131 for (int i=0; i < 2; i++)
133 Real r = curve_.control_[i+1][X_AXIS];
134 curve_.control_[i+1][X_AXIS] += grow;
135 da[i] = (get_enclosed_area () - area) / grow;
136 curve_.control_[i+1][X_AXIS] = r;
138 return da;
142 ugh, should have another look, and use a regular optimization
143 algorithm, instead of this homebrew.
145 void
146 Slur_bezier_bow::minimise_enclosed_area (Real beauty,
147 SCM bezier_props)
149 Real length = curve_.control_[3][X_AXIS];
150 Real beautiful = beauty * length * slur_height (length, h_inf_, r_0_);
153 if (fit_factor () > 1.0)
154 blow_fit ();
156 Real pct_c0 = gh_scm2double (ly_cdr (scm_assoc (ly_symbol2scm ("bezier-pct-c0"), bezier_props)));
157 Real pct_c3 = gh_scm2double (ly_cdr (scm_assoc (ly_symbol2scm ("bezier-pct-c3"), bezier_props)));
158 Real pct_in_max = gh_scm2double (ly_cdr (scm_assoc (ly_symbol2scm ("bezier-pct-in-max"), bezier_props)));
159 Real pct_out_max = gh_scm2double (ly_cdr (scm_assoc (ly_symbol2scm ("bezier-pct-out-max"), bezier_props)));
160 Real steps = gh_scm2double (ly_cdr (scm_assoc (ly_symbol2scm ("bezier-area-steps"),bezier_props)));
162 for (int i=0; i < steps; i++)
164 Real area = get_enclosed_area ();
165 if (area <= beautiful)
166 break;
168 Array<Real> da = area_x_gradientses (area);
170 // urg
171 Real pct = pct_c0 + pct_c3 * length * length * length;
172 pct *= (steps - i) / steps;
173 if (da[0] > 0 || da[1] < 0)
174 pct = pct <? pct_out_max;
175 else
176 pct = pct <? pct_in_max;
178 Real u = (abs (curve_.control_[1][X_AXIS] / da[0])
179 <? abs ((curve_.control_[3][X_AXIS]
180 - curve_.control_[2][X_AXIS]) / da[1]));
182 curve_.control_[1][X_AXIS] -= da[0] * u * pct;
183 curve_.control_[2][X_AXIS] -= da[1] * u * pct;
190 max (encompass.y / curve.y)
193 Real
194 Slur_bezier_bow::fit_factor () const
196 Real x1 = encompass_[0][X_AXIS];
197 Real x2 = encompass_.top ()[X_AXIS];
199 Real factor = 0.0;
200 for (int i=1; i < encompass_.size ()-1; i++)
202 if (encompass_[i][X_AXIS] > x1 && encompass_[i][X_AXIS] < x2)
204 Real y = curve_.get_other_coordinate (X_AXIS, encompass_[i][X_AXIS]);
205 if (y>0)
207 Real f = encompass_[i][Y_AXIS] / y;
208 factor = factor >? f;
214 return factor;