newton_test.dart 10.4 KB
Newer Older
1
// Copyright 2015 The Chromium Authors. All rights reserved.
2 3 4 5 6
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'package:test/test.dart';

7
import 'package:flutter/physics.dart';
8
import 'package:flutter/widgets.dart';
9

10 11
void main() {
  test('test_friction', () {
12
    final FrictionSimulation friction = new FrictionSimulation(0.3, 100.0, 400.0);
13

14 15
    friction.tolerance = const Tolerance(velocity: 1.0);

16 17 18 19 20 21 22 23 24 25 26 27 28 29
    expect(friction.isDone(0.0), false);
    expect(friction.x(0.0), 100);
    expect(friction.dx(0.0), 400.0);

    expect(friction.x(1.0) > 330 && friction.x(1.0) < 335, true);

    expect(friction.dx(1.0), 120.0);
    expect(friction.dx(2.0), 36.0);
    expect(friction.dx(3.0), 10.8);
    expect(friction.dx(4.0) < 3.5, true);

    expect(friction.isDone(5.0), true);
    expect(friction.x(5.0) > 431 && friction.x(5.0) < 432, true);
  });
Chinmay Garde's avatar
Chinmay Garde committed
30

31 32 33
  test('test_friction_through', () {
    // Use a normal FrictionSimulation to generate start and end
    // velocity and positions with drag = 0.025.
34 35 36 37 38
    double startPosition = 10.0;
    double startVelocity = 600.0;
    FrictionSimulation f = new FrictionSimulation(0.025, startPosition, startVelocity);
    double endPosition = f.x(1.0);
    double endVelocity = f.dx(1.0);
39 40 41 42 43 44
    expect(endPosition, greaterThan(startPosition));
    expect(endVelocity, lessThan(startVelocity));

    // Verify that that the "through" FrictionSimulation ends up at
    // endPosition and endVelocity; implies that it computed the right
    // value for _drag.
45
    FrictionSimulation friction = new FrictionSimulation.through(
46 47 48 49 50
        startPosition, endPosition, startVelocity, endVelocity);
    expect(friction.isDone(0.0), false);
    expect(friction.x(0.0), 10.0);
    expect(friction.dx(0.0), 600.0);

51
    final double epsilon = 1e-4;
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
    expect(friction.isDone(1.0 + epsilon), true);
    expect(friction.x(1.0), closeTo(endPosition, epsilon));
    expect(friction.dx(1.0), closeTo(endVelocity, epsilon));

    // Same scenario as above except that the velocities are
    // are negative.
    startPosition = 1000.0;
    startVelocity = -500.0;
    f = new FrictionSimulation(0.025, 1000.0, -500.0);
    endPosition = f.x(1.0);
    endVelocity = f.dx(1.0);
    expect(endPosition, lessThan(startPosition));
    expect(endVelocity, greaterThan(startVelocity));

    friction = new FrictionSimulation.through(
        startPosition, endPosition, startVelocity, endVelocity);
    expect(friction.isDone(1.0 + epsilon), true);
    expect(friction.x(1.0), closeTo(endPosition, epsilon));
    expect(friction.dx(1.0), closeTo(endVelocity, epsilon));
  });

73
  test('BoundedFrictionSimulation control test', () {
74
    final BoundedFrictionSimulation friction = new BoundedFrictionSimulation(0.3, 100.0, 400.0, 50.0, 150.0);
75 76 77 78 79 80 81 82 83 84 85 86

    friction.tolerance = const Tolerance(velocity: 1.0);

    expect(friction.isDone(0.0), false);
    expect(friction.x(0.0), 100);
    expect(friction.dx(0.0), 400.0);

    expect(friction.x(1.0), equals(150.0));

    expect(friction.isDone(1.0), true);
  });

Chinmay Garde's avatar
Chinmay Garde committed
87
  test('test_gravity', () {
88
    final GravitySimulation gravity = new GravitySimulation(200.0, 100.0, 600.0, 0.0);
Chinmay Garde's avatar
Chinmay Garde committed
89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115

    expect(gravity.isDone(0.0), false);
    expect(gravity.x(0.0), 100.0);
    expect(gravity.dx(0.0), 0.0);

    // Starts at 100
    expect(gravity.x(0.25), 106.25);
    expect(gravity.x(0.50), 125);
    expect(gravity.x(0.75), 156.25);
    expect(gravity.x(1.00), 200);
    expect(gravity.x(1.25), 256.25);
    expect(gravity.x(1.50), 325);
    expect(gravity.x(1.75), 406.25);

    // Starts at 0.0
    expect(gravity.dx(0.25), 50.0);
    expect(gravity.dx(0.50), 100);
    expect(gravity.dx(0.75), 150.00);
    expect(gravity.dx(1.00), 200.0);
    expect(gravity.dx(1.25), 250.0);
    expect(gravity.dx(1.50), 300);
    expect(gravity.dx(1.75), 350);

    expect(gravity.isDone(2.5), true);
    expect(gravity.x(2.5), 725);
    expect(gravity.dx(2.5), 500.0);
  });
116 117

  test('spring_types', () {
118
    SpringSimulation crit = new SpringSimulation(new SpringDescription.withDampingRatio(
119
        mass: 1.0, springConstant: 100.0), 0.0, 300.0, 0.0);
120 121
    expect(crit.type, SpringType.criticallyDamped);

122 123 124 125
    crit = new SpringSimulation(new SpringDescription.withDampingRatio(
        mass: 1.0, springConstant: 100.0, ratio: 1.0), 0.0, 300.0, 0.0);
    expect(crit.type, SpringType.criticallyDamped);

126
    final SpringSimulation under = new SpringSimulation(new SpringDescription.withDampingRatio(
127
        mass: 1.0, springConstant: 100.0, ratio: 0.75), 0.0, 300.0, 0.0);
128 129
    expect(under.type, SpringType.underDamped);

130
    final SpringSimulation over = new SpringSimulation(new SpringDescription.withDampingRatio(
131
        mass: 1.0, springConstant: 100.0, ratio: 1.25), 0.0, 300.0, 0.0);
132 133 134
    expect(over.type, SpringType.overDamped);

    // Just so we don't forget how to create a desc without the ratio.
135
    final SpringSimulation other = new SpringSimulation(
136
        const SpringDescription(mass: 1.0, springConstant: 100.0, damping: 20.0),
137
        0.0, 20.0, 20.0);
138 139
    expect(other.type, SpringType.criticallyDamped);
  });
140 141

  test('crit_spring', () {
142
    final SpringSimulation crit = new SpringSimulation(new SpringDescription.withDampingRatio(
143
        mass: 1.0, springConstant: 100.0, ratio: 1.0), 0.0, 500.0, 0.0);
144 145 146

    crit.tolerance = const Tolerance(distance: 0.01, velocity: 0.01);

147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166
    expect(crit.type, SpringType.criticallyDamped);

    expect(crit.isDone(0.0), false);
    expect(crit.x(0.0), 0.0);
    expect(crit.dx(0.0), 5000.0);

    expect(crit.x(0.25).floor(), 458.0);
    expect(crit.x(0.50).floor(), 496.0);
    expect(crit.x(0.75).floor(), 499.0);

    expect(crit.dx(0.25).floor(), 410);
    expect(crit.dx(0.50).floor(), 33);
    expect(crit.dx(0.75).floor(), 2);

    expect(crit.isDone(1.50), true);
    expect(crit.x(1.5) > 499.0 && crit.x(1.5) < 501.0, true);
    expect(crit.dx(1.5) < 0.1, true /* basically within tolerance */);
  });

  test('overdamped_spring', () {
167
    final SpringSimulation over = new SpringSimulation(new SpringDescription.withDampingRatio(
168
        mass: 1.0, springConstant: 100.0, ratio: 1.25), 0.0, 500.0, 0.0);
169 170 171

    over.tolerance = const Tolerance(distance: 0.01, velocity: 0.01);

172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188
    expect(over.type, SpringType.overDamped);

    expect(over.isDone(0.0), false);
    expect(over.x(0.0), 0.0);

    expect(over.x(0.5).floor(), 445.0);
    expect(over.x(1.0).floor(), 495.0);
    expect(over.x(1.5).floor(), 499.0);

    expect(over.dx(0.5).floor(), 273.0);
    expect(over.dx(1.0).floor(), 22.0);
    expect(over.dx(1.5).floor(), 1.0);

    expect(over.isDone(3.0), true);
  });

  test('underdamped_spring', () {
189
    final SpringSimulation under = new SpringSimulation(new SpringDescription.withDampingRatio(
190
        mass: 1.0, springConstant: 100.0, ratio: 0.25), 0.0, 300.0, 0.0);
191 192 193 194 195 196 197 198 199 200 201 202 203
    expect(under.type, SpringType.underDamped);

    expect(under.isDone(0.0), false);

    // Overshot with negative velocity
    expect(under.x(1.0).floor(), 325);
    expect(under.dx(1.0).floor(), -65);

    expect(under.dx(6.0).floor(), 0.0);
    expect(under.x(6.0).floor(), 299);

    expect(under.isDone(6.0), true);
  });
204 205

  test('test_kinetic_scroll', () {
206
    final SpringDescription spring = new SpringDescription.withDampingRatio(
207
        mass: 1.0, springConstant: 50.0, ratio: 0.5);
208

209
    final BouncingScrollSimulation scroll = new BouncingScrollSimulation(
210 211 212 213 214 215
      position: 100.0,
      velocity: 800.0,
      leadingExtent: 0.0,
      trailingExtent: 300.0,
      spring: spring,
    );
216
    scroll.tolerance = const Tolerance(velocity: 0.5, distance: 0.1);
217
    expect(scroll.isDone(0.0), false);
218
    expect(scroll.isDone(0.5), false); // switch from friction to spring
219 220
    expect(scroll.isDone(3.5), true);

221
    final BouncingScrollSimulation scroll2 = new BouncingScrollSimulation(
222 223 224 225 226 227
      position: 100.0,
      velocity: -800.0,
      leadingExtent: 0.0,
      trailingExtent: 300.0,
      spring: spring,
    );
228 229 230 231
    scroll2.tolerance = const Tolerance(velocity: 0.5, distance: 0.1);
    expect(scroll2.isDone(0.0), false);
    expect(scroll2.isDone(0.5), false); // switch from friction to spring
    expect(scroll2.isDone(3.5), true);
232
  });
233 234

  test('scroll_with_inf_edge_ends', () {
235
    final SpringDescription spring = new SpringDescription.withDampingRatio(
236 237
        mass: 1.0, springConstant: 50.0, ratio: 0.5);

238
    final BouncingScrollSimulation scroll = new BouncingScrollSimulation(
239 240 241 242 243 244
      position: 100.0,
      velocity: 400.0,
      leadingExtent: 0.0,
      trailingExtent: double.INFINITY,
      spring: spring,
    );
245 246
    scroll.tolerance = const Tolerance(velocity: 1.0);

247 248 249 250
    expect(scroll.isDone(0.0), false);
    expect(scroll.x(0.0), 100);
    expect(scroll.dx(0.0), 400.0);

251
    expect(scroll.x(1.0), closeTo(272.0, 1.0));
252

253 254 255
    expect(scroll.dx(1.0), closeTo(54.0, 1.0));
    expect(scroll.dx(2.0), closeTo(7.0, 1.0));
    expect(scroll.dx(3.0), lessThan(1.0));
256 257

    expect(scroll.isDone(5.0), true);
258
    expect(scroll.x(5.0), closeTo(300.0, 1.0));
259
  });
260 261

  test('over/under scroll spring', () {
262 263
    final SpringDescription spring = new SpringDescription.withDampingRatio(mass: 1.0, springConstant: 170.0, ratio: 1.1);
    final BouncingScrollSimulation scroll = new BouncingScrollSimulation(
264 265 266 267 268 269
      position: 500.0,
      velocity: -7500.0,
      leadingExtent: 0.0,
      trailingExtent: 1000.0,
      spring: spring,
    );
270
    scroll.tolerance = const Tolerance(velocity: 45.0, distance: 1.5);
271 272 273 274 275

    expect(scroll.isDone(0.0), false);
    expect(scroll.x(0.0), closeTo(500.0, .0001));
    expect(scroll.dx(0.0), closeTo(-7500.0, .0001));

276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296
    // Expect to reach 0.0 at about t=.07 at which point the simulation will
    // switch from friction to the spring
    expect(scroll.isDone(0.065), false);
    expect(scroll.x(0.065), closeTo(42.0, 1.0));
    expect(scroll.dx(0.065), closeTo(-6584.0, 1.0));

    // We've overscrolled (0.1 > 0.07). Trigger the underscroll
    // simulation, and reverse direction
    expect(scroll.isDone(0.1), false);
    expect(scroll.x(0.1), closeTo(-123.0, 1.0));
    expect(scroll.dx(0.1), closeTo(-2613.0, 1.0));

    // Headed back towards 0.0 and slowing down.
    expect(scroll.isDone(0.5), false);
    expect(scroll.x(0.5), closeTo(-15.0, 1.0));
    expect(scroll.dx(0.5), closeTo(124.0, 1.0));

    // Now jump back to the beginning, because we can.
    expect(scroll.isDone(0.0), false);
    expect(scroll.x(0.0), closeTo(500.0, .0001));
    expect(scroll.dx(0.0), closeTo(-7500.0, .0001));
297 298 299

    expect(scroll.isDone(2.0), true);
    expect(scroll.x(2.0), 0.0);
300
    expect(scroll.dx(2.0), closeTo(0.0, 1.0));
301
  });
302
}