X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=lily%2Ftie.cc;h=b96a815dfa3b6a4df8b40d7dcc5f3564d0847976;hb=a6193f6f613e0b2ff519b804d28f99fcd6ec9b92;hp=80170cf0b3c27e2af386d6a3f6a8af8c78675eff;hpb=04f01c7e890bd4f1b358378e5911fb7c117c3802;p=lilypond.git diff --git a/lily/tie.cc b/lily/tie.cc index 80170cf0b3..b96a815dfa 100644 --- a/lily/tie.cc +++ b/lily/tie.cc @@ -3,92 +3,260 @@ source file of the GNU LilyPond music typesetter - (c) 1997 Han-Wen Nienhuys + (c) 1997--2000 Han-Wen Nienhuys */ +#include +#include "lookup.hh" #include "paper-def.hh" #include "tie.hh" #include "note-head.hh" -#include "p-col.hh" - +#include "bezier.hh" +#include "paper-column.hh" +#include "debug.hh" +#include "staff-symbol-referencer.hh" +#include "directional-element-interface.hh" +#include "molecule.hh" +#include "bezier-bow.hh" +#include "stem.hh" void -Tie::set_head(int x_pos, Note_head * head_l) +Tie::set_head (Direction d, Item * head_l) { - if (x_pos >0) { - assert(!right_head_l_); - right_head_l_ = head_l; - } else { - assert(!left_head_l_); - left_head_l_ = head_l; - } - add_dependency(head_l); + assert (!head (d)); + index_set_cell (get_elt_property ("heads"), d, head_l->self_scm_); + + set_bounds (d, head_l); + add_dependency (head_l); } Tie::Tie() { - right_head_l_ =0; - left_head_l_ =0; - same_pitch_b_ =false; + set_elt_property ("heads", gh_cons (SCM_EOL, SCM_EOL)); + dy_f_drul_[LEFT] = dy_f_drul_[RIGHT] = 0.0; + dx_f_drul_[LEFT] = dx_f_drul_[RIGHT] = 0.0; + } -void -Tie::set_default_dir() +Note_head* +Tie::head (Direction d) const +{ + SCM c = get_elt_property ("heads"); + c = index_cell (c, d); + + return dynamic_cast (unsmob_element (c)); +} + +Real +Tie::position_f () const { - int m= (left_head_l_->position_i_ + right_head_l_->position_i_) /2 ; - dir_i_ = (m < 5)? -1:1; // ugh + return head (LEFT) + ? staff_symbol_referencer (head (LEFT)).position_f () + : staff_symbol_referencer (head (RIGHT)).position_f () ; +} + + +/* + ugh: direction of the Tie is more complicated. See [Ross] p136 and further + */ +Direction +Tie::get_default_dir () const +{ + Stem * sl = head(LEFT) ? head (LEFT)->stem_l () :0; + Stem * sr = head(RIGHT) ? head (RIGHT)->stem_l () :0; + + if (sl && directional_element (sl).get () == UP + && sr && directional_element (sr).get () == UP) + return DOWN; + else + return UP; } - void Tie::do_add_processing() { - assert(left_head_l_ && right_head_l_); - left_col_l_ = left_head_l_ -> pcol_l_; - right_col_l_ = right_head_l_ -> pcol_l_; + if (!(head (LEFT) && head (RIGHT))) + warning (_ ("lonely tie")); + + Direction d = LEFT; + Drul_array new_head_drul; + new_head_drul[LEFT] = head(LEFT); + new_head_drul[RIGHT] = head(RIGHT); + do { + if (!head (d)) + new_head_drul[d] = head((Direction)-d); + } while (flip(&d) != LEFT); + + index_set_cell (get_elt_property ("heads"), LEFT, new_head_drul[LEFT]->self_scm_ ); + index_set_cell (get_elt_property ("heads"), RIGHT, new_head_drul[RIGHT]->self_scm_ ); } -/** - This is already getting hairy. Should use Note_head *heads[2] - */ void Tie::do_post_processing() { - assert(left_head_l_ || right_head_l_); - left_pos_i_ = (left_head_l_)? - left_head_l_->position_i_ : right_head_l_->position_i_; - right_pos_i_ = (right_head_l_) ? - right_head_l_->position_i_ : left_head_l_->position_i_; + if (!head (LEFT) && !head (RIGHT)) + { + programming_error ("Tie without heads."); + set_elt_property ("transparent", SCM_BOOL_T); + set_empty (X_AXIS); + set_empty (Y_AXIS); + return; + } + + if (!directional_element (this).get ()) + directional_element (this).set (get_default_dir ()); + + Real staff_space = paper_l ()->get_var ("interline"); + Real half_staff_space = staff_space / 2; + Real x_gap_f = paper_l ()->get_var ("tie_x_gap"); + Real y_gap_f = paper_l ()->get_var ("tie_y_gap"); + + /* + Slur and tie placement [OSU] + + Ties: + + * x = inner vertical tangent - d * gap + + */ + + + /* + OSU: not different for outer notes, so why all this code? + ie, can we drop this, or should it be made switchable. + */ + if (head (LEFT)) + dx_f_drul_[LEFT] = head (LEFT)->extent (X_AXIS).length (); + else + dx_f_drul_[LEFT] = get_broken_left_end_align (); + dx_f_drul_[LEFT] += x_gap_f; + dx_f_drul_[RIGHT] -= x_gap_f; + + /* + Slur and tie placement [OSU] -- check this + + Ties: + + * y = dx < 5ss: horizontal tangent + y = dx >= 5ss: y next interline - d * 0.25 ss + + which probably means that OSU assumes that + + dy <= 5 dx + + for smal slurs + */ + + + Real ypos = position_f (); + + Real y_f = half_staff_space * ypos; + int ypos_i = int (ypos); - if ( right_head_l_ && right_head_l_->extremal_i_) { - right_pos_i_ += 2*dir_i_; - right_dx_f_ -= 0.25; - } else - right_dx_f_ -= 0.5; - - if (left_head_l_ && left_head_l_->extremal_i_) { - left_pos_i_ += 2*dir_i_; - left_dx_f_ += 0.25; - } else - left_dx_f_ += 0.5; - - if (!right_head_l_) - right_pos_i_ = left_pos_i_; - if (! left_head_l_) - left_pos_i_ = right_pos_i_; + Real dx_f = extent (X_AXIS).length () + dx_f_drul_[RIGHT] - dx_f_drul_[LEFT]; + Direction dir = directional_element (this).get(); + if (dx_f < paper_l ()->get_var ("tie_staffspace_length")) + { + if (abs (ypos_i) % 2) + y_f += dir * half_staff_space; + y_f += dir * y_gap_f; + } + else + { + if (! (abs (ypos_i) % 2)) + y_f += dir * half_staff_space; + y_f += dir * half_staff_space; + y_f -= dir * y_gap_f; + } + + dy_f_drul_[LEFT] = dy_f_drul_[RIGHT] = y_f; } -void -Tie::do_substitute_dependency(Score_elem*o, Score_elem*n) +Array +Tie::get_rods () const +{ + Array a; + Rod r; + r.item_l_drul_ = spanned_drul_; + r.distance_f_ = paper_l ()->get_var ("tie_x_minimum"); + a.push (r); + return a; +} + + + + +Molecule* +Tie::do_brew_molecule_p () const +{ + Real thick = paper_l ()->get_var ("tie_thickness"); + Bezier one = get_curve (); + + Molecule a; + SCM d = get_elt_property ("dashed"); + if (gh_number_p (d)) + a = lookup_l ()->dashed_slur (one, thick, gh_scm2int (d)); + else + a = lookup_l ()->slur (one, directional_element (this).get () * thick, thick); + + return new Molecule (a); +} + + + +Bezier +Tie::get_curve () const +{ + Direction d (directional_element (this).get ()); + Bezier_bow b (get_encompass_offset_arr (), d); + + b.ratio_ = paper_l ()->get_var ("slur_ratio"); + b.height_limit_ = paper_l ()->get_var ("slur_height_limit"); + b.rc_factor_ = paper_l ()->get_var ("slur_rc_factor"); + + b.calculate (); + Bezier c (b.get_curve ()); + + /* should do this for slurs as well. */ + Array horizontal (c.solve_derivative (Offset (1,0))); + + if (horizontal.size ()) + { + /* + ugh. Doesnt work for non-horizontal curves. + */ + Real space = staff_symbol_referencer (this).staff_space (); + Real y = c.curve_point (horizontal[0])[Y_AXIS]; + + Real ry = rint (y/space) * space; + Real diff = ry - y; + Real newy = y; + if (fabs (diff) < paper_l ()->get_var ("tie_staffline_clearance")) + { + newy = ry - 0.5 * space * sign (diff) ; + } + + Real y0 = c.control_ [0][Y_AXIS]; + c.control_[2][Y_AXIS] = + c.control_[1][Y_AXIS] = + (c.control_[1][Y_AXIS] - y0) * ((newy - y0) / (y - y0)) + y0; + } + else + programming_error ("Tie is nowhere horizontal"); + return c; +} + +Array +Tie::get_encompass_offset_arr () const { - Note_head *new_l =n?(Note_head*)n->item():0; - if (o->item() == left_head_l_) - left_head_l_ = new_l; - else if (o->item() == right_head_l_) - right_head_l_ = new_l; + Array offset_arr; + offset_arr.push (Offset (dx_f_drul_[LEFT], dy_f_drul_[LEFT])); + offset_arr.push (Offset (spanner_length () + dx_f_drul_[RIGHT], + dy_f_drul_[RIGHT])); + + return offset_arr; } -IMPLEMENT_STATIC_NAME(Tie);