X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=lily%2Fstem.cc;h=55b2036269b12ddfb95110d1d3709e0cef11c521;hb=1b071315c1d318e46035ec8bc0b73da55a025ae8;hp=74ea4b57fcf0f500e46353139a5b356357bd30c3;hpb=daee8243ff1c66bc714455a2d265ab02f03546ec;p=lilypond.git diff --git a/lily/stem.cc b/lily/stem.cc index 74ea4b57fc..55b2036269 100644 --- a/lily/stem.cc +++ b/lily/stem.cc @@ -1,200 +1,338 @@ +/* + stem.cc -- implement Stem + + source file of the GNU LilyPond music typesetter + + (c) 1996, 1997--1999 Han-Wen Nienhuys + + TODO: This is way too hairy +*/ + #include "stem.hh" -#include "dimen.hh" #include "debug.hh" #include "paper-def.hh" -#include "notehead.hh" +#include "note-head.hh" #include "lookup.hh" #include "molecule.hh" -#include "pcol.hh" +#include "p-col.hh" #include "misc.hh" +#include "beam.hh" +#include "rest.hh" + +void +Stem::set_direction (Direction d) +{ + if (!dir_) + warning ("Stem direction set already!"); -const int STEMLEN=7; + dir_ = d; + /* + todo + */ +} -Stem::Stem(int c) //, Moment len) +Stem::Stem () { - beams_left = 0; - beams_right = 0; - minnote = 1000; // invalid values - maxnote = -1000; - bot = top = 0; - flag = 4; - dir =0; - staff_center=c; - stemlen=0; - print_flag=true; - stem_xoffset=0; + beams_i_drul_[LEFT] = beams_i_drul_[RIGHT] = -1; + yextent_drul_[DOWN] = yextent_drul_[UP] = 0; + flag_i_ = 2; + dir_ = CENTER; + beam_l_ = 0; +} + +Interval_t +Stem::head_positions () const +{ + /* + Mysterious FreeBSD fix by John Galbraith. Somehow, the empty intervals + trigger FP exceptions on FreeBSD. Fix: do not return infinity + + */ + if (!head_l_arr_.size ()) + { + return Interval_t (100,-100); + } + + Interval_t r; + for (int i =0; i < head_l_arr_.size (); i++) + { + int p = head_l_arr_[i]->position_i_; + r[BIGGER] = r[BIGGER] >? p; + r[SMALLER] = r[SMALLER] 0 && se >= maxnote) || (se <= minnote && dir <0)) ) - warning("Weird stem size; check for narrow beams",0); - - top = (dir < 0) ? maxnote : se; - bot = (dir < 0) ? se : minnote; - flag = dir*abs(flag); +Real +Stem::stem_length_f () const +{ + return yextent_drul_[UP]-yextent_drul_[DOWN] ; } -void -Stem::add(Notehead *n) +Real +Stem::stem_begin_f () const { - assert(status < PRECALCED); - - if (n->balltype == 1) - return; - int p = n->position; - if (p < minnote) - minnote = p; - if (p > maxnote) - maxnote = p; - heads.push(n); - n->add_dependency(this); + return yextent_drul_[Direction(-dir_)]; } +Real +Stem::chord_start_f () const +{ + return head_positions()[dir_] * staff_line_leading_f ()/2.0; +} -int -Stem::get_default_dir() +Real +Stem::stem_end_f () const { - if (dir) - return dir; - Real mean = (minnote+maxnote)/2; - return (mean > staff_center) ? -1: 1; + return yextent_drul_[dir_]; } void -Stem::set_default_dir() +Stem::set_stemend (Real se) { - dir = get_default_dir(); + // todo: margins + if (dir_ && dir_ * head_positions()[dir_] >= se*dir_) + warning (_ ("weird stem size; check for narrow beams")); + + + yextent_drul_[dir_] = se; + yextent_drul_[Direction(-dir_)] = head_positions()[-dir_]; +} + +int +Stem::type_i () const +{ + return head_l_arr_[0]->balltype_i_; } void -Stem::set_default_stemlen() -{ - if (!dir) - set_default_dir(); - - int stafftop = 2*staff_center; - stemlen = STEMLEN + (maxnote - minnote); - - // uhh... how about non 5-line staffs? - if (maxnote < -2 && dir == 1){ - int t = staff_center - staff_center/2; - stemlen = t - minnote +2; - } else if (minnote > stafftop + 2 && dir == -1) { - int t = staff_center + staff_center/2; - stemlen = maxnote -t +2; +Stem::add_head (Rhythmic_head *n) +{ + n->add_dependency (this); // ? + if (Note_head *nh = dynamic_cast (n)) + { + head_l_arr_.push (nh); } + else if (Rest *r = dynamic_cast (n)) + { + rest_l_arr_.push (r); + } +} + +bool +Stem::invisible_b () const +{ + return (!head_l_arr_.size () || + head_l_arr_[0]->balltype_i_ <= 0); +} + +int +Stem::get_center_distance (Direction d) const +{ + int staff_center = 0; + int distance = d*(head_positions()[d] - staff_center); + return distance >? 0; +} + +Direction +Stem::get_default_dir () const +{ + return (get_center_distance (UP) > + get_center_distance (DOWN)) + ? DOWN + : UP; +} - assert(stemlen); +Direction +Stem::get_dir () const +{ + return dir_; } void -Stem::set_default_extents() +Stem::set_default_stemlen () { - if (minnote > maxnote) { - warning("Empty stem. Ugh!", 0); - minnote = -10; - maxnote = 20; - } + Real internote_f = staff_line_leading_f ()/2.0; + Real length_f = paper_l ()->get_var ("stem_length0") / internote_f; + Real shorten_f = paper_l ()->get_var ("forced_stem_shorten0") / internote_f; + + if (!dir_) + dir_ = get_default_dir (); + + /* + stems in unnatural (forced) direction should be shortened, + according to [Roush & Gourlay] + */ + if (((int)chord_start_f ()) + && (dir_ != get_default_dir ())) + length_f -= shorten_f; - if (!stemlen) - set_default_stemlen(); + if (flag_i_ >= 5) + length_f += 2.0; + if (flag_i_ >= 6) + length_f += 1.0; + + set_stemend ((dir_ > 0) ? head_positions()[BIGGER] + length_f: + head_positions()[SMALLER] - length_f); - set_stemend((dir< 0) ? maxnote-stemlen: minnote +stemlen); - if (dir > 0){ - stem_xoffset = paper()->note_width()-paper()->rule_thickness(); - } else - stem_xoffset = 0; + if (dir_ * stem_end_f () < 0) + set_stemend (0); } +//xxx void -Stem::set_noteheads() -{ - if(!heads.size()) - return; - heads.sort(Notehead::compare); - heads[0]->extremal = -1; - heads.top()->extremal = 1; - int parity=1; - int lastpos = heads[0]->position; - for (int i=1; i < heads.size(); i ++) { - int dy =abs(lastpos- heads[i]->position); - - if (dy <= 1) { - if (parity) - heads[i]->x_dir = (stem_xoffset>0) ? 1:-1; - parity = !parity; - } else - parity = 0; - lastpos = heads[i]->position; +Stem::set_default_extents () +{ + if (!stem_length_f ()) + set_default_stemlen (); + +} + +void +Stem::set_noteheads () +{ + if (!head_l_arr_.size ()) + return; + head_l_arr_.sort (Note_head::compare); + if (dir_ < 0) + head_l_arr_.reverse (); + + Note_head * beginhead = head_l_arr_[0]; + beginhead->set_elt_property (extremal_scm_sym, SCM_BOOL_T); + if (beginhead != head_l_arr_.top ()) + head_l_arr_.top ()->set_elt_property (extremal_scm_sym, SCM_BOOL_T); + + int parity=1; + int lastpos = beginhead->position_i_; + for (int i=1; i < head_l_arr_.size (); i ++) + { + int dy =abs (lastpos- head_l_arr_[i]->position_i_); + + if (dy <= 1) + { + if (parity) + head_l_arr_[i]->flip_around_stem (dir_); + parity = !parity; + } + else + parity = 1; + lastpos = head_l_arr_[i]->position_i_; } } void -Stem::do_pre_processing() +Stem::do_pre_processing () { - if (bot == top) - set_default_extents(); - set_noteheads(); + if (yextent_drul_[DOWN]== yextent_drul_[UP]) + set_default_extents (); + set_noteheads (); + + if (invisible_b ()) + { + set_elt_property (transparent_scm_sym, SCM_BOOL_T); + } + set_empty (invisible_b ()); } Interval -Stem::width()const +Stem::do_width () const { - if (!print_flag || abs(flag) <= 4) - return Interval(0,0); // TODO! - Paper_def*p= paper(); - Interval r(p->lookup_p_->flag(flag).dim.x); - r+= stem_xoffset; - return r; + Interval r (0, 0); + if (beam_l_ || abs (flag_i_) <= 2) + ; // TODO! + else + { + r = lookup_l ()->flag (flag_i_, dir_).dim_.x (); + r += note_delta_f (); + } + return r; } + + + +const Real ANGLE = 20* (2.0*M_PI/360.0); // ugh! + Molecule* -Stem::brew_molecule_p()const return out; -{ - assert(bot!=top); - - - Paper_def *p =paper(); - - Real dy = p->internote(); - Symbol ss =p->lookup_p_->stem(bot*dy,top*dy); - - - out = new Molecule(Atom(ss)); - - if (print_flag&&abs(flag) > 4){ - Symbol fl = p->lookup_p_->flag(flag); - Molecule m(fl); - if (flag < -4){ - out->add_bottom(m); - } else if (flag > 4) { - out->add_top(m); - } else - assert(false); +Stem::do_brew_molecule_p () const +{ + Molecule *mol_p =new Molecule; + Drul_array stem_y = yextent_drul_; + Real dy = staff_line_leading_f ()/2.0; + + Real head_wid = 0; + if (head_l_arr_.size ()) + head_wid = head_l_arr_[0]->extent (X_AXIS).length (); + stem_y[Direction(-dir_)] += dir_ * head_wid * tan(ANGLE)/(2*dy); + + if (!invisible_b ()) + { + Molecule ss =lookup_l ()->stem (stem_y[DOWN]*dy, + stem_y[UP]*dy); + mol_p->add_molecule (ss); + } + + if (!beam_l_ && abs (flag_i_) > 2) + { + Molecule fl = lookup_l ()->flag (flag_i_, dir_); + fl.translate_axis(stem_y[dir_]*dy, Y_AXIS); + mol_p->add_molecule (fl); } - out->translate(Offset(stem_xoffset,0)); + if (head_l_arr_.size()) + { + mol_p->translate_axis (note_delta_f (), X_AXIS); + } + return mol_p; } Real -Stem::hindex()const +Stem::note_delta_f () const { - return pcol_l_->hpos + stem_xoffset; // hmm. + offset_.x; + Real r=0; + if (head_l_arr_.size()) + { + Interval head_wid(0, head_l_arr_[0]->extent (X_AXIS).length ()); + Real rule_thick(paper_l ()->rule_thickness ()); + Interval stem_wid(-rule_thick/2, rule_thick/2); + if (dir_ == CENTER) + r = head_wid.center (); + else + r = head_wid[dir_] - stem_wid[dir_]; + } + return r; } +Real +Stem::hpos_f () const +{ + return note_delta_f () + Item::hpos_f (); +} +void +Stem::do_substitute_element_pointer (Score_element*o,Score_element*n) +{ + if (Note_head*h=dynamic_cast (o)) + head_l_arr_.substitute (h, dynamic_cast(n)); + if (Rest *r=dynamic_cast (o)) + rest_l_arr_.substitute (r, dynamic_cast(n)); + if (Beam* b = dynamic_cast (o)) + { + if (b == beam_l_) + beam_l_ = dynamic_cast (n); + } + Staff_symbol_referencer::do_substitute_element_pointer (o,n); +}