2 bezier.cc -- implement Bezier and Bezier_bow
4 source file of the GNU LilyPond music typesetter
6 (c) 1998--1999 Jan Nieuwenhuizen <janneke@gnu.org>
10 #include "bezier-bow.hh"
13 #include "dimensions.hh"
14 #include "direction.hh"
15 #include "paper-def.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 (Paper_def* paper_l,
43 Array<Offset> points, Direction dir)
51 if (fit_factor () > 1.0)
53 calc_tangent_controls ();
59 Bezier_bow::blow_fit ()
61 Real f = fit_factor ();
63 curve_.control_[1][Y_AXIS] *= f;
64 curve_.control_[2][Y_AXIS] *= f;
66 curve_.check_sanity ();
75 Bezier_bow::get_curve ()const
85 rv.translate (origin_);
89 static Real const FUDGE = 1e-8;
92 This function calculates 2 center control points,
93 based on lines through c_0 --> left disturbing
94 and c_3--> right disturbing encompass points.
96 See Documentation/fonts.tex
99 Bezier_bow::calc_tangent_controls ()
101 Real b = curve_.control_[3][X_AXIS];
102 Real h = curve_.control_[1][Y_AXIS];
105 Drul_array<Offset> disturb;
106 Drul_array<Real> maxtan;
107 maxtan[LEFT] = maxtan[RIGHT] = h/(b/2);
108 disturb[LEFT] = disturb[RIGHT] = Offset (b / 2, h);
110 for (int i = 1; i < encompass_.size () -1; i++)
112 Real y= encompass_[i][Y_AXIS];
115 Real x = encompass_[i][X_AXIS];
122 Real tan = y / ((1-k)* b - d * x);
127 disturb[d] = Offset (x,y);
130 while (flip (&d)!=LEFT);
134 for (int i = 0; i < encompass_.size (); i++ )
135 h = h >? encompass_[i][Y_AXIS];
138 The curve will always be under line between curve_.control_0 -> curve_.control_1, so
139 make it extra steep by slur_rc_factor
141 Real rc_correct = paper_l_->get_var ("slur_rc_factor");
143 Drul_array<Real> angles;
147 maxtan[d] *= -d * rc_correct;
148 angles[d] = atan (maxtan[d]);
150 while (flip(&d) != LEFT);
155 if we have two disturbing points, have line through those...
156 in order to get a sane line, make sure points are reasonably far apart
157 X distance must be reasonably(!) big (division)
159 if (abs (disturb[LEFT][X_AXIS] - disturb[RIGHT][X_AXIS]) > FUDGE)
160 rc3 = (disturb[RIGHT][Y_AXIS] - disturb[LEFT][Y_AXIS]) / (disturb[RIGHT][X_AXIS] - disturb[LEFT][X_AXIS]);
163 rc3 = tan ((angles[LEFT] - angles[RIGHT]) / 2);
166 // ugh: be less steep
170 Real c2 = -maxtan[RIGHT] * curve_.control_[3][X_AXIS];
172 // use highest because rc3 is damped.
173 Real maxy = disturb[LEFT][Y_AXIS] >? disturb[RIGHT][Y_AXIS];
174 Real c3 = disturb[LEFT][Y_AXIS] > disturb[RIGHT][Y_AXIS] ?
175 maxy - rc3 * disturb[LEFT][X_AXIS] :
176 maxy - rc3 * disturb[RIGHT][X_AXIS];
178 curve_.control_[1][X_AXIS] = c3 / (maxtan[LEFT] - rc3);
179 curve_.control_[1][Y_AXIS] = maxtan[LEFT] * curve_.control_[1][X_AXIS];
181 curve_.control_[2][X_AXIS] = (c3 - c2) / (maxtan[RIGHT] - rc3);
182 curve_.control_[2][Y_AXIS] = maxtan[RIGHT] * curve_.control_[2][X_AXIS] + c2;
185 curve_.check_sanity();
189 The maximum amount that the encompass points stick out above the bezier curve.
192 Bezier_bow::fit_factor () const
194 Real x1 = encompass_[0][X_AXIS];
195 Real x2 = encompass_.top ()[X_AXIS];
198 for (int i=1; i < encompass_.size ()-1; i++)
200 if (encompass_[i][X_AXIS] > x1 && encompass_[i][X_AXIS] < x2)
202 Real y = curve_.get_other_coordinate (X_AXIS, encompass_[i][X_AXIS]);
205 Real f = encompass_[i][Y_AXIS] / y;
206 factor = factor >? f;
219 Bezier_bow::to_canonic_form ()
221 origin_ = encompass_[0];
222 translate (encompass_,-origin_);
224 Offset delta = encompass_.top () - encompass_[0];
225 alpha_ = delta.arg ();
227 rotate (encompass_, -alpha_);
237 See Documentation/fonts.tex
240 Bezier_bow::calc_default (Real h)
244 Real height_limit = paper_l_->get_var ("slur_height_limit");
245 Real ratio = paper_l_->get_var ("slur_ratio");
247 Real alpha = height_limit * 2.0 / pi;
248 Real beta = pi * ratio / (2.0 * height_limit);
250 Offset delta (encompass_.top ()[X_AXIS]
251 - encompass_[0][X_AXIS], 0);
253 Real b = delta.length ();
254 Real indent = alpha * atan (beta * b);
255 Real height = indent + h;
257 curve_.control_ [0] = Offset (0, 0);
258 curve_.control_ [1] = Offset (indent, height);
259 curve_.control_ [2] = Offset (b - indent, height);
260 curve_.control_ [3] = Offset (b, 0);