X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=lily%2Ftie.cc;h=0f7f0830cefac107bdf7951194c0ccda7457e815;hb=05eb1cca1ff8c27bf2e0de35a28042995570390a;hp=403b991a3261d9b19a14df49d872fb6c0606ecff;hpb=c802622f935af83bb791ded58056428d6be31d0a;p=lilypond.git diff --git a/lily/tie.cc b/lily/tie.cc index 403b991a32..0f7f0830ce 100644 --- a/lily/tie.cc +++ b/lily/tie.cc @@ -3,7 +3,7 @@ source file of the GNU LilyPond music typesetter - (c) 1997--2000 Han-Wen Nienhuys + (c) 1997--2002 Han-Wen Nienhuys */ #include @@ -37,39 +37,33 @@ void -Tie::set_head (Score_element*me,Direction d, Item * head_l) +Tie::set_head (Grob*me,Direction d, Item * head_l) { assert (!head (me,d)); - index_set_cell (me->get_elt_property ("heads"), d, head_l->self_scm ()); + index_set_cell (me->get_grob_property ("heads"), d, head_l->self_scm ()); dynamic_cast (me)->set_bound (d, head_l); me->add_dependency (head_l); } void -Tie::set_interface (Score_element*me) +Tie::set_interface (Grob*me) { - me->set_elt_property ("heads", gh_cons (SCM_EOL, SCM_EOL)); - me->set_interface (ly_symbol2scm ("tie-interface")); + me->set_grob_property ("heads", gh_cons (SCM_EOL, SCM_EOL)); } -bool -Tie::has_interface (Score_element*me) -{ - return me->has_interface (ly_symbol2scm ("tie-interface")); -} -Score_element* -Tie::head (Score_element*me, Direction d) +Grob* +Tie::head (Grob*me, Direction d) { - SCM c = me->get_elt_property ("heads"); + SCM c = me->get_grob_property ("heads"); c = index_cell (c, d); - return unsmob_element (c); + return unsmob_grob (c); } Real -Tie::position_f (Score_element*me) +Tie::position_f (Grob*me) { Direction d = head (me,LEFT) ? LEFT:RIGHT; return Staff_symbol_referencer::position_f (head (me,d)); @@ -85,10 +79,10 @@ Tie::position_f (Score_element*me) further). */ Direction -Tie::get_default_dir (Score_element*me) +Tie::get_default_dir (Grob*me) { - Item * sl = head(me,LEFT) ? Rhythmic_head::stem_l (head (me,LEFT)) :0; - Item * sr = head(me,RIGHT) ? Rhythmic_head::stem_l (head (me,RIGHT)) :0; + Item * sl = head (me,LEFT) ? Rhythmic_head::stem_l (head (me,LEFT)) :0; + Item * sr = head (me,RIGHT) ? Rhythmic_head::stem_l (head (me,RIGHT)) :0; if (sl && sr) { @@ -110,11 +104,11 @@ Tie::get_default_dir (Score_element*me) SCM Tie::get_control_points (SCM smob) { - Spanner*me = dynamic_cast (unsmob_element (smob)); + Spanner*me = unsmob_spanner (smob); Direction headdir = CENTER; if (head (me,LEFT)) headdir = LEFT; - else if (head(me,RIGHT)) + else if (head (me,RIGHT)) headdir = RIGHT; else { @@ -122,39 +116,49 @@ Tie::get_control_points (SCM smob) me->suicide (); return SCM_UNSPECIFIED; } + if (!Directional_element_interface::get (me)) Directional_element_interface::set (me, Tie::get_default_dir (me)); + Direction dir = Directional_element_interface::get (me); Real staff_space = Staff_symbol_referencer::staff_space (me); - Real x_gap_f = gh_scm2double (me->get_elt_property ("x-gap")); + Real x_gap_f = gh_scm2double (me->get_grob_property ("x-gap")); - Score_element* l = me->get_bound (LEFT); - Score_element* r = me->get_bound (RIGHT); + Grob* l = me->get_bound (LEFT); + Grob* r = me->get_bound (RIGHT); - Score_element* commonx = me->common_refpoint (l, X_AXIS); + Grob* commonx = me->common_refpoint (l, X_AXIS); commonx = me->common_refpoint (r, X_AXIS); Real left_x; /* - this is a kludge: the tie has to be long enough to be - visible, but should not go through key sigs. - - (please fixme) + the tie has to be long enough to be visible, but should not go + through key sigs. In the 1.5 series the pref.matter - note + distance is fixed , so this won't be a problem anymore. */ - Real lambda = 0.5; + Real lambda = 0.9; - if (Note_head::has_interface (me->get_bound (LEFT))) - left_x = l->extent (l, X_AXIS)[RIGHT] + x_gap_f; + if (Note_head::has_interface (l)) + { + Real where = RIGHT; + + /* + This correction is due te the shape of the black note head. + */ + if (Rhythmic_head::duration_log (l) == 2) + where += dir* 0.2; + left_x = l->extent (l, X_AXIS).linear_combination (where) + + x_gap_f; + } else left_x = l->extent (l, X_AXIS).linear_combination (lambda); Real width; - if (Note_head::has_interface (me->get_bound (LEFT)) - && Note_head::has_interface (me->get_bound (RIGHT))) + if (Note_head::has_interface (l) && Note_head::has_interface (r)) { width = + r->extent (commonx,X_AXIS)[LEFT] @@ -163,7 +167,7 @@ Tie::get_control_points (SCM smob) } else { - if (Note_head::has_interface (me->get_bound (LEFT))) + if (Note_head::has_interface (l)) width = r->relative_coordinate (commonx, X_AXIS) - l->extent (commonx, X_AXIS)[RIGHT] - 2 * x_gap_f; @@ -174,48 +178,50 @@ Tie::get_control_points (SCM smob) - 2 * x_gap_f; } - Direction dir = Directional_element_interface::get(me); - SCM details = me->get_elt_property ("details"); + + SCM details = me->get_grob_property ("details"); SCM lim // groetjes aan de chirurgendochter. = scm_assq (ly_symbol2scm ("height-limit"),details); - Real h_inf = gh_scm2double (gh_cdr (lim)) * staff_space; - Real r_0 = gh_scm2double (gh_cdr (scm_assq (ly_symbol2scm ("ratio"),details))); + Real h_inf = gh_scm2double (ly_cdr (lim)) * staff_space; + Real r_0 = gh_scm2double (ly_cdr (scm_assq (ly_symbol2scm ("ratio"),details))); Bezier b = slur_shape (width, h_inf, r_0); - Offset leave_dir = b.control_[1] - b.control_[0]; - - Score_element *hed =head (me, headdir); - Real dx = (hed->extent (hed, X_AXIS).length () + x_gap_f)/2.0; - Real max_gap = leave_dir[Y_AXIS] * dx / leave_dir[X_AXIS]; - /* - for small ties (t small) we want to start in the Y-center (so dy = 0), for - large ties, the tie should appear to come from the center of the - head, so dy = max_gap - - maybe use a different formula? + I think this better, particularly for small ties. It always allows the user to move ties if + they seem in the wrong place TODO: what if 2 heads have different size. - TODO: for small ties, it is better to start over the heads - iso. next to the heads. */ - Real t = (width / staff_space - 5.0); // ugh. - Real dy = t > 0 ? max_gap * sqr (t / (1 + t)) : 0.0; - Real ypos = Tie::position_f (me) * staff_space/2 + dir * dy; + Real ypos = Tie::position_f (me) * staff_space/2 + + dir * gh_scm2double (me->get_grob_property ("y-offset"));; + /* + Make sure we don't start on a dots + */ + if (Note_head::has_interface (l) && Rhythmic_head::dots_l (l)) + { + Grob* dots = Rhythmic_head::dots_l(l); + if(fabs (staff_space * Staff_symbol_referencer::position_f (dots) /2 + - ypos) < 0.5) + { + ypos += 0.5 * dir ; + } + } + + /* todo: prevent ending / staffline collision. todo: tie / stem collision */ - b = slur_shape(width,h_inf, r_0); + b = slur_shape (width,h_inf, r_0); b.scale (1, dir); b.translate (Offset (left_x, ypos)); @@ -241,17 +247,29 @@ Tie::get_control_points (SCM smob) Real diff = ry - y; Real newy = y; - Real clear = staff_space * gh_scm2double (me->get_elt_property ("staffline-clearance")); + Real clear = staff_space * gh_scm2double (me->get_grob_property ("staffline-clearance")); - if (fabs (y) <= Staff_symbol_referencer::staff_radius (me) + if (fabs (y) <= Staff_symbol_referencer::staff_radius (me) && fabs (diff) < clear) { Real y1 = ry + clear; Real y2 = ry - clear; + + /* + ugh, we shove the 0.5 out of our sleeves. + + Any way. This test is to make sure that staffline + collision avoidance does not result in completely flat + ties. + */ + if (fabs (y1 - ypos) < 0.5) + y1 = y2; + else if (fabs (y2 - ypos) < 0.5) + y2 = y1; - newy = (fabs (y1 - y) < fabs (y2 - y)) ? y1 : y2; + newy = (fabs (y1 - y) < fabs (y2 - y)) ? y1 : y2; - // newy = ry - 0.5 * staff_space * sign (diff) ; + // newy = ry - 0.5 * staff_space * sign (diff) ; /* we don't want horizontal ties @@ -265,7 +283,7 @@ Tie::get_control_points (SCM smob) Real y0 = b.control_ [0][Y_AXIS]; b.control_[2][Y_AXIS] = b.control_[1][Y_AXIS] = - (b.control_[1][Y_AXIS] - y0) * ((newy - y0) / (y - y0)) + y0; + (b.control_[1][Y_AXIS] - y0) * ((newy - y0) / (y - y0)) + y0; } else programming_error ("Tie is nowhere horizontal"); @@ -274,54 +292,33 @@ Tie::get_control_points (SCM smob) SCM controls = SCM_EOL; for (int i= 4; i--;) - controls = gh_cons ( ly_offset2scm (b.control_[i]), controls); + controls = gh_cons (ly_offset2scm (b.control_[i]), controls); return controls; } -MAKE_SCHEME_CALLBACK(Tie,set_spacing_rods,1); -/* - TODO: set minimum distances for begin/end of line - */ -SCM -Tie::set_spacing_rods (SCM smob) -{ - Score_element*me = unsmob_element (smob); - Spanner*sp = dynamic_cast (me); - Rod r; - - r.item_l_drul_ [LEFT]=sp->get_bound (LEFT); - r.item_l_drul_ [RIGHT]=sp->get_bound (RIGHT); - - r.distance_f_ - = gh_scm2double (me->get_elt_property ("minimum-length")) - * 1.0; - r.add_to_cols (); - return SCM_UNSPECIFIED; -} - -MAKE_SCHEME_CALLBACK(Tie,brew_molecule,1); +MAKE_SCHEME_CALLBACK (Tie,brew_molecule,1); SCM Tie::brew_molecule (SCM smob) { - Score_element*me = unsmob_element (smob); + Grob*me = unsmob_grob (smob); - SCM cp = me->get_elt_property ("control-points"); + SCM cp = me->get_grob_property ("control-points"); if (cp == SCM_EOL) { cp = get_control_points (smob); - me->set_elt_property ("control-points", cp); + me->set_grob_property ("control-points", cp); } Real thick = - gh_scm2double (me->get_elt_property ("thickness")) - * me->paper_l ()->get_var ("stafflinethickness"); + gh_scm2double (me->get_grob_property ("thickness")) + * me->paper_l ()->get_var ("linethickness"); Bezier b; int i = 0; - for (SCM s= cp; s != SCM_EOL; s = gh_cdr (s)) + for (SCM s= cp; s != SCM_EOL; s = ly_cdr (s)) { - b.control_[i] = ly_scm2offset (gh_car (s)); + b.control_[i] = ly_scm2offset (ly_car (s)); i++; } @@ -331,3 +328,8 @@ Tie::brew_molecule (SCM smob) } + +ADD_INTERFACE (Tie,"tie-interface", + "A tie connecting two noteheads. +direction = Forced direction for all ties", + "y-offset staffline-clearance control-points heads details thickness x-gap direction minimum-length");