From 3b9d63b1f11e1c8cfb738d7aaf385282576f0043 Mon Sep 17 00:00:00 2001 From: Han-Wen Nienhuys Date: Wed, 1 Sep 2004 23:17:59 +0000 Subject: [PATCH] * lily/simple-spacer.cc (LY_DEFINE): ly_solve_spring_rod_problem: export spacing routine to SCM. * lily/include/simple-spacer.hh (struct Simple_spacer_wrapper): new class, separate Grobs from interface. --- ChangeLog | 8 + lily/break-algorithm.cc | 15 +- lily/gourlay-breaking.cc | 6 +- lily/include/break-algorithm.hh | 11 +- lily/include/lily-proto.hh | 37 ++-- lily/include/simple-spacer.hh | 32 +++- lily/simple-spacer.cc | 288 +++++++++++++++++++++----------- 7 files changed, 255 insertions(+), 142 deletions(-) diff --git a/ChangeLog b/ChangeLog index 2cec1be1c4..007620b4f7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2004-09-02 Han-Wen Nienhuys + + * lily/simple-spacer.cc (LY_DEFINE): ly_solve_spring_rod_problem: + export spacing routine to SCM. + + * lily/include/simple-spacer.hh (struct Simple_spacer_wrapper): + new class, separate Grobs from interface. + 2004-09-01 Han-Wen Nienhuys * lily/include/lily-guile.hh: compatibility glue for 1.6 diff --git a/lily/break-algorithm.cc b/lily/break-algorithm.cc index 72d7021e95..2fe726b5b8 100644 --- a/lily/break-algorithm.cc +++ b/lily/break-algorithm.cc @@ -54,19 +54,18 @@ Break_algorithm::find_breaks () const } -Simple_spacer* +Simple_spacer_wrapper* Break_algorithm::generate_spacing_problem (Link_array const &curline, Interval line) const { - Simple_spacer * sp = new Simple_spacer; - + Simple_spacer_wrapper * spw = new Simple_spacer_wrapper; + Simple_spacer * sp = spw->spacer_; + /* this is hardcoded, but this shouldn't happen anyway. used to be get_dimension (ly_symbol2scm ("loose_column_distance")); */ sp->default_space_ = 1.0; - - sp->indent_ = line[LEFT]; /* @@ -79,10 +78,8 @@ Break_algorithm::generate_spacing_problem (Link_array const &curline, else sp->line_len_ = line.length (); - sp->add_columns (curline); - - - return sp; + spw->add_columns (curline); + return spw; } Break_algorithm::Break_algorithm () diff --git a/lily/gourlay-breaking.cc b/lily/gourlay-breaking.cc index 9cfd6b531f..a8245fe7d7 100644 --- a/lily/gourlay-breaking.cc +++ b/lily/gourlay-breaking.cc @@ -66,6 +66,10 @@ print_break_nodes (Array const & arr) This algorithms is adapted from the OSU Tech report on breaking lines. this function is longish, but not very complicated. + + TODO: should rewrite. See the function in scm/page-layout.scm for + inspiration. + */ Array Gourlay_breaking::do_solve () const @@ -107,7 +111,7 @@ Gourlay_breaking::do_solve () const Interval line_dims = line_dimensions_int (pscore_->paper_, optimal_paths[start_idx].line_); - Simple_spacer * sp = generate_spacing_problem (line, line_dims); + Simple_spacer_wrapper * sp = generate_spacing_problem (line, line_dims); bool last_line = break_idx == breaks.size ()-1; bool ragged = ragged_right || (last_line && ragged_last); diff --git a/lily/include/break-algorithm.hh b/lily/include/break-algorithm.hh index f9b7385d06..9729d9ca99 100644 --- a/lily/include/break-algorithm.hh +++ b/lily/include/break-algorithm.hh @@ -27,20 +27,12 @@ protected: Paper_score *pscore_; Real linewidth_; - /// search all pcols which are breakable. Link_array find_breaks () const; - Array find_break_indices () const; - - - /// helper: solve for the columns in #curline#. void solve_line (Column_x_positions*) const; - - /// does curline fit on the paper? bool feasible (Link_array const &) const; - - Simple_spacer* generate_spacing_problem (Link_array const &, Interval) const; + Simple_spacer_wrapper* generate_spacing_problem (Link_array const &, Interval) const; virtual Array do_solve () const=0; @@ -48,7 +40,6 @@ public: Simple_spacer* (*get_line_spacer) (); Break_algorithm (); void set_pscore (Paper_score*); - Array solve () const; }; diff --git a/lily/include/lily-proto.hh b/lily/include/lily-proto.hh index 0650c5683c..841de441db 100644 --- a/lily/include/lily-proto.hh +++ b/lily/include/lily-proto.hh @@ -37,7 +37,6 @@ class Beaming_info_list; class Bezier; class Bezier_bow; class Book; -class Output_def; class Break_algorithm; class Change_iterator; class Change_translator; @@ -49,27 +48,31 @@ class Context_specced_music; class Engraver; class Engraver; class Engraver_group_engraver; +class Event; +class Event_chord; +class Event_chord_iterator; class Folded_repeat_iterator; class Font_metric; class Font_size_engraver; class Global_context; -class Grace_fixup; class Gourlay_breaking; +class Grace_fixup; class Grace_iterator; class Grace_music; +class Grob; class Hara_kiri_engraver; class Hara_kiri_line_group_engraver; class Includable_lexer; -class Input_file_results; class Input; +class Input_file_results; class Item; class Key_performer; class Keyword_ent; class Keyword_table; -class Ligature_engraver; class Ligature_bracket_engraver; +class Ligature_engraver; +class Lily_lexer; class Line_group_engraver_group; -class System; class Lookup; class Lyric_combine_music; class Lyric_combine_music_iterator; @@ -93,51 +96,47 @@ class Midi_tempo; class Midi_text; class Midi_time_signature; class Midi_track; -class Stencil; +class Modified_font_metric; class Moment; class Music; class Music_iterator; class Music_list; class Music_output; -class Output_def; class Music_sequence; class Music_wrapper; class Music_wrapper_iterator; -class Page; -class Pitch; -class Lily_lexer; class Note_performer; +class Output_def; +class Output_def; +class Output_def; class Output_property; +class Page; class Paper_book; class Paper_column; -class Output_def; -class Paper_system; class Paper_outputter; class Paper_score; class Paper_stream; +class Paper_system; class Performance; class Performer; class Performer_group_performer; class Piano_bar_engraver; +class Pitch; class Pitch_squash_engraver; class Property_iterator; class Rational; class Relative_octave_music; class Repeated_music; -class Event; -class Event_chord; -class Event_chord_iterator; -class Modified_font_metric; class Scheme_hash_table; class Score; -class Grob; -class Score_engraver; class Score_context; +class Score_engraver; class Score_performer; class Sequential_music; class Sequential_music_iterator; class Simple_music_iterator; class Simple_spacer; +class Simple_spacer_wrapper; class Simultaneous_music; class Simultaneous_music_iterator; class Slur_bezier_bow; @@ -145,8 +144,10 @@ class Span_score_bar_engraver; class Spanner; class Staff_group_bar_engraver; class Staff_performer; +class Stencil; class Swallow_engraver; class Swallow_performer; +class System; class Tempo_performer; class Tex_font_metric; class Tie; diff --git a/lily/include/simple-spacer.hh b/lily/include/simple-spacer.hh index bfd8b38b65..755bdb7008 100644 --- a/lily/include/simple-spacer.hh +++ b/lily/include/simple-spacer.hh @@ -12,7 +12,7 @@ #include "parray.hh" #include "lily-proto.hh" - +#include "smobs.hh" struct Spring_description { @@ -27,31 +27,47 @@ struct Spring_description bool is_sane () const; }; -struct Simple_spacer +class Simple_spacer { +public: Array springs_; - Link_array spaced_cols_; - Link_array loose_cols_; Real force_; Real indent_; Real line_len_; Real default_space_; int active_count_; - + Simple_spacer (); - void solve (Column_x_positions *, bool); - void add_columns (Link_array const &); + void my_solve_linelen (); void my_solve_natural_len (); Real active_springs_stiffness () const; Real range_stiffness (int, int) const; void add_rod (int l, int r, Real dist); + void add_spring (Real, Real); Real range_ideal_len (int l, int r) const; - Real is_activelocking_force ()const; + Real active_blocking_force ()const; Real configuration_length ()const; void set_active_states (); bool is_active () const; + + DECLARE_SIMPLE_SMOBS(Simple_spacer, ); +}; + + +struct Simple_spacer_wrapper +{ + Simple_spacer *spacer_; + Link_array spaced_cols_; + Link_array loose_cols_; + + Simple_spacer_wrapper (); + void add_columns (Link_array const &); + void solve (Column_x_positions *, bool); + ~Simple_spacer_wrapper(); +private: + Simple_spacer_wrapper(Simple_spacer_wrapper const&); }; #endif /* SIMPLE_SPACER_HH */ diff --git a/lily/simple-spacer.cc b/lily/simple-spacer.cc index 746da5826a..08fd455e15 100644 --- a/lily/simple-spacer.cc +++ b/lily/simple-spacer.cc @@ -129,7 +129,7 @@ Simple_spacer::range_stiffness (int l, int r) const } Real -Simple_spacer::is_activelocking_force () const +Simple_spacer::active_blocking_force () const { Real bf = - infinity_f; for (int i=0; i < springs_.size (); i++) @@ -180,7 +180,7 @@ Simple_spacer::my_solve_linelen () { while (is_active ()) { - force_ = is_activelocking_force (); + force_ = active_blocking_force (); Real conf = configuration_length (); if (conf < line_len_) @@ -199,7 +199,7 @@ Simple_spacer::my_solve_natural_len () { while (is_active ()) { - force_ = is_activelocking_force () >? 0.0; + force_ = active_blocking_force () >? 0.0; if (force_ < 1e-8) // ugh., break; @@ -208,87 +208,107 @@ Simple_spacer::my_solve_natural_len () } } -void -Simple_spacer::add_columns (Link_array const &icols) +LY_DEFINE(ly_solve_spring_rod_problem, "ly:solve-spring-rod-problem", + 4, 1, 0, (SCM springs, SCM rods, SCM length, SCM ragged), + "Solve a spring and rod problem for @var{count} objects, that " + "are connected by @var{count-1} springs, and an arbitrary number of rods " + "Springs have the format (ideal, hooke) and rods (idx1, idx2, distance) " + "@var{length} is a number, @var{ragged} a boolean " + "Return: a list containing the force (#f for non-satisfied constraints)" + "followed by positions of the objects." + ) { - Link_array cols (icols); - - for (int i = cols.size (); i--;) - if (ly_c_pair_p (cols[i]->get_property ("between-cols"))) - { - loose_cols_.push (cols[i]); - cols.del (i); - } - - spaced_cols_ = cols; - for (int i=0; i < cols.size () - 1; i++) + SCM_ASSERT_TYPE (scm_ilength (springs) >= 0, springs, SCM_ARG1, __FUNCTION__, "list of springs"); + SCM_ASSERT_TYPE (scm_ilength (rods) >= 0, rods, SCM_ARG2, __FUNCTION__, "list of rods"); + SCM_ASSERT_TYPE (scm_is_number (length) || length == SCM_BOOL_F, + length, SCM_ARG3, __FUNCTION__, "number or #f"); + + bool is_ragged = ragged == SCM_BOOL_T; + Simple_spacer spacer; + for (SCM s = springs; ly_c_pair_p (s); s = ly_cdr (s)) { - Spring_smob *spring = 0; + Real ideal = scm_to_double (ly_caar (s)); + Real hooke = scm_to_double (ly_cadar (s)); - for (SCM s = cols[i]->get_property ("ideal-distances"); - !spring && ly_c_pair_p (s); - s = ly_cdr (s)) - { - Spring_smob *sp = unsmob_spring (ly_car (s)); - - - if (sp->other_ == cols[i+1]) - spring = sp; - } - - Spring_description desc; - if (spring) - { - desc.ideal_ = spring->distance_; - desc.hooke_ = spring->strength_; - } - else - { - programming_error (_f ("No spring between column %d and next one", - Paper_column::get_rank (cols[i]) - )); - desc.hooke_ = 1.0; - desc.ideal_ = default_space_; + spacer.add_spring (ideal, hooke); + } - continue; - } + for (SCM s = rods; ly_c_pair_p (s); s = ly_cdr (s)) + { + SCM entry = ly_car (s); + int l = scm_to_int (ly_car (s)); + int r = scm_to_int (ly_cadr (s)); + entry = ly_cddr (s); + + Real distance = scm_to_double (ly_car (s)); + spacer.add_rod (l, r, distance); + } - if (!desc.is_sane ()) - { - programming_error ("Insane spring found. Setting to unit spring."); + if (is_ragged) + spacer.my_solve_natural_len (); + else + { + spacer.line_len_ = scm_to_double (length); + + spacer.my_solve_linelen (); + } - desc.hooke_ = 1.0; - desc.ideal_ = 1.0; - } + Array posns; + posns.push (0.0); + for (int i = 0; i < spacer.springs_.size(); i++) + { + Real l = spacer.springs_[i].length ((is_ragged) ? 0.0 : spacer.force_); + posns.push (posns.top() + l); + } - if (isinf (desc.hooke_)) - { - desc.is_active_ = false; - springs_.push (desc); - } + SCM force_return = scm_from_double (spacer.force_); + if (is_ragged) + { + Real len = posns.top (); + if (spacer.line_len_ - len >= 0) + force_return = scm_from_double ((spacer.line_len_ - len) + * spacer.active_springs_stiffness ()); else - { - desc.block_force_ = - desc.hooke_ * desc.ideal_; // block at distance 0 - springs_.push (desc); - - active_count_ ++; - } + force_return = SCM_BOOL_F; } - - for (int i=0; i < cols.size () - 1; i++) + + SCM retval= SCM_EOL; + for (int i = posns.size(); i--;) { - for (SCM s = Spaceable_grob::get_minimum_distances (cols[i]); - ly_c_pair_p (s); s = ly_cdr (s)) - { - Grob * other = unsmob_grob (ly_caar (s)); - int oi = cols.find_index (other); - if (oi >= 0) - { - add_rod (i, oi, ly_scm2double (ly_cdar (s))); - } - } + retval = scm_cons (scm_from_double (posns[i]), retval); } + + retval = scm_cons (force_return, retval); + return retval; +} + + +/****************************************************************/ + +Spring_description::Spring_description () +{ + ideal_ =0.0; + hooke_ =0.0; + is_active_ = true; + block_force_ = 0.0; +} + + +bool +Spring_description::is_sane () const +{ + return (hooke_ > 0) && !isinf (ideal_) && !isnan (ideal_); +} + +Real +Spring_description::length (Real f) const +{ + if (!is_active_) + f = block_force_; + return ideal_ + f / hooke_ ; } +/****************************************************************/ + /* @@ -306,23 +326,23 @@ Simple_spacer::add_columns (Link_array const &icols) */ void -Simple_spacer::solve (Column_x_positions *positions, bool ragged) +Simple_spacer_wrapper::solve (Column_x_positions *positions, bool ragged) { if (ragged) - my_solve_natural_len (); + spacer_->my_solve_natural_len (); else - my_solve_linelen (); + spacer_->my_solve_linelen (); - positions->force_ = force_; + positions->force_ = spacer_->force_; /* We used to have a penalty for compression, no matter what, but that fucked up wtk1-fugue2 (taking 3 full pages.) */ - positions->config_.push (indent_); - for (int i=0; i config_.push (spacer_->indent_); + for (int i=0; i < spacer_->springs_.size (); i++) { - Real l = springs_[i].length ((ragged) ? 0.0 : force_); + Real l = spacer_->springs_[i].length ((ragged) ? 0.0 : spacer_->force_); positions->config_.push (positions->config_.top () + l); /* we have l>= 0 here, up to rounding errors @@ -336,8 +356,9 @@ Simple_spacer::solve (Column_x_positions *positions, bool ragged) if (ragged) { Real len = positions->config_.top (); - if (line_len_ - len >= 0) - positions->force_ = ((line_len_ - len) * active_springs_stiffness ()); + if (spacer_->line_len_ - len >= 0) + positions->force_ = ((spacer_->line_len_ - len) + * spacer_->active_springs_stiffness ()); else { positions->force_ = 0.0; @@ -352,7 +373,7 @@ Simple_spacer::solve (Column_x_positions *positions, bool ragged) positions->cols_ = spaced_cols_; positions->loose_cols_ = loose_cols_; positions->satisfies_constraints_ = - positions->satisfies_constraints_ && is_active (); + positions->satisfies_constraints_ && spacer_->is_active (); /* Check if breaking constraints are met. @@ -376,27 +397,102 @@ Simple_spacer::solve (Column_x_positions *positions, bool ragged) positions->satisfies_constraints_ && break_satisfy; } -/****************************************************************/ +void +Simple_spacer::add_spring (Real ideal, Real hooke) +{ + Spring_description desc; -Spring_description::Spring_description () + desc.ideal_ = ideal; + desc.hooke_ = hooke; + if (!desc.is_sane ()) + { + programming_error ("Insane spring found. Setting to unit spring."); + + desc.hooke_ = 1.0; + desc.ideal_ = 1.0; + } + + if (isinf (hooke)) + { + desc.is_active_ = false; + } + else + { + /* + desc.is_active_ ? + */ + desc.block_force_ = - desc.hooke_ * desc.ideal_; // block at distance 0 + + active_count_ ++; + } + springs_.push (desc); +} + +void +Simple_spacer_wrapper::add_columns (Link_array const &icols) { - ideal_ =0.0; - hooke_ =0.0; - is_active_ = true; - block_force_ = 0.0; + Link_array cols (icols); + + for (int i = cols.size (); i--;) + if (ly_c_pair_p (cols[i]->get_property ("between-cols"))) + { + loose_cols_.push (cols[i]); + cols.del (i); + } + + spaced_cols_ = cols; + for (int i=0; i < cols.size () - 1; i++) + { + Spring_smob *spring = 0; + + for (SCM s = cols[i]->get_property ("ideal-distances"); + !spring && ly_c_pair_p (s); + s = ly_cdr (s)) + { + Spring_smob *sp = unsmob_spring (ly_car (s)); + + + if (sp->other_ == cols[i+1]) + spring = sp; + } + + if (!spring) + programming_error (_f ("No spring between column %d and next one", + Paper_column::get_rank (cols[i]) + )); + + Real ideal = (spring) ? spring->distance_ : spacer_->default_space_; + Real hooke = (spring) ? spring->strength_ : 1.0; + + spacer_->add_spring (ideal, hooke); + } + + for (int i=0; i < cols.size () - 1; i++) + { + for (SCM s = Spaceable_grob::get_minimum_distances (cols[i]); + ly_c_pair_p (s); s = ly_cdr (s)) + { + Grob * other = unsmob_grob (ly_caar (s)); + int oi = cols.find_index (other); + if (oi >= 0) + { + spacer_->add_rod (i, oi, ly_scm2double (ly_cdar (s))); + } + } + } } +Simple_spacer_wrapper::Simple_spacer_wrapper () +{ + spacer_ = new Simple_spacer (); +} -bool -Spring_description::is_sane () const +Simple_spacer_wrapper::~Simple_spacer_wrapper () { - return (hooke_ > 0) && !isinf (ideal_) && !isnan (ideal_); + delete spacer_; } -Real -Spring_description::length (Real f) const + +Simple_spacer_wrapper::Simple_spacer_wrapper (Simple_spacer_wrapper const&) { - if (!is_active_) - f = block_force_; - return ideal_ + f / hooke_ ; } -- 2.39.5