2 bezier.cc -- implement Bezier and Bezier_bow
4 source file of the GNU LilyPond music typesetter
6 (c) 1998 Jan Nieuwenhuizen <jan@digicash.com>
13 #include "direction.hh"
15 #include "paper-def.hh"
18 #define SLUR_DOUT if (check_debug && !monitor->silent_b ("Slur")) cout
20 #define SLUR_DOUT cerr
26 for (int i
= 0; i
< size (); i
++)
27 (*this)[i
].mirror (Y_AXIS
);
31 Curve::largest_disturbing ()
35 for (int i
= 1; i
< size (); i
++)
37 if ((*this)[i
].y () > 0)
39 Real phi
= (*this)[i
].y () / (*this)[i
].x ();
51 Curve::rotate (Real phi
)
53 Offset
rot (complex_exp (Offset (0, phi
)));
54 for (int i
= 1; i
< size (); i
++)
55 (*this)[i
] = complex_multiply (rot
, (*this)[i
]);
59 Curve::translate (Offset o
)
61 for (int i
= 1; i
< size (); i
++)
67 control_
.set_size (4);
71 Bezier::calc (int steps
)
74 curve_
.set_size (steps
);
75 Real dt
= 1.0 / curve_
.size ();
76 Offset c
= 3.0 * (control_
[1] - control_
[0]);
77 Offset b
= 3.0 * (control_
[2] - control_
[1]) - c
;
78 Offset a
= control_
[3] - (control_
[0] + c
+ b
);
80 for (int i
= 0; i
< curve_
.size (); i
++ )
82 curve_
[i
] = ((a
* t
+ b
) * t
+ c
) * t
+ control_
[0];
88 Bezier::set (Array
<Offset
> points
)
90 assert (points
.size () == 4);
97 // if (x <= curve_[0].x ())
98 // return curve_[0].y ();
99 for (int i
= 1; i
< curve_
.size (); i
++ )
101 if (x
< curve_
[i
].x () || (i
== curve_
.size () - 1))
103 Offset z1
= curve_
[i
-1];
104 Offset z2
= curve_
[i
];
105 Real multiplier
= (x
- z2
.x ()) / (z1
.x () - z2
.x ());
106 Real y
= z1
.y () * multiplier
+ (1.0 - multiplier
) z2
.y();
117 Bezier_bow::Bezier_bow (Paper_def
* paper_l
)
120 return_
.set_size (4);
124 Bezier_bow::blow_fit ()
126 Real dy1
= check_fit_f ();
130 // be careful not to take too big step
133 control_
[1].y () += h1
;
134 control_
[2].y () += h1
;
135 return_
[1].y () += h1
;
136 return_
[2].y () += h1
;
139 Real dy2
= check_fit_f ();
144 Real epsilon
= paper_l_
->rule_thickness ();
146 Real epsilon
= 1.5 * 0.4 PT
;
148 if (abs (dy2
- dy1
) < epsilon
)
157 Then we get for h : B (h) = 0
159 B(0) = dy1 = a * 0 + b => b = dy1
160 B(h1) = dy2 = a * h1 + b => a * f * dy1 + b = dy2
164 a * dy1 / 2 + dy1 = dy2 => a = (dy2 - dy1) / (f * dy1)
167 Real a
= (dy2
- dy1
) / (f
* dy1
);
171 control_
[1].y () += -h1
+h
;
172 control_
[2].y () += -h1
+h
;
173 return_
[1].y () += -h1
+h
;
174 return_
[2].y () += -h1
+h
;
178 Bezier_bow::calc_bezier ()
180 Real s
= sqrt (control_
[3].x () * control_
[3].x ()
181 + control_
[1].y () * control_
[2].y ());
183 Real internote
= paper_l_
->internote_f ();
185 Real internote
= STAFFHEIGHT
/ 8;
187 int steps
= (int)rint (s
/ internote
);
188 Bezier::calc (steps
);
192 Bezier_bow::calc_f (Real height
)
195 calc_default (height
);
199 Real dy
= check_fit_f ();
202 transform_controls_back ();
221 transform_controls_back ();
225 Bezier_bow::calc_return (Real begin_alpha
, Real end_alpha
)
228 Real thick
= 1.8 * paper_l_
->rule_thickness ();
230 Real thick
= 1.8 * 0.4 PT
;
233 return_
[0] = control_
[3];
234 return_
[3] = control_
[0];
236 return_
[1] = control_
[2] - thick
* complex_exp (Offset (0, 90 + end_alpha
));
237 return_
[2] = control_
[1]
238 - thick
* complex_exp (Offset (0, 90 - begin_alpha
));
243 Document algorithm in:
244 See Documentation/fonts.tex
247 Bezier_bow::calc_controls ()
249 Offset
ijk_p (control_
[3].x () / 2, control_
[1].y ());
250 SLUR_DOUT
<< "ijk: " << ijk_p
.x () << ", " << ijk_p
.y () << endl
;
252 Real default_rc
= ijk_p
.y () / ijk_p
.x ();
254 int begin_disturb
= encompass_
.largest_disturbing ();
255 Offset begin_p
= begin_disturb
? Offset (encompass_
[begin_disturb
].x (),
256 encompass_
[begin_disturb
].y ()) : ijk_p
;
257 Real begin_rc
= begin_p
.y () / begin_p
.x ();
258 if (default_rc
> begin_rc
)
261 begin_rc
= default_rc
;
265 reversed
.set_size (encompass_
.size ());
266 Real b
= control_
[3].x ();
267 for (int i
= 0; i
< encompass_
.size (); i
++ )
272 reversed
[i
].x () = b
- encompass_
[encompass_
.size () - i
- 1].x ();
273 reversed
[i
].y () = encompass_
[encompass_
.size () - i
- 1].y ();
276 int end_disturb
= reversed
.largest_disturbing ();
277 end_disturb
= end_disturb
? encompass_
.size () - end_disturb
- 1 : 0;
278 Offset end_p
= end_disturb
? Offset (encompass_
[end_disturb
].x (),
279 encompass_
[end_disturb
].y ()) : ijk_p
;
280 Real end_rc
= end_p
.y () / (control_
[3].x () - end_p
.x ());
281 if (default_rc
> end_rc
)
286 SLUR_DOUT
<< "begin " << begin_p
.x () << ", " << begin_p
.y () << endl
;
287 SLUR_DOUT
<< "end " << end_p
.x () << ", " << end_p
.y () << endl
;
289 Real height
=control_
[1].y ();
290 for (int i
= 0; i
< encompass_
.size (); i
++ )
291 height
= height
>? encompass_
[i
].y ();
293 // emperic computer science:
294 // * tangents somewhat steeper than minimal line
295 Real rc_correct
= 2.4;
297 begin_rc
*= rc_correct
;
298 end_rc
*= rc_correct
;
302 Real begin_alpha
= atan (begin_rc
);
303 Real end_alpha
= atan (-end_rc
);
304 Real theta
= (begin_alpha
- end_alpha
) / 2;
307 Real internote
= paper_l_
->internote_f ();
309 Real internote
= STAFFHEIGHT
/ 8;
311 Real epsilon
= internote
/ 5;
313 // if we have two disturbing points, have height line through those...
314 if (!((abs (begin_p
.x () - end_p
.x ()) < epsilon
)
315 && (abs (begin_p
.y () - end_p
.y ()) < epsilon
)))
316 theta
= atan (end_p
.y () - begin_p
.y ()) / (end_p
.x () - begin_p
.x ());
318 Real rc3
= tan (theta
);
319 // ugh: be less steep
322 Real c2
= -rc2
* control_
[3].x ();
323 Real c3
= begin_p
.y () > end_p
.y () ? begin_p
.y ()
324 - rc3
* begin_p
.x () : end_p
.y () - rc3
* end_p
.x ();
326 SLUR_DOUT
<< "y1 = " << rc1
<< " x + 0" << endl
;
327 SLUR_DOUT
<< "y2 = " << rc2
<< " x + " << c2
<< endl
;
328 SLUR_DOUT
<< "y3 = " << rc3
<< " x + " << c3
<< endl
;
329 control_
[1].x () = c3
/ (rc1
- rc3
);
330 control_
[1].y () = rc1
* control_
[1].x ();
331 control_
[2].x () = (c3
- c2
) / (rc2
- rc3
);
332 SLUR_DOUT
<< "c2.x () = " << control_
[2].x () << endl
;
333 SLUR_DOUT
<< "(c3 - c2) = " << (c3
- c2
) << endl
;
334 SLUR_DOUT
<< "(rc2 - rc3) = " << (rc2
- rc3
) << endl
;
335 control_
[2].y () = rc2
* control_
[2].x () + c2
;
336 SLUR_DOUT
<< "c2.y ()" << control_
[2].y () << endl
;
338 calc_return (begin_alpha
, end_alpha
);
342 Bezier_bow::check_fit_bo ()
344 for (int i
= 1; i
< encompass_
.size () - 1; i
++)
345 if (encompass_
[i
].y () > y (encompass_
[i
].x ()))
351 Bezier_bow::check_fit_f ()
354 for (int i
= 1; i
< encompass_
.size () - 1; i
++)
355 dy
= dy
>? (encompass_
[i
].y () - y (encompass_
[i
].x ()));
360 Bezier_bow::set (Array
<Offset
> points
, int dir
)
367 Bezier_bow::transform ()
369 origin_
= encompass_
[0];
370 encompass_
.translate (-origin_
);
372 Offset delta
= encompass_
[encompass_
.size () - 1] - encompass_
[0];
374 alpha_
= delta
.arg ();
375 encompass_
.rotate (-alpha_
);
382 Bezier_bow::transform_controls_back ()
384 // silly name; let's transform encompass back too
385 // to allow recalculation without re-set()ting encompass array
393 control_
.rotate (alpha_
);
394 control_
.translate (origin_
);
396 return_
.rotate (alpha_
);
397 return_
.translate (origin_
);
399 encompass_
.rotate (alpha_
);
400 encompass_
.translate (origin_
);
404 See Documentation/fonts.tex
407 Bezier_bow::calc_default (Real h
)
411 Real staffsize_f
= paper_l_
->get_var ("barsize");
413 Real staffsize_f
= STAFFHEIGHT
;
416 Real height_limit
= staffsize_f
;
417 Real ratio
= 1.0/3.0;
419 Real alpha
= height_limit
* 2.0 / pi
;
420 Real beta
= pi
* ratio
/ (2.0 * height_limit
);
422 Offset
delta (encompass_
[encompass_
.size () - 1].x ()
423 - encompass_
[0].x (), 0);
424 Real b
= delta
.length ();
425 Real indent
= alpha
* atan (beta
* b
);
426 Real height
= indent
+ h
;
428 Array
<Offset
> control
;
429 control
.push (Offset (0, 0));
430 control
.push (Offset (indent
, height
));
431 control
.push (Offset (b
- indent
, height
));
432 control
.push (Offset (b
, 0));
433 Bezier::set (control
);