From a0054494bc71aff902b2bac8449acbcb118192e4 Mon Sep 17 00:00:00 2001 From: rnv Date: Wed, 16 Oct 2013 12:45:53 +0000 Subject: [PATCH] First stage of the "0021793: [CEA 625] Clipping : from coordinates or from bounding box" issue. --- doc/salome/gui/images/Clipping_Absolute.png | Bin 0 -> 23163 bytes doc/salome/gui/images/Clipping_Relative.png | Bin 0 -> 25195 bytes doc/salome/gui/input/occ_3d_viewer.doc | 123 +- src/OCCViewer/OCCViewer_ClippingDlg.cxx | 1193 +++++++++++++++---- src/OCCViewer/OCCViewer_ClippingDlg.h | 170 ++- src/OCCViewer/OCCViewer_ViewWindow.cxx | 95 +- src/OCCViewer/resources/OCCViewer_msg_en.ts | 113 +- src/OCCViewer/resources/OCCViewer_msg_fr.ts | 113 +- src/STD/resources/STD_msg_en.ts | 4 + src/STD/resources/STD_msg_fr.ts | 4 + src/SVTK/SVTK_RenderWindowInteractor.cxx | 14 +- 11 files changed, 1483 insertions(+), 346 deletions(-) create mode 100644 doc/salome/gui/images/Clipping_Absolute.png create mode 100644 doc/salome/gui/images/Clipping_Relative.png diff --git a/doc/salome/gui/images/Clipping_Absolute.png b/doc/salome/gui/images/Clipping_Absolute.png new file mode 100644 index 0000000000000000000000000000000000000000..943fe56c9a67ff20376cd7904e361bdcc5266271 GIT binary patch literal 23163 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
    @As!FSWB< zm1q6U9aR26QiS)qM_&Gc9RAGduj?SxlB8tkS1+OS=~ zkE>O@%`t@jx6UC4@$;f$~&QwEru8vl>3j~nEONCt`^VawG9=|G}%5mRc<+7T1+9~zB(h~k9 zIm`l?{XO-q$od=Xa4Z2GH=j97Y5=uRr0wk3*{PUYbxfQ$ZKmDjT$pPQ2a@yJwQFR! zH>iiIbaa^Gq*5Q0S5z!)yPTgKm}jMwp5ERV{j6ryj;@dN*qMhDBFCN}4Ikx$cEc)k z{D)DQE!omjdje+lYPaFl=4K=W?Hf04JaMk-eRs3{4)S-Eb$D3V!NE>ZQPD|b!ub@40cqjiY#krx^)Re<5bW;m=I7@ZyAd)nG<4Q>MhfJ1uOHI?XxG%T zq&^($i>S5L>yOs*%9=yZefG*7UcY{g5&cblDdDq(|90K|`@sA%H9DbL3~O>%wJCxLE&?2pDZ?nWNwUSy9xVPAfgL)-G& z7gr3{B;|^rp~B;ot#tmV^!5Cl{%#BTvby|pJs|@FRCb{`-JBN!nZ2H!t9+_r{mZ8> z%inO4|F^$rNB<}=K>UP}vjE4P#+#LQ$O1u}5FtaaT5Xdqy=oc+$em_HxZIHi-`60T z-nuJ89xgS;J?%;EIX5PGc35XFs2gpCf}SG)fBdGOx=;Hn{Ui#etS1#a`?Um= zazb<3kxECxah8Amh}zFO7FaTqs>Ge{(y;UEy1Ry?Bw)h&rV`rO>Ycssq;|rJxhpl}xg0+S;GK{CU}QFo)Wo zf#^OvyWP>-SxshVNNRV?X`oh6FP;>=9)fFPXRy$X#pW2?}!7#9bz1 z$-WO~XC8Lh?X2PT^?ck(4Hjdig&I{oi9B7sz1HJHruP=^S#Y1`bff|L)?xMbfj8P4 z_YRvd7-)+xJza-oy<3=srOHSU-1WBCt06%t(+1ZPmr{3O)rw$M= z;3ffY7?!A(u$BBHH5m%_Ow}8fy?=i*x)VErRDYuTsAuxo_Jg@_%4c44CpaVCdPD~^ zvwr?cScELvj1M33Y_(q_2;M(f{~Zw#0YsFMq2ck-33@LkJ*F??PhD0RMhvn6m=0@q zuR6E=yp)v5;--rq`XwN-e#*$OU*1X&`ArP#Ydl;^=YU0rhVtBapf&-e1t?bpa+>96 zs-tf?NqhQxYimGIQ1mX4@DRI2(&bMM*47pl9G}fWjo`rBP+q>LHpTHM#?08bU6`mbN&WhK`eQ$P)8CW(R8${p zYfqX3Zbj3})Y|R8Z*05(3bM*#44Ep;%);`7lT#Q|CXsJty{?MG=qKn;bExf1TD9dL zKR%~IRO33`&%b*!0O*5?q`v-s>IV*v4#0QbLEdk@4@zJR{<7IbOfrj%(u?S1-4ZoW zz*aUBr7;u~6l8ROI9GoGLe(wvh;HJ!lM^9?zkx3mCU45d`g#Mq#{xihPft%{j9$$e zv#hi<$^fKVsmr@~1RgqskriPKz?GT zpT!-YoSdKw0q}tWSW2;U#*w=(-RHk~0el)$1&%-by?rH!b&_>90Tj0PIk60$x;pAR zI#=Pw|6lQ$;MG8F#tRRDwBDuQ)<0%KTyb4Yj~@p=yQ8A6K3=Htgd+TKW$*zWUi9kf zDvavG?!#)#rQKuTPJeWE&ThMaNWw`X!$^=6AMda}?g)c{DqNHK$(q6loRFhS5yW>; zwjMJwGBQ7!s(GDLRrMsT*V);*$?N>&_`@z7dVsEc6upg2{A$&;wTZn;bNZSL_)%P- zW8t9-$%16NDA2ty8ZM1iNWzPP5|K1=9>x~l{sQw3`W=F+FVUPqkV{4{s~dp`0_9NV zd*bo#BFvh(sW||AED$bN{V!aBiYXkM(Hld@mfU!#>ZhZrJ}h6>QDIarA$bpNAD2 z%ZLQ*`uYa-ihKS*#18wezUoH*x3uFRS@@KfuAhgw;UASLX#8|J0^K7J73H}*hIcMp z|9{b%@gLK~|6u0moNIgm8%$%xbj5P=y6enS`}sixxILZ+&CksZf`p^R%*<@NZM$Q7 z3pAvUFPd%ZLG*ETNR|FbB^F%KxqhTTBCOFvHB%u(ACcY@jfFtMv=Uv<(8Vu^t=v$b z`?r)+to37f_@z~QIM?&?1#DDpGy_!PRpo>?6XFa+0seYA*$m`!cOOQID=&G#USp1X zywt;a^AnRXVvEFv%>XrFML7XQZ+SNmnI#Y2f&gTe*F{yK`v{$*)g#!%zz`|DdIcdM z&O43-wLg{v^T_+1Z3*Mab;POxTtt-a$m0T#S+Qp0r=lVO>x+6wB9)FeNEO_b`UeI` z2%m;^8x^ZJNNQ=FLt$$RSp$`-RjITSJQSNCfSOkM;=6F>Y>d>?=&d8tVG`e+m-H z%zh?6bKY3x$~PR;!gOI``iTzn1hEX0`ewkV{CrXb0zpABwUb^6)tj1zMsLcqs(}5D zgfn)Z($bySLXE}VBte%gU67D)1g*YQRK)0!Jjav}l{Hl+K{7mixUx0d0>P)Pt?lCC zVtacVR-N5Kb}`dAF$6ml_;yJvI*Y7cLF2o<%PXr54?PAyj9-~|Qr4V-n^WXvkS2k5vul!TO8MFjv!j@@9lx`MK6;$ z1gtG!@2X7MtIZEZSPOY^hoeIW=mnFLp2K-B0o6mzuosiB(s2wFb+cJ|T9eMLwFku+ zR5uiFP2<0M`EqQ0oSg`pH^s`>_z;v44x*6Q#-I_pG38q4wJ=1j%`7sd6>dYj(QVAc z67KTOojXzlEHy4Ge`32e+z$SN`gf%`iv$yNW>z6AO+jkyG>95JX4z>$wp4EZvNAFX z)ZM>8R$dch5_o;)YKyJ#8J|=msnPTFB59X}xh()WTe)lr#3ibaZhZTfw{J1Ilg=R- zE`V8LaZxdM2uScsi!on>+tJo+ZN(ZeKl9))v@jPgqG0M#!uCrhW+W5ua$oi-@EgB9<2x%u3-3*<=5#JltB z>oPq)!%1|zZ>nsXG#Ck@FK-4kw~vKy0&N8HIazzgr%x1oE)h15gd`*$LeK~Il*rNh zG#YP`MK(ryZczsO3$UgD`Rje@1>`R&w-u;+Ky1o(OhiC#@$&Klj-;ZzJekMdsLP!} zZl?zw&MdeX?3WJ6S*%$)e|BqdcV*gj%HqXH0&^vTiG_{|wHmOy3wFapL*vJ?c+64f zZg}^|7k=7a39LX;7pE1&zXG#BlhKEqoXQ$v?qj8fQ9NJVq75jv2(+IGGjIH~rBCZg znNCRchE}!l`}{eAfIV00RR9)B&JObN!W^oSafA zQZcE6E^uLI$FXSPVq!i=r}-`%R97T1l|aSJTr}hOjVewE6sZrx1d0!!{^CwbiHYHY z1Lofcf@VkAi}eHpm5zad(%C2w6|D4AL`6lxZMC?#$h4~Vnrb|A+WYdnXZ_j3B_;LK zAF`NFqxxNa;V1wd3LK#s1T-NbAy7X*ebNU(Vm=o*$RiJdu({dUSpeunJa(C3VLdRR zq9H^I5NZ+z4ZE-wBSqT+w2sX}?#uxT+rwHTt-cs;WAi-A0T>9ZS-emI*4C0x z1KIz3VI*x}V4$Z!&D<9JKDa1b8~Btldt<5TxVvxr`i8!;VrS@5q*8!j+S%FZ zYj!QXx2vOr!A0p!uq}>EC_p);&7|ZeA*QC+zCaop8W?B--V;b+wQUBTq6)|m;9}KM z6!V2dL>7Qlh9lf*;PlqLY^ZvMcg`s=!|%1YxcI%|_bRP*An~`YhmaUHN@`oBV)qh_ zew^tSNU+&~d7gdT+@j(yW#s1KM#krYcx4^+Q^h(VnXSz>xuE^W_>X~sosLLa`xlEF zm!6j&K0XARlCH`4>#U8{Wc|GwHbp9giMjb@^{f~q6GOv=|Cx+<8a4;#w=0&}e(`Bt zZS6(%Y&)1VQ@=ESY9@H4_YVg_7d=%j?518@Qo`oTc@mDlg*vD?9o7smARvt`$@BGc}0yQn0VTuHyizA-ljDm_QymJM~|$ za%z7Ii>WNl+N@S6#|bg#jw=5CUE>pm3y^^Qwo4FcuyrpLUODZ)C3YOMj_+;y1V59m zgr8_rvqeJ||NLg_8l4=%k|)~rEBuIkD3|>k)D7TC?Ir|xSwjD*(0%*fzeaIQG|1rd zZZaDN3PTu>DKbpml^Y^!H+Amd8ixSnp|+8xdU54^CBF-p#TRTd%Ml}@1(s{f4ix|V z_;!23;H&AKwGZ=d(@^B2tY6`$|Jp74pF*<#rC+32To@$;)C5ScLLExwt*WP>r*Q}` zpKJL37feHG&HHjaC`j#0MCkvUO_$2L(CeP5gL3&L!{v##jI3;<-SH0q4F5}tnyzn^YfJNos!W~}>fTQopW5Y!nhbYid-s=xlbzy@@9`~op{F+s zv?|zggPPJV$KO_1a6e;Vv6k$^@2N_Dqi_v$6WV-mG^(Do418nuyMaq2PM}e4b0@9$ zkZ5t1?Po@HwM%y**X8N-Wk+)rhZWeEyN_cz?wd$@c?s|gI(}J;Y!RamNn@RGKT6~> zhb&ze8{tY#zB~aVEtg+2LIvhPzvMF~n2ilRA%U-Oe_sc!1_%Y&9Hr0r@LL0Ru(63} z^cQJ1>~t0BJbL^%M>c`ie5BxS`xq(h6R)P3Q{WZYh(c=Y7tPj8aSl@ zHk0lLH#FxY3b6xJAf;So-q0TXlBq^d(z|y{fhi~`V5HPZn<4&&F7!o}5xWIqJ!F*V z#KaRYFoIT7w)$_T;Ek`zr1YCeMBo>eL9lbgH#T~KxD~1bW>ug}?fxh?KfDsd1!zq< z6U)jtf?8^z+PxCL|Fi~!Dhsw(_Jp6-P3H&p3*vb@EL`;W@8ghh_H|E&_I&JxE4J!S zR@}_duhGXHTK2^2J^5=n7%gl&SjOA zpcMi9+&b7Hc<&Dhx<#Z~oZ&wy$!`lGfXc8CXTbkMqdD-IvpNDF<>OO>El*T5Pe0yv zxsKwPiZ46d*L0ZCP#o~t!H3!U8g<9P9IYzRByA=T+>RoHK!+HxZ|xkI4Zkv2w%Ab< z2Un!X;OZgGx~j^;3-C}fP`OUTkO*kQX5jySZJPWaY?kx3SJ@z<5Ud@Q8@_xt$viuz znE%w!JKNi)Ys}@$pfXno3EraoC|G>bs8wx^uLcXFRZRUs+wyj`FA>F_rZ3|lYVYRhaZA$ z{=%a4AXh;+k9&Q?t-pWbH;}DuvovMMW2le?5~N3S=QW z`@I=O$#}s|H!8gal_W^y-&m!=`~&3zRH0xZiJ7IqajlmIF9+wNP)QC>PR&vS2|GLX z03_IdO3kwNhklt33=Z#Z?lE4_#{i;IO;WQTB>srS@0q z@rrM&lPC!{>hCAK(IjZM9ivc1pi>hBcX~e?p$@L+xCWEmZxR?72-+F20ed@pwNO9- z30Ke8ps)WLcvU4u%|DBam79m2;EMu-1r*b&Y8@V`eay@IF)_i%_7F^?b{cz?*QZ(FtefaB00X0L*A}lyKsZ-TlqP81SXp^6 zm?H-aUw(S}He{u}{e5pxkim@whQJ`kCT@KupSNIWiHVIZQfpXT>`r1NFh2=d`S$G_ zW;(EVK;fOA9!-N59zrQ7aR2@S_&VW_$=D4#0z=7lXK*XlU45bCcUYTR2fh*HeF!4M z;Q8*&O4cYh=?6g;{1bPOt~IV=xRl3vz4SME0wuEsOgMS3DCb<|M}d0e<~b{4yT&q% z$1mxw-NwWOw^h;S&+_MB&+1Kr%B3Ist z^|7)C3=GTp?AOpW)uo(jTlLwFS;FSfg}@Td#>^}$C1nn~qtf~}#j(;nFelCy(?Aoa z7Zildxd2_0+Tbos)BkfO;r#EZR+BA|=A0&W^5Gl&jifu|LI|+jx3{)~1O5*BHs@h3 zI9I?Zq47(?)ohNV?ZoY5fwJok67PX5pZCQX3<`Qa1nlBHhDUoxM|-PQDkPi|Gph)8 z-0E;k2K|H8J+r9MigI$6=I0&2jSsw*cB6+H2!=rAw6$S;V$z5jCZ!fedHAWhd7N|Bn!L3w0iV9I@&_V9(q&RrHMNvy z?mg4fmu>r`j09aHZ3ngob2)Np6oOvKl366nq|&K;JP#k50(*fjbaZsIY_jIDan}cv zt-plX(rivz{-2b6i-+IzPv%3VY>UwGaq3rVBUEGeO3TYFs^>xIO&ay5n*j!f-)_F+ z`#Ze3KYu_In5-Y?<#ZJ#r7nkR$=P~(ee!YHAO?BZPc-KIU37FIu=hvX1FDMax}PH! zLS%cgXG%$#23s?njOXru@XM6m{l_n3U5WvoObPGr`fSM$j&8znD%Nhav$I2D+SW_} z8vsB};L#&9AZVb#G<7|PY)pl@bNGE}7tUGeNKtWOjKw4H<&>9{@OaGIjGbPdf$w+{ z{54QAcas)J;8y3vEkW0ay`9}f%~mgTWf%^)zOCe3G0}PIJ?kxY>3lGuM!d1`{HtL+ z79Hip{O3D7{0_@~;KgZxq8iE*Fx*0;2*}|tUvjarDV(@Z8sN-t`X+-kvNwn;G&L=Y zAKXe4`MJ9KDI1$@+a57=6;xGJh+smgJP!70Uf%J^ZqKm+Lxb7BfB%v{bKcz^RC@`8r(`Epnp^! z;R-e%E_QY#V*OR{0USdDCiQaTO$rb?Bsu|U?5~Y@gX?YVJm^jIl6%tmbIf;GY|Ixs zJQs$I2I>vLwcy-3`e8#$o3X)PJEuQU5SO5!k^yEzxtKJ6n%TjL95CS)YxxCci(Yh{ z5je^9On;1ZrdK^WZ?U8!YgzI8HdBVAY`vDAnu=cxHXWC0CTUtn`he)c2h7%2)%=%hqW78g+ zQ0Vc~Fn2fCDe0z_g@yYMYhZRD&43h&b^}|p!OZar6O-7G9q#VB+g$o^wDWj~xJdCn z44?i%_-iz^GOrtStk2cr^bMx({;k<7tp_e>KVH!^NorByO@qzzoGQeksJXbh@bLaFAGr)`Xl-c~Q2H z=OEWXU7jh=0C5d??)xhayvVnm1~<`tL9FGmUj&~Ye)~4`-*G4LgW(?Tf!04&z!Snq zLQ;}cmSX1)+;3<|$OH^Kg8Butn2Z)`fIk}Y4>5+HP|hF@4h|^xNCcExNX+|mbn)@= zFryN6C~roTrYUp5OXLjXR)%*oML9){5vq^;7pT(iOT~uVA`{Di!hKvkEz;}43pg<{ zdVN-60|{QgFa*3{(P=n?Y+HZ4+i}}mjzz8%CAb@j`S9UmYJX+rmnNJfNO3B}RnI^> zr8gOe6E;#@N@Hy+vgLgJv^_24_RX80`c0s2TqIb$)I2i=4ir*-9E(mW8RxM?58l7W z=jtnIWr$Xc$`fHu?-I2;4=W01T=`~ z+2&0`XzT3+ixk;XWCT7fhtT5WPhft*m?o-tJNg?LaHthS=HSl;oPym#FB^XZoOw9( z6;Kii8gxW3uWG@b%j84(xIg5a`bMMEa^@w~4ZCjiv_}E}Y`Gk{0AW+$Mfh>gvk9eS zypW~`n;;hydyI^KK|h9`4B%-u#w#AHg?!VEXzh@e{|Ap0WM$o-{0!zs2;X43NRe%4 zwSWu<#>ga`8^U6x62DpB68H{0;{B#)ZtjV4xe#g??86lb*azGdsIn(YR~?$ zzeD<~0s9pW>XfBfqV<=Skpa;6#9tmr6xarfJt;|1Q8W+zV3~*v==(-Tm+Wd#eV)Sv zEB1oV3JBm%cA~(C4U$uOCUHP*=8;7Sx z@jyV``AZbBHc8Lurtvv14~(j>+~|c6nCak^Z*bX0vhR+S8DFu@CDrNadXOq0AFk!6 zkqNvH4UPGko0rGyc~YK~l;ltXoGY|s^0Tr=@bzM&MBMHt1Qi)G{q5VgeP8;AZI?k_^E%0Tu!Qm#vwT{WY+yl97>t>mUqa=j3z&21$5*@pp^^ zt^-3VRxLrL&dkm}fHvBl*IG(S_Apd{uQ)@LckhBcdc|qu$boCSg4b=c>q6C*jM(e=f09X(W*&EMT ziK4LRqb1V6YAIY>{s}%%cSzmtjSUSAWo7nYM}TQu)3mubJGPll#{lEhJYT1&-u*3S zpkD11m%j8ChG@u!$wCL_w~z9qSL|y<^ogh!_|D!4rB_~6&QuS!Y^SZRNYf6iu$FVW z@rPG!jyyiEeVwF=5_J2UMRqK3QTn|6p_jkloynT^o7&FJNAQ>i6!r(v`Qo#Wy#CM0 z+6PI``qbhzIx;EXV|O0-J?jH1cDYa20rUS{q5m)F;L)RLMvlHG5ikDnn?-&4^C|Ea z=Sr~(w>mt2;mtv3^90S3glvo9|3_mn5rMu)a0-A?PBVJr`3*C1IVtOE6rjMzO=tdl zv!r-_B`R-Fc0tL`%DbODyiczh^r3;SaznfwBVi^#D<|s)Iy&d;Z=0G;?mP2XNO7oF z48L@>g_3e{awbmV{JYnY1s7ioZ}b;v4ZKS?{zGG=iSG6p;W2dhx%Tcf=2^p0$UqZ? zjAJ)-=BiUc6~WYj-u=OqB^sHot4Jru^pmNBz2Zq>is0tn;i32W>ON#r@Aqe>;0TY3 z6Q;QndT_4^7m_gtM_FvsosU!`s;?j7|9H~Sm}{R4D8bmsh=hbVJ2Nwcj7M>?;eF`4 ziZ5T@hK2@6_f^jD32|`I;zUTnvjbA;`2iY(!V-cgttdHPSkjr8oDA}Kf=;~$tSNp?vawN{rSUg^fUff zylSWPTu~cDz56+%1!`rkgGT;+kokeF0~=k2-yAT!SiZj++^eE9qGPg#K}&=bC11A# z-t_O^zk?zR%~y-isW$%;>~W8!@(VR8aStg3ei?3kL%Y#=49{c0(zzpGv=^Vg@d6DE z4V+Y2`9NSa%21M$wRh%#Dh5fZ`*!RfAL%}6oE)D(D6^oW9y~=6avbdJ(5+aUt$iO; zA4+e~Mx8gN-U$+W&u>L~UmOD}c5!tF;1Cf2^mg~G4Y+>qR{)>z|Lns%hlzz;0PQ&j zhKAJsR@u|=w27YXZm1V>a_payI|>t(3!|BS^pUoqIrt8!0;m?1B2CxB4K1{N%Kx$T zFUp2}w(r}E_Atsi&m}OsrAr~rS)!7Y3knO@XJ%L(e)WOS(Rl_HAP8KU^O@C0)!-Tf zVJ~7Ao*Uxzd-r#MH#4>k#n$=Zw3LdWv2jj%y6yhzONpxX5aPkT85G!*!d8O+cMqC% zZp`dsOG}GF#zF)V`no$4z-B~@jS;AKDR6PP5}or{rO<#q0WOjv;OX`!LD;{K;ZgzE zi^u?A%2ot_=+yT3M`Ilv96-NJreZGHRU?{atpgVI_gR~P!NE??synoznK?O4;0G)% zg{}|9gISbyZJ3Wn>4?Zk1y$9j7Qa}*2Btl|$LqRdFqjk^9-elGuVrXRSwg}Tv<>iX z&e_#){eTS-Ld1hg%?b6n5>^g0@@MA5VDBKIBmG(i+Fe<%DV!b31-T8h?qn{Gb^bq@YbE3?~p!w#cxT((e?{Vpgjj3y^)`r zOYILXX%N4Sx)X=LF9MQ<7BWd$QX-;0lkz`*uDYKje86m6PHGB7x+o?NF}pAoLbKkb ze{c|wIum+t;2{|VgTwvZUFRMI>SAI+;2cy1R0fv90YVvgHVDyQ_UgR6RXBK%|3Mp& z3B!3K-KRNUDJ(lGj)vngl$V<;F=Dim*MS9nM?knj_as-P^rINw0b>Jbvkj~40d*L- z{7fA#PId=d+p#)p>rgWuvK~nEI5^lmWMLT@bER2bs?sA>$<|F54Za|TaLO-{bS>@n zCJXq@RTqXbUEyNrXyogGCKbcn%uMAgzW-GIKuAr3nA%_AqHF-VVgSKM3__bCO{BPv zj!x~@cfatUV|L)X#JrNvbHuJQb^;a%Q1Bd{=h|wAJHt|)zVN^jng;@2XR3fT^K%|+ zUA4;zo_fL2hX-23vl~iE>1VysJ^Yf;VJUI4DJ(Vc9IYK4r>wmE??~Zq(D`aKnZxGb zgf}>EQXEG$HC?VK<;=~^nN#k9NoNYc6-*m4{R?Psu#lC=UnMDDg%D#DOnh- zH|zvO#k%_2Q|jAY2HFT+rd)q%;;3xZ~d3J{qJsuiTsqYFfJdkz8U}WRfQBdu$Qv6v z&P!)WbL;C&EqxDB;r!E$y|>%7>-QdfUUo(Q^4M%Wx3w+dXdnAAVAlEPK6qZ{rJxf4 z;>jasW{N-DnQe-&XWB1$z4kg3k_5P+@8S1;7xPXOwSOP1HY7`sqwXN#+h>dfIy+Q$kNqZ`$kh z_&K+YhpvlDbw$iRn7^QVK&`HKYHA7&DKyGkaBH;9uKoRT(kM&wZ{tAPlmq7cp#unE zoHlCODj7wg7z8NC%c|xU+S;kb;noLpe@S+si)?OwnbY#5Jdn_N@hNNr*NCo^SdcLcuH@Qy{MIf^ISv0pNpG^hdBMxd~?Guv35t`%{01%#G^;L@;0>_99F?2 zgqTd2jD8D+Z|buYHJ(|1n;h|!Hf(3lAiw@>|DKAFZNbi22~*vEZrwdh7Sw*Rd;*V0 zkp!RbxxOmDMgBe0^A+Oz-7iZM=X2xIfm;N2-)4@z=)IQ{l6H5VEp5$BC23Yq2VNW~ zI2){fBY&NQC1*ms@hkx)EHLt3Qt2Z|@Cz-plz#?o=icOl=`x%{lN=QV8WTXF`hp8c z_Ko8eaxHiPP*#`x>WLj|SN;OkAOO8zd9SFBk^kpgNe9csyS-E3@m&;x8G^z1@ZGwa z7yUnd`?*r4wtWMAIwcAUtB~lq#@_1_fom6^_))&%2Q-<0=$G-oaq<7~*0#Ng^pejF z%8y^YWW0roMWNg*u3LBm_mi&EIqS2n?K@0(He_(r==3eI0lo~zniO_Xo_@uBVuQF| zwiYzz6YdwE@CHGnZ>byj)t5hBOYkSI2U!GGHVQhy-*10U^qgkq-bk}vr~0CM+i3K5 z85-pc1&(VX6A#c)Zyo&W8ny@yJb9!@0nSf^>X#e;`p_2qYTmsu<1~n#WP)BEG>@JH zhlNemI+_a$`_DOa{uGk6J3l{%4k>ut3x%WDS8lv2FM3znU#oYlk{?#7(bM7;s8_6l z69M$7m`;Pa&#{U>cF%<69`){iP+WTj@dqC21m)%b)yS2`L%Fx%wi6B#!Y6;Gyms#?)$#3`?{`QwrHV&27=G=NIVxs)FV!Yk+tNdTK4Li0Eigf+--8 zrzM%T1A){+ILYzWm{983GP@g ze`);vKjzvCA=^EWy$dD(7}1U<=i22T%yMZ0=bDMBDbyOcB;5&+`lG2C%2BNJN{ReR z>+_s$7&ewWOMhJpsS#Y=b%cnBXT)d%bmdX+PRBwPA1bKq>FQU8biQKJwQFyt!g4O; zt=R-U;p9|Tv#Gs?>(3>E;Ct{-fO^Q{`hldhG$BF3nC0Q{b)L0^c_^=7V*sej9-=v( zX`R2gS-uX$WXC`bZIX5bV>glccTq}e^6-;@dOtERiq%sDSI+a{nG81yJ}^+^=g^Q) zCk5v16Uoq zjF|T9DK--eG4;6upS1bP_Tm~KIe?~E4g#$leIt+^4RQNKE9w%A{zJyRURK}=aC zEIWbVBbgMkK<5w�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 L*qT+Dc>nPqHS5go literal 0 HcmV?d00001 diff --git a/doc/salome/gui/images/Clipping_Relative.png b/doc/salome/gui/images/Clipping_Relative.png new file mode 100644 index 0000000000000000000000000000000000000000..82fc137d903fea01adff06497984f9cb085c5ef8 GIT binary patch literal 25195 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

    343Y5mllRZfP*YK`;9`9M3nK6d7%xF1)eq%Sc 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 literal 0 HcmV?d00001 diff --git a/doc/salome/gui/input/occ_3d_viewer.doc b/doc/salome/gui/input/occ_3d_viewer.doc index 783adee96..647318992 100644 --- a/doc/salome/gui/input/occ_3d_viewer.doc +++ b/doc/salome/gui/input/occ_3d_viewer.doc @@ -20,9 +20,13 @@ jpeg image format. \image html occ_view_style_switch.png -Interaction style switch - allows to switch between "Salome -standard controls" and "Keyboard free" \ref viewer_navigation_modes "interaction styles". - +Interaction style switch - allows to switch between standard +and "keyboard free" interaction styles. "Keyboard free" style allows +to process all view transformations without using keyboard (only by +mouse) and perform selection in view by pressing "S" key. By default, +rotation in this mode is performed by left mouse button, panning - by +middle mouse button, zooming - by left and middle mouse buttons +pressed simultaneously.


    \image html occ_view_zooming_style_switch.png @@ -151,12 +155,20 @@ scene. Clone view - opens a new duplicate scene.
    +\anchor clipping_planes \image html occ_view_clipping.png Clipping - allows to create cross-section views (clipping planes) of geometrical objects. -\image html clipping.png +To start, click on the \em New button. + +Now you must specify what mode of creating plane you want to choose: +absolute or relative. + +Absolute mode + +\image html Clipping_Absolute.png - Base point - allows to define the coordinates of the base point for the clipping plane. @@ -168,9 +180,23 @@ planes) of geometrical objects. - Invert - allows to select which part of the object will be removed and which will remain after clipping. + +Relative mode + +\image html Clipping_Relative.png -- Preview - allows to see the results of clipping in the - viewer. +- \b Orientation ( ||X-Y, ||X-Z or ||Y-Z). +- \b Distance between the opposite extremities of the boundary box of +selected objects, if it is set to 0.5 the boundary box is split in two halves. +- \b Rotation (in angle degrees) around X (Y to Z) and around +Y (X to Z) (depending on the chosen Orientation) + + +If the Show preview button is on, you can see the clipping plane +in the viewer. + +If the Auto Apply button is on, you can preview the +cross-section in the viewer.
    @@ -218,28 +244,8 @@ on/off. \image html occ_view_minimized.png \image html occ_view_maximized.png -Create sub-views/Maximize - these buttons allow switching the current +Minimize/Maximize - these buttons allow switching the current view area to the minimized / maximized state. - -Create sub-views - user can select the layout and types of child sub-views: - -\image html create_sub-views_dlg.png - -- Sub-views Layout - - - Three radio-buttons to specify numbers of the views to arrange (2, 3 or 4). - - - Buttons (depending on the chosen number of views) with images to specify - view layout. - - - Buttons "Previous" and "Next" for possibility to change split schemas. - -- Sub-views Properties - - - Type of each sub-view: XZ, YZ, XY or XYZ. - -Maximize - the current view area will be converted to maximized state. -
    \image html occ_view_sync.png @@ -256,5 +262,68 @@ In addition, when this button is in the "checked" state, the dynamic synchronization of the views is performed, i.e. any zoom, pan, rotate or other view operation done in one view is automatically applied to the other view. +
    + +\anchor occ_background +

    Background

    + +OCC Viewer background can be customized using the "Change background" +popup menu command that opens the following dialog box: + +\image html change_background_dlg.png + +The following types of the background are supported: + +- Single color: the background is colored with the solid color + specified by the user in the dialog box. + +- Gradient background: the background is gradiently colored according + to two colors and the gradient type specified in the dialog box. The + following types of background are supported: + + - Horizontal + + - Vertical + + - First diagonal + + - Second diagonal + + - First corner + + - Second corner + + - Third corner + + - Fourth corner + +- Image: allows to set image as viewer background and define filling type: + + - Center: the image is located at the center of the viewer backgound + + - Tile: the image fills the entire viewer backgound one by one + + - Stretch: the image is stretched to the entire viewer backgound. + +Default background for the viewer is specified via the +\ref occ_preferences "application preferences". + +

    Polyline selection

    + +OCC Viewer features a special Polyline Selection mechanism, +which allows selecting an arbitraty part of the graphic area using a +polygon frame (rubber band), instead of the usual selection with a +rectangular frame. + +To produce a Polyline Selection, lock the right mouse button and draw +the first side of the polygon, then change the direction by clicking +the left mouse button add draw another side, etc. The whole selection +frame is drawn with the locked right mouse button. + +\image html polyselection1.png + +As a result, only the nodes within the frame are selected. + +\image html polyselection2.png */ diff --git a/src/OCCViewer/OCCViewer_ClippingDlg.cxx b/src/OCCViewer/OCCViewer_ClippingDlg.cxx index f49c43c8e..065ef91f2 100644 --- a/src/OCCViewer/OCCViewer_ClippingDlg.cxx +++ b/src/OCCViewer/OCCViewer_ClippingDlg.cxx @@ -33,6 +33,7 @@ #include "OCCViewer_ViewModel.h" #include +#include #include #include #include @@ -42,6 +43,7 @@ #include #include #include +#include // QT Includes #include @@ -53,7 +55,217 @@ #include #include #include +#include +#include +#include +/*! + Constructor of class ClipPlane + */ +ClipPlane::ClipPlane(): + RelativeMode(), + X(0.0), Y(0.0), Z(0.0), + Dx(1.0), Dy(1.0), Dz(1.0), + Orientation(0), + IsActive( true ), + IsInvert( false ), + PlaneMode( Absolute ) +{ +} + +/*! + Constructor of class OrientedPlane + */ +OrientedPlane::OrientedPlane(): + Orientation(0), + Distance(0.5), + Rotation1(0), + Rotation2(0) +{ +} + +/********************************************************************************** + ************************ Internal functions ************************ + *********************************************************************************/ + +/*! + Compute the point of bounding box and current clipping plane + */ +void ComputeBoundsParam( double theBounds[6], + double theDirection[3], + double theMinPnt[3], + double& theMaxBoundPrj, + double& theMinBoundPrj ) +{ + //Enlarge bounds in order to avoid conflicts of precision + for(int i = 0; i < 6; i += 2) { + static double EPS = 1.0E-3; + double aDelta = (theBounds[i+1] - theBounds[i])*EPS; + theBounds[i] -= aDelta; + theBounds[i+1] += aDelta; + } + + double aBoundPoints[8][3] = { { theBounds[0], theBounds[2], theBounds[4] }, + { theBounds[1], theBounds[2], theBounds[4] }, + { theBounds[0], theBounds[3], theBounds[4] }, + { theBounds[1], theBounds[3], theBounds[4] }, + { theBounds[0], theBounds[2], theBounds[5] }, + { theBounds[1], theBounds[2], theBounds[5] }, + { theBounds[0], theBounds[3], theBounds[5] }, + { theBounds[1], theBounds[3], theBounds[5] } }; + + int aMaxId = 0; + theMaxBoundPrj = theDirection[0] * aBoundPoints[aMaxId][0] + theDirection[1] * aBoundPoints[aMaxId][1] + + theDirection[2] * aBoundPoints[aMaxId][2]; + theMinBoundPrj = theMaxBoundPrj; + for(int i = 1; i < 8; i++) { + double aTmp = theDirection[0] * aBoundPoints[i][0] + theDirection[1] * aBoundPoints[i][1] + + theDirection[2] * aBoundPoints[i][2]; + if(theMaxBoundPrj < aTmp) { + theMaxBoundPrj = aTmp; + aMaxId = i; + } + if(theMinBoundPrj > aTmp) { + theMinBoundPrj = aTmp; + } + } + double *aMinPnt = aBoundPoints[aMaxId]; + theMinPnt[0] = aMinPnt[0]; + theMinPnt[1] = aMinPnt[1]; + theMinPnt[2] = aMinPnt[2]; +} + +/*! + Compute the position of current plane by distance + */ +void DistanceToPosition( double theBounds[6], + double theDirection[3], + double theDist, + double thePos[3] ) +{ + double aMaxBoundPrj, aMinBoundPrj, aMinPnt[3]; + ComputeBoundsParam( theBounds,theDirection,aMinPnt,aMaxBoundPrj,aMinBoundPrj ); + double aLength = (aMaxBoundPrj - aMinBoundPrj)*theDist; + thePos[0] = aMinPnt[0] - theDirection[0]*aLength; + thePos[1] = aMinPnt[1] - theDirection[1]*aLength; + thePos[2] = aMinPnt[2] - theDirection[2]*aLength; +} + +/*! + Compute the parameters of clipping plane + */ +bool ComputeClippingPlaneParameters( double theNormal[3], + double theDist, + double theBounds[6], + double theOrigin[3], + Handle(V3d_View) theView3d ) +{ + bool anIsOk = false; + theBounds[0] = theBounds[2] = theBounds[4] = 999.99; + theBounds[1] = theBounds[3] = theBounds[5] = -999.99; + double aBounds[6] = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }; + + theView3d->View()->MinMaxValues( aBounds[0], aBounds[2], aBounds[4], aBounds[1], aBounds[3], aBounds[5]); + if ( !theView3d->View()->ContainsFacet() ) { + aBounds[0] = aBounds[2] = aBounds[4] = 0.0; + aBounds[1] = aBounds[3] = aBounds[5] = 100.0; + } + anIsOk = true; + + if( !anIsOk ) + return false; + + DistanceToPosition( aBounds, theNormal, theDist, theOrigin ); + return true; +} + +/*! + Cross product of two 3-vectors. Result vector in result[3]. + */ +void Cross(const double first[3], const double second[3], double result[3]) +{ + result[0] = first[1]*second[2] - first[2]*second[1]; + result[1] = first[2]*second[0] - first[0]*second[2]; + result[2] = first[0]*second[1] - first[1]*second[0]; +} + +/*! + Compute relative clipping plane in absolute coordinates + */ +void RelativePlaneToAbsolute ( ClipPlane* thePlane, Handle(V3d_View) theView3d ) +{ + double aNormal[3]; + double aDir[2][3] = { { 0, 0, 0 }, { 0, 0, 0 } }; + { + static double aCoeff = M_PI/180.0; + + double anU[2] = { cos( aCoeff * thePlane->RelativeMode.Rotation1 ), cos( aCoeff * thePlane->RelativeMode.Rotation2 ) }; + double aV[2] = { sqrt( 1.0 - anU[0]*anU[0] ), sqrt( 1.0 - anU[1] * anU[1] ) }; + aV[0] = thePlane->RelativeMode.Rotation1 > 0? aV[0]: -aV[0]; + aV[1] = thePlane->RelativeMode.Rotation2 > 0? aV[1]: -aV[1]; + + switch ( thePlane->RelativeMode.Orientation ) { + case 0: + aDir[0][1] = anU[0]; + aDir[0][2] = aV[0]; + aDir[1][0] = anU[1]; + aDir[1][2] = aV[1]; + break; + case 1: + aDir[0][2] = anU[0]; + aDir[0][0] = aV[0]; + aDir[1][1] = anU[1]; + aDir[1][0] = aV[1]; + break; + case 2: + aDir[0][0] = anU[0]; + aDir[0][1] = aV[0]; + aDir[1][2] = anU[1]; + aDir[1][1] = aV[1]; + break; + } + + Cross( aDir[1], aDir[0], aNormal ); + // Normalize + double den; + den = sqrt( aNormal[0] * aNormal[0] + aNormal[1] * aNormal[1] + aNormal[2] * aNormal[2] ); + if ( den != 0.0 ) { + for (int i=0; i < 3; i++) { + aNormal[i] /= den; + } + } + Cross( aNormal, aDir[1], aDir[0] ); + } + + double aBounds[6]; + double anOrigin[3]; + + bool anIsOk = false; + + anOrigin[0] = anOrigin[1] = anOrigin[2] = 0; + aBounds[0] = aBounds[2] = aBounds[4] = 0; + aBounds[1] = aBounds[3] = aBounds[5] = 0; + anIsOk = true; + + anIsOk = ComputeClippingPlaneParameters( aNormal, + thePlane->RelativeMode.Distance, + aBounds, + anOrigin, + theView3d ); + if( !anIsOk ) + return; + + thePlane->Dx = aNormal[0]; + thePlane->Dy = aNormal[1]; + thePlane->Dz = aNormal[2]; + thePlane->X = anOrigin[0]; + thePlane->Y = anOrigin[1]; + thePlane->Z = anOrigin[2]; +} + +/********************************************************************************* + ********************* class OCCViewer_ClippingDlg ********************* + *********************************************************************************/ /*! Constructor \param view - view window @@ -73,130 +285,266 @@ OCCViewer_ClippingDlg::OCCViewer_ClippingDlg( OCCViewer_ViewWindow* view, const QVBoxLayout* topLayout = new QVBoxLayout( this ); topLayout->setMargin( 11 ); topLayout->setSpacing( 6 ); - + /***************************************************************/ - GroupPoint = new QGroupBox( this ); - GroupPoint->setObjectName( "GroupPoint" ); - GroupPoint->setTitle( tr("Base point") ); - QGridLayout* GroupPointLayout = new QGridLayout( GroupPoint ); - GroupPointLayout->setAlignment( Qt::AlignTop ); - GroupPointLayout->setSpacing( 6 ); - GroupPointLayout->setMargin( 11 ); - - // Controls + // Controls for selecting, creating, deleting planes + QGroupBox* GroupPlanes = new QGroupBox( tr("CLIPPING_PLANES"), this ); + QHBoxLayout* GroupPlanesLayout = new QHBoxLayout( GroupPlanes ); + ComboBoxPlanes = new QComboBox( GroupPlanes ); + isActivePlane = new QCheckBox( tr("IS_ACTIVE_PLANE"), this ); + buttonNew = new QPushButton( tr("BTN_NEW"), GroupPlanes ); + buttonDelete = new QPushButton( tr("BTN_DELETE"), GroupPlanes ); + buttonDisableAll = new QPushButton( tr("BTN_DISABLE_ALL"), GroupPlanes ); + MenuMode = new QMenu( "MenuMode", buttonNew ); + MenuMode->addAction( tr( "ABSOLUTE" ), this, SLOT( onModeAbsolute() ) ); + MenuMode->addAction( tr( "RELATIVE" ), this, SLOT( onModeRelative() ) ); + buttonNew->setMenu( MenuMode ); + CurrentMode = Absolute; + + GroupPlanesLayout->addWidget( ComboBoxPlanes ); + GroupPlanesLayout->addWidget( isActivePlane ); + GroupPlanesLayout->addWidget( buttonNew ); + GroupPlanesLayout->addWidget( buttonDelete ); + GroupPlanesLayout->addWidget( buttonDisableAll ); + + ModeStackedLayout = new QStackedLayout(); + + /********************** Mode Absolute **********************/ + /* Controls for absolute mode of clipping plane: + X, Y, Z - coordinates of the intersection of cutting plane and the three axes + Dx, Dy, Dz - components of normal to the cutting plane + Orientation - direction of cutting plane + */ const double min = -1e+7; const double max = 1e+7; const double step = 5; const int precision = -7; - TextLabelX = new QLabel( GroupPoint ); + // Croup Point + QGroupBox* GroupAbsolutePoint = new QGroupBox( this ); + GroupAbsolutePoint->setObjectName( "GroupPoint" ); + GroupAbsolutePoint->setTitle( tr("BASE_POINT") ); + QGridLayout* GroupPointLayout = new QGridLayout( GroupAbsolutePoint ); + GroupPointLayout->setAlignment( Qt::AlignTop ); + GroupPointLayout->setSpacing( 6 ); GroupPointLayout->setMargin( 11 ); + + TextLabelX = new QLabel( GroupAbsolutePoint ); TextLabelX->setObjectName( "TextLabelX" ); TextLabelX->setText( tr("X:") ); GroupPointLayout->addWidget( TextLabelX, 0, 0 ); - SpinBox_X = new QtxDoubleSpinBox( min, max, step, GroupPoint ); + SpinBox_X = new QtxDoubleSpinBox( min, max, step, GroupAbsolutePoint ); SpinBox_X->setObjectName("SpinBox_X" ); SpinBox_X->setPrecision( precision ); GroupPointLayout->addWidget( SpinBox_X, 0, 1 ); - TextLabelY = new QLabel( GroupPoint ); + TextLabelY = new QLabel( GroupAbsolutePoint ); TextLabelY->setObjectName( "TextLabelY" ); TextLabelY->setText( tr("Y:") ); GroupPointLayout->addWidget( TextLabelY, 0, 2 ); - SpinBox_Y = new QtxDoubleSpinBox( min, max, step, GroupPoint ); + SpinBox_Y = new QtxDoubleSpinBox( min, max, step, GroupAbsolutePoint ); SpinBox_Y->setObjectName("SpinBox_Y" ); SpinBox_Y->setPrecision( precision ); GroupPointLayout->addWidget( SpinBox_Y, 0, 3 ); - TextLabelZ = new QLabel( GroupPoint ); + TextLabelZ = new QLabel( GroupAbsolutePoint ); TextLabelZ->setObjectName( "TextLabelZ" ); TextLabelZ->setText( tr("Z:") ); GroupPointLayout->addWidget( TextLabelZ, 0, 4 ); - SpinBox_Z = new QtxDoubleSpinBox( min, max, step, GroupPoint ); + SpinBox_Z = new QtxDoubleSpinBox( min, max, step, GroupAbsolutePoint ); SpinBox_Z->setObjectName("SpinBox_Z" ); SpinBox_Z->setPrecision( precision ); GroupPointLayout->addWidget( SpinBox_Z, 0, 5 ); - resetButton = new QPushButton( GroupPoint ); + resetButton = new QPushButton( GroupAbsolutePoint ); resetButton->setObjectName( "resetButton" ); - resetButton->setText( tr( "Reset" ) ); + resetButton->setText( tr( "RESET" ) ); GroupPointLayout->addWidget( resetButton, 0, 6 ); - /***************************************************************/ - GroupDirection = new QGroupBox( this ); - GroupDirection->setObjectName( "GroupDirection" ); - GroupDirection->setTitle( tr("Direction") ); - QGridLayout* GroupDirectionLayout = new QGridLayout( GroupDirection ); + // Group Direction + GroupAbsoluteDirection = new QGroupBox( this ); + GroupAbsoluteDirection->setObjectName( "GroupDirection" ); + GroupAbsoluteDirection->setTitle( tr("DIRECTION") ); + QGridLayout* GroupDirectionLayout = new QGridLayout( GroupAbsoluteDirection ); GroupDirectionLayout->setAlignment( Qt::AlignTop ); GroupDirectionLayout->setSpacing( 6 ); GroupDirectionLayout->setMargin( 11 ); - // Controls - TextLabelDx = new QLabel( GroupDirection ); + TextLabelDx = new QLabel( GroupAbsoluteDirection ); TextLabelDx->setObjectName( "TextLabelDx" ); TextLabelDx->setText( tr("Dx:") ); GroupDirectionLayout->addWidget( TextLabelDx, 0, 0 ); - SpinBox_Dx = new QtxDoubleSpinBox( min, max, step, GroupDirection ); + SpinBox_Dx = new QtxDoubleSpinBox( min, max, step, GroupAbsoluteDirection ); SpinBox_Dx->setObjectName("SpinBox_Dx" ); SpinBox_Dx->setPrecision( precision ); GroupDirectionLayout->addWidget( SpinBox_Dx, 0, 1 ); - TextLabelDy = new QLabel( GroupDirection ); + TextLabelDy = new QLabel( GroupAbsoluteDirection ); TextLabelDy->setObjectName( "TextLabelDy" ); TextLabelDy->setText( tr("Dy:") ); GroupDirectionLayout->addWidget( TextLabelDy, 0, 2 ); - SpinBox_Dy = new QtxDoubleSpinBox( min, max, step, GroupDirection ); + SpinBox_Dy = new QtxDoubleSpinBox( min, max, step, GroupAbsoluteDirection ); SpinBox_Dy->setObjectName("SpinBox_Dy" ); SpinBox_Dy->setPrecision( precision ); GroupDirectionLayout->addWidget( SpinBox_Dy, 0, 3 ); - TextLabelDz = new QLabel( GroupDirection ); + TextLabelDz = new QLabel( GroupAbsoluteDirection ); TextLabelDz->setObjectName( "TextLabelDz" ); TextLabelDz->setText( tr("Dz:") ); GroupDirectionLayout->addWidget( TextLabelDz, 0, 4 ); - SpinBox_Dz = new QtxDoubleSpinBox( min, max, step, GroupDirection ); + SpinBox_Dz = new QtxDoubleSpinBox( min, max, step, GroupAbsoluteDirection ); SpinBox_Dz->setObjectName("SpinBox_Dz" ); SpinBox_Dz->setPrecision( precision ); GroupDirectionLayout->addWidget( SpinBox_Dz, 0, 5 ); - invertButton = new QPushButton( GroupDirection ); + invertButton = new QPushButton( GroupAbsoluteDirection ); invertButton->setObjectName( "invertButton" ); - invertButton->setText( tr( "Invert" ) ); + invertButton->setText( tr( "INVERT" ) ); GroupDirectionLayout->addWidget( invertButton, 0, 6 ); - DirectionCB = new QComboBox( GroupDirection ); - DirectionCB->setObjectName( "DirectionCB" ); - DirectionCB->insertItem(DirectionCB->count(),tr("CUSTOM")); - DirectionCB->insertItem(DirectionCB->count(),tr("||X-Y")); - DirectionCB->insertItem(DirectionCB->count(),tr("||Y-Z")); - DirectionCB->insertItem(DirectionCB->count(),tr("||Z-X")); - GroupDirectionLayout->addWidget( DirectionCB, 1, 0, 1, 6 ); - + CBAbsoluteOrientation = new QComboBox( GroupAbsoluteDirection ); + CBAbsoluteOrientation->setObjectName( "AbsoluteOrientation" ); + CBAbsoluteOrientation->insertItem( CBAbsoluteOrientation->count(), tr( "CUSTOM" ) ); + CBAbsoluteOrientation->insertItem( CBAbsoluteOrientation->count(), tr( "||X-Y" ) ); + CBAbsoluteOrientation->insertItem( CBAbsoluteOrientation->count(), tr( "||Y-Z" ) ); + CBAbsoluteOrientation->insertItem( CBAbsoluteOrientation->count(), tr( "||Z-X" ) ); + GroupDirectionLayout->addWidget( CBAbsoluteOrientation, 1, 0, 1, 6 ); + + QVBoxLayout* ModeActiveLayout = new QVBoxLayout(); + ModeActiveLayout->setMargin( 11 ); ModeActiveLayout->setSpacing( 6 ); + ModeActiveLayout->addWidget( GroupAbsolutePoint ); + ModeActiveLayout->addWidget( GroupAbsoluteDirection ); + + QWidget* ModeActiveWidget = new QWidget( this ); + ModeActiveWidget->setLayout( ModeActiveLayout ); + + /********************** Mode Relative **********************/ + /* Controls for relative mode of clipping plane: + Distance - Value from 0 to 1. + Specifies the distance from the minimum value in a given direction of bounding box to the current position + Rotation1, Rotation2 - turn angles of cutting plane in given directions + Orientation - direction of cutting plane + */ + QGroupBox* GroupParameters = new QGroupBox( tr("PARAMETERS"), this ); + QGridLayout* GroupParametersLayout = new QGridLayout( GroupParameters ); + GroupParametersLayout->setMargin( 11 ); GroupParametersLayout->setSpacing( 6 ); + + TextLabelOrientation = new QLabel( tr("ORIENTATION"), GroupParameters); + TextLabelOrientation->setObjectName( "TextLabelOrientation" ); + GroupParametersLayout->addWidget( TextLabelOrientation, 0, 0 ); + + CBRelativeOrientation = new QComboBox(GroupParameters); + CBRelativeOrientation->setObjectName( "RelativeOrientation" ); + CBRelativeOrientation->addItem( tr("ALONG_XY") ); + CBRelativeOrientation->addItem( tr("ALONG_YZ") ); + CBRelativeOrientation->addItem( tr("ALONG_ZX") ); + GroupParametersLayout->addWidget( CBRelativeOrientation, 0, 1 ); + + TLValueDistance = new QLabel( GroupParameters ); + TLValueDistance->setObjectName( "TLValueDistance" ); + TLValueDistance->setAlignment( Qt::AlignCenter ); + TLValueDistance->setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed ) ); + QFont fnt = TLValueDistance->font(); fnt.setBold( true ); TLValueDistance->setFont( fnt ); + GroupParametersLayout->addWidget( TLValueDistance, 1, 1 ); + + TextLabelDistance = new QLabel( tr("DISTANCE"), GroupParameters ); + TextLabelDistance->setObjectName( "TextLabelDistance" ); + GroupParametersLayout->addWidget( TextLabelDistance, 2, 0 ); + + SliderDistance = new QSlider( Qt::Horizontal, GroupParameters ); + SliderDistance->setObjectName( "SliderDistance" ); + SliderDistance->setFocusPolicy( Qt::NoFocus ); + SliderDistance->setMinimumSize( 300, 0 ); + SliderDistance->setMinimum( 0 ); + SliderDistance->setMaximum( 100 ); + SliderDistance->setSingleStep( 1 ); + SliderDistance->setPageStep( 10 ); + SliderDistance->setTracking( false ); + GroupParametersLayout->addWidget( SliderDistance, 2, 1 ); + + TLValueRotation1 = new QLabel( GroupParameters ); + TLValueRotation1->setObjectName( "TLValueRotation1" ); + TLValueRotation1->setAlignment( Qt::AlignCenter ); + TLValueRotation1->setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed ) ); + TLValueRotation1->setFont( fnt ); + GroupParametersLayout->addWidget( TLValueRotation1, 3, 1 ); + + TextLabelRotation1 = new QLabel( tr("ROTATION_AROUND_X_Y2Z"), GroupParameters ); + TextLabelRotation1->setObjectName( "TextLabelRotation1" ); + GroupParametersLayout->addWidget( TextLabelRotation1, 4, 0 ); + + SliderRotation1 = new QSlider( Qt::Horizontal, GroupParameters ); + SliderRotation1->setObjectName( "SliderRotation1" ); + SliderRotation1->setFocusPolicy( Qt::NoFocus ); + SliderRotation1->setMinimumSize( 300, 0 ); + SliderRotation1->setMinimum( -180 ); + SliderRotation1->setMaximum( 180 ); + SliderRotation1->setSingleStep( 1 ); + SliderRotation1->setPageStep( 10 ); + SliderRotation1->setTracking(false); + GroupParametersLayout->addWidget( SliderRotation1, 4, 1 ); + + TLValueRotation2 = new QLabel( GroupParameters ); + TLValueRotation2->setObjectName( "TLValueRotation2" ); + TLValueRotation2->setAlignment( Qt::AlignCenter ); + TLValueRotation2->setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed ) ); + TLValueRotation2->setFont( fnt ); + GroupParametersLayout->addWidget( TLValueRotation2, 5, 1 ); + + TextLabelRotation2 = new QLabel(tr("ROTATION_AROUND_Y_X2Z"), GroupParameters); + TextLabelRotation2->setObjectName( "TextLabelRotation2" ); + TextLabelRotation2->setObjectName( "TextLabelRotation2" ); + GroupParametersLayout->addWidget( TextLabelRotation2, 6, 0 ); + + SliderRotation2 = new QSlider( Qt::Horizontal, GroupParameters ); + SliderRotation2->setObjectName( "SliderRotation2" ); + SliderRotation2->setFocusPolicy( Qt::NoFocus ); + SliderRotation2->setMinimumSize( 300, 0 ); + SliderRotation2->setMinimum( -180 ); + SliderRotation2->setMaximum( 180 ); + SliderRotation2->setSingleStep( 1 ); + SliderRotation2->setPageStep( 10 ); + SliderRotation2->setTracking(false); + GroupParametersLayout->addWidget( SliderRotation2, 6, 1 ); + /***************************************************************/ + QGroupBox* CheckBoxWidget = new QGroupBox( this ); + QHBoxLayout* CheckBoxLayout = new QHBoxLayout( CheckBoxWidget ); - PreviewChB = new QCheckBox( tr("Preview") ,this ); - PreviewChB->setObjectName( "PreviewChB" ); - PreviewChB->setChecked( true ); + PreviewCheckBox = new QCheckBox( tr("PREVIEW"), CheckBoxWidget ); + PreviewCheckBox->setObjectName( "PreviewCheckBox" ); + PreviewCheckBox->setChecked( true ); + CheckBoxLayout->addWidget( PreviewCheckBox, 0, Qt::AlignCenter ); + AutoApplyCheckBox = new QCheckBox( tr("AUTO_APPLY"), CheckBoxWidget ); + AutoApplyCheckBox->setObjectName( "AutoApplyCheckBox" ); + CheckBoxLayout->addWidget( AutoApplyCheckBox, 0, Qt::AlignCenter ); + /***************************************************************/ QGroupBox* GroupButtons = new QGroupBox( this ); - GroupButtons->setObjectName( "GroupButtons" ); QHBoxLayout* GroupButtonsLayout = new QHBoxLayout( GroupButtons ); GroupButtonsLayout->setAlignment( Qt::AlignTop ); GroupButtonsLayout->setMargin( 11 ); GroupButtonsLayout->setSpacing( 6 ); + buttonOk = new QPushButton( GroupButtons ); + buttonOk->setObjectName( "buttonOk" ); + buttonOk->setText( tr( "BUT_APPLY_AND_CLOSE" ) ); + buttonOk->setAutoDefault( TRUE ); + buttonOk->setDefault( TRUE ); + GroupButtonsLayout->addWidget( buttonOk ); + buttonApply = new QPushButton( GroupButtons ); buttonApply->setObjectName( "buttonApply" ); buttonApply->setText( tr( "BUT_APPLY" ) ); - buttonApply->setAutoDefault( TRUE ); + buttonApply->setAutoDefault( TRUE ); buttonApply->setDefault( TRUE ); GroupButtonsLayout->addWidget( buttonApply ); - + GroupButtonsLayout->addStretch(); buttonClose = new QPushButton( GroupButtons ); @@ -205,47 +553,65 @@ OCCViewer_ClippingDlg::OCCViewer_ClippingDlg( OCCViewer_ViewWindow* view, const buttonClose->setAutoDefault( TRUE ); GroupButtonsLayout->addWidget( buttonClose ); + QPushButton* buttonHelp = new QPushButton( tr( "SMESH_BUT_HELP" ), GroupButtons ); + buttonHelp->setAutoDefault( TRUE ); + GroupButtonsLayout->addWidget( buttonHelp ); + /***************************************************************/ - - topLayout->addWidget( GroupPoint ); - topLayout->addWidget( GroupDirection ); - - topLayout->addWidget( PreviewChB ); + ModeStackedLayout->addWidget( ModeActiveWidget ); + ModeStackedLayout->addWidget( GroupParameters ); + topLayout->addWidget( GroupPlanes ); + topLayout->addLayout( ModeStackedLayout ); + topLayout->addWidget( CheckBoxWidget ); topLayout->addWidget( GroupButtons ); - /* initializations */ + this->setLayout( topLayout ); - SpinBox_X->setValue( 0.0 ); - SpinBox_Y->setValue( 0.0 ); - SpinBox_Z->setValue( 0.0 ); + // Initializations + initParam(); - SpinBox_Dx->setValue( 1.0 ); - SpinBox_Dy->setValue( 1.0 ); - SpinBox_Dz->setValue( 1.0 ); + // Signals and slots connections + connect( ComboBoxPlanes, SIGNAL( activated( int ) ), this, SLOT( onSelectPlane( int ) ) ); + connect( isActivePlane, SIGNAL ( toggled ( bool ) ), this, SLOT( onValueChanged() ) ); + connect( buttonNew, SIGNAL( clicked() ), buttonNew, SLOT( showMenu() ) ); + connect( buttonDelete, SIGNAL( clicked() ), this, SLOT( ClickOnDelete() ) ); + connect( buttonDisableAll, SIGNAL( clicked() ), this, SLOT( ClickOnDisableAll() ) ); - /* signals and slots connections */ connect( resetButton, SIGNAL (clicked() ), this, SLOT( onReset() ) ); connect( invertButton, SIGNAL (clicked() ), this, SLOT( onInvert() ) ) ; - connect( SpinBox_X, SIGNAL ( valueChanged( double ) ), this, SLOT( onValueChanged() ) ); connect( SpinBox_Y, SIGNAL ( valueChanged( double ) ), this, SLOT( onValueChanged() ) ); connect( SpinBox_Z, SIGNAL ( valueChanged( double ) ), this, SLOT( onValueChanged() ) ); connect( SpinBox_Dx, SIGNAL ( valueChanged( double ) ), this, SLOT( onValueChanged() ) ); connect( SpinBox_Dy, SIGNAL ( valueChanged( double ) ), this, SLOT( onValueChanged() ) ); connect( SpinBox_Dz, SIGNAL ( valueChanged( double ) ), this, SLOT( onValueChanged() ) ); - - connect( DirectionCB, SIGNAL ( activated ( int ) ), this, SLOT( onModeChanged( int ) ) ) ; - - connect( PreviewChB, SIGNAL ( toggled ( bool ) ), this, SLOT( onPreview( bool ) ) ) ; + connect( CBAbsoluteOrientation, SIGNAL ( activated ( int ) ), this, SLOT( onOrientationAbsoluteChanged( int ) ) ) ; + + connect( CBRelativeOrientation, SIGNAL( activated( int ) ), this, SLOT( onOrientationRelativeChanged( int ) ) ); + connect( SliderDistance, SIGNAL( sliderMoved( int ) ), this, SLOT( SliderDistanceHasMoved( int ) ) ); + connect( SliderDistance, SIGNAL( valueChanged( int ) ), this, SLOT( SliderDistanceHasMoved( int ) ) ); + connect( SliderRotation1, SIGNAL( sliderMoved( int ) ), this, SLOT( SliderRotation1HasMoved( int ) ) ); + connect( SliderRotation1, SIGNAL( valueChanged( int ) ), this, SLOT( SliderRotation1HasMoved( int ) ) ); + connect( SliderRotation2, SIGNAL( sliderMoved( int ) ), this, SLOT( SliderRotation2HasMoved( int ) ) ); + connect( SliderRotation2, SIGNAL( valueChanged( int ) ), this, SLOT( SliderRotation2HasMoved( int ) ) ); + + connect( PreviewCheckBox, SIGNAL ( toggled ( bool ) ), this, SLOT( onPreview( bool ) ) ) ; + connect( AutoApplyCheckBox, SIGNAL ( toggled( bool ) ), this, SLOT( onAutoApply( bool ) ) ); connect( buttonClose, SIGNAL( clicked() ), this, SLOT( ClickOnClose() ) ) ; + connect( buttonOk, SIGNAL( clicked() ), this, SLOT( ClickOnOk() ) ); connect( buttonApply, SIGNAL( clicked() ), this, SLOT( ClickOnApply() ) ); + connect( buttonHelp, SIGNAL( clicked() ), this, SLOT( ClickOnHelp() ) ); + connect(view, SIGNAL(Show( QShowEvent* ) ), this, SLOT( onViewShow() ) ); + connect(view, SIGNAL(Hide( QHideEvent* ) ), this, SLOT( onViewHide() ) ); + myBusy = false; + myIsSelectPlane = false; + myView3d = myView->getViewPort()->getView(); - connect(view, SIGNAL(Show( QShowEvent * )), this, SLOT(onViewShow())); - connect(view, SIGNAL(Hide( QHideEvent * )), this, SLOT(onViewHide())); + synchronize(); } /*! @@ -255,39 +621,29 @@ OCCViewer_ClippingDlg::OCCViewer_ClippingDlg( OCCViewer_ViewWindow* view, const OCCViewer_ClippingDlg::~ OCCViewer_ClippingDlg() { // no need to delete child widgets, Qt does it all for us + foreach( ClipPlane* aPlane, myClippingPlanes ) + delete aPlane; } - /*! Custom handling of close event: erases preview */ void OCCViewer_ClippingDlg::closeEvent( QCloseEvent* e ) { erasePreview(); - - // Set the clipping plane back - /*Handle(V3d_View) aView3d = myView->getViewPort()->getView(); - if ( !aView3d.IsNull() && !myClippingPlane.IsNull() ) - aView3d->SetPlaneOn( myClippingPlane );*/ - myAction->setChecked( false ); - QDialog::closeEvent( e ); } - /*! Custom handling of show event: displays preview */ void OCCViewer_ClippingDlg::showEvent( QShowEvent* e ) { - //ReserveClippingPlane(); - QDialog::showEvent( e ); - onPreview( PreviewChB->isChecked() ); + onPreview( PreviewCheckBox->isChecked() ); } - /*! Custom handling of hide event: erases preview */ @@ -297,42 +653,400 @@ void OCCViewer_ClippingDlg::hideEvent( QHideEvent* e ) QDialog::hideEvent( e ); } +/*! + Initialization of initial values of widgets +*/ +void OCCViewer_ClippingDlg::initParam() +{ + SpinBox_X->setValue( 0.0 ); + SpinBox_Y->setValue( 0.0 ); + SpinBox_Z->setValue( 0.0 ); + + SpinBox_Dx->setValue( 1.0 ); + SpinBox_Dy->setValue( 1.0 ); + SpinBox_Dz->setValue( 1.0 ); + + CBAbsoluteOrientation->setCurrentIndex(0); + + TLValueDistance->setText( "0" ); + TLValueRotation1->setText( "0\xB0" ); + TLValueRotation2->setText( "0\xB0" ); + CBRelativeOrientation->setCurrentIndex( 0 ); + SliderDistance->setValue( 50 ); + SliderRotation1->setValue( 0 ); + SliderRotation2->setValue( 0 ); +} /*! - SLOT on close button click: erases preview and rejects dialog + Synchronize dialog's widgets with data */ -void OCCViewer_ClippingDlg::ClickOnClose() +void OCCViewer_ClippingDlg::synchronize() { - erasePreview(); + ComboBoxPlanes->clear(); + int aNbPlanesAbsolute = myClippingPlanes.size(); - // Set the clipping plane back - /*Handle(V3d_View) aView3d = myView->getViewPort()->getView(); - if ( !aView3d.IsNull() && !myClippingPlane.IsNull() ) - aView3d->SetPlaneOn( myClippingPlane ); - */ - myAction->setChecked( false ); - - reject(); + QString aName; + for(int i = 1; i<=aNbPlanesAbsolute; i++ ) { + aName = QString("Plane %1").arg(i); + ComboBoxPlanes->addItem( aName ); + } + + int aPos = ComboBoxPlanes->count() - 1; + ComboBoxPlanes->setCurrentIndex( aPos ); + + bool anIsControlsEnable = ( aPos >= 0 ); + if ( anIsControlsEnable ) { + onSelectPlane( aPos ); + } + else { + ComboBoxPlanes->addItem( tr( "NO_PLANES" ) ); + initParam(); + ClickOnDisableAll(); + } + if ( CurrentMode == Absolute ) { + SpinBox_X->setEnabled( anIsControlsEnable ); + SpinBox_Y->setEnabled( anIsControlsEnable ); + SpinBox_Z->setEnabled( anIsControlsEnable ); + SpinBox_Dx->setEnabled( anIsControlsEnable ); + SpinBox_Dy->setEnabled( anIsControlsEnable ); + SpinBox_Dz->setEnabled( anIsControlsEnable ); + CBAbsoluteOrientation->setEnabled( anIsControlsEnable ); + invertButton->setEnabled( anIsControlsEnable ); + resetButton->setEnabled( anIsControlsEnable ); + } + else if( CurrentMode == Relative ) { + CBRelativeOrientation->setEnabled( anIsControlsEnable ); + SliderDistance->setEnabled( anIsControlsEnable ); + SliderRotation1->setEnabled( anIsControlsEnable ); + SliderRotation2->setEnabled( anIsControlsEnable ); + isActivePlane->setEnabled( anIsControlsEnable ); + } + isActivePlane->setEnabled( anIsControlsEnable ); } +/*! + Displays preview of clipping plane +*/ +void OCCViewer_ClippingDlg::displayPreview() +{ + if ( myBusy || !isValid() ) + return; + + OCCViewer_Viewer* anOCCViewer = (OCCViewer_Viewer*)myView->getViewManager()->getViewModel(); + if ( !anOCCViewer ) + return; + + Handle(AIS_InteractiveContext) ic = anOCCViewer->getAISContext(); + + double aXMin, aYMin, aZMin, aXMax, aYMax, aZMax; + aXMin = aYMin = aZMin = DBL_MAX; + aXMax = aYMax = aZMax = -DBL_MAX; + + bool isFound = false; + AIS_ListOfInteractive aList; + ic->DisplayedObjects( aList ); + for ( AIS_ListIteratorOfListOfInteractive it( aList ); it.More(); it.Next() ) + { + Handle(AIS_InteractiveObject) anObj = it.Value(); + if ( !anObj.IsNull() && anObj->HasPresentation() && + !anObj->IsKind( STANDARD_TYPE(AIS_Plane) ) ) { + Handle(Prs3d_Presentation) aPrs = anObj->Presentation(); + if ( !aPrs->IsEmpty() && !aPrs->IsInfinite() ) { + isFound = true; + double xmin, ymin, zmin, xmax, ymax, zmax; + aPrs->MinMaxValues( xmin, ymin, zmin, xmax, ymax, zmax ); + aXMin = qMin( aXMin, xmin ); aXMax = qMax( aXMax, xmax ); + aYMin = qMin( aYMin, ymin ); aYMax = qMax( aYMax, ymax ); + aZMin = qMin( aZMin, zmin ); aZMax = qMax( aZMax, zmax ); + } + } + } + + double aSize = 50; + + ClipPlane* aClipPlane; + for ( int i=0; i < myClippingPlanes.size(); i++ ) { + Pnt_ClipPlane aPlane = myClippingPlanes[i]; + aClipPlane = aPlane; + + double Epsilon = 0.0001; + double Epsilon_Dx = ( aClipPlane->Dx > 0 ) ? Epsilon: -Epsilon; + double Epsilon_Dy = ( aClipPlane->Dy > 0 ) ? Epsilon: -Epsilon; + double Epsilon_Dz = ( aClipPlane->Dz > 0 ) ? Epsilon: -Epsilon; + + gp_Pnt aBasePnt( aClipPlane->X + Epsilon_Dx, aClipPlane->Y + Epsilon_Dy, aClipPlane->Z + Epsilon_Dz ); + gp_Dir aNormal( aClipPlane->Dx, aClipPlane->Dy, aClipPlane->Dz ); + gp_Pnt aCenter = aBasePnt; + + if ( isFound ) + { + // compute clipping plane size + aCenter = gp_Pnt( ( aXMin + aXMax ) / 2, ( aYMin + aYMax ) / 2, ( aZMin + aZMax ) / 2 ); + double aDiag = aCenter.Distance( gp_Pnt( aXMax, aYMax, aZMax ) )*2; + aSize = aDiag * 1.1; + + // compute clipping plane center ( redefine the base point ) + IntAna_IntConicQuad intersector = IntAna_IntConicQuad(); + + intersector.Perform( gp_Lin( aCenter, aNormal), gp_Pln( aBasePnt, aNormal), Precision::Confusion() ); + if ( intersector.IsDone() && intersector.NbPoints() == 1 ) + aBasePnt = intersector.Point( 1 ); + } + + if ( aClipPlane->IsActive == true ) { + Handle(AIS_Plane) myPreviewPlane; + myPreviewPlane = new AIS_Plane( new Geom_Plane( aBasePnt, aNormal ) ); + myPreviewPlane->SetSize( aSize, aSize ); + + ic->Display( myPreviewPlane, 1, -1, false ); + ic->SetWidth( myPreviewPlane, 10, false ); + ic->SetMaterial( myPreviewPlane, Graphic3d_NOM_PLASTIC, false ); + ic->SetTransparency( myPreviewPlane, 0.5, false ); + ic->SetColor( myPreviewPlane, Quantity_Color( 85 / 255., 85 / 255., 255 / 255., Quantity_TOC_RGB ), false ); + + myPreviewPlaneVector.push_back( myPreviewPlane ); + } + } + anOCCViewer->update(); +} /*! - SLOT on apply button click: sets cutting plane + Erases preview of clipping plane */ -void OCCViewer_ClippingDlg::ClickOnApply() +void OCCViewer_ClippingDlg::erasePreview() { - qApp->processEvents(); - QApplication::setOverrideCursor( Qt::WaitCursor ); - qApp->processEvents(); - - myView->setCuttingPlane( true, SpinBox_X->value() , SpinBox_Y->value() , SpinBox_Z->value(), - SpinBox_Dx->value(), SpinBox_Dy->value(), SpinBox_Dz->value() ); + OCCViewer_Viewer* anOCCViewer = (OCCViewer_Viewer*)myView->getViewManager()->getViewModel(); + if ( !anOCCViewer ) + return; - QApplication::restoreOverrideCursor(); + Handle(AIS_InteractiveContext) ic = anOCCViewer->getAISContext(); + for ( int i=0; i < myPreviewPlaneVector.size(); i++ ) { + Handle(AIS_Plane) myPreviewPlane = myPreviewPlaneVector[i]; + if ( !myPreviewPlane.IsNull() && ic->IsDisplayed( myPreviewPlane ) ) { + ic->Erase( myPreviewPlane, false ); + ic->Remove( myPreviewPlane, false ); + myPreviewPlane.Nullify(); + } + } + anOCCViewer->update(); +} + +/*! + Return true if plane parameters are valid +*/ +bool OCCViewer_ClippingDlg::isValid() +{ + return ( SpinBox_Dx->value() !=0 || SpinBox_Dy->value() !=0 || SpinBox_Dz->value() !=0 ); +} + +/*! + Update view after changes +*/ +void OCCViewer_ClippingDlg::updateView() +{ + if ( PreviewCheckBox->isChecked() || AutoApplyCheckBox->isChecked() ) { + erasePreview(); + if ( AutoApplyCheckBox->isChecked() ) + onApply(); + if ( PreviewCheckBox->isChecked() && !isRestore ) + displayPreview(); + } +} + +/*! + SLOT on new button click: create a new clipping plane +*/ +void OCCViewer_ClippingDlg::ClickOnNew() +{ + ClipPlane* aPlane = new ClipPlane(); + aPlane->PlaneMode = CurrentMode; + myClippingPlanes.push_back( aPlane ); + synchronize(); +} + +/*! + SLOT on delete button click: Delete selected clipping plane +*/ +void OCCViewer_ClippingDlg::ClickOnDelete() +{ + if ( myClippingPlanes.empty() ) + return; + + int aPlaneIndex = ComboBoxPlanes->currentIndex(); + + ClipPlaneVector::iterator anIter = myClippingPlanes.begin() + aPlaneIndex; + myClippingPlanes.erase( anIter ); + updateView(); + synchronize(); +} + +/*! + SLOT on disable all button click: Restore initial state of viewer, + erase all clipping planes +*/ +void OCCViewer_ClippingDlg::ClickOnDisableAll() +{ + AutoApplyCheckBox->setChecked( false ); + Graphic3d_SetOfHClipPlane aPlanes = myView3d->GetClipPlanes(); + Graphic3d_SetOfHClipPlane::Iterator anIter (aPlanes); + for( ;anIter.More();anIter.Next() ){ + Handle(Graphic3d_ClipPlane) aClipPlane = anIter.Value(); + aClipPlane->SetOn(Standard_False); + } + myView3d->Update(); + myView3d->Redraw(); +} + +/*! + SLOT on ok button click: sets cutting plane and closes dialog +*/ +void OCCViewer_ClippingDlg::ClickOnOk() +{ + onApply(); erasePreview(); - - //ReserveClippingPlane(); + myAction->setChecked( false ); +} + +/*! + SLOT on Apply button click: sets cutting plane and update viewer +*/ +void OCCViewer_ClippingDlg::ClickOnApply() +{ + onApply(); + myView3d->Update(); + myView3d->Redraw(); +} + +/*! + SLOT on close button click: erases preview and rejects dialog +*/ +void OCCViewer_ClippingDlg::ClickOnClose() +{ + erasePreview(); + myAction->setChecked( false ); +} + +/*! + SLOT on help button click: opens a help page +*/ +void OCCViewer_ClippingDlg::ClickOnHelp() +{ + SUIT_Application* app = SUIT_Session::session()->activeApplication(); + if ( app ) + app->onHelpContextModule( "GUI", "occ_3d_viewer_page.html", "clipping_planes" ); +} + +/*! + Set absolute mode of clipping plane +*/ +void OCCViewer_ClippingDlg::onModeAbsolute() +{ + ModeStackedLayout->setCurrentIndex(0); + CurrentMode = Absolute; + ClickOnNew(); + onValueChanged(); +} + +/*! + Set relative mode of clipping plane +*/ +void OCCViewer_ClippingDlg::onModeRelative() +{ + ModeStackedLayout->setCurrentIndex(1); + CurrentMode = Relative; + ClickOnNew(); + onValueChanged(); +} + +/*! + SLOT: called on value of clipping plane changed +*/ +void OCCViewer_ClippingDlg::onValueChanged() +{ + SetCurrentPlaneParam(); + if ( myIsSelectPlane ) + return; + updateView(); +} + +/*! + Set current parameters of selected plane +*/ +void OCCViewer_ClippingDlg::onSelectPlane ( int theIndex ) +{ + if ( myClippingPlanes.empty() ) + return; + + Pnt_ClipPlane aPlane = myClippingPlanes[theIndex]; + ClipPlane* aClipPlane = aPlane; + + myIsSelectPlane = true; + if ( aClipPlane->PlaneMode == Absolute ) { + ModeStackedLayout->setCurrentIndex( 0 ); + CurrentMode = Absolute; + int anOrientation = aClipPlane->Orientation; + // Set plane parameters in the dialog + SpinBox_X->setValue( aClipPlane->X ); + SpinBox_Y->setValue( aClipPlane->Y ); + SpinBox_Z->setValue( aClipPlane->Z ); + SpinBox_Dx->setValue( aClipPlane->Dx ); + SpinBox_Dy->setValue( aClipPlane->Dy ); + SpinBox_Dz->setValue( aClipPlane->Dz ); + CBAbsoluteOrientation->setCurrentIndex( anOrientation ); + onOrientationAbsoluteChanged( anOrientation ); + } + else if( aClipPlane->PlaneMode == Relative ) { + ModeStackedLayout->setCurrentIndex( 1 ); + CurrentMode = Relative; + int anOrientation = aClipPlane->RelativeMode.Orientation; + // Set plane parameters in the dialog + SliderDistance->setValue( aClipPlane->RelativeMode.Distance*100 ); + TLValueDistance->setText( QString::number(aClipPlane->RelativeMode.Distance ) ); + SliderRotation1->setValue( aClipPlane->RelativeMode.Rotation1 ); + TLValueRotation1->setText( QString( "%1\xB0" ).arg( aClipPlane->RelativeMode.Rotation1 ) ); + SliderRotation2->setValue( aClipPlane->RelativeMode.Rotation2 ); + TLValueRotation2->setText( QString( "%1\xB0" ).arg( aClipPlane->RelativeMode.Rotation2 ) ); + CBRelativeOrientation->setCurrentIndex( anOrientation ); + onOrientationRelativeChanged( anOrientation ); + } + isActivePlane->setChecked( aClipPlane->IsActive ); + ComboBoxPlanes->setCurrentIndex( theIndex ); + + myIsSelectPlane = false; +} + +/*! + Restore parameters of selected plane +*/ +void OCCViewer_ClippingDlg::SetCurrentPlaneParam() +{ + if ( myClippingPlanes.empty() || myIsSelectPlane ) + return; + + int aCurPlaneIndex = ComboBoxPlanes->currentIndex(); + + Pnt_ClipPlane aPlane = myClippingPlanes[aCurPlaneIndex]; + ClipPlane* aPlaneData = aPlane; + + if ( aPlaneData->PlaneMode == Absolute ) { + aPlaneData->Orientation = CBAbsoluteOrientation->currentIndex(); + aPlaneData->X = SpinBox_X->value(); + aPlaneData->Y = SpinBox_Y->value(); + aPlaneData->Z = SpinBox_Z->value(); + aPlaneData->Dx = SpinBox_Dx->value(); + aPlaneData->Dy = SpinBox_Dy->value(); + aPlaneData->Dz = SpinBox_Dz->value(); + } + else if( aPlaneData->PlaneMode == Relative ) { + aPlaneData->RelativeMode.Orientation = CBRelativeOrientation->currentIndex(); + aPlaneData->RelativeMode.Distance = TLValueDistance->text().toDouble(); + aPlaneData->RelativeMode.Rotation1 = TLValueRotation1->text().remove("\xB0").toInt(); + aPlaneData->RelativeMode.Rotation2 = TLValueRotation2->text().remove("\xB0").toInt(); + erasePreview(); + RelativePlaneToAbsolute( aPlane, myView3d ); + } + aPlaneData->IsActive = isActivePlane->isChecked(); } /*! @@ -346,11 +1060,7 @@ void OCCViewer_ClippingDlg::onReset() SpinBox_Z->setValue(0); myBusy = false; - if ( PreviewChB->isChecked() ) - { - erasePreview(); - displayPreview(); - } + updateView(); } /*! @@ -361,27 +1071,29 @@ void OCCViewer_ClippingDlg::onInvert() double Dx = SpinBox_Dx->value(); double Dy = SpinBox_Dy->value(); double Dz = SpinBox_Dz->value(); - + myBusy = true; SpinBox_Dx->setValue( -Dx ); SpinBox_Dy->setValue( -Dy ); SpinBox_Dz->setValue( -Dz ); myBusy = false; - if ( PreviewChB->isChecked() ) - { - erasePreview(); - displayPreview(); - } + if ( !myClippingPlanes.empty() ) { + int aCurPlaneIndex = ComboBoxPlanes->currentIndex(); + Pnt_ClipPlane aPlane = myClippingPlanes[aCurPlaneIndex]; + ClipPlane* aPlaneData = aPlane; + aPlaneData->IsInvert = !aPlaneData->IsInvert; + } + updateView(); } /*! - SLOT: called on mode changed + SLOT: called on orientation of clipping plane in absolute mode changed */ -void OCCViewer_ClippingDlg::onModeChanged( int mode ) +void OCCViewer_ClippingDlg::onOrientationAbsoluteChanged( int mode ) { bool isUserMode = (mode==0); - + TextLabelX->setEnabled( isUserMode ); TextLabelY->setEnabled( isUserMode ); TextLabelZ->setEnabled( isUserMode ); @@ -397,196 +1109,126 @@ void OCCViewer_ClippingDlg::onModeChanged( int mode ) SpinBox_Dx->setEnabled( isUserMode ); SpinBox_Dy->setEnabled( isUserMode ); SpinBox_Dz->setEnabled( isUserMode ); - + if ( isUserMode ) return; double aDx = 0, aDy = 0, aDz = 0; if ( mode == 1 ) - { - aDz = 1; - TextLabelZ->setEnabled( true ); - SpinBox_Z->setEnabled( true ); - SpinBox_Z->setFocus(); - } + { + aDz = 1; + TextLabelZ->setEnabled( true ); + SpinBox_Z->setEnabled( true ); + SpinBox_Z->setFocus(); + } else if ( mode == 2 ) - { - aDx = 1; - TextLabelX->setEnabled( true ); - SpinBox_X->setEnabled( true ); - SpinBox_X->setFocus(); - } + { + aDx = 1; + TextLabelX->setEnabled( true ); + SpinBox_X->setEnabled( true ); + SpinBox_X->setFocus(); + } else if ( mode == 3 ) - { - aDy = 1; - TextLabelY->setEnabled( true ); - SpinBox_Y->setEnabled( true ); - SpinBox_Y->setFocus(); - } - + { + aDy = 1; + TextLabelY->setEnabled( true ); + SpinBox_Y->setEnabled( true ); + SpinBox_Y->setFocus(); + } + + int aCurPlaneIndex = ComboBoxPlanes->currentIndex(); + Pnt_ClipPlane aPlane = myClippingPlanes[aCurPlaneIndex]; + ClipPlane* aPlaneData = aPlane; + if ( aPlaneData->IsInvert == true ) { + aDx = -aDx; aDy = -aDy; aDz = -aDz; + } + myBusy = true; SpinBox_Dx->setValue( aDx ); SpinBox_Dy->setValue( aDy ); SpinBox_Dz->setValue( aDz ); myBusy = false; - if ( PreviewChB->isChecked() ) - { - erasePreview(); - displayPreview(); - } + SetCurrentPlaneParam(); + updateView(); } - /*! - Displays preview of clipping plane + SLOT: called on orientation of clipping plane in relative mode changed */ -void OCCViewer_ClippingDlg::displayPreview() +void OCCViewer_ClippingDlg::onOrientationRelativeChanged (int theItem) { - if ( myBusy || !isValid() ) + if ( myClippingPlanes.empty() ) return; - OCCViewer_Viewer* anOCCViewer = (OCCViewer_Viewer*)myView->getViewManager()->getViewModel(); - if (!anOCCViewer) - return; - - Handle(AIS_InteractiveContext) ic = anOCCViewer->getAISContext(); - - double aXMin, aYMin, aZMin, aXMax, aYMax, aZMax; - aXMin = aYMin = aZMin = DBL_MAX; - aXMax = aYMax = aZMax = -DBL_MAX; - - bool isFound = false; - AIS_ListOfInteractive aList; - ic->DisplayedObjects( aList ); - for ( AIS_ListIteratorOfListOfInteractive it( aList ); it.More(); it.Next() ) - { - Handle(AIS_InteractiveObject) anObj = it.Value(); - if ( !anObj.IsNull() && anObj->HasPresentation() && - !anObj->IsKind( STANDARD_TYPE(AIS_Plane) ) ) - { - Handle(Prs3d_Presentation) aPrs = anObj->Presentation(); - if ( !aPrs->IsEmpty() && !aPrs->IsInfinite() ) - { - isFound = true; - double xmin, ymin, zmin, xmax, ymax, zmax; - aPrs->MinMaxValues( xmin, ymin, zmin, xmax, ymax, zmax ); - aXMin = qMin( aXMin, xmin ); aXMax = qMax( aXMax, xmax ); - aYMin = qMin( aYMin, ymin ); aYMax = qMax( aYMax, ymax ); - aZMin = qMin( aZMin, zmin ); aZMax = qMax( aZMax, zmax ); - } - } + if ( theItem == 0 ) { + TextLabelRotation1->setText( tr( "ROTATION_AROUND_X_Y2Z" ) ); + TextLabelRotation2->setText( tr( "ROTATION_AROUND_Y_X2Z" ) ); + } + else if ( theItem == 1 ) { + TextLabelRotation1->setText( tr( "ROTATION_AROUND_Y_Z2X" ) ); + TextLabelRotation2->setText( tr( "ROTATION_AROUND_Z_Y2X" ) ); + } + else if ( theItem == 2 ) { + TextLabelRotation1->setText( tr( "ROTATION_AROUND_Z_X2Y" ) ); + TextLabelRotation2->setText( tr( "ROTATION_AROUND_X_Z2Y" ) ); } - double aSize = 50; - - gp_Pnt aBasePnt( SpinBox_X->value(), SpinBox_Y->value(), SpinBox_Z->value() ); - gp_Dir aNormal( SpinBox_Dx->value(), SpinBox_Dy->value(), SpinBox_Dz->value() ); - gp_Pnt aCenter = aBasePnt; - - if ( isFound ) - { - // compute clipping plane size - aCenter = gp_Pnt( ( aXMin + aXMax ) / 2, ( aYMin + aYMax ) / 2, ( aZMin + aZMax ) / 2 ); - double aDiag = aCenter.Distance(gp_Pnt(aXMax, aYMax, aZMax ))*2; - aSize = aDiag * 1.1; - - // compute clipping plane center ( redefine the base point ) - IntAna_IntConicQuad intersector = IntAna_IntConicQuad(); - - intersector.Perform( gp_Lin( aCenter, aNormal), gp_Pln( aBasePnt, aNormal), Precision::Confusion() ); - if ( intersector.IsDone() && intersector.NbPoints() == 1 ) - aBasePnt = intersector.Point( 1 ); - } - - myPreviewPlane = new AIS_Plane( new Geom_Plane( aBasePnt, aNormal ) ); - myPreviewPlane->SetSize( aSize, aSize ); - - // Deactivate clipping planes - //myView->getViewPort()->getView()->SetPlaneOff(); - //myView->setPlaneOff(); - - ic->Display( myPreviewPlane, 1, -1, false ); - ic->SetWidth( myPreviewPlane, 10, false ); - ic->SetMaterial( myPreviewPlane, Graphic3d_NOM_PLASTIC, false ); - ic->SetTransparency( myPreviewPlane, 0.5, false ); - ic->SetColor( myPreviewPlane, Quantity_Color( 85 / 255., 85 / 255., 255 / 255., Quantity_TOC_RGB ), false ); - - anOCCViewer->update(); -} - - -/*! - Erases preview of clipping plane -*/ -void OCCViewer_ClippingDlg::erasePreview () -{ - OCCViewer_Viewer* anOCCViewer = (OCCViewer_Viewer*)myView->getViewManager()->getViewModel(); - if (!anOCCViewer) - return; - - Handle(AIS_InteractiveContext) ic = anOCCViewer->getAISContext(); - - if ( !myPreviewPlane.IsNull() && ic->IsDisplayed( myPreviewPlane ) ) - { -#if OCC_VERSION_LARGE <= 0x06060000 - ic->Erase( myPreviewPlane, false, false ); -#else - ic->Erase( myPreviewPlane, false ); -#endif - ic->Remove( myPreviewPlane, false ); - myPreviewPlane.Nullify(); - } - - anOCCViewer->update(); -} - - -/*! - SLOT: called on value changes (co-ordinates of point or normal) -*/ -void OCCViewer_ClippingDlg::onValueChanged() -{ - if ( PreviewChB->isChecked() ) - { - erasePreview(); - displayPreview(); - } + if( (QComboBox*)sender() == CBRelativeOrientation ) + SetCurrentPlaneParam(); + updateView(); } - /*! SLOT: called on preview check box toggled */ void OCCViewer_ClippingDlg::onPreview( bool on ) { erasePreview(); - if ( on ) displayPreview(); } /*! - \return true if plane parameters are valid + SLOT: called on Auto Apply check box toggled */ -bool OCCViewer_ClippingDlg::isValid() +void OCCViewer_ClippingDlg::onAutoApply( bool toggled ) { - return ( SpinBox_Dx->value()!=0 || SpinBox_Dy->value()!=0 || SpinBox_Dz->value()!=0 ); + if ( toggled ) onApply(); + myView3d->Update(); + myView3d->Redraw(); } /*! - Remember the current clipping plane + SLOT on Apply button click: sets cutting plane */ -void OCCViewer_ClippingDlg::ReserveClippingPlane() +void OCCViewer_ClippingDlg::onApply() { - /*Handle(V3d_View) aView3d = myView->getViewPort()->getView(); - if ( !aView3d.IsNull() ) - { - aView3d->InitActivePlanes(); - if ( aView3d->MoreActivePlanes() ) - myClippingPlane = aView3d->ActivePlane(); - }*/ + if ( myBusy ) + return; + myIsSelectPlane = true; + Graphic3d_SetOfHClipPlane aPlanes = myView3d->GetClipPlanes(); + Graphic3d_SetOfHClipPlane::Iterator anIter (aPlanes); + for( ;anIter.More();anIter.Next() ){ + Handle(Graphic3d_ClipPlane) aClipPlane = anIter.Value(); + aClipPlane->SetOn(Standard_False); + } + + qApp->processEvents(); + QApplication::setOverrideCursor( Qt::WaitCursor ); + qApp->processEvents(); + + for ( int i=0;iIsActive == true ) + myView->setCuttingPlane( true, aClipPlane->X , aClipPlane->Y , aClipPlane->Z, + aClipPlane->Dx, aClipPlane->Dy, aClipPlane->Dz ); + } + + QApplication::restoreOverrideCursor(); + myIsSelectPlane = false; } void OCCViewer_ClippingDlg::onViewShow() @@ -602,3 +1244,30 @@ void OCCViewer_ClippingDlg::onViewHide() hide(); } +/*! + SLOT: Called when value of slider distance change +*/ +void OCCViewer_ClippingDlg::SliderDistanceHasMoved( int value ) +{ + double new_value = value/100.; + TLValueDistance->setText( QString("%1").arg( new_value ) ); + onValueChanged(); +} + +/*! + SLOT: Called when value of slider rotation1 change +*/ +void OCCViewer_ClippingDlg::SliderRotation1HasMoved( int value ) +{ + TLValueRotation1->setText( QString("%1\xB0").arg( value ) ); + onValueChanged(); +} + +/*! + SLOT: Called when value of slider rotation2 change +*/ +void OCCViewer_ClippingDlg::SliderRotation2HasMoved( int value ) +{ + TLValueRotation2->setText( QString("%1\xB0").arg( value ) ); + onValueChanged(); +} diff --git a/src/OCCViewer/OCCViewer_ClippingDlg.h b/src/OCCViewer/OCCViewer_ClippingDlg.h index 92c785ab3..63ee8d84f 100644 --- a/src/OCCViewer/OCCViewer_ClippingDlg.h +++ b/src/OCCViewer/OCCViewer_ClippingDlg.h @@ -37,9 +37,43 @@ class QComboBox; class QCheckBox; class QtxDoubleSpinBox; class QtxAction; +class QStackedLayout; +class QSlider; +class QMenu; class OCCViewer_ViewWindow; +enum Mode { Absolute, Relative }; + +/*! + \class OrientedPlane + \brief Parameters of clipping plane in relative mode +*/ +class OrientedPlane { +public: + int Orientation; + double Distance; + double Rotation1; + double Rotation2; + OrientedPlane(); +}; + +/*! + \class ClipPlane + \brief Parameters of clipping plane +*/ +class ClipPlane { +public: + OrientedPlane RelativeMode; + double X,Y,Z,Dx,Dy,Dz; + int Orientation; + bool IsActive; + bool IsInvert; + Mode PlaneMode; + ClipPlane(); +}; +typedef ClipPlane* Pnt_ClipPlane; +typedef std::vector ClipPlaneVector; /*! \class OCCViewer_ClippingDlg @@ -49,69 +83,121 @@ class OCCViewer_ClippingDlg : public QDialog { Q_OBJECT - public: - OCCViewer_ClippingDlg(OCCViewer_ViewWindow* , const char* name = 0, bool modal = FALSE, Qt::WindowFlags fl = 0); - ~OCCViewer_ClippingDlg(); + public: + OCCViewer_ClippingDlg(OCCViewer_ViewWindow* , const char* name = 0, bool modal = FALSE, Qt::WindowFlags fl = 0); + ~OCCViewer_ClippingDlg(); - void SetAction( QtxAction* theAction ) { myAction = theAction; } + void SetAction( QtxAction* theAction ) { myAction = theAction; } + void synchronize(); + void SetCurrentPlaneParam(); + ClipPlaneVector myClippingPlanes; + bool isRestore; + private : - virtual void closeEvent( QCloseEvent* e ); - virtual void showEvent ( QShowEvent * ); - virtual void hideEvent ( QHideEvent * ); - void displayPreview(); - void erasePreview(); - void ReserveClippingPlane(); - - bool isValid(); - - QGroupBox* GroupPoint; - QLabel* TextLabelX; - QLabel* TextLabelY; - QLabel* TextLabelZ; - QtxDoubleSpinBox* SpinBox_X; - QtxDoubleSpinBox* SpinBox_Y; - QtxDoubleSpinBox* SpinBox_Z; - QPushButton* resetButton; + virtual void closeEvent( QCloseEvent* e ); + virtual void showEvent ( QShowEvent * ); + virtual void hideEvent ( QHideEvent * ); + void initParam(); + void displayPreview(); + void erasePreview(); + bool isValid(); + void updateView(); + + QComboBox* ComboBoxPlanes; + QCheckBox* isActivePlane; + QPushButton* buttonNew; + QMenu* MenuMode; + QPushButton* buttonDelete; + QPushButton* buttonDisableAll; + + QStackedLayout *ModeStackedLayout; + + QGroupBox* GroupAbsolutePoint; + QLabel* TextLabelX; + QLabel* TextLabelY; + QLabel* TextLabelZ; + QtxDoubleSpinBox* SpinBox_X; + QtxDoubleSpinBox* SpinBox_Y; + QtxDoubleSpinBox* SpinBox_Z; + QPushButton* resetButton; + + QGroupBox* GroupAbsoluteDirection; + QLabel* TextLabelDx; + QLabel* TextLabelDy; + QLabel* TextLabelDz; + QtxDoubleSpinBox* SpinBox_Dx; + QtxDoubleSpinBox* SpinBox_Dy; + QtxDoubleSpinBox* SpinBox_Dz; + QPushButton* invertButton; + QComboBox* CBAbsoluteOrientation; - QGroupBox* GroupDirection; - QLabel* TextLabelDx; - QLabel* TextLabelDy; - QLabel* TextLabelDz; - QtxDoubleSpinBox* SpinBox_Dx; - QtxDoubleSpinBox* SpinBox_Dy; - QtxDoubleSpinBox* SpinBox_Dz; - QPushButton* invertButton; + QGroupBox* GroupRelative; + QLabel* TextLabelOrientation; + QLabel* TextLabelDistance; + QLabel* TextLabelRotation1; + QLabel* TextLabelRotation2; + QLabel* TLValueDistance; + QLabel* TLValueRotation1; + QLabel* TLValueRotation2; + QSlider* SliderDistance; + QSlider* SliderRotation1; + QSlider* SliderRotation2; + QComboBox* CBRelativeOrientation; + + QCheckBox* PreviewCheckBox; + QCheckBox* AutoApplyCheckBox; + + QPushButton* buttonOk; + QPushButton* buttonApply; + QPushButton* buttonClose; - QComboBox* DirectionCB; + OCCViewer_ViewWindow* myView; + Handle(V3d_View) myView3d; - QCheckBox* PreviewChB; + std::vector myPreviewPlaneVector; - QPushButton* buttonApply; - QPushButton* buttonClose; - - OCCViewer_ViewWindow* myView; + bool myIsSelectPlane; + bool myBusy; - Handle(AIS_Plane) myPreviewPlane; - //Handle(V3d_Plane) myClippingPlane; - - bool myBusy; + Mode CurrentMode; + + QtxAction* myAction; - QtxAction* myAction; +public slots: + void onApply(); private slots: + + void ClickOnNew(); + void ClickOnDelete(); + void ClickOnDisableAll(); + void ClickOnOk(); void ClickOnApply(); void ClickOnClose(); + void ClickOnHelp(); + + void onModeAbsolute(); + void onModeRelative(); + + void onValueChanged(); + void onSelectPlane( int ); void onReset(); void onInvert(); - void onModeChanged( int mode ); - void onValueChanged(); + void onOrientationAbsoluteChanged( int ); + void onOrientationRelativeChanged (int); + void onPreview( bool on ); + void onAutoApply(bool); void onViewShow(); void onViewHide(); + + void SliderDistanceHasMoved(int); + void SliderRotation1HasMoved(int); + void SliderRotation2HasMoved(int); }; #endif // OCCVIEWER_CLIPPINGDLG_H diff --git a/src/OCCViewer/OCCViewer_ViewWindow.cxx b/src/OCCViewer/OCCViewer_ViewWindow.cxx index c783846ce..4697e6acb 100755 --- a/src/OCCViewer/OCCViewer_ViewWindow.cxx +++ b/src/OCCViewer/OCCViewer_ViewWindow.cxx @@ -1216,7 +1216,8 @@ void OCCViewer_ViewWindow::createActions() myClippingAction->setStatusTip(tr("DSC_CLIPPING")); myClippingAction->setCheckable( true ); connect(myClippingAction, SIGNAL(toggled( bool )), this, SLOT(onClipping( bool ))); - toolMgr()->registerAction( myClippingAction, ClippingId ); + // RNV: Temporary commented, this functionality will be moved into Geometry module + //toolMgr()->registerAction( myClippingAction, ClippingId ); aAction = new QtxAction(tr("MNU_SHOOT_VIEW"), aResMgr->loadPixmap( "OCCViewer", tr( "ICON_OCCVIEWER_SHOOT_VIEW" ) ), tr( "MNU_SHOOT_VIEW" ), 0, this); @@ -1587,7 +1588,6 @@ void OCCViewer_ViewWindow::onClipping( bool on ) { if ( myClippingDlg->isVisible() ) myClippingDlg->hide(); - aParent->setCuttingPlane(false); } } @@ -1671,6 +1671,10 @@ void OCCViewer_ViewWindow::performRestoring( const viewAspect& anItem, bool base aView3d->SetEye( anItem.eyeX, anItem.eyeY, anItem.eyeZ ); aView3d->SetProj( anItem.projX, anItem.projY, anItem.projZ ); aView3d->SetAxialScale( anItem.scaleX, anItem.scaleY, anItem.scaleZ ); + if ( myClippingDlg ) { + myClippingDlg->onApply(); + myClippingDlg->isRestore = false; + } if ( !baseParamsOnly ) { @@ -1957,15 +1961,15 @@ void OCCViewer_ViewWindow::setCuttingPlane( bool on, const double x, const doub gp_Pln pln (gp_Pnt(x, y, z), gp_Dir(dx, dy, dz)); double a, b, c, d; pln.Coefficients(a, b, c, d); - + #if OCC_VERSION_LARGE > 0x06060000 // Porting to OCCT higher 6.6.0 version Graphic3d_SetOfHClipPlane aPlanes = view->GetClipPlanes(); Handle(Graphic3d_ClipPlane) aClipPlane; if(aPlanes.Size() > 0 ) { Graphic3d_SetOfHClipPlane::Iterator anIter (aPlanes); - anIter.Next(); aClipPlane = anIter.Value(); aClipPlane->SetEquation(pln); + aClipPlane->SetOn(Standard_True); } else { aClipPlane = new Graphic3d_ClipPlane(pln); view->AddClipPlane(aClipPlane); @@ -1981,13 +1985,8 @@ void OCCViewer_ViewWindow::setCuttingPlane( bool on, const double x, const doub view->SetPlaneOn(clipPlane); } #else - if (view->MoreActivePlanes()) - clipPlane = view->ActivePlane(); - else - clipPlane = new V3d_Plane (viewer); - + clipPlane = new V3d_Plane (viewer); clipPlane->SetPlane(a, b, c, d); - view->SetPlaneOn(clipPlane); #endif } else { @@ -2023,7 +2022,17 @@ bool OCCViewer_ViewWindow::isCuttingPlane() { Handle(V3d_View) view = myViewPort->getView(); #if OCC_VERSION_LARGE > 0x06060000 // Porting to OCCT higher 6.6.0 version - return (view->GetClipPlanes().Size()); + bool res = false; + Graphic3d_SetOfHClipPlane aPlanes = view->GetClipPlanes(); + Graphic3d_SetOfHClipPlane::Iterator anIter (aPlanes); + for( ;anIter.More();anIter.Next() ) { + Handle(Graphic3d_ClipPlane) aClipPlane = anIter.Value(); + if(aClipPlane->IsOn()) { + res = true; + break; + } + } + return res; #else view->InitActivePlanes(); return (view->MoreActivePlanes()); @@ -2127,7 +2136,6 @@ viewAspect OCCViewer_ViewWindow::getViewParams() const return params; } - /*! \brief Get visual parameters of this view window. \return visual parameters of view window @@ -2157,6 +2165,34 @@ QString OCCViewer_ViewWindow::getVisualParameters() data << QString( "isVisible=%1" ).arg( params.isVisible ); data << QString( "size=%1" ) .arg( params.size, 0, 'f', 2 ); + if ( myClippingDlg ) { + if ( !myClippingDlg->myClippingPlanes.empty() ) { + for ( int i=0; i < myClippingDlg->myClippingPlanes.size(); i++ ) { + QString ClippingPlane = QString( "ClippingPlane%1=").arg( i+1 ); + Pnt_ClipPlane aPlane = myClippingDlg->myClippingPlanes[i]; + ClippingPlane += QString( "Mode~%1;").arg( (int)aPlane->PlaneMode ); + ClippingPlane += QString( "IsActive~%1;").arg( aPlane->IsActive ); + if ( aPlane->PlaneMode == Absolute ) { + ClippingPlane += QString( "AbsoluteOrientation~%1;" ).arg( aPlane->Orientation ); + ClippingPlane += QString( "IsInvert~%1;" ).arg( aPlane->IsInvert ); + ClippingPlane += QString( "X~%1;" ).arg( aPlane->X ); + ClippingPlane += QString( "Y~%1;" ).arg( aPlane->Y ); + ClippingPlane += QString( "Z~%1;" ).arg( aPlane->Z ); + ClippingPlane += QString( "Dx~%1;" ).arg( aPlane->Dx ); + ClippingPlane += QString( "Dy~%1;" ).arg( aPlane->Dy );; + ClippingPlane += QString( "Dz~%1" ).arg( aPlane->Dz ); + } + else if ( aPlane->PlaneMode == Relative ) { + ClippingPlane += QString( "RelativeOrientation~%1;" ).arg( aPlane->RelativeMode.Orientation ); + ClippingPlane += QString( "Distance~%1;" ).arg( aPlane->RelativeMode.Distance ); + ClippingPlane += QString( "Rotation1~%1;" ).arg( aPlane->RelativeMode.Rotation1 ); + ClippingPlane += QString( "Rotation2~%1" ).arg( aPlane->RelativeMode.Rotation2 ); + } + data << ClippingPlane; + } + } + } + #if OCC_VERSION_LARGE > 0x06030009 // available only with OCC-6.3-sp10 or newer version // graduated trihedron data << QString( "gtIsVisible=%1" ) .arg( params.gtIsVisible ); @@ -2239,6 +2275,41 @@ void OCCViewer_ViewWindow::setVisualParameters( const QString& parameters ) else if ( paramName == "scaleZ" ) params.scaleZ = paramValue.toDouble(); else if ( paramName == "isVisible" ) params.isVisible = paramValue.toInt(); else if ( paramName == "size" ) params.size = paramValue.toDouble(); + else if ( paramName.contains( "ClippingPlane" ) ) { + OCCViewer_ViewWindow* aParent = dynamic_cast(parent()->parent()); + if (!aParent) + aParent = this; + if ( !myClippingDlg ) + { + myClippingDlg = new OCCViewer_ClippingDlg( aParent ); + myClippingDlg->SetAction( myClippingAction ); + myClippingDlg->hide(); + } + QStringList ClipPlaneData = paramValue.split( ';' ); + ClipPlane* aPlane = new ClipPlane(); + foreach( QString ClipPlaneParam, ClipPlaneData ) { + QString ClipPlane_paramName = ClipPlaneParam.section( '~', 0, 0 ).trimmed(); + QString ClipPlane_paramValue = ClipPlaneParam.section( '~', 1, 1 ).trimmed(); + if ( ClipPlane_paramName == "Mode" ) aPlane->PlaneMode = ( Mode )ClipPlane_paramValue.toInt(); + else if ( ClipPlane_paramName == "IsActive" ) aPlane->IsActive = ClipPlane_paramValue.toInt(); + else if ( ClipPlane_paramName == "AbsoluteOrientation" ) aPlane->Orientation = ClipPlane_paramValue.toInt(); + else if ( ClipPlane_paramName == "IsInvert" ) aPlane->IsInvert = ClipPlane_paramValue.toInt(); + else if ( ClipPlane_paramName == "X" ) aPlane->X = ClipPlane_paramValue.toDouble(); + else if ( ClipPlane_paramName == "Y" ) aPlane->Y = ClipPlane_paramValue.toDouble(); + else if ( ClipPlane_paramName == "Z" ) aPlane->Z = ClipPlane_paramValue.toDouble(); + else if ( ClipPlane_paramName == "Dx" ) aPlane->Dx = ClipPlane_paramValue.toDouble(); + else if ( ClipPlane_paramName == "Dy" ) aPlane->Dy = ClipPlane_paramValue.toDouble(); + else if ( ClipPlane_paramName == "Dz" ) aPlane->Dz = ClipPlane_paramValue.toDouble(); + else if ( ClipPlane_paramName == "RelativeOrientation" ) aPlane->RelativeMode.Orientation = ClipPlane_paramValue.toInt(); + else if ( ClipPlane_paramName == "Distance" ) aPlane->RelativeMode.Distance = ClipPlane_paramValue.toDouble(); + else if ( ClipPlane_paramName == "Rotation1" ) aPlane->RelativeMode.Rotation1 = ClipPlane_paramValue.toDouble(); + else if ( ClipPlane_paramName == "Rotation2" ) aPlane->RelativeMode.Rotation2 = ClipPlane_paramValue.toDouble(); + } + myClippingDlg->myClippingPlanes.push_back( aPlane ); + myClippingDlg->isRestore = true; + myClippingDlg->synchronize(); + myClippingDlg->SetCurrentPlaneParam(); + } // graduated trihedron else if ( paramName == "gtIsVisible" ) params.gtIsVisible = paramValue.toInt(); else if ( paramName == "gtDrawNameX" ) params.gtDrawNameX = paramValue.toInt(); diff --git a/src/OCCViewer/resources/OCCViewer_msg_en.ts b/src/OCCViewer/resources/OCCViewer_msg_en.ts index d9d1f0d99..705f737b3 100644 --- a/src/OCCViewer/resources/OCCViewer_msg_en.ts +++ b/src/OCCViewer/resources/OCCViewer_msg_en.ts @@ -305,7 +305,7 @@ MNU_MINIMIZE_VIEW - Create sub-views + Minimize @@ -443,4 +443,115 @@ Z: + + OCCViewer_ClippingDlg + + CLIPPING_PLANES + Clipping planes + + + NO_PLANES + No planes + + + IS_ACTIVE_PLANE + Active + + + BTN_NEW + New + + + BTN_DELETE + Delete + + + AUTO_APPLY + Auto Apply + + + MODE + Mode + + + ORIENTATION + Orientation + + + DISTANCE + Distance + + + ROTATION_AROUND_X_Y2Z + Rotation around X (Y to Z): + + + ROTATION_AROUND_Y_X2Z + Rotation around Y (X to Z): + + + ROTATION_AROUND_Z_Y2X + Rotation around Z (Y to X): + + + ROTATION_AROUND_X_Z2Y + Rotation around X (Z to Y): + + + ROTATION_AROUND_Y_Z2X + Rotation around Y (Z to X): + + + ROTATION_AROUND_Z_X2Y + Rotation around Z (X to Y): + + + ALONG_XY + || X-Y + + + ALONG_YZ + || Y-Z + + + ALONG_ZX + || Z-X + + + ABSOLUTE + Absolute + + + RELATIVE + Relative + + + BTN_DISABLE_ALL + Disable all + + + PREVIEW + Preview + + + RESET + Reset + + + INVERT + Invert + + + BASE_POINT + Base point + + + DIRECTION + Direction + + + PARAMETERS + Parameters + + diff --git a/src/OCCViewer/resources/OCCViewer_msg_fr.ts b/src/OCCViewer/resources/OCCViewer_msg_fr.ts index 0f09189f0..250fda174 100755 --- a/src/OCCViewer/resources/OCCViewer_msg_fr.ts +++ b/src/OCCViewer/resources/OCCViewer_msg_fr.ts @@ -305,7 +305,7 @@ MNU_MINIMIZE_VIEW - Créer les sous-vues + Minimiser @@ -443,4 +443,115 @@ Z: + + OCCViewer_ClippingDlg + + CLIPPING_PLANES + Les plans de coupe + + + NO_PLANES + Aucuns plans + + + IS_ACTIVE_PLANE + Active + + + BTN_NEW + Nouveau + + + BTN_DELETE + Supprimer + + + AUTO_APPLY + Appliquer automatiquement + + + MODE + Mode + + + ORIENTATION + Orientation + + + DISTANCE + Distance + + + ROTATION_AROUND_X_Y2Z + Rotation autour de X (Y à Z): + + + ROTATION_AROUND_Y_X2Z + Rotation autour de Y (X à Z): + + + ROTATION_AROUND_Z_Y2X + Rotation autour de Z (Y à X): + + + ROTATION_AROUND_X_Z2Y + Rotation autour de X (Z à Y): + + + ROTATION_AROUND_Y_Z2X + Rotation autour de Y (Z à X): + + + ROTATION_AROUND_Z_X2Y + Rotation autour de Z (X à Y): + + + ALONG_XY + || X-Y + + + ALONG_YZ + || Y-Z + + + ALONG_ZX + || Z-X + + + ABSOLUTE + Absolute + + + RELATIVE + Relative + + + BTN_DISABLE_ALL + Désactiver tous + + + PREVIEW + Prévisualiser + + + RESET + Réinitialiser + + + INVERT + Inverser + + + BASE_POINT + Le point fondamental + + + DIRECTION + Direction + + + PARAMETERS + Paramètres + + diff --git a/src/STD/resources/STD_msg_en.ts b/src/STD/resources/STD_msg_en.ts index 84899db0f..dd91f9b92 100644 --- a/src/STD/resources/STD_msg_en.ts +++ b/src/STD/resources/STD_msg_en.ts @@ -215,6 +215,10 @@ Do you want to reload it ? BUT_CLOSE &Close + + BUT_APPLY_AND_CLOSE + A&pply and Close + INF_DESK_EXIT Exit diff --git a/src/STD/resources/STD_msg_fr.ts b/src/STD/resources/STD_msg_fr.ts index e8f4b4e79..87c71765e 100755 --- a/src/STD/resources/STD_msg_fr.ts +++ b/src/STD/resources/STD_msg_fr.ts @@ -215,6 +215,10 @@ Voulez-vous le réouvrir? BUT_CLOSE &Fermer + + BUT_APPLY_AND_CLOSE + A&ppliquer et Fermer + INF_DESK_EXIT &Quitter diff --git a/src/SVTK/SVTK_RenderWindowInteractor.cxx b/src/SVTK/SVTK_RenderWindowInteractor.cxx index 560cef7c3..6301ece1d 100644 --- a/src/SVTK/SVTK_RenderWindowInteractor.cxx +++ b/src/SVTK/SVTK_RenderWindowInteractor.cxx @@ -292,8 +292,20 @@ QVTK_RenderWindowInteractor GetDevice()->LeftButtonReleaseEvent(); else if( event->button() & Qt::MidButton ) GetDevice()->MiddleButtonReleaseEvent(); - else if( event->button() & Qt::RightButton ) + else if( event->button() & Qt::RightButton ) { + #ifndef Fix_Of_vtkImplicitPlaneWidget_bug + GetDevice()->SetEventInformationFlipY( -99999, -99999, + event->modifiers() & Qt::ControlModifier, + event->modifiers() & Qt::ShiftModifier); + GetDevice()->LeftButtonPressEvent(); + GetDevice()->LeftButtonReleaseEvent(); + GetDevice()->SetEventInformationFlipY(event->x(), + event->y(), + event->modifiers() & Qt::ControlModifier, + event->modifiers() & Qt::ShiftModifier); + #endif GetDevice()->RightButtonReleaseEvent(); + } } -- 2.39.2