2 stem.cc -- implement Stem
4 source file of the GNU LilyPond music typesetter
6 (c) 1996, 1997--1999 Han-Wen Nienhuys <hanwen@cs.uu.nl>
8 TODO: This is way too hairy
13 #include "paper-def.hh"
14 #include "note-head.hh"
16 #include "molecule.hh"
17 #include "paper-column.hh"
23 Stem::set_direction (Direction d
)
26 warning ("Stem direction set already!");
37 beams_i_drul_
[LEFT
] = beams_i_drul_
[RIGHT
] = -1;
38 yextent_drul_
[DOWN
] = yextent_drul_
[UP
] = 0;
45 Stem::head_positions () const
48 Mysterious FreeBSD fix by John Galbraith. Somehow, the empty intervals
49 trigger FP exceptions on FreeBSD. Fix: do not return infinity
52 if (!head_l_arr_
.size ())
54 return Interval_t
<int> (100,-100);
58 for (int i
=0; i
< head_l_arr_
.size (); i
++)
60 int p
= head_l_arr_
[i
]->position_i_
;
61 r
[BIGGER
] = r
[BIGGER
] >? p
;
62 r
[SMALLER
] = r
[SMALLER
] <? p
;
68 Stem::do_print () const
71 DOUT
<< "flag "<< flag_i_
;
78 Stem::stem_length_f () const
80 return yextent_drul_
[UP
]-yextent_drul_
[DOWN
] ;
84 Stem::stem_begin_f () const
86 return yextent_drul_
[Direction(-dir_
)];
90 Stem::chord_start_f () const
92 return head_positions()[dir_
] * staff_line_leading_f ()/2.0;
96 Stem::stem_end_f () const
98 return yextent_drul_
[dir_
];
102 Stem::set_stemend (Real se
)
105 if (dir_
&& dir_
* head_positions()[dir_
] >= se
*dir_
)
106 warning (_ ("weird stem size; check for narrow beams"));
109 yextent_drul_
[dir_
] = se
;
110 yextent_drul_
[Direction(-dir_
)] = head_positions()[-dir_
];
114 Stem::type_i () const
116 return head_l_arr_
[0]->balltype_i_
;
120 Stem::add_head (Rhythmic_head
*n
)
123 n
->add_dependency (this); // ?
124 if (Note_head
*nh
= dynamic_cast<Note_head
*> (n
))
126 head_l_arr_
.push (nh
);
128 else if (Rest
*r
= dynamic_cast<Rest
*> (n
))
130 rest_l_arr_
.push (r
);
135 Stem::invisible_b () const
137 return (!head_l_arr_
.size () ||
138 head_l_arr_
[0]->balltype_i_
<= 0);
142 Stem::get_center_distance (Direction d
) const
144 int staff_center
= 0;
145 int distance
= d
*(head_positions()[d
] - staff_center
);
146 return distance
>? 0;
150 Stem::get_default_dir () const
152 int du
= get_center_distance (UP
);
153 int dd
= get_center_distance (DOWN
);
156 return Direction (sign (dd
-du
));
158 return Direction (int(paper_l ()->get_var ("stem_default_neutral_direction")));
162 Stem::get_dir () const
169 Stem::set_default_stemlen ()
172 SCM scm_len
= get_elt_property(length_scm_sym
);
173 if (scm_len
!= SCM_BOOL_F
)
175 length_f
= gh_scm2double (SCM_CDR(scm_len
));
178 length_f
= paper_l ()->get_var ("stem_length0");
180 bool grace_b
= get_elt_property (grace_scm_sym
) != SCM_BOOL_F
;
181 String type_str
= grace_b
? "grace_" : "";
183 Real shorten_f
= paper_l ()->get_var (type_str
+ "forced_stem_shorten0");
186 dir_
= get_default_dir ();
189 stems in unnatural (forced) direction should be shortened,
190 according to [Roush & Gourlay]
192 if (((int)chord_start_f ())
193 && (dir_
!= get_default_dir ()))
194 length_f
-= shorten_f
;
201 set_stemend ((dir_
> 0) ? head_positions()[BIGGER
] + length_f
:
202 head_positions()[SMALLER
] - length_f
);
204 if (!grace_b
&& (dir_
* stem_end_f () < 0))
210 Stem::set_default_extents ()
212 if (!stem_length_f ())
213 set_default_stemlen ();
218 Stem::set_noteheads ()
220 if (!head_l_arr_
.size ())
222 head_l_arr_
.sort (Note_head::compare
);
224 head_l_arr_
.reverse ();
226 Note_head
* beginhead
= head_l_arr_
[0];
227 beginhead
->set_elt_property (extremal_scm_sym
, SCM_BOOL_T
);
228 if (beginhead
!= head_l_arr_
.top ())
229 head_l_arr_
.top ()->set_elt_property (extremal_scm_sym
, SCM_BOOL_T
);
232 int lastpos
= beginhead
->position_i_
;
233 for (int i
=1; i
< head_l_arr_
.size (); i
++)
235 int dy
=abs (lastpos
- head_l_arr_
[i
]->position_i_
);
240 head_l_arr_
[i
]->flip_around_stem (dir_
);
245 lastpos
= head_l_arr_
[i
]->position_i_
;
250 Stem::do_pre_processing ()
252 if (yextent_drul_
[DOWN
]== yextent_drul_
[UP
])
253 set_default_extents ();
258 set_elt_property (transparent_scm_sym
, SCM_BOOL_T
);
260 set_empty (invisible_b ());
261 set_spacing_hints ();
267 set stem directions for hinting the optical spacing correction.
269 Modifies DIR_LIST property of the Stem's Score_column
271 TODO: more advanced: supply height of noteheads as well, for more advanced spacing possibilities
274 Stem::set_spacing_hints ()
278 SCM scmdir
= gh_int2scm (dir_
);
279 SCM dirlist
= column_l ()->get_elt_property (dir_list_scm_sym
);
280 if (dirlist
== SCM_BOOL_F
)
283 dirlist
= SCM_CDR (dirlist
);
285 if (scm_sloppy_memq (scmdir
, dirlist
) == SCM_EOL
)
287 dirlist
= gh_cons (scmdir
, dirlist
);
288 column_l ()->set_elt_property (dir_list_scm_sym
, dirlist
);
297 SCM st
= get_elt_property (style_scm_sym
);
298 if ( st
!= SCM_BOOL_F
)
301 style
= ly_scm2string (st
);
304 char c
= (dir_
== UP
) ? 'u' : 'd';
305 Molecule m
= lookup_l ()->afm_find (String ("flags-") + to_str (c
) +
307 if (!style
.empty_b ())
308 m
.add_molecule(lookup_l ()->afm_find (String ("flags-") + to_str (c
) + style
));
313 Stem::do_width () const
316 if (beam_l_
|| abs (flag_i_
) <= 2)
320 r
= flag ().dim_
.x ();
321 r
+= note_delta_f ();
329 const Real ANGLE
= 20* (2.0*M_PI
/360.0); // ugh!
332 Stem::do_brew_molecule_p () const
334 Molecule
*mol_p
=new Molecule
;
335 Drul_array
<Real
> stem_y
= yextent_drul_
;
336 Real dy
= staff_line_leading_f ()/2.0;
339 if (head_l_arr_
.size ())
340 head_wid
= head_l_arr_
[0]->extent (X_AXIS
).length ();
341 stem_y
[Direction(-dir_
)] += dir_
* head_wid
* tan(ANGLE
)/(2*dy
);
345 Real stem_width
= paper_l ()->get_var ("stemthickness");
346 Molecule ss
=lookup_l ()->filledbox (Box (Interval (-stem_width
/2, stem_width
/2),
347 Interval (stem_y
[DOWN
]*dy
, stem_y
[UP
]*dy
)));
348 mol_p
->add_molecule (ss
);
351 if (!beam_l_
&& abs (flag_i_
) > 2)
353 Molecule fl
= flag ();
354 fl
.translate_axis(stem_y
[dir_
]*dy
, Y_AXIS
);
355 mol_p
->add_molecule (fl
);
358 if (head_l_arr_
.size())
360 mol_p
->translate_axis (note_delta_f (), X_AXIS
);
366 Stem::note_delta_f () const
369 if (head_l_arr_
.size())
371 Interval
head_wid(0, head_l_arr_
[0]->extent (X_AXIS
).length ());
372 Real
rule_thick(paper_l ()->rule_thickness ());
373 Interval
stem_wid(-rule_thick
/2, rule_thick
/2);
375 r
= head_wid
.center ();
377 r
= head_wid
[dir_
] - stem_wid
[dir_
];
383 Stem::hpos_f () const
385 return note_delta_f () + Item::hpos_f ();
389 Stem::do_substitute_element_pointer (Score_element
*o
,Score_element
*n
)
391 if (Note_head
*h
=dynamic_cast<Note_head
*> (o
))
392 head_l_arr_
.substitute (h
, dynamic_cast<Note_head
*>(n
));
393 if (Rest
*r
=dynamic_cast<Rest
*> (o
))
394 rest_l_arr_
.substitute (r
, dynamic_cast<Rest
*>(n
));
395 if (Beam
* b
= dynamic_cast<Beam
*> (o
))
398 beam_l_
= dynamic_cast<Beam
*> (n
);
400 Staff_symbol_referencer::do_substitute_element_pointer (o
,n
);