Commit 36694ac0 authored by Ian Hickson's avatar Ian Hickson

Merge pull request #2452 from Hixie/unsimulatable

Remove Simulatable and restyle simulation_group.dart
parents fdb4bd5e 0a4cc82a
...@@ -4,20 +4,18 @@ ...@@ -4,20 +4,18 @@
import 'tolerance.dart'; import 'tolerance.dart';
abstract class Simulatable {
/// The current position of the object in the simulation
double x(double time);
/// The current velocity of the object in the simulation
double dx(double time);
}
/// 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.
abstract class Simulation implements Simulatable { abstract class Simulation {
Tolerance tolerance = toleranceDefault; Tolerance tolerance = toleranceDefault;
/// The current position of the object in the simulation
double x(double time);
/// The current velocity of the object in the simulation
double dx(double time); // TODO(ianh): remove this; see https://github.com/flutter/flutter/issues/2092
/// 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);
} }
...@@ -10,7 +10,8 @@ import 'utils.dart'; ...@@ -10,7 +10,8 @@ import 'utils.dart';
/// must implement the appropriate methods to select the appropriate simulation /// must implement the appropriate methods to select the appropriate simulation
/// at a given time interval. The simulation group takes care to call the `step` /// 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 /// method at appropriate intervals. If more fine grained control over the the
/// step is necessary, subclasses may override `Simulatable` methods. /// step is necessary, subclasses may override the [x], [dx], and [isDone]
/// methods.
abstract class SimulationGroup extends Simulation { abstract class SimulationGroup extends Simulation {
/// The currently active simulation /// The currently active simulation
......
...@@ -7,120 +7,154 @@ import 'dart:math' as math; ...@@ -7,120 +7,154 @@ import 'dart:math' as math;
import 'simulation.dart'; import 'simulation.dart';
import 'utils.dart'; import 'utils.dart';
abstract class _SpringSolution implements Simulatable { enum SpringType { unknown, criticallyDamped, underDamped, overDamped }
factory _SpringSolution(
SpringDescription desc, double initialPosition, double initialVelocity) {
double cmk =
desc.damping * desc.damping - 4 * desc.mass * desc.springConstant;
if (cmk == 0.0) { abstract class _SpringSolution {
factory _SpringSolution(
SpringDescription desc,
double initialPosition,
double initialVelocity
) {
double cmk = desc.damping * desc.damping - 4 * desc.mass * desc.springConstant;
if (cmk == 0.0)
return new _CriticalSolution(desc, initialPosition, initialVelocity); return new _CriticalSolution(desc, initialPosition, initialVelocity);
} else if (cmk > 0.0) { if (cmk > 0.0)
return new _OverdampedSolution(desc, initialPosition, initialVelocity); return new _OverdampedSolution(desc, initialPosition, initialVelocity);
} else { return new _UnderdampedSolution(desc, initialPosition, initialVelocity);
return new _UnderdampedSolution(desc, initialPosition, initialVelocity);
}
return null;
} }
double x(double time);
double dx(double time);
SpringType get type; SpringType get type;
} }
class _CriticalSolution implements _SpringSolution { class _CriticalSolution implements _SpringSolution {
final double _r, _c1, _c2;
factory _CriticalSolution( factory _CriticalSolution(
SpringDescription desc, double distance, double velocity) { SpringDescription desc,
double distance,
double velocity
) {
final double r = -desc.damping / (2.0 * desc.mass); final double r = -desc.damping / (2.0 * desc.mass);
final double c1 = distance; final double c1 = distance;
final double c2 = velocity / (r * distance); final double c2 = velocity / (r * distance);
return new _CriticalSolution.withArgs(r, c1, c2); return new _CriticalSolution.withArgs(r, c1, c2);
} }
SpringType get type => SpringType.criticallyDamped;
_CriticalSolution.withArgs(double r, double c1, double c2) _CriticalSolution.withArgs(double r, double c1, double c2)
: _r = r, : _r = r,
_c1 = c1, _c1 = c1,
_c2 = c2; _c2 = c2;
double x(double time) => (_c1 + _c2 * time) * math.pow(math.E, _r * time); final double _r, _c1, _c2;
double x(double time) {
return (_c1 + _c2 * time) * math.pow(math.E, _r * time);
}
double dx(double time) { double dx(double time) {
final double power = math.pow(math.E, _r * time); final double power = math.pow(math.E, _r * time);
return _r * (_c1 + _c2 * time) * power + _c2 * power; return _r * (_c1 + _c2 * time) * power + _c2 * power;
} }
SpringType get type => SpringType.criticallyDamped;
} }
class _OverdampedSolution implements _SpringSolution { class _OverdampedSolution implements _SpringSolution {
final double _r1, _r2, _c1, _c2;
factory _OverdampedSolution( factory _OverdampedSolution(
SpringDescription desc, double distance, double velocity) { SpringDescription desc,
final double cmk = double distance,
desc.damping * desc.damping - 4 * desc.mass * desc.springConstant; double velocity
) {
final double cmk = desc.damping * desc.damping - 4 * desc.mass * desc.springConstant;
final double r1 = (-desc.damping - math.sqrt(cmk)) / (2.0 * desc.mass); final double r1 = (-desc.damping - math.sqrt(cmk)) / (2.0 * desc.mass);
final double r2 = (-desc.damping + math.sqrt(cmk)) / (2.0 * desc.mass); final double r2 = (-desc.damping + math.sqrt(cmk)) / (2.0 * desc.mass);
final double c2 = (velocity - r1 * distance) / (r2 - r1); final double c2 = (velocity - r1 * distance) / (r2 - r1);
final double c1 = distance - c2; final double c1 = distance - c2;
return new _OverdampedSolution.withArgs(r1, r2, c1, c2); return new _OverdampedSolution.withArgs(r1, r2, c1, c2);
} }
_OverdampedSolution.withArgs(double r1, double r2, double c1, double c2) _OverdampedSolution.withArgs(double r1, double r2, double c1, double c2)
: _r1 = r1, : _r1 = r1,
_r2 = r2, _r2 = r2,
_c1 = c1, _c1 = c1,
_c2 = c2; _c2 = c2;
SpringType get type => SpringType.overDamped; final double _r1, _r2, _c1, _c2;
double x(double time) => double x(double time) {
(_c1 * math.pow(math.E, _r1 * time) + _c2 * math.pow(math.E, _r2 * time)); return _c1 * math.pow(math.E, _r1 * time) +
_c2 * math.pow(math.E, _r2 * time);
}
double dx(double time) {
return _c1 * _r1 * math.pow(math.E, _r1 * time) +
_c2 * _r2 * math.pow(math.E, _r2 * time);
}
double dx(double time) => (_c1 * _r1 * math.pow(math.E, _r1 * time) + SpringType get type => SpringType.overDamped;
_c2 * _r2 * math.pow(math.E, _r2 * time));
} }
class _UnderdampedSolution implements _SpringSolution { class _UnderdampedSolution implements _SpringSolution {
final double _w, _r, _c1, _c2;
factory _UnderdampedSolution( factory _UnderdampedSolution(
SpringDescription desc, double distance, double velocity) { SpringDescription desc,
double distance,
double velocity
) {
final double w = math.sqrt(4.0 * desc.mass * desc.springConstant - final double w = math.sqrt(4.0 * desc.mass * desc.springConstant -
desc.damping * desc.damping) / desc.damping * desc.damping) / (2.0 * desc.mass);
(2.0 * desc.mass);
final double r = -(desc.damping / 2.0 * desc.mass); final double r = -(desc.damping / 2.0 * desc.mass);
final double c1 = distance; final double c1 = distance;
final double c2 = (velocity - r * distance) / w; final double c2 = (velocity - r * distance) / w;
return new _UnderdampedSolution.withArgs(w, r, c1, c2); return new _UnderdampedSolution.withArgs(w, r, c1, c2);
} }
_UnderdampedSolution.withArgs(double w, double r, double c1, double c2) _UnderdampedSolution.withArgs(double w, double r, double c1, double c2)
: _w = w, : _w = w,
_r = r, _r = r,
_c1 = c1, _c1 = c1,
_c2 = c2; _c2 = c2;
SpringType get type => SpringType.underDamped; final double _w, _r, _c1, _c2;
double x(double time) => math.pow(math.E, _r * time) * double x(double time) {
(_c1 * math.cos(_w * time) + _c2 * math.sin(_w * time)); return math.pow(math.E, _r * time) *
(_c1 * math.cos(_w * time) + _c2 * math.sin(_w * time));
}
double dx(double time) { double dx(double time) {
final double power = math.pow(math.E, _r * time); final double power = math.pow(math.E, _r * time);
final double cosine = math.cos(_w * time); final double cosine = math.cos(_w * time);
final double sine = math.sin(_w * time); final double sine = math.sin(_w * time);
return power * (_c2 * _w * cosine - _c1 * _w * sine) +
return power * (_c2 * _w * cosine - _c1 * _w * sine) + _r * power * (_c2 * sine + _c1 * cosine);
_r * power * (_c2 * sine + _c1 * cosine);
} }
SpringType get type => SpringType.underDamped;
} }
class SpringDescription { 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) /// The mass of the spring (m)
final double mass; final double mass;
...@@ -131,41 +165,23 @@ class SpringDescription { ...@@ -131,41 +165,23 @@ class SpringDescription {
/// Not to be confused with the damping ratio. Use the separate /// Not to be confused with the damping ratio. Use the separate
/// constructor provided for this purpose /// constructor provided for this purpose
final double damping; final double damping;
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);
} }
enum SpringType { unknown, criticallyDamped, underDamped, overDamped, }
/// Creates a spring simulation. Depending on the spring description, a /// Creates a spring simulation. Depending on the spring description, a
/// critically, under or overdamped spring will be created. /// critically, under or overdamped spring will be created.
class SpringSimulation extends Simulation { class SpringSimulation extends Simulation {
final double _endPosition;
final _SpringSolution _solution;
/// A spring description with the provided spring description, start distance, /// A spring description with the provided spring description, start distance,
/// end distance and velocity. /// end distance and velocity.
SpringSimulation( SpringSimulation(
SpringDescription desc, double start, double end, double velocity) SpringDescription desc,
: this._endPosition = end, double start,
_solution = new _SpringSolution(desc, start - end, velocity); double end,
double velocity
) : _endPosition = end,
_solution = new _SpringSolution(desc, start - end, velocity);
final double _endPosition;
final _SpringSolution _solution;
SpringType get type => _solution.type; SpringType get type => _solution.type;
...@@ -182,8 +198,12 @@ class SpringSimulation extends Simulation { ...@@ -182,8 +198,12 @@ class SpringSimulation extends Simulation {
/// A SpringSimulation where the value of x() is guaranteed to have exactly the /// A SpringSimulation where the value of x() is guaranteed to have exactly the
/// end value when the simulation isDone(). /// end value when the simulation isDone().
class ScrollSpringSimulation extends SpringSimulation { class ScrollSpringSimulation extends SpringSimulation {
ScrollSpringSimulation(SpringDescription desc, double start, double end, double velocity) ScrollSpringSimulation(
: super(desc, start, end, velocity); SpringDescription desc,
double start,
double end,
double velocity
) : super(desc, start, end, velocity);
double x(double time) => isDone(time) ? _endPosition : super.x(time); double x(double time) => isDone(time) ? _endPosition : super.x(time);
} }
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