lilypond-1.3.16
[lilypond.git] / lily / bezier-bow.cc
blobafdd951b8e587a9f1694afdc253e1af0f36691f7
1 /*
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>
7 */
9 #include <math.h>
10 #include "bezier-bow.hh"
11 #include "misc.hh"
12 #include "bezier.hh"
13 #include "dimensions.hh"
14 #include "direction.hh"
15 #include "paper-def.hh"
16 #include "debug.hh"
17 #include "main.hh"
19 void
20 flipy (Array<Offset> &c)
22 for (int i = c.size (); i--;)
23 c[i][Y_AXIS] = - c[i][Y_AXIS];
26 void
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]);
34 void
35 translate (Array<Offset> &c, Offset o)
37 for (int i = 0; i < c.size (); i++)
38 c[i] += o;
42 Bezier_bow::Bezier_bow (Paper_def* paper_l,
43 Array<Offset> points, Direction dir)
45 paper_l_ = paper_l;
46 dir_ = dir;
47 encompass_ = points;
48 to_canonic_form ();
50 calc_default (0.0);
51 if (fit_factor () > 1.0)
53 calc_tangent_controls ();
54 blow_fit ();
58 void
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 ();
74 Bezier
75 Bezier_bow::get_curve ()const
78 Bezier rv = curve_;
79 if (dir_ == DOWN)
81 rv.flip (Y_AXIS);
84 rv.rotate (alpha_);
85 rv.translate (origin_);
86 return rv;
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
98 void
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];
113 if (y> 0)
115 Real x = encompass_[i][X_AXIS];
117 Direction d = LEFT;
120 // 1 if d == LEFT
121 int k = (1 - d)/2;
122 Real tan = y / ((1-k)* b - d * x);
124 if (tan > maxtan[d])
126 maxtan[d] = tan;
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;
144 Direction d = LEFT;
147 maxtan[d] *= -d * rc_correct;
148 angles[d] = atan (maxtan[d]);
150 while (flip(&d) != LEFT);
152 Real rc3 = 0.0;
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]);
162 else
163 rc3 = tan ((angles[LEFT] - angles[RIGHT]) / 2);
166 // ugh: be less steep
167 rc3 /= 2*rc_correct;
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.
191 Real
192 Bezier_bow::fit_factor () const
194 Real x1 = encompass_[0][X_AXIS];
195 Real x2 = encompass_.top ()[X_AXIS];
197 Real factor = 1.0;
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]);
203 if (y>0)
205 Real f = encompass_[i][Y_AXIS] / y;
206 factor = factor >? f;
212 return factor;
218 void
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_);
228 if (dir_ == DOWN)
230 flipy (encompass_);
237 See Documentation/fonts.tex
239 void
240 Bezier_bow::calc_default (Real h)
242 Real pi = M_PI;
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);