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"
19 flipy (Array<Offset> &c)
21 for (int i = c.size (); i--;)
22 c[i][Y_AXIS] = - c[i][Y_AXIS];
26 rotate (Array<Offset> &c, Real phi)
28 Offset rot (complex_exp (Offset (0, phi)));
29 for (int i = 0; i < c.size (); i++)
30 c[i] = complex_multiply (rot, c[i]);
34 translate (Array<Offset> &c, Offset o)
36 for (int i = 0; i < c.size (); i++)
41 Bezier_bow::Bezier_bow (Array<Offset> points, Direction dir)
53 Bezier_bow::blow_fit ()
55 Real f = fit_factor ();
57 curve_.control_[1][Y_AXIS] *= f;
58 curve_.control_[2][Y_AXIS] *= f;
60 curve_.check_sanity ();
64 Bezier_bow::calculate ()
67 if (fit_factor () > 1.0)
69 calc_tangent_controls ();
74 Bezier_bow::get_curve ()const
83 rv.translate (origin_);
87 static Real const FUDGE = 1e-8;
90 This function calculates 2 center control points,
91 based on lines through c_0 --> left disturbing
92 and c_3--> right disturbing encompass points.
94 See Documentation/fonts.tex
97 Bezier_bow::calc_tangent_controls ()
99 Real b = curve_.control_[3][X_AXIS];
100 Real h = curve_.control_[1][Y_AXIS];
103 Drul_array<Offset> disturb;
104 Drul_array<Real> maxtan;
105 maxtan[LEFT] = maxtan[RIGHT] = h/(b/2);
106 disturb[LEFT] = disturb[RIGHT] = Offset (b / 2, h);
108 for (int i = 1; i < encompass_.size () -1; i++)
110 Real y= encompass_[i][Y_AXIS];
113 Real x = encompass_[i][X_AXIS];
120 Real tan = y / ((1-k)* b - d * x);
125 disturb[d] = Offset (x,y);
128 while (flip (&d)!=LEFT);
132 for (int i = 0; i < encompass_.size (); i++ )
133 h = h >? encompass_[i][Y_AXIS];
136 The curve will always be under line between curve_.control_0 -> curve_.control_1, so
137 make it extra steep by slur_rc_factor
141 Drul_array<Real> angles;
145 maxtan[d] *= -d * rc_factor_;
146 angles[d] = atan (maxtan[d]);
148 while (flip(&d) != LEFT);
153 if we have two disturbing points, have line through those...
154 in order to get a sane line, make sure points are reasonably far apart
155 X distance must be reasonably(!) big (division)
157 if (abs (disturb[LEFT][X_AXIS] - disturb[RIGHT][X_AXIS]) > FUDGE)
158 rc3 = (disturb[RIGHT][Y_AXIS] - disturb[LEFT][Y_AXIS]) / (disturb[RIGHT][X_AXIS] - disturb[LEFT][X_AXIS]);
161 rc3 = tan ((angles[LEFT] - angles[RIGHT]) / 2);
164 // ugh: be less steep
168 Real c2 = -maxtan[RIGHT] * curve_.control_[3][X_AXIS];
170 // use highest because rc3 is damped.
171 Real maxy = disturb[LEFT][Y_AXIS] >? disturb[RIGHT][Y_AXIS];
172 Real c3 = disturb[LEFT][Y_AXIS] > disturb[RIGHT][Y_AXIS] ?
173 maxy - rc3 * disturb[LEFT][X_AXIS] :
174 maxy - rc3 * disturb[RIGHT][X_AXIS];
176 curve_.control_[1][X_AXIS] = c3 / (maxtan[LEFT] - rc3);
177 curve_.control_[1][Y_AXIS] = maxtan[LEFT] * curve_.control_[1][X_AXIS];
179 curve_.control_[2][X_AXIS] = (c3 - c2) / (maxtan[RIGHT] - rc3);
180 curve_.control_[2][Y_AXIS] = maxtan[RIGHT] * curve_.control_[2][X_AXIS] + c2;
183 curve_.check_sanity();
187 The maximum amount that the encompass points stick out above the bezier curve.
190 Bezier_bow::fit_factor () const
192 Real x1 = encompass_[0][X_AXIS];
193 Real x2 = encompass_.top ()[X_AXIS];
196 for (int i=1; i < encompass_.size ()-1; i++)
198 if (encompass_[i][X_AXIS] > x1 && encompass_[i][X_AXIS] < x2)
200 Real y = curve_.get_other_coordinate (X_AXIS, encompass_[i][X_AXIS]);
203 Real f = encompass_[i][Y_AXIS] / y;
204 factor = factor >? f;
217 Bezier_bow::to_canonic_form ()
219 origin_ = encompass_[0];
220 translate (encompass_,-origin_);
222 Offset delta = encompass_.top () - encompass_[0];
223 alpha_ = delta.arg ();
225 rotate (encompass_, -alpha_);
231 while (encompass_.size () > 1 && encompass_[1][X_AXIS] <= 0.0)
233 programming_error ("Degenerate slur: infinite steepness reqd");
237 Real l = encompass_.top ()[X_AXIS];
238 while (encompass_.size () > 1 && encompass_.top (1)[X_AXIS] >= l)
240 programming_error ("Degenerate slur: infinite steepness reqd");
241 encompass_.del (encompass_.size ()-2);
248 See Documentation/fonts.tex
251 Bezier_bow::calc_default (Real h)
255 Real alpha = height_limit_ * 2.0 / pi;
256 Real beta = pi * ratio_ / (2.0 * height_limit_);
258 Offset delta (encompass_.top ()[X_AXIS]
259 - encompass_[0][X_AXIS], 0);
261 Real b = delta.length ();
262 Real indent = alpha * atan (beta * b);
263 Real height = indent + h;
265 curve_.control_ [0] = Offset (0, 0);
266 curve_.control_ [1] = Offset (indent, height);
267 curve_.control_ [2] = Offset (b - indent, height);
268 curve_.control_ [3] = Offset (b, 0);