X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=lily%2Fline-spanner.cc;h=e7e59d525948f9fc7186aa8f3eff8dbceded1dcc;hb=05fabaaf86fd44f9bd903f282bb98d343a991e40;hp=391e73f8512ce2dfb70846acb7a2b4e27cd12fa1;hpb=75f8a001fe30f30fa2d32a961218d0f1cdbeeb7e;p=lilypond.git diff --git a/lily/line-spanner.cc b/lily/line-spanner.cc index 391e73f851..e7e59d5259 100644 --- a/lily/line-spanner.cc +++ b/lily/line-spanner.cc @@ -3,9 +3,11 @@ source file of the GNU LilyPond music typesetter - (c) 2000--2001 Jan Nieuwenhuizen + (c) 2000--2004 Jan Nieuwenhuizen */ +#include + #include "molecule.hh" #include "item.hh" #include "spanner.hh" @@ -14,145 +16,151 @@ #include "paper-column.hh" #include "staff-symbol-referencer.hh" #include "font-interface.hh" +#include "warn.hh" +#include "align-interface.hh" +#include "lookup.hh" +#include "line-interface.hh" -#include - -SCM -Line_spanner::line_atom (Grob* me, Real dx, Real dy) +Molecule +zigzag_molecule (Grob *me, + Offset from, + Offset to) { - SCM type = me->get_grob_property ("type"); - Real staff_space = Staff_symbol_referencer::staff_space (me); - Real thick = me->paper_l ()->get_var ("stafflinethickness"); + Offset dz = to -from; + Real dx = dz[X_AXIS]; + Real dy = dz[Y_AXIS]; - SCM s = me->get_grob_property ("line-thickness"); - if (gh_number_p (s)) - thick *= gh_scm2double (s); + Real thick = Staff_symbol_referencer::line_thickness (me); + thick *= robust_scm2double (me->get_grob_property ("thickness"), 1.0); // todo: staff sym referencer? - // maybe these should be in line-thickness? - Real length = staff_space; - s = me->get_grob_property ("dash-length"); - if (gh_number_p (s)) - length = gh_scm2double (s) * staff_space; - - Real period = 2 * length + thick; - s = me->get_grob_property ("dash-period"); - if (gh_number_p (s)) - period = gh_scm2double (s) * staff_space; - - if (type == ly_symbol2scm ("dotted-line")) - length = thick; - - if (type == ly_symbol2scm ("line")) - length = period + thick; - - Real on = length - thick; - Real off = period - on; + Real staff_space = Staff_symbol_referencer::staff_space (me); - SCM list = scm_list_n (ly_symbol2scm ("dashed-line"), + double w = robust_scm2double (me->get_grob_property ("zigzag-width"), 1)*staff_space; + double l = robust_scm2double ( me->get_grob_property ("zigzag-length"), 1)* w; + double h = l>w/2 ? sqrt(l*l-w*w/4) : 0; + + SCM list = scm_list_n (ly_symbol2scm ("zigzag-line"), + gh_bool2scm (true), + gh_double2scm (w), + gh_double2scm (h), gh_double2scm (thick), - gh_double2scm (on), - gh_double2scm (off), gh_double2scm (dx), gh_double2scm (dy), SCM_UNDEFINED); + Box b; + b.add_point (Offset (0,0)); + b.add_point (dz); + b[X_AXIS].widen (thick/2); + b[Y_AXIS].widen (thick/2); + + return Molecule (b, list); +} + +MAKE_SCHEME_CALLBACK(Line_spanner, after_line_breaking, 1); +SCM +Line_spanner::after_line_breaking (SCM g) +{ + Grob *me = unsmob_grob (g); + Spanner*sp = dynamic_cast (me); - return list; + /* + We remove the line at the start of the line. For piano voice + indicators, it makes no sense to have them at the start of the + line. + + I'm not sure what the official rules for glissandi are, but + usually the 2nd note of the glissando is "exact", so when playing + from the start of the line, there is no need to glide. + + From a typographical p.o.v. this makes sense, since the amount of + space left of a note at the start of a line is very small. + + --hwn. + + */ + if (sp->get_bound (LEFT)->break_status_dir() + && !sp->get_bound (RIGHT)->break_status_dir()) + { + /* + Can't do suicide, since this mucks up finding the trend. + */ + me->set_grob_property ("print-function", SCM_EOL); + + } + return SCM_EOL; } + Molecule -Line_spanner::line_molecule (Grob* me, Real dx, Real dy) +Line_spanner::line_molecule (Grob *me, + Offset from, + Offset to) { - Molecule mol; - SCM type = me->get_grob_property ("type"); + Offset dz = to -from ; + SCM type = me->get_grob_property ("style"); if (gh_symbol_p (type) && (type == ly_symbol2scm ("line") || type == ly_symbol2scm ("dashed-line") || type == ly_symbol2scm ("dotted-line") - || (type == ly_symbol2scm ("trill") && dy != 0))) + || type == ly_symbol2scm ("zigzag") + || (type == ly_symbol2scm ("trill") && dz[Y_AXIS] != 0))) { - Box b (Interval (0, dx), Interval (0, dy)); - mol = Molecule (b, line_atom (me, dx, dy)); + return (type == ly_symbol2scm ("zigzag")) + ? zigzag_molecule (me, from, to) + : Line_interface::line (me, from, to); } else if (gh_symbol_p (type) && type == ly_symbol2scm ("trill")) { SCM alist_chain = Font_interface::font_alist_chain (me); - SCM style_chain = scm_list_n (gh_cons (ly_symbol2scm ("font-family"), - ly_symbol2scm ("music")), - SCM_UNDEFINED); + SCM style_alist = scm_list_n (gh_cons (ly_symbol2scm ("font-family"), + ly_symbol2scm ("music")), + SCM_UNDEFINED); - Font_metric *fm = Font_interface::get_font (me, - scm_list_n (style_chain, - alist_chain, - SCM_UNDEFINED)); + Font_metric *fm = select_font (me->get_paper (), + gh_cons (style_alist, + alist_chain)); Molecule m = fm->find_by_name ("scripts-trill-element"); + Molecule mol; + do - mol.add_at_edge (X_AXIS, RIGHT, m, 0); + mol.add_at_edge (X_AXIS, RIGHT, m, 0,0); while (m.extent (X_AXIS).length () && mol.extent (X_AXIS).length () - + m.extent (X_AXIS).length () < dx); + + m.extent (X_AXIS).length () < dz[X_AXIS]); /* FIXME: should center element on x/y */ mol.translate_axis (m.extent (X_AXIS).length () / 2, X_AXIS); mol.translate_axis (-(mol.extent (Y_AXIS)[DOWN] - + mol.extent (Y_AXIS).length ())/2, Y_AXIS); - } - return mol; -} + + mol.extent (Y_AXIS).length ())/2, Y_AXIS); -Offset -Line_spanner::get_broken_offset (Grob *me, Direction dir) -{ - Spanner *spanner = dynamic_cast (me); - Item* bound = spanner->get_bound (dir); - - if (!bound->break_status_dir ()) - { - Grob *common[] = { - bound->common_refpoint (Staff_symbol_referencer::staff_symbol_l (me), - X_AXIS), - bound->common_refpoint (Staff_symbol_referencer::staff_symbol_l (me), - Y_AXIS) - }; - - return Offset (abs (bound->extent (common[X_AXIS], X_AXIS)[-dir]), - bound->extent (common[Y_AXIS], Y_AXIS).center ()); + mol.translate (from); + return mol; } - return Offset (); + return Molecule(); } -Offset -Line_spanner::broken_trend_offset (Grob *me, Direction dir) +/* + Find a common Y parent, which --if found-- should be the + fixed-distance alignment. + */ +Grob * +line_spanner_common_parent (Grob *me) { - /* A broken line-spaner should maintain the same vertical trend - the unbroken line-spanner would have had. - From slur */ - Offset o; - if (Spanner *mother = dynamic_cast (me->original_l_)) + Grob * common = find_fixed_alignment_parent (me); + if (!common) { - for (int i = dir == LEFT ? 0 : mother->broken_into_l_arr_.size () - 1; - dir == LEFT ? i < mother->broken_into_l_arr_.size () : i > 0; - dir == LEFT ? i++ : i--) - { - if (mother->broken_into_l_arr_[i - dir] == me) - { - Grob *neighbour = mother->broken_into_l_arr_[i]; - Offset neighbour_o = get_broken_offset (neighbour, dir); - Offset me_o = get_broken_offset (me, -dir); - // Hmm, why not return me_o[X], but recalc in brew_mol? - o = Offset (0, - (neighbour_o[Y_AXIS]*me_o[X_AXIS] - - me_o[Y_AXIS]*neighbour_o[X_AXIS]) * dir / - (me_o[X_AXIS] + neighbour_o[X_AXIS])); - break; - } - } + common = Staff_symbol_referencer::get_staff_symbol (me); + if (common) + common = common->get_parent (Y_AXIS); + else + common = me->get_parent (Y_AXIS); } - return o; -} + return common; +} /* Warning: this thing is a cross-staff object, so it should have empty Y-dimensions. @@ -163,89 +171,129 @@ Line_spanner::broken_trend_offset (Grob *me, Direction dir) */ -MAKE_SCHEME_CALLBACK (Line_spanner, brew_molecule, 1); + +MAKE_SCHEME_CALLBACK (Line_spanner, print, 1); SCM -Line_spanner::brew_molecule (SCM smob) +Line_spanner::print (SCM smob) { - Grob *me= unsmob_grob (smob); - - Spanner *spanner = dynamic_cast (me); - Item* bound_drul[] = { - spanner->get_bound (LEFT), - 0, - spanner->get_bound (RIGHT) - }; - - Item** bound = bound_drul + 1; + Spanner *me = dynamic_cast (unsmob_grob (smob)); - Grob *common[] = { 0, 0 }; - for (Axis a = X_AXIS; a < NO_AXES; a = Axis (a + 1)) - { - common[a] = bound[LEFT]->common_refpoint (bound[RIGHT], a); - - if (!common[a]) - return SCM_EOL; - } + Drul_array bound (me->get_bound (LEFT), + me->get_bound (RIGHT)); - Real gap = gh_scm2double (me->get_grob_property ("gap")); - Real dist; /*distance between points */ + + Real gap = robust_scm2double (me->get_grob_property ("gap"), 0.0); Offset ofxy (gap, 0); /*offset from start point to start of line*/ Offset dxy ; Offset my_off; Offset his_off; - - if (bound[LEFT]->break_status_dir () || bound[RIGHT]->break_status_dir ()) - /* across line break */ - { - Direction broken = bound[LEFT]->break_status_dir () ? LEFT : RIGHT; - dxy[X_AXIS] = bound[RIGHT]->extent (common[X_AXIS], X_AXIS)[LEFT] - - bound[LEFT]->extent (common[X_AXIS], X_AXIS)[RIGHT]; - - dxy += broken_trend_offset (me, broken); - dxy[X_AXIS] -= 1 * gap; + if (bound[RIGHT]->break_status_dir()) + { + if (bound[LEFT]->break_status_dir ()) + { + programming_error ("line-spanner with two broken ends. Farewell sweet world."); - my_off = Offset (0, - me->relative_coordinate (common[Y_AXIS], Y_AXIS)); + me->suicide(); + return SCM_EOL; + } - his_off = Offset (0, - bound[-broken]->relative_coordinate (common[Y_AXIS], - Y_AXIS)); + /* + This is hairy. For the normal case, we simply find common + parents, and draw a line between the bounds. When two note + heads are on different lines, there is no common parent + anymore. We have to find the piano-staff object. + */ + + int k = broken_spanner_index (me); + Spanner *parent_sp = dynamic_cast (me->original_); + Spanner *next_sp = parent_sp->broken_intos_ [k+1]; + Item *next_bound = next_sp->get_bound (RIGHT); - if (broken == LEFT) + if (next_bound->break_status_dir ()) { - my_off[Y_AXIS] += dxy[Y_AXIS]; + programming_error ("no note heads for the line spanner on next line?" + " Confused."); + me->suicide(); + return SCM_EOL; } + + Grob *commonx = bound[LEFT]->common_refpoint (bound[RIGHT], X_AXIS); + commonx = me->common_refpoint (commonx, X_AXIS); + + Grob *next_common_y = line_spanner_common_parent (next_bound); + Grob *this_common_y = line_spanner_common_parent (bound[LEFT]); + + Grob *all_common_y = me->common_refpoint (this_common_y, Y_AXIS); + + Interval next_ext = next_bound->extent (next_common_y, Y_AXIS); + Interval this_ext = bound[LEFT]->extent (this_common_y, Y_AXIS); + + Real yoff = this_common_y->relative_coordinate (all_common_y, Y_AXIS); + + Offset p1 (bound[LEFT]->extent (commonx, X_AXIS)[RIGHT], + this_ext.center () + yoff); + Offset p2 (bound[RIGHT]->extent (commonx, X_AXIS)[LEFT], + next_ext.center () + yoff); + + Offset dz (p2 -p1); + Real len = dz.length (); + + Offset dir = dz *(1/ len); + dz = (dz.length () - 2*gap) *dir; + + + Molecule l (line_molecule (me, Offset(0, 0), dz)); + + l.translate (dir * gap + p1 + - Offset (me->relative_coordinate (commonx, X_AXIS), + me->relative_coordinate (all_common_y, Y_AXIS))); + + return l.smobbed_copy (); } else { - Real off = gap + ((bound[LEFT]->extent (bound[LEFT], X_AXIS).length ()*3)/4); // distance from center to start of line - dxy[X_AXIS] = bound[RIGHT]->extent (common[X_AXIS], X_AXIS).center () - - bound[LEFT]->extent (common[X_AXIS], X_AXIS).center (); - dxy[Y_AXIS] = bound[RIGHT]->extent (common[Y_AXIS], Y_AXIS).center () - - bound[LEFT]->extent (common[Y_AXIS], Y_AXIS).center (); - - dist = sqrt (dxy[X_AXIS]*dxy[X_AXIS]+dxy[Y_AXIS]*dxy[Y_AXIS]); - ofxy = dxy* (off/dist); - dxy -= 2*ofxy; + Grob *common[] = { me, me }; + for (int a = X_AXIS; a < NO_AXES; a++) + { + common[a] = me->common_refpoint (bound[RIGHT], Axis (a)); + common[a] = common[a]->common_refpoint (bound[LEFT], Axis (a)); + } - my_off = Offset (me->relative_coordinate (common[X_AXIS], X_AXIS), - me->relative_coordinate (common[Y_AXIS], Y_AXIS)); - - his_off = Offset (bound[LEFT]->relative_coordinate (common[X_AXIS], - X_AXIS), - bound[LEFT]->relative_coordinate (common[Y_AXIS], - Y_AXIS)); - - } + // distance from center to start of line + Real off = gap + ((bound[LEFT]->extent (bound[LEFT], X_AXIS).length ()*3)/4); + + for (int a = X_AXIS; a < NO_AXES; a++) + { + Axis ax = (Axis)a; + dxy[ax] = + + bound[RIGHT]->extent (common[X_AXIS], ax).center () + - bound[LEFT]->extent (common[X_AXIS], ax).center (); + + my_off[ax] =me->relative_coordinate (common[a], ax); + his_off[ax] = bound[LEFT]->relative_coordinate (common[a], ax); + + } + + ofxy = dxy * (off/dxy.length ()); + dxy -= 2*ofxy; - Molecule line = line_molecule (me, dxy[X_AXIS], dxy[Y_AXIS]); - line.translate_axis (bound[LEFT]->extent (bound[LEFT], - X_AXIS).length ()/2, X_AXIS); - line.translate (ofxy - my_off + his_off); - return line.smobbed_copy (); + Molecule line = line_molecule (me, Offset (0,0),dxy); + + line.translate_axis (bound[LEFT]->extent (bound[LEFT], X_AXIS).length ()/2, X_AXIS); + line.translate (ofxy - my_off + his_off); + return line.smobbed_copy (); + } } +ADD_INTERFACE (Line_spanner, "line-spanner-interface", + "Generic line drawn between two objects, eg. for use with glissandi.\n" +"gap is measured in staff-spaces.\n" +"The property 'type is one of: line, dashed-line, trill, dotted-line or zigzag.\n" +"\n", + "gap zigzag-width zigzag-length thickness"); + +