#include "debug.hh"
#include "main.hh"
#include "lily-guile.hh"
+#include "paper-def.hh"
-void
-flipy (Array<Offset> &c)
-{
- for (int i = c.size (); i--;)
- c[i][Y_AXIS] = - c[i][Y_AXIS];
-}
-
-void
-rotate (Array<Offset> &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<Offset> &c, Offset o)
-{
- for (int i = 0; i < c.size (); i++)
- c[i] += o;
-}
-
-
-Bezier_bow::Bezier_bow (Array<Offset> points, Direction dir)
+Bezier_bow::Bezier_bow (Array<Offset> encompass, Direction dir)
{
+ alpha_ = 0;
dir_ = dir;
- encompass_ = points;
- to_canonic_form ();
-
- rc_factor_ = 1.0;
- height_limit_ = 1.0;
- ratio_ = 1.0;
+ encompass_ = encompass;
+ to_canonical_form ();
}
-void
-Bezier_bow::blow_fit ()
-{
- Real len = curve_.control_[3][X_AXIS] ;
- Real ind = curve_.control_[1][X_AXIS] / len;
- Real h = curve_.control_[1][Y_AXIS] * fit_factor () / len;
-
- // ugh. Unhardcode this
- if (h > 4 * ind)
- {
- h = 4* ind;
- }
-
- if (h > 0.8 + -2 * ind)
- {
- h = 0.8 - 2 *ind;
- }
-
- curve_.control_[1][Y_AXIS] = h * len;
- curve_.control_[2][Y_AXIS] = h * len;
-
- curve_.check_sanity ();
-}
-
-Real
-Bezier_bow::calc_enclosed_area_f () const
-{
- Real a = 0;
- for (int i=0; i < encompass_.size (); i++)
- {
- Interval x;
- Interval y;
- if (i == 0)
- x = Interval (0, encompass_[1][X_AXIS]/2);
- else if (i == encompass_.size () - 1)
- x = Interval ((encompass_[i-1][X_AXIS] + encompass_[i][X_AXIS])/2,
- encompass_[i][X_AXIS]);
- else
- x = Interval ((encompass_[i-1][X_AXIS] + encompass_[i][X_AXIS])/2,
- (encompass_[i][X_AXIS] + encompass_[i+1][X_AXIS])/2);
-
- y[MIN] = encompass_[i][Y_AXIS];
- // solve_point (X, 0|Xmax) has no solutions...
- y[MAX] = (x[MIN] ? curve_.get_other_coordinate (X_AXIS, x[MIN]) : 0
- + curve_.get_other_coordinate (X_AXIS, (x[MIN] + x[MAX])/2)
- + x[MAX] != encompass_.top ()[X_AXIS] ? curve_.get_other_coordinate (X_AXIS, x[MAX]) : 0)/3;
- Real da = x.length () * y.length ();
- if (da > 0)
- a += da;
- }
- return a;
-}
-
-void
-Bezier_bow::minimise_enclosed_area ()
-{
- Real area = calc_enclosed_area_f ();
-
- Array<Offset> da (2);
- for (int i=1; i < 3; i++)
- {
- for (Axis a=X_AXIS; a < NO_AXES; incr (a))
- {
- Real r = curve_.control_[i][a];
- curve_.control_[i][a] += 1;
- da[i-1][a] = (calc_enclosed_area_f () - area) / area;
- curve_.control_[i][a] = r;
- }
- }
-
- for (int i=1; i < 3; i++)
- {
- da[i-1] *= da[i-1].length () ? 1.0 / da[i-1].length () : 1.0;
- curve_.control_[i] -= da[i-1] * curve_.control_[i].length ();
- }
-}
-
-void
-Bezier_bow::calculate ()
-{
- calc_default ();
- if (fit_factor () > 1.0)
- {
- // calc_tangent_controls ();
- blow_fit ();
- minimise_enclosed_area ();
- }
-}
-
-
-
Bezier
-Bezier_bow::get_curve ()const
+Bezier_bow::get_bezier () const
{
Bezier rv = curve_;
if (dir_ == DOWN)
return rv;
}
-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<Offset> disturb;
- Drul_array<Real> 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
- */
-
-
- Drul_array<Real> angles;
- Direction d = LEFT;
- do
- {
- maxtan[d] *= -d * rc_factor_;
- 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_factor_;
-
-
- 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;
-}
-
-
-
-
-void
-Bezier_bow::to_canonic_form ()
+Bezier_bow::to_canonical_form ()
{
origin_ = encompass_[0];
- translate (encompass_,-origin_);
+ translate (&encompass_, -origin_);
Offset delta = encompass_.top () - encompass_[0];
alpha_ = delta.arg ();
- rotate (encompass_, -alpha_);
+ rotate (&encompass_, -alpha_);
if (dir_ == DOWN)
{
- flipy (encompass_);
+ flip (&encompass_, Y_AXIS);
}
while (encompass_.size () > 1 && encompass_[1][X_AXIS] <= 0.0)
{
- programming_error ("Degenerate slur: infinite steepness reqd");
+ programming_error ("Degenerate bow: infinite steepness reqd");
encompass_.del (1);
}
Real l = encompass_.top ()[X_AXIS];
while (encompass_.size () > 1 && encompass_.top (1)[X_AXIS] >= l)
{
- programming_error ("Degenerate slur: infinite steepness reqd");
+ programming_error ("Degenerate bow: infinite steepness reqd");
encompass_.del (encompass_.size ()-2);
}
}
-
+void
+Bezier_bow::set_default_bezier (Real h_inf, Real r_0)
+{
+ curve_ = get_default_bezier (h_inf, r_0);
+}
/*
- See Documentation/fonts.tex
+ See Documentation/programmer/fonts.doc
*/
-void
-Bezier_bow::calc_default ()
+Bezier
+Bezier_bow::get_default_bezier (Real h_inf, Real r_0) const
{
- Real pi = M_PI;
-
- 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);
-
+ Offset delta (encompass_.top ()[X_AXIS] - encompass_[0][X_AXIS], 0);
Real b = delta.length ();
- Real indent = alpha * atan (beta * b);
- Real height = indent;
-
- 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);
+ Real height = get_default_height (h_inf, r_0, b);
+ // urg: scmify this?
+ Real indent = height;
+
+ Bezier curve;
+ 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);
+ return curve;
}
+/*
+ See Documentation/programmer/fonts.doc
+ */
+Real
+Bezier_bow::get_default_height (Real h_inf, Real r_0, Real b) const
+{
+#if 0
+ Real pi = M_PI;
-
+ Real alpha = 2.0 * h_inf / pi;
+ Real beta = pi * r_0 / (2.0 * h_inf);
+
+ return alpha * atan (beta * b);
+#else
+ SCM h = scm_eval (scm_listify (ly_symbol2scm ("slur-default-height"),
+ gh_double2scm (h_inf),
+ gh_double2scm (r_0),
+ gh_double2scm (b),
+ SCM_UNDEFINED));
+ return gh_scm2double (h);
+#endif
+}
+