1 package com.github.celldynamics.quimp.plugin.ecmm;
2
3 import com.github.celldynamics.quimp.Vert;
4 import com.github.celldynamics.quimp.geom.ExtendedVector2d;
5 import com.github.celldynamics.quimp.utils.QuimpToolsCollection;
6
7 import ij.IJ;
8 import ij.process.ImageProcessor;
9
10
11
12
13
14
15
16 public class ODEsolver {
17
18 private static boolean inside;
19
20
21
22
23 public ODEsolver() {
24 }
25
26
27
28
29
30
31
32
33 public static ExtendedVector2d euler(Vert v, Sector s) {
34
35 int x;
36 int y;
37 int lastSampleX = -1;
38 int lastSampleY = -1;
39 double dist = 0;
40 double tempFlu;
41 Vert edge;
42 ExtendedVector2d p;
43 ExtendedVector2d pp;
44
45 v.snapped = false;
46
47 if (ECMp.ANA) {
48 p = v.getPoint();
49 x = (int) Math.round(p.getX());
50 y = (int) Math.round(p.getY());
51 lastSampleX = x;
52 lastSampleY = y;
53 tempFlu = ODEsolver.sampleFluo(ECMp.image, x, y);
54 v.fluores[0].intensity = tempFlu;
55 v.fluores[0].x = x;
56 v.fluores[0].y = y;
57 }
58
59 if (ECMp.plot) {
60 ECMM_Mapping.plot.setColor(0, 0, 0);
61 }
62
63 p = new ExtendedVector2d(v.getX(), v.getY());
64 pp = new ExtendedVector2d(v.getX(), v.getY());
65
66
67
68 boolean maxHit = false;
69 int i = 1;
70 ExtendedVector2d k;
71
72 for (; i < ECMp.maxIter - 1; i++) {
73
74 if (ODEsolver.proximity(p, s) || (ECMp.ANA && dist >= (ECMp.anaMigDist)) || maxHit) {
75
76
77 pp.setX(p.getX());
78 pp.setY(p.getY());
79
80
81
82 edge = ODEsolver.snap(p, s);
83 dist += ExtendedVector2d.lengthP2P(pp, p);
84 v.distance = QuimpToolsCollection.speedToScale(dist, ECMp.scale, ECMp.frameInterval);
85
86 v.setLandingCoord(p, edge);
87
88
89
90 if (ECMp.plot && ECMp.drawPaths) {
91 ECMM_Mapping.plot.setColor(0, 0, 0);
92 ECMM_Mapping.plot.drawLine(pp, p);
93 }
94
95 v.snapped = true;
96
97 break;
98 }
99
100 k = ODEsolver.dydt(p, s);
101 k.multiply(ECMp.h);
102
103 pp.setX(p.getX());
104 pp.setY(p.getY());
105 p.setX(p.getX() + k.getX());
106 p.setY(p.getY() + k.getY());
107 dist += ExtendedVector2d.lengthP2P(pp, p);
108
109 if (ECMp.plot && ECMp.drawPaths) {
110
111 ECMM_Mapping.plot.drawLine(pp, p);
112 }
113
114
115 if (ECMp.ANA) {
116 x = (int) Math.round(p.getX());
117 y = (int) Math.round(p.getY());
118 if (!(x == lastSampleX && y == lastSampleY)) {
119 lastSampleX = x;
120 lastSampleY = y;
121 tempFlu = ODEsolver.sampleFluo(ECMp.image, x, y);
122
123 if (tempFlu > v.fluores[0].intensity) {
124
125
126
127 v.fluores[0].intensity = tempFlu;
128 v.fluores[0].x = x;
129 v.fluores[0].y = y;
130
131 }
132 }
133 }
134
135 ECMp.its++;
136 }
137
138 if (ECMp.plot && !v.snapped && ECMp.drawFails) {
139 ECMM_Mapping.plot.setColor(1, 0, 0);
140
141
142 ECMM_Mapping.plot.drawCircle(v.getPoint(), 5);
143 }
144
145 return p;
146 }
147
148
149
150
151
152
153
154
155 public static ExtendedVector2d/../../../../com/github/celldynamics/quimp/geom/ExtendedVector2d.html#ExtendedVector2d">ExtendedVector2d dydt(ExtendedVector2d p, Sector s) {
156 ExtendedVector2d result = fieldAt(p, s);
157 result.multiply(ECMp.mobileQ);
158
159 if (true) {
160
161
162 result.makeUnit();
163 result.multiply(ECMp.maxVertF);
164 }
165 return result;
166 }
167
168
169
170
171
172
173
174
175 public static boolean proximity(ExtendedVector2d p, Sector s) {
176
177
178
179
180
181 Vert v = s.getTarStart();
182 do {
183 double d = ExtendedVector2d.distPointToSegment(p, v.getPoint(), v.getNext().getPoint());
184
185 if (d <= ECMp.d) {
186 return true;
187 }
188 v = v.getNext();
189 } while (!v.isIntPoint());
190 return false;
191 }
192
193 private static Vert snap(ExtendedVector2d p, Sector s) {
194
195 ExtendedVector2d current;
196 Vert closestEdge;
197 double distance;
198 double tempDis;
199
200 Vert v = s.getTarStart().getPrev();
201 distance = ExtendedVector2d.distPointToSegment(p, v.getPoint(), v.getNext().getPoint());
202 v = v.getNext();
203 closestEdge = v;
204 do {
205 current = ExtendedVector2d.pointToSegment(p, v.getPoint(), v.getNext().getPoint());
206 tempDis = ExtendedVector2d.lengthP2P(p, current);
207
208 if (tempDis < distance) {
209 closestEdge = v;
210 distance = tempDis;
211 }
212 v = v.getNext();
213 } while (!v.isIntPoint());
214
215
216
217
218 return closestEdge;
219 }
220
221 private static ExtendedVector2d/../../../com/github/celldynamics/quimp/geom/ExtendedVector2d.html#ExtendedVector2d">ExtendedVector2d fieldAt(ExtendedVector2d p, Sector s) {
222
223
224
225 if (ECMp.lineCharges) {
226 return fieldAtLines(p, s);
227 } else {
228 return fieldAtPoints(p, s);
229 }
230 }
231
232 private static ExtendedVector2d/../com/github/celldynamics/quimp/geom/ExtendedVector2d.html#ExtendedVector2d">ExtendedVector2d fieldAtPoints(ExtendedVector2d p, Sector s) {
233
234 ExtendedVector2deom/ExtendedVector2d.html#ExtendedVector2d">ExtendedVector2d field = new ExtendedVector2d(0, 0);
235 ExtendedVector2dom/ExtendedVector2d.html#ExtendedVector2d">ExtendedVector2d totalF = new ExtendedVector2d(0, 0);
236
237 Vert v = s.migCharges.getHead();
238 do {
239
240 forceP(field, p, v.getPoint(), ECMp.migQ, ECMp.migPower);
241 totalF.addVec(field);
242
243 v = v.getNext();
244 } while (!v.getPrev().isIntPoint() || v.getPrev().isHead());
245
246 v = s.tarCharges.getHead();
247 do {
248 forceP(field, p, v.getPoint(), ECMp.tarQ, ECMp.tarPower);
249 totalF.addVec(field);
250 v = v.getNext();
251 } while (!v.getPrev().isIntPoint() || v.getPrev().isHead());
252
253 return totalF;
254 }
255
256 private static void forceP(ExtendedVector2d../../../../../com/github/celldynamics/quimp/geom/ExtendedVector2d.html#ExtendedVector2d">ExtendedVector2d./../../../com/github/celldynamics/quimp/geom/ExtendedVector2d.html#ExtendedVector2d">ExtendedVector2d force, ExtendedVector2d../../../../../com/github/celldynamics/quimp/geom/ExtendedVector2d.html#ExtendedVector2d">ExtendedVector2d p, ExtendedVector2d pq,
257 double q, double power) {
258 double r = ExtendedVector2d.lengthP2P(pq, p);
259
260 if (r == 0) {
261 force.setX(250);
262 force.setY(250);
263 IJ.log("!WARNING-FORCE INFINITE");
264 return;
265 }
266 r = Math.abs(Math.pow(r, power));
267 ExtendedVector2d unitV = ExtendedVector2d.unitVector(pq, p);
268 double multiplier = (ECMp.k * (q / r));
269 force.setX(unitV.getX() * multiplier);
270 force.setY(unitV.getY() * multiplier);
271 }
272
273 private static ExtendedVector2d./../com/github/celldynamics/quimp/geom/ExtendedVector2d.html#ExtendedVector2d">ExtendedVector2d fieldAtLines(ExtendedVector2d p, Sector s) {
274
275 ExtendedVector2deom/ExtendedVector2d.html#ExtendedVector2d">ExtendedVector2d field = new ExtendedVector2d(0, 0);
276 ExtendedVector2dom/ExtendedVector2d.html#ExtendedVector2d">ExtendedVector2d totalF = new ExtendedVector2d(0, 0);
277 double polarDir;
278
279
280 inside = s.insideCharges(p);
281
282 if (!inside) {
283 polarDir = -1;
284
285 } else {
286 polarDir = 1;
287 }
288
289 Vert v = s.migCharges.getHead();
290 do {
291
292
293
294
295
296
297
298
299
300
301
302 forceLpolar(field, p, v.getPoint(), v.getNext().getPoint(), ECMp.migQ, ECMp.migPower,
303 polarDir);
304
305 totalF.addVec(field);
306 v = v.getNext();
307 } while (!v.isIntPoint() || v.isHead());
308
309 v = s.tarCharges.getHead();
310 do {
311
312
313
314
315
316
317
318
319
320
321 forceLpolar(field, p, v.getPoint(), v.getNext().getPoint(), ECMp.tarQ, ECMp.tarPower,
322 polarDir);
323
324 totalF.addVec(field);
325 v = v.getNext();
326 } while (!v.isIntPoint() || v.isHead());
327
328 return totalF;
329 }
330
331 private static void forceLpolar(ExtendedVector2d../../../../../com/github/celldynamics/quimp/geom/ExtendedVector2d.html#ExtendedVector2d">ExtendedVector2d./../../../com/github/celldynamics/quimp/geom/ExtendedVector2d.html#ExtendedVector2d">ExtendedVector2d force, ExtendedVector2d../../../../../com/github/celldynamics/quimp/geom/ExtendedVector2d.html#ExtendedVector2d">ExtendedVector2d p, ExtendedVector2d s1,
332 ExtendedVector2d s2, double q, double power, double orientation) {
333 double l = ExtendedVector2d.lengthP2P(s1, s2);
334 ExtendedVector2d ru = ExtendedVector2d.unitVector(s2, p);
335 double r = ExtendedVector2d.lengthP2P(s2, p);
336 ExtendedVector2d rpU = ExtendedVector2d.unitVector(s1, p);
337 double rp = ExtendedVector2d.lengthP2P(s1, p);
338
339 double d = (((rp + r) * (rp + r)) - (l * l)) / (2 * l);
340
341 double multiplier = ((ECMp.k * q) / d);
342 rpU.addVec(ru);
343
344 force.setX(rpU.getX() * multiplier * orientation);
345 force.setY(rpU.getY() * multiplier * orientation);
346 }
347
348
349
350
351
352
353
354
355
356 public static double sampleFluo(ImageProcessor ip, int x, int y) {
357 double tempFlu = ip.getPixelValue(x, y) + ip.getPixelValue(x - 1, y)
358 + ip.getPixelValue(x + 1, y) + ip.getPixelValue(x, y - 1) + ip.getPixelValue(x, y + 1)
359 + ip.getPixelValue(x - 1, y - 1) + ip.getPixelValue(x + 1, y + 1)
360 + ip.getPixelValue(x + 1, y - 1) + ip.getPixelValue(x - 1, y + 1);
361 tempFlu = tempFlu / 9d;
362 return tempFlu;
363 }
364 }