From 4c70a0cd0f3c600a69185daa308ae0932b7b10f7 Mon Sep 17 00:00:00 2001 From: Thomas <thomas.musset@pasteur.fr> Date: Sun, 7 Jul 2024 17:51:43 +0200 Subject: [PATCH] updated pom to v3.0.0-a.1, fix classes accordingly to new architecture, added icon, updated .gitignore --- .gitignore | 41 +- pom.xml | 47 +- .../TrackPainter$TrackOverlay$1.class | Bin 1268 -> 0 bytes .../TrackPainter$TrackOverlay$2.class | Bin 1264 -> 0 bytes .../TrackPainter$TrackOverlay$3.class | Bin 1326 -> 0 bytes .../TrackPainter$TrackOverlay$4.class | Bin 1393 -> 0 bytes .../TrackPainter$TrackOverlay$5.class | Bin 1271 -> 0 bytes .../TrackPainter$TrackOverlay.class | Bin 17222 -> 0 bytes .../trackprocessors/TrackPainter.class | Bin 4180 -> 0 bytes .../adufour/trackprocessors/TrackPainter.java | 475 ++++++++---------- src/main/resources/track-painter.png | Bin 0 -> 14115 bytes 11 files changed, 263 insertions(+), 300 deletions(-) delete mode 100644 src/main/java/plugins/adufour/trackprocessors/TrackPainter$TrackOverlay$1.class delete mode 100644 src/main/java/plugins/adufour/trackprocessors/TrackPainter$TrackOverlay$2.class delete mode 100644 src/main/java/plugins/adufour/trackprocessors/TrackPainter$TrackOverlay$3.class delete mode 100644 src/main/java/plugins/adufour/trackprocessors/TrackPainter$TrackOverlay$4.class delete mode 100644 src/main/java/plugins/adufour/trackprocessors/TrackPainter$TrackOverlay$5.class delete mode 100644 src/main/java/plugins/adufour/trackprocessors/TrackPainter$TrackOverlay.class delete mode 100644 src/main/java/plugins/adufour/trackprocessors/TrackPainter.class create mode 100644 src/main/resources/track-painter.png diff --git a/.gitignore b/.gitignore index 3d47f98..57f16fb 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,41 @@ -.idea/ +/build* +/workspace +setting.xml +release/ target/ -.settings/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ +icy.log + +### IntelliJ IDEA ### +.idea/ +*.iws *.iml +*.ipr + +### Eclipse ### +.apt_generated +.classpath +.factorypath .project -.classpath \ No newline at end of file +.settings +.springBeans +.sts4-cache + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ + +### Mac OS ### +**/.DS_Store +Icon? \ No newline at end of file diff --git a/pom.xml b/pom.xml index b2ac9bb..68dd4b7 100644 --- a/pom.xml +++ b/pom.xml @@ -6,23 +6,21 @@ <!-- Inherited Icy Parent POM --> <parent> - <artifactId>pom-icy</artifactId> + <artifactId>pom-icy</artifactId> <groupId>org.bioimageanalysis.icy</groupId> - <version>2.0.0</version> - </parent> + <version>3.0.0-a.1</version> + </parent> <!-- Project Information --> <artifactId>track-painter</artifactId> - <version>2.2.1</version> - - <packaging>jar</packaging> + <version>3.0.0-a.1</version> <name>Track Painter</name> <description> Track Manager plugin that displays available tracks on the selected sequence, in both 2D and 3D viewers, with various visualisation options. Tracks never looked so good! </description> - <url>http://icy.bioimageanalysis.org/plugin/track-painter/</url> + <url>https://icy.bioimageanalysis.org/plugin/track-painter/</url> <inceptionYear>2020</inceptionYear> <organization> @@ -56,39 +54,23 @@ </developer> </developers> - <!-- Project properties --> - <properties> - - </properties> - - <profiles> - <profile> - <id>icy-plugin</id> - <activation> - <activeByDefault>true</activeByDefault> - </activation> - </profile> - </profiles> - - <!-- List of project's dependencies --> <dependencies> - <!-- The core of Icy --> <dependency> <groupId>org.bioimageanalysis.icy</groupId> - <artifactId>icy-kernel</artifactId> - <version>${icy-kernel.version}</version> + <artifactId>ezplug</artifactId> </dependency> - - <dependency> + + <dependency> <groupId>org.bioimageanalysis.icy</groupId> - <artifactId>icy-vtk</artifactId> - <version>${icy-vtk.version}</version> + <artifactId>spot-detection-utilities</artifactId> </dependency> - <dependency> <groupId>org.bioimageanalysis.icy</groupId> <artifactId>track-manager</artifactId> - <version>${track-manager.version}</version> + </dependency> + <dependency> + <groupId>org.bioimageanalysis.icy</groupId> + <artifactId>vecmath</artifactId> </dependency> </dependencies> @@ -96,8 +78,7 @@ <repositories> <repository> <id>icy</id> - <name>Icy's Nexus</name> - <url>https://icy-nexus.pasteur.fr/repository/Icy/</url> + <url>https://nexus-icy.pasteur.cloud/repository/icy/</url> </repository> </repositories> </project> diff --git a/src/main/java/plugins/adufour/trackprocessors/TrackPainter$TrackOverlay$1.class b/src/main/java/plugins/adufour/trackprocessors/TrackPainter$TrackOverlay$1.class deleted file mode 100644 index eb6281a50c89ae7fad5d7bd157e72eaca215bf47..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1268 zcmbtT-%k@k5dOBU92^IftD>T4)l>QlO3@cn^+C`?Q$+)5Oy9QcQVx$@a(Aua&oWU+ zctD>0ql~lHLr&C0@siuynVb1$zWH{)emgt@u#5)=QVjK7uitZJQ03kJrt16E(C3}^ zyT0m(AW(i#-O%<M?#fX3PGqbNgzxb^r)D6-;G6{*aLV$y>{XlGf2x!xxMUa!x7@&~ zQNhO9gukv>CzwaBbi*eMZwvo{)7a(%KJ0Nl^j+Djw~9@M%!=xYF))l<xPTE8X-rr! zFv&1e_(RTA!<FK7f2S?{4c_(ygWXUa?h$ua+p#mF=`%b&f74El=#M*GD!I3#`oWT} z^b3!lLTK8o#gN-{eR0yy$`&ajx(vl6qgbYT0`SCDY?_$GbpzKJrcdj|zb(w+27}ce z>fGdBpGJ@_6k8_pxNYDT!^3k6Zs86bA`pmhRfM7wx=OCP!7iOXQma6sX^rk#xQuy* z`6Q#Y_BO>Q3B?{Q^r-T>ajUuCP^JJWK12Z~ora3WzrtXy)BWg(=dM<HI(aV^^;{UH zp2?1<0y<BxM7X7B$kq!fg}>tQAP|9pWdi$`VGuy_#?eG+wsd(}HmeUP?X+cJl>B3~ zdr5YNzE-LH8D^<6cL3`n*(prXIzmyvA+ogQqf86au*sqf<ZzMV^zIU7A{-(e<Gv$X zSF%f=U{>~VbsslN<;nr>o}y1i5l0xu7eYNwRIz_lu~9%V>cU2ecB$;DmM*Tc5LcNf tm5(u7p?4qU(*ncxSp=*bO=E%96c$mXZ-yuVOZ3|0%cF+-1gi<t^BuB;MDG9q diff --git a/src/main/java/plugins/adufour/trackprocessors/TrackPainter$TrackOverlay$2.class b/src/main/java/plugins/adufour/trackprocessors/TrackPainter$TrackOverlay$2.class deleted file mode 100644 index 12df67be3bdcbd8aea76960581666b999dd539e7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1264 zcmbtTQBTuQ6#nj*D|7`$r>H18waV5F2GbWa^+C`?GerYg3~zVcg%!&!X}cMImWe{* zgYm%!<wqIM?TS>?M6pS4@3}qa`_6aHxrg6Ad<4+I9Ss?V=C0S@a%EWO-TtQE59(3C zo!7g8?}#w;gRs7?>=)dXkqE5VSRIJK<9k*^Lzclh2{7Ok<#D-HZ}Z@x?|XtvhFsKh zLu-i$TPFklnz2bR_gv{l4;WsS{{yGB%?Es#<60EBa;v#fX)|P({jL}TL*Bp{<aCT+ z+<=A&hUxMjVkTRz6wmuR9TBYajwcw*mhW(nw7beq4zo%=!~N4IZ8b=K-r~}idpmwV zTvSZI==jNns?9bSikogAj`CUVQD;P#p^{dVw5gc_JUXhhb<E(hhD!`n$9&0e1GBio zV04CkZga0sB^W7JHguG5UBfkoyQglrfg7+GCPNX$leglAyEJ*!sWLT8_2-s>^O$3p zORHJ!Yzrq!i%CvYlSh58o1|I%ja+h&;!W(J(<Ias{sjhojqZjc9=oc;Q|UXgplU)n zK9Y{-hcrviMAY-Cz{V3PMX>DgFchJN27&!cAqXIS+o+mUSGu^YP*B53J7sAYrSmb` zJtaF!U&F4xhi=zq4`93{JA+ADbL0hlMuFB+9BE(*CRr4LBF>VZ+MUC6j6<Rm+*f2P zCewZgy|#~w`?zXXYX`V_j6M;2d_f*x3H30=V*X$;QAQ=s!h}t`OkqW}E@7EZSjO$@ sC(P97-ADD9V3<COfmNa-n5Q*^1=Q)AB}u>{y(XQNu!P$Ls|3^Y9hSI5YXATM diff --git a/src/main/java/plugins/adufour/trackprocessors/TrackPainter$TrackOverlay$3.class b/src/main/java/plugins/adufour/trackprocessors/TrackPainter$TrackOverlay$3.class deleted file mode 100644 index 64de8e96805093b8f6d8f660db86941cb3ef52e8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1326 zcmbtTTTc@~6#k~IY$*%9X}wlaSLqE3)E84PiB%I#6%C{hJUQJC?cy>^cDERQmWhJ# z!T4<AgO}f9JhLoxMNJeo*_m@r&iTG`n@>O9e*mzE8yaE^%}smQx1?9+z2TZObnCv$ z&6k_5V+zl6T(7>O^k>|XzHp5|S=th=&9{w)h6ICg7+{N2l+9(o-r?>&$FT*M3}gPl z@{9!{Y#$EzXT~PM+_I$Q-(h%OItEUAop15I9G899lKtjtxx<iXIXy8Bh6x=fFqT3b zlR7j^F%(LFiAlFDDV`2Dy24%IU0X2Z+K$O>s@+n0XiTW`8EzjvX`?~qPZ(S}a(lxW zdh?3uw>o}tp>DHPhWwi4iv4_A1DcHJF_fbfg=1<)0QXJhj_SiX9j9@gVI~^2)Lj>* z9}NmEDyE1_8ZI*2Jo318Oye>`lACH54J!EVafVJKR#{!uVc;6W)aKq!A2cLhQag}z z>|Tf4LmFiM58WUKDP9E*8Y&Fg(FDSVrD%U@s#|9mQp@zBO!3fCdy$R4q&XGGkbWRd z+wo`vp9p{8&{*_GQVO?abI%i=hD8GVp9T^@^o>#n8BGshnT%R#l9Z+)N%nD)9+RG+ zTd!2#B2}psccH%~J%%)$W8?*VMuyJmAW}ybInpQsd7LCaC7nVcz@ef;+!v%Prb4A! z+r`<+8>Hgza6#QWxH4kM1?*pl=_{u2jgY=a*a`=11zg8WkWB$4l46<rY9T|m*^q6r uQvHZ>js6`}M<jb?umD&k9LFr3G0dS(cY>Azn5RESwjvhLAXrs6eLn$0C0Zr` diff --git a/src/main/java/plugins/adufour/trackprocessors/TrackPainter$TrackOverlay$4.class b/src/main/java/plugins/adufour/trackprocessors/TrackPainter$TrackOverlay$4.class deleted file mode 100644 index 7b1497261f426535cfe5942d43016f37fc73a535..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1393 zcmbtUTTj$b5dIFkQYeMJpsOOQs8#j`3yK%AUJ_PKG>d2;`@q}T?g5JBbklY*{1ktN ziGuOL`0PLM!D#e<80VCN6*W=Vq&;V5XXcx4F8%QR?K=QhFsq@5q1JJ_tG4v3yxm=K zyIwW$xb>{#xt8#K*Ym4ON`As^83@k|g@sMwIeg2U(U4>?4+hxe<mGU=T5WP~&UGEZ zB|~qpX8Yze0X7ag{4-*W!rZc@9o%7fS~x<S#ya2RyE!ffo-J2v%f%)`vhKD;KNtoK z97C^;1O^Rg7-Gm3{^FBr*it<1ZnT8A#9NMF$TnPyJH*{qa->Wu`V6-ZpR_qc^ao5X zUAeX4cKs=Z^c#;~OsLvynPGUv_QYO3^)>2@XfqV!jG{KxVgdJ5#iouCjA}T;kok!h z{cRwRvkXRSx6e)Pbg2Z1LUCEg7%pfy&oF!Fh8wsDlcA4WY8p+VeD^4ArzWecE*ls} zfnlh#JJtIop|r^$fs%ofC^L-5OSI5h7gi9jP^3|l)8{(vi2Lv#YDflBJdX?p7X#X; zdEN;}L#J_@R(Piv^hH`gOFXdE7-iy%H>nEGkh(7|$MtDo=S8sQQWuSfQVOr`aNifc zh8ql(|EV?wh_5sihnh!U2bNB&4WOHnH1v_apKgyxPSR<V%CDi9D)}84FG=n}ir&3s z1$;!B-eaMsfef-Fkq3rxob1%?1ae^<A|1sINLEPs$~I2FK(_P>dg2YvsdF2bO6AH9 ziV7$Z0_7+<;1ebGndC1N?kh&|Ee4$52hO8{i7>G|Ch69LY8Z#*()U!GqYNgZ3<gW( r_ZX?rvyG{P)L4k1NF?Y3s%T%u44p}$3tXcoOS&;!$4v^Wib200;=5@* diff --git a/src/main/java/plugins/adufour/trackprocessors/TrackPainter$TrackOverlay$5.class b/src/main/java/plugins/adufour/trackprocessors/TrackPainter$TrackOverlay$5.class deleted file mode 100644 index 8e4a2a969e26241a7c08063ed838303688d3c275..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1271 zcmbtTT~E|N6g{)MQYZzMqNpf}T4ldr0p-E0nkZnRSw+KUV|bh09iUjIn@+oipJk$u z_+WhYhxnlW2IHMlq@pH@O*)-Bz4x4Z?!EKz+q?Gw7I4czhN0H=qD@z-D(^%aeiT&0 zfVW?E1HUbl@&i?EX!{v=WheqCHdcEg@c6E?XduVn90%xeit@PJtTuV@!1q1DB|~4h z<tk^M2<yiK{+h8yFn3((hW8kr7ybjMzRi35Ajh>ZaOGxgz1U>PE%_ZW0ER&er_g62 ziy;dJh8e~Se~1~WyHY%jc3L86@RlbS?7H9P9%*;AogC)0e1^LxPuf`|`GXFZzTDmM zBQ>X)e$nxh3ssw~GmLGxfjG=(X^T1|It<0MqNGi=6yV`ev1wug7Y$rs7(L=kep{Ht zB?hZ?(B~%iA}T?)P+T`Lg{uaxFx)<I!!2BcL&aAjj3;l|Rb86A`>GMO1eG&apuXug z-LP;L(+tyTQLC+O(GJs^k`vwQe&6dP*^d22H91J}Dt0hwASxRF9D}(=SEMZ-y1LP$ z>8mlTOT#d-BHNy?Xr!KqaLcDUTaTm^!IH<763V~=f&EK82q1mwsHjw4y1y)+*E32x zZ5imN^8wmDCOb!8t5kjqvs9VfhxMB53`S_}BQM|+^0ZFHkrqZ_lSL62!)fx<yE7P% zaY%H6`+{uEWS8E+tnA_Z9xj*4m3>@4LLZJjK4TDH2=!}<#s0x!qkv+Zg^d#JGWliQ zx`bsWVHqlwKVYIl?;grW1PAG}7+5Eo#SE<(%%V!)97zJ^=(Xu=3iG&0uv#!Z-vLXH BMz;U} diff --git a/src/main/java/plugins/adufour/trackprocessors/TrackPainter$TrackOverlay.class b/src/main/java/plugins/adufour/trackprocessors/TrackPainter$TrackOverlay.class deleted file mode 100644 index 7fbca38c9758049c2a618310ecf5ef7642844dde..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17222 zcmbt*3t&{m_4hgFZuV|Amn4t`SP(%)fdEDU5dtbt5#%KaV4zZ$WJy*+HtueCX<MK5 ztthn$^+mN!)lyqaHqul@t7v`HN2}IHTP@aFwOXsys!0C7Gxy%j27+Jv70tbKXU@!= zIdk4K`^3IqJU~Qatm!rh)5PY+mil;8sv=s~vMSM%tVk!LwX2(xiP~5yl}M&4s`Yze zG~SesC5M`i1#4r;#^?r{0!$_G+6@)WZfixhA;{D>w_!=zAAu>~Ot3JKXk;2X*Pne= zbfr7<nrKtBK9=;R1=J*_;QFfCXk(0tXW(Ol_YvIa74n-Csdze`XsQOpY(S)%8)8X- zm(5+9UR{B|DpOH~<<-V8UZD%HFwwYSMl>B|>g@yiRRFSGpcGTF-#V*tLvzE}8EACe z#(B}^=2()cpAX^pcN+j$-~vvqO(y_X=);+BH0L$On_`$EJHS*7*i`2a1BkFf`19oJ zhc{NQweeJZWuyCPuskceHd@h=jyG1!ji=J+n_m^LZ;GZ{lomtgc5j~C9hDOS9;}Tv zt&L)+zH@c++^>q+wHv0JdO(DdKn|qEQnDml<W*^NOLKJs6xE$t2D;V7(y?0Im>Ka@ zGdPCnsO*OO?6x)v9&3y?)mJQuCZ}P)W6>rI<rpr>_A9M(N2rQ5x+5-VYQ%5_(Ux?= zaKTt`M%eVJZds`m4W=97siDU(9eu!*2J9dlu4I@TZ;Gc+WLiA@zw4TX{t9Luv4klw zJy93SC#JCuji#eRbR5$FZ>d8Ja;YJSrXi`=*)6fA+E|z@I^LlQngEU-?rx(YSXDY1 zZ>pa(Vu?+aki;H%Jxmj6vUWXz$r?UliB5WwLq$|<(^RG+uZz!aVVXjd6=sG*y{V5) zCxc}@7?1bEG}8r{?NAAo+H@+A+HV+_Tf;QRg`DqD8TGYkVb_Fn7tAnR9Hs>>OqE0Z zsJ~5%yGH9S31O;sAy0QGLIV`ZWeyG0alZy`@i6cPUG9Q@-JwHtPzZQQ7xPa|CZiiv zK*Dq;)hco7uqDH1yVP0b&>%Wghi`D`2pX!Tvm82-j<N{~Ym%?8eD?h+Uh1YThaMZE zCQzWNA+c^qRxnawT20N0#Mw-z{dfG<ZTLwC^2IWDMJb1d(Qunu{wM6mglHY)&0z1c zXqeK}tmN6~&<LI2-2Z8Uu_5{<Q>mFCWu!b-=LtiY&T(ft-=T7y>B9eMrg0&<7&A?U z>KL6;yE0^5Jl!y4V<NF8Oc%H_UFy(Co$2!bX{O^sbfv#0Pp+e>A!$`mVY<wn=^BSd z(Qu{XwGP=73e#q~-lp#`9q#km!PSXF-=!Ov`qanLp8lxvlm=5|_z0uMeKk_yH%-#X zwm6heVJ&^np#rybvqKJr!*nZcv*|WSqFR9ix;ylJx}B*P=3E$GA8V|NZ;YL8)XNO* z`U8i4ctCrNw*1JUI}d1CrYPL)P%kPBqqN<jpU^!JlT<7Xt1~UOD7GfCHfAIg{EUXV zuz>Sh)~t*rtD~@fSp3`sHW9`nuHRl|K(#;iE~}FNYk7qsu&{PD%{`I<?Y*kfaE+kt z%%nEm$27{{v;Sm1tOi6}(5x0RwJ_QggM#UcT~l4Pz9O{_%DrNash?!iFR{`C8^Y8< zllAeSL%Zl9n0yd!S|SM}&2*@1Ec~HXn(7L-)mV*RVUKgioR(NWH@YFw0@e61J*rx1 zH&cJl<V4q{E2bx!((v_S$w^R`I_={Q{hFR|r**qB4b17_*3EN$Iy2`}Sff$KI^L{g zylz^w-k<bIcP-E8%um?#9Mj-j^t=UB$J33mI(Hc%`Yot9J+WquF_`HzXa?DOmX25K zUUcXs`aL!>S_cj)&%p~lniEa2rt~D2+!gNX{7Rc%VH&jmUUqX;Y<dk#-G3z@PzsU` zXBk+$N|SB+6Y$GI&2GZ>pyiMBhOY6?@G^(b#y{26uhN?i{e|9w0|Iv(VCrM-*At@q zD!uK{->48aYgN3l(WZCzXN<Ygm9fS!y-a_1=zaPCbAZd{N7q1BN<Hp!9WKv*2-7<* zx&Eo-`iN;nkA%uGFbh_m1uqQSsp$O6p-(7`S=Pnk^$qFuTK8{<K2sF)>#@P>;&tf; z#per$_R^Q2M{P0&ClMk$vo3D@;-i39kJPSjiK}1e!a)i;nMNNJ(3O}fm78pzFzsV@ zSX8NmLDiW}swL{QI^b{~BT`ZA=}wU43ixCD%VD-{QkX*=wmIKpWM91IWFZ_b(CHjZ zcXFb(C8aZlxEIXl*ctHZTqXr^YJF+K#`GlgaK5sRf~OuV@F1k3XJYwYw5qQ9m9^mD zF8=W(Er&nV(~WubujqL|rG8IDMOW9?_LWw56}+L@SHp+*Jg$%E<Z=x=#`Fwyu*tQP z&4(bOS>AI;e{>A(s3-3SC<r&Z9IVx`B=oHx<19(9_F^2UH6Fr;+k6<v>~q>dfE_-9 zhhkU3KV5T_fN?x;)UQ;7%SSnM7#$9WoQFF+LVeCYRk3t+Lo6L#6iX!<5w|6pw0We% zqqMmg%?lgixs5aVXorn6AJ(7;e7<1SDtP34tixl}#~+A3(-Vz}<UB+e)d^FaX5!^& zQsKrqd>oGlT>v+`sktTXhQED>`zY&oR=O3N2@X$WL>Ikg!BVxP(Pd#GnReyFce)$v z6G?bbYuxrpI?-f@Phf;lC78$!yTN%)Zs=w##6kM1Rhh{X5IgWxho|WfN+yGA*9c)+ z&NCdI$%s$#(d>uEeX{FtYoMVN^c06@D@A(&bcqJd@y2+110o8ZP{4C}zRmL>YDU#& zqi2T~C_(dT5sxOrd>U8Tya*iRvxINoA&&=yuMSr;0+|r_Vo9{I<p90w5!mLXQ1ND3 z!?IrR8|Eck;~;)sj(u9`2E^Vl2;r8&OX4#eUZEPMBn7{3zZhHF&vZDd?dnBUYx*V| zN9Tj?E~hgcmKC3a@HaHw5{@~%itC}?*XmLhtWp<cnP)U}(FX8o9C!FEUX7(=Vh`tT z5o-=>E$1~3H*vyct*&h`p5$y@#n}!gbq@-?^wRVOWC_$2w7p~iw2;YxnC%2!`>l3r z%1Z?ldhpqbJToHG%p5~ED;aHWh}WjZ%$Rf#hp*?Ph_V>-Mu!LSp<zCkziIO~pwD|s zpg8<3U9SVaSm<Z0;O_JJ4qw2CY1A7u+vWL7YKgn-V$V^4?^=cVV!p)YZ!;a~v*=fL zaQITir36z>Z%HQM33Z`_p)Pm$3KbdUumjq$-m4tG+9;{IWOQAY1yf@Y0x)lK_*&gK zM;pz8&|vdsY*9~S88aiy*YgcFe;4y*9iFcJaQH^v0%PTR4RBdK(`<Y;9}HTD`FjrE z#5Z@Fc+3o@W4>aWYfWmaE6IiJ*DymlzAV>zW|_k<x0{%O@<}(ud~vcMT4BD9zp0NO zIBcSze9+hAr%n$}LDE(KY4cqU-_1V;J>2Q56SLPK={Yx1KO@$djv|`Ud<01L6L3<N zBGaO&crARk#Ohd>xARZoLGsTO^kg+!*YnRE-ob4^3VY^)sl(T`2)9n1aBj~!{%d2k zYoh6fiiHXItYhlJoPpEIzsPlM>tl&E$S5|&#>^NxBhdn9Cd@l&a&StiyC9n%M68iT z(}2%xY>YRja(g_$4=KVALwtwNz`qeof+xN14xq^IcK9)VTq&B2Hl-R(4lxgaDqijU zgu_oVB8O14R@2g&)|=90%Y9vpt_RIr`+j~_!B0}v{~L#&;b$>!9LepdaYg+A%uS@u z_UZxsJpaySL>ndw>)z_{3##w~O|kW9n_v2W%3xKjehnlp%rElG4!^>$!rFsTvT~%^ zDFmKApBtRBX)AF0nfwQb|ETgCNFn;xiq{=}gAq?y7)M29cCL!f8k{$w^?miwRND}1 zO0-0ibrq@RM7kn7dzkm|TMqwK4N!hO<$KJi{hPz@Xapa?B&RFbdk+8Iuc!g<@COe6 zL$?v3GnTi9|LO2Y{4ofO9>yC1{rqLQAs3t#n2ziD6Nf+Le;euYAxm<Y*K}5UjzK?n z_zOiY98bCV;8<Ngf61LT@AK_=c5Fv*$N@XPt^r%Dsr)RTx+7vdu^b5)VgkwPe9lPF z5nDqVUZ2koNKmW7jvz~dstsBd2F6n8NRbqS8mi`?x^l3sYKS(+47S%vA4f_wNuzF} zpMud@%N$<E>p?W>=SY8vK>x!|rK8CBR-KJ)QA;<#9dmufequUl1a#(38R*C%MxsD% z6;Lp#9O}qmC63(?P0a^CB7pDFa6!>AN&Oh$ubD3>&BjDsbwe_iYDhF<>VlNfG)pyj z!?NLNN%OIq4N(Ffh>$j8EJg|=C+av*bzsthlv3y9sCOh%=Q}WlXmIPhwx~x{k{w|> zL`c&dqM`DztTWTI+4DpWox|A)(aqEG`$-sR(gbn9a_}d0SoRUw;SVY{O3pfvpwh*^ z`;e3WgZ?K%4u(jjBa>t@Bu^y<L3=U^ClMm!Im~X=q_CVQQ*1d2-cz>*N2aPg7R)jU zLBmX8nJzPJfgN;RT;sIOgU)y4WSNDfrp{J}J}`X7h#A2tAy*{_ryT7UhWLdVx1i&l z=Ex$cf|##~Bd2Zj^bD<E?8p*Xs`b(JT93>IT)Aqgab%f#1VwH-Z)#(s@#s^we64E* z#ssCpg6zF5UkBfMD_h)@!ZB8?4*p-#Xu+_opvfUwsXl=QJLt1Q>Kuvb35i|hCOfpQ z-jN3NQp&W><O~<A%0}raH2|;M0(aF*f^`$Jv9N`EWQ`+DzJgm8ma{~2^>Q|5RwIT4 z2&#hm2<xN8k+nuiY{V*Ly(1fBBNnY$pJZBv(JayLJUh%^%DIkwLv>FO+r0>R2~>T{ zk@K`lb>^&OEY_rz7dUdER%$M18XR$5-o=i5TX8AwnxML+xiL0YSM~>6E`zvwG+Y=> zf|qb!R9n@IxDnkiMXpUQl`9>&O0EXGfkf^GsD}2r&8<<FK{g>CK47quTbj)Io*UwY z<r*FI8rkf~cjS7P?p-tcz$P(y(4kaof_OJLa-*)dH#phfI-fzVk*$t=PdBy@STD|r zkTLhoj@+WG7F^t12QNa=xy_Mn@_nokW4SS^YU`{>`KMnntW)F;M}8nbgf;}Mna_=o zHF4&nte%qALI{5(ciD0$c3}TDNA4E*cVXbC?jM3gP$NrL?QJ-D(umo%z{%_F_1A#q z<ai_0T3EI#Ew}SHJmg+Sel9!QU0M{ai??7n6<CmJyJQ?`*A?ea$7!_Y1e&yVrz5{G z9(oS%SH<ga@_@!)I&!~uDK#}vyvf)SuxK34mD~Gfg}O~e_aR3fmS2G&Q|sz-QU-7= zvuk!w(apwfmq#7hZRihI7Mfj$xEbNRKBmZ{x*d32s*e@=ST2tO^R@BVI^!mTWO_W} zudzTss{FJ;q4`>qNTeHZXbuttn{_WxDC$B+E1-%8_%#P;4>aayO#r0KzdUdd+cvfi z9rBExfjx+0QXFMNf^fj%PtnEVu5h74Xq6`!8fN>1%F3WG3E2w?Asx}>v^-rTtXhfR ztvbsS827jw<Dy>Te`r@|qTGu}Q{HssFY0Y-qzNSq8|TtiJ;>ka23@H<eKU63y|&=* zLy`OGhlrrK2Vk5i-HD_*r@>LRyzj_+$^hXtiI!AsdSkp68n!COIf|`?;jWmctuwXg z#@lIR4J*uky0OS{ez4&-?;ocrw_&n>I`V=1BVRt2pe_G`@1X(aL5EVfaB#{{&!V05 ztY^^>w*NrQ*OzL(s%$})+0DxsBVG+1jC@j9_UZA&W=kB)QX*>XY@%Dww=ieQR-R?s zRxmei%W;AnD`X*WT+j?pupUX7bQRQhzKMrmO=g6x0;`v8IZ!CZO*N+44Y`nou?kg( z%*b`@-8LwqeO9q!^|t!J^dd#aG{K{{8NqY^UDnC1$sNiA!chDN9k0x>`da<4jjQ6x z6w>DDB<@>u4@p3jp{8L{ffYf5%o+fq7{m?Tvdu80)*+5HNK;Y;DfNQ&5{D+?H(P@p zYlw2op_nFSsOhHS7y1{F+^i2o4-z-9%QZZJiGXQbgJ`3)HAViFoB&Zma!k?4ae2dF zvbuO3tOhu`BuCOb4nU`%y6C!T4C^!hK#<8fMD{i(>-l}PV~V7<H3~{48=vgILSSqp zYH33();P~S6g|CXu`(e4t87`vIM!(E=xz>q4o*39xULFztQmAG9zJ5Zue!7f%Q_C* z?(0C*;0nrr7rS@A=wOb4!>;Ottpr>2Hhkk<Q9D`*2>mo0>E`70#%L-POW78-&g7mB zR1MfuccW|z$>x4p@^_CtY-<V})o#2EtKdn6W9IiRztLeh#<uX6hZ`+@^h6&@M)a`V zyb(m2HxAm(8|U75_t7gk=8bDN=8d~G=8c;(=8fAi=8d~A=8c;#=8X$3=8a1$m~$}7 zLPPL}vj$Vf6&CZx1r`H`t03l$8yn`0`xNGl+YaW9y9h+Z#d<FZ-$fX+f{wxSSR#Iz zf)v2pE+5%OW6JxCYp3z$9W=3~ohG%>i6~A%aatQqM{y>Kv)bqs6z8Bgw~gkZxB$h| z+Gr7q)hI4$qorK{H7G7e?HO&f0>v|H^4e)-8^y}Gjq1y-Hj1NmbxnDnHGy_Yv{4eD zX?(85=lV9<fX{RA`3<X`zSTzO;qwA~UWC?fx6vi|ybPaL;Pa|By1IN+8*Lhuq3h<4 zevHb>i`wW$eQedoO|3Mrd~}9x(Mr7U(0aUE(WH3XRc>YI$3FvsEcz*)-!z2(2e$k} z+@<&tw&qT3z+Jf5aW@@LKc;E8)G&|kq0<3fOZQTO+HiTMoi@-f=u&!wZlI@eY2szn zzJ;%kaHRe(`VD<b&*K#JCHkCRqc7+UoSnW&o%9|PeauXI*<!}=Wst+9m<$0f*cy!f zb9`w@Sx+#|MB0IoEy|#}FG(kc3D^qIZqsHP7c;=9Ogn*#*=E^`o?uSCq=P!J8~4v0 ziKO5IBRlBfnvo#wBN=*3TRP}Tv_9QVznM3xgPyJF^L#t~P60vG7nTO^r<ZH2@*R|{ zstMq=p{gbiuk)&EDuWM<&$Gq{TB$J-EDMa8-$Acppg&aF5xax_Sd&*A&I`5E>ut0r zV&}EdUorYSHK6``?evd`ouLmSHumV_h>e~26!o9)qJ5R2NGOnj`V3{*vNCLsG9?3k zQGm+=WqI2=H+M&S{%A$JgdGoW4E4g&JRk2%T)eLa!uA8>gVy-GR!T(dvb-^s0Uu*b zx<AGt#TWy>QxgezD2Ei~kU=@5C~JekIX{wbaL)H|9v#sV5T_3>%Hy)Uvf#GPO(T`T z0*1{lSDEHQ3ULwj;$j-Wr8I)eXgv3&$=sjnc>p!@A#^?uqD%Ntx{-&_EqoZ=!H3g! zK7xMELvfAdNO}yg&v7}u&Lio495#N;M{|Ua;lp_hkHvozc^sdLW5Uz;cpOnp;3#V9 zaR}JVllUCKUd$&NmRseriN|swoNg2XGn`uR3NA)Ts2+Z0Z|(!;Yo?`K0(@=S4!p~N zafn{0R_+HlizBqszy*M5je!es)Pu_hwuF0M0dKSjMsvp)07|$$Be;s}!ViF^RYpIa z0-Y2k+c0{Ejmsd+HV-67QbQ-rqENP>Tia@63vrO+N&-lO>>&o*Q9d%mgH;KQY~v%r z#wQjRXLy)jC`aLx43BnS$LI@x(=$BQE1sC)<1;)7U-Psk!zX2U3QCK#Cd1RU2&SEd zcMblQW_XSZutIBGfE6A<Y$x`HbjoCg7w+OE89qJ3U(<>WITc@5ogjv7=BP>GIUv@l zV4L~W7e||ec_AIer_pF$grrFoE_znuICL?6otJ`*mf^DCaypOCpi4p4Yk4JopKHNB zb!OY4LzE`IrlB3Y60LBF^ia~J99<6>=p!1Zcn-Xe>oVLha0}Ux`hax;D(iPsU%VD& zxbcu%sX&W|C<QXy+@)6sz~B%!Qvs)_j9X|Juf-9<dK$|cx^y0m%VIJPa7O`yGORBR z!zzXq^2sWh!h69^KoRGnJ)pSZD^Og~h2n~Xp?EP+yc8&24iv8didO-}tN(vdY{{ay z7%Na(mw`N2dnmeg&?A$(!F`NX-U1xHN5y;-mGaFw8&#GiPZ`Lk<Y7%byHwzZ(KioM zd@%YU9<qggH+mNjsZ@ns4>iSue?W!hkw80dFw;V_--4zaZ`eu$QN9D^ttc0v+=}u| zH*BFH<qD*BQvuX&YNKa2<D)Zt4gl}El`3FQ`5ZN+J7`me&&%*dZbNUcLccP6nY-K_ z6yHLDpP{ac>9JljMmt}L`YzrFmzB5kHRS>L3#}Bvx~|(oeN=+Kvx~3C`mSr|tzA6U zgiFN4-zS^zfOPzjBK#w8&z&@se+;F%olfC<aC7;mbUObG%Isc>!5L|0I2<?wyNrK< z%>FOwCVmh}!d+0b4?`M$1tt3kJ;jgGv-}vnz>nh!+OKgB>`5rwr_IKUb4i}vm=E|C zz7-pSZQ$Ert98#m;B8R%7A{6U&MJKY!^<TU-b+Jm9&*GX#|G?vC7+XB29<?VPj^29 zJ8^{*`ch8w$OyWQ%JA*Cl22Ft0$n|F%*W>)69c8(+CPw(7#x+C;X5}?2#xIE?KS;E z?R-y$@9p4BO*`LLneP|E9lR4Y9hC*8{L6_>2R~3#SlBOgRexu-`)uc3m0kr#PE0Hs zS<1h{{~3N1XpOm#f4!5RMy9+^D{qVR*~!l_?cx_Jdq;X_`1h41k&+C*HonvvU)IVS zBPC^J8UE8Q-c#8((swtniuBF!U$#=Pm6u2I_2X@Qyqn?oM{4224F3z0fT29)xP=O} z{<E!w;f9;y77CBNm-hk^pCU?<+c<#HsS{muS?q&IVI+Tt<n=GAZ<CPwk#9bnk&(iT z^osNyJt`x;@mJbP4=J*NGd*<sMf&Zg_DDYuUHUP`&Sle^B4KTOTOW!(Ruj%h-~PcH zZ=yx0^bn&49jA6b#HxTxI2SQ|bVsaT4q`_}3d}O}fmzT`ANd&>FfvkrRkTvkMP*!8 zR#qCQ+txYRD{tF(F?L4=F>T$qTqVYJLtdfrkeKJGH~$ur@&Z)ei?AcV$FCS(K_veg zuI~I1ck=%PNqK|L;y=?`-h;d0e}-G~CSApEL1Ny9l)OV7{2o2b?}NYpLBHb<=?(rT zy~!Wp2I9x?Za=}Ty?=8le+C!f3m(jS`6wLk%@W~iu{eqoyL!pvq~vpp6!3-O@FwZS zo27_vm)?A@l<<SnmtU6w{C641pUWXorGunEhDf0tA;V;-jF#bYjO636<$XDs-<E|k z+DPXv{ICH6<V&ZV=1V6^+eCw_VNx!KL1HZ$jd2c#8x)}9FvAfj1?dDSMeUJraH@Ep z93{ixl6;N-h1rIoJ;v|J2q{OLa2EenMxw?6WuBE$n7t76c|?vzT@fgBom9v%_#H+E zUm?fJ7-01<UnFAzRZ5TY`7#crGElBTj+61Q>KD>>IUc2c#$j@x5Zs;<&{JKaTc~hw zC*qAFb$$4Ho3F#uvc%?$`G2Qn^8*$X;q!zzW3c}I<1657ei4v1bRzWDUK(igo-u`A z(EPnL2*odG<L7jkd`=<68^Ql*N~kg18u8TF4$z=Cc41=q4nA@h56Q^HjGS<vOoJHQ zh`+5W4>#4WE|pUfrwl8VIf*%?GPhLb4@=x93$GrZ2ZujUcb`;`4+3y$Mo!18OYwwS z`K3rGt9TH3sN%`*5QLv{MrF7|R-kZZWkIB%M4}m~jT8hkvdS9ow9+Gy{4!^!#05HQ zPi3!2ug9Q^=x&VPUFY;NItNXgA}Ic43tieFXVqx=ZNT2RT1)Suv{g&eh|*1~+a*z1 z*li?*`s_9;(D#R}6olHUEP~=F+#yMQr1X)_$hxK0_~KR?1VJy#$T^qj^PA>*{v{c? z=%QjSE7o}8&lfpd=0x&$$|X$OI>&d&rC90Zl}^M_?Q=zkT!ZgxbzKoBBiG@D>hG2X z8#1y*5xq$tw^kOa_Pbq`N9$4`e07exo!24TF~&W>vq+(S8Yvo)k)J6>ZIPnfZOX`f zTHB$I2QbP~Ej*Z!UHX2cl^j!tA$DmYBah)#laa@D)L$zePbiL0Di%*Enona-U3GP2 zm%92VO$H+!OM@XohvPjIB2+HN(FBOfG?_rNrIJ?3WLhI9(pou*z9m!W5}8U@$#i7Q zXVNyAML(2N=uVkU56K*QMCQ^{GN0a*1@u1NAIU;4hH5Cmy9|e-<+7NMktI-7i}^H} z&S%Opj>~dxmNR&Rtl;zH>wJ}*3Gt5d793*UA$7b%>iK?Yfbhrp2|0_Oku^|VP5c*W z=67(!_lczW3u%Em*&w!@3l;VaDU<VLfSfOb<pQXi3!zjllB1<kCdjvq8q28LFB3gA zHWcu`flwiIz^#R6P_jS)mS>?v@@N`=D$k)5q*eU5Q9CxR;fFx2L!rFZ@_q8W{1$z_ z#rMcc`5lzkCVJK=AcwZmPvr&BvKJB;E96Cai3$;uPL|&bGL}3V^nMv57jv8*l~?3d za^SqT$!qclxLaH3dif*pEady?MER4vjvgBAsq!-O%Nt%icRTg!q-7?aL-rl#pstph zKn2iJTI1;>o@>i;8)R0cR0d5nU@x6&%URQG{_;yY1W%5rMml&mD6BiFSI?u`a;YuX z*ffPG)Cpf&!^<vopuun{&edRY2gv2XPA&(}=4dQcShM$6YQtB<kxEQdxBJBYfsFjw zS42Ty5kW(FipW+)1i(!h*^`mCD)U?EL5Q>KL+#N#$Zq<HCO?diM7Iz89u*D5x5%xk zr#7Q&cRdAA_(o`2Z}byBJ^h4|r=QTfOFxCXji56b{e-u#p9&(u2;7ULK2rKH`YB?o zoI*3<3C)D3(M+m})Whi1sBn4&tNW`KRJquma?y{BC|2`S_)-0o!ad#P#BT(jl3Y$D zas`c)D`}iu4KsWVoh+MZzFdnl$jy|H>*-wiF68@0x>B~#H8?_Um7C};oEJX~;yi`- zb8;JGdK-O+_eXL&hvW_(ESq_RwDK7F5ub#^-q~^&FT~;QVjRvclb;w_`x>|uTkX3H zC~007hX{O%kvgG~&<TG7O9bE|9V+iYnt}+r%j8{1lZ}L+D?=fA4*04Jg&|F&j0_bR z<Gq;dPUH?XZ2^vRdE6I*f!(XY^hP?0!1~iY*6&0@w}-yOdRFIhEG>j*qcMm^3iZ1w z<fdKQ<?mf|Hj$?MoNU=aj%279C(qid@`{e$`qkO6h*7DBbMEL?3_wV6^Qq+{M~!Zm z4>c~^ikNOx%?|kpu>t(+kF@-WTmGa}J}s5c@Eo0yFJRR7!mdvYbjZG%c8e<2s&C3z zxIFb%WvG>I?ZKF9GVQfM-T1IIzMz%X!fF?IjycR<SwYrKhn?F^)sbGiX#uQ>8tPeU zY+do0tW|I8<6W(MTOaR^0>=3J<UT7fv9Nz({{S5Jl1Q+B;eA#Z+-VgpZKYlp6>wQW zS$JFLWxi4BJOf;7mE1ye^j*5s>Tkjxcply=4$H1$k0wLaDftZ1tc9FOAY(y@JxO`h zUHqY4Hf}9`v`X?z?8^gGC=XJRJVXQKVK}OfKn@;<96Ui$d5Rjqjb}sWuLJ*G2+q4! zUZlIhZ9kD$Xg7586L>!Z&HR%53HI#``YT{RMBgvuEw<!uJWSr<iFi+!_jr!HZ}$Fb za5}a%%loHVhgpX!Kk%v65!O%*W|6USgV__f&^ppc!O5Iw9c2xJ6hvv0XK@<nGUMpx z)7f;Madh=Jrr$7jrhqP_I^*a%bS*70j&3h{hWcB>F<v1LqdwLMSRvck4^2_IGn8Wn zciah{C3%gUqE7sZ*<=8%k+ytn^SO|yeZDvyW{iWK+tkh3{gTET5!>?_EU4O&gN!ty z6TehGpv{v`*sDFAkduS8!z<szomj>J06v<<6ofM9h9<^iJ+pH~jy6Ku;Jk(gfnP4k zanM3;Qbpy^s@Pw+KY~zyOl9&39U`Ba4c62v2JttT24RDbH3C1#-(VW#ZLlZ$Wx!*M zHP*x91Pq}1p(O8qYn(Y0Sm7qu7gcF;+f8Bx6$EDwUFxL7ov}E?Pg>)>p^gHyW=DeM z1CicQ*qq)tQE_WfYaOp`)&y%J-is(KA6u2yWWwc5>jd-OiIaMKTM_FdYiba`(4lr~ Y8lI~Gum95S3qL(}|6Sm{FLU4j2TTYfG5`Po diff --git a/src/main/java/plugins/adufour/trackprocessors/TrackPainter.class b/src/main/java/plugins/adufour/trackprocessors/TrackPainter.class deleted file mode 100644 index bdd3ca266783068259e3fa5acca8cb930244d83f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4180 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 diff --git a/src/main/java/plugins/adufour/trackprocessors/TrackPainter.java b/src/main/java/plugins/adufour/trackprocessors/TrackPainter.java index 1d432ee..8fd7a82 100644 --- a/src/main/java/plugins/adufour/trackprocessors/TrackPainter.java +++ b/src/main/java/plugins/adufour/trackprocessors/TrackPainter.java @@ -1,34 +1,34 @@ -package plugins.adufour.trackprocessors; - -import java.awt.BasicStroke; -import java.awt.BorderLayout; -import java.awt.Color; -import java.awt.Graphics2D; -import java.awt.GridBagConstraints; -import java.awt.GridBagLayout; -import java.awt.Insets; -import java.awt.event.MouseEvent; -import java.awt.event.MouseWheelEvent; -import java.awt.geom.Ellipse2D; -import java.awt.geom.Line2D; -import java.util.ArrayList; -import java.util.List; -import java.util.TreeMap; +/* + * Copyright (c) 2010-2024. Institut Pasteur. + * + * This file is part of Icy. + * Icy is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Icy is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Icy. If not, see <https://www.gnu.org/licenses/>. + */ -import javax.swing.BoxLayout; -import javax.swing.JLabel; -import javax.swing.JPanel; -import javax.swing.border.TitledBorder; -import javax.vecmath.Point2d; -import javax.vecmath.Point3d; +package plugins.adufour.trackprocessors; -import icy.canvas.IcyCanvas; -import icy.canvas.IcyCanvas2D; -import icy.painter.Overlay; -import icy.painter.OverlayWrapper; -import icy.painter.VtkPainter; -import icy.sequence.Sequence; -import icy.type.point.Point5D; +import org.bioimageanalysis.icy.common.geom.point.Point5D; +import org.bioimageanalysis.icy.extension.plugin.annotation_.IcyPluginIcon; +import org.bioimageanalysis.icy.extension.plugin.annotation_.IcyPluginName; +import org.bioimageanalysis.icy.gui.canvas.IcyCanvas; +import org.bioimageanalysis.icy.gui.canvas.IcyCanvas2D; +import org.bioimageanalysis.icy.gui.canvas.VtkCanvas; +import org.bioimageanalysis.icy.model.overlay.Overlay; +import org.bioimageanalysis.icy.model.overlay.VtkPainter; +import org.bioimageanalysis.icy.model.sequence.Sequence; +import org.bioimageanalysis.icy.system.logging.IcyLogger; +import org.jetbrains.annotations.NotNull; import plugins.adufour.vars.gui.swing.SwingVarEditor; import plugins.adufour.vars.lang.Var; import plugins.adufour.vars.lang.VarBoolean; @@ -36,50 +36,47 @@ import plugins.fab.trackmanager.PluginTrackManagerProcessor; import plugins.fab.trackmanager.TrackManagerPainter; import plugins.fab.trackmanager.TrackPool; import plugins.fab.trackmanager.TrackSegment; -import plugins.kernel.canvas.VtkCanvas; import plugins.nchenouard.spot.Detection; -import vtk.vtkActor; -import vtk.vtkAppendPolyData; -import vtk.vtkGlyph3D; -import vtk.vtkLODActor; -import vtk.vtkParametricFunctionSource; -import vtk.vtkParametricSpline; -import vtk.vtkPoints; -import vtk.vtkPolyData; -import vtk.vtkPolyDataMapper; -import vtk.vtkProp; -import vtk.vtkRenderer; -import vtk.vtkSphereSource; -import vtk.vtkTubeFilter; -import vtk.vtkUnsignedCharArray; - -public class TrackPainter extends PluginTrackManagerProcessor -{ +import vtk.*; + +import javax.swing.*; +import javax.swing.border.TitledBorder; +import javax.vecmath.Point2d; +import javax.vecmath.Point3d; +import java.awt.*; +import java.awt.event.MouseEvent; +import java.awt.event.MouseWheelEvent; +import java.awt.geom.Ellipse2D; +import java.awt.geom.Line2D; +import java.util.ArrayList; +import java.util.List; +import java.util.TreeMap; + +@IcyPluginName("Track Painter") +@IcyPluginIcon(path = "/track-painter.png") +public class TrackPainter extends PluginTrackManagerProcessor { private static final String filterName = "Display tracks on sequence"; private TrackOverlay overlay; - private boolean keepLegacyOverlay = true; + private final boolean keepLegacyOverlay = true; private Overlay legacyOverlay; private List<TrackSegment> tracks; - public TrackPainter() - { + public TrackPainter() { super(); setName(filterName); - tracks = new ArrayList<TrackSegment>(); + tracks = new ArrayList<>(); } @Override - public void Close() - { + public void Close() { if (overlay != null) overlay.remove(); // put the legacy overlay back in place - if (keepLegacyOverlay && legacyOverlay != null) - { + if (keepLegacyOverlay && legacyOverlay != null) { if (trackPool.getDisplaySequence() != null) trackPool.getDisplaySequence().addOverlay(legacyOverlay); @@ -88,11 +85,9 @@ public class TrackPainter extends PluginTrackManagerProcessor } @Override - public void displaySequenceChanged() - { - System.out.println("display sequence changed"); - if (overlay != null) - { + public void displaySequenceChanged() { + IcyLogger.info(this.getClass(), "Display sequence changed."); + if (overlay != null) { overlay.remove(); overlay = null; } @@ -100,22 +95,21 @@ public class TrackPainter extends PluginTrackManagerProcessor } @Override - public void Compute() - { - if (overlay == null) - { - Sequence s = trackPool.getDisplaySequence(); - if (s != null) - { + public void Compute() { + if (overlay == null) { + final Sequence s = trackPool.getDisplaySequence(); + if (s != null) { // remove the current legacy painter and store it here - for (Overlay layer : s.getOverlays(OverlayWrapper.class)) - { - OverlayWrapper wrapper = (OverlayWrapper) layer; - if (wrapper.getPainter() instanceof TrackManagerPainter) - { + /*for (final Overlay layer : s.getOverlays(OverlayWrapper.class)) { + final OverlayWrapper wrapper = (OverlayWrapper) layer; + if (wrapper.getPainter() instanceof TrackManagerPainter) { legacyOverlay = layer; s.removeOverlay(legacyOverlay); } + }*/ + + for (final Overlay layer : s.getOverlays(TrackManagerPainter.class)) { + s.removeOverlay(layer); } s.addOverlay(overlay = new TrackOverlay(trackPool)); @@ -126,26 +120,22 @@ public class TrackPainter extends PluginTrackManagerProcessor panel.invalidate(); } } - else - { - // overlay.upToDate = false; - } + //else { + // overlay.upToDate = false; + //} - // store current state of tracks (so we display it correctly depending the order of the processor) - final List<TrackSegment> newTracks = new ArrayList<TrackSegment>(); - for (TrackSegment track : trackPool.getTrackSegmentList()) - { - final ArrayList<Detection> detections = new ArrayList<Detection>(); + // store current state of tracks (so we display it correctly depending on the order of the processor) + final List<TrackSegment> newTracks = new ArrayList<>(); + for (final TrackSegment track : trackPool.getTrackSegmentList()) { + final ArrayList<Detection> detections = new ArrayList<>(); - try - { - for (Detection detection : track.getDetectionList()) + try { + for (final Detection detection : track.getDetectionList()) detections.add((Detection) detection.clone()); } - catch (CloneNotSupportedException e) - { + catch (final CloneNotSupportedException e) { // should never happen - e.printStackTrace(); + IcyLogger.error(this.getClass(), e, "Clone not supported."); } newTracks.add(new TrackSegment(detections)); @@ -158,8 +148,7 @@ public class TrackPainter extends PluginTrackManagerProcessor overlay.upToDate = false; } - public class TrackOverlay extends Overlay implements VtkPainter - { + public class TrackOverlay extends Overlay implements VtkPainter { private final TrackPool trackPool; private double xScale, yScale, zScale; @@ -175,7 +164,7 @@ public class TrackPainter extends PluginTrackManagerProcessor private final vtkPolyDataMapper lineMapper = new vtkPolyDataMapper(); private final vtkActor lineActor = new vtkActor(); - private final List<vtkActor> visibleActors = new ArrayList<vtkActor>(2); + private final List<vtkActor> visibleActors = new ArrayList<>(2); private IcyCanvas canvas; private vtkRenderer renderer = null; @@ -183,29 +172,26 @@ public class TrackPainter extends PluginTrackManagerProcessor private boolean upToDate = false; // user settings (detections) - private final VarBoolean detectionDisplay = new VarBoolean("Show detections", true) - { - protected void fireVariableChanged(Boolean oldValue, Boolean newValue) - { + private final VarBoolean detectionDisplay = new VarBoolean("Show detections", true) { + @Override + protected void fireVariableChanged(final Boolean oldValue, final Boolean newValue) { setDetectionDisplay(newValue); super.fireVariableChanged(oldValue, newValue); } }; // user settings (tracks) - private final VarBoolean trackDisplay = new VarBoolean("Show tracks", true) - { - protected void fireVariableChanged(Boolean oldValue, Boolean newValue) - { + private final VarBoolean trackDisplay = new VarBoolean("Show tracks", true) { + @Override + protected void fireVariableChanged(final Boolean oldValue, final Boolean newValue) { setTrackDisplay(newValue); super.fireVariableChanged(oldValue, newValue); } }; - private final VarBoolean displaySelectionOnly = new VarBoolean("Show selected tracks", false) - { - protected void fireVariableChanged(Boolean oldValue, Boolean newValue) - { + private final VarBoolean displaySelectionOnly = new VarBoolean("Show selected tracks", false) { + @Override + protected void fireVariableChanged(final Boolean oldValue, final Boolean newValue) { super.fireVariableChanged(oldValue, newValue); upToDate = false; painterChanged(); @@ -214,12 +200,10 @@ public class TrackPainter extends PluginTrackManagerProcessor // 3D settings - private final VarBoolean autoScale3D = new VarBoolean("Auto-scale with zoom", true) - { - protected void fireVariableChanged(Boolean oldValue, Boolean newValue) - { - if (newValue) - { + private final VarBoolean autoScale3D = new VarBoolean("Auto-scale with zoom", true) { + @Override + protected void fireVariableChanged(final Boolean oldValue, final @NotNull Boolean newValue) { + if (newValue) { upToDate = false; painterChanged(); } @@ -227,31 +211,27 @@ public class TrackPainter extends PluginTrackManagerProcessor } }; - private final VarBoolean trackTubes = new VarBoolean("Show tracks as tubes", true) - { - protected void fireVariableChanged(Boolean oldValue, Boolean newValue) - { + private final VarBoolean trackTubes = new VarBoolean("Show tracks as tubes", true) { + @Override + protected void fireVariableChanged(final Boolean oldValue, final Boolean newValue) { setTrackDisplayAsTubes(newValue); super.fireVariableChanged(oldValue, newValue); } }; - public TrackOverlay(TrackPool trackPool) - { + public TrackOverlay(final @NotNull TrackPool trackPool) { super(filterName); this.trackPool = trackPool; final Sequence seq = trackPool.getDisplaySequence(); - if (seq == null) - { + if (seq == null) { xScale = 1d; yScale = 1d; zScale = 1d; } - else - { + else { xScale = seq.getPixelSizeX(); yScale = seq.getPixelSizeY(); zScale = seq.getPixelSizeZ(); @@ -265,21 +245,20 @@ public class TrackPainter extends PluginTrackManagerProcessor // createGUI(getOptionsPanel()); } - public JPanel getOptionsPanel() - { - JPanel container = new JPanel(); + @Override + public JPanel getOptionsPanel() { + final JPanel container = new JPanel(); container.setBorder(null); container.setLayout(new BoxLayout(container, BoxLayout.X_AXIS)); // Create a panel for the detections - JPanel detectionPanel = new JPanel(new GridBagLayout()); + final JPanel detectionPanel = new JPanel(new GridBagLayout()); detectionPanel.setBorder(new TitledBorder("Common settings")); container.add(detectionPanel); - for (Var<?> var : new Var<?>[] {detectionDisplay, trackDisplay, displaySelectionOnly}) - { - GridBagConstraints gbc = new GridBagConstraints(); + for (final Var<?> var : new Var<?>[]{detectionDisplay, trackDisplay, displaySelectionOnly}) { + final GridBagConstraints gbc = new GridBagConstraints(); gbc.insets = new Insets(2, 10, 2, 5); gbc.fill = GridBagConstraints.HORIZONTAL; @@ -287,7 +266,7 @@ public class TrackPainter extends PluginTrackManagerProcessor gbc.weightx = 1; gbc.gridwidth = GridBagConstraints.REMAINDER; - SwingVarEditor<?> editor = (SwingVarEditor<?>) var.createVarEditor(); + final SwingVarEditor<?> editor = (SwingVarEditor<?>) var.createVarEditor(); editor.setEnabled(true); editor.getEditorComponent().setFocusable(false); detectionPanel.add(editor.getEditorComponent(), gbc); @@ -295,13 +274,12 @@ public class TrackPainter extends PluginTrackManagerProcessor // Create a panel for the tracks - JPanel trackPanel = new JPanel(new GridBagLayout()); + final JPanel trackPanel = new JPanel(new GridBagLayout()); trackPanel.setBorder(new TitledBorder("3D settings")); container.add(trackPanel); - for (Var<?> var : new Var<?>[] {autoScale3D, trackTubes}) - { - GridBagConstraints gbc = new GridBagConstraints(); + for (final Var<?> var : new Var<?>[]{autoScale3D, trackTubes}) { + final GridBagConstraints gbc = new GridBagConstraints(); gbc.insets = new Insets(2, 10, 2, 5); gbc.fill = GridBagConstraints.HORIZONTAL; @@ -309,7 +287,7 @@ public class TrackPainter extends PluginTrackManagerProcessor gbc.weightx = 1; gbc.gridwidth = GridBagConstraints.REMAINDER; - SwingVarEditor<?> editor = (SwingVarEditor<?>) var.createVarEditor(); + final SwingVarEditor<?> editor = (SwingVarEditor<?>) var.createVarEditor(); editor.setEnabled(true); editor.getEditorComponent().setFocusable(false); trackPanel.add(editor.getEditorComponent(), gbc); @@ -320,11 +298,10 @@ public class TrackPainter extends PluginTrackManagerProcessor /** * Initializes (immutable) rendering components and default user settings - * + * * @param vtkCanvas */ - private void initRenderer(VtkCanvas vtkCanvas) - { + private void initRenderer(final @NotNull VtkCanvas vtkCanvas) { // 1) initialize immutable items renderer = vtkCanvas.getRenderer(); @@ -357,14 +334,12 @@ public class TrackPainter extends PluginTrackManagerProcessor /** * Enables/Disables detection display. See below for further display options - * - * @param display - * <code>true</code> if detections should be displayed, <code>false</code> - * otherwise - * see #setDetectionRadius(double) + * + * @param display <code>true</code> if detections should be displayed, <code>false</code> + * otherwise + * see #setDetectionRadius(double) */ - public void setDetectionDisplay(boolean display) - { + public void setDetectionDisplay(final boolean display) { this.detectionDisplay.setValue(display); // VTK uses integers... @@ -378,14 +353,12 @@ public class TrackPainter extends PluginTrackManagerProcessor /** * Enables/Disables track display. See below for further display options - * - * @param display - * <code>true</code> if tracks should be displayed, <code>false</code> otherwise + * + * @param display <code>true</code> if tracks should be displayed, <code>false</code> otherwise * @see #setTrackDisplayAsTubes(boolean) * see #setTrackTubeRadius(double) */ - public void setTrackDisplay(boolean display) - { + public void setTrackDisplay(final boolean display) { this.trackDisplay.setValue(display); // VTK uses integers... @@ -398,14 +371,12 @@ public class TrackPainter extends PluginTrackManagerProcessor } /** - * @param displayAsTubes - * <code>true</code> if the tracks should be displayed as 3D tubes, or - * <code>false</code> to display tracks as lines (no thickness). Note that - * displaying tracks as 3D tubes can be considerably slower on some systems - * see #setTrackTubeRadius(double) + * @param displayAsTubes <code>true</code> if the tracks should be displayed as 3D tubes, or + * <code>false</code> to display tracks as lines (no thickness). Note that + * displaying tracks as 3D tubes can be considerably slower on some systems + * see #setTrackTubeRadius(double) */ - public void setTrackDisplayAsTubes(boolean displayAsTubes) - { + public void setTrackDisplayAsTubes(final boolean displayAsTubes) { this.trackTubes.setValue(displayAsTubes); upToDate = false; @@ -413,29 +384,22 @@ public class TrackPainter extends PluginTrackManagerProcessor } @Override - public void paint(Graphics2D g, Sequence sequence, IcyCanvas theCanvas) - { - if (theCanvas instanceof VtkCanvas) - { - VtkCanvas vtk = (VtkCanvas) theCanvas; - - if (renderer != vtk.getRenderer()) - { + public void paint(final Graphics2D g, final Sequence sequence, final IcyCanvas theCanvas) { + if (theCanvas instanceof final VtkCanvas vtk) { + if (renderer != vtk.getRenderer()) { initRenderer(vtk); upToDate = false; } if ((sequence.getPixelSizeX() != xScale) || (sequence.getPixelSizeY() != yScale) - || (sequence.getPixelSizeZ() != zScale)) - { + || (sequence.getPixelSizeZ() != zScale)) { xScale = sequence.getPixelSizeX(); yScale = sequence.getPixelSizeY(); zScale = sequence.getPixelSizeZ(); upToDate = false; } - if (theCanvas.getPositionT() != positionT) - { + if (theCanvas.getPositionT() != positionT) { positionT = theCanvas.getPositionT(); // need to check that because of the screenshot rendering which doesn't send position change event if (trackPool.getTrackManager().getCurrentPositionT() != positionT) @@ -454,61 +418,56 @@ public class TrackPainter extends PluginTrackManagerProcessor upToDate = true; } - else if (theCanvas instanceof IcyCanvas2D) - { + else if (theCanvas instanceof IcyCanvas2D) { drawTracks2D((Graphics2D) g.create(), (IcyCanvas2D) theCanvas); } } - private void drawTracks2D(Graphics2D g, IcyCanvas2D theCanvas) - { + private void drawTracks2D(final Graphics2D g, final @NotNull IcyCanvas2D theCanvas) { // need to check that because of the screenshot rendering which doesn't send position change event if (trackPool.getTrackManager().getCurrentPositionT() != theCanvas.getPositionT()) trackPool.getTrackManager().setCurrentPositionT(theCanvas.getPositionT()); - Graphics2D g2 = (Graphics2D) g.create(); - double zoom = theCanvas.getScaleX(); + final Graphics2D g2 = (Graphics2D) g.create(); + final double zoom = theCanvas.getScaleX(); - double lodThreshold = 2.0 / zoom; + final double lodThreshold = 2.0 / zoom; - float strokeWidth = (float) theCanvas.canvasToImageLogDeltaX(2); + final float strokeWidth = (float) theCanvas.canvasToImageLogDeltaX(2); g.setStroke(new BasicStroke(strokeWidth)); - Point2d p1 = new Point2d(), p2 = new Point2d(); - Line2D.Double l = new Line2D.Double(); + final Point2d p1 = new Point2d(); + final Point2d p2 = new Point2d(); + final Line2D.Double l = new Line2D.Double(); - double shapeFactor = 5.0; - Ellipse2D.Double detectionShape = new Ellipse2D.Double(0, 0, strokeWidth * shapeFactor, + final double shapeFactor = 5.0; + final Ellipse2D.Double detectionShape = new Ellipse2D.Double(0, 0, strokeWidth * shapeFactor, strokeWidth * shapeFactor); - double shapeCenter = strokeWidth * shapeFactor / 2; + final double shapeCenter = strokeWidth * shapeFactor / 2; g.translate(0.5, 0.5); - for (TrackSegment ts : tracks) - { - ArrayList<Detection> detections = ts.getDetectionList(); + for (final TrackSegment ts : tracks) { + final ArrayList<Detection> detections = ts.getDetectionList(); - int nDet = detections.size(); + final int nDet = detections.size(); - for (int t = 0; t < nDet; t++) - { - Detection d1 = detections.get(t); + for (int t = 0; t < nDet; t++) { + final Detection d1 = detections.get(t); if (d1 == null || !d1.isEnabled()) continue; p1.set(d1.getX(), d1.getY()); g.setColor(d1.getColor()); - if (displaySelectionOnly.getValue()) - { + if (displaySelectionOnly.getValue()) { if (!d1.isSelected()) continue; } else if (d1.isSelected()) g.setColor(Color.white); - if (d1.getT() == theCanvas.getPositionT() && d1 != null && detectionDisplay.getValue()) - { + if (d1.getT() == theCanvas.getPositionT() && d1 != null && detectionDisplay.getValue()) { // draw current detection // if selected, switch color to white detectionShape.x = p1.x - shapeCenter; @@ -518,21 +477,17 @@ public class TrackPainter extends PluginTrackManagerProcessor } // LOD find the shortest segment above the drawing threshold - for (; t < nDet - 1; t++) - { - Detection d2 = detections.get(t + 1); + for (; t < nDet - 1; t++) { + final Detection d2 = detections.get(t + 1); if (d2 == null || !d2.isEnabled()) break; - if (trackDisplay.getValue()) - { + if (trackDisplay.getValue()) { p2.set(d2.getX(), d2.getY()); - if (p1.distanceSquared(p2) < lodThreshold) - { + if (p1.distanceSquared(p2) < lodThreshold) { // draw the detection in case it was skipped due to the LOD - if (d2.getT() == theCanvas.getPositionT() && d2 != null && detectionDisplay.getValue()) - { + if (d2.getT() == theCanvas.getPositionT() && d2 != null && detectionDisplay.getValue()) { // draw current detection // if selected, switch color to white detectionShape.x = p2.x - shapeCenter; @@ -556,40 +511,37 @@ public class TrackPainter extends PluginTrackManagerProcessor } } - private void drawTracks3D() - { - double viewScale = Math.sqrt(((VtkCanvas) canvas).getCamera().GetDistance()) * (xScale + yScale + zScale) + private void drawTracks3D() { + final double viewScale = Math.sqrt(((VtkCanvas) canvas).getCamera().GetDistance()) * (xScale + yScale + zScale) / 3; - double tubeRadius = viewScale / 15.0; + final double tubeRadius = viewScale / 15.0; - int tubeSection = (int) Math.min(8, 100.0 / viewScale); - int tubeSmoothness = Math.max(1, tubeSection - 1); + final int tubeSection = (int) Math.min(8, 100.0 / viewScale); + final int tubeSmoothness = Math.max(1, tubeSection - 1); lines.RemoveAllInputs(); - for (TrackSegment ts : tracks) - { - List<Detection> detections = ts.getDetectionList(); + for (final TrackSegment ts : tracks) { + final List<Detection> detections = ts.getDetectionList(); - vtkPoints points = new vtkPoints(); - vtkUnsignedCharArray colors = new vtkUnsignedCharArray(); + final vtkPoints points = new vtkPoints(); + final vtkUnsignedCharArray colors = new vtkUnsignedCharArray(); colors.SetName("colors"); colors.SetNumberOfComponents(3); - for (int t = 0; t < detections.size(); t++) - { - Detection detection = detections.get(t); - + for (final Detection detection : detections) { if (detection == null) continue; if (displaySelectionOnly.getValue() && !detection.isSelected()) continue; - if (detection.isEnabled()) - { - Point3d position = new Point3d(detection.getX() * xScale, detection.getY() * yScale, - detection.getZ() * zScale); - Color color = (displaySelectionOnly.getValue() == detection.isSelected()) ? detection.getColor() + if (detection.isEnabled()) { + final Point3d position = new Point3d( + detection.getX() * xScale, + detection.getY() * yScale, + detection.getZ() * zScale + ); + final Color color = (displaySelectionOnly.getValue() == detection.isSelected()) ? detection.getColor() : Color.white; points.InsertNextPoint(position.x, position.y, position.z); @@ -599,20 +551,19 @@ public class TrackPainter extends PluginTrackManagerProcessor } } - vtkParametricSpline spline = new vtkParametricSpline(); + final vtkParametricSpline spline = new vtkParametricSpline(); spline.SetPoints(points); - vtkParametricFunctionSource function = new vtkParametricFunctionSource(); + final vtkParametricFunctionSource function = new vtkParametricFunctionSource(); function.SetParametricFunction(spline); - function.SetUResolution(points.GetNumberOfPoints() * tubeSmoothness); + function.SetUResolution((int) (points.GetNumberOfPoints() * tubeSmoothness)); function.Update(); - vtkPolyData lineData = function.GetOutput(); + final vtkPolyData lineData = function.GetOutput(); lineData.GetPointData().SetScalars(colors); - if (trackTubes.getValue()) - { + if (trackTubes.getValue()) { // draw the splines as thick 3D tubes - vtkTubeFilter tuber = new vtkTubeFilter(); + final vtkTubeFilter tuber = new vtkTubeFilter(); tuber.SetInputData(lineData); tuber.SetRadius(tubeRadius); tuber.CappingOn(); @@ -627,8 +578,7 @@ public class TrackPainter extends PluginTrackManagerProcessor // cleanup tuber.Delete(); } - else - { + else { // just draw the spline itself (no thickness) lines.AddInputData(lineData); } @@ -645,19 +595,17 @@ public class TrackPainter extends PluginTrackManagerProcessor } } - private void drawDetections3D(int positionT) - { - double viewScale = (xScale + yScale + zScale) / 3; - double sphereRadius = Math.sqrt(((VtkCanvas) canvas).getCamera().GetDistance()) * viewScale / 5.0; + private void drawDetections3D(final int positionT) { + final double viewScale = (xScale + yScale + zScale) / 3; + final double sphereRadius = Math.sqrt(((VtkCanvas) canvas).getCamera().GetDistance()) * viewScale / 5.0; sphere.SetRadius(sphereRadius); - vtkPoints spherePositions = new vtkPoints(); - vtkUnsignedCharArray sphereColors = new vtkUnsignedCharArray(); + final vtkPoints spherePositions = new vtkPoints(); + final vtkUnsignedCharArray sphereColors = new vtkUnsignedCharArray(); sphereColors.SetName("colors"); sphereColors.SetNumberOfComponents(3); - for (Detection detection : trackPool.getAllDetection()) - { + for (final Detection detection : trackPool.getAllDetection()) { if (detection == null || !detection.isEnabled()) continue; @@ -667,9 +615,9 @@ public class TrackPainter extends PluginTrackManagerProcessor if (displaySelectionOnly.getValue() && !detection.isSelected()) continue; - Point3d position = new Point3d(detection.getX() * xScale, detection.getY() * yScale, + final Point3d position = new Point3d(detection.getX() * xScale, detection.getY() * yScale, detection.getZ() * zScale); - Color color = (displaySelectionOnly.getValue() == detection.isSelected()) ? detection.getColor() + final Color color = (displaySelectionOnly.getValue() == detection.isSelected()) ? detection.getColor() : Color.white; spherePositions.InsertNextPoint(position.x, position.y, position.z); @@ -686,8 +634,7 @@ public class TrackPainter extends PluginTrackManagerProcessor } @Override - public void remove() - { + public void remove() { if (renderer != null) renderer = null; @@ -695,8 +642,7 @@ public class TrackPainter extends PluginTrackManagerProcessor } @Override - public void mouseClick(MouseEvent e, Point5D.Double imagePoint, IcyCanvas theCanvas) - { + public void mouseClick(final MouseEvent e, final Point5D.Double imagePoint, final IcyCanvas theCanvas) { super.mouseClick(e, imagePoint, theCanvas); if (!(theCanvas instanceof IcyCanvas2D)) @@ -705,33 +651,37 @@ public class TrackPainter extends PluginTrackManagerProcessor imagePoint.x -= 0.5; imagePoint.y -= 0.5; - double selectThreshold = Math.min(10.0, Math.max(0.25, 10.0 / theCanvas.getScaleX())); + final double selectThreshold = Math.min(10.0, Math.max(0.25, 10.0 / theCanvas.getScaleX())); // List all candidate tracks close to the click // => store this in a map of [distance <=> track] - TreeMap<Double, TrackSegment> candidates = new TreeMap<Double, TrackSegment>(); + final TreeMap<Double, TrackSegment> candidates = new TreeMap<>(); - for (TrackSegment ts : trackPool.getTrackSegmentList()) - { - ArrayList<Detection> detections = ts.getDetectionList(); + for (final TrackSegment ts : trackPool.getTrackSegmentList()) { + final ArrayList<Detection> detections = ts.getDetectionList(); - int nDet = detections.size() - 1; + final int nDet = detections.size() - 1; - detectionLoop: for (int t = 0; t < nDet; t++) - { + detectionLoop: + for (int t = 0; t < nDet; t++) { // Retrieve the "d1-d2" segment - Detection d1 = detections.get(t); - Detection d2 = detections.get(t + 1); + final Detection d1 = detections.get(t); + final Detection d2 = detections.get(t + 1); if (d1 == null || d2 == null || !d1.isEnabled() || !d2.isEnabled()) continue; // Check if the click is close to the segment - double distSq = Line2D.ptSegDistSq(d1.getX(), d1.getY(), d2.getX(), d2.getY(), imagePoint.x, - imagePoint.y); - - if (distSq < selectThreshold) - { + final double distSq = Line2D.ptSegDistSq( + d1.getX(), + d1.getY(), + d2.getX(), + d2.getY(), + imagePoint.x, + imagePoint.y + ); + + if (distSq < selectThreshold) { candidates.put(distSq, ts); // move to the next track segment break detectionLoop; @@ -739,10 +689,9 @@ public class TrackPainter extends PluginTrackManagerProcessor } } - if (candidates.size() > 0) - { + if (!candidates.isEmpty()) { // highlight the closest candidate - for (Detection d : candidates.firstEntry().getValue().getDetectionList()) + for (final Detection d : candidates.firstEntry().getValue().getDetectionList()) d.setSelected(!d.isSelected()); trackPool.fireTrackEditorProcessorChange(); @@ -750,8 +699,7 @@ public class TrackPainter extends PluginTrackManagerProcessor } @Override - public void mouseWheelMoved(MouseWheelEvent e, icy.type.point.Point5D.Double imagePoint, IcyCanvas theCanvas) - { + public void mouseWheelMoved(final MouseWheelEvent e, final Point5D.Double imagePoint, final IcyCanvas theCanvas) { if (autoScale3D.getValue()) upToDate = false; @@ -759,9 +707,8 @@ public class TrackPainter extends PluginTrackManagerProcessor } @Override - public vtkProp[] getProps() - { - return new vtkProp[] {lineActor, sphereActor}; + public vtkProp[] getProps() { + return new vtkProp[]{lineActor, sphereActor}; } } } diff --git a/src/main/resources/track-painter.png b/src/main/resources/track-painter.png new file mode 100644 index 0000000000000000000000000000000000000000..33283de571a12bdc0a1a87c395ede199ff040035 GIT binary patch literal 14115 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 literal 0 HcmV?d00001 -- GitLab