]> git.donarmstrong.com Git - lilypond.git/blob - lily/spring.cc
Patch for auto-beam; Fix issue 511
[lilypond.git] / lily / spring.cc
1 /*
2   spring.cc -- declare Spring
3
4   source file of the GNU LilyPond music typesetter
5
6   (c) 2007 Joe Neeman <joeneeman@gmail.com>
7 */
8
9 #include "spring.hh"
10
11 Spring::Spring ()
12 {
13   distance_ = 1.0;
14   min_distance_ = 1.0;
15   inverse_stretch_strength_ = 1.0;
16   inverse_compress_strength_ = 1.0;
17
18   update_blocking_force ();
19 }
20
21 Spring::Spring (Real dist, Real min_dist)
22 {
23   distance_ = 1.0;
24   min_distance_ = 1.0;
25
26   set_distance (dist);
27   set_min_distance (min_dist);
28   set_default_strength ();
29   update_blocking_force ();
30 }
31
32 void
33 Spring::update_blocking_force ()
34 {
35   if (distance_ == min_distance_)
36     blocking_force_ = 0.0;
37   else
38     blocking_force_ = (min_distance_ - distance_) / inverse_compress_strength_;
39 }
40
41 /* scale a spring, but in a way that doesn't violate min_distance */
42 void
43 Spring::operator*= (Real r)
44 {
45   distance_ = max (min_distance_, distance_ * r);
46   inverse_compress_strength_ = distance_ - min_distance_;
47   inverse_stretch_strength_ *= 0.8;
48 }
49
50 bool
51 Spring::operator> (Spring const &other) const
52 {
53   return blocking_force_ > other.blocking_force_;
54 }
55
56 /* merge springs, basically by averaging them, but leave a little headroom
57    above the largest minimum distance so that things don't get too cramped */
58 Spring
59 merge_springs (vector<Spring> const &springs)
60 {
61   Real avg_distance = 0;
62   Real min_distance = 0;
63   Real avg_stretch = 0;
64   Real avg_compress = 0;
65
66   for (vsize i = 0; i < springs.size (); i++)
67     {
68       avg_distance += springs[i].distance ();
69       avg_stretch += springs[i].inverse_stretch_strength ();
70       avg_compress += 1 / springs[i].inverse_compress_strength ();
71       min_distance = max (springs[i].min_distance (), min_distance);
72     }
73
74   avg_stretch /= springs.size ();
75   avg_compress /= springs.size ();
76   avg_distance /= springs.size ();
77   avg_distance = max (min_distance + 0.3, avg_distance);
78
79   Spring ret = Spring (avg_distance, min_distance);
80   ret.set_inverse_stretch_strength (avg_stretch);
81   ret.set_inverse_compress_strength (1 / avg_compress);
82
83   return ret;
84 }
85
86 void
87 Spring::set_distance (Real d)
88 {
89   if (d < 0 || isinf (d) || isnan (d))
90     programming_error ("insane spring distance requested, ignoring it");
91   else
92     {
93       min_distance_ = min (min_distance_, d);
94       distance_ = d;
95       update_blocking_force ();
96     }
97 }
98
99 void
100 Spring::set_min_distance (Real d)
101 {
102   if (d < 0 || isinf (d) || isnan (d))
103     programming_error ("insane spring min_distance requested, ignoring it");
104   else
105     {
106       min_distance_ = d;
107       distance_ = max (distance_, min_distance_);
108       update_blocking_force ();
109     }
110 }
111
112 void
113 Spring::set_inverse_stretch_strength (Real f)
114 {
115   if (isinf (f) || isnan (f) || f < 0)
116     programming_error ("insane spring constant");
117   else
118     inverse_stretch_strength_ = f;
119 }
120
121 void
122 Spring::set_inverse_compress_strength (Real f)
123 {
124   if (isinf (f) || isnan (f) || f < 0)
125     programming_error ("insane spring constant");
126   else
127     inverse_compress_strength_ = f;
128
129   update_blocking_force ();
130 }
131
132 void
133 Spring::set_blocking_force (Real f)
134 {
135   if (isinf (f) || isnan (f))
136     {
137       programming_error ("insane blocking force");
138       return;
139     }
140
141   blocking_force_ = -infinity_f;
142   min_distance_ = length (f);
143   distance_ = max (distance_, min_distance_);
144   update_blocking_force ();
145 }
146
147 void
148 Spring::set_default_strength ()
149 {
150   inverse_compress_strength_ = distance_ - min_distance_;
151   inverse_stretch_strength_ = distance_ - min_distance_;
152 }
153
154 Real
155 Spring::length (Real f) const
156 {
157   Real force = max (f, blocking_force_);
158   Real inv_k = force < 0.0 ? inverse_compress_strength_ : inverse_stretch_strength_;
159
160   if (isinf (force))
161     {
162       programming_error ("cruelty to springs");
163       force = 0.0;
164     }
165
166   return distance_ + force * inv_k;
167 }