]> git.donarmstrong.com Git - lilypond.git/blob - lily/tie-column-format.cc
* lily/grob-property.cc (get_interfaces): new function.
[lilypond.git] / lily / tie-column-format.cc
1 /*
2   tie-column-format.cc -- implement formatting routines for Tie_column
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 "stem.hh"
11 #include "note-head.hh"
12 #include "tie.hh"
13 #include "parray.hh"
14 #include "spanner.hh"
15 #include "item.hh"
16 #include "staff-symbol-referencer.hh"
17 #include "directional-element-interface.hh"
18
19 #include <set>
20
21 void
22 set_manual_tie_configuration (Array<Tie_configuration> *tie_configs,
23                               bool *manual_override,
24                               SCM manual_configs
25                               )
26 {
27   *manual_override = false;
28   int k = 0;
29   for (SCM s = manual_configs;
30        scm_is_pair (s) && k < tie_configs->size(); s = scm_cdr (s))
31     {
32       SCM entry = scm_car (s);
33       if (!scm_is_pair (entry))
34         continue;
35
36       *manual_override = true;
37       Tie_configuration &conf = tie_configs->elem_ref (k);
38       
39       Real complete_pos = robust_scm2double (scm_car (entry),
40                                              conf.position_);
41
42       conf.position_ = int (rint (complete_pos));
43       conf.delta_y_ = complete_pos - conf.position_;
44       conf.dir_ = Direction (robust_scm2int (scm_cdr (entry),
45                                              conf.dir_));
46       k ++;
47     }
48 }
49
50 void
51 set_chord_outline (Array<Skyline_entry> *skyline,
52                    Link_array<Item> bounds,
53                    Grob *common,
54                    Direction d)
55 {
56   Real staff_space = Staff_symbol_referencer::staff_space (bounds[0]);
57
58   Array<Box> boxes;
59   Interval x_union;
60
61   Grob *stem = 0;
62   for (int i = 0; i < bounds.size (); i++)
63     {
64       Grob *head = bounds[i];
65       if (!Note_head::has_interface (head))
66         continue;
67       
68       if (!stem)
69         stem = unsmob_grob (head->get_object ("stem"));
70           
71       Real p = Staff_symbol_referencer::get_position (head);
72       Interval y ((p-1) * 0.5 * staff_space,
73                   (p+1) * 0.5 * staff_space);
74
75       Interval x = head->extent (common, X_AXIS);
76       boxes.push (Box (x, y));
77       x_union.unite (x);
78     }
79
80   (*skyline) = empty_skyline (-d);
81
82   if (bounds[0]->break_status_dir ())
83     {
84       Real x = robust_relative_extent (bounds[0],  common, X_AXIS)[-d];
85       skyline->elem_ref (0).height_ = x; 
86     }
87           
88   for (int i = 0; i < boxes.size (); i++)
89     insert_extent_into_skyline (skyline,
90                                 boxes[i], Y_AXIS, -d);
91   if (stem
92       && !Stem::is_invisible (stem))
93     {
94       Interval x;
95       x.add_point (stem->relative_coordinate (common, X_AXIS));
96       x.widen (staff_space / 20); // ugh.
97       Interval y;
98       y.add_point (Stem::stem_end_position (stem) * staff_space * .5);
99
100       Direction stemdir = get_grob_direction (stem);
101       y.add_point (Stem::head_positions (stem)[-stemdir]
102                    * staff_space * .5);
103           
104       insert_extent_into_skyline (skyline, Box (x,y), Y_AXIS, -d);
105
106
107
108       if (d == LEFT)
109         {
110           Box flag_box = Stem::get_translated_flag (stem).extent_box ();
111           flag_box.translate( Offset (x[RIGHT], X_AXIS));
112           insert_extent_into_skyline (skyline, flag_box,
113                                       Y_AXIS, -d);
114         }
115     }
116   
117   Direction updowndir = DOWN;
118   do
119     {
120       Interval x ;
121       Interval y;
122       if (boxes.size())
123         {
124           Box b = boxes.boundary (updowndir, 0);
125           x = b[X_AXIS];
126           x[-d] =  b[X_AXIS].linear_combination (-d / 2);
127           y[-updowndir] = b[Y_AXIS][updowndir];
128           y[updowndir] = updowndir * infinity_f;
129         }
130
131       if (!x.is_empty ())
132         insert_extent_into_skyline (skyline,
133                                     Box (x,y),
134                                     Y_AXIS, -d);
135     }
136   while (flip (&updowndir) != DOWN);
137
138   for (int i = 0; i < bounds.size (); i++)
139     {
140       if (!Note_head::has_interface (bounds[i]))
141         continue;
142
143       
144       Grob *dots = unsmob_grob (bounds[i]->get_object ("dot"));
145       if (dots && d == LEFT)
146         {
147           Interval x = dots->extent (common, X_AXIS);
148           Real p = Staff_symbol_referencer::get_position (dots);
149               
150           Interval y (-1,1);
151           y *= (staff_space /4);
152           y.translate (p * staff_space * .5);
153
154           insert_extent_into_skyline (skyline,
155                                       Box (x,y), Y_AXIS, -d);
156         }
157     }
158 }
159
160 void
161 set_chord_outlines (Drul_array< Array<Skyline_entry> > *skyline_drul,
162                     Link_array<Grob> ties,
163                     Grob *common)
164 {
165   Direction d = LEFT;
166
167   do
168     {
169       Link_array<Item> bounds;
170       
171       for (int i = 0; i < ties.size (); i++)
172         {
173           Item *it = dynamic_cast<Spanner*> (ties[i])->get_bound (d);
174                                              
175           bounds.push (it);
176         }
177       
178       set_chord_outline (&skyline_drul->elem_ref (d),
179                          bounds, common, d);
180     }
181   while (flip (&d) != LEFT);
182 }
183
184 void
185 shift_small_ties (Array<Tie_configuration> *tie_configs,
186                   Grob *staff_referencer,
187                   Tie_details const &details)
188 {
189   set<int> positions_taken;
190   for (int i = 0; i < tie_configs->size (); i++)
191     positions_taken.insert (int (rint (tie_configs->elem (i).position_)));
192
193   for (int i = 0; i < tie_configs->size (); i++)
194     {
195       Tie_configuration * conf = &tie_configs->elem_ref (i);
196
197       /*
198         on staff line and small enough, translate a little further 
199       */
200       Real h = conf->height (details);
201       bool next_free = positions_taken.find (int (rint (conf->position_ + conf->dir_)))
202         == positions_taken.end ();
203
204       int rounded_pos = int (rint (conf->position_ + conf->delta_y_ / details.staff_space_));
205       bool on_line = Staff_symbol_referencer::on_staffline (staff_referencer, rounded_pos);
206       
207       if (next_free)
208         if (on_line && h < 0.4 * details.staff_space_)
209           {
210             positions_taken.insert (int (rint (conf->position_ + conf->dir_)));
211             conf->delta_y_ += 0.2 * details.staff_space_ * conf->dir_;
212           }
213         else if (!on_line && h > 0.6 * details.staff_space_)
214           {
215             positions_taken.insert (int (rint (conf->position_ + conf->dir_)));
216             conf->delta_y_ += 0.5 * details.staff_space_ * conf->dir_;
217           }
218     }
219 }
220
221
222 void
223 final_shape_adjustment (Tie_configuration &conf,
224                         Drul_array< Array<Skyline_entry> > const &skylines,
225                         Grob *staff_referencer,
226                         Tie_details const &details)
227 {
228   Real line_dy = 0.0;
229   bool on_line = Staff_symbol_referencer::on_staffline (staff_referencer,
230                                                         int (rint (conf.position_)));
231   if (on_line)
232     line_dy = - sign (conf.height (details) - 0.6 * details.staff_space_)
233       * 0.2 * details.staff_space_ * conf.dir_;
234
235   Real y = conf.position_ * details.staff_space_ * 0.5
236     + line_dy;
237   
238   conf.attachment_x_ = get_skyline_attachment (skylines, y);
239   conf.attachment_x_.intersect (get_skyline_attachment (skylines,
240                                                         y + conf.dir_ * details.staff_space_ * 0.5));
241
242   conf.delta_y_ += line_dy;
243   conf.attachment_x_.widen (-details.x_gap_);
244   if (!on_line
245       && Staff_symbol_referencer::staff_radius (staff_referencer) * details.staff_space_ > y)
246     conf.center_tie_vertically (details);
247 }
248
249 void
250 set_tie_config_directions (Array<Tie_configuration> *tie_configs_ptr)
251 {
252   Array<Tie_configuration> &tie_configs (*tie_configs_ptr);
253   
254   if (!tie_configs[0].dir_)
255     tie_configs[0].dir_ = DOWN;
256   if (!tie_configs.top().dir_)
257     tie_configs.top().dir_ = UP;
258
259   /*
260     Seconds
261    */
262   for (int i = 1; i < tie_configs.size(); i++)
263     {
264       Real diff = tie_configs[i-1].position_ - tie_configs[i].position_;
265       if (fabs (diff) <= 1)
266         {
267           if (!tie_configs[i-1].dir_)
268             tie_configs[i-1].dir_ = DOWN;
269           if (!tie_configs[i].dir_)
270             tie_configs[i].dir_ = UP;
271         }
272     }
273
274   for (int i = 1; i < tie_configs.size() - 1; i++)
275     {
276       if (tie_configs[i].dir_)
277         continue;
278
279       Direction position_dir = (Direction) sign (tie_configs[i].position_);
280       if (!position_dir)
281         position_dir = DOWN;
282       
283       tie_configs[i].dir_ = position_dir;
284     }
285 }
286