]> git.donarmstrong.com Git - lilypond.git/blob - lily/spacing-spanner.cc
release: 1.1.58
[lilypond.git] / lily / spacing-spanner.cc
1 /*   
2   spacing-spanner.cc --  implement Spacing_spanner
3   
4   source file of the GNU LilyPond music typesetter
5   
6   (c) 1999 Han-Wen Nienhuys <hanwen@cs.uu.nl>
7   
8  */
9
10 #include "spacing-spanner.hh"
11 #include "score-column.hh"
12 #include "dimensions.hh"
13 #include "paper-def.hh"
14 #include "warn.hh"
15 #include "paper-score.hh"
16 #include "line-of-score.hh"
17
18 Spacing_spanner::Spacing_spanner ()
19 {
20   set_elt_property (break_helper_only_scm_sym, SCM_BOOL_T);
21   set_elt_property (transparent_scm_sym, SCM_BOOL_T);
22 }
23
24 int
25 Spacing_spanner::col_count () const
26 {
27   return pscore_l_->line_l_->cols_.size ();
28 }
29
30 Score_column *
31 Spacing_spanner::scol (int i)const
32 {
33   return dynamic_cast<Score_column*> (pscore_l_->line_l_->cols_[i]);
34 }
35
36 /*
37   cut 'n paste from spring-spacer.cc
38
39   generate springs between columns.
40
41
42   The algorithm is partly taken from :
43
44   John S. Gourlay. ``Spacing a Line of Music,'' Technical Report
45   OSU-CISRC-10/87-TR35, Department of Computer and Information
46   Science, The Ohio State University, 1987.
47   
48  */
49 Array<Spring>
50 Spacing_spanner::do_measure (int col1, int col2) const
51 {
52   for (int i =col1; i < col2; i++)
53     {
54       scol (i)->preprocess ();
55       scol (i)->print ();
56     }
57
58   Moment shortest;
59   shortest.set_infinite (1);
60   for (int i =col1; i < col2; i++)
61     {
62       if (scol(i)->musical_b ())
63         {
64           shortest = shortest <? scol(i)->shortest_starter_mom_;
65         }
66     }
67
68   Array<Spring> meas_springs;
69
70   Real non_musical_space_strength = paper_l ()->get_var ("non_musical_space_strength");
71   for (int i= col1; i < col2; i++)
72     {
73       Item * l = scol(i);
74       Item * r = scol(i+1);
75       Item * lb = l->find_prebroken_piece (RIGHT);
76       Item * rb = r->find_prebroken_piece (LEFT);      
77
78       Item* combinations[4][2]={{l,r}, {lb,r}, {l,rb},{lb,rb}};
79
80       for (int i=0; i < 4; i++)
81         {
82           Score_column * lc = dynamic_cast<Score_column*> (combinations[i][0]);
83           Score_column *rc = dynamic_cast<Score_column*> (combinations[i][1]);
84           if (!lc || !rc)
85             continue;
86
87           Spring s;
88           s.item_l_drul_[LEFT] = lc;
89           s.item_l_drul_[RIGHT] = rc;
90           
91           SCM hint = lc->get_elt_property (extra_space_scm_sym);
92           SCM next_hint = rc->get_elt_property (extra_space_scm_sym);
93         
94           if (hint != SCM_BOOL_F)
95             {
96               hint = SCM_CDDR (hint);
97               
98               s.distance_f_ = gh_scm2double (hint); 
99               if (!lc->musical_b ())
100                 s.strength_f_ = 2.0;
101             }
102           else if (!lc->musical_b() && i+1 < col_count())
103             {
104               s.distance_f_ = default_bar_spacing (lc,rc,shortest);
105               s.strength_f_ = non_musical_space_strength; // fixed after complaints by michael krause
106             }
107           else if (lc->musical_b())
108             {
109               s.distance_f_ = note_spacing (lc, rc, shortest);
110               
111             }
112           
113           if (next_hint != SCM_BOOL_F)
114             {
115              next_hint = SCM_CADR(next_hint);
116              s.distance_f_ += gh_scm2double (next_hint);
117             }
118           else
119             {
120               Interval ext (rc->extent (X_AXIS));
121               Real correction =  ext.empty_b() ? 0.0 : - ext [LEFT];
122
123               /*
124                 don't want to create too much extra space for accidentals
125                */
126               if (lc->musical_b () && rc->musical_b ())
127                 correction /= 2.0;
128
129               s.distance_f_ += correction;
130             }
131
132           if (s.distance_f_ <=0)
133             {
134               /*
135                 \bar "".  We give it 0 space, with high strength. 
136                */
137               s.distance_f_ = 0.0 PT;
138               s.strength_f_ = 20.0; 
139             }
140           meas_springs.push (s);        
141         }
142     }
143
144   return meas_springs;
145 }
146
147 /**
148    Do something if breakable column has no spacing hints set.
149  */
150 Real
151 Spacing_spanner::default_bar_spacing (Score_column *lc, Score_column *rc, Moment shortest) const
152 {
153   Real symbol_distance = lc->extent (X_AXIS)[RIGHT] ;
154   Real durational_distance = 0;
155   Moment delta_t =  rc->when_mom () - lc->when_mom () ;
156
157   /*
158                 ugh should use shortest_playing distance
159   */
160   if (delta_t)
161     {
162       Real k=  paper_l()->arithmetic_constant (shortest);
163       durational_distance =  paper_l()->length_mom_to_dist (delta_t,k);
164     }
165
166   return  symbol_distance >? durational_distance;
167 }
168
169
170 Real
171 Spacing_spanner::note_spacing (Score_column *lc, Score_column *rc, Moment shortest) const
172 {
173   Moment shortest_playing_len = lc->shortest_playing_mom_;
174   if (! shortest_playing_len)
175     {
176       warning (_f ("can't find a ruling note at %s", 
177                    lc->when_mom ().str ()));
178       shortest_playing_len = 1;
179     }
180   if (! shortest)
181     {
182       warning (_f ("no minimum in measure at %s", 
183                    lc->when_mom ().str ()));
184       shortest = 1;
185     }
186   Moment delta_t = rc->when_mom () - lc->when_mom ();
187   Real k=  paper_l()->arithmetic_constant(shortest);
188   Real dist = paper_l()->length_mom_to_dist (shortest_playing_len, k);
189   dist *= (double)(delta_t / shortest_playing_len);
190
191   dist += stem_dir_correction (lc,rc);
192   return dist;
193 }
194
195
196 /**
197    Correct for optical illusions. See [Wanske] p. 138. The combination
198    up-stem + down-stem should get extra space, the combination
199    down-stem + up-stem less.
200
201    This should be more advanced, since relative heights of the note
202    heads also influence required correction.
203
204    Also might not work correctly ico. multi voices or staff changing voices
205
206    TODO: lookup correction distances?  More advanced correction?
207    Possibly turn this off?
208
209    This routine reads the DIR_LIST property of both its L and R arguments.
210 */
211 Real
212 Spacing_spanner::stem_dir_correction (Score_column*l, Score_column*r) const
213 {
214   SCM dl = l->get_elt_property (dir_list_scm_sym);
215   SCM dr = r->get_elt_property (dir_list_scm_sym);
216   if (dl == SCM_BOOL_F || dr == SCM_BOOL_F)
217     return 0.0;
218
219   dl = SCM_CDR (dl);
220   dr = SCM_CDR (dr);
221
222   if (scm_ilength (dl) != 1 && scm_ilength (dr) != 1)
223     return 0.;
224
225   dl = SCM_CAR(dl);
226   dr = SCM_CAR(dr);
227
228   assert (gh_number_p (dl) && gh_number_p(dr));
229   int d1 = gh_scm2int (dl);
230   int d2 = gh_scm2int (dr);
231
232   if (d1 == d2)
233     return 0.0;
234
235   bool err = false;
236   Real correction = 0.0;
237   Real ssc = paper_l ()->get_realvar(ly_symbol ("stemSpacingCorrection"));
238
239
240   if (d1 && d2)
241     {
242       if (d1 == 1 && d2 == -1)
243         correction = ssc;
244       else if (d1 == -1 && d2 == 1)
245         correction = -ssc;
246       else
247         err = true;
248     }
249   
250   else
251     err = true;
252
253   if (err)
254     programming_error ("Stem directions not set correctly for optical correction");
255   return correction;
256 }
257   
258
259 Array<Spring>
260 Spacing_spanner::get_springs () const
261 {
262   Array<Spring> springs;
263   int last_break =0;
264   for (int i=1; i < col_count (); i++)
265     {
266       if (scol (i)->breakable_b ())
267         {
268           springs.concat (do_measure (last_break, i));
269           last_break  = i;
270         }
271     }
272   return springs;
273 }
274
275
276
277