]> git.donarmstrong.com Git - lilypond.git/blob - lily/tie-formatting-problem.cc
* lily/include/tie-formatting-problem.hh (class
[lilypond.git] / lily / tie-formatting-problem.cc
1 /*
2   tie-formatting-problem.cc -- implement Tie_formatting_problem6
3
4   source file of the GNU LilyPond music typesetter
5
6   (c) 2005 Han-Wen Nienhuys <hanwen@xs4all.nl>
7
8 */
9
10 #include "tie-formatting-problem.hh"
11
12 #include "directional-element-interface.hh"
13 #include "staff-symbol-referencer.hh"
14 #include "tie.hh"
15
16 #include "item.hh"
17 #include "spanner.hh" 
18
19 #include "stem.hh"
20 #include "note-head.hh"
21 #include "rhythmic-head.hh"
22
23 Interval
24 Tie_formatting_problem::get_attachment (Real y) const
25 {
26   Interval attachments;
27   Direction d = LEFT;
28   do
29     {
30       attachments[d] = skyline_height (chord_outlines_[d], y, -d);
31     }
32   while (flip (&d) != LEFT);
33   
34   return attachments;
35 }
36
37
38
39
40 Tie_formatting_problem::Tie_formatting_problem()
41 {
42   x_refpoint_ = 0;
43   
44 }
45
46 void
47 Tie_formatting_problem::set_chord_outline (Link_array<Item> bounds,
48                                            Direction d)
49 {
50   Real staff_space = Staff_symbol_referencer::staff_space (bounds[0]);
51
52   Array<Box> boxes;
53
54   Grob *stem = 0;
55   for (int i = 0; i < bounds.size (); i++)
56     {
57       Grob *head = bounds[i];
58       if (!Note_head::has_interface (head))
59         continue;
60       
61       if (!stem)
62         stem = unsmob_grob (head->get_object ("stem"));
63           
64       Real p = Staff_symbol_referencer::get_position (head);
65       Interval y ((p-1) * 0.5 * staff_space,
66                   (p+1) * 0.5 * staff_space);
67
68       Interval x = head->extent (x_refpoint_, X_AXIS);
69       boxes.push (Box (x, y));
70
71       Grob *dots = Rhythmic_head::get_dots (head);
72       if (d == LEFT && dots)
73         {
74           Interval x = dots->extent (x_refpoint_, X_AXIS);
75           Interval y (-0.5, 0.5);
76           y.translate (Staff_symbol_referencer::get_position (dots));
77           y *= staff_space * 0.5;
78           
79           boxes.push (Box (x, y));
80         }
81     }
82
83   chord_outlines_[d] = empty_skyline (-d);
84
85   if (bounds[0]->break_status_dir ())
86     {
87       Real x = robust_relative_extent (bounds[0],  x_refpoint_, X_AXIS)[-d];
88       chord_outlines_[d].elem_ref (0).height_ = x; 
89     }
90           
91   for (int i = 0; i < boxes.size (); i++)
92     insert_extent_into_skyline (&chord_outlines_[d]  ,
93                                 boxes[i], Y_AXIS, -d);
94
95   if (stem
96       && !Stem::is_invisible (stem))
97     {
98       Interval x;
99       x.add_point (stem->relative_coordinate (x_refpoint_, X_AXIS));
100       x.widen (staff_space / 20); // ugh.
101       Interval y;
102       y.add_point (Stem::stem_end_position (stem) * staff_space * .5);
103
104       Direction stemdir = get_grob_direction (stem);
105       y.add_point (Stem::head_positions (stem)[-stemdir]
106                    * staff_space * .5);
107           
108       insert_extent_into_skyline (&chord_outlines_[d], Box (x,y), Y_AXIS, -d);
109
110
111
112       if (d == LEFT)
113         {
114           Box flag_box = Stem::get_translated_flag (stem).extent_box ();
115           flag_box.translate( Offset (x[RIGHT], X_AXIS));
116           insert_extent_into_skyline (&chord_outlines_[d], flag_box,
117                                       Y_AXIS, -d);
118         }
119     }
120   
121   Direction updowndir = DOWN;
122   do
123     {
124       Interval x ;
125       Interval y;
126       if (boxes.size())
127         {
128           Box b = boxes.boundary (updowndir, 0);
129           x = b[X_AXIS];
130           x[-d] =  b[X_AXIS].linear_combination (-d / 2);
131           y[-updowndir] = b[Y_AXIS][updowndir];
132           y[updowndir] = updowndir * infinity_f;
133         }
134
135       if (!x.is_empty ())
136         insert_extent_into_skyline (&chord_outlines_[d],
137                                     Box (x,y),
138                                     Y_AXIS, -d);
139     }
140   while (flip (&updowndir) != DOWN);
141
142   for (int i = 0; i < bounds.size (); i++)
143     {
144       if (!Note_head::has_interface (bounds[i]))
145         continue;
146
147       
148       Grob *dots = unsmob_grob (bounds[i]->get_object ("dot"));
149       if (dots && d == LEFT)
150         {
151           Interval x = dots->extent (x_refpoint_, X_AXIS);
152           Real p = Staff_symbol_referencer::get_position (dots);
153               
154           Interval y (-1,1);
155           y *= (staff_space /4);
156           y.translate (p * staff_space * .5);
157
158           insert_extent_into_skyline (&chord_outlines_[d],
159                                       Box (x,y), Y_AXIS, -d);
160         }
161     }
162 }
163
164
165 void
166 Tie_formatting_problem::from_tie (Grob *tie)
167 {
168   Link_array<Grob> ties;
169   ties.push (tie);
170
171   from_ties (ties);
172 }
173
174 Grob *
175 Tie_formatting_problem::common_x_refpoint () const
176 {
177   return x_refpoint_;
178 }
179
180 void
181 Tie_formatting_problem::from_ties (Link_array<Grob> const &ties)
182 {
183   if (ties.is_empty ())
184     return;
185   
186   x_refpoint_ = ties[0];
187   for (int i = 0; i < ties.size (); i++)
188     {
189       x_refpoint_ = dynamic_cast<Spanner*> (ties[i])->get_bound (LEFT)->common_refpoint (x_refpoint_, X_AXIS); 
190       x_refpoint_ = dynamic_cast<Spanner*> (ties[i])->get_bound (RIGHT)->common_refpoint (x_refpoint_, X_AXIS); 
191     }
192   
193   Direction d = LEFT;
194   do
195     {
196       Link_array<Item> bounds;
197       
198       for (int i = 0; i < ties.size (); i++)
199         {
200           Item *it = dynamic_cast<Spanner*> (ties[i])->get_bound (d);
201                                              
202           bounds.push (it);
203         }
204       
205       set_chord_outline (bounds, d);
206     }
207   while (flip (&d) != LEFT);
208 }
209
210 void
211 Tie_formatting_problem::from_lv_ties (Link_array<Grob> const &lv_ties)
212 {
213   if (lv_ties.is_empty ())
214     return ;
215   
216   Link_array<Item> heads;
217   for (int i = 0; i < lv_ties.size (); i++)
218     {
219       Item *head = unsmob_item (lv_ties[i]->get_object ("note-head"));
220       heads.push (head);
221     }
222
223   x_refpoint_ = lv_ties [0];
224   for (int i = 0; i < lv_ties.size (); i++)
225     {
226       x_refpoint_ = lv_ties[i]->common_refpoint (x_refpoint_, X_AXIS); 
227     }
228
229   set_chord_outline (heads, LEFT);
230
231   Real right_most = - infinity_f;   
232
233   for (int i = 0; i < chord_outlines_[LEFT].size (); i++)
234     {
235       right_most = max (right_most, chord_outlines_[LEFT][i].height_);
236     }
237
238   Skyline_entry right_entry;
239   right_entry.width_.set_full ();
240   right_entry.height_ = right_most + 1.5;
241   
242   chord_outlines_[RIGHT].push (right_entry);
243 }