X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=lily%2Fbezier-bow.cc;h=e049bd734c244f78c8411324296514e8de219cc1;hb=90e4d7057f3857da049dfda3d130017d4719bd6b;hp=afdd951b8e587a9f1694afdc253e1af0f36691f7;hpb=19fbc4154436823f3365e0bc42c4420f2233a860;p=lilypond.git diff --git a/lily/bezier-bow.cc b/lily/bezier-bow.cc index afdd951b8e..e049bd734c 100644 --- a/lily/bezier-bow.cc +++ b/lily/bezier-bow.cc @@ -1,263 +1,128 @@ /* - bezier.cc -- implement Bezier and Bezier_bow + This file is part of LilyPond, the GNU music typesetter. - source file of the GNU LilyPond music typesetter + Copyright (C) 1998--2015 Jan Nieuwenhuizen - (c) 1998--1999 Jan Nieuwenhuizen + LilyPond is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + LilyPond is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with LilyPond. If not, see . */ -#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) +static Real +F0_1 (Real x) { - for (int i = c.size (); i--;) - c[i][Y_AXIS] = - c[i][Y_AXIS]; + return 2 / M_PI * atan (M_PI * x / 2); } -void -rotate (Array &c, Real phi) +Real +slur_height (Real width, Real h_inf, Real r_0) { - Offset rot (complex_exp (Offset (0, phi))); - for (int i = 0; i < c.size (); i++) - c[i] = complex_multiply (rot, c[i]); + return F0_1 (width * r_0 / h_inf) * h_inf; } -void -translate (Array &c, Offset o) -{ - for (int i = 0; i < c.size (); i++) - c[i] += o; -} +/* + ^ x x + | + height + | + v x x -Bezier_bow::Bezier_bow (Paper_def* paper_l, - Array points, Direction dir) -{ - paper_l_ = paper_l; - dir_ = dir; - encompass_ = points; - to_canonic_form (); - - calc_default (0.0); - if (fit_factor () > 1.0) - { - calc_tangent_controls (); - blow_fit (); - } -} -void -Bezier_bow::blow_fit () -{ - Real f = fit_factor (); - - curve_.control_[1][Y_AXIS] *= f; - curve_.control_[2][Y_AXIS] *= f; + For small w, the height should be proportional to w, for w -> + infinity, the height should rise to a limit asymptotically. - curve_.check_sanity (); -} + Hence we take F (x) such that + F (0) = 0 , F' (0) = 1, and F (infty) = 1 + and use + h = h_infinity * F (x * r_0 / h_infinity) + Examples: + * F (x) = 2/pi * atan (pi x/2) -Bezier -Bezier_bow::get_curve ()const -{ + * F (x) = 1/alpha * x^alpha / (1 + x^alpha) - Bezier rv = curve_; - if (dir_ == DOWN) - { - rv.flip (Y_AXIS); - } + * (etc.) - rv.rotate (alpha_); - rv.translate (origin_); - return rv; -} + [with the 2nd recipe you can determine how quickly the conversion from + `small' slurs to `big' slurs occurs.] -static Real const FUDGE = 1e-8; + 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 layout settings, but we did + no experiments for determining the best combinations of F, h_inf and + r_0. -/* - 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; - - /* - 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]); - - else - rc3 = tan ((angles[LEFT] - angles[RIGHT]) / 2); - - - // ugh: be less steep - rc3 /= 2*rc_correct; - - - Real c2 = -maxtan[RIGHT] * curve_.control_[3][X_AXIS]; - - // 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]; - - 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; - - - curve_.check_sanity(); -} -/* - The maximum amount that the encompass points stick out above the bezier curve. - */ -Real -Bezier_bow::fit_factor () const -{ - 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; - } - } - } - - - return factor; -} + The indent is proportional to the height of the slur for small + slurs. For large slurs, this gives a certain hookiness at the end, + so we increase the indent. + indent = G (w) + w -> 0, G (w) -> .33 w -void -Bezier_bow::to_canonic_form () -{ - origin_ = encompass_[0]; - translate (encompass_,-origin_); + (due to derivative constraints, we cannot have indent > len/3) - Offset delta = encompass_.top () - encompass_[0]; - alpha_ = delta.arg (); + w -> inf, G (w) -> 2*h_inf - rotate (encompass_, -alpha_); - if (dir_ == DOWN) - { - flipy (encompass_); - } -} + i.e. + G (0) = 0 , G'(0) 1/3, G (infty) = 2h_inf -/* - See Documentation/fonts.tex - */ -void -Bezier_bow::calc_default (Real h) -{ - Real pi = M_PI; + solve from - Real height_limit = paper_l_->get_var ("slur_height_limit"); - Real ratio = paper_l_->get_var ("slur_ratio"); + G (w) = r + p/(w+q) - Real alpha = height_limit * 2.0 / pi; - Real beta = pi * ratio / (2.0 * height_limit); + yields - Offset delta (encompass_.top ()[X_AXIS] - - encompass_[0][X_AXIS], 0); + G (w) = 2 h_inf - max_fraction * q^2/ (w + q) - 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); -} + with q = 2 h_inf +*/ + +void +get_slur_indent_height (Real *indent, Real *height, + Real width, Real h_inf, Real r_0) +{ + Real max_fraction = 1.0 / 3.1; + *height = slur_height (width, h_inf, r_0); + Real q = 2 * h_inf / max_fraction; + *indent = 2 * h_inf - sqr (q) * max_fraction / (width + q); +} +Bezier +slur_shape (Real width, Real h_inf, Real r_0) +{ + Real indent; + Real height; + + get_slur_indent_height (&indent, &height, + width, h_inf, r_0); + + Bezier curve; + 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; +}