Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(355)

Side by Side Diff: sky/framework/animation/mechanics.dart

Issue 1100583002: [Effen] implement bounce back behaviour for lists. Turns out this is (Closed) Base URL: https://github.com/domokit/mojo.git@master
Patch Set: Created 5 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | sky/framework/animation/scroll_behavior.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 import 'dart:math' as math; 5 import 'dart:math' as math;
6 6
7 const double kGravity = -0.980; 7 const double kGravity = -0.980; // m^s-2
8 8
9 abstract class System { 9 abstract class System {
10 void update(double deltaT); 10 void update(double deltaT);
11 } 11 }
12 12
13 class Particle extends System { 13 class Particle extends System {
14 final double mass; 14 final double mass;
15 double velocity; 15 double velocity;
16 double position; 16 double position;
17 17
18 Particle({this.mass: 1.0, this.velocity: 0.0, this.position: 0.0}); 18 Particle({this.mass: 1.0, this.velocity: 0.0, this.position: 0.0});
19 19
20 void applyImpulse(double impulse) { 20 void applyImpulse(double impulse) {
21 velocity += impulse / mass; 21 velocity += impulse / mass;
22 } 22 }
23 23
24 void update(double deltaT) { 24 void update(double deltaT) {
25 position += velocity * deltaT; 25 position += velocity * deltaT;
26 } 26 }
27 27
28 double get energy => 0.5 * mass * velocity * velocity; 28 double get energy => 0.5 * mass * velocity * velocity;
29 set energy(double e) { 29 set energy(double e) { // J
30 assert(e >= 0.0); 30 assert(e >= 0.0);
31 velocity = math.sqrt(2 * e / mass); 31 velocity = math.sqrt(2.0 * e / mass);
32 } 32 }
33 } 33 }
34 34
35 class Box { 35 abstract class Box {
36 final double min; 36 void confine(Particle p);
37 final double max; 37 }
38 38
39 Box({this.min, this.max}) { 39 class ClosedBox extends Box {
40 final double min; // m
41 final double max; // m
42
43 ClosedBox({this.min, this.max}) {
40 assert(min == null || max == null || min <= max); 44 assert(min == null || max == null || min <= max);
41 } 45 }
42 46
43 void confine(Particle p) { 47 void confine(Particle p) {
44 if (min != null) { 48 if (min != null) {
45 p.position = math.max(min, p.position); 49 p.position = math.max(min, p.position);
46 if (p.position == min) 50 if (p.position == min)
47 p.velocity = math.max(0.0, p.velocity); 51 p.velocity = math.max(0.0, p.velocity);
48 } 52 }
49 if (max != null) { 53 if (max != null) {
50 p.position = math.min(max, p.position); 54 p.position = math.min(max, p.position);
51 if (p.position == max) 55 if (p.position == max)
52 p.velocity = math.min(0.0, p.velocity); 56 p.velocity = math.min(0.0, p.velocity);
53 } 57 }
54 } 58 }
55 } 59 }
56 60
61 class GeofenceBox extends Box {
62 final double min; // m
63 final double max; // m
64
65 final Function onEscape;
66
67 GeofenceBox({this.min, this.max, this.onEscape}) {
68 assert(min == null || max == null || min <= max);
69 assert(onEscape != null);
70 }
71
72 void confine(Particle p) {
73 if (((min != null) && (p.position < min)) ||
74 ((max != null) && (p.position > max)))
75 onEscape();
76 }
77 }
78
57 class ParticleInBox extends System { 79 class ParticleInBox extends System {
58 final Particle particle; 80 final Particle particle;
59 final Box box; 81 final Box box;
60 82
61 ParticleInBox({this.particle, this.box}) { 83 ParticleInBox({this.particle, this.box}) {
62 box.confine(particle); 84 box.confine(particle);
63 } 85 }
64 86
65 void update(double deltaT) { 87 void update(double deltaT) {
66 particle.update(deltaT); 88 particle.update(deltaT);
67 box.confine(particle); 89 box.confine(particle);
68 } 90 }
69 } 91 }
70 92
71 class ParticleInBoxWithFriction extends ParticleInBox { 93 class ParticleInBoxWithFriction extends ParticleInBox {
72 final double friction; 94 final double friction; // unitless
73 final double _sign; 95 final double _sign;
74 96
75 ParticleInBoxWithFriction({Particle particle, Box box, this.friction}) 97 final Function onStop;
98
99 ParticleInBoxWithFriction({Particle particle, Box box, this.friction, this.onS top})
76 : super(particle: particle, box: box), 100 : super(particle: particle, box: box),
77 _sign = particle.velocity.sign; 101 _sign = particle.velocity.sign;
78 102
79 void update(double deltaT) { 103 void update(double deltaT) {
80 double force = -_sign * friction; 104 double force = -_sign * friction * particle.mass * -kGravity;
81 particle.applyImpulse(force * deltaT); 105 particle.applyImpulse(force * deltaT);
82 if (particle.velocity.sign != _sign) 106 if (particle.velocity.sign != _sign) {
83 particle.velocity = 0.0; 107 particle.velocity = 0.0;
108 }
84 super.update(deltaT); 109 super.update(deltaT);
110 if ((particle.velocity == 0.0) && (onStop != null))
111 onStop();
85 } 112 }
86 } 113 }
87 114
88 class Spring { 115 class Spring {
89 final double k; 116 final double k;
90 double displacement; 117 double displacement;
91 118
92 Spring(this.k, {this.displacement: 0.0}); 119 Spring(this.k, {this.displacement: 0.0});
93 120
94 double get force => -k * displacement; 121 double get force => -k * displacement;
(...skipping 14 matching lines...) Expand all
109 _applyInvariants(); 136 _applyInvariants();
110 } 137 }
111 138
112 void _applyInvariants() { 139 void _applyInvariants() {
113 box.confine(particle); 140 box.confine(particle);
114 spring.displacement = particle.position; 141 spring.displacement = particle.position;
115 } 142 }
116 } 143 }
117 144
118 class ParticleClimbingRamp extends System { 145 class ParticleClimbingRamp extends System {
146
147 // This is technically the same as ParticleInBoxWithFriction. The
148 // difference is in how the system is set up. Here, we configure the
149 // system so as to stop by a certain distance after having been
150 // given an initial impulse from rest, whereas
151 // ParticleInBoxWithFriction is set up to stop with a consistent
152 // decelerating force assuming an initial velocity. The angle theta
153 // (0 < theta < π/2) is used to configure how much energy the
154 // particle is to start with; lower angles result in a gentler kick
155 // while higher angles result in a faster conclusion.
156
119 final Particle particle; 157 final Particle particle;
120 final Box box; 158 final Box box;
121 final double slope; 159 final double theta;
160 final double _sinTheta;
122 161
123 ParticleClimbingRamp({ 162 ParticleClimbingRamp({
124 this.particle, 163 this.particle,
125 this.box, 164 this.box,
126 this.slope, 165 double theta, // in radians
127 double targetPosition}) { 166 double targetPosition}) : this.theta = theta, this._sinTheta = math.sin(th eta) {
167 assert(theta > 0.0);
168 assert(theta < math.PI / 2.0);
128 double deltaPosition = targetPosition - particle.position; 169 double deltaPosition = targetPosition - particle.position;
129 particle.energy = -kGravity * slope * deltaPosition * particle.mass; 170 double tanTheta = math.tan(theta);
171 // We need to give the particle exactly as much (kinetic) energy
172 // as it needs to get to the top of the slope and stop with
173 // energy=0. This is exactly the same amount of energy as the
174 // potential energy at the top of the slope, which is g*h*m.
175 // If the slope's horizontal component is delta P long, then
176 // the height is delta P times tan theta.
177 particle.energy = -kGravity * (deltaPosition * tanTheta) * particle.mass;
130 box.confine(particle); 178 box.confine(particle);
131 } 179 }
132 180
133 void update(double deltaT) { 181 void update(double deltaT) {
134 particle.update(deltaT); 182 particle.update(deltaT);
135 // Note that we apply the impulse from gravity after updating the particle's 183 // Note that we apply the impulse from gravity after updating the particle's
136 // position so that we overestimate the distance traveled by the particle. 184 // position so that we overestimate the distance traveled by the particle.
137 // That ensures that we actually hit the edge of the box and don't wind up 185 // That ensures that we actually hit the edge of the box and don't wind up
138 // reversing course. 186 // reversing course.
139 particle.applyImpulse(kGravity * slope * deltaT); 187 particle.applyImpulse(particle.mass * kGravity * _sinTheta * deltaT);
140 box.confine(particle); 188 box.confine(particle);
141 } 189 }
142 } 190 }
191
192 class Multisystem extends System {
193 final Particle particle;
194
195 System _currentSystem;
196
197 Multisystem({ this.particle, System system }) {
198 assert(system != null);
199 _currentSystem = system;
200 }
201
202 void update(double deltaT) {
203 _currentSystem.update(deltaT);
204 }
205
206 void transitionToSystem(System system) {
207 assert(system != null);
208 _currentSystem = system;
209 }
210 }
OLDNEW
« no previous file with comments | « no previous file | sky/framework/animation/scroll_behavior.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698