lilypond-1.3.145
[lilypond.git] / lily / slur-bezier-bow.cc
blobb5f0db22d72365f7de7e5097256d545380da68e0
1 /*
2 slur-bezier-bow.cc -- implement Slur_bezier_bow
4 source file of the GNU LilyPond music typesetter
6 (c) 2000--2001 Jan Nieuwenhuizen <janneke@gnu.org>
7 */
9 #include "debug.hh"
10 #include "paper-def.hh"
11 #include "slur-bezier-bow.hh"
12 #include "main.hh"
14 Slur_bezier_bow::Slur_bezier_bow (Array<Offset> encompass, Direction dir,
15 Real h_inf, Real r_0)
17 h_inf_ = h_inf;
18 r_0_ = r_0;
19 alpha_ = 0;
20 dir_ = dir;
21 encompass_ = encompass;
22 to_canonical_form ();
24 Real w = encompass_.top ()[X_AXIS] - encompass_[0][X_AXIS];
25 curve_ = slur_shape (w, h_inf, r_0);
28 Bezier
29 Slur_bezier_bow::get_bezier () const
31 Bezier rv = curve_;
32 if (dir_ == DOWN)
34 rv.scale (1, -1);
37 rv.rotate (alpha_);
38 rv.translate (origin_);
40 return rv;
43 void
44 Slur_bezier_bow::to_canonical_form ()
46 origin_ = encompass_[0];
47 translate (&encompass_, -origin_);
49 Offset delta = encompass_.top () - encompass_[0];
50 alpha_ = delta.arg ();
52 rotate (&encompass_, -alpha_);
53 if (dir_ == DOWN)
55 scale (&encompass_, 1, -1);
58 while (encompass_.size () > 1 && encompass_[1][X_AXIS] <= 0.0)
60 programming_error ("Degenerate bow: infinite steepness reqd");
61 encompass_.del (1);
64 Real l = encompass_.top ()[X_AXIS];
65 while (encompass_.size () > 1 && encompass_.top (1)[X_AXIS] >= l)
67 programming_error ("Degenerate bow: infinite steepness reqd");
68 encompass_.del (encompass_.size ()-2);
74 void
75 Slur_bezier_bow::blow_fit ()
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 ();
85 Real
86 Slur_bezier_bow::enclosed_area_f () const
88 Real a = 0;
89 for (int i=0; i < encompass_.size (); i++)
91 Interval x;
92 Interval y;
93 if (i == 0)
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));
101 else if (i == encompass_.size () - 1)
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)));
109 else
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);
120 Real da = x.length () * y.length ();
121 a += da;
123 return a;
126 Array<Real>
127 Slur_bezier_bow::area_x_gradients_array (Real area)
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++)
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;
139 return da;
143 ugh, should have another look, and use a regular optimization
144 algorithm, instead of this homebrew.
146 void
147 Slur_bezier_bow::minimise_enclosed_area (Real beauty,
148 SCM bezier_props)
150 Real length = curve_.control_[3][X_AXIS];
151 Real beautiful = beauty * length * slur_height (length, h_inf_, r_0_);
154 if (fit_factor () > 1.0)
155 blow_fit ();
157 Real pct_c0 = gh_scm2double (gh_cdr (scm_assoc (ly_symbol2scm ("bezier-pct-c0"), bezier_props)));
158 Real pct_c3 = gh_scm2double (gh_cdr (scm_assoc (ly_symbol2scm ("bezier-pct-c3"), bezier_props)));
159 Real pct_in_max = gh_scm2double (gh_cdr (scm_assoc (ly_symbol2scm ("bezier-pct-in-max"), bezier_props)));
160 Real pct_out_max = gh_scm2double (gh_cdr (scm_assoc (ly_symbol2scm ("bezier-pct-out-max"), bezier_props)));
161 Real steps = gh_scm2double (gh_cdr (scm_assoc (ly_symbol2scm ("bezier-area-steps"),bezier_props)));
163 for (int i=0; i < steps; i++)
165 Real area = enclosed_area_f ();
166 if (area <= beautiful)
167 break;
169 Array<Real> da = area_x_gradients_array (area);
171 // urg
172 Real pct = pct_c0 + pct_c3 * length * length * length;
173 pct *= (steps - i) / steps;
174 if (da[0] > 0 || da[1] < 0)
175 pct = pct <? pct_out_max;
176 else
177 pct = pct <? pct_in_max;
179 Real u = (abs (curve_.control_[1][X_AXIS] / da[0])
180 <? abs ((curve_.control_[3][X_AXIS]
181 - curve_.control_[2][X_AXIS]) / da[1]));
183 curve_.control_[1][X_AXIS] -= da[0] * u * pct;
184 curve_.control_[2][X_AXIS] -= da[1] * u * pct;
191 max (encompass.y / curve.y)
194 Real
195 Slur_bezier_bow::fit_factor () const
197 Real x1 = encompass_[0][X_AXIS];
198 Real x2 = encompass_.top ()[X_AXIS];
200 Real factor = 0.0;
201 for (int i=1; i < encompass_.size ()-1; i++)
203 if (encompass_[i][X_AXIS] > x1 && encompass_[i][X_AXIS] < x2)
205 Real y = curve_.get_other_coordinate (X_AXIS, encompass_[i][X_AXIS]);
206 if (y>0)
208 Real f = encompass_[i][Y_AXIS] / y;
209 factor = factor >? f;
215 return factor;