X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=lily%2Fbezier-bow.cc;h=c0a87c155299c18a269de75da7e94e8eef9f48c0;hb=d9b43b93f2c885409bafdb157138158f65cc49aa;hp=a029f36e661b8f3b85db7cab39ef1ad363450f93;hpb=dc66be1e4d7546979dca2780c7634f277a37b76a;p=lilypond.git diff --git a/lily/bezier-bow.cc b/lily/bezier-bow.cc index a029f36e66..c0a87c1552 100644 --- a/lily/bezier-bow.cc +++ b/lily/bezier-bow.cc @@ -3,411 +3,70 @@ source file of the GNU LilyPond music typesetter - (c) 1998--1999 Jan Nieuwenhuizen + (c) 1998--2002 Jan Nieuwenhuizen */ #include + #include "bezier-bow.hh" #include "misc.hh" #include "bezier.hh" -#include "dimensions.hh" -#include "direction.hh" -#include "paper-def.hh" -#include "debug.hh" -#include "main.hh" - -void -flipy (Array &c) -{ - for (int i = c.size (); i--;) - c[i][Y_AXIS] = - c[i][Y_AXIS]; -} - -void -rotate (Array &c, Real phi) -{ - Offset rot (complex_exp (Offset (0, phi))); - for (int i = 0; i < c.size (); i++) - c[i] = complex_multiply (rot, c[i]); -} - -void -translate (Array &c, Offset o) -{ - for (int i = 0; i < c.size (); i++) - c[i] += o; -} - -Bezier_bow::Bezier_bow (Paper_def* paper_l) -{ - paper_l_ = paper_l; -} -void -Bezier_bow::blow_fit () +static Real +F0_1 (Real x) { - Real x1 = encompass_[0][X_AXIS]; - Real x2 = encompass_.top ()[X_AXIS]; - - Real factor = 1.0; - for (int i=1; i < encompass_.size ()-1; i++) - { - if (encompass_[i][X_AXIS] > x1 && encompass_[i][X_AXIS] < x2) - { - Real y = curve_.get_other_coordinate (X_AXIS, encompass_[i][X_AXIS]); - if (y>0) - { - Real f = encompass_[i][Y_AXIS] / y; - factor = factor >? f; - } - } - } - - curve_.control_[1][Y_AXIS] *= factor; - curve_.control_[2][Y_AXIS] *= factor; - return_.control_[1][Y_AXIS] *= factor; - return_.control_[2][Y_AXIS] *= factor; - - curve_.check_sanity (); + return 2 / M_PI * atan (M_PI * x / 2); } Real -Bezier_bow::calc_f (Real height) -{ - transform (); - calc_default (height); - - Real dy = check_fit_f (); - calc_return (0, 0); - - transform_back (); - return dy; -} - -void -Bezier_bow::calc () -{ - transform (); - calc_controls (); - transform_back (); -} - - - -/* - [TODO] - * see if it works - * document in Documentation/fonts.tex - */ - -/* - Clipping - - This function tries to address two issues: - * the tangents of the slur should always point inwards - in the actual slur, i.e. *after rotating back*. - - * slurs shouldn't be too high - let's try : h <= 1.2 b && h <= 3 staffheight? - - We could calculate the tangent of the bezier curve from - both ends going inward, and clip the slur at the point - where the tangent (after rotation) points up (or inward - with a certain maximum angle). - - However, we assume that real clipping is not the best - answer. We expect that moving the outer control point up - if the slur becomes too high will result in a nicer slur - after recalculation. - - Knowing that the tangent is the line through the first - two control points, we'll clip (move the outer control - point upwards) too if the tangent points outwards. - */ - -bool -Bezier_bow::calc_clipping () -{ - Real clip_height = paper_l_->get_var ("slur_clip_height"); - Real clip_ratio = paper_l_->get_var ("slur_clip_ratio"); - Real clip_angle = paper_l_->get_var ("slur_clip_angle"); - - Real b = curve_.control_[3][X_AXIS] - curve_.control_[0][X_AXIS]; - Real clip_h = clip_ratio * b ? begin_h - clip_h; - Real end_dy = 0 >? end_h - clip_h; - - Real pi = M_PI; - Real begin_alpha = (curve_.control_[1] - curve_.control_[0]).arg () + dir_ * alpha_; - Real end_alpha = pi - (curve_.control_[2] - curve_.control_[3]).arg () - dir_ * alpha_; - - Real max_alpha = clip_angle / 90 * pi / 2; - if ((begin_dy < 0) && (end_dy < 0) - && (begin_alpha < max_alpha) && (end_alpha < max_alpha)) - return false; - - transform_back (); - - bool again = true; - - if ((begin_dy > 0) || (end_dy > 0)) - { - Real dy = (begin_dy + end_dy) / 4; - dy *= cos (alpha_); - encompass_[0][Y_AXIS] += dir_ * dy; - encompass_.top ()[Y_AXIS] += dir_ * dy; - } - else - { - //ugh - Real c = 0.4; - if (begin_alpha >= max_alpha) - begin_dy = 0 >? c * begin_alpha / max_alpha * begin_h; - if (end_alpha >= max_alpha) - end_dy = 0 >? c * end_alpha / max_alpha * end_h; - - encompass_[0][Y_AXIS] += dir_ * begin_dy; - encompass_.top ()[Y_AXIS] += dir_ * end_dy; - - Offset delta = encompass_.top () - encompass_[0]; - alpha_ = delta.arg (); - } - - transform (); - - return again; -} - -void -Bezier_bow::calc_controls () -{ - for (int i = 0; i < 3; i++) - { - - if (i && !calc_clipping ()) - return; - - /* - why do we always recalc from 0? - shouldn't calc_f () be used (too), rather than blow_fit () (only)? - */ - calc_default (0); - curve_.check_sanity (); - if (check_fit_f () > 0) - { - calc_tangent_controls (); - blow_fit (); - } - else - { - calc_return (0, 0); - return; - } - } -} - -void -Bezier_bow::calc_return (Real begin_alpha, Real end_alpha) +slur_height (Real width, Real h_inf, Real r_0) { - Real thick = paper_l_->get_var ("slur_thickness"); - - return_.control_[0] = curve_.control_[3]; - return_.control_[3] = curve_.control_[0]; - - return_.control_[1] = curve_.control_[2] - thick * complex_exp (Offset (0, 90 + end_alpha)); - return_.control_[2] = curve_.control_[1] - thick * complex_exp (Offset (0, 90 - begin_alpha)); + return F0_1 (width * r_0 / h_inf) * h_inf; } -static Real const FUDGE = 1e-8; - -/* - This function calculates 2 center control points, - based on lines through c_0 --> left disturbing - and c_3--> right disturbing encompass points. - - See Documentation/fonts.tex - */ -void -Bezier_bow::calc_tangent_controls () -{ - Real b = curve_.control_[3][X_AXIS]; - Real h = curve_.control_[1][Y_AXIS]; - - - Drul_array disturb; - Drul_array maxtan; - maxtan[LEFT] = maxtan[RIGHT] = h/(b/2); - disturb[LEFT] = disturb[RIGHT] = Offset (b / 2, h); - - for (int i = 1; i < encompass_.size () -1; i++) - { - Real y= encompass_[i][Y_AXIS]; - if (y> 0) - { - Real x = encompass_[i][X_AXIS]; - - Direction d = LEFT; - do - { - // 1 if d == LEFT - int k = (1 - d)/2; - Real tan = y / ((1-k)* b - d * x); - - if (tan > maxtan[d]) - { - maxtan[d] = tan; - disturb[d] = Offset (x,y); - } - } - while (flip (&d)!=LEFT); - } - } - - for (int i = 0; i < encompass_.size (); i++ ) - h = h >? encompass_[i][Y_AXIS]; - /* - The curve will always be under line between curve_.control_0 -> curve_.control_1, so - make it extra steep by slur_rc_factor - */ - Real rc_correct = paper_l_->get_var ("slur_rc_factor"); - - Drul_array angles; - Direction d = LEFT; - do - { - maxtan[d] *= -d * rc_correct; - angles[d] = atan (maxtan[d]); - } - while (flip(&d) != LEFT); - - Real rc3 = 0.0; + For small w, the height should be proportional to w, for w -> + infinity, the height should rise to a limit asymptotically. - /* - if we have two disturbing points, have line through those... - in order to get a sane line, make sure points are reasonably far apart - X distance must be reasonably(!) big (division) - */ - if (abs (disturb[LEFT][X_AXIS] - disturb[RIGHT][X_AXIS]) > FUDGE) - rc3 = (disturb[RIGHT][Y_AXIS] - disturb[LEFT][Y_AXIS]) / (disturb[RIGHT][X_AXIS] - disturb[LEFT][X_AXIS]); + Hence we take F (x) such that + F (0) = 0 , F' (0) = 1, and F (infty) = 1 - else - rc3 = tan ((angles[LEFT] - angles[RIGHT]) / 2); + and use + h = h_infinity * F (x * r_0 / h_infinity) - // ugh: be less steep - rc3 /= 2*rc_correct; + Examples: - Real c2 = -maxtan[RIGHT] * curve_.control_[3][X_AXIS]; + * F (x) = 2/pi * atan (pi x/2) - // use highest because rc3 is damped. - Real maxy = disturb[LEFT][Y_AXIS] >? disturb[RIGHT][Y_AXIS]; - Real c3 = disturb[LEFT][Y_AXIS] > disturb[RIGHT][Y_AXIS] ? - maxy - rc3 * disturb[LEFT][X_AXIS] : - maxy - rc3 * disturb[RIGHT][X_AXIS]; + * F (x) 1/alpha * x^alpha / (1 + x^alpha) - curve_.control_[1][X_AXIS] = c3 / (maxtan[LEFT] - rc3); - curve_.control_[1][Y_AXIS] = maxtan[LEFT] * curve_.control_[1][X_AXIS]; - - curve_.control_[2][X_AXIS] = (c3 - c2) / (maxtan[RIGHT] - rc3); - curve_.control_[2][Y_AXIS] = maxtan[RIGHT] * curve_.control_[2][X_AXIS] + c2; + * (etc.) + [with the 2nd recipe you can determine how quickly the conversion from + `small' slurs to `big' slurs occurs.] - curve_.check_sanity(); - - calc_return (angles[LEFT], angles[RIGHT]); -} + Although this might seem cand_idates to SCM-ify, it is not all clear + which parameters (ie. h_inf, r_0, F (.)) should be candidates for + this. At present h_inf and r_0 come from paper settings, but we did + no experiments for determining the best combinations of F, h_inf and + r_0. -/* - The maximum amount that the encompass points stick out above the bezier curve. - */ -Real -Bezier_bow::check_fit_f () const -{ - Real dy = 0; - Real x1 = encompass_[0][X_AXIS]; - Real x2 = encompass_.top ()[X_AXIS]; - for (int i = 1; i < encompass_.size () - 1; i++) - { - Real x = encompass_[i][X_AXIS]; - if (x1< x&& x < x2) - dy = dy >? (encompass_[i][Y_AXIS] - curve_.get_other_coordinate (X_AXIS, x)); - } - return dy; -} - - -void -Bezier_bow::set (Array points, Direction dir) -{ - dir_ = dir; - encompass_ = points; -} - -void -Bezier_bow::transform () -{ - origin_ = encompass_[0]; - translate (encompass_,-origin_); - - Offset delta = encompass_.top () - encompass_[0]; - alpha_ = delta.arg (); - - rotate (encompass_, -alpha_); - - if (dir_ == DOWN) - flipy (encompass_); -} + */ -void -Bezier_bow::transform_back () +Bezier +slur_shape (Real width, Real h_inf, Real r_0) { - if (dir_ == DOWN) - { - curve_.flip (Y_AXIS); - return_.flip (Y_AXIS); - flipy (encompass_); - } + Bezier curve; + Real height = slur_height (width, h_inf, r_0); + Real indent = height; - curve_.rotate (alpha_); - curve_.translate (origin_); - - return_.rotate (alpha_); - return_.translate (origin_); - - rotate (encompass_,alpha_); - translate (encompass_,origin_); + curve.control_[0] = Offset (0, 0); + curve.control_[1] = Offset (indent, height); + curve.control_[2] = Offset (width - indent, height); + curve.control_[3] = Offset (width, 0); + return curve; } -/* - See Documentation/fonts.tex - */ -void -Bezier_bow::calc_default (Real h) -{ - Real pi = M_PI; - - Real height_limit = paper_l_->get_var ("slur_height_limit"); - Real ratio = paper_l_->get_var ("slur_ratio"); - - Real alpha = height_limit * 2.0 / pi; - Real beta = pi * ratio / (2.0 * height_limit); - - Offset delta (encompass_.top ()[X_AXIS] - - encompass_[0][X_AXIS], 0); - - Real b = delta.length (); - Real indent = alpha * atan (beta * b); - Real height = indent + h; - - curve_.control_ [0] = Offset (0, 0); - curve_.control_ [1] = Offset (indent, height); - curve_.control_ [2] = Offset (b - indent, height); - curve_.control_ [3] = Offset (b, 0); -} - -