2 This file is part of LilyPond, the GNU music typesetter.
4 Copyright (C) 2007--2015 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.
45 inverse_stretch_strength_ = 1.0;
46 inverse_compress_strength_ = 1.0;
48 update_blocking_force ();
51 Spring::Spring (Real dist, Real min_dist)
55 inverse_stretch_strength_ = 1.0;
56 inverse_compress_strength_ = 1.0;
59 set_min_distance (min_dist);
60 set_default_strength ();
61 update_blocking_force ();
65 Spring::update_blocking_force ()
67 // blocking_force_ is the value of force
68 // below which length(force) is constant, and
69 // above which length(force) varies according to inverse_*_strength.
70 // Simple_spacer::compress_line() depends on the condition above.
71 // We assume inverse_*_strength are non-negative.
72 if (min_distance_ > distance_)
73 if (inverse_stretch_strength_ > 0.0)
74 blocking_force_ = (min_distance_ - distance_) / inverse_stretch_strength_;
76 // Conceptually, this should be +inf, but 0.0 meets the requirements
77 // of Simple_spacer and creates fewer cases of 0.0*inf to handle.
78 blocking_force_ = 0.0;
79 else if (inverse_compress_strength_ > 0.0)
80 blocking_force_ = (min_distance_ - distance_) / inverse_compress_strength_;
82 blocking_force_ = 0.0;
85 /* scale a spring, but in a way that doesn't violate min_distance */
87 Spring::operator *= (Real r)
89 distance_ = std::max (min_distance_, distance_ * r);
90 inverse_compress_strength_ = std::max (0.0, distance_ - min_distance_);
91 inverse_stretch_strength_ *= r;
92 update_blocking_force ();
96 Spring::operator > (Spring const &other) const
98 return blocking_force_ > other.blocking_force_;
101 /* merge springs, basically by averaging them, but leave a little headroom
102 above the largest minimum distance so that things don't get too cramped */
104 merge_springs (vector<Spring> const &springs)
106 Real avg_distance = 0;
107 Real min_distance = 0;
108 Real avg_stretch = 0;
109 Real avg_compress = 0;
111 for (vsize i = 0; i < springs.size (); i++)
113 avg_distance += springs[i].distance ();
114 avg_stretch += springs[i].inverse_stretch_strength ();
115 avg_compress += 1 / springs[i].inverse_compress_strength ();
116 min_distance = std::max (springs[i].min_distance (), min_distance);
119 avg_stretch /= Real (springs.size ());
120 avg_compress /= Real (springs.size ());
121 avg_distance /= Real (springs.size ());
122 avg_distance = std::max (min_distance + 0.3, avg_distance);
124 Spring ret = Spring (avg_distance, min_distance);
125 ret.set_inverse_stretch_strength (avg_stretch);
126 ret.set_inverse_compress_strength (1 / avg_compress);
132 Spring::set_distance (Real d)
134 if (d < 0 || isinf (d) || isnan (d))
135 programming_error ("insane spring distance requested, ignoring it");
139 update_blocking_force ();
144 Spring::set_min_distance (Real d)
146 if (d < 0 || isinf (d) || isnan (d))
147 programming_error ("insane spring min_distance requested, ignoring it");
151 update_blocking_force ();
156 Spring::ensure_min_distance (Real d)
158 set_min_distance (std::max (d, min_distance_));
162 Spring::set_inverse_stretch_strength (Real f)
164 if (isinf (f) || isnan (f) || f < 0)
165 programming_error ("insane spring constant");
167 inverse_stretch_strength_ = f;
169 update_blocking_force ();
173 Spring::set_inverse_compress_strength (Real f)
175 if (isinf (f) || isnan (f) || f < 0)
176 programming_error ("insane spring constant");
178 inverse_compress_strength_ = f;
180 update_blocking_force ();
184 Spring::set_blocking_force (Real f)
186 if (isinf (f) || isnan (f))
188 programming_error ("insane blocking force");
192 blocking_force_ = -infinity_f;
193 min_distance_ = length (f);
194 update_blocking_force ();
198 Spring::set_default_strength ()
200 set_default_stretch_strength ();
201 set_default_compress_strength ();
205 Spring::set_default_compress_strength ()
207 inverse_compress_strength_ = (distance_ >= min_distance_) ? distance_ - min_distance_ : 0;
208 update_blocking_force ();
212 Spring::set_default_stretch_strength ()
214 inverse_stretch_strength_ = distance_;
218 Spring::length (Real f) const
220 Real force = std::max (f, blocking_force_);
221 Real inv_k = force < 0.0 ? inverse_compress_strength_ : inverse_stretch_strength_;
225 programming_error ("cruelty to springs");
229 // There is a corner case here: if min_distance_ is larger than
230 // distance_ but the spring is fixed, then inv_k will be zero
231 // and we need to make sure that we return min_distance_.
232 return std::max (min_distance_, distance_ + force * inv_k);