blob: 2032e6e05c7a0dd97b45b08dffbbf4ca83c695e0 [file] [log] [blame]
Adrien Béraud04463092013-05-06 14:17:22 +10001package com.savoirfairelinux.sflphone.model;
2
3import java.util.ArrayList;
Adrien Béraud0c9bd8f2013-05-30 16:16:57 +10004import java.util.List;
Adrien Béraud04463092013-05-06 14:17:22 +10005
Adrien Béraud33268882013-05-18 03:41:15 +10006import android.graphics.PointF;
alisiondf1dac92013-06-27 17:35:53 -04007import android.util.Log;
Adrien Béraude0ef0c22013-05-18 01:56:27 +10008
Adrien Béraud04463092013-05-06 14:17:22 +10009public class BubbleModel
10{
Adrien Béraud25fc4092013-05-06 15:28:39 +100011 private static final String TAG = BubbleModel.class.getSimpleName();
12
Adrien Béraud0c9bd8f2013-05-30 16:16:57 +100013 private long lastUpdate = 0;
Adrien Béraud04463092013-05-06 14:17:22 +100014 public int width, height;
Adrien Béraud0c9bd8f2013-05-30 16:16:57 +100015 private ArrayList<Bubble> bubbles = new ArrayList<Bubble>();
16 private ArrayList<Attractor> attractors = new ArrayList<Attractor>();
Adrien Béraud25fc4092013-05-06 15:28:39 +100017
Adrien Béraud6bbce912013-05-24 00:48:13 +100018 private static final double BUBBLE_RETURN_TIME_HALF_LIFE = .3;
Adrien Béraud7ed23dc2013-05-06 16:27:24 +100019 private static final double BUBBLE_RETURN_TIME_LAMBDA = Math.log(2)/BUBBLE_RETURN_TIME_HALF_LIFE;
Adrien Béraud33268882013-05-18 03:41:15 +100020
Adrien Béraud6bbce912013-05-24 00:48:13 +100021 private static final double FRICTION_VISCOUS = Math.log(2)/.2f; // Viscous friction factor
Adrien Béraude0ef0c22013-05-18 01:56:27 +100022
Adrien Béraud6bbce912013-05-24 00:48:13 +100023 private static final float BUBBLE_MAX_SPEED = 2500.f; // px.s-1 : Max target speed in px/sec
24 private static final float ATTRACTOR_SMOOTH_DIST = 50.f; // px : Size of the "gravity hole" around the attractor
25 private static final float ATTRACTOR_STALL_DIST = 15.f; // px : Size of the "gravity hole" flat bottom
26 private static final float ATTRACTOR_DIST_SUCK = 20.f; // px
27
28 private static final float BORDER_REPULSION = 60000; // px.s^-2
29
30 private final float border_repulsion;
31 private final float bubble_max_speed;
32 private final float attractor_smooth_dist;
33 private final float attractor_stall_dist;
34 private final float attractor_dist_suck;
35
36 private float density = 1.f;
37
38 public BubbleModel(float screen_density) {
39 this.density = screen_density;
40 attractor_dist_suck = ATTRACTOR_DIST_SUCK*density;
41 bubble_max_speed = BUBBLE_MAX_SPEED*density;
42 attractor_smooth_dist = ATTRACTOR_SMOOTH_DIST*density;
43 attractor_stall_dist = ATTRACTOR_STALL_DIST*density;
44 border_repulsion = BORDER_REPULSION*density;
45 }
46
Adrien Béraud0c9bd8f2013-05-30 16:16:57 +100047 public void addBubble(Bubble b) {
48 b.setDensity(density);
49 bubbles.add(b);
50 }
51
52 public List<Bubble> getBubbles()
53 {
54 return bubbles;
55 }
56
57 public void addAttractor(Attractor a) {
58 a.setDensity(density);
59 attractors.add(a);
60 }
61
62 public List<Attractor> getAttractors()
63 {
64 return attractors;
65 }
66
67 public void clearAttractors() {
68 attractors.clear();
69 }
70
71 public void clear() {
72 clearAttractors();
73 bubbles.clear();
74 }
75
Adrien Béraud25fc4092013-05-06 15:28:39 +100076 public void update()
77 {
78 long now = System.nanoTime();
79
80 // Do nothing if lastUpdate is in the future.
81 if (lastUpdate > now)
82 return;
83
Adrien Béraude0ef0c22013-05-18 01:56:27 +100084 double ddt = Math.min((now - lastUpdate) / 1000000000.0, .2);
Adrien Béraud25fc4092013-05-06 15:28:39 +100085 lastUpdate = now;
86
Adrien Béraude0ef0c22013-05-18 01:56:27 +100087 float dt = (float)ddt;
Adrien Béraud25fc4092013-05-06 15:28:39 +100088 //Log.w(TAG, "update dt="+dt);
89
Adrien Béraud33268882013-05-18 03:41:15 +100090 int attr_n = attractors.size();
91
Adrien Béraud25fc4092013-05-06 15:28:39 +100092 // Iterators should not be used in frequently called methods
93 // to avoid garbage collection glitches caused by iterator objects.
Adrien Béraud0c9bd8f2013-05-30 16:16:57 +100094 for(int i=0, n=bubbles.size(); i<n; i++) {
95 Bubble b = bubbles.get(i);
Adrien Béraud25fc4092013-05-06 15:28:39 +100096 //Log.w(TAG, "update b");
Adrien Béraud33268882013-05-18 03:41:15 +100097
98 if(!b.dragged) {
Adrien Béraude0ef0c22013-05-18 01:56:27 +100099 float bx=b.getPosX(), by=b.getPosY();
100
Adrien Béraud33268882013-05-18 03:41:15 +1000101 Attractor attractor = null;
102 PointF attractor_pos = b.attractor;
103 float attractor_dist = (attractor_pos.x-bx)*(attractor_pos.x-bx) + (attractor_pos.y-by)*(attractor_pos.x-by);
104
Adrien Béraudc9c424d2013-05-30 17:47:35 +1000105 for(int j=0; j<attr_n; j++) {
alision907bde72013-06-20 14:40:37 -0400106 try{
Adrien Béraudc9c424d2013-05-30 17:47:35 +1000107 Attractor t = attractors.get(j);
alision907bde72013-06-20 14:40:37 -0400108
Adrien Béraud33268882013-05-18 03:41:15 +1000109 float dx = t.pos.x-bx, dy = t.pos.y-by;
110 float adist = dx*dx + dy*dy;
111 if(adist < attractor_dist) {
112 attractor = t;
113 attractor_pos = t.pos;
114 attractor_dist = adist;
115 }
alision907bde72013-06-20 14:40:37 -0400116 } catch (IndexOutOfBoundsException e){
117 // Try to update when layout was changing
118 }
Adrien Béraud33268882013-05-18 03:41:15 +1000119 }
120
Adrien Béraud6bbce912013-05-24 00:48:13 +1000121 //float friction_coef = 1.f-FRICTION_VISCOUS*dt;
122 double friction_coef = 1+Math.expm1(-FRICTION_VISCOUS*ddt);
123 b.speed.x *= friction_coef;
124 b.speed.y *= friction_coef;
125
126 //if(attractor != null) {
127 float target_speed;
128 float tdx = attractor_pos.x - bx, tdy = attractor_pos.y - by;
129 float dist = Math.max(1.f, (float) Math.sqrt(tdx*tdx + tdy*tdy));
130 if(dist > attractor_smooth_dist)
131 target_speed = bubble_max_speed;
132 else if(dist < attractor_stall_dist)
133 target_speed = 0;
134 else {
135 float a = (dist-attractor_stall_dist)/(attractor_smooth_dist-attractor_stall_dist);
136 target_speed = bubble_max_speed*a;
137 }
138 if(attractor != null) {
139 if(dist > attractor_smooth_dist)
140 b.target_scale = 1.f;
141 else if(dist < attractor_stall_dist)
142 b.target_scale = .2f;
143 else {
144 float a = (dist-attractor_stall_dist)/(attractor_smooth_dist-attractor_stall_dist);
145 b.target_scale = a*.8f+.2f;
146 }
Adrien Béraud6bbce912013-05-24 00:48:13 +1000147 }
148
149 // border repulsion
150 if(bx < 0 && b.speed.x < 0) {
151 b.speed.x += dt * border_repulsion;
152 } else if(bx > width && b.speed.x > 0) {
153 b.speed.x -= dt * border_repulsion;
154 }
155 if(by < 0 && b.speed.y < 0) {
156 b.speed.y += dt * border_repulsion;
157 } else if(by > height && b.speed.y > 0) {
158 b.speed.y -= dt * border_repulsion;
159 }
160
Adrien Béraud6bbce912013-05-24 00:48:13 +1000161 b.speed.x += dt * target_speed * tdx/dist;
162 b.speed.y += dt * target_speed * tdy/dist;
163
164 double edt = -Math.expm1(-BUBBLE_RETURN_TIME_LAMBDA*ddt);
165 double dx = (attractor_pos.x - bx) * edt + Math.min(bubble_max_speed, b.speed.x) * dt;
166 double dy = (attractor_pos.y - by) * edt + Math.min(bubble_max_speed, b.speed.y) * dt;
167 // Log.w(TAG, "update dx="+dt+" dy="+dy);
Adrien Béraud33268882013-05-18 03:41:15 +1000168 b.setPos((float)(bx+dx), (float)(by+dy));
169
Adrien Béraud6bbce912013-05-24 00:48:13 +1000170 if(attractor != null && attractor_dist < attractor_dist_suck*attractor_dist_suck) {
Adrien Béraudc9c424d2013-05-30 17:47:35 +1000171 b.dragged = false;
172 if(attractor.callback.onBubbleSucked(b)) {
173 bubbles.remove(b);
174 n--;
175 } else {
176 b.target_scale = 1.f;
177 }
Adrien Béraud33268882013-05-18 03:41:15 +1000178 }
Adrien Béraud25fc4092013-05-06 15:28:39 +1000179 }
Adrien Béraud33268882013-05-18 03:41:15 +1000180
Adrien Béraud6bbce912013-05-24 00:48:13 +1000181 b.setScale(b.getScale() + (b.target_scale-b.getScale())*dt*10.f);
182
Adrien Béraud25fc4092013-05-06 15:28:39 +1000183 }
184 }
Adrien Béraud0c9bd8f2013-05-30 16:16:57 +1000185
alisiondf1dac92013-06-27 17:35:53 -0400186 public Bubble getBubble(SipCall call) {
187 for(Bubble b : bubbles){
alisiondf1dac92013-06-27 17:35:53 -0400188 if(b.associated_call.getCallId().contentEquals(call.getCallId()))
189 return b;
190 }
191 return null;
192 }
193
194 public void removeBubble(SipCall sipCall) {
alisiondf1dac92013-06-27 17:35:53 -0400195 bubbles.remove(getBubble(sipCall));
196
197 }
198
Adrien Béraud0c9bd8f2013-05-30 16:16:57 +1000199
Adrien Béraud04463092013-05-06 14:17:22 +1000200}