Skip to content

Commit 9793885

Browse files
gnpricePiinks
andauthored
Fix buggy formula for critically-damped springs (#120488)
Fixes #109675. This formula would produce an initial velocity quite different from the one specified as an argument. To update the test, I computed the expected results separately by using the physical formula. Happily, the framework by default never ends up actually exercising this code. Of the four SpringDescription call sites within the framework, two are explicitly overdamped; the other two are by design critically damped, but due to rounding they end up being treated as (very slightly) overdamped too. Details here: flutter/flutter#109675 (comment) So the only way an app could be affected by this bug is if it called a SpringDescription constructor itself, and managed to create a spring description where the distinguishing formula in _SpringSolution comes out exactly equal to zero. It's likely nobody has ever shipped such an app, because the behavior this produces would be so wildly wrong that it'd be hard to miss when exercised. Co-authored-by: Kate Lovett <katelovett@google.com>
1 parent 8080bec commit 9793885

2 files changed

Lines changed: 12 additions & 9 deletions

File tree

packages/flutter/lib/src/physics/spring_simulation.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ class _CriticalSolution implements _SpringSolution {
176176
) {
177177
final double r = -spring.damping / (2.0 * spring.mass);
178178
final double c1 = distance;
179-
final double c2 = velocity / (r * distance);
179+
final double c2 = velocity - (r * distance);
180180
return _CriticalSolution.withArgs(r, c1, c2);
181181
}
182182

packages/flutter/test/physics/newton_test.dart

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -167,19 +167,19 @@ void main() {
167167

168168
expect(crit.isDone(0.0), false);
169169
expect(crit.x(0.0), 0.0);
170-
expect(crit.dx(0.0), 5000.0);
170+
expect(crit.dx(0.0), 0.0);
171171

172-
expect(crit.x(0.25).floor(), 458.0);
173-
expect(crit.x(0.50).floor(), 496.0);
174-
expect(crit.x(0.75).floor(), 499.0);
172+
expect(crit.x(0.25).floor(), 356);
173+
expect(crit.x(0.50).floor(), 479);
174+
expect(crit.x(0.75).floor(), 497);
175175

176-
expect(crit.dx(0.25).floor(), 410);
177-
expect(crit.dx(0.50).floor(), 33);
178-
expect(crit.dx(0.75).floor(), 2);
176+
expect(crit.dx(0.25).floor(), 1026);
177+
expect(crit.dx(0.50).floor(), 168);
178+
expect(crit.dx(0.75).floor(), 20);
179179

180-
expect(crit.isDone(1.50), true);
181180
expect(crit.x(1.5) > 499.0 && crit.x(1.5) < 501.0, true);
182181
expect(crit.dx(1.5) < 0.1, true /* basically within tolerance */);
182+
expect(crit.isDone(1.60), true);
183183
});
184184

185185
test('overdamped_spring', () {
@@ -195,6 +195,7 @@ void main() {
195195

196196
expect(over.isDone(0.0), false);
197197
expect(over.x(0.0), 0.0);
198+
expect(over.dx(0.0), moreOrLessEquals(0.0));
198199

199200
expect(over.x(0.5).floor(), 445.0);
200201
expect(over.x(1.0).floor(), 495.0);
@@ -216,6 +217,8 @@ void main() {
216217
expect(under.type, SpringType.underDamped);
217218

218219
expect(under.isDone(0.0), false);
220+
expect(under.x(0.0), moreOrLessEquals(0.0));
221+
expect(under.dx(0.0), moreOrLessEquals(0.0));
219222

220223
// Overshot with negative velocity
221224
expect(under.x(1.0).floor(), 325);

0 commit comments

Comments
 (0)