]> git.donarmstrong.com Git - lilypond.git/blob - lily/simple-spacer.cc
release: 1.2.8
[lilypond.git] / lily / simple-spacer.cc
1 /*   
2   simple-spacer.cc -- implement Simple_spacer
3   
4   source file of the GNU LilyPond music typesetter
5   
6   (c) 1999 Han-Wen Nienhuys <hanwen@cs.uu.nl>
7
8   TODO:
9   - add support for different stretch/shrink constants?
10   - Use force as a minimizing function, and use it to discourage mixes of
11   wide and tight lines.
12   
13 */
14
15
16 #include "simple-spacer.hh"
17 #include "paper-column.hh"
18 #include "spring.hh"
19 #include "rod.hh"
20 #include "warn.hh"
21 #include "column-x-positions.hh"
22
23 Simple_spacer::Simple_spacer ()
24 {
25   force_f_ = 0.;
26 }
27
28 void
29 Simple_spacer::add_rod (int l, int r, Real dist)
30 {
31   Real c = range_stiffness (l,r);
32   Real d = range_ideal_len (l,r);
33   Real block_stretch = dist - d;
34   
35   Real block_force = c * block_stretch;
36   force_f_ = force_f_ >? block_force;
37   
38   for (int i=l; i < r; i++)
39     springs_[i].block_force_f_ = block_force >?
40       springs_[i].block_force_f_ ;
41 }
42
43 Real
44 Simple_spacer::range_ideal_len (int l, int r)   const
45 {
46   Real d =0.;
47   for (int i=l; i < r; i++)
48     d += springs_[i].ideal_f_;
49   return d;
50 }
51
52 Real
53 Simple_spacer::range_stiffness (int l, int r) const
54 {
55   Real den =0.0;
56   for (int i=l; i < r; i++)
57     den += 1 / springs_[i].hooke_f_;
58
59   return 1 / den;
60 }
61
62 Real
63 Simple_spacer::active_blocking_force () const
64 {
65   Real bf = - infinity_f; 
66   for (int i=0; i < springs_.size (); i++)
67     if (springs_[i].active_b_)
68       {
69         bf = bf >? springs_[i].block_force_f_;
70       }
71   return bf;
72 }
73
74 Real
75 Simple_spacer::active_springs_stiffness () const
76 {
77   Real den = 0.0;
78   for (int i=0; i < springs_.size (); i++)
79     if (springs_[i].active_b_)
80       {
81         den += 1 / springs_[i].hooke_f_;
82       }
83   return 1/den;
84 }
85
86 void
87 Simple_spacer::set_active_states ()
88 {
89   // safe, since
90   // force is only copied.
91   for (int i=0 ; i <springs_.size (); i++)
92     if (springs_[i].block_force_f_ >= force_f_) 
93       springs_[i].active_b_ = false;
94 }   
95
96 Real
97 Simple_spacer::configuration_length () const
98 {
99   Real l =0.;
100   for (int i=0; i < springs_.size (); i++)
101     l += springs_[i].length (force_f_);
102
103   return l;
104 }
105
106 Real
107 Spring_description::length (Real f) const
108 {
109   if (!active_b_)
110     f = block_force_f_;
111   return ideal_f_ + f / hooke_f_ ;
112 }
113
114 bool
115 Simple_spacer::active_b () const
116 {
117    for (int i=0; i < springs_.size (); i++)
118     if (springs_[i].active_b_)
119       return true;
120    return false;
121 }
122
123 void
124 Simple_spacer::my_solve_linelen ()
125 {
126   while (active_b ())
127     {
128       force_f_ = active_blocking_force ();
129       Real conf = configuration_length ();
130
131       if (conf < line_len_f_)
132         {
133           force_f_ +=  (line_len_f_  - conf) * active_springs_stiffness ();
134           break;
135         }
136       else
137         set_active_states ();
138     }
139 }
140
141
142 void
143 Simple_spacer::my_solve_natural_len ()
144 {
145   while (active_b ())
146     {
147       force_f_ = active_blocking_force () >? 0.0;
148
149       if (force_f_ < 1e-8) // ugh.,
150         break;
151       
152       set_active_states ();
153     }
154 }
155
156 void
157 Simple_spacer::add_columns (Link_array<Paper_column> cols)
158 {
159   for (int i=0; i < cols.size () - 1; i++)
160     {
161       Paper_column * c = cols [i];
162       Column_spring *to_next = 0;
163       for (int j =0; !to_next && j < c->spring_arr_drul_[RIGHT].size( ); j++)
164         {
165           Column_spring &sp = c->spring_arr_drul_[RIGHT] [j];
166           if (sp.other_l_ != cols[i+1])
167             continue;
168
169           to_next = &sp;
170         }
171
172       Spring_description desc;
173       if (to_next)
174         {
175           desc.hooke_f_ = to_next->strength_f_;
176           desc.ideal_f_ = to_next->distance_f_;
177         }
178       else
179         {
180           desc.hooke_f_ = 1.0;
181           desc.ideal_f_ = default_space_f_;
182         }
183       desc.block_force_f_ = - desc.hooke_f_ * desc.ideal_f_; // block at distance 0
184       springs_.push  (desc);
185     }
186   
187   for (int i=0; i < cols.size () - 1; i++)
188     {
189       Array<Column_rod> * rods = &cols [i]->minimal_dists_arr_drul_[RIGHT];
190       for (int j =0; j < rods->size( ); j++)
191         {
192           int oi = cols.find_i (rods->elem (j).other_l_ );
193           if (oi >= 0)
194             {
195               add_rod (i, oi, rods->elem (j).distance_f_);
196             }
197         }
198     }
199
200   if (line_len_f_ < 0)
201     my_solve_natural_len ();
202   else
203     my_solve_linelen ();
204 }
205
206 void
207 Simple_spacer::solve (Column_x_positions *positions) const
208 {
209   positions->energy_f_  = energy_f ();  // abs (force_f_);
210   positions->config_.push (indent_f_);
211   for (int i=0; i <springs_.size (); i++)
212     {
213       positions->config_.push (positions->config_.top () + springs_[i].length (force_f_));
214     }
215
216   positions->satisfies_constraints_b_ = active_b ();
217 }
218
219 void
220 Simple_spacer::lower_bound_solution (Column_x_positions * posns) const
221 {
222   solve (posns);
223 }
224
225
226 Spring_description::Spring_description( )
227 {
228   ideal_f_ =0.0;
229   hooke_f_ =0.0;
230   active_b_ = true;
231   block_force_f_ = 0.0;
232 }
233
234 Real
235 Spring_description::energy_f (Real force) const
236 {
237   Real stretch = (force >? block_force_f_) / hooke_f_;
238   Real e = 0.5 * stretch * stretch * hooke_f_;
239
240   /*
241     be harder to compress.
242    */
243   if (stretch < 0)
244     e *= 4;
245
246   return e;
247 }
248
249 Real
250 Simple_spacer::energy_f () const
251 {
252   Real e =0.;
253
254   for (int i=0; i <springs_.size (); i++)
255     e += springs_[i].energy_f (force_f_);
256       
257   return e;
258 }