1 package com.github.celldynamics.quimp;
2
3 import java.util.List;
4
5 import org.scijava.vecmath.Tuple2d;
6 import org.slf4j.Logger;
7 import org.slf4j.LoggerFactory;
8
9 import com.github.celldynamics.quimp.filesystem.IQuimpSerialize;
10 import com.github.celldynamics.quimp.geom.ExtendedVector2d;
11
12 import ij.IJ;
13 import ij.gui.Roi;
14 import ij.process.FloatPolygon;
15
16
17
18
19
20
21
22
23
24
25 public class Outline extends Shape<Vert> implements Cloneable, IQuimpSerialize {
26
27
28
29
30 static final Logger LOGGER = LoggerFactory.getLogger(Outline.class.getName());
31
32
33
34
35 public Outline() {
36 super();
37 }
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58 public Outline(final Vert h, int nn) {
59 super(h, nn);
60
61 this.updateCurvature();
62 this.updateNormals(false);
63 }
64
65
66
67
68
69
70 public Outline(final Vert h) {
71 super(h);
72 this.updateCurvature();
73 }
74
75
76
77
78
79
80 public Outlines/quimp/Outline.html#Outline">Outline(final Outline src) {
81 super(src);
82 }
83
84
85
86
87
88
89
90
91
92
93
94
95 @SuppressWarnings({ "unchecked", "rawtypes" })
96 public Outline(final Snake src) {
97 super((Shape) src, new Vert());
98 this.updateCurvature();
99 setPositions();
100 this.updateNormals(false);
101 }
102
103
104
105
106
107
108 public Outline(final Roi roi) {
109 head = new Vert(0);
110 POINTS = 1;
111 head.setPrev(head);
112 head.setNext(head);
113 head.setHead(true);
114
115 Vert v = head;
116
117 FloatPolygon p = roi.getFloatPolygon();
118 for (int i = 0; i < p.npoints; i++) {
119 v = insertVert(v);
120 v.setX(p.xpoints[i]);
121 v.setY(p.ypoints[i]);
122 }
123 removeVert(head);
124 updateNormals(false);
125 this.updateCurvature();
126 setPositions();
127 calcCentroid();
128 }
129
130
131
132
133
134
135 public Outline(final List<? extends Tuple2d> list) {
136 super(list, new Vert(0), false);
137 this.updateCurvature();
138 }
139
140
141
142
143
144
145
146 public Outline(final double[] x, final double[] y) {
147 super(x, y, new Vert(0), false);
148 this.updateCurvature();
149 }
150
151
152
153
154
155
156 @Override
157 public String toString() {
158 return "Outline [POINTS=" + POINTS + ", centroid=" + centroid + ", toString()="
159 + super.toString() + "]";
160 }
161
162
163
164
165 public void print() {
166 IJ.log("Print verts (" + POINTS + ")");
167 int i = 0;
168 Vert v = head;
169 do {
170
171
172 double x = v.getPoint().getX();
173 double y = v.getPoint().getY();
174 double c = v.coord;
175 double f = v.fCoord;
176
177 String xx = IJ.d2s(x, 8);
178 String yy = IJ.d2s(y, 8);
179 String cc = IJ.d2s(c, 3);
180 String ff = IJ.d2s(f, 3);
181
182 String sh = "";
183 String si = "\t";
184 if (v.isHead()) {
185 sh = " isHead";
186 }
187 if (v.isIntPoint()) {
188 si = "\t isIntPoint(" + v.intsectID + ")";
189 }
190
191 IJ.log("Vert " + v.getTrackNum() + " (" + cc + ")(" + ff + "), x:" + xx + ", y:" + yy + si
192 + sh);
193 v = v.getNext();
194 i++;
195 } while (!v.isHead());
196 if (i != POINTS) {
197 IJ.log("VERTS and linked list dont tally!!");
198 }
199 }
200
201
202
203
204
205
206
207
208
209 public void removeVert(final Vert v) {
210 if (POINTS <= 3) {
211 LOGGER.error("Outline. 175. Can't remove node. Less than 3 would remain");
212 return;
213 }
214 super.removePoint(v, true);
215 if (POINTS < 3) {
216 IJ.error("Outline.199. WARNING! Nodes less then 3");
217 }
218 }
219
220
221
222
223 public void updateCurvature() {
224 Vert v = head;
225 do {
226 v.setCurvatureLocal();
227 v = v.getNext();
228 } while (!v.isHead());
229 }
230
231
232
233
234
235
236
237 public VertVert.html#Vert">Vert insertVert(final Vert v) {
238 return insertPoint(v, new Vert());
239 }
240
241
242
243
244
245
246
247
248
249 public Vertrt">Vert insertInterpolatedVert(final Vert v) {
250 Vert newVert = insertVert(v);
251 newVert.setX((newVert.getPrev().getX() + newVert.getNext().getX()) / 2);
252 newVert.setY((newVert.getPrev().getY() + newVert.getNext().getY()) / 2);
253
254 newVert.updateNormale(true);
255 newVert.distance = (newVert.getPrev().distance + newVert.getNext().distance) / 2;
256 newVert.gCoord = interpolateCoord(newVert.getPrev().gCoord, newVert.getNext().gCoord);
257 newVert.fCoord = interpolateCoord(newVert.getPrev().fCoord, newVert.getNext().fCoord);
258
259 return newVert;
260 }
261
262
263
264
265
266
267
268
269 public double interpolateCoord(double a, double b) {
270 if (a > b) {
271 b = b + 1;
272 }
273 double dis = a + ((b - a) / 2);
274
275 if (dis >= 1) {
276 dis += -1;
277 }
278 return dis;
279 }
280
281
282
283
284
285
286 public void setResolution(double density) {
287 double length = getLength();
288 int numVerts = (int) Math.round((length / density));
289 density = length / numVerts;
290
291 double remaining = 0.;
292 double lastPlacement;
293 double currentDis;
294
295 Vert oldHead = head;
296 Vert v1 = oldHead;
297
298
299 head = new Vert(v1.getX(), v1.getY(), v1.getTrackNum());
300 head.setHead(true);
301 head.setIntPoint(oldHead.isIntPoint(), oldHead.intsectID);
302 head.setNext(head);
303 head.setPrev(head);
304
305 head.gCoord = 0.;
306 head.coord = 0.;
307
308 nextTrackNumber = oldHead.getTrackNum() + 1;
309 POINTS = 1;
310
311 double coorSpaceing = 1.0 / numVerts;
312
313 double currentCoor = coorSpaceing;
314
315 Vert temp;
316 Vert newV;
317 newV = head;
318
319 int numVertsInserted = 1;
320 ExtendedVector2d uedge;
321 ExtendedVector2d edge;
322 ExtendedVector2d placementVector;
323 do {
324 Vert v2 = v1.getNext();
325 lastPlacement = 0.0;
326 currentDis = 0.0;
327 edge = ExtendedVector2d.vecP2P(v1.getPoint(), v2.getPoint());
328
329 uedge = ExtendedVector2d.unitVector(v1.getPoint(), v2.getPoint());
330
331 if (edge.length() == 0) {
332 v1 = v1.getNext();
333 continue;
334 }
335
336 while (true) {
337 placementVector = new ExtendedVector2d(uedge.getX(), uedge.getY());
338
339
340
341 placementVector.multiply((density + currentDis) - remaining);
342
343
344
345 if (placementVector.length() <= edge.length() && numVertsInserted < numVerts) {
346 currentDis = placementVector.length();
347 lastPlacement = currentDis;
348 remaining = 0;
349
350 placementVector.addVec(v1.getPoint());
351
352 temp = insertVert(newV);
353 temp.setX(placementVector.getX());
354 temp.setY(placementVector.getY());
355 temp.gCoord = currentCoor;
356 temp.coord = currentCoor;
357
358 newV = temp;
359
360 numVertsInserted++;
361 currentCoor += coorSpaceing;
362
363 } else {
364 if (v2.isHead()) {
365 break;
366 }
367 if (v2.isIntPoint()) {
368 temp = insertVert(newV);
369 temp.setX(v2.getX());
370 temp.setY(v2.getY());
371 temp.setIntPoint(true, v2.intsectID);
372 newV = temp;
373 }
374 remaining = edge.length() - lastPlacement + remaining;
375 break;
376 }
377 }
378
379 v1 = v1.getNext();
380 } while (!v1.isHead());
381 oldHead = null;
382
383 }
384
385
386
387
388
389
390 public void setResolutionN(double numVerts) {
391 double length = getLength();
392
393
394 double density = length / numVerts;
395
396 double remaining = 0.0;
397 double lastPlacement;
398 double currentDis;
399
400 Vert oldHead = head;
401 Vert v1 = oldHead;
402
403
404 head = new Vert(v1.getX(), v1.getY(), v1.getTrackNum());
405 head.setHead(true);
406 head.setIntPoint(oldHead.isIntPoint(), oldHead.intsectID);
407 head.setNext(head);
408 head.setPrev(head);
409
410 head.gCoord = 0.;
411 head.coord = 0.;
412
413 nextTrackNumber = oldHead.getTrackNum() + 1;
414 POINTS = 1;
415
416 double coorSpaceing = 1.0 / numVerts;
417
418 double currentCoor = coorSpaceing;
419
420 Vert temp;
421 Vert newV;
422 newV = head;
423
424 int numVertsInserted = 1;
425 ExtendedVector2d uedge;
426 ExtendedVector2d edge;
427 ExtendedVector2d placementVector;
428 do {
429 Vert v2 = v1.getNext();
430 lastPlacement = 0.0;
431 currentDis = 0.0;
432 edge = ExtendedVector2d.vecP2P(v1.getPoint(), v2.getPoint());
433
434 uedge = ExtendedVector2d.unitVector(v1.getPoint(), v2.getPoint());
435
436 if (edge.length() == 0) {
437 v1 = v1.getNext();
438 continue;
439 }
440
441 while (true) {
442 placementVector = new ExtendedVector2d(uedge.getX(), uedge.getY());
443
444
445
446 placementVector.multiply((density + currentDis) - remaining);
447
448
449
450 if (placementVector.length() <= edge.length() && numVertsInserted < numVerts) {
451 currentDis = placementVector.length();
452 lastPlacement = currentDis;
453 remaining = 0;
454
455 placementVector.addVec(v1.getPoint());
456
457 temp = insertVert(newV);
458 temp.setX(placementVector.getX());
459 temp.setY(placementVector.getY());
460 temp.gCoord = currentCoor;
461 temp.coord = currentCoor;
462
463 newV = temp;
464
465 numVertsInserted++;
466 currentCoor += coorSpaceing;
467
468 } else {
469 if (v2.isHead()) {
470 break;
471 }
472 if (v2.isIntPoint()) {
473 temp = insertVert(newV);
474 temp.setX(v2.getX());
475 temp.setY(v2.getY());
476 temp.setIntPoint(true, v2.intsectID);
477 newV = temp;
478 }
479 remaining = edge.length() - lastPlacement + remaining;
480 break;
481 }
482 }
483
484 v1 = v1.getNext();
485 } while (!v1.isHead());
486 oldHead = null;
487 }
488
489
490
491
492
493
494 public double calcVolume() {
495 double sum;
496 sum = 0.0;
497 Vert n = head;
498 Vert np1 = n.getNext();
499 do {
500 sum += (n.getX() * np1.getY()) - (np1.getX() * n.getY());
501 n = n.getNext();
502 np1 = n.getNext();
503
504 } while (!n.isHead());
505 return 0.5 * sum;
506 }
507
508
509
510
511
512
513 public double calcArea() {
514 double area;
515 double sum;
516 sum = 0.0;
517 Vert n = head;
518 Vert np1 = n.getNext();
519 do {
520 sum += (n.getX() * np1.getY()) - (np1.getX() * n.getY());
521 n = n.getNext();
522 np1 = n.getNext();
523
524 } while (!n.isHead());
525 area = 0.5 * sum;
526 return area;
527 }
528
529
530
531
532
533
534
535 public static Vert/../../com/github/celldynamics/quimp/Vert.html#Vert">Vert getNextIntersect(Vert v) {
536 do {
537 v = v.getNext();
538 } while (!v.isIntPoint());
539 return v;
540 }
541
542
543
544
545
546
547
548
549 public static Vert/../../../com/github/celldynamics/quimp/Vert.html#Vert">Vert findIntersect(Vert v, int id) {
550 int count = 0;
551 do {
552 if (v.isIntPoint() && v.intsectID == id) {
553 break;
554 }
555 v = v.getNext();
556 if (count++ > 2000) {
557 System.out.println("Outline->findIntersect - search exceeded 2000");
558 break;
559 }
560 } while (true);
561
562 return v;
563 }
564
565
566
567
568
569
570
571
572 public static int distBetweenInts(Verthref="../../../../com/github/celldynamics/quimp/Vert.html#Vert">Vert intA, Vert intB) {
573 int d = 0;
574 do {
575 d++;
576 intA = intA.getNext();
577 if (d > 2000) {
578 System.out.println("Outline:distBetween->search exceeded 2000");
579 break;
580 }
581 } while (intA.intsectID != intB.intsectID);
582 return d;
583 }
584
585
586
587
588
589
590
591
592 public static int invertsBetween(Verthref="../../../../com/github/celldynamics/quimp/Vert.html#Vert">Vert intA, Vert intB) {
593 int i = 0;
594 int count = 0;
595 do {
596 intA = intA.getNext();
597 if (intA.isIntPoint() && intA.intState > 2) {
598 i++;
599 }
600 if (intA.isIntPoint() && intA.intState == 1) {
601 i--;
602 }
603 if (count++ > 2000) {
604 System.out.println("Outline:invertsBetween. search exceeded 2000");
605 break;
606 }
607 } while (intA.intsectID != intB.intsectID);
608 return i;
609 }
610
611
612
613
614
615
616
617
618
619
620
621
622 public void correctDensity(double max, double min) {
623 double dist;
624 Vert v = head;
625 boolean canEnd = true;
626 do {
627 dist = ExtendedVector2d.lengthP2P(v.getPoint(), v.getNext().getPoint());
628 canEnd = true;
629 if (dist < min) {
630 if (!v.getNext().isHead()) {
631 removeVert(v.getNext());
632 v = v.getNext();
633 } else {
634 removeVert(v.getNext());
635 break;
636 }
637 } else if (dist > max) {
638 this.insertInterpolatedVert(v);
639
640
641 if (v.isHead()) {
642 canEnd = false;
643 }
644 } else {
645 v = v.getNext();
646 }
647 } while (!(v.isHead() && canEnd));
648 }
649
650
651
652
653
654
655
656
657
658
659
660 public boolean cutSelfIntersects() {
661 boolean icut = false;
662 int interval;
663 int state;
664
665 Vert na;
666 Vert nb;
667 double[] intersect = new double[2];
668 Vert newN;
669
670 boolean cutHead;
671
672 na = head;
673 do {
674 cutHead = (na.getNext().isHead()) ? true : false;
675 nb = na.getNext().getNext();
676 interval = (POINTS > 6) ? POINTS / 2 : 2;
677 for (int i = 2; i < interval; i++) {
678 if (nb.isHead()) {
679 cutHead = true;
680 }
681 intersect = new double[2];
682 state = ExtendedVector2d.segmentIntersection(na.getX(), na.getY(), na.getNext().getX(),
683 na.getNext().getY(), nb.getX(), nb.getY(), nb.getNext().getX(), nb.getNext().getY(),
684 intersect);
685
686 if (state == 1) {
687 icut = true;
688 newN = this.insertInterpolatedVert(na);
689 newN.setX(intersect[0]);
690 newN.setY(intersect[1]);
691
692 newN.setNext(nb.getNext());
693 nb.getNext().setPrev(newN);
694
695 newN.updateNormale(true);
696 nb.getNext().updateNormale(true);
697
698 if (cutHead) {
699
700 newN.setHead(true);
701 head = newN;
702 }
703
704
705
706 if (POINTS - (i) < 3) {
707 LOGGER.warn("OUTLINE 594_VERTS WILL BE than 3. i = " + i + ", VERT=" + POINTS);
708 }
709 POINTS -= (i);
710 break;
711 }
712 nb = nb.getNext();
713 }
714 na = na.getNext();
715 } while (!na.isHead());
716
717 return icut;
718 }
719
720
721
722
723
724
725
726
727 public boolean removeNanoEdges() {
728 double nano = 0.1;
729 double length;
730 boolean deleted = false;
731
732 Vert na;
733 Vert nb;
734
735 na = head;
736 do {
737 do {
738 nb = na.getNext();
739 length = ExtendedVector2d.lengthP2P(na.getPoint(), nb.getPoint());
740 if (length < nano) {
741 this.removeVert(nb);
742 deleted = true;
743 }
744 } while (length < nano);
745
746 na = na.getNext();
747 } while (!na.isHead());
748
749 return deleted;
750 }
751
752
753
754
755
756
757 public void coordReset() {
758 Vert vertFirst = findFirstNode('g');
759 head.setHead(false);
760 head = vertFirst;
761 head.setHead(true);
762
763 double length = getLength();
764 double d = 0.;
765
766 Vert v = head;
767 do {
768 v.coord = d / length;
769 d = d + ExtendedVector2d.lengthP2P(v.getPoint(), v.getNext().getPoint());
770 v = v.getNext();
771 } while (!v.isHead());
772 }
773
774
775
776
777
778 public void resetAllCoords() {
779 double length = getLength();
780 double d = 0.;
781
782 Vert v = head;
783 do {
784 v.coord = d / length;
785 v.gCoord = v.coord;
786 v.fCoord = v.coord;
787 d = d + ExtendedVector2d.lengthP2P(v.getPoint(), v.getNext().getPoint());
788 v = v.getNext();
789 } while (!v.isHead());
790
791 }
792
793
794
795
796
797
798
799
800 public Object clone() {
801
802 Vert ov = head;
803
804 Verts/quimp/Vert.html#Vert">Vert nv = new Vert(ov.getX(), ov.getY(), ov.getTrackNum());
805 nv.coord = ov.coord;
806 nv.fCoord = ov.fCoord;
807 nv.gCoord = ov.gCoord;
808 nv.distance = ov.distance;
809
810 nv.setFluores(ov.fluores);
811
812 Outlinequimp/Outline.html#Outline">Outline n = new Outline(nv);
813
814 ov = ov.getNext();
815 do {
816 nv = n.insertVert(nv);
817 nv.setX(ov.getX());
818 nv.setY(ov.getY());
819 nv.coord = ov.coord;
820 nv.fCoord = ov.fCoord;
821 nv.gCoord = ov.gCoord;
822 nv.distance = ov.distance;
823
824 nv.setFluores(ov.fluores);
825 nv.setTrackNum(ov.getTrackNum());
826
827 ov = ov.getNext();
828 } while (!ov.isHead());
829 n.updateNormals(true);
830 n.calcCentroid();
831 n.updateCurvature();
832
833 return n;
834 }
835
836
837
838
839
840
841 public boolean checkCoordErrors() {
842 Vert v = head;
843
844 do {
845
846 if (v.gCoord >= 1 || v.gCoord < 0 || v.fCoord >= 1 || v.fCoord < 0 || v.coord >= 1
847 || v.coord < 0) {
848 System.out.println("Outline587: Errors in tracking Coordinates\n\t" + "coord=" + v.coord
849 + ", gCoord= " + v.gCoord + ", fCoord = " + v.fCoord);
850 return true;
851 }
852
853 v = v.getNext();
854 } while (!v.isHead());
855
856 return false;
857
858 }
859
860
861
862
863
864
865
866 public Vert findFirstNode(char c) {
867
868 Vert v = head;
869 Vert vertFirst = v;
870
871 double coord;
872 double coordPrev;
873 double dis;
874 double disFirst = 0;
875
876 do {
877
878
879 if (c == 'f') {
880 coord = v.fCoord;
881 coordPrev = v.getPrev().fCoord;
882 } else if (c == 'g') {
883 coord = v.gCoord;
884 coordPrev = v.getPrev().gCoord;
885 } else {
886 coord = v.coord;
887 coordPrev = v.getPrev().coord;
888 }
889
890 dis = Math.abs(coord - coordPrev);
891
892
893 if (dis > disFirst) {
894 vertFirst = v;
895 disFirst = dis;
896
897
898 }
899
900 v = v.getNext();
901 } while (!v.isHead());
902
903
904
905
906 return vertFirst;
907
908 }
909
910
911
912
913 public void clearFluores() {
914 Vert v = head;
915 do {
916 v.setFluoresChannel(-2, -2, -2, 0);
917 v.setFluoresChannel(-2, -2, -2, 1);
918 v.setFluoresChannel(-2, -2, -2, 2);
919 v = v.getNext();
920 } while (!v.isHead());
921 }
922
923
924
925
926
927
928
929 public Vert findCoordEdge(double a) {
930 Vert v = head;
931 do {
932
933 if (v.coord < a && v.coord > a) {
934 return v;
935 }
936
937 if (v.coord > a && v.getPrev().coord > a && v.getNext().coord > a
938 && v.getNext().getNext().coord > a) {
939 return v;
940 }
941
942 if (v.coord < a && v.getPrev().coord < a && v.getNext().coord < a
943 && v.getNext().getNext().coord < a) {
944 return v;
945 }
946
947 v = v.getNext();
948 } while (!v.isHead());
949 return head;
950 }
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966 public void scaleOutline(double amount, double stepRes, double angleTh, double freezeTh) {
967 int j;
968 updateNormals(true);
969 double steps = Math.abs(amount / stepRes);
970 for (j = 0; j < steps; j++) {
971 if (getNumPoints() <= 3) {
972 break;
973 }
974 super.scale(stepRes);
975 updateNormals(true);
976 removeProx(1.5, 1.5);
977 freezeProx(angleTh, freezeTh);
978 if (j > MAX_NODES) {
979 LOGGER.warn("shrink (336) hit max iterations!");
980 break;
981 }
982 }
983
984 if (getNumPoints() < 3) {
985 LOGGER.info("ANA 377_NODES LESS THAN 3 BEFORE CUTS");
986 }
987
988 if (cutSelfIntersects()) {
989 LOGGER.debug("ANA_(382)...fixed ana intersects");
990 }
991
992 if (getNumPoints() < 3) {
993 LOGGER.info("ANA 377_NODES LESS THAN 3");
994 }
995 calcCentroid();
996 setPositions();
997 }
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009 public void removeProx(double d1th, double d2th) {
1010 if (getNumPoints() <= 3) {
1011 return;
1012 }
1013 Vert v;
1014 Vert vl;
1015 Vert vr;
1016 double d1;
1017 double d2;
1018 v = getHead();
1019 vl = v.getPrev();
1020 vr = v.getNext();
1021 do {
1022 d1 = ExtendedVector2d.lengthP2P(v.getPoint(), vl.getPoint());
1023 d2 = ExtendedVector2d.lengthP2P(v.getPoint(), vr.getPoint());
1024
1025 if ((d1 < d1th || d2 < d2th) && !v.isFrozen()) {
1026 removeVert(v);
1027 }
1028 v = v.getNext().getNext();
1029 vl = v.getPrev();
1030 vr = v.getNext();
1031 } while (!v.isHead() && !vl.isHead());
1032
1033 }
1034
1035
1036
1037
1038
1039
1040
1041 public void freezeProx(double angleTh, double freezeTh) {
1042 Vert v;
1043 Vert vtmp;
1044 ExtendedVector2d closest;
1045 ExtendedVector2d edge;
1046 ExtendedVector2d link;
1047 double dis;
1048 double angle;
1049
1050 v = getHead();
1051 do {
1052
1053 vtmp = getHead();
1054 do {
1055 if (vtmp.getTrackNum() == v.getTrackNum()
1056 || vtmp.getNext().getTrackNum() == v.getTrackNum()) {
1057 vtmp = vtmp.getNext();
1058 continue;
1059 }
1060 closest = ExtendedVector2d.pointToSegment(v.getPoint(), vtmp.getPoint(),
1061 vtmp.getNext().getPoint());
1062 dis = ExtendedVector2d.lengthP2P(v.getPoint(), closest);
1063
1064
1065 if (dis < freezeTh) {
1066 edge = ExtendedVector2d.unitVector(vtmp.getPoint(), vtmp.getNext().getPoint());
1067 link = ExtendedVector2d.unitVector(v.getPoint(), closest);
1068 angle = Math.abs(ExtendedVector2d.angle(edge, link));
1069 if (angle > Math.PI) {
1070 angle = angle - Math.PI;
1071 }
1072
1073 angle = angle - 1.5708;
1074
1075
1076 if (angle < angleTh && angle > -angleTh) {
1077 v.freeze();
1078 vtmp.freeze();
1079 vtmp.getNext().freeze();
1080 }
1081
1082 }
1083 vtmp = vtmp.getNext();
1084 } while (!vtmp.isHead());
1085
1086 v = v.getNext();
1087 } while (!v.isHead());
1088 }
1089
1090
1091
1092
1093
1094
1095 @SuppressWarnings("unused")
1096 @Override
1097 public int hashCode() {
1098 final int prime = 31;
1099 int result = super.hashCode();
1100 return result;
1101 }
1102
1103
1104
1105
1106
1107
1108 @SuppressWarnings("unused")
1109 @Override
1110 public boolean equals(Object obj) {
1111 if (this == obj) {
1112 return true;
1113 }
1114 if (!super.equals(obj)) {
1115 return false;
1116 }
1117 if (getClass() != obj.getClass()) {
1118 return false;
1119 }
1120 Outline../../../../com/github/celldynamics/quimp/Outline.html#Outline">Outline other = (Outline) obj;
1121 return true;
1122 }
1123
1124
1125
1126
1127
1128
1129 @Override
1130 public void beforeSerialize() {
1131 super.beforeSerialize();
1132 this.updateCurvature();
1133 }
1134
1135
1136
1137
1138
1139
1140 @Override
1141 public void afterSerialize() throws Exception {
1142 super.afterSerialize();
1143 this.updateCurvature();
1144 }
1145
1146 }