+MAKE_SCHEME_CALLBACK (Beam,brew_molecule,1);
+SCM
+Beam::brew_molecule (SCM smob)
+{
+ Grob * me =unsmob_grob (smob);
+
+ Molecule mol;
+ if (!gh_pair_p (me->get_grob_property ("stems")))
+ return SCM_EOL;
+ Real x0,dx;
+ Link_array<Item>stems =
+ Pointer_group_interface__extract_elements (me, (Item*) 0, "stems");
+ if (visible_stem_count (me))
+ {
+ // ugh -> use commonx
+ x0 = first_visible_stem (me)->relative_coordinate (0, X_AXIS);
+ dx = last_visible_stem (me)->relative_coordinate (0, X_AXIS) - x0;
+ }
+ else
+ {
+ x0 = stems[0]->relative_coordinate (0, X_AXIS);
+ dx = stems.top ()->relative_coordinate (0, X_AXIS) - x0;
+ }
+
+
+
+ /*
+ TODO: the naming of the grob properties sucks.
+ */
+ SCM dy_s = me->get_grob_property ("dy");
+ SCM y_s = me->get_grob_property ("y");
+
+
+ Real dy = gh_number_p (dy_s) ? gh_scm2double (dy_s) : 0.0;
+ Real dydx = dy && dx ? dy/dx : 0;
+ Real y = gh_number_p (y_s) ? gh_scm2double (y_s) : 0.0;
+
+
+ for (int j=0; j <stems.size (); j++)
+ {
+ Item *i = stems[j];
+ Item * prev = (j > 0)? stems[j-1] : 0;
+ Item * next = (j < stems.size ()-1) ? stems[j+1] :0;
+
+ Molecule sb = stem_beams (me, i, next, prev, dy, dydx);
+ Real x = i->relative_coordinate (0, X_AXIS)-x0;
+ sb.translate (Offset (x, x * dydx + y));
+ mol.add_molecule (sb);
+ }
+ mol.translate_axis (x0
+ - dynamic_cast<Spanner*> (me)->get_bound (LEFT)->relative_coordinate (0, X_AXIS), X_AXIS);
+
+ return mol.smobbed_copy ();
+}
+
+int
+Beam::forced_stem_count (Grob*me)
+{
+ Link_array<Item>stems =
+ Pointer_group_interface__extract_elements (me, (Item*) 0, "stems");
+ int f = 0;
+ for (int i=0; i < stems.size (); i++)
+ {
+ Item *s = stems[i];
+
+ if (Stem::invisible_b (s))
+ continue;
+
+ if (( (int)Stem::chord_start_f (s))
+ && (Stem::get_direction (s) != Stem::get_default_dir (s)))
+ f++;
+ }
+ return f;
+}
+
+
+
+
+/* TODO:
+ use filter and standard list functions.
+ */
+int
+Beam::visible_stem_count (Grob*me)
+{
+ Link_array<Item>stems =
+ Pointer_group_interface__extract_elements (me, (Item*) 0, "stems");
+ int c = 0;
+ for (int i = stems.size (); i--;)
+ {
+ if (!Stem::invisible_b (stems[i]))
+ c++;
+ }
+ return c;
+}
+
+Item*
+Beam::first_visible_stem (Grob*me)
+{
+ Link_array<Item>stems =
+ Pointer_group_interface__extract_elements (me, (Item*) 0, "stems");
+
+ for (int i = 0; i < stems.size (); i++)
+ {
+ if (!Stem::invisible_b (stems[i]))
+ return stems[i];
+ }
+ return 0;
+}
+
+Item*
+Beam::last_visible_stem (Grob*me)
+{
+ Link_array<Item>stems =
+ Pointer_group_interface__extract_elements (me, (Item*) 0, "stems");
+ for (int i = stems.size (); i--;)
+ {
+ if (!Stem::invisible_b (stems[i]))
+ return stems[i];
+ }
+ return 0;
+}
+
+
+/*
+ [TODO]
+ handle rest under beam (do_post: beams are calculated now)
+ what about combination of collisions and rest under beam.
+
+ Should lookup
+
+ rest -> stem -> beam -> interpolate_y_position ()
+*/
+MAKE_SCHEME_CALLBACK (Beam,rest_collision_callback,2);
+SCM
+Beam::rest_collision_callback (SCM element_smob, SCM axis)
+{
+ Grob *rest = unsmob_grob (element_smob);
+ Axis a = (Axis) gh_scm2int (axis);
+
+ assert (a == Y_AXIS);
+
+ Grob * st = unsmob_grob (rest->get_grob_property ("stem"));
+ Grob * stem = st;
+ if (!stem)
+ return gh_double2scm (0.0);
+ Grob * beam = unsmob_grob (stem->get_grob_property ("beam"));
+ if (!beam || !Beam::has_interface (beam) || !Beam::visible_stem_count (beam))
+ return gh_double2scm (0.0);
+
+ // make callback for rest from this.
+ Real beam_dy = 0;
+ Real beam_y = 0;
+
+
+ // todo: make sure this calced already.
+ SCM s = beam->get_grob_property ("dy");
+ if (gh_number_p (s))
+ beam_dy = gh_scm2double (s);
+
+ s = beam->get_grob_property ("y");
+ if (gh_number_p (s))
+ beam_y = gh_scm2double (s);
+
+ // ugh -> use commonx
+ Real x0 = first_visible_stem (beam)->relative_coordinate (0, X_AXIS);
+ Real dx = last_visible_stem (beam)->relative_coordinate (0, X_AXIS) - x0;
+ Real dydx = beam_dy && dx ? beam_dy/dx : 0;
+
+ Direction d = Stem::get_direction (stem);
+ Real beamy = (stem->relative_coordinate (0, X_AXIS) - x0) * dydx + beam_y;
+
+ Real staff_space = Staff_symbol_referencer::staff_space (rest);
+
+
+ Real rest_dim = rest->extent (rest, Y_AXIS)[d]*2.0 / staff_space ; // refp??
+
+ Real minimum_dist
+ = gh_scm2double (rest->get_grob_property ("minimum-beam-collision-distance"));
+ Real dist =
+ minimum_dist + -d * (beamy - rest_dim) >? 0;
+
+ int stafflines = Staff_symbol_referencer::line_count (rest);
+
+ // move discretely by half spaces.
+ int discrete_dist = int (ceil (dist));
+
+ // move by whole spaces inside the staff.
+ if (discrete_dist < stafflines+1)
+ discrete_dist = int (ceil (discrete_dist / 2.0)* 2.0);
+
+ return gh_double2scm (-d * discrete_dist);
+}
+
+
+bool
+Beam::has_interface (Grob*me)
+{
+ return me->has_interface (ly_symbol2scm ("beam-interface"));
+}
+