]> git.donarmstrong.com Git - lilypond.git/blob - lily/bow.cc
release: 1.3.18
[lilypond.git] / lily / bow.cc
1 /*
2   bow.cc -- implement Bow
3
4   source file of the GNU LilyPond music typesetter
5
6   (c)  1997--1999 Han-Wen Nienhuys <hanwen@cs.uu.nl>
7       Jan Nieuwenhuizen <janneke@gnu.org>
8 */
9
10 #include "dimension-cache.hh"
11 #include "bow.hh"
12 #include "debug.hh"
13 #include "paper-def.hh"
14 #include "molecule.hh"
15 #include "lookup.hh"
16 #include "bezier-bow.hh"
17 #include "main.hh"
18 #include "directional-element-interface.hh"
19
20 Bow::Bow ()
21 {
22   dy_f_drul_[LEFT] = dy_f_drul_[RIGHT] = 0.0;
23   dx_f_drul_[LEFT] = dx_f_drul_[RIGHT] = 0.0;
24 }
25
26 Molecule*
27 Bow::do_brew_molecule_p () const
28 {
29   Real thick = paper_l ()->get_var ("slur_thickness");
30   Bezier one = get_curve ();
31
32   Molecule a;
33   SCM d =  get_elt_property ("dashed");
34   if (gh_number_p (d))
35     a = lookup_l ()->dashed_slur (one, thick, gh_scm2int (d));
36   else
37     a = lookup_l ()->slur (one, directional_element (this).get () * thick, thick);
38   
39   return new Molecule (a); 
40 }
41
42 Offset
43 Bow::center () const
44 {
45   Real dy = dy_f_drul_[RIGHT] - dy_f_drul_[LEFT];
46   Real dx =  extent(X_AXIS).length ();
47
48   return Offset (dx / 2, dy);
49 }
50
51
52 Interval
53 Bow::curve_extent (Axis a) const
54 {
55   return get_curve ().extent (a);
56 }
57
58 Bezier
59 Bow::get_curve () const
60 {
61   Bezier_bow b (get_encompass_offset_arr (), directional_element (this).get ());
62
63   b.ratio_ = paper_l ()->get_var ("slur_ratio");
64   b.height_limit_ = paper_l ()->get_var ("slur_height_limit");
65   b.rc_factor_ = paper_l ()->get_var ("slur_rc_factor");
66
67   b.calculate ();
68   return b.get_curve ();
69 }
70
71 #if 0
72
73 /*
74   TODO: FIXME.
75  */
76
77 /*
78   Clipping
79
80   This function tries to address two issues:
81     * the tangents of the slur should always point inwards 
82       in the actual slur, i.e.  *after rotating back*.
83
84     * slurs shouldn't be too high 
85       let's try : h <= 1.2 b && h <= 3 staffheight?
86
87   We could calculate the tangent of the bezier curve from
88   both ends going inward, and clip the slur at the point
89   where the tangent (after rotation) points up (or inward
90   with a certain maximum angle).
91   
92   However, we assume that real clipping is not the best
93   answer.  We expect that moving the outer control point up 
94   if the slur becomes too high will result in a nicer slur 
95   after recalculation.
96
97   Knowing that the tangent is the line through the first
98   two control points, we'll clip (move the outer control
99   point upwards) too if the tangent points outwards.
100  */
101
102 bool
103 Bezier_bow::calc_clipping ()
104 {
105   Real clip_height = paper_l_->get_var ("slur_clip_height");
106   Real clip_ratio = paper_l_->get_var ("slur_clip_ratio");
107   Real clip_angle = paper_l_->get_var ("slur_clip_angle");
108
109   Real b = curve_.control_[3][X_AXIS] - curve_.control_[0][X_AXIS];
110   Real clip_h = clip_ratio * b <? clip_height;
111   Real begin_h = curve_.control_[1][Y_AXIS] - curve_.control_[0][Y_AXIS];
112   Real end_h = curve_.control_[2][Y_AXIS] - curve_.control_[3][Y_AXIS];
113   Real begin_dy = 0 >? begin_h - clip_h;
114   Real end_dy = 0 >? end_h - clip_h;
115   
116   Real pi = M_PI;
117   Real begin_alpha = (curve_.control_[1] - curve_.control_[0]).arg () + dir_ * alpha_;
118   Real end_alpha = pi -  (curve_.control_[2] - curve_.control_[3]).arg () - dir_  * alpha_;
119
120   Real max_alpha = clip_angle / 90 * pi / 2;
121   if ((begin_dy < 0) && (end_dy < 0)
122     && (begin_alpha < max_alpha) && (end_alpha < max_alpha))
123     return false;
124
125   transform_back ();
126
127   if ((begin_dy > 0) || (end_dy > 0))
128     {
129       Real dy = (begin_dy + end_dy) / 4;
130       dy *= cos (alpha_);
131       encompass_[0][Y_AXIS] += dir_ * dy;
132       encompass_.top ()[Y_AXIS] += dir_ * dy;
133     }
134   else
135     {
136       //ugh
137       Real c = 0.4;
138       if (begin_alpha >= max_alpha)
139         begin_dy = 0 >? c * begin_alpha / max_alpha * begin_h;
140       if (end_alpha >= max_alpha)
141         end_dy = 0 >? c * end_alpha / max_alpha * end_h;
142
143       encompass_[0][Y_AXIS] += dir_ * begin_dy;
144       encompass_.top ()[Y_AXIS] += dir_ * end_dy;
145
146       Offset delta = encompass_.top () - encompass_[0];
147       alpha_ = delta.arg ();
148     }
149
150   to_canonic_form ();
151
152   return true;
153 }
154 #endif
155
156
157
158 Array<Offset>
159 Bow::get_encompass_offset_arr () const
160 {
161   Array<Offset> offset_arr;
162   offset_arr.push (Offset (dx_f_drul_[LEFT], dy_f_drul_[LEFT]));
163   offset_arr.push (Offset (spanner_length () + dx_f_drul_[RIGHT],
164                            dy_f_drul_[RIGHT]));
165                       
166   return offset_arr;
167 }
168
169