simulation_group.dart 2.57 KB
Newer Older
1
// Copyright 2016 The Chromium Authors. All rights reserved.
2 3 4
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

5 6 7
import 'simulation.dart';
import 'tolerance.dart';
import 'utils.dart';
8

Ian Hickson's avatar
Ian Hickson committed
9 10 11 12 13 14 15 16 17 18 19 20
/// 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.
21
abstract class SimulationGroup extends Simulation {
22 23
  /// Initializes the [tolerance] field for subclasses.
  SimulationGroup({ Tolerance tolerance: Tolerance.defaultTolerance }) : super(tolerance: tolerance);
24

Ian Hickson's avatar
Ian Hickson committed
25 26 27 28
  /// The currently active simulation.
  ///
  /// This getter should return the same value until [step] is called and
  /// returns true.
29 30
  Simulation get currentSimulation;

Ian Hickson's avatar
Ian Hickson committed
31 32
  /// The time offset applied to the currently active simulation when deferring
  /// [x], [dx], and [isDone] to it.
33 34 35
  double get currentIntervalOffset;

  /// Called when a significant change in the interval is detected. Subclasses
Ian Hickson's avatar
Ian Hickson committed
36 37 38 39 40 41 42
  /// 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.
43
  bool step(double time);
44

Ian Hickson's avatar
Ian Hickson committed
45 46 47 48 49 50 51 52 53 54
  double _lastStep = -1.0;
  void _stepIfNecessary(double time) {
    if (nearEqual(_lastStep, time, Tolerance.defaultTolerance.time))
      return;

    _lastStep = time;
    if (step(time))
      currentSimulation.tolerance = tolerance;
  }

55
  @override
56 57
  double x(double time) {
    _stepIfNecessary(time);
58
    return currentSimulation.x(time - currentIntervalOffset);
59 60
  }

61
  @override
62 63
  double dx(double time) {
    _stepIfNecessary(time);
64
    return currentSimulation.dx(time - currentIntervalOffset);
65 66 67 68 69
  }

  @override
  bool isDone(double time) {
    _stepIfNecessary(time);
70
    return currentSimulation.isDone(time - currentIntervalOffset);
71 72
  }

Ian Hickson's avatar
Ian Hickson committed
73
  @override
74 75 76
  set tolerance(Tolerance value) {
    currentSimulation.tolerance = value;
    super.tolerance = value;
77 78
  }
}