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);