1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
// Copyright 2016 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 'simulation.dart';
import 'tolerance.dart';
import 'utils.dart';
/// 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.
///
/// 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 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 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);
return currentSimulation.x(time - currentIntervalOffset);
}
@override
double dx(double time) {
_stepIfNecessary(time);
return currentSimulation.dx(time - currentIntervalOffset);
}
@override
bool isDone(double time) {
_stepIfNecessary(time);
return currentSimulation.isDone(time - currentIntervalOffset);
}
@override
set tolerance(Tolerance t) {
currentSimulation.tolerance = t;
super.tolerance = t;
}
}