Unverified Commit 4bb50465 authored by Ian Hickson's avatar Ian Hickson Committed by GitHub

More toStrings and tests for physics (#82503)

parent 2f3f5f09
......@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter/foundation.dart';
import 'simulation.dart';
/// A simulation that applies limits to another simulation.
......@@ -15,8 +17,13 @@ import 'simulation.dart';
/// difference would just be that the position would be reported as pinned to
/// the maximum value for the times that it would otherwise have been reported
/// as higher.
///
/// Similarly, this means that the [x] value will change at a rate that does not
/// match the reported [dx] value while one or the other is being clamped.
///
/// The [isDone] logic is unaffected by the clamping; it reflects the logic of
/// the underlying simulation.
class ClampedSimulation extends Simulation {
/// Creates a [ClampedSimulation] that clamps the given simulation.
///
/// The named arguments specify the ranges for the clamping behavior, as
......@@ -55,4 +62,7 @@ class ClampedSimulation extends Simulation {
@override
bool isDone(double time) => simulation.isDone(time);
@override
String toString() => '${objectRuntimeType(this, 'ClampedSimulation')}(simulation: $simulation, x: ${xMin.toStringAsFixed(1)}..${xMax.toStringAsFixed(1)}, dx: ${dxMin.toStringAsFixed(1)}..${dxMax.toStringAsFixed(1)})';
}
......@@ -4,6 +4,8 @@
import 'dart:math' as math;
import 'package:flutter/foundation.dart';
import 'simulation.dart';
import 'tolerance.dart';
......@@ -15,8 +17,8 @@ import 'tolerance.dart';
/// the current velocity [tolerance]).
class FrictionSimulation extends Simulation {
/// Creates a [FrictionSimulation] with the given arguments, namely: the fluid
/// drag coefficient, a unitless value; the initial position, in the same
/// length units as used for [x]; and the initial velocity, in the same
/// drag coefficient _cₓ_, a unitless value; the initial position _x₀_, in the same
/// length units as used for [x]; and the initial velocity _dx₀_, in the same
/// velocity units as used for [dx].
FrictionSimulation(
double drag,
......@@ -29,7 +31,7 @@ class FrictionSimulation extends Simulation {
_v = velocity,
super(tolerance: tolerance);
/// Creates a new friction simulation with its fluid drag coefficient set so
/// Creates a new friction simulation with its fluid drag coefficient (_cₓ_) set so
/// as to ensure that the simulation starts and ends at the specified
/// positions and velocities.
///
......@@ -90,14 +92,20 @@ class FrictionSimulation extends Simulation {
@override
bool isDone(double time) => dx(time).abs() < tolerance.velocity;
@override
String toString() => '${objectRuntimeType(this, 'FrictionSimulation')}(cₓ: ${_drag.toStringAsFixed(1)}, x₀: ${_x.toStringAsFixed(1)}, dx₀: ${_v.toStringAsFixed(1)})';
}
/// A [FrictionSimulation] that clamps the modeled particle to a specific range
/// of values.
///
/// Only the position is clamped. The velocity [dx] will continue to report
/// unbounded simulated velocities once the particle has reached the bounds.
class BoundedFrictionSimulation extends FrictionSimulation {
/// Creates a [BoundedFrictionSimulation] with the given arguments, namely:
/// the fluid drag coefficient, a unitless value; the initial position, in the
/// same length units as used for [x]; the initial velocity, in the same
/// the fluid drag coefficient _cₓ_, a unitless value; the initial position _x₀_, in the
/// same length units as used for [x]; the initial velocity _dx₀_, in the same
/// velocity units as used for [dx], the minimum value for the position, and
/// the maximum value for the position. The minimum and maximum values must be
/// in the same units as the initial position, and the initial position must
......@@ -125,4 +133,7 @@ class BoundedFrictionSimulation extends FrictionSimulation {
(x(time) - _minX).abs() < tolerance.distance ||
(x(time) - _maxX).abs() < tolerance.distance;
}
@override
String toString() => '${objectRuntimeType(this, 'BoundedFrictionSimulation')}(cₓ: ${_drag.toStringAsFixed(1)}, x₀: ${_x.toStringAsFixed(1)}, dx₀: ${_v.toStringAsFixed(1)}, x: ${_minX.toStringAsFixed(1)}..${_maxX.toStringAsFixed(1)})';
}
......@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter/foundation.dart';
import 'simulation.dart';
// Examples can assume:
......@@ -10,7 +12,7 @@ import 'simulation.dart';
/// A simulation that applies a constant accelerating force.
///
/// Models a particle that follows Newton's second law of motion. The simulation
/// ends when the position reaches a defined point.
/// ends when the position exceeds a defined threshold.
///
/// {@tool snippet}
///
......@@ -32,6 +34,18 @@ import 'simulation.dart';
/// This [AnimationController] could be used with an [AnimatedBuilder] to
/// animate the position of a child as if it was falling.
///
/// The end distance threshold (the constructor's third argument) must be
/// specified as a positive number but can be reached in either the positive or
/// negative direction. For example (assuming negative numbers represent higher
/// physical positions than positive numbers, as is the case with the normal
/// [Canvas] coordinate system), if the acceleration is positive ("down") the
/// starting velocity is negative ("up"), and the starting distance is zero, the
/// particle will climb from the origin, reach a plateau, then fall back towards
/// and past the origin. If the end distance threshold is less than the height
/// of the plateau, then the simulation will end during the climb; otherwise, it
/// will end during the fall, after the particle travels below the origin by
/// that distance.
///
/// See also:
///
/// * [Curves.bounceOut], a [Curve] that has a similar aesthetics but includes
......@@ -79,4 +93,7 @@ class GravitySimulation extends Simulation {
@override
bool isDone(double time) => x(time).abs() >= _end;
@override
String toString() => '${objectRuntimeType(this, 'GravitySimulation')}(g: ${_a.toStringAsFixed(1)}, x₀: ${_x.toStringAsFixed(1)}, dx₀: ${_v.toStringAsFixed(1)}, xₘₐₓ: ±${_end.toStringAsFixed(1)})';
}
......@@ -121,7 +121,7 @@ class SpringSimulation extends Simulation {
}
@override
String toString() => '${objectRuntimeType(this, 'SpringSimulation')}(end: $_endPosition, $type)';
String toString() => '${objectRuntimeType(this, 'SpringSimulation')}(end: ${_endPosition.toStringAsFixed(1)}, $type)';
}
/// A [SpringSimulation] where the value of [x] is guaranteed to have exactly the
......
......@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter/foundation.dart';
/// Structure that specifies maximum allowable magnitudes for distances,
/// durations, and velocity differences to be considered equal.
class Tolerance {
......@@ -42,5 +44,5 @@ class Tolerance {
final double velocity;
@override
String toString() => 'Tolerance(distance: ±$distance, time: ±$time, velocity: ±$velocity)';
String toString() => '${objectRuntimeType(this, 'Tolerance')}(distance: ±$distance, time: ±$time, velocity: ±$velocity)';
}
......@@ -6,7 +6,7 @@ import 'package:flutter/physics.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
test('Clamped simulation', () {
test('Clamped simulation 1', () {
final GravitySimulation gravity = GravitySimulation(9.81, 10.0, 0.0, 0.0);
final ClampedSimulation clamped = ClampedSimulation(gravity, xMin: 20.0, xMax: 100.0, dxMin: 7.0, dxMax: 11.0);
......@@ -16,4 +16,25 @@ void main() {
expect(clamped.x(100.0), equals(100.0));
expect(clamped.dx(100.0), equals(11.0));
});
test('Clamped simulation 2', () {
final GravitySimulation gravity = GravitySimulation(-10, 0.0, 6.0, 10.0);
final ClampedSimulation clamped = ClampedSimulation(gravity, xMin: 0.0, xMax: 2.5, dxMin: -1.0, dxMax: 1.0);
expect(clamped.x(0.0), equals(0.0));
expect(clamped.dx(0.0), equals(1.0));
expect(clamped.isDone(0.0), isFalse);
expect(clamped.x(1.0), equals(2.5));
expect(clamped.dx(1.0), equals(0.0));
expect(clamped.isDone(0.2), isFalse);
expect(clamped.x(2.0), equals(0.0));
expect(clamped.dx(2.0), equals(-1.0));
expect(clamped.isDone(2.0), isFalse);
expect(clamped.x(3.0), equals(0.0));
expect(clamped.dx(3.0), equals(-1.0));
expect(clamped.isDone(3.0), isTrue);
});
}
......@@ -6,8 +6,28 @@ import 'package:flutter/physics.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
test('gravity simulation', () {
test('Gravity simulation 1', () {
expect(GravitySimulation(9.81, 10.0, 0.0, 0.0), hasOneLineDescription);
expect(GravitySimulation(9.81, 10.0, 0.0, 0.0).x(10.0), moreOrLessEquals(50.0 * 9.81 + 10.0));
});
test('Gravity simulation 2', () {
final GravitySimulation gravity = GravitySimulation(-10, 0.0, 6.0, 10.0);
expect(gravity.x(0.0), equals(0.0));
expect(gravity.dx(0.0), equals(10.0));
expect(gravity.isDone(0.0), isFalse);
expect(gravity.x(1.0), equals(5.0));
expect(gravity.dx(1.0), equals(0.0));
expect(gravity.isDone(0.2), isFalse);
expect(gravity.x(2.0), equals(0.0));
expect(gravity.dx(2.0), equals(-10.0));
expect(gravity.isDone(2.0), isFalse);
expect(gravity.x(3.0), equals(-15.0));
expect(gravity.dx(3.0), equals(-20.0));
expect(gravity.isDone(3.0), isTrue);
});
}
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter/physics.dart';
import 'package:flutter_test/flutter_test.dart';
class TestSimulation extends Simulation {
@override
double x(double t) => 0.0;
@override
double dx(double t) => 0.0;
@override
bool isDone(double t) => true;
}
void main() {
test('Simulation.toString', () {
expect(ClampedSimulation(TestSimulation(), xMin: -1.0, xMax: 2.0, dxMin: -3.0, dxMax: 4.0).toString(), 'ClampedSimulation(simulation: TestSimulation, x: -1.0..2.0, dx: -3.0..4.0)');
expect(TestSimulation().toString(), 'TestSimulation');
expect(GravitySimulation(1.0, -2.0, 3.0, -4.0).toString(), 'GravitySimulation(g: 1.0, x₀: -2.0, dx₀: -4.0, xₘₐₓ: ±3.0)');
expect(FrictionSimulation(1.0, -2.0, 3.0).toString(), 'FrictionSimulation(cₓ: 1.0, x₀: -2.0, dx₀: 3.0)');
expect(BoundedFrictionSimulation(1.0, -2.0, 3.0, -4.0, 5.0).toString(), 'BoundedFrictionSimulation(cₓ: 1.0, x₀: -2.0, dx₀: 3.0, x: -4.0..5.0)');
expect(const SpringDescription(mass: 1.0, stiffness: -2.0, damping: 3.0).toString(), 'SpringDescription(mass: 1.0, stiffness: -2.0, damping: 3.0)');
expect(SpringDescription.withDampingRatio(mass: 1.0, stiffness: 9.0).toString(), 'SpringDescription(mass: 1.0, stiffness: 9.0, damping: 6.0)');
expect(SpringSimulation(const SpringDescription(mass: 1.0, stiffness: 2.0, damping: 3.0), 0.0, 1.0, 2.0).toString(), 'SpringSimulation(end: 1.0, SpringType.overDamped)');
});
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment