2 bezier.cc -- implement Bezier and Bezier_bow
4 source file of the GNU LilyPond music typesetter
6 (c) 1998--2000 Jan Nieuwenhuizen <janneke@gnu.org>
10 #include "bezier-bow.hh"
13 #include "dimensions.hh"
14 #include "direction.hh"
17 #include "lily-guile.hh"
20 flipy (Array<Offset> &c)
22 for (int i = c.size (); i--;)
23 c[i][Y_AXIS] = - c[i][Y_AXIS];
27 rotate (Array<Offset> &c, Real phi)
29 Offset rot (complex_exp (Offset (0, phi)));
30 for (int i = 0; i < c.size (); i++)
31 c[i] = complex_multiply (rot, c[i]);
35 translate (Array<Offset> &c, Offset o)
37 for (int i = 0; i < c.size (); i++)
42 Bezier_bow::Bezier_bow (Array<Offset> points, Direction dir)
54 Bezier_bow::blow_fit ()
56 Real len = curve_.control_[3][X_AXIS] ;
57 Real ind = curve_.control_[1][X_AXIS] / len;
58 Real h = curve_.control_[1][Y_AXIS] * fit_factor () / len;
60 // ugh. Unhardcode this
66 if (h > 0.8 + -2 * ind)
71 curve_.control_[1][Y_AXIS] = h * len;
72 curve_.control_[2][Y_AXIS] = h * len;
74 curve_.check_sanity ();
78 Bezier_bow::calculate ()
81 if (fit_factor () > 1.0)
83 // calc_tangent_controls ();
91 Bezier_bow::get_curve ()const
100 rv.translate (origin_);
105 static Real const FUDGE = 1e-8;
108 This function calculates 2 center control points,
109 based on lines through c_0 --> left disturbing
110 and c_3--> right disturbing encompass points.
112 See Documentation/fonts.tex
115 Bezier_bow::calc_tangent_controls ()
117 Real b = curve_.control_[3][X_AXIS];
118 Real h = curve_.control_[1][Y_AXIS];
121 Drul_array<Offset> disturb;
122 Drul_array<Real> maxtan;
123 maxtan[LEFT] = maxtan[RIGHT] = h/(b/2);
124 disturb[LEFT] = disturb[RIGHT] = Offset (b / 2, h);
126 for (int i = 1; i < encompass_.size () -1; i++)
128 Real y= encompass_[i][Y_AXIS];
131 Real x = encompass_[i][X_AXIS];
138 Real tan = y / ((1-k)* b - d * x);
143 disturb[d] = Offset (x,y);
146 while (flip (&d)!=LEFT);
150 for (int i = 0; i < encompass_.size (); i++ )
151 h = h >? encompass_[i][Y_AXIS];
154 The curve will always be under line between curve_.control_0 -> curve_.control_1, so
155 make it extra steep by slur_rc_factor
159 Drul_array<Real> angles;
163 maxtan[d] *= -d * rc_factor_;
164 angles[d] = atan (maxtan[d]);
166 while (flip(&d) != LEFT);
171 if we have two disturbing points, have line through those...
172 in order to get a sane line, make sure points are reasonably far apart
173 X distance must be reasonably(!) big (division)
175 if (abs (disturb[LEFT][X_AXIS] - disturb[RIGHT][X_AXIS]) > FUDGE)
176 rc3 = (disturb[RIGHT][Y_AXIS] - disturb[LEFT][Y_AXIS]) / (disturb[RIGHT][X_AXIS] - disturb[LEFT][X_AXIS]);
179 rc3 = tan ((angles[LEFT] - angles[RIGHT]) / 2);
182 // ugh: be less steep
186 Real c2 = -maxtan[RIGHT] * curve_.control_[3][X_AXIS];
188 // use highest because rc3 is damped.
189 Real maxy = disturb[LEFT][Y_AXIS] >? disturb[RIGHT][Y_AXIS];
190 Real c3 = disturb[LEFT][Y_AXIS] > disturb[RIGHT][Y_AXIS] ?
191 maxy - rc3 * disturb[LEFT][X_AXIS] :
192 maxy - rc3 * disturb[RIGHT][X_AXIS];
194 curve_.control_[1][X_AXIS] = c3 / (maxtan[LEFT] - rc3);
195 curve_.control_[1][Y_AXIS] = maxtan[LEFT] * curve_.control_[1][X_AXIS];
197 curve_.control_[2][X_AXIS] = (c3 - c2) / (maxtan[RIGHT] - rc3);
198 curve_.control_[2][Y_AXIS] = maxtan[RIGHT] * curve_.control_[2][X_AXIS] + c2;
201 curve_.check_sanity();
205 The maximum amount that the encompass points stick out above the bezier curve.
208 Bezier_bow::fit_factor () const
210 Real x1 = encompass_[0][X_AXIS];
211 Real x2 = encompass_.top ()[X_AXIS];
214 for (int i=1; i < encompass_.size ()-1; i++)
216 if (encompass_[i][X_AXIS] > x1 && encompass_[i][X_AXIS] < x2)
218 Real y = curve_.get_other_coordinate (X_AXIS, encompass_[i][X_AXIS]);
221 Real f = encompass_[i][Y_AXIS] / y;
222 factor = factor >? f;
235 Bezier_bow::to_canonic_form ()
237 origin_ = encompass_[0];
238 translate (encompass_,-origin_);
240 Offset delta = encompass_.top () - encompass_[0];
241 alpha_ = delta.arg ();
243 rotate (encompass_, -alpha_);
249 while (encompass_.size () > 1 && encompass_[1][X_AXIS] <= 0.0)
251 programming_error ("Degenerate slur: infinite steepness reqd");
255 Real l = encompass_.top ()[X_AXIS];
256 while (encompass_.size () > 1 && encompass_.top (1)[X_AXIS] >= l)
258 programming_error ("Degenerate slur: infinite steepness reqd");
259 encompass_.del (encompass_.size ()-2);
266 See Documentation/fonts.tex
269 Bezier_bow::calc_default ()
273 Real alpha = height_limit_ * 2.0 / pi;
274 Real beta = pi * ratio_ / (2.0 * height_limit_);
276 Offset delta (encompass_.top ()[X_AXIS]
277 - encompass_[0][X_AXIS], 0);
279 Real b = delta.length ();
280 Real indent = alpha * atan (beta * b);
281 Real height = indent;
283 curve_.control_ [0] = Offset (0, 0);
284 curve_.control_ [1] = Offset (indent, height);
285 curve_.control_ [2] = Offset (b - indent, height);
286 curve_.control_ [3] = Offset (b, 0);