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