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>
11 #include "direction.hh"
14 #include "direction.hh"
16 #include "paper-def.hh"
19 #define SLUR_DOUT if (check_debug && !monitor->silent_b ("Slur")) cout
21 #define SLUR_DOUT cerr
27 // ugh, Offset should have mirror funcs
28 for (int i
= 0; i
< size (); i
++)
29 (*this)[i
].mirror (Y_AXIS
);
33 Curve::largest_disturbing ()
37 for (int i
= 1; i
< size (); i
++)
39 if ((*this)[i
].y () > 0)
41 Real phi
= (*this)[i
].y () / (*this)[i
].x ();
53 Curve::rotate (Real phi
)
55 Offset
rot (complex_exp (Offset (0,phi
)));
57 for (int i
= 1; i
< size (); i
++)
58 (*this)[i
] = complex_multiply (rot
, (*this)[i
]);
62 Curve::translate (Offset o
)
64 for (int i
= 1; i
< size (); i
++)
68 Bezier::Bezier (int steps
)
70 control_
.set_size (4);
71 curve_
.set_size (steps
);
74 //from GNU gs3.33: ega.c
78 Real dt
= 1.0 / curve_
.size ();
79 Offset c
= 3.0 * (control_
[1] - control_
[0]);
80 Offset b
= 3.0 * (control_
[2] - control_
[1]) - c
;
81 Offset a
= control_
[3] - (control_
[0] + c
+ b
);
83 for (int i
= 0; i
< curve_
.size (); i
++ )
85 curve_
[i
] = ((a
* t
+ b
) * t
+ c
) * t
+ control_
[0];
91 Bezier::set (Array
<Offset
> points
)
93 assert (points
.size () == 4);
100 if (x
<= curve_
[0].x ())
101 return curve_
[0].y ();
102 for (int i
= 1; i
< curve_
.size (); i
++ )
104 if (x
< curve_
[i
].x ())
107 Real lin
= (x
- curve_
[i
-1].x ()) / (curve_
[i
] - curve_
[i
-1]).x ();
109 return (curve_
[i
-1] + lin
* (curve_
[i
] - curve_
[i
-1])).y ();
112 return curve_
[curve_
.size ()-1].y ();
116 Bezier_bow::Bezier_bow (Paper_def
* paper_l
)
120 return_
.set_size (4);
126 slurheightlimit#:=staffsize#/2;
127 sluralpha:=slurheightlimit#*pi/2;
130 slurbeta:=3/4*pi*slurratio/sluralpha;
134 indent#:=2/5*sluralpha*atan(slurbeta*b#);
135 height:=(indent+h)*d;
139 z4=(b-indent,height);
141 boogje:=boogje rotated angle(dxs,dys);
145 Bezier_bow::blow_fit ()
147 Real dy1
= check_fit_f ();
151 // be careful not to take too big step
154 control_
[1].y () += h1
;
155 control_
[2].y () += h1
;
156 return_
[1].y () += h1
;
157 return_
[2].y () += h1
;
159 Real dy2
= check_fit_f ();
164 Real epsilon
= paper_l_
->rule_thickness ();
166 Real epsilon
= 1.5 * 0.4 PT
;
168 if (abs (dy2
- dy1
) < epsilon
)
177 Then we get for h : B (h) = 0
179 B(0) = dy1 = a * 0 + b => b = dy1
180 B(h1) = dy2 = a * h1 + b => a * f * dy1 + b = dy2
184 a * dy1 / 2 + dy1 = dy2 => a = (dy2 - dy1) / (f * dy1)
187 Real a
= (dy2
- dy1
) / (f
* dy1
);
191 control_
[1].y () += -h1
+h
;
192 control_
[2].y () = -h1
+h
;
193 return_
[1].y () = -h1
+h
;
194 return_
[2].y () = -h1
+h
;
198 Bezier_bow::calc_f (Real height
)
201 calc_default (height
);
204 Real dy
= check_fit_f ();
207 transform_controls_back ();
226 transform_controls_back ();
230 Bezier_bow::calc_return (Real begin_alpha
, Real end_alpha
)
233 Real thick
= 1.8 * paper_l_
->rule_thickness ();
235 Real thick
= 10.0 * 1.8 * 0.4 PT
;
237 return_
[0] = control_
[3];
239 return_
[1] = control_
[2] - thick
* complex_exp (Offset (0, 90 + end_alpha
));
240 return_
[2] = control_
[1] - thick
* complex_exp (Offset (0, 90 - begin_alpha
));
243 return_[1].x () = control_[2].x () - thick * cos (90 + end_alpha);
244 return_[1].y () = control_[2].y () - thick * sin (90 + end_alpha);
245 return_[2].x () = control_[1].x () - thick * cos (90 - begin_alpha);
246 return_[2].y () = control_[1].y () - thick * sin (90 - begin_alpha);
248 return_
[3] = control_
[0];
252 Bezier_bow::calc_controls ()
255 // Real default_rc = atan (control_[1].y () / control_[1].x ());
257 Offset
ijk_p (control_
[3].x () / 2, control_
[1].y ());
258 SLUR_DOUT
<< "ijk: " << ijk_p
.x () << ", " << ijk_p
.y () << endl
;
260 Real default_rc
= ijk_p
.y () / ijk_p
.x ();
262 int begin_disturb
= encompass_
.largest_disturbing ();
263 Offset begin_p
= begin_disturb
? Offset (encompass_
[begin_disturb
].x (),
264 encompass_
[begin_disturb
].y ()) : ijk_p
;
265 Real begin_rc
= begin_p
.y () / begin_p
.x ();
266 if (default_rc
> begin_rc
)
269 begin_rc
= default_rc
;
274 reversed
.set_size (encompass_
.size ());
275 Real b
= control_
[3].x ();
276 for (int i
= 0; i
< encompass_
.size (); i
++ )
278 reversed
[i
] = Offset (b
,0) - encompass_
[encompass_
.size () - i
-1];
280 reversed[i].x () = b - encompass_[encompass_.size () - i - 1].x ();
281 reversed[i].y () = encompass_[encompass_.size () - i - 1].y ();
285 int end_disturb
= reversed
.largest_disturbing ();
286 end_disturb
= end_disturb
? encompass_
.size () - end_disturb
- 1 : 0;
287 Offset end_p
= end_disturb
? Offset (encompass_
[end_disturb
].x (),
288 encompass_
[end_disturb
].y ()) : ijk_p
;
289 Real end_rc
= end_p
.y () / (control_
[3].x () - end_p
.x ());
290 if (default_rc
> end_rc
)
295 SLUR_DOUT
<< "begin " << begin_p
.x () << ", " << begin_p
.y () << endl
;
296 SLUR_DOUT
<< "end " << end_p
.x () << ", " << end_p
.y () << endl
;
298 Real height
=control_
[1].y ();
299 for (int i
= 0; i
< encompass_
.size (); i
++ )
300 height
= height
>? encompass_
[i
].y ();
302 // emperic computer science:
303 // * tangents somewhat steeper than minimal line
304 Real rc_correct
= 2.4;
306 begin_rc
*= rc_correct
;
307 end_rc
*= rc_correct
;
311 Real begin_alpha
= atan (begin_rc
);
312 Real end_alpha
= atan (-end_rc
);
313 Real theta
= (begin_alpha
- end_alpha
) / 2;
315 // if we have two disturbing points, have height line through those...
317 UGH UGH UGH! NEVER compare floats with ==
319 if (!((begin_p
.x () == end_p
.x ()) && (begin_p
.y () == end_p
.y ())))
320 theta
= atan (end_p
.y () - begin_p
.y ()) / (end_p
.x () - begin_p
.x ());
322 Real rc3
= tan (theta
);
323 // ugh: be less steep
326 Real c2
= -rc2
* control_
[3].x ();
327 Real c3
= begin_p
.y () > end_p
.y () ? begin_p
.y ()
328 - rc3
* begin_p
.x () : end_p
.y () - rc3
* end_p
.x ();
330 SLUR_DOUT
<< "y1 = " << rc1
<< " x + 0" << endl
;
331 SLUR_DOUT
<< "y2 = " << rc2
<< " x + " << c2
<< endl
;
332 SLUR_DOUT
<< "y3 = " << rc3
<< " x + " << c3
<< endl
;
333 control_
[1].x () = c3
/ (rc1
- rc3
);
334 control_
[1].y () = rc1
* control_
[1].x ();
335 control_
[2].x () = (c3
- c2
) / (rc2
- rc3
);
336 SLUR_DOUT
<< "c2.x () = " << control_
[2].x () << endl
;
337 SLUR_DOUT
<< "(c3 - c2) = " << (c3
- c2
) << endl
;
338 SLUR_DOUT
<< "(rc2 - rc3) = " << (rc2
- rc3
) << endl
;
339 control_
[2].y () = rc2
* control_
[2].x () + c2
;
340 SLUR_DOUT
<< "c2.y ()" << control_
[2].y () << endl
;
342 calc_return (begin_alpha
, end_alpha
);
346 Bezier_bow::check_fit_bo ()
348 for (int i
= 1; i
< encompass_
.size () - 1; i
++)
349 if (encompass_
[i
].y () > y (encompass_
[i
].x ()))
355 Bezier_bow::check_fit_f ()
358 for (int i
= 1; i
< encompass_
.size () - 1; i
++)
359 dy
= dy
>? (encompass_
[i
].y () - y (encompass_
[i
].x ()));
364 Bezier_bow::set (Array
<Offset
> points
, int dir
)
371 Bezier_bow::transform ()
373 origin_
= encompass_
[0];
374 encompass_
.translate (-origin_
);
376 Offset delta
= encompass_
[encompass_
.size () - 1] - encompass_
[0];
378 Real dx = encompass_[encompass_.size () - 1].x () - encompass_[0].x ();
379 Real dy = encompass_[encompass_.size () - 1].y () - encompass_[0].y ();
382 alpha_
= delta
.arg ();
383 encompass_
.rotate (-alpha_
);
390 Bezier_bow::transform_controls_back ()
392 // silly name; let's transform encompass back too
393 // to allow recalculation without re-set()ting encompass array
401 control_
.rotate (alpha_
);
402 control_
.translate (origin_
);
404 return_
.rotate (alpha_
);
405 return_
.translate (origin_
);
407 encompass_
.rotate (alpha_
);
408 encompass_
.translate (origin_
);
412 Bezier_bow::calc_default (Real h
)
416 Real staffsize_f
= paper_l_
->get_var ("barsize");
418 Real staffsize_f
= 16 PT
;
421 Real height_limit
= staffsize_f
;
422 Real alpha
= height_limit
* pi
/ 2.0;
423 Real ratio
= 1.0/3.0;
424 Real beta
= 3.0/4.0 * pi
* ratio
/alpha
;
427 Offset
delta (encompass_
[encompass_
.size () - 1].x () - encompass_
[0].x (), 0);
431 Real b
= delta
.length ();
432 Real indent
= 2.0/5.0 * alpha
* atan (beta
* b
);
433 // ugh, ugly height hack, see lily-ps-defs.tex
434 Real height
= (indent
+ h
) * d
;
436 // Offset control[4] = {0, 0, indent, height, b - indent, height, b, 0 };
437 Array
<Offset
> control
;
438 control
.push (Offset (0, 0));
439 control
.push (Offset (indent
, height
));
440 control
.push (Offset (b
- indent
, height
));
441 control
.push (Offset (b
, 0));
442 Bezier::set (control
);
444 // Real phi = dx ? atan (dy/dx) : sign (dy) * pi / 2.0;
445 // control.rotate (phi);