1 package com.github.celldynamics.quimp;
2
3 import java.io.BufferedReader;
4 import java.io.File;
5 import java.io.FileReader;
6 import java.io.FileWriter;
7 import java.io.IOException;
8 import java.io.PrintWriter;
9 import java.security.InvalidParameterException;
10
11 import org.slf4j.Logger;
12 import org.slf4j.LoggerFactory;
13
14 import com.github.celldynamics.quimp.filesystem.FileExtensions;
15 import com.github.celldynamics.quimp.filesystem.IQuimpSerialize;
16 import com.github.celldynamics.quimp.geom.ExtendedVector2d;
17 import com.github.celldynamics.quimp.utils.QuimpToolsCollection;
18
19 import ij.IJ;
20
21
22
23
24
25
26
27 public class OutlineHandler extends ShapeHandler<Outline> implements IQuimpSerialize {
28
29
30
31
32 static final Logger LOGGER = LoggerFactory.getLogger(OutlineHandler.class.getName());
33
34
35
36 private Outline[] outlines;
37 private transient QParams qp;
38
39 private transient int size;
40
41
42
43
44 public transient ExtendedVector2d maxCoor;
45
46
47
48
49 public transient ExtendedVector2d minCoor;
50
51
52
53
54
55 public transient double[] migLimits;
56
57
58
59
60 public transient double[][] fluLims;
61
62
63
64
65 public transient double[] curvLimits;
66
67
68
69 public transient double maxLength = 0;
70
71
72
73
74 public transient boolean readSuccess;
75
76
77
78
79
80
81 public OutlineHandler(QParams params) {
82 qp = params;
83 startFrame = qp.getStartFrame();
84 endFrame = qp.getEndFrame();
85
86
87
88
89 if (!readOutlines(qp.getSnakeQP())) {
90 IJ.error("Failed to read in snakQP (OutlineHandler:36)");
91 readSuccess = false;
92 size = 0;
93 } else {
94 size = outlines.length;
95 readSuccess = true;
96 }
97 }
98
99
100
101
102
103
104 public OutlineHandler/OutlineHandler.html#OutlineHandler">OutlineHandler(final OutlineHandler src) {
105 super(src);
106 this.outlines = new Outline[src.outlines.length];
107 for (int o = 0; o < this.outlines.length; o++) {
108 this.outlines[o] = new Outline(src.outlines[o]);
109 }
110 size = src.size;
111
112
113
114
115
116
117
118
119
120 for (Outline o : outlines) {
121 if (o.getLength() > maxLength) {
122 maxLength = o.getLength();
123 }
124 }
125 findStatLimits();
126 }
127
128
129
130
131
132
133
134
135 public OutlineHandler(final SnakeHandler snake) {
136 this(snake.startFrame, snake.endFrame);
137 for (int f = startFrame; f <= endFrame; f++) {
138 Snake s = snake.getStoredSnake(f);
139 if (s != null) {
140 setOutline(f, new Outline(s));
141 }
142 }
143 findStatLimits();
144 }
145
146
147
148
149
150
151
152 public OutlineHandler(int s, int e) {
153 size = e - s + 1;
154 outlines = new Outline[size];
155 startFrame = s;
156 endFrame = e;
157 }
158
159
160
161
162 public OutlineHandler() {
163 this(0, 0);
164 }
165
166
167
168
169
170
171 @Override
172 public int getStartFrame() {
173 return startFrame;
174 }
175
176
177
178
179
180
181 @Override
182 public int getEndFrame() {
183 return endFrame;
184 }
185
186
187
188
189
190
191
192 public Outline getStoredOutline(int f) {
193 if (f - startFrame < 0 || f - startFrame > outlines.length) {
194 LOGGER.info("Tried to access negative frame store: frame: " + f);
195 return null;
196 }
197 return outlines[f - startFrame];
198 }
199
200
201
202
203
204
205
206 public boolean isOutlineAt(int f) {
207 if (f - startFrame < 0) {
208 return false;
209 } else if (f - startFrame >= outlines.length) {
210 return false;
211 } else if (outlines[f - startFrame] == null) {
212 return false;
213 } else {
214 return true;
215 }
216 }
217
218
219
220
221
222
223
224 public Outline indexGetOutline(int i) {
225 return outlines[i];
226 }
227
228
229
230
231
232
233
234 public void setOutline(int f, Outline o) {
235 outlines[f - startFrame] = o;
236 double length = o.getLength();
237 if (length > maxLength) {
238 maxLength = length;
239 }
240
241 }
242
243 private boolean readOutlines(final File f) {
244 if (!f.exists()) {
245 IJ.error("Cannot locate snake file (" + FileExtensions.snakeFileExt + ")\n'"
246 + f.getAbsolutePath() + "'");
247 return false;
248 }
249 if (qp == null) {
250 throw new InvalidParameterException(
251 "QParams is null. This object has not been created (loaded) from QParams data");
252 }
253
254 String thisLine;
255
256 maxLength = 0;
257
258 int nn;
259 int index;
260 double length;
261 Vert head;
262 Vert n;
263 Vert prevn;
264 size = 0;
265
266 try {
267
268 BufferedReader br = new BufferedReader(new FileReader(f));
269 while ((thisLine = br.readLine()) != null) {
270 if (thisLine.startsWith("#")) {
271 continue;
272 }
273 nn = (int) QuimpToolsCollection.s2d(thisLine);
274 for (int i = 0; i < nn; i++) {
275
276 br.readLine();
277
278 }
279 size++;
280 }
281 br.close();
282
283 outlines = new Outline[size];
284
285 int s = 0;
286
287 br = new BufferedReader(new FileReader(f));
288
289 while ((thisLine = br.readLine()) != null) {
290
291 if (thisLine.startsWith("#")) {
292 continue;
293 }
294
295 index = 0;
296 head = new Vert(index);
297 head.setHead(true);
298 prevn = head;
299 index++;
300
301 nn = (int) QuimpToolsCollection.s2d(thisLine);
302
303 for (int i = 0; i < nn; i++) {
304 thisLine = br.readLine();
305 String[] split = thisLine.split("\t");
306 n = new Vert(index);
307
308 n.coord = QuimpToolsCollection.s2d(split[0]);
309 n.setX(QuimpToolsCollection.s2d(split[1]));
310 n.setY(QuimpToolsCollection.s2d(split[2]));
311
312 n.fCoord = QuimpToolsCollection.s2d(split[3]);
313 n.gCoord = QuimpToolsCollection.s2d(split[4]);
314 n.distance = QuimpToolsCollection.s2d(split[5]);
315
316
317 n.fluores[0].intensity = QuimpToolsCollection.s2d(split[6]);
318
319 if (qp.paramFormat == QParams.QUIMP_11) {
320
321 n.fluores[0].x = QuimpToolsCollection.s2d(split[7]);
322 n.fluores[0].y = QuimpToolsCollection.s2d(split[8]);
323
324 n.fluores[1].intensity = QuimpToolsCollection.s2d(split[9]);
325 n.fluores[1].x = QuimpToolsCollection.s2d(split[10]);
326 n.fluores[1].y = QuimpToolsCollection.s2d(split[11]);
327
328 n.fluores[2].intensity = QuimpToolsCollection.s2d(split[12]);
329 n.fluores[2].x = QuimpToolsCollection.s2d(split[13]);
330 n.fluores[2].y = QuimpToolsCollection.s2d(split[14]);
331 }
332
333 n.unfreeze();
334 index++;
335 prevn.setNext(n);
336 n.setPrev(prevn);
337 prevn = n;
338
339 }
340
341 prevn.setNext(head);
342 head.setPrev(prevn);
343
344
345
346 Vert newHead = head.getNext();
347
348 Outlineimp/Outline.html#Outline">Outline tmp = new Outline(head, nn + 1);
349
350
351 tmp.removeVert(head);
352 tmp.setHead(newHead);
353
354 outlines[s] = tmp;
355 outlines[s].updateNormals(true);
356 outlines[s].makeAntiClockwise();
357 outlines[s].coordReset();
358 length = outlines[s].getLength();
359 if (length > maxLength) {
360 maxLength = length;
361 }
362 s++;
363 LOGGER.trace("Outline: " + s + " head =[" + outlines[s - 1].getHead().getX() + ","
364 + outlines[s - 1].getHead().getY() + "]");
365 }
366 br.close();
367
368 if (qp.paramFormat == QParams.OLD_QUIMP) {
369 qp.setStartFrame(1);
370 qp.setEndFrame(size);
371 this.endFrame = size;
372 this.startFrame = 1;
373 qp.writeParams();
374 }
375 this.findStatLimits();
376
377 return true;
378 } catch (IOException e) {
379 LOGGER.debug(e.getMessage(), e);
380 LOGGER.error("Could not read outlines", e.getMessage());
381 return false;
382 } catch (NullPointerException e1) {
383 LOGGER.debug(e1.getMessage(), e1);
384 LOGGER.error("Damaged snQP file", e1.getMessage());
385 return false;
386 }
387 }
388
389
390
391
392
393
394
395 private void findStatLimits() {
396 maxCoor = new ExtendedVector2d();
397 minCoor = new ExtendedVector2d();
398 fluLims = new double[3][2];
399 migLimits = new double[2];
400
401 curvLimits = new double[2];
402
403
404
405 Outline outline;
406 Vert n;
407 for (int i = 0; i < outlines.length; i++) {
408 outline = outlines[i];
409 if (outline == null) {
410 continue;
411 }
412 n = outline.getHead();
413 if (i == 0) {
414 minCoor.setXY(n.getX(), n.getY());
415 maxCoor.setXY(n.getX(), n.getY());
416 migLimits[0] = n.distance;
417 migLimits[1] = n.distance;
418
419
420 for (int j = 0; j < n.fluores.length; j++) {
421 fluLims[j][0] = n.fluores[j].intensity;
422 fluLims[j][1] = n.fluores[j].intensity;
423 }
424 }
425
426 do {
427 if (n.getX() > maxCoor.getX()) {
428 maxCoor.setX(n.getX());
429 }
430 if (n.getY() > maxCoor.getY()) {
431 maxCoor.setY(n.getY());
432 }
433 if (n.getX() < minCoor.getX()) {
434 minCoor.setX(n.getX());
435 }
436 if (n.getY() < minCoor.getY()) {
437 minCoor.setY(n.getY());
438 }
439
440 if (n.distance < migLimits[0]) {
441 migLimits[0] = n.distance;
442 }
443 if (n.distance > migLimits[1]) {
444 migLimits[1] = n.distance;
445 }
446
447
448
449
450 for (int j = 0; j < n.fluores.length; j++) {
451 if (n.fluores[j].intensity < fluLims[j][0]) {
452 fluLims[j][0] = n.fluores[j].intensity;
453 }
454 if (n.fluores[j].intensity > fluLims[j][1]) {
455 fluLims[j][1] = n.fluores[j].intensity;
456 }
457 }
458
459 n = n.getNext();
460 } while (!n.isHead());
461
462 Vert v;
463 for (int f = getStartFrame(); f <= getEndFrame(); f++) {
464 Outline o = getStoredOutline(f);
465 if (o == null) {
466 continue;
467 }
468 v = o.getHead();
469
470
471 v = o.getHead();
472 if (f == getStartFrame()) {
473 curvLimits[1] = v.curvatureSum;
474 curvLimits[0] = v.curvatureSum;
475 }
476 do {
477 if (v.curvatureSum > curvLimits[1]) {
478 curvLimits[1] = v.curvatureSum;
479 }
480 if (v.curvatureSum < curvLimits[0]) {
481 curvLimits[0] = v.curvatureSum;
482 }
483 v = v.getNext();
484 } while (!v.isHead());
485 }
486 }
487
488
489 migLimits = QuimpToolsCollection.setLimitsEqual(migLimits);
490 curvLimits = QuimpToolsCollection.setLimitsEqual(curvLimits);
491 }
492
493
494
495
496
497
498 public int getSize() {
499 return size;
500 }
501
502
503
504
505
506
507
508 public void save(Outline o, int frame) {
509 outlines[frame - startFrame] = new Outline(o);
510 }
511
512
513
514
515
516
517
518 public void writeOutlines(File outFile, boolean isEccmRun) {
519 LOGGER.debug("Write outline at: " + outFile);
520 try {
521 PrintWriter pw = new PrintWriter(new FileWriter(outFile), true);
522 pw.write("#QuimP11 node data");
523 if (isEccmRun) {
524 pw.print("-ECMM");
525 }
526 pw.write("\n#Node Position\tX-coord\tY-coord\tOrigin\tG-Origin\tSpeed");
527 pw.write("\tFluor_Ch1\tCh1_x\tCh1_y\tFluor_Ch2\tCh2_x\tCh2_y\tFluor_CH3\tCH3_x\tCh3_y\n#");
528
529 Outline o;
530 for (int i = startFrame; i <= endFrame; i++) {
531 o = getStoredOutline(i);
532 pw.write("\n#Frame " + i);
533 write(pw, o.getNumPoints(), o.getHead());
534 }
535 pw.close();
536 } catch (Exception e) {
537 IJ.log("could not open out file " + outFile.getAbsolutePath());
538 return;
539 }
540 }
541
542 private static void write(PrintWriter pw, int verts, Vert v) {
543 pw.print("\n" + verts);
544
545 do {
546 pw.print("\n" + IJ.d2s(v.coord, 6) + "\t"
547 + IJ.d2s(v.getX(), 2) + "\t"
548 + IJ.d2s(v.getY(), 2) + "\t"
549 + IJ.d2s(v.fCoord, 6) + "\t"
550 + IJ.d2s(v.gCoord, 6) + "\t"
551 + IJ.d2s(v.distance, 6) + "\t"
552 + IJ.d2s(v.fluores[0].intensity, 6) + "\t"
553 + IJ.d2s(v.fluores[0].x, 0) + "\t"
554 + IJ.d2s(v.fluores[0].y, 0) + "\t"
555 + IJ.d2s(v.fluores[1].intensity, 6) + "\t"
556 + IJ.d2s(v.fluores[1].x, 0) + "\t"
557 + IJ.d2s(v.fluores[1].y, 0) + "\t"
558 + IJ.d2s(v.fluores[2].intensity, 6) + "\t"
559 + IJ.d2s(v.fluores[2].x, 0) + "\t"
560 + IJ.d2s(v.fluores[2].y, 0));
561
562 v = v.getNext();
563 } while (!v.isHead());
564 }
565
566
567
568
569 @Override
570 public void beforeSerialize() {
571 for (Outline o : outlines) {
572 if (o != null) {
573 o.beforeSerialize();
574 }
575 }
576 }
577
578
579
580
581 @Override
582 public void afterSerialize() throws Exception {
583 for (Outline o : outlines) {
584 if (o != null) {
585 o.afterSerialize();
586 }
587 }
588
589 size = outlines.length;
590 for (Outline o : outlines) {
591 if (o.getLength() > maxLength) {
592 maxLength = o.getLength();
593 }
594 }
595 findStatLimits();
596
597 }
598 }