blob: ee5cb300c7f3838ef9aaa9c0b03c72595557b8f8 [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
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) {
Alexandre Lision6e8931e2013-09-19 16:49:34 -040039 Log.d(TAG, "Creating BubbleModel");
Adrien Béraud6bbce912013-05-24 00:48:13 +100040 this.density = screen_density;
41 attractor_dist_suck = ATTRACTOR_DIST_SUCK*density;
42 bubble_max_speed = BUBBLE_MAX_SPEED*density;
43 attractor_smooth_dist = ATTRACTOR_SMOOTH_DIST*density;
44 attractor_stall_dist = ATTRACTOR_STALL_DIST*density;
45 border_repulsion = BORDER_REPULSION*density;
46 }
47
Adrien Béraud0c9bd8f2013-05-30 16:16:57 +100048 public void addBubble(Bubble b) {
49 b.setDensity(density);
50 bubbles.add(b);
51 }
52
53 public List<Bubble> getBubbles()
54 {
55 return bubbles;
56 }
57
58 public void addAttractor(Attractor a) {
59 a.setDensity(density);
60 attractors.add(a);
61 }
62
63 public List<Attractor> getAttractors()
64 {
65 return attractors;
66 }
67
68 public void clearAttractors() {
69 attractors.clear();
70 }
71
72 public void clear() {
73 clearAttractors();
74 bubbles.clear();
75 }
76
Adrien Béraud25fc4092013-05-06 15:28:39 +100077 public void update()
78 {
79 long now = System.nanoTime();
80
81 // Do nothing if lastUpdate is in the future.
82 if (lastUpdate > now)
83 return;
84
Adrien Béraude0ef0c22013-05-18 01:56:27 +100085 double ddt = Math.min((now - lastUpdate) / 1000000000.0, .2);
Adrien Béraud25fc4092013-05-06 15:28:39 +100086 lastUpdate = now;
87
Adrien Béraude0ef0c22013-05-18 01:56:27 +100088 float dt = (float)ddt;
Adrien Béraud25fc4092013-05-06 15:28:39 +100089 //Log.w(TAG, "update dt="+dt);
90
Adrien Béraud33268882013-05-18 03:41:15 +100091 int attr_n = attractors.size();
92
Adrien Béraud25fc4092013-05-06 15:28:39 +100093 // Iterators should not be used in frequently called methods
94 // to avoid garbage collection glitches caused by iterator objects.
Adrien Béraud0c9bd8f2013-05-30 16:16:57 +100095 for(int i=0, n=bubbles.size(); i<n; i++) {
96 Bubble b = bubbles.get(i);
Alexandre Lision0edf18c2013-09-23 17:35:50 -040097
Alexandre Lision23628c12013-09-24 11:17:05 -040098 if (b.markedToDie){
Alexandre Lision0edf18c2013-09-23 17:35:50 -040099 continue;
100 }
Adrien Béraud33268882013-05-18 03:41:15 +1000101
102 if(!b.dragged) {
Alexandre Lision23628c12013-09-24 11:17:05 -0400103
Adrien Béraude0ef0c22013-05-18 01:56:27 +1000104 float bx=b.getPosX(), by=b.getPosY();
105
Adrien Béraud33268882013-05-18 03:41:15 +1000106 Attractor attractor = null;
107 PointF attractor_pos = b.attractor;
108 float attractor_dist = (attractor_pos.x-bx)*(attractor_pos.x-bx) + (attractor_pos.y-by)*(attractor_pos.x-by);
109
Adrien Béraudc9c424d2013-05-30 17:47:35 +1000110 for(int j=0; j<attr_n; j++) {
alision907bde72013-06-20 14:40:37 -0400111 try{
Adrien Béraudc9c424d2013-05-30 17:47:35 +1000112 Attractor t = attractors.get(j);
alision907bde72013-06-20 14:40:37 -0400113
Adrien Béraud33268882013-05-18 03:41:15 +1000114 float dx = t.pos.x-bx, dy = t.pos.y-by;
115 float adist = dx*dx + dy*dy;
116 if(adist < attractor_dist) {
117 attractor = t;
118 attractor_pos = t.pos;
119 attractor_dist = adist;
120 }
alision907bde72013-06-20 14:40:37 -0400121 } catch (IndexOutOfBoundsException e){
122 // Try to update when layout was changing
123 }
Adrien Béraud33268882013-05-18 03:41:15 +1000124 }
125
Adrien Béraud6bbce912013-05-24 00:48:13 +1000126 //float friction_coef = 1.f-FRICTION_VISCOUS*dt;
127 double friction_coef = 1+Math.expm1(-FRICTION_VISCOUS*ddt);
128 b.speed.x *= friction_coef;
129 b.speed.y *= friction_coef;
130
131 //if(attractor != null) {
132 float target_speed;
133 float tdx = attractor_pos.x - bx, tdy = attractor_pos.y - by;
134 float dist = Math.max(1.f, (float) Math.sqrt(tdx*tdx + tdy*tdy));
135 if(dist > attractor_smooth_dist)
136 target_speed = bubble_max_speed;
137 else if(dist < attractor_stall_dist)
138 target_speed = 0;
139 else {
140 float a = (dist-attractor_stall_dist)/(attractor_smooth_dist-attractor_stall_dist);
141 target_speed = bubble_max_speed*a;
142 }
143 if(attractor != null) {
144 if(dist > attractor_smooth_dist)
145 b.target_scale = 1.f;
146 else if(dist < attractor_stall_dist)
147 b.target_scale = .2f;
148 else {
149 float a = (dist-attractor_stall_dist)/(attractor_smooth_dist-attractor_stall_dist);
150 b.target_scale = a*.8f+.2f;
151 }
Adrien Béraud6bbce912013-05-24 00:48:13 +1000152 }
153
154 // border repulsion
155 if(bx < 0 && b.speed.x < 0) {
156 b.speed.x += dt * border_repulsion;
157 } else if(bx > width && b.speed.x > 0) {
158 b.speed.x -= dt * border_repulsion;
159 }
160 if(by < 0 && b.speed.y < 0) {
161 b.speed.y += dt * border_repulsion;
162 } else if(by > height && b.speed.y > 0) {
163 b.speed.y -= dt * border_repulsion;
164 }
165
Adrien Béraud6bbce912013-05-24 00:48:13 +1000166 b.speed.x += dt * target_speed * tdx/dist;
167 b.speed.y += dt * target_speed * tdy/dist;
168
169 double edt = -Math.expm1(-BUBBLE_RETURN_TIME_LAMBDA*ddt);
170 double dx = (attractor_pos.x - bx) * edt + Math.min(bubble_max_speed, b.speed.x) * dt;
171 double dy = (attractor_pos.y - by) * edt + Math.min(bubble_max_speed, b.speed.y) * dt;
172 // Log.w(TAG, "update dx="+dt+" dy="+dy);
Adrien Béraud33268882013-05-18 03:41:15 +1000173 b.setPos((float)(bx+dx), (float)(by+dy));
174
Alexandre Lision23628c12013-09-24 11:17:05 -0400175// Log.i(TAG,"Model:");
Adrien Béraud6bbce912013-05-24 00:48:13 +1000176 if(attractor != null && attractor_dist < attractor_dist_suck*attractor_dist_suck) {
Adrien Béraudc9c424d2013-05-30 17:47:35 +1000177 b.dragged = false;
178 if(attractor.callback.onBubbleSucked(b)) {
179 bubbles.remove(b);
180 n--;
181 } else {
182 b.target_scale = 1.f;
183 }
Adrien Béraud33268882013-05-18 03:41:15 +1000184 }
Adrien Béraud25fc4092013-05-06 15:28:39 +1000185 }
Adrien Béraud33268882013-05-18 03:41:15 +1000186
Adrien Béraud6bbce912013-05-24 00:48:13 +1000187 b.setScale(b.getScale() + (b.target_scale-b.getScale())*dt*10.f);
188
Adrien Béraud25fc4092013-05-06 15:28:39 +1000189 }
190 }
Adrien Béraud0c9bd8f2013-05-30 16:16:57 +1000191
Alexandre Lisionee2494d2013-10-09 17:14:00 -0400192 public Bubble getBubble(String call) {
alisiondf1dac92013-06-27 17:35:53 -0400193 for(Bubble b : bubbles){
Alexandre Lision68855472013-10-10 16:20:46 -0400194 if(b.callIDEquals(call))
alisiondf1dac92013-06-27 17:35:53 -0400195 return b;
196 }
197 return null;
198 }
199
200 public void removeBubble(SipCall sipCall) {
Alexandre Lisionee2494d2013-10-09 17:14:00 -0400201 bubbles.remove(getBubble(sipCall.getCallId()));
alisiondf1dac92013-06-27 17:35:53 -0400202
203 }
204
Adrien Béraud0c9bd8f2013-05-30 16:16:57 +1000205
Adrien Béraud04463092013-05-06 14:17:22 +1000206}