Document newton more.
diff --git a/packages/flutter/lib/src/widgets/scrollable.dart b/packages/flutter/lib/src/widgets/scrollable.dart
index 29d02aa..dbc4f26 100644
--- a/packages/flutter/lib/src/widgets/scrollable.dart
+++ b/packages/flutter/lib/src/widgets/scrollable.dart
@@ -20,8 +20,9 @@
/// The accuracy to which scrolling is computed.
final Tolerance kPixelScrollTolerance = new Tolerance(
- velocity: 1.0 / (0.050 * ui.window.devicePixelRatio), // logical pixels per second
- distance: 1.0 / ui.window.devicePixelRatio // logical pixels
+ // TODO(ianh): Handle the case of the device pixel ratio changing.
+ velocity: 1.0 / (0.050 * ui.window.devicePixelRatio), // logical pixels per second
+ distance: 1.0 / ui.window.devicePixelRatio // logical pixels
);
typedef void ScrollListener(double scrollOffset);
diff --git a/packages/newton/lib/newton.dart b/packages/newton/lib/newton.dart
index 94b6df0..c56aa1d 100644
--- a/packages/newton/lib/newton.dart
+++ b/packages/newton/lib/newton.dart
@@ -2,7 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-/// Simple Physics Simulations for Dart. Springs, friction, gravity, etc.
+/// Simple one-dimensional physics simulations, such as springs, friction, and
+/// gravity, for use in user interface animations.
library newton;
export 'src/clamped_simulation.dart';
diff --git a/packages/newton/lib/src/clamped_simulation.dart b/packages/newton/lib/src/clamped_simulation.dart
index daa172b..82fe080 100644
--- a/packages/newton/lib/src/clamped_simulation.dart
+++ b/packages/newton/lib/src/clamped_simulation.dart
@@ -4,7 +4,23 @@
import 'simulation.dart';
+/// A simulation that applies limits to another simulation.
+///
+/// The limits are only applied to the other simulation's outputs. For example,
+/// if a maximum position was applied to a gravity simulation with the
+/// particle's initial velocity being up, and the accerelation being down, and
+/// the maximum position being between the initial position and the curve's
+/// apogee, then the particle would return to its initial position in the same
+/// amount of time as it would have if the maximum had not been applied; the
+/// 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.
class ClampedSimulation extends Simulation {
+
+ /// Creates a [ClampedSimulation] that clamps the given simulation.
+ ///
+ /// The named arguments specify the ranges for the clamping behavior, as
+ /// applied to [x] and [dx].
ClampedSimulation(this.simulation, {
this.xMin: double.NEGATIVE_INFINITY,
this.xMax: double.INFINITY,
@@ -16,10 +32,20 @@
assert(dxMax >= dxMin);
}
+ /// The simulation being clamped. Calls to [x], [dx], and [isDone] are
+ /// forwarded to the simulation.
final Simulation simulation;
+
+ /// The minimum to apply to [x].
final double xMin;
+
+ /// The maximum to apply to [x].
final double xMax;
+
+ /// The minimum to apply to [dx].
final double dxMin;
+
+ /// The maximum to apply to [dx].
final double dxMax;
@override
diff --git a/packages/newton/lib/src/friction_simulation.dart b/packages/newton/lib/src/friction_simulation.dart
index 1958655..b138d0f 100644
--- a/packages/newton/lib/src/friction_simulation.dart
+++ b/packages/newton/lib/src/friction_simulation.dart
@@ -7,21 +7,43 @@
import 'simulation.dart';
import 'tolerance.dart';
+/// A simulation that applies a drag to slow a particle down.
+///
+/// Models a particle affected by fluid drag, e.g. air resistance.
+///
+/// The simulation ends when the velocity of the particle drops to zero (within
+/// 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
+ /// velocity units as used for [dx].
FrictionSimulation(double drag, double position, double velocity)
: _drag = drag,
_dragLog = math.log(drag),
_x = position,
_v = velocity;
- // A friction simulation that starts and ends at the specified positions
- // and velocities.
+ /// Creates a new friction simulation with its fluid drag coefficient set so
+ /// as to ensure that the simulation starts and ends at the specified
+ /// positions and velocities.
+ ///
+ /// The positions must use the same units as expected from [x], and the
+ /// velocities must use the same units as expected from [dx].
+ ///
+ /// The sign of the start and end velocities must be the same, the magnitude
+ /// of the start velocity must be greater than the magnitude of the end
+ /// velocity, and the velocities must be in the direction appropriate for the
+ /// particle to start from the start position and reach the end position.
factory FrictionSimulation.through(double startPosition, double endPosition, double startVelocity, double endVelocity) {
+ assert(startVelocity.sign == endVelocity.sign);
+ assert(startVelocity.abs() >= endVelocity.abs());
+ assert((endPosition - startPosition).sign == startVelocity.sign);
return new FrictionSimulation(
_dragFor(startPosition, endPosition, startVelocity, endVelocity),
startPosition,
- startVelocity)
- .. tolerance = new Tolerance(velocity: endVelocity.abs());
+ startVelocity
+ )..tolerance = new Tolerance(velocity: endVelocity.abs());
}
final double _drag;
@@ -50,14 +72,25 @@
bool isDone(double time) => dx(time).abs() < tolerance.velocity;
}
+/// A [FrictionSimulation] that clamps the modelled particle to a specific range
+/// of values.
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
+ /// 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
+ /// be within the given range.
BoundedFrictionSimulation(
double drag,
double position,
double velocity,
this._minX,
this._maxX
- ) : super(drag, position, velocity);
+ ) : super(drag, position, velocity) {
+ assert(position.clamp(_minX, _maxX) == position);
+ }
final double _minX;
final double _maxX;
diff --git a/packages/newton/lib/src/gravity_simulation.dart b/packages/newton/lib/src/gravity_simulation.dart
index a53ad93..b75eb93 100644
--- a/packages/newton/lib/src/gravity_simulation.dart
+++ b/packages/newton/lib/src/gravity_simulation.dart
@@ -4,19 +4,46 @@
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.
class GravitySimulation extends Simulation {
+ /// Creates a [GravitySimulation] using the given arguments, which are,
+ /// respectively: an acceleration that is to be applied continually over time;
+ /// an initial position relative to an origin; the magnitude of the distance
+ /// from that origin beyond which (in either direction) to consider the
+ /// simulation to be "done", which must be positive; and an initial velocity.
+ ///
+ /// The initial position and maximum distance are measured in arbitrary length
+ /// units L from an arbitrary origin. The units will match those used for [x].
+ ///
+ /// The time unit T used for the arguments to [x], [dx], and [isDone],
+ /// combined with the aforementioned length unit, together determine the units
+ /// that must be used for the velocity and acceleration arguments: L/T and
+ /// L/T² respectively. The same units of velocity are used for the velocity
+ /// obtained from [dx].
+ GravitySimulation(
+ double acceleration,
+ double distance,
+ double endDistance,
+ double velocity
+ ) : _a = acceleration,
+ _x = distance,
+ _v = velocity,
+ _end = endDistance {
+ assert(acceleration != null);
+ assert(distance != null);
+ assert(velocity != null);
+ assert(endDistance != null);
+ assert(endDistance >= 0);
+ }
+
final double _x;
final double _v;
final double _a;
final double _end;
- GravitySimulation(
- double acceleration, double distance, double endDistance, double velocity)
- : _a = acceleration,
- _x = distance,
- _v = velocity,
- _end = endDistance;
-
@override
double x(double time) => _x + _v * time + 0.5 * _a * time * time;
diff --git a/packages/newton/lib/src/scroll_simulation.dart b/packages/newton/lib/src/scroll_simulation.dart
index fb8d10d..5d9fd97 100644
--- a/packages/newton/lib/src/scroll_simulation.dart
+++ b/packages/newton/lib/src/scroll_simulation.dart
@@ -7,10 +7,25 @@
import 'simulation.dart';
import 'spring_simulation.dart';
+/// Composite simulation for scrollable interfaces.
+///
/// Simulates kinetic scrolling behavior between a leading and trailing
-/// boundary. Friction is applied within the extends and a spring action applied
-/// at the boundaries. This simulation can only step forward.
+/// boundary. Friction is applied within the extents and a spring action is
+/// applied at the boundaries. This simulation can only step forward.
class ScrollSimulation extends SimulationGroup {
+ /// Creates a [ScrollSimulation] with the given parameters.
+ ///
+ /// The position and velocity arguments must use the same units as will be
+ /// expected from the [x] and [dx] methods respectively.
+ ///
+ /// The leading and trailing extents must use the unit of length, the same
+ /// unit as used for the position argument and as expected from the [x]
+ /// method.
+ ///
+ /// The units used with the provided [SpringDescription] must similarly be
+ /// consistent with the other arguments.
+ ///
+ /// The final argument is the coefficient of friction, which is unitless.
ScrollSimulation(
double position,
double velocity,
diff --git a/packages/newton/lib/src/simulation.dart b/packages/newton/lib/src/simulation.dart
index 512f1b6..13357ba 100644
--- a/packages/newton/lib/src/simulation.dart
+++ b/packages/newton/lib/src/simulation.dart
@@ -4,18 +4,47 @@
import 'tolerance.dart';
-/// The base class for all simulations. The user is meant to instantiate an
-/// instance of a simulation and query the same for the position and velocity
-/// of the body at a given interval.
+/// The base class for all simulations.
+///
+/// A simulation models an object, in a one-dimensional space, on which particular
+/// forces are being applied, and exposes:
+///
+/// * The object's position, [x]
+/// * The object's velocity, [dx]
+/// * Whether the simulation is "done", [isDone]
+///
+/// A simulation is generally "done" if the object has, to a given [tolerance],
+/// come to a complete rest.
+///
+/// The [x], [dx], and [isDone] functions take a time argument which specifies
+/// the time for which they are to be evaluated. In principle, simulations can
+/// be stateless, and thus can be queried with arbitrary times. In practice,
+/// however, some simulations are not, and calling any of these functions will
+/// advance the simulation to the given time.
+///
+/// As a general rule, therefore, a simulation should only be queried using
+/// times that are equal to or greater than all times previously used for that
+/// simulation.
+///
+/// Simulations do not specify units for distance, velocity, and time. Client
+/// should establish a convention and use that convention consistently with all
+/// related objects.
abstract class Simulation {
- Tolerance tolerance = toleranceDefault;
-
- /// The current position of the object in the simulation
+ /// The position of the object in the simulation at the given time.
double x(double time);
- /// The current velocity of the object in the simulation
+ /// The velocity of the object in the simulation at the given time.
double dx(double time);
- /// Returns if the simulation is done at a given time
+ /// Whether the simulation is "done" at the given time.
bool isDone(double time);
+
+ /// How close to the actual end of the simulation a value at a particular time
+ /// must be before [isDone] considers the simulation to be "done".
+ ///
+ /// A simulation with an asymptotic curve would never technically be "done",
+ /// but once the difference from the value at a particular time and the
+ /// asymptote itself could not be seen, it would be pointless to continue. The
+ /// tolerance defines how to determine if the difference could not be seen.
+ Tolerance tolerance = Tolerance.defaultTolerance;
}
diff --git a/packages/newton/lib/src/simulation_group.dart b/packages/newton/lib/src/simulation_group.dart
index 83269be..86411bf 100644
--- a/packages/newton/lib/src/simulation_group.dart
+++ b/packages/newton/lib/src/simulation_group.dart
@@ -6,25 +6,50 @@
import 'tolerance.dart';
import 'utils.dart';
-/// The abstract base class for all composite simulations. Concrete subclasses
-/// must implement the appropriate methods to select the appropriate simulation
-/// at a given time interval. The simulation group takes care to call the `step`
-/// method at appropriate intervals. If more fine grained control over the the
-/// step is necessary, subclasses may override the [x], [dx], and [isDone]
-/// methods.
+/// Base class for composite simulations.
+///
+/// Concrete subclasses must implement the [currentSimulation] getter, the
+/// [currentIntervalOffset] getter, and the [step] function to select the
+/// appropriate simulation at a given time interval. This class implements the
+/// [x], [dx], and [isDone] functions by calling the [step] method if necessary
+/// and then deferring to the [currentSimulation]'s methods with a time offset
+/// by [currentIntervalOffset].
+///
+/// The tolerance of this simulation is pushed to the simulations that are used
+/// by this group as they become active. This mean simulations should not be
+/// shared among different groups that are active at the same time.
abstract class SimulationGroup extends Simulation {
- /// The currently active simulation
+ /// The currently active simulation.
+ ///
+ /// This getter should return the same value until [step] is called and
+ /// returns true.
Simulation get currentSimulation;
- /// The time offset applied to the currently active simulation;
+ /// The time offset applied to the currently active simulation when deferring
+ /// [x], [dx], and [isDone] to it.
double get currentIntervalOffset;
/// Called when a significant change in the interval is detected. Subclasses
- /// must decide if the the current simulation must be switched (or updated).
- /// The result is whether the simulation was switched in this step.
+ /// must decide if the current simulation must be switched (or updated).
+ ///
+ /// Must return true if the simulation was switched in this step, otherwise
+ /// false.
+ ///
+ /// If this function returns true, then [currentSimulation] must start
+ /// returning a new value.
bool step(double time);
+ double _lastStep = -1.0;
+ void _stepIfNecessary(double time) {
+ if (nearEqual(_lastStep, time, Tolerance.defaultTolerance.time))
+ return;
+
+ _lastStep = time;
+ if (step(time))
+ currentSimulation.tolerance = tolerance;
+ }
+
@override
double x(double time) {
_stepIfNecessary(time);
@@ -38,26 +63,14 @@
}
@override
- void set tolerance(Tolerance t) {
- this.currentSimulation.tolerance = t;
- super.tolerance = t;
- }
-
- @override
bool isDone(double time) {
_stepIfNecessary(time);
return currentSimulation.isDone(time - currentIntervalOffset);
}
- double _lastStep = -1.0;
- void _stepIfNecessary(double time) {
- if (nearEqual(_lastStep, time, toleranceDefault.time)) {
- return;
- }
-
- _lastStep = time;
- if (step(time)) {
- this.currentSimulation.tolerance = this.tolerance;
- }
+ @override
+ void set tolerance(Tolerance t) {
+ currentSimulation.tolerance = t;
+ super.tolerance = t;
}
}
diff --git a/packages/newton/lib/src/spring_simulation.dart b/packages/newton/lib/src/spring_simulation.dart
index c205119..5109ce9 100644
--- a/packages/newton/lib/src/spring_simulation.dart
+++ b/packages/newton/lib/src/spring_simulation.dart
@@ -7,7 +7,135 @@
import 'simulation.dart';
import 'utils.dart';
-enum SpringType { unknown, criticallyDamped, underDamped, overDamped }
+/// Structure that describes a spring's constants.
+///
+/// Used to configure a [SpringSimulation].
+class SpringDescription {
+ /// Creates a spring given the mass, spring constant and the damping coefficient.
+ ///
+ /// See [mass], [springConstant], and [damping] for the units of the arguments.
+ const SpringDescription({
+ this.mass,
+ this.springConstant,
+ this.damping
+ });
+
+ /// Creates a spring given the mass (m), spring constant (k), and damping
+ /// ratio (ζ). The damping ratio is especially useful trying to determing the
+ /// type of spring to create. A ratio of 1.0 creates a critically damped
+ /// spring, > 1.0 creates an overdamped spring and < 1.0 an underdamped one.
+ ///
+ /// See [mass] and [springConstant] for the units for those arguments. The
+ /// damping ratio is unitless.
+ SpringDescription.withDampingRatio({
+ double mass,
+ double springConstant,
+ double ratio: 1.0
+ }) : mass = mass,
+ springConstant = springConstant,
+ damping = ratio * 2.0 * math.sqrt(mass * springConstant);
+
+ /// The mass of the spring (m). The units are arbitrary, but all springs
+ /// within a system should use the same mass units.
+ final double mass;
+
+ /// The spring constant (k). The units of the spring constant are M/T², where
+ /// M is the mass unit used for the value of the [mass] property, and T is the
+ /// time unit used for driving the [SpringSimulation].
+ final double springConstant;
+
+ /// The damping coefficient (c).
+ ///
+ /// Do not confuse the damping _coefficient_ (c) with the damping _ratio_ (ζ).
+ /// To create a [SpringDescription] with a damping ratio, use the [new
+ /// SpringDescription.withDampingRatio] constructor.
+ ///
+ /// The units of the damping coefficient are M/T, where M is the mass unit
+ /// used for the value of the [mass] property, and T is the time unit used for
+ /// driving the [SpringSimulation].
+ final double damping;
+}
+
+/// The kind of spring solution that the [SpringSimulation] is using to simulate the spring.
+///
+/// See [SpringSimulation.type].
+enum SpringType {
+ /// A spring that does not bounce and returns to its rest position in the
+ /// shortest possible time.
+ criticallyDamped,
+
+ /// A spring that bounces.
+ underDamped,
+
+ /// A spring that does not bounce but takes longer to return to its rest
+ /// position than a [criticallyDamped] one.
+ overDamped,
+}
+
+/// A spring simulation.
+///
+/// Models a particle attached to a spring that follows Hooke's law.
+class SpringSimulation extends Simulation {
+ /// Creates a spring simulation from the provided spring description, start
+ /// distance, end distance, and initial velocity.
+ ///
+ /// The units for the start and end distance arguments are arbitrary, but must
+ /// be consistent with the units used for other lengths in the system.
+ ///
+ /// The units for the velocity are L/T, where L is the aforementioned
+ /// arbitrary unit of length, and T is the time unit used for driving the
+ /// [SpringSimulation].
+ SpringSimulation(
+ SpringDescription desc,
+ double start,
+ double end,
+ double velocity
+ ) : _endPosition = end,
+ _solution = new _SpringSolution(desc, start - end, velocity);
+
+ final double _endPosition;
+ final _SpringSolution _solution;
+
+ /// The kind of spring being simulated, for debugging purposes.
+ ///
+ /// This is derived from the [SpringDescription] provided to the [new
+ /// SpringSimulation] constructor.
+ SpringType get type => _solution.type;
+
+ @override
+ double x(double time) => _endPosition + _solution.x(time);
+
+ @override
+ double dx(double time) => _solution.dx(time);
+
+ @override
+ bool isDone(double time) {
+ return nearZero(_solution.x(time), tolerance.distance) &&
+ nearZero(_solution.dx(time), tolerance.velocity);
+ }
+}
+
+/// A SpringSimulation where the value of [x] is guaranteed to have exactly the
+/// end value when the simulation isDone().
+class ScrollSpringSimulation extends SpringSimulation {
+ /// Creates a spring simulation from the provided spring description, start
+ /// distance, end distance, and initial velocity.
+ ///
+ /// See the [new SpringSimulation] constructor on the superclass for a
+ /// discussion of the arguments' units.
+ ScrollSpringSimulation(
+ SpringDescription desc,
+ double start,
+ double end,
+ double velocity
+ ) : super(desc, start, end, velocity);
+
+ @override
+ double x(double time) => isDone(time) ? _endPosition : super.x(time);
+}
+
+
+// SPRING IMPLEMENTATIONS
abstract class _SpringSolution {
factory _SpringSolution(
@@ -15,6 +143,12 @@
double initialPosition,
double initialVelocity
) {
+ assert(desc != null);
+ assert(desc.mass != null);
+ assert(desc.springConstant != null);
+ assert(desc.damping != null);
+ assert(initialPosition != null);
+ assert(initialVelocity != null);
double cmk = desc.damping * desc.damping - 4 * desc.mass * desc.springConstant;
if (cmk == 0.0)
return new _CriticalSolution(desc, initialPosition, initialVelocity);
@@ -140,83 +274,3 @@
@override
SpringType get type => SpringType.underDamped;
}
-
-class SpringDescription {
- SpringDescription({
- this.mass,
- this.springConstant,
- this.damping
- }) {
- assert(mass != null);
- assert(springConstant != null);
- assert(damping != null);
- }
-
- /// Create a spring given the mass, spring constant and the damping ratio. The
- /// damping ratio is especially useful trying to determing the type of spring
- /// to create. A ratio of 1.0 creates a critically damped spring, > 1.0
- /// creates an overdamped spring and < 1.0 an underdamped one.
- SpringDescription.withDampingRatio({
- double mass,
- double springConstant,
- double ratio: 1.0
- }) : mass = mass,
- springConstant = springConstant,
- damping = ratio * 2.0 * math.sqrt(mass * springConstant);
-
- /// The mass of the spring (m)
- final double mass;
-
- /// The spring constant (k)
- final double springConstant;
-
- /// The damping coefficient.
- /// Not to be confused with the damping ratio. Use the separate
- /// constructor provided for this purpose
- final double damping;
-}
-
-/// Creates a spring simulation. Depending on the spring description, a
-/// critically, under or overdamped spring will be created.
-class SpringSimulation extends Simulation {
- /// A spring description with the provided spring description, start distance,
- /// end distance and velocity.
- SpringSimulation(
- SpringDescription desc,
- double start,
- double end,
- double velocity
- ) : _endPosition = end,
- _solution = new _SpringSolution(desc, start - end, velocity);
-
- final double _endPosition;
- final _SpringSolution _solution;
-
- SpringType get type => _solution.type;
-
- @override
- double x(double time) => _endPosition + _solution.x(time);
-
- @override
- double dx(double time) => _solution.dx(time);
-
- @override
- bool isDone(double time) {
- return nearZero(_solution.x(time), tolerance.distance) &&
- nearZero(_solution.dx(time), tolerance.velocity);
- }
-}
-
-/// A SpringSimulation where the value of x() is guaranteed to have exactly the
-/// end value when the simulation isDone().
-class ScrollSpringSimulation extends SpringSimulation {
- ScrollSpringSimulation(
- SpringDescription desc,
- double start,
- double end,
- double velocity
- ) : super(desc, start, end, velocity);
-
- @override
- double x(double time) => isDone(time) ? _endPosition : super.x(time);
-}
diff --git a/packages/newton/lib/src/tolerance.dart b/packages/newton/lib/src/tolerance.dart
index 5ff48c7..47d2afe 100644
--- a/packages/newton/lib/src/tolerance.dart
+++ b/packages/newton/lib/src/tolerance.dart
@@ -2,17 +2,45 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+/// Structure that specifies maximum allowable magnitudes for distances,
+/// durations, and velocity differences to be considered equal.
class Tolerance {
+ /// Creates a [Tolerance] object. By default, the distance, time, and velocity
+ /// tolerances are all ±0.001; the constructor arguments override this.
+ ///
+ /// The arguments should all be positive values.
+ const Tolerance({
+ this.distance: _kEpsilonDefault,
+ this.time: _kEpsilonDefault,
+ this.velocity: _kEpsilonDefault
+ });
+
+ static const double _kEpsilonDefault = 1e-3;
+
+ /// A default tolerance of 0.001 for all three values.
+ static const Tolerance defaultTolerance = const Tolerance();
+
+ /// The magnitude of the maximum distance between two points for them to be
+ /// considered within tolerance.
+ ///
+ /// The units for the distance tolerance must be the same as the units used
+ /// for the distances that are to be compared to this tolerance.
final double distance;
+
+ /// The magnitude of the maximum duration between two times for them to be
+ /// considered within tolerance.
+ ///
+ /// The units for the time tolerance must be the same as the units used
+ /// for the times that are to be compared to this tolerance.
final double time;
+
+ /// The magnitude of the maximum difference between two velocities for them to
+ /// be considered within tolerance.
+ ///
+ /// The units for the velocity tolerance must be the same as the units used
+ /// for the velocities that are to be compared to this tolerance.
final double velocity;
- const Tolerance({this.distance: epsilonDefault, this.time: epsilonDefault,
- this.velocity: epsilonDefault});
-
@override
- String toString() => 'Tolerance(distance: $distance, time=$time, velocity: $velocity)';
+ String toString() => 'Tolerance(distance: ±$distance, time: ±$time, velocity: ±$velocity)';
}
-
-const double epsilonDefault = 1e-3;
-const Tolerance toleranceDefault = const Tolerance();
diff --git a/packages/newton/lib/src/utils.dart b/packages/newton/lib/src/utils.dart
index b66bb46..26d8148 100644
--- a/packages/newton/lib/src/utils.dart
+++ b/packages/newton/lib/src/utils.dart
@@ -2,9 +2,15 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+/// Whether two doubles are within a given distance of each other.
+///
+/// The epsilon argument must be positive.
bool nearEqual(double a, double b, double epsilon) {
assert(epsilon >= 0.0);
return (a > (b - epsilon)) && (a < (b + epsilon));
}
+/// Whether a double is within a given distance of zero.
+///
+/// The epsilon argument must be positive.
bool nearZero(double a, double epsilon) => nearEqual(a, 0.0, epsilon);
diff --git a/packages/newton/test/all.dart b/packages/newton/test/all.dart
index 34f4260..84523ac 100644
--- a/packages/newton/test/all.dart
+++ b/packages/newton/test/all.dart
@@ -2,8 +2,10 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+import 'near_equal_test.dart' as near_equal_test;
import 'newton_test.dart' as newton_test;
void main() {
+ near_equal_test.main();
newton_test.main();
}
diff --git a/packages/newton/test/near_equal_test.dart b/packages/newton/test/near_equal_test.dart
new file mode 100644
index 0000000..f584280
--- /dev/null
+++ b/packages/newton/test/near_equal_test.dart
@@ -0,0 +1,16 @@
+// Copyright (c) 2015 The Chromium 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:test/test.dart';
+
+import 'package:newton/newton.dart';
+
+void main() {
+ test('test_friction', () {
+ expect(nearEqual(5.0, 6.0, 2.0), isTrue);
+ expect(nearEqual(6.0, 5.0, 2.0), isTrue);
+ expect(nearEqual(5.0, 6.0, 0.5), isFalse);
+ expect(nearEqual(6.0, 5.0, 0.5), isFalse);
+ });
+}
diff --git a/packages/newton/test/newton_test.dart b/packages/newton/test/newton_test.dart
index cacc584..75d3ba0 100644
--- a/packages/newton/test/newton_test.dart
+++ b/packages/newton/test/newton_test.dart
@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-library simple_physics.test;
-
import 'package:test/test.dart';
import 'package:newton/newton.dart';