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