blob: 97a3cd2b11a046ef1e35ab356a8a45e5ba5e3860 [file] [log] [blame]
Alexandre Lision064e1e02013-10-01 16:18:42 -04001package org.sflphone.model;
Adrien Béraud04463092013-05-06 14:17:22 +10002
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
Alexandre Lisiond5686032013-10-29 11:09:21 -04009public class BubbleModel {
10 private static final String TAG = BubbleModel.class.getSimpleName();
Adrien Béraud25fc4092013-05-06 15:28:39 +100011
Alexandre Lisiond5686032013-10-29 11:09:21 -040012 private long lastUpdate = 0;
13 public int width, height;
14 private ArrayList<Bubble> bubbles = new ArrayList<Bubble>();
15 private ArrayList<Attractor> attractors = new ArrayList<Attractor>();
Adrien Béraud25fc4092013-05-06 15:28:39 +100016
Alexandre Lisiond5686032013-10-29 11:09:21 -040017 private static final double BUBBLE_RETURN_TIME_HALF_LIFE = .3;
18 private static final double BUBBLE_RETURN_TIME_LAMBDA = Math.log(2) / BUBBLE_RETURN_TIME_HALF_LIFE;
Adrien Béraud33268882013-05-18 03:41:15 +100019
Alexandre Lisiond5686032013-10-29 11:09:21 -040020 private static final double FRICTION_VISCOUS = Math.log(2) / .2f; // Viscous friction factor
Adrien Béraude0ef0c22013-05-18 01:56:27 +100021
Alexandre Lisiond5686032013-10-29 11:09:21 -040022 private static final float BUBBLE_MAX_SPEED = 2500.f; // px.s-1 : Max target speed in px/sec
23 private static final float ATTRACTOR_SMOOTH_DIST = 50.f; // px : Size of the "gravity hole" around the attractor
24 private static final float ATTRACTOR_STALL_DIST = 15.f; // px : Size of the "gravity hole" flat bottom
25 private static final float ATTRACTOR_DIST_SUCK = 20.f; // px
Adrien Béraud6bbce912013-05-24 00:48:13 +100026
Alexandre Lisiond5686032013-10-29 11:09:21 -040027 private static final float BORDER_REPULSION = 60000; // px.s^-2
Adrien Béraud6bbce912013-05-24 00:48:13 +100028
Alexandre Lisiond5686032013-10-29 11:09:21 -040029 private final float border_repulsion;
30 private final float bubble_max_speed;
31 private final float attractor_smooth_dist;
32 private final float attractor_stall_dist;
33 private final float attractor_dist_suck;
Adrien Béraud6bbce912013-05-24 00:48:13 +100034
Alexandre Lisiond5686032013-10-29 11:09:21 -040035 private float density = 1.f;
Adrien Béraud6bbce912013-05-24 00:48:13 +100036
Alexandre Lisiond5686032013-10-29 11:09:21 -040037 public BubbleModel(float screen_density) {
38 Log.d(TAG, "Creating BubbleModel");
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 }
Adrien Béraud6bbce912013-05-24 00:48:13 +100046
Alexandre Lisiond5686032013-10-29 11:09:21 -040047 public void addBubble(Bubble b) {
48 b.setDensity(density);
49 bubbles.add(b);
50 }
Adrien Béraud0c9bd8f2013-05-30 16:16:57 +100051
Alexandre Lisiond5686032013-10-29 11:09:21 -040052 public List<Bubble> getBubbles() {
53 return bubbles;
54 }
Adrien Béraud0c9bd8f2013-05-30 16:16:57 +100055
Alexandre Lisiond5686032013-10-29 11:09:21 -040056 public void addAttractor(Attractor a) {
57 a.setDensity(density);
58 attractors.add(a);
59 }
Adrien Béraud0c9bd8f2013-05-30 16:16:57 +100060
Alexandre Lisiond5686032013-10-29 11:09:21 -040061 public List<Attractor> getAttractors() {
62 return attractors;
63 }
Adrien Béraud0c9bd8f2013-05-30 16:16:57 +100064
Alexandre Lisiond5686032013-10-29 11:09:21 -040065 public void clearAttractors() {
66 attractors.clear();
67 }
Adrien Béraud0c9bd8f2013-05-30 16:16:57 +100068
Alexandre Lisiond5686032013-10-29 11:09:21 -040069 public void clear() {
70 clearAttractors();
71 bubbles.clear();
72 }
Adrien Béraud0c9bd8f2013-05-30 16:16:57 +100073
Alexandre Lisiond5686032013-10-29 11:09:21 -040074 public void update() {
75 long now = System.nanoTime();
Adrien Béraud25fc4092013-05-06 15:28:39 +100076
Alexandre Lisiond5686032013-10-29 11:09:21 -040077 // Do nothing if lastUpdate is in the future.
78 if (lastUpdate > now)
79 return;
Adrien Béraud25fc4092013-05-06 15:28:39 +100080
Alexandre Lisiond5686032013-10-29 11:09:21 -040081 double ddt = Math.min((now - lastUpdate) / 1000000000.0, .2);
82 lastUpdate = now;
Adrien Béraud25fc4092013-05-06 15:28:39 +100083
Alexandre Lisiond5686032013-10-29 11:09:21 -040084 float dt = (float) ddt;
85 // Log.w(TAG, "update dt="+dt);
Adrien Béraud25fc4092013-05-06 15:28:39 +100086
Alexandre Lisiond5686032013-10-29 11:09:21 -040087 int attr_n = attractors.size();
Adrien Béraud33268882013-05-18 03:41:15 +100088
Alexandre Lisiond5686032013-10-29 11:09:21 -040089 // Iterators should not be used in frequently called methods
90 // to avoid garbage collection glitches caused by iterator objects.
91 for (int i = 0, n = bubbles.size(); i < n; i++) {
Alexandre Lision4e7b7832013-10-29 15:55:06 -040092
93 if(i > bubbles.size()){ // prevent updating a bubble already removed
94 return;
95 }
Alexandre Lisiond5686032013-10-29 11:09:21 -040096 Bubble b = bubbles.get(i);
Adrien Béraud33268882013-05-18 03:41:15 +100097
Alexandre Lision4e7b7832013-10-29 15:55:06 -040098
Alexandre Lisiond5686032013-10-29 11:09:21 -040099 if (b.markedToDie) {
100 continue;
101 }
Adrien Béraude0ef0c22013-05-18 01:56:27 +1000102
Alexandre Lisiond5686032013-10-29 11:09:21 -0400103 if (!b.dragged) {
Adrien Béraud33268882013-05-18 03:41:15 +1000104
Alexandre Lisiond5686032013-10-29 11:09:21 -0400105 float bx = b.getPosX(), by = b.getPosY();
106
107 Attractor attractor = null;
108 PointF attractor_pos = b.attractor;
109 float attractor_dist = (attractor_pos.x - bx) * (attractor_pos.x - bx) + (attractor_pos.y - by) * (attractor_pos.x - by);
110
111 for (int j = 0; j < attr_n; j++) {
112 try {
113 Attractor t = attractors.get(j);
114
115 float dx = t.pos.x - bx, dy = t.pos.y - by;
116 float adist = dx * dx + dy * dy;
117 if (adist < attractor_dist) {
118 attractor = t;
119 attractor_pos = t.pos;
120 attractor_dist = adist;
121 }
122 } catch (IndexOutOfBoundsException e) {
alision907bde72013-06-20 14:40:37 -0400123 // Try to update when layout was changing
124 }
Alexandre Lisiond5686032013-10-29 11:09:21 -0400125 }
Adrien Béraud33268882013-05-18 03:41:15 +1000126
Alexandre Lisiond5686032013-10-29 11:09:21 -0400127 // float friction_coef = 1.f-FRICTION_VISCOUS*dt;
128 double friction_coef = 1 + Math.expm1(-FRICTION_VISCOUS * ddt);
129 b.speed.x *= friction_coef;
130 b.speed.y *= friction_coef;
Adrien Béraud6bbce912013-05-24 00:48:13 +1000131
Alexandre Lisiond5686032013-10-29 11:09:21 -0400132 // if(attractor != null) {
133 float target_speed;
134 float tdx = attractor_pos.x - bx, tdy = attractor_pos.y - by;
135 float dist = Math.max(1.f, (float) Math.sqrt(tdx * tdx + tdy * tdy));
136 if (dist > attractor_smooth_dist)
137 target_speed = bubble_max_speed;
138 else if (dist < attractor_stall_dist)
139 target_speed = 0;
140 else {
141 float a = (dist - attractor_stall_dist) / (attractor_smooth_dist - attractor_stall_dist);
142 target_speed = bubble_max_speed * a;
143 }
144 if (attractor != null) {
145 if (dist > attractor_smooth_dist)
146 b.target_scale = 1.f;
147 else if (dist < attractor_stall_dist)
148 b.target_scale = .2f;
149 else {
150 float a = (dist - attractor_stall_dist) / (attractor_smooth_dist - attractor_stall_dist);
151 b.target_scale = a * .8f + .2f;
152 }
153 }
Adrien Béraud6bbce912013-05-24 00:48:13 +1000154
Alexandre Lisiond5686032013-10-29 11:09:21 -0400155 // border repulsion
156 if (bx < 0 && b.speed.x < 0) {
157 b.speed.x += dt * border_repulsion;
158 } else if (bx > width && b.speed.x > 0) {
159 b.speed.x -= dt * border_repulsion;
160 }
161 if (by < 0 && b.speed.y < 0) {
162 b.speed.y += dt * border_repulsion;
163 } else if (by > height && b.speed.y > 0) {
164 b.speed.y -= dt * border_repulsion;
165 }
Adrien Béraud6bbce912013-05-24 00:48:13 +1000166
Alexandre Lisiond5686032013-10-29 11:09:21 -0400167 b.speed.x += dt * target_speed * tdx / dist;
168 b.speed.y += dt * target_speed * tdy / dist;
Adrien Béraud6bbce912013-05-24 00:48:13 +1000169
Alexandre Lisiond5686032013-10-29 11:09:21 -0400170 double edt = -Math.expm1(-BUBBLE_RETURN_TIME_LAMBDA * ddt);
171 double dx = (attractor_pos.x - bx) * edt + Math.min(bubble_max_speed, b.speed.x) * dt;
172 double dy = (attractor_pos.y - by) * edt + Math.min(bubble_max_speed, b.speed.y) * dt;
173 // Log.w(TAG, "update dx="+dt+" dy="+dy);
174 b.setPos((float) (bx + dx), (float) (by + dy));
Adrien Béraud33268882013-05-18 03:41:15 +1000175
Alexandre Lisiond5686032013-10-29 11:09:21 -0400176 // Log.i(TAG,"Model:");
177 if (attractor != null && attractor_dist < attractor_dist_suck * attractor_dist_suck) {
178 b.dragged = false;
179 if (attractor.callback.onBubbleSucked(b)) {
180 bubbles.remove(b);
181 n--;
182 } else {
183 b.target_scale = 1.f;
184 }
185 }
186 }
Adrien Béraud33268882013-05-18 03:41:15 +1000187
Alexandre Lisiond5686032013-10-29 11:09:21 -0400188 b.setScale(b.getScale() + (b.target_scale - b.getScale()) * dt * 10.f);
Adrien Béraud6bbce912013-05-24 00:48:13 +1000189
Alexandre Lisiond5686032013-10-29 11:09:21 -0400190 }
191 }
Adrien Béraud0c9bd8f2013-05-30 16:16:57 +1000192
Alexandre Lisionee2494d2013-10-09 17:14:00 -0400193 public Bubble getBubble(String call) {
Alexandre Lisiond5686032013-10-29 11:09:21 -0400194 for (Bubble b : bubbles) {
195 if (!b.isUser && b.callIDEquals(call))
alisiondf1dac92013-06-27 17:35:53 -0400196 return b;
197 }
198 return null;
199 }
200
201 public void removeBubble(SipCall sipCall) {
Alexandre Lisionee2494d2013-10-09 17:14:00 -0400202 bubbles.remove(getBubble(sipCall.getCallId()));
Alexandre Lisiond5686032013-10-29 11:09:21 -0400203
alisiondf1dac92013-06-27 17:35:53 -0400204 }
205
Alexandre Lisiond5686032013-10-29 11:09:21 -0400206 public Bubble getUser() {
207 for (Bubble b : bubbles) {
208 if (b.isUser)
209 return b;
210 }
211 return null;
212 }
Adrien Béraud0c9bd8f2013-05-30 16:16:57 +1000213
Adrien Béraud04463092013-05-06 14:17:22 +1000214}