]> git.donarmstrong.com Git - lilypond.git/blob - lily/tie.cc
release: 1.3.18
[lilypond.git] / lily / tie.cc
1 /*
2   tie.cc -- implement Tie
3
4   source file of the GNU LilyPond music typesetter
5
6   (c)  1997--1999 Han-Wen Nienhuys <hanwen@cs.uu.nl>
7 */
8
9 #include "paper-def.hh"
10 #include "tie.hh"
11 #include "note-head.hh"
12 #include "paper-column.hh"
13 #include "debug.hh"
14 #include "staff-symbol-referencer.hh"
15 #include "directional-element-interface.hh"
16
17 void
18 Tie::set_head (Direction d, Item * head_l)
19 {
20   assert (!head (d));
21   index_set_cell (get_elt_property ("heads"), d, head_l->self_scm_);
22   
23   set_bounds (d, head_l);
24   add_dependency (head_l);
25 }
26
27 Tie::Tie()
28 {
29   set_elt_property ("heads", gh_cons (SCM_EOL, SCM_EOL));
30 }
31
32 Note_head* 
33 Tie::head (Direction d) const
34 {
35   SCM c = get_elt_property ("heads");
36   c = index_cell (c, d);
37
38   return dynamic_cast<Note_head*> (unsmob_element (c));  
39 }
40
41
42 /*
43   ugh: direction of the Tie is more complicated.  See [Ross] p136 and further
44  */
45 Direction
46 Tie::get_default_dir () const
47 {
48   Real p1 = Staff_symbol_referencer_interface (head (LEFT)).position_f () ;
49   Real p2 = Staff_symbol_referencer_interface (head (RIGHT)).position_f () ;  
50   
51   int m = int (p1  + p2);
52
53   /*
54     If dir is not determined: inverse of stem: down
55     (see stem::get_default_dir ())
56    */
57   Direction neutral_dir = (Direction)(int)paper_l ()->get_var ("stem_default_neutral_direction");
58   return (m == 0) ? other_dir (neutral_dir) : (m < 0) ? DOWN : UP;
59 }
60
61 void
62 Tie::do_add_processing()
63 {
64   if (!(head (LEFT) && head (RIGHT)))
65     warning (_ ("lonely tie"));
66
67   Direction d = LEFT;
68   Drul_array<Note_head *> new_head_drul;
69   new_head_drul[LEFT] = head(LEFT);
70   new_head_drul[RIGHT] = head(RIGHT);  
71   do {
72     if (!head (d))
73       new_head_drul[d] = head((Direction)-d);
74   } while (flip(&d) != LEFT);
75
76   index_set_cell (get_elt_property ("heads"), LEFT, new_head_drul[LEFT]->self_scm_ );
77   index_set_cell (get_elt_property ("heads"), RIGHT, new_head_drul[LEFT]->self_scm_ );
78
79 }
80
81 void
82 Tie::do_post_processing()
83 {
84   if (!head (LEFT) && !head (RIGHT))
85     {
86       programming_error ("Tie without heads.");
87       set_elt_property ("transparent", SCM_BOOL_T);
88       set_empty (X_AXIS);
89       set_empty (Y_AXIS);
90       return;
91     }
92
93   Real staff_space = paper_l ()->get_var ("interline");
94   Real half_staff_space = staff_space / 2;
95   Real x_gap_f = paper_l ()->get_var ("tie_x_gap");
96   Real y_gap_f = paper_l ()->get_var ("tie_y_gap");
97
98   /* 
99    Slur and tie placement [OSU]
100
101    Ties:
102
103        * x = inner vertical tangent - d * gap
104
105    */
106
107
108   /*
109     OSU: not different for outer notes, so why all this code?
110     ie,  can we drop this, or should it be made switchable.
111    */
112 #if 0
113   Direction d = LEFT;
114   do
115     {
116       Real head_width_f = head (d)
117         ? head (d)->extent (X_AXIS).length ()
118         : 0;
119       /*
120         side attached to outer (upper or lower) notehead of chord
121       */
122       if (head (d)
123           /*
124
125                 a~a~a;
126
127             to second tie, middle notehead seems not extremal
128
129             Getting scared a bit by score-element's comment:
130             // is this a good idea?
131           */
132           // FIXME extremal deprecated
133           && (head (d)->get_elt_property ("extremal")
134               != SCM_UNDEFINED))
135         {
136         if (d == LEFT)
137             dx_f_drul_[d] += head_width_f;
138           dx_f_drul_[d] += -d * x_gap_f;
139         }
140       /*
141         side attached to inner notehead
142       */
143       else
144         {
145           dx_f_drul_[d] += -d * head_width_f;
146         }
147     } while (flip (&d) != LEFT);
148
149 #else
150
151   if (head (LEFT))
152     dx_f_drul_[LEFT] = head (LEFT)->extent (X_AXIS).length ();
153   else
154     dx_f_drul_[LEFT] = get_broken_left_end_align ();
155   dx_f_drul_[LEFT] += x_gap_f;
156   dx_f_drul_[RIGHT] -= x_gap_f;
157
158 #endif
159
160   /* 
161    Slur and tie placement [OSU]  -- check this
162
163    Ties:
164
165        * y = dx <  5ss: horizontal tangent
166          y = dx >= 5ss: y next interline - d * 0.25 ss
167
168          which probably means that OSU assumes that
169
170             dy <= 5 dx
171
172          for smal slurs
173    */
174
175
176   Real ypos = head (LEFT)
177     ? Staff_symbol_referencer_interface (head (LEFT)).position_f ()
178     : Staff_symbol_referencer_interface (head (RIGHT)).position_f () ;  
179
180   Real y_f = half_staff_space * ypos; 
181   int ypos_i = int (ypos);
182  
183   Real dx_f = extent (X_AXIS).length () + dx_f_drul_[RIGHT] - dx_f_drul_[LEFT];
184   Direction dir = directional_element (this).get();
185   if (dx_f < paper_l ()->get_var ("tie_staffspace_length"))
186     {
187       if (abs (ypos_i) % 2)
188         y_f += dir * half_staff_space;
189       y_f += dir * y_gap_f;
190     }
191   else
192     {
193       if (! (abs (ypos_i) % 2))
194         y_f += dir * half_staff_space;
195       y_f += dir * half_staff_space;
196       y_f -= dir * y_gap_f;
197     }
198   
199   dy_f_drul_[LEFT] = dy_f_drul_[RIGHT] = y_f;
200 }
201
202
203
204 Array<Rod>
205 Tie::get_rods () const
206 {
207   Array<Rod> a;
208   Rod r;
209   r.item_l_drul_ = spanned_drul_;
210   r.distance_f_ = paper_l ()->get_var ("tie_x_minimum");
211   a.push (r);
212   return a;
213 }
214