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