mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00
Allow explicitly setting tolerances on simulations
This commit is contained in:
parent
1f1cd6c279
commit
1ad857b53b
@ -8,6 +8,7 @@ import 'dart:math' as math;
|
|||||||
|
|
||||||
part 'src/simulation.dart';
|
part 'src/simulation.dart';
|
||||||
part 'src/simulation_group.dart';
|
part 'src/simulation_group.dart';
|
||||||
|
part 'src/tolerance.dart';
|
||||||
part 'src/utils.dart';
|
part 'src/utils.dart';
|
||||||
|
|
||||||
part 'src/friction_simulation.dart';
|
part 'src/friction_simulation.dart';
|
||||||
|
@ -22,5 +22,5 @@ class FrictionSimulation extends Simulation {
|
|||||||
double dx(double time) => _v * math.pow(_drag, time);
|
double dx(double time) => _v * math.pow(_drag, time);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool isDone(double time) => dx(time).abs() < 1.0;
|
bool isDone(double time) => dx(time).abs() < this.tolerance.velocity;
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,7 @@ class ScrollSimulation extends SimulationGroup {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void step(double time) => _chooseSimulation(
|
bool step(double time) => _chooseSimulation(
|
||||||
_currentSimulation.x(time - _offset),
|
_currentSimulation.x(time - _offset),
|
||||||
_currentSimulation.dx(time - _offset), time);
|
_currentSimulation.dx(time - _offset), time);
|
||||||
|
|
||||||
@ -37,7 +37,7 @@ class ScrollSimulation extends SimulationGroup {
|
|||||||
@override
|
@override
|
||||||
double get currentIntervalOffset => _offset;
|
double get currentIntervalOffset => _offset;
|
||||||
|
|
||||||
void _chooseSimulation(
|
bool _chooseSimulation(
|
||||||
double position, double velocity, double intervalOffset) {
|
double position, double velocity, double intervalOffset) {
|
||||||
|
|
||||||
/// This simulation can only step forward.
|
/// This simulation can only step forward.
|
||||||
@ -47,19 +47,21 @@ class ScrollSimulation extends SimulationGroup {
|
|||||||
_offset = intervalOffset;
|
_offset = intervalOffset;
|
||||||
_currentSimulation = new SpringSimulation(
|
_currentSimulation = new SpringSimulation(
|
||||||
_springDesc, position, _trailingExtent, velocity);
|
_springDesc, position, _trailingExtent, velocity);
|
||||||
return;
|
return true;
|
||||||
} else if (position < _leadingExtent) {
|
} else if (position < _leadingExtent) {
|
||||||
_isSpringing = true;
|
_isSpringing = true;
|
||||||
_offset = intervalOffset;
|
_offset = intervalOffset;
|
||||||
_currentSimulation = new SpringSimulation(
|
_currentSimulation = new SpringSimulation(
|
||||||
_springDesc, position, _leadingExtent, velocity);
|
_springDesc, position, _leadingExtent, velocity);
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_currentSimulation == null) {
|
if (_currentSimulation == null) {
|
||||||
_currentSimulation = new FrictionSimulation(_drag, position, velocity);
|
_currentSimulation = new FrictionSimulation(_drag, position, velocity);
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,9 +15,8 @@ abstract class Simulatable {
|
|||||||
/// The base class for all simulations. The user is meant to instantiate an
|
/// 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
|
/// instance of a simulation and query the same for the position and velocity
|
||||||
/// of the body at a given interval.
|
/// of the body at a given interval.
|
||||||
///
|
|
||||||
/// Note: All operations on subclasses of Simulation are idempotent.
|
|
||||||
abstract class Simulation implements Simulatable {
|
abstract class Simulation implements Simulatable {
|
||||||
|
Tolerance tolerance = toleranceDefault;
|
||||||
|
|
||||||
/// Returns if the simulation is done at a given time
|
/// Returns if the simulation is done at a given time
|
||||||
bool isDone(double time);
|
bool isDone(double time);
|
||||||
|
@ -19,7 +19,8 @@ abstract class SimulationGroup extends Simulation {
|
|||||||
|
|
||||||
/// Called when a significant change in the interval is detected. Subclasses
|
/// Called when a significant change in the interval is detected. Subclasses
|
||||||
/// must decide if the the current simulation must be switched (or updated).
|
/// must decide if the the current simulation must be switched (or updated).
|
||||||
void step(double time);
|
/// The result is whether the simulation was switched in this step.
|
||||||
|
bool step(double time);
|
||||||
|
|
||||||
double x(double time) {
|
double x(double time) {
|
||||||
_stepIfNecessary(time);
|
_stepIfNecessary(time);
|
||||||
@ -31,6 +32,12 @@ abstract class SimulationGroup extends Simulation {
|
|||||||
return currentSimulation.dx(time - currentIntervalOffset);
|
return currentSimulation.dx(time - currentIntervalOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void set tolerance(Tolerance t) {
|
||||||
|
this.currentSimulation.tolerance = t;
|
||||||
|
super.tolerance = t;
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool isDone(double time) {
|
bool isDone(double time) {
|
||||||
_stepIfNecessary(time);
|
_stepIfNecessary(time);
|
||||||
@ -39,11 +46,13 @@ abstract class SimulationGroup extends Simulation {
|
|||||||
|
|
||||||
double _lastStep = -1.0;
|
double _lastStep = -1.0;
|
||||||
void _stepIfNecessary(double time) {
|
void _stepIfNecessary(double time) {
|
||||||
if (_nearEqual(_lastStep, time)) {
|
if (_nearEqual(_lastStep, time, toleranceDefault.time)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_lastStep = time;
|
_lastStep = time;
|
||||||
step(time);
|
if (step(time)) {
|
||||||
|
this.currentSimulation.tolerance = this.tolerance;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -58,5 +58,6 @@ class SpringSimulation extends Simulation {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
bool isDone(double time) =>
|
bool isDone(double time) =>
|
||||||
_nearEqual(x(time), _endPosition) && _nearZero(dx(time));
|
_nearEqual(x(time), _endPosition, this.tolerance.distance) &&
|
||||||
|
_nearZero(dx(time), this.tolerance.velocity);
|
||||||
}
|
}
|
||||||
|
17
packages/newton/lib/src/tolerance.dart
Normal file
17
packages/newton/lib/src/tolerance.dart
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
part of newton;
|
||||||
|
|
||||||
|
class Tolerance {
|
||||||
|
final double distance;
|
||||||
|
final double time;
|
||||||
|
final double velocity;
|
||||||
|
|
||||||
|
const Tolerance({this.distance: epsilonDefault, this.time: epsilonDefault,
|
||||||
|
this.velocity: epsilonDefault});
|
||||||
|
}
|
||||||
|
|
||||||
|
const double epsilonDefault = 1e-3;
|
||||||
|
const Tolerance toleranceDefault = const Tolerance();
|
@ -4,9 +4,7 @@
|
|||||||
|
|
||||||
part of newton;
|
part of newton;
|
||||||
|
|
||||||
const double _simulationEpsilon = 0.2;
|
bool _nearEqual(double a, double b, double epsilon) =>
|
||||||
|
(a > (b - epsilon)) && (a < (b + epsilon));
|
||||||
|
|
||||||
bool _nearEqual(double a, double b) =>
|
bool _nearZero(double a, double epsilon) => _nearEqual(a, 0.0, epsilon);
|
||||||
(a > (b - _simulationEpsilon)) && (a < (b + _simulationEpsilon));
|
|
||||||
|
|
||||||
bool _nearZero(double a) => _nearEqual(a, 0.0);
|
|
||||||
|
@ -12,6 +12,8 @@ void main() {
|
|||||||
test('test_friction', () {
|
test('test_friction', () {
|
||||||
var friction = new FrictionSimulation(0.3, 100.0, 400.0);
|
var friction = new FrictionSimulation(0.3, 100.0, 400.0);
|
||||||
|
|
||||||
|
friction.tolerance = const Tolerance(velocity: 1.0);
|
||||||
|
|
||||||
expect(friction.isDone(0.0), false);
|
expect(friction.isDone(0.0), false);
|
||||||
expect(friction.x(0.0), 100);
|
expect(friction.x(0.0), 100);
|
||||||
expect(friction.dx(0.0), 400.0);
|
expect(friction.dx(0.0), 400.0);
|
||||||
@ -84,6 +86,9 @@ void main() {
|
|||||||
test('crit_spring', () {
|
test('crit_spring', () {
|
||||||
var crit = new SpringSimulation(new SpringDescription.withDampingRatio(
|
var crit = new SpringSimulation(new SpringDescription.withDampingRatio(
|
||||||
mass: 1.0, springConstant: 100.0, ratio: 1.0), 0.0, 500.0, 0.0);
|
mass: 1.0, springConstant: 100.0, ratio: 1.0), 0.0, 500.0, 0.0);
|
||||||
|
|
||||||
|
crit.tolerance = const Tolerance(distance: 0.01, velocity: 0.01);
|
||||||
|
|
||||||
expect(crit.type, SpringType.criticallyDamped);
|
expect(crit.type, SpringType.criticallyDamped);
|
||||||
|
|
||||||
expect(crit.isDone(0.0), false);
|
expect(crit.isDone(0.0), false);
|
||||||
@ -106,6 +111,9 @@ void main() {
|
|||||||
test('overdamped_spring', () {
|
test('overdamped_spring', () {
|
||||||
var over = new SpringSimulation(new SpringDescription.withDampingRatio(
|
var over = new SpringSimulation(new SpringDescription.withDampingRatio(
|
||||||
mass: 1.0, springConstant: 100.0, ratio: 1.25), 0.0, 500.0, 0.0);
|
mass: 1.0, springConstant: 100.0, ratio: 1.25), 0.0, 500.0, 0.0);
|
||||||
|
|
||||||
|
over.tolerance = const Tolerance(distance: 0.01, velocity: 0.01);
|
||||||
|
|
||||||
expect(over.type, SpringType.overDamped);
|
expect(over.type, SpringType.overDamped);
|
||||||
|
|
||||||
expect(over.isDone(0.0), false);
|
expect(over.isDone(0.0), false);
|
||||||
@ -145,6 +153,8 @@ void main() {
|
|||||||
|
|
||||||
var scroll = new ScrollSimulation(100.0, 800.0, 0.0, 300.0, spring, 0.3);
|
var scroll = new ScrollSimulation(100.0, 800.0, 0.0, 300.0, spring, 0.3);
|
||||||
|
|
||||||
|
scroll.tolerance = const Tolerance(velocity: 0.01, distance: 0.01);
|
||||||
|
|
||||||
expect(scroll.isDone(0.0), false);
|
expect(scroll.isDone(0.0), false);
|
||||||
expect(scroll.isDone(3.5), true);
|
expect(scroll.isDone(3.5), true);
|
||||||
|
|
||||||
@ -159,6 +169,8 @@ void main() {
|
|||||||
var scroll =
|
var scroll =
|
||||||
new ScrollSimulation(100.0, 400.0, 0.0, double.INFINITY, spring, 0.3);
|
new ScrollSimulation(100.0, 400.0, 0.0, double.INFINITY, spring, 0.3);
|
||||||
|
|
||||||
|
scroll.tolerance = const Tolerance(velocity: 1.0);
|
||||||
|
|
||||||
expect(scroll.isDone(0.0), false);
|
expect(scroll.isDone(0.0), false);
|
||||||
expect(scroll.x(0.0), 100);
|
expect(scroll.x(0.0), 100);
|
||||||
expect(scroll.dx(0.0), 400.0);
|
expect(scroll.dx(0.0), 400.0);
|
||||||
|
Loading…
Reference in New Issue
Block a user