From 9150fb3db9f16daea68ed8b24447aaadc171b61e Mon Sep 17 00:00:00 2001 From: vsr Date: Fri, 10 Dec 2010 13:15:53 +0000 Subject: [PATCH 1/1] Merge from PHASE_25_BR 09/12/2010 --- .../SMESH/images/bare_border_faces_smpl.png | Bin 0 -> 9095 bytes .../SMESH/images/bare_border_volumes_smpl.png | Bin 0 -> 7555 bytes .../gui/SMESH/images/controls_popup.png | Bin 0 -> 1900 bytes doc/salome/gui/SMESH/images/copy_mesh_dlg.png | Bin 0 -> 24617 bytes .../gui/SMESH/images/copy_mesh_icon.png | Bin 0 -> 1117 bytes .../SMESH/images/over_constrained_faces.png | Bin 0 -> 6599 bytes .../SMESH/images/over_constrained_volumes.png | Bin 0 -> 8184 bytes .../gui/SMESH/images/scalar_bar_dlg.png | Bin 0 -> 22098 bytes doc/salome/gui/SMESH/input/about_meshes.doc | 3 + .../SMESH/input/about_quality_controls.doc | 19 + .../gui/SMESH/input/bare_border_face.doc | 15 + .../gui/SMESH/input/bare_border_volumes.doc | 15 + doc/salome/gui/SMESH/input/copy_mesh.doc | 56 ++ .../SMESH/input/over_constrained_faces.doc | 14 + .../SMESH/input/over_constrained_volumes.doc | 14 + doc/salome/gui/SMESH/input/scalar_bar.doc | 40 ++ .../SMESH/input/selection_filter_library.doc | 16 +- .../gui/SMESH/input/tui_creating_meshes.doc | 44 ++ doc/salome/gui/SMESH/input/tui_filters.doc | 104 ++- .../gui/SMESH/input/tui_quality_controls.doc | 84 +++ idl/SMESH_Filter.idl | 35 +- idl/SMESH_Gen.idl | 68 +- resources/Makefile.am | 5 + resources/bare_border_face.png | Bin 0 -> 3168 bytes resources/bare_border_volume.png | Bin 0 -> 3369 bytes resources/copy_mesh.png | Bin 0 -> 1117 bytes resources/over_constrained_face.png | Bin 0 -> 3329 bytes resources/over_constrained_volume.png | Bin 0 -> 3444 bytes src/Controls/SMESH_Controls.cxx | 149 +++- src/Controls/SMESH_ControlsDef.hxx | 75 +- src/OBJECT/SMESH_Actor.cxx | 92 ++- src/OBJECT/SMESH_Actor.h | 4 +- src/OBJECT/SMESH_ActorDef.h | 2 + src/OBJECT/SMESH_DeviceActor.cxx | 33 +- src/SMESH/SMESH_Mesh.cxx | 14 +- src/SMESH/SMESH_MeshEditor.cxx | 38 +- src/SMESH/SMESH_subMesh.cxx | 2 +- src/SMESH/SMESH_subMesh.hxx | 2 +- src/SMESHFiltersSelection/SMESH_Type.h | 4 +- .../SMESH_TypeFilter.cxx | 6 + src/SMESHGUI/Makefile.am | 3 + src/SMESHGUI/SMESHGUI.cxx | 108 ++- src/SMESHGUI/SMESHGUI_CopyMeshDlg.cxx | 667 ++++++++++++++++++ src/SMESHGUI/SMESHGUI_CopyMeshDlg.h | 125 ++++ src/SMESHGUI/SMESHGUI_FilterDlg.cxx | 68 +- .../SMESHGUI_Preferences_ScalarBarDlg.cxx | 49 +- src/SMESHGUI/SMESHGUI_Utils.cxx | 2 +- src/SMESHGUI/SMESH_images.ts | 24 + src/SMESHGUI/SMESH_msg_en.ts | 99 +++ src/SMESH_I/SMESH_2smeshpy.cxx | 2 +- src/SMESH_I/SMESH_DumpPython.cxx | 81 ++- src/SMESH_I/SMESH_Filter_i.cxx | 182 ++++- src/SMESH_I/SMESH_Filter_i.hxx | 59 +- src/SMESH_I/SMESH_Gen_i.cxx | 215 +++++- src/SMESH_I/SMESH_Gen_i.hxx | 6 + src/SMESH_SWIG/smeshDC.py | 207 +++--- src/StdMeshers/StdMeshers_Import_1D.cxx | 432 +++++++----- src/StdMeshers/StdMeshers_Import_1D2D.cxx | 19 +- 58 files changed, 2829 insertions(+), 472 deletions(-) create mode 100644 doc/salome/gui/SMESH/images/bare_border_faces_smpl.png create mode 100644 doc/salome/gui/SMESH/images/bare_border_volumes_smpl.png create mode 100755 doc/salome/gui/SMESH/images/controls_popup.png create mode 100644 doc/salome/gui/SMESH/images/copy_mesh_dlg.png create mode 100644 doc/salome/gui/SMESH/images/copy_mesh_icon.png create mode 100644 doc/salome/gui/SMESH/images/over_constrained_faces.png create mode 100644 doc/salome/gui/SMESH/images/over_constrained_volumes.png create mode 100755 doc/salome/gui/SMESH/images/scalar_bar_dlg.png create mode 100644 doc/salome/gui/SMESH/input/bare_border_face.doc create mode 100644 doc/salome/gui/SMESH/input/bare_border_volumes.doc create mode 100644 doc/salome/gui/SMESH/input/copy_mesh.doc create mode 100644 doc/salome/gui/SMESH/input/over_constrained_faces.doc create mode 100644 doc/salome/gui/SMESH/input/over_constrained_volumes.doc create mode 100755 doc/salome/gui/SMESH/input/scalar_bar.doc create mode 100644 resources/bare_border_face.png create mode 100644 resources/bare_border_volume.png create mode 100644 resources/copy_mesh.png create mode 100644 resources/over_constrained_face.png create mode 100644 resources/over_constrained_volume.png create mode 100644 src/SMESHGUI/SMESHGUI_CopyMeshDlg.cxx create mode 100644 src/SMESHGUI/SMESHGUI_CopyMeshDlg.h diff --git a/doc/salome/gui/SMESH/images/bare_border_faces_smpl.png b/doc/salome/gui/SMESH/images/bare_border_faces_smpl.png new file mode 100644 index 0000000000000000000000000000000000000000..6b7ead85ef02ab273a2decc40729602d0bf24254 GIT binary patch literal 9095 zcmaJ{dpMJC+#lkXZKc`FCMBESj3(Q3(8(!h%dwb4*c>Zo;3P&Uf1Pf_j5n@bKl>?=kxh~pKzn{k7y*%7j=L1A%OUSeY6hh`I3PtzC!T;gh|y zBU=9)5U}61MP)gdo<i8U-237qLrzC_Won%-_TwpnTz_{TW>AAik*%d`86EZ6WKjCJ$D&9e4}#8 zAaZKRVC2{GrMThMU~B*PPtx-}oJFEo!S3Wl9R4IlT&%fC2k91bTMe^Q;<5pN1HLN>0O)y3h&0r`C@FydJu z1bXLC*5dNhqQuFi^jfg~14N>xSlM|O@!bKaOvkvDsp)bdr%nmEewx;J^3ziKv^lFL z2}*=-O4ZD*O8oU*d3tEcFLZz7@ZDAmL=SowVN;pidjm*u+@IazOuLhdubwu=Z9tFp zg<~4DP9Gt{i{WuCIGjNmhZDMY!^XYqEwZIv+GC8QLhSa5_qzxE=_XKdCILo2QF2-B zF+0sgGsifb#d^+k(elI05LWApnGdd}^e0K*V!6^410)mC@y({D@js~I`{b`7>2DLe zU;1QA{X4g`3SE0Eji1u`B0zU6*Jn`t)bPhtIG=BHy@7hF?6YenT|C01$fS+?$!pZu z(uWpzq``@quQjsTmKfniO1U77Ym1>9g#Z)@|iKVaxuAliDely_rH6JeT0LlN+ z^#*V6@L076hnYEP9Z9({_Z~T>ow!un%G03H-o9a_W}A?i z+RD2Vtf+%avFHKIZ?F2Nzv_#CuZYzwNNN4j^e@%BD_tt&gC^;!Y1_lKtk!N_VC2y} z2;yN%>)Bvz+y*SVHZi>$QYCetAn{$lKAsfv2WcvIaZb9}LMTqUg!ef~|GeC1Dz`WC zdmn-kUOG%59ByGw7LlkQ@@{mR9}edW_*D-(=ppsu;l!$r z;vJPS=cx&oq65=W1AP8CH2tE_I_$C5_qMRFZk2)4Ix$=FE_EsjnU6)R%DUd`{glY8 z?ZcPYrfjI4~9ifofhPy3qj@8&(Pp$h3**~SVU;sZVt-TSk%tq%v>z9I?2 z%duNRtk2Eh)!9w5RhIJE4u|QV1$^Tck2k0z^*!hF!=i(XDm{+kfidK6MYuZUAK%DS zr#iZRq17m(od|@jowEB8uM&6VcUby8(|Z&3_ii7Lr{iZAstarUN^`bTo#QS=pE8xx z3D>$)^U-IAOnRoJ7Y1WrbRD#jUc+iV z%eB%L;*`>{FFOA1`l$kwgy;$9DQdx$hmY+U)_BX3_Z8m~?Y4Qt=z+jsE z^tjmIFfi9()Az-FW?W4kfxQkq;Jal%$>qY;q6cGFine{({yGPVMRgs2qss`dslod^ zO{L#WAh`H2O$t1+-y+afccYI!`F`x?k8a;BXg%VYuIk-|!kLlzp9Azs-O=hou%B#W z2aoi(*!J+4`K_KFZTtT0w<~`Bz(<}zd1+pm_ejKwsDnP3yHCcoRdj(nQQB#|=R&51 zS-|Zuu;M8j!R|p}%u}X06u4S<4{)ftHZJ+IN8;NzI=pq*&a+X`H;JUH(4Ko~9Qe10 z+2a9r3{z2h7pE6Hm$wd^m(rS{*zGG5)U^qJ?ojj(<+hYo9_n_3tlhUg)6Y4)pTpx< zJG_rq)_+yimMnKOGCIhoUJOCz&J8t^X*7BftaA4P%AC*FxZ~lwRZRknsvl?A45sk0 z$C0=7P2}w)|I(}ad`>{it^y8bs~8GOEA-MIr^-971R zkh!KTGwm~G=54SRrd(%&_JWjsUaB3Qx^JNHg-x9`hrhmJXVszpy*I0~yV z&YbER+Q!q#4!_&7kU21&!7dMXH!t`^ClEBosZ%z$g{zUdajJ=b)?u$72q$!bC<9kU zRi@)6%%rjyknPIZAm)U$R@zc6bw9 z?7YxgybsaLoaGgeot<%ninZxlgH(RY@xF6qP@j^*R-W0kn%P6ys)42KXEaHcHphBw zO>nItUzzQo|5Ud;^S10ZUGudYK-TPLtOq5*wSj!4nQK+~D;1>nWxY51B*qWZer@gb zipV>&q^xIMm&oUr=8&n@b!6&oe)FscF~PNpeC1UKab|@vZ-R^~L` zbi+6}`Jzrr&U@h)0Tv5Dfkx9$`Bb8NRM{N$P^aYYlim;OxyFR#12d=A>o4V8CU3WP zds4oz!f-d&j_dJ#sBCVIOP2A#CUiPuvJI){>m^{~7fC3rCr3~yqgyJujpHOO&0faxq>>E)a>eBpT1pta&5?z zj~5IV8&PhU_0c5%)#+0W$J#@9{FafJ_j ze%7{0w=i!!_t@M^pbAB$GSKAH!8m+S7r$b>gSdwjbvB-``P;77B>%g%4Eq|858o0e z7v#>?bbGnbX?anEPkzkjd)UTnXf#J6<6_gWfUiADt7#UM21Apr0S@H&U2Hld=w~pg zee=~jwpual6+ouFa-EzWtv-w!gNH`UC7-KGocL+h*upS|CIcoc6%6f4%*f#SsJoS9K2UK_9B<0lx9pWgGvd(G=@H>C_4I4{AzgF`&uL;GyIM*cQ@6UySKW0R2?xo2?zuad`4rCwA-)w2a=-qNiR>*khA=0*QD^SZw$`v8^;~GWOihPR^9ZlWh!R2bA2Q8<9*$ zO9>j3QZ-+*Wc_Y8T~&S`I>#%EKJoS7K3^0DUF-V9Qd}yL4WH+Oz!R68XGEoGf_~r@ z@i3P=8S8{#8!uR&=UjxB|(2ausud#cb{t&%BXG;jc*a2p3s8VwKQ<8CM8sJl_mSz9urpEr%3?8F-T>}Zg9ke z72yd4q1ZDaq-z~|p2m2D_{!(6PIm&4g+Q-^%4BRS03Ua{UF6f$nChfWD03HTyjS&) zJ@G2KTT%n3Uez_`6A1a6-)(`G;9E+r0e4KK54Ag1hw~UQst)2EHWfB6L5N8$IARjs z+-0}&>aCaj4Rv^t`!c4&&~sf z#FfncY$fY|dFqHU1-56po8vaqXe?RMe#VUXFxLv7-~)zW`@zsnb4FNlF!rz{TYZ`0 z*x@X;(EHqf0})Za^va|Llw4eYes&62UNacj%6>Jw`Qm?D8XXSC3Z<<}$oI(^W3iXL znK_bKwO|L*X=UWP)W19A25A!3gMsgx0I8;aVanZ+m~i9BpRT%=nC~(71J!kleP5CF z^Z(AiHt5_+ZfN|`<}hvY5hbSy4h}r3U)v&G&Jn)zHSozv>ERC<(~Z`n@lPck;a*e z+|G2vh~GO5(v%I=6h^$h7_nr-_OP38yPfBcFDF)C97CoBZq<` zAakR~S}m@fybI3P<$&?^W=3SB{-Jp8sq?JtcYRVfoIfjWrev#=l9Y(>Z)D2OuGH6F z4RMhap9eZ)y^}6%S;5tR>J^eIgO&C4AGa*v4S0)WamlBiyr5k^dX%5XM4)wm^ITq@ z-*Ltzv%R9-aOr`XLd&0lWu;j*XWIQ||EXbm%O<_-@bj-fA&WlyioUC~UGw_$p*3}E zF|trM^cEeCC`w=aarz&5?=>a=jOn8dxc#=Y2sO)t8ynRW3=3`s#H-GRi|P(_Vp7f( zHii7|9#Nhh!Jka{y-)7`6*3VdVdUqJykOt>$dS;+TZkq@vHMXq&0aOOv9W1eLCCST zcEm`=;$DQ;kTN!rD0acEgr+2~+Eqd(b`hw@+IIeZ47Od@7OfYB8;ir8v=Ajejba(u zq2yYz8~5JhQ+gCkd5Aw$@gTyBw-{k+3P((vE?@hka0x=PVb~M1DT7z_R!)fQfTsg+ zC-;gIeGQ1k>kV#M*Y8={I)dNw0_p+&06S(Bw=yj#@_|qJ0jE| zrl!0e-3T@5%?_9Y-qSm5O7@P$P~a`?!5yOFm=>-oc^CQw97-CM?-VB3z|rZ12M(vZzI~ zUO}A2c6=mSwVfsFN`$-lGfjF}vawq5fdHn73rm)5k2%&XVok`y0NQ+DbLICdqER-C ztsy+j0sCaqXyqJ0L|SZPfS|;J_s}EP$REyg<;&`0 zwzW-M9uS^>tOY*-)|cPTKp=ES*58f~J!ommFk*4#3urC4>1?A2sEj8Pd()iWE5nuw z1t|DT-xI!X?AjrEuM%5o2RL+u@U(#zydM-MKUuN>F9bzg`AGy?aGCth_V|7psMHuU zi1r|s>}Pw-t@Z8YqhIN_0S12VcQ#uMt21NV4Z*a9!)<=g1>s8aTX`vG#{A@WM06>I z!P(Cm@8>Vs`2Px+WXWDIWy}lTQsl2y?*l|pLf$2AK?D>!v-|qF9*oh#9Dx7Nl##g_ z7ur%>tCJ3(%ri;fHAlBzrDiC<_VSoG5mqNi8b_I5`#aiQy(XOzv;Al1LHs_t?_aNI zHY7kxyx64g0ftEh(4A+L-mFKvx6A~wfzlO7v!Cs@`E8|tW?`2q+NsMdMUb>j3r_le zO`ZBgY8L=cG&Fg&&2Mhty<2la=8?JeJ)Tcy_JnrWGG@7ywPLtzs1|Ir8@l2# z*fI0lWpdE8jl8ETVbeVGzK1$#sgz6{`0=a==hOJbI;Got=b*qIaF@2g^~pNyT=0Mp z)cW!;VEq@(qVc5Jsc)rBGDTg9(JTc`J_1yL29>{$4l>c$4^%kSI>}D*FxxBS@=VZr zQVQ;jhypeO4+ z6ogiXKUYPdgTKr}<_6P){(Ny93lg68K*`;z27^HQ)wZ0zBM-angt-fLlcxmo38&65 z1|st4kV7q~ecYHp$|wTtv}D}%IiZ}OO4$>i^U3ltgPCK01L#dlOS(Ok{p{v7-Af*6 zJPr_80o_3FXlRhiPYVP4CJaY$K3yV>%VU~^K82*!=>YVOJ7B&nnu{j!D?Lw(P*`^Y zL4HF9yi4h@JWRWc>^5hC$BA!&7X7^o|2PssAcTYh5eY6z&^QBFaxfU%r$)7Cn~dET z0WI0!mASZlt7w_na_Yb%kOhb7XJ_JPZyah++2K_Vb-P0TaE{xF{ZUC@^glfLMn3(c zwA@xB#@&f?_~Fh3xDoUP~uQ{x6cr8P!9q_=_ zU93lF1&usy1E1R`=|C!&!p}Hhf|qQ8+E@t^HKi>cYMGhFtvsn(nOYq4>P+xZ+8j$M zx&LurbvC0_TG0{nbZI@pD8| z#c}u*SCJZL@ePL}wm|^>diLQ9uSSr<2Rj%Sgky17wHU_Z=%v&pX?-6$Ues1&(mhh$($yo*&h7L@*sL`FY;q9?Ko@2SO-#u0}^;a;u@n-lw2sE|0IB! z(;LO4{!5ZT=z3FgMG#M*`~h@S0!YnW^4Y54XH8;SfrY|%M6ed0&k`hs5aAhq%pB7q zWbQ{F9hU4d6GoUcV3(x=J}BQVX~Av%!POjYXUy?}<-vPP-gx7*A21dBIEiL@Y z0ViWRjLpG5ZM|#3$Vv&uTAkevs%H?Wa#{s^jqC(T-2`6LakuTHxO(M-#> zCaA|tfw4rpkjS1nInW8AKL+*d&R_7ywY?%ygsfmIyZJPYmSd?eS?>r+t_yS)m=luH z>yxAo3ZUiaAD67oL&qZp4I^jMWYp?`*v~!-azpKns3?D zo7+Hg3F8A94+OXhqd6O>Y|tHi)mjn0_|ETZ$tDwe*e2vZ*i(>5{bYgn259nq zE?hrH0Fowo>P@~>^z5EcK&5vd)xi0;J&fg1a$msfkVxU_D@6EtCetJpba=q!HWABq zH4OTnIKQQceqqAsB_WY+I8u3ru-FgiYFoNJpy^*gS7!){0Yz@%^Fd)@Y_n?%&knb7 z==Z+!;B7}WOLqTM9eE?|hB)_0yYL7gZ`O_C*bT~UYhjqTfL`$oW5cB_ynkL-D1W=6 zM<9R#r1$a`*qD_l_fwS`CVRe1#43}Aop|NN*i*kUGTnIsbJo~bu!`&wBLW>y=ziT{o=Gf8^4}dI&^DNAg_&rqGHdtNJR0F|;=Qmgdoo|7?3>OCvV_ zuYdagCB3tJs?>H$kc0>6T(7{oy&9%}a5Gz-WC>o-@ecqkuYc%0_(-Rf6;T)lT}oM| z_t@2kVY-R=<9dWc2y~Wn9-CqgPZoLqOCSUz(Sj^(7#>$S$V6dpJ`$Dg6-wtjhcbfT zxa8w}{#|4Gqa#Ojc>v;j|6Xj&-q9h<~9-k;0MEubZr$(wNozbK0%n>9xAN0WV zDX@kXMze~ziv^#mnozTNn~lm1{>+FZLDB@c?5=t8$1%6{0)1qz7DMWHIS9O%uRHR{ z05y6qr@`=*_?E`~k6%wp=%MFE{F~6Ce;N<9ti!&*S^4r@&gqV9o^O3{D{URRxAyTX z@+I5GMeZj7dGlr5EeWhcc583uJ$zzaZet_q(`IHTfqlhkRGV-o@l8wb@z3?-Vzg#cx~4Hc~to1T@bhELe@R*n?=w{)O3e znOQ3V-;5>b*tJMC2+jIc@??%V622PK*!j~_*D@fOj3u+q}>rp0L{h;V}Aui z(51;WH?0^(mmT*@wh1a`;=mip7RSrT#m6)yjXlt&lTxY!O&(Ixb0WOFO(IPoY44k? p?F*iYeD~4+?{A;{zoP-a{;Xwlk2k`594o)O*-8D`#{I)KcP;%B`;V(hXmAJ zd{!MhmemT0ddTw)}3aaPlFBU=#WEN`&nB-$X zBORtgg@@VqkBSj0r+WTPGa*E$vsgjkEd@{W1dj&AY=#8}C5ox%`?|D3<*QlkiBufq z@Px;Ce#Gz0B{M~+Gnl>P#dccb(U9ZLv)8-FDjLhaCnF%=Zin_;dtitdCphjVXIPn_ zp^m3L!xRS`w66|N>xKDwbSR;`#UVYHv5-%IP8TKR`e!0sBll0@@(8GWD8R*6-^ra&F9j&{+L&EH0akI1Gf8U)@D>O3UjqBNpkQ>fZfy zXdiv}@uity9RbbF+l$>u;870KMb<@%Rug2z7Jbx{T2CLd@Z7eExrg;o3AeBC4T=_7 zFT$XjDkdD#9kp(IwL-je6pochob`&!w>xSR|)=BkH5%d136P;Wp ztYE|Rg8LM(&ey$FbXLBAR&H&^)We|EbN@b0&UDn0?L0WW_S`7OJ*c71z^-#(YTLLm z&F1c}dwoI|k2#)Lf%Pta`yHp+Hj#mc^t)3=UfTr!#huDQJrnevN#@$^$9&B4w^S^C z{Yn!CqJ7TRmcd%PVlzc*J4(AD24#8RIZyepYa9jCESrcqK1e?Za~~Yp+;($%AxoP0 z!C*LM=IZ*!x+Wl9@EKP6kxJ4E%x?SSVwNT{#v89~qgiiT-mm9c^GL5^^Y6&YxweCr z_tZ=O)Jrpq=>LWmvo*n_(tX}oo&R7ozi~}#y{J8n` zd(Ktpz@Mvl!S{vqrAyiqGY;a+^FuiQg;txeK?l zT;`tP8`rd%l9y=fV~mD7S0@t<^+)NF!S{JJafWsOy3Ad~8?SCFuf4P>{b9kiUU)bm zVManM+5_)7Kb^rVFFVG}*egxdJnnd28&bOYXZWJl*eKlY;EP1>lNOvzS6eWQZ5sZZ zWIk@bb{R$3^At>5&O~$XwC%;3T_j*o@G(-__jJ50&xpX)!*EM_P2LmZq4KUpYW`s+Kv9g4jJ&T20{~~->Iw@^5i>SaD9rT7( zmZ7iA>iKjlOd1C}AKn^;TU1^LufLs3IwEcnh;h63G`mZP^<5)*+_uIYqYrJPO*T2# zi+wM;XRsM7nCioOV40WP)#Wkmv2fjIDh3tgr*ITkB0n6aTkQ1tdvf&4*oE0`r&d@5 zg!PoNThd8GMg;W5lH}PFQJo^=doRp9u$^W??&Bjr-|~;G_LjTqKBgt)k%r7LY0{`Z z*bTk%ZoK6CuMQhq^jnG$idI-!u;j62Mk}>nE>LU_*?e+mSi(WvhbuSy2J~DPW%hXO zfdjX`IsC0Or1lex1zwW>U}wjqbO$c)YQJ z;jb(#1Y+2C_@{N}i(3xgrR3%J!V4Sx5KdL=J0pJ$Q-m=d?{gVitoCz*P8qExFV6%J z(D$Y`3NGN!tKTJGM#k06=eZZ0AfW&Fhi-+ZO-V>;rsR+sDsIZNZZSljYu6b&HI-$o zDS({53`oMWNkjkX>n2`CF5Pbzjw5Qu!;1uO;>sTuME1hH^qm?Ej|mwwxo5RDT6T2x z4%b(2<_0}9SNg3iE1-8W|Et&9UB|G0yF*#{)gX`FR27$UKZAsd?7urc^lvSwC%7sJ zQ{8>c)*?LDUEZ?hVLjh?kq{at*x5Ta`Z2~PD8f&QBud`dDB02Y5RM#S%sp9GXcx|g ziA&dYiq6$sb^lcQv}2Nr+qp3mcrXc-aAt$D&=%Zd{xT2wM6$&_Blu5>H4tqhP-|dAPQcV?u*NWUS#IF12CI(@Qmp?QKT_mKm z-=yMB;~IwcH>neXG$10-OFPZ?oy#-Foz!u*+RyGZ?N}Bs8L+T)Q_vHlMMzYC=wmj+ zi(NpkGv6qm7?upX$$vu);tq*cLlr`SX5smE?;Kb)m~7xshdxvC?3wCUzae##h2>pO zeGvV7+c8ExuinK=B0QutZ@A>?#ML!&1XDuvCpiG^0{gD1?U$3ALF#9GF{!L)_R-b> z!}VU=-pLIlGClyq<&tDSI+93`pg?W z3w=(Fa1rykQA#kMk-G?r9n4U|G*BK*<&4tjO82fOL zThe-Ag1XpE#l0S@1GZ4Kf|kYRdJIL=wW z7DP)l4wH8G)?@f6zN_!du61tgqwLt9DejVKpxTlbMM=T4L?_$bax-E5qCtr=P(E>8 zl`#8X6z)KSpX;AOcOaC`#r4h=@~|^#IS*6QF7g$(IOe28VB;@nzsYs8{ zU&rPc<#TDgn^)akK(W@pV2QT74$L!`?Zwf_D}%$Ftm&I?TqmWC?AaeL6~*fSREIoh zmH<>e9FwUs7LF?@F{xve{{OUmULhN?B^?X=VPL9(5Cxm_#FsTYhiSJF;W%#C&4D)O zAZ|&nrO@F1BvXC*e+t^20QK>Y!53zxnPLQPd-iWY%{J}G5i_m@cv0{5!W~#y-y?6jIs%8&)wD92h~EMd35;EIjb@$Hjk9%v^J-#o5^V{RJ&<={s{^-1=8a5_Rgsq-`P96 z?yUx8#gljE^Kv9aCwIB4SKrYSWxV#k2%zL{R0Eh^)@Y@4o~uF8xS)6sJ6CzE^R8;F z9yg48FXeX~{_};Iy)Ov8M-y>zpytMeA;&E&Xk|8nWyPskOg-XWJfvdi}-MqUax=c@4W0 zLIhWJjKaBLF%vTmtZPWhC>?q$Sa zSt__wTw*qD={&N3yNTSXi7@*>F%ZxVPBHO}{rbv}Rfb1ZtTHWo{{o?pup* zbCeSAR?+401j0?=tn9PvhwxqBrhfoo-BJQTo>Ol*PCgf>Y_k8Q?G4vg#{!)UZUupC zUzyL*RzDAnogDLl=>#Tv?p#{x70})cj9NNV@;*OH9ErMyY>PjgNAUyRyeyY57?%^* zgZ4Ul)Y0m!AAUoGCh=<3s_H85EcdLoExpZwrIqBS%-@uS^~n~ElGOT>Kq!329lZBb z(D-2}cG~JECzB~zq%?aEX}_jb+bK|Z!;jXUWHj2^j@TX?Y2!#6K6_`EklGwr;n&FR zh9+oL<-R){qG8LmklM&!0bAEoWer4lNy1V8DG3`NoU7S5?UA9r(NR3+=J!Um0WI~p zA?@;f*t=E2Nnz+S(Td~z_URi}UgtIuZd5nO07)eVw9_YqpkTr}5nZ!!K#6 zGsihF-HC~gFHF)}aX{0Q;dAlcf2?yZQlDnyhlTO9ixgJL4L$}XJv-!W`wCb#>o4gK zsw|QSzpP`xY{gTrlFXOWy+0aqQrPgPwSJumHL8ZsUBbt-)H%FBF-J~7-*%TX4nI?n zd;f{_a3!NB53Xq9`dzmq92a5ke%=pX#8y5QGm2zJ2kS;Q8aC8^U} ze&sPu?=by9fFNcKXgold?ch5$tF6sH^P3?sxy{+g3-nmT`|_2}+?PdMPsN#H6=Zv0 zZk7Z*$!uh7bdB1At&A-1z2H1OM_PO5H?!80zgOA`eD&2&?Hy$|^b0LtVP^*yRjUeJ zACV~47n1g$_|JLJRyP{QVtHMu{rYoXD#rdtLa81q8%|osD`4YG!1|1A&4EDyPj}$J znJiXJOCL?|*vRW}15YY{!~S)l$H{gIa#N91>bM71@rj0tmolPzV&T8!c|g=7Q%7;` zDU6D&Xt28J#~5*t6%q|>;DGDo9ei`%9Bg?$r$1s-t-WunsOQ;LMBiB1n{30|1MCV_ zqc|E)FrGKa=Q&^Qr^Gue?Ge6#+tH&H?q?~O#qZN zCV2jdm38Tcgw4Fo{4)Iq)AP@Zhp?19-^VnLf?h7euXhfagR@-vL&q;5AWM8-giJ#M z=4%wD5#f6Vv}d{W^1^|w=HU&RtG%BtMjX1#0I6(T_)TMt4^-JR8T+waqTDPz(K=Zf zl;}}eC-H0*89tpz^qgUzwFe4esw}nD(q7p8&-mk^=}31ad`OIVqr1>w1~$d_`yt(mjBoi>X>b$*TrZ`x5PHWW=R-T7<^DM3#8a*hv`^5@<7T!v}}c$yYk)GfW$*t z?ubDxS|8I9_hV+3HXCz&Zx->sgy=yL=2xovX4AtjG`bv$Sm;n4`^wk%E&VIliH8p))m4p~kX(NyT--Ci7H=BQA?f(9Ka)Sq&vGJsLMgjLFoaWG1*G+WKHC z4XS@~!k{9;I?kIakRW{Z_yVqsMA1_qfuos<2i(=2pkvm(Tivz?Ca$9jzZffI{4fj4 za)gPRF{u3pT((wefrQvoDn?9#1_@BH@dPyji;D^f0~r`m!G;aG2XfB}QYz|1om5V2!Nj7?8p@k=kw+$kZRy0xCoLWs8+O+4PUXKM~0suxd$KsSuIFtGla?7^)9Um zrO33Jh?5KtY*4Nk5vyxr2g;qY2l^x1L8+HY#le4-;JX01dExk;zZ(`|hP*wgU+~T9 zgs5+^yT7R_!Gxe8WSfIFP|JO!Vs2*KoS;G<)81iR+SA$k z?{gq1D80j~?%sYhAJFg6vcad=;+T^NtJphf86`1v8X)UM|2p}*#`!rGDnM0L?x4@_ zNn5I4SbWHM&)_hs<}LY;S^Hli@8+wnyY9LbO4j&8qK!@tuDH9b!gS4odH2>BWIV(d zrjHqE4JpMFMR^dEKe7SiwmYh|ACwi)oBiC>x{~9nhG3QH@(~MMcfJ->PSy9KBez=0 z0EG^5WgTQVbJ7qE_@_o9PhV_?%9xmZWm|rBN%g~cT6O-gd1f_jmOpkBl@CH8VXpIqU9W$ReEGWi`Ly&)&gxmt1k!WMo4KvW z259|BJ`*ixiU&gGCA=xgc;fl;OX4xh;BW!!`Ux$IUGa`5{nEWxHk+Nqf2S{}1VQCZ z?>~n)CaQn1K|geP0Uhl8u?Zjn!#~ z2K0zSt`LlOr4-l?ndJ#rtg@|7L_$U%-b$XYrX5g)mV7Z#OH9-`_h#)rF2+GlG5hJ$ z_M3xOUr9KUV!raLSq9!ww$*|zSiA4MXw}{MGOtO+dv%WJO%nv=%-B@FUiGK#-Ns!% z7tc<8_`a&S9f4cZDSG8ulsD5fQhnV>5je#!z1=@0s80alwpl zgXn8XeVFUkmR(nWHU7Gk*dzaGu~ijXpXj!J!cq3O|7gg!+3fH4Y@%>bzx>9_>9I?v ze$C!WU0m-iN8~poO}72=8_l83x^qAkyw)4;=~5m}`^6dk#ryAk{?C)&tq}j6lOvAb z&Zob!4w>=d{F;34fA@Q_S2zywem{{ZFU#u@9}S`BH$u$L8&jf6NJJ-|nYS=};8H z>5ew)NgESY{AoEJg8H0f(2wTbE=k}IFi~`=hsZtHNtDy<1{nprl`qo7)ETEF=xH#! zoCN+VQ>|aHN<;|u5v>R&h}?qxet+){4iM$%9YSzR$FTVk59dOr=J!Z0hBiwYmiIyB zdh6#09gBvz@;SKrTTk@^-`b(lpM24Rj=b$cMz*%2IXxhleI|nt7X}ZYx??V*beo4& zb|oKN{sLYBEq3Thi`EZs7{x%=x8k&VvbyzecTekn8NzB!?oLK+YSw9yl{|HUY*-Ct nAf5$FN=YJmaIT>C*B_h4i`TH?_2R+5s*pF!&*QY4Aoc$M1H!$y literal 0 HcmV?d00001 diff --git a/doc/salome/gui/SMESH/images/controls_popup.png b/doc/salome/gui/SMESH/images/controls_popup.png new file mode 100755 index 0000000000000000000000000000000000000000..b0bd01fb9aa0a7abf50480a84e69439a29d91b18 GIT binary patch literal 1900 zcmZ`)X*3&X7Y;pCRWX)PdoeY{l9sf-Dx*|uX%v+rRAZT_p_T@*HK;8gB^ZJ%YO7eP zsV0_`;B<^Nw%F5(jM}29t(bNwKGT`bv}fk~ao_vnzUQ9%-1|KDraD};Iwqk$z=cwzXyn+NVlh&3z}01*HAcN4(rh${jBhgEDW&7qN`k9y`zLWQ^MJ*^+^*w;6< zqt%qMODHTtifV4ysMOf`)wd6;bsy&0zR!?4AtNi9Ci;0%4$uo)z!Q5$wyS2-&6|m& zx%J3N1RNTnh?jwnK52u8@dm}q1^>eE$M=s}xxJ!`-Jam6zeuO% zGD9@3XKqQw#NL5!cDWiYs}qKEi9SBwSU8AEx+tf~j6N3@1D?><2czlrD!npK#jDaW z=YlNysqZzd^NxY&qgbyIg!1`B({JDHc#L>^INC3$Hjtn+V|lxgN0^pPGcz+Qr7BoD z{#Lf_NC3MI!mnx6P5QYJYT$7wn&Yt5U$0VSfpxDVpHdLNsQe%q8gkCsS=z%ddn>Ou zUPniFQs;$y31<6*kHLB<(8m1ZY(B&Fd3VC3!}SmK-e?J2Zwhx>R9rJO!+EwD(>wU% z0YlSH!^*o}s2EOk^(n9pD}3QBhdm%=O2i1${AP5T2l^a3X*q`>6L_Jn$g>N9)G|JV zJ4GL?3M-5f^D;TQT9xoz*UfqYCZBP$Q9u7^5j2!o%<8QH9X(yOoE*q-j5fqr$yqycLcvqQekW$ugs)|Ms|V5M!l z{mHHS*JGnMrY=yldz{x$*?i(AhyX%B`N1X|S{p$m6`meGSV$H@!0bpLkwK?s(nW2BkkuQIleuCINK<2CyJ_Wb5hrSKkUoA5<{ z{#M?5u2#!_2q37S+zsam{{P^a$r6h3u~$ZZ^z%qODwN$doIpPC+-+s@L+6hoBaCn{}RAKhOxw(BK+2U@LFyhZ)s#!&b* z1l+B9ztr7{mDG0;oyD7XH975j22C&1#8WypbryTNEA||YAA4p_Y03QBD(720HRNL} zh3|4)lNgLCWt@#mcn+2`R(lte+jS@C?37noewMBO6~v@=@P+ByswvYK6?Ozo=(#%-oZBt0^%@ZdvEC}KjQ<4uuXXWLjge%*masT&8c+iLXZYia z11=yL&YQbUqyGgNMZ3ai^~H-`DUcXrSIbB06?7RZJ~ig_GMUTcebt%g!W(O3RxRA% z(&V~0tfR6XxaPTzo);~{ka7K`$^Mc1;$=MNex!3gLxlKVf^!3Ghhfb_ZB+EKi;SoS9dj1aB>3)lJ4PK1M)cQ+(PchdK5{^8 zZ|=+J=h^?VGe4@qI>0f8jY8tfiyVPzZiAFNlSxyhwe`i1v=gsbk>fbVg}!PTWVrn= zyh&Sj(@)7zX%^w;T%{2tSau^XG~$VA_;Ot=rzth#@hf=Z8FZvj1-?u2iMt#fy)SX^ zm6NCYVH6>1GmaCzOn#SaC^sIKzS9&Q5$`V?;IB}}y87!ab+@*l-CE=dJ3m5+`-5}h z_%kr9v${rfTN#5SjK#yH|2#gQ=9v|j34YmNS~R%0!G3BqC-t9e0#SyYAGTLrR)ey1 bep5}Ipqq<4t?NHHp8%UnS1loNIjF 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 literal 0 HcmV?d00001 diff --git a/doc/salome/gui/SMESH/images/copy_mesh_icon.png b/doc/salome/gui/SMESH/images/copy_mesh_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..263479f3bf79e868ee99d860c0c3b13ffb9b3d55 GIT binary patch literal 1117 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 literal 0 HcmV?d00001 diff --git a/doc/salome/gui/SMESH/images/over_constrained_volumes.png b/doc/salome/gui/SMESH/images/over_constrained_volumes.png new file mode 100644 index 0000000000000000000000000000000000000000..761144382c7140950b71a664885556b86018fd12 GIT binary patch literal 8184 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%0AgYRI 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 literal 0 HcmV?d00001 diff --git a/doc/salome/gui/SMESH/input/about_meshes.doc b/doc/salome/gui/SMESH/input/about_meshes.doc index 8a81c7ea0..c79f26644 100644 --- a/doc/salome/gui/SMESH/input/about_meshes.doc +++ b/doc/salome/gui/SMESH/input/about_meshes.doc @@ -16,6 +16,9 @@ for example, a face. Several created meshes can be \subpage building_compounds_page "combined into mesh compounds". +The whole mesh or it's part can be \subpage copy_mesh_page "copied" +into another mesh. + All created meshes and submeshes can be \subpage editing_meshes_page "edited". Meshes can be also edited using the MESH functions destined for diff --git a/doc/salome/gui/SMESH/input/about_quality_controls.doc b/doc/salome/gui/SMESH/input/about_quality_controls.doc index 8f78c38c5..124867c9e 100644 --- a/doc/salome/gui/SMESH/input/about_quality_controls.doc +++ b/doc/salome/gui/SMESH/input/about_quality_controls.doc @@ -32,6 +32,8 @@ Edge quality controls: Face quality controls:
  • \subpage free_faces_page "Free faces"
  • +
  • \subpage bare_border_faces_page "Bare border faces"
  • +
  • \subpage over_constrained_faces_page "Over-constrained faces"
  • \subpage length_2d_page "Length 2D"
  • \subpage borders_at_multi_connection_2d_page "Borders at multi-connection 2D"
  • \subpage area_page "Area"
  • @@ -48,6 +50,23 @@ Volume quality controls:
  • \subpage aspect_ratio_3d_page "Aspect ratio 3D"
  • \subpage volume_page "Volume"
  • \subpage max_element_length_3d_page "Max element length 3D"
  • +
  • \subpage bare_border_volumes_page "Bare border volumes"
  • +
  • \subpage over_constrained_volumes_page "Over-constrained volumes"
+To manage the quality controls call pop-up in the VTK viewer and select "Controls" sub-menu +\image html controls_popup.png + +
    +
  • Reset switches off quality controls;
  • +
  • Node Controls provides access to the node quality controls;
  • +
  • Edge Controls provides access to the edge quality controls;
  • +
  • Face Controls provides access to the face quality controls;
  • +
  • Volume Controls provides access to the volume quality controls;
  • +
  • Scalar Bar Properties allows setting \subpage scalar_bar_dlg;
  • +
  • Export Distribution... allows saving the distribution of quality control values in the text file;
  • +
  • Show Distribution Shows/Hides the distribution histogram of the quality control values in the VTK Viewer.
  • +
+ + */ diff --git a/doc/salome/gui/SMESH/input/bare_border_face.doc b/doc/salome/gui/SMESH/input/bare_border_face.doc new file mode 100644 index 000000000..2115d3249 --- /dev/null +++ b/doc/salome/gui/SMESH/input/bare_border_face.doc @@ -0,0 +1,15 @@ +/*! + +\page bare_border_faces_page Bare border faces + +This mesh quality control highlights the faces having the border not +shared with other faces (free border) and missing an edge based on +nodes of the free border. The faces with bare border are shown with a +color different from the color of shared faces. + +\image html bare_border_faces_smpl.png + +\sa A sample TUI Script making a group of faces highlighted in the +picture is \ref tui_bare_border_faces "Bare border faces Control". + +*/ diff --git a/doc/salome/gui/SMESH/input/bare_border_volumes.doc b/doc/salome/gui/SMESH/input/bare_border_volumes.doc new file mode 100644 index 000000000..d0dd894ba --- /dev/null +++ b/doc/salome/gui/SMESH/input/bare_border_volumes.doc @@ -0,0 +1,15 @@ +/*! + +\page bare_border_volumes_page Bare border volumes + +This mesh quality control highlights the volumes having the border not +shared with other volumes (free border) and missing a face based on +nodes of the free border. The volumes with bare border are shown with a +color different from the color of shared volumes. + +\image html bare_border_volumes_smpl.png + +\sa A sample TUI Script making a group of volumes highlighted in the +picture is \ref tui_bare_border_volumes "Bare border volumes Control". + +*/ diff --git a/doc/salome/gui/SMESH/input/copy_mesh.doc b/doc/salome/gui/SMESH/input/copy_mesh.doc new file mode 100644 index 000000000..2c65ab8d0 --- /dev/null +++ b/doc/salome/gui/SMESH/input/copy_mesh.doc @@ -0,0 +1,56 @@ +/*! + +\page copy_mesh_page Copy Mesh + +\n A mesh can be created by copying a part of or the whole other mesh. + +To make a copy of a mesh: + +\par +From the \b Mesh menu select Copy Mesh or click "Copy Mesh" +button in the toolbar. + +\image html copy_mesh_icon.png +
"Copy Mesh" button
+ +\par +The following dialog box will appear: + +\image html copy_mesh_dlg.png + +\par +In the dialog: +
    +
  • specify the part of mesh to copy: + +
      +
    • Select the whole mesh, submesh or group by mouse activating +this checkbox; or
    • +
    • choose mesh elements with the mouse in the 3D Viewer. It is +possible to select a whole area with a mouse frame; or
    • +
    • input the Source Element IDs directly in this field. The +selected elements will be highlighted in the viewer; or
    • +
    • apply Filters. Set filter button allows to apply a filter +to the selection of elements. See more about filters in the \ref +selection_filter_library_page "Selection filter library" page.
    • +
    +
  • + +
  • specify the New Mesh Name;
  • + +
  • specify the conditions of copying: +
      +
    • activate Generate groups checkbox to copy the groups of +elements of the source mesh to the newly created mesh.
    • +
    • activate Preserve IDs of elements checkbox to keep +the IDs of new nodes and elements the same as the IDs of source nodes +and elements.
    • +
    +
  • + +
  • Click \b Apply or Apply and Close button to confirm the operation.
  • +
+ +See Also a sample +\ref tui_copy_mesh "TUI Example of mesh copying." +*/ diff --git a/doc/salome/gui/SMESH/input/over_constrained_faces.doc b/doc/salome/gui/SMESH/input/over_constrained_faces.doc new file mode 100644 index 000000000..26ad944f7 --- /dev/null +++ b/doc/salome/gui/SMESH/input/over_constrained_faces.doc @@ -0,0 +1,14 @@ +/*! + +\page over_constrained_faces_page Over-constrained faces + +\n This mesh quality control highlights faces sharing only one of its borders with other faces. + +\image html over_constrained_faces.png + +In this picture the over-constrained face is displayed in red. + +
See Also a sample TUI Script of a +\ref tui_over_constrained_faces "Over-constrained faces" filter. + +*/ diff --git a/doc/salome/gui/SMESH/input/over_constrained_volumes.doc b/doc/salome/gui/SMESH/input/over_constrained_volumes.doc new file mode 100644 index 000000000..1519e0ae6 --- /dev/null +++ b/doc/salome/gui/SMESH/input/over_constrained_volumes.doc @@ -0,0 +1,14 @@ +/*! + +\page over_constrained_volumes_page Over-constrained volumes + +\n This mesh quality control highlights volumes sharing only one of its borders with other volumes. + +\image html over_constrained_volumes.png + +In this picture the over-constrained volume is displayed in red. + +
See Also a sample TUI Script of a +\ref tui_over_constrained_volumes "Over-constrained volumes" filter. + +*/ \ No newline at end of file diff --git a/doc/salome/gui/SMESH/input/scalar_bar.doc b/doc/salome/gui/SMESH/input/scalar_bar.doc new file mode 100755 index 000000000..146a7fa78 --- /dev/null +++ b/doc/salome/gui/SMESH/input/scalar_bar.doc @@ -0,0 +1,40 @@ +/*! + +\page scalar_bar_dlg Scalar Bar properties + +In this dialog you can specify the properties of the scalar bar + +\image html scalar_bar_dlg.png + +
    +
  • Scalar Range in this menu you can specify +Min value and Max value of the Scalar Bar
  • + +
  • Font - in this menu you can set type, face and color for +the font of Title and Labels of the Scalar +Bar
  • + +
  • Colors & Labels - in this menu you can set the number of +colors and the number of labels of the Scalar +Bar
  • + +
  • Orientation - allows choosing between vertical and +horizontal orientation of the Scalar Bar
  • . + +
  • Origin & Size Vertical & Horizontal - allows defining the +location (X and Y) and size (Width and +Height) of Scalar Bar
  • +
      +
    • X: abscissa of the origin (from the left +side)
    • +
    • Y: ordinate of the origin (from the bottom)
    • +
    +
  • Distribution in this menu you can Show/Hide distribution histogram of the values of the Scalar Bar and specify histogram properties
  • +
      +
    • Multicolor the histogram is colored as Scalar Bar
    • +
    • Monocolor the histogram is colored as selected with Distribution color selector
    • +
    +
+ + +*/ diff --git a/doc/salome/gui/SMESH/input/selection_filter_library.doc b/doc/salome/gui/SMESH/input/selection_filter_library.doc index 1f612994f..9657f4c0d 100644 --- a/doc/salome/gui/SMESH/input/selection_filter_library.doc +++ b/doc/salome/gui/SMESH/input/selection_filter_library.doc @@ -144,7 +144,14 @@ Additional criteria to select mesh Faces are the following: one element of mesh only. See also a \ref free_edges_page "Free Edges quality control".
  • -Free faces selects 3D mesh elements wich belong to less than two volumes. +Free faces selects 2D mesh elements wich belong to less than two volumes. +
  • +Faces with bare border selects 2D mesh elements having a free border without an edge on it. +See also \ref bare_border_faces_page "Bare border faces quality control". +
  • +Over-constrained faces selects 2D mesh elements having only one border shared +with other 2D elements. +See also \ref over_constrained_faces_page "Over-constrained faces quality control".
  • Borders at Multi-Connections 2D selects cells consisting of edges belonging to several elements of mesh. The number of mesh elements should be more, less or equal @@ -187,6 +194,13 @@ diagonals with a value of length, which is more, less or equal
  • Bad oriented volume selects mesh volumes, which are incorrectly oriented from the point of view of MED convention. +
  • +Over-constrained volumes selects mesh volumes having only one border shared +with other volumes. +See also \ref over_constrained_volumes_page "Over-constrained volumes quality control". +
  • +Volumes with bare border selects 3D mesh elements having a free border without a face on it. +See also \ref bare_border_volumes_page "Bare border volumes quality control".
  • diff --git a/doc/salome/gui/SMESH/input/tui_creating_meshes.doc b/doc/salome/gui/SMESH/input/tui_creating_meshes.doc index 359ffd7d5..bad32ebf4 100644 --- a/doc/salome/gui/SMESH/input/tui_creating_meshes.doc +++ b/doc/salome/gui/SMESH/input/tui_creating_meshes.doc @@ -249,4 +249,48 @@ demonstrating the resulting mesh. \skipline import geompy \until #end +
    +\anchor tui_copy_mesh +

    Mesh Copying

    +\code +from smesh import * +SetCurrentStudy(salome.myStudy) + +# make geometry of a box +box = geompy.MakeBoxDXDYDZ(100,100,100) +face = geompy.SubShapeAllSorted(box, geompy.ShapeType["FACE"])[0] + +# generate 3D mesh +mesh = Mesh(box) +localAlgo = mesh.Triangle(face) +mesh.AutomaticHexahedralization() + +# objects to copy +fGroup = mesh.GroupOnGeom( face, "2D on face") +nGroup = mesh.GroupOnGeom( face, "nodes on face", NODE) +subMesh = localAlgo.GetSubMesh() + +# make a new mesh by copying different part of the mesh + +# 1. copy the whole mesh +newMesh = CopyMesh( mesh, "whole mesh copy") + +# 2. copy a group of 2D elements along with groups +newMesh = CopyMesh( fGroup, "face group copy with groups",toCopyGroups=True) + +# 3. copy a group of nodes with preseving their ids +newMesh = CopyMesh( nGroup, "node group copy", toKeepIDs=True) + +# 4. copy some faces +faceIds = fGroup.GetIDs()[-10:] +newMesh = CopyMesh( mesh.GetIDSource( faceIds, FACE ), "some faces copy") + +# 5. copy some nodes +nodeIds = nGroup.GetIDs()[-10:] +newMesh = CopyMesh( mesh.GetIDSource( nodeIds, NODE), "some nodes copy") + +# 6. copy a sub-mesh +newMesh = CopyMesh( subMesh, "submesh copy" ) +\endcode + */ diff --git a/doc/salome/gui/SMESH/input/tui_filters.doc b/doc/salome/gui/SMESH/input/tui_filters.doc index 6677b2ab5..aa3e1eb1c 100755 --- a/doc/salome/gui/SMESH/input/tui_filters.doc +++ b/doc/salome/gui/SMESH/input/tui_filters.doc @@ -90,7 +90,7 @@ Filter 2D mesh elements (faces) according to the minimum angle value: # create mesh from SMESH_mechanic import * # get faces with minimum angle > 75 -filter = smesh.GetFilter(smesh.FACE, smesh.FT_MinimumAngle, smesh.FT_MoreThan, 75) +filter = smesh.GetFilter(smesh.FACE, smesh.FT_MinimumAngle,">", 75) ids = mesh.GetIdsFromFilter(filter) print "Number of faces with minimum angle > 75:", len(ids) \endcode @@ -237,7 +237,7 @@ from SMESH_mechanic import * # add node mesh.AddNode(0,0,0) # get all free nodes -filter = smesh.GetFilter(smesh.EDGE, smesh.FT_FreeNodes) +filter = smesh.GetFilter(smesh.NODE, smesh.FT_FreeNodes) ids = mesh.GetIdsFromFilter(filter) print "Number of free nodes:", len(ids) \endcode @@ -255,13 +255,69 @@ Filter free faces: # create mesh from SMESH_mechanic import * # get all free faces -filter = smesh.GetFilter(smesh.EDGE, smesh.FT_FreeFaces) +filter = smesh.GetFilter(smesh.FACE, smesh.FT_FreeFaces) ids = mesh.GetIdsFromFilter(filter) print "Number of free faces:", len(ids) \endcode \sa \ref tui_free_faces +\section filter_bare_border_faces Bare border faces + +Filter faces with bare borders: +- element type is \a smesh.FACE +- functor type is \a smesh.FT_BareBorderFace +- threshold value is not required + +\code +# create mesh +from SMESH_mechanic import * +# remove some faces to have faces with bare borders +mesh.RemoveElements( mesh.GetElementsByType(FACE)[0:5] ) +# get all faces bare borders +filter = smesh.GetFilter(smesh.FACE, smesh.FT_BareBorderFace) +ids = mesh.GetIdsFromFilter(filter) +print "Faces with bare borders:", ids +\endcode + +\sa \ref tui_bare_border_faces + +\section filter_coplanar_faces Coplanar faces + +Filter faces with bare borders: +- element type is \a smesh.FACE +- functor type is \a smesh.FT_CoplanarFaces +- threshold value is the face ID +- tolerance is in degrees + +\code +# create mesh +from SMESH_mechanic import * +faceID = mesh.GetElementsByType(FACE)[0] +# get all faces co-planar to the first face with tolerance 5 degrees +filter = smesh.GetFilter(smesh.FACE, smesh.FT_CoplanarFaces,faceID,Tolerance=5.0) +ids = mesh.GetIdsFromFilter(filter) +print "Number of faces coplanar with the first one:", len(ids) +\endcode + +\section filter_over_constrained_faces Over-constrained faces + +Filter over-constrained faces: +- element type is \a smesh.FACE +- functor type is \a smesh.FT_OverConstrainedFace +- threshold value is not required + +\code +# create mesh +from SMESH_mechanic import * +# get all over-constrained faces +filter = smesh.GetFilter(smesh.FACE, smesh.FT_OverConstrainedFace) +ids = mesh.GetIdsFromFilter(filter) +print "Over-constrained faces:", ids +\endcode + +\sa \ref tui_over_constrained_faces + \section filter_borders_multiconnection Borders at multi-connection Filter border 1D mesh elements (edges) according to the specified number of @@ -377,6 +433,48 @@ print "Number of volumes with maximum element length > 10:", len(ids) \sa \ref tui_max_element_length_3d +\section filter_bare_border_volumes Bare border volumes + +Filter 3D mesh elements with bare borders: +- element type is \a smesh.VOLUME +- functor type is \a smesh.FT_BareBorderVolume +- threshold value is not required + +\code +# create mesh +from SMESH_mechanic import * +mesh.Tetrahedron() +mesh.Compute() +# remove some volumes to have volumes with bare borders +mesh.RemoveElements( mesh.GetElementsByType(VOLUME)[0:5] ) +# get all volumes with bare borders +filter = smesh.GetFilter(smesh.VOLUME, smesh.FT_BareBorderVolume) +ids = mesh.GetIdsFromFilter(filter) +print "Volumes with bare borders:", ids +\endcode + +\sa \ref tui_bare_border_volumes + +\section filter_over_constrained_volumes Over-constrained volumes + +Filter over-constrained volumes: +- element type is \a smesh.VOLUME +- functor type is \a smesh.FT_OverConstrainedVolume +- threshold value is not required + +\code +# create mesh +from SMESH_mechanic import * +mesh.Tetrahedron() +mesh.Compute() +# get all over-constrained volumes +filter = smesh.GetFilter(smesh.VOLUME, smesh.FT_OverConstrainedVolume) +ids = mesh.GetIdsFromFilter(filter) +print "Over-constrained volumes:", ids +\endcode + +\sa \ref tui_over_constrained_faces + \section filter_belong_to_geom Belong to Geom Filter mesh entities (nodes or elements) which all nodes lie on the diff --git a/doc/salome/gui/SMESH/input/tui_quality_controls.doc b/doc/salome/gui/SMESH/input/tui_quality_controls.doc index fc496dcde..420e507e1 100644 --- a/doc/salome/gui/SMESH/input/tui_quality_controls.doc +++ b/doc/salome/gui/SMESH/input/tui_quality_controls.doc @@ -309,6 +309,90 @@ aGroup.Add(aFaceIds) salome.sg.updateObjBrowser(1) \endcode +\section tui_bare_border_faces Bare border faces + +\code +from smesh import * +SetCurrentStudy(salome.myStudy) + +box = geompy.MakeBoxDXDYDZ(100, 100, 100) +geompy.addToStudy( box, "box" ) + +mesh = smesh.Mesh(box) +mesh.Segment().NumberOfSegments(3) +mesh.Quadrangle() +mesh.Compute() + +# remove 2 faces +allFaces = mesh.GetElementsByType(FACE) +mesh.RemoveElements( allFaces[0:2]) + +bareGroup = mesh.MakeGroup("bare faces", FACE, FT_BareBorderFace) +assert(bareGroup.Size() == 3) +\endcode + +\section tui_bare_border_volumes Bare border volumes + +\code +from smesh import * +SetCurrentStudy(salome.myStudy) + +box = geompy.MakeBoxDXDYDZ(100, 30, 10) +# the smallest face of the box +face = geompy.SubShapeAllSorted( box, geompy.ShapeType["FACE"])[0] + +geompy.addToStudy( box, "box" ) +geompy.addToStudyInFather( box, face, "face" ) + +mesh = Mesh(box) +mesh.AutomaticHexahedralization(); + +# remove half of mesh faces from the smallest face +faceFaces = mesh.GetSubMeshElementsId(face) +faceToRemove = faceFaces[: len(faceFaces)/2] +mesh.RemoveElements( faceToRemove ) + +# make a group of volumes missing the removed faces +bareGroup = mesh.MakeGroup("bare volumes", VOLUME, FT_BareBorderVolume) +assert(bareGroup.Size() == len( faceToRemove)) +\endcode + +\section tui_over_constrained_faces Over-constrained faces +\code +from smesh import * +SetCurrentStudy(salome.myStudy) + +mesh = Mesh() +faceFilter = GetFilter(FACE,FT_OverConstrainedFace) + +#make an edge +n1 = mesh.AddNode(0,0,0) +n2 = mesh.AddNode(10,0,0) +edge = mesh.AddEdge([n1,n2]) +assert( not mesh.GetIdsFromFilter( faceFilter )) + +# make faces +mesh.ExtrusionSweep([edge], MakeDirStruct(0,7,0), 5) +assert( 2 == len( mesh.GetIdsFromFilter( faceFilter ))) +\endcode + +\section tui_over_constrained_volumes Over-constrained volumes +\code +from smesh import * +SetCurrentStudy(salome.myStudy) + +mesh = Mesh() +volumeFilter = GetFilter(VOLUME,FT_OverConstrainedVolume) + +# make volumes by extrusion of one face +n1 = mesh.AddNode(0,0,0) +n2 = mesh.AddNode(10,0,0) +edge = mesh.AddEdge([n1,n2]) +mesh.ExtrusionSweep([edge], MakeDirStruct(0,7,0), 1) +mesh.ExtrusionSweep( mesh.GetElementsByType(FACE), MakeDirStruct(0,0,5), 7) +assert( 2 == len( mesh.GetIdsFromFilter( volumeFilter ))) +\endcode + \section tui_length_2d Length 2D \code diff --git a/idl/SMESH_Filter.idl b/idl/SMESH_Filter.idl index e12607bcd..087a0b48b 100644 --- a/idl/SMESH_Filter.idl +++ b/idl/SMESH_Filter.idl @@ -64,6 +64,10 @@ module SMESH FT_LyingOnGeom, FT_RangeOfIds, FT_BadOrientedVolume, + FT_BareBorderVolume, + FT_BareBorderFace, + FT_OverConstrainedVolume, + FT_OverConstrainedFace, FT_LinearOrQuadratic, FT_GroupColor, FT_ElemGeomType, @@ -88,6 +92,7 @@ module SMESH }; typedef sequence Histogram; + /*! * Base interface for all functors ( i.e. numerical functors and predicates ) */ @@ -98,8 +103,6 @@ module SMESH ElementType GetElementType(); }; - - /*! * Numerical functors are intended for calculating value by Id of mesh entity */ @@ -150,6 +153,7 @@ module SMESH Values GetValues(); }; + /*! * Predicates are intended for verification of criteria, * must return bool value by mesh id @@ -166,6 +170,29 @@ module SMESH */ interface BadOrientedVolume: Predicate {}; + /*! + * Logical functor (predicate) "Volumes with bare border". + * Verify whether a mesh volume has a free facet without a mesh face on it + */ + interface BareBorderVolume: Predicate {}; + /*! + * Logical functor (predicate) "Faces with bare border". + * Verify whether a mesh face has a side not shared with another face + * and without a mesh edge on it + */ + interface BareBorderFace: Predicate {}; + + /*! + * Logical functor (predicate) "Over-constrained Volume" + * Verify whether a mesh volume has only one facet shared with other volumes + */ + interface OverConstrainedVolume: Predicate {}; + /*! + * Logical functor (predicate) "Over-constrained Face". + * Verify whether a mesh face has only one border shared with other faces + */ + interface OverConstrainedFace: Predicate {}; + /*! * Logical functor (predicate) "Belong To Geometry". * Verify whether mesh element or node belong to pointed Geom Object @@ -503,6 +530,10 @@ module SMESH RangeOfIds CreateRangeOfIds(); BadOrientedVolume CreateBadOrientedVolume(); + BareBorderVolume CreateBareBorderVolume(); + BareBorderFace CreateBareBorderFace(); + OverConstrainedVolume CreateOverConstrainedVolume(); + OverConstrainedFace CreateOverConstrainedFace(); LinearOrQuadratic CreateLinearOrQuadratic(); GroupColor CreateGroupColor(); diff --git a/idl/SMESH_Gen.idl b/idl/SMESH_Gen.idl index 3c375e625..d958719e3 100644 --- a/idl/SMESH_Gen.idl +++ b/idl/SMESH_Gen.idl @@ -221,10 +221,45 @@ module SMESH raises ( SALOME::SALOME_Exception ); /*! - * Create a Mesh object, without a geometry shape reference + * Create a mesh by copying a part of another mesh + * \param meshPart - a part of mesh to copy + * \param meshName - a name of the new mesh + * \param toCopyGroups - to create in the new mesh groups + * the copied elements belongs to + * \param toKeepIDs - to preserve IDs of the copied elements or not */ -// SMESH_Mesh NewEmpty() -// raises ( SALOME::SALOME_Exception ); + SMESH_Mesh CopyMesh(in SMESH_IDSource meshPart, + in string meshName, + in boolean toCopyGroups, + in boolean toKeepIDs) + raises ( SALOME::SALOME_Exception ); + + /*! + * Concatenate the given meshes into one mesh. + * Union groups with the same name and type if + * theUniteIdenticalGroups flag is true. + * Merge coincident nodes and elements if + * theMergeNodesAndElements flag is true. + */ + SMESH_Mesh Concatenate(in mesh_array theMeshesArray, + in boolean theUniteIdenticalGroups, + in boolean theMergeNodesAndElements, + in double theMergeTolerance) + raises ( SALOME::SALOME_Exception ); + + /*! + * Concatenate the given meshes into one mesh. + * Union groups with the same name and type if + * theUniteIdenticalGroups flag is true. + * Merge coincident nodes and elements if + * theMergeNodesAndElements flag is true. + * Create the groups of all elements from initial meshes. + */ + SMESH_Mesh ConcatenateWithGroups(in mesh_array theMeshesArray, + in boolean theUniteIdenticalGroups, + in boolean theMergeNodesAndElements, + in double theMergeTolerance) + raises ( SALOME::SALOME_Exception ); /*! * Mesh a subShape. @@ -309,33 +344,6 @@ module SMESH in long theElementID) raises ( SALOME::SALOME_Exception ); - /*! - * Concatenate the given meshes into one mesh. - * Union groups with the same name and type if - * theUniteIdenticalGroups flag is true. - * Merge coincident nodes and elements if - * theMergeNodesAndElements flag is true. - */ - SMESH_Mesh Concatenate(in mesh_array theMeshesArray, - in boolean theUniteIdenticalGroups, - in boolean theMergeNodesAndElements, - in double theMergeTolerance) - raises ( SALOME::SALOME_Exception ); - - /*! - * Concatenate the given meshes into one mesh. - * Union groups with the same name and type if - * theUniteIdenticalGroups flag is true. - * Merge coincident nodes and elements if - * theMergeNodesAndElements flag is true. - * Create the groups of all elements from initial meshes. - */ - SMESH_Mesh ConcatenateWithGroups(in mesh_array theMeshesArray, - in boolean theUniteIdenticalGroups, - in boolean theMergeNodesAndElements, - in double theMergeTolerance) - raises ( SALOME::SALOME_Exception ); - /*! * \brief Return id of object, registered in current study context * diff --git a/resources/Makefile.am b/resources/Makefile.am index cc7d5a885..623d04ff1 100644 --- a/resources/Makefile.am +++ b/resources/Makefile.am @@ -107,6 +107,10 @@ dist_salomeres_DATA = \ mesh_vertex_n.png \ mesh_vertex.png \ mesh_volume_3d.png \ + bare_border_volume.png \ + bare_border_face.png \ + over_constrained_volume.png \ + over_constrained_face.png \ mesh_wireframe.png \ mesh_points.png \ mesh_wrap.png \ @@ -173,6 +177,7 @@ dist_salomeres_DATA = \ mesh_tree_hypo_projection_3d.png \ mesh_tree_hypo_projection_2d.png \ mesh_build_compound.png \ + copy_mesh.png \ mesh_node_to_point.png \ mesh_tree_mesh_partial.png \ mesh_extractGroup.png \ diff --git a/resources/bare_border_face.png b/resources/bare_border_face.png new file mode 100644 index 0000000000000000000000000000000000000000..1993f2087f86b35ee09a9f1fdb7530e0785a0ae1 GIT binary patch literal 3168 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 literal 0 HcmV?d00001 diff --git a/resources/copy_mesh.png b/resources/copy_mesh.png new file mode 100644 index 0000000000000000000000000000000000000000..263479f3bf79e868ee99d860c0c3b13ffb9b3d55 GIT binary patch literal 1117 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 LNkvXXu0mjfR4HPG literal 0 HcmV?d00001 diff --git a/resources/over_constrained_volume.png b/resources/over_constrained_volume.png new file mode 100644 index 0000000000000000000000000000000000000000..0e2da263fc8d6a08e7d1634fd589703529a3a5b8 GIT binary patch literal 3444 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 nbEvents, - std::vector& funValues) + std::vector& funValues, + const vector& elements, + const double* minmax) { if ( nbIntervals < 1 || !myMesh || @@ -326,13 +330,30 @@ void NumericalFunctor::GetHistogram(int nbIntervals, // get all values sorted std::multiset< double > values; - SMDS_ElemIteratorPtr elemIt = myMesh->elementsIterator(GetType()); - while ( elemIt->more() ) - values.insert( GetValue( elemIt->next()->GetID() )); + if ( elements.empty() ) + { + SMDS_ElemIteratorPtr elemIt = myMesh->elementsIterator(GetType()); + while ( elemIt->more() ) + values.insert( GetValue( elemIt->next()->GetID() )); + } + else + { + vector::const_iterator id = elements.begin(); + for ( ; id != elements.end(); ++id ) + values.insert( GetValue( *id )); + } + if ( minmax ) + { + funValues[0] = minmax[0]; + funValues[nbIntervals] = minmax[1]; + } + else + { + funValues[0] = *values.begin(); + funValues[nbIntervals] = *values.rbegin(); + } // case nbIntervals == 1 - funValues[0] = *values.begin(); - funValues[nbIntervals] = *values.rbegin(); if ( nbIntervals == 1 ) { nbEvents[0] = values.size(); @@ -350,15 +371,21 @@ void NumericalFunctor::GetHistogram(int nbIntervals, std::multiset< double >::iterator min = values.begin(), max; for ( int i = 0; i < nbIntervals; ++i ) { + // find end value of i-th interval double r = (i+1) / double( nbIntervals ); funValues[i+1] = funValues.front() * (1-r) + funValues.back() * r; + + // count values in the i-th interval if there are any if ( min != values.end() && *min <= funValues[i+1] ) { - max = values.upper_bound( funValues[i+1] ); // greater than funValues[i+1], or end() + // find the first value out of the interval + max = values.upper_bound( funValues[i+1] ); // max is greater than funValues[i+1], or end() nbEvents[i] = std::distance( min, max ); min = max; } } + // add values larger than minmax[1] + nbEvents.back() += std::distance( min, values.end() ); } //======================================================================= @@ -1902,7 +1929,115 @@ SMDSAbs_ElementType BadOrientedVolume::GetType() const return SMDSAbs_Volume; } +/* + Class : BareBorderVolume +*/ + +bool BareBorderVolume::IsSatisfy(long theElementId ) +{ + SMDS_VolumeTool myTool; + if ( myTool.Set( myMesh->FindElement(theElementId))) + { + for ( int iF = 0; iF < myTool.NbFaces(); ++iF ) + if ( myTool.IsFreeFace( iF )) + { + const SMDS_MeshNode** n = myTool.GetFaceNodes(iF); + vector< const SMDS_MeshNode*> nodes( n, n+myTool.NbFaceNodes(iF)); + if ( !myMesh->FindElement( nodes, SMDSAbs_Face, /*Nomedium=*/false)) + return true; + } + } + return false; +} + +/* + Class : BareBorderFace +*/ + +bool BareBorderFace::IsSatisfy(long theElementId ) +{ + if ( const SMDS_MeshElement* face = myMesh->FindElement(theElementId)) + if ( face->GetType() == SMDSAbs_Face ) + { + int nbN = face->NbCornerNodes(); + for ( int i = 0; i < nbN; ++i ) + { + // check if a link is shared by another face + const SMDS_MeshNode* n1 = face->GetNode( i ); + const SMDS_MeshNode* n2 = face->GetNode( (i+1)%nbN ); + SMDS_ElemIteratorPtr fIt = n1->GetInverseElementIterator( SMDSAbs_Face ); + bool isShared = false; + while ( !isShared && fIt->more() ) + { + const SMDS_MeshElement* f = fIt->next(); + isShared = ( f != face && f->GetNodeIndex(n2) != -1 ); + } + if ( !isShared ) + { + myLinkNodes.resize( 2 + face->IsQuadratic()); + myLinkNodes[0] = n1; + myLinkNodes[1] = n2; + if ( face->IsQuadratic() ) + myLinkNodes[2] = face->GetNode( i+nbN ); + return !myMesh->FindElement( myLinkNodes, SMDSAbs_Edge, /*noMedium=*/false); + } + } + } + return false; +} + +/* + Class : OverConstrainedVolume +*/ +bool OverConstrainedVolume::IsSatisfy(long theElementId ) +{ + // An element is over-constrained if it has N-1 free borders where + // N is the number of edges/faces for a 2D/3D element. + SMDS_VolumeTool myTool; + if ( myTool.Set( myMesh->FindElement(theElementId))) + { + int nbSharedFaces = 0; + for ( int iF = 0; iF < myTool.NbFaces(); ++iF ) + if ( !myTool.IsFreeFace( iF ) && ++nbSharedFaces > 1 ) + break; + return ( nbSharedFaces == 1 ); + } + return false; +} + +/* + Class : OverConstrainedFace +*/ + +bool OverConstrainedFace::IsSatisfy(long theElementId ) +{ + // An element is over-constrained if it has N-1 free borders where + // N is the number of edges/faces for a 2D/3D element. + if ( const SMDS_MeshElement* face = myMesh->FindElement(theElementId)) + if ( face->GetType() == SMDSAbs_Face ) + { + int nbSharedBorders = 0; + int nbN = face->NbCornerNodes(); + for ( int i = 0; i < nbN; ++i ) + { + // check if a link is shared by another face + const SMDS_MeshNode* n1 = face->GetNode( i ); + const SMDS_MeshNode* n2 = face->GetNode( (i+1)%nbN ); + SMDS_ElemIteratorPtr fIt = n1->GetInverseElementIterator( SMDSAbs_Face ); + bool isShared = false; + while ( !isShared && fIt->more() ) + { + const SMDS_MeshElement* f = fIt->next(); + isShared = ( f != face && f->GetNodeIndex(n2) != -1 ); + } + if ( isShared && ++nbSharedBorders > 1 ) + break; + } + return ( nbSharedBorders == 1 ); + } + return false; +} /* Class : FreeBorders diff --git a/src/Controls/SMESH_ControlsDef.hxx b/src/Controls/SMESH_ControlsDef.hxx index 915bd9f4b..0a71438d7 100644 --- a/src/Controls/SMESH_ControlsDef.hxx +++ b/src/Controls/SMESH_ControlsDef.hxx @@ -127,9 +127,11 @@ namespace SMESH{ virtual void SetMesh( const SMDS_Mesh* theMesh ); virtual double GetValue( long theElementId ); virtual double GetValue(const TSequenceOfXYZ& thePoints) { return -1.0;}; - void GetHistogram(int nbIntervals, - std::vector& nbEvents, - std::vector& funValues); + void GetHistogram(int nbIntervals, + std::vector& nbEvents, + std::vector& funValues, + const std::vector& elements, + const double* minmax=0); virtual SMDSAbs_ElementType GetType() const = 0; virtual double GetBadRate( double Value, int nbNodes ) const = 0; long GetPrecision() const; @@ -373,11 +375,72 @@ namespace SMESH{ virtual void SetMesh( const SMDS_Mesh* theMesh ); virtual bool IsSatisfy( long theElementId ); virtual SMDSAbs_ElementType GetType() const; - + protected: const SMDS_Mesh* myMesh; }; - + + /* + BareBorderVolume + */ + class SMESHCONTROLS_EXPORT BareBorderVolume: public Predicate + { + public: + BareBorderVolume():myMesh(0) {} + virtual void SetMesh( const SMDS_Mesh* theMesh ) { myMesh = theMesh; } + virtual SMDSAbs_ElementType GetType() const { return SMDSAbs_Volume; } + virtual bool IsSatisfy( long theElementId ); + protected: + const SMDS_Mesh* myMesh; + }; + typedef boost::shared_ptr BareBorderVolumePtr; + + /* + BareBorderFace + */ + class SMESHCONTROLS_EXPORT BareBorderFace: public Predicate + { + public: + BareBorderFace():myMesh(0) {} + virtual void SetMesh( const SMDS_Mesh* theMesh ) { myMesh = theMesh; } + virtual SMDSAbs_ElementType GetType() const { return SMDSAbs_Face; } + virtual bool IsSatisfy( long theElementId ); + protected: + const SMDS_Mesh* myMesh; + std::vector< const SMDS_MeshNode* > myLinkNodes; + }; + typedef boost::shared_ptr BareBorderFacePtr; + + /* + OverConstrainedVolume + */ + class SMESHCONTROLS_EXPORT OverConstrainedVolume: public Predicate + { + public: + OverConstrainedVolume():myMesh(0) {} + virtual void SetMesh( const SMDS_Mesh* theMesh ) { myMesh = theMesh; } + virtual SMDSAbs_ElementType GetType() const { return SMDSAbs_Volume; } + virtual bool IsSatisfy( long theElementId ); + protected: + const SMDS_Mesh* myMesh; + }; + typedef boost::shared_ptr OverConstrainedVolumePtr; + + /* + OverConstrainedFace + */ + class SMESHCONTROLS_EXPORT OverConstrainedFace: public Predicate + { + public: + OverConstrainedFace():myMesh(0) {} + virtual void SetMesh( const SMDS_Mesh* theMesh ) { myMesh = theMesh; } + virtual SMDSAbs_ElementType GetType() const { return SMDSAbs_Face; } + virtual bool IsSatisfy( long theElementId ); + protected: + const SMDS_Mesh* myMesh; + std::vector< const SMDS_MeshNode* > myLinkNodes; + }; + typedef boost::shared_ptr OverConstrainedFacePtr; /* Class : FreeEdges @@ -399,7 +462,7 @@ namespace SMESH{ }; typedef std::set TBorders; void GetBoreders(TBorders& theBorders); - + protected: const SMDS_Mesh* myMesh; }; diff --git a/src/OBJECT/SMESH_Actor.cxx b/src/OBJECT/SMESH_Actor.cxx index 4afc7f4ca..bba1f3b32 100644 --- a/src/OBJECT/SMESH_Actor.cxx +++ b/src/OBJECT/SMESH_Actor.cxx @@ -199,6 +199,25 @@ SMESH_ActorDef::SMESH_ActorDef() aFilter->RegisterCellsWithType(VTK_QUADRATIC_PYRAMID); aFilter->RegisterCellsWithType(VTK_CONVEX_POINT_SET); + my3DExtActor = SMESH_DeviceActor::New(); + my3DExtActor->SetUserMatrix(aMatrix); + my3DExtActor->PickableOff(); + my3DExtActor->SetProperty(my2DExtProp); + my3DExtActor->SetBackfaceProperty(my2DExtProp); + my3DExtActor->SetRepresentation(SMESH_DeviceActor::eSurface); + aFilter = my3DExtActor->GetExtractUnstructuredGrid(); + aFilter->SetModeOfChanging(VTKViewer_ExtractUnstructuredGrid::eAdding); + aFilter->RegisterCellsWithType(VTK_TETRA); + aFilter->RegisterCellsWithType(VTK_VOXEL); + aFilter->RegisterCellsWithType(VTK_HEXAHEDRON); + aFilter->RegisterCellsWithType(VTK_WEDGE); + aFilter->RegisterCellsWithType(VTK_PYRAMID); + aFilter->RegisterCellsWithType(VTK_QUADRATIC_TETRA); + aFilter->RegisterCellsWithType(VTK_QUADRATIC_HEXAHEDRON); + aFilter->RegisterCellsWithType(VTK_QUADRATIC_WEDGE); + aFilter->RegisterCellsWithType(VTK_QUADRATIC_PYRAMID); + aFilter->RegisterCellsWithType(VTK_CONVEX_POINT_SET); + //Definition 1D device of the actor //--------------------------------- myEdgeProp = vtkProperty::New(); @@ -532,6 +551,7 @@ SMESH_ActorDef::~SMESH_ActorDef() my2DExtProp->Delete(); my2DExtActor->Delete(); my3DActor->Delete(); + my3DExtActor->Delete(); myNodeActor->Delete(); myBaseActor->Delete(); @@ -723,8 +743,8 @@ SetControlMode(eControl theMode, bool anIsScalarVisible = theMode > eNone; - if(anIsScalarVisible){ - switch(theMode){ + if(anIsScalarVisible) { + switch(theMode) { case eLength: { SMESH::Controls::Length* aControl = new SMESH::Controls::Length(); @@ -755,6 +775,14 @@ SetControlMode(eControl theMode, myFunctor.reset(new SMESH::Controls::FreeFaces()); myControlActor = my2DActor; break; + case eBareBorderFace: + myFunctor.reset(new SMESH::Controls::BareBorderFace()); + myControlActor = my2DActor; + break; + case eOverConstrainedFace: + myFunctor.reset(new SMESH::Controls::OverConstrainedFace()); + myControlActor = my2DActor; + break; case eMultiConnection: myFunctor.reset(new SMESH::Controls::MultiConnection()); myControlActor = my1DActor; @@ -819,6 +847,18 @@ SetControlMode(eControl theMode, myControlActor = my3DActor; break; } + case eBareBorderVolume: + { + myFunctor.reset(new SMESH::Controls::BareBorderVolume()); + myControlActor = my3DActor; + break; + } + case eOverConstrainedVolume: + { + myFunctor.reset(new SMESH::Controls::OverConstrainedVolume()); + myControlActor = my3DActor; + break; + } case eMinimumAngle: { SMESH::Controls::MinimumAngle* aControl = new SMESH::Controls::MinimumAngle(); @@ -860,14 +900,22 @@ SetControlMode(eControl theMode, my1DExtActor->SetExtControlMode(myFunctor); break; case eFreeFaces: + case eBareBorderFace: + case eOverConstrainedFace: my2DExtActor->SetExtControlMode(myFunctor); break; + case eBareBorderVolume: + case eOverConstrainedVolume: + my3DExtActor->SetExtControlMode(myFunctor); + break; case eLength2D: case eMultiConnection2D: my1DExtActor->SetExtControlMode(myFunctor,myScalarBarActor,myLookupTable); + UpdateDistribution(); break; default: myControlActor->SetControlMode(myFunctor,myScalarBarActor,myLookupTable); + UpdateDistribution(); } } @@ -911,6 +959,7 @@ void SMESH_ActorDef::AddToRender(vtkRenderer* theRenderer){ theRenderer->AddActor(myNodeExtActor); my3DActor->AddToRender(theRenderer); + my3DExtActor->AddToRender(theRenderer); my2DActor->AddToRender(theRenderer); my2DExtActor->AddToRender(theRenderer); @@ -954,6 +1003,7 @@ void SMESH_ActorDef::RemoveFromRender(vtkRenderer* theRenderer){ my2DActor->RemoveFromRender(theRenderer); my2DExtActor->RemoveFromRender(theRenderer); my3DActor->RemoveFromRender(theRenderer); + my3DExtActor->RemoveFromRender(theRenderer); theRenderer->RemoveActor(myScalarBarActor); theRenderer->RemoveActor(myPointLabels); @@ -989,6 +1039,7 @@ bool SMESH_ActorDef::Init(TVisualObjPtr theVisualObj, my2DActor->Init(myVisualObj,myImplicitBoolean); my2DExtActor->Init(myVisualObj,myImplicitBoolean); my3DActor->Init(myVisualObj,myImplicitBoolean); + my3DExtActor->Init(myVisualObj,myImplicitBoolean); my0DActor->GetMapper()->SetLookupTable(myLookupTable); //my0DExtActor->GetMapper()->SetLookupTable(myLookupTable); @@ -999,6 +1050,7 @@ bool SMESH_ActorDef::Init(TVisualObjPtr theVisualObj, my2DActor->GetMapper()->SetLookupTable(myLookupTable); my2DExtActor->GetMapper()->SetLookupTable(myLookupTable); my3DActor->GetMapper()->SetLookupTable(myLookupTable); + my3DExtActor->GetMapper()->SetLookupTable(myLookupTable); vtkFloatingPointType aFactor, aUnits; my2DActor->GetPolygonOffsetParameters(aFactor,aUnits); @@ -1071,6 +1123,7 @@ void SMESH_ActorDef::SetTransform(VTKViewer_Transform* theTransform){ my2DActor->SetTransform(theTransform); my2DExtActor->SetTransform(theTransform); my3DActor->SetTransform(theTransform); + my3DExtActor->SetTransform(theTransform); Modified(); } @@ -1126,6 +1179,7 @@ void SMESH_ActorDef::SetShrinkFactor(vtkFloatingPointType theValue){ my2DActor->SetShrinkFactor(theValue); my2DExtActor->SetShrinkFactor(theValue); my3DActor->SetShrinkFactor(theValue); + my3DExtActor->SetShrinkFactor(theValue); Modified(); } @@ -1141,6 +1195,7 @@ void SMESH_ActorDef::SetShrink(){ my2DActor->SetShrink(); my2DExtActor->SetShrink(); my3DActor->SetShrink(); + my3DExtActor->SetShrink(); myIsShrunk = true; Modified(); @@ -1157,6 +1212,7 @@ void SMESH_ActorDef::UnShrink(){ my2DActor->UnShrink(); my2DExtActor->UnShrink(); my3DActor->UnShrink(); + my3DExtActor->UnShrink(); myIsShrunk = false; Modified(); @@ -1203,6 +1259,7 @@ void SMESH_ActorDef::SetVisibility(int theMode, bool theIsUpdateRepersentation){ my2DActor->VisibilityOff(); my2DExtActor->VisibilityOff(); my3DActor->VisibilityOff(); + my3DExtActor->VisibilityOff(); myScalarBarActor->VisibilityOff(); myPointLabels->VisibilityOff(); @@ -1222,8 +1279,14 @@ void SMESH_ActorDef::SetVisibility(int theMode, bool theIsUpdateRepersentation){ my1DExtActor->VisibilityOn(); break; case eFreeFaces: + case eBareBorderFace: + case eOverConstrainedFace: my2DExtActor->VisibilityOn(); break; + case eBareBorderVolume: + case eOverConstrainedVolume: + my3DExtActor->VisibilityOn(); + break; case eLength2D: case eMultiConnection2D: my1DExtActor->VisibilityOn(); @@ -1456,6 +1519,7 @@ void SMESH_ActorDef::SetRepresentation (int theMode) //my0DExtActor->SetVisibility(false); my1DExtActor->SetVisibility(false); my2DExtActor->SetVisibility(false); + my3DExtActor->SetVisibility(false); // ??? //my0DActor->SetProperty(aProp); @@ -1786,6 +1850,7 @@ SMESH_ActorDef::SetImplicitFunctionUsed(bool theIsImplicitFunctionUsed) my2DActor->SetImplicitFunctionUsed(theIsImplicitFunctionUsed); my2DExtActor->SetImplicitFunctionUsed(theIsImplicitFunctionUsed); my3DActor->SetImplicitFunctionUsed(theIsImplicitFunctionUsed); + my3DExtActor->SetImplicitFunctionUsed(theIsImplicitFunctionUsed); } vtkIdType @@ -1947,7 +2012,7 @@ void SMESH_ActorDef::UpdateScalarBar() myScalarBarActor->SetDistributionColoringType(coloringType); QColor distributionColor = mgr->colorValue("SMESH", "distribution_color", - QColor(255, 255, 255)); + QColor(255, 255, 255)); double rgb[3]; rgb[0]= distributionColor.red()/255.; rgb[1]= distributionColor.green()/255.; @@ -1957,6 +2022,27 @@ void SMESH_ActorDef::UpdateScalarBar() } +void SMESH_ActorDef::UpdateDistribution() +{ + if(SMESH::Controls::NumericalFunctor* fun = + dynamic_cast(myFunctor.get())) + { + int nbIntervals = myScalarBarActor->GetMaximumNumberOfColors(); + std::vector nbEvents; + std::vector funValues; + SMESH_VisualObjDef::TEntityList elems; + if ( ! dynamic_cast(myVisualObj.get())) + dynamic_cast(myVisualObj.get())->GetEntities( fun->GetType(), elems ); + std::vector elemIds; + for ( SMESH_VisualObjDef::TEntityList::iterator e = elems.begin(); e != elems.end(); ++e) + elemIds.push_back( (*e)->GetID()); + vtkLookupTable* lookupTable = static_cast(myScalarBarActor->GetLookupTable()); + double * range = lookupTable->GetRange(); + fun->GetHistogram(nbIntervals, nbEvents, funValues, elemIds, range); + myScalarBarActor->SetDistribution(nbEvents); + } +} + void SMESH_ActorDef::SetQuadratic2DRepresentation(EQuadratic2DRepresentation theMode) { switch(theMode) { diff --git a/src/OBJECT/SMESH_Actor.h b/src/OBJECT/SMESH_Actor.h index 24a57a00a..744571e41 100644 --- a/src/OBJECT/SMESH_Actor.h +++ b/src/OBJECT/SMESH_Actor.h @@ -123,7 +123,8 @@ class SMESHOBJECT_EXPORT SMESH_Actor: public SALOME_Actor enum eControl{eNone, eLength, eLength2D, eFreeBorders, eFreeEdges, eFreeNodes, eFreeFaces, eMultiConnection, eArea, eTaper, eAspectRatio, eMinimumAngle, eWarping, eSkew, eAspectRatio3D, eMultiConnection2D, eVolume3D, - eMaxElementLength2D, eMaxElementLength3D}; + eMaxElementLength2D, eMaxElementLength3D, eBareBorderFace, eBareBorderVolume, + eOverConstrainedFace, eOverConstrainedVolume}; virtual void SetControlMode(eControl theMode) = 0; virtual eControl GetControlMode() = 0; virtual SMESH::Controls::FunctorPtr GetFunctor() = 0; @@ -141,6 +142,7 @@ class SMESHOBJECT_EXPORT SMESH_Actor: public SALOME_Actor virtual long GetControlsPrecision() const = 0; virtual void UpdateScalarBar() = 0; + virtual void UpdateDistribution() = 0; }; diff --git a/src/OBJECT/SMESH_ActorDef.h b/src/OBJECT/SMESH_ActorDef.h index 09b2232f0..53001f4ef 100644 --- a/src/OBJECT/SMESH_ActorDef.h +++ b/src/OBJECT/SMESH_ActorDef.h @@ -196,6 +196,7 @@ class SMESH_ActorDef : public SMESH_Actor virtual long GetControlsPrecision() const { return myControlsPrecision; } virtual void UpdateScalarBar(); + virtual void UpdateDistribution(); virtual void SetQuadratic2DRepresentation(EQuadratic2DRepresentation); @@ -234,6 +235,7 @@ class SMESH_ActorDef : public SMESH_Actor SMESH_DeviceActor* my2DActor; SMESH_DeviceActor* my2DExtActor; SMESH_DeviceActor* my3DActor; + SMESH_DeviceActor* my3DExtActor; SMESH_DeviceActor* myControlActor; vtkProperty* myNodeExtProp; diff --git a/src/OBJECT/SMESH_DeviceActor.cxx b/src/OBJECT/SMESH_DeviceActor.cxx index 600a4987c..d4a04203b 100644 --- a/src/OBJECT/SMESH_DeviceActor.cxx +++ b/src/OBJECT/SMESH_DeviceActor.cxx @@ -310,12 +310,6 @@ SMESH_DeviceActor double aValue = aNumericalFunctor->GetValue(anObjId); aScalars->SetValue(i,aValue); } - int nbIntervals = theScalarBarActor->GetMaximumNumberOfColors(); - std::vector nbEvents; - std::vector funValues; - aNumericalFunctor->GetHistogram(nbIntervals, nbEvents, funValues); - theScalarBarActor->SetDistribution(nbEvents); - }else if(Predicate* aPredicate = dynamic_cast(theFunctor.get())){ for(vtkIdType i = 0; i < aNbCells; i++){ vtkIdType anId = myExtractUnstructuredGrid->GetInputId(i); @@ -475,16 +469,6 @@ SMESH_DeviceActor myMergeFilter->SetScalars(aDataSet); aDataSet->Delete(); } - - //Set Distribution - if(NumericalFunctor* aNumericalFunctor = dynamic_cast(theFunctor.get())){ - int nbIntervals = theScalarBarActor->GetMaximumNumberOfColors(); - std::vector nbEvents; - std::vector funValues; - aNumericalFunctor->GetHistogram(nbIntervals, nbEvents, funValues); - theScalarBarActor->SetDistribution(nbEvents); - } - } GetMapper()->SetScalarVisibility(anIsInitialized); theScalarBarActor->SetVisibility(anIsInitialized); @@ -500,8 +484,13 @@ SMESH_DeviceActor myVisualObj->UpdateFunctor(theFunctor); using namespace SMESH::Controls; - if ( dynamic_cast(theFunctor.get()) || - dynamic_cast(theFunctor.get()) ) { + if ( dynamic_cast(theFunctor.get()) || + dynamic_cast(theFunctor.get()) || + dynamic_cast(theFunctor.get()) || + dynamic_cast(theFunctor.get()) || + dynamic_cast(theFunctor.get()) || + dynamic_cast(theFunctor.get())) + { Predicate* aFreePredicate = dynamic_cast(theFunctor.get()); myExtractUnstructuredGrid->SetModeOfChanging(VTKViewer_ExtractUnstructuredGrid::eAdding); vtkUnstructuredGrid* aGrid = myVisualObj->GetUnstructuredGrid(); @@ -514,7 +503,9 @@ SMESH_DeviceActor if(!myExtractUnstructuredGrid->IsCellsRegistered()) myExtractUnstructuredGrid->RegisterCell(-1); SetUnstructuredGrid(myVisualObj->GetUnstructuredGrid()); - }else if(FreeEdges* aFreeEdges = dynamic_cast(theFunctor.get())){ + } + else if(FreeEdges* aFreeEdges = dynamic_cast(theFunctor.get())) + { SMESH::Controls::FreeEdges::TBorders aBorders; aFreeEdges->GetBoreders(aBorders); vtkUnstructuredGrid* aDataSet = vtkUnstructuredGrid::New(); @@ -561,7 +552,9 @@ SMESH_DeviceActor SetUnstructuredGrid(aDataSet); aDataSet->Delete(); - }else if(FreeNodes* aFreeNodes = dynamic_cast(theFunctor.get())){ + } + else if(FreeNodes* aFreeNodes = dynamic_cast(theFunctor.get())) + { myExtractUnstructuredGrid->SetModeOfChanging(VTKViewer_ExtractUnstructuredGrid::eAdding); vtkIdType aNbNodes = myVisualObj->GetNbEntities(SMDSAbs_Node); for( vtkIdType i = 0; i < aNbNodes; i++ ){ diff --git a/src/SMESH/SMESH_Mesh.cxx b/src/SMESH/SMESH_Mesh.cxx index 39c2ca976..a85e23e23 100644 --- a/src/SMESH/SMESH_Mesh.cxx +++ b/src/SMESH/SMESH_Mesh.cxx @@ -265,14 +265,12 @@ void SMESH_Mesh::Clear() _myMeshDS->ClearMesh(); // update compute state of submeshes - if ( SMESH_subMesh *sm = GetSubMeshContaining( GetShapeToMesh() ) ) { - SMESH_subMeshIteratorPtr smIt = sm->getDependsOnIterator(/*includeSelf=*/true, - /*complexShapeFirst=*/false); - while ( smIt->more() ) { - sm = smIt->next(); - sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE ); - sm->ComputeStateEngine( SMESH_subMesh::CLEAN ); // for event listeners (issue 0020918) - } + if ( SMESH_subMesh *sm = GetSubMeshContaining( GetShapeToMesh() ) ) + { + sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE ); + sm->ComputeSubMeshStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE ); + sm->ComputeStateEngine( SMESH_subMesh::CLEAN ); // for event listeners (issue 0020918) + sm->ComputeSubMeshStateEngine( SMESH_subMesh::CLEAN ); } _isModified = false; } diff --git a/src/SMESH/SMESH_MeshEditor.cxx b/src/SMESH/SMESH_MeshEditor.cxx index f26db9a0c..48c10820f 100644 --- a/src/SMESH/SMESH_MeshEditor.cxx +++ b/src/SMESH/SMESH_MeshEditor.cxx @@ -128,19 +128,7 @@ SMESH_MeshEditor::AddElement(const vector & node, int nbnode = node.size(); SMESHDS_Mesh* mesh = GetMeshDS(); switch ( type ) { - case SMDSAbs_0DElement: - if ( nbnode == 1 ) - if ( ID ) e = mesh->Add0DElementWithID(node[0], ID); - else e = mesh->Add0DElement (node[0] ); - break; - case SMDSAbs_Edge: - if ( nbnode == 2 ) - if ( ID ) e = mesh->AddEdgeWithID(node[0], node[1], ID); - else e = mesh->AddEdge (node[0], node[1] ); - else if ( nbnode == 3 ) - if ( ID ) e = mesh->AddEdgeWithID(node[0], node[1], node[2], ID); - else e = mesh->AddEdge (node[0], node[1], node[2] ); - break; + case SMDSAbs_Face: if ( !isPoly ) { if (nbnode == 3) @@ -164,6 +152,7 @@ SMESH_MeshEditor::AddElement(const vector & node, else e = mesh->AddPolygonalFace (node ); } break; + case SMDSAbs_Volume: if ( !isPoly ) { if (nbnode == 4) @@ -221,6 +210,29 @@ SMESH_MeshEditor::AddElement(const vector & node, node[12],node[13],node[14],node[15], node[16],node[17],node[18],node[19] ); } + break; + + case SMDSAbs_Edge: + if ( nbnode == 2 ) + if ( ID ) e = mesh->AddEdgeWithID(node[0], node[1], ID); + else e = mesh->AddEdge (node[0], node[1] ); + else if ( nbnode == 3 ) + if ( ID ) e = mesh->AddEdgeWithID(node[0], node[1], node[2], ID); + else e = mesh->AddEdge (node[0], node[1], node[2] ); + break; + + case SMDSAbs_0DElement: + if ( nbnode == 1 ) + if ( ID ) e = mesh->Add0DElementWithID(node[0], ID); + else e = mesh->Add0DElement (node[0] ); + break; + + case SMDSAbs_Node: + if ( ID ) e = mesh->AddNodeWithID(node[0]->X(), node[0]->Y(), node[0]->Z(), ID); + else e = mesh->AddNode (node[0]->X(), node[0]->Y(), node[0]->Z()); + break; + + default:; } if ( e ) myLastCreatedElems.Append( e ); return e; diff --git a/src/SMESH/SMESH_subMesh.cxx b/src/SMESH/SMESH_subMesh.cxx index 69b33a94c..76418c59f 100644 --- a/src/SMESH/SMESH_subMesh.cxx +++ b/src/SMESH/SMESH_subMesh.cxx @@ -1699,7 +1699,7 @@ bool SMESH_subMesh::CheckComputeError(SMESH_Algo* theAlgo, const TopoDS_Shape& t // Check my state if ( !_computeError || _computeError->IsOK() ) { - _computeState = COMPUTE_OK; + _computeState = IsMeshComputed() ? COMPUTE_OK : FAILED_TO_COMPUTE; } else { diff --git a/src/SMESH/SMESH_subMesh.hxx b/src/SMESH/SMESH_subMesh.hxx index 2929c023f..05c1d7f82 100644 --- a/src/SMESH/SMESH_subMesh.hxx +++ b/src/SMESH/SMESH_subMesh.hxx @@ -192,6 +192,7 @@ public: void DumpAlgoState(bool isMain); bool ComputeStateEngine(int event); + void ComputeSubMeshStateEngine(int event); bool Evaluate(MapShapeNbElems& aResMap); @@ -249,7 +250,6 @@ protected: void RemoveSubMeshElementsAndNodes(); void UpdateDependantsState(const compute_event theEvent); void UpdateSubMeshState(const compute_state theState); - void ComputeSubMeshStateEngine(int event); void CleanDependants(); void CleanDependsOn(); void SetAlgoState(int state); diff --git a/src/SMESHFiltersSelection/SMESH_Type.h b/src/SMESHFiltersSelection/SMESH_Type.h index 89857d89c..ee962f22e 100644 --- a/src/SMESHFiltersSelection/SMESH_Type.h +++ b/src/SMESHFiltersSelection/SMESH_Type.h @@ -25,7 +25,6 @@ // Author : Nicolas REJNERI // Project : SALOME // Module : SMESH -// $Header$ // #ifndef SMESH_TYPE_HEADER #define SMESH_TYPE_HEADER @@ -57,7 +56,8 @@ enum MeshObjectType { GROUP_FACE, GROUP_VOLUME, GROUP_0D, - COMPONENT + COMPONENT, + IDSOURCE }; #endif diff --git a/src/SMESHFiltersSelection/SMESH_TypeFilter.cxx b/src/SMESHFiltersSelection/SMESH_TypeFilter.cxx index 1fbb37516..a684d7023 100644 --- a/src/SMESHFiltersSelection/SMESH_TypeFilter.cxx +++ b/src/SMESHFiltersSelection/SMESH_TypeFilter.cxx @@ -203,6 +203,12 @@ bool SMESH_TypeFilter::isOk (const SUIT_DataOwner* theDataOwner) const Ok = true; break; } + case IDSOURCE: + { + Ok = ( SMESH_TypeFilter(MESHorSUBMESH).isOk( theDataOwner ) || + SMESH_TypeFilter(GROUP) .isOk( theDataOwner )); + break; + } } } return Ok; diff --git a/src/SMESHGUI/Makefile.am b/src/SMESHGUI/Makefile.am index 7e7448f59..6da5d4076 100644 --- a/src/SMESHGUI/Makefile.am +++ b/src/SMESHGUI/Makefile.am @@ -94,6 +94,7 @@ salomeinclude_HEADERS = \ SMESHGUI_MeshOrderDlg.h \ SMESHGUI_MeshOrderOp.h \ SMESHGUI_FileValidator.h \ + SMESHGUI_CopyMeshDlg.h \ SMESH_SMESHGUI.hxx # Libraries targets @@ -167,6 +168,7 @@ dist_libSMESH_la_SOURCES = \ SMESHGUI_FindElemByPointDlg.cxx \ SMESHGUI_MeshOrderDlg.cxx \ SMESHGUI_MeshOrderOp.cxx \ + SMESHGUI_CopyMeshDlg.cxx \ SMESHGUI_FileValidator.cxx MOC_FILES = \ @@ -224,6 +226,7 @@ MOC_FILES = \ SMESHGUI_Make2DFrom3DOp_moc.cxx \ SMESHGUI_FindElemByPointDlg_moc.cxx \ SMESHGUI_MeshOrderDlg_moc.cxx \ + SMESHGUI_CopyMeshDlg_moc.cxx \ SMESHGUI_MeshOrderOp_moc.cxx nodist_libSMESH_la_SOURCES= \ diff --git a/src/SMESHGUI/SMESHGUI.cxx b/src/SMESHGUI/SMESHGUI.cxx index e684d705d..1ae0a94a5 100644 --- a/src/SMESHGUI/SMESHGUI.cxx +++ b/src/SMESHGUI/SMESHGUI.cxx @@ -76,6 +76,7 @@ #include "SMESHGUI_TransparencyDlg.h" //#include "SMESHGUI_WhatIsDlg.h" #include "SMESHGUI_DuplicateNodesDlg.h" +#include "SMESHGUI_CopyMeshDlg.h" #include "SMESHGUI_Utils.h" #include "SMESHGUI_MeshUtils.h" @@ -141,6 +142,7 @@ #include #include #include +#include // SALOME KERNEL includes #include @@ -759,6 +761,14 @@ type = QObject::tr( "FREE_BORDERS" ); else if ( dynamic_cast< SMESH::Controls::FreeFaces* >( f.get() ) ) type = QObject::tr( "FREE_FACES" ); + else if ( dynamic_cast< SMESH::Controls::BareBorderVolume* >( f.get() ) ) + type = QObject::tr( "BARE_BORDER_VOLUME" ); + else if ( dynamic_cast< SMESH::Controls::BareBorderFace* >( f.get() ) ) + type = QObject::tr( "BARE_BORDER_FACE" ); + else if ( dynamic_cast< SMESH::Controls::OverConstrainedVolume* >( f.get() ) ) + type = QObject::tr( "OVER_CONSTRAINED_VOLUME" ); + else if ( dynamic_cast< SMESH::Controls::OverConstrainedFace* >( f.get() ) ) + type = QObject::tr( "OVER_CONSTRAINED_FACE" ); return type; } @@ -779,10 +789,26 @@ if ( aScalarBarActor && aFunctor ) { SMESH::Controls::NumericalFunctor* aNumFun = dynamic_cast( aFunctor.get() ); if ( aNumFun ) { - int nbRanges = aScalarBarActor->GetMaximumNumberOfColors(); + std::vector elements; + SMESH::SMESH_Mesh_var mesh = SMESH::IObjectToInterface(anIO); + if ( mesh->_is_nil() ) { + SMESH::SMESH_IDSource_var idSource = + SMESH::IObjectToInterface(anIO); + if ( !idSource->_is_nil() ) + { + SMESH::long_array_var ids = idSource->GetIDs(); + elements.resize( ids->length() ); + for ( unsigned i = 0; i < elements.size(); ++i ) + elements[i] = ids[i]; + } + } + int nbIntervals = aScalarBarActor->GetMaximumNumberOfColors(); + vtkLookupTable* lookupTable = + static_cast(aScalarBarActor->GetLookupTable()); + double * minmax = lookupTable->GetRange(); std::vector nbEvents; std::vector funValues; - aNumFun->GetHistogram( nbRanges, nbEvents, funValues ); + aNumFun->GetHistogram( nbIntervals, nbEvents, funValues, elements, minmax ); QString anInitialPath = ""; if ( SUIT_FileDlg::getLastVisitedPath().isEmpty() ) anInitialPath = QDir::currentPath(); @@ -1178,6 +1204,18 @@ case 6023: aControl = SMESH_Actor::eMaxElementLength3D; break; + case 6024: + aControl = SMESH_Actor::eBareBorderVolume; + break; + case 6025: + aControl = SMESH_Actor::eBareBorderFace; + break; + case 6026: + aControl = SMESH_Actor::eOverConstrainedVolume; + break; + case 6027: + aControl = SMESH_Actor::eOverConstrainedFace; + break; } anActor->SetControlMode(aControl); anActor->GetScalarBarActor()->SetTitle( functorToString( anActor->GetFunctor() ).toLatin1().constData() ); @@ -2013,6 +2051,13 @@ bool SMESHGUI::OnGUIEvent( int theCommandID ) case 704: // Edit mesh/sub-mesh startOperation( theCommandID ); break; + case 705: // copy mesh + { + if (checkLock(aStudy)) break; + EmitSignalDeactivateDialog(); + ( new SMESHGUI_CopyMeshDlg( this ) )->show(); + } + break; case 710: // Build compound mesh { if (checkLock(aStudy)) break; @@ -2962,6 +3007,10 @@ bool SMESHGUI::OnGUIEvent( int theCommandID ) case 6021: case 6022: case 6023: + case 6024: + case 6025: + case 6026: + case 6027: if ( vtkwnd ) { LightApp_SelectionMgr* mgr = selectionMgr(); @@ -3178,6 +3227,7 @@ void SMESHGUI::initialize( CAM_Application* app ) createSMESHAction( 702, "CREATE_MESH", "ICON_DLG_INIT_MESH" ); createSMESHAction( 703, "CREATE_SUBMESH", "ICON_DLG_ADD_SUBMESH" ); createSMESHAction( 704, "EDIT_MESHSUBMESH","ICON_DLG_EDIT_MESH" ); + createSMESHAction( 705, "COPY_MESH", "ICON_COPY_MESH" ); createSMESHAction( 710, "BUILD_COMPOUND", "ICON_BUILD_COMPOUND" ); createSMESHAction( 711, "PRECOMPUTE", "ICON_PRECOMPUTE" ); createSMESHAction( 712, "EVALUATE", "ICON_COMPUTE" ); @@ -3203,6 +3253,10 @@ void SMESHGUI::initialize( CAM_Application* app ) createSMESHAction( 6021, "FREE_FACES", "ICON_FREE_FACES", 0, true ); createSMESHAction( 6022, "MAX_ELEMENT_LENGTH_2D", "ICON_MAX_ELEMENT_LENGTH_2D", 0, true ); createSMESHAction( 6023, "MAX_ELEMENT_LENGTH_3D", "ICON_MAX_ELEMENT_LENGTH_3D", 0, true ); + createSMESHAction( 6024, "BARE_BORDER_VOLUME","ICON_BARE_BORDER_VOLUME", 0, true ); + createSMESHAction( 6025, "BARE_BORDER_FACE","ICON_BARE_BORDER_FACE", 0, true ); + createSMESHAction( 6026, "OVER_CONSTRAINED_VOLUME","ICON_OVER_CONSTRAINED_VOLUME", 0, true ); + createSMESHAction( 6027, "OVER_CONSTRAINED_FACE","ICON_OVER_CONSTRAINED_FACE", 0, true ); createSMESHAction( 6003, "FREE_BORDER", "ICON_FREE_EDGE_2D", 0, true ); createSMESHAction( 6004, "CONNECTION", "ICON_CONNECTION", 0, true ); createSMESHAction( 6005, "FREE_NODE", "ICON_FREE_NODE", 0, true ); @@ -3342,6 +3396,7 @@ void SMESHGUI::initialize( CAM_Application* app ) createMenu( 703, meshId, -1 ); createMenu( 704, meshId, -1 ); createMenu( 710, meshId, -1 ); + createMenu( 705, meshId, -1 ); createMenu( separator(), meshId, -1 ); createMenu( 701, meshId, -1 ); createMenu( 711, meshId, -1 ); @@ -3372,6 +3427,8 @@ void SMESHGUI::initialize( CAM_Application* app ) createMenu( 6001, edgeId, -1 ); createMenu( 6004, edgeId, -1 ); createMenu( 6021, faceId, -1 ); + createMenu( 6025, faceId, -1 ); + createMenu( 6027, faceId, -1 ); createMenu( 6018, faceId, -1 ); createMenu( 6019, faceId, -1 ); createMenu( 6011, faceId, -1 ); @@ -3384,6 +3441,8 @@ void SMESHGUI::initialize( CAM_Application* app ) createMenu( 6017, volumeId, -1 ); createMenu( 6009, volumeId, -1 ); createMenu( 6023, volumeId, -1 ); + createMenu( 6024, volumeId, -1 ); + createMenu( 6026, volumeId, -1 ); createMenu( 4000, addId, -1 ); createMenu( 4009, addId, -1 ); @@ -3453,6 +3512,7 @@ void SMESHGUI::initialize( CAM_Application* app ) createTool( 703, meshTb ); createTool( 704, meshTb ); createTool( 710, meshTb ); + createTool( 705, meshTb ); createTool( separator(), meshTb ); createTool( 701, meshTb ); createTool( 711, meshTb ); @@ -3479,6 +3539,8 @@ void SMESHGUI::initialize( CAM_Application* app ) createTool( 6004, ctrlTb ); createTool( separator(), ctrlTb ); createTool( 6021, ctrlTb ); + createTool( 6025, ctrlTb ); + createTool( 6027, ctrlTb ); createTool( 6018, ctrlTb ); createTool( 6019, ctrlTb ); createTool( 6011, ctrlTb ); @@ -3492,6 +3554,8 @@ void SMESHGUI::initialize( CAM_Application* app ) createTool( 6017, ctrlTb ); createTool( 6009, ctrlTb ); createTool( 6023, ctrlTb ); + createTool( 6024, ctrlTb ); + createTool( 6026, ctrlTb ); createTool( separator(), ctrlTb ); createTool( 4000, addRemTb ); @@ -3794,50 +3858,58 @@ void SMESHGUI::initialize( CAM_Application* app ) aSubId = popupMgr()->insert( tr( "MEN_FACE_CTRL" ), anId, -1 ); // FACE CONTROLS - popupMgr()->insert( action( 6021 ), aSubId, -1 ); // FREE_FACE + popupMgr()->insert ( action( 6021 ), aSubId, -1 ); // FREE_FACE popupMgr()->setRule( action( 6021 ), aMeshInVtkHasFaces /*aMeshInVtkHasVolumes*/, QtxPopupMgr::VisibleRule ); popupMgr()->setRule( action( 6021 ), "controlMode = 'eFreeFaces'", QtxPopupMgr::ToggleRule ); - popupMgr()->insert( action( 6018 ), aSubId, -1 ); // LENGTH_2D + popupMgr()->insert ( action( 6018 ), aSubId, -1 ); // LENGTH_2D popupMgr()->setRule( action( 6018 ), aMeshInVtkHasFaces, QtxPopupMgr::VisibleRule ); popupMgr()->setRule( action( 6018 ), "controlMode = 'eLength2D'", QtxPopupMgr::ToggleRule ); - popupMgr()->insert( action( 6019 ), aSubId, -1 ); // CONNECTION_2D + popupMgr()->insert ( action( 6019 ), aSubId, -1 ); // CONNECTION_2D popupMgr()->setRule( action( 6019 ), aMeshInVtkHasFaces, QtxPopupMgr::VisibleRule ); popupMgr()->setRule( action( 6019 ), "controlMode = 'eMultiConnection2D'", QtxPopupMgr::ToggleRule ); - popupMgr()->insert( action( 6011 ), aSubId, -1 ); // AREA + popupMgr()->insert ( action( 6011 ), aSubId, -1 ); // AREA popupMgr()->setRule( action( 6011 ), aMeshInVtkHasFaces, QtxPopupMgr::VisibleRule ); popupMgr()->setRule( action( 6011 ), "controlMode = 'eArea'", QtxPopupMgr::ToggleRule ); - popupMgr()->insert( action( 6012 ), aSubId, -1 ); // TAPER + popupMgr()->insert ( action( 6012 ), aSubId, -1 ); // TAPER popupMgr()->setRule( action( 6012 ), aMeshInVtkHasFaces, QtxPopupMgr::VisibleRule ); popupMgr()->setRule( action( 6012 ), "controlMode = 'eTaper'", QtxPopupMgr::ToggleRule ); - popupMgr()->insert( action( 6013 ), aSubId, -1 ); // ASPECT + popupMgr()->insert ( action( 6013 ), aSubId, -1 ); // ASPECT popupMgr()->setRule( action( 6013 ), aMeshInVtkHasFaces, QtxPopupMgr::VisibleRule ); popupMgr()->setRule( action( 6013 ), "controlMode = 'eAspectRatio'", QtxPopupMgr::ToggleRule ); - popupMgr()->insert( action( 6014 ), aSubId, -1 ); // MIN_ANG + popupMgr()->insert ( action( 6014 ), aSubId, -1 ); // MIN_ANG popupMgr()->setRule( action( 6014 ), aMeshInVtkHasFaces, QtxPopupMgr::VisibleRule ); popupMgr()->setRule( action( 6014 ), "controlMode = 'eMinimumAngle'", QtxPopupMgr::ToggleRule ); - popupMgr()->insert( action( 6015 ), aSubId, -1 ); // WARP + popupMgr()->insert ( action( 6015 ), aSubId, -1 ); // WARP popupMgr()->setRule( action( 6015 ), aMeshInVtkHasFaces, QtxPopupMgr::VisibleRule ); popupMgr()->setRule( action( 6015 ), "controlMode = 'eWarping'", QtxPopupMgr::ToggleRule ); - popupMgr()->insert( action( 6016 ), aSubId, -1 ); // SKEW + popupMgr()->insert ( action( 6016 ), aSubId, -1 ); // SKEW popupMgr()->setRule( action( 6016 ), aMeshInVtkHasFaces, QtxPopupMgr::VisibleRule ); popupMgr()->setRule( action( 6016 ), "controlMode = 'eSkew'", QtxPopupMgr::ToggleRule ); - popupMgr()->insert( action( 6022 ), aSubId, -1 ); // MAX_ELEMENT_LENGTH_2D + popupMgr()->insert ( action( 6022 ), aSubId, -1 ); // MAX_ELEMENT_LENGTH_2D popupMgr()->setRule( action( 6022 ), aMeshInVtkHasFaces, QtxPopupMgr::VisibleRule ); popupMgr()->setRule( action( 6022 ), "controlMode = 'eMaxElementLength2D'", QtxPopupMgr::ToggleRule ); + popupMgr()->insert ( action( 6025 ), aSubId, -1 ); // BARE_BORDER_FACE + popupMgr()->setRule( action( 6025 ), aMeshInVtkHasFaces, QtxPopupMgr::VisibleRule ); + popupMgr()->setRule( action( 6025 ), "controlMode = 'eBareBorderFace'", QtxPopupMgr::ToggleRule ); + + popupMgr()->insert ( action( 6027 ), aSubId, -1 ); // OVER_CONSTRAINED_FACE + popupMgr()->setRule( action( 6027 ), aMeshInVtkHasFaces, QtxPopupMgr::VisibleRule ); + popupMgr()->setRule( action( 6027 ), "controlMode = 'eOverConstrainedFace'", QtxPopupMgr::ToggleRule ); + aSubId = popupMgr()->insert( tr( "MEN_VOLUME_CTRL" ), anId, -1 ); // VOLUME CONTROLS - popupMgr()->insert( action( 6017 ), aSubId, -1 ); // ASPECT_3D + popupMgr()->insert ( action( 6017 ), aSubId, -1 ); // ASPECT_3D popupMgr()->setRule( action( 6017 ), aMeshInVtkHasVolumes, QtxPopupMgr::VisibleRule ); popupMgr()->setRule( action( 6017 ), "controlMode = 'eAspectRatio3D'", QtxPopupMgr::ToggleRule ); @@ -3845,10 +3917,18 @@ void SMESHGUI::initialize( CAM_Application* app ) popupMgr()->setRule( action( 6009 ), aMeshInVtkHasVolumes, QtxPopupMgr::VisibleRule ); popupMgr()->setRule( action( 6009 ), "controlMode = 'eVolume3D'", QtxPopupMgr::ToggleRule ); - popupMgr()->insert( action( 6023 ), aSubId, -1 ); // MAX_ELEMENT_LENGTH_3D + popupMgr()->insert ( action( 6023 ), aSubId, -1 ); // MAX_ELEMENT_LENGTH_3D popupMgr()->setRule( action( 6023 ), aMeshInVtkHasVolumes, QtxPopupMgr::VisibleRule ); popupMgr()->setRule( action( 6023 ), "controlMode = 'eMaxElementLength3D'", QtxPopupMgr::ToggleRule ); + popupMgr()->insert ( action( 6024 ), aSubId, -1 ); // BARE_BORDER_VOLUME + popupMgr()->setRule( action( 6024 ), aMeshInVtkHasVolumes, QtxPopupMgr::VisibleRule ); + popupMgr()->setRule( action( 6024 ), "controlMode = 'eBareBorderVolume'", QtxPopupMgr::ToggleRule ); + + popupMgr()->insert ( action( 6026 ), aSubId, -1 ); // OVER_CONSTRAINED_VOLUME + popupMgr()->setRule( action( 6026 ), aMeshInVtkHasVolumes, QtxPopupMgr::VisibleRule ); + popupMgr()->setRule( action( 6026 ), "controlMode = 'eOverConstrainedVolume'", QtxPopupMgr::ToggleRule ); + popupMgr()->insert( separator(), anId, -1 ); popupMgr()->insert( action( 201 ), anId, -1 ); // SCALAR_BAR_PROP diff --git a/src/SMESHGUI/SMESHGUI_CopyMeshDlg.cxx b/src/SMESHGUI/SMESHGUI_CopyMeshDlg.cxx new file mode 100644 index 000000000..f4b6950bf --- /dev/null +++ b/src/SMESHGUI/SMESHGUI_CopyMeshDlg.cxx @@ -0,0 +1,667 @@ +// Copyright (C) 2007-2010 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, +// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// SMESH SMESHGUI : GUI for SMESH component +// File : SMESHGUI_CopyMeshDlg.cxx + +#include "SMESHGUI_CopyMeshDlg.h" + +#include "SMESHGUI.h" +#include "SMESHGUI_SpinBox.h" +#include "SMESHGUI_Utils.h" +#include "SMESHGUI_VTKUtils.h" +#include "SMESHGUI_MeshUtils.h" +#include "SMESHGUI_IdValidator.h" +#include "SMESHGUI_FilterDlg.h" + +#include +#include +#include + +// SALOME GUI includes +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +// SALOME KERNEL includes +#include + +// OCCT includes +#include + +// Qt includes +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// IDL includes +#include +#include CORBA_SERVER_HEADER(SMESH_Group) +#include CORBA_SERVER_HEADER(SMESH_MeshEditor) + +/*! + \class BusyLocker + \brief Simple 'busy state' flag locker. + \internal +*/ + +namespace +{ + class BusyLocker + { + public: + //! Constructor. Sets passed boolean flag to \c true. + BusyLocker( bool& busy ) : myBusy( busy ) { myBusy = true; } + //! Destructor. Clear external boolean flag passed as parameter to the constructor to \c false. + ~BusyLocker() { myBusy = false; } + private: + bool& myBusy; //! External 'busy state' boolean flag + }; +} + +#define SPACING 6 +#define MARGIN 11 + +//To disable automatic genericobj management, the following line should be commented. +//Otherwise, it should be uncommented. Refer to KERNEL_SRC/src/SALOMEDSImpl/SALOMEDSImpl_AttributeIOR.cxx +#define WITHGENERICOBJ + + +//================================================================================ +/*! + * \brief Constructor + */ +//================================================================================ + +SMESHGUI_CopyMeshDlg::SMESHGUI_CopyMeshDlg( SMESHGUI* theModule ) + : QDialog( SMESH::GetDesktop( theModule ) ), + mySMESHGUI( theModule ), + mySelectionMgr( SMESH::GetSelectionMgr( theModule ) ), + myFilterDlg(0), + mySelectedObject(SMESH::SMESH_IDSource::_nil()) +{ + QPixmap image (SMESH::GetResourceMgr( mySMESHGUI )->loadPixmap("SMESH", tr("ICON_COPY_MESH"))); + + setModal(false); + setAttribute(Qt::WA_DeleteOnClose, true); + setWindowTitle(tr("SMESH_COPY_MESH_TITLE")); + setSizeGripEnabled(true); + + QVBoxLayout* SMESHGUI_CopyMeshDlgLayout = new QVBoxLayout(this); + SMESHGUI_CopyMeshDlgLayout->setSpacing(SPACING); + SMESHGUI_CopyMeshDlgLayout->setMargin(MARGIN); + + /***************************************************************/ + ConstructorsBox = new QGroupBox(tr("SMESH_COPY_MESH_TITLE"), this); + QButtonGroup* GroupConstructors = new QButtonGroup(this); + QHBoxLayout* ConstructorsBoxLayout = new QHBoxLayout(ConstructorsBox); + ConstructorsBoxLayout->setSpacing(SPACING); + ConstructorsBoxLayout->setMargin(MARGIN); + + QRadioButton* RadioButton1= new QRadioButton(ConstructorsBox); + RadioButton1->setIcon(image); + GroupConstructors->addButton(RadioButton1, 0); + + ConstructorsBoxLayout->addWidget(RadioButton1); + RadioButton1->setChecked(true); + GroupConstructors->addButton(RadioButton1, 0); + + /***************************************************************/ + GroupArguments = new QGroupBox(tr("SMESH_ARGUMENTS"), this); + QGridLayout* GroupArgumentsLayout = new QGridLayout(GroupArguments); + GroupArgumentsLayout->setSpacing(SPACING); + GroupArgumentsLayout->setMargin(MARGIN); + + myIdValidator = new SMESHGUI_IdValidator(this); + + // Controls for idSource/elements selection + myTextLabelElements = new QLabel(tr("OBJECT_NAME"), GroupArguments); + myLineEditElements = new QLineEdit(GroupArguments); + myLineEditElements->setValidator(myIdValidator); + myLineEditElements->setMaxLength(-1); + myFilterBtn = new QPushButton( tr( "SMESH_BUT_FILTER" ), GroupArguments ); + connect(myFilterBtn, SIGNAL(clicked()), this, SLOT(setFilters())); + + // Control for the mesh objects selection + myIdSourceCheck = new QCheckBox(tr("SMESH_SELECT_WHOLE_MESH"), GroupArguments); + + // Name of a mesh to create + QLabel* meshNameLabel = new QLabel(tr("NEW_NAME"), GroupArguments); + myMeshNameEdit = new QLineEdit(GroupArguments); + + // CheckBox for copying groups + myCopyGroupsCheck = new QCheckBox(tr("SMESH_MAKE_GROUPS"), GroupArguments); + myCopyGroupsCheck->setChecked(false); + + // CheckBox for keeping ids + myKeepIdsCheck = new QCheckBox(tr("SMESH_KEEP_IDS"), GroupArguments); + myKeepIdsCheck->setChecked(true); + + // layout + GroupArgumentsLayout->addWidget(myTextLabelElements, 0, 0); + GroupArgumentsLayout->addWidget(myLineEditElements, 0, 1, 1, 5); + GroupArgumentsLayout->addWidget(myFilterBtn, 0, 6); + GroupArgumentsLayout->addWidget(myIdSourceCheck, 1, 0, 1, 6); + GroupArgumentsLayout->addWidget(meshNameLabel, 2, 0); + GroupArgumentsLayout->addWidget(myMeshNameEdit, 2, 1, 1, 5); + GroupArgumentsLayout->addWidget(myCopyGroupsCheck, 3, 0, 1, 6); + GroupArgumentsLayout->addWidget(myKeepIdsCheck, 4, 0, 1, 6); + + /***************************************************************/ + GroupButtons = new QGroupBox(this); + QHBoxLayout* GroupButtonsLayout = new QHBoxLayout(GroupButtons); + GroupButtonsLayout->setSpacing(SPACING); + GroupButtonsLayout->setMargin(MARGIN); + + buttonOk = new QPushButton(tr("SMESH_BUT_APPLY_AND_CLOSE"), GroupButtons); + buttonOk->setAutoDefault(true); + buttonOk->setDefault(true); + buttonApply = new QPushButton(tr("SMESH_BUT_APPLY"), GroupButtons); + buttonApply->setAutoDefault(true); + buttonCancel = new QPushButton(tr("SMESH_BUT_CLOSE"), GroupButtons); + buttonCancel->setAutoDefault(true); + buttonHelp = new QPushButton(tr("SMESH_BUT_HELP"), GroupButtons); + buttonHelp->setAutoDefault(true); + + GroupButtonsLayout->addWidget(buttonOk); + GroupButtonsLayout->addSpacing(10); + GroupButtonsLayout->addWidget(buttonApply); + GroupButtonsLayout->addSpacing(10); + GroupButtonsLayout->addStretch(); + GroupButtonsLayout->addWidget(buttonCancel); + GroupButtonsLayout->addWidget(buttonHelp); + + /***************************************************************/ + SMESHGUI_CopyMeshDlgLayout->addWidget(ConstructorsBox); + SMESHGUI_CopyMeshDlgLayout->addWidget(GroupArguments); + SMESHGUI_CopyMeshDlgLayout->addWidget(GroupButtons); + + /* Initialisations */ + mySelector = (SMESH::GetViewWindow( mySMESHGUI ))->GetSelector(); + + mySMESHGUI->SetActiveDialogBox((QDialog*)this); + + // Selection filter + myIdSourceFilter = new SMESH_TypeFilter( IDSOURCE ); + + myHelpFileName = "copy_mesh_page.html"; + + Init(); + + /* signals and slots connections */ + connect(buttonOk, SIGNAL(clicked()), this, SLOT(ClickOnOk())); + connect(buttonCancel, SIGNAL(clicked()), this, SLOT(ClickOnCancel())); + connect(buttonApply, SIGNAL(clicked()), this, SLOT(ClickOnApply())); + connect(buttonHelp, SIGNAL(clicked()), this, SLOT(ClickOnHelp())); + + connect(mySMESHGUI, SIGNAL (SignalDeactivateActiveDialog()), + this, SLOT (DeactivateActiveDialog())); + connect(mySelectionMgr, SIGNAL (currentSelectionChanged()), + this, SLOT (SelectionIntoArgument())); + connect(mySMESHGUI, SIGNAL (SignalCloseAllDialogs()),/* to close dialog if study change */ + this, SLOT (ClickOnCancel())); + + connect(myLineEditElements, SIGNAL(textChanged(const QString&)), + this, SLOT (onTextChange(const QString&))); + connect(myIdSourceCheck, SIGNAL(toggled(bool)), + this, SLOT (onSelectIdSource(bool))); + + SelectionIntoArgument(); +} + +//================================================================================= +// function : ~SMESHGUI_CopyMeshDlg() +// purpose : Destroys the object and frees any allocated resources +//================================================================================= + +SMESHGUI_CopyMeshDlg::~SMESHGUI_CopyMeshDlg() +{ + if ( myFilterDlg ) + { + myFilterDlg->setParent( 0 ); + delete myFilterDlg; myFilterDlg = 0; + } + if ( myIdSourceFilter ) + { + if ( mySelectionMgr ) + mySelectionMgr->removeFilter( myIdSourceFilter ); + delete myIdSourceFilter; myIdSourceFilter=0; + } +} + +//================================================================================= +// function : Init() +// purpose : +//================================================================================= +void SMESHGUI_CopyMeshDlg::Init (bool ResetControls) +{ + myBusy = false; + + myMeshNameEdit->setText( SMESH::UniqueMeshName("Mesh")); + if ( ResetControls ) + { + myLineEditElements->clear(); + //myElementsId = ""; + myNbOkElements = 0; + + buttonOk->setEnabled(false); + buttonApply->setEnabled(false); + + myActor = 0; + myMesh = SMESH::SMESH_Mesh::_nil(); + + myIdSourceCheck->setChecked(true); + myCopyGroupsCheck->setChecked(false); + myKeepIdsCheck->setChecked(false); + + onSelectIdSource( myIdSourceCheck->isChecked() ); + } +} + +//================================================================================= +// function : ClickOnApply() +// purpose : +//================================================================================= + +bool SMESHGUI_CopyMeshDlg::ClickOnApply() +{ + if (mySMESHGUI->isActiveStudyLocked()) + return false; + + if( !isValid() ) + return false; + + try + { + SUIT_OverrideCursor aWaitCursor; + SMESH::SMESH_IDSource_var aPartToCopy; + if ( myIdSourceCheck->isChecked()) + { + aPartToCopy = mySelectedObject; + } + else + { + QStringList aListElementsId = myLineEditElements->text().split(" ", QString::SkipEmptyParts); + SMESH::long_array_var anElementsId = new SMESH::long_array; + anElementsId->length(aListElementsId.count()); + for (int i = 0; i < aListElementsId.count(); i++) + anElementsId[i] = aListElementsId[i].toInt(); + + SMESH::SMESH_MeshEditor_var aMeshEditor = myMesh->GetMeshEditor(); + aPartToCopy = aMeshEditor->MakeIDSource( anElementsId, SMESH::ALL ); + } + QByteArray meshName = myMeshNameEdit->text().toLatin1(); + bool toCopyGroups = ( myCopyGroupsCheck->isChecked() ); + bool toKeepIDs = ( myKeepIdsCheck->isChecked() ); + + SMESH::SMESH_Gen_var gen = SMESHGUI::GetSMESHGen(); + SMESH::SMESH_Mesh_var newMesh = + gen->CopyMesh(aPartToCopy, meshName.constData(), toCopyGroups, toKeepIDs); +#ifdef WITHGENERICOBJ + // obj has been published in study. Its refcount has been incremented. + // It is safe to decrement its refcount + // so that it will be destroyed when the entry in study will be removed + newMesh->Destroy(); +#endif + } catch (...) { + } + + mySMESHGUI->updateObjBrowser(true); + SMESHGUI::Modified(); + + Init(false); + mySelectedObject = SMESH::SMESH_IDSource::_nil(); + SelectionIntoArgument(); + + return true; +} + +//================================================================================= +// function : ClickOnOk() +// purpose : +//================================================================================= +void SMESHGUI_CopyMeshDlg::ClickOnOk() +{ + if( ClickOnApply() ) + ClickOnCancel(); +} + +//================================================================================= +// function : ClickOnCancel() +// purpose : +//================================================================================= +void SMESHGUI_CopyMeshDlg::ClickOnCancel() +{ + disconnect(mySelectionMgr, 0, this, 0); + if ( mySelectionMgr ) + mySelectionMgr->removeFilter( myIdSourceFilter ); + if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI )) + aViewWindow->SetSelectionMode( ActorSelection ); + mySMESHGUI->ResetState(); + reject(); +} + +//================================================================================= +// function : ClickOnHelp() +// purpose : +//================================================================================= +void SMESHGUI_CopyMeshDlg::ClickOnHelp() +{ + LightApp_Application* app = (LightApp_Application*)(SUIT_Session::session()->activeApplication()); + if (app) + app->onHelpContextModule(mySMESHGUI ? app->moduleName(mySMESHGUI->moduleName()) : QString(""), myHelpFileName); + else { + QString platform; +#ifdef WIN32 + platform = "winapplication"; +#else + platform = "application"; +#endif + SUIT_MessageBox::warning(this, tr("WRN_WARNING"), + tr("EXTERNAL_BROWSER_CANNOT_SHOW_PAGE"). + arg(app->resourceMgr()->stringValue("ExternalBrowser", + platform)). + arg(myHelpFileName)); + } +} + +//======================================================================= +// function : onTextChange() +// purpose : +//======================================================================= + +void SMESHGUI_CopyMeshDlg::onTextChange (const QString& theNewText) +{ + QLineEdit* send = (QLineEdit*)sender(); + + if (myBusy) return; + BusyLocker lock( myBusy ); + + //if (send == myLineEditElements) + myNbOkElements = 0; + + buttonOk->setEnabled(false); + buttonApply->setEnabled(false); + + // hilight entered elements + SMDS_Mesh* aMesh = 0; + if (myActor) + aMesh = myActor->GetObject()->GetMesh(); + + QStringList aListId = theNewText.split(" ", QString::SkipEmptyParts); + if (myActor && aMesh) + { + TColStd_MapOfInteger newIndices; + if (send == myLineEditElements) { + for (int i = 0; i < aListId.count(); i++) + if ( const SMDS_MeshElement * e = aMesh->FindElement(aListId[ i ].toInt())) + { + newIndices.Add(e->GetID()); + } + } + myNbOkElements = newIndices.Extent(); + + Handle(SALOME_InteractiveObject) anIO = myActor->getIO(); + mySelector->AddOrRemoveIndex( anIO, newIndices, false ); + if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI )) + aViewWindow->highlight( anIO, true, true ); + } + else + { + myNbOkElements = aListId.count(); + } + + if (myNbOkElements) { + buttonOk->setEnabled(true); + buttonApply->setEnabled(true); + } +} + +//================================================================================= +// function : SelectionIntoArgument() +// purpose : Called when selection as changed or other case +//================================================================================= + +void SMESHGUI_CopyMeshDlg::SelectionIntoArgument() +{ + if (myBusy) return; + BusyLocker lock( myBusy ); + + // clear + myActor = 0; + QString aString = ""; + + myLineEditElements->setText(aString); + myNbOkElements = 0; + buttonOk->setEnabled(false); + buttonApply->setEnabled(false); + myFilterBtn->setEnabled(false); + + // get selected mesh + SALOME_ListIO aList; + mySelectionMgr->selectedObjects(aList,SVTK_Viewer::Type()); + int nbSel = aList.Extent(); + if (nbSel != 1) + return; + + Handle(SALOME_InteractiveObject) IO = aList.First(); + mySelectedObject = SMESH::IObjectToInterface( IO ); + if ( mySelectedObject->_is_nil() ) + return; + + myMesh = SMESH::GetMeshByIO(IO); + if (myMesh->_is_nil()) + return; + + myActor = SMESH::FindActorByEntry(IO->getEntry()); + if (!myActor) + myActor = SMESH::FindActorByObject(myMesh); + + if (myIdSourceCheck->isChecked()) + { + SMESH::GetNameOfSelectedIObjects( mySelectionMgr, aString ); + if ( aString.isEmpty() ) aString = " "; + } + else + { + SMESH::GetNameOfSelectedElements( mySelector, IO, aString ); + myNbOkElements = aString.size(); + myFilterBtn->setEnabled(true); + } + myLineEditElements->setText( aString ); + bool ok = !aString.isEmpty(); + + buttonOk->setEnabled(ok); + buttonApply->setEnabled(ok); +} + +//======================================================================= +//function : onSelectIdSource +//purpose : +//======================================================================= +void SMESHGUI_CopyMeshDlg::onSelectIdSource (bool toSelectMesh) +{ + if (toSelectMesh) + myTextLabelElements->setText(tr("OBJECT_NAME")); + else + myTextLabelElements->setText(tr("ELEM_IDS")); + + if (toSelectMesh) { + myLineEditElements->clear(); + } + + mySelectionMgr->clearFilters(); + mySelectionMgr->installFilter(myIdSourceFilter); + SMESH::SetPointRepresentation(false); + + if (toSelectMesh) { + if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI )) + aViewWindow->SetSelectionMode( ActorSelection ); + myLineEditElements->setReadOnly(true); + myLineEditElements->setValidator(0); + } + else + { + if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI )) + aViewWindow->SetSelectionMode( CellSelection ); + myLineEditElements->setReadOnly(false); + myLineEditElements->setValidator(myIdValidator); + onTextChange(myLineEditElements->text()); + } + + SelectionIntoArgument(); +} + +//================================================================================= +// function : isValid +// purpose : +//================================================================================= + +bool SMESHGUI_CopyMeshDlg::isValid() +{ + if ( myIdSourceCheck->isChecked() ) + return !mySelectedObject->_is_nil(); + + return myNbOkElements > 0; +} + +//================================================================================= +// function : DeactivateActiveDialog() +// purpose : +//================================================================================= +void SMESHGUI_CopyMeshDlg::DeactivateActiveDialog() +{ + if (ConstructorsBox->isEnabled()) { + ConstructorsBox->setEnabled(false); + GroupArguments->setEnabled(false); + GroupButtons->setEnabled(false); + mySMESHGUI->ResetState(); + mySMESHGUI->SetActiveDialogBox(0); + if ( mySelectionMgr ) + mySelectionMgr->removeFilter( myIdSourceFilter ); + } +} + +//================================================================================= +// function : ActivateThisDialog() +// purpose : +//================================================================================= +void SMESHGUI_CopyMeshDlg::ActivateThisDialog() +{ + /* Emit a signal to deactivate the active dialog */ + mySMESHGUI->EmitSignalDeactivateDialog(); + ConstructorsBox->setEnabled(true); + GroupArguments->setEnabled(true); + GroupButtons->setEnabled(true); + + mySMESHGUI->SetActiveDialogBox((QDialog*)this); + + onSelectIdSource( myIdSourceCheck->isChecked() ); + + SelectionIntoArgument(); +} + +//================================================================================= +// function : enterEvent() +// purpose : +//================================================================================= +void SMESHGUI_CopyMeshDlg::enterEvent (QEvent*) +{ + if (!ConstructorsBox->isEnabled()) + ActivateThisDialog(); +} + +//================================================================================= +// function : closeEvent() +// purpose : +//================================================================================= +void SMESHGUI_CopyMeshDlg::closeEvent (QCloseEvent*) +{ + /* same than click on cancel button */ + ClickOnCancel(); +} + +//======================================================================= +//function : hideEvent +//purpose : caused by ESC key +//======================================================================= +void SMESHGUI_CopyMeshDlg::hideEvent (QHideEvent*) +{ + if (!isMinimized()) + ClickOnCancel(); +} + +//================================================================================= +// function : keyPressEvent() +// purpose : +//================================================================================= +void SMESHGUI_CopyMeshDlg::keyPressEvent( QKeyEvent* e ) +{ + QDialog::keyPressEvent( e ); + if ( e->isAccepted() ) + return; + + if ( e->key() == Qt::Key_F1 ) { + e->accept(); + ClickOnHelp(); + } +} + +//================================================================================= +// function : setFilters() +// purpose : SLOT. Called when "Filter" button pressed. +//================================================================================= +void SMESHGUI_CopyMeshDlg::setFilters() +{ + if(myMesh->_is_nil()) { + SUIT_MessageBox::critical(this, + tr("SMESH_ERROR"), + tr("NO_MESH_SELECTED")); + return; + } + if ( !myFilterDlg ) + myFilterDlg = new SMESHGUI_FilterDlg( mySMESHGUI, SMESH::ALL ); + + myFilterDlg->SetSelection(); + myFilterDlg->SetMesh( myMesh ); + myFilterDlg->SetSourceWg( myLineEditElements ); + + myFilterDlg->show(); +} diff --git a/src/SMESHGUI/SMESHGUI_CopyMeshDlg.h b/src/SMESHGUI/SMESHGUI_CopyMeshDlg.h new file mode 100644 index 000000000..83fcd095b --- /dev/null +++ b/src/SMESHGUI/SMESHGUI_CopyMeshDlg.h @@ -0,0 +1,125 @@ +// Copyright (C) 2007-2010 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, +// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +// SMESH SMESHGUI : GUI for SMESH component +// File : SMESHGUI_CopyMeshDlg.h +// +#ifndef SMESHGUI_CopyMeshDLG_H +#define SMESHGUI_CopyMeshDLG_H + +// SMESH includes +#include "SMESH_SMESHGUI.hxx" + +// Qt includes +#include + +// IDL includes +#include +#include CORBA_SERVER_HEADER(SMESH_Mesh) + +class QCheckBox; +class QGroupBox; +class QLabel; +class QLineEdit; +class QPushButton; + +class SMESHGUI; +class SMESHGUI_IdValidator; +class SMESHGUI_FilterDlg; +class SMESH_Actor; +class SVTK_Selector; +class LightApp_SelectionMgr; +class SUIT_SelectionFilter; + +//================================================================================= +// class : SMESHGUI_CopyMeshDlg +// purpose : copy some elements or a mesh object into a new mesh +//================================================================================= + +class SMESHGUI_EXPORT SMESHGUI_CopyMeshDlg : public QDialog +{ + Q_OBJECT + +public: + SMESHGUI_CopyMeshDlg( SMESHGUI* ); + ~SMESHGUI_CopyMeshDlg(); + +private: + void Init( bool = true ); + void closeEvent( QCloseEvent* ); + void enterEvent( QEvent* ); /* mouse enter the QWidget */ + void hideEvent( QHideEvent* ); /* ESC key */ + void keyPressEvent( QKeyEvent* ); + int GetConstructorId(); + void setNewMeshName(); + + bool isValid(); + + SMESHGUI* mySMESHGUI; /* Current SMESHGUI object */ + SMESHGUI_IdValidator* myIdValidator; + LightApp_SelectionMgr* mySelectionMgr; /* User shape selection */ + int myNbOkElements; /* to check when elements are defined */ + + SVTK_Selector* mySelector; + + bool myBusy; + SMESH::SMESH_Mesh_var myMesh; + SMESH_Actor* myActor; + SUIT_SelectionFilter* myIdSourceFilter; + + SMESH::SMESH_IDSource_var mySelectedObject; + + QGroupBox* ConstructorsBox; + QGroupBox* GroupArguments; + QGroupBox* GroupButtons; + + QPushButton* buttonOk; + QPushButton* buttonCancel; + QPushButton* buttonApply; + QPushButton* buttonHelp; + + QLabel* myTextLabelElements; + QLineEdit* myLineEditElements; + QLineEdit* myMeshNameEdit; + QCheckBox* myIdSourceCheck; + QCheckBox* myCopyGroupsCheck; + QCheckBox* myKeepIdsCheck; + + QPushButton* myFilterBtn; + SMESHGUI_FilterDlg* myFilterDlg; + + QString myHelpFileName; + +private slots: + void ClickOnOk(); + void ClickOnCancel(); + bool ClickOnApply(); + void ClickOnHelp(); + void SelectionIntoArgument(); + void DeactivateActiveDialog(); + void ActivateThisDialog(); + void onTextChange( const QString& ); + void onSelectIdSource( bool ); + void setFilters(); +}; + +#endif // SMESHGUI_CopyMeshDLG_H diff --git a/src/SMESHGUI/SMESHGUI_FilterDlg.cxx b/src/SMESHGUI/SMESHGUI_FilterDlg.cxx index ee88f7662..de2d8e05d 100755 --- a/src/SMESHGUI/SMESHGUI_FilterDlg.cxx +++ b/src/SMESHGUI/SMESHGUI_FilterDlg.cxx @@ -1169,18 +1169,22 @@ void SMESHGUI_FilterTable::SetCriterion (const int theRow, aTable->item( theRow, 2 )->setText( QString( theCriterion.ThresholdID ) ); } else if (theCriterion.Type != SMESH::FT_RangeOfIds && - theCriterion.Type != SMESH::FT_BelongToGeom && - theCriterion.Type != SMESH::FT_BelongToPlane && - theCriterion.Type != SMESH::FT_BelongToCylinder && - theCriterion.Type != SMESH::FT_BelongToGenSurface && - theCriterion.Type != SMESH::FT_LyingOnGeom && - theCriterion.Type != SMESH::FT_CoplanarFaces && - theCriterion.Type != SMESH::FT_FreeBorders && - theCriterion.Type != SMESH::FT_FreeEdges && - theCriterion.Type != SMESH::FT_FreeNodes && - theCriterion.Type != SMESH::FT_FreeFaces && - theCriterion.Type != SMESH::FT_BadOrientedVolume && - theCriterion.Type != SMESH::FT_LinearOrQuadratic) + theCriterion.Type != SMESH::FT_BelongToGeom && + theCriterion.Type != SMESH::FT_BelongToPlane && + theCriterion.Type != SMESH::FT_BelongToCylinder && + theCriterion.Type != SMESH::FT_BelongToGenSurface && + theCriterion.Type != SMESH::FT_LyingOnGeom && + theCriterion.Type != SMESH::FT_CoplanarFaces && + theCriterion.Type != SMESH::FT_FreeBorders && + theCriterion.Type != SMESH::FT_FreeEdges && + theCriterion.Type != SMESH::FT_FreeNodes && + theCriterion.Type != SMESH::FT_FreeFaces && + theCriterion.Type != SMESH::FT_BadOrientedVolume && + theCriterion.Type != SMESH::FT_BareBorderFace && + theCriterion.Type != SMESH::FT_BareBorderVolume && + theCriterion.Type != SMESH::FT_OverConstrainedFace && + theCriterion.Type != SMESH::FT_OverConstrainedVolume && + theCriterion.Type != SMESH::FT_LinearOrQuadratic) { aTable->item( theRow, 2 )->setText(QString("%1").arg(theCriterion.Threshold, 0, 'g', 15)); } @@ -1341,10 +1345,14 @@ void SMESHGUI_FilterTable::updateAdditionalWidget() aCriterion != SMESH::FT_RangeOfIds && aCriterion != SMESH::FT_FreeEdges && aCriterion != SMESH::FT_FreeFaces && - aCriterion != SMESH::FT_BadOrientedVolume) + aCriterion != SMESH::FT_BadOrientedVolume && + aCriterion != SMESH::FT_BareBorderFace && + aCriterion != SMESH::FT_BareBorderVolume && + aCriterion != SMESH::FT_OverConstrainedFace && + aCriterion != SMESH::FT_OverConstrainedVolume) || aCriterion == SMESH::FT_CoplanarFaces); - + if (!myAddWidgets.contains(anItem)) { myAddWidgets[ anItem ] = new AdditionalWidget(myWgStack); @@ -1520,9 +1528,13 @@ void SMESHGUI_FilterTable::onCriterionChanged (const int row, const int col, con if ((aType == SMESH::NODE && aCriterionType == SMESH::FT_FreeNodes ) || (aType == SMESH::EDGE && aCriterionType == SMESH::FT_FreeBorders ) || - (aType == SMESH::FACE && (aCriterionType == SMESH::FT_FreeEdges || + (aType == SMESH::FACE && (aCriterionType == SMESH::FT_BareBorderFace || + aCriterionType == SMESH::FT_OverConstrainedFace || + aCriterionType == SMESH::FT_FreeEdges || aCriterionType == SMESH::FT_FreeFaces)) || - (aType == SMESH::VOLUME && aCriterionType == SMESH::FT_BadOrientedVolume) || + (aType == SMESH::VOLUME && (aCriterionType == SMESH::FT_BadOrientedVolume || + aCriterionType == SMESH::FT_OverConstrainedVolume || + aCriterionType == SMESH::FT_BareBorderVolume)) || aCriterionType == SMESH::FT_LinearOrQuadratic || aCriterionType == SMESH::FT_GroupColor || aCriterionType == SMESH::FT_ElemGeomType || @@ -1808,6 +1820,8 @@ const QMap& SMESHGUI_FilterTable::getCriteria (const int theType) aCriteria[ SMESH::FT_Length2D ] = tr("LENGTH2D"); aCriteria[ SMESH::FT_MultiConnection2D ] = tr("MULTI2D_BORDERS"); aCriteria[ SMESH::FT_FreeFaces ] = tr("FREE_FACES"); + aCriteria[ SMESH::FT_BareBorderFace ] = tr("BARE_BORDER_FACE"); + aCriteria[ SMESH::FT_OverConstrainedFace] = tr("OVER_CONSTRAINED_FACE"); aCriteria[ SMESH::FT_LinearOrQuadratic ] = tr("LINEAR"); aCriteria[ SMESH::FT_GroupColor ] = tr("GROUP_COLOR"); aCriteria[ SMESH::FT_ElemGeomType ] = tr("GEOM_TYPE"); @@ -1820,16 +1834,18 @@ const QMap& SMESHGUI_FilterTable::getCriteria (const int theType) static QMap aCriteria; if (aCriteria.isEmpty()) { - aCriteria[ SMESH::FT_AspectRatio3D ] = tr("ASPECT_RATIO_3D"); - aCriteria[ SMESH::FT_RangeOfIds ] = tr("RANGE_OF_IDS"); - aCriteria[ SMESH::FT_BelongToGeom ] = tr("BELONG_TO_GEOM"); - aCriteria[ SMESH::FT_LyingOnGeom ] = tr("LYING_ON_GEOM"); - aCriteria[ SMESH::FT_BadOrientedVolume ] = tr("BAD_ORIENTED_VOLUME"); - aCriteria[ SMESH::FT_Volume3D ] = tr("VOLUME_3D"); - aCriteria[ SMESH::FT_MaxElementLength3D ] = tr("MAX_ELEMENT_LENGTH_3D"); - aCriteria[ SMESH::FT_LinearOrQuadratic ] = tr("LINEAR"); - aCriteria[ SMESH::FT_GroupColor ] = tr("GROUP_COLOR"); - aCriteria[ SMESH::FT_ElemGeomType ] = tr("GEOM_TYPE"); + aCriteria[ SMESH::FT_AspectRatio3D ] = tr("ASPECT_RATIO_3D"); + aCriteria[ SMESH::FT_RangeOfIds ] = tr("RANGE_OF_IDS"); + aCriteria[ SMESH::FT_BelongToGeom ] = tr("BELONG_TO_GEOM"); + aCriteria[ SMESH::FT_LyingOnGeom ] = tr("LYING_ON_GEOM"); + aCriteria[ SMESH::FT_BadOrientedVolume ] = tr("BAD_ORIENTED_VOLUME"); + aCriteria[ SMESH::FT_BareBorderVolume ] = tr("BARE_BORDER_VOLUME"); + aCriteria[ SMESH::FT_OverConstrainedVolume] = tr("OVER_CONSTRAINED_VOLUME"); + aCriteria[ SMESH::FT_Volume3D ] = tr("VOLUME_3D"); + aCriteria[ SMESH::FT_MaxElementLength3D ] = tr("MAX_ELEMENT_LENGTH_3D"); + aCriteria[ SMESH::FT_LinearOrQuadratic ] = tr("LINEAR"); + aCriteria[ SMESH::FT_GroupColor ] = tr("GROUP_COLOR"); + aCriteria[ SMESH::FT_ElemGeomType ] = tr("GEOM_TYPE"); } return aCriteria; } diff --git a/src/SMESHGUI/SMESHGUI_Preferences_ScalarBarDlg.cxx b/src/SMESHGUI/SMESHGUI_Preferences_ScalarBarDlg.cxx index 43640501e..b1f9284c6 100644 --- a/src/SMESHGUI/SMESHGUI_Preferences_ScalarBarDlg.cxx +++ b/src/SMESHGUI/SMESHGUI_Preferences_ScalarBarDlg.cxx @@ -418,7 +418,7 @@ SMESHGUI_Preferences_ScalarBarDlg::SMESHGUI_Preferences_ScalarBarDlg( SMESHGUI* } QColor distributionColor = mgr->colorValue("SMESH", "distribution_color", - QColor(255, 255, 255)); + QColor(255, 255, 255)); myMonoColorBtn->setColor(distributionColor); @@ -509,18 +509,6 @@ bool SMESHGUI_Preferences_ScalarBarDlg::onApply() myScalarBarActor->SetLabelTextProperty( aLabelsTextPrp ); myScalarBarActor->SetNumberOfLabels( myLabelsSpin->value() ); - if( myColorsSpin->value() != myScalarBarActor->GetMaximumNumberOfColors() ) { - myScalarBarActor->SetMaximumNumberOfColors( myColorsSpin->value() ); - SMESH::Controls::FunctorPtr fn = myActor->GetFunctor(); - SMESH::Controls::NumericalFunctor* aNumericalFunctor = dynamic_cast(fn.get()); - if( aNumericalFunctor ) { - int nbIntervals = myColorsSpin->value(); - std::vector nbEvents; - std::vector funValues; - aNumericalFunctor->GetHistogram(nbIntervals, nbEvents, funValues); - myScalarBarActor->SetDistribution(nbEvents); - } - } if ( myHorizRadioBtn->isChecked() ) myScalarBarActor->SetOrientationToHorizontal(); @@ -550,9 +538,22 @@ bool SMESHGUI_Preferences_ScalarBarDlg::onApply() double aMax = myMaxEdit->text().toDouble(); vtkLookupTable* myLookupTable = static_cast(myScalarBarActor->GetLookupTable()); + double oldMinMax[2] = { myLookupTable->GetRange()[0], myLookupTable->GetRange()[1] }; + bool rangeChanges = ( fabs( oldMinMax[0] - aMin ) + fabs( oldMinMax[1] - aMax ) > + 0.001 * ( aMax-aMin + oldMinMax[1]-oldMinMax[0] )); + + bool nbColorsChanged = (myColorsSpin->value() != myScalarBarActor->GetMaximumNumberOfColors()); + if(nbColorsChanged) + myScalarBarActor->SetMaximumNumberOfColors(myColorsSpin->value()); + + myLookupTable->SetRange( aMin, aMax ); myLookupTable->SetNumberOfTableValues(myColorsSpin->value()); myLookupTable->Build(); + + if( nbColorsChanged || rangeChanges) + myActor->UpdateDistribution(); + SMESH::RepaintCurrentView(); return true; } @@ -655,17 +656,17 @@ void SMESHGUI_Preferences_ScalarBarDlg::onSelectionChanged() myIniH = myScalarBarActor->GetHeight(); setOriginAndSize( myIniX, myIniY, myIniW, myIniH ); - myDistributionGrp->setChecked((bool)myScalarBarActor->GetDistributionVisibility()); - int coloringType = myScalarBarActor->GetDistributionColoringType(); - myScalarBarActor->GetDistributionColor( aTColor ); - myMonoColorBtn->setColor( QColor( (int)( aTColor[0]*255 ), (int)( aTColor[1]*255 ), (int)( aTColor[2]*255 ) ) ); - if ( coloringType == SMESH_MONOCOLOR_TYPE ) { - myDMonoColor->setChecked(true); - onDistributionChanged(myDistribColorGrp->id(myDMonoColor)); - } else { - myDMultiColor->setChecked(true); - onDistributionChanged(myDistribColorGrp->id(myDMultiColor)); - } + myDistributionGrp->setChecked((bool)myScalarBarActor->GetDistributionVisibility()); + int coloringType = myScalarBarActor->GetDistributionColoringType(); + myScalarBarActor->GetDistributionColor( aTColor ); + myMonoColorBtn->setColor( QColor( (int)( aTColor[0]*255 ), (int)( aTColor[1]*255 ), (int)( aTColor[2]*255 ) ) ); + if ( coloringType == SMESH_MONOCOLOR_TYPE ) { + myDMonoColor->setChecked(true); + onDistributionChanged(myDistribColorGrp->id(myDMonoColor)); + } else { + myDMultiColor->setChecked(true); + onDistributionChanged(myDistribColorGrp->id(myDMultiColor)); + } myRangeGrp->setEnabled( true ); myFontGrp->setEnabled( true ); myLabColorGrp->setEnabled( true ); diff --git a/src/SMESHGUI/SMESHGUI_Utils.cxx b/src/SMESHGUI/SMESHGUI_Utils.cxx index dfe778831..331ad9f92 100644 --- a/src/SMESHGUI/SMESHGUI_Utils.cxx +++ b/src/SMESHGUI/SMESHGUI_Utils.cxx @@ -214,7 +214,7 @@ namespace SMESH QString IOR = app->orb()->object_to_string( theObject ); SalomeApp_Study* study = dynamic_cast( app->activeStudy() ); if ( study && !IOR.isEmpty() ) - res = study->studyDS()->FindObjectIOR( IOR.toLatin1().constData() ); + res = study->studyDS()->FindObjectIOR( IOR.toLatin1().constData() ); } return res; } diff --git a/src/SMESHGUI/SMESH_images.ts b/src/SMESHGUI/SMESH_images.ts index 856e88f32..3eff547c5 100644 --- a/src/SMESHGUI/SMESH_images.ts +++ b/src/SMESHGUI/SMESH_images.ts @@ -53,6 +53,10 @@ ICON_BUILD_COMPOUND mesh_build_compound.png + + ICON_COPY_MESH + copy_mesh.png + ICON_COMPUTE mesh_compute.png @@ -109,6 +113,10 @@ ICON_DLG_BUILD_COMPOUND_MESH mesh_build_compound.png + + ICON_DLG_COPY_MESH + copy_mesh.png + ICON_DLG_ELEM0D mesh_vertex.png @@ -457,6 +465,22 @@ ICON_VOLUME_3D mesh_volume_3d.png + + ICON_BARE_BORDER_VOLUME + bare_border_volume.png + + + ICON_BARE_BORDER_FACE + bare_border_face.png + + + ICON_OVER_CONSTRAINED_VOLUME + over_constrained_volume.png + + + ICON_OVER_CONSTRAINED_FACE + over_constrained_face.png + ICON_WARP mesh_wrap.png diff --git a/src/SMESHGUI/SMESH_msg_en.ts b/src/SMESHGUI/SMESH_msg_en.ts index 81e2619ee..fdac42bca 100644 --- a/src/SMESHGUI/SMESH_msg_en.ts +++ b/src/SMESHGUI/SMESH_msg_en.ts @@ -187,6 +187,10 @@ MEN_BUILD_COMPOUND Build Compound + + MEN_COPY_MESH + Copy Mesh + MEN_CLIP Clipping @@ -395,6 +399,22 @@ STB_FIND_ELEM Find Element by Point + + MEN_BARE_BORDER_VOLUME + Volumes with bare border + + + MEN_BARE_BORDER_FACE + Faces with bare border + + + MEN_OVER_CONSTRAINED_VOLUME + Over-constrained volumes + + + MEN_OVER_CONSTRAINED_FACE + Over-constrained faces + MEN_FREE_BORDER Free Borders @@ -1040,6 +1060,14 @@ Please enter correct values and try again SMESH_BUILD_COMPOUND_TITLE Create a Compound + + SMESH_COPY_MESH_TITLE + Copy Mesh + + + SMESH_KEEP_IDS + Preserve IDs of elements + SMESH_BUT_ADD A&dd @@ -2274,6 +2302,10 @@ Please check preferences of Mesh module. STB_BUILD_COMPOUND Build Compound Mesh + + STB_COPY_MESH + Copy Mesh + STB_CLIP Clipping @@ -2434,6 +2466,22 @@ Please check preferences of Mesh module. STB_FACES Faces + + STB_BARE_BORDER_VOLUME + Volumes with bare border + + + STB_BARE_BORDER_FACE + Faces with bare border + + + STB_OVER_CONSTRAINED_VOLUME + Over-constrained volumes + + + STB_OVER_CONSTRAINED_FACE + Over-constrained faces + STB_FREE_BORDER Free Borders @@ -2810,6 +2858,10 @@ Please check preferences of Mesh module. TOP_BUILD_COMPOUND Build Compound Mesh + + TOP_COPY_MESH + Copy Mesh + TOP_CLIP Clipping @@ -2970,6 +3022,22 @@ Please check preferences of Mesh module. TOP_FACES Faces + + TOP_BARE_BORDER_VOLUME + Volumes with bare border + + + TOP_BARE_BORDER_FACE + Faces with bare border + + + TOP_OVER_CONSTRAINED_VOLUME + Over-constrained volumes + + + TOP_OVER_CONSTRAINED_FACE + Over-constrained faces + TOP_FREE_BORDER Free Borders @@ -4320,6 +4388,22 @@ Please check input data and try again BAD_ORIENTED_VOLUME Bad oriented volume + + BARE_BORDER_VOLUME + Volumes with bare border + + + BARE_BORDER_FACE + Faces with bare border + + + OVER_CONSTRAINED_VOLUME + Over-constrained volumes + + + OVER_CONSTRAINED_FACE + Over-constrained faces + BELONG_TO_CYLINDER Belong to Cylinder @@ -5847,6 +5931,21 @@ It is impossible to read point coordinates from file Distance + + SMESHGUI_CopyMeshDlg + + OBJECT_NAME + Source Object + + + ELEM_IDS + Source Element IDs + + + NEW_NAME + New Mesh Name + + SMESHGUI_MeasureDlg diff --git a/src/SMESH_I/SMESH_2smeshpy.cxx b/src/SMESH_I/SMESH_2smeshpy.cxx index fd62cbd2f..c6bc91e8d 100644 --- a/src/SMESH_I/SMESH_2smeshpy.cxx +++ b/src/SMESH_I/SMESH_2smeshpy.cxx @@ -363,7 +363,7 @@ void _pyGen::Process( const Handle(_pyCommand)& theCommand ) myMeshes.insert( make_pair( mesh->GetID(), mesh )); return; } - if ( method == "CreateMeshesFromUNV" || method == "CreateMeshesFromSTL") + if ( method == "CreateMeshesFromUNV" || method == "CreateMeshesFromSTL" || method == "CopyMesh" ) { Handle(_pyMesh) mesh = new _pyMesh( theCommand, theCommand->GetResultValue() ); myMeshes.insert( make_pair( mesh->GetID(), mesh )); diff --git a/src/SMESH_I/SMESH_DumpPython.cxx b/src/SMESH_I/SMESH_DumpPython.cxx index 3fd8ff22f..a8e4205b2 100644 --- a/src/SMESH_I/SMESH_DumpPython.cxx +++ b/src/SMESH_I/SMESH_DumpPython.cxx @@ -232,7 +232,10 @@ namespace SMESH if(!aSObject->_is_nil() || CORBA::is_nil( theArg )) return *this << aSObject; SMESH::long_array_var anElementsId = theArg->GetIDs(); - return *this << anElementsId; + SMESH::SMESH_Mesh_var mesh = theArg->GetMesh(); + SMESH::array_of_ElementType_var types = theArg->GetTypes(); + SMESH::ElementType type = types->length() ? types[0] : SMESH::ALL; + return *this << mesh << ".GetIDSource(" << anElementsId << ", " << type << ")"; } TPythonDump& @@ -266,43 +269,47 @@ namespace SMESH if ( theArg ) { FunctorType aFunctorType = theArg->GetFunctorType(); switch(aFunctorType){ - case FT_AspectRatio: myStream<< "anAspectRatio"; break; - case FT_AspectRatio3D: myStream<< "anAspectRatio3D"; break; - case FT_Warping: myStream<< "aWarping"; break; - case FT_MinimumAngle: myStream<< "aMinimumAngle"; break; - case FT_Taper: myStream<< "aTaper"; break; - case FT_Skew: myStream<< "aSkew"; break; - case FT_Area: myStream<< "aArea"; break; - case FT_Volume3D: myStream<< "aVolume3D"; break; - case FT_MaxElementLength2D:myStream<< "aMaxElementLength2D";break; - case FT_MaxElementLength3D:myStream<< "aMaxElementLength3D";break; - case FT_FreeBorders: myStream<< "aFreeBorders"; break; - case FT_FreeEdges: myStream<< "aFreeEdges"; break; - case FT_FreeNodes: myStream<< "aFreeNodes"; break; - case FT_FreeFaces: myStream<< "aFreeFaces"; break; - case FT_MultiConnection: myStream<< "aMultiConnection"; break; - case FT_MultiConnection2D:myStream<< "aMultiConnection2D";break; - case FT_Length: myStream<< "aLength"; break; - case FT_Length2D: myStream<< "aLength"; break; - case FT_BelongToGeom: myStream<< "aBelongToGeom"; break; - case FT_BelongToPlane: myStream<< "aBelongToPlane"; break; - case FT_BelongToCylinder: myStream<< "aBelongToCylinder"; break; - case FT_BelongToGenSurface:myStream<<"aBelongToGenSurface";break; - case FT_LyingOnGeom: myStream<< "aLyingOnGeom"; break; - case FT_CoplanarFaces: myStream<< "aCoplanarFaces"; break; - case FT_RangeOfIds: myStream<< "aRangeOfIds"; break; - case FT_BadOrientedVolume:myStream<< "aBadOrientedVolume";break; - case FT_LinearOrQuadratic:myStream<< "aLinearOrQuadratic";break; - case FT_GroupColor: myStream<< "aGroupColor"; break; - case FT_ElemGeomType: myStream<< "anElemGeomType"; break; - case FT_LessThan: myStream<< "aLessThan"; break; - case FT_MoreThan: myStream<< "aMoreThan"; break; - case FT_EqualTo: myStream<< "anEqualTo"; break; - case FT_LogicalNOT: myStream<< "aLogicalNOT"; break; - case FT_LogicalAND: myStream<< "aLogicalAND"; break; - case FT_LogicalOR: myStream<< "aLogicalOR"; break; + case FT_AspectRatio: myStream<< "anAspectRatio"; break; + case FT_AspectRatio3D: myStream<< "anAspectRatio3D"; break; + case FT_Warping: myStream<< "aWarping"; break; + case FT_MinimumAngle: myStream<< "aMinimumAngle"; break; + case FT_Taper: myStream<< "aTaper"; break; + case FT_Skew: myStream<< "aSkew"; break; + case FT_Area: myStream<< "aArea"; break; + case FT_Volume3D: myStream<< "aVolume3D"; break; + case FT_MaxElementLength2D: myStream<< "aMaxElementLength2D"; break; + case FT_MaxElementLength3D: myStream<< "aMaxElementLength3D"; break; + case FT_FreeBorders: myStream<< "aFreeBorders"; break; + case FT_FreeEdges: myStream<< "aFreeEdges"; break; + case FT_FreeNodes: myStream<< "aFreeNodes"; break; + case FT_FreeFaces: myStream<< "aFreeFaces"; break; + case FT_MultiConnection: myStream<< "aMultiConnection"; break; + case FT_MultiConnection2D: myStream<< "aMultiConnection2D"; break; + case FT_Length: myStream<< "aLength"; break; + case FT_Length2D: myStream<< "aLength2D"; break; + case FT_BelongToGeom: myStream<< "aBelongToGeom"; break; + case FT_BelongToPlane: myStream<< "aBelongToPlane"; break; + case FT_BelongToCylinder: myStream<< "aBelongToCylinder"; break; + case FT_BelongToGenSurface: myStream<< "aBelongToGenSurface"; break; + case FT_LyingOnGeom: myStream<< "aLyingOnGeom"; break; + case FT_CoplanarFaces: myStream<< "aCoplanarFaces"; break; + case FT_RangeOfIds: myStream<< "aRangeOfIds"; break; + case FT_BadOrientedVolume: myStream<< "aBadOrientedVolume"; break; + case FT_BareBorderVolume: myStream<< "aBareBorderVolume"; break; + case FT_BareBorderFace: myStream<< "aBareBorderFace"; break; + case FT_OverConstrainedVolume: myStream<< "aOverConstrainedVolume"; break; + case FT_OverConstrainedFace: myStream<< "aOverConstrainedFace"; break; + case FT_LinearOrQuadratic: myStream<< "aLinearOrQuadratic"; break; + case FT_GroupColor: myStream<< "aGroupColor"; break; + case FT_ElemGeomType: myStream<< "anElemGeomType"; break; + case FT_LessThan: myStream<< "aLessThan"; break; + case FT_MoreThan: myStream<< "aMoreThan"; break; + case FT_EqualTo: myStream<< "anEqualTo"; break; + case FT_LogicalNOT: myStream<< "aLogicalNOT"; break; + case FT_LogicalAND: myStream<< "aLogicalAND"; break; + case FT_LogicalOR: myStream<< "aLogicalOR"; break; case FT_Undefined: - default: myStream<< "anUndefined"; break; + default: myStream<< "anUndefined"; break; } myStream< nbEvents; std::vector funValues; - myNumericalFunctorPtr->GetHistogram(nbIntervals,nbEvents,funValues); + std::vector elements; + myNumericalFunctorPtr->GetHistogram(nbIntervals,nbEvents,funValues,elements); nbIntervals = CORBA::Short( std::min( nbEvents.size(), funValues.size() - 1)); SMESH::Histogram_var histogram = new SMESH::Histogram; @@ -937,6 +939,66 @@ FunctorType BadOrientedVolume_i::GetFunctorType() return SMESH::FT_BadOrientedVolume; } +/* + Class : BareBorderVolume_i + Description : Verify whether a mesh volume has a free facet without a face on it +*/ +BareBorderVolume_i::BareBorderVolume_i() +{ + Controls::PredicatePtr control( new Controls::BareBorderVolume() ); + myFunctorPtr = myPredicatePtr = control; +}; + +FunctorType BareBorderVolume_i::GetFunctorType() +{ + return SMESH::FT_BareBorderVolume; +} + +/* + Class : BareBorderFace_i + Description : Verify whether a mesh face has a free border without an edge on it +*/ +BareBorderFace_i::BareBorderFace_i() +{ + Controls::PredicatePtr control( new Controls::BareBorderFace() ); + myFunctorPtr = myPredicatePtr = control; +}; + +FunctorType BareBorderFace_i::GetFunctorType() +{ + return SMESH::FT_BareBorderFace; +} + +/* + Class : OverConstrainedVolume_i + Description : Verify whether a mesh volume has only one facet shared with other volumes +*/ +OverConstrainedVolume_i::OverConstrainedVolume_i() +{ + Controls::PredicatePtr control( new Controls::OverConstrainedVolume() ); + myFunctorPtr = myPredicatePtr = control; +}; + +FunctorType OverConstrainedVolume_i::GetFunctorType() +{ + return SMESH::FT_OverConstrainedVolume; +} + +/* + Class : OverConstrainedFace_i + Description : Verify whether a mesh face has only one border shared with other faces +*/ +OverConstrainedFace_i::OverConstrainedFace_i() +{ + Controls::PredicatePtr control( new Controls::OverConstrainedFace() ); + myFunctorPtr = myPredicatePtr = control; +}; + +FunctorType OverConstrainedFace_i::GetFunctorType() +{ + return SMESH::FT_OverConstrainedFace; +} + /* Class : BelongToGeom_i Description : Predicate for selection on geometrical support @@ -2036,6 +2098,38 @@ BadOrientedVolume_ptr FilterManager_i::CreateBadOrientedVolume() return anObj._retn(); } +BareBorderVolume_ptr FilterManager_i::CreateBareBorderVolume() +{ + SMESH::BareBorderVolume_i* aServant = new SMESH::BareBorderVolume_i(); + SMESH::BareBorderVolume_var anObj = aServant->_this(); + TPythonDump()<_this(); + TPythonDump()<_this(); + TPythonDump()<_this(); + TPythonDump()<GetElementType(); + return true; + } + case FT_BareBorderVolume: + { + BareBorderVolume_i* aPred = dynamic_cast( thePred ); + + CORBA::ULong i = theCriteria->length(); + theCriteria->length( i + 1 ); + + theCriteria[ i ] = createCriterion(); + + theCriteria[ i ].Type = FT_BareBorderVolume; + theCriteria[ i ].TypeOfElement = aPred->GetElementType(); + + return true; + } + case FT_BareBorderFace: + { + BareBorderFace_i* aPred = dynamic_cast( thePred ); + + CORBA::ULong i = theCriteria->length(); + theCriteria->length( i + 1 ); + + theCriteria[ i ] = createCriterion(); + + theCriteria[ i ].Type = FT_BareBorderFace; + theCriteria[ i ].TypeOfElement = aPred->GetElementType(); + + return true; + } + case FT_OverConstrainedVolume: + { + OverConstrainedVolume_i* aPred = dynamic_cast( thePred ); + + CORBA::ULong i = theCriteria->length(); + theCriteria->length( i + 1 ); + + theCriteria[ i ] = createCriterion(); + + theCriteria[ i ].Type = FT_OverConstrainedVolume; + theCriteria[ i ].TypeOfElement = aPred->GetElementType(); + + return true; + } + case FT_OverConstrainedFace: + { + OverConstrainedFace_i* aPred = dynamic_cast( thePred ); + + CORBA::ULong i = theCriteria->length(); + theCriteria->length( i + 1 ); + + theCriteria[ i ] = createCriterion(); + + theCriteria[ i ].Type = FT_OverConstrainedFace; + theCriteria[ i ].TypeOfElement = aPred->GetElementType(); + return true; } case FT_LessThan: @@ -2723,6 +2873,26 @@ CORBA::Boolean Filter_i::SetCriteria( const SMESH::Filter::Criteria& theCriteria aPredicate = aFilterMgr->CreateBadOrientedVolume(); } break; + case SMESH::FT_BareBorderVolume: + { + aPredicate = aFilterMgr->CreateBareBorderVolume(); + } + break; + case SMESH::FT_BareBorderFace: + { + aPredicate = aFilterMgr->CreateBareBorderFace(); + } + break; + case SMESH::FT_OverConstrainedVolume: + { + aPredicate = aFilterMgr->CreateOverConstrainedVolume(); + } + break; + case SMESH::FT_OverConstrainedFace: + { + aPredicate = aFilterMgr->CreateOverConstrainedFace(); + } + break; case SMESH::FT_LinearOrQuadratic: { SMESH::LinearOrQuadratic_ptr tmpPred = aFilterMgr->CreateLinearOrQuadratic(); @@ -2963,7 +3133,11 @@ static inline LDOMString toString( CORBA::Long theType ) case FT_BelongToCylinder: return "Belong to Cylinder"; case FT_BelongToGenSurface: return "Belong to Generic Surface"; case FT_LyingOnGeom : return "Lying on Geom"; - case FT_BadOrientedVolume: return "Bad Oriented Volume"; + case FT_BadOrientedVolume:return "Bad Oriented Volume"; + case FT_BareBorderVolume: return "Volumes with bare border"; + case FT_BareBorderFace : return "Faces with bare border"; + case FT_OverConstrainedVolume: return "Over-constrained Volumes"; + case FT_OverConstrainedFace : return "Over-constrained Faces"; case FT_RangeOfIds : return "Range of IDs"; case FT_FreeBorders : return "Free borders"; case FT_FreeEdges : return "Free edges"; @@ -3017,6 +3191,10 @@ static inline SMESH::FunctorType toFunctorType( const LDOMString& theStr ) // else if ( theStr.equals( "Length2D" ) ) return FT_Length2D; else if ( theStr.equals( "Range of IDs" ) ) return FT_RangeOfIds; else if ( theStr.equals( "Bad Oriented Volume" ) ) return FT_BadOrientedVolume; + else if ( theStr.equals( "Volumes with bare border" ) ) return FT_BareBorderVolume; + else if ( theStr.equals( "Faces with bare border" ) ) return FT_BareBorderFace; + else if ( theStr.equals( "Over-constrained Volumes" ) ) return FT_OverConstrainedVolume; + else if ( theStr.equals( "Over-constrained Faces" ) ) return FT_OverConstrainedFace; else if ( theStr.equals( "Less than" ) ) return FT_LessThan; else if ( theStr.equals( "More than" ) ) return FT_MoreThan; else if ( theStr.equals( "Equal to" ) ) return FT_EqualTo; diff --git a/src/SMESH_I/SMESH_Filter_i.hxx b/src/SMESH_I/SMESH_Filter_i.hxx index bef8c2252..9ca20ddb4 100644 --- a/src/SMESH_I/SMESH_Filter_i.hxx +++ b/src/SMESH_I/SMESH_Filter_i.hxx @@ -44,6 +44,7 @@ class SMESHDS_Mesh; namespace SMESH { + // ================================================================================ namespace Controls { @@ -123,8 +124,10 @@ namespace SMESH Controls::ElementsOnShapePtr myElementsOnShapePtr; // only if myIsSubshape == false }; typedef boost::shared_ptr LyingOnGeomPtr; - } - + + } // namespace Controls + + // ================================================================================ /* FUNCTORS */ @@ -387,6 +390,54 @@ namespace SMESH FunctorType GetFunctorType(); }; + /* + Class : BareBorderVolume_i + Description : Verify whether a mesh volume has a free facet without a face on it + */ + class SMESH_I_EXPORT BareBorderVolume_i: public virtual POA_SMESH::BareBorderVolume, + public virtual Predicate_i + { + public: + BareBorderVolume_i(); + FunctorType GetFunctorType(); + }; + + /* + Class : BareBorderFace_i + Description : Verify whether a mesh face has a free border without an edge on it + */ + class SMESH_I_EXPORT BareBorderFace_i: public virtual POA_SMESH::BareBorderFace, + public virtual Predicate_i + { + public: + BareBorderFace_i(); + FunctorType GetFunctorType(); + }; + + /* + Class : OverConstrainedVolume_i + Description : Verify whether a mesh volume has only one facet shared with other volumes + */ + class SMESH_I_EXPORT OverConstrainedVolume_i: public virtual POA_SMESH::OverConstrainedVolume, + public virtual Predicate_i + { + public: + OverConstrainedVolume_i(); + FunctorType GetFunctorType(); + }; + + /* + Class : OverConstrainedFace_i + Description : Verify whether a mesh face has only one border shared with other faces + */ + class SMESH_I_EXPORT OverConstrainedFace_i: public virtual POA_SMESH::OverConstrainedFace, + public virtual Predicate_i + { + public: + OverConstrainedFace_i(); + FunctorType GetFunctorType(); + }; + /* Class : BelongToGeom_i Description : Predicate for selection on geometrical support @@ -954,6 +1005,10 @@ namespace SMESH RangeOfIds_ptr CreateRangeOfIds(); BadOrientedVolume_ptr CreateBadOrientedVolume(); + BareBorderFace_ptr CreateBareBorderFace(); + BareBorderVolume_ptr CreateBareBorderVolume(); + OverConstrainedFace_ptr CreateOverConstrainedFace(); + OverConstrainedVolume_ptr CreateOverConstrainedVolume(); LinearOrQuadratic_ptr CreateLinearOrQuadratic(); GroupColor_ptr CreateGroupColor(); ElemGeomType_ptr CreateElemGeomType(); diff --git a/src/SMESH_I/SMESH_Gen_i.cxx b/src/SMESH_I/SMESH_Gen_i.cxx index a0ce885aa..76e96275f 100644 --- a/src/SMESH_I/SMESH_Gen_i.cxx +++ b/src/SMESH_I/SMESH_Gen_i.cxx @@ -91,9 +91,10 @@ #include "SMDS_EdgePosition.hxx" #include "SMDS_FacePosition.hxx" -#include "SMDS_VertexPosition.hxx" -#include "SMDS_SpacePosition.hxx" #include "SMDS_PolyhedralVolumeOfNodes.hxx" +#include "SMDS_SetIterator.hxx" +#include "SMDS_SpacePosition.hxx" +#include "SMDS_VertexPosition.hxx" #include CORBA_SERVER_HEADER(SMESH_Group) #include CORBA_SERVER_HEADER(SMESH_Filter) @@ -898,7 +899,7 @@ SMESH::SMESH_Mesh_ptr SMESH_Gen_i::CreateMeshesFromUNV( const char* theFileName aServant->ImportUNVFile( theFileName ); // Dump creation of groups - aServant->GetGroups(); + SMESH::ListOfGroups_var groups = aServant->GetGroups(); return aMesh._retn(); } @@ -977,7 +978,7 @@ SMESH::mesh_array* SMESH_Gen_i::CreateMeshesFromMED( const char* theFileName, } // Dump creation of groups for ( int i = 0; i < aResult->length(); ++i ) - aResult[ i ]->GetGroups(); + SMESH::ListOfGroups_var groups = aResult[ i ]->GetGroups(); return aResult._retn(); } @@ -2201,6 +2202,212 @@ SMESH_Gen_i::ConcatenateCommon(const SMESH::mesh_array& theMeshesArray, return aNewMesh._retn(); } +//================================================================================ +/*! + * \brief Create a mesh by copying a part of another mesh + * \param meshPart - a part of mesh to copy + * \param toCopyGroups - to create in the new mesh groups + * the copied elements belongs to + * \param toKeepIDs - to preserve IDs of the copied elements or not + * \retval SMESH::SMESH_Mesh_ptr - the new mesh + */ +//================================================================================ + +SMESH::SMESH_Mesh_ptr SMESH_Gen_i::CopyMesh(SMESH::SMESH_IDSource_ptr meshPart, + const char* meshName, + CORBA::Boolean toCopyGroups, + CORBA::Boolean toKeepIDs) +{ + Unexpect aCatch(SALOME_SalomeException); + + TPythonDump* pyDump = new TPythonDump; // prevent dump from CreateMesh() + + // 1. Get source mesh + + if ( CORBA::is_nil( meshPart )) + THROW_SALOME_CORBA_EXCEPTION( "bad IDSource", SALOME::BAD_PARAM ); + + SMESH::SMESH_Mesh_var srcMesh = meshPart->GetMesh(); + SMESH_Mesh_i* srcMesh_i = SMESH::DownCast( srcMesh ); + if ( !srcMesh_i ) + THROW_SALOME_CORBA_EXCEPTION( "bad mesh of IDSource", SALOME::BAD_PARAM ); + + SMESHDS_Mesh* srcMeshDS = srcMesh_i->GetImpl().GetMeshDS(); + + // 2. Make a new mesh + + SMESH::SMESH_Mesh_var newMesh = CreateMesh(GEOM::GEOM_Object::_nil()); + SMESH_Mesh_i* newMesh_i = SMESH::DownCast( newMesh ); + if ( !newMesh_i ) + THROW_SALOME_CORBA_EXCEPTION( "can't create a mesh", SALOME::INTERNAL_ERROR ); + SALOMEDS::SObject_var meshSO = ObjectToSObject(myCurrentStudy, newMesh ); + if ( !meshSO->_is_nil() ) + { + SetName( meshSO, meshName, "Mesh" ); + SetPixMap( meshSO, "ICON_SMESH_TREE_MESH_IMPORTED"); + } + SMESHDS_Mesh* newMeshDS = newMesh_i->GetImpl().GetMeshDS(); + ::SMESH_MeshEditor editor( &newMesh_i->GetImpl() ); + + // 3. Get elements to copy + + SMDS_ElemIteratorPtr srcElemIt; + TIDSortedElemSet srcElems; + SMESH::array_of_ElementType_var srcElemTypes = meshPart->GetTypes(); + if ( SMESH::DownCast( meshPart )) + { + srcElemIt = srcMeshDS->elementsIterator(); + } + else + { + SMESH::long_array_var ids = meshPart->GetIDs(); + if ( srcElemTypes->length() == 1 && srcElemTypes[0] == SMESH::NODE ) // group of nodes + { + for (int i=0; i < ids->length(); i++) + if ( const SMDS_MeshElement * elem = srcMeshDS->FindNode( ids[i] )) + srcElems.insert( elem ); + } + else + { + for (int i=0; i < ids->length(); i++) + if ( const SMDS_MeshElement * elem = srcMeshDS->FindElement( ids[i] )) + srcElems.insert( elem ); + } + if ( srcElems.empty() ) + return newMesh._retn(); + + typedef SMDS_SetIterator< SMDS_pElement, TIDSortedElemSet::const_iterator > ElIter; + srcElemIt = SMDS_ElemIteratorPtr( new ElIter( srcElems.begin(), srcElems.end() )); + } + + // 4. Copy elements + + typedef map TE2EMap; + TE2EMap e2eMapByType[ SMDSAbs_NbElementTypes ]; + TE2EMap& n2nMap = e2eMapByType[ SMDSAbs_Node ]; + int iN; + const SMDS_MeshNode *nSrc, *nTgt; + vector< const SMDS_MeshNode* > nodes; + while ( srcElemIt->more() ) + { + const SMDS_MeshElement * elem = srcElemIt->next(); + nodes.resize( elem->NbNodes()); + SMDS_ElemIteratorPtr nIt = elem->nodesIterator(); + if ( toKeepIDs ) { + for ( iN = 0; nIt->more(); ++iN ) + { + nSrc = static_cast( nIt->next() ); + nTgt = newMeshDS->FindNode( nSrc->GetID()); + if ( !nTgt ) + nTgt = newMeshDS->AddNodeWithID( nSrc->X(), nSrc->Y(), nSrc->Z(), nSrc->GetID()); + nodes[ iN ] = nTgt; + } + } + else { + for ( iN = 0; nIt->more(); ++iN ) + { + nSrc = static_cast( nIt->next() ); + TE2EMap::iterator n2n = n2nMap.insert( make_pair( nSrc, SMDS_pNode(0) )).first; + if ( !n2n->second ) + n2n->second = newMeshDS->AddNode( nSrc->X(), nSrc->Y(), nSrc->Z() ); + nodes[ iN ] = (const SMDS_MeshNode*) n2n->second; + } + } + if ( elem->GetType() != SMDSAbs_Node ) + { + int ID = toKeepIDs ? elem->GetID() : 0; + const SMDS_MeshElement * newElem = editor.AddElement( nodes, + elem->GetType(), + elem->IsPoly(), + ID); + if ( toCopyGroups && !toKeepIDs ) + e2eMapByType[ elem->GetType() ].insert( make_pair( elem, newElem )); + } + } + + // 5. Copy groups + + int nbNewGroups = 0; + if ( toCopyGroups ) + { + SMESH_Mesh::GroupIteratorPtr gIt = srcMesh_i->GetImpl().GetGroups(); + while ( gIt->more() ) + { + SMESH_Group* group = gIt->next(); + const SMESHDS_GroupBase* groupDS = group->GetGroupDS(); + + // Check group type. We copy nodal groups containing nodes of copied element + SMDSAbs_ElementType groupType = groupDS->GetType(); + if ( groupType != SMDSAbs_Node && + newMeshDS->GetMeshInfo().NbElements( groupType ) == 0 ) + continue; // group type differs from types of meshPart + + // Find copied elements in the group + vector< const SMDS_MeshElement* > groupElems; + SMDS_ElemIteratorPtr eIt = groupDS->GetElements(); + if ( toKeepIDs ) + { + const SMDS_MeshElement* foundElem; + if ( groupType == SMDSAbs_Node ) + { + while ( eIt->more() ) + if (( foundElem = newMeshDS->FindNode( eIt->next()->GetID() ))) + groupElems.push_back( foundElem ); + } + else + { + while ( eIt->more() ) + if (( foundElem = newMeshDS->FindElement( eIt->next()->GetID() ))) + groupElems.push_back( foundElem ); + } + } + else + { + TE2EMap & e2eMap = e2eMapByType[ groupDS->GetType() ]; + if ( e2eMap.empty() ) continue; + int minID = e2eMap.begin()->first->GetID(); + int maxID = e2eMap.rbegin()->first->GetID(); + TE2EMap::iterator e2e; + while ( eIt->more() && groupElems.size() < e2eMap.size()) + { + const SMDS_MeshElement* e = eIt->next(); + if ( e->GetID() < minID || e->GetID() > maxID ) continue; + if ((e2e = e2eMap.find( e )) != e2eMap.end()) + groupElems.push_back( e2e->second ); + } + } + // Make a new group + if ( !groupElems.empty() ) + { + SMESH::SMESH_Group_var newGroupObj = + newMesh->CreateGroup( SMESH::ElementType(groupType), group->GetName() ); + if ( SMESH_GroupBase_i* newGroup_i = SMESH::DownCast( newGroupObj)) + { + SMESHDS_GroupBase * newGroupDS = newGroup_i->GetGroupDS(); + SMDS_MeshGroup& smdsGroup = ((SMESHDS_Group*)newGroupDS)->SMDSGroup(); + for ( unsigned i = 0; i < groupElems.size(); ++i ) + smdsGroup.Add( groupElems[i] ); + + nbNewGroups++; + } + } + } + } + + *pyDump << newMesh << " = " << this + << ".CopyMesh( " << meshPart << ", " + << "'" << meshName << "', " + << toCopyGroups << ", " + << toKeepIDs << ")"; + + delete pyDump; pyDump = 0; // allow dump in GetGroups() + + if ( nbNewGroups > 0 ) // dump created groups + SMESH::ListOfGroups_var groups = newMesh->GetGroups(); + + return newMesh._retn(); +} + //================================================================================ /*! * SMESH_Gen_i::GetMEDVersion diff --git a/src/SMESH_I/SMESH_Gen_i.hxx b/src/SMESH_I/SMESH_Gen_i.hxx index b2c90805c..b4003818d 100644 --- a/src/SMESH_I/SMESH_Gen_i.hxx +++ b/src/SMESH_I/SMESH_Gen_i.hxx @@ -236,6 +236,12 @@ public: SMESH::SMESH_Mesh_ptr CreateMeshesFromSTL( const char* theFileName ) throw ( SALOME::SALOME_Exception ); + // Copy a part of mesh + SMESH::SMESH_Mesh_ptr CopyMesh(SMESH::SMESH_IDSource_ptr meshPart, + const char* meshName, + CORBA::Boolean toCopyGroups, + CORBA::Boolean toKeepIDs); + // Compute mesh on a shape CORBA::Boolean Compute( SMESH::SMESH_Mesh_ptr theMesh, GEOM::GEOM_Object_ptr theShapeObject ) diff --git a/src/SMESH_SWIG/smeshDC.py b/src/SMESH_SWIG/smeshDC.py index a2476107a..64aace0e5 100644 --- a/src/SMESH_SWIG/smeshDC.py +++ b/src/SMESH_SWIG/smeshDC.py @@ -663,27 +663,6 @@ class smeshDC(SMESH._objref_SMESH_Gen): aMesh = Mesh(self, self.geompyD, aSmeshMesh) return aMesh - ## From SMESH_Gen interface - # @return the list of integer values - # @ingroup l1_auxiliary - def GetSubShapesId( self, theMainObject, theListOfSubObjects ): - return SMESH._objref_SMESH_Gen.GetSubShapesId(self,theMainObject, theListOfSubObjects) - - ## From SMESH_Gen interface. Creates a pattern - # @return an instance of SMESH_Pattern - # - # Example of Patterns usage - # @ingroup l2_modif_patterns - def GetPattern(self): - return SMESH._objref_SMESH_Gen.GetPattern(self) - - ## Sets number of segments per diagonal of boundary box of geometry by which - # default segment length of appropriate 1D hypotheses is defined. - # Default value is 10 - # @ingroup l1_auxiliary - def SetBoundaryBoxSegmentation(self, nbSegments): - SMESH._objref_SMESH_Gen.SetBoundaryBoxSegmentation(self,nbSegments) - ## Concatenate the given meshes into one mesh. # @return an instance of Mesh class # @param meshes the meshes to combine into one mesh @@ -707,6 +686,41 @@ class smeshDC(SMESH._objref_SMESH_Gen): aMesh = Mesh(self, self.geompyD, aSmeshMesh) return aMesh + ## Create a mesh by copying a part of another mesh. + # @param meshPart a part of mesh to copy, either a Mesh, a sub-mesh or a group; + # to copy nodes or elements not contained in any mesh object, + # pass result of Mesh.GetIDSource( list_of_ids, type ) as meshPart + # @param meshName a name of the new mesh + # @param toCopyGroups to create in the new mesh groups the copied elements belongs to + # @param toKeepIDs to preserve IDs of the copied elements or not + # @return an instance of Mesh class + def CopyMesh( self, meshPart, meshName, toCopyGroups=False, toKeepIDs=False): + if (isinstance( meshPart, Mesh )): + meshPart = meshPart.GetMesh() + mesh = SMESH._objref_SMESH_Gen.CopyMesh( self,meshPart,meshName,toCopyGroups,toKeepIDs ) + return Mesh(self, self.geompyD, mesh) + + ## From SMESH_Gen interface + # @return the list of integer values + # @ingroup l1_auxiliary + def GetSubShapesId( self, theMainObject, theListOfSubObjects ): + return SMESH._objref_SMESH_Gen.GetSubShapesId(self,theMainObject, theListOfSubObjects) + + ## From SMESH_Gen interface. Creates a pattern + # @return an instance of SMESH_Pattern + # + # Example of Patterns usage + # @ingroup l2_modif_patterns + def GetPattern(self): + return SMESH._objref_SMESH_Gen.GetPattern(self) + + ## Sets number of segments per diagonal of boundary box of geometry by which + # default segment length of appropriate 1D hypotheses is defined. + # Default value is 10 + # @ingroup l1_auxiliary + def SetBoundaryBoxSegmentation(self, nbSegments): + SMESH._objref_SMESH_Gen.SetBoundaryBoxSegmentation(self,nbSegments) + # Filtering. Auxiliary functions: # ------------------------------ @@ -735,6 +749,8 @@ class smeshDC(SMESH._objref_SMESH_Gen): # @param UnaryOp FT_LogicalNOT or FT_Undefined # @param BinaryOp a binary logical operation FT_LogicalAND, FT_LogicalOR or # FT_Undefined (must be for the last criterion of all criteria) + # @param Tolerance the tolerance used by FT_BelongToGeom, FT_BelongToSurface, + # FT_LyingOnGeom, FT_CoplanarFaces criteria # @return SMESH.Filter.Criterion # @ingroup l1_controls def GetCriterion(self,elementType, @@ -742,10 +758,12 @@ class smeshDC(SMESH._objref_SMESH_Gen): Compare = FT_EqualTo, Treshold="", UnaryOp=FT_Undefined, - BinaryOp=FT_Undefined): + BinaryOp=FT_Undefined, + Tolerance=1e-07): aCriterion = self.GetEmptyCriterion() aCriterion.TypeOfElement = elementType aCriterion.Type = self.EnumToLong(CritType) + aCriterion.Tolerance = Tolerance aTreshold = Treshold @@ -810,7 +828,9 @@ class smeshDC(SMESH._objref_SMESH_Gen): return None pass elif CritType in [FT_FreeBorders, FT_FreeEdges, FT_BadOrientedVolume, FT_FreeNodes, - FT_FreeFaces, FT_LinearOrQuadratic]: + FT_FreeFaces, FT_LinearOrQuadratic, + FT_BareBorderFace, FT_BareBorderVolume, + FT_OverConstrainedFace, FT_OverConstrainedVolume]: # At this point the treshold is unnecessary if aTreshold == FT_LogicalNOT: aCriterion.UnaryOp = self.EnumToLong(FT_LogicalNOT) @@ -845,14 +865,17 @@ class smeshDC(SMESH._objref_SMESH_Gen): # @param Compare belongs to {FT_LessThan, FT_MoreThan, FT_EqualTo} # @param Treshold the threshold value (range of id ids as string, shape, numeric) # @param UnaryOp FT_LogicalNOT or FT_Undefined + # @param Tolerance the tolerance used by FT_BelongToGeom, FT_BelongToSurface, + # FT_LyingOnGeom, FT_CoplanarFaces criteria # @return SMESH_Filter # @ingroup l1_controls def GetFilter(self,elementType, CritType=FT_Undefined, Compare=FT_EqualTo, Treshold="", - UnaryOp=FT_Undefined): - aCriterion = self.GetCriterion(elementType, CritType, Compare, Treshold, UnaryOp, FT_Undefined) + UnaryOp=FT_Undefined, + Tolerance=1e-07): + aCriterion = self.GetCriterion(elementType, CritType, Compare, Treshold, UnaryOp, FT_Undefined,Tolerance) aFilterMgr = self.CreateFilterManager() aFilter = aFilterMgr.CreateFilter() aCriteria = [] @@ -1744,6 +1767,8 @@ class Mesh: # @param Compare belongs to {FT_LessThan, FT_MoreThan, FT_EqualTo} # @param Treshold the threshold value (range of id ids as string, shape, numeric) # @param UnaryOp FT_LogicalNOT or FT_Undefined + # @param Tolerance the tolerance used by FT_BelongToGeom, FT_BelongToSurface, + # FT_LyingOnGeom, FT_CoplanarFaces criteria # @return SMESH_Group # @ingroup l2_grps_create def MakeGroup(self, @@ -1752,8 +1777,9 @@ class Mesh: CritType=FT_Undefined, Compare=FT_EqualTo, Treshold="", - UnaryOp=FT_Undefined): - aCriterion = self.smeshpyD.GetCriterion(elementType, CritType, Compare, Treshold, UnaryOp, FT_Undefined) + UnaryOp=FT_Undefined, + Tolerance=1e-07): + aCriterion = self.smeshpyD.GetCriterion(elementType, CritType, Compare, Treshold, UnaryOp, FT_Undefined,Tolerance) group = self.MakeGroupByCriterion(groupName, aCriterion) return group @@ -1969,6 +1995,13 @@ class Mesh: def GetMeshEditor(self): return self.mesh.GetMeshEditor() + ## Wrap a list of IDs of elements or nodes into SMESH_IDSource which + # can be passed as argument to accepting mesh, group or sub-mesh + # @return an instance of SMESH_IDSource + # @ingroup l1_auxiliary + def GetIDSource(self, ids, elemType): + return self.GetMeshEditor().MakeIDSource(ids, elemType) + ## Gets MED Mesh # @return an instance of SALOME_MED::MESH # @ingroup l1_auxiliary @@ -3213,7 +3246,7 @@ class Mesh: ## Generates new elements by extrusion of the elements with given ids # @param IDsOfElements the list of elements ids for extrusion - # @param StepVector vector, defining the direction and value of extrusion + # @param StepVector vector or DirStruct, defining the direction and value of extrusion # @param NbOfSteps the number of steps # @param MakeGroups forces the generation of new groups from existing ones # @return the list of created groups (SMESH_GroupBase) if MakeGroups=True, empty list otherwise @@ -3700,7 +3733,7 @@ class Mesh: if ( isinstance( theObject, Mesh )): theObject = theObject.GetMesh() if ( isinstance( theObject, list )): - theObject = self.editor.MakeIDSource(theObject, SMESH.ALL) + theObject = self.GetIDSource(theObject, SMESH.ALL) thePoint, Parameters = ParsePointStruct(thePoint) self.mesh.SetParameters(Parameters) @@ -3721,7 +3754,7 @@ class Mesh: if (isinstance(theObject, Mesh)): theObject = theObject.GetMesh() if ( isinstance( theObject, list )): - theObject = self.editor.MakeIDSource(theObject,SMESH.ALL) + theObject = self.GetIDSource(theObject,SMESH.ALL) mesh = self.editor.ScaleMakeMesh(theObject, thePoint, theScaleFact, MakeGroups, NewMeshName) @@ -3855,7 +3888,7 @@ class Mesh: if not isinstance( exceptNodes, list): exceptNodes = [ exceptNodes ] if exceptNodes and isinstance( exceptNodes[0], int): - exceptNodes = [ self.editor.MakeIDSource( exceptNodes, SMESH.NODE)] + exceptNodes = [ self.GetIDSource( exceptNodes, SMESH.NODE)] return self.editor.FindCoincidentNodesOnPartBut(SubMeshOrGroup, Tolerance,exceptNodes) ## Merges nodes @@ -4329,8 +4362,11 @@ class Mesh_Algorithm: pass self.mesh.smeshpyD.SetName(hypo, hyp + a) pass + geomName="" + if self.geom: + geomName = GetName(self.geom) status = self.mesh.mesh.AddHypothesis(self.geom, hypo) - TreatHypoStatus( status, GetName(hypo), GetName(self.geom), 0 ) + TreatHypoStatus( status, GetName(hypo), geomName, 0 ) return hypo ## Returns entry of the shape to mesh in the study @@ -4873,20 +4909,31 @@ class Mesh_Triangle(Mesh_Algorithm): self.Parameters().SetOptionValue(optionName,level) ## Sets QuadAllowed flag. - # Only for algoType == NETGEN || NETGEN_2D || BLSURF + # Only for algoType == NETGEN(NETGEN_1D2D) || NETGEN_2D || BLSURF # @ingroup l3_hypos_netgen l3_hypos_blsurf def SetQuadAllowed(self, toAllow=True): if self.algoType == NETGEN_2D: - if toAllow: # add QuadranglePreference - self.Hypothesis("QuadranglePreference", UseExisting=1, CompareMethod=self.CompareEqualHyp) - else: # remove QuadranglePreference + if not self.params: + # use simple hyps + hasSimpleHyps = False + simpleHyps = ["QuadranglePreference","LengthFromEdges","MaxElementArea"] for hyp in self.mesh.GetHypothesisList( self.geom ): - if hyp.GetName() == "QuadranglePreference": - self.mesh.RemoveHypothesis( self.geom, hyp ) + if hyp.GetName() in simpleHyps: + hasSimpleHyps = True + if hyp.GetName() == "QuadranglePreference": + if not toAllow: # remove QuadranglePreference + self.mesh.RemoveHypothesis( self.geom, hyp ) + pass + return pass pass + if hasSimpleHyps: + if toAllow: # add QuadranglePreference + self.Hypothesis("QuadranglePreference", UseExisting=1, CompareMethod=self.CompareEqualHyp) + pass + return pass - return + pass if self.Parameters(): self.params.SetQuadAllowed(toAllow) return @@ -4895,30 +4942,25 @@ class Mesh_Triangle(Mesh_Algorithm): # # @ingroup l3_hypos_netgen def Parameters(self, which=SOLE): - if self.params: - return self.params - if self.algoType == NETGEN: - if which == SIMPLE: - self.params = self.Hypothesis("NETGEN_SimpleParameters_2D", [], + if not self.params: + if self.algoType == NETGEN: + if which == SIMPLE: + self.params = self.Hypothesis("NETGEN_SimpleParameters_2D", [], + "libNETGENEngine.so", UseExisting=0) + else: + self.params = self.Hypothesis("NETGEN_Parameters_2D", [], + "libNETGENEngine.so", UseExisting=0) + elif self.algoType == MEFISTO: + print "Mefisto algo support no multi-parameter hypothesis" + elif self.algoType == NETGEN_2D: + self.params = self.Hypothesis("NETGEN_Parameters_2D_ONLY", [], "libNETGENEngine.so", UseExisting=0) + elif self.algoType == BLSURF: + self.params = self.Hypothesis("BLSURF_Parameters", [], + "libBLSURFEngine.so", UseExisting=0) else: - self.params = self.Hypothesis("NETGEN_Parameters_2D", [], - "libNETGENEngine.so", UseExisting=0) - return self.params - elif self.algoType == MEFISTO: - print "Mefisto algo support no multi-parameter hypothesis" - return None - elif self.algoType == NETGEN_2D: - print "NETGEN_2D_ONLY algo support no multi-parameter hypothesis" - print "NETGEN_2D_ONLY uses 'MaxElementArea' and 'LengthFromEdges' ones" - return None - elif self.algoType == BLSURF: - self.params = self.Hypothesis("BLSURF_Parameters", [], - "libBLSURFEngine.so", UseExisting=0) - return self.params - else: - print "Mesh_Triangle with algo type %s does not have such a parameter, check algo type"%self.algoType - return None + print "Mesh_Triangle with algo type %s does not have such a parameter, check algo type"%self.algoType + return self.params ## Sets MaxSize # @@ -5155,33 +5197,34 @@ class Mesh_Tetrahedron(Mesh_Algorithm): # # @ingroup l3_hypos_netgen def Parameters(self, which=SOLE): - if self.params: - return self.params + if not self.params: - if self.algoType == FULL_NETGEN: - if which == SIMPLE: - self.params = self.Hypothesis("NETGEN_SimpleParameters_3D", [], - "libNETGENEngine.so", UseExisting=0) - else: - self.params = self.Hypothesis("NETGEN_Parameters", [], + if self.algoType == FULL_NETGEN: + if which == SIMPLE: + self.params = self.Hypothesis("NETGEN_SimpleParameters_3D", [], + "libNETGENEngine.so", UseExisting=0) + else: + self.params = self.Hypothesis("NETGEN_Parameters", [], + "libNETGENEngine.so", UseExisting=0) + + if self.algoType == NETGEN: + self.params = self.Hypothesis("NETGEN_Parameters_3D", [], "libNETGENEngine.so", UseExisting=0) - return self.params - if self.algoType == GHS3D: - self.params = self.Hypothesis("GHS3D_Parameters", [], - "libGHS3DEngine.so", UseExisting=0) - return self.params + elif self.algoType == GHS3D: + self.params = self.Hypothesis("GHS3D_Parameters", [], + "libGHS3DEngine.so", UseExisting=0) - if self.algoType == GHS3DPRL: - self.params = self.Hypothesis("GHS3DPRL_Parameters", [], - "libGHS3DPRLEngine.so", UseExisting=0) - return self.params + elif self.algoType == GHS3DPRL: + self.params = self.Hypothesis("GHS3DPRL_Parameters", [], + "libGHS3DPRLEngine.so", UseExisting=0) + else: + print "Algo supports no multi-parameter hypothesis" - print "Algo supports no multi-parameter hypothesis" - return None + return self.params ## Sets MaxSize - # Parameter of FULL_NETGEN + # Parameter of FULL_NETGEN and NETGEN # @ingroup l3_hypos_netgen def SetMaxSize(self, theSize): self.Parameters().SetMaxSize(theSize) @@ -5193,7 +5236,7 @@ class Mesh_Tetrahedron(Mesh_Algorithm): self.Parameters().SetSecondOrder(theVal) ## Sets Optimize flag - # Parameter of FULL_NETGEN + # Parameter of FULL_NETGEN and NETGEN # @ingroup l3_hypos_netgen def SetOptimize(self, theVal): self.Parameters().SetOptimize(theVal) diff --git a/src/StdMeshers/StdMeshers_Import_1D.cxx b/src/StdMeshers/StdMeshers_Import_1D.cxx index fe0f05476..dcd66eca9 100644 --- a/src/StdMeshers/StdMeshers_Import_1D.cxx +++ b/src/StdMeshers/StdMeshers_Import_1D.cxx @@ -120,6 +120,7 @@ namespace // INTERNAL STUFF enum _ListenerDataType { WAIT_HYP_MODIF=1, // data indicating awaiting for valid parameters of src hyp + LISTEN_SRC_MESH, // data storing submesh depending on source mesh state SRC_HYP // data storing ImportSource hyp }; //================================================================================ @@ -130,10 +131,29 @@ namespace // INTERNAL STUFF struct _ListenerData : public SMESH_subMeshEventListenerData { const StdMeshers_ImportSource1D* _srcHyp; - _ListenerData(const StdMeshers_ImportSource1D* h): + _ListenerData(const StdMeshers_ImportSource1D* h, _ListenerDataType type=SRC_HYP): SMESH_subMeshEventListenerData(/*isDeletable=*/true), _srcHyp(h) { - myType = SRC_HYP; + myType = type; + } + }; + //================================================================================ + /*! + * \brief Comparator of sub-meshes + */ + struct _SubLess + { + bool operator()(const SMESH_subMesh* sm1, const SMESH_subMesh* sm2 ) const + { + if ( sm1 == sm2 ) return false; + if ( !sm1 || !sm2 ) return sm1 < sm2; + const TopoDS_Shape& s1 = sm1->GetSubShape(); + const TopoDS_Shape& s2 = sm2->GetSubShape(); + TopAbs_ShapeEnum t1 = s1.IsNull() ? TopAbs_SHAPE : s1.ShapeType(); + TopAbs_ShapeEnum t2 = s2.IsNull() ? TopAbs_SHAPE : s2.ShapeType(); + if ( t1 == t2) + return (sm1 < sm2); + return t1 < t2; // to have: face < edge } }; //================================================================================ @@ -146,10 +166,10 @@ namespace // INTERNAL STUFF StdMeshers_Import_1D::TNodeNodeMap _n2n; StdMeshers_Import_1D::TElemElemMap _e2e; - set< SMESH_subMesh*> _subM; // submeshes relating to this srcMesh - set< SMESH_subMesh*> _copyMeshSubM; // submeshes requesting mesh copying - set< SMESH_subMesh*> _copyGroupSubM; // submeshes requesting mesh copying - set< SMESH_subMesh*> _computedSubM; + set< SMESH_subMesh*, _SubLess > _subM; // submeshes relating to this srcMesh + set< SMESH_subMesh*, _SubLess > _copyMeshSubM; // submeshes requesting mesh copying + set< SMESH_subMesh*, _SubLess > _copyGroupSubM; // submeshes requesting mesh copying + set< SMESH_subMesh*, _SubLess > _computedSubM; SMESHDS_SubMesh* _importMeshSubDS; // submesh storing a copy of _srcMesh int _importMeshSubID; // id of _importMeshSubDS @@ -196,10 +216,30 @@ namespace // INTERNAL STUFF if ( toCopyGroups ) _copyGroupSubM.insert( sm ); else _copyGroupSubM.erase( sm ); } + void addComputed( SMESH_subMesh* sm ) + { + SMESH_subMeshIteratorPtr smIt = sm->getDependsOnIterator(/*includeSelf=*/true, + /*complexShapeFirst=*/true); + while ( smIt->more() ) + { + sm = smIt->next(); + switch ( sm->GetSubShape().ShapeType() ) + { + case TopAbs_EDGE: + case TopAbs_FACE: + _subM.insert( sm ); + if ( !sm->IsEmpty() ) + _computedSubM.insert( sm ); + case TopAbs_VERTEX: + break; + default:; + } + } + } }; //================================================================================ /*! - * Listener notified on events of an imported submesh + * Listener notified on events relating to imported submesh */ class _Listener : public SMESH_subMeshEventListener { @@ -212,198 +252,248 @@ namespace // INTERNAL STUFF // return poiter to a static listener static _Listener* get() { static _Listener theListener; return &theListener; } - //-------------------------------------------------------------------------------- - /*! - * \brief Find or create ImportData for given meshes - */ - static _ImportData* getImportData(const SMESH_Mesh* srcMesh, - SMESH_Mesh* tgtMesh) - { - list< _ImportData >& dList = get()->_tgtMesh2ImportData[tgtMesh]; - list< _ImportData >::iterator d = dList.begin(); - for ( ; d != dList.end(); ++d ) - if ( d->_srcMesh == srcMesh ) - return &*d; - dList.push_back(_ImportData(srcMesh)); - return &dList.back(); - } + static _ImportData* getImportData(const SMESH_Mesh* srcMesh, SMESH_Mesh* tgtMesh); - //-------------------------------------------------------------------------------- - /*! - * \brief Remember an imported mesh and groups - * \param smDS - submesh DS holding the imported mesh - * \param sm - submesh computed by Import algo - * \param srcMeshDS - source mesh - * \param srcHyp - ImportSource hypothesis - */ - static _ImportData* storeImportSubmesh(SMESH_subMesh* importSub, - const SMESH_Mesh* srcMesh, - const StdMeshers_ImportSource1D* srcHyp) - { - // set listener to hear events of the submesh computed by "Import" algo - importSub->SetEventListener( get(), new _ListenerData(srcHyp), importSub ); - - // set a listener to hear events of the source mesh - SMESH_subMesh* smToNotify = importSub; - SMESH_subMesh* smToListen = srcMesh->GetSubMeshContaining(1); - importSub->SetEventListener - ( new SMESH_subMeshEventListener(/*isDeletable=*/true), - SMESH_subMeshEventListenerData::MakeData( smToNotify ), - smToListen ); - - // remeber the submesh - _ImportData* iData = _Listener::getImportData( srcMesh, importSub->GetFather()); - iData->_subM.insert( importSub ); - iData->trackHypParams( importSub, srcHyp ); - if ( !importSub->IsEmpty() ) - iData->_computedSubM.insert( importSub ); - if ( !iData->_copyMeshSubM.empty() && iData->_importMeshSubID < 1 ) - { - SMESH_Mesh* tgtMesh = importSub->GetFather(); - iData->_importMeshSubID = getSubmeshIDForCopiedMesh( srcMesh->GetMeshDS(),tgtMesh); - iData->_importMeshSubDS = tgtMesh->GetMeshDS()->NewSubMesh( iData->_importMeshSubID ); - } - if ( !importSub->IsEmpty() ) - iData->_computedSubM.insert( importSub ); + static void storeImportSubmesh(SMESH_subMesh* importSub, + const SMESH_Mesh* srcMesh, + const StdMeshers_ImportSource1D* srcHyp); - return iData; - } - //-------------------------------------------------------------------------------- - /*! - * \brief mark sm as missing src hyp with valid groups - */ + virtual void ProcessEvent(const int event, + const int eventType, + SMESH_subMesh* subMesh, + SMESH_subMeshEventListenerData* data, + const SMESH_Hypothesis* hyp); + void removeSubmesh( SMESH_subMesh* sm, _ListenerData* data ); + void clearSubmesh ( SMESH_subMesh* sm, _ListenerData* data, bool clearAllSub ); + + // mark sm as missing src hyp with valid groups static void waitHypModification(SMESH_subMesh* sm) { sm->SetEventListener (get(), SMESH_subMeshEventListenerData::MakeData( sm, WAIT_HYP_MODIF ), sm); } + }; + //-------------------------------------------------------------------------------- + /*! + * \brief Find or create ImportData for given meshes + */ + _ImportData* _Listener::getImportData(const SMESH_Mesh* srcMesh, + SMESH_Mesh* tgtMesh) + { + list< _ImportData >& dList = get()->_tgtMesh2ImportData[tgtMesh]; + list< _ImportData >::iterator d = dList.begin(); + for ( ; d != dList.end(); ++d ) + if ( d->_srcMesh == srcMesh ) + return &*d; + dList.push_back(_ImportData(srcMesh)); + return &dList.back(); + } - //-------------------------------------------------------------------------------- - /*! - * \brief Remove imported mesh and/or groups as soon as no more imported submeshes - * remain computed - * \param sm - submesh loosing Import algo - * \param data - data holding imported groups - */ - void removeSubmesh( SMESH_subMesh* sm, _ListenerData* data ) + //-------------------------------------------------------------------------------- + /*! + * \brief Remember an imported sub-mesh and set needed even listeners + * \param importSub - submesh computed by Import algo + * \param srcMesh - source mesh + * \param srcHyp - ImportSource hypothesis + */ + void _Listener::storeImportSubmesh(SMESH_subMesh* importSub, + const SMESH_Mesh* srcMesh, + const StdMeshers_ImportSource1D* srcHyp) + { + // set listener to hear events of the submesh computed by "Import" algo + importSub->SetEventListener( get(), new _ListenerData(srcHyp), importSub ); + + // set a listener to hear events of the source mesh + SMESH_subMesh* smToNotify = importSub; + SMESH_subMesh* smToListen = srcMesh->GetSubMeshContaining(1); + SMESH_subMeshEventListenerData* data = new _ListenerData(srcHyp, LISTEN_SRC_MESH); + data->mySubMeshes.push_back( smToNotify ); + importSub->SetEventListener( get(), data, smToListen ); + + // remeber the submesh importSub and its sub-submeshes + _ImportData* iData = _Listener::getImportData( srcMesh, importSub->GetFather()); + iData->trackHypParams( importSub, srcHyp ); + iData->addComputed( importSub ); + if ( !iData->_copyMeshSubM.empty() && iData->_importMeshSubID < 1 ) { - list< _ImportData > & dList = _tgtMesh2ImportData[ sm->GetFather() ]; - list< _ImportData >::iterator d = dList.begin(); - for ( ; d != dList.end(); ++d ) - if ( (*d)._subM.erase( sm )) + SMESH_Mesh* tgtMesh = importSub->GetFather(); + iData->_importMeshSubID = getSubmeshIDForCopiedMesh( srcMesh->GetMeshDS(),tgtMesh); + iData->_importMeshSubDS = tgtMesh->GetMeshDS()->NewSubMesh( iData->_importMeshSubID ); + } + } + //-------------------------------------------------------------------------------- + /*! + * \brief Remove imported mesh and/or groups if needed + * \param sm - submesh loosing Import algo + * \param data - data holding imported groups + */ + void _Listener::removeSubmesh( SMESH_subMesh* sm, _ListenerData* data ) + { + list< _ImportData > & dList = _tgtMesh2ImportData[ sm->GetFather() ]; + list< _ImportData >::iterator d = dList.begin(); + for ( ; d != dList.end(); ++d ) + if ( (*d)._subM.erase( sm )) + { + d->_computedSubM.erase( sm ); + bool rmMesh = d->_copyMeshSubM.erase( sm ) && d->_copyMeshSubM.empty(); + bool rmGroups = (d->_copyGroupSubM.erase( sm ) && d->_copyGroupSubM.empty()) || rmMesh; + if ( rmMesh ) + d->removeImportedMesh( sm->GetFather()->GetMeshDS() ); + if ( rmGroups && data ) + d->removeGroups( sm, data->_srcHyp ); + } + } + //-------------------------------------------------------------------------------- + /*! + * \brief Clear submeshes and remove imported mesh and/or groups if necessary + * \param sm - cleared submesh + * \param data - data holding imported groups + */ + void _Listener::clearSubmesh(SMESH_subMesh* sm, _ListenerData* data, bool clearAllSub) + { + list< _ImportData > & dList = _tgtMesh2ImportData[ sm->GetFather() ]; + list< _ImportData >::iterator d = dList.begin(); + for ( ; d != dList.end(); ++d ) + { + if ( !d->_subM.count( sm )) continue; + if ( (*d)._computedSubM.erase( sm ) ) + { + bool copyMesh = !d->_copyMeshSubM.empty(); + if ( copyMesh || clearAllSub ) { - d->_computedSubM.erase( sm ); - bool rmMesh = d->_copyMeshSubM.erase( sm ) && d->_copyMeshSubM.empty(); - bool rmGroups = (d->_copyGroupSubM.erase( sm ) && d->_copyGroupSubM.empty()) || rmMesh; - if ( rmMesh ) - d->removeImportedMesh( sm->GetFather()->GetMeshDS() ); - if ( rmGroups && data ) + // remove imported mesh and groups + d->removeImportedMesh( sm->GetFather()->GetMeshDS() ); + + if ( data ) d->removeGroups( sm, data->_srcHyp ); + + // clear the rest submeshes + if ( !d->_computedSubM.empty() ) + { + set< SMESH_subMesh*, _SubLess> subs; + subs.swap( d->_computedSubM ); // avoid recursion via events + while ( !subs.empty() ) + { + SMESH_subMesh* subM = *subs.begin(); subs.erase( subs.begin() ); + _ListenerData* hypData = (_ListenerData*) subM->GetEventListenerData( get() ); + if ( hypData ) + d->removeGroups( sm, hypData->_srcHyp ); + + subM->ComputeStateEngine( SMESH_subMesh::CLEAN ); + if ( subM->GetSubShape().ShapeType() == TopAbs_FACE ) + subM->ComputeSubMeshStateEngine( SMESH_subMesh::CLEAN ); + } + } } + sm->ComputeStateEngine( SMESH_subMesh::CLEAN ); + if ( sm->GetSubShape().ShapeType() == TopAbs_FACE ) + sm->ComputeSubMeshStateEngine( SMESH_subMesh::CLEAN ); + } + if ( data ) + d->trackHypParams( sm, data->_srcHyp ); + d->_n2n.clear(); + d->_e2e.clear(); } - //-------------------------------------------------------------------------------- - /*! - * \brief Remove imported mesh and/or groups and - * clear all submeshes with common source mesh - * \param sm - cleared submesh - * \param data - data holding imported groups - */ - void clearSubmesh( SMESH_subMesh* sm, _ListenerData* data ) + } + //-------------------------------------------------------------------------------- + /*! + * \brief Remove imported mesh and/or groups + */ + void _Listener::ProcessEvent(const int event, + const int eventType, + SMESH_subMesh* subMesh, + SMESH_subMeshEventListenerData* data, + const SMESH_Hypothesis* /*hyp*/) + { + if ( data && data->myType == WAIT_HYP_MODIF ) { - list< _ImportData > & dList = _tgtMesh2ImportData[ sm->GetFather() ]; - list< _ImportData >::iterator d = dList.begin(); - for ( ; d != dList.end(); ++d ) + // event of Import submesh + if ( SMESH_subMesh::MODIF_HYP == event && + SMESH_subMesh::ALGO_EVENT == eventType ) { - if ( !d->_subM.count( sm )) continue; - if ( (*d)._computedSubM.erase( sm ) ) - { - bool copyMesh = !d->_copyMeshSubM.empty(); - if ( copyMesh ) + // re-call SetEventListener() to take into account valid parameters + // of ImportSource hypothesis + SMESH_Gen* gen = subMesh->GetFather()->GetGen(); + if ( SMESH_Algo* algo = gen->GetAlgo(*subMesh->GetFather(), subMesh->GetSubShape())) + algo->SetEventListener( subMesh ); + } + } + else if ( data && data->myType == LISTEN_SRC_MESH ) + { + // event of source mesh + if ( SMESH_subMesh::COMPUTE_EVENT == eventType ) + { + switch ( event ) { + case SMESH_subMesh::CLEAN: + // source mesh cleaned -> clean target mesh + clearSubmesh( data->mySubMeshes.front(), (_ListenerData*) data, /*all=*/true ); + break; + case SMESH_subMesh::SUBMESH_COMPUTED: { + // source mesh computed -> reset FAILED state of Import submeshes to + // READY_TO_COMPUTE + SMESH_Mesh* srcMesh = subMesh->GetFather(); + if ( srcMesh->NbEdges() > 0 || srcMesh->NbFaces() > 0 ) { - // clear submeshes - if ( !d->_computedSubM.empty() ) + SMESH_Mesh* m = data->mySubMeshes.front()->GetFather(); + if ( SMESH_subMesh* sm1 = m->GetSubMeshContaining(1)) { - set< SMESH_subMesh*> subs; - subs.swap( d->_computedSubM ); // avoid recursion via events - while ( !subs.empty() ) - { - SMESH_subMesh* subM = *subs.begin(); subs.erase( subs.begin() ); - _ListenerData* hypData = (_ListenerData*) subM->GetEventListenerData( get() ); - if ( hypData ) - d->removeGroups( sm, hypData->_srcHyp ); - - subM->ComputeStateEngine( SMESH_subMesh::CLEAN ); - } + sm1->ComputeStateEngine(SMESH_subMesh::SUBMESH_COMPUTED ); + sm1->ComputeSubMeshStateEngine( SMESH_subMesh::SUBMESH_COMPUTED ); } - // remove imported mesh and groups - d->removeImportedMesh( sm->GetFather()->GetMeshDS() ); - - if ( data ) - d->removeGroups( sm, data->_srcHyp ); } + break; + } + default:; } - if ( data ) - d->trackHypParams( sm, data->_srcHyp ); - d->_n2n.clear(); - d->_e2e.clear(); } } - //-------------------------------------------------------------------------------- - /*! - * \brief Remove imported mesh and/or groups - */ - virtual void ProcessEvent(const int event, - const int eventType, - SMESH_subMesh* subMesh, - SMESH_subMeshEventListenerData* data, - const SMESH_Hypothesis* /*hyp*/) + else // event of Import submesh { - if ( data && data->myType == WAIT_HYP_MODIF ) + // find out what happens: import hyp modified or removed + bool removeImport = false, modifHyp = false; + if ( SMESH_subMesh::ALGO_EVENT == eventType ) + modifHyp = true; + if ( subMesh->GetAlgoState() != SMESH_subMesh::HYP_OK ) { - if ( SMESH_subMesh::MODIF_HYP == event && - SMESH_subMesh::ALGO_EVENT == eventType ) - { - SMESH_Gen* gen = subMesh->GetFather()->GetGen(); - if ( SMESH_Algo* algo = gen->GetAlgo(*subMesh->GetFather(), subMesh->GetSubShape())) - algo->SetEventListener( subMesh ); - } + removeImport = true; } - else + else if ( SMESH_subMesh::REMOVE_ALGO == event || + SMESH_subMesh::REMOVE_FATHER_ALGO == event ) { SMESH_Gen* gen = subMesh->GetFather()->GetGen(); SMESH_Algo* algo = gen->GetAlgo(*subMesh->GetFather(),subMesh->GetSubShape() ); + removeImport = ( strncmp( "Import", algo->GetName(), 6 ) != 0 ); + } - if ( subMesh->GetAlgoState() != SMESH_subMesh::HYP_OK || - strncmp( "Import", algo->GetName(), 6 ) != 0 ) - { - // treate removal of Import algo from subMesh - removeSubmesh( subMesh, (_ListenerData*) data ); - } - else if ( subMesh->IsEmpty() ) - { - // treate modification of ImportSource hypothesis - clearSubmesh( subMesh, (_ListenerData*) data ); - } - else if ( SMESH_subMesh::CHECK_COMPUTE_STATE == event && - SMESH_subMesh::COMPUTE_EVENT == eventType ) - { - // check compute state of all submeshes impoting from same src mesh; - // this is to take into account 1D computed submeshes hidden by 2D import algo; - // else source mesh is not copied as _subM.size != _computedSubM.size() - list< _ImportData > & dList = _tgtMesh2ImportData[ subMesh->GetFather() ]; - list< _ImportData >::iterator d = dList.begin(); - for ( ; d != dList.end(); ++d ) - if ( d->_subM.count( subMesh )) - { - set::iterator smIt = d->_subM.begin(); - for( ; smIt != d->_subM.end(); ++smIt ) - if ( (*smIt)->IsMeshComputed() ) - d->_computedSubM.insert( *smIt); - } - } + if ( removeImport ) + { + // treate removal of Import algo from subMesh + removeSubmesh( subMesh, (_ListenerData*) data ); + } + else if ( modifHyp ) + { + // treate modification of ImportSource hypothesis + clearSubmesh( subMesh, (_ListenerData*) data, /*all=*/false ); + } + else if ( SMESH_subMesh::CHECK_COMPUTE_STATE == event && + SMESH_subMesh::COMPUTE_EVENT == eventType ) + { + // check compute state of all submeshes impoting from same src mesh; + // this is to take into account 1D computed submeshes hidden by 2D import algo; + // else source mesh is not copied as _subM.size != _computedSubM.size() + list< _ImportData > & dList = _tgtMesh2ImportData[ subMesh->GetFather() ]; + list< _ImportData >::iterator d = dList.begin(); + for ( ; d != dList.end(); ++d ) + if ( d->_subM.count( subMesh )) + { + set::iterator smIt = d->_subM.begin(); + for( ; smIt != d->_subM.end(); ++smIt ) + if ( (*smIt)->IsMeshComputed() ) + d->_computedSubM.insert( *smIt); + } } } - }; // class _Listener + } //================================================================================ /*! @@ -495,7 +585,7 @@ namespace // INTERNAL STUFF _ImportData* iData = _Listener::getImportData(srcMesh,tgtMesh); SMESH_subMesh* importedSM = tgtMesh->GetSubMesh( tgtShape ); - iData->_computedSubM.insert( importedSM ); + iData->addComputed( importedSM ); if ( iData->_computedSubM.size() != iData->_subM.size() ) return 0; // not all submeshes computed yet @@ -543,8 +633,8 @@ bool StdMeshers_Import_1D::Compute(SMESH_Mesh & theMesh, const TopoDS_Shape & th subShapeIDs.insert( shapeID ); // get nodes on vertices - list < SMESH_MeshEditor::TNodeXYZ > vertexNodes; - list < SMESH_MeshEditor::TNodeXYZ >::iterator vNIt; + list < SMESH_MeshEditor::TNodeXYZ > vertexNodes; + list < SMESH_MeshEditor::TNodeXYZ >::iterator vNIt; TopExp_Explorer vExp( theShape, TopAbs_VERTEX ); for ( ; vExp.More(); vExp.Next() ) { diff --git a/src/StdMeshers/StdMeshers_Import_1D2D.cxx b/src/StdMeshers/StdMeshers_Import_1D2D.cxx index 5513a1077..c05480d9c 100644 --- a/src/StdMeshers/StdMeshers_Import_1D2D.cxx +++ b/src/StdMeshers/StdMeshers_Import_1D2D.cxx @@ -153,8 +153,8 @@ bool StdMeshers_Import_1D2D::Compute(SMESH_Mesh & theMesh, const TopoDS_Shape & const bool toCheckOri = (helper.NbAncestors( geomFace, theMesh, TopAbs_SOLID ) == 1 ); Handle(Geom_Surface) surface = BRep_Tool::Surface( geomFace ); - if ( helper.GetSubShapeOri( tgtMesh->ShapeToMesh(), geomFace) == TopAbs_REVERSED ) - surface->UReverse(); + const bool reverse = + ( helper.GetSubShapeOri( tgtMesh->ShapeToMesh(), geomFace) == TopAbs_REVERSED ); gp_Pnt p; gp_Vec du, dv; set subShapeIDs; @@ -262,7 +262,7 @@ bool StdMeshers_Import_1D2D::Compute(SMESH_Mesh & theMesh, const TopoDS_Shape & { uv = helper.GetNodeUV( geomFace, newNodes[++iNode] ); surface->D1( uv.X(),uv.Y(), p, du,dv ); - geomNorm = du ^ dv; + geomNorm = reverse ? dv^du : du^dv; } while ( geomNorm.SquareMagnitude() < 1e-6 && iNode+1 < face->NbCornerNodes()); @@ -340,7 +340,7 @@ bool StdMeshers_Import_1D2D::Compute(SMESH_Mesh & theMesh, const TopoDS_Shape & int nbFaces = link2Nb->second; if ( nbFaces == 1 ) { - // check if the link lie on face boundary + // check if a not shared link lie on face boundary bool nodesOnBoundary = true; list< TopoDS_Shape > bndShapes; for ( int is1stN = 0; is1stN < 2 && nodesOnBoundary; ++is1stN ) @@ -355,6 +355,7 @@ bool StdMeshers_Import_1D2D::Compute(SMESH_Mesh & theMesh, const TopoDS_Shape & if ( Abs(u-f) < 2 * faceTol || Abs(u-l) < 2 * faceTol ) // duplicated node on vertex return error("Source elements overlap one another"); + tgtSM->RemoveNode( n, /*isNodeDeleted=*/false ); tgtMesh->SetNodeOnEdge( (SMDS_MeshNode*)n, edges[iE], u ); break; } @@ -370,10 +371,10 @@ bool StdMeshers_Import_1D2D::Compute(SMESH_Mesh & theMesh, const TopoDS_Shape & } } if ( !nodesOnBoundary ) - break; // free internal link + break; // error: free internal link if ( bndShapes.front().ShapeType() == TopAbs_EDGE && bndShapes.front() != bndShapes.back() ) - break; // link nodes on different geom edges + break; // error: link nodes on different geom edges // find geom edge the link is on if ( bndShapes.back().ShapeType() != TopAbs_EDGE ) @@ -388,7 +389,7 @@ bool StdMeshers_Import_1D2D::Compute(SMESH_Mesh & theMesh, const TopoDS_Shape & geomEdge.Nullify(); } if ( geomEdge.IsNull() ) - break; // vertices belong to different edges -> free internal link + break; // vertices belong to different edges -> error: free internal link bndShapes.push_back( geomEdge ); } @@ -406,15 +407,13 @@ bool StdMeshers_Import_1D2D::Compute(SMESH_Mesh & theMesh, const TopoDS_Shape & TopoDS_Edge geomEdge = TopoDS::Edge(bndShapes.back()); helper.CheckNodeU( geomEdge, link._medium, u, 10*faceTol, /*force=*/true ); + tgtSM->RemoveNode( link._medium, /*isNodeDeleted=*/false ); tgtMesh->SetNodeOnEdge( (SMDS_MeshNode*)link._medium, geomEdge, u ); } else { edge = tgtMesh->AddEdge( newNodes[0], newNodes[1]); } - // remove nodes from submesh of theShape - for ( unsigned i = 0; i < newNodes.size(); ++i ) - tgtSM->RemoveNode( newNodes[i], /*isNodeDeleted=*/false ); if ( !edge ) return false; -- 2.30.2