2 beam.cc -- implement Beam
4 source file of the GNU LilyPond music typesetter
6 (c) 1997--2000 Han-Wen Nienhuys <hanwen@cs.uu.nl>
7 Jan Nieuwenhuizen <janneke@gnu.org>
14 * move paper vars to scm
16 remove *-hs variables.
20 #include <math.h> // tanh.
21 #include "directional-element-interface.hh"
23 #include "dimensions.hh"
27 #include "least-squares.hh"
29 #include "paper-def.hh"
31 #include "group-interface.hh"
32 #include "staff-symbol-referencer.hh"
33 #include "cross-staff.hh"
38 Score_element
*me
=this;
40 Pointer_group_interface
g (me
, "stems");
43 set_elt_property ("height", gh_int2scm (0)); // ugh.
44 set_elt_property ("y-position" ,gh_int2scm (0));
48 Beam::add_stem (Score_element
*s
)
50 Score_element
*me
=this;
51 Pointer_group_interface
gi (me
, "stems");
54 s
->add_dependency (me
);
56 assert (!Stem::beam_l (s
));
57 s
->set_elt_property ("beam", self_scm_
);
59 add_bound_item (dynamic_cast<Spanner
*> (me
), dynamic_cast<Item
*> (s
));
63 Beam::get_multiplicity () const
65 Score_element
*me
=(Score_element
*)this;
67 for (SCM s
= me
->get_elt_property ("stems"); gh_pair_p (s
); s
= gh_cdr (s
))
69 Score_element
* sc
= unsmob_element (gh_car (s
));
71 if (Stem::has_interface (sc
))
72 m
= m
>? Stem::beam_count (sc
,LEFT
) >? Stem::beam_count (sc
,RIGHT
);
78 After pre-processing all directions should be set.
79 Several post-processing routines (stem, slur, script) need stem/beam
81 Currenly, this means that beam has set all stem's directions.
82 [Alternatively, stems could set its own directions, according to
83 their beam, during 'final-pre-processing'.]
85 MAKE_SCHEME_CALLBACK(Beam
,before_line_breaking
);
87 Beam::before_line_breaking (SCM smob
)
90 Score_element
* beam
= unsmob_element (smob
);
91 Beam
* me
=dynamic_cast<Beam
*> (beam
);
94 if (me
->visible_stem_count () < 2)
96 warning (_ ("beam has less than two stems"));
100 if (!Directional_element_interface (me
).get ())
101 Directional_element_interface (me
).set (me
->get_default_dir ());
104 me
->set_stem_directions ();
105 me
->set_stem_shorten ();
114 Beam::get_default_dir () const
116 Drul_array
<int> total
;
117 total
[UP
] = total
[DOWN
] = 0;
118 Drul_array
<int> count
;
119 count
[UP
] = count
[DOWN
] = 0;
121 Spanner
*me
= (Spanner
*)this;
122 Link_array
<Item
> stems
=
123 Pointer_group_interface__extract_elements (me
, (Item
*)0, "stems");
125 for (int i
=0; i
<stems
.size (); i
++)
126 do { // HUH -- waar slaat dit op?
127 Score_element
*s
= stems
[i
];
128 Direction sd
= Directional_element_interface (s
).get ();
129 int current
= sd
? (1 + d
* sd
)/2
130 : Stem::get_center_distance (s
, (Direction
)-d
);
138 } while (flip(&d
) != DOWN
);
141 SCM s
= scm_eval (gh_list (ly_symbol2scm ("beam-dir-algorithm"),
142 ly_quote_scm (gh_cons (gh_int2scm (count
[UP
]),
143 gh_int2scm (count
[DOWN
]))),
144 ly_quote_scm (gh_cons (gh_int2scm (total
[UP
]),
145 gh_int2scm (total
[DOWN
]))),
147 if (gh_number_p (s
) && gh_scm2int (s
))
151 If dir is not determined: get default
153 return to_dir (get_elt_property ("default-neutral-direction"));
158 Set all stems with non-forced direction to beam direction.
159 Urg: non-forced should become `without/with unforced' direction,
160 once stem gets cleaned-up.
163 Beam::set_stem_directions ()
165 Link_array
<Item
> stems
166 =Pointer_group_interface__extract_elements (this, (Item
*) 0, "stems");
167 Direction d
= Directional_element_interface (this).get ();
169 for (int i
=0; i
<stems
.size (); i
++)
171 Score_element
*s
= stems
[i
];
172 SCM force
= s
->remove_elt_property ("dir-forced");
173 if (!gh_boolean_p (force
) || !gh_scm2bool (force
))
174 Directional_element_interface (s
).set (d
);
181 if (!auto_knee ("auto-interstaff-knee-gap", true))
182 auto_knee ("auto-knee-gap", false);
186 Simplistic auto-knees; only consider vertical gap between two
189 `Forced' stem directions are ignored. If you don't want auto-knees,
190 don't set, or unset autoKneeGap/autoInterstaffKneeGap.
193 Beam::auto_knee (String gap_str
, bool interstaff_b
)
197 SCM gap
= get_elt_property (gap_str
.ch_C());
200 Direction d
= Directional_element_interface (me
).get ();
201 Link_array
<Item
> stems
=
202 Pointer_group_interface__extract_elements (me
, (Item
*)0, "stems");
204 if (gh_number_p (gap
))
206 int auto_gap_i
= gh_scm2int (gap
);
207 for (int i
=1; i
< stems
.size (); i
++)
209 bool is_b
= (bool)(calc_interstaff_dist (stems
[i
], me
)
210 - calc_interstaff_dist (stems
[i
-1], me
));
211 int l_y
= (int)(Stem::head_positions(stems
[i
-1])[d
])
212 + (int)calc_interstaff_dist (stems
[i
-1], me
);
213 int r_y
= (int)(Stem::head_positions(stems
[i
])[d
])
214 + (int)calc_interstaff_dist (stems
[i
], me
);
215 int gap_i
= r_y
- l_y
;
217 if ((abs (gap_i
) >= auto_gap_i
) && (!interstaff_b
|| is_b
))
219 knee_y
= (r_y
+ l_y
) / 2;
227 for (int i
=0; i
< stems
.size (); i
++)
230 int y
= (int)(Stem::head_positions(s
)[d
])
231 + (int)calc_interstaff_dist (s
, me
);
233 Directional_element_interface (s
).set (y
< knee_y
? UP
: DOWN
);
234 s
->set_elt_property ("dir-forced", SCM_BOOL_T
);
241 Set stem's shorten property if unset.
243 take some y-position (chord/beam/nearest?) into account
244 scmify forced-fraction
247 Beam::set_stem_shorten ()
250 if (!visible_stem_count ())
253 Real forced_fraction
= forced_stem_count () / visible_stem_count ();
254 if (forced_fraction
< 0.5)
257 int multiplicity
= get_multiplicity ();
260 SCM shorten
= scm_eval (ly_symbol2scm ("beamed-stem-shorten"));
262 if (shorten
== SCM_EOL
)
265 int sz
= scm_ilength (shorten
);
267 Real staff_space
= Staff_symbol_referencer::staff_space (me
);
268 SCM shorten_elt
= scm_list_ref (shorten
, gh_int2scm (multiplicity
<? (sz
- 1)));
269 Real shorten_f
= gh_scm2double (shorten_elt
) * staff_space
;
271 /* cute, but who invented this -- how to customise ? */
272 if (forced_fraction
< 1)
275 Link_array
<Item
> stems
=
276 Pointer_group_interface__extract_elements (me
, (Item
*)0, "stems");
278 for (int i
=0; i
< stems
.size (); i
++)
281 if (Stem::invisible_b (s
))
283 if (gh_number_p (s
->get_elt_property ("shorten")))
284 s
->set_elt_property ("shorten", gh_double2scm (shorten_f
));
289 Set elt properties height and y-position if not set.
290 Adjust stem lengths to reach beam.
292 MAKE_SCHEME_CALLBACK(Beam
,after_line_breaking
);
294 Beam::after_line_breaking (SCM smob
)
296 Score_element
* beam
= unsmob_element (smob
);
297 Beam
* me
=dynamic_cast<Beam
*> (beam
);
299 /* first, calculate y, dy */
301 me
->calc_default_position_and_height (&y
, &dy
);
302 if (me
->visible_stem_count ())
304 if (me
->suspect_slope_b (y
, dy
))
307 Real damped_dy
= me
->calc_slope_damping_f (dy
);
308 Real quantised_dy
= me
->quantise_dy_f (damped_dy
);
310 y
+= (dy
- quantised_dy
) / 2;
314 until here, we used only stem_info, which acts as if dir=up
316 y
*= Directional_element_interface (me
).get ();
317 dy
*= Directional_element_interface (me
).get ();
320 Real half_space
= Staff_symbol_referencer::staff_space (me
) / 2;
322 /* check for user-override of dy */
323 SCM s
= me
->remove_elt_property ("height-hs");
326 dy
= gh_scm2double (s
) * half_space
;
328 me
->set_elt_property ("height", gh_double2scm (dy
));
330 /* check for user-override of y */
331 s
= me
->remove_elt_property ("y-position-hs");
334 y
= gh_scm2double (s
) * half_space
;
338 /* we can modify y, so we should quantise y */
339 Real y_shift
= me
->check_stem_length_f (y
, dy
);
341 y
= me
->quantise_y_f (y
, dy
, 0);
342 me
->set_stem_length (y
, dy
);
343 y_shift
= me
->check_stem_length_f (y
, dy
);
345 if (y_shift
> half_space
/ 4)
350 for significantly lengthened or shortened stems,
351 request quanting the other way.
354 if (abs (y_shift
) > half_space
/ 2)
355 quant_dir
= sign (y_shift
) * Directional_element_interface (me
).get ();
356 y
= me
->quantise_y_f (y
, dy
, quant_dir
);
359 // UGH. Y is not in staff position unit?
360 // Ik dacht datwe daar juist van weg wilden?
361 me
->set_stem_length (y
, dy
);
362 me
->set_elt_property ("y-position", gh_double2scm (y
));
364 return SCM_UNDEFINED
;
368 See Documentation/tex/fonts.doc
371 Beam::calc_default_position_and_height (Real
* y
, Real
* dy
) const
373 Spanner
*me
= (Spanner
*)this;
376 if (visible_stem_count () <= 1)
379 Real first_ideal
= Stem::calc_stem_info (first_visible_stem ()).idealy_f_
;
380 if (first_ideal
== Stem::calc_stem_info (last_visible_stem ()).idealy_f_
)
387 Array
<Offset
> ideals
;
388 Real x0
= first_visible_stem ()->relative_coordinate (0, X_AXIS
);
389 Link_array
<Item
> stems
=
390 Pointer_group_interface__extract_elements (me
, (Item
*)0, "stems");
392 for (int i
=0; i
< stems
.size (); i
++)
395 if (Stem::invisible_b (s
))
397 ideals
.push (Offset (s
->relative_coordinate (0, X_AXIS
) - x0
,
398 Stem::calc_stem_info (s
).idealy_f_
));
401 minimise_least_squares (&dydx
, y
, ideals
); // duh, takes references
403 Real dx
= last_visible_stem ()->relative_coordinate (0, X_AXIS
) - x0
;
408 Beam::suspect_slope_b (Real y
, Real dy
) const
410 /* first, calculate y, dy */
412 steep slope running against lengthened stem is suspect
414 Real first_ideal
= Stem::calc_stem_info (first_visible_stem ()).idealy_f_
;
415 Real last_ideal
= Stem::calc_stem_info (last_visible_stem ()).idealy_f_
;
416 Real lengthened
= paper_l ()->get_var ("beam_lengthened");
417 Real steep
= paper_l ()->get_var ("beam_steep_slope");
419 Real dx
= last_visible_stem ()->relative_coordinate (0, X_AXIS
) - first_visible_stem ()->relative_coordinate (0, X_AXIS
);
420 Real dydx
= dy
&& dx
? dy
/dx
: 0;
422 if (((y
- first_ideal
> lengthened
) && (dydx
> steep
))
423 || ((y
+ dy
- last_ideal
> lengthened
) && (dydx
< -steep
)))
431 This neat trick is by Werner Lemberg,
432 damped = tanh (slope)
433 corresponds with some tables in [Wanske]
436 Beam::calc_slope_damping_f (Real dy
) const
438 SCM damp
= get_elt_property ("damping");
439 int damping
= gh_scm2int (damp
);
443 Real dx
= last_visible_stem ()->relative_coordinate (0, X_AXIS
)
444 - first_visible_stem ()->relative_coordinate (0, X_AXIS
);
445 Real dydx
= dy
&& dx
? dy
/dx
: 0;
446 dydx
= 0.6 * tanh (dydx
) / damping
;
453 Beam::calc_stem_y_f (Item
* s
, Real y
, Real dy
) const
455 Score_element
*me
= (Score_element
*)this;
456 Real thick
= gh_scm2double (get_elt_property ("beam-thickness"));
457 thick
*= paper_l ()->get_var ("staffspace");
459 int beam_multiplicity
= get_multiplicity ();
460 int stem_multiplicity
= (Stem::flag_i (s
) - 2) >? 0;
462 Real interbeam_f
= paper_l ()->interbeam_f (beam_multiplicity
);
463 Real x0
= first_visible_stem ()->relative_coordinate (0, X_AXIS
);
464 Real dx
= last_visible_stem ()->relative_coordinate (0, X_AXIS
) - x0
;
465 Real stem_y
= (dy
&& dx
? (s
->relative_coordinate (0, X_AXIS
) - x0
) / dx
* dy
: 0) + y
;
468 Direction dir
= Directional_element_interface(me
).get ();
469 Direction sdir
= Directional_element_interface (s
).get ();
475 * (thick
/ 2 + (beam_multiplicity
- 1) * interbeam_f
);
479 // huh, why not for first visible?
480 if (Staff_symbol_referencer::staff_symbol_l (s
)
481 != Staff_symbol_referencer::staff_symbol_l (last_visible_stem ()))
482 stem_y
+= Directional_element_interface (me
).get ()
483 * (beam_multiplicity
- stem_multiplicity
) * interbeam_f
;
490 Beam::check_stem_length_f (Real y
, Real dy
) const
492 Score_element
* me
= (Score_element
*)this;
495 Direction dir
= Directional_element_interface (me
).get ();
497 Link_array
<Item
> stems
=
498 Pointer_group_interface__extract_elements (me
, (Item
*)0, "stems");
500 for (int i
=0; i
< stems
.size(); i
++)
503 if (Stem::invisible_b (s
))
506 Real stem_y
= calc_stem_y_f (s
, y
, dy
);
509 Stem_info info
= Stem::calc_stem_info (s
);
511 // if (0 > info.maxy_f_ - stem_y)
512 shorten
= shorten
<? info
.maxy_f_
- stem_y
;
513 // if (0 < info.miny_f_ - stem_y)
514 lengthen
= lengthen
>? info
.miny_f_
- stem_y
;
517 if (lengthen
&& shorten
)
518 warning (_ ("weird beam vertical offset"));
520 /* when all stems are too short, normal stems win */
521 return dir
* ((shorten
) ? shorten
: lengthen
);
525 Hmm. At this time, beam position and slope are determined. Maybe,
526 stem directions and length should set to relative to the chord's
527 position of the beam. */
529 Beam::set_stem_length (Real y
, Real dy
)
533 Real half_space
= Staff_symbol_referencer::staff_space (me
)/2;
534 Link_array
<Item
> stems
=
535 Pointer_group_interface__extract_elements (me
, (Item
*)0, "stems");
538 for (int i
=0; i
< stems
.size (); i
++)
541 if (Stem::invisible_b (s
))
544 Real stem_y
= calc_stem_y_f (s
, y
, dy
);
546 /* caution: stem measures in staff-positions */
547 Stem::set_stemend (s
,(stem_y
+ calc_interstaff_dist (s
, me
)) / half_space
);
552 [Ross] (simplification of)
553 Set dy complying with:
555 - thick / 2 + staffline_f / 2
556 - thick + staffline_f
560 Beam::quantise_dy_f (Real dy
) const
562 Score_element
*me
= (Score_element
*)this;
564 for (SCM s
= scm_eval (ly_symbol2scm ("beam-height-quants")); s
!=SCM_EOL
; s
= gh_cdr (s
))
565 a
.push (gh_scm2double (gh_car (s
)));
570 Real staff_space
= Staff_symbol_referencer::staff_space (me
);
572 Interval iv
= quantise_iv (a
, abs (dy
)/staff_space
) * staff_space
;
573 Real q
= (abs (dy
) - iv
[SMALLER
] <= iv
[BIGGER
] - abs (dy
))
577 return q
* sign (dy
);
581 Prevent interference from stafflines and beams.
582 See Documentation/tex/fonts.doc
584 We only need to quantise the (left) y-position of the beam,
585 since dy is quantised too.
586 if extend_b then stems must *not* get shorter
589 Beam::quantise_y_f (Real y
, Real dy
, int quant_dir
)
591 int multiplicity
= get_multiplicity ();
592 Score_element
*me
= (Score_element
*)this;
594 Real staff_space
= Staff_symbol_referencer::staff_space (me
);
595 SCM quants
= scm_eval (gh_list (ly_symbol2scm ("beam-vertical-position-quants"),
596 gh_int2scm (multiplicity
),
597 gh_double2scm (dy
/staff_space
),
602 for (; quants
!= SCM_EOL
; quants
= gh_cdr (quants
))
603 a
.push (gh_scm2double (gh_car (quants
)));
608 Real up_y
= Directional_element_interface (me
).get () * y
;
609 Interval iv
= quantise_iv (a
, up_y
/staff_space
) * staff_space
;
611 Real q
= up_y
- iv
[SMALLER
] <= iv
[BIGGER
] - up_y
612 ? iv
[SMALLER
] : iv
[BIGGER
];
614 q
= iv
[(Direction
)quant_dir
];
616 return q
* Directional_element_interface (me
).get ();
620 Beam::set_beaming (Beaming_info_list
*beaming
)
622 Score_element
*me
= this;
623 Link_array
<Score_element
> stems
=
624 Pointer_group_interface__extract_elements (me
, (Score_element
*)0, "stems");
627 for (int i
=0; i
< stems
.size(); i
++)
631 if (Stem::beam_count (stems
[i
], d
) == 0)
632 Stem::set_beaming ( stems
[i
], beaming
->infos_
.elem (i
).beams_i_drul_
[d
],d
);
634 while (flip (&d
) != LEFT
);
641 beams to go with one stem.
647 Beam::stem_beams (Item
*here
, Item
*next
, Item
*prev
) const
649 Score_element
*me
= (Score_element
*)this;
650 if ((next
&& !(next
->relative_coordinate (0, X_AXIS
) > here
->relative_coordinate (0, X_AXIS
))) ||
651 (prev
&& !(prev
->relative_coordinate (0, X_AXIS
) < here
->relative_coordinate (0, X_AXIS
))))
652 programming_error ("Beams are not left-to-right");
654 Real staffline_f
= paper_l ()->get_var ("stafflinethickness");
655 int multiplicity
= get_multiplicity ();
658 Real interbeam_f
= paper_l ()->interbeam_f (multiplicity
);
659 Real thick
= gh_scm2double (get_elt_property ("beam-thickness"));
660 thick
*= paper_l ()->get_var ("staffspace");
662 Real bdy
= interbeam_f
;
663 Real stemdx
= staffline_f
;
665 Real dx
= visible_stem_count () ?
666 last_visible_stem ()->relative_coordinate (0, X_AXIS
) - first_visible_stem ()->relative_coordinate (0, X_AXIS
)
668 Real dy
= gh_scm2double (get_elt_property ("height"));
669 Real dydx
= dy
&& dx
? dy
/dx
: 0;
676 if (!Stem::first_head (here
))
678 else if (Stem::type_i (here
)== 1)
679 nw_f
= paper_l ()->get_var ("wholewidth");
680 else if (Stem::type_i (here
) == 2)
681 nw_f
= paper_l ()->get_var ("notewidth") * 0.8;
683 nw_f
= paper_l ()->get_var ("quartwidth");
686 Direction dir
= Directional_element_interface (me
).get ();
688 /* half beams extending to the left. */
691 int lhalfs
= lhalfs
= Stem::beam_count (here
,LEFT
) - Stem::beam_count (prev
,RIGHT
);
692 int lwholebeams
= Stem::beam_count (here
,LEFT
) <? Stem::beam_count (prev
,RIGHT
) ;
694 Half beam should be one note-width,
695 but let's make sure two half-beams never touch
697 Real w
= here
->relative_coordinate (0, X_AXIS
) - prev
->relative_coordinate (0, X_AXIS
);
700 if (lhalfs
) // generates warnings if not
701 a
= lookup_l ()->beam (dydx
, w
, thick
);
702 a
.translate (Offset (-w
, -w
* dydx
));
703 for (int j
= 0; j
< lhalfs
; j
++)
706 b
.translate_axis (-dir
* bdy
* (lwholebeams
+j
), Y_AXIS
);
707 leftbeams
.add_molecule (b
);
713 int rhalfs
= Stem::beam_count (here
,RIGHT
) - Stem::beam_count (next
,LEFT
);
714 int rwholebeams
= Stem::beam_count (here
,RIGHT
) <? Stem::beam_count (next
,LEFT
) ;
716 Real w
= next
->relative_coordinate (0, X_AXIS
) - here
->relative_coordinate (0, X_AXIS
);
717 Molecule a
= lookup_l ()->beam (dydx
, w
+ stemdx
, thick
);
718 a
.translate_axis( - stemdx
/2, X_AXIS
);
722 SCM gap
= get_elt_property ("beam-gap");
723 if (gh_number_p (gap
))
725 int gap_i
= gh_scm2int ( (gap
));
726 int nogap
= rwholebeams
- gap_i
;
728 for (; j
< nogap
; j
++)
731 b
.translate_axis (-dir
* bdy
* j
, Y_AXIS
);
732 rightbeams
.add_molecule (b
);
734 // TODO: notehead widths differ for different types
737 a
= lookup_l ()->beam (dydx
, w
+ stemdx
, thick
);
740 for (; j
< rwholebeams
; j
++)
743 b
.translate (Offset (Stem::invisible_b (here
) ? 0 : gap_f
, -dir
* bdy
* j
));
744 rightbeams
.add_molecule (b
);
749 a
= lookup_l ()->beam (dydx
, w
, thick
);
751 for (; j
< rwholebeams
+ rhalfs
; j
++)
754 b
.translate_axis (- dir
* bdy
* j
, Y_AXIS
);
755 rightbeams
.add_molecule (b
);
759 leftbeams
.add_molecule (rightbeams
);
762 Does beam quanting think of the asymetry of beams?
763 Refpoint is on bottom of symbol. (FIXTHAT) --hwn.
768 MAKE_SCHEME_CALLBACK(Beam
,brew_molecule
);
770 Beam::brew_molecule (SCM smob
)
772 Score_element
* beam
= unsmob_element (smob
);
773 Beam
* me
=dynamic_cast<Beam
*> (beam
);
776 if (!gh_pair_p (me
->get_elt_property ("stems")))
779 Link_array
<Item
>stems
=
780 Pointer_group_interface__extract_elements ((Beam
*) me
, (Item
*) 0, "stems");
781 if (me
->visible_stem_count ())
783 x0
= me
->first_visible_stem ()->relative_coordinate (0, X_AXIS
);
784 dx
= me
->last_visible_stem ()->relative_coordinate (0, X_AXIS
) - x0
;
788 x0
= stems
[0]->relative_coordinate (0, X_AXIS
);
789 dx
= stems
.top()->relative_coordinate (0, X_AXIS
) - x0
;
793 Real dy
= gh_scm2double (me
->get_elt_property ("height"));
794 Real dydx
= dy
&& dx
? dy
/dx
: 0;
795 Real y
= gh_scm2double (me
->get_elt_property ("y-position"));
798 for (int j
=0; j
<stems
.size (); j
++)
801 Item
* prev
= (j
> 0)? stems
[j
-1] : 0;
802 Item
* next
= (j
< stems
.size()-1) ? stems
[j
+1] :0;
804 Molecule sb
= me
->stem_beams (i
, next
, prev
);
805 Real x
= i
->relative_coordinate (0, X_AXIS
)-x0
;
806 sb
.translate (Offset (x
, x
* dydx
+ y
));
807 mol
.add_molecule (sb
);
809 mol
.translate_axis (x0
810 - me
->get_bound (LEFT
)->relative_coordinate (0, X_AXIS
), X_AXIS
);
812 return mol
.create_scheme ();
816 Beam::forced_stem_count () const
818 Score_element
* me
= (Score_element
*)this;
819 Link_array
<Item
>stems
=
820 Pointer_group_interface__extract_elements ((Beam
*) me
, (Item
*) 0, "stems");
822 for (int i
=0; i
< stems
.size (); i
++)
826 if (Stem::invisible_b (s
))
829 if (((int)Stem::chord_start_f (s
))
830 && (Stem::get_direction (s
) != Stem::get_default_dir (s
)))
840 use filter and standard list functions.
843 Beam::visible_stem_count () const
845 Score_element
* me
= (Score_element
*)this;
846 Link_array
<Item
>stems
=
847 Pointer_group_interface__extract_elements (me
, (Item
*) 0, "stems");
849 for (int i
= stems
.size (); i
--;)
851 if (!Stem::invisible_b (stems
[i
]))
858 Beam::first_visible_stem() const
860 Score_element
* me
= (Score_element
*)this;
861 Link_array
<Item
>stems
=
862 Pointer_group_interface__extract_elements ((Beam
*) me
, (Item
*) 0, "stems");
864 for (int i
= 0; i
< stems
.size (); i
++)
866 if (!Stem::invisible_b (stems
[i
]))
873 Beam::last_visible_stem() const
875 Score_element
* me
= (Score_element
*)this;
876 Link_array
<Item
>stems
=
877 Pointer_group_interface__extract_elements ((Beam
*) me
, (Item
*) 0, "stems");
878 for (int i
= stems
.size (); i
--;)
880 if (!Stem::invisible_b (stems
[i
]))
889 handle rest under beam (do_post: beams are calculated now)
890 what about combination of collisions and rest under beam.
894 rest -> stem -> beam -> interpolate_y_position ()
897 Beam::rest_collision_callback (Score_element
*rest
, Axis a
)
899 assert (a
== Y_AXIS
);
901 Score_element
* st
= unsmob_element (rest
->get_elt_property ("stem"));
902 Score_element
* stem
= st
;
905 Beam
* beam
= dynamic_cast<Beam
*> (unsmob_element (stem
->get_elt_property ("beam")));
906 if (!beam
|| !beam
->visible_stem_count ())
909 // make callback for rest from this.
914 // todo: make sure this calced already.
915 SCM s
= beam
->get_elt_property ("height");
917 beam_dy
= gh_scm2double (s
);
919 s
= beam
->get_elt_property ("y-position");
921 beam_y
= gh_scm2double (s
);
923 Real x0
= beam
->first_visible_stem()->relative_coordinate (0, X_AXIS
);
924 Real dx
= beam
->last_visible_stem()->relative_coordinate (0, X_AXIS
) - x0
;
925 Real dydx
= beam_dy
&& dx
? beam_dy
/dx
: 0;
927 Direction d
= Stem::get_direction (stem
);
928 Real beamy
= (stem
->relative_coordinate (0, X_AXIS
) - x0
) * dydx
+ beam_y
;
930 Real staff_space
= Staff_symbol_referencer::staff_space (rest
);
931 Real rest_dim
= rest
->extent (Y_AXIS
)[d
]*2.0 / staff_space
;
934 = gh_scm2double (rest
->get_elt_property ("minimum-beam-collision-distance"));
936 minimum_dist
+ -d
* (beamy
- rest_dim
) >? 0;
938 int stafflines
= Staff_symbol_referencer::line_count (rest
);
940 // move discretely by half spaces.
941 int discrete_dist
= int (ceil (dist
));
943 // move by whole spaces inside the staff.
944 if (discrete_dist
< stafflines
+1)
945 discrete_dist
= int (ceil (discrete_dist
/ 2.0)* 2.0);
947 return (-d
* discrete_dist
);