2 This file is part of LilyPond, the GNU music typesetter.
4 Copyright (C) 2007--2014 Joe Neeman <joeneeman@gmail.com>
6 LilyPond is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
11 LilyPond is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with LilyPond. If not, see <http://www.gnu.org/licenses/>.
21 Springs help chains of objects, such as the notes in a line of music,
22 distribute themselves evenly.
23 Each spring decides the length from the reference point of one object
24 along the line to the reference point of the next, based on a force
25 applied to the entire chain (see Spring::length() for details):
26 length = distance_ + flexibility * force
28 distance_ is the ideal separation between reference points
29 inverse_stretch_strength_ is the flexibility when the force is stretching
30 inverse_compress_strength_ is the flexibility when the force is compressing
31 min_distance_ sets a lower limit on length
33 Typically, the force applied to a list of objects ranges from about
34 -1 to about 1, though there are no set limits.
43 inverse_stretch_strength_ = 1.0;
44 inverse_compress_strength_ = 1.0;
46 update_blocking_force ();
49 Spring::Spring (Real dist, Real min_dist)
53 inverse_stretch_strength_ = 1.0;
54 inverse_compress_strength_ = 1.0;
57 set_min_distance (min_dist);
58 set_default_strength ();
59 update_blocking_force ();
63 Spring::update_blocking_force ()
65 // blocking_force_ is the value of force
66 // below which length(force) is constant, and
67 // above which length(force) varies according to inverse_*_strength.
68 // Simple_spacer::compress_line() depends on the condition above.
69 // We assume inverse_*_strength are non-negative.
70 if (min_distance_ > distance_)
71 if (inverse_stretch_strength_ > 0.0)
72 blocking_force_ = (min_distance_ - distance_) / inverse_stretch_strength_;
74 // Conceptually, this should be +inf, but 0.0 meets the requirements
75 // of Simple_spacer and creates fewer cases of 0.0*inf to handle.
76 blocking_force_ = 0.0;
77 else if (inverse_compress_strength_ > 0.0)
78 blocking_force_ = (min_distance_ - distance_) / inverse_compress_strength_;
80 blocking_force_ = 0.0;
83 /* scale a spring, but in a way that doesn't violate min_distance */
85 Spring::operator *= (Real r)
87 distance_ = max (min_distance_, distance_ * r);
88 inverse_compress_strength_ = max (0.0, distance_ - min_distance_);
89 inverse_stretch_strength_ *= r;
90 update_blocking_force ();
94 Spring::operator > (Spring const &other) const
96 return blocking_force_ > other.blocking_force_;
99 /* merge springs, basically by averaging them, but leave a little headroom
100 above the largest minimum distance so that things don't get too cramped */
102 merge_springs (vector<Spring> const &springs)
104 Real avg_distance = 0;
105 Real min_distance = 0;
106 Real avg_stretch = 0;
107 Real avg_compress = 0;
109 for (vsize i = 0; i < springs.size (); i++)
111 avg_distance += springs[i].distance ();
112 avg_stretch += springs[i].inverse_stretch_strength ();
113 avg_compress += 1 / springs[i].inverse_compress_strength ();
114 min_distance = max (springs[i].min_distance (), min_distance);
117 avg_stretch /= Real (springs.size ());
118 avg_compress /= Real (springs.size ());
119 avg_distance /= Real (springs.size ());
120 avg_distance = max (min_distance + 0.3, avg_distance);
122 Spring ret = Spring (avg_distance, min_distance);
123 ret.set_inverse_stretch_strength (avg_stretch);
124 ret.set_inverse_compress_strength (1 / avg_compress);
130 Spring::set_distance (Real d)
132 if (d < 0 || isinf (d) || isnan (d))
133 programming_error ("insane spring distance requested, ignoring it");
137 update_blocking_force ();
142 Spring::set_min_distance (Real d)
144 if (d < 0 || isinf (d) || isnan (d))
145 programming_error ("insane spring min_distance requested, ignoring it");
149 update_blocking_force ();
154 Spring::ensure_min_distance (Real d)
156 set_min_distance (max (d, min_distance_));
160 Spring::set_inverse_stretch_strength (Real f)
162 if (isinf (f) || isnan (f) || f < 0)
163 programming_error ("insane spring constant");
165 inverse_stretch_strength_ = f;
167 update_blocking_force ();
171 Spring::set_inverse_compress_strength (Real f)
173 if (isinf (f) || isnan (f) || f < 0)
174 programming_error ("insane spring constant");
176 inverse_compress_strength_ = f;
178 update_blocking_force ();
182 Spring::set_blocking_force (Real f)
184 if (isinf (f) || isnan (f))
186 programming_error ("insane blocking force");
190 blocking_force_ = -infinity_f;
191 min_distance_ = length (f);
192 update_blocking_force ();
196 Spring::set_default_strength ()
198 set_default_stretch_strength ();
199 set_default_compress_strength ();
203 Spring::set_default_compress_strength ()
205 inverse_compress_strength_ = (distance_ >= min_distance_) ? distance_ - min_distance_ : 0;
206 update_blocking_force ();
210 Spring::set_default_stretch_strength ()
212 inverse_stretch_strength_ = distance_;
216 Spring::length (Real f) const
218 Real force = max (f, blocking_force_);
219 Real inv_k = force < 0.0 ? inverse_compress_strength_ : inverse_stretch_strength_;
223 programming_error ("cruelty to springs");
227 // There is a corner case here: if min_distance_ is larger than
228 // distance_ but the spring is fixed, then inv_k will be zero
229 // and we need to make sure that we return min_distance_.
230 return max (min_distance_, distance_ + force * inv_k);