From: Han-Wen Nienhuys Date: Fri, 8 Oct 2004 23:39:38 +0000 (+0000) Subject: * lily/include/slur-scoring.hh (struct Slur_score_state): new file X-Git-Tag: release/2.3.21~1 X-Git-Url: https://git.donarmstrong.com/?a=commitdiff_plain;h=2ed0044bc7425734a1e44356b9afd68d46bb72e7;p=lilypond.git * lily/include/slur-scoring.hh (struct Slur_score_state): new file * lily/include/slur-configuration.hh (class Slur_configuration): new file. * lily/slur-configuration.cc: new file. move scoring functions into Slur_configuration. * lily/slur-scoring.cc (Slur_score_state): change static functions to methods of Slur_score_state. * lily/bezier-bow.cc (Message): * flower/include/interval-set.hh (Message): new file. * flower/interval-set.cc (Message): new file. --- diff --git a/ChangeLog b/ChangeLog index 68159fd1de..50dfcfe2ef 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,35 @@ +2004-10-09 Han-Wen Nienhuys + + * lily/include/slur-scoring.hh (struct Slur_score_state): new file + + * lily/include/slur-configuration.hh (class Slur_configuration): + new file. + + * lily/slur-configuration.cc: new file. move scoring functions + into Slur_configuration. + + * lily/slur-scoring.cc (Slur_score_state): change static functions + to methods of Slur_score_state. + + * lily/bezier-bow.cc (Message): + + * flower/include/interval-set.hh (Message): new file. + + * flower/interval-set.cc (Message): new file. + +2004-10-08 Han-Wen Nienhuys + + * lily/multi-measure-rest-engraver.cc (process_music): always + generate MultiMeasureRestNumbers. + + * SConstruct (txt_files): switch of make dist + + * lily/bezier-bow.cc (get_slur_indent_height): change recipe to + make sure that (indent < len / 3). This fixes progerror-max_h.ly + + * lily/multi-measure-rest-engraver.cc (process_music): make + MultiMeasureRestNumber too. + 2004-10-08 Mats Bengtsson * Documentation/user/notation.itely (Bar lines): Added a note that @@ -5,7 +37,7 @@ 2004-10-07 Han-Wen Nienhuys - * lily/include/guile-compatibility.hh: + * lily/include/guile-compatibility.hh: add file. * scm/framework-tex.scm (convert-to-dvi): use max of current extra_mem_top and 1M. diff --git a/SConstruct b/SConstruct index 6c6a032964..5b14fc2eb1 100644 --- a/SConstruct +++ b/SConstruct @@ -385,13 +385,12 @@ def configure (target, source, env): if env['fast']: # Using CCFLAGS = -I rather than CPPPATH = [ # ] speeds up SCons - print 'cpp', env['CPPPATH'] env['CCFLAGS'] += map (lambda x: '-I' + x, env['CPPPATH'][len (cpppath):]) env['CPPPATH'] = cpppath if required: -F print + print print '********************************' print 'Please install required packages' for i in required: @@ -733,36 +732,43 @@ if env['fast']\ subdirs = ['lily', 'lily/include', 'flower', 'flower/include', 'mf'] else: subdirs = flatten (cvs_dirs ('.'), []) + +src_files = reduce (lambda x, y: x + y, map (cvs_files, subdirs)) readme_files = ['AUTHORS', 'README', 'INSTALL', 'NEWS'] -foo = map (lambda x: env.TXT (x + '.txt', - os.path.join ('Documentation/topdocs', x)), - readme_files) txt_files = map (lambda x: x + '.txt', readme_files) -src_files = reduce (lambda x, y: x + y, map (cvs_files, subdirs)) -tar_base = package.name + '-' + version -tar_name = tar_base + '.tar.gz' -ball_prefix = os.path.join (outdir, tar_base) -tar_ball = os.path.join (outdir, tar_name) - -dist_files = src_files + txt_files -ball_files = map (lambda x: os.path.join (ball_prefix, x), dist_files) -map (lambda x: env.Depends (tar_ball, x), ball_files) -map (lambda x: env.Command (os.path.join (ball_prefix, x), x, - 'ln $SOURCE $TARGET'), dist_files) -tar = env.Command (tar_ball, src_files, - ['rm -f $$(find $TARGET.dir -name .sconsign)', - 'tar czf $TARGET -C $TARGET.dir %s' % tar_base,]) -env.Alias ('tar', tar) - -dist_ball = os.path.join (package.release_dir, tar_name) -env.Command (dist_ball, tar_ball, - 'if [ -e $SOURCE -a -e $TARGET ]; then rm $TARGET; fi;' \ - + 'ln $SOURCE $TARGET') -env.Depends ('dist', dist_ball) -patch_name = os.path.join (outdir, tar_base + '.diff.gz') -patch = env.PATCH (patch_name, tar_ball) -env.Depends (patch_name, dist_ball) -env.Alias ('release', patch) + + +# +# speeds up build by +- 5% +# +if 0: + foo = map (lambda x: env.TXT (x + '.txt', + os.path.join ('Documentation/topdocs', x)), + readme_files) + tar_base = package.name + '-' + version + tar_name = tar_base + '.tar.gz' + ball_prefix = os.path.join (outdir, tar_base) + tar_ball = os.path.join (outdir, tar_name) + + dist_files = src_files + txt_files + ball_files = map (lambda x: os.path.join (ball_prefix, x), dist_files) + map (lambda x: env.Depends (tar_ball, x), ball_files) + map (lambda x: env.Command (os.path.join (ball_prefix, x), x, + 'ln $SOURCE $TARGET'), dist_files) + tar = env.Command (tar_ball, src_files, + ['rm -f $$(find $TARGET.dir -name .sconsign)', + 'tar czf $TARGET -C $TARGET.dir %s' % tar_base,]) + env.Alias ('tar', tar) + + dist_ball = os.path.join (package.release_dir, tar_name) + env.Command (dist_ball, tar_ball, + 'if [ -e $SOURCE -a -e $TARGET ]; then rm $TARGET; fi;' \ + + 'ln $SOURCE $TARGET') + env.Depends ('dist', dist_ball) + patch_name = os.path.join (outdir, tar_base + '.diff.gz') + patch = env.PATCH (patch_name, tar_ball) + env.Depends (patch_name, dist_ball) + env.Alias ('release', patch) #### web web_base = os.path.join (outdir, 'web') diff --git a/VERSION b/VERSION index 65a21c169c..d4811779fb 100644 --- a/VERSION +++ b/VERSION @@ -1,6 +1,6 @@ PACKAGE_NAME=LilyPond MAJOR_VERSION=2 MINOR_VERSION=3 -PATCH_LEVEL=20 +PATCH_LEVEL=21 MY_PATCH_LEVEL= diff --git a/buildscripts/builder.py b/buildscripts/builder.py index b7dd899f9a..3a65c176e1 100644 --- a/buildscripts/builder.py +++ b/buildscripts/builder.py @@ -222,10 +222,13 @@ pfa = Builder (action = a, env.Append (BUILDERS = {'PFA': pfa}) # Specific builders -env['DIFF_PY'] = '$srcdir/stepmake/bin/package-diff.py' -a = '$PYTHON $DIFF_PY $__verbose --outdir=${TARGET.dir}' -patch = Builder (action = a, suffix = '.diff', src_suffix = '.tar.gz') -env.Append (BUILDERS = {'PATCH': patch}) + +# experiment: switch off for speed. +if 0: + env['DIFF_PY'] = '$srcdir/stepmake/bin/package-diff.py' + a = '$PYTHON $DIFF_PY $__verbose --outdir=${TARGET.dir}' + patch = Builder (action = a, suffix = '.diff', src_suffix = '.tar.gz') + env.Append (BUILDERS = {'PATCH': patch}) atvars = [ 'BASH', diff --git a/flower/include/interval-set.hh b/flower/include/interval-set.hh new file mode 100644 index 0000000000..fef00300e7 --- /dev/null +++ b/flower/include/interval-set.hh @@ -0,0 +1,32 @@ +/* + interval-set.hh -- declare Interval_set + + source file of the GNU LilyPond music typesetter + + (c) 2004 Han-Wen Nienhuys + +*/ + +#ifndef INTERVAL_SET_HH +#define INTERVAL_SET_HH + +#include "array.hh" +#include "interval.hh" + +/* + A union of intervals in the real line. + + Abysmal performance (quadratic) for large N, hopefully we don't have + that large N. In any case, this should probably be rewritten to use + a balanced tree. + */ +struct Interval_set +{ + Array allowed_regions_; + + Interval_set (); + void set_full (); + void remove_interval (Interval rm); +}; + +#endif /* INTERVAL_SET_HH */ diff --git a/flower/interval-set.cc b/flower/interval-set.cc new file mode 100644 index 0000000000..c0d3241fc9 --- /dev/null +++ b/flower/interval-set.cc @@ -0,0 +1,66 @@ +/* + interval-set.hh -- implement Interval_set + + source file of the GNU LilyPond music typesetter + + (c) 2004 Han-Wen Nienhuys + +*/ + +#include "interval-set.hh" + +/* + A union of intervals in the real line. + + Abysmal performance (quadratic) for large N, hopefully we don't have + that large N. In any case, this should probably be rewritten to use + a balanced tree. +*/ + +Interval_set::Interval_set () +{ + set_full (); +} + +void +Interval_set::set_full () +{ + allowed_regions_.clear (); + Interval s; + s.set_full (); + allowed_regions_.push (s); +} + +void +Interval_set::remove_interval (Interval rm) +{ + for (int i = 0; i < allowed_regions_.size (); ) + { + Interval s = rm; + + s.intersect (allowed_regions_[i]); + + if (!s.is_empty ()) + { + Interval before = allowed_regions_[i]; + Interval after = allowed_regions_[i]; + + before[RIGHT] = s[LEFT]; + after[LEFT] = s[RIGHT]; + + if (!before.is_empty () && before.length () > 0.0) + { + allowed_regions_.insert (before, i); + i++; + } + allowed_regions_.del (i); + if (!after.is_empty () && after.length () > 0.0) + { + allowed_regions_.insert (after, i); + i++; + } + } + else + i++; + } +} diff --git a/input/regression/new-slur.ly b/input/regression/new-slur.ly index 0127e66fdf..2c1355a72b 100644 --- a/input/regression/new-slur.ly +++ b/input/regression/new-slur.ly @@ -36,7 +36,7 @@ _( f ) _( g ) _( \stemDown g \stemNeutral ) - c,^( c'' c) + c,='^( c'' c) c,,^( c'') c,,^( c') | b='2( a4) s4 diff --git a/lily/SConscript b/lily/SConscript index 3b447239cb..663213c671 100644 --- a/lily/SConscript +++ b/lily/SConscript @@ -11,7 +11,10 @@ includes = src_glob ('include/*.hh') e = env.Copy () e.Append ( - CPPPATH = ['#/lily/include', '#/flower/include', outdir], + CPPPATH = [ + '#/lily/include', + '#/flower/include', + outdir], LEXFLAGS = ['-Cfe', '-p', '-p'], LIBS = ['flower'], ) diff --git a/lily/accidental.cc b/lily/accidental.cc index 5a7c32daae..0c62beee98 100644 --- a/lily/accidental.cc +++ b/lily/accidental.cc @@ -4,6 +4,7 @@ source file of the GNU LilyPond music typesetter (c) 2001--2004 Han-Wen Nienhuys + ofog */ #include "font-interface.hh" #include "item.hh" diff --git a/lily/beam.cc b/lily/beam.cc index b85bd91ee1..abe86359f1 100644 --- a/lily/beam.cc +++ b/lily/beam.cc @@ -28,6 +28,7 @@ Notes: #include // tanh. +#include "interval-set.hh" #include "stencil.hh" #include "directional-element-interface.hh" #include "beaming.hh" @@ -595,65 +596,6 @@ Beam::set_stem_directions (Grob *me, Direction d) } } -/* - A union of intervals in the real line. - - Abysmal performance (quadratic) for large N, hopefully we don't have - that large N. In any case, this should probably be rewritten to use - a balanced tree. - */ -struct Int_set -{ - Array allowed_regions_; - - Int_set () - { - set_full (); - } - - void set_full () - { - allowed_regions_.clear (); - Interval s; - s.set_full (); - allowed_regions_.push (s); - } - - void remove_interval (Interval rm) - { - for (int i = 0; i < allowed_regions_.size (); ) - { - Interval s = rm; - - s.intersect (allowed_regions_[i]); - - if (!s.is_empty ()) - { - Interval before = allowed_regions_[i]; - Interval after = allowed_regions_[i]; - - before[RIGHT] = s[LEFT]; - after[LEFT] = s[RIGHT]; - - if (!before.is_empty () && before.length () > 0.0) - { - allowed_regions_.insert (before, i); - i++; - } - allowed_regions_.del (i); - if (!after.is_empty () && after.length () > 0.0) - { - allowed_regions_.insert (after, i); - i++; - } - } - else - i++; - } - } -}; - - /* Only try horizontal beams for knees. No reliable detection of anything else is possible here, since we don't know funky-beaming @@ -669,7 +611,7 @@ Beam::consider_auto_knees (Grob* me) Real threshold = scm_to_double (scm); - Int_set gaps; + Interval_set gaps; gaps.set_full (); diff --git a/lily/bezier-bow.cc b/lily/bezier-bow.cc index b9f6c104bd..fa2db2c855 100644 --- a/lily/bezier-bow.cc +++ b/lily/bezier-bow.cc @@ -68,16 +68,29 @@ height slurs. For large slurs, this gives a certain hookiness at the end, so we increase the indent. - ind = G(w) + indent = G(w) - w -> 0, G(w) -> .5 h + w -> 0, G(w) -> .33 w + + + (due to derivative constraints, we cannot have indent > len/3) + + w -> inf, G(w) -> 2*h_inf + + i.e. - w -> inf, G(w) -> 2*h - eg. + G(0) = 0 , G'(0) 1/3, G(infty) = 2h_inf + solve from - G(w) = h (w/(w+h_inf) 1.5 + .5 h + G(w) = r + p/(w+q) + + yields + + G(w) = 2 h_inf - max_fraction * q^2/ (w + q) + + with q = 2 h_inf */ @@ -86,8 +99,12 @@ void get_slur_indent_height (Real *indent, Real *height, Real width, Real h_inf, Real r_0) { + Real max_fraction = 1.0 / 3.1; *height = slur_height (width, h_inf, r_0); - *indent = (width / (h_inf + width) * 1.5 + 0.5) * (*height); + + Real q = 2 * h_inf / max_fraction; + *indent = + 2 *h_inf - sqr (q) * max_fraction / (width + q); } Bezier diff --git a/lily/include/lily-proto.hh b/lily/include/lily-proto.hh index 841de441db..fd531f86ec 100644 --- a/lily/include/lily-proto.hh +++ b/lily/include/lily-proto.hh @@ -139,7 +139,8 @@ class Simple_spacer; class Simple_spacer_wrapper; class Simultaneous_music; class Simultaneous_music_iterator; -class Slur_bezier_bow; +class Slur_configuration; +class Slur_score_state; class Span_score_bar_engraver; class Spanner; class Staff_group_bar_engraver; diff --git a/lily/include/main.hh b/lily/include/main.hh index 21171a71a4..a36d29c699 100644 --- a/lily/include/main.hh +++ b/lily/include/main.hh @@ -51,4 +51,10 @@ extern Array failed_files; extern int exit_status_global; extern File_path global_path; +/* + Debugging options + */ + +#define DEBUG_SLUR_SCORING 1 + #endif /* MAIN_HH */ diff --git a/lily/include/misc.hh b/lily/include/misc.hh index 811858e4bb..c76c8a9a86 100644 --- a/lily/include/misc.hh +++ b/lily/include/misc.hh @@ -22,5 +22,14 @@ sign (int i) +inline Real +linear_interpolate (Real x, Real x1, Real x2, Real y1, Real y2) +{ + return (x2 - x) / (x2 - x1) * y1 + + (x - x1) / (x2 - x1) * y2 ; +} + + + #endif diff --git a/lily/include/slur-configuration.hh b/lily/include/slur-configuration.hh new file mode 100644 index 0000000000..0a59c053da --- /dev/null +++ b/lily/include/slur-configuration.hh @@ -0,0 +1,43 @@ +/* + slur-configuration.hh -- declare Slur_configuration + + source file of the GNU LilyPond music typesetter + + (c) 2004 Han-Wen Nienhuys + +*/ + +#ifndef SLUR_CONFIGURATION_HH +#define SLUR_CONFIGURATION_HH + +#include "drul-array.hh" +#include "bezier.hh" +#include "lily-proto.hh" +#include "parray.hh" +#include "main.hh" + +class Slur_configuration +{ +public: + Drul_array attachment_; + Real score_; + Bezier curve_; + +#if DEBUG_SLUR_SCORING + String score_card_; +#endif + + Slur_configuration (); + + void generate_curve (Slur_score_state const &state, Real r0, Real h_inf); + void score (Slur_score_state const&); + +protected: + void score_extra_encompass (Slur_score_state const&); + void score_slopes (Slur_score_state const&); + void score_edges (Slur_score_state const&); + void score_encompass (Slur_score_state const&); +}; + +#endif /* SLUR_CONFIGURATION_HH */ + diff --git a/lily/include/slur-scoring.hh b/lily/include/slur-scoring.hh new file mode 100644 index 0000000000..fc44a48dae --- /dev/null +++ b/lily/include/slur-scoring.hh @@ -0,0 +1,148 @@ +/* + slur-scoring.hh -- declare Slur_score_parameters + + source file of the GNU LilyPond music typesetter + + (c) 2004 Han-Wen Nienhuys + +*/ + +#ifndef SLUR_SCORING_HH +#define SLUR_SCORING_HH + +#include "box.hh" +#include "lily-proto.hh" +#include "parray.hh" + +struct Slur_score_parameters +{ + int region_size_; + Real head_encompass_penalty_; + Real stem_encompass_penalty_; + Real closeness_factor_; + Real edge_attraction_factor_; + Real same_slope_penalty_; + Real steeper_slope_factor_; + Real non_horizontal_penalty_; + Real max_slope_; + Real max_slope_factor_; + Real extra_object_collision_; + Real accidental_collision_; + Real free_slur_distance_; + Real free_head_distance_; + Real extra_encompass_free_distance_; + Real edge_slope_exponent_; + Real head_slur_distance_max_ratio_; + Real head_slur_distance_factor_; +}; + + + +struct Extra_collision_info +{ + Real idx_; + Box extents_; + Real penalty_; + Grob * grob_; + + Extra_collision_info (Grob *g, Real idx, Interval x, Interval y, Real p) + { + idx_ = idx; + extents_[X_AXIS] = x; + extents_[Y_AXIS] = y; + penalty_ = p; + grob_ = g; + } + Extra_collision_info () + { + idx_ = 0.0; + penalty_ = 0.; + grob_ = 0; + } +}; + + +struct Encompass_info +{ + Real x_; + Real stem_; + Real head_; + Encompass_info () + { + x_ = 0.0; + stem_ = 0.0; + head_ = 0.0; + } + Real get_point (Direction dir) const + { + Interval y; + y.add_point (stem_); + y.add_point (head_); + return y[dir]; + } +}; + +struct Bound_info +{ + Box stem_extent_; + Direction stem_dir_; + Item *bound_; + Grob *note_column_; + Grob *slur_head_; + Grob *staff_; + Grob *stem_; + Interval slur_head_extent_; + Real staff_space_; + + Bound_info () + { + stem_ = 0; + staff_ = 0; + slur_head_ = 0; + stem_dir_ = CENTER; + note_column_ = 0; + } +}; + +struct Slur_score_state +{ + Spanner *slur_; + Grob *common_[NO_AXES]; + bool valid_; + bool edge_has_beams_; + bool is_broken_; + bool has_same_beam_; + + Real musical_dy_; + Link_array columns_; + Array encompass_infos_; + Array extra_encompass_infos_; + + Direction dir_; + Slur_score_parameters parameters_; + Drul_array extremes_; + Drul_array base_attachments_; + Array *scores_; + Real staff_space_; + Real thickness_; + + Slur_score_state(); + ~Slur_score_state(); + + Bezier get_best_curve (); + void fill (Grob*); + void set_next_direction (); + + Drul_array get_bound_info () const; + void generate_curves () const; + Array *enumerate_attachments (Drul_array end_ys) const; + Drul_array get_base_attachments() const; + Drul_array get_y_attachment_range() const; + Encompass_info get_encompass_info (Grob *col) const; + Array get_extra_encompass_infos () const; +}; + + +void set_slur_control_points (Grob *me); + +#endif /* SLUR_SCORING_HH */ diff --git a/lily/include/slur.hh b/lily/include/slur.hh index 5dd31b6f5c..125697632c 100644 --- a/lily/include/slur.hh +++ b/lily/include/slur.hh @@ -13,8 +13,6 @@ #include "lily-proto.hh" #include "lily-guile.hh" -#define DEBUG_SLUR_QUANTING 1 - class Slur { public: diff --git a/lily/multi-measure-rest-engraver.cc b/lily/multi-measure-rest-engraver.cc index d19f922997..4b69b38de4 100644 --- a/lily/multi-measure-rest-engraver.cc +++ b/lily/multi-measure-rest-engraver.cc @@ -82,6 +82,10 @@ Multi_measure_rest_engraver::process_music () { mmrest_ = make_spanner ("MultiMeasureRest", rest_ev_->self_scm ()); + Spanner *sp + = make_spanner ("MultiMeasureRestNumber", rest_ev_->self_scm () ); + numbers_.push (sp); + if (text_events_.size ()) { for (int i = 0; i < text_events_.size (); i++) @@ -116,12 +120,6 @@ Multi_measure_rest_engraver::process_music () } } while (flip (&d) != DOWN); } - else - { - Spanner *sp - = make_spanner ("MultiMeasureRestNumber", rest_ev_->self_scm () ); - numbers_.push (sp); - } for (int i =0 ; i < numbers_.size (); i++) { diff --git a/lily/slur-configuration.cc b/lily/slur-configuration.cc new file mode 100644 index 0000000000..a8d52ca0b7 --- /dev/null +++ b/lily/slur-configuration.cc @@ -0,0 +1,508 @@ +/* + slur-configuration.cc -- implement Slur_configuration + + source file of the GNU LilyPond music typesetter + + (c) 2004 Han-Wen Nienhuys + +*/ + +#include + +#include "stem.hh" +#include "warn.hh" +#include "misc.hh" +#include "item.hh" +#include "group-interface.hh" +#include "slur.hh" +#include "slur-scoring.hh" +#include "slur-configuration.hh" +#include "spanner.hh" +#include "staff-symbol-referencer.hh" +#include "libc-extension.hh" + +Bezier +avoid_staff_line (Slur_score_state const &state, + Bezier bez) +{ + Offset horiz (1,0); + Array ts = bez.solve_derivative (horiz); + + /* TODO: handle case of broken slur. */ + if (!ts.is_empty () + && (state.extremes_[LEFT].staff_ == state.extremes_[RIGHT].staff_) + && state.extremes_[LEFT].staff_ && state.extremes_[RIGHT].staff_) + { + Real y = bez.curve_point (ts[0])[Y_AXIS]; + + Grob *staff = state.extremes_[LEFT].staff_; + + Real p = 2 * (y - staff->relative_coordinate (state.common_[Y_AXIS], Y_AXIS)) + / state.staff_space_; + + Real distance = fabs (my_round (p) - p); // in halfspaces + if (distance < 4 * state.thickness_ + && (int) fabs (my_round (p)) + <= 2 * Staff_symbol_referencer::staff_radius (staff) + 0.1 + && (int (fabs (my_round (p))) % 2 + != Staff_symbol_referencer::line_count (staff) % 2)) + { + Direction resolution_dir = + (distance ? state.dir_ : Direction (sign (p - my_round (p)))); + + // TODO: parameter + Real newp = my_round (p) + resolution_dir + * 5 * state.thickness_; + + Real dy = (newp - p) * state.staff_space_ / 2.0; + + bez.control_[1][Y_AXIS] += dy; + bez.control_[2][Y_AXIS] += dy; + } + } + return bez; +} + +Real +fit_factor (Offset dz_unit, Offset dz_perp, + Bezier curve, Direction d, Array const &avoid) +{ + Real fit_factor = 0.0; + Offset x0 = curve.control_[0]; + curve.translate (-x0); + curve.rotate (-dz_unit.arg ()); + curve.scale (1, d); + + Interval curve_xext; + curve_xext.add_point (curve.control_[0][X_AXIS]); + curve_xext.add_point (curve.control_[3][X_AXIS]); + + for (int i = 0; i < avoid.size (); i++) + { + Offset z = (avoid[i] - x0) ; + Offset p (dot_product (z, dz_unit), + d* dot_product (z, dz_perp)); + if (!curve_xext.contains (p[X_AXIS])) + continue; + + Real y = curve.get_other_coordinate (X_AXIS, p[X_AXIS]); + if (y) + { + fit_factor = fit_factor >? (p[Y_AXIS] / y); + } + } + return fit_factor; +} + + +Bezier +get_bezier (Slur_score_state const &state, + Drul_array attachments, + Real r_0, Real h_inf) +{ + Link_array encompasses = state.columns_; + + Array avoid; + for (int i = 0; i < encompasses.size (); i++) + { + if (state.extremes_[LEFT].note_column_ == encompasses[i] + || state.extremes_[RIGHT].note_column_ == encompasses[i]) + continue; + + Encompass_info inf (state.get_encompass_info (encompasses[i])); + Real y = state.dir_ * ((state.dir_ * inf.head_) >? (state.dir_ *inf.stem_)); + + avoid.push (Offset (inf.x_, y + state.dir_ * state.parameters_.free_head_distance_)); + } + + Link_array extra_encompasses + = Pointer_group_interface__extract_grobs (state.slur_, (Grob *)0, "encompass-objects"); + for (int i = 0; i < extra_encompasses.size (); i++) + if (Slur::has_interface (extra_encompasses[i])) + { + Grob * small_slur = extra_encompasses[i]; + Bezier b = Slur::get_curve (small_slur); + + Offset z = b.curve_point (0.5); + z += Offset (small_slur->relative_coordinate (state.common_[X_AXIS], X_AXIS), + small_slur->relative_coordinate (state.common_[Y_AXIS], Y_AXIS)); + + z[Y_AXIS] += state.dir_ * state.parameters_.free_slur_distance_; + avoid.push (z); + } + + Offset dz = attachments[RIGHT]- attachments[LEFT];; + Offset dz_unit = dz; + dz_unit *= 1 / dz.length (); + Offset dz_perp = dz_unit * Offset (0, 1); + + Real indent, height; + get_slur_indent_height (&indent, &height, dz.length (), h_inf, r_0); + + + Real len = dz.length (); + + /* This condition, + + len^2 > 4h^2 + 3 (i + 1/3len)^2 - 1/3 len^2 + + is equivalent to: + + |bez' (0)| < | bez' (.5)| + + when (control2 - control1) has the same direction as + (control3 - control0). */ + + + + Real max_indent = len / 3.1; + indent = indent get_property ("excentricity"), 0); + + Real x1 = (excentricity + indent); + Real x2 = (excentricity - indent); + + Bezier curve; + curve.control_[0] = attachments[LEFT]; + curve.control_[1] = attachments[LEFT] + dz_perp * height * state.dir_ + + dz_unit * x1; + curve.control_[2] = attachments[RIGHT] + dz_perp * height * state.dir_ + + dz_unit * x2; + curve.control_[3] = attachments[RIGHT]; + + Real ff = fit_factor (dz_unit, dz_perp, curve, state.dir_, avoid); + + height = height >? ((height * ff) convex_head_distances; + Array edge_distances; + for (int j = 0; j < state.encompass_infos_.size (); j++) + { + Real x = state.encompass_infos_[j].x_; + + bool l_edge = j==0; + bool r_edge = j==state.encompass_infos_.size ()-1; + bool edge = l_edge || r_edge; + + + if (edge) + { + edge_distances.push (fabs (attachment_[l_edge ? LEFT : RIGHT][Y_AXIS] + - state.encompass_infos_[j].get_point (state.dir_))); + } + + + if (! (x < attachment_[RIGHT][X_AXIS] + && x > attachment_[LEFT][X_AXIS])) + continue; + + Real y = bez.get_other_coordinate (X_AXIS, x); + if (!edge) + { + Real head_dy = (y - state.encompass_infos_[j].head_); + if (state.dir_ * head_dy < 0) + { + demerit += state.parameters_.head_encompass_penalty_; + convex_head_distances.push (0.0); + } + else + { + Real hd = (head_dy) + ? (1 / fabs (head_dy) - 1 / state.parameters_.free_head_distance_) + : state.parameters_.head_encompass_penalty_; + hd = (hd >? 0) state.dir_ *line_y ) + { + + Real closest = + state.dir_ * (state.dir_ * state.encompass_infos_[j].get_point (state.dir_) + >? state.dir_ *line_y + ); + Real d = fabs (closest - y); + + convex_head_distances.push (d); + } + } + + + + if (state.dir_ * (y - state.encompass_infos_[j].stem_) < 0) + { + Real stem_dem =state.parameters_.stem_encompass_penalty_ ; + if ((l_edge && state.dir_ == UP) + || (r_edge && state.dir_ == DOWN)) + stem_dem /= 5; + + demerit += stem_dem; + } + else if (!edge) + { + Interval ext; + ext.add_point (state.encompass_infos_[j].stem_); + ext.add_point (state.encompass_infos_[j].head_); + + // ? + demerit += -state.parameters_.closeness_factor_ + * (state.dir_ + * (y - (ext[state.dir_] + state.dir_ * state.parameters_.free_head_distance_)) + 0.0) + variance_penalty = ((avg_distance / (min_dist +state.parameters_.free_head_distance_)) - 1.0) + attachment = attachment_; + Interval slur_wid (attachment[LEFT][X_AXIS], attachment[RIGHT][X_AXIS]); + + /* + to prevent numerical inaccuracies in + Bezier::get_other_coordinate (). + */ + Direction d = LEFT; + bool found = false; + Real y = 0.0; + + do + { + /* + We need to check for the bound explicitly, since the + slur-ending can be almost vertical, making the Y + coordinate a bad approximation of the object-slur + distance. + */ + Item * as_item = dynamic_cast (state.extra_encompass_infos_[j].grob_); + if ((as_item + && as_item->get_column () + == state.extremes_[d] .bound_->get_column ()) + || state.extra_encompass_infos_[j].extents_[X_AXIS].contains (attachment[d][X_AXIS])) + { + y = attachment[d][Y_AXIS]; + found = true; + } + } + while (flip (&d) != LEFT); + + if (!found) + { + Real x = state.extra_encompass_infos_[j].extents_[X_AXIS] + .linear_combination (state.extra_encompass_infos_[j].idx_); + + if (!slur_wid.contains (x)) + continue; + + y = curve_.get_other_coordinate (X_AXIS, x); + } + + Real dist = state.extra_encompass_infos_[j].extents_[Y_AXIS].distance (y); + demerit += + fabs (0 >? (state.parameters_.extra_encompass_free_distance_ - dist)) / + state.parameters_.extra_encompass_free_distance_ + * state.extra_encompass_infos_[j].penalty_; + } +#if DEBUG_SLUR_SCORING + score_card_ += to_string ("X%.2f", demerit); +#endif + score_ += demerit; +} + +void +Slur_configuration::score_edges (Slur_score_state const &state) +{ + Direction d = LEFT; + Offset dz = attachment_[RIGHT] + - attachment_[LEFT]; + Real slope = dz[Y_AXIS] / dz[X_AXIS]; + do + { + Real y = attachment_[d][Y_AXIS]; + Real dy = fabs (y - state.base_attachments_[d][Y_AXIS]); + + Real factor = state.parameters_.edge_attraction_factor_; + Real demerit = factor * dy; + if (state.extremes_[d].stem_ + && state.extremes_[d].stem_dir_ == state.dir_ + && !Stem::get_beaming (state.extremes_[d].stem_, -d) + ) + demerit /= 5; + + demerit *= exp (state.dir_ * d * slope + * state.parameters_.edge_slope_exponent_ ); + + score_ += demerit; +#if DEBUG_SLUR_SCORING + score_card_ += to_string ("E%.2f", demerit); +#endif + } + while (flip (&d) != LEFT); +} + +void +Slur_configuration ::score_slopes (Slur_score_state const &state) +{ + Real dy = state.musical_dy_; + Offset slur_dz = attachment_[RIGHT] - attachment_[LEFT]; + Real slur_dy = slur_dz[Y_AXIS]; + Real demerit = 0.0; + + demerit += ((fabs (slur_dy / slur_dz[X_AXIS]) + - state.parameters_.max_slope_) >? 0) + * state.parameters_.max_slope_factor_; + + /* 0.2: account for staffline offset. */ + Real max_dy = (fabs (dy) + 0.2); + if (state.edge_has_beams_) + max_dy += 1.0; + + if (!state.is_broken_) + demerit += state.parameters_.steeper_slope_factor_ + * ((fabs (slur_dy) -max_dy) >? 0); + + demerit += ((fabs (slur_dy/slur_dz[X_AXIS]) + - state.parameters_.max_slope_) >? 0) + * state.parameters_.max_slope_factor_; + + if (sign (dy) == 0 + && sign (slur_dy) != 0 + && !state.is_broken_) + demerit += state.parameters_.non_horizontal_penalty_; + + if (sign (dy) + && !state.is_broken_ + && sign (slur_dy) + && sign (slur_dy) != sign (dy)) + demerit += state.edge_has_beams_ + ? state.parameters_.same_slope_penalty_ / 10 + : state.parameters_.same_slope_penalty_; + +#if DEBUG_SLUR_SCORING + score_card_ += to_string ("S%.2f", demerit); +#endif + score_ += demerit; +} + + +void +Slur_configuration::score (Slur_score_state const &state) +{ + score_extra_encompass (state); + score_slopes (state); + score_edges (state); + score_encompass (state); +} diff --git a/lily/slur-scoring.cc b/lily/slur-scoring.cc index dbbd18c229..1e4279baf8 100644 --- a/lily/slur-scoring.cc +++ b/lily/slur-scoring.cc @@ -1,5 +1,5 @@ /* - slur-quanting.cc -- Score based slur formatting + slur-scoring.cc -- Score based slur formatting source file of the GNU LilyPond music typesetter @@ -9,11 +9,12 @@ #include -#include "accidental-interface.hh" +#include "libc-extension.hh" +#include "slur-configuration.hh" +#include "slur-scoring.hh" #include "beam.hh" #include "directional-element-interface.hh" #include "group-interface.hh" -#include "libc-extension.hh" #include "lily-guile.hh" #include "slur.hh" #include "note-column.hh" @@ -26,13 +27,14 @@ #include "stem.hh" #include "warn.hh" #include "paper-column.hh" +#include "accidental-interface.hh" /* TODO: - curve around flag for y coordinate - - this file is a big mess, clean it up + - this file is a mess, clean it up - short-cut: try a smaller region first. @@ -48,138 +50,7 @@ - optimize. */ - -struct Slur_score -{ - Drul_array attachment_; - Real score_; - Bezier curve_; - -#if DEBUG_SLUR_QUANTING - String score_card_; -#endif - - Slur_score () - { - score_ = 0.0; - } -}; - -struct Slur_score_parameters -{ - int region_size_; - Real head_encompass_penalty_; - Real stem_encompass_penalty_; - Real closeness_factor_; - Real edge_attraction_factor_; - Real same_slope_penalty_; - Real steeper_slope_factor_; - Real non_horizontal_penalty_; - Real max_slope_; - Real max_slope_factor_; - Real extra_object_collision_; - Real accidental_collision_; - Real free_slur_distance_; - Real free_head_distance_; - Real extra_encompass_free_distance_; - Real edge_slope_exponent_; - Real head_slur_distance_max_ratio_; - Real head_slur_distance_factor_; -}; - - - -struct Extra_collision_info -{ - Real idx_; - Box extents_; - Real penalty_; - Grob * grob_; - - Extra_collision_info (Grob *g, Real idx, Interval x, Interval y, Real p) - { - idx_ = idx; - extents_[X_AXIS] = x; - extents_[Y_AXIS] = y; - penalty_ = p; - grob_ = g; - } - Extra_collision_info () - { - idx_ = 0.0; - penalty_ = 0.; - grob_ = 0; - } -}; - - -struct Encompass_info -{ - Real x_; - Real stem_; - Real head_; - Encompass_info () - { - x_ = 0.0; - stem_ = 0.0; - head_ = 0.0; - } - Real get_point (Direction dir) const - { - Interval y; - y.add_point (stem_); - y.add_point (head_); - return y[dir]; - } -}; - -struct Bound_info -{ - Box stem_extent_; - Direction stem_dir_; - Item *bound_; - Grob *note_column_; - Grob *slur_head_; - Grob *staff_; - Grob *stem_; - Interval slur_head_extent_; - Real staff_space_; - - Bound_info () - { - stem_ = 0; - staff_ = 0; - slur_head_ = 0; - stem_dir_ = CENTER; - note_column_ = 0; - } -}; - -struct Slur_score_state -{ - Spanner *slur_; - Grob *common_[NO_AXES]; - bool valid_; - bool edge_has_beams_; - bool is_broken_; - bool has_same_beam_; - - Real musical_dy_; - Link_array columns_; - Array encompass_infos_; - Array extra_encompass_infos_; - - Direction dir_; - Slur_score_parameters parameters_; - Drul_array extremes_; - Drul_array base_attachments_; - Array *scores_; - Real staff_space_; - Real thickness_; - - Slur_score_state(); - ~Slur_score_state(); -}; +struct Slur_score_state; Slur_score_state::Slur_score_state() { @@ -200,28 +71,8 @@ Slur_score_state::~Slur_score_state () delete scores_; } -static Array get_extra_encompass_infos (Slur_score_state const &state); -static void score_extra_encompass (Slur_score_state const&); -static void score_slopes (Slur_score_state const&); -static void score_edges (Slur_score_state const&); -static void score_encompass (Slur_score_state const&); -static Bezier avoid_staff_line (Slur_score_state const&, - Bezier bez); -static Encompass_info get_encompass_info (Slur_score_state const&, Grob *col); -static Bezier get_bezier (Slur_score_state const&, - Drul_array, - Real r_0, Real h_inf); -static Direction get_default_dir (Grob *me); - -static void set_end_points (Grob *); -static Real broken_trend_y (Slur_score_state const&, Direction dir); -static Drul_array get_bound_info (Slur_score_state const&); - -static void generate_curves (Slur_score_state const&); -static Array *enumerate_attachments (Slur_score_state const&, - Drul_array end_ys); -static Drul_array get_base_attachments(Slur_score_state const&); -static Drul_array get_y_attachment_range(Slur_score_state const&); + + Real @@ -278,7 +129,6 @@ init_score_param (Grob *me, = get_detail (details, ly_symbol2scm ("edge-slope-exponent")); } - Real broken_trend_y (Slur_score_state const &state, Direction hdir) { @@ -303,12 +153,8 @@ broken_trend_y (Slur_score_state const &state, Direction hdir) return by; Grob *common_next_system = common_mother->broken_intos_[common_j]; - - - SCM last_point = scm_car (scm_last_pair (neighbor->get_property ("control-points"))); - return scm_to_double (scm_cdr (last_point)) + neighbor->relative_coordinate (common_next_system, Y_AXIS); @@ -318,29 +164,28 @@ broken_trend_y (Slur_score_state const &state, Direction hdir) /* -copy slur dir forwards across line break. + copy slur dir forwards across line break. */ void -set_next_direction (Slur_score_state const &state) +Slur_score_state::set_next_direction () { - if (state.extremes_[RIGHT].note_column_) + if (extremes_[RIGHT].note_column_) return; - if (Spanner *mother = dynamic_cast (state.slur_->original_)) + if (Spanner *mother = dynamic_cast (slur_->original_)) { - int k = broken_spanner_index (state.slur_); + int k = broken_spanner_index (slur_); int j = k + 1; if (j < 0 || j >= mother->broken_intos_.size ()) return; Grob *neighbor = mother->broken_intos_[j]; - set_grob_direction (neighbor, state.dir_); + set_grob_direction (neighbor, dir_); } } Encompass_info -get_encompass_info (Slur_score_state const &state, - Grob *col) +Slur_score_state::get_encompass_info (Grob *col) const { Grob *stem = unsmob_grob (col->get_property ("stem")); Encompass_info ei; @@ -348,37 +193,37 @@ get_encompass_info (Slur_score_state const &state, if (!stem) { programming_error ("No stem for note column?"); - ei.x_ = col->relative_coordinate (state.common_[X_AXIS], X_AXIS); - ei.head_ = ei.stem_ = col->extent (state.common_[Y_AXIS], - Y_AXIS)[state.dir_]; + ei.x_ = col->relative_coordinate (common_[X_AXIS], X_AXIS); + ei.head_ = ei.stem_ = col->extent (common_[Y_AXIS], + Y_AXIS)[dir_]; return ei; } Direction stem_dir = get_grob_direction (stem); if (Grob *head = Note_column::first_head (col)) - ei.x_ = head->extent (state.common_[X_AXIS], X_AXIS).center (); + ei.x_ = head->extent (common_[X_AXIS], X_AXIS).center (); else - ei.x_ = col->extent (state.common_[X_AXIS], X_AXIS).center (); + ei.x_ = col->extent (common_[X_AXIS], X_AXIS).center (); - Grob *h = Stem::extremal_heads (stem)[Direction (state.dir_)]; + Grob *h = Stem::extremal_heads (stem)[Direction (dir_)]; if (!h) { - ei.head_ = ei.stem_ = col->extent (state.common_[Y_AXIS], Y_AXIS)[state.dir_]; + ei.head_ = ei.stem_ = col->extent (common_[Y_AXIS], Y_AXIS)[dir_]; return ei; } - ei.head_ = h->extent (state.common_[Y_AXIS], Y_AXIS)[state.dir_]; + ei.head_ = h->extent (common_[Y_AXIS], Y_AXIS)[dir_]; - if ((stem_dir == state.dir_) + if ((stem_dir == dir_) && !stem->extent (stem, Y_AXIS).is_empty ()) { - ei.stem_ = stem->extent (state.common_[Y_AXIS], Y_AXIS)[state.dir_]; + ei.stem_ = stem->extent (common_[Y_AXIS], Y_AXIS)[dir_]; if (Grob *b = Stem::get_beam (stem)) ei.stem_ += stem_dir * 0.5 * Beam::get_thickness (b); - Interval x = stem->extent (state.common_[X_AXIS], X_AXIS); + Interval x = stem->extent (common_[X_AXIS], X_AXIS); ei.x_ = x.is_empty () - ? stem->relative_coordinate (state.common_[X_AXIS], X_AXIS) + ? stem->relative_coordinate (common_[X_AXIS], X_AXIS) : x.center (); } else @@ -388,66 +233,28 @@ get_encompass_info (Slur_score_state const &state, } -Direction -get_default_dir (Grob*me) -{ - Link_array encompasses - = Pointer_group_interface__extract_grobs (me, (Grob*) 0, "note-columns"); - Direction d = DOWN; - for (int i= 0; i < encompasses.size (); i ++) - { - if (Note_column::dir (encompasses[i]) < 0) - { - d = UP; - break; - } - } - return d; -} - - - -MAKE_SCHEME_CALLBACK (Slur, after_line_breaking,1); -SCM -Slur::after_line_breaking (SCM smob) -{ - Spanner *me = dynamic_cast (unsmob_grob (smob)); - if (!scm_ilength (me->get_property ("note-columns"))) - { - me->suicide (); - return SCM_UNSPECIFIED; - } - - if (!get_grob_direction (me)) - set_grob_direction (me, get_default_dir (me)); - - if (scm_ilength (me->get_property ("control-points")) < 4) - set_end_points (me); - - return SCM_UNSPECIFIED; -} Drul_array -get_bound_info (Slur_score_state const &state) +Slur_score_state::get_bound_info () const { Drul_array extremes; Direction d = LEFT; - Direction dir = state.dir_; + Direction dir = dir_; do { - extremes[d].bound_ = state.slur_->get_bound (d); + extremes[d].bound_ = slur_->get_bound (d); if (Note_column::has_interface (extremes[d].bound_)) { extremes[d].note_column_ = extremes[d].bound_; extremes[d].stem_ = Note_column::get_stem (extremes[d].note_column_); extremes[d].stem_dir_ = get_grob_direction (extremes[d].stem_); extremes[d].stem_extent_[X_AXIS] - = extremes[d].stem_->extent (state.common_[X_AXIS], X_AXIS); + = extremes[d].stem_->extent (common_[X_AXIS], X_AXIS); extremes[d].stem_extent_[Y_AXIS] - = extremes[d].stem_->extent (state.common_[Y_AXIS], Y_AXIS); + = extremes[d].stem_->extent (common_[Y_AXIS], Y_AXIS); extremes[d].slur_head_ = Stem::extremal_heads (extremes[d].stem_)[dir]; if (!extremes[d].slur_head_ @@ -458,7 +265,7 @@ get_bound_info (Slur_score_state const &state) if (extremes[d].slur_head_) extremes[d].slur_head_extent_ - = extremes[d].slur_head_->extent (state.common_[X_AXIS], X_AXIS); + = extremes[d].slur_head_->extent (common_[X_AXIS], X_AXIS); extremes[d].staff_ = Staff_symbol_referencer ::get_staff_symbol (extremes[d].stem_); @@ -471,25 +278,24 @@ get_bound_info (Slur_score_state const &state) } void -fill_scoring_state (Grob *me, Slur_score_state *state_ptr) +Slur_score_state::fill (Grob *me) { - Slur_score_state &state = *state_ptr; - state.slur_ = dynamic_cast (me); - state.columns_ + slur_ = dynamic_cast (me); + columns_ = Pointer_group_interface__extract_grobs (me, (Grob *) 0, "note-columns"); - if (state.columns_.is_empty ()) + if (columns_.is_empty ()) { me->suicide (); return ; } - state.staff_space_ = Staff_symbol_referencer::staff_space (me); + staff_space_ = Staff_symbol_referencer::staff_space (me); Real lt = me->get_paper ()->get_dimension (ly_symbol2scm ("linethickness")); - state.thickness_ = robust_scm2double (me->get_property ("thickness"), 1.0) * lt; + thickness_ = robust_scm2double (me->get_property ("thickness"), 1.0) * lt; - state.dir_ = get_grob_direction (me); - init_score_param (me, &state.parameters_); + dir_ = get_grob_direction (me); + init_score_param (me, ¶meters_); SCM eltlist = me->get_property ("note-columns"); SCM extra_list = me->get_property ("encompass-objects"); @@ -498,97 +304,115 @@ fill_scoring_state (Grob *me, Slur_score_state *state_ptr) for (int i = X_AXIS; i < NO_AXES; i++) { Axis a = (Axis)i; - state.common_[a] = common_refpoint_of_list (eltlist, me, a); - state.common_[a] = common_refpoint_of_list (extra_list, state.common_[a], a); + common_[a] = common_refpoint_of_list (eltlist, me, a); + common_[a] = common_refpoint_of_list (extra_list, common_[a], a); Direction d = LEFT; do { - state.common_[a] = state.common_[a]->common_refpoint (sp->get_bound (d), a); + common_[a] = common_[a]->common_refpoint (sp->get_bound (d), a); } while (flip (&d) != LEFT); } - state.extremes_ = get_bound_info (state); - state.is_broken_ = (!state.extremes_[LEFT].note_column_ - || !state.extremes_[RIGHT].note_column_); + extremes_ = get_bound_info (); + is_broken_ = (!extremes_[LEFT].note_column_ + || !extremes_[RIGHT].note_column_); - state.base_attachments_ = get_base_attachments (state); + base_attachments_ = get_base_attachments (); Drul_array end_ys - = get_y_attachment_range (state); + = get_y_attachment_range (); - state.scores_ = enumerate_attachments (state, end_ys); - for (int i = 0; i < state.columns_.size (); i++) - state.encompass_infos_.push (get_encompass_info (state, state.columns_[i])); + scores_ = enumerate_attachments ( end_ys); + for (int i = 0; i < columns_.size (); i++) + encompass_infos_.push (get_encompass_info ( columns_[i])); - state.extra_encompass_infos_ = get_extra_encompass_infos (state); - state.valid_ = true; + extra_encompass_infos_ = get_extra_encompass_infos (); + valid_ = true; - state.musical_dy_ = 0.0; + musical_dy_ = 0.0; Direction d = LEFT; do { - if (!state.is_broken_) - state.musical_dy_ += d - * state.extremes_[d].slur_head_->relative_coordinate (state.common_[Y_AXIS], Y_AXIS); + if (!is_broken_) + musical_dy_ += d + * extremes_[d].slur_head_->relative_coordinate (common_[Y_AXIS], Y_AXIS); } while (flip (&d) != LEFT); - state.edge_has_beams_ - = (state.extremes_[LEFT].stem_ && Stem::get_beam (state.extremes_[LEFT].stem_)) - || (state.extremes_[RIGHT].stem_ && Stem::get_beam (state.extremes_[RIGHT].stem_)); + edge_has_beams_ + = (extremes_[LEFT].stem_ && Stem::get_beam (extremes_[LEFT].stem_)) + || (extremes_[RIGHT].stem_ && Stem::get_beam (extremes_[RIGHT].stem_)); - state.has_same_beam_ = - (state.extremes_[LEFT].stem_ && state.extremes_[RIGHT].stem_ - && Stem::get_beam (state.extremes_[LEFT].stem_) == Stem::get_beam (state.extremes_[RIGHT].stem_)); + has_same_beam_ = + (extremes_[LEFT].stem_ && extremes_[RIGHT].stem_ + && Stem::get_beam (extremes_[LEFT].stem_) == Stem::get_beam (extremes_[RIGHT].stem_)); - set_next_direction (state); + set_next_direction (); - if (state.is_broken_) - state.musical_dy_ = 0.0; + if (is_broken_) + musical_dy_ = 0.0; } void -set_end_points (Grob *me) +set_slur_control_points (Grob *me) { Slur_score_state state; - fill_scoring_state (me, &state); + state.fill (me); if (!state.valid_) return; - generate_curves (state); - score_edges (state); - score_slopes (state); - score_encompass (state); - score_extra_encompass (state); + state.generate_curves (); + Bezier best (state.get_best_curve()); + + + SCM controls = SCM_EOL; + for (int i = 4; i--;) + { + Offset o = best.control_[i] + - Offset (me->relative_coordinate (state.common_[X_AXIS], X_AXIS), + me->relative_coordinate (state.common_[Y_AXIS], Y_AXIS)); + controls = scm_cons (ly_offset2scm (o), controls); + } + me->set_property ("control-points", controls); +} + + +Bezier +Slur_score_state::get_best_curve () +{ + for (int i = 0; i < scores_->size (); i++) + { + scores_->elem (i).score (*this); + } Real opt = 1e6; int opt_idx = -1; - for (int i = 0; i < state.scores_->size (); i++) + for (int i = 0; i < scores_->size (); i++) { - if ((*state.scores_)[i].score_ < opt) + if ((*scores_)[i].score_ < opt) { - opt = (*state.scores_)[i].score_; + opt = (*scores_)[i].score_; opt_idx = i; } } -#if DEBUG_SLUR_QUANTING - SCM inspect_quants = me->get_property ("inspect-quants"); - if (to_boolean (me->get_paper () +#if DEBUG_SLUR_SCORING + SCM inspect_quants = slur_->get_property ("inspect-quants"); + if (to_boolean (slur_->get_paper () ->lookup_variable (ly_symbol2scm ("debug-slur-scoring"))) && scm_is_pair (inspect_quants)) { Drul_array ins = ly_scm2interval (inspect_quants); Real mindist = 1e6; - for (int i = 0; i < state.scores_->size (); i ++) + for (int i = 0; i < scores_->size (); i ++) { - Real d =fabs ((*state.scores_)[i].attachment_[LEFT][Y_AXIS] - ins[LEFT]) - + fabs ((*state.scores_)[i].attachment_[RIGHT][Y_AXIS] - ins[RIGHT]); + Real d =fabs ((*scores_)[i].attachment_[LEFT][Y_AXIS] - ins[LEFT]) + + fabs ((*scores_)[i].attachment_[RIGHT][Y_AXIS] - ins[RIGHT]); if (d < mindist) { opt_idx = i; @@ -598,23 +422,14 @@ set_end_points (Grob *me) if (mindist > 1e5) programming_error ("Could not find quant."); } - (*state.scores_)[opt_idx].score_card_ += to_string ("i%d", opt_idx); + (*scores_)[opt_idx].score_card_ += to_string ("i%d", opt_idx); // debug quanting - me->set_property ("quant-score", - scm_makfrom0str ((*state.scores_)[opt_idx].score_card_.to_str0 ())); + slur_->set_property ("quant-score", + scm_makfrom0str ((*scores_)[opt_idx].score_card_.to_str0 ())); #endif - Bezier b = (*state.scores_)[opt_idx].curve_; - SCM controls = SCM_EOL; - for (int i = 4; i--;) - { - Offset o = b.control_[i] - - Offset (me->relative_coordinate (state.common_[X_AXIS], X_AXIS), - me->relative_coordinate (state.common_[Y_AXIS], Y_AXIS)); - controls = scm_cons (ly_offset2scm (o), controls); - } - me->set_property ("control-points", controls); + return scores_->elem (opt_idx).curve_; } /* @@ -623,22 +438,22 @@ set_end_points (Grob *me) */ Drul_array -get_y_attachment_range (Slur_score_state const &state) +Slur_score_state::get_y_attachment_range () const { Drul_array end_ys; Direction d = LEFT; do { - if (state.extremes_[d].note_column_) + if (extremes_[d].note_column_) { - end_ys[d] = state.dir_ - * ((state.dir_ * (state.base_attachments_[d][Y_AXIS] + state.parameters_.region_size_* state.dir_)) - >? (state.dir_ * (state.dir_ + state.extremes_[d].note_column_->extent (state.common_[Y_AXIS], - Y_AXIS)[state.dir_])) - >? (state.dir_ * state.base_attachments_[-d][Y_AXIS])); + end_ys[d] = dir_ + * ((dir_ * (base_attachments_[d][Y_AXIS] + parameters_.region_size_* dir_)) + >? (dir_ * (dir_ + extremes_[d].note_column_->extent (common_[Y_AXIS], + Y_AXIS)[dir_])) + >? (dir_ * base_attachments_[-d][Y_AXIS])); } else - end_ys[d] = state.base_attachments_[d][Y_AXIS] + state.parameters_.region_size_ * state.dir_; + end_ys[d] = base_attachments_[d][Y_AXIS] + parameters_.region_size_ * dir_; } while (flip (&d) != LEFT); @@ -662,37 +477,37 @@ spanner_less (Spanner *s1, Spanner* s2) Drul_array -get_base_attachments (Slur_score_state const &state) +Slur_score_state::get_base_attachments () const { Drul_array base_attachment; Direction d = LEFT; do { - Grob *stem = state.extremes_[d].stem_; - Grob *head = state.extremes_[d].slur_head_; + Grob *stem = extremes_[d].stem_; + Grob *head = extremes_[d].slur_head_; Real x = 0.0; Real y = 0.0; - if (state.extremes_[d].note_column_) + if (extremes_[d].note_column_) { /* fixme: X coord should also be set in this case. */ if (stem - && state.extremes_[d].stem_dir_ == state.dir_ + && extremes_[d].stem_dir_ == dir_ && Stem::get_beaming (stem, -d) - && (!spanner_less (state.slur_, Stem::get_beam (stem)) - || state.has_same_beam_)) - y = state.extremes_[d].stem_extent_[Y_AXIS][state.dir_]; + && (!spanner_less (slur_, Stem::get_beam (stem)) + || has_same_beam_)) + y = extremes_[d].stem_extent_[Y_AXIS][dir_]; else if (head) - y = head->extent (state.common_[Y_AXIS], Y_AXIS)[state.dir_]; - y += state.dir_ * 0.5 * state.staff_space_; + y = head->extent (common_[Y_AXIS], Y_AXIS)[dir_]; + y += dir_ * 0.5 * staff_space_; Real pos - = (y - state.extremes_[d].staff_->relative_coordinate (state.common_[Y_AXIS], + = (y - extremes_[d].staff_->relative_coordinate (common_[Y_AXIS], Y_AXIS)) - * 2.0 / state.staff_space_; + * 2.0 / staff_space_; /* start off staffline. */ if (fabs (pos - my_round (pos)) < 0.2 @@ -700,12 +515,12 @@ get_base_attachments (Slur_score_state const &state) && Staff_symbol_referencer::line_count (head) - 1 >= rint (pos) ) // TODO: calc from slur thick & line thick, parameter. - y += 1.5 * state.staff_space_ * state.dir_ / 10; + y += 1.5 * staff_space_ * dir_ / 10; - Grob * fh = Note_column::first_head (state.extremes_[d].note_column_); + Grob * fh = Note_column::first_head (extremes_[d].note_column_); x = - (fh ? fh->extent (state.common_[X_AXIS], X_AXIS) - : state.extremes_[d].bound_->extent (state.common_[X_AXIS], X_AXIS)) + (fh ? fh->extent (common_[X_AXIS], X_AXIS) + : extremes_[d].bound_->extent (common_[X_AXIS], X_AXIS)) .linear_combination (CENTER); } base_attachment[d] = Offset (x, y); @@ -714,24 +529,24 @@ get_base_attachments (Slur_score_state const &state) do { - if (!state.extremes_[d].note_column_) + if (!extremes_[d].note_column_) { Real x, y; if (d == RIGHT) { - x = state.extremes_[d].bound_->extent (state.common_[X_AXIS], X_AXIS)[d]; + x = extremes_[d].bound_->extent (common_[X_AXIS], X_AXIS)[d]; } else { - x = state.slur_->get_broken_left_end_align (); + x = slur_->get_broken_left_end_align (); } - Grob * col = (d == LEFT) ? state.columns_[0] : state.columns_.top(); + Grob * col = (d == LEFT) ? columns_[0] : columns_.top(); - if (state.extremes_[-d].bound_ != col) + if (extremes_[-d].bound_ != col) { - y = robust_relative_extent (col, state.common_[Y_AXIS], Y_AXIS)[state.dir_]; - if (get_grob_direction (col) == state.dir_) - y -= state.dir_ ; + y = robust_relative_extent (col, common_[Y_AXIS], Y_AXIS)[dir_]; + if (get_grob_direction (col) == dir_) + y -= dir_ ; } else y = base_attachment[-d][Y_AXIS]; @@ -745,106 +560,59 @@ get_base_attachments (Slur_score_state const &state) } void -generate_curves (Slur_score_state const &state) +Slur_score_state::generate_curves () const { - Real r_0 = robust_scm2double (state.slur_->get_property ("ratio"), 0.33); - Real h_inf = state.staff_space_ *scm_to_double (state.slur_->get_property ("height-limit")); - for (int i = 0; i < state.scores_->size (); i++) - { - Bezier bez = get_bezier (state, - (*state.scores_)[i].attachment_, r_0, h_inf); - - bez = avoid_staff_line (state, bez); - (*state.scores_)[i].attachment_[LEFT] = bez.control_[0]; - (*state.scores_)[i].attachment_[RIGHT] = bez.control_[3]; - (*state.scores_)[i].curve_ = bez; - } + Real r_0 = robust_scm2double (slur_->get_property ("ratio"), 0.33); + Real h_inf = staff_space_ *scm_to_double (slur_->get_property ("height-limit")); + for (int i = 0; i < scores_->size (); i++) + scores_->elem(i).generate_curve (*this, r_0, h_inf); } -Bezier -avoid_staff_line (Slur_score_state const &state, - Bezier bez) -{ - Offset horiz (1,0); - Array ts = bez.solve_derivative (horiz); - - /* TODO: handle case of broken slur. */ - if (!ts.is_empty () - && (state.extremes_[LEFT].staff_ == state.extremes_[RIGHT].staff_) - && state.extremes_[LEFT].staff_ && state.extremes_[RIGHT].staff_) - { - Real y = bez.curve_point (ts[0])[Y_AXIS]; - Grob *staff = state.extremes_[LEFT].staff_; - Real p = 2 * (y - staff->relative_coordinate (state.common_[Y_AXIS], Y_AXIS)) - / state.staff_space_; - Real distance = fabs (my_round (p) - p); // in halfspaces - if (distance < 4 * state.thickness_ - && (int) fabs (my_round (p)) - <= 2 * Staff_symbol_referencer::staff_radius (staff) + 0.1 - && (int (fabs (my_round (p))) % 2 - != Staff_symbol_referencer::line_count (staff) % 2)) - { - Direction resolution_dir = - (distance ? state.dir_ : Direction (sign (p - my_round (p)))); - - // TODO: parameter - Real newp = my_round (p) + resolution_dir - * 5 * state.thickness_; - - Real dy = (newp - p) * state.staff_space_ / 2.0; - - bez.control_[1][Y_AXIS] += dy; - bez.control_[2][Y_AXIS] += dy; - } - } - return bez; -} - -Array * -enumerate_attachments (Slur_score_state const &state, Drul_array end_ys) +Array * +Slur_score_state::enumerate_attachments (Drul_array end_ys) const { /*ugh. */ - Array scores; + Array scores; Drul_array os; - os[LEFT] = state.base_attachments_[LEFT]; - Real minimum_length = state.staff_space_ - * robust_scm2double (state.slur_->get_property ("minimum-length"), 2.0); + os[LEFT] = base_attachments_[LEFT]; + Real minimum_length = staff_space_ + * robust_scm2double (slur_->get_property ("minimum-length"), 2.0); - for (int i = 0; state.dir_ * os[LEFT][Y_AXIS] <= state.dir_ * end_ys[LEFT]; i++) + for (int i = 0; dir_ * os[LEFT][Y_AXIS] <= dir_ * end_ys[LEFT]; i++) { - os[RIGHT] = state.base_attachments_[RIGHT]; - for (int j = 0; state.dir_ * os[RIGHT][Y_AXIS] <= state.dir_ * end_ys[RIGHT]; j++) + os[RIGHT] = base_attachments_[RIGHT]; + for (int j = 0; dir_ * os[RIGHT][Y_AXIS] <= dir_ * end_ys[RIGHT]; j++) { - Slur_score s; + Slur_configuration s; Direction d = LEFT; Drul_array attach_to_stem (false, false); do { - os[d][X_AXIS] = state.base_attachments_[d][X_AXIS]; - if (state.extremes_[d].stem_ - && !Stem::is_invisible (state.extremes_[d].stem_) - && state.extremes_[d].stem_dir_ == state.dir_) + os[d][X_AXIS] = base_attachments_[d][X_AXIS]; + if (extremes_[d].stem_ + && !Stem::is_invisible (extremes_[d].stem_) + && extremes_[d].stem_dir_ == dir_) { - Interval stem_y = state.extremes_[d].stem_extent_[Y_AXIS]; - stem_y.widen (0.25 * state.staff_space_); - if (state.dir_ == -d + Interval stem_y = extremes_[d].stem_extent_[Y_AXIS]; + stem_y.widen (0.25 * staff_space_); + if (dir_ == -d && stem_y.contains (os[d][Y_AXIS])) { - os[d][X_AXIS] = state.extremes_[d].slur_head_extent_[-d] + os[d][X_AXIS] = extremes_[d].slur_head_extent_[-d] - d * 0.3; attach_to_stem[d] = true; } - else if (state.dir_ *state.extremes_[d].stem_extent_[Y_AXIS][state.dir_] - < state.dir_ * os[d][Y_AXIS] - && !state.extremes_[d].stem_extent_[X_AXIS].is_empty () + else if (dir_ *extremes_[d].stem_extent_[Y_AXIS][dir_] + < dir_ * os[d][Y_AXIS] + && !extremes_[d].stem_extent_[X_AXIS].is_empty () ) - os[d][X_AXIS] = state.extremes_[d].stem_extent_[X_AXIS].center (); + os[d][X_AXIS] = extremes_[d].stem_extent_[X_AXIS].center (); } } while (flip (&d) != LEFT); @@ -852,14 +620,14 @@ enumerate_attachments (Slur_score_state const &state, Drul_array end_ys) Offset dz; dz = os[RIGHT] - os[LEFT]; if (dz[X_AXIS] < minimum_length - || fabs (dz[Y_AXIS] / dz[X_AXIS]) > state.parameters_.max_slope_ + || fabs (dz[Y_AXIS] / dz[X_AXIS]) > parameters_.max_slope_ ) { do { - if (state.extremes_[d].slur_head_) + if (extremes_[d].slur_head_) { - os[d][X_AXIS] = state.extremes_[d].slur_head_extent_.center (); + os[d][X_AXIS] = extremes_[d].slur_head_extent_.center (); attach_to_stem[d] = false; } } @@ -869,7 +637,7 @@ enumerate_attachments (Slur_score_state const &state, Drul_array end_ys) dz = os[RIGHT] - os[LEFT]; do { - if (state.extremes_[d].slur_head_ + if (extremes_[d].slur_head_ && !attach_to_stem[d]) { /* Horizontally move tilted slurs a little. Move @@ -877,7 +645,7 @@ enumerate_attachments (Slur_score_state const &state, Drul_array end_ys) TODO: parameter */ os[d][X_AXIS] - -= state.dir_ * state.extremes_[d].slur_head_extent_.length () + -= dir_ * extremes_[d].slur_head_extent_.length () * sin (dz.arg ()) / 3; } } @@ -886,177 +654,22 @@ enumerate_attachments (Slur_score_state const &state, Drul_array end_ys) s.attachment_ = os; scores.push (s); - os[RIGHT][Y_AXIS] += state.dir_ * state.staff_space_ / 2; + os[RIGHT][Y_AXIS] += dir_ * staff_space_ / 2; } - os[LEFT][Y_AXIS] += state.dir_ * state.staff_space_ / 2; + os[LEFT][Y_AXIS] += dir_ * staff_space_ / 2; } assert (scores.size () > 0); - return new Array (scores); -} - -inline Real -linear_interpolate (Real x, Real x1, Real x2, Real y1, Real y2) -{ - return (x2 - x) / (x2 - x1) * y1 + - (x - x1) / (x2 - x1) * y2 ; + return new Array (scores); } -void -score_encompass (Slur_score_state const &state) -{ - for (int i = 0; i < state.scores_->size (); i++) - { - Slur_score &configuration = state.scores_->elem_ref (i); - Bezier const &bez (configuration.curve_); - Real demerit = 0.0; - - /* - Distances for heads that are between slur and line between - attachment points. - */ - Array convex_head_distances; - Array edge_distances; - for (int j = 0; j < state.encompass_infos_.size (); j++) - { - Real x = state.encompass_infos_[j].x_; - - bool l_edge = j==0; - bool r_edge = j==state.encompass_infos_.size ()-1; - bool edge = l_edge || r_edge; - - - if (edge) - { - edge_distances.push (fabs (configuration.attachment_[l_edge ? LEFT : RIGHT][Y_AXIS] - - state.encompass_infos_[j].get_point (state.dir_))); - } - - - if (! (x < configuration.attachment_[RIGHT][X_AXIS] - && x > configuration.attachment_[LEFT][X_AXIS])) - continue; - - Real y = bez.get_other_coordinate (X_AXIS, x); - if (!edge) - { - Real head_dy = (y - state.encompass_infos_[j].head_); - if (state.dir_ * head_dy < 0) - { - demerit += state.parameters_.head_encompass_penalty_; - convex_head_distances.push (0.0); - } - else - { - Real hd = (head_dy) - ? (1 / fabs (head_dy) - 1 / state.parameters_.free_head_distance_) - : state.parameters_.head_encompass_penalty_; - hd = (hd >? 0) state.dir_ *line_y ) - { - - Real closest = - state.dir_ * (state.dir_ * state.encompass_infos_[j].get_point (state.dir_) - >? state.dir_ *line_y - ); - Real d = fabs (closest - y); - - convex_head_distances.push (d); - } - } - - - - if (state.dir_ * (y - state.encompass_infos_[j].stem_) < 0) - { - Real stem_dem =state.parameters_.stem_encompass_penalty_ ; - if ((l_edge && state.dir_ == UP) - || (r_edge && state.dir_ == DOWN)) - stem_dem /= 5; - - demerit += stem_dem; - } - else if (!edge) - { - Interval ext; - ext.add_point (state.encompass_infos_[j].stem_); - ext.add_point (state.encompass_infos_[j].head_); - - // ? - demerit += -state.parameters_.closeness_factor_ - * (state.dir_ - * (y - (ext[state.dir_] + state.dir_ * state.parameters_.free_head_distance_)) - 0.0) - variance_penalty = ((avg_distance / (min_dist +state.parameters_.free_head_distance_)) - 1.0) - -get_extra_encompass_infos (Slur_score_state const &state) +Slur_score_state::get_extra_encompass_infos ( ) const { Link_array encompasses - = Pointer_group_interface__extract_grobs (state.slur_, (Grob *)0, + = Pointer_group_interface__extract_grobs (slur_, (Grob *)0, "encompass-objects"); Array collision_infos; for (int i = encompasses.size (); i--; ) @@ -1066,8 +679,8 @@ get_extra_encompass_infos (Slur_score_state const &state) Spanner * small_slur = dynamic_cast (encompasses[i]); Bezier b = Slur::get_curve (small_slur); - Offset relative (small_slur->relative_coordinate (state.common_[X_AXIS], X_AXIS), - small_slur->relative_coordinate (state.common_[Y_AXIS], Y_AXIS)); + Offset relative (small_slur->relative_coordinate (common_[X_AXIS], X_AXIS), + small_slur->relative_coordinate (common_[Y_AXIS], Y_AXIS)); for (int k = 0; k < 3; k++) { @@ -1077,7 +690,7 @@ get_extra_encompass_infos (Slur_score_state const &state) Only take bound into account if small slur starts together with big slur. */ - if (hdir && small_slur->get_bound (hdir) != state.slur_->get_bound (hdir)) + if (hdir && small_slur->get_bound (hdir) != slur_->get_bound (hdir)) continue; @@ -1086,29 +699,29 @@ get_extra_encompass_infos (Slur_score_state const &state) Interval yext; yext.set_full (); - yext[state.dir_] = z[Y_AXIS] + state.dir_ * state.thickness_ * 1.0; + yext[dir_] = z[Y_AXIS] + dir_ * thickness_ * 1.0; Interval xext (-1, 1); - xext = xext * (state.thickness_*2) + z[X_AXIS]; + xext = xext * (thickness_*2) + z[X_AXIS]; Extra_collision_info info (small_slur, k - 1.0, xext, yext, - state.parameters_.extra_object_collision_); + parameters_.extra_object_collision_); collision_infos.push (info); } } else { Grob *g = encompasses [i]; - Interval xe = g->extent (state.common_[X_AXIS], X_AXIS); - Interval ye = g->extent (state.common_[Y_AXIS], Y_AXIS); + Interval xe = g->extent (common_[X_AXIS], X_AXIS); + Interval ye = g->extent (common_[Y_AXIS], Y_AXIS); Real xp = 0.0; - Real penalty = state.parameters_.extra_object_collision_; + Real penalty = parameters_.extra_object_collision_; if (Accidental_interface::has_interface (g)) { - penalty = state.parameters_.accidental_collision_; + penalty = parameters_.accidental_collision_; /* Begin copy accidental.cc */ bool parens = false; if (to_boolean (g->get_property ("cautionary"))) @@ -1131,17 +744,17 @@ get_extra_encompass_infos (Slur_score_state const &state) xp = LEFT; break ; case SHARP: - xp = 0.5 * state.dir_; + xp = 0.5 * dir_; break ; case NATURAL: - xp = -state.dir_; + xp = -dir_; break; } } } - ye.widen (state.thickness_ * 0.5); - xe.widen (state.thickness_ * 1.0); + ye.widen (thickness_ * 0.5); + xe.widen (thickness_ * 1.0); Extra_collision_info info (g, xp, xe, ye, penalty); collision_infos.push (info); } @@ -1150,271 +763,3 @@ get_extra_encompass_infos (Slur_score_state const &state) return collision_infos; } -void -score_extra_encompass (Slur_score_state const &state) -{ - for (int i = 0; i < state.scores_->size (); i++) - { - Real demerit = 0.0; - for (int j = 0; j < state.extra_encompass_infos_.size (); j++) - { - Drul_array attachment = state.scores_->elem (i).attachment_; - Interval slur_wid (attachment[LEFT][X_AXIS], attachment[RIGHT][X_AXIS]); - - /* - to prevent numerical inaccuracies in - Bezier::get_other_coordinate (). - */ - Direction d = LEFT; - bool found = false; - Real y = 0.0; - - do - { - /* - We need to check for the bound explicitly, since the - slur-ending can be almost vertical, making the Y - coordinate a bad approximation of the object-slur - distance. - */ - Item * as_item = dynamic_cast (state.extra_encompass_infos_[j].grob_); - if ((as_item - && as_item->get_column () - == state.extremes_[d] .bound_->get_column ()) - || state.extra_encompass_infos_[j].extents_[X_AXIS].contains (attachment[d][X_AXIS])) - { - y = attachment[d][Y_AXIS]; - found = true; - } - } - while (flip (&d) != LEFT); - - if (!found) - { - Real x = state.extra_encompass_infos_[j].extents_[X_AXIS] - .linear_combination (state.extra_encompass_infos_[j].idx_); - - if (!slur_wid.contains (x)) - continue; - - y = state.scores_->elem (i).curve_.get_other_coordinate (X_AXIS, x); - } - - Real dist = state.extra_encompass_infos_[j].extents_[Y_AXIS].distance (y); - demerit += - fabs (0 >? (state.parameters_.extra_encompass_free_distance_ - dist)) / - state.parameters_.extra_encompass_free_distance_ - * state.extra_encompass_infos_[j].penalty_; - } -#if DEBUG_SLUR_QUANTING - (*state.scores_)[i].score_card_ += to_string ("X%.2f", demerit); -#endif - (*state.scores_)[i].score_ += demerit; - } -} - -void -score_edges (Slur_score_state const &state) -{ - for (int i = 0; i < state.scores_->size (); i++) - { - Direction d = LEFT; - Slur_score &config = state.scores_->elem_ref (i); - Offset dz = config.attachment_[RIGHT] - config.attachment_[LEFT]; - Real slope = dz[Y_AXIS] / dz[X_AXIS]; - do - { - Real y = config.attachment_[d][Y_AXIS]; - Real dy = fabs (y - state.base_attachments_[d][Y_AXIS]); - - Real factor = state.parameters_.edge_attraction_factor_; - Real demerit = factor * dy; - if (state.extremes_[d].stem_ - && state.extremes_[d].stem_dir_ == state.dir_ - && !Stem::get_beaming (state.extremes_[d].stem_, -d) - ) - demerit /= 5; - - demerit *= exp (state.dir_ * d * slope - * state.parameters_.edge_slope_exponent_ ); - - (*state.scores_)[i].score_ += demerit; -#if DEBUG_SLUR_QUANTING - (*state.scores_)[i].score_card_ += to_string ("E%.2f", demerit); -#endif - } - while (flip (&d) != LEFT); - } -} - -void -score_slopes (Slur_score_state const &state) -{ - Real dy = state.musical_dy_; - for (int i = 0; i < state.scores_->size (); i++) - { - Offset slur_dz = (*state.scores_)[i].attachment_[RIGHT] - - (*state.scores_)[i].attachment_[LEFT]; - Real slur_dy = slur_dz[Y_AXIS]; - Real demerit = 0.0; - - demerit += ((fabs (slur_dy / slur_dz[X_AXIS]) - - state.parameters_.max_slope_) >? 0) - * state.parameters_.max_slope_factor_; - - /* 0.2: account for staffline offset. */ - Real max_dy = (fabs (dy) + 0.2); - if (state.edge_has_beams_) - max_dy += 1.0; - - if (!state.is_broken_) - demerit += state.parameters_.steeper_slope_factor_ - * ((fabs (slur_dy) -max_dy) >? 0); - - demerit += ((fabs (slur_dy/slur_dz[X_AXIS]) - - state.parameters_.max_slope_) >? 0) - * state.parameters_.max_slope_factor_; - - if (sign (dy) == 0 - && sign (slur_dy) != 0 - && !state.is_broken_) - demerit += state.parameters_.non_horizontal_penalty_; - - if (sign (dy) - && !state.is_broken_ - && sign (slur_dy) - && sign (slur_dy) != sign (dy)) - demerit += state.edge_has_beams_ - ? state.parameters_.same_slope_penalty_ / 10 - : state.parameters_.same_slope_penalty_; - -#if DEBUG_SLUR_QUANTING - (*state.scores_)[i].score_card_ += to_string ("S%.2f", demerit); -#endif - (*state.scores_)[i].score_ += demerit; - } - -} - - -Real -fit_factor (Offset dz_unit, Offset dz_perp, - Bezier curve, Direction d, Array const &avoid) -{ - Real fit_factor = 0.0; - Offset x0 = curve.control_[0]; - curve.translate (-x0); - curve.rotate (-dz_unit.arg ()); - curve.scale (1, d); - - Interval curve_xext; - curve_xext.add_point (curve.control_[0][X_AXIS]); - curve_xext.add_point (curve.control_[3][X_AXIS]); - - for (int i = 0; i < avoid.size (); i++) - { - Offset z = (avoid[i] - x0) ; - Offset p (dot_product (z, dz_unit), - d* dot_product (z, dz_perp)); - if (!curve_xext.contains (p[X_AXIS])) - continue; - - Real y = curve.get_other_coordinate (X_AXIS, p[X_AXIS]); - if (y) - { - fit_factor = fit_factor >? (p[Y_AXIS] / y); - } - } - return fit_factor; -} - - -Bezier -get_bezier (Slur_score_state const &state, - Drul_array attachments, - Real r_0, Real h_inf) -{ - Link_array encompasses = state.columns_; - - Array avoid; - for (int i = 0; i < encompasses.size (); i++) - { - if (state.extremes_[LEFT].note_column_ == encompasses[i] - || state.extremes_[RIGHT].note_column_ == encompasses[i]) - continue; - - Encompass_info inf (get_encompass_info (state, encompasses[i])); - - Real y = state.dir_ * ((state.dir_ * inf.head_) >? (state.dir_ *inf.stem_)); - - avoid.push (Offset (inf.x_, y + state.dir_ * state.parameters_.free_head_distance_)); - } - - Link_array extra_encompasses - = Pointer_group_interface__extract_grobs (state.slur_, (Grob *)0, "encompass-objects"); - for (int i = 0; i < extra_encompasses.size (); i++) - if (Slur::has_interface (extra_encompasses[i])) - { - Grob * small_slur = extra_encompasses[i]; - Bezier b = Slur::get_curve (small_slur); - - Offset z = b.curve_point (0.5); - z += Offset (small_slur->relative_coordinate (state.common_[X_AXIS], X_AXIS), - small_slur->relative_coordinate (state.common_[Y_AXIS], Y_AXIS)); - - z[Y_AXIS] += state.dir_ * state.parameters_.free_slur_distance_; - avoid.push (z); - } - - Offset dz = attachments[RIGHT]- attachments[LEFT];; - Offset dz_unit = dz; - dz_unit *= 1 / dz.length (); - Offset dz_perp = dz_unit * Offset (0, 1); - - Real indent, height; - get_slur_indent_height (&indent, &height, dz.length (), h_inf, r_0); - - Real excentricity = robust_scm2double (state.slur_->get_property ("excentricity"), 0); - Bezier curve; - - Real x1 = (excentricity + indent); - Real x2 = (excentricity - indent); - curve.control_[0] = attachments[LEFT]; - curve.control_[1] = attachments[LEFT] + dz_perp * height * state.dir_ + dz_unit * x1; - curve.control_[2] = attachments[RIGHT] + dz_perp * height * state.dir_ - + dz_unit * x2; - curve.control_[3] = attachments[RIGHT]; - - Real ff = fit_factor (dz_unit, dz_perp, curve, state.dir_, avoid); - Real len = dz.length (); - - /* This condition, - - len^2 > 4h^2 + 3 (i 1/3len)^2 - 1/3 len^2 - - is equivalent to: - - |bez' (0)| < | bez' (.5)| - - when (control2 - control1) has the same direction as - (control3 - control0). */ - - Real a1 = sqr (len) / 3.0; - Real a2 = 0.75 * sqr (indent + len / 3.0); - Real max_h; - if (a1 >= a2) - max_h = sqrt (a1 - a2); - else - { - programming_error ("FIXME: max_h is broken; setting to length / 3"); - max_h = len / 3.0; - } - height = height >? ((height * ff) get_property ("quant-score"); if (to_boolean (me->get_paper () @@ -200,8 +201,47 @@ Slur::outside_slur_callback (SCM grob, SCM axis) return scm_make_real (offset); } +static Direction +get_default_dir (Grob*me) +{ + Link_array encompasses + = Pointer_group_interface__extract_grobs (me, (Grob*) 0, "note-columns"); + + Direction d = DOWN; + for (int i= 0; i < encompasses.size (); i ++) + { + if (Note_column::dir (encompasses[i]) < 0) + { + d = UP; + break; + } + } + return d; +} + + +MAKE_SCHEME_CALLBACK (Slur, after_line_breaking,1); +SCM +Slur::after_line_breaking (SCM smob) +{ + Spanner *me = dynamic_cast (unsmob_grob (smob)); + if (!scm_ilength (me->get_property ("note-columns"))) + { + me->suicide (); + return SCM_UNSPECIFIED; + } + + if (!get_grob_direction (me)) + set_grob_direction (me, get_default_dir (me)); + + if (scm_ilength (me->get_property ("control-points")) < 4) + set_slur_control_points (me); + + return SCM_UNSPECIFIED; +} ADD_INTERFACE (Slur, "slur-interface", "A slur", "quant-score excentricity encompass-objects control-points dashed slur-details direction height-limit note-columns ratio thickness"); + diff --git a/po/lilypond.pot b/po/lilypond.pot index c5f0fefa95..fb44319090 100644 --- a/po/lilypond.pot +++ b/po/lilypond.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2004-09-15 00:34+0200\n" +"POT-Creation-Date: 2004-10-08 17:12+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -126,6 +126,14 @@ msgid "" "\n" msgstr "" +#. Bug in option parser: --output=foe is taken as an abbreviation +#. for --output-format. +#. Bug in option parser: --output=foe is taken as an abbreviation +#. for --output-format. +#. Bug in option parser: --output=foe is taken as an abbreviation +#. for --output-format. +#. Bug in option parser: --output=foe is taken as an abbreviation +#. for --output-format. #. Bug in option parser: --output=foe is taken as an abbreviation #. for --output-format. #. Bug in option parser: --output=foe is taken as an abbreviation @@ -597,22 +605,25 @@ msgid "Continuing; crossing fingers" msgstr "" #: accidental-engraver.cc:194 lily/accidental-engraver.cc:201 +#: lily/accidental-engraver.cc:243 #, c-format msgid "Accidental typesetting list must begin with context-name: %s" msgstr "" #: accidental-engraver.cc:222 lily/accidental-engraver.cc:229 +#: lily/accidental-engraver.cc:271 #, c-format msgid "ignoring unknown accidental: %s" msgstr "" #: accidental-engraver.cc:239 lily/accidental-engraver.cc:246 +#: lily/accidental-engraver.cc:288 #, c-format msgid "Accidental rule must be pair or context-name; Found %s" msgstr "" #: accidental.cc:221 key-signature-interface.cc:137 lily/accidental.cc:221 -#: lily/key-signature-interface.cc:137 +#: lily/key-signature-interface.cc:137 lily/accidental.cc:222 #, c-format msgid "accidental `%s' not found" msgstr "" @@ -622,6 +633,10 @@ msgstr "" msgid "Error parsing AFM file: `%s'" msgstr "" +#. FIXME: broken sentence +#. FIXME: broken sentence +#. FIXME: broken sentence +#. FIXME: broken sentence #. FIXME: broken sentence #. FIXME: broken sentence #. FIXME: broken sentence @@ -722,7 +737,7 @@ msgstr "" msgid "removing beam with less than two stems" msgstr "" -#: beam.cc:1038 lily/beam.cc:1038 lily/beam.cc:1063 +#: beam.cc:1038 lily/beam.cc:1038 lily/beam.cc:1063 lily/beam.cc:1065 msgid "no viable initial configuration found: may not find good beam slope" msgstr "" @@ -736,6 +751,30 @@ msgstr "" msgid "can't change `%s' to `%s'" msgstr "" +#. +#. We could change the current translator's id, but that would make +#. errors hard to catch +#. +#. last->translator_id_string () = get_change ()->change_to_id_string (); +#. +#. +#. We could change the current translator's id, but that would make +#. errors hard to catch +#. +#. last->translator_id_string () = get_change ()->change_to_id_string (); +#. +#. +#. We could change the current translator's id, but that would make +#. errors hard to catch +#. +#. last->translator_id_string () = get_change ()->change_to_id_string (); +#. +#. +#. We could change the current translator's id, but that would make +#. errors hard to catch +#. +#. last->translator_id_string () = get_change ()->change_to_id_string (); +#. #. #. We could change the current translator's id, but that would make #. errors hard to catch @@ -810,12 +849,12 @@ msgstr "" msgid "can't find: `%s'" msgstr "" -#: context.cc:164 lily/context.cc:164 +#: context.cc:164 lily/context.cc:164 lily/context.cc:163 #, c-format msgid "Cannot find or create `%s' called `%s'" msgstr "" -#: context.cc:201 lily/context.cc:201 +#: context.cc:201 lily/context.cc:201 lily/context.cc:200 #, c-format msgid "can't find or create: `%s'" msgstr "" @@ -831,22 +870,27 @@ msgstr "" #: dynamic-engraver.cc:186 span-dynamic-performer.cc:86 #: lily/dynamic-engraver.cc:186 lily/span-dynamic-performer.cc:86 +#: lily/dynamic-engraver.cc:185 msgid "can't find start of (de)crescendo" msgstr "" #: dynamic-engraver.cc:196 lily/dynamic-engraver.cc:196 +#: lily/dynamic-engraver.cc:195 msgid "already have a decrescendo" msgstr "" #: dynamic-engraver.cc:198 lily/dynamic-engraver.cc:198 +#: lily/dynamic-engraver.cc:197 msgid "already have a crescendo" msgstr "" #: dynamic-engraver.cc:201 lily/dynamic-engraver.cc:201 +#: lily/dynamic-engraver.cc:200 msgid "Cresc started here" msgstr "" #: dynamic-engraver.cc:307 lily/dynamic-engraver.cc:317 +#: lily/dynamic-engraver.cc:321 msgid "unterminated (de)crescendo" msgstr "" @@ -856,18 +900,19 @@ msgstr "" msgid "Junking event: `%s'" msgstr "" -#: event.cc:49 lily/event.cc:49 +#: event.cc:49 lily/event.cc:49 lily/music.cc:184 #, c-format msgid "Transposition by %s makes alteration larger than two" msgstr "" -#: event.cc:72 lily/event.cc:72 +#: event.cc:72 lily/event.cc:72 lily/event.cc:50 #, c-format msgid "octave check failed; expected %s, found: %s" msgstr "" #: extender-engraver.cc:141 extender-engraver.cc:150 #: lily/extender-engraver.cc:141 lily/extender-engraver.cc:150 +#: lily/extender-engraver.cc:140 lily/extender-engraver.cc:149 msgid "unterminated extender" msgstr "" @@ -879,7 +924,7 @@ msgstr "" msgid "Unterminated glissando." msgstr "" -#: global-context.cc:150 lily/global-context.cc:150 +#: global-context.cc:150 lily/global-context.cc:150 lily/global-context.cc:157 #, c-format msgid "can't find `%s' context" msgstr "" @@ -913,11 +958,11 @@ msgstr "" msgid "Grob `%s' has no interface for property `%s'" msgstr "" -#: hairpin.cc:92 lily/hairpin.cc:107 +#: hairpin.cc:92 lily/hairpin.cc:107 lily/hairpin.cc:106 msgid "decrescendo too small" msgstr "" -#: hairpin.cc:93 lily/hairpin.cc:108 +#: hairpin.cc:93 lily/hairpin.cc:108 lily/hairpin.cc:107 msgid "crescendo too small" msgstr "" @@ -997,20 +1042,20 @@ msgstr "" msgid "(load path: `%s')" msgstr "" -#: lily-guile.cc:559 lily/lily-guile.cc:559 +#: lily-guile.cc:559 lily/lily-guile.cc:559 lily/lily-guile.cc:575 #, c-format msgid "Can't find property type-check for `%s' (%s)." msgstr "" -#: lily-guile.cc:562 lily/lily-guile.cc:562 +#: lily-guile.cc:562 lily/lily-guile.cc:562 lily/lily-guile.cc:578 msgid "Perhaps you made a typing error?" msgstr "" -#: lily-guile.cc:568 lily/lily-guile.cc:568 +#: lily-guile.cc:568 lily/lily-guile.cc:568 lily/lily-guile.cc:584 msgid "Doing assignment anyway." msgstr "" -#: lily-guile.cc:582 lily/lily-guile.cc:582 +#: lily-guile.cc:582 lily/lily-guile.cc:582 lily/lily-guile.cc:598 #, c-format msgid "Type check for `%s' failed; value `%s' must be of type `%s'" msgstr "" @@ -1132,6 +1177,10 @@ msgid "" "%s and others." msgstr "" +#. No version number or newline here. It confuses help2man. +#. No version number or newline here. It confuses help2man. +#. No version number or newline here. It confuses help2man. +#. No version number or newline here. It confuses help2man. #. No version number or newline here. It confuses help2man. #. No version number or newline here. It confuses help2man. #. No version number or newline here. It confuses help2man. @@ -1155,12 +1204,12 @@ msgstr "" msgid "For more information, see %s" msgstr "" -#: main.cc:410 lily/main.cc:410 +#: main.cc:410 lily/main.cc:410 lily/main.cc:412 #, c-format msgid "This option is for developers only." msgstr "" -#: main.cc:411 lily/main.cc:411 +#: main.cc:411 lily/main.cc:411 lily/main.cc:413 #, c-format msgid "Read the sources for more information." msgstr "" @@ -1214,6 +1263,18 @@ msgstr "" msgid "could not write file: `%s'" msgstr "" +#. +#. music for the softenon children? +#. +#. +#. music for the softenon children? +#. +#. +#. music for the softenon children? +#. +#. +#. music for the softenon children? +#. #. #. music for the softenon children? #. @@ -1260,7 +1321,7 @@ msgstr "" msgid "Preprocessing graphical objects..." msgstr "" -#: parse-scm.cc:77 lily/parse-scm.cc:77 +#: parse-scm.cc:77 lily/parse-scm.cc:77 lily/parse-scm.cc:84 msgid "GUILE signaled an error for the expression beginning here" msgstr "" @@ -1319,11 +1380,11 @@ msgstr "" msgid "Not a grob name, `%s'." msgstr "" -#: quote-iterator.cc:108 lily/quote-iterator.cc:124 +#: quote-iterator.cc:108 lily/quote-iterator.cc:124 lily/quote-iterator.cc:125 msgid "No events found for \\quote" msgstr "" -#: quote-iterator.cc:183 lily/quote-iterator.cc:199 +#: quote-iterator.cc:183 lily/quote-iterator.cc:199 lily/quote-iterator.cc:204 #, c-format msgid "In quotation: junking event %s" msgstr "" @@ -1400,26 +1461,31 @@ msgid "Install the ec-mftraced package from %s. Aborting" msgstr "" #: score.cc:100 score.cc:126 lily/score.cc:100 lily/score.cc:126 +#: lily/score.cc:102 lily/score.cc:128 msgid "Need music in a score" msgstr "" -#: score.cc:116 lily/score.cc:116 +#: score.cc:116 lily/score.cc:116 lily/score.cc:118 msgid "Interpreting music... " msgstr "" -#: score.cc:137 lily/score.cc:137 +#: score.cc:137 lily/score.cc:137 lily/score.cc:139 #, c-format msgid "elapsed time: %.2f seconds" msgstr "" -#: score.cc:312 lily/score.cc:312 +#: score.cc:312 lily/score.cc:312 lily/score.cc:322 msgid "Already have music in score" msgstr "" -#: score.cc:313 lily/score.cc:313 +#: score.cc:313 lily/score.cc:313 lily/score.cc:323 msgid "This is the previous music" msgstr "" +#. FIXME: +#. FIXME: +#. FIXME: +#. FIXME: #. FIXME: #. FIXME: #. FIXME: @@ -1431,6 +1497,10 @@ msgstr "" msgid "Scheme encoding: " msgstr "" +#. this shouldn't happen, but let's continue anyway. +#. this shouldn't happen, but let's continue anyway. +#. this shouldn't happen, but let's continue anyway. +#. this shouldn't happen, but let's continue anyway. #. this shouldn't happen, but let's continue anyway. #. this shouldn't happen, but let's continue anyway. #. this shouldn't happen, but let's continue anyway. @@ -1439,7 +1509,7 @@ msgstr "" msgid "Separation_item: I've been drinking too much" msgstr "" -#: simple-spacer.cc:489 lily/simple-spacer.cc:489 +#: simple-spacer.cc:489 lily/simple-spacer.cc:489 lily/simple-spacer.cc:484 #, c-format msgid "No spring between column %d and next one" msgstr "" @@ -1467,6 +1537,10 @@ msgstr "" msgid "tremolo duration is too long" msgstr "" +#. FIXME: +#. FIXME: +#. FIXME: +#. FIXME: #. FIXME: #. FIXME: #. FIXME: @@ -1483,12 +1557,12 @@ msgstr "" msgid "Weird stem size; check for narrow beams" msgstr "" -#: stem.cc:575 lily/stem.cc:575 +#: stem.cc:575 lily/stem.cc:575 lily/stem.cc:574 #, c-format msgid "flag `%s' not found" msgstr "" -#: stem.cc:586 lily/stem.cc:586 +#: stem.cc:586 lily/stem.cc:586 lily/stem.cc:585 #, c-format msgid "flag stroke `%s' not found" msgstr "" @@ -1519,6 +1593,14 @@ msgstr "" msgid "unterminated text spanner" msgstr "" +#. Not using ngettext's plural feature here, as this message is +#. more of a programming error. +#. Not using ngettext's plural feature here, as this message is +#. more of a programming error. +#. Not using ngettext's plural feature here, as this message is +#. more of a programming error. +#. Not using ngettext's plural feature here, as this message is +#. more of a programming error. #. Not using ngettext's plural feature here, as this message is #. more of a programming error. #. Not using ngettext's plural feature here, as this message is @@ -1548,6 +1630,26 @@ msgstr "" msgid "no one to print a tuplet start bracket" msgstr "" +#. +#. Todo: should make typecheck? +#. +#. OTOH, Tristan Keuris writes 8/20 in his Intermezzi. +#. +#. +#. Todo: should make typecheck? +#. +#. OTOH, Tristan Keuris writes 8/20 in his Intermezzi. +#. +#. +#. Todo: should make typecheck? +#. +#. OTOH, Tristan Keuris writes 8/20 in his Intermezzi. +#. +#. +#. Todo: should make typecheck? +#. +#. OTOH, Tristan Keuris writes 8/20 in his Intermezzi. +#. #. #. Todo: should make typecheck? #. @@ -1568,6 +1670,14 @@ msgstr "" msgid "Found strange time signature %d/%d." msgstr "" +#. If there is no such symbol, we default to the numbered style. +#. (Here really with a warning!) +#. If there is no such symbol, we default to the numbered style. +#. (Here really with a warning!) +#. If there is no such symbol, we default to the numbered style. +#. (Here really with a warning!) +#. If there is no such symbol, we default to the numbered style. +#. (Here really with a warning!) #. If there is no such symbol, we default to the numbered style. #. (Here really with a warning!) #. If there is no such symbol, we default to the numbered style. @@ -1769,3 +1879,15 @@ msgstr "" #: lily.scm:614 msgid "error: failed files: " msgstr "" + +#: lily/includable-lexer.cc:50 +msgid "include files are not allowed in safe mode" +msgstr "" + +#: lily/phrasing-slur-engraver.cc:116 +msgid "unterminated phrasing slur" +msgstr "" + +#: lily/score.cc:328 +msgid "Error found in this music expression. Ignoring it" +msgstr ""