From 0a057ad10d10cbec461c916216f468dbe94390c7 Mon Sep 17 00:00:00 2001 From: eap Date: Wed, 28 Jul 2021 20:36:57 +0300 Subject: [PATCH] bos #16292 [CEA 656] MGCADSurf: option SetEnforced1D mesh --- doc/salome/examples/blsurfdemo.py | 25 +- .../images/blsurf_enforced_meshes.png | Bin 0 -> 24491 bytes .../gui/BLSURFPLUGIN/input/blsurf_hypo.doc | 15 + idl/BLSURFPlugin_Algorithm.idl | 23 +- src/BLSURFPlugin/BLSURFPluginBuilder.py | 17 + src/BLSURFPlugin/BLSURFPlugin_BLSURF.cxx | 463 +++--- src/BLSURFPlugin/BLSURFPlugin_BLSURF.hxx | 11 +- .../BLSURFPlugin_EnforcedMesh1D.cxx | 1332 +++++++++++++++++ .../BLSURFPlugin_EnforcedMesh1D.hxx | 172 +++ src/BLSURFPlugin/BLSURFPlugin_Hypothesis.cxx | 123 +- src/BLSURFPlugin/BLSURFPlugin_Hypothesis.hxx | 80 +- .../BLSURFPlugin_Hypothesis_i.cxx | 235 +++ .../BLSURFPlugin_Hypothesis_i.hxx | 6 + src/BLSURFPlugin/CMakeLists.txt | 2 + src/GUI/BLSURFPluginGUI_HypothesisCreator.cxx | 331 +++- src/GUI/BLSURFPluginGUI_HypothesisCreator.h | 22 +- src/GUI/BLSURFPlugin_msg_en.ts | 31 + 17 files changed, 2583 insertions(+), 305 deletions(-) create mode 100644 doc/salome/gui/BLSURFPLUGIN/images/blsurf_enforced_meshes.png create mode 100644 src/BLSURFPlugin/BLSURFPlugin_EnforcedMesh1D.cxx create mode 100644 src/BLSURFPlugin/BLSURFPlugin_EnforcedMesh1D.hxx diff --git a/doc/salome/examples/blsurfdemo.py b/doc/salome/examples/blsurfdemo.py index 4cb045d..ad4e0d6 100644 --- a/doc/salome/examples/blsurfdemo.py +++ b/doc/salome/examples/blsurfdemo.py @@ -108,12 +108,33 @@ algo2d.SetAttractorGeom(Face_2, Wire_1, 1, 36.641, 20, 10) # the gradation to its maximum algo2d.SetGradation( 2.5 ) +# ----------------------- +# Adding enforced meshes +# ----------------------- + +# create 1D mesh +OZ = geompy.MakeVectorDXDYDZ(0, 0, 1) +circle_1 = geompy.MakeCircle( geompy.MakeVertex( 100, 75, 200 ), OZ, 50 ) +circle_2 = geompy.MakeCircle( geompy.MakeVertex( 100, 150, 200 ), OZ, 70 ) +circles = geompy.MakeCompound([ circle_1, circle_2 ], theName="circles") +mesh_1D = smesh.Mesh( circles, "enforced circles" ) +mesh_1D.Segment().LocalLength( 7 ) +mesh_1D.Compute() + +# Add enforced mesh +algo2d.SetEnforcedMeshes([ + smeshBuilder.MG_EnforcedMesh1D( mesh_1D, "Enforced edges")]) + +# ----------------- # compute the mesh +# ----------------- + cadsurfMesh.Compute() -# --------------------------------------------------------------- + +# ================================================================ # blsurf_construct_mesh_internal_vertices Using internal vertices -# --------------------------------------------------------------- +# ================================================================ # Creating a geometry containing internal vertices Face_3 = geompy.MakeFaceHW(1, 1, 1) diff --git a/doc/salome/gui/BLSURFPLUGIN/images/blsurf_enforced_meshes.png b/doc/salome/gui/BLSURFPLUGIN/images/blsurf_enforced_meshes.png new file mode 100644 index 0000000000000000000000000000000000000000..cbc928e69a16b7dd37ef576a7bff3a735a2edd5a GIT binary patch literal 24491 zcmaI81yogE)ICZFBB_Klh=L#pDBVa4NXMm-?(P=pR=QK9OFA#zCEeY1>5l)#-}fKy z8{@t47{lScmvhfKd+&ADnsctX36hl-!$2iMg@c2`5dSPJ4+n=(2L9EcAcIfz#JGZQ3!EBG$G*dLnSl2wS3YT>t^0-q)7dAy4 zOCZG@M2hD4^DQa-&rF1id++2|`!r&IH+PNrZL68f%k9eh+7|W-Uo&uN1U(l-q40ek z6R7M0`SkcoFfcRnmGZw=id@+3sQ*5a5c{t3_yR?48<#sU<>E|m!=tg3W%u>tXB56_ z!FcV1H?9;oZ>9D6znNfn|Mx8>i1G8JMLdYmD?T2P{nLLJ5{!;T@R@SaX4G%_j`Uuo z6popWd)y7~-6x4BoC`_d#BW1WIuFTg{r>+UK(YMlwuNV+atG+#>|NVme zg5_HnRsaWd4r1*0?-pq2gIiOlVjPgpRU!8nuk2(6dPg4=&^cjFekVFl6ONWEI|JCcVI~pMsc!ySLDr=BJ>*SQ_C}% zFZ13dz?-|9O8i8edRa89V`(8HYi%8VQGdP_mJmZ4$8b}yFzdDSO4IGMb0P0#CR{xk;Bf(;omF`2j=oWZF4hZ zIcjHHb4ApB%C~~9u648nwI`n7F!HWMha=0mP{s`p5qbH@nVYn@bvosd8k;w-VaVce zbdL-0^J%5!9>NxDm(N|AX67VGga*7t7G|aO{@1QPUek2~{(@rHvz8$n-t$m{kJq{F^`JY#jdSI)jk-XP zMySH)ei}&8COTXtWp>M$+~Krn`Q=OKboFBO=bMMZAH%XdbMwO!6AW^k|6*gPz&!v* zANtV@ga#aq0ABaT*#n&&kD|+OnKVqNpd%-h0(gfrNxq+V}^l6z)zt_0vNfbuO!=2N&1jrnXm9YHIkl`!u%bCdz zEX^0o3Wn=uW@es~lSg=a!{1!&Q8Ljck~Ln-);G~b+U0)zOi*wPnI0gXgpjVi$Y;K=qF}7q*7oKDGc#hk)bNt%7>h=UBAP%R$Wi{J$`P)&#Z9r6tB;u!*6%; z<+D*W>+Lt1TYOHpn)tf7tQcj!NJ&lAKftvGVD>OSY)y)Nygrl5pUlh4i%(1}H5<|r zZQ|mAT#t<@I_^(P>gwti6aQtnxmi8fh~0E#&^)L9Koc0J&N5V4tUQnyN_xUY?tU4x z!|UPUAy3Yy*cjf3AM#T!hU5x2e|PG?R7~nODE-4h>E$PQ7cK7&ICOams#NTO7dNXH zAt*IAtdmmm$jHe339M0skv_9hGLWGc2slB`EH`NL|CWTUb-`YiTeiI=VlxpybYkR7U=5gN zHX5!~=yE@ChdNUfD3^4!-B77jSq_D#)Dy5fq9;{fesG_9etK$ex8`zJ`O|#1DXOA^ z1@7_Y43!;OEGHt#?=Nt07RZK<(;l9FO5v*99?5${?#UE2b2h&*#^GfPmdkm}ZlKZX1%4-&7$iJFQ z@eRRp?|c7IsS5^1X=RDGW|--(Cwx**KRB+bD7n_6{;LrbEZNP=Pp(vJ@8L)r+^`Sg zT8~PpuuK1^P%9O_dijH{_+MCL&Vdq-_utC~TvxrgfA#e_Uf7ee|2`b~`TxcTIn6G* zAln7LuSP)l{N)QJ+uN#!g4e+Vscz9zIlhLhg!*xwOIRqn_v?m70 zl~h0Q`~ri+1tir2W*m0#-YxDYO$G%9HxD=e5DiOu`3_dgoCB9Vb65UZ!2I);W@J>9 z^Wl=fPg<%mg-TPUd?KZ6R|hwfUHMo0sC(sWY98^JGA z#R2C^mR2Ara(L-g@nTI-YHD$X!?VwBvB?z~-3w23^>hWAs@)jcJKN<4#uURh**1f;Unno{>&)dC`?gNQDJRuyK!AfHF-MJ@Kjh*ox1C|m#%Sq@B#X8CtUt};Iovt;dO-xQDI&#`kKmnHzcH_ zckkXMu)F6Iwl{H`V6$7!<+=-)L*WtgCYxi#BFJJoHhM#yvf^kpmW~>#98}Fln-FK6 z_P}*zLG3kz(nQlH9jGGd%nhJmZ3Wu}cDe1#n#Bt1(qgXgpy9K$O zC{h;^z1AE5W3@?y?&CRdKe)IKnOOd(wAoyIaMG?-) z)TCL}ijaDyAH8Cur1UM{9Mm%~=*VajV`;3#Ppmi#S>MZhI6Oao9K%))xz{VE_llL~ zD%HyS4H+33HTAU_MMavt`hXNL>d#3UJ_gm8^c%Vk0&3SRV zJ>|PQWuBYk%{4Xet+83HwclnMNP>pSDdD)DyRY{!9<)~9O&g`@8Nt3~$6#1NdA+08 zaFymcPT)9p3^zFWeic0HaRnK=*yGslBLS(U)8piKxMaDeEa6j zn?)9vMywx+iM>-ct2K^yuBlhSu5aQyeN@scW=$50NqwGTwHnP$tVu$2fK5UrrYZz5(CfjuM|ZyRXL*j zbzc(B`5+})S?WVt9FzHNhcDiUfBB-A9T6UGIG1E4w>X|6DwSAfeick&K!4@(u4vXF z-LVll)XVJq4(cYjxn~i9>1G#XQ&Zffwr8erO`0_*P9^?hP7a%QSp2V9Su1hX%fBL3 zo`n&!gNhWFuc`Nkx9>9G;jSHg+3r^wrx_cw;UGe~WOcuXeW6^4C9j*!(Fm1N-S-)k zSFf2OkE|NQLh7jpv@Cl{pkzu#bh-Oz`BpCVI0W746m7YhCGbTv6?#Jp9{CPP`&I(` zDnD+o6(`31=H1TM>Q<&3C+R-5SZFMu?r;kQKzrdAeZHjJ^Rb;{YScS6HaiaOYRJFz zC@Iy;DLs)q=h}3V?(xLStGQ8B+st0+lt3!F;B|h!i1@T-#VbKFj!udecXXByquZ_f9rXqmpBhN54e z??%Wey(mka#7O_v_)Cx5})F-Rdj zw09xZll0W;-PK#@mOBtj>;Jm3$C*7WPX$rAdyKKR2hU8UB*!r)8@=nNs_*x>!9Uv%Y1YCSiX+CdX4_291X9YYgJ4dN=BvhZ}rG8JT-- zmp@O6AS_pv4u=H0x`iC>SSs(Lt+ta$d+Kf&N?{9Cc(wC|j3!B#8@$#ks zz}eZ>mU3bweR5@##^kcY!l2otv2-uEydRJ6aILt==b;GU@`25D&h|wu3kBqlL;KV{ zJ&gK(huQDW#E76ZQ8B%bu5;L3n>|qdlP1}l55u$H%N@O+-c6q5q^e&zP}ok33x3HE z=DP1t;b5=S*OlfTsdu-h%4}_K-@LF8&gXG$JQBc6CbKGxD z7eJh@Fp0`9R4q4L+S_|VQ)_*Mz;3y)mh*5I7#7A_X*&M(Z&XqngH~NPVC*Ul#uSEz zi7Y7|5-6p;OcD=m_CD*KXq}N~6ndp}(Eicd3YUHXgzhV+X z#sb5`VJ(nwFFnp zz#ww4IgMw}N8ekfGF8hisns>LB!GBz7r|fS1S5lsAmh~qF@#RUk*+wC|7$F7F_qVC zxhOOe_(emwYTAf(r80x z23H$OaiTd>TrNAfFJAn#-<~4`$$4&GW4hLi-71_sM}pa62bY9|1g^&U2peGW1g0zA zipt9EiAp-snQF#k#~i8DP%vR^Dx-xa3P4)0cCtfEH;OpWsENOdn~f=e)ViF!b#sCV ztE(rO{{9_Get~>*4$HC235WZV#)RbN<_1^iwA%|N`DDJhxR}A!^;(fNKR77p;~Onf zt+hIQh=7I1(F)bd%4!0i11ey!r#sU=nESJN$6Op7OWVsW;Nc_k` zZy5$6BBGX;1up+xLo~Oy_gJ1LaW^#VwnSsuv6=LIe>yBRl?+bX{rsJ*^{l#@3a-lH zvHkXlLFVf>SC?&Af5*o&gl-&9UDoj&_vVm(!0rv>w7EC3b3IIt$4pqvr+)l=qt)@y z8zXpA{aec22^(iI<(KQ-LHo1*F z(mb;>{!9~&iMh4AyGcvOK@)#@>5N{WIB_&d`@d(Vq(8L5%W&rtwOd$%y!U4>g+eSGM}&lgkEGaDQ(9QiKahX&{7G|tMK zn)nPi3^}!oJYrrF5lOV(-Ed6g#;od(e=aabBI_M$<@upZeQ_y{bTHKJMAlL`XQ;5JCgRr zmb{{5Q9NT6QPhv#dDT}E*4o-yT3xM>qWA~Y=J7l$m!QDV=D`I_&H0>w@bYq;$>K#C zYp;w$$9_q<>#+!adWzStzk~XODO=)YHY3A--`os;ccNKxaHJ$#Z`9+-@UE{ZZm}#& z`o^flPA9ltCfikuc91c-l>u&p{d_5b#nI8xccHOwRV+fu+x$~AY5pt(k_}0hz1v$_ z`t;eD2C%seRDDtsrV>Nsr^uPkhK|3?3MUY(9wGvp36tyy@E|5SrAi& zl6?IB^Nr}?QVXJJ1Zm$~?MVW^Rq?e&wtx%iP>ysOgCjrVRt>|yR8#!{RDx0SRk+TSkVAA|qq01OkZ>)z(f6z)B0> z1h6=j)|!qMqz`io^FwZ@w--Ia7^p>aSs#(Hh`K?t6qk_D9a($#UhS5YneVDbmJdBc!x|!SsE{QTV4&+lXlXvfrX-)HV`U7&)y>RRC9&#=%ok5*a6gVk1u%MMXR-hgi1Z(JP zsMY?F9N8bie;*-&hQGAF?H!ecGrH)NhQ)sgM^BFgQY|$VRSbJqMB7-qZ|%v(M}uQG z68?Mc04(y(`GLwOH%F%r->dewmYP8ZCOFzDP|VW}l+UB&TEt7UWT68k;e z%)!&jphU>COSHId%_h`gZ`j)e=GAT06@CH))Uu^ntK)7}Pt*c!<1NkcnCTxso|~sW z`7Ls1u0_lmIVl>Z*x2N9;=i-|u!oM0k*hkI@QvF$opSQJkS_tE#p}TvOMgR%gA>Jb z%sWuP5Ed51>%8^c)z#G(dA`TS$##~_;&8f(cZdh%Z31G5!I9HqRD68*@*6P@$6M!c z76t~4M?nlQOp=E?EX+%?_l~6V8k%_rvMHQt9@1aFpkEx!>y5_J7pgUi7Tqex#%eS= zDxJl(gEKId_=|`FL|U9ECN+v`W+o$p^(8b+_4Jn}78zH2*(!9CrmeO0dn{x1Qe%&T zjjesA<$OOs2@p8`j!bm6kNE=03ee$bFyzXe^@9!3eKppr!z`J=@bI@B9Pz4ld`PI4 zZVo%@T0A^+WmQ!h1trks`#a(Ahx@1X7YEs1&?ck?b`mCg3N9&ee?nb7SZ3<3^Rwkv-*(W7f#M4AhxNvu zYO?8=?s0Tpp-NS>CwrXsa==j3eJkn#c8J7MXLQy{1sk)Z0t*JCv$3AE}{~D zjHAQjjWn-&y~A{GV>7dIy)HIPG9F($z!e|X@%=G~)%NbZlm%uF#`4}=z!q~>U0=#vkoYk~bo3?{WDpTKoWcjEAFT~BE+v`u?w9Co*-v$*S~@Bbt| zbl{U5o^`a2W<|>ERw1hjSb-`D-{pro6#dvImcX# z@EQ%)si$37cJDU_Qihd9Ks+#H zJ@|pjAColFN)>LrV77eTi0<#tWsUkBnFz9ZrCoFLLRF|E#~EL5=coZ zIw{|G%#^yN<>kS8*q0{~WUFvLy7u5zLjXdM4#%uD!tZ|BZs_Ipw-sqDPl0;zIJyHx z7tiMJvgta9+X2bKLKtdeQe6cG8CUW`$tmqg(u>}Zswy^5&-KxXp*JQ&kx^{80ArHy zdxqX4BEP(f3(ftSs*z#2*yKYpG_7%dkpqD>U231wO*|KoN~1n0NUMhkRawmo`XFcX z&mC+G5IeiDD~5R}#esMWz`PzQa*NR2+#f6RQQKy9)q~g+szbd&^;_Q9>Agp6O6GA0 zhC$U8okfAFOhmO@;7pdClT&Vfg?fFltG?%E&XT9G3kfaAs`bagr7lUN)p$Nz=RgON z1iYswzO|#R?tG$>NSzPlU+q#3iZk#St#GULG%;MILA-}Kl=LmU(L-m_8NYVe;F^% znkmO2x!aGQ@dHA+a}$tI|K?a}C#0m0C|IwwFA9r@#5jovBN^%F1cgU~nmNxVrKblb zjmh*MrR9%)&p&1seHnl72g(mVY!?3^ck`ZYDqS#Ao>7%Aw5>UpYCe+w(Qi)r`K+Ip=FVaJ(MqYHDLVUlo+SQYMor z(2@8R=9jC#vbvJ1RDg*}j|8X)(X@Y6IOgCW>ob&^7^}pZ8jcxrhsphzZW`$nRAc~yFgE${4e7Itq>z|cPV+Jus7dW2nEz;IU3sqp90x$fKh_SIr|R=g>P;s3w!dnUc9fI6S-{^i;XoV#)mfB z@`w670xl3?lneoCnY2#W$Qkvj5rxo|eV%qbvV}UE2n14{Z1&Fg`MQvvg891`Ds^N` zGJj7zoYR8%4@dJowG-^-bLe-pZwUwzbPW_zlr6Xqp=q&^v9Vf(`*_Nmbr^FTcIWOv z=Xr)H$W#nMmC=I4(C)qi-W%iD3}(Yvwkaj2-+FNez-*E}w@W3tt}QWIYqweZB30Nw zhFyHTp|)Uipf+HE1hquOJ>R7$_X%gM>DYhq9c z!_)4?Oj)S2!+&tuIi+6hvW=^DUAOheAQcoAeggW!13>#)O7nWqS-r08n9FAx+J~E~ zaphD`jO_Lz7Gcba_R?#5<*8bmNXTq-G9G8QJ>fvF6dGFNzRk4waEUXJ*yLMT>EHs9 zLxI~FD<06!aU6A8L3mA0^Enuy=*M%W1LP=dVqsm~*I49yt;56V!n4oN&{n&DzVQtR z0MrwYhlj^_JRc8$yX*>TB=rj87eWD;9SaM5i!AC@=F1>A!m(J+#cMUXuB$-xd$2Rp zLhDB-C%Z;Qu(7bP64@+*1?8^W=$dX0xRJ5QG`^;wWes|wQ5@&A(3SPdtNvN3(14ws z8W9r{176uNAw@h@>BeX@m^@Hks9tR~ngt;*G|yihFMS5O3zRog^4g0+&aCF&EgX#A zHreX${-O*H%aWQJdJ(>5B$;qvus&<#x1y>FCGc@KF79T&dZLG(s z12qr1u&@wZfn&U|FSBFuvE4SsJ@LNcfgm9s=f#T*SKhljtb~(k{QOC2*4^X%?;=;{ zB}Vu;i4Ll_^H?k(=ID}kLJ3$CL2r8e`eo6K?pOWbyjs?x8OJ3+PDot%)40iDqEa8L z|Ew21gIRC?;RnBJ?jP~zyF-q&erTfg5V%u~&19sCNlhI*OJY~OU1f44JINaFcF{mr zI39{2U`V-6`4PoOnW`={pLkA5MI9A;Uei813w$s@AJg3#%L^srB?7(fVy#BC6_0mP zU?B|#lQ~&TMkp6qKqk=xZyHVpxhu@4BOmT>BKBvi&3^GkQOm?GDFoUoFI(-&XA0-_ zYo=n`Ho}&drHc|-uWs7;Sxm=1h+P9Ph>S@jabY<>RiQ&qEt6_^87Mbatb|rVZTHS{ zwk%4M+e4NH7oCvpyI%-&GYjkY=2T8-C^|BhM~pv4;}O(3ygSzz8G}spU*EVE2QdJ> zt!*HzJm;R`9cMyX97B#7=FxP6oKp2lwcLWmYgDI$TNi9>?5)WXnT-8v zBN(5fP=3)`EeDfHsq9bSI3H(g0;VPWBVcF^~mUfsoG>@%G7 ztqaMw=x9YY^SSmwxvV2@CkcnFA^wNk5ZFC0C^El1x{7aaU|xlqjo1L|B4ZE^GSWdl zt~ZL)#Pqt~*i{#62G90q#;@RDbGTok#38QAs??2IeOMidpdS4vQ%a^f6%`UJ7UQ7~>PsYYHZ{NPHFq_0=XJ;S3CT6!RwU}ii1C7w6 zB;xscCkUzDbV<8%^xex9k*u;;Z1j!xohAmF^W93R*i1}JwvAS1W_^t{H5#xq?oBag zVM=Br&+i~{?{in=XhWOKXI6ZY>bcX`d@gcUmzGeP#mGIIf!W63x*|_z2Y#DS;+8>c zW#){Sgv%KYtVBLh(&726)gO;8hQh)kAV0ngz#{vktxax+7SC^WFj~j+F6);?RyNZ1 zcI|~GE(0x>Kdn;!S7Q~CaZigGhvp#|0$dVX@gr^c7Kz30On$R7E-pDFoAsc7epSfC z%oMG^wpEREQ8E|pe%Nv|H8TxATyBKLpxqR?%RD(gs&~3Isd_q(HCN-31mtTti3Kk& zu2^Md6*bkrnJ&ycyu3CZ$9-2Z5LcT87=p<*p+=oM=iJ%^4r-Rl?s$GfQA-M#@j2&*a##F zk>bZR+On{aDjxOr2xvZRRtuqien<|x6H0WNDO?Uye+Mj?0Om5~-k|;Nj6x3&1>pufW~j-MO5NL*Sc-GZnSj^-I(;siX;C|AmeWSBKNn)8qMvk;`7W zJjIRKx0zozHVi4LsR8%@4B`>~a`n;*&Y9iyUDu|bnNh*DYRdh|p3(8%_;KqsM9X17 z&FbsdPkW7S`IB^zqKzCX&`QGY%@T`%3k(cQmrj|fJ>DTESaUBbk&%#)$hcFzhD@Vk zMJyS9Cc&tOiX@uw7S9K*Z!D@myK|#rrMGuBPVP)uk|lB*>zeKf0)rwTCXRD%$O#X} zEP>v0dEFj8El@5J%u`%hSrN>UPWiyXLdnDw86Qv38A|9Qn9OQcX$-kENXYWK29=5 zgy1v2aJ^v2%ftFRIpiVaD=1lT`h7~C$m=5W==>P8FQR$f&Of?e4$nRNGoy5Mnt?6r z{P1^jlA4uDDTa@Y?d6*+S{eQ~tk;l1SN#GsnFCiZTavj3hmaw@w7x-7zM9%vo%E83 z9H%#AIlRi_yj`;XM%R*tL-z-E8X!Tfot?kOEF1n*ROmNiTW53?_gPM2TmZ@dR- zbPK36<6op|owu={J-cA$kK6M&=o#`mBWH&|*vzN8qkCXSL(qpZr$x_&ghR*hq0cGz zF+y5tW!RBXk$)#9I>*|hPrFQRYi{ws`v}?o9-@YoKj4q0b%l|t`^Mr?WoKnc?X-0X zFUU|IwCH^f%dRSaV_94b#D85&OKDS6TF{m1{QLI>SaYJhfZAG4sYI5R$w_=TpzwkY zQ34k$G=mX0kpYO~Hy1EqxlA?sloK?K_@{~(A3p&2ql+Ct;Lkz5(m)YcdiD4rcsgjM z+}(K`W&BUuySg@2;<8^KfJB2jFd!}4>ZRSEB*ThEr(CGfv%_kZXQdh9$A! z?uIb_zR-B?7vbW=;TvEP2{Dk2TT@Mqt$In!Uc3rgWEyk4S6izxmq#}p&aSRJ@35{< zUHssEkVo?^+!`8qT&zawIjeGng9Ig8{4vae!h@FAV~b4gZ6&2sxkR8%9s=;h?1fYm z6yApPY9qjhJX2|rMXR?n*3+NzK((RF29&cn>`Iv)^~;XCi|gI2%cB68O1&p91~Gd^ zQvr8ce|!&UR6eemMCw9vOiWJc{mD4wWUAha|4d^}rP7tP(e0x5C$#kbY!7Nw9kIhp z1xhzMIa@SPKZbL~nGq0R!|4JZO4oBPc4Sf0+F+&nZtU_4AA$?&8hK}WbcBUFzE$xd zhYtj~r?*c`AUmk8n&AT$!Q*)w4_FugY*|D(CVF~4 zd3o;uG62XSXl+e@FpYm`do;%`T0xcz6oL2e-*Z?m!2z`atcu;`p^lOk;3V=XQD-ea zPc<4{V~W(PS2i|&qY9UUpDd85NVpwC!Rc&o&MiOzIXXO)&A!?#fd)oIP=h%H$cVX1 zN*m7x>gW8I2G|$Jxpv9!_6hE;FCb=YFp#uHK%*8LQvBNH#5{0lBMi{X2b@Nb6l*>2 z)QXd6g*%iMJ5uJkt5;V>(t!t#WpAw~>S_VE+H8^`k;No-vqA*`d;Nhr3=-5o&H3X` z$f!H5FD_u)8q{GIZ<|zqWgv2K)g|+JL;{EJx_X4SkUwIAw%5(gjotB@IIv)Xq?Q9x z2WS$Cuv+qfNofnf!g>B2?o*@d8CXOdrF_L6hd58qZEPGIPUpi{-rn9Ir;GqVHO{#Q z>MIG4^N;rSc6ZnaKQKmk-JL+)LvV6(QaX&q2N2`>0+zN}*Aqou5HmP66%ST= zvv#nf0|_5L4q zMkXdUj#j(ye)DBoZ*n`g>?jgt1o!Alco? zk{pA+SeHT9SH3jdph5NEX}A|j24tKd*)5LbO|EfnSSOU>Z0wSrWN6jV)7E(u2f!rCvU? za=9EK*OH^Z^UdAr@9*#Kmdz~65^_~b6s^htFGT&ZnVHMoM^)mJ?9NZciP&A541c~5 zROB&|PU}ChnaCE%5-1!FwND^d50vO>ol9;`hco4v6a)pef3r2_Efpc51Og)LtBy&6 z6)gk;xxFhnyeZQT>N)qNrSPSZdPK4+DognpsvIoD?Y%|7*POAkyxr4*h7ZIX5ebuUwy*8B{eMYyW5SH8)`E zPzFYdN4EiZyzs-r!}Bjdof(=gH+p;^i;FvwkF(>C=7Ft^!*&e?uB7Rj_GEKtsI19u zb8xQ42B?wVKYzXeFgY9eenW{^^WDkeRhvBzW-3FF&|WTWZU%tf<-x(hmlUoT;4F#O zyh9zXw$eV|n?`I-vTEuX$(FP$1dmJC;vzXX7XWvlC5=wbmmGvc-K)p$_Z$wW$J7iA z(i=5+ncvGR{x1_e8i~I-Ew}_!xTmUAc;2~+h7t%kJ97Yr&Ir!5 z34=a#c6H^vFQE0!{RYhLkGmssoK}yEgP#jxI9V>XFFpi|Zv18#rFO(1;rMa3JIQR& zi;Ihjq+V@lu+;2*d)S7R&+_r($Np5_BphmKSs?m!hLiRYTQ$HpuXKb=m+Bw_3Gj4p zItna~-q){i&E#IUE$u-#Kq$%r8p3ne9D0f8C)Ev2_VQz0Y5Z`aU;hVz=sqb$O0| zo=zmix#^dcrWT_n$>%;C3i1MqrO`$4JUYn-*-EX14E;Ic)zXU6wITj{{kCfia}}t! z9+Y%-q(jntrY2~Aw(8_U+iP|Cpd~LVN6{tX&M_4DMQm=TY>G7-JBw55S(r%1$2;(h zs5ePwi&2Dh0o0WQI0;zwXixQ~K}84U;}z(10SyH>`J~$XF#x;LIa=uev*iz>9$!s5 z_OV9q?)HIUb2#kaF1nwD&A5y&@9#^2xqGb55|tVh!s~B@P<(UUSsdnKufjCJ`P;jU z=%5dt$v~#lF)}JpbK0L#vYfB$N#-p7$jX}GxUU8-k%;)%^UeY;8wRBUA{}#$7@ao% zk>65gN(((vi){-Fm>{(S8&>9D;zrO=68{`HsdCj3q_3x|3wD3BPEDztEj+SW!HiEC zvbjy2Pvd#r*aim&;gY$X!VeFv0f`C#_ymN;<64@})yNge5HJPkjTNd!0bB3~qd^kD zdJ7%39HwVy&GtT~JZ6|&_g;Gr_)h?(#`Amef$&5pW_#aN2fC35i%=PGE;-tm{Pp!X z?aq!4KcJ^G*{lcy6N&L+6R%an5i;mnecCu_Ehiu#FlJc_0t8a6(v*k}%JH6_9(WC2 zfBYzi*PY5~hy0DpVQ1~LdZVku_z(bA92^|!1qB7JCCWu=mp3;Bjr)b)2+~1q1Y8}@ zj2zYW;y|;1U_i1_<1zCoN*j1mRY~9paXIca1EFPWB-<|BK@}ozwb;~=!VUifd4Yn4 z<_C~);3bgJw<02jlqX8G1E3EEo|nrvJk=RJ>%Dkh-+g?HCkjFS=7tuO!hvM@8{F&O zR9V)rj0l)e&#LNbY8IC0t_bpi1vC^CS)@9!=LAsB{E3eC_BC2Y8k)~%cAzB!Ob>n& z88o-Iw_pS1Bh$}TD}HQ1(3UWf;v`kN-waf19M*qJE!GOZ&?Kt)YGpJu$GCw_jMLXR z<#uU)rZYd|aO=7T@zgqI{`unPubk|xe%Z*#WO+jyJ$pr#08BF7+nOWb=R(7BiZ~9@ zISJImz`(fLDJY5Oa-aoV`ZZv{(b2f~cNf|#tE+ZTilM4%(C_}iQ>~=<;>C--x!S1vyBlWb z!>>f_vGqSYPIN9(8!Id);c=KH3-|L!n-uWR4`#I&#`7y2_h&@Q?J&u!Dne5UP@rXn^Vfh&G7De|xAuK|&$y$wJirl9fTh*raSF zPCGC>C_`a$(0*?$Xw+zMxE#W$R%t1<;`8*>bsbNw;g*R|f(j;`sF=xdIE#d4ZR=>b zU*}*xRr7+{$f)Udr+~y{A&G|&yqT%6=o^xZV>%CGSGk>c!h7ebAjES!F_=vhQZO<7X()KAFHN5d`tKYzx=kh^&SgYJktd5a zSADSfmg-?meXMKJC_kgXj@pLwn$PRNy1F$9<)=ZD@jTs<0~@<+&W+VpP=n{BwVyR} z@%nGj_dV=7fZzdQS#W*5+aqeUy;uz57ytY@T_H!>rC3H>yroQ(zUl6oP852t*0iqZ zRM-;z4pwG)hYUzS5IWlW#Qy9T_f1~u6h0{+m2C8<_N03!cq#5cKEB-=q&H9NN8)vu zxp}N7L;Oiuv{oa(oK&EmZ+^=CL?;NjM!8?rc0`i(|YQ1zSAX zEK~x3Z~+Hqw1M4)whMSR^W~J@O1TE~L@f+dTY&KGXr^dW+BdPX8fx`Jv-?7SSs2Vz z`E}xU%7u4r{jrR;2foO^08hE`T+K(YMN+zB>Eg5^ZQJ4lVB9Ol_1jDR-`t zWi2}Ok8IzN=b7?cP6s?kN6)~hpu-jQ7kdVashYre9GRLb4ZZg<-r5&g+E03~afo3R z>V?J+MKiUUHJWui-=FW;j(V`&IVA*6`rPJIpl@w7-}7E-AFm!8c(GZ!a_x5KdCB}Z z|Bw*h{XvVEGg7A{y#HwYVv+iOxm!njF!?%;*X@GI{t_kj{*?baY;Hq99=p#=_1QQ1 zJpJZ$iYXO!ySrfirl;qB%%@SohG2QKG<{P63N3R3Pd$h#1F(p4aC5KM`uh7vyWLR+ zTfZJSO2p7m0P-7199p~S0?z^n;;hJSM|=q_)xdty3=hkpR$ zrx>tR1B;nwT@fL8P9V@Mw$M8u#3)$oI$e=y*XPluGVp%DCDJQ zNP;RW(OAjQFQ-MFoA5b3*vV@JG}I$qx|4TRy^%gXLgCz-BHJN>fiwV5%bBRCsjMZU z!p5M~aJjHZyU)^R=H>3begO)Ar;;cvj~A-?&_Rmx|0_aZXQ<9Hl8m2`iB8`2bo21H zDYvrxNy)gPr5kcjO0a7i=)>>{o8Pa`cGd^YzJBxb>lmH9M*j8d7u<7Pk}vM=2uh&^ z>+#BE9`%l<`%xfj+C!w;AdlT@eULUN#`6>Y*i9Y?j&8)G4h@C_77AX#22(yMr9aO1 zR1UmRZ2HpI@gZ*kfvH(ME82!#c1y5{!+fGhwWDzhWrXal0+?Aq^IylsIApW4Zu3RR zlO1xf22}*~+`3Ldif)-I)1Nc4VMGKe^=1Z%pvb)=BqCz+I?(v-bw~kr0#fn3{{C1$ zZeWy0&#q+rCQCEetJtdgQ%?wiM#g!(E9YKiVKg<|zr8m%Kd(}5NZQlWLvnRSQ}4K$ zs%3f)(Z(Ub6_&Lwrk(bHgCnPU{JQ`j>^8l6(gkXbh~&g<<(WWtIbNBWik?0UbfMmq z#xFX%xVkQFt##j!yMwKF00);9YL&-=mSA3t_V1UtD;;kiXDAarjGR3duP^qG?HSQd zea)&$)=P!Ohi@+0?gAhqob+cE6%7E1G?~*4b5qSBp2>l$FOETO0Ojy5({FFCk@)GR z+I#h;@Ar4t8?<_#9z0L?#sfN~6949Au#0X)NCdWv=h zKdCY$t$gl@rEUssV8`vNr=^PZ2rfE)3`M|B6Llra*&Tb>7l|^ufA~M{VgzvjEWXob z0{Uybl;XHif(ZhW5i@f&@i(2I5f8R3;`@pEsPu)-IoStC*4rGB{kR&>elCc+Vfp#1 z3uL+W--$mOzYmN#N(2Z0)milLqsHzqG%-+GPy)yO{2i{IkOKa6f^fEuj^*I=D0N>w zksu0d3a1BC7ov>BsNG#V1Gvx-{{JGdLE#Lr9TW=GuaEu*Kcr%YjwJt*5C8t!Lat(J zKwhiwb1Le#XaD%*|Mpr?{?EqDnDGA(;|3GA_jAGMjHRXLKt&Cd31o!j1FR{k#9ZVr zH=fVI#bx}<{n5XX8T#aDz>nCU-XQ@HP=;Nsnmr6Cw*|0^ z$x_o5W1Wxq0);eU01JWr`^hOOA(dKz!NUKJRp_M- zd7ixql5b>Wl*zHYUPZ-N0zy+MAB~5iqWk0Q2ouWFG6OzNqXaZG%A*!UuzTTg8^X(% z8&|)T_?}6}^oHsd;b(5?e*v7G2VbAVo5n&;?yn*%T z^70?qii3;8fz!V(pHF4Vm4cS(-|*1IpVLXG+kZg^3JL*)^)=-w0|4uS5O(J0jgEJ3 z!R2aLa%BWtJuDaM!ctO-^2uLTfMH1g8-|bs751w@`Kb8IZy;+a42Q6P<}&SmYTwIdO!7Jll5HuC57$F};G5XmVUElX3sE2ExU*K_fqZ{uJ12 zrvYk_lpZDVw0+APszNB&3i&(&FGQ)LVTU};0&J)P+CZLvuv{b zQce89*2X3NOkd3~BdUkxli`TtM)If6f=Q{&15ZZIE8deLOf`RsG#NSVPZ<27fIv7g z)!7*dIi&4jnwq*u;Wzj7v*^hji6Or_;oRiiu!P;sr)k}K!gepTNE@XF%+10M!jg0c z_s&%+zIvK(?S#i^Pm^Jso&6n|N6M1S=#eLW&H5011Q=ri2)VB#@B&JN7vjr{}*o_s0va z*x7r3d#$~`wchopPV91NS$wez5o((8KS z)DC?6`7Tz1+U{C(C(Q8=?Xxd2L$-caoy}RcJl~;sq-v%U;$!5j^~i{$ZG%rf*xeCB za3tOa^>1!JxB!mJ4`Hu!pwgCN{ykXEU&B!I;yD~L=iU*bS;GB>t3r7gt0zlM4H4+* z@M7~=w2l$Vtfs<%T(9NwAY=M4Znt9v0@e4-8AYLdu zucjvG^QpmG(M}kptW9eGe6FayeLS)z`SSfhxi5E06lHB=L-`qCUT^Mx4F)r!oBMZ4 zZTpx{cM$;rx*MFK!twE26QuCyO+K&a^KUc{Dn~!heQ07BCOco{O5Af#;U+h5;U@8! zSa$>z4bUji-$)&$(^X@vngW^&cXpQ1GCXE}i>^umJtNStF||Zd2sqplk5{lTaEo%s zHIF^H7=r8R=|Q$eet)*HsbDNRgb-^%KJ<7h0?aAc7>lk;_i(sn76Q%6!lDKlTBuhy zO@|q84prF35`j>Wa`)@vS`++43nsuU_>l>|Ry#%c+hc~Bzu@tPZf33-=$V}~@Q1@i zM#T__>6kh&766G{?A92vJ?6^IGxfKvulT+$PxjzWbR7k@adUfJHlq({Gem&Cd!kUT zqdqnIBMn|4>$}A{Jj^0n;A?R*nGEz~P69a4_)NX;%>l1r2IG)p3K!7O(-AIN8C*u2 zBZG0FuA#v$3Isnu4cU=M@?c8JoTLwO^5+uzi6RsG>&JqQyD%;UhQ()R-w)Xc+Y}1> z35kAO7THAw28YVu_7z`aer#i7qY~rSR&0Dwn(EaEEoLQl`8K-gIlKxC2uQWJAWl2i zKQs@?+G@kq;uPlU!bG&fwj!YYUl;EANVl7J3K$8Y=52h@q`!Ch!>y49Dpz=Z_$eB7 zv*MO#aBS@8*f?eT=#Y~T;o06;=M&(N85gVkM9;IG%y`+Ruqmhs5%Bf!O@;q}{L2Jy zc%eMPO+@i($(93yV|~m*+mmKb%*;_B*KWF*_5L(liOj`p>QfD&sKf8@M8YggH|7<6|_uA$!7 z^m2P!|9Gs0XIG=Crul6HP(lzRYOp{pbou6hWvaIXUDT&PG^d^9K)fKTy}nV`ghffY z%MoCkwnHnGT3{o(olon-JxHy0963W}PLUO`IOT-apK*I{YwP8Qn+%j5E5tpMTf0bJ z&;vBw)quy~AHyAq=|SKsFdg{Xn-kj+$tq8##~C`Y4<0C$HjIw-|LlIC=sZpLLU~19 zeb@Hw)jS;~(ik#M3;1h!=I;mWt3b@ie|7^oo5VhC*8Ab7VLy!Ig9RbwIy(D$-u&j< zNDw7JDCfMqyv`jdiHwTW`#VxL#>WtjRoHn-Dkl;5O#6|tFLZMR{%-ZZ^^JQ~)b)US zdUt$sQcd^ClQ2|3>L!n;%b$Y~8Y#Jy$jB(d5D`Tl46_DH|KCEcXWs{qe-UweA)mn1 z4nR)A4K*P-N&hJ}zaRMic>dQ5`@K`VcZ&B;@h*3Le-++eh4)wC|L0Y(O27Y|^cvLw z*5t1QNhsGX#_jg*b3U%wv=@?tOMvfzK=$YV&r0{7(ZWbxJ>h#rITs8yj(1b*UcZw^ ziPD2W65gEY?ub9;%^^O0`V{4)34wTHK*DI8OfGglgne}MLr6{w=UVW87tsHl_CIBF zm_Jw(TYv*HOz*HuS(`u%3hs_E#x)lx6rhEX?dPMsJvo;+P{^Y{_ZV3P?Yo&0&$>X` zdZk5gF7j>s!n|`yi;|h6{<7Fd`q>#o-yid5+a0p7x#fP47pL}-oLrN8(LTmYtGt2( z<|O-C6Eh>EIcbRvibSV1)n}DNS>*>OHQ^UG9cMcm)Il@R3KV%G1{}9G(7jO)iT7qz zs}Gt&F5OXL_NXWK?x*D+GgJvUZrprMXZt$UihqZk)rMc}%U#J)H^{dcu3JmGJ<|Wpt-jEi)X<=$VfT3_D8#=0(sGWOWc||~ z<92QO0#L#fq=saotxG@^!6bFgK!tSv3byE|uva>6(%yi=} z;tEm3OX=Nj)NXQQzCCj_kc9`N4$Gdm*J+-q^jz_(TySlPIRPsT$+$uiGMW(3lIIrp zOlnPz2qsWP{TcxwhqGl7**XThOL^2}unXSelhuda>>XOL0X;-g(Xz8hqx#f{zs_9o zBdf_5d}Nn`LbKJzDiqtvkg)A^uUyQ3PA{VOWSYS*;&8_(;gg_pmQpR`A=4SF0c^U< z_RGkqC<5r8^ks>d>VX}x1!R(B%>>VWL2JPIH|Y~;QcfG1?D;+@^xftGfT2Rz zkg()moghVpOSz54^IZ`&1z5hM3DnsN6re`B<>T&}l_lNGuj#8RI&sKFCSZ9Wpn#*# zwsYR1u?bc~xW(!$xPJO2|4hk{<2;rnk@aRYIRLMBAItd65N|&u+dMr@ycDXhCYaf$ zPbg7!g31@O<-yYD>OOsRGMZ{S{GF>CSNszfu-j{Uu4Y(|(hV?Ez(2#NL_2Z>kLn_u zLiWU*Cv8+|6%HVaf^(`?=BM8e~t6~a{9?ir}N8tuf!S*difX}+mr zMrR>Wf%)j!O~0KI%(|+=&c|E6ni~38mIBG~L$)!F7_tFcRj|BOs5Iar-;7Y9@;(+V zsHufY+2o?3A>z`~Z7n<2W`Cz##;*n@WUHpY^s~l*OqjF8XK7(2JH)QosqqKHyphEE@YuiCwE+tVq#LslL zjb&_dR+~ABkmetAgFn5^TjH-CM#`i#S<*#iBSxvG8+AHesnpRC9tOx34Q_!|;?rET zifaI>YgT%o7BF%2Gb0y%S(S)*1yp@`NKoR-&jplj&|%#{wyi+m$jb&ONzyzJm zQToW-?ay{2hn4}vQ}5Sm^>a&@gRwdecn~@&t=a`4fImPAii+~iz9iTo6duEG0S%imcYhURu1X6?b@);PK zld-171*n~Dibfr>~yjd>Tku4MZLcfbfQo}fDG zkcIgJY$vjqiELq$It480s$cB`MegCm88?tE#j~%KUNt$Q!5Vfr1VBu|F5gMtK)jHh z@j8~X$vYgSh{5+^zo#uv0#lc?WKKRpr_1iZXMZB6*y`=o?JBlE6z%Q#B6H7i#3gQy zk!LbBcG~p>f4`A%(3Li3Q{M$)~Z;nRgw+m9irJ36s8 zU%+gh9b%ShF&=#?L0^-r<(#gCmV_Pa_*d$Uexqx(6QJb>ETSPU8%$%02X2 z1_uX0Y^^CPx543X=9zKco^hQHdvnZ^dS4u*@1Yh>B>MTCkpF>ciJ4qC z8M|p%Ykdn<3BmscElHc()~XFMHxTJ_lJ4f#yi0Tlqiv!pl$K_5H`|knR*4wz!N9KYSh&SRN+1a*S#!9(A Umv!w5_%GyZcW<|cr!M~ZZ&{Vf&;S4c literal 0 HcmV?d00001 diff --git a/doc/salome/gui/BLSURFPLUGIN/input/blsurf_hypo.doc b/doc/salome/gui/BLSURFPLUGIN/input/blsurf_hypo.doc index 1b1c1d5..fefba64 100644 --- a/doc/salome/gui/BLSURFPLUGIN/input/blsurf_hypo.doc +++ b/doc/salome/gui/BLSURFPLUGIN/input/blsurf_hypo.doc @@ -392,6 +392,21 @@ A group can optionnaly be defined on those enforced vertices. \ref blsurf_top "Back to top" +\section blsurf_enforced_meshes Enforced Meshes + +\image html blsurf_enforced_meshes.png + +MG-CADSurf algorithm can be forced by other 1D meshes, sub-meshes or +groups. 1D meshes are allowed to pass over face boundaries and to +intersect other enforced meshes. +If a group name is given, the enforced 1D elements will be added to the group. +If the group does not exist, it is created. + +\sa Sample TUI Script of the \ref tui_blsurf "creation of a MG-CADSurf hypothesis", including enforced meshes. + +\ref blsurf_top "Back to top" + + \section blsurf_periodicity Periodicity \subsection periodicity_introduction Introduction diff --git a/idl/BLSURFPlugin_Algorithm.idl b/idl/BLSURFPlugin_Algorithm.idl index 7e3bd78..e380f2f 100644 --- a/idl/BLSURFPlugin_Algorithm.idl +++ b/idl/BLSURFPlugin_Algorithm.idl @@ -26,9 +26,10 @@ #ifndef _SMESH_BLSURFALGORITHM_IDL_ #define _SMESH_BLSURFALGORITHM_IDL_ -#include "SMESH_Hypothesis.idl" #include "GEOM_Gen.idl" #include "SALOME_Exception.idl" +#include "SMESH_Hypothesis.idl" +#include "SMESH_Mesh.idl" /*! * BLSURFPlugin: interfaces to BLSURF related hypotheses and algorithms @@ -37,6 +38,14 @@ module BLSURFPlugin { typedef sequence string_array; + // Enforced 1D Mesh + struct MG_EnforcedMesh1D + { + SMESH::SMESH_IDSource mesh; // mesh, group or sub-mesh + string groupName; // optional name of a group to add mesh edges to + }; + typedef sequence< MG_EnforcedMesh1D > EnforcedMeshesList; + // Enforced vertex name typedef string TEnfName; // Entry @@ -44,12 +53,12 @@ module BLSURFPlugin typedef sequence TEntryList; // Group name typedef string TEnfGroupName; - + // Coordinates of enforced vertex typedef sequence TEnfVertexCoords; // List of coords typedef sequence TEnfVertexCoordsList; - + // Enforced vertex struct TEnfVertex { TEnfName name; @@ -358,11 +367,17 @@ module BLSURFPlugin double GetVolumeProximityRatio(); /*! - *Set verbosity level in the range 0 to 100. + * Set verbosity level in the range 0 to 100. */ void SetVerbosity(in short theVal) raises (SALOME::SALOME_Exception); short GetVerbosity(); + /*! + * Set/Get enforced 1D meshes + */ + void SetEnforcedMeshes( in EnforcedMeshesList enforcedMeshes ); + EnforcedMeshesList GetEnforcedMeshes(); + /*! * Set enforce_cad_edge_sizes parameter * diff --git a/src/BLSURFPlugin/BLSURFPluginBuilder.py b/src/BLSURFPlugin/BLSURFPluginBuilder.py index ac507f2..8a7e946 100644 --- a/src/BLSURFPlugin/BLSURFPluginBuilder.py +++ b/src/BLSURFPlugin/BLSURFPluginBuilder.py @@ -42,6 +42,8 @@ BLSURF_Custom, BLSURF_GlobalSize, BLSURF_LocalSize = MG_CADSURF_Custom, MG_CADSU noBLSURFPlugin = 0 try: import BLSURFPlugin + from BLSURFPlugin import MG_EnforcedMesh1D + except ImportError: noBLSURFPlugin = 1 pass @@ -652,6 +654,21 @@ class BLSURF_Algorithm(Mesh_Algorithm): def GetInternalEnforcedVertexAllFacesGroup(self): return self.Parameters().GetInternalEnforcedVertexAllFacesGroup() + #----------------------------------------- + # Enforced mesh + #----------------------------------------- + + ## Set enforced 1D meshes + # @param enfMeshes : list of smeshBuilder.MG_EnforcedMesh1D structures + # + # Example: cadsurf.SetEnforcedMeshes([ smeshBuilder.MG_EnforcedMesh1D( mesh1D, "Group 1D")] + def SetEnforcedMeshes( self, enfMeshes ): + from salome.smesh.smeshBuilder import Mesh + for em in enfMeshes: + if isinstance( em.mesh, Mesh ): + em.mesh = em.mesh.GetMesh() + return self.Parameters().SetEnforcedMeshes( enfMeshes ) + #----------------------------------------- # Attractors #----------------------------------------- diff --git a/src/BLSURFPlugin/BLSURFPlugin_BLSURF.cxx b/src/BLSURFPlugin/BLSURFPlugin_BLSURF.cxx index 6bd3f2d..14b9f4b 100644 --- a/src/BLSURFPlugin/BLSURFPlugin_BLSURF.cxx +++ b/src/BLSURFPlugin/BLSURFPlugin_BLSURF.cxx @@ -25,21 +25,19 @@ // --- #include "BLSURFPlugin_BLSURF.hxx" -#include "BLSURFPlugin_Hypothesis.hxx" + #include "BLSURFPlugin_Attractor.hxx" +#include "BLSURFPlugin_EnforcedMesh1D.hxx" +#include "BLSURFPlugin_Hypothesis.hxx" extern "C"{ #include #include } -#include - - -#include - #include #include +#include #include #include #include @@ -47,15 +45,17 @@ extern "C"{ #include #include #include -#include +#include #include +#include #include #include -#include #include -#include +#include + +#include // python // OPENCASCADE includes #include @@ -405,14 +405,12 @@ status_t size_on_surface(integer face_id, real *uv, real *size, void *user_data) status_t size_on_edge(integer edge_id, real t, real *size, void *user_data); status_t size_on_vertex(integer vertex_id, real *size, void *user_data); -typedef struct { - gp_XY uv; - gp_XYZ xyz; -} projectionPoint; - ///////////////////////////////////////////////////////// -projectionPoint getProjectionPoint(TopoDS_Face& theFace, const gp_Pnt& thePoint) +BLSURFPlugin_BLSURF::projectionPoint +BLSURFPlugin_BLSURF::getProjectionPoint(TopoDS_Face& theFace, + const gp_Pnt& thePoint, + const bool theAllowStateON) { projectionPoint myPoint; @@ -444,12 +442,13 @@ projectionPoint getProjectionPoint(TopoDS_Face& theFace, const gp_Pnt& thePoint) { if ( !foundFace.IsNull() ) return myPoint; // thePoint seems to be TopAbs_ON - foundFace = face; - myPoint.uv = uv.XY(); - myPoint.xyz = surface->Value( uv ).XYZ(); + foundFace = face; + myPoint.uv = uv.XY(); + myPoint.xyz = surface->Value( uv ).XYZ(); + myPoint.state = FC.State(); // break; } - if ( FC.State() == TopAbs_ON ) + if ( FC.State() == TopAbs_ON && !theAllowStateON ) return myPoint; } } @@ -462,12 +461,15 @@ projectionPoint getProjectionPoint(TopoDS_Face& theFace, const gp_Pnt& thePoint) const TopoDS_Face& face = d2f->second.first; const gp_Pnt2d & uv = d2f->second.second; BRepClass_FaceClassifier FC( face, uv, Precision::Confusion()); - if ( FC.State() == TopAbs_IN ) + if (( FC.State() == TopAbs_IN ) || + ( FC.State() == TopAbs_ON && theAllowStateON )) { - foundFace = face; - myPoint.uv = uv.XY(); - myPoint.xyz = theHelper->GetSurface( face )->Value( uv ).XYZ(); - break; + foundFace = face; + myPoint.uv = uv.XY(); + myPoint.xyz = theHelper->GetSurface( face )->Value( uv ).XYZ(); + myPoint.state = FC.State(); + if ( FC.State() == TopAbs_IN ) + break; } } } @@ -477,7 +479,7 @@ projectionPoint getProjectionPoint(TopoDS_Face& theFace, const gp_Pnt& thePoint) // "getProjectionPoint: can't find a face by a vertex"); theFace = TopoDS::Face( foundFace ); } - else + else // !theFace.IsNull() { Handle(Geom_Surface) surface = BRep_Tool::Surface( theFace ); GeomAPI_ProjectPointOnSurf projector( thePoint, surface ); @@ -487,12 +489,14 @@ projectionPoint getProjectionPoint(TopoDS_Face& theFace, const gp_Pnt& thePoint) Standard_Real u,v; projector.LowerDistanceParameters(u,v); - myPoint.uv = gp_XY(u,v); - gp_Pnt aPnt = projector.NearestPoint(); - myPoint.xyz = gp_XYZ(aPnt.X(),aPnt.Y(),aPnt.Z()); + myPoint.uv = gp_XY(u,v); + myPoint.xyz = projector.NearestPoint().XYZ(); BRepClass_FaceClassifier FC( theFace, myPoint.uv, Precision::Confusion()); - if ( FC.State() != TopAbs_IN ) + myPoint.state = FC.State(); + + if (( FC.State() != TopAbs_IN ) && + ( FC.State() != TopAbs_ON || !theAllowStateON )) theFace.Nullify(); } @@ -502,16 +506,8 @@ projectionPoint getProjectionPoint(TopoDS_Face& theFace, const gp_Pnt& thePoint) ///////////////////////////////////////////////////////// TopoDS_Shape BLSURFPlugin_BLSURF::entryToShape(std::string entry) { - GEOM::GEOM_Object_var aGeomObj; - TopoDS_Shape S = TopoDS_Shape(); - SALOMEDS::SObject_var aSObj = SMESH_Gen_i::GetSMESHGen()->getStudyServant()->FindObjectID( entry.c_str() ); - if (!aSObj->_is_nil()) { - CORBA::Object_var obj = aSObj->GetObject(); - aGeomObj = GEOM::GEOM_Object::_narrow(obj); - aSObj->UnRegister(); - } - if ( !aGeomObj->_is_nil() ) - S = SMESH_Gen_i::GetSMESHGen()->GeomObjectToShape( aGeomObj.in() ); + GEOM::GEOM_Object_var aGeomObj = SMESH_Gen_i::GetSMESHGen()->GetGeomObjectByEntry( entry ); + TopoDS_Shape S = SMESH_Gen_i::GetSMESHGen()->GeomObjectToShape( aGeomObj ); return S; } @@ -520,7 +516,8 @@ void _createEnforcedVertexOnFace(TopoDS_Face faceShape, gp_Pnt aPnt, BLSURFPlugi BLSURFPlugin_Hypothesis::TEnfVertexCoords enf_coords, coords, s_coords; // Find the face and get the (u,v) values of the enforced vertex on the face - projectionPoint myPoint = getProjectionPoint(faceShape,aPnt); + BLSURFPlugin_BLSURF::projectionPoint myPoint = + BLSURFPlugin_BLSURF::getProjectionPoint(faceShape,aPnt); if ( faceShape.IsNull() ) return; @@ -639,30 +636,30 @@ void createAttractorOnFace(TopoDS_Shape GeomShape, std::string AttractorFunction // xa pos1 = AttractorFunction.find(sep); if (pos1!=string::npos) - xa = atof(AttractorFunction.substr(10, pos1-10).c_str()); + xa = atof(AttractorFunction.substr(10, pos1-10).c_str()); // ya pos2 = AttractorFunction.find(sep, pos1+1); if (pos2!=string::npos) { - ya = atof(AttractorFunction.substr(pos1+1, pos2-pos1-1).c_str()); - pos1 = pos2; + ya = atof(AttractorFunction.substr(pos1+1, pos2-pos1-1).c_str()); + pos1 = pos2; } // za pos2 = AttractorFunction.find(sep, pos1+1); if (pos2!=string::npos) { - za = atof(AttractorFunction.substr(pos1+1, pos2-pos1-1).c_str()); - pos1 = pos2; + za = atof(AttractorFunction.substr(pos1+1, pos2-pos1-1).c_str()); + pos1 = pos2; } // a pos2 = AttractorFunction.find(sep, pos1+1); if (pos2!=string::npos) { - a = atof(AttractorFunction.substr(pos1+1, pos2-pos1-1).c_str()); - pos1 = pos2; + a = atof(AttractorFunction.substr(pos1+1, pos2-pos1-1).c_str()); + pos1 = pos2; } // b pos2 = AttractorFunction.find(sep, pos1+1); if (pos2!=string::npos) { - b = atof(AttractorFunction.substr(pos1+1, pos2-pos1-1).c_str()); - pos1 = pos2; + b = atof(AttractorFunction.substr(pos1+1, pos2-pos1-1).c_str()); + pos1 = pos2; } // createNode pos2 = AttractorFunction.find(sep, pos1+1); @@ -674,13 +671,14 @@ void createAttractorOnFace(TopoDS_Shape GeomShape, std::string AttractorFunction // d pos2 = AttractorFunction.find(")"); if (pos2!=string::npos) { - d = atof(AttractorFunction.substr(pos1+1, pos2-pos1-1).c_str()); + d = atof(AttractorFunction.substr(pos1+1, pos2-pos1-1).c_str()); } // Get the (u,v) values of the attractor on the face - projectionPoint myPoint = getProjectionPoint(TopoDS::Face(GeomShape),gp_Pnt(xa,ya,za)); - gp_XY uvPoint = myPoint.uv; - gp_XYZ xyzPoint = myPoint.xyz; + BLSURFPlugin_BLSURF::projectionPoint myPoint = + BLSURFPlugin_BLSURF::getProjectionPoint(TopoDS::Face(GeomShape),gp_Pnt(xa,ya,za)); + gp_XY uvPoint = myPoint.uv; + gp_XYZ xyzPoint = myPoint.xyz; Standard_Real u0 = uvPoint.X(); Standard_Real v0 = uvPoint.Y(); Standard_Real x0 = xyzPoint.X(); @@ -1931,10 +1929,14 @@ bool BLSURFPlugin_BLSURF::compute(SMESH_Mesh& aMesh, SMESHDS_Mesh* meshDS = aMesh.GetMeshDS(); SMESH_MesherHelper helper( aMesh ), helperWithShape( aMesh ); - myHelper = theHelper = & helperWithShape; + theHelper = & helperWithShape; // do not call helper.IsQuadraticSubMesh() because sub-meshes // may be cleaned and helper.myTLinkNodeMap gets invalid in such a case bool haveQuadraticSubMesh = helperWithShape.IsQuadraticSubMesh( aShape ); + haveQuadraticSubMesh = haveQuadraticSubMesh || (_hypothesis && _hypothesis->GetQuadraticMesh()); + helper.SetIsQuadratic( haveQuadraticSubMesh ); + helperWithShape.SetIsQuadratic( haveQuadraticSubMesh ); + bool quadraticSubMeshAndViscousLayer = false; bool needMerge = false; typedef set< SMESHDS_SubMesh*, ShapeTypeCompare > TSubMeshSet; @@ -1947,6 +1949,8 @@ bool BLSURFPlugin_BLSURF::compute(SMESH_Mesh& aMesh, TopTools_IndexedDataMapOfShapeListOfShape e2ffmap; TopExp::MapShapesAndAncestors( aShape, TopAbs_EDGE, TopAbs_FACE, e2ffmap ); + BLSURFPlugin_EnforcedMesh1D enforcedMesh( helperWithShape, _hypothesis ); + // Issue 0019864. On DebianSarge, FE signals do not obey to OSD::SetSignal(false) #ifndef WIN32 feclearexcept( FE_ALL_EXCEPT ); @@ -1988,9 +1992,6 @@ bool BLSURFPlugin_BLSURF::compute(SMESH_Mesh& aMesh, SetParameters(_hypothesis, css, aShape); - haveQuadraticSubMesh = haveQuadraticSubMesh || (_hypothesis != NULL && _hypothesis->GetQuadraticMesh()); - helper.SetIsQuadratic( haveQuadraticSubMesh ); - // To remove as soon as quadratic mesh is allowed - BEGIN // GDD: Viscous layer is not allowed with quadratic mesh if (_haveViscousLayers && haveQuadraticSubMesh ) { @@ -2030,8 +2031,8 @@ bool BLSURFPlugin_BLSURF::compute(SMESH_Mesh& aMesh, { TopoDS_Face f = TopoDS::Face(face_iter.Current()); - SMESH_subMesh* fSM = aMesh.GetSubMesh( f ); - if ( !fSM->IsEmpty() ) continue; // skip already meshed FACE with viscous layers + //SMESH_subMesh* fSM = aMesh.GetSubMesh( f ); + //if ( !fSM->IsEmpty() ) continue; // skip already meshed FACE with viscous layers // make INTERNAL face oriented FORWARD (issue 0020993) if (f.Orientation() != TopAbs_FORWARD && f.Orientation() != TopAbs_REVERSED ) @@ -2088,35 +2089,29 @@ bool BLSURFPlugin_BLSURF::compute(SMESH_Mesh& aMesh, } // Specific size map = Attractor - std::map >::iterator attractor_iter = FaceId2AttractorCoords.begin(); - - for (; attractor_iter != FaceId2AttractorCoords.end(); ++attractor_iter) { - if (attractor_iter->first == faceKey) + std::map >::iterator attractor_iter = + FaceId2AttractorCoords.find( faceKey ); + if (attractor_iter != FaceId2AttractorCoords.end() ) + { + double * xyzCoords = & attractor_iter->second[2]; + gp_Pnt P(xyzCoords[0],xyzCoords[1],xyzCoords[2]); + BRepClass_FaceClassifier scl(f,P,1e-7); + TopAbs_State result = scl.State(); + if ( result == TopAbs_OUT ) + MESSAGE("Point is out of face: node is not created"); + if ( result == TopAbs_UNKNOWN ) + MESSAGE("Point position on face is unknown: node is not created"); + if ( result == TopAbs_ON ) + MESSAGE("Point is on border of face: node is not created"); + if ( result == TopAbs_IN ) { - double xyzCoords[3] = {attractor_iter->second[2], - attractor_iter->second[3], - attractor_iter->second[4]}; - - gp_Pnt P(xyzCoords[0],xyzCoords[1],xyzCoords[2]); - BRepClass_FaceClassifier scl(f,P,1e-7); - scl.Perform(f, P, 1e-7); - TopAbs_State result = scl.State(); - if ( result == TopAbs_OUT ) - MESSAGE("Point is out of face: node is not created"); - if ( result == TopAbs_UNKNOWN ) - MESSAGE("Point position on face is unknown: node is not created"); - if ( result == TopAbs_ON ) - MESSAGE("Point is on border of face: node is not created"); - if ( result == TopAbs_IN ) - { - // Point is inside face and not on border - double uvCoords[2] = {attractor_iter->second[0],attractor_iter->second[1]}; - ienf++; - cad_point_t* point_p = cad_point_new(fce, ienf, uvCoords); - cad_point_set_tag(point_p, ienf); - } - FaceId2AttractorCoords.erase(faceKey); + // Point is inside face and not on border + double * uvCoords = & attractor_iter->second[0]; + ienf++; + cad_point_t* point_p = cad_point_new(fce, ienf, uvCoords); + cad_point_set_tag(point_p, ienf); } + FaceId2AttractorCoords.erase(faceKey); } // ----------------- @@ -2182,19 +2177,24 @@ bool BLSURFPlugin_BLSURF::compute(SMESH_Mesh& aMesh, EDGES now create the edges associated to this face *****************************************************************************************/ - int edgeKey = -1; - for (TopExp_Explorer edge_iter(f,TopAbs_EDGE);edge_iter.More();edge_iter.Next()) + + std::vector< TopoDS_Edge > edges; + for ( TopExp_Explorer edge_iter( f, TopAbs_EDGE ); edge_iter.More(); edge_iter.Next() ) { - TopoDS_Edge e = TopoDS::Edge(edge_iter.Current()); - int ic = emap.FindIndex(e); - if (ic <= 0) - ic = emap.Add(e); + const TopoDS_Edge& e = TopoDS::Edge( edge_iter.Current() ); + if ( !enforcedMesh.GetSplitsOfEdge( e, edges, emap )) + edges.push_back( e ); + } + for ( const TopoDS_Edge& e : edges ) + { + int ic = emap.Add(e); double tmin,tmax; curves.push_back(BRep_Tool::CurveOnSurface(e, f, tmin, tmax)); - if (HasSizeMapOnEdge){ - edgeKey = EdgesWithSizeMap.FindIndex(e); + if ( HasSizeMapOnEdge ) + { + int edgeKey = EdgesWithSizeMap.FindIndex(e); if (EdgeId2SizeMap.find(edgeKey)!=EdgeId2SizeMap.end()) { theSizeMapStr = EdgeId2SizeMap[edgeKey]; @@ -2256,6 +2256,7 @@ bool BLSURFPlugin_BLSURF::compute(SMESH_Mesh& aMesh, The following call sets it to the same value as the edge_id : */ // IMP23368. Do not set tag to an EDGE shared by FACEs of a hyper-patch bool isInHyperPatch = false; + if ( e2ffmap.Contains( e )) // not there for a part of EDGE divided by enforced segments { std::set< int > faceTags, faceIDs; TopTools_ListIteratorOfListOfShape fIt( e2ffmap.FindFromKey( e )); @@ -2275,7 +2276,7 @@ bool BLSURFPlugin_BLSURF::compute(SMESH_Mesh& aMesh, if ( !isInHyperPatch ) cad_edge_set_tag(edg, ic); - /* by default, an edge does not necessalry appear in the resulting mesh, + /* by default, an edge does not necessarily appear in the resulting mesh, unless the following property is set : */ cad_edge_set_property(edg, EDGE_PROPERTY_SOFT_REQUIRED); @@ -2299,9 +2300,9 @@ bool BLSURFPlugin_BLSURF::compute(SMESH_Mesh& aMesh, for ( int iN = 0; iN < nbNodes; ++iN ) { const UVPtStruct& nData = nodeDataVec[ iN ]; - double t = nData.param; - real uv[2] = { nData.u, nData.v }; - SMESH_TNodeXYZ nXYZ( nData.node ); + double t = nData.param; + real uv[2] = { nData.u, nData.v }; + SMESH_TNodeXYZ nXYZ = nData.node; // cout << "\tt = " << t // << "\t uv = ( " << uv[0] << ","<< uv[1] << " ) " // << "\t u = " << nData.param @@ -2324,38 +2325,23 @@ bool BLSURFPlugin_BLSURF::compute(SMESH_Mesh& aMesh, *****************************************************************************************/ int npts = 0; - int ip1, ip2, *ip; - gp_Pnt2d e0 = curves.back()->Value(tmin); - gp_Pnt ee0 = surfaces.back()->Value(e0.X(), e0.Y()); - Standard_Real d1=0,d2=0; - - int vertexKey = -1; - for (TopExp_Explorer ex_edge(e ,TopAbs_VERTEX); ex_edge.More(); ex_edge.Next()) { - TopoDS_Vertex v = TopoDS::Vertex(ex_edge.Current()); - ++npts; - if (npts == 1){ - ip = &ip1; - d1 = ee0.SquareDistance(BRep_Tool::Pnt(v)); - } else { - ip = &ip2; - d2 = ee0.SquareDistance(BRep_Tool::Pnt(v)); - } - *ip = pmap.FindIndex(v); - if(*ip <= 0) { - *ip = pmap.Add(v); - // SMESH_subMesh* sm = aMesh.GetSubMesh(v); - // if ( sm->IsMeshComputed() ) - // edgeSubmeshes.insert( sm->GetSubMeshDS() ); - } + int ip[2]; + double d[2]; + gp_Pnt2d uv0 = curves.back()->Value(tmin); + gp_Pnt p0 = surfaces.back()->Value( uv0.X(), uv0.Y() ); -// std::string aFileName = "fmap_vertex_"; -// aFileName.append(val_to_string(*ip)); -// aFileName.append(".brep"); -// BRepTools::Write(v,aFileName.c_str()); + for (TopExp_Explorer ex_edge(e ,TopAbs_VERTEX); ex_edge.More(); ex_edge.Next()) + { + const TopoDS_Vertex& v = TopoDS::Vertex(ex_edge.Current()); + ip[ npts ] = pmap.Add(v); + d [ npts ] = p0.SquareDistance(BRep_Tool::Pnt(v)); + ++npts; - if (HasSizeMapOnVertex){ - vertexKey = VerticesWithSizeMap.FindIndex(v); - if (VertexId2SizeMap.find(vertexKey)!=VertexId2SizeMap.end()){ + if (HasSizeMapOnVertex) + { + int vertexKey = VerticesWithSizeMap.FindIndex(v); + if (VertexId2SizeMap.find(vertexKey)!=VertexId2SizeMap.end()) + { theSizeMapStr = VertexId2SizeMap[vertexKey]; if (theSizeMapStr.find(bad_end) == (theSizeMapStr.size()-bad_end.size()-1)) continue; @@ -2371,23 +2357,65 @@ bool BLSURFPlugin_BLSURF::compute(SMESH_Mesh& aMesh, PyGILState_Release(gstate); } } - } - if (npts != 2) { - // should not happen + } // loop on vertices + + if (npts != 2) { // should not happen MESSAGE("An edge does not have 2 extremities."); - } else { - if (d1 < d2) { - // This defines the curves extremity connectivity - cad_edge_set_extremities(edg, ip1, ip2); - /* set the tag (color) to the same value as the extremity id : */ - cad_edge_set_extremities_tag(edg, ip1, ip2); - } - else { - cad_edge_set_extremities(edg, ip2, ip1); - cad_edge_set_extremities_tag(edg, ip2, ip1); - } + continue; } + + if ( d[0] > d[1] ) + std::swap( ip[0], ip[1] ); + + // This defines the curves extremity connectivity + cad_edge_set_extremities (edg, ip[0], ip[1]); + /* set the tag (color) to the same value as the extremity id : */ + cad_edge_set_extremities_tag(edg, ip[0], ip[1]); + } // for edge + + // ============================== + // Add segments of enforced mesh + // ============================== + + if ( enforcedMesh.HasSegmentsOnFace( f )) + { + BLSURFPlugin_EnforcedMesh1D::Segmemnt seg; + while ( enforcedMesh.NextSegment( seg, pmap )) + { + curves.push_back( seg._pcurve ); + + cad_edge_t *edg = cad_edge_new( fce, seg._tag, seg._u[0], seg._u[1], + curv_fun,seg._pcurve.get()); + cad_edge_set_tag( edg, seg._tag ); + + cad_edge_set_property( edg, EDGE_PROPERTY_SOFT_REQUIRED ); + cad_edge_set_property( edg, EDGE_PROPERTY_INTERNAL ); + + cad_edge_set_extremities ( edg, seg._vTag[0], seg._vTag[1]); + cad_edge_set_extremities_tag( edg, seg._vTag[0], seg._vTag[1]); + + dcad_edge_discretization_t *dedge; + dcad_get_edge_discretization( dcad, edg, &dedge ); + dcad_edge_discretization_set_vertex_count( dedge, 2 ); + + dcad_edge_discretization_set_vertex_coordinates( dedge, 1, + seg._u [0], + &seg._uv[0].ChangeCoord(1), + seg._xyz[0].ChangeData() ); + dcad_edge_discretization_set_vertex_coordinates( dedge, 2, + seg._u [1], + &seg._uv[1].ChangeCoord(1), + seg._xyz[1].ChangeData() ); + + dcad_edge_discretization_set_vertex_tag( dedge, 1, seg._vTag[0] ); + dcad_edge_discretization_set_vertex_tag( dedge, 2, seg._vTag[1] ); + + dcad_edge_discretization_set_property(dedge, DISTENE_DCAD_PROPERTY_REQUIRED); + } + } + + } //for face /////////////////////// @@ -2502,10 +2530,6 @@ bool BLSURFPlugin_BLSURF::compute(SMESH_Mesh& aMesh, // set_param(css, "max_size", val_to_string( minFaceSize * 5 ).c_str()); } - // TODO: be able to use a mesh in input. - // See imsh usage in Products/templates/mg-cadsurf_template_common.cpp - // => cadsurf_set_mesh - // Use the original dcad cadsurf_set_dcad(css, dcad); @@ -2591,7 +2615,8 @@ bool BLSURFPlugin_BLSURF::compute(SMESH_Mesh& aMesh, std::string GMFFileName = BLSURFPlugin_Hypothesis::GetDefaultGMFFile(); if (_hypothesis) GMFFileName = _hypothesis->GetGMFFile(); - if (GMFFileName != "") { + if (GMFFileName != "") + { bool asciiFound = (GMFFileName.find(".mesh", GMFFileName.length()-5) != std::string::npos); bool binaryFound = (GMFFileName.find(".meshb",GMFFileName.length()-6) != std::string::npos); if (!asciiFound && !binaryFound) @@ -2604,9 +2629,9 @@ bool BLSURFPlugin_BLSURF::compute(SMESH_Mesh& aMesh, integer *evedg, *evtri, *evquad, *tags_buff, type; real xyz[3]; - mesh_get_vertex_count(msh, &nv); - mesh_get_edge_count(msh, &ne); - mesh_get_triangle_count(msh, &nt); + mesh_get_vertex_count (msh, &nv); + mesh_get_edge_count (msh, &ne); + mesh_get_triangle_count (msh, &nt); mesh_get_quadrangle_count(msh, &nq); evedg = (integer *)mesh_calloc_generic_buffer(msh); @@ -2617,82 +2642,79 @@ bool BLSURFPlugin_BLSURF::compute(SMESH_Mesh& aMesh, std::vector nodes(nv+1); std::vector tags(nv+1); + BLSURFPlugin_Hypothesis::TEnfVertexCoords projVertex; + /* enumerated vertices */ - for(int iv=1;iv<=nv;iv++) { + for ( int iv = 1; iv <= nv; iv++ ) + { mesh_get_vertex_coordinates(msh, iv, xyz); mesh_get_vertex_tag(msh, iv, &tag); // Issue 0020656. Use vertex coordinates nodes[iv] = NULL; - if ( tag > 0 && tag <= pmap.Extent() ) { - TopoDS_Vertex v = TopoDS::Vertex(pmap(tag)); - double tol = BRep_Tool::Tolerance( v ); - gp_Pnt p = BRep_Tool::Pnt( v ); - if ( p.IsEqual( gp_Pnt( xyz[0], xyz[1], xyz[2]), 1e3*tol)) - xyz[0] = p.X(), xyz[1] = p.Y(), xyz[2] = p.Z(); - else - tag = 0; // enforced or attracted vertex - nodes[iv] = SMESH_Algo::VertexNode( v, meshDS ); + if ( tag > 0 ) + { + if ( tag <= pmap.Extent() ) + { + TopoDS_Vertex v = TopoDS::Vertex(pmap(tag)); + double tol = BRep_Tool::Tolerance( v ); + gp_Pnt p = BRep_Tool::Pnt( v ); + if ( p.IsEqual( gp_Pnt( xyz[0], xyz[1], xyz[2]), 1e3*tol)) + xyz[0] = p.X(), xyz[1] = p.Y(), xyz[2] = p.Z(); + else + tag = 0; // enforced or attracted vertex + nodes[iv] = SMESH_Algo::VertexNode( v, meshDS ); + } + if ( !nodes[iv] && ( nodes[iv] = enforcedMesh.GetNodeByTag( tag, pmap ))) + { + continue; + } } if ( !nodes[iv] ) nodes[iv] = meshDS->AddNode(xyz[0], xyz[1], xyz[2]); // Create group of enforced vertices if requested - BLSURFPlugin_Hypothesis::TEnfVertexCoords projVertex; - projVertex.clear(); - projVertex.push_back((double)xyz[0]); - projVertex.push_back((double)xyz[1]); - projVertex.push_back((double)xyz[2]); - std::map< BLSURFPlugin_Hypothesis::TEnfVertexCoords, BLSURFPlugin_Hypothesis::TEnfVertexList >::const_iterator enfCoordsIt = EnfVertexCoords2EnfVertexList.find(projVertex); + projVertex.assign( xyz, xyz + 3 ); + auto enfCoordsIt = EnfVertexCoords2EnfVertexList.find( projVertex ); if (enfCoordsIt != EnfVertexCoords2EnfVertexList.end()) { - BLSURFPlugin_Hypothesis::TEnfVertexList::const_iterator enfListIt = enfCoordsIt->second.begin(); - BLSURFPlugin_Hypothesis::TEnfVertex *currentEnfVertex; - for (; enfListIt != enfCoordsIt->second.end(); ++enfListIt) { - currentEnfVertex = (*enfListIt); - if (currentEnfVertex->grpName != "") { - bool groupDone = false; - SMESH_Mesh::GroupIteratorPtr grIt = aMesh.GetGroups(); - while (grIt->more()) { + for ( BLSURFPlugin_Hypothesis::TEnfVertex *currentEnfVertex : enfCoordsIt->second ) + if (currentEnfVertex->grpName != "") + { + SMDS_MeshGroup* groupDS = nullptr; + for ( SMESH_Mesh::GroupIteratorPtr grIt = aMesh.GetGroups(); grIt->more() && !groupDS; ) + { SMESH_Group * group = grIt->next(); - if ( !group ) continue; - SMESHDS_GroupBase* groupDS = group->GetGroupDS(); - if ( !groupDS ) continue; - if ( groupDS->GetType()==SMDSAbs_Node && currentEnfVertex->grpName.compare(group->GetName())==0) { - SMESHDS_Group* aGroupDS = static_cast( groupDS ); - aGroupDS->SMDSGroup().Add(nodes[iv]); - // How can I inform the hypothesis ? - // _hypothesis->AddEnfVertexNodeID(currentEnfVertex->grpName,nodes[iv]->GetID()); - groupDone = true; - break; - } + SMESHDS_Group * grp = dynamic_cast< SMESHDS_Group* >( group->GetGroupDS() ); + if ( grp && + grp->GetType() == SMDSAbs_Node && + currentEnfVertex->grpName == group->GetName() ) + groupDS = &grp->SMDSGroup(); } - if (!groupDone) + if ( !groupDS ) { - SMESH_Group* aGroup = aMesh.AddGroup( SMDSAbs_Node, currentEnfVertex->grpName.c_str() ); - aGroup->SetName( currentEnfVertex->grpName.c_str() ); - SMESHDS_Group* aGroupDS = static_cast( aGroup->GetGroupDS() ); - aGroupDS->SMDSGroup().Add(nodes[iv]); - groupDone = true; + SMESH_Group * group = aMesh.AddGroup( SMDSAbs_Node, currentEnfVertex->grpName.c_str() ); + SMESHDS_Group * grp = static_cast< SMESHDS_Group* >( group->GetGroupDS() ); + groupDS = &grp->SMDSGroup(); } - if (!groupDone) - throw SALOME_Exception(LOCALIZED("An enforced vertex node was not added to a group")); + groupDS->Add( nodes[iv] ); } - else - MESSAGE("Group name is empty: '"<grpName<<"' => group is not created"); - } } // internal points are tagged to zero - if(tag > 0 && tag <= pmap.Extent() ){ + if ( tag > 0 && tag <= pmap.Extent() ) + { meshDS->SetNodeOnVertex(nodes[iv], TopoDS::Vertex(pmap(tag))); tags[iv] = false; - } else { + } + else + { tags[iv] = true; } } /* enumerate edges */ - for(int it=1;it<=ne;it++) { + for ( int it = 1; it <= ne; it++ ) + { SMDS_MeshEdge* edg; mesh_get_edge_vertices(msh, it, vtx); mesh_get_edge_extra_vertices(msh, it, &type, evedg); @@ -2703,14 +2725,21 @@ bool BLSURFPlugin_BLSURF::compute(SMESH_Mesh& aMesh, // Get the initial tags corresponding to the output tag and redefine the tag as // the last of the two initial tags (else the output tag is out of emap and hasn't any meaning) mesh_get_composite_tag_definition(msh, tag, &nb_tag, tags_buff); - if(nb_tag > 1) - tag=tags_buff[nb_tag-1]; + if ( nb_tag > 1 ) + tag = tags_buff[ nb_tag-1 ]; if ( tag < 1 || tag > emap.Extent() ) { - std::cerr << "MG-CADSurf BUG:::: Edge tag " << tag - << " does not point to a CAD edge (nb edges " << emap.Extent() << ")" << std::endl; + if ( !enforcedMesh.IsSegmentTag( tag )) // it's a false INTERNAL EDGE of enforced mesh + { + std::cerr << "MG-CADSurf BUG:::: Edge tag " << tag + << " does not point to a CAD edge (nb edges " << emap.Extent() << ")" + << std::endl; + } continue; } + if ( meshDS->ShapeToIndex( emap( tag )) == 0 ) + tag = enforcedMesh.GetTagOfSplitEdge( tag ); + if (tags[vtx[0]]) { Set_NodeOnEdge(meshDS, nodes[vtx[0]], emap(tag)); tags[vtx[0]] = false; @@ -3207,31 +3236,27 @@ void BLSURFPlugin_BLSURF::Set_NodeOnEdge(SMESHDS_Mesh* meshDS, */ status_t curv_fun(real t, real *uv, real *dt, real *dtt, void *user_data) { - /* t is given. It contains the t (time) 1D parametric coordintaes - of the point PreCAD/MG-CADSurf is querying on the curve */ + /* t is given. It contains the 1D parametric coordintaes + of the point MG-CADSurf is querying on the curve */ - /* user_data identifies the edge PreCAD/MG-CADSurf is querying - * (see cad_edge_new later in this example) */ - const Geom2d_Curve*pargeo = (const Geom2d_Curve*) user_data; + /* user_data identifies the edge MG-CADSurf is querying */ + const Geom2d_Curve* pargeo = (const Geom2d_Curve*) user_data; - if (uv){ - /* MG-CADSurf is querying the function evaluation */ - gp_Pnt2d P; - P=pargeo->Value(t); + if (uv) { + /* MG-CADSurf is querying the function evaluation */ + gp_Pnt2d P = pargeo->Value(t); uv[0]=P.X(); uv[1]=P.Y(); } - if(dt) { - /* query for the first order derivatives */ - gp_Vec2d V1; - V1=pargeo->DN(t,1); + if (dt) { + /* query for the first order derivatives */ + gp_Vec2d V1 = pargeo->DN(t,1); dt[0]=V1.X(); dt[1]=V1.Y(); } - if(dtt){ + if (dtt) { /* query for the second order derivatives */ - gp_Vec2d V2; - V2=pargeo->DN(t,2); + gp_Vec2d V2 = pargeo->DN(t,2); dtt[0]=V2.X(); dtt[1]=V2.Y(); } diff --git a/src/BLSURFPlugin/BLSURFPlugin_BLSURF.hxx b/src/BLSURFPlugin/BLSURFPlugin_BLSURF.hxx index 167b761..936bdd3 100644 --- a/src/BLSURFPlugin/BLSURFPlugin_BLSURF.hxx +++ b/src/BLSURFPlugin/BLSURFPlugin_BLSURF.hxx @@ -132,6 +132,16 @@ public: typedef std::vector< TEdgePeriodicityIDs > TEdgesIDsPeriodicityVector; typedef std::vector< TVertexPeriodicityIDs > TVerticesIDsPeriodicityVector; + // Point projection on FACE + typedef struct { + gp_XY uv; + gp_XYZ xyz; + TopAbs_State state; + } projectionPoint; + + static projectionPoint getProjectionPoint(TopoDS_Face& theFace, + const gp_Pnt& thePoint, + const bool theAllowStateON=false); protected: @@ -162,7 +172,6 @@ private: private: PyObject * main_mod; PyObject * main_dict; - SMESH_MesherHelper* myHelper; volatile bool _compute_canceled; }; diff --git a/src/BLSURFPlugin/BLSURFPlugin_EnforcedMesh1D.cxx b/src/BLSURFPlugin/BLSURFPlugin_EnforcedMesh1D.cxx new file mode 100644 index 0000000..923bdfa --- /dev/null +++ b/src/BLSURFPlugin/BLSURFPlugin_EnforcedMesh1D.cxx @@ -0,0 +1,1332 @@ +// Copyright (C) 2007-2021 CEA/DEN, EDF R&D +// +// 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, or (at your option) any later version. +// +// 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 +// +// File : BLSURFPlugin_EnforcedMesh1D.cxx +// Author : Edward AGAPOV (OCC) + +#include "BLSURFPlugin_EnforcedMesh1D.hxx" + +#include "BLSURFPlugin_BLSURF.hxx" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +// allow range iteration on NCollection_IndexedMap +template < class IMAP > +typename IMAP::const_iterator begin( const IMAP & m ) { return m.cbegin(); } +template < class IMAP > +typename IMAP::const_iterator end( const IMAP & m ) { return m.cend(); } + + +namespace +{ + //================================================================================ + /*! + * \brief Look for a node coincident with a given nodes among end nodes of a segment + * and among its internal nodes + * \param [in] p - the epoint + * \param [in] tol - 3D tolarace + * \param [in] segment - the segment + * \param [in] segInternalNodes - map of segment internal nodes + * \param [out] index - return index of found internal node; -1 if an end node is found + * \return const SMDS_MeshNode* - found node + */ + //================================================================================ + + const SMDS_MeshNode* findNode( const gp_Pnt& p, + const double tol, + const SMDS_MeshElement* segment, + BLSURFPlugin_EnforcedMesh1D::TNodesOnSeg & segInternalNodes, + int & index ) + { + + SMESH_NodeXYZ node0 = segment->GetNode(0); + if ( p.IsEqual( node0, tol )) + return index = -1, node0.Node(); + SMESH_NodeXYZ node1 = segment->GetNode(1); + if ( p.IsEqual( node1, tol )) + return index = -1, node1.Node(); + + auto seg2nodes = segInternalNodes.find( segment ); + if ( seg2nodes != segInternalNodes.end() ) + { + const std::vector< const SMDS_MeshNode* >& nodes = seg2nodes->second; + for ( size_t i = 0; i < nodes.size(); ++i ) + if ( p.IsEqual( SMESH_NodeXYZ( nodes[i] ), tol )) + { + index = (int) i; + return nodes[i]; + } + } + return nullptr; + } + + //================================================================================ + /*! + * \brief Orient segments to correspond to order of nodes in a branch + * \param [in] braSegs - segments of the branch + * \param [in] braNodes - nodes of the branch + * \param [in] nodeIndex - index of a node of the branch + * \param [inout] mesh - mesh holding the nodes and segments + * + * + */ + //================================================================================ + + void orientSegments( const std::vector< const SMDS_MeshElement* > & braSegs, + const std::vector< const SMDS_MeshNode* > & braNodes, + const size_t nodeIndex, + SMESH_Mesh* mesh ) + { + const SMDS_MeshElement* toReverse[2] = { nullptr, nullptr }; + + if ( nodeIndex > 0 && + braSegs[ nodeIndex - 1 ]->GetNode(1) != braNodes[ nodeIndex ]) + toReverse[ 0 ] = braSegs[ nodeIndex - 1 ]; + + if ( nodeIndex < braSegs.size() && + braSegs[ nodeIndex ]->GetNode(0) != braNodes[ nodeIndex ]) + toReverse[ bool( toReverse[0]) ] = braSegs[ nodeIndex ]; + + if ( !toReverse[0] ) + return; + + SMESH_MeshEditor editor( mesh ); + for ( int i = 0; i < 2; ++i ) + if ( toReverse[ i ]) + editor.Reorient( toReverse[ i ]); + } + +} // namespace + +//================================================================================ +/*! + * \brief Create enforced mesh segments in a mesh + * \param [in] helper - contains the mesh and the shape to compute + * \param [in] hyp - hypothesis containing data of enforced meshes + */ +//================================================================================ + +BLSURFPlugin_EnforcedMesh1D::BLSURFPlugin_EnforcedMesh1D( SMESH_MesherHelper& helper, + const BLSURFPlugin_Hypothesis* hyp ) + : _mesh ( helper.GetMesh() ), + _shape( helper.GetSubShape() ), + _helper( *_mesh ), + _isQuadratic( helper.GetIsQuadratic() ) +{ + if ( !hyp || !_mesh || hyp->GetEnforcedMeshes().empty() ) + return; + + _tol = 2 * BRep_Tool::MaxTolerance( _shape, TopAbs_VERTEX ); + _segTag = 1000 + helper.Count( _shape, TopAbs_EDGE, /*ignoreSame=*/false ); + _segTag0 = _segTag; + _nodeTag0 = 1000 + helper.Count( _shape, TopAbs_VERTEX, /*ignoreSame=*/false ); + + for ( const BLSURFPlugin_Hypothesis::EnforcedMesh& enfMesh : hyp->GetEnforcedMeshes() ) + { + copyEnforcedMesh( enfMesh, hyp, _shape ); + } + + for ( const SMDS_MeshElement* segment : _segmentsOnSeveralShapes ) + { + splitSegmentOnSeveralShapes( segment ); + } + + for ( const TopoDS_Shape & face : _faces ) + { + splitSelfIntersectingSegments( face ); + } + + for ( TEdge2Nodes::Iterator e2nn( _nodesOnEdge ); e2nn.More(); e2nn.Next() ) + { + splitEdgeByNodes( e2nn.Key(), e2nn.Value() ); + } +} + +//================================================================================ +/*! + * \brief Convert enforced segments to quadratic + */ +//================================================================================ + +BLSURFPlugin_EnforcedMesh1D::~BLSURFPlugin_EnforcedMesh1D() +{ + if ( !_isQuadratic ) + return; + + _helper.SetIsQuadratic( true ); + + SMESHDS_Mesh* meshDS = _mesh->GetMeshDS(); + std::vector nodes(2); + std::vector trias; + + SMDS_MeshGroup* group = nullptr; + if ( !_name2Group.empty() ) + group = _name2Group.begin()->second; + + for ( const TopoDS_Shape& f : _faces ) + if ( HasSegmentsOnFace( TopoDS::Face( f ))) + while ( _segIterator->more() ) + { + const SMDS_MeshElement* segment = _segIterator->next(); + if ( segment->GetType() != SMDSAbs_Edge ) + break; + + nodes[0] = segment->GetNode(0); + nodes[1] = segment->GetNode(1); + if ( meshDS->GetElementsByNodes( nodes, trias, SMDSAbs_Face )) + { + if ( !group || !group->Contains( segment )) + { + SMDS_MeshGroup* otherGroup = nullptr; + if ( _name2Group.size() > bool( group )) + for ( auto & n2g : _name2Group ) + if ( n2g.second != group && n2g.second->Contains( segment )) + { + otherGroup = n2g.second; + break; + } + group = otherGroup; + } + + _helper.AddTLinks( static_cast< const SMDS_MeshFace* >( trias[0] )); + + meshDS->RemoveFreeElement( segment, meshDS->MeshElements( f ), /*fromGroup=*/false ); + + SMDS_MeshElement* quadSegment = _helper.AddEdge( nodes[0], nodes[1], + /*id=*/0, /*force3d=*/false ); + if ( group && segment != quadSegment ) + { + group->Remove( segment ); + group->Add( quadSegment ); + } + } + } + return; +} + +//================================================================================ +/*! + * \brief Return EDGEs resulted from division of FACE boundary by enforced segments + * \param [in] edge - possibly divided EDGE + * \param [out] splits - split EDGEs + * \return bool - true if the EDGE is split + */ +//================================================================================ + +bool BLSURFPlugin_EnforcedMesh1D::GetSplitsOfEdge( const TopoDS_Edge& edge, + std::vector< TopoDS_Edge > & splits, + TopTools_IndexedMapOfShape & edgeTags ) +{ + std::vector< TopoDS_Edge > * splitsInMap = _edgeSplitsOfEdge.ChangeSeek( edge ); + if ( !splitsInMap ) + return false; + + splits.insert( splits.end(), splitsInMap->begin(), splitsInMap->end() ); + + int eTag = edgeTags.Add( edge ); + + size_t index = splits.size() - 1; + for ( size_t i = 0; i < splitsInMap->size(); ++i, --index ) + { + int splitTag = edgeTags.Add( splits[ index ]); + _splitTags2EdgeTag[ splitTag ] = eTag; + + if ( edge.Orientation() == TopAbs_REVERSED ) + splits[ index ].Reverse(); + } + + return true; +} + + +//================================================================================ +/*! + * \brief Add 1D elements to the mesh + */ +//================================================================================ + +void BLSURFPlugin_EnforcedMesh1D:: + +copyEnforcedMesh( const BLSURFPlugin_Hypothesis::EnforcedMesh& theEnfMesh, + const BLSURFPlugin_Hypothesis* theHyp, + const TopoDS_Shape& theShape) +{ + SMESH_Mesh* mesh1D; + SMDS_ElemIteratorPtr segIt = theHyp->GetEnforcedSegments( theEnfMesh, mesh1D ); + if ( !segIt->more() ) + return; + + // setup predicates to detect nodes on FACE boundary + setupPredicates( theShape ); + + SMDS_MeshGroup* group = getGroup( theEnfMesh._groupName ); + SMESHDS_Mesh* meshDS = _helper.GetMeshDS(); + + // get ordered nodes and segments of theEnfMesh + SMESH_MeshAlgos::TElemGroupVector edgeBranches; + SMESH_MeshAlgos::TNodeGroupVector nodeBranches; + SMESH_MeshAlgos::Get1DBranches( segIt, edgeBranches, nodeBranches ); + + + // Copy nodes and segments from an enforced mesh to my mesh + + TopoDS_Shape vertex, edge; + + // first treat ends of branches that can be shared by branches + for ( size_t iB = 0; iB < nodeBranches.size(); ++iB ) + { + std::vector< const SMDS_MeshNode* > & braNodes = nodeBranches[ iB ]; + std::vector< const SMDS_MeshElement* > & braSegs = edgeBranches[ iB ]; + + for ( int isLast = 0; isLast < 2; ++isLast ) + { + const SMDS_MeshNode* enfNode = isLast ? braNodes.back() : braNodes[0]; + if ( meshDS->Contains( enfNode )) + continue; // already in my mesh + + const SMDS_MeshNode* newNode = copyEnforcedNode( enfNode ); + if ( !newNode ) + orientSegments( braSegs, braNodes, isLast ? 0 : braNodes.size() - 1, mesh1D ); + + // replace enfNode at branch ends by newNode + SMESH_NodeXYZ enfPnt( newNode ? newNode : enfNode ); + for ( std::vector< const SMDS_MeshNode* > & braNodes : nodeBranches ) + { + for ( int isLast = 0; isLast < 2; ++isLast ) + { + const SMDS_MeshNode* & endNode = isLast ? braNodes.back() : braNodes[0]; + if ( endNode == enfNode || enfPnt.SquareDistance( endNode ) < _tol*_tol ) + endNode = newNode; + } + } + continue; + } // loop on branch ends + } // loop on nodeBranches + + // copy nodes and segments + + for ( size_t iB = 0; iB < nodeBranches.size(); ++iB ) + { + std::vector< const SMDS_MeshNode* > & braNodes = nodeBranches[ iB ]; + std::vector< const SMDS_MeshElement* > & braSegs = edgeBranches[ iB ]; + + // copy nodes of the branch + for ( size_t i = 0; i < braNodes.size(); ++i ) + { + const SMDS_MeshNode* & enfNode = braNodes[ i ]; + const SMDS_MeshNode* newNode = copyEnforcedNode( enfNode ); + + if ( !newNode ) // orient segments to be able to get enforced not projected node + orientSegments( braSegs, braNodes, i, mesh1D ); + + enfNode = newNode; + } + + // copy segments of the branch + for ( size_t i = 0; i < braSegs.size(); ++i ) + { + //braSegs[ i ] = nullptr; + + const SMDS_MeshNode* node0 = braNodes[ i ]; + const SMDS_MeshNode* node1 = braNodes[ i + 1 ]; + if ( !node0 && !node1 ) + continue; + + TopoDS_Shape shape0 = _helper.GetSubShapeByNode( node0, meshDS ); + TopoDS_Shape shape1 = _helper.GetSubShapeByNode( node1, meshDS ); + if ( shape0.IsNull() && shape1.IsNull() ) + continue; + + if ( !node0 && shape1.ShapeType() != TopAbs_FACE ) + continue; + if ( !node1 && shape0.ShapeType() != TopAbs_FACE ) + continue; + + if ( !node0 || !node1 ) // create missing node at location of enforced node projected nowhere + { + SMESH_NodeXYZ pn = braSegs[i]->GetNode( !node1 ); + ( node0 ? node1 : node0 ) = _helper.AddNode( pn->X(), pn->Y(), pn->Z() ); + } + + SMDS_MeshEdge* newSeg = _helper.AddEdge( node0, node1 ); + if ( group ) + group->Add( newSeg ); + braSegs[ i ] = newSeg; + + // check if the both nodes are on the same FACE + TopoDS_Shape face = shape0; + if ( !shape0.IsSame( shape1 ) && !shape0.IsNull() && !shape1.IsNull() ) + { + if ( shape0.ShapeType() == TopAbs_FACE && + _helper.IsSubShape( shape1, shape0 )) + { + face = shape0; + } + else if ( shape1.ShapeType() == TopAbs_FACE && + _helper.IsSubShape( shape0, shape1 )) + { + face = shape1; + } + else // try to find a FACE by projecting a segment middle point + { + face.Nullify(); + gp_Pnt middlePnt = 0.5 * ( SMESH_NodeXYZ( node0 ) + SMESH_NodeXYZ( node1 )); + //BLSURFPlugin_BLSURF::projectionPoint projPnt = + BLSURFPlugin_BLSURF::getProjectionPoint( TopoDS::Face( face ), middlePnt ); + + if ( !face.IsNull() && + ( !_helper.IsSubShape( shape0, face ) || + !_helper.IsSubShape( shape1, face ) )) + face.Nullify(); + } + } + if ( !face.IsNull() && face.ShapeType() == TopAbs_FACE ) + { + meshDS->SetMeshElementOnShape( newSeg, face ); + _faces.Add( face ); + } + + if ( face.IsNull() || shape0.IsNull() || shape1.IsNull() ) + { + _segmentsOnSeveralShapes.push_back( newSeg ); + } + + } // loop on branch segments + continue; + } // loop on branches + + return; +} + +//================================================================================ +/*! + * \brief Create a copy of a node of enforced mesh in my mesh + * \param [in] enfNode - enforced node + * \return const SMDS_MeshNode* - a node in my mesh + */ +//================================================================================ + +const SMDS_MeshNode* BLSURFPlugin_EnforcedMesh1D::copyEnforcedNode( const SMDS_MeshNode* enfNode ) +{ + SMESHDS_Mesh * meshDS = _helper.GetMeshDS(); + + if ( !enfNode || meshDS->Contains( enfNode )) + return enfNode; // already in my mesh + + SMESH_NodeXYZ enfPnt = enfNode; + + const SMDS_MeshNode* newNode = nullptr; + + // check if enfNode is on VERTEX + TopoDS_Vertex vertex; + if ( _onVertexPredicate->IsSatisfy( enfNode, &vertex )) + { + _mesh->GetSubMesh( vertex )->ComputeStateEngine( SMESH_subMesh::COMPUTE ); + newNode = SMESH_Algo::VertexNode( vertex, meshDS ); + } + + // check if enfNode is on EDGE + bool setNodeOnEdge = false; + TopoDS_Edge edge; + if ( !newNode ) + { + setNodeOnEdge = _onEdgePredicate->IsSatisfy( enfNode, &edge ); + if ( setNodeOnEdge ) + { + newNode = findNodeOnEdge( enfPnt, edge ); + setNodeOnEdge = !newNode; + } + } + + // create a new node and set it on FACE + if ( !newNode ) + { + TopoDS_Face face; + BLSURFPlugin_BLSURF::projectionPoint projPnt = + BLSURFPlugin_BLSURF::getProjectionPoint( face, enfPnt, /*allowStateON=*/true ); + if ( face.IsNull() ) return newNode; + + if ( projPnt.state == TopAbs_ON ) + { + SMDS_MeshNode* projNode = const_cast< SMDS_MeshNode* >( enfNode ); + projNode->setXYZ( projPnt.xyz.X(), projPnt.xyz.Y(), projPnt.xyz.Z() ); + vertex.Nullify(); + edge.Nullify(); + if ( _onVertexPredicate->IsSatisfy( projNode, &vertex )) + { + _mesh->GetSubMesh( vertex )->ComputeStateEngine( SMESH_subMesh::COMPUTE ); + newNode = SMESH_Algo::VertexNode( vertex, meshDS ); + } + else if (( setNodeOnEdge = _onEdgePredicate->IsSatisfy( projNode, &edge ))) + { + newNode = findNodeOnEdge( projPnt.xyz, edge ); + setNodeOnEdge = !newNode; + } + projNode->setXYZ( enfPnt.X(), enfPnt.Y(), enfPnt.Z() ); + } + + if ( !newNode ) + newNode = meshDS->AddNode( projPnt.xyz.X(), projPnt.xyz.Y(), projPnt.xyz.Z() ); + + if ( vertex.IsNull() && edge.IsNull() ) + meshDS->SetNodeOnFace( newNode, face, projPnt.uv.X(), projPnt.uv.Y() ); + } + + // set the new node on EDGE + if ( newNode && setNodeOnEdge ) + { + addNodeOnEdge( newNode, edge ); + } + + return newNode; +} + +//================================================================================ +/*! + * \brief Split a segment whose nodes are on different FACEs into smaller parts + * lying each on one FACE + */ +//================================================================================ + +void BLSURFPlugin_EnforcedMesh1D::splitSegmentOnSeveralShapes( const SMDS_MeshElement* segment ) +{ + const SMDS_MeshNode* node0 = segment->GetNode(0); + const SMDS_MeshNode* node1 = segment->GetNode(1); + SMESHDS_Mesh * meshDS = _helper.GetMeshDS(); + + TopoDS_Shape shape0 = _helper.GetSubShapeByNode( node0, meshDS ); + TopoDS_Shape shape1 = _helper.GetSubShapeByNode( node1, meshDS ); + + if ( shape0.IsNull() ) + { + std::swap( node0, node1 ); + shape0 = shape1; + shape1.Nullify(); + } + + gp_XYZ xyz0 = SMESH_NodeXYZ( node0 ); + gp_XYZ xyz1 = SMESH_NodeXYZ( node1 ); + gp_XYZ segDir = ( xyz1 - xyz0 ).Normalized(); + + //std::map< double, const SMDS_MeshNode* > mediumNodes; // nodes splitting the segment + + while ( !shape0.IsSame( shape1 )) // move along the segment till shape1 + { + if ( shape0.ShapeType() == TopAbs_FACE ) // make a node on an EDGE of the FACE + { // ---------------------------------- + TopoDS_Edge edge; + double paramOnE; + gp_Pnt edgeIntPnt = getEdgeIntersection( shape0, xyz0, xyz1, edge, paramOnE ); + if ( edge.IsNull() ) + break; + + // check if edgeIntPnt in on VERTEX + TopoDS_Vertex vertex; + for ( int iV = 0; iV < 2 && vertex.IsNull(); ++iV ) + { + TopoDS_Vertex v = _helper.IthVertex( iV, edge ); + if ( edgeIntPnt.SquareDistance( BRep_Tool::Pnt( v )) < _tol *_tol ) + vertex = v; + } + + // make a node on the EDGE + const SMDS_MeshNode* nodeOnEdge = nullptr; + if ( vertex.IsNull() ) + { + nodeOnEdge = findNodeOnEdge( edgeIntPnt, edge ); + if ( !nodeOnEdge ) + { + if ( shape1.IsNull() && node1 ) + { + nodeOnEdge = node1; + node1 = nullptr; + meshDS->MoveNode( nodeOnEdge, edgeIntPnt.X(), edgeIntPnt.Y(), edgeIntPnt.Z() ); + } + else + { + nodeOnEdge = _helper.AddNode( edgeIntPnt.X(), edgeIntPnt.Y(), edgeIntPnt.Z() ); + } + addNodeOnEdge( nodeOnEdge, edge, paramOnE ); + } + } + else + { + _mesh->GetSubMesh( vertex )->ComputeStateEngine( SMESH_subMesh::COMPUTE ); + nodeOnEdge = SMESH_Algo::VertexNode( vertex, meshDS ); + } + + // create a sub-segment + SMDS_MeshElement* newSeg = _helper.AddEdge( node0, nodeOnEdge ); + meshDS->SetMeshElementOnShape( newSeg, shape0 ); + + SMESH_MeshEditor::AddToSameGroups( newSeg, segment, meshDS ); + + node0 = nodeOnEdge; + xyz0 = SMESH_NodeXYZ( node0 ); + if ( vertex.IsNull() ) + shape0 = edge; + else + shape0 = vertex; + } + + else // shape0 is EDGE or VERTEX; look for the next FACE + { // ------------------------------------------------ + + if ( !shape1.IsNull() && + shape1.ShapeType() == TopAbs_FACE && + _helper.IsSubShape( shape0, shape1 )) // shape0 belongs to FACE shape1 + { + SMDS_MeshElement* newSeg = _helper.AddEdge( node0, node1 ); + SMESH_MeshEditor::AddToSameGroups( newSeg, segment, meshDS ); + meshDS->SetMeshElementOnShape( newSeg, shape1 ); + break; + } + // FACE search + TopoDS_Face face; + double shift = 10 * _tol; + for ( int nbAttemp = 0; face.IsNull() && nbAttemp < 10; ++nbAttemp ) + { + xyz0 += segDir * shift; + shift *= 2; + BLSURFPlugin_BLSURF::getProjectionPoint( face, xyz0 ); + } + if ( !face.IsNull() ) + { + if ( _helper.IsSubShape( shape0, face )) + _faces.Add( face ); + else + break; + shape0 = face; + } + else + { + break; + } + } + continue; + } //while ( !shape0.IsSame( shape1 )) + + meshDS->RemoveFreeElement( segment, /*submesh=*/nullptr ); +} + +//================================================================================ +/*! + * \brief Find intersection of FACE EDGEs and a segment + * \param [in] theFace - the FACE + * \param [in] thePnt0 - first end of the segment + * \param [in] thePnt1 - last end of the segment + * \param [out] theFounfEdge - return the intersected EDGE + * \param [out] theParamOnEdge - return parameter of intersection point on EDGE + * \return gp_XYZ - point on an EDGE closest to the segment + */ +//================================================================================ + +gp_Pnt BLSURFPlugin_EnforcedMesh1D::getEdgeIntersection( const TopoDS_Shape& theFaceOrEdge, + const gp_XYZ& thePnt0, + const gp_XYZ& thePnt1, + TopoDS_Edge & theFounfEdge, + double & theParamOnEdge) +{ + const double segLen = ( thePnt1 - thePnt0 ).Modulus(); + const double maxSegDist2 = segLen * segLen * 0.5 * 0.5; + + Handle(Geom_Line) segLine = new Geom_Line( thePnt0, thePnt1 - thePnt0 ); + GeomAdaptor_Curve segLineAdpt( segLine, 0, segLen ); + + TopTools_MapOfShape edges; + double minParamOnSeg = segLen; + gp_Pnt foundPnt; + for ( TopExp_Explorer edgeExp( theFaceOrEdge, TopAbs_EDGE ); edgeExp.More(); edgeExp.Next() ) + { + const TopoDS_Edge& edge = TopoDS::Edge( edgeExp.Current() ); + if ( !edges.Add( edge )) + continue; + + Extrema_ExtCC extrema( segLineAdpt, BRepAdaptor_Curve( edge ), _tol, _tol ); + + if ( extrema.IsDone() && !extrema.IsParallel() ) + for ( int i = 1, nb = extrema.NbExt(); i <= nb; ++i ) + if ( extrema.SquareDistance( i ) < maxSegDist2 ) + { + Extrema_POnCurv pOnSeg, pOnEdge; + extrema.Points( i, pOnSeg, pOnEdge ); + double paramOnSeg = pOnSeg.Parameter(); + if ( 0 < paramOnSeg && paramOnSeg < minParamOnSeg ) + { + minParamOnSeg = paramOnSeg; + foundPnt = pOnEdge.Value(); + theFounfEdge = edge; + theParamOnEdge = pOnEdge.Parameter(); + } + } + } + return foundPnt; +} + +//================================================================================ +/*! + * \brief Split self-intersecting segments on a given FACE + */ +//================================================================================ + +void BLSURFPlugin_EnforcedMesh1D::splitSelfIntersectingSegments( const TopoDS_Shape & theFace ) +{ + const TopoDS_Face& face = TopoDS::Face( theFace ); + + SMESHDS_Mesh* meshDS = _helper.GetMeshDS(); + SMESHDS_SubMesh* sm = meshDS->MeshElements( face ); + if ( !sm || sm->NbElements() <= 1 ) + return; + + // get ordered nodes and segments on the face + SMESH_MeshAlgos::TElemGroupVector edgeBranches; + SMESH_MeshAlgos::TNodeGroupVector nodeBranches; + SMESH_MeshAlgos::Get1DBranches( sm->GetElements(), edgeBranches, nodeBranches ); + + // create element searcher + SMESH_ElementSearcher* elemSearcher; + SMESHUtils::Deleter< SMESH_ElementSearcher > elSearchdeleter; + std::vector< const SMDS_MeshElement* > foundElems; + { + std::vector< SMDS_ElemIteratorPtr > elemItVec; + for ( std::vector< const SMDS_MeshElement* > & braSegs : edgeBranches ) + { + SMDS_ElemIteratorPtr segIt = + boost::make_shared< SMDS_ElementVectorIterator >( braSegs.begin(), braSegs.end() ); + elemItVec.push_back( segIt ); + } + typedef SMDS_IteratorOnIterators< const SMDS_MeshElement*, + std::vector< SMDS_ElemIteratorPtr > > TVecIterator; + SMDS_ElemIteratorPtr segIt = boost::make_shared< TVecIterator >( elemItVec ); + + elemSearcher = SMESH_MeshAlgos::GetElementSearcher( *meshDS, segIt, _tol ); + elSearchdeleter._obj = elemSearcher; + + // force usage of iterators before they die + elemSearcher->FindElementsByPoint( gp_Pnt( 0,0,1e+20), SMDSAbs_Edge, foundElems ); + } + + + // Find intersecting segments + + std::map< const SMDS_MeshElement* , std::vector< const SMDS_MeshNode* > > segInternalNodes; + SMESH_MeshEditor::TListOfListOfNodes nodeGroupsToMerge; + + for ( std::vector< const SMDS_MeshElement* > & braSegs : edgeBranches ) + { + braSegs.push_back( braSegs.back() ); + const SMDS_MeshElement* prevSeg = nullptr; + + for ( size_t i = 0, nb = braSegs.size() - 1; i < nb; ++i ) + { + const SMDS_MeshElement* seg = braSegs[ i ]; + const SMDS_MeshElement* nextSeg = braSegs[ i + 1 ]; + const SMDS_MeshNode* node0 = seg->GetNode(0); + const SMDS_MeshNode* node1 = seg->GetNode(1); + + gp_XYZ xyz0 = SMESH_NodeXYZ( node0 ); + gp_XYZ xyz1 = SMESH_NodeXYZ( node1 ); + gp_XYZ middlePnt = 0.5 * ( SMESH_NodeXYZ( node0 ) + SMESH_NodeXYZ( node1 )); + double segLen = ( xyz0 - xyz1 ).Modulus(); + + foundElems.clear(); + elemSearcher->GetElementsInSphere( middlePnt, 0.5 * segLen + _tol, SMDSAbs_Edge, foundElems ); + + for ( const SMDS_MeshElement* closeSeg : foundElems ) + { + if ( closeSeg == prevSeg || + closeSeg >= seg || + closeSeg == nextSeg ) + continue; + + gp_Pnt intPnt; + gp_Pnt2d uv; + if ( intersectSegments( seg, closeSeg, face, intPnt, uv )) + { + int i0, i1; + const SMDS_MeshNode* intNode0 = findNode( intPnt, _tol, seg, segInternalNodes, i0 ); + const SMDS_MeshNode* intNode1 = findNode( intPnt, _tol, closeSeg, segInternalNodes, i1 ); + if ( !intNode0 && intNode1 ) + { + segInternalNodes[ seg ].push_back( intNode1 ); + } + else if ( !intNode1 && intNode0 ) + { + segInternalNodes[ closeSeg ].push_back( intNode0 ); + } + else if ( intNode1 && intNode0 ) + { + if ( intNode1 == intNode0 ) + continue; + if ( i0 < 0 && i1 < 0 ) + { + nodeGroupsToMerge.push_back // merge end nodes + ( std::list< const SMDS_MeshNode* >({ intNode0, intNode1 })); + } + else if ( i0 < 0 ) + { + segInternalNodes[ closeSeg ][ i1 ] = intNode0; + } + else if ( i1 < 0 ) + { + segInternalNodes[ seg ][ i0 ] = intNode1; + } + else // two internal nodes coincide + { + segInternalNodes[ seg ][ i0 ] = intNode1; + nodeGroupsToMerge.push_back + ( std::list< const SMDS_MeshNode* >({ intNode1, intNode0 })); + } + } + else // ( !intNode1 && !intNode0 ) + { + intNode0 = _helper.AddNode( intPnt.X(), intPnt.Y(), intPnt.Z() ); + meshDS->SetNodeOnFace( intNode0, face, uv.X(), uv.Y() ); + segInternalNodes[ seg ].push_back( intNode0 ); + segInternalNodes[ closeSeg ].push_back( intNode0 ); + } + } + } + + prevSeg = seg; + + } // loop on segments of a branch + } // loop on branches + + + findIntersectionWithSeamEdge( face, segInternalNodes ); // on periodic FACE + + + // Split segments + + for ( auto& seg2nodes : segInternalNodes ) + { + const SMDS_MeshElement* seg = seg2nodes.first; + std::vector< const SMDS_MeshNode* > & nodes = seg2nodes.second; + if ( nodes.empty() ) continue; + + const SMDS_MeshNode* n0 = seg->GetNode( 0 ); + const SMDS_MeshNode* n1 = seg->GetNode( 1 ); + nodes.push_back( n1 ); + + // sort nodes on the segment + gp_Pnt p0 = SMESH_NodeXYZ( n0 ); + std::map< double, const SMDS_MeshNode* > sortedNodes; + for ( SMESH_NodeXYZ pn : nodes ) + sortedNodes.insert({ p0.SquareDistance( pn ), pn.Node() }); + + // make new segments + for ( auto & d2n : sortedNodes ) + { + n1 = d2n.second; + SMDS_MeshElement* newSeg = _helper.AddEdge( n0, n1 ); + n0 = n1; + meshDS->SetMeshElementOnShape( newSeg, face ); + SMESH_MeshEditor::AddToSameGroups( newSeg, seg, meshDS ); + } + meshDS->RemoveFreeElement( seg, /*submesh=*/nullptr ); + } + + + // merge equal nodes + SMESH_MeshEditor( _mesh ).MergeNodes( nodeGroupsToMerge ); +} + +//================================================================================ +/*! + * \brief Find intersections of segments with a seam EDGE on a periodic FACE + */ +//================================================================================ + +void BLSURFPlugin_EnforcedMesh1D::findIntersectionWithSeamEdge( const TopoDS_Face & face, + TNodesOnSeg & segInternalNodes ) +{ + _helper.SetSubShape( face ); + if ( !_helper.HasSeam() ) + return; + + SMESHDS_Mesh* meshDS = _helper.GetMeshDS(); + SMESHDS_SubMesh* sm = meshDS->MeshElements( face ); + if ( !sm || sm->NbElements() == 0 ) + return; + + TopTools_MapOfShape treatedEdges; + for ( TopExp_Explorer edgeExp( face, TopAbs_EDGE ); edgeExp.More(); edgeExp.Next() ) + { + const TopoDS_Edge& edge = TopoDS::Edge( edgeExp.Current() ); + if ( !_helper.IsSeamShape( edge ) || !treatedEdges.Add( edge )) + continue; + + for ( SMDS_ElemIteratorPtr setIt = sm->GetElements(); setIt->more(); ) + { + const SMDS_MeshElement* segment = setIt->next(); + const SMESH_NodeXYZ pn0 = segment->GetNode( 0 ); + const SMESH_NodeXYZ pn1 = segment->GetNode( 1 ); + + gp_XY uv0 = _helper.GetNodeUV( face, pn0.Node() ); + gp_XY uv1 = _helper.GetNodeUV( face, pn1.Node() ); + + for ( int iCoo = 1; iCoo <= 2; ++iCoo ) + if ( iCoo & _helper.GetPeriodicIndex() ) + { + double distParam = Abs( uv0.Coord( iCoo ) - uv1.Coord( iCoo )); + if ( distParam > 0.5 * _helper.GetPeriod( iCoo )) + { + double paramOnE; TopoDS_Edge edge2; + gp_Pnt edgeIntPnt = getEdgeIntersection( edge, pn0, pn1, edge2, paramOnE ); + if ( edge2.IsNull() ) + continue; + + const SMDS_MeshNode* nodeOnSeam = findNodeOnEdge( edgeIntPnt, edge ); + bool isOnEdge = nodeOnSeam; + + int indexOnSegment = 3; + if ( !nodeOnSeam ) + nodeOnSeam = findNode( edgeIntPnt, _tol, segment, segInternalNodes, indexOnSegment ); + + if ( !nodeOnSeam ) + { + nodeOnSeam = _helper.AddNode( edgeIntPnt.X(), edgeIntPnt.Y(), edgeIntPnt.Z() ); + } + + if ( !isOnEdge ) + { + addNodeOnEdge( nodeOnSeam, edge, paramOnE ); + } + if ( indexOnSegment == 3 ) + segInternalNodes[ segment ].push_back( nodeOnSeam ); + } + } + } + } +} + +//================================================================================ +/*! + * \brief Intersect two segments + * \param [in] seg1 - segment 1 + * \param [in] seg2 - segment 2 + * \param [in] face - the FACE on which segments lie + * \param [out] intPnt - intersection point + * \param [out] intUV - UV of intersection point on the FACE + * \return bool - true if intersection found + */ +//================================================================================ + +bool BLSURFPlugin_EnforcedMesh1D::intersectSegments( const SMDS_MeshElement* seg1, + const SMDS_MeshElement* seg2, + const TopoDS_Face& face, + gp_Pnt & intPnt, + gp_Pnt2d & intUV ) const +{ + SMESH_NodeXYZ n10 = seg1->GetNode(0); + SMESH_NodeXYZ n11 = seg1->GetNode(1); + SMESH_NodeXYZ n20 = seg2->GetNode(0); + SMESH_NodeXYZ n21 = seg2->GetNode(1); + if ( n10 == n20 || n10 == n21 || n11 == n20 || n10 == n21 ) + return false; + + gp_Lin lin1( n10, n11 - n10 ); + gp_Lin lin2( n20, n21 - n20 ); + + Extrema_ExtElC extrema( lin1, lin2, Precision::Angular() ); + + if ( !extrema.IsDone() || extrema.IsParallel() ) + return false; + + Extrema_POnCurv poc1, poc2; + extrema.Points( 1, poc1, poc2 ); + + double len1 = lin1.Direction().XYZ() * ( n11 - n10 ); + double len2 = lin2.Direction().XYZ() * ( n21 - n20 ); + double u1 = poc1.Parameter(); + double u2 = poc2.Parameter(); + + if ( u1 < -_tol || u1 > len1 + _tol ) + return false; + if ( u2 < -_tol || u2 > len2 + _tol ) + return false; + + intPnt = 0.5 * ( poc1.Value().XYZ() + poc2.Value().XYZ() ); + + // compute approximate UV + + u1 /= len1; + u2 /= len2; + + gp_XY uv10 = _helper.GetNodeUV( face, n10.Node(), n11.Node() ); + gp_XY uv11 = _helper.GetNodeUV( face, n11.Node(), n10.Node() ); + gp_XY uv1 = uv10 * ( 1 - u1 ) + uv11 * u1; + + gp_XY uv20 = _helper.GetNodeUV( face, n20.Node(), n21.Node() ); + gp_XY uv21 = _helper.GetNodeUV( face, n21.Node(), n20.Node() ); + gp_XY uv2 = uv20 * ( 1 - u2 ) + uv21 * u2; + + intUV = 0.5 * ( uv1 + uv2 ); + + // compute precise UV and XYZ by projecting intPnt to the FACE + + Handle(ShapeAnalysis_Surface) surface = _helper.GetSurface( face ); + intUV = surface->NextValueOfUV( intUV, intPnt, _tol ); + if ( surface->Gap() > Min( len1, len2 )) + intUV = surface->ValueOfUV( intPnt, _tol ); + + intPnt = surface->Value( intUV ); + + return true; +} + +//================================================================================ +/*! + * \brief Setup predicates to detect nodes on FACE boundary + * \param [in] shape - shape containing FACEs to mesh + */ +//================================================================================ + +void BLSURFPlugin_EnforcedMesh1D::setupPredicates( const TopoDS_Shape& theShape ) +{ + if ( _onVertexPredicate ) + return; + + _onVertexPredicate.reset( new TPredicate() ); + _onVertexPredicate->SetTolerance( _tol ); + _onVertexPredicate->SetMesh( _helper.GetMeshDS() ); + { + TopTools_IndexedMapOfShape vertices; + TopExp::MapShapes( theShape, TopAbs_VERTEX, vertices ); + TopoDS_Compound vCompound; + BRep_Builder builder; + builder.MakeCompound( vCompound ); + for ( const TopoDS_Shape& v : vertices ) + builder.Add( vCompound, v ); + + _onVertexPredicate->SetShape( vCompound, SMDSAbs_Node ); + } + + + _onEdgePredicate.reset( new TPredicate() ); + _onEdgePredicate->SetTolerance( _tol ); + _onEdgePredicate->SetMesh( _helper.GetMeshDS() ); + { + TopTools_IndexedMapOfShape edges; + TopExp::MapShapes( theShape, TopAbs_EDGE, edges ); + TopoDS_Compound eCompound; + BRep_Builder builder; + builder.MakeCompound( eCompound ); + for ( const TopoDS_Shape& e : edges ) + builder.Add( eCompound, e ); + + _onEdgePredicate->SetShape( eCompound, SMDSAbs_Node ); + } + return; +} + +//================================================================================ +/*! + * \brief Find or create a group of edges with given name + */ +//================================================================================ + +SMDS_MeshGroup* BLSURFPlugin_EnforcedMesh1D::getGroup( const std::string& groupName ) +{ + SMDS_MeshGroup* group = nullptr; + if ( !groupName.empty() ) + { + if ( _name2Group.count( groupName )) + return _name2Group[ groupName ]; + + // find existing group + for ( SMESH_Mesh::GroupIteratorPtr grIt = _mesh->GetGroups(); grIt->more(); ) + { + SMESH_Group* grp = grIt->next(); + SMESHDS_Group* grpDS = dynamic_cast< SMESHDS_Group* >( grp->GetGroupDS() ); + if ( grpDS && + grpDS->GetType() == SMDSAbs_Edge && + groupName == grp->GetName() ) + { + _name2Group[ groupName ] = & grpDS->SMDSGroup(); + return & grpDS->SMDSGroup(); + } + } + + // create a new group + SMESH_Group* grp = _mesh->AddGroup( SMDSAbs_Edge, groupName.c_str() ); + SMESHDS_Group* grpDS = static_cast< SMESHDS_Group* >( grp->GetGroupDS() ); + + group = & grpDS->SMDSGroup(); + _name2Group[ groupName ] = group; + } + return group; +} + +//================================================================================ +/*! + * \brief Look for a node dividing a given EDGE + */ +//================================================================================ + +const SMDS_MeshNode* BLSURFPlugin_EnforcedMesh1D::findNodeOnEdge( const gp_Pnt& p, + const TopoDS_Edge& edge ) +{ + // look for an equal node on the EDGE + if ( std::vector< const SMDS_MeshNode* >* nodesOnE = _nodesOnEdge.ChangeSeek( edge )) + for ( const SMDS_MeshNode* n : *nodesOnE ) + if ( p.SquareDistance( SMESH_NodeXYZ( n )) < _tol * _tol ) + { + return n; + } + + return nullptr; +} + +//================================================================================ +/*! + * \brief Add a node to an EDGE + */ +//================================================================================ + +void BLSURFPlugin_EnforcedMesh1D::addNodeOnEdge( const SMDS_MeshNode* node, + const TopoDS_Edge& edge, + const double u) +{ + _mesh->GetMeshDS()->SetNodeOnEdge( node, edge, u ); + + std::vector< const SMDS_MeshNode* > * nodesOnE = _nodesOnEdge.ChangeSeek( edge ); + if ( !nodesOnE ) + nodesOnE = _nodesOnEdge.Bound( edge, std::vector< const SMDS_MeshNode* >() ); + + nodesOnE->push_back( node ); +} + +//================================================================================ +/*! + * \brief Create EDGEs by dividing a given EDGE by nodes on it + * \param [in] edge - the EDGE to divide + * \param [in] nodes - the nodes to divide by + */ +//================================================================================ + +void BLSURFPlugin_EnforcedMesh1D:: + +splitEdgeByNodes( TopoDS_Edge edge, const std::vector< const SMDS_MeshNode* >& nodes ) +{ + if ( nodes.empty() ) + return; + + edge.Orientation( TopAbs_FORWARD ); + + TopoDS_Vertex v0 = _helper.IthVertex( 0, edge ); + TopoDS_Vertex v1 = _helper.IthVertex( 1, edge ); + + // create VERTEXes and sort them along the EDGE + + std::map< double, TopoDS_Vertex > sortedVertices; + + BRepAdaptor_Curve curve( edge ); + for ( SMESH_NodeXYZ pn : nodes ) + { + gp_Pnt projPnt; + double u; + ShapeAnalysis_Curve().Project( curve, pn, _tol, projPnt, u, false ); + projPnt = curve.Value( u ); + + TopoDS_Vertex v = BRepBuilderAPI_MakeVertex( projPnt ); + + sortedVertices.insert({ u, v }); + + _nOnE2Vertex[ pn.Node() ] = v; + } + sortedVertices.insert({ BRep_Tool::Parameter( v1, edge ), v1 }); + + + // create EDGEs + + BRep_Builder builder; + std::vector< TopoDS_Edge >& newEdges = *_edgeSplitsOfEdge.Bound( edge, TEdge2Edges::value_type()); + + double u0 = BRep_Tool::Parameter( v0, edge ); + for ( auto& u2v : sortedVertices ) + { + double u1 = u2v.first; + v1 = u2v.second; + + TopoDS_Shape newShape = edge.EmptyCopied(); + TopoDS_Edge newEdge = TopoDS::Edge( newShape ); + builder.Add( newEdge, v0 ); + builder.Add( newEdge, v1 ); + builder.Range( newEdge, u0, u1 ); + newEdges.push_back( newEdge ); + + v0 = v1; + u0 = u1; + } + + return; +} + +//================================================================================ +/*! + * \brief Return true if there are enforced segments on a FACE. Start iteration on segments + */ +//================================================================================ + +bool BLSURFPlugin_EnforcedMesh1D::HasSegmentsOnFace( const TopoDS_Face& face ) +{ + _segIterator.reset(); + + if ( _faces.Contains( face )) + { + _currentFace = face; + _segIterator = _helper.GetMeshDS()->MeshElements( face )->GetElements(); + + _helper.SetSubShape( face ); + + return _segIterator->more(); + } + return false; +} + + +//================================================================================ +/*! + * \brief Return next segment on the FACE + */ +//================================================================================ + +bool BLSURFPlugin_EnforcedMesh1D::NextSegment( Segmemnt & seg, + TopTools_IndexedMapOfShape & vertexTags ) +{ + if ( _segIterator && _segIterator->more() ) + { + const SMDS_MeshElement* segment = _segIterator->next(); + + while ( segment->GetType() != SMDSAbs_Edge && _segIterator->more() ) + segment = _segIterator->next(); + if ( segment->GetType() != SMDSAbs_Edge ) + return false; + + const SMDS_MeshNode * node[2] = { segment->GetNode(0), + segment->GetNode(1) }; + + seg._tag = _segTag++; + + seg._xyz[0] = SMESH_NodeXYZ( node[0]); + seg._xyz[1] = SMESH_NodeXYZ( node[1]); + + seg._uv[0] = _helper.GetNodeUV( _currentFace, node[0], node[1] ); + seg._uv[1] = _helper.GetNodeUV( _currentFace, node[1], node[0] ); + + seg._pcurve = new Geom2d_Line( seg._uv[0], ( seg._uv[1] - seg._uv[0] )); + + seg._u[0] = 0.0; + seg._u[1] = ( seg._uv[1] - seg._uv[0] ).Modulus(); + + for ( int i = 0; i < 2; ++i ) + { + auto n2v = _nOnE2Vertex.find( node[i] ); // find VERTEX by node + + if ( n2v != _nOnE2Vertex.end() ) + seg._vTag[i] = vertexTags.Add( n2v->second ); + else + seg._vTag[i] = _nodeTag0 + _nodeTags.Add( node[i] ); + } + + if ( !_isQuadratic ) + _mesh->GetMeshDS()->UnSetMeshElementOnShape( segment, _currentFace ); + + return true; + } + return false; +} + +//================================================================================ +/*! + * \brief Return enforced node by the tag that was returned by Segmemnt::_vTag[i] + */ +//================================================================================ + +const SMDS_MeshNode* +BLSURFPlugin_EnforcedMesh1D::GetNodeByTag( int tag, + const TopTools_IndexedMapOfShape & vertexTags ) +{ + const SMDS_MeshNode* node = nullptr; + + if ( tag <= vertexTags.Size() && !_nOnE2Vertex.empty() ) + { + const TopoDS_Shape& vertex = vertexTags( tag ); + + for ( auto n2v = _nOnE2Vertex.begin(); n2v != _nOnE2Vertex.end(); ++n2v ) + if ( vertex.IsSame( n2v->second )) + { + node = n2v->first; + _nOnE2Vertex.erase( n2v ); + return node; + } + } + + tag -= _nodeTag0; + + bool isValid = ( 0 < tag && tag <= _nodeTags.Size() ); + if ( isValid ) + node = _nodeTags( tag ); + + return node; +} + +//================================================================================ +/*! + * \brief Return true if a tag corresponds to the tag of enforced segment + * that was returned by Segment::_tag + */ +//================================================================================ + +bool BLSURFPlugin_EnforcedMesh1D::IsSegmentTag( int tag ) const +{ + return ( _segTag0 <= tag && tag <= _segTag ); +} + +//================================================================================ +/*! + * \brief Return tag of EDGE by tags of its splits + */ +//================================================================================ + +int BLSURFPlugin_EnforcedMesh1D::GetTagOfSplitEdge( int splitTag ) const +{ + auto sTag2eTag = _splitTags2EdgeTag.find( splitTag ); + return ( sTag2eTag == _splitTags2EdgeTag.end() ) ? splitTag : sTag2eTag->second; +} diff --git a/src/BLSURFPlugin/BLSURFPlugin_EnforcedMesh1D.hxx b/src/BLSURFPlugin/BLSURFPlugin_EnforcedMesh1D.hxx new file mode 100644 index 0000000..aac128d --- /dev/null +++ b/src/BLSURFPlugin/BLSURFPlugin_EnforcedMesh1D.hxx @@ -0,0 +1,172 @@ +// Copyright (C) 2007-2021 CEA/DEN, EDF R&D +// +// 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, or (at your option) any later version. +// +// 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 +// +// File : BLSURFPlugin_EnforcedMesh1D.hxx +// Author : Edward AGAPOV (OCC) + +#ifndef __BLSURFPlugin_EnforcedMesh1D_HXX__ +#define __BLSURFPlugin_EnforcedMesh1D_HXX__ + +#include "BLSURFPlugin_Hypothesis.hxx" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +class SMDS_MeshElement; +class SMDS_MeshGroup; +class SMDS_MeshNode; +class SMESH_Mesh; + +/*! + * \brief Implement 1D mesh into the mesh made by MG-CADSurf + */ +class BLSURFPlugin_EnforcedMesh1D +{ +public: + + BLSURFPlugin_EnforcedMesh1D( SMESH_MesherHelper& helper, + const BLSURFPlugin_Hypothesis* hyp ); + + ~BLSURFPlugin_EnforcedMesh1D(); + + // Return EDGEs resulted from division of FACE boundary by enforced segments + bool GetSplitsOfEdge( const TopoDS_Edge& edge, + std::vector< TopoDS_Edge > & splits, + TopTools_IndexedMapOfShape & edgeTags ); + + // Return true if there are enforced segments on a FACE. Start iteration on segments + bool HasSegmentsOnFace( const TopoDS_Face& face ); + + // Data of an enforced segment to provide MG-CADSurf with + struct Segmemnt + { + int _tag; + Handle(Geom2d_Curve) _pcurve; + + // data of two ends + double _u [2]; + gp_XY _uv [2]; + gp_XYZ _xyz [2]; + int _vTag[2]; + }; + + // Return next segment on the FACE. Iteration starts upon calling HasSegmentsOnFace() + bool NextSegment( Segmemnt & seg, TopTools_IndexedMapOfShape & vertexTags ); + + // Return enforced node by tag + const SMDS_MeshNode* GetNodeByTag( int tag, const TopTools_IndexedMapOfShape & vertexTags ); + + // Return true if a tad corresponds to an enforced segment + bool IsSegmentTag( int tag ) const; + + // Return tag of EDGE by tags of its splits + int GetTagOfSplitEdge( int splitTag ) const; + + typedef std::map< const SMDS_MeshElement* , std::vector< const SMDS_MeshNode* > > TNodesOnSeg; + +private: + + void copyEnforcedMesh( const BLSURFPlugin_Hypothesis::EnforcedMesh& theEnfMesh, + const BLSURFPlugin_Hypothesis* theHyp, + const TopoDS_Shape& theShape); + + const SMDS_MeshNode* copyEnforcedNode( const SMDS_MeshNode* enfNode ); + + void setupPredicates( const TopoDS_Shape& shape ); + + void splitSegmentOnSeveralShapes( const SMDS_MeshElement* segment ); + + void splitSelfIntersectingSegments( const TopoDS_Shape & face ); + + void findIntersectionWithSeamEdge( const TopoDS_Face & face, TNodesOnSeg & segInternalNodes ); + + bool intersectSegments( const SMDS_MeshElement* seg1, const SMDS_MeshElement* seg2, + const TopoDS_Face& face, gp_Pnt& intPnt, gp_Pnt2d& inUV ) const; + + gp_Pnt getEdgeIntersection( const TopoDS_Shape& faceOrEdge, + const gp_XYZ& xyz0, const gp_XYZ& xyz1, + TopoDS_Edge & edge, double & paramOnEdge ); + + void splitEdgeByNodes( TopoDS_Edge edge, const std::vector< const SMDS_MeshNode* >& nodes); + + SMDS_MeshGroup* getGroup( const std::string& groupName ); + + const SMDS_MeshNode* findNodeOnEdge( const gp_Pnt& p, const TopoDS_Edge& edge ); + void addNodeOnEdge( const SMDS_MeshNode*node , const TopoDS_Edge& edge, const double u = 0. ); + + + SMESH_Mesh* _mesh; + TopoDS_Shape _shape; + SMESH_MesherHelper _helper; + bool _isQuadratic; + std::map< std::string, SMDS_MeshGroup* > _name2Group; + double _tol; + TopTools_IndexedMapOfShape _faces; + + // segments whose nodes are on different FACEs; + // such segments will be split into segments lying each on own FACE + std::vector< const SMDS_MeshElement* > _segmentsOnSeveralShapes; + + // nodes projected on EDGEs; EDGEs will be divided by them + typedef NCollection_DataMap< TopoDS_Edge, + std::vector< const SMDS_MeshNode* >, + TopTools_ShapeMapHasher> TEdge2Nodes; + typedef NCollection_DataMap< TopoDS_Edge, + std::vector< TopoDS_Edge >, + TopTools_ShapeMapHasher> TEdge2Edges; + TEdge2Nodes _nodesOnEdge; + TEdge2Edges _edgeSplitsOfEdge; // result of EDGE division by nodes + std::map< int, int > _splitTags2EdgeTag; + std::map< const SMDS_MeshNode* , TopoDS_Vertex > _nOnE2Vertex; // VERTEXes on _nodesOnEdge + + typedef SMESH::Controls::ElementsOnShape TPredicate; + typedef SMESH::Controls::ElementsOnShapePtr TPredicatePtr; + TPredicatePtr _onVertexPredicate; + TPredicatePtr _onEdgePredicate; + + // for iteration of segments of FACE + + SMDS_ElemIteratorPtr _segIterator; + TopoDS_Face _currentFace; + int _segTag0; + int _segTag; + + typedef NCollection_IndexedMap< const SMDS_MeshNode* > TNodeIndMap; + TNodeIndMap _nodeTags; + int _nodeTag0; + + // nodes not projected to geometry; they are reused during next projection to geometry + std::vector< const SMDS_MeshNode* > _freeNodes; + +}; + + +#endif diff --git a/src/BLSURFPlugin/BLSURFPlugin_Hypothesis.cxx b/src/BLSURFPlugin/BLSURFPlugin_Hypothesis.cxx index 9b85b3b..bc094a3 100644 --- a/src/BLSURFPlugin/BLSURFPlugin_Hypothesis.cxx +++ b/src/BLSURFPlugin/BLSURFPlugin_Hypothesis.cxx @@ -26,16 +26,18 @@ // #include "BLSURFPlugin_Hypothesis.hxx" #include "BLSURFPlugin_Attractor.hxx" -#include "SMESH_Gen_i.hxx" -#include -#include -#include -#include + +#include +#include +#include +#include +#include #include +#include // cascade include -#include "ShapeAnalysis.hxx" +#include // CORBA includes #include CORBA_CLIENT_HEADER(SALOMEDS) @@ -974,6 +976,63 @@ int BLSURFPlugin_Hypothesis::GetHyperPatchTag( const int fa } return faceTag; } + +//============================================================================= +void BLSURFPlugin_Hypothesis::SetEnforcedMeshes( std::vector< EnforcedMesh > & enforcedMeshes ) +{ + if ( _enforcedMeshes != enforcedMeshes ) + { + _enforcedMeshes.swap( enforcedMeshes ); + NotifySubMeshesHypothesisModification(); + } +} + +//================================================================================ +/*! + * \brief Return elements of 1D enforced mesh. Result can be NULL + */ +//================================================================================ + +SMDS_ElemIteratorPtr +BLSURFPlugin_Hypothesis::GetEnforcedSegments( const EnforcedMesh& enfMesh, + SMESH_Mesh* & mesh ) const +{ + SMDS_ElemIteratorPtr it; + if (( mesh = SMESH_Hypothesis::GetMeshByPersistentID( enfMesh._meshID ))) + { + mesh->Load(); + + switch( enfMesh._type ) + { + case ENFORCED_MESH: + it = mesh->GetMeshDS()->elementsIterator( SMDSAbs_Edge ); + break; + + case ENFORCED_GROUP: + if ( SMESH_Group* grp = mesh->GetGroup( enfMesh._subID )) + { + if ( grp->GetGroupDS()->GetType() == SMDSAbs_Edge ) + it = grp->GetGroupDS()->GetElements(); + } + break; + + case ENFORCED_SUBMESH: + if ( SMESH_subMesh* sm = mesh->GetSubMeshContaining( enfMesh._subID )) + if ( SMESHDS_SubMesh * smDS = sm->GetSubMeshDS() ) + { + it = smDS->GetElements(); + if ( it->more() && it->next()->GetType() != SMDSAbs_Edge ) + it = SMDS_ElemIteratorPtr(); + else + it = smDS->GetElements(); + } + break; + } + } + return it; +} + + //============================================================================= void BLSURFPlugin_Hypothesis::SetPreCADMergeEdges(bool theVal) { @@ -2292,8 +2351,13 @@ std::ostream & BLSURFPlugin_Hypothesis::SaveTo(std::ostream & save) std::ostringstream hpStream; boost::archive::text_oarchive( hpStream ) << _hyperPatchEntriesList; std::string hpString = hpStream.str(); - save << " " << hpString.size() << " " << hpString; + SMESHDS_Hypothesis::SaveString( save, hpString ); + // Enforced meshes + std::ostringstream enfMStream; + boost::archive::text_oarchive( enfMStream ) << _enforcedMeshes; + std::string enfMString = enfMStream.str(); + SMESHDS_Hypothesis::SaveString( save, enfMString ); return save; } @@ -3328,23 +3392,52 @@ std::istream & BLSURFPlugin_Hypothesis::LoadFrom(std::istream & load) } // hyper-patches as entries (issue bos #20543) - if ( static_cast( load >> i ) && i > 0 ) + std::string buffer; + if ( SMESHDS_Hypothesis::LoadString( load, buffer )) { - std::string buffer( i, '\0' ); - load.get( buffer[0] ); // remove a white-space - load.get( & buffer[0], i + 1 ); + std::istringstream istream( buffer.data() ); + boost::archive::text_iarchive archive( istream ); + SMESH_TRY; + archive >> _hyperPatchEntriesList; + SMESH_CATCH( SMESH::printErrorInDebugMode ); + } + // Enforced meshes (issue bos $16292) + buffer.clear(); + if ( SMESHDS_Hypothesis::LoadString( load, buffer )) + { std::istringstream istream( buffer.data() ); boost::archive::text_iarchive archive( istream ); - try { - archive >> _hyperPatchEntriesList; - } - catch (...) {} + SMESH_TRY; + archive >> _enforcedMeshes; + SMESH_CATCH( SMESH::printErrorInDebugMode ); } return load; } +namespace boost { + namespace serialization { + + //======================================================================= + //function : serialize + //purpose : serialize EnforcedMesh + //======================================================================= + + template + void serialize(Archive & ar, BLSURFPlugin_Hypothesis::EnforcedMesh & enfM, + const unsigned int /*version*/) + { + ar & enfM._meshID; + ar & enfM._subID; + ar & enfM._type; + ar & enfM._groupName; + } + + } // namespace serialization +} // namespace boost + + void BLSURFPlugin_Hypothesis::LoadFacesPeriodicity(std::istream & load) { bool isOK = true; diff --git a/src/BLSURFPlugin/BLSURFPlugin_Hypothesis.hxx b/src/BLSURFPlugin/BLSURFPlugin_Hypothesis.hxx index 134a51d..693def6 100644 --- a/src/BLSURFPlugin/BLSURFPlugin_Hypothesis.hxx +++ b/src/BLSURFPlugin/BLSURFPlugin_Hypothesis.hxx @@ -27,20 +27,23 @@ #ifndef _BLSURFPlugin_Hypothesis_HXX_ #define _BLSURFPlugin_Hypothesis_HXX_ -#include "SMESH_Hypothesis.hxx" +#include "BLSURFPlugin_Attractor.hxx" + +#include +#include +#include + #include #include #include -#include #include -#include -#include -#include -#include -#include "BLSURFPlugin_Attractor.hxx" + +class SMESH_Mesh; // Parameters for work of MG-CADSurf +enum EnforcedMeshType { ENFORCED_MESH, ENFORCED_GROUP, ENFORCED_SUBMESH }; + class BLSURFPlugin_Hypothesis: public SMESH_Hypothesis { public: @@ -221,9 +224,9 @@ public: std::string GetTags(); // Hyper-patches - typedef std::set< int > THyperPatchTags; - typedef std::vector< THyperPatchTags > THyperPatchList; - typedef std::set< std::string > THyperPatchEntries; + typedef std::set< int > THyperPatchTags; + typedef std::vector< THyperPatchTags > THyperPatchList; + typedef std::set< std::string > THyperPatchEntries; typedef std::vector< THyperPatchEntries > THyperPatchEntriesList; void SetHyperPatches(const THyperPatchList& hpl, bool notifyMesh=true); @@ -234,6 +237,29 @@ public: const THyperPatchEntriesList& GetHyperPatchEntries() const { return _hyperPatchEntriesList; } static int GetHyperPatchTag( int faceTag, const BLSURFPlugin_Hypothesis* hyp, int* iPatch=0 ); + // Enforced mesh + struct EnforcedMesh + { + int _meshID; // persistent mesh ID + int _subID; // either persistent group ID or sub-shape ID for sub-mesh + EnforcedMeshType _type; /* specify what _subID means: + - nothing for ENFORCED_MESH + - group ID for ENFORCED_GROUP + - sub-shape ID for ENFORCED_SUBMESH */ + std::string _groupName; // name of a group to add mesh edges to + + bool operator==(const EnforcedMesh& em ) const + { + return ( _meshID == em._meshID && _subID == em._subID && + _type == em._type && _groupName == em._groupName ); + } + }; + + void SetEnforcedMeshes( std::vector< EnforcedMesh > & enforcedMeshes ); + const std::vector< EnforcedMesh > & GetEnforcedMeshes() const { return _enforcedMeshes; } + SMDS_ElemIteratorPtr GetEnforcedSegments( const EnforcedMesh& enfMesh, + SMESH_Mesh* & mesh ) const; + void SetPreCADMergeEdges(bool theVal); bool GetPreCADMergeEdges() const { return _preCADMergeEdges; } @@ -647,30 +673,32 @@ private: TSizeMap _attractors; TAttractorMap _classAttractors; - TFaceEntryEnfVertexListMap _faceEntryEnfVertexListMap; - TEnfVertexList _enfVertexList; + TFaceEntryEnfVertexListMap _faceEntryEnfVertexListMap; + TEnfVertexList _enfVertexList; // maps to get "manual" enf vertex (through their coordinates) - TFaceEntryCoordsListMap _faceEntryCoordsListMap; - TCoordsEnfVertexMap _coordsEnfVertexMap; + TFaceEntryCoordsListMap _faceEntryCoordsListMap; + TCoordsEnfVertexMap _coordsEnfVertexMap; // maps to get "geom" enf vertex (through their geom entries) - TFaceEntryEnfVertexEntryListMap _faceEntryEnfVertexEntryListMap; - TEnfVertexEntryEnfVertexMap _enfVertexEntryEnfVertexMap; - TGroupNameNodeIDMap _groupNameNodeIDMap; + TFaceEntryEnfVertexEntryListMap _faceEntryEnfVertexEntryListMap; + TEnfVertexEntryEnfVertexMap _enfVertexEntryEnfVertexMap; + TGroupNameNodeIDMap _groupNameNodeIDMap; // Enable internal enforced vertices on specific face if requested by user // TFaceEntryInternalVerticesList _faceEntryInternalVerticesList; - bool _enforcedInternalVerticesAllFaces; - TEnfGroupName _enforcedInternalVerticesAllFacesGroup; + bool _enforcedInternalVerticesAllFaces; + TEnfGroupName _enforcedInternalVerticesAllFacesGroup; - TPreCadPeriodicityVector _preCadFacesPeriodicityVector; - TPreCadPeriodicityVector _preCadEdgesPeriodicityVector; + TPreCadPeriodicityVector _preCadFacesPeriodicityVector; + TPreCadPeriodicityVector _preCadEdgesPeriodicityVector; + + TFacesPeriodicityVector _facesPeriodicityVector; + TEdgesPeriodicityVector _edgesPeriodicityVector; + TVerticesPeriodicityVector _verticesPeriodicityVector; - TFacesPeriodicityVector _facesPeriodicityVector; - TEdgesPeriodicityVector _edgesPeriodicityVector; - TVerticesPeriodicityVector _verticesPeriodicityVector; + THyperPatchList _hyperPatchList; + THyperPatchEntriesList _hyperPatchEntriesList; - THyperPatchList _hyperPatchList; - THyperPatchEntriesList _hyperPatchEntriesList; + std::vector< EnforcedMesh > _enforcedMeshes; // enforced 1D meshes // Called by SaveTo to store content of _preCadFacesPeriodicityVector and _preCadEdgesPeriodicityVector void SavePreCADPeriodicity(std::ostream & save, const char* shapeType); diff --git a/src/BLSURFPlugin/BLSURFPlugin_Hypothesis_i.cxx b/src/BLSURFPlugin/BLSURFPlugin_Hypothesis_i.cxx index fe72d2e..5a90eb0 100644 --- a/src/BLSURFPlugin/BLSURFPlugin_Hypothesis_i.cxx +++ b/src/BLSURFPlugin/BLSURFPlugin_Hypothesis_i.cxx @@ -28,6 +28,7 @@ #include #include +#include #include #include @@ -40,6 +41,142 @@ using namespace std; +namespace +{ + //================================================================================ + /*! + * \brief Return persistent ID of a mesh + * \param [in] mesh - the mesh + * \return int - -1 in case of failure + */ + //================================================================================ + + int GetMeshPersistentId( SMESH::SMESH_Mesh_ptr mesh ) + { + int id = -1; + if ( SMESH_Mesh_i* mesh_i = SMESH::DownCast( mesh )) + id = mesh_i->GetImpl().GetMeshDS()->GetPersistentId(); + return id; + } + + //================================================================================ + /*! + * \brief Return persistent ID of a group or sub-mesh + * \param [in] meshPart - the mesh part + * \param [out] isGroup - return true if meshPart is a group + * \return int - -1 in case if meshPart is neither a group nor a sub-mesh + */ + //================================================================================ + + int GetMeshPartPersistentId( SMESH::SMESH_IDSource_ptr meshPart, bool & isGroup ) + { + int id = -1; + isGroup = false; + SMESH_GroupBase_i* group_i = SMESH::DownCast( meshPart ); + if ( group_i ) + { + id = group_i->GetLocalID(); + isGroup = true; + } + else + { + SMESH::SMESH_subMesh_var subMesh = SMESH::SMESH_subMesh::_narrow( meshPart ); + if ( !subMesh->_is_nil() ) + id = subMesh->GetId(); + } + return id; + } + + //================================================================================ + /*! + * \brief Find a mesh in the study by mesh persistent ID + */ + //================================================================================ + + SMESH::SMESH_Mesh_ptr FindMeshByID( int theMeshID ) + { + SMESH::SMESH_Mesh_var mesh; + + SMESH_Gen_i* gen = SMESH_Gen_i::GetSMESHGen(); + CORBA::String_var compDataType = gen->ComponentDataType(); + SALOMEDS::Study_var aStudy = gen->getStudyServant(); + SALOMEDS::SComponent_wrap genSO = aStudy->FindComponent( compDataType.in() ); + if ( !genSO->_is_nil() ) + { + SALOMEDS::ChildIterator_wrap anIter = aStudy->NewChildIterator( genSO ); + for ( ; anIter->More(); anIter->Next() ) + { + SALOMEDS::SObject_wrap so = anIter->Value(); + CORBA::Object_var obj = gen->SObjectToObject( so ); + mesh = SMESH::SMESH_Mesh::_narrow( obj ); + if ( !mesh->_is_nil() && GetMeshPersistentId( mesh ) == theMeshID ) + break; + mesh = SMESH::SMESH_Mesh::_nil(); + } + } + return mesh._retn(); + } + + //================================================================================ + /*! + * \brief Return a group by its ID + */ + //================================================================================ + + SMESH::SMESH_GroupBase_ptr GetGroupByID( SMESH::SMESH_Mesh_ptr mesh, int ID ) + { + SMESH::SMESH_GroupBase_var group; + if ( !CORBA::is_nil( mesh )) + { + SMESH::ListOfGroups_var groups = mesh->GetGroups(); + for ( CORBA::ULong i = 0; i < groups->length(); ++i ) + if ( SMESH_GroupBase_i* group_i = SMESH::DownCast( groups[i] )) + if ( group_i->GetLocalID() == ID ) + { + group = SMESH::SMESH_GroupBase::_narrow( groups[i] ); + break; + } + } + return group._retn(); + } + + //================================================================================ + /*! + * \brief Return a sub-mesh by sub-shape ID + */ + //================================================================================ + + SMESH::SMESH_subMesh_ptr GetSubMeshByID( SMESH::SMESH_Mesh_ptr mesh, + const int shapeID, + CORBA::Long subMeshTag ) + { + SMESH::SMESH_subMesh_var subMesh; + if ( !CORBA::is_nil( mesh )) + { + SMESH_Gen_i* gen = SMESH_Gen_i::GetSMESHGen(); + SALOMEDS::SObject_wrap meshSO = gen->ObjectToSObject( mesh ); + SALOMEDS::Study_var aStudy = gen->getStudyServant(); + SALOMEDS::SObject_wrap subMeshRootSO; + if ( !meshSO->_is_nil() && meshSO->FindSubObject( subMeshTag, subMeshRootSO.inout() )) + { + SALOMEDS::ChildIterator_wrap anIter = aStudy->NewChildIterator( subMeshRootSO ); + for ( ; anIter->More(); anIter->Next() ) + { + SALOMEDS::SObject_wrap so = anIter->Value(); + CORBA::Object_var obj = gen->SObjectToObject( so ); + subMesh = SMESH::SMESH_subMesh::_narrow( obj ); + if ( !subMesh->_is_nil() && subMesh->GetId() == shapeID ) + break; + subMesh = SMESH::SMESH_subMesh::_nil(); + } + } + return subMesh._retn(); + } + return subMesh._retn(); + } + +} // namespace + //============================================================================= /*! * BLSURFPlugin_Hypothesis_i::BLSURFPlugin_Hypothesis_i @@ -921,6 +1058,104 @@ CORBA::Short BLSURFPlugin_Hypothesis_i::GetVerbosity() { return (CORBA::Short) this->GetImpl()->GetVerbosity(); } + +//============================================================================= +void BLSURFPlugin_Hypothesis_i::SetEnforcedMeshes(const BLSURFPlugin::EnforcedMeshesList& theMeshes ) +{ + std::vector< ::BLSURFPlugin_Hypothesis::EnforcedMesh > enforcedMeshes; + for ( CORBA::ULong i = 0; i < theMeshes.length(); ++i ) + { + const BLSURFPlugin::MG_EnforcedMesh1D & inEM = theMeshes[ i ]; + if ( CORBA::is_nil( inEM.mesh )) + THROW_SALOME_CORBA_EXCEPTION( "NULL enforced mesh",SALOME::BAD_PARAM ); + + SMESH::SMESH_Mesh_var mesh = inEM.mesh->GetMesh(); + if ( CORBA::is_nil( mesh )) + THROW_SALOME_CORBA_EXCEPTION( "BAD enforced mesh",SALOME::BAD_PARAM ); + + int meshID = GetMeshPersistentId( mesh ); + if ( meshID < 0 ) + THROW_SALOME_CORBA_EXCEPTION( "BAD enforced mesh",SALOME::BAD_PARAM ); + + bool isGroup = false; + int partID = GetMeshPartPersistentId( inEM.mesh, isGroup ); + ::EnforcedMeshType partType = ENFORCED_MESH; + if ( partID > -1 ) + partType = isGroup ? ENFORCED_GROUP : ENFORCED_SUBMESH; + + enforcedMeshes.push_back({ meshID, partID, partType, inEM.groupName.in() }); + } + + this->GetImpl()->SetEnforcedMeshes( enforcedMeshes ); + + // dump + + SMESH::TPythonDump pyDump; + pyDump << BLSURFPlugin::BLSURFPlugin_Hypothesis_var( _this() ) + << ".SetEnforcedMeshes([ "; + + for ( CORBA::ULong i = 0; i < theMeshes.length(); ++i ) + { + const BLSURFPlugin::MG_EnforcedMesh1D & inEM = theMeshes[ i ]; + pyDump << "BLSURFPlugin.MG_EnforcedMesh1D( " << inEM.mesh.in() << ", "; + if ( inEM.groupName.in() && inEM.groupName.in()[0] ) + pyDump << "'" << inEM.groupName.in() << "'"; + else + pyDump << "''"; + pyDump << ")" << ( i + 1 < theMeshes.length() ? ", " : "])"); + } +} + +//============================================================================= + +BLSURFPlugin::EnforcedMeshesList* BLSURFPlugin_Hypothesis_i::GetEnforcedMeshes() +{ + const std::vector< ::BLSURFPlugin_Hypothesis::EnforcedMesh > & hypEnfMeshes = + this->GetImpl()->GetEnforcedMeshes(); + + BLSURFPlugin::EnforcedMeshesList_var outEnfMeshes = new BLSURFPlugin::EnforcedMeshesList(); + outEnfMeshes->length( hypEnfMeshes.size() ); + + int nbMeshes = 0; + for ( size_t i = 0; i < hypEnfMeshes.size(); ++i ) + { + const ::BLSURFPlugin_Hypothesis::EnforcedMesh& enfMeshData = hypEnfMeshes[ i ]; + BLSURFPlugin::MG_EnforcedMesh1D & outEnfMesh = outEnfMeshes[ nbMeshes ]; + + SMESH::SMESH_Mesh_var mesh = FindMeshByID( enfMeshData._meshID ); + switch ( enfMeshData._type ) { + case ENFORCED_MESH : + { + outEnfMesh.mesh = SMESH::SMESH_IDSource::_narrow( mesh ); + break; + } + case ENFORCED_GROUP : + { + SMESH::SMESH_GroupBase_var group = GetGroupByID( mesh, enfMeshData._subID ); + outEnfMesh.mesh = SMESH::SMESH_IDSource::_narrow( group ); + break; + } + case ENFORCED_SUBMESH: + { + SMESH::SMESH_subMesh_var subMesh; + subMesh = GetSubMeshByID( mesh, enfMeshData._subID, SMESH::Tag_SubMeshOnEdge ); + if ( CORBA::is_nil( subMesh )) + subMesh = GetSubMeshByID( mesh, enfMeshData._subID, SMESH::Tag_SubMeshOnCompound ); + + outEnfMesh.mesh = SMESH::SMESH_IDSource::_narrow( subMesh ); + break; + } + default: continue; + } + outEnfMesh.groupName = enfMeshData._groupName.c_str(); + + nbMeshes += ( !CORBA::is_nil( outEnfMesh.mesh )); + } + outEnfMeshes->length( nbMeshes ); + + return outEnfMeshes._retn(); +} + //============================================================================= void BLSURFPlugin_Hypothesis_i::SetEnforceCadEdgesSize( CORBA::Boolean toEnforce ) { diff --git a/src/BLSURFPlugin/BLSURFPlugin_Hypothesis_i.hxx b/src/BLSURFPlugin/BLSURFPlugin_Hypothesis_i.hxx index 5b6c749..00f3bed 100644 --- a/src/BLSURFPlugin/BLSURFPlugin_Hypothesis_i.hxx +++ b/src/BLSURFPlugin/BLSURFPlugin_Hypothesis_i.hxx @@ -173,6 +173,12 @@ public: void SetVerbosity(CORBA::Short theVal); CORBA::Short GetVerbosity(); + /*! + * Set/Get enforced 1D meshes + */ + void SetEnforcedMeshes( const BLSURFPlugin::EnforcedMeshesList& enforcedMeshes ); + BLSURFPlugin::EnforcedMeshesList* GetEnforcedMeshes(); + void SetEnforceCadEdgesSize( CORBA::Boolean toEnforce ); CORBA::Boolean GetEnforceCadEdgesSize(); diff --git a/src/BLSURFPlugin/CMakeLists.txt b/src/BLSURFPlugin/CMakeLists.txt index 62d0fc4..a58e725 100644 --- a/src/BLSURFPlugin/CMakeLists.txt +++ b/src/BLSURFPlugin/CMakeLists.txt @@ -73,6 +73,7 @@ SET(BLSURFEngine_HEADERS BLSURFPlugin_Hypothesis.hxx BLSURFPlugin_Hypothesis_i.hxx BLSURFPlugin_Attractor.hxx + BLSURFPlugin_EnforcedMesh1D.hxx ) # --- sources --- @@ -85,6 +86,7 @@ SET(BLSURFEngine_SOURCES BLSURFPlugin_Hypothesis_i.cxx BLSURFPlugin_i.cxx BLSURFPlugin_Attractor.cxx + BLSURFPlugin_EnforcedMesh1D.cxx ) # --- scripts --- diff --git a/src/GUI/BLSURFPluginGUI_HypothesisCreator.cxx b/src/GUI/BLSURFPluginGUI_HypothesisCreator.cxx index c21e967..7e0870a 100644 --- a/src/GUI/BLSURFPluginGUI_HypothesisCreator.cxx +++ b/src/GUI/BLSURFPluginGUI_HypothesisCreator.cxx @@ -83,7 +83,8 @@ enum { STD_TAB = 0, ADV_TAB, SMP_TAB, - ENF_TAB, + ENF_V_TAB, + ENF_M_TAB, PERIODICITY_TAB, HYPERPATCH_TAB, SMP_NAME_COLUMN =0, @@ -104,7 +105,11 @@ enum { ENF_VER_ENTRY_COLUMN, ENF_VER_GROUP_COLUMN, ENF_VER_NB_COLUMNS, -// Periodicity + + // Enforced 1D meshes + ENF_MESH_NB_COLUMNS = 2, + + // Periodicity PERIODICITY_OBJ_SOURCE_COLUMN = 0, PERIODICITY_OBJ_TARGET_COLUMN, PERIODICITY_P1_SOURCE_COLUMN, @@ -713,39 +718,39 @@ QFrame* BLSURFPluginGUI_HypothesisCreator::buildFrame() lay->addWidget( myTabWidget ); myName = 0; - + // basic parameters myStdGroup = new QWidget(); QGridLayout* aStdLayout = new QGridLayout( myStdGroup ); aStdLayout->setSpacing( 6 ); aStdLayout->setMargin( 11 ); - + if( isCreation() ) myName = new QLineEdit( myStdGroup ); myStdWidget = new BLSURFPluginGUI_StdWidget(myStdGroup); if ( !hasGeom() ) { myStdWidget->myPhysicalMesh->removeItem( PhysicalLocalSize ); } - + int row = 0; if( isCreation() ) { aStdLayout->addWidget( new QLabel( tr( "SMESH_NAME" ), myStdGroup ), 0, 0, 1, 1 ); aStdLayout->addWidget( myName, row++, 1, 1, 3 ); } aStdLayout->addWidget( myStdWidget, row++, 0, 1, 4 ); - + row = 0; if( isCreation() ) row = 1; aStdLayout->setRowStretch(row,1); aStdLayout->setColumnStretch(1,1); - + // advanced parameters myAdvGroup = new QWidget(); QGridLayout* anAdvLayout = new QGridLayout( myAdvGroup ); anAdvLayout->setSpacing( 6 ); - anAdvLayout->setMargin( 11 ); + anAdvLayout->setMargin( 11 ); myAdvWidget = new BLSURFPluginGUI_AdvWidget(myAdvGroup); anAdvLayout->addWidget( myAdvWidget ); @@ -756,7 +761,7 @@ QFrame* BLSURFPluginGUI_HypothesisCreator::buildFrame() //Layout QGridLayout* anSmpLayout = new QGridLayout(mySmpGroup); - + // Table mySizeMapTable = new QTreeWidget( mySmpGroup ); mySizeMapTable ->setMinimumWidth(200); @@ -951,7 +956,7 @@ QFrame* BLSURFPluginGUI_HypothesisCreator::buildFrame() anEnfLayout->addWidget(myEnforcedTreeWidget, 0, 0, ENF_VER_NB_LINES, 1); QGridLayout* anEnfLayout2 = new QGridLayout(myEnfGroup); -// FACE AND VERTEX SELECTION + // FACE AND VERTEX SELECTION //anEnfLayout2->addWidget(myEnfFaceWdg, ENF_VER_FACE, 0, 1, 2); anEnfLayout2->addWidget(myEnfVertexWdg, ENF_VER_VERTEX, 0, 1, 2); anEnfLayout2->addWidget(myXCoordLabel, ENF_VER_X_COORD, 0, 1, 1); @@ -970,6 +975,56 @@ QFrame* BLSURFPluginGUI_HypothesisCreator::buildFrame() anEnfLayout2->setRowStretch(ENF_VER_NB_LINES+1, 1); anEnfLayout->addLayout(anEnfLayout2, 0,1,ENF_VER_NB_LINES+1,2); + // --------------------------- + // Enforced meshes parameters + // --------------------------- + + myEnfMeshGroup = new QWidget(); + QGridLayout* anEnfMeshLayout = new QGridLayout(myEnfMeshGroup); + + myEnfMeshTableWdg = new QTableWidget(myEnfGroup); + //myEnfMeshTableWdg->setRowCount( 0 ); + myEnfMeshTableWdg->setColumnCount( ENF_MESH_NB_COLUMNS ); + myEnfMeshTableWdg->setSortingEnabled(true); + myEnfMeshTableWdg->verticalHeader()->hide(); + myEnfMeshTableWdg->setHorizontalHeaderLabels( QStringList() + << tr( "ENF_NAME_COLUMN" ) + << tr( "ENF_GROUP_COLUMN" )); + myEnfMeshTableWdg->horizontalHeader()->setStretchLastSection(true); + myEnfMeshTableWdg->horizontalHeader()->setSectionResizeMode(QHeaderView::Interactive); + myEnfMeshTableWdg->setAlternatingRowColors(true); + myEnfMeshTableWdg->setSelectionMode(QAbstractItemView::ExtendedSelection); + myEnfMeshTableWdg->setSelectionBehavior(QAbstractItemView::SelectItems); + myEnfMeshTableWdg->resizeColumnsToContents(); + //myEnfMeshTableWdg->setItemDelegate(new EnforcedMeshTableWidgetDelegate()); + + myEnfMeshWdg = new StdMeshersGUI_ObjectReferenceParamWdg( SMESH::IDSOURCE_EDGE, myEnfMeshGroup, /*multiSel=*/false); + myEnfMeshWdg->SetDefaultText(tr("ENF_SELECT_MESH"), "QLineEdit { color: grey }"); + + myEnfMeshWdg->AvoidSimultaneousSelection(myEnfVertexWdg); + myEnfMeshWdg->AvoidSimultaneousSelection(myGeomSelWdg1); + myEnfMeshWdg->AvoidSimultaneousSelection(myGeomSelWdg2); + myEnfMeshWdg->AvoidSimultaneousSelection(myAttSelWdg); + + QLabel* enforcedGroupNameLabel = new QLabel( tr( "ENF_GROUP_LABEL" ), myEnfMeshGroup ); + myEnforcedGroupName = new QLineEdit(myEnfMeshGroup); + + myAddEnfMeshButton = new QPushButton(tr("ENF_ADD"),myEnfMeshGroup); + myRemoveEnfMeshButton = new QPushButton(tr("ENF_REMOVE"),myEnfMeshGroup); + + QGridLayout* anEnfMeshLayout2 = new QGridLayout(myEnfMeshGroup); + anEnfMeshLayout2->addWidget(myEnfMeshWdg, 0, 0, 1, 2); + anEnfMeshLayout2->addWidget(enforcedGroupNameLabel, 1, 0, 1, 1); + anEnfMeshLayout2->addWidget(myEnforcedGroupName, 1, 1, 1, 1); + anEnfMeshLayout2->addWidget(myAddEnfMeshButton, 2, 0, 1, 2); + anEnfMeshLayout2->addWidget(myRemoveEnfMeshButton, 3, 0, 1, 2); + anEnfMeshLayout2->setRowStretch( 4, 1 ); + + anEnfMeshLayout->addWidget(myEnfMeshTableWdg, 0, 0, 5, 1); + anEnfMeshLayout->addLayout(anEnfMeshLayout2, 0, 1, 1, 1); + anEnfMeshLayout->setRowStretch( 2, 1 ); + + // --- // Periodicity parameters myPeriodicityGroup = new QWidget( dlg() ); @@ -1200,7 +1255,8 @@ QFrame* BLSURFPluginGUI_HypothesisCreator::buildFrame() myTabWidget->insertTab( ADV_TAB, myAdvGroup, tr( "BLSURF_ADV_ARGS" ) ); if ( hasGeom() ) { myTabWidget->insertTab( SMP_TAB, mySmpGroup, tr( "LOCAL_SIZE" ) ); - myTabWidget->insertTab( ENF_TAB, myEnfGroup, tr( "BLSURF_ENF_VER" ) ); + myTabWidget->insertTab( ENF_V_TAB, myEnfGroup, tr( "BLSURF_ENF_VER" ) ); + myTabWidget->insertTab( ENF_M_TAB, myEnfMeshGroup, tr( "ENF_MESH" ) ); myTabWidget->insertTab( PERIODICITY_TAB, myPeriodicityGroup, tr( "BLSURF_PERIODICITY" ) ); myTabWidget->insertTab( HYPERPATCH_TAB, hpGroup, tr( "BLSURF_HYPERPATCH_TAB" )); } @@ -1208,47 +1264,55 @@ QFrame* BLSURFPluginGUI_HypothesisCreator::buildFrame() { mySmpGroup->hide(); myEnfGroup->hide(); + myEnfMeshGroup->hide(); myPeriodicityGroup->hide(); hpGroup->hide(); } myTabWidget->setCurrentIndex( STD_TAB ); - connect( myAdvWidget->addBtn, SIGNAL( clicked() ), this, SLOT( onAddOption() ) ); + connect( myAdvWidget->addBtn, SIGNAL( clicked() ), SLOT( onAddOption() ) ); // Size Maps - connect( addMapButton, SIGNAL( clicked()), this, SLOT( onAddMap() ) ); - connect( removeMapButton, SIGNAL( clicked()), this, SLOT( onRemoveMap() ) ); - connect( modifyMapButton, SIGNAL( clicked()), this, SLOT( onModifyMap() ) ); - connect( mySizeMapTable, SIGNAL( itemClicked (QTreeWidgetItem *, int)),this, SLOT( onSmpItemClicked(QTreeWidgetItem *, int) ) ); - connect( myGeomSelWdg2, SIGNAL( contentModified() ), this, SLOT( onMapGeomContentModified() ) ); - connect( myGeomSelWdg1, SIGNAL( contentModified() ), this, SLOT( onMapGeomContentModified() ) ); - connect( myAttSelWdg, SIGNAL( contentModified() ), this, SLOT( onMapGeomContentModified() ) ); - connect( mySizeMapTable, SIGNAL( itemChanged (QTreeWidgetItem *, int)),this, SLOT( onSetSizeMap(QTreeWidgetItem *, int) ) ); - connect( myAttractorCheck, SIGNAL( stateChanged ( int )), this, SLOT( onAttractorClicked( int ) ) ); - connect( myConstSizeCheck, SIGNAL( stateChanged ( int )), this, SLOT( onConstSizeClicked( int ) ) ); - connect( smpTab, SIGNAL( currentChanged ( int )), this, SLOT( onTabChanged( int ) ) ); - connect( myTabWidget, SIGNAL( currentChanged ( int )), this, SLOT( onTabChanged( int ) ) ); + connect( addMapButton, SIGNAL( clicked()), SLOT( onAddMap() ) ); + connect( removeMapButton, SIGNAL( clicked()), SLOT( onRemoveMap() ) ); + connect( modifyMapButton, SIGNAL( clicked()), SLOT( onModifyMap() ) ); + connect( mySizeMapTable, SIGNAL( itemClicked (QTreeWidgetItem *, int)), SLOT( onSmpItemClicked(QTreeWidgetItem *, int) ) ); + connect( myGeomSelWdg2, SIGNAL( contentModified() ), SLOT( onMapGeomContentModified() ) ); + connect( myGeomSelWdg1, SIGNAL( contentModified() ), SLOT( onMapGeomContentModified() ) ); + connect( myAttSelWdg, SIGNAL( contentModified() ), SLOT( onMapGeomContentModified() ) ); + connect( mySizeMapTable, SIGNAL( itemChanged (QTreeWidgetItem *, int)), SLOT( onSetSizeMap(QTreeWidgetItem *, int) ) ); + connect( myAttractorCheck, SIGNAL( stateChanged ( int )), SLOT( onAttractorClicked( int ) ) ); + connect( myConstSizeCheck, SIGNAL( stateChanged ( int )), SLOT( onConstSizeClicked( int ) ) ); + connect( smpTab, SIGNAL( currentChanged ( int )), SLOT( onTabChanged( int ) ) ); + connect( myTabWidget, SIGNAL( currentChanged ( int )), SLOT( onTabChanged( int ) ) ); // Enforced vertices - connect( myEnforcedTreeWidget,SIGNAL( itemClicked(QTreeWidgetItem *, int)), this, SLOT( synchronizeCoords() ) ); - connect( myEnforcedTreeWidget,SIGNAL( itemChanged(QTreeWidgetItem *, int)), this, SLOT( updateEnforcedVertexValues(QTreeWidgetItem *, int) ) ); - connect( myEnforcedTreeWidget,SIGNAL( itemSelectionChanged() ), this, SLOT( synchronizeCoords() ) ); - connect( addVertexButton, SIGNAL( clicked()), this, SLOT( onAddEnforcedVertices() ) ); - connect( removeVertexButton, SIGNAL( clicked()), this, SLOT( onRemoveEnforcedVertex() ) ); - connect( myEnfVertexWdg, SIGNAL( contentModified()), this, SLOT( onSelectEnforcedVertex() ) ); - connect( myInternalEnforcedVerticesAllFaces, SIGNAL( stateChanged ( int )), this, SLOT( onInternalVerticesClicked( int ) ) ); + connect( myEnforcedTreeWidget,SIGNAL( itemClicked(QTreeWidgetItem *, int)), SLOT( synchronizeCoords() ) ); + connect( myEnforcedTreeWidget,SIGNAL( itemChanged(QTreeWidgetItem *, int)), SLOT( updateEnforcedVertexValues(QTreeWidgetItem *, int) ) ); + connect( myEnforcedTreeWidget,SIGNAL( itemSelectionChanged() ), SLOT( synchronizeCoords() ) ); + connect( addVertexButton, SIGNAL( clicked()), SLOT( onAddEnforcedVertices() ) ); + connect( removeVertexButton, SIGNAL( clicked()), SLOT( onRemoveEnforcedVertex() ) ); + connect( myEnfVertexWdg, SIGNAL( contentModified()), SLOT( onSelectEnforcedVertex() ) ); + connect( myInternalEnforcedVerticesAllFaces, SIGNAL( stateChanged ( int )), SLOT( onInternalVerticesClicked( int ) ) ); + + // Enforced mesh + connect( myAddEnfMeshButton, SIGNAL( clicked()), SLOT( onAddEnforcedMesh())); + connect( myRemoveEnfMeshButton, SIGNAL( clicked()), SLOT( onRemoveEnforcedMesh())); + connect( myEnfMeshWdg, SIGNAL( contentModified()), SLOT( onEnforcedMeshSelected())); + connect( myEnfMeshTableWdg, SIGNAL( itemSelectionChanged()), SLOT( onEnfMeshTableSelected())); + // Periodicity - connect( myPeriodicityAddButton, SIGNAL( clicked()), this, SLOT( onAddPeriodicity() ) ); - connect( myPeriodicityRemoveButton, SIGNAL( clicked()), this, SLOT( onRemovePeriodicity() ) ); - connect( myPeriodicityTreeWidget, SIGNAL( itemClicked(QTreeWidgetItem*, int)), this, SLOT( onPeriodicityTreeClicked(QTreeWidgetItem *, int) ) ); - connect( myPeriodicityGroupBox2, SIGNAL(toggled(bool)), this, SLOT(onPeriodicityByVerticesChecked(bool))); + connect( myPeriodicityAddButton, SIGNAL( clicked()), SLOT( onAddPeriodicity() ) ); + connect( myPeriodicityRemoveButton, SIGNAL( clicked()), SLOT( onRemovePeriodicity() ) ); + connect( myPeriodicityTreeWidget, SIGNAL( itemClicked(QTreeWidgetItem*, int)), SLOT( onPeriodicityTreeClicked(QTreeWidgetItem *, int) ) ); + connect( myPeriodicityGroupBox2, SIGNAL(toggled(bool)), SLOT(onPeriodicityByVerticesChecked(bool))); ListOfWidgets::const_iterator anIt = myPeriodicitySelectionWidgets.begin(); for (; anIt != myPeriodicitySelectionWidgets.end(); anIt++) { StdMeshersGUI_ObjectReferenceParamWdg * w1 = ( StdMeshersGUI_ObjectReferenceParamWdg* ) ( *anIt ); - connect( w1, SIGNAL(contentModified ()), this, SLOT(onPeriodicityContentModified())); + connect( w1, SIGNAL( contentModified ()), SLOT( onPeriodicityContentModified() )); } @@ -2025,6 +2089,7 @@ void BLSURFPluginGUI_HypothesisCreator::retrieveParams() const } // Hyper patches + QString patchEntries; for ( int i = 0; i < data.hyperpatches.size(); ++i ) { @@ -2036,6 +2101,18 @@ void BLSURFPluginGUI_HypothesisCreator::retrieveParams() const that->myStdWidget->onPhysicalMeshChanged(); that->myStdWidget->onGeometricMeshChanged(); that->onStateChange(); + + // Enforced mesh + + BLSURFPlugin::BLSURFPlugin_Hypothesis_var h = + BLSURFPlugin::BLSURFPlugin_Hypothesis::_narrow( initParamsHypothesis() ); + + BLSURFPlugin::EnforcedMeshesList_var enfMeshes = h->GetEnforcedMeshes(); + for ( CORBA::ULong i = 0; i < enfMeshes->length(); ++i ) + { + BLSURFPlugin::MG_EnforcedMesh1D & enfMesh = enfMeshes[i]; + that->addEnforcedMesh( enfMesh.mesh.in(), enfMesh.groupName.in() ); + } } /** BLSURFPluginGUI_HypothesisCreator::storeParams() @@ -2589,6 +2666,31 @@ bool BLSURFPluginGUI_HypothesisCreator::storeParamsToHypo( const BlsurfHypothesi h->SetHyperPatches( hpl ); + // Enforced meshes + BLSURFPlugin::EnforcedMeshesList_var enfMeshesList = new BLSURFPlugin::EnforcedMeshesList(); + enfMeshesList->length( myEnfMeshTableWdg->rowCount() ); + + int nbMeshes = 0; + for ( int row = 0, nbRow = myEnfMeshTableWdg->rowCount(); row < nbRow; ++row ) + { + QTableWidgetItem * meshCell = myEnfMeshTableWdg->item( row, 0 ); + QString entry = meshCell->data( Qt::UserRole ).toString(); + QTableWidgetItem * groupCell = myEnfMeshTableWdg->item( row, 1 ); + QString groupName = groupCell->text(); + + SMESH::SMESH_IDSource_var mesh = SMESH::EntryToInterface< SMESH::SMESH_IDSource >( entry ); + if ( !mesh->_is_nil() ) + { + enfMeshesList[ nbMeshes ].mesh = SMESH::SMESH_IDSource::_duplicate( mesh ); + enfMeshesList[ nbMeshes ].groupName = CORBA::string_dup( groupName.toStdString().c_str() ); + ++nbMeshes; + } + } + enfMeshesList->length( nbMeshes ); + + h->SetEnforcedMeshes( enfMeshesList ); + + } // try catch(...) { ok = false; @@ -2898,6 +3000,7 @@ void BLSURFPluginGUI_HypothesisCreator::onTabChanged(int tab) myPeriodicityP1TargetWdg ->deactivateSelection(); myPeriodicityP2TargetWdg ->deactivateSelection(); myPeriodicityP3TargetWdg ->deactivateSelection(); + myEnfMeshWdg ->deactivateSelection(); if ( myHyPatchFaceSelBtn->isChecked() ) myHyPatchFaceSelBtn->toggle(); if ( myHyPatchGroupSelBtn->isChecked() ) @@ -2934,6 +3037,15 @@ void BLSURFPluginGUI_HypothesisCreator::onTabChanged(int tab) mySmpSizeSpin->RangeStepAndValidator(minSize, maxSize, 1.0, "length_precision"); myAttSizeSpin->RangeStepAndValidator(minSize, maxSize, 1.0, "length_precision"); } + + if ( tab == ENF_M_TAB ) + { + myEnfMeshWdg->activateSelection(); + onEnforcedMeshSelected(); // update buttons + onEnfMeshTableSelected(); + if ( myEnforcedGroupName->text().isEmpty() ) + myEnforcedGroupName->setText("Group 1D"); + } } void BLSURFPluginGUI_HypothesisCreator::onAttractorClicked(int state) @@ -3573,6 +3685,153 @@ void BLSURFPluginGUI_HypothesisCreator::onHyPatchRemove() } } +//================================================================================ +/*! + * \brief Add a new row in Enforced mesh table + */ +//================================================================================ + +void BLSURFPluginGUI_HypothesisCreator::addEnforcedMesh( SMESH::SMESH_IDSource_ptr mesh, + const QString& groupName ) +{ + _PTR(SObject) sobj = SMESH::FindSObject( mesh ); + if ( !sobj ) + return; + + QString meshEntry = sobj->GetID().c_str(); + QString meshName = sobj->GetName().c_str(); + + QTableWidgetItem* meshCell = new QTableWidgetItem( meshName ); + meshCell->setData( Qt::UserRole, meshEntry ); + meshCell->setFlags( Qt::ItemIsSelectable | Qt::ItemIsEnabled ); + + QTableWidgetItem* groupCell = new QTableWidgetItem( groupName ); + groupCell->setFlags( Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable ); + + int row = myEnfMeshTableWdg->rowCount(); + myEnfMeshTableWdg->insertRow( row ); + myEnfMeshTableWdg->setItem( row, 0, meshCell ); + myEnfMeshTableWdg->setItem( row, 1, groupCell ); + + myEnfMeshTableWdg->resizeColumnToContents( 0 ); + myEnfMeshTableWdg->resizeColumnToContents( 1 ); +} + +//================================================================================ +/*! + * \brief SLOT called when [Add] is clicked in Enforced mesh tab. + * Add an item to the enforced meshes table + */ +//================================================================================ + +void BLSURFPluginGUI_HypothesisCreator::onAddEnforcedMesh() +{ + if ( myEnfMeshWdg->NbObjects() != 1 ) + return; + + SMESH::SMESH_IDSource_var mesh = myEnfMeshWdg->GetObject< SMESH::SMESH_IDSource >(); + QString groupName = myEnforcedGroupName->text().simplified(); + + addEnforcedMesh( mesh, groupName ); + + selectionMgr()->clearSelected(); + myEnfMeshWdg->SetObject( SMESH::SMESH_IDSource::_nil() ); +} + +//================================================================================ +/*! + * \brief SLOT called when [Remove] is clicked in Enforced mesh tab. + * Remove a selected mesh from the enforced meshes table + */ +//================================================================================ + +void BLSURFPluginGUI_HypothesisCreator::onRemoveEnforcedMesh() +{ + QList selectedRows; + QList selectedItems = myEnfMeshTableWdg->selectedItems(); + QTableWidgetItem* item; + int row; + foreach( item, selectedItems ) + { + row = item->row(); + if (!selectedRows.contains( row ) ) + selectedRows.append(row); + } + + qSort( selectedRows ); + QListIterator it( selectedRows ); + it.toBack(); + while ( it.hasPrevious() ) { + row = it.previous(); + myEnfMeshTableWdg->removeRow(row ); + } + + myEnfMeshTableWdg->selectionModel()->clearSelection(); + + onEnforcedMeshSelected(); // to activate [Add] if possible +} + +//================================================================================ +/*! + * \brief SLOT called when mesh selection changes. Enable/disable [Add] button + */ +//================================================================================ + +void BLSURFPluginGUI_HypothesisCreator::onEnforcedMeshSelected() +{ + bool enable = ( myEnfMeshWdg->NbObjects() == 1 ); + if ( enable ) + { + // check if a selected mesh contains segments + SMESH::SMESH_IDSource_var mesh = myEnfMeshWdg->GetObject< SMESH::SMESH_IDSource >(); + if (( enable = !mesh->_is_nil() )) + { + SMESH::array_of_ElementType_var types = mesh->GetTypes(); + if (( enable = ( types->length() > 0 ))) + { + enable = false; + for ( CORBA::ULong i = 0; i < types->length() && !enable; ++i ) + enable = ( types[ i ] = SMESH::EDGE ); + } + } + + // check if this mesh is already in the table + if ( enable ) + { + _PTR(SObject) sobj = SMESH::FindSObject( mesh ); + if (( enable = bool( sobj ))) + { + QString meshEntry = sobj->GetID().c_str(); + for ( int row = 0, nbRow = myEnfMeshTableWdg->rowCount(); row < nbRow && enable; ++row ) + { + QTableWidgetItem * cell = myEnfMeshTableWdg->item( row, 0 ); + enable = ( meshEntry != cell->data( Qt::UserRole ).toString() ); + } + } + } + } + myAddEnfMeshButton->setEnabled( enable ); +} + +//================================================================================ +/*! + * \brief SLOT called when selection changes in the table. Enable/disable [Remove] button + */ +//================================================================================ + +void BLSURFPluginGUI_HypothesisCreator::onEnfMeshTableSelected() +{ + bool enable = !myEnfMeshTableWdg->selectedItems().empty(); + + myRemoveEnfMeshButton->setEnabled( enable ); +} + +//================================================================================ +/*! + * \brief Return false if algorithm is a re-mesher + */ +//================================================================================ + bool BLSURFPluginGUI_HypothesisCreator::hasGeom() const { return hypType() == BLSURFPlugin_Hypothesis::GetHypType(true); diff --git a/src/GUI/BLSURFPluginGUI_HypothesisCreator.h b/src/GUI/BLSURFPluginGUI_HypothesisCreator.h index 0f5788e..1ae9ef4 100644 --- a/src/GUI/BLSURFPluginGUI_HypothesisCreator.h +++ b/src/GUI/BLSURFPluginGUI_HypothesisCreator.h @@ -242,6 +242,11 @@ protected slots: void onSelectEnforcedVertex(); void clearEnforcedVertexWidgets(); void onInternalVerticesClicked(int); + // Enforced mesh tab + void onAddEnforcedMesh(); + void onRemoveEnforcedMesh(); + void onEnforcedMeshSelected(); + void onEnfMeshTableSelected(); // Periodicity tab void onPeriodicityByVerticesChecked(bool); void onAddPeriodicity(); @@ -274,6 +279,8 @@ private: void addHyPatchToTable(const QString& tags, const QString& entries); bool hasGeom() const; + void addEnforcedMesh( SMESH::SMESH_IDSource_ptr mesh, const QString& groupName ); + private: QTabWidget* myTabWidget; @@ -336,6 +343,17 @@ private: QCheckBox *myInternalEnforcedVerticesAllFaces; QLineEdit *myInternalEnforcedVerticesAllFacesGroup; + + // Enforced meshes + QWidget* myEnfMeshGroup; + StdMeshersGUI_ObjectReferenceParamWdg *myEnfMeshWdg; + QTableWidget* myEnfMeshTableWdg; + QLineEdit* myEnforcedGroupName; + QPushButton* myAddEnfMeshButton; + QPushButton* myRemoveEnfMeshButton; + + + // map = entry , size map QMap mySMPMap; // Map QMap myATTMap; // Map @@ -396,7 +414,7 @@ private: class EnforcedTreeWidgetDelegate : public QItemDelegate { - Q_OBJECT + Q_OBJECT public: EnforcedTreeWidgetDelegate(QObject *parent = 0); @@ -409,7 +427,7 @@ public: const QModelIndex &index) const; void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, - const QModelIndex &index) const; + const QModelIndex &index) const; bool vertexExists(QAbstractItemModel *model, const QModelIndex &index, QString value) const; }; diff --git a/src/GUI/BLSURFPlugin_msg_en.ts b/src/GUI/BLSURFPlugin_msg_en.ts index 9016435..537e927 100644 --- a/src/GUI/BLSURFPlugin_msg_en.ts +++ b/src/GUI/BLSURFPlugin_msg_en.ts @@ -695,6 +695,37 @@ The smaller this distance is, the closer the mesh is to the exact surface (only Hyper-patch + + BLSURFPluginGUI_HypothesisCreator + + ENF_NAME_COLUMN + 1D object + + + ENF_GROUP_COLUMN + Group name + + + ENF_SELECT_MESH + Select 1D object + + + ENF_GROUP_LABEL + Group name + + + ENF_ADD + Add + + + ENF_REMOVE + Remove + + + ENF_MESH + Enforced mesh + + BLSURFPluginGUI_AdvWidget -- 2.39.2