From 23d90107acec5e54ded86d9f309fe5cb42720b78 Mon Sep 17 00:00:00 2001 From: eap Date: Wed, 24 Jun 2015 12:17:07 +0300 Subject: [PATCH] 0023064: [CEA 1471] Create and support quadratic polygons in SMESH --- doc/salome/gui/SMESH/images/image152.png | Bin 23082 -> 26057 bytes doc/salome/gui/SMESH/input/about_meshes.doc | 10 +- .../SMESH/input/adding_nodes_and_elements.doc | 13 +- .../SMESH/input/adding_quadratic_elements.doc | 34 +- .../gui/SMESH/input/quad_from_ma_algo.doc | 2 +- idl/SMESH_Mesh.idl | 11 +- idl/SMESH_MeshEditor.idl | 7 + resources/CMakeLists.txt | 1 + resources/mesh_quad_polygon.png | Bin 0 -> 620 bytes src/Controls/SMESH_Controls.cxx | 250 ++- src/Controls/SMESH_ControlsDef.hxx | 12 +- src/DriverCGNS/DriverCGNS_Write.cxx | 16 + src/DriverMED/DriverMED_R_SMESHDS_Mesh.cxx | 1574 +++++++++-------- src/DriverMED/DriverMED_W_SMESHDS_Mesh.cxx | 27 +- src/MEDWrapper/Base/MED_Common.hxx | 2 +- src/MEDWrapper/Base/MED_Utilities.cxx | 1 + src/MEDWrapper/V2_2/MED_V2_2_Wrapper.cxx | 130 +- src/OBJECT/SMESH_Actor.cxx | 19 +- src/OBJECT/SMESH_ExtractGeometry.cxx | 133 +- src/OBJECT/SMESH_Object.cxx | 104 +- src/OBJECT/SMESH_SVTKActor.cxx | 8 +- src/SMDS/SMDS_Mesh.cxx | 134 +- src/SMDS/SMDS_Mesh.hxx | 18 +- src/SMDS/SMDS_MeshCell.cxx | 53 +- src/SMDS/SMDS_MeshCell.hxx | 17 +- src/SMDS/SMDS_MeshInfo.hxx | 51 +- src/SMDS/SMDS_VolumeTool.cxx | 36 +- src/SMDS/SMDS_VtkCellIterator.cxx | 186 +- src/SMDS/SMDS_VtkFace.cxx | 101 +- src/SMDS/SMDS_VtkFace.hxx | 1 + src/SMESH/SMESH_Mesh.cxx | 4 +- src/SMESH/SMESH_Mesh.hxx | 2 +- src/SMESH/SMESH_MeshEditor.cxx | 853 +++++---- src/SMESH/SMESH_MeshEditor.hxx | 54 +- src/SMESH/SMESH_MesherHelper.cxx | 14 +- src/SMESHClient/SMESH_Client.cxx | 28 + src/SMESHDS/SMESHDS_Command.cxx | 22 + src/SMESHDS/SMESHDS_Command.hxx | 2 + src/SMESHDS/SMESHDS_CommandType.hxx | 1 + src/SMESHDS/SMESHDS_Mesh.cxx | 59 +- src/SMESHDS/SMESHDS_Mesh.hxx | 8 + src/SMESHDS/SMESHDS_Script.cxx | 13 + src/SMESHDS/SMESHDS_Script.hxx | 2 + src/SMESHGUI/SMESHGUI.cxx | 27 +- src/SMESHGUI/SMESHGUI_AddMeshElementDlg.cxx | 54 +- .../SMESHGUI_AddQuadraticElementDlg.cxx | 160 +- src/SMESHGUI/SMESHGUI_DisplayEntitiesDlg.h | 2 +- src/SMESHGUI/SMESHGUI_FilterDlg.cxx | 2 +- src/SMESHGUI/SMESHGUI_MeshInfo.cxx | 19 +- src/SMESHGUI/SMESHGUI_Operations.h | 1 + src/SMESHGUI/SMESH_images.ts | 4 + src/SMESHGUI/SMESH_msg_en.ts | 27 +- src/SMESHUtils/SMESH_MAT2d.cxx | 52 +- src/SMESH_I/SMESH_Gen_i.cxx | 57 +- src/SMESH_I/SMESH_MeshEditor_i.cxx | 58 +- src/SMESH_I/SMESH_MeshEditor_i.hxx | 2 + src/SMESH_I/SMESH_Mesh_i.cxx | 9 +- src/SMESH_I/SMESH_Mesh_i.hxx | 2 +- src/SMESH_SWIG/smeshBuilder.py | 57 +- src/StdMeshers/StdMeshers_Import_1D.cxx | 3 +- src/StdMeshers/StdMeshers_Import_1D2D.cxx | 2 +- .../StdMeshers_QuadFromMedialAxis_1D2D.cxx | 365 +++- .../StdMeshersGUI_DistrPreview.cxx | 2 +- .../StdMeshersGUI_ObjectReferenceParamWdg.h | 2 +- 64 files changed, 2858 insertions(+), 2062 deletions(-) mode change 100755 => 100644 doc/salome/gui/SMESH/images/image152.png create mode 100644 resources/mesh_quad_polygon.png diff --git a/doc/salome/gui/SMESH/images/image152.png b/doc/salome/gui/SMESH/images/image152.png old mode 100755 new mode 100644 index 604a15063003df69f012406ff841c83782c1e729..d30ae67dc5a81dd5e284e39437d1020f04dd3f54 GIT binary patch literal 26057 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
E&9ARNVrOR`3b+=Z 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 HXYT!PbMT(J literal 23082 zcmZU*1z1(z);){?5|WB^2uMkHBi&un-QCSWLb|(41Vp3-q@+Q*M5MdBrA#~70cWko4;R6nEXeFy>J(K<2`_{rtVPZIDA z$wW>{90C6Dk>6U91dgCMNo%_zAfUZ?_f#=iS^&h1ojU%*7*+fh)aPWP>0sXX5W3F0wRq+oYjVR6cZSwE3I~zvr7M!~ z=fkX*0!Xut!>2xy>xC2#E{f7klOxASJ*7mZz!$;lKn_CQbdi>pPvobWzYmg;mN(h^ zU2%GhMv>lIV?XCnQ&UsC8JeZVLL_t>o(4OeDOX+oB$JfR4IyPp+iP(zD=U-txwS^3 z!CcuX$$QPnh#qK4M<>8_;+z=vd}G*raDFb2*Y#uBrpMMOmSRatPx3Gsd4b=~~eX>;?~GPEmOf2A4vOE^29;Ntl#RTTF-JgF{@QwjN?X$ea!tKR#GS|JB$dn-&^QKm# zYevfE)mC|x$GEaYgT5@28oikzc@cUSKPEejwQ|3@l|FT?xj5vN^nk1d~#SJw9onZfm((+0|jDXR+FF6ncJ=(zl!RC=G$@*1_cMpY%j%)7fBVV(-Xak zwAXFW^DHnpa>dF_H~KZ2k}}`;)*|mo$~iT7ul49uy5||$r&5J)+|ry>=bSA8reAC znS6@$)JtHbhjavN*L}!=yMgb4dwwsD{$Tv;0os?SKiu~|E;v|jkG(!zYHDhVS#0;c za#-Kk7Nrd3h(P5(!g#qhKHO>WGG?`}I2#f#vfNZQ!YqrGCH zpxZgk;>J6@o$SZL4z>|A(5Y{dzpMX z%Lgq3|CGBvp?4q`-7G{g|F*R#o3;@Z6_p0@l0Ye?=aIDEgZKHQHz<@ruQB}e^i(cD z#i{I$h6dB(zAH{yMdh_ZZ5DA{F3hq0E*E^oI_Nh~G^t5FM+%-w9s8>NW1n#po0|GF zB0&a$s$9@mI(0^m-Dk@1)*wrdB0YB zXk0JWa?X?DWzZg6Ks@=Nle|xdl_f@-AkQ6T20&|UsjQnIf z^X;qlnMl!|$>F>=71$#eU#_Zeb(wwa@ygF^ag259_kJE5U!7jH!w?6LEOCBV(H}vt zgoy<`qU-A1^qBBoMIoM@Dve{bp}Cir%F%yq^17u_${qUazIQz{!A-!mZ$L`S{cZ8~ z{M-%Hyg9V)Al$xDJYR zQ1DGy@cTzbjOYH~5tKWv?(K<5OS4cXCBU8_vF-i#QX53Y-^#Vw3HTPa79s32$$ocsGHjqVjQGMA0h@4+P}-Sox1*%ew+E;@2K3l zp56OQF6hN5>h>XxA-<1 zopdzV+cCjMAd zjtl?f^0y2+>M%xJWlBlwHAH=`+#B9{Ma#_GH8)2T+(ABT8e$RCH}mT%jzD5Y*I`9m zhY%?kyIzN}{*83VNnIgGg6f)oY3b;C2jy<*gPcS)<2 zIeoHhX{nR)`}YzC2D~24PoiceysOc5&EKS?a1nd-y}>h3Ro#WbxziZeFx%n6d>;G# zi>$jJjs z@^aS=gk088h3RA~(xjxM_?@`Fo)el@)hq3^DF1e2RmM&nwqb^ zqY@D!rhgRzafwa*G9<5u;&%15sHu{tww@W=u^DB368I>o}{4_b-V*8oJ&_D#>h?Qp5fJ3nC3kcdVGr0fjrze zS*cDxZo_%)b(gPFesXz2O-tJk<&rPfG-knPA$$%_GWIK4R@C*CyuC2kEum>?upsMq zhy_jLhR+ZmaQDADEYVu*q2Km%#YmwRJ?1p>26bL2SyyJtnwq_1uLszEypKm-i&$O7 z!AQMU@wmiNEJ>Pg5%6@0F7Fu@*lHP*r-+{1p=vLUj#xCZu~-;}IjAfs&!4+7w~y(a z201NI$jf-++P3j1w#PpD6Y1*IqzCG1@95}JO<`mSbw-KztWvIk49M4Rd?cU?YdPtC z>?wZAk=8=4hu4vutX1vq$yXuP>Xf{-=F$|7jM-;Wt#|Qk3S4eNLP8pcVKcd28ue^p zkKFsS9_LO5!WP^Obqx({0_@nlyp71VCNG;rg$%X~_q`c*zi#Q8+FFRV&<(-wZ@Pn^ z*W&fxfD2q#i&4-v-|u>zpDTHJ2?z_ZXXyI4y*XHyIc$M`-=j|r>847S zeKS6;BA>;lahN?;cguoNl5~P8)UPBA6<0PQ7ZPflsaIoMatNVj#BWuU^7E6szrVK; zlHDytcE*vM zQBdCow0qR)LqiNOA%7%CX#0X+)yN1<-fZ#5ryWT~pb7AH-aTv7Q&HC>F8;w6JhP?F zX6x|Ab#uk*4jYwq>6m#i$rY;104dJi_yD3xSULaMWKOr}dqL20eiI0X{MkF6Hk@g!E3B$&m#|J->n7DCeJ_q z(WLAjM?DUo+W5ia1i2E{UyFIW&eoh2&StP%rt{eo4v2kZJ2|1@@mmj{_g?vhxMonQ zj)P@XEOsaA0k;w_pEkL?=-J`<@cZy75|Z9;6mZvDMKMH# z(bBqHjwXMnwzM0!^A0x_sU0=Hy&sv{Dyi{0!TDKx)c)!OjyCg2MiUR*sNPp*Lx}G1 zY_y4v_#UW!emCy8l42-GVyv%UCxG+jYZ`hyRsbl-H8tjqyyA3WcFE0;qtj}K9 za~a73SuOx*>$5sL}XIT zVd~h|4e2rI=wBs@Q#DK2eH=Oojdq@a(Z z>hWVFCnlFRl9YtS z$|sFk2-g*o$b(KA6I2JLwsMOd^A^=L)mL5kiZ`EHC+dec`_A_)2p%R9zM$$v{?F!` zuL|OI+h(yGwUA~+rAUu*z7CI4F(q4$k%+3AwNp(BLjL@ELg~k!2FnW3UapG;>`u4c#OI%#j zi-yF+zo`bEc*f{etM;c3Q_2~*Z?#w*_Tq{ULPwze~U zCWArBCud+lpYu1bQ!_&}K;%)tE3^vTdI~NsqzX+X4GmmPVUWe`i%>zo$FBstlzIGB z6MW`^7VP`cpTp__SJpUqb@EHntn0?PK|{~EA5D)14w!i#hrE3y5B4(&|6*|K?b8%o z-+|%5o|&1j>+94yJA$zGb~3&kj8IV-Z*N44+NN=)-uZbwQPH4>_3FZ z*P}W7aqH_HUkxsVG$FRF2cyHdm7D zS&<2tP=nifQT+qMZ)mvFLZe_Z zE~iFUJ`f0`4Gw!|$3?U^1IHl&?NW3JjbP7TOyT7t$X)qejGnssOR$)I7PUEB8&oort8xKrR^>iu;hmUSZj|2(FPyaQA7#$3`#RKmAM8GT zUo|Ibvn#pi?a9igACpfwm_A+v`g!AtPcqRYcL>$2tn=J<>AuhxN&+K$wFZ{w>34MH zYTsz$;K_7J+6@7MT~g6h{QPsKO^KB68g)RWgV!A~82S|(UALkF0#CcGCWxtlhn9JC zqksGeFb$5|3*~tJK3ARld%gpRknkr}C>n*FX}X z(9KYoTFDtcm%51djtnX)8VWjk!OViEDH|bk^RX`y`f9F7aHidcbSy%FN)AlNAi$m4 zax@i(46cQ9i<^*V7^vW4^n}p!7zpl2Pg4L`OnINZ3nU44o2_M#vx9W0`{A~~`nhn!|zG!ai-Q9S~ zmKzK#Q~&L0^ZD~vP?mqKkw1 zD)pVMui=Hry^{Cx!dDW$Kdu0{Qdrhf+A>C7)~6Rhe=Eheg-QM z2fITfseDb=POevDbnYX#@WTfz*w3BkomLz^#CB!Mw58uL$lHHPZz*D^f9c(LH3#~} zEFoC9xg*oY_c;f5=Kq!x#B-3J9B+q6y}yCcBYbyU8VSdy3_OEg#qcfyR(0F$hmTNz zNTXRt>9ozNiRsSNc$k{yRC02%fs7>7Ub{a|j7bH>KoX`W}Zy*lvICqn~H-_s@TO|Kv)3C95& z2~)1DaT{VY3yYPbqoeU!$aQ#3fIt25DI3QvdIrtv>gxN(a+(!RdYDA2T?w}+$+ z%IN7mi;PrM)zti`SlPY_4MLN69D&p6jyL2;iXSz5&q_b-K+)MXZnL+ggn@RTxQp^u zHU%fe>ppao3H*L2$8%oMycoS+7I8})%g~Sv)DQqS8b6r@1Uadp_8PH_75Mv>y%s4A zt}FgWH38k5)!!gqpL2XcpDXi=XJiJ)QSCrdL5S%M`}vbf@zag-rd`2QDtS=T*ssd= zvm*CB?DZ|YssK}Lk7j)vd8`hO?yx=L?%qGnyk{(4BorH7oCFye3Yr{RyU?`xN1~=y z$Ncgt*vY9HDw;kx^*Rd8-|dl6=!`b#Uv!0~Oi=vw(;)5t__21M&s5g$= zm_>ZqsjkrU&aMsiJu@DQ=);E(;!+Z7sy>m-?XjZe6%-8WzA}i@k?)?qp65`g(K7VS zfw$d(^iMiH-IP6yoNsQ&Yhd8xH{4cdOZ3q|t7G(;ENx|JV_^_c=3W~Y>U0h_8_+#M zqh7H(jR{^9D*tb=?ATwvq|B?#{^Hd11)1m8<5J)K9~&|b2pvU6xml;&K|wzfUG87f zmA!7%Q>@cLf28@AuOc=7=Q}?4vG@e-o`@GcTIx<>t_w4g4~1(gO7w(r?Z#^DqtCd_ z;HJU@+l+<>oosD+T^S&@fiU#nRo%5*H+LNgOMq+O?{^f?=cIidGFe@vcj6P{O(hhU zOeL(Rj%yQyj{AB~e%WC4@FR?F@O*>4lEytSQ9R`SKo?$pwfuivNttu-?;Ldd{&=&O zs1kyeZ6z)flan&C^5P|vtWL`aub6bEjJ)fc9)Z^M2@=(Glq7lz4F_chpa!w=_68$f zSl>6&BwwfIJ;t(%=^m6DE#Z$kX7ehTL>y!L7T+V6Q)hd|+py$81Zr%Wx|5zB@snp5 z`C6m77c~<=Z9M%)194?mD+`brINz)>zhAk6OZCN)%r<+1#(HP;&>cNuM2)vT7akG< zyKs4wt!uDwK*b%XTq$G0L3mR8Ub#$z_9d24{g0B}C&;Kn9r;Sdh4;^Wue_6T1G0so z8;(GY!b?d>OXd4LsdqIn5KI6+rX)2yizVg_B4BRs6k8*sezS3Hp2lwe%j|cB;V5W{ z2S!FN8{5Ge?-pJ!piSzALU{a=`;B7niuPCN&x)Dry`&ytkb6^K}gRm%ne8jEP57U0juLunmT)U!ogA_7H4p zbQFCi#2pk_i_Oi~*OQCXudzrM32JAxY}Bj*{P6=v+piNF;82>|tGg!^x_z!oV2Z5~Bme%#3qbpl^Q;s6qU}yZ$!eP< zIW;vgCkN2oRa2$lR%+paN&H9B>s~g9)RSqTjZxnklF118g1BOgxa~$+_H|w=AfOG< zSpf<)T~c~4@iZpOOy%yO952&C3TAd#vxd`$EilMKCQD3(hUs3&?*q|~tC@!7K?nLck5 z!UC0k*3Mxn*z231Hp5^i`rCB=qeha7-{SALukc%BSqY!;Bo*|Gs!Cdgqtxq2$eP)9 zcG0LQdwqPxD1Uv&U#($XOdYy8L*;uvE`@^8meNT={NRsb-jHhs1?7_id8?z7K>J16}A)x6&CjThgp|mszuSjTXiZd&bL)sj#rP; z`8{KOW91$$R)Yn>nN{QdT#e^Vu{RGf#^Z` zr78%##O?6UTBK5M61=UZCJ_SPYHtxR<#TL@a897~NJsBJVgI)tD4rHlMKfYv6z3>sb`5Ir@ev^2>zqmOxTdU>AmV1ANhR0+w z-?%hZq0229Lp%@^%8C8%9@<$s?427B$Z1<%Mhj28JSe1PLhs&9>xuJiD{gE|k6$*5 zCALNRg!PJ0d>4iPm;m%Y0<0&jWhyJ5&39@V2ubC>dmcT9-OntYt{Jc|epa2BkUKuJ zm23X)e{yCE#2UHxx0_MKeEZ}A`}nVFn+$ZQM69^LrU&A+>mXy!Yy%v)E?Ab=)}qqV zND)!>m}mk5oa<~oGpok@ueC+D{}en)NWfOj5+{OO0856CXJ6{DWQzOX^ zs)<`N>L=phfFhZckpJ^B2HE9izside#b?R}0pamRxL5P+B+S7pU!J$Myb1?#@fmw_ zZCE#5(34aKrKq&DuJE_p#@LF}b0kBbOP+TkA|eV&3T2;K=0C`8NGVl3H}qzn}mQC7xMqZSqej-n5Q z5Xb`5_iA^ex&^o$hO%!6Gcq!slkj~q5O2O(EU=ru#(qHcQ&Z{|qZwj4I(&?UMc%NR zt?<}bhhsnR#y3iThyR9++tgdt>jVV_g~!A^3dPY)L1$)u0$ys3O%el|eKWR#aVzEJ zcSpriMdKVl=s0=2k>NT&>T(|qCM}VUTn)~kngQkZBGY{J2ru9Qxk!b6yp;3lGem4$ zf`RH}f&FO@4nlOB`ps;DK0R8E<*#2TXlVKbz4v=E&Cpi{95G|g2BW~UWeO^*nRDjd zr^PjDz;ivF(yEKZq!M7*Zy7MuS1c_pr7p=wCJQT42|5X(X@@qgmPwRMCgkNEaeaG8 z`_oxw7-7LRr!IP^G&(t{k-y~IU_Nw!V~iEG_OP@qiyGF9=~`)AeGSXKzs!|ZBptdA zBXf47fd#D0lV$F7<(o= z-=5RCxVYZTWZBcv_FL?IAMo0tnJ5r@R;E&Lb734?^7-_jVJSYteEA!{>cDVR*9wbi zEpPvzmT4`bQA3vX!Y&nGMNCVJt}=ZJaH<$1W2O<}W~Ldn!Hv21xQCX%>*lSWXLzle zxC1$OiV$6&FAru|^6Dp1$z=D~YcW6ufFvsZfIxzpn)~$c4@0f91vF&6-qVSQcudiA zdW3;85LsD?sbjD3J;0ER?ANbfv`kE|X=#=Jc@qj6`bNSDCg&|eVw}8{V)&Zszg;5_ z^57XBQ=yV5&h+$jqaITkr^wT_h!#IQ3@IW}v1iA_4Wa7l>e3Y`6zLynnLhg89bDgB z35G*0e@$mzpF;s@BwKnzGa__p1;gA|i6zO%6@wE1n#p z#dMhdPM;URD=vPszEP~Aj2}2q`mSVftACt%_ITX>dHZNcgN&y(=HB%2xgk^Hvv-ZV zK{CQSt3L~Dek{7APQBpz@+JBDwpUr%DKJhbSI%R^>mJ(2Y87}(ET+9i`u^k`jawm! z0s1NGh4plLG*>J!dqN^%w5D#Xq}oTodyBRQboX9Y@1Zr%EqG}o&YYZ+@p#3f#0hOW zY&PjJkrE2$s+A}v#HV)y*&m;0JJ%I^^TW9|~Ik!wX~s zDf#s5!xM3FaV%^V_Hyl*G+2a>%C8NVY6v`Fb0lk2cX09PPcx2clN;atrS`lu*tsQX z9?v+`_xC>U`Tp#rf3(g~fT{^a7MFc0=z-ljUcP#@y5)%z>PqwGO))-tTXJftGvBXp z2W*8oE_;O1FJD&wREvH3++caY2ld?Qk6v%`5U9p3vmF;Sp>wN?G7jfQY< z0WZV{60+xWOM>xCLPFvz?5CogywH*#-Un6hM8HmuH@VV0H!!%b8y)$5z?H4YFKPP5 zUI(wrbqlG+bwazvsRK7BdT?WPL(5-%AfAFMdko*&iu$LY?P;_x;$*C`sRGtWL?UnYKNJniTZ(sE-1P9o5m!OkbhBp5nl z#&;@lV}QC4{4DP^Wi4^eCA@LXgP*a`6?iH7He3=?9r_$9cbu|@Elf;J$Mjajn8;p+ z5~;Ev0Ish3D$b&hCU0d8iar**iX#lt2Vu;|gMJK@pDGy(#|hGcn}A^5v;@J{9jVHW@!F|Yk`6kxzm=1!N!{g20U>=UBv z@=p;H-FoBkRora8jpZr2XHl;z$-iq51qeC4vr&pygy^fP*3WzFReZ{Is(}?fM^Mam za+#}Wa1qduy7N%|5QK~r$T&woz)ZUga+e8cEHBCia^{O&pPQRw0$afP0X%#8`UEmr zqQ&fU(W2WnhBjO&^WA;U~ z(^RQNs*h=b$7`DLmuzGnLv-}>?+S$OBSM7AIvz>bd z5Q3933-s=CW3d3zJ@^(#FrDQ-Y!6^#x6Yahli*i(U*7U@0wuywmhjTSz!DIMf%U5r zuVCcjicHWaxsNn!`*LqavKqh!YC$MRa8lUu`Q&JPYU-v??|*wjw-Dow=zQA1wgMXB z>7VXC-qgfZ0|Ravk%OiO|CwYov4&&7aPQ_DtW2Ylb|#>AFf%iM)r25K_o7B4b(y1V ziYinA4>Y^cGJ-)aYp|g26}VF3R0e|~H6@_|GWa!4XlSV4#q`Ym8X2T=rki(WN!WAI z4K!D@f1kj2Pkc@k=6g%&~yrT+72CV|5OD_PM^uU~gBxV83Vhno6 zNKOHYj{{TQYMpk!h?{J1T=J>qF_blUTo8e}sq=kh4|N+@rtbjBG-KdPa@}L{RkNHx z(B~y{%QgSzNX}XS(bm8c%}Zb4Bbkeuo~g|z z+l#G4KrqG=XrtNPM1EkFcu{OJ1iaa7XDZeV<(AC;RQUq#ve9R2JiXw2 zrgPcT6LEjF1lY=MK{aW(`2TcE8X6jbmJo=UnOSfE^oI~^II97Rgk-~DCSGtw^yUfS zy{U4^P-&@Q?7~?8VVnOQ3uIBxz< zm=#UtXiol=bJD)dNFUaGjzmWPww#XXQE^SACSyab+bk++77Nh+TFF`smOe3!I5gCH z9Pj}ZXuWdEf4x9(jI|X)6i;YDc5kNAtb{wtc|~DRXuCyW&P_ zc}MdIVSRH$MMGoZ)6=B*^bplDDn7nQYqgSJ3$MNb2*6q({Hi^7A6gba-$I;?LBh(Y zGgdA33|O2H{OV*B0z~LMuaM2h0twu#w!{G(EGOxuOSd zcRKGIPgNZUiSp^hy!JHxX0C~~Z&VIDZiGPmc5_2(X*pNT>Qsp9YcQiuiqLI-%j;%^ zhEz$cBff$CDpADXFwPI&^$b788r(pg11@lQQE}37EFr7Or2%i-b%NMM>cYYroxyFF znyPD%IGA|&mpML!`fYl4wq7imQp#UI_TbHtwt#jOr`lHV^=tY>4O?ed*YR1c9*0PGPhMXH3ZNd1x}V&3fSi`ET1*<+fkQW}kO1Y*|tscXtgp#CzD8IkYnv;e@Ze;KL zX!hn<)I%0C<^;X}e@jZgdzAW?V(rYIN4e+`?~uZ{)H-NW= zftxuR;GhGa-n(Tqvu&o$eeLt^5E?4#gmjKTXH22)!-eJ#y_SL2R`9>3Gw!CpVcd+2 zF_zRy#>@G>OieNyJK3?Mg1=1T6x^6A1;3T-b9JKQ7z3**@I)b%EUT5Nr^{2jxSsV7 zKOrMKlA~wf=1z-`H@Z3+8&h_1B}x-F0k{P8{Fg^dqx0Tp-nO$@htFAn*U|28UDM(v zCxKD!aU&cMW&$IA_qSiQ&-doiw1K?od^qA7s_sjyw8il+ASWv-3ioMxYB8KS9Qfgh zmv`^;%l(BxFcR^;#;aN&gFDiQDMYro)9$ybwX3SKG7=+G1xxv~tfVA0@I4@83;L!8 z1_mNERAha({%@aHhCX4^quxnaF5sOl$MQw+vbQfqXB`RoN|I=l6643naulUNTkF_T z{gWht@RtMSJh?(m6gHk(s3MW1a|A|Mm$P-weh7@=c8db=HvXd;>J?Ia<9t$^&HwB@9yqqv7Vsnjr9-wla7B##5L3ki=ZLhy3np<_ZfmF zr$7^fJl6ZMhrDiZNeSUBbaZ_SgG5;mxB71}Y>TtUMFozJY=vpFA+xn1tpkAKtG1?={x+P}!_a|-PHT~i*VQs`ug zS(+6x3WCnsOJ+|CX2JB`VylmFd5v+c2H0H1)WFLUij0C{aUTr4ET|JyFaD!yH#!8B zm6opeClmpS;`dxX-x;TgLu(Gmc#=xPG|1eoMnDO@8NLqlzFW#WS-?~b5K?B}{8D8u zcj>W0eUSu+UA@y9iNc*PmPS`@ZPXgeZk$JRZ?Su4`ofxh&&jE_@hwNx*PQMH z(;S2gUYA5TYD??cJt|S$VE4_9(RQ^T(v9zEK4P>SU2IKGOEbJev!Mq=MuLH=NM>9l zyZ&LoTMBY2ArSYu99c~oh>$V96c!dDGgoF79MYR(8yC>b!erzQNmM1SzD?3G(Sdo@ z9567VS5=kOF}Z{<-2VK7HFb~*?MuL9n{xCPjDI>C@jcl2U61dWG_Ww+z)yT%SBY=9 zg12!c%L+DmV-UysIcZFKu3P<*ip@W-gp^sLTy_ty?+B;;*wEi^dGzsrSxaqT zR$iyj844Jj`VSSm-I7Ruc!E0op4}%WHXK>d`-ZEgMs{Gt!{y!!yF=s#$dYV{IJ2fK zPP^wjk~epb7D^B?2#Y|<-j4Cr`dy{OJzPPVMdIM^Ne|TYdiUHKu&m*6ld9(I@u>#g zT1%QZ1PO6nE9A5+@yRr~%Xg);z#&QWCOvBaJV0<3lz;h5AyD4YNkd?b7@oGfStG61&0jrHU?jo@uG)BY^ z&aG2oSlnq+Jq0nfU~^txc5Az@iEoErjCy6sPpq^^_BZ4ZeZ^cW6XUm7m;T|_gxI|B zx}I7(qzNDR=01Pd>~5D(LTh6$`}g0Pidy*L$Pf`FH zG$x&yTmqjVl%@rySy`*(k|p<3{NDS=ktU|!`X>#2)o@V}J32Z9_*SsNBpk{;8qrzq(epKUYG**c$$oxC=nf1>Z}oyc7j1Y3ZUud9cyI?g6q>Zh+5(_g-H#=|dbO zQ7cdgw+F6VEzIN}Em@SC02}k+Mm@|Ml)%$v!>3%pDPb|<7tU7j9CYYO60=4yr z;8jFg3d#mFX$TXWTz$H!N?;6?yWEYx@pj+9CRiNpC%1 znmMnpZ4&(N0H25d3&2eJjdW%h1aSA&5y1%*eygXY1Tn>0YTu$|Y=eKE*a2f_Nm7~b z6-pUxxxv~^&RIxfrYim%_g`R9}87gaQqrAJ7!6V`ZYD#&b*j)tZVR#c#!2oa? z&`leReu;_wIlXuN>dD9JfBPH_PwQ+FMqgMId3>oz!}AFf#LNAC5cP@u=d$aI$}9JI z+8J+37ns#XAq5+IZFqEackzVlJWXy90bziFB|xWW1HXPz2v-KS2q20qK5|npk6_Ir z+CXa}xW836;S1TrHx`<^;9VmP2zjtDcf~QCq84t?tH{BHtceAEq6-U6z?hDzDnASD zrR7J)Tbd6`kfl;;ZT)uG|9F?V^@wLvaPV$4$;uhm zyNZl#A;Ikaeo9cE06D$nvsnc^o;wq~NfT_0&aBm5zFE8GfhXO=t22&~Gp}Lry)h~^ z+?PfM&9PMzHE@D%8+jA=p2VcR)#VPdKd=GGdxn6g&z@lu6GwL#HG0w9QJ?H_*Y6#l zS4F|$glLjE2{J$P;6W>4WXiNJfhkQ{M^lrz=Dw;q@&ygo=}2?b!neU*Hj8sB6BCnk zFx6@bhOO=70vtUdthI(PXH>3M#q zbb!s|`V(etGqVx_X5owv;EqQ_YlYv=gkjmi87rjtA6HU!IWXnL-%8Y;{&CnRZZ1%8)G#_}BS~bmD*f-U0r07~_c$ph5W;XQGA$yVY43T%SunZkx1|u39jj^TQ z2*B4^*_W=i?l$jM&u%c5wyv5l<$9I80uxsgxuEdqXnATyS$k(DnkpruJNeg973u+-)Wi)XC&3+uS3Z^t(yF?%tf*n`9 z^zkcC*PRLQo|598Gh-?o6bA=~#^&a=&rVNlPENRrRLe@$$_GwQI$n`T0GfJn5zLx= z!Dx5JLCy{(!yv7zq%C<)@~c>Gx-?l9*gg_2qf4yru0qr`P3j}j7!gfmem@4xYMqoW z-+h9hPk1bf9$|GZ4zjq>)5qBOAM$;lN%BA+W2ajnml%?7iyMVZGGn<>u*^*Ev>V{T zP>$Mt4=lCTe(*tK+Mh;4RPlko?AJ==9b$n5oTk|4w0A32=U_o zSH^WlH4(I34ZSE*lwK4BL?ATjReDDRRHRB*np6=;L_m~;4u%?f?*dXok>0B!EtDV- zr5Axfl6QUIKi@gu&)qXSdv<2_nP={E?+tnNx_mbB6ue~-b}pAixbNoaCOxJMG(|%j zEfX7l9Se94^Q>(>5)~${r)Ls2C_Y$;ZjOUHW`6sx;%W9eo|6@c6sri!(2ZY)2tgIa zs(xTQ4iRZzy>F|3pmjTF*(XGvE_-}-{F@2E9J?h$>S>##i-~$=Wugtpu!vJ|8*!H* zHG2W;WtAAiCHYxqW7OsEwtyu{v<$8(9r(NJfjX?$~_{Er;S*y zh-EhFcy*@@+D~uPp}NBJ4a-bf<)r(AWA&JZw37bMy)ac$EuI@;^pq_SJ6duQIl1PU znN-b2(mP_DDEo`pEQ5;^;V(wWo|g^Lu~Zs%^WFW$GUDQO=a48Bt^7xR20S2#xI=38 zi@#Af=G2GheE*zZ>IWg(=OQJ~aAQ8>S6zB{iS`dS6*c1rHP+OR1{Xaw*zIzsObm@Y zZ@#XzjN%~Ne@$-NVc7a5W_*ruoYaUdmE^bDOnIz{ciD}Up)5$~MUIJ;-7MFG`OHv_ z+3ft6mrX`DU+p%Nj08Jy-M6T497-NsDzcBceIx9KzQoXw=>Crd{ip4}1t~r(c5SYP zPW}MyVGg)51ZU*;fpa7wO{`j5$=U2ZUkd z#ghP)WmyGxbbal2gIXSunCIHGE=%)Zg-p$%z06xtE@;JJP^oU!NPVbS4T52_>qu*TAz{zsROd zs~RUI4(`F7m-Fkk8deMyQA@RuLv9?rYPH;pE9dX_!7$=n;Uf?xMzQcCh{!GqB_I1Y zr=;X#twVo~nGma_vmb1(r1C9@!kGp5WvsfXw2(vJDi5!unBHGL-R(sS$z0d&uagmc zpWhE>fh*JM2zOa6Al6KSVBxJxjLrhUKs$^FdA(YgT|+OFV_fOdJHSezya@?P^OXYL zJYqi0naU~TMY}=SI-kN&n+|g!n_25_f6k9)VItV?SQkQy44BMP0*U;o19FG8)}i>5P@`#uCbNBB$w0 zf;VUvl!f@7Act8ol?Ak;-=?P-15*?%UMV^Iia6J$;ojbT{#7#x(TJ?5Xgu4;7t#_B zzE;Ps2)DO)`n&!*CVBe(C6l^vvb%0qH;SR$9H5+ll+nt^sC<>y7tr3JF5j9Tvk8jc z6zyoIW0bw3TyszsH5?dL5VJBiYFOq_ayI>*GAivV$%}!(lXbsZ`sd+S8*>}&sE?f2 z_a7FRQZb)!@f~k}8g=eoUbgjnyz(|IL9cLou^~e#_({Tqud?{0XHTznK~Y~%z|K?P z@Gt?02N*aELfkp7&R+p=n?q-TR8ZJ3Df!AO#bZEO+3hGFZE#E7!$S~_M!yLPqG#mP z%&~xJ<#&yaR$^_2fwtsDPac9$3=A59r0?%PvCAU^g;By)c|g23{9v8Qh$jGDLeEd1 z2ZR~OP_}LTT$~-ul{Dx#YOH^YGE-TMK#*bNQjV!y{w{5eDI~0@&k%8{ekMF1-@8cU z0Vyfmak<@a`{&)Rmkn#@JJQMQQ-Ea2dc#wqYQ1}bz1$lIwV6-BrksG%FAnc(~D7g^4t*3|vRm0JA1+wTI4 zTxPw{^$FD-mi=(-^z)xE5Hk(@_m+4)4BeBAFfP>??fRH&_JljH>n#;v_~QDAzLZs; zg`=Lk*($t?CGz3wPfo|oNi0H-7dPethlzzaGi-U5e)^l5|fTHkhJ=mc%#q@0v2t_c6>dhR)HU?f7_wDnu3C3SD zH8uVD#fgTI-(c%Fm5uYFpn&i9pFho~=-_mSC>ZSZs2asZS=FCtQ21@3m3eZ~=Zn!> zlMuFw6V~Is*6j5H2BzqcMf2>Ozvu9)_&7#-NNf+J3(lh4hDmY~@WWN}2@AuKN|?cs zk#z$sE5pU<-b`vvgTpfV`^wIVsy8QyH$`ty<(FEaP4rsG^*CtNrQeAuPB23qH#oL9MuSReyhavUa5)Or$1&zIw`9 z08=H)Eb6|gk}c}=Xg*}bS#ksSwnBO#&e%GD!^I!B$MS%!&~$JZjMt6moioN!2+-w~ z={*bx5Vx^WGO=h~Z4IPDyvUP#>Vi4@5OA@GiZM#y z@jixR0D6#@0h*&F^9Pgv(&Q2wMVK#deZi|ub@G!=)(e5|3gBD1%m29l8fMxu!ZlE)_A(ZPL& zb|>kEGnVc;FGmFHeB;e6qQ`)oBpuW20&b^>Wn@e2`IKbt=*Tu`sG_+wzXH^;N`aCH?eGhrJNRE6*+~-^3Lj zR)_vJkgBdO7Thj5wtd_>g{N-$PJ3jC)4J7uehZHi=``MnnPgEjssjINP>3HA+FJHf z@$`{nC}m12y_(W`-Pe%yjYAuoLNedQm~@q!bto=2`@hC?x`T-urNccGKqOX*#jJn4pTMwTbs0^9Q!}d7$g*%fAl+ zh8Mc}&j-pQS{#wXGLKb6{veKOHU3rM?61o;3u5~$&7=FIaTaEKIA?=G+BmLXsp zH_b3)S2KCEPUX3bd-weZA}64wj5NZu;w(fC3+@IJt6iA5oRRO7(X3MXQZjmP`h6UyUgb`M0T9pP|bU52}ZOtQGR>ztG1((7uwGq_a zUD$V1xqH^O(&4Bm#(n;*qhr^j`TR+2u4EN7_=ID}@aVJ<_#BBZ+W-9&3VyM8RB36l zMufd|MoFn$|5(;u?W;JdPi8S?ZSUU&9X;ZdUu0ojm$+x2n+u%c0-lcC%p`0gv;N_S zi~@yUDb~M~$ zq}*1cxNw(~*mm4GEnR8fX zS%Jz-NSc9`xAzS++J9!|%_DnZeje3ufVy7)mb0ZqjF1@L7kTJ&OdQgz20N(Z7)z4l z68tbRSwg!NMjf5K?RSU4f_CG`C3mAU&UWQts(Z)$ChVgkLnhK@=@3;GUsIiNyx#k`+Ndmt-@{C{48^`l@Z!H(1#Fmdo@@4 z;P_ah)NBn~YQGji1-Q03NLhUHq_zT!b$>vAs~cAwP2g3Sbgkd=+Z}N7IdoJ@7GkIL z_T?28W&*TrITrd>?zCDCz?LFEX&Cm0j33a8_Cu7WSFZsU5in6|EAsyv(omrM5wI#` z6*?|ZS}LBD;?IDx0R!=Ar*j)!hp1fm>%H|cCOpdH(tAK_Yj4vIzbSN`!`+TZcdcUC zq_ZcAYook+*7m#q6OdY9ch&DEpA#1|v(z_RUEc0rhnX#%V_CZB>mq!k;=~*;0zkv? zK(n+?1F2;NI!XW3X)vqsTz?b>KWL@{y}s{aZ~7=Ro2@MnKJ z?cbbS=$^}j1OpvIPZyRCi&an>PEL0L3c;EeG`MgHPqKOti0#zCf><|#5-wZjhvUX$ z<2Gx`(zl~u=7kQi%I<3&9^wJ%B9HLMHDHBlWorldYAJR_Mj9CE0`X8%0Y6IOI9>;U zG6v~V2`<^eNSS4;89yi~(DC%$G+YR45*lfEImj)>R;k0sa5-bj#wH{e{8t$A@&WzE zi_78i(sEz*I|)*pX4H+bUUlo#Mk+r~w?~~NxkE3xZGunsgr9$yB)A&6O#?? zA8+y_E9Tw~{;U7Fts9Wt>jI^PH4?i0zlnkKoVG5FU`0Z9_AP+QY0as^p*ZlB*2^#K zZrj-?1qZApvQk%<>E_Nub{1oJTw;EIc#Ruq{}fT{wI~0hN+06|Jy+o}$XfTd2k?v* zb|AI@KXi434TqxH5OxhDnu#KP0{HDM8GfNc18{QeX$rg3-W#Ll-oiyoCHNVQzx!IEdoaDiJGXNM z0PM7+y6JwA>WW0zq^lI1J5UAFZ0o1PgnMQ5fW^4UI+i#|nZa(Ge5dZkDv!TP#9-eVHzSfh#f4Zn9wU!wZR32uF< z&}!6iP^ED2@uY93ZM6*O&viFlhSTgDo_QAvf?+BOlbQv$LGDixs!_)jJyegPRdyuFPlhXNNo!y?%5e~l*0wt)?cHrIkB_|rj0r*syH_!t&B{FN2Edozlbup)CDX)8Zyebjv44{+ zf0N}OhUdWx*AL5K)UgOTtlim9$j@U0sZkv7%_4{tTiAgF4ABJvSU6wN)ilzmdT96l EKUa%K^#A|> diff --git a/doc/salome/gui/SMESH/input/about_meshes.doc b/doc/salome/gui/SMESH/input/about_meshes.doc index 14b7a5441..a67f47d00 100644 --- a/doc/salome/gui/SMESH/input/about_meshes.doc +++ b/doc/salome/gui/SMESH/input/about_meshes.doc @@ -97,10 +97,14 @@ generated on (if any). The node generated on the geometrical edge or surface in addition stores its position in parametric space of the associated geometrical entity. +Mesh entities are identified by integer IDs starting from 1. +Nodes and elements are countered separately, i.e. there can be a node +and element with the same ID. + SALOME supports elements of second order, without a central node -(quadratic triangle, quadrangle, tetrahedron, hexahedron, pentahedron -and pyramid) and with central nodes (bi-quadratic triangle and -quadrangle and tri-quadratic hexahedron).
+(quadratic triangle, quadrangle, polygon, tetrahedron, hexahedron, +pentahedron and pyramid) and with central nodes (bi-quadratic triangle +and quadrangle and tri-quadratic hexahedron).
Quadratic mesh can be obtained in two ways: - Using a global \ref quadratic_mesh_anchor "Quadratic Mesh" hypothesis. (Elements with the central node are not generated in this way). diff --git a/doc/salome/gui/SMESH/input/adding_nodes_and_elements.doc b/doc/salome/gui/SMESH/input/adding_nodes_and_elements.doc index e46385b2d..1aa0661ab 100644 --- a/doc/salome/gui/SMESH/input/adding_nodes_and_elements.doc +++ b/doc/salome/gui/SMESH/input/adding_nodes_and_elements.doc @@ -32,7 +32,7 @@ nodal connectivity of elements in the documentation on MED library or
  • From the \b Modification menu choose the \b Add item, the following associated sub-menu will appear:
  • - \image html image146.png + \image html image152.png From this sub-menu select the type of element which you would like to add to your mesh. @@ -47,10 +47,13 @@ existing groups of the corresponding type becomes available. By default, no group is selected. In this case, when the user presses Apply or Apply & Close button, the warning message box informs the user about the necessity to input new group name. The -combo box lists both \ref standalone_group "standalone groups" -and \ref group_on_geom "groups on geometry". If the user chooses a -group on geometry, he is warned and proposed to -\ref convert_to_standalone "convert this group to standalone". +combo box lists groups of all the +\ref grouping_elements_page "three types": both +\ref standalone_group "standalone groups", +\ref group_on_filter "groups on filter", and +\ref group_on_geom "groups on geometry". If the user chooses a +group on geometry or on filter, he is warned and proposed to +convert this group to standalone. If the user rejects conversion operation, it is cancelled and a new node/element is not created! diff --git a/doc/salome/gui/SMESH/input/adding_quadratic_elements.doc b/doc/salome/gui/SMESH/input/adding_quadratic_elements.doc index 6a9527b5d..2fd906baf 100644 --- a/doc/salome/gui/SMESH/input/adding_quadratic_elements.doc +++ b/doc/salome/gui/SMESH/input/adding_quadratic_elements.doc @@ -36,7 +36,7 @@ one of the following: \image html image152.png -\note All dialogs for quadratic element adding to the mesh +\note All dialogs for adding quadratic element to the mesh provide the possibility to automatically add an element to the specified group or to create the group anew using Add to group box, that allows choosing an existing group for @@ -47,23 +47,29 @@ existing groups of the corresponding type becomes available. By default, no group is selected. In this case, when the user presses Apply or Apply & Close button, the warning message box informs the user about the necessity to input a new group name. The -combo box lists both \ref standalone_group "standalone groups" -and \ref group_on_geom "groups on geometry". If the user chooses a -group on geometry, he is warned and proposed to -\ref convert_to_standalone "convert this group to standalone". +combo box lists groups of all the +\ref grouping_elements_page "three types": both +\ref standalone_group "standalone groups", +\ref group_on_filter "groups on filter", and +\ref group_on_geom "groups on geometry". If the user chooses a +group on geometry or on filter, he is warned and proposed to +convert this group to standalone. If the user rejects conversion operation, it is cancelled and a new quadratic element is not created. -To create any Quadratic Element specify the nodes which will form your -element by selecting them in the 3D viewer with pressed Shift -button. Their numbers will appear in the dialog box as Corner Nodes -(alternatively you can just input numbers in this field without -selection). The edges formed by the corner nodes will appear in the -table. To define the middle nodes for each edge, double-click on the -respective field and input the number of the node (or pick the node in -the viewer). For bi-quadratic and tri-quadratic elements, your also -need to specify central nodes. +To create any Quadratic Element specify the nodes which will +form your element by selecting them in the 3D viewer with pressed +Shift button and click \a Selection button to the right of +Corner Nodes label. Their numbers will appear in the dialog box +as Corner Nodes (alternatively you can just input numbers in +this field without selection; note that to use this way the mesh +should be selected before invoking this operation). The edges formed +by the corner nodes will appear in the table. To define the middle +nodes for each edge, double-click on the respective field and input +the number of the node (or pick the node in the viewer). For +bi-quadratic and tri-quadratic elements, your also need to specify +central nodes. As soon as all needed nodes are specified, a preview of a new quadratic element will be displayed in the 3D viewer. Then you will be able to click \b Apply or Apply and Close button to diff --git a/doc/salome/gui/SMESH/input/quad_from_ma_algo.doc b/doc/salome/gui/SMESH/input/quad_from_ma_algo.doc index 976783d40..80c3f59aa 100644 --- a/doc/salome/gui/SMESH/input/quad_from_ma_algo.doc +++ b/doc/salome/gui/SMESH/input/quad_from_ma_algo.doc @@ -13,7 +13,7 @@ The algorithm assures good shape of quadrangles by constructing Medial Axis between sinuous borders of the face and using it to discretize the borders. -\image html quad_from_ma_medial_axis.png "Media Axis between two blue sinuous borders" +\image html quad_from_ma_medial_axis.png "Medial Axis between two blue sinuous borders" The Medial Axis is used in two ways:
      diff --git a/idl/SMESH_Mesh.idl b/idl/SMESH_Mesh.idl index bb193bcc1..0805ce235 100644 --- a/idl/SMESH_Mesh.idl +++ b/idl/SMESH_Mesh.idl @@ -66,6 +66,7 @@ module SMESH ADD_QUADEDGE, ADD_QUADTRIANGLE, ADD_QUADQUADRANGLE, + ADD_QUADPOLYGON, ADD_QUADTETRAHEDRON, ADD_QUADPYRAMID, ADD_QUADPENTAHEDRON, @@ -89,18 +90,18 @@ module SMESH struct PointStruct { double x; double y; - double z; } ; + double z; }; typedef sequence nodes_array; - struct DirStruct { PointStruct PS ; } ; // analog to OCCT gp_Vec + struct DirStruct { PointStruct PS; }; // analog to OCCT gp_Vec struct AxisStruct { double x; double y; double z; double vx; double vy; - double vz; } ; + double vz; }; /*! * Node location on a shape */ @@ -132,7 +133,7 @@ module SMESH BALL, NB_ELEMENT_TYPES }; - typedef sequence array_of_ElementType ; + typedef sequence array_of_ElementType; /*! * Enumeration for element geometry type, like SMDSAbs_GeometryType in SMDSAbs_ElementType.hxx @@ -775,7 +776,7 @@ module SMESH long NbBiQuadQuadrangles() raises (SALOME::SALOME_Exception); - long NbPolygons() + long NbPolygons(in ElementOrder order) raises (SALOME::SALOME_Exception); long NbVolumes() diff --git a/idl/SMESH_MeshEditor.idl b/idl/SMESH_MeshEditor.idl index cc6dc0874..3cdbea8bf 100644 --- a/idl/SMESH_MeshEditor.idl +++ b/idl/SMESH_MeshEditor.idl @@ -143,6 +143,13 @@ module SMESH long AddPolygonalFace(in long_array IdsOfNodes) raises (SALOME::SALOME_Exception); + /*! + * Create a quadratic polygonal face + * \param IdsOfNodes - nodes of the polygon; corner nodes follow first + * \return long - ID of a new polygon + */ + long AddQuadPolygonalFace(in long_array IdsOfNodes) raises (SALOME::SALOME_Exception); + /*! * Create volume, either linear and quadratic (this is determed * by number of given nodes). diff --git a/resources/CMakeLists.txt b/resources/CMakeLists.txt index 24a83d09a..c50ed7efd 100755 --- a/resources/CMakeLists.txt +++ b/resources/CMakeLists.txt @@ -170,6 +170,7 @@ SET(SMESH_RESOURCES_FILES mesh_quad_edge.png mesh_quad_triangle.png mesh_quad_quadrangle.png + mesh_quad_polygon.png mesh_quad_tetrahedron.png mesh_quad_pyramid.png mesh_quad_pentahedron.png diff --git a/resources/mesh_quad_polygon.png b/resources/mesh_quad_polygon.png new file mode 100644 index 0000000000000000000000000000000000000000..e9dfa3587ae7b16a4a3df2c73e28074cfb2f7bfe GIT binary patch literal 620 zcmV-y0+aoTP)Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2j2!3 z3pf`|moH=h00HbtL_t(I%dM2XZW=)pg}-4*AYqAyZhP38^rUw%wrmW2T&2ka_;vCC z>755~q9{%XDI!@4?r9=YEHM0JuM6Kr%W5r<;wz1`8qJ(J_uO;VhzO5by8vsonpCS* zc{IRMsU)7~$?@@b0V@9ms33LV9dOaS9GDXaNUjXFsG|E{o@RvemM+R#vMOv)RlC8bAOoJ(2^6l4h8=INw+BVa5d=k4}qfY(4!0C3JV4iB$U@gqGv-C>XfbOeGD z@e>W}z{SzgH&M;@F1>T0)@mkz6`}xB#@9hcxmhk2i(-t~8jiE! z#M$sq7Ef0%-BB_7>UzBfpxyp71cNb#=*wGT3UoTx0x@yC=JK+YTnW-P%lkPrfxdoU zsn~fHsBh7n|IB5Wid>M2VP5%(?i>9cU|89>e!q&+dA|d9z}Gy#gIbjU0000 #include -#include /* AUXILIARY METHODS @@ -159,29 +158,6 @@ namespace { } int aResult = std::max ( aResult0, aResult1 ); -// TColStd_MapOfInteger aMap; - -// SMDS_ElemIteratorPtr anIter = anEdge->nodesIterator(); -// if ( anIter != 0 ) { -// while( anIter->more() ) { -// const SMDS_MeshNode* aNode = (SMDS_MeshNode*)anIter->next(); -// if ( aNode == 0 ) -// return 0; -// SMDS_ElemIteratorPtr anElemIter = aNode->GetInverseElementIterator(); -// while( anElemIter->more() ) { -// const SMDS_MeshElement* anElem = anElemIter->next(); -// if ( anElem != 0 && anElem->GetType() != SMDSAbs_Edge ) { -// int anId = anElem->GetID(); - -// if ( anIter->more() ) // i.e. first node -// aMap.Add( anId ); -// else if ( aMap.Contains( anId ) ) -// aResult++; -// } -// } -// } -// } - return aResult; } @@ -233,7 +209,7 @@ void NumericalFunctor::SetMesh( const SMDS_Mesh* theMesh ) myMesh = theMesh; } -bool NumericalFunctor::GetPoints(const int theId, +bool NumericalFunctor::GetPoints(const int theId, TSequenceOfXYZ& theRes ) const { theRes.clear(); @@ -257,6 +233,7 @@ bool NumericalFunctor::GetPoints(const SMDS_MeshElement* anElem, return false; theRes.reserve( anElem->NbNodes() ); + theRes.setElement( anElem ); // Get nodes of the element SMDS_ElemIteratorPtr anIter; @@ -273,7 +250,6 @@ bool NumericalFunctor::GetPoints(const SMDS_MeshElement* anElem, break; default: anIter = anElem->nodesIterator(); - //return false; } } else { @@ -281,9 +257,13 @@ bool NumericalFunctor::GetPoints(const SMDS_MeshElement* anElem, } if ( anIter ) { + double xyz[3]; while( anIter->more() ) { if ( const SMDS_MeshNode* aNode = static_cast( anIter->next() )) - theRes.push_back( gp_XYZ( aNode->X(), aNode->Y(), aNode->Z() ) ); + { + aNode->GetXYZ( xyz ); + theRes.push_back( gp_XYZ( xyz[0], xyz[1], xyz[2] )); + } } } @@ -348,7 +328,7 @@ void NumericalFunctor::GetHistogram(int nbIntervals, std::multiset< double > values; if ( elements.empty() ) { - SMDS_ElemIteratorPtr elemIt = myMesh->elementsIterator(GetType()); + SMDS_ElemIteratorPtr elemIt = myMesh->elementsIterator( GetType() ); while ( elemIt->more() ) values.insert( GetValue( elemIt->next()->GetID() )); } @@ -481,6 +461,27 @@ double MaxElementLength2D::GetValue( const TSequenceOfXYZ& P ) double D2 = getDistance(P( 3 ),P( 7 )); aVal = Max(Max(Max(L1,L2),Max(L3,L4)),Max(D1,D2)); } + // Diagonals are undefined for concave polygons + // else if ( P.getElementEntity() == SMDSEntity_Quad_Polygon && P.size() > 2 ) // quad polygon + // { + // // sides + // aVal = getDistance( P( 1 ), P( P.size() )) + getDistance( P( P.size() ), P( P.size()-1 )); + // for ( size_t i = 1; i < P.size()-1; i += 2 ) + // { + // double L = getDistance( P( i ), P( i+1 )) + getDistance( P( i+1 ), P( i+2 )); + // aVal = Max( aVal, L ); + // } + // // diagonals + // for ( int i = P.size()-5; i > 0; i -= 2 ) + // for ( int j = i + 4; j < P.size() + i - 2; i += 2 ) + // { + // double D = getDistance( P( i ), P( j )); + // aVal = Max( aVal, D ); + // } + // } + // { // polygons + + // } if( myPrecision >= 0 ) { @@ -699,8 +700,9 @@ double MinimumAngle::GetValue( const TSequenceOfXYZ& P ) aMin = getAngle(P( P.size() ), P( 1 ), P( 2 )); aMin = Min(aMin,getAngle(P( P.size()-1 ), P( P.size() ), P( 1 ))); - for (int i=2; i 2 ) { + if ( P.size() > 2 ) + { gp_Vec aVec1( P(2) - P(1) ); gp_Vec aVec2( P(3) - P(1) ); gp_Vec SumVec = aVec1 ^ aVec2; - for (int i=4; i<=P.size(); i++) { + + for (int i=4; i<=P.size(); i++) + { gp_Vec aVec1( P(i-1) - P(1) ); gp_Vec aVec2( P(i) - P(1) ); gp_Vec tmp = aVec1 ^ aVec2; @@ -1523,7 +1528,7 @@ SMDSAbs_ElementType Length::GetType() const //================================================================================ /* Class : Length2D - Description : Functor for calculating length of edge + Description : Functor for calculating minimal length of edge */ //================================================================================ @@ -1531,63 +1536,59 @@ double Length2D::GetValue( long theElementId ) { TSequenceOfXYZ P; - //cout<<"Length2D::GetValue"<FindElement( theElementId ); - SMDSAbs_ElementType aType = aElem->GetType(); - + if ( GetPoints( theElementId, P )) + { + double aVal = 0; int len = P.size(); + SMDSAbs_EntityType aType = P.getElementEntity(); - switch (aType){ - case SMDSAbs_All: - case SMDSAbs_Node: - case SMDSAbs_Edge: - if (len == 2){ + switch (aType) { + case SMDSEntity_Edge: + if (len == 2) aVal = getDistance( P( 1 ), P( 2 ) ); - break; - } - else if (len == 3){ // quadratic edge + break; + case SMDSEntity_Quad_Edge: + if (len == 3) // quadratic edge aVal = getDistance(P( 1 ),P( 3 )) + getDistance(P( 3 ),P( 2 )); - break; - } - case SMDSAbs_Face: + break; + case SMDSEntity_Triangle: if (len == 3){ // triangles double L1 = getDistance(P( 1 ),P( 2 )); double L2 = getDistance(P( 2 ),P( 3 )); double L3 = getDistance(P( 3 ),P( 1 )); aVal = Min(L1,Min(L2,L3)); - break; } - else if (len == 4){ // quadrangles + break; + case SMDSEntity_Quadrangle: + if (len == 4){ // quadrangles double L1 = getDistance(P( 1 ),P( 2 )); double L2 = getDistance(P( 2 ),P( 3 )); double L3 = getDistance(P( 3 ),P( 4 )); double L4 = getDistance(P( 4 ),P( 1 )); aVal = Min(Min(L1,L2),Min(L3,L4)); - break; } - if (len == 6){ // quadratic triangles + break; + case SMDSEntity_Quad_Triangle: + case SMDSEntity_BiQuad_Triangle: + if (len >= 6){ // quadratic triangles double L1 = getDistance(P( 1 ),P( 2 )) + getDistance(P( 2 ),P( 3 )); double L2 = getDistance(P( 3 ),P( 4 )) + getDistance(P( 4 ),P( 5 )); double L3 = getDistance(P( 5 ),P( 6 )) + getDistance(P( 6 ),P( 1 )); aVal = Min(L1,Min(L2,L3)); - //cout<<"L1="< -#include +#include "utilities.h" + +//#include #ifdef _DEBUG_ static int MYDEBUG = 1; @@ -62,579 +63,836 @@ namespace DriverMED const TID2FamilyMap& myFamilies); /*! * \brief Ensure aFamily has a required ID - * \param aFamily - a family to check - * \param anID - an ID aFamily should have - * \param myFamilies - a map of the family ID to the Family - * \retval bool - true if successful + * \param aFamily - a family to check + * \param anID - an ID aFamily should have + * \param myFamilies - a map of the family ID to the Family + * \retval bool - true if successful */ bool checkFamilyID(DriverMED_FamilyPtr & aFamily, int anID, const TID2FamilyMap& myFamilies); -} -void -DriverMED_R_SMESHDS_Mesh -::SetMeshName(string theMeshName) -{ - myMeshName = theMeshName; + + const SMDS_MeshNode* FindNode(const SMDS_Mesh* theMesh, TInt theId) + { + const SMDS_MeshNode* aNode = theMesh->FindNode(theId); + if(aNode) return aNode; + EXCEPTION(runtime_error,"SMDS_Mesh::FindNode - cannot find a SMDS_MeshNode for ID = "<FindNode(theId); - if(aNode) return aNode; - EXCEPTION(runtime_error,"SMDS_Mesh::FindNode - cannot find a SMDS_MeshNode for ID = "<GetNbMeshes()){ - for(int iMesh = 0; iMesh < aNbMeshes; iMesh++){ - // Reading the MED mesh - //--------------------- - PMeshInfo aMeshInfo = aMed->GetPMeshInfo(iMesh+1); + TInt aNbMeshes = aMed->GetNbMeshes(); + for (int iMesh = 0; iMesh < aNbMeshes; iMesh++) + { + // Reading the MED mesh + //--------------------- + PMeshInfo aMeshInfo = aMed->GetPMeshInfo(iMesh+1); - string aMeshName; - if (myMeshId != -1) { - ostringstream aMeshNameStr; - aMeshNameStr<GetName()); - if(aMeshName != aMeshInfo->GetName()) continue; - aResult = DRS_OK; - - // Reading MED families to the temporary structure - //------------------------------------------------ - TErr anErr; - TInt aNbFams = aMed->GetNbFamilies(aMeshInfo); - if(MYDEBUG) MESSAGE("Read " << aNbFams << " families"); - for (TInt iFam = 0; iFam < aNbFams; iFam++) { - PFamilyInfo aFamilyInfo = aMed->GetPFamilyInfo(aMeshInfo,iFam+1,&anErr); - if(anErr >= 0){ - TInt aFamId = aFamilyInfo->GetId(); - if(MYDEBUG) MESSAGE("Family " << aFamId << " :"); - - DriverMED_FamilyPtr aFamily (new DriverMED_Family); - - TInt aNbGrp = aFamilyInfo->GetNbGroup(); - if(MYDEBUG) MESSAGE("belong to " << aNbGrp << " groups"); - bool isAttrOk = false; - if(aFamilyInfo->GetNbAttr() == aNbGrp) - isAttrOk = true; - for (TInt iGr = 0; iGr < aNbGrp; iGr++) { - string aGroupName = aFamilyInfo->GetGroupName(iGr); - if(isAttrOk){ - TInt anAttrVal = aFamilyInfo->GetAttrVal(iGr); - aFamily->SetGroupAttributVal(anAttrVal); - } - - if(MYDEBUG) MESSAGE(aGroupName); - aFamily->AddGroupName(aGroupName); - + string aMeshName; + if (myMeshId != -1) aMeshName = SMESH_Comment( myMeshId ); + else aMeshName = myMeshName; + + if(MYDEBUG) MESSAGE("Perform - aMeshName : "<GetName()); + if ( aMeshName != aMeshInfo->GetName() ) continue; + aResult = DRS_OK; + + // Reading MED families to the temporary structure + //------------------------------------------------ + TErr anErr; + TInt aNbFams = aMed->GetNbFamilies(aMeshInfo); + if(MYDEBUG) MESSAGE("Read " << aNbFams << " families"); + for (TInt iFam = 0; iFam < aNbFams; iFam++) + { + PFamilyInfo aFamilyInfo = aMed->GetPFamilyInfo(aMeshInfo,iFam+1,&anErr); + if(anErr >= 0){ + TInt aFamId = aFamilyInfo->GetId(); + if(MYDEBUG) MESSAGE("Family " << aFamId << " :"); + + DriverMED_FamilyPtr aFamily (new DriverMED_Family); + + TInt aNbGrp = aFamilyInfo->GetNbGroup(); + if(MYDEBUG) MESSAGE("belong to " << aNbGrp << " groups"); + bool isAttrOk = false; + if(aFamilyInfo->GetNbAttr() == aNbGrp) + isAttrOk = true; + for (TInt iGr = 0; iGr < aNbGrp; iGr++) + { + string aGroupName = aFamilyInfo->GetGroupName(iGr); + if ( isAttrOk ) { + TInt anAttrVal = aFamilyInfo->GetAttrVal(iGr); + aFamily->SetGroupAttributVal(anAttrVal); } - aFamily->SetId( aFamId ); - myFamilies[aFamId] = aFamily; + if(MYDEBUG) MESSAGE(aGroupName); + aFamily->AddGroupName(aGroupName); } + aFamily->SetId( aFamId ); + myFamilies[aFamId] = aFamily; } + } - if (aMeshInfo->GetType() == MED::eSTRUCTURE){ - /*bool aRes = */DriverMED::buildMeshGrille(aMed,aMeshInfo,myMesh,myFamilies); - continue; - } + if (aMeshInfo->GetType() == MED::eSTRUCTURE) + { + /*bool aRes = */DriverMED::buildMeshGrille(aMed,aMeshInfo,myMesh,myFamilies); + continue; + } - // Reading MED nodes to the corresponding SMDS structure - //------------------------------------------------------ - PNodeInfo aNodeInfo = aMed->GetPNodeInfo(aMeshInfo); - if (!aNodeInfo) { - aResult = DRS_FAIL; - continue; + // Reading MED nodes to the corresponding SMDS structure + //------------------------------------------------------ + PNodeInfo aNodeInfo = aMed->GetPNodeInfo(aMeshInfo); + if (!aNodeInfo) { + aResult = DRS_FAIL; + continue; + } + aMeshInfo->myDim=aMeshInfo->mySpaceDim;// ignore meshdim in MEDFile because it can be false + PCoordHelper aCoordHelper = GetCoordHelper(aNodeInfo); + + EBooleen anIsNodeNum = aNodeInfo->IsElemNum(); + TInt aNbElems = aNodeInfo->GetNbElem(); + if(MYDEBUG) MESSAGE("Perform - aNodeInfo->GetNbElem() = "<GetNbElem() = "<GetFamNum(iElem); + bool isRenum = false; + const SMDS_MeshElement* anElement = NULL; + TInt aFamNum = aCellInfo->GetFamNum(iElem); #ifndef _DEXCEPT_ - try{ + try{ #endif - //MESSAGE("Try to create element # " << iElem << " with id = " - // << aCellInfo->GetElemNum(iElem)); - switch(aGeom) { - case ePOINT1: - //anElement = FindNode(myMesh,aNodeIds[0]); - if(anIsElemNum) - anElement = myMesh->Add0DElementWithID - (aNodeIds[0], aCellInfo->GetElemNum(iElem)); - if (!anElement) { - anElement = myMesh->Add0DElement(FindNode(myMesh,aNodeIds[0])); - isRenum = anIsElemNum; - } - break; - case eSEG2: - if(anIsElemNum) - anElement = myMesh->AddEdgeWithID(aNodeIds[0], - aNodeIds[1], + //MESSAGE("Try to create element # " << iElem << " with id = " + // << aCellInfo->GetElemNum(iElem)); + switch(aGeom) { + case ePOINT1: + //anElement = FindNode(myMesh,aNodeIds[0]); + if(anIsElemNum) + anElement = myMesh->Add0DElementWithID + (aNodeIds[0], aCellInfo->GetElemNum(iElem)); + if (!anElement) { + anElement = myMesh->Add0DElement(FindNode(myMesh,aNodeIds[0])); + isRenum = anIsElemNum; + } + break; + case eSEG2: + if(anIsElemNum) + anElement = myMesh->AddEdgeWithID(aNodeIds[0], + aNodeIds[1], + aCellInfo->GetElemNum(iElem)); + if (!anElement) { + anElement = myMesh->AddEdge(FindNode(myMesh,aNodeIds[0]), + FindNode(myMesh,aNodeIds[1])); + isRenum = anIsElemNum; + } + break; + case eSEG3: + if(anIsElemNum) + anElement = myMesh->AddEdgeWithID(aNodeIds[0], + aNodeIds[1], + aNodeIds[2], + aCellInfo->GetElemNum(iElem)); + if (!anElement) { + anElement = myMesh->AddEdge(FindNode(myMesh,aNodeIds[0]), + FindNode(myMesh,aNodeIds[1]), + FindNode(myMesh,aNodeIds[2])); + isRenum = anIsElemNum; + } + break; + case eTRIA3: + aNbNodes = 3; + if(anIsElemNum) + anElement = myMesh->AddFaceWithID(aNodeIds[0], + aNodeIds[1], + aNodeIds[2], + aCellInfo->GetElemNum(iElem)); + if (!anElement) { + anElement = myMesh->AddFace(FindNode(myMesh,aNodeIds[0]), + FindNode(myMesh,aNodeIds[1]), + FindNode(myMesh,aNodeIds[2])); + isRenum = anIsElemNum; + } + break; + case eTRIA6: + aNbNodes = 6; + if(anIsElemNum) + anElement = myMesh->AddFaceWithID(aNodeIds[0], aNodeIds[1], + aNodeIds[2], aNodeIds[3], + aNodeIds[4], aNodeIds[5], + aCellInfo->GetElemNum(iElem)); + if (!anElement) { + anElement = myMesh->AddFace(FindNode(myMesh,aNodeIds[0]), + FindNode(myMesh,aNodeIds[1]), + FindNode(myMesh,aNodeIds[2]), + FindNode(myMesh,aNodeIds[3]), + FindNode(myMesh,aNodeIds[4]), + FindNode(myMesh,aNodeIds[5])); + isRenum = anIsElemNum; + } + break; + case eTRIA7: + aNbNodes = 7; + if(anIsElemNum) + anElement = myMesh->AddFaceWithID(aNodeIds[0], aNodeIds[1], + aNodeIds[2], aNodeIds[3], + aNodeIds[4], aNodeIds[5], aNodeIds[6], + aCellInfo->GetElemNum(iElem)); + if (!anElement) { + anElement = myMesh->AddFace(FindNode(myMesh,aNodeIds[0]), + FindNode(myMesh,aNodeIds[1]), + FindNode(myMesh,aNodeIds[2]), + FindNode(myMesh,aNodeIds[3]), + FindNode(myMesh,aNodeIds[4]), + FindNode(myMesh,aNodeIds[5]), + FindNode(myMesh,aNodeIds[6])); + isRenum = anIsElemNum; + } + break; + case eQUAD4: + aNbNodes = 4; + if(anIsElemNum) + anElement = myMesh->AddFaceWithID(aNodeIds[0], aNodeIds[1], + aNodeIds[2], aNodeIds[3], + aCellInfo->GetElemNum(iElem)); + if (!anElement) { + anElement = myMesh->AddFace(FindNode(myMesh,aNodeIds[0]), + FindNode(myMesh,aNodeIds[1]), + FindNode(myMesh,aNodeIds[2]), + FindNode(myMesh,aNodeIds[3])); + isRenum = anIsElemNum; + } + break; + case eQUAD8: + aNbNodes = 8; + if(anIsElemNum) + anElement = myMesh->AddFaceWithID(aNodeIds[0], aNodeIds[1], + aNodeIds[2], aNodeIds[3], + aNodeIds[4], aNodeIds[5], + aNodeIds[6], aNodeIds[7], + aCellInfo->GetElemNum(iElem)); + if (!anElement) { + anElement = myMesh->AddFace(FindNode(myMesh,aNodeIds[0]), + FindNode(myMesh,aNodeIds[1]), + FindNode(myMesh,aNodeIds[2]), + FindNode(myMesh,aNodeIds[3]), + FindNode(myMesh,aNodeIds[4]), + FindNode(myMesh,aNodeIds[5]), + FindNode(myMesh,aNodeIds[6]), + FindNode(myMesh,aNodeIds[7])); + isRenum = anIsElemNum; + } + break; + case eQUAD9: + aNbNodes = 9; + if(anIsElemNum) + anElement = myMesh->AddFaceWithID(aNodeIds[0], aNodeIds[1], + aNodeIds[2], aNodeIds[3], + aNodeIds[4], aNodeIds[5], + aNodeIds[6], aNodeIds[7], aNodeIds[8], + aCellInfo->GetElemNum(iElem)); + if (!anElement) { + anElement = myMesh->AddFace(FindNode(myMesh,aNodeIds[0]), + FindNode(myMesh,aNodeIds[1]), + FindNode(myMesh,aNodeIds[2]), + FindNode(myMesh,aNodeIds[3]), + FindNode(myMesh,aNodeIds[4]), + FindNode(myMesh,aNodeIds[5]), + FindNode(myMesh,aNodeIds[6]), + FindNode(myMesh,aNodeIds[7]), + FindNode(myMesh,aNodeIds[8])); + isRenum = anIsElemNum; + } + break; + case eTETRA4: + aNbNodes = 4; + if(anIsElemNum) + anElement = myMesh->AddVolumeWithID(aNodeIds[0], aNodeIds[1], + aNodeIds[2], aNodeIds[3], aCellInfo->GetElemNum(iElem)); - if (!anElement) { - anElement = myMesh->AddEdge(FindNode(myMesh,aNodeIds[0]), - FindNode(myMesh,aNodeIds[1])); - isRenum = anIsElemNum; - } - break; - case eSEG3: - if(anIsElemNum) - anElement = myMesh->AddEdgeWithID(aNodeIds[0], - aNodeIds[1], - aNodeIds[2], + if (!anElement) { + anElement = myMesh->AddVolume(FindNode(myMesh,aNodeIds[0]), + FindNode(myMesh,aNodeIds[1]), + FindNode(myMesh,aNodeIds[2]), + FindNode(myMesh,aNodeIds[3])); + isRenum = anIsElemNum; + } + break; + case eTETRA10: + aNbNodes = 10; + if(anIsElemNum) + anElement = myMesh->AddVolumeWithID(aNodeIds[0], aNodeIds[1], + aNodeIds[2], aNodeIds[3], + aNodeIds[4], aNodeIds[5], + aNodeIds[6], aNodeIds[7], + aNodeIds[8], aNodeIds[9], aCellInfo->GetElemNum(iElem)); - if (!anElement) { - anElement = myMesh->AddEdge(FindNode(myMesh,aNodeIds[0]), + if (!anElement) { + anElement = myMesh->AddVolume(FindNode(myMesh,aNodeIds[0]), FindNode(myMesh,aNodeIds[1]), - FindNode(myMesh,aNodeIds[2])); - isRenum = anIsElemNum; - } - break; - case eTRIA3: - aNbNodes = 3; - if(anIsElemNum) - anElement = myMesh->AddFaceWithID(aNodeIds[0], - aNodeIds[1], - aNodeIds[2], + FindNode(myMesh,aNodeIds[2]), + FindNode(myMesh,aNodeIds[3]), + FindNode(myMesh,aNodeIds[4]), + FindNode(myMesh,aNodeIds[5]), + FindNode(myMesh,aNodeIds[6]), + FindNode(myMesh,aNodeIds[7]), + FindNode(myMesh,aNodeIds[8]), + FindNode(myMesh,aNodeIds[9])); + isRenum = anIsElemNum; + } + break; + case ePYRA5: + aNbNodes = 5; + if(anIsElemNum) + anElement = myMesh->AddVolumeWithID(aNodeIds[0], aNodeIds[1], + aNodeIds[2], aNodeIds[3], + aNodeIds[4], aCellInfo->GetElemNum(iElem)); - if (!anElement) { - anElement = myMesh->AddFace(FindNode(myMesh,aNodeIds[0]), + if (!anElement) { + anElement = myMesh->AddVolume(FindNode(myMesh,aNodeIds[0]), FindNode(myMesh,aNodeIds[1]), - FindNode(myMesh,aNodeIds[2])); - isRenum = anIsElemNum; - } - break; - case eTRIA6: - aNbNodes = 6; - if(anIsElemNum) - anElement = myMesh->AddFaceWithID(aNodeIds[0], aNodeIds[1], + FindNode(myMesh,aNodeIds[2]), + FindNode(myMesh,aNodeIds[3]), + FindNode(myMesh,aNodeIds[4])); + isRenum = anIsElemNum; + } + break; + case ePYRA13: + aNbNodes = 13; + if(anIsElemNum) + anElement = myMesh->AddVolumeWithID(aNodeIds[0], aNodeIds[1], aNodeIds[2], aNodeIds[3], aNodeIds[4], aNodeIds[5], + aNodeIds[6], aNodeIds[7], + aNodeIds[8], aNodeIds[9], + aNodeIds[10], aNodeIds[11], + aNodeIds[12], + aCellInfo->GetElemNum(iElem)); + if (!anElement) { + anElement = myMesh->AddVolume(FindNode(myMesh,aNodeIds[0]), + FindNode(myMesh,aNodeIds[1]), + FindNode(myMesh,aNodeIds[2]), + FindNode(myMesh,aNodeIds[3]), + FindNode(myMesh,aNodeIds[4]), + FindNode(myMesh,aNodeIds[5]), + FindNode(myMesh,aNodeIds[6]), + FindNode(myMesh,aNodeIds[7]), + FindNode(myMesh,aNodeIds[8]), + FindNode(myMesh,aNodeIds[9]), + FindNode(myMesh,aNodeIds[10]), + FindNode(myMesh,aNodeIds[11]), + FindNode(myMesh,aNodeIds[12])); + isRenum = anIsElemNum; + } + break; + case ePENTA6: + aNbNodes = 6; + if(anIsElemNum) + anElement = myMesh->AddVolumeWithID(aNodeIds[0], + aNodeIds[1], + aNodeIds[2], + aNodeIds[3], + aNodeIds[4], + aNodeIds[5], aCellInfo->GetElemNum(iElem)); - if (!anElement) { - anElement = myMesh->AddFace(FindNode(myMesh,aNodeIds[0]), + if (!anElement) { + anElement = myMesh->AddVolume(FindNode(myMesh,aNodeIds[0]), FindNode(myMesh,aNodeIds[1]), FindNode(myMesh,aNodeIds[2]), FindNode(myMesh,aNodeIds[3]), FindNode(myMesh,aNodeIds[4]), FindNode(myMesh,aNodeIds[5])); - isRenum = anIsElemNum; - } - break; - case eTRIA7: - aNbNodes = 7; - if(anIsElemNum) - anElement = myMesh->AddFaceWithID(aNodeIds[0], aNodeIds[1], + isRenum = anIsElemNum; + } + break; + case ePENTA15: + aNbNodes = 15; + if(anIsElemNum) + anElement = myMesh->AddVolumeWithID(aNodeIds[0], aNodeIds[1], aNodeIds[2], aNodeIds[3], - aNodeIds[4], aNodeIds[5], aNodeIds[6], + aNodeIds[4], aNodeIds[5], + aNodeIds[6], aNodeIds[7], + aNodeIds[8], aNodeIds[9], + aNodeIds[10], aNodeIds[11], + aNodeIds[12], aNodeIds[13], + aNodeIds[14], aCellInfo->GetElemNum(iElem)); - if (!anElement) { - anElement = myMesh->AddFace(FindNode(myMesh,aNodeIds[0]), + if (!anElement) { + anElement = myMesh->AddVolume(FindNode(myMesh,aNodeIds[0]), FindNode(myMesh,aNodeIds[1]), FindNode(myMesh,aNodeIds[2]), FindNode(myMesh,aNodeIds[3]), FindNode(myMesh,aNodeIds[4]), FindNode(myMesh,aNodeIds[5]), - FindNode(myMesh,aNodeIds[6])); - isRenum = anIsElemNum; - } - break; - case eQUAD4: - aNbNodes = 4; - if(anIsElemNum) - anElement = myMesh->AddFaceWithID(aNodeIds[0], aNodeIds[1], - aNodeIds[2], aNodeIds[3], + FindNode(myMesh,aNodeIds[6]), + FindNode(myMesh,aNodeIds[7]), + FindNode(myMesh,aNodeIds[8]), + FindNode(myMesh,aNodeIds[9]), + FindNode(myMesh,aNodeIds[10]), + FindNode(myMesh,aNodeIds[11]), + FindNode(myMesh,aNodeIds[12]), + FindNode(myMesh,aNodeIds[13]), + FindNode(myMesh,aNodeIds[14])); + isRenum = anIsElemNum; + } + break; + case eHEXA8: + aNbNodes = 8; + if(anIsElemNum) + anElement = myMesh->AddVolumeWithID(aNodeIds[0], + aNodeIds[1], + aNodeIds[2], + aNodeIds[3], + aNodeIds[4], + aNodeIds[5], + aNodeIds[6], + aNodeIds[7], aCellInfo->GetElemNum(iElem)); - if (!anElement) { - anElement = myMesh->AddFace(FindNode(myMesh,aNodeIds[0]), + if (!anElement) { + anElement = myMesh->AddVolume(FindNode(myMesh,aNodeIds[0]), FindNode(myMesh,aNodeIds[1]), FindNode(myMesh,aNodeIds[2]), - FindNode(myMesh,aNodeIds[3])); - isRenum = anIsElemNum; - } - break; - case eQUAD8: - aNbNodes = 8; - if(anIsElemNum) - anElement = myMesh->AddFaceWithID(aNodeIds[0], aNodeIds[1], + FindNode(myMesh,aNodeIds[3]), + FindNode(myMesh,aNodeIds[4]), + FindNode(myMesh,aNodeIds[5]), + FindNode(myMesh,aNodeIds[6]), + FindNode(myMesh,aNodeIds[7])); + isRenum = anIsElemNum; + } + break; + + case eHEXA20: + aNbNodes = 20; + if(anIsElemNum) + anElement = myMesh->AddVolumeWithID(aNodeIds[0], aNodeIds[1], aNodeIds[2], aNodeIds[3], aNodeIds[4], aNodeIds[5], aNodeIds[6], aNodeIds[7], + aNodeIds[8], aNodeIds[9], + aNodeIds[10], aNodeIds[11], + aNodeIds[12], aNodeIds[13], + aNodeIds[14], aNodeIds[15], + aNodeIds[16], aNodeIds[17], + aNodeIds[18], aNodeIds[19], aCellInfo->GetElemNum(iElem)); - if (!anElement) { - anElement = myMesh->AddFace(FindNode(myMesh,aNodeIds[0]), + if (!anElement) { + anElement = myMesh->AddVolume(FindNode(myMesh,aNodeIds[0]), FindNode(myMesh,aNodeIds[1]), FindNode(myMesh,aNodeIds[2]), FindNode(myMesh,aNodeIds[3]), FindNode(myMesh,aNodeIds[4]), FindNode(myMesh,aNodeIds[5]), FindNode(myMesh,aNodeIds[6]), - FindNode(myMesh,aNodeIds[7])); - isRenum = anIsElemNum; - } - break; - case eQUAD9: - aNbNodes = 9; - if(anIsElemNum) - anElement = myMesh->AddFaceWithID(aNodeIds[0], aNodeIds[1], + FindNode(myMesh,aNodeIds[7]), + FindNode(myMesh,aNodeIds[8]), + FindNode(myMesh,aNodeIds[9]), + FindNode(myMesh,aNodeIds[10]), + FindNode(myMesh,aNodeIds[11]), + FindNode(myMesh,aNodeIds[12]), + FindNode(myMesh,aNodeIds[13]), + FindNode(myMesh,aNodeIds[14]), + FindNode(myMesh,aNodeIds[15]), + FindNode(myMesh,aNodeIds[16]), + FindNode(myMesh,aNodeIds[17]), + FindNode(myMesh,aNodeIds[18]), + FindNode(myMesh,aNodeIds[19])); + isRenum = anIsElemNum; + } + break; + + case eHEXA27: + aNbNodes = 27; + if(anIsElemNum) + anElement = myMesh->AddVolumeWithID(aNodeIds[0], aNodeIds[1], aNodeIds[2], aNodeIds[3], aNodeIds[4], aNodeIds[5], - aNodeIds[6], aNodeIds[7], aNodeIds[8], + aNodeIds[6], aNodeIds[7], + aNodeIds[8], aNodeIds[9], + aNodeIds[10], aNodeIds[11], + aNodeIds[12], aNodeIds[13], + aNodeIds[14], aNodeIds[15], + aNodeIds[16], aNodeIds[17], + aNodeIds[18], aNodeIds[19], + aNodeIds[20], aNodeIds[21], + aNodeIds[22], aNodeIds[23], + aNodeIds[24], aNodeIds[25], + aNodeIds[26], aCellInfo->GetElemNum(iElem)); - if (!anElement) { - anElement = myMesh->AddFace(FindNode(myMesh,aNodeIds[0]), + if (!anElement) { + anElement = myMesh->AddVolume(FindNode(myMesh,aNodeIds[0]), FindNode(myMesh,aNodeIds[1]), FindNode(myMesh,aNodeIds[2]), FindNode(myMesh,aNodeIds[3]), @@ -642,322 +900,98 @@ DriverMED_R_SMESHDS_Mesh FindNode(myMesh,aNodeIds[5]), FindNode(myMesh,aNodeIds[6]), FindNode(myMesh,aNodeIds[7]), - FindNode(myMesh,aNodeIds[8])); - isRenum = anIsElemNum; - } - break; - case eTETRA4: - aNbNodes = 4; - if(anIsElemNum) - anElement = myMesh->AddVolumeWithID(aNodeIds[0], aNodeIds[1], - aNodeIds[2], aNodeIds[3], - aCellInfo->GetElemNum(iElem)); - if (!anElement) { - anElement = myMesh->AddVolume(FindNode(myMesh,aNodeIds[0]), - FindNode(myMesh,aNodeIds[1]), - FindNode(myMesh,aNodeIds[2]), - FindNode(myMesh,aNodeIds[3])); - isRenum = anIsElemNum; - } - break; - case eTETRA10: - aNbNodes = 10; - if(anIsElemNum) - anElement = myMesh->AddVolumeWithID(aNodeIds[0], aNodeIds[1], - aNodeIds[2], aNodeIds[3], - aNodeIds[4], aNodeIds[5], - aNodeIds[6], aNodeIds[7], - aNodeIds[8], aNodeIds[9], - aCellInfo->GetElemNum(iElem)); - if (!anElement) { - anElement = myMesh->AddVolume(FindNode(myMesh,aNodeIds[0]), - FindNode(myMesh,aNodeIds[1]), - FindNode(myMesh,aNodeIds[2]), - FindNode(myMesh,aNodeIds[3]), - FindNode(myMesh,aNodeIds[4]), - FindNode(myMesh,aNodeIds[5]), - FindNode(myMesh,aNodeIds[6]), - FindNode(myMesh,aNodeIds[7]), - FindNode(myMesh,aNodeIds[8]), - FindNode(myMesh,aNodeIds[9])); - isRenum = anIsElemNum; - } - break; - case ePYRA5: - aNbNodes = 5; - if(anIsElemNum) - anElement = myMesh->AddVolumeWithID(aNodeIds[0], aNodeIds[1], - aNodeIds[2], aNodeIds[3], - aNodeIds[4], - aCellInfo->GetElemNum(iElem)); - if (!anElement) { - anElement = myMesh->AddVolume(FindNode(myMesh,aNodeIds[0]), - FindNode(myMesh,aNodeIds[1]), - FindNode(myMesh,aNodeIds[2]), - FindNode(myMesh,aNodeIds[3]), - FindNode(myMesh,aNodeIds[4])); - isRenum = anIsElemNum; - } - break; - case ePYRA13: - aNbNodes = 13; - if(anIsElemNum) - anElement = myMesh->AddVolumeWithID(aNodeIds[0], aNodeIds[1], - aNodeIds[2], aNodeIds[3], - aNodeIds[4], aNodeIds[5], - aNodeIds[6], aNodeIds[7], - aNodeIds[8], aNodeIds[9], - aNodeIds[10], aNodeIds[11], - aNodeIds[12], - aCellInfo->GetElemNum(iElem)); - if (!anElement) { - anElement = myMesh->AddVolume(FindNode(myMesh,aNodeIds[0]), - FindNode(myMesh,aNodeIds[1]), - FindNode(myMesh,aNodeIds[2]), - FindNode(myMesh,aNodeIds[3]), - FindNode(myMesh,aNodeIds[4]), - FindNode(myMesh,aNodeIds[5]), - FindNode(myMesh,aNodeIds[6]), - FindNode(myMesh,aNodeIds[7]), - FindNode(myMesh,aNodeIds[8]), - FindNode(myMesh,aNodeIds[9]), - FindNode(myMesh,aNodeIds[10]), - FindNode(myMesh,aNodeIds[11]), - FindNode(myMesh,aNodeIds[12])); - isRenum = anIsElemNum; - } - break; - case ePENTA6: - aNbNodes = 6; - if(anIsElemNum) - anElement = myMesh->AddVolumeWithID(aNodeIds[0], - aNodeIds[1], - aNodeIds[2], - aNodeIds[3], - aNodeIds[4], - aNodeIds[5], - aCellInfo->GetElemNum(iElem)); - if (!anElement) { - anElement = myMesh->AddVolume(FindNode(myMesh,aNodeIds[0]), - FindNode(myMesh,aNodeIds[1]), - FindNode(myMesh,aNodeIds[2]), - FindNode(myMesh,aNodeIds[3]), - FindNode(myMesh,aNodeIds[4]), - FindNode(myMesh,aNodeIds[5])); - isRenum = anIsElemNum; - } - break; - case ePENTA15: - aNbNodes = 15; - if(anIsElemNum) - anElement = myMesh->AddVolumeWithID(aNodeIds[0], aNodeIds[1], - aNodeIds[2], aNodeIds[3], - aNodeIds[4], aNodeIds[5], - aNodeIds[6], aNodeIds[7], - aNodeIds[8], aNodeIds[9], - aNodeIds[10], aNodeIds[11], - aNodeIds[12], aNodeIds[13], - aNodeIds[14], - aCellInfo->GetElemNum(iElem)); - if (!anElement) { - anElement = myMesh->AddVolume(FindNode(myMesh,aNodeIds[0]), - FindNode(myMesh,aNodeIds[1]), - FindNode(myMesh,aNodeIds[2]), - FindNode(myMesh,aNodeIds[3]), + FindNode(myMesh,aNodeIds[8]), + FindNode(myMesh,aNodeIds[9]), + FindNode(myMesh,aNodeIds[10]), + FindNode(myMesh,aNodeIds[11]), + FindNode(myMesh,aNodeIds[12]), + FindNode(myMesh,aNodeIds[13]), + FindNode(myMesh,aNodeIds[14]), + FindNode(myMesh,aNodeIds[15]), + FindNode(myMesh,aNodeIds[16]), + FindNode(myMesh,aNodeIds[17]), + FindNode(myMesh,aNodeIds[18]), + FindNode(myMesh,aNodeIds[19]), + FindNode(myMesh,aNodeIds[20]), + FindNode(myMesh,aNodeIds[21]), + FindNode(myMesh,aNodeIds[22]), + FindNode(myMesh,aNodeIds[23]), + FindNode(myMesh,aNodeIds[24]), + FindNode(myMesh,aNodeIds[25]), + FindNode(myMesh,aNodeIds[26])); + isRenum = anIsElemNum; + } + break; + + case eOCTA12: + aNbNodes = 12; + if(anIsElemNum) + anElement = myMesh->AddVolumeWithID(aNodeIds[0], aNodeIds[1], + aNodeIds[2], aNodeIds[3], + aNodeIds[4], aNodeIds[5], + aNodeIds[6], aNodeIds[7], + aNodeIds[8], aNodeIds[9], + aNodeIds[10], aNodeIds[11], + aCellInfo->GetElemNum(iElem)); + if (!anElement) { + anElement = myMesh->AddVolume(FindNode(myMesh,aNodeIds[0]), + FindNode(myMesh,aNodeIds[1]), + FindNode(myMesh,aNodeIds[2]), + FindNode(myMesh,aNodeIds[3]), FindNode(myMesh,aNodeIds[4]), - FindNode(myMesh,aNodeIds[5]), - FindNode(myMesh,aNodeIds[6]), - FindNode(myMesh,aNodeIds[7]), - FindNode(myMesh,aNodeIds[8]), - FindNode(myMesh,aNodeIds[9]), - FindNode(myMesh,aNodeIds[10]), - FindNode(myMesh,aNodeIds[11]), - FindNode(myMesh,aNodeIds[12]), - FindNode(myMesh,aNodeIds[13]), - FindNode(myMesh,aNodeIds[14])); - isRenum = anIsElemNum; - } - break; - case eHEXA8: - aNbNodes = 8; - if(anIsElemNum) - anElement = myMesh->AddVolumeWithID(aNodeIds[0], - aNodeIds[1], - aNodeIds[2], - aNodeIds[3], - aNodeIds[4], - aNodeIds[5], - aNodeIds[6], - aNodeIds[7], - aCellInfo->GetElemNum(iElem)); - if (!anElement) { - anElement = myMesh->AddVolume(FindNode(myMesh,aNodeIds[0]), - FindNode(myMesh,aNodeIds[1]), - FindNode(myMesh,aNodeIds[2]), - FindNode(myMesh,aNodeIds[3]), - FindNode(myMesh,aNodeIds[4]), - FindNode(myMesh,aNodeIds[5]), - FindNode(myMesh,aNodeIds[6]), - FindNode(myMesh,aNodeIds[7])); - isRenum = anIsElemNum; - } - break; - - case eHEXA20: - aNbNodes = 20; - if(anIsElemNum) - anElement = myMesh->AddVolumeWithID(aNodeIds[0], aNodeIds[1], - aNodeIds[2], aNodeIds[3], - aNodeIds[4], aNodeIds[5], - aNodeIds[6], aNodeIds[7], - aNodeIds[8], aNodeIds[9], - aNodeIds[10], aNodeIds[11], - aNodeIds[12], aNodeIds[13], - aNodeIds[14], aNodeIds[15], - aNodeIds[16], aNodeIds[17], - aNodeIds[18], aNodeIds[19], - aCellInfo->GetElemNum(iElem)); - if (!anElement) { - anElement = myMesh->AddVolume(FindNode(myMesh,aNodeIds[0]), - FindNode(myMesh,aNodeIds[1]), - FindNode(myMesh,aNodeIds[2]), - FindNode(myMesh,aNodeIds[3]), - FindNode(myMesh,aNodeIds[4]), - FindNode(myMesh,aNodeIds[5]), - FindNode(myMesh,aNodeIds[6]), - FindNode(myMesh,aNodeIds[7]), - FindNode(myMesh,aNodeIds[8]), - FindNode(myMesh,aNodeIds[9]), - FindNode(myMesh,aNodeIds[10]), - FindNode(myMesh,aNodeIds[11]), - FindNode(myMesh,aNodeIds[12]), - FindNode(myMesh,aNodeIds[13]), - FindNode(myMesh,aNodeIds[14]), - FindNode(myMesh,aNodeIds[15]), - FindNode(myMesh,aNodeIds[16]), - FindNode(myMesh,aNodeIds[17]), - FindNode(myMesh,aNodeIds[18]), - FindNode(myMesh,aNodeIds[19])); - isRenum = anIsElemNum; - } - break; - - case eHEXA27: - aNbNodes = 27; - if(anIsElemNum) - anElement = myMesh->AddVolumeWithID(aNodeIds[0], aNodeIds[1], - aNodeIds[2], aNodeIds[3], - aNodeIds[4], aNodeIds[5], - aNodeIds[6], aNodeIds[7], - aNodeIds[8], aNodeIds[9], - aNodeIds[10], aNodeIds[11], - aNodeIds[12], aNodeIds[13], - aNodeIds[14], aNodeIds[15], - aNodeIds[16], aNodeIds[17], - aNodeIds[18], aNodeIds[19], - aNodeIds[20], aNodeIds[21], - aNodeIds[22], aNodeIds[23], - aNodeIds[24], aNodeIds[25], - aNodeIds[26], - aCellInfo->GetElemNum(iElem)); - if (!anElement) { - anElement = myMesh->AddVolume(FindNode(myMesh,aNodeIds[0]), - FindNode(myMesh,aNodeIds[1]), - FindNode(myMesh,aNodeIds[2]), - FindNode(myMesh,aNodeIds[3]), - FindNode(myMesh,aNodeIds[4]), - FindNode(myMesh,aNodeIds[5]), - FindNode(myMesh,aNodeIds[6]), - FindNode(myMesh,aNodeIds[7]), - FindNode(myMesh,aNodeIds[8]), - FindNode(myMesh,aNodeIds[9]), - FindNode(myMesh,aNodeIds[10]), - FindNode(myMesh,aNodeIds[11]), - FindNode(myMesh,aNodeIds[12]), - FindNode(myMesh,aNodeIds[13]), - FindNode(myMesh,aNodeIds[14]), - FindNode(myMesh,aNodeIds[15]), - FindNode(myMesh,aNodeIds[16]), - FindNode(myMesh,aNodeIds[17]), - FindNode(myMesh,aNodeIds[18]), - FindNode(myMesh,aNodeIds[19]), - FindNode(myMesh,aNodeIds[20]), - FindNode(myMesh,aNodeIds[21]), - FindNode(myMesh,aNodeIds[22]), - FindNode(myMesh,aNodeIds[23]), - FindNode(myMesh,aNodeIds[24]), - FindNode(myMesh,aNodeIds[25]), - FindNode(myMesh,aNodeIds[26])); - isRenum = anIsElemNum; - } - break; - - case eOCTA12: - aNbNodes = 12; - if(anIsElemNum) - anElement = myMesh->AddVolumeWithID(aNodeIds[0], aNodeIds[1], - aNodeIds[2], aNodeIds[3], - aNodeIds[4], aNodeIds[5], - aNodeIds[6], aNodeIds[7], - aNodeIds[8], aNodeIds[9], - aNodeIds[10], aNodeIds[11], - aCellInfo->GetElemNum(iElem)); - if (!anElement) { - anElement = myMesh->AddVolume(FindNode(myMesh,aNodeIds[0]), - FindNode(myMesh,aNodeIds[1]), - FindNode(myMesh,aNodeIds[2]), - FindNode(myMesh,aNodeIds[3]), - FindNode(myMesh,aNodeIds[4]), - FindNode(myMesh,aNodeIds[5]), - FindNode(myMesh,aNodeIds[6]), - FindNode(myMesh,aNodeIds[7]), - FindNode(myMesh,aNodeIds[8]), - FindNode(myMesh,aNodeIds[9]), - FindNode(myMesh,aNodeIds[10]), - FindNode(myMesh,aNodeIds[11])); - isRenum = anIsElemNum; - } - break; - - } // switch(aGeom) + FindNode(myMesh,aNodeIds[5]), + FindNode(myMesh,aNodeIds[6]), + FindNode(myMesh,aNodeIds[7]), + FindNode(myMesh,aNodeIds[8]), + FindNode(myMesh,aNodeIds[9]), + FindNode(myMesh,aNodeIds[10]), + FindNode(myMesh,aNodeIds[11])); + isRenum = anIsElemNum; + } + break; + + } // switch(aGeom) #ifndef _DEXCEPT_ - }catch(const std::exception& exc){ - INFOS("The following exception was caught:\n\t"<AddElement(anElement); - myFamilies[aFamNum]->SetType(anElement->GetType()); - } + if ( DriverMED::checkFamilyID ( aFamily, aFamNum, myFamilies )) { + // Save reference to this element from its family + myFamilies[aFamNum]->AddElement(anElement); + myFamilies[aFamNum]->SetType(anElement->GetType()); } } - }} - } + } + }} } - if (aDescendingEntitiesMap.Extent()) isDescConn = true; // Mantis issue 0020483 - } // for(int iMesh = 0; iMesh < aNbMeshes; iMesh++) - } // if aNbMeshes + } + if (aDescendingEntitiesMap.Extent()) isDescConn = true; // Mantis issue 0020483 + } // for(int iMesh = 0; iMesh < aNbMeshes; iMesh++) #ifndef _DEXCEPT_ - }catch(const std::exception& exc){ + } + catch(const std::exception& exc) + { INFOS("The following exception was caught:\n\t"<_geomType == ePOLYGONE ) + if ( aElemTypeData->_geomType == ePOLYGONE || + aElemTypeData->_geomType == ePOLYGON2 ) { - elemIterator = myMesh->elementGeomIterator( SMDSGeom_POLYGON ); + if ( aElemTypeData->_geomType == ePOLYGONE ) + elemIterator = myMesh->elementEntityIterator( SMDSEntity_Polygon ); + else + elemIterator = myMesh->elementEntityIterator( SMDSEntity_Quad_Polygon ); + if ( nbPolygonNodes == 0 ) { // Count nb of nodes while ( elemIterator->more() ) { @@ -758,9 +772,10 @@ Driver_Mesh::Status DriverMED_W_SMESHDS_Mesh::Perform() break; } myMed->SetPolygoneInfo(aPolygoneInfo); - } - } + nbPolygonNodes = 0; // to treat next polygon type + } + } // Treat POLYEDREs // ---------------- diff --git a/src/MEDWrapper/Base/MED_Common.hxx b/src/MEDWrapper/Base/MED_Common.hxx index 2b393f44c..ff12d3821 100644 --- a/src/MEDWrapper/Base/MED_Common.hxx +++ b/src/MEDWrapper/Base/MED_Common.hxx @@ -71,7 +71,7 @@ namespace MED{ eQUAD4=204, eTRIA6=206, eTRIA7=207, eQUAD8=208, eQUAD9=209,eTETRA4=304, ePYRA5=305, ePENTA6=306, eHEXA8=308, eOCTA12=312, eTETRA10=310, ePYRA13=313, ePENTA15=315, eHEXA20=320, eHEXA27=327, - ePOLYGONE=400, ePOLYEDRE=500, eNONE=0, + ePOLYGONE=400, ePOLYGON2=420, ePOLYEDRE=500, eNONE=0, eBALL=1101 /*no such a type in med.h, it's just a trick*/, eAllGeoType=-1 } EGeometrieElement; diff --git a/src/MEDWrapper/Base/MED_Utilities.cxx b/src/MEDWrapper/Base/MED_Utilities.cxx index 1475ee8ab..d04b05762 100644 --- a/src/MEDWrapper/Base/MED_Utilities.cxx +++ b/src/MEDWrapper/Base/MED_Utilities.cxx @@ -79,6 +79,7 @@ bool InitEntity2GeomSet() aGeomFACESet.insert(eQUAD8); aGeomFACESet.insert(eQUAD9); aGeomFACESet.insert(ePOLYGONE); + aGeomFACESet.insert(ePOLYGON2); TGeomSet& aGeomMAILLESet = Entity2GeomSet[eMAILLE]; aGeomMAILLESet.insert(ePOINT1); diff --git a/src/MEDWrapper/V2_2/MED_V2_2_Wrapper.cxx b/src/MEDWrapper/V2_2/MED_V2_2_Wrapper.cxx index b12af7850..549f1944a 100644 --- a/src/MEDWrapper/V2_2/MED_V2_2_Wrapper.cxx +++ b/src/MEDWrapper/V2_2/MED_V2_2_Wrapper.cxx @@ -960,22 +960,19 @@ namespace MED MED::TMeshInfo& aMeshInfo = *theInfo.myMeshInfo; - TValueHolder aMeshName(aMeshInfo.myName); - TValueHolder anIndex(theInfo.myIndex); - TInt aNbElem = (TInt)theInfo.myElemNum->size(); - TValueHolder aConn(theInfo.myConn); - TValueHolder anEntity(theInfo.myEntity); + TValueHolder aMeshName(aMeshInfo.myName); + TValueHolder anIndex (theInfo.myIndex); + TValueHolder aConn (theInfo.myConn); + TValueHolder anEntity (theInfo.myEntity); + TValueHolder aGeom (theInfo.myGeom); TValueHolder aConnMode(theInfo.myConnMode); + TInt aNbElem = (TInt)theInfo.myElemNum->size(); TErr aRet; - aRet = MEDmeshPolygonRd(myFile->Id(), - &aMeshName, - MED_NO_DT, - MED_NO_IT, - anEntity, - aConnMode, - &anIndex, - &aConn); + aRet = MEDmeshPolygon2Rd(myFile->Id(), &aMeshName, + MED_NO_DT, MED_NO_IT, + anEntity, aGeom, + aConnMode, &anIndex, &aConn); if(theErr) *theErr = aRet; @@ -983,18 +980,18 @@ namespace MED EXCEPTION(std::runtime_error,"GetPolygoneInfo - MEDmeshPolygonRd(...)"); if(theInfo.myIsElemNames){ - GetNames(theInfo,aNbElem,theInfo.myEntity,ePOLYGONE,&aRet); + GetNames(theInfo,aNbElem,theInfo.myEntity,theInfo.myGeom,&aRet); if(theErr) *theErr = aRet; } if(theInfo.myIsElemNum){ - GetNumeration(theInfo,aNbElem,theInfo.myEntity,ePOLYGONE,&aRet); + GetNumeration(theInfo,aNbElem,theInfo.myEntity,theInfo.myGeom,&aRet); if(theErr) *theErr = aRet; } - GetFamilies(theInfo,aNbElem,theInfo.myEntity,ePOLYGONE,&aRet); + GetFamilies(theInfo,aNbElem,theInfo.myEntity,theInfo.myGeom,&aRet); if(theErr) *theErr = aRet; } @@ -1023,37 +1020,32 @@ namespace MED MED::TPolygoneInfo& anInfo = const_cast(theInfo); MED::TMeshInfo& aMeshInfo = *anInfo.myMeshInfo; - TValueHolder aMeshName(aMeshInfo.myName); - TValueHolder anIndex(anInfo.myIndex); - TValueHolder aConn(anInfo.myConn); - TValueHolder anEntity(anInfo.myEntity); + TValueHolder aMeshName(aMeshInfo.myName); + TValueHolder anIndex (anInfo.myIndex); + TValueHolder aConn (anInfo.myConn); + TValueHolder anEntity (anInfo.myEntity); + TValueHolder aGeom (anInfo.myGeom); TValueHolder aConnMode(anInfo.myConnMode); - TErr aRet = MEDmeshPolygonWr(myFile->Id(), - &aMeshName, - MED_NO_DT, - MED_NO_IT, - MED_UNDEF_DT, - anEntity, - aConnMode, - anInfo.myNbElem + 1, - &anIndex, - &aConn); - - if(theErr) + TErr aRet = MEDmeshPolygon2Wr(myFile->Id(), &aMeshName, + MED_NO_DT, MED_NO_IT, MED_UNDEF_DT, + anEntity, aGeom, + aConnMode, anInfo.myNbElem + 1, + &anIndex, &aConn); + if(theErr) *theErr = aRet; else if(aRet < 0) EXCEPTION(std::runtime_error,"SetPolygoneInfo - MEDmeshPolygonWr(...)"); - SetNames(anInfo,theInfo.myEntity,ePOLYGONE,&aRet); + SetNames(anInfo,theInfo.myEntity,anInfo.myGeom,&aRet); if(theErr) *theErr = aRet; - SetNumeration(anInfo,theInfo.myEntity,ePOLYGONE,&aRet); + SetNumeration(anInfo,theInfo.myEntity,anInfo.myGeom,&aRet); if(theErr) *theErr = aRet; - SetFamilies(anInfo,theInfo.myEntity,ePOLYGONE,&aRet); + SetFamilies(anInfo,theInfo.myEntity,anInfo.myGeom,&aRet); if(theErr) *theErr = aRet; } @@ -1094,7 +1086,7 @@ namespace MED MED_NO_DT, MED_NO_IT, med_entity_type(theEntity), - MED_POLYGON, + med_geometry_type(theGeom), MED_CONNECTIVITY, med_connectivity_mode(theConnMode), &chgt, @@ -1430,16 +1422,14 @@ namespace MED } return anInfo; } - - + + //----------------------------------------------------------------- - TInt - TVWrapper - ::GetNbCells(const MED::TMeshInfo& theMeshInfo, - EEntiteMaillage theEntity, - EGeometrieElement theGeom, - EConnectivite theConnMode, - TErr* theErr) + TInt TVWrapper::GetNbCells(const MED::TMeshInfo& theMeshInfo, + EEntiteMaillage theEntity, + EGeometrieElement theGeom, + EConnectivite theConnMode, + TErr* theErr) { TFileWrapper aFileWrapper(myFile,eLECTURE,theErr); @@ -1449,48 +1439,50 @@ namespace MED MED::TMeshInfo& aMeshInfo = const_cast(theMeshInfo); TValueHolder aMeshName(aMeshInfo.myName); med_bool chgt,trsf; - if(theGeom!=MED::ePOLYGONE && theGeom!=MED::ePOLYEDRE && theGeom != MED::eBALL) + switch ( theGeom ) { - return MEDmeshnEntity(myFile->Id(), - &aMeshName, - MED_NO_DT, - MED_NO_IT, - med_entity_type(theEntity), - med_geometry_type(theGeom), - MED_CONNECTIVITY, - med_connectivity_mode(theConnMode), - &chgt, - &trsf); - } - else if(theGeom==MED::ePOLYGONE) + case MED::ePOLYGONE: + case MED::ePOLYGON2: { - return MEDmeshnEntity(myFile->Id(),&aMeshName,MED_NO_DT,MED_NO_IT,med_entity_type(theEntity), - MED_POLYGON,MED_INDEX_NODE,med_connectivity_mode(theConnMode),&chgt,&trsf)-1; + return MEDmeshnEntity(myFile->Id(),&aMeshName, + MED_NO_DT,MED_NO_IT, + med_entity_type(theEntity),med_geometry_type(theGeom), + MED_INDEX_NODE,med_connectivity_mode(theConnMode), + &chgt,&trsf)-1; } - else if ( theGeom==MED::ePOLYEDRE ) + case MED::ePOLYEDRE: { - return MEDmeshnEntity(myFile->Id(),&aMeshName,MED_NO_DT,MED_NO_IT,med_entity_type(theEntity), - MED_POLYHEDRON,MED_INDEX_FACE,med_connectivity_mode(theConnMode),&chgt,&trsf)-1; + return MEDmeshnEntity(myFile->Id(),&aMeshName, + MED_NO_DT,MED_NO_IT, + med_entity_type(theEntity),MED_POLYHEDRON, + MED_INDEX_FACE,med_connectivity_mode(theConnMode), + &chgt,&trsf)-1; } - else if ( theGeom==MED::eBALL ) + case MED::eBALL: { return GetNbBalls( theMeshInfo ); } + default: + { + return MEDmeshnEntity(myFile->Id(),&aMeshName, + MED_NO_DT,MED_NO_IT, + med_entity_type(theEntity),med_geometry_type(theGeom), + MED_CONNECTIVITY,med_connectivity_mode(theConnMode), + &chgt,&trsf); + } + } return 0; } //---------------------------------------------------------------------------- - void - TVWrapper - ::GetCellInfo(MED::TCellInfo& theInfo, - TErr* theErr) + void TVWrapper::GetCellInfo(MED::TCellInfo& theInfo, TErr* theErr) { TFileWrapper aFileWrapper(myFile,eLECTURE,theErr); if(theErr && *theErr < 0) return; - + MED::TMeshInfo& aMeshInfo = *theInfo.myMeshInfo; TValueHolder aMeshName (aMeshInfo.myName); diff --git a/src/OBJECT/SMESH_Actor.cxx b/src/OBJECT/SMESH_Actor.cxx index 65f9e8787..1c9af415d 100644 --- a/src/OBJECT/SMESH_Actor.cxx +++ b/src/OBJECT/SMESH_Actor.cxx @@ -222,10 +222,11 @@ SMESH_ActorDef::SMESH_ActorDef() aFilter = my2DActor->GetExtractUnstructuredGrid(); aFilter->SetModeOfChanging(VTKViewer_ExtractUnstructuredGrid::eAdding); aFilter->RegisterCellsWithType(VTK_TRIANGLE); - aFilter->RegisterCellsWithType(VTK_POLYGON); aFilter->RegisterCellsWithType(VTK_QUAD); + aFilter->RegisterCellsWithType(VTK_POLYGON); aFilter->RegisterCellsWithType(VTK_QUADRATIC_TRIANGLE); aFilter->RegisterCellsWithType(VTK_QUADRATIC_QUAD); + aFilter->RegisterCellsWithType(VTK_QUADRATIC_POLYGON); aFilter->RegisterCellsWithType(VTK_BIQUADRATIC_QUAD); aFilter->RegisterCellsWithType(VTK_BIQUADRATIC_TRIANGLE); @@ -245,10 +246,11 @@ SMESH_ActorDef::SMESH_ActorDef() my2DExtActor->SetRepresentation(SMESH_DeviceActor::eInsideframe); aFilter = my2DExtActor->GetExtractUnstructuredGrid(); aFilter->RegisterCellsWithType(VTK_TRIANGLE); - aFilter->RegisterCellsWithType(VTK_POLYGON); aFilter->RegisterCellsWithType(VTK_QUAD); + aFilter->RegisterCellsWithType(VTK_POLYGON); aFilter->RegisterCellsWithType(VTK_QUADRATIC_TRIANGLE); aFilter->RegisterCellsWithType(VTK_QUADRATIC_QUAD); + aFilter->RegisterCellsWithType(VTK_QUADRATIC_POLYGON); aFilter->RegisterCellsWithType(VTK_BIQUADRATIC_QUAD); aFilter->RegisterCellsWithType(VTK_BIQUADRATIC_TRIANGLE); @@ -275,10 +277,7 @@ SMESH_ActorDef::SMESH_ActorDef() aFilter->RegisterCellsWithType(VTK_QUADRATIC_WEDGE); aFilter->RegisterCellsWithType(VTK_QUADRATIC_PYRAMID); aFilter->RegisterCellsWithType(VTK_CONVEX_POINT_SET); -//#ifdef VTK_HAVE_POLYHEDRON - MESSAGE("RegisterCellsWithType(VTK_POLYHEDRON)"); aFilter->RegisterCellsWithType(VTK_POLYHEDRON); -//#endif my3DExtProp = vtkProperty::New(); my3DExtProp->DeepCopy(myNormalVProp); @@ -1565,18 +1564,20 @@ void SMESH_ActorDef::SetEntityMode(unsigned int theMode) if (myEntityMode & eFaces) { if (MYDEBUG) MESSAGE("FACES"); aFilter->RegisterCellsWithType(VTK_TRIANGLE); - aFilter->RegisterCellsWithType(VTK_POLYGON); aFilter->RegisterCellsWithType(VTK_QUAD); + aFilter->RegisterCellsWithType(VTK_POLYGON); aFilter->RegisterCellsWithType(VTK_QUADRATIC_TRIANGLE); aFilter->RegisterCellsWithType(VTK_QUADRATIC_QUAD); + aFilter->RegisterCellsWithType(VTK_QUADRATIC_POLYGON); aFilter->RegisterCellsWithType(VTK_BIQUADRATIC_QUAD); aFilter->RegisterCellsWithType(VTK_BIQUADRATIC_TRIANGLE); aHightFilter->RegisterCellsWithType(VTK_TRIANGLE); - aHightFilter->RegisterCellsWithType(VTK_POLYGON); aHightFilter->RegisterCellsWithType(VTK_QUAD); + aHightFilter->RegisterCellsWithType(VTK_POLYGON); aHightFilter->RegisterCellsWithType(VTK_QUADRATIC_TRIANGLE); aHightFilter->RegisterCellsWithType(VTK_QUADRATIC_QUAD); + aHightFilter->RegisterCellsWithType(VTK_QUADRATIC_POLYGON); aHightFilter->RegisterCellsWithType(VTK_BIQUADRATIC_QUAD); aHightFilter->RegisterCellsWithType(VTK_BIQUADRATIC_TRIANGLE); } @@ -1595,9 +1596,7 @@ void SMESH_ActorDef::SetEntityMode(unsigned int theMode) aFilter->RegisterCellsWithType(VTK_QUADRATIC_PYRAMID); aFilter->RegisterCellsWithType(VTK_QUADRATIC_WEDGE); aFilter->RegisterCellsWithType(VTK_CONVEX_POINT_SET); -//#ifdef VTK_HAVE_POLYHEDRON aFilter->RegisterCellsWithType(VTK_POLYHEDRON); -//#endif aHightFilter->RegisterCellsWithType(VTK_TETRA); aHightFilter->RegisterCellsWithType(VTK_VOXEL); @@ -1611,9 +1610,7 @@ void SMESH_ActorDef::SetEntityMode(unsigned int theMode) aHightFilter->RegisterCellsWithType(VTK_QUADRATIC_WEDGE); aHightFilter->RegisterCellsWithType(VTK_QUADRATIC_PYRAMID); aHightFilter->RegisterCellsWithType(VTK_CONVEX_POINT_SET); -//#ifdef VTK_HAVE_POLYHEDRON aHightFilter->RegisterCellsWithType(VTK_POLYHEDRON); -//#endif } aFilter->Update(); if (MYDEBUG) MESSAGE(aFilter->GetOutput()->GetNumberOfCells()); diff --git a/src/OBJECT/SMESH_ExtractGeometry.cxx b/src/OBJECT/SMESH_ExtractGeometry.cxx index 3a9b380a3..b3ff7d74b 100644 --- a/src/OBJECT/SMESH_ExtractGeometry.cxx +++ b/src/OBJECT/SMESH_ExtractGeometry.cxx @@ -55,35 +55,36 @@ SMESH_ExtractGeometry::SMESH_ExtractGeometry() {} -SMESH_ExtractGeometry::~SMESH_ExtractGeometry(){} - +SMESH_ExtractGeometry::~SMESH_ExtractGeometry() +{} -vtkIdType SMESH_ExtractGeometry::GetElemObjId(int theVtkID){ +vtkIdType SMESH_ExtractGeometry::GetElemObjId(int theVtkID) +{ if( theVtkID < 0 || theVtkID >= myElemVTK2ObjIds.size()) return -1; return myElemVTK2ObjIds[theVtkID]; } -vtkIdType SMESH_ExtractGeometry::GetNodeObjId(int theVtkID){ +vtkIdType SMESH_ExtractGeometry::GetNodeObjId(int theVtkID) +{ if ( theVtkID < 0 || theVtkID >= myNodeVTK2ObjIds.size()) return -1; return myNodeVTK2ObjIds[theVtkID]; } -int SMESH_ExtractGeometry::RequestData( - vtkInformation *vtkNotUsed(request), - vtkInformationVector **inputVector, - vtkInformationVector *outputVector) +int SMESH_ExtractGeometry::RequestData(vtkInformation *vtkNotUsed(request), + vtkInformationVector **inputVector, + vtkInformationVector *outputVector) { // get the info objects vtkInformation *inInfo = inputVector[0]->GetInformationObject(0); vtkInformation *outInfo = outputVector->GetInformationObject(0); // get the input and ouptut - vtkDataSet *input = vtkDataSet::SafeDownCast( - inInfo->Get(vtkDataObject::DATA_OBJECT())); - vtkUnstructuredGrid *output = vtkUnstructuredGrid::SafeDownCast( - outInfo->Get(vtkDataObject::DATA_OBJECT())); + vtkDataSet *input = + vtkDataSet::SafeDownCast(inInfo->Get(vtkDataObject::DATA_OBJECT())); + vtkUnstructuredGrid *output = + vtkUnstructuredGrid::SafeDownCast(outInfo->Get(vtkDataObject::DATA_OBJECT())); vtkIdType ptId, numPts, numCells, i, cellId, newCellId, newId, *pointMap; vtkIdList *cellPts; @@ -100,35 +101,35 @@ int SMESH_ExtractGeometry::RequestData( int npts; numCells = input->GetNumberOfCells(); numPts = input->GetNumberOfPoints(); - + vtkDebugMacro(<< "Extracting geometry"); if ( ! this->ImplicitFunction ) - { + { vtkErrorMacro(<<"No implicit function specified"); return 0; - } + } newCellPts = vtkIdList::New(); newCellPts->Allocate(VTK_CELL_SIZE); if ( this->ExtractInside ) - { + { multiplier = 1.0; - } - else - { + } + else + { multiplier = -1.0; - } + } // Loop over all points determining whether they are inside the // implicit function. Copy the points and point data if they are. // pointMap = new vtkIdType[numPts]; // maps old point ids into new for (i=0; i < numPts; i++) - { + { pointMap[i] = -1; - } + } output->Allocate(numCells/4); //allocate storage for geometry/topology newPts = vtkPoints::New(); @@ -136,7 +137,7 @@ int SMESH_ExtractGeometry::RequestData( outputPD->CopyAllocate(pd); outputCD->CopyAllocate(cd); vtkFloatArray *newScalars = NULL; - + if(myStoreMapping){ myElemVTK2ObjIds.clear(); myElemVTK2ObjIds.reserve(numCells); @@ -145,110 +146,110 @@ int SMESH_ExtractGeometry::RequestData( } if ( ! this->ExtractBoundaryCells ) - { + { for ( ptId=0; ptId < numPts; ptId++ ) - { + { x = input->GetPoint(ptId); if ( (this->ImplicitFunction->FunctionValue(x)*multiplier) < 0.0 ) - { + { newId = newPts->InsertNextPoint(x); pointMap[ptId] = newId; myNodeVTK2ObjIds.push_back(ptId); outputPD->CopyData(pd,ptId,newId); - } } } + } else - { + { // To extract boundary cells, we have to create supplemental information if ( this->ExtractBoundaryCells ) - { + { double val; newScalars = vtkFloatArray::New(); newScalars->SetNumberOfValues(numPts); for (ptId=0; ptId < numPts; ptId++ ) - { + { x = input->GetPoint(ptId); val = this->ImplicitFunction->FunctionValue(x) * multiplier; newScalars->SetValue(ptId, val); if ( val < 0.0 ) - { + { newId = newPts->InsertNextPoint(x); pointMap[ptId] = newId; myNodeVTK2ObjIds.push_back(ptId); outputPD->CopyData(pd,ptId,newId); - } } } } + } // Now loop over all cells to see whether they are inside implicit // function (or on boundary if ExtractBoundaryCells is on). // for (cellId=0; cellId < numCells; cellId++) - { + { cell = input->GetCell(cellId); cellPts = cell->GetPointIds(); numCellPts = cell->GetNumberOfPoints(); newCellPts->Reset(); if ( ! this->ExtractBoundaryCells ) //requires less work - { + { for ( npts=0, i=0; i < numCellPts; i++, npts++) - { + { ptId = cellPts->GetId(i); if ( pointMap[ptId] < 0 ) - { + { break; //this cell won't be inserted - } + } else - { + { newCellPts->InsertId(i,pointMap[ptId]); - } } - } //if don't want to extract boundary cells - + } + } //if don't want to extract boundary cells + else //want boundary cells - { + { for ( npts=0, i=0; i < numCellPts; i++ ) - { + { ptId = cellPts->GetId(i); if ( newScalars->GetValue(ptId) <= 0.0 ) - { + { npts++; - } } + } if ( npts > 0 ) - { + { for ( i=0; i < numCellPts; i++ ) - { + { ptId = cellPts->GetId(i); if ( pointMap[ptId] < 0 ) - { + { x = input->GetPoint(ptId); newId = newPts->InsertNextPoint(x); pointMap[ptId] = newId; myNodeVTK2ObjIds.push_back(ptId); outputPD->CopyData(pd,ptId,newId); - } - newCellPts->InsertId(i,pointMap[ptId]); } - }//a boundary or interior cell - }//if mapping boundary cells - - if ( npts >= numCellPts || (this->ExtractBoundaryCells && npts > 0) ) - { - if(cell->GetCellType() == VTK_POLYHEDRON) { - newCellPts->Reset(); - vtkUnstructuredGrid::SafeDownCast(input)->GetFaceStream( cellId ,newCellPts ); - vtkUnstructuredGrid::ConvertFaceStreamPointIds(newCellPts, pointMap); + newCellPts->InsertId(i,pointMap[ptId]); } - newCellId = output->InsertNextCell(cell->GetCellType(),newCellPts); - myElemVTK2ObjIds.push_back(cellId); - outputCD->CopyData(cd,cellId,newCellId); + }//a boundary or interior cell + }//if mapping boundary cells + + if ( npts >= numCellPts || (this->ExtractBoundaryCells && npts > 0) ) + { + if(cell->GetCellType() == VTK_POLYHEDRON) { + newCellPts->Reset(); + vtkUnstructuredGrid::SafeDownCast(input)->GetFaceStream( cellId ,newCellPts ); + vtkUnstructuredGrid::ConvertFaceStreamPointIds(newCellPts, pointMap); } - }//for all cells + newCellId = output->InsertNextCell(cell->GetCellType(),newCellPts); + myElemVTK2ObjIds.push_back(cellId); + outputCD->CopyData(cd,cellId,newCellId); + } + }//for all cells // Update ourselves and release memory // @@ -256,11 +257,11 @@ int SMESH_ExtractGeometry::RequestData( newCellPts->Delete(); output->SetPoints(newPts); newPts->Delete(); - + if ( this->ExtractBoundaryCells ) - { + { newScalars->Delete(); - } + } output->Squeeze(); return 1; diff --git a/src/OBJECT/SMESH_Object.cxx b/src/OBJECT/SMESH_Object.cxx index ec37985d4..bcb589937 100644 --- a/src/OBJECT/SMESH_Object.cxx +++ b/src/OBJECT/SMESH_Object.cxx @@ -28,14 +28,16 @@ #include "SMESH_ObjectDef.h" #include "SMESH_ActorUtils.h" +#include "SMDS_BallElement.hxx" #include "SMDS_Mesh.hxx" +#include "SMDS_MeshCell.hxx" #include "SMDS_PolyhedralVolumeOfNodes.hxx" -#include "SMDS_BallElement.hxx" #include "SMESH_Actor.h" #include "SMESH_ControlsDef.hxx" -#include "SalomeApp_Application.h" -#include "VTKViewer_ExtractUnstructuredGrid.h" -#include "VTKViewer_CellLocationsArray.h" + +#include +#include +#include #include CORBA_SERVER_HEADER(SMESH_Gen) #include CORBA_SERVER_HEADER(SALOME_Exception) @@ -82,48 +84,48 @@ static int MYDEBUGWITHFILES = 0; // function : getCellType // purpose : Get type of VTK cell //================================================================================= -static inline vtkIdType getCellType( const SMDSAbs_ElementType theType, - const bool thePoly, - const int theNbNodes ) -{ - switch( theType ) - { - case SMDSAbs_0DElement: return VTK_VERTEX; - - case SMDSAbs_Ball: return VTK_POLY_VERTEX; - - case SMDSAbs_Edge: - if( theNbNodes == 2 ) return VTK_LINE; - else if ( theNbNodes == 3 ) return VTK_QUADRATIC_EDGE; - else return VTK_EMPTY_CELL; - - case SMDSAbs_Face : - if (thePoly && theNbNodes>2 ) return VTK_POLYGON; - else if ( theNbNodes == 3 ) return VTK_TRIANGLE; - else if ( theNbNodes == 4 ) return VTK_QUAD; - else if ( theNbNodes == 6 ) return VTK_QUADRATIC_TRIANGLE; - else if ( theNbNodes == 8 ) return VTK_QUADRATIC_QUAD; - else if ( theNbNodes == 9 ) return VTK_BIQUADRATIC_QUAD; - else if ( theNbNodes == 7 ) return VTK_BIQUADRATIC_TRIANGLE; - else return VTK_EMPTY_CELL; +// static inline vtkIdType getCellType( const SMDSAbs_ElementType theType, +// const bool thePoly, +// const int theNbNodes ) +// { +// switch( theType ) +// { +// case SMDSAbs_0DElement: return VTK_VERTEX; + +// case SMDSAbs_Ball: return VTK_POLY_VERTEX; + +// case SMDSAbs_Edge: +// if( theNbNodes == 2 ) return VTK_LINE; +// else if ( theNbNodes == 3 ) return VTK_QUADRATIC_EDGE; +// else return VTK_EMPTY_CELL; + +// case SMDSAbs_Face : +// if (thePoly && theNbNodes>2 ) return VTK_POLYGON; +// else if ( theNbNodes == 3 ) return VTK_TRIANGLE; +// else if ( theNbNodes == 4 ) return VTK_QUAD; +// else if ( theNbNodes == 6 ) return VTK_QUADRATIC_TRIANGLE; +// else if ( theNbNodes == 8 ) return VTK_QUADRATIC_QUAD; +// else if ( theNbNodes == 9 ) return VTK_BIQUADRATIC_QUAD; +// else if ( theNbNodes == 7 ) return VTK_BIQUADRATIC_TRIANGLE; +// else return VTK_EMPTY_CELL; - case SMDSAbs_Volume: - if (thePoly && theNbNodes>3 ) return VTK_POLYHEDRON; //VTK_CONVEX_POINT_SET; - else if ( theNbNodes == 4 ) return VTK_TETRA; - else if ( theNbNodes == 5 ) return VTK_PYRAMID; - else if ( theNbNodes == 6 ) return VTK_WEDGE; - else if ( theNbNodes == 8 ) return VTK_HEXAHEDRON; - else if ( theNbNodes == 12 ) return VTK_HEXAGONAL_PRISM; - else if ( theNbNodes == 10 ) return VTK_QUADRATIC_TETRA; - else if ( theNbNodes == 20 ) return VTK_QUADRATIC_HEXAHEDRON; - else if ( theNbNodes == 27 ) return VTK_TRIQUADRATIC_HEXAHEDRON; - else if ( theNbNodes == 15 ) return VTK_QUADRATIC_WEDGE; - else if ( theNbNodes == 13 ) return VTK_QUADRATIC_PYRAMID; //VTK_CONVEX_POINT_SET; - else return VTK_EMPTY_CELL; - - default: return VTK_EMPTY_CELL; - } -} +// case SMDSAbs_Volume: +// if (thePoly && theNbNodes>3 ) return VTK_POLYHEDRON; //VTK_CONVEX_POINT_SET; +// else if ( theNbNodes == 4 ) return VTK_TETRA; +// else if ( theNbNodes == 5 ) return VTK_PYRAMID; +// else if ( theNbNodes == 6 ) return VTK_WEDGE; +// else if ( theNbNodes == 8 ) return VTK_HEXAHEDRON; +// else if ( theNbNodes == 12 ) return VTK_HEXAGONAL_PRISM; +// else if ( theNbNodes == 10 ) return VTK_QUADRATIC_TETRA; +// else if ( theNbNodes == 20 ) return VTK_QUADRATIC_HEXAHEDRON; +// else if ( theNbNodes == 27 ) return VTK_TRIQUADRATIC_HEXAHEDRON; +// else if ( theNbNodes == 15 ) return VTK_QUADRATIC_WEDGE; +// else if ( theNbNodes == 13 ) return VTK_QUADRATIC_PYRAMID; //VTK_CONVEX_POINT_SET; +// else return VTK_EMPTY_CELL; + +// default: return VTK_EMPTY_CELL; +// } +// } //================================================================================= // functions : SMESH_VisualObjDef @@ -438,23 +440,23 @@ void SMESH_VisualObjDef::buildElemPrs() for ( int i = 0; i < nbTypes; i++ ) // iterate through all types of elements { if ( nbEnts[ aTypes[ i ] ] > 0 ) { - + const SMDSAbs_ElementType& aType = aTypes[ i ]; const TEntityList& aList = anEnts[ aType ]; TEntityList::const_iterator anIter; for ( anIter = aList.begin(); anIter != aList.end(); ++anIter ) { const SMDS_MeshElement* anElem = *anIter; - + vtkIdType aNbNodes = anElem->NbNodes(); anIdList->SetNumberOfIds( aNbNodes ); - const vtkIdType vtkElemType = getCellType( aType, anElem->IsPoly(), aNbNodes ); - + const vtkIdType vtkElemType = SMDS_MeshCell::toVtkType( anElem->GetEntityType() ); + int anId = anElem->GetID(); - + mySMDS2VTKElems.insert( TMapOfIds::value_type( anId, iElem ) ); myVTK2SMDSElems.insert( TMapOfIds::value_type( iElem, anId ) ); - + SMDS_ElemIteratorPtr aNodesIter = anElem->nodesIterator(); { // Convertions connectivities from SMDS to VTK diff --git a/src/OBJECT/SMESH_SVTKActor.cxx b/src/OBJECT/SMESH_SVTKActor.cxx index 4503dd1c4..78ec260d6 100644 --- a/src/OBJECT/SMESH_SVTKActor.cxx +++ b/src/OBJECT/SMESH_SVTKActor.cxx @@ -123,7 +123,7 @@ SMESH_SVTKActor SVTK::CopyPoints( GetSource(), aSourceDataSet ); SVTK::CopyPoints( myBallGrid, aSourceDataSet ); SVTK::CopyPoints( my0DGrid, aSourceDataSet ); - + int aNbOfParts = theMapIndex.Extent(); @@ -143,12 +143,14 @@ SMESH_SVTKActor { if(aCell->GetCellType() == VTK_VERTEX ) { my0DGrid->InsertNextCell(aCell->GetCellType(),aCell->GetPointIds()); - } else if(aCell->GetCellType() == VTK_POLY_VERTEX ) { + } + else if(aCell->GetCellType() == VTK_POLY_VERTEX ) { vtkIdType newCellId = myBallGrid->InsertNextCell(aCell->GetCellType(),aCell->GetPointIds()); if(myVisualObj) { outputCD->CopyData(cd, myVisualObj->GetElemVTKId(aPartId), newCellId); } - } else { + } + else { myUnstructuredGrid->InsertNextCell(aCell->GetCellType(),aCell->GetPointIds()); } } diff --git a/src/SMDS/SMDS_Mesh.cxx b/src/SMDS/SMDS_Mesh.cxx index 056509ffe..58641e56b 100644 --- a/src/SMDS/SMDS_Mesh.cxx +++ b/src/SMDS/SMDS_Mesh.cxx @@ -1339,8 +1339,6 @@ SMDS_Mesh::AddPolygonalFaceWithID (const vector & nodes, } else { - //#ifdef VTK_HAVE_POLYHEDRON - //MESSAGE("AddPolygonalFaceWithID vtk " << ID); myNodeIds.resize( nodes.size() ); for ( size_t i = 0; i < nodes.size(); ++i ) myNodeIds[i] = nodes[i]->getVtkId(); @@ -1354,25 +1352,12 @@ SMDS_Mesh::AddPolygonalFaceWithID (const vector & nodes, return 0; } face = facevtk; - //#else - // MESSAGE("AddPolygonalFaceWithID smds " << ID); - // for ( int i = 0; i < nodes.size(); ++i ) - // if ( !nodes[ i ] ) return 0; - // face = new SMDS_PolygonalFaceOfNodes(nodes); - //#endif + adjustmyCellsCapacity(ID); myCells[ID] = face; myInfo.myNbPolygons++; } - //#ifndef VTK_HAVE_POLYHEDRON - // if (!registerElement(ID, face)) - // { - // registerElement(myElementIDFactory->GetFreeID(), face); - // //RemoveElement(face, false); - // //face = NULL; - // } - //#endif return face; } @@ -1386,6 +1371,69 @@ SMDS_MeshFace* SMDS_Mesh::AddPolygonalFace (const vector & return SMDS_Mesh::AddPolygonalFaceWithID(nodes, myElementIDFactory->GetFreeID()); } +/////////////////////////////////////////////////////////////////////////////// +/// Add a quadratic polygon defined by its nodes IDs +/////////////////////////////////////////////////////////////////////////////// + +SMDS_MeshFace* SMDS_Mesh::AddQuadPolygonalFaceWithID (const vector & nodes_ids, + const int ID) +{ + vector nodes( nodes_ids.size() ); + for ( size_t i = 0; i < nodes.size(); i++) { + nodes[i] = (SMDS_MeshNode *)myNodeIDFactory->MeshElement(nodes_ids[i]); + if (!nodes[i]) return NULL; + } + return SMDS_Mesh::AddQuadPolygonalFaceWithID(nodes, ID); +} + +/////////////////////////////////////////////////////////////////////////////// +/// Add a quadratic polygon defined by its nodes +/////////////////////////////////////////////////////////////////////////////// + +SMDS_MeshFace* +SMDS_Mesh::AddQuadPolygonalFaceWithID (const vector & nodes, + const int ID) +{ + SMDS_MeshFace * face; + + if ( NbFaces() % CHECKMEMORY_INTERVAL == 0 ) CheckMemory(); + if (hasConstructionEdges()) + { + MESSAGE("Error : Not implemented"); + return NULL; + } + else + { + myNodeIds.resize( nodes.size() ); + for ( size_t i = 0; i < nodes.size(); ++i ) + myNodeIds[i] = nodes[i]->getVtkId(); + + SMDS_VtkFace *facevtk = myFacePool->getNew(); + facevtk->initQuadPoly(myNodeIds, this); + if (!this->registerElement(ID,facevtk)) + { + this->myGrid->GetCellTypesArray()->SetValue(facevtk->getVtkId(), VTK_EMPTY_CELL); + myFacePool->destroy(facevtk); + return 0; + } + face = facevtk; + adjustmyCellsCapacity(ID); + myCells[ID] = face; + myInfo.myNbQuadPolygons++; + } + return face; +} + +/////////////////////////////////////////////////////////////////////////////// +/// Add a quadratic polygon defined by its nodes. +/// An ID is automatically affected to the created face. +/////////////////////////////////////////////////////////////////////////////// + +SMDS_MeshFace* SMDS_Mesh::AddQuadPolygonalFace (const vector & nodes) +{ + return SMDS_Mesh::AddQuadPolygonalFaceWithID(nodes, myElementIDFactory->GetFreeID()); +} + /////////////////////////////////////////////////////////////////////////////// /// Create a new polyhedral volume and add it to the mesh. /// @param ID The ID of the new volume @@ -1779,8 +1827,8 @@ SMDS_MeshFace * SMDS_Mesh::createQuadrangle(const SMDS_MeshNode * node1, void SMDS_Mesh::RemoveNode(const SMDS_MeshNode * node) { - MESSAGE("RemoveNode"); - RemoveElement(node, true); + MESSAGE("RemoveNode"); + RemoveElement(node, true); } /////////////////////////////////////////////////////////////////////////////// @@ -1789,7 +1837,7 @@ void SMDS_Mesh::RemoveNode(const SMDS_MeshNode * node) void SMDS_Mesh::Remove0DElement(const SMDS_Mesh0DElement * elem0d) { - MESSAGE("Remove0DElement"); + MESSAGE("Remove0DElement"); RemoveElement(elem0d,true); } @@ -1799,8 +1847,8 @@ void SMDS_Mesh::Remove0DElement(const SMDS_Mesh0DElement * elem0d) void SMDS_Mesh::RemoveEdge(const SMDS_MeshEdge * edge) { - MESSAGE("RemoveEdge"); - RemoveElement(edge,true); + MESSAGE("RemoveEdge"); + RemoveElement(edge,true); } /////////////////////////////////////////////////////////////////////////////// @@ -1809,8 +1857,8 @@ void SMDS_Mesh::RemoveEdge(const SMDS_MeshEdge * edge) void SMDS_Mesh::RemoveFace(const SMDS_MeshFace * face) { - MESSAGE("RemoveFace"); - RemoveElement(face, true); + MESSAGE("RemoveFace"); + RemoveElement(face, true); } /////////////////////////////////////////////////////////////////////////////// @@ -1819,8 +1867,8 @@ void SMDS_Mesh::RemoveFace(const SMDS_MeshFace * face) void SMDS_Mesh::RemoveVolume(const SMDS_MeshVolume * volume) { - MESSAGE("RemoveVolume"); - RemoveElement(volume, true); + MESSAGE("RemoveVolume"); + RemoveElement(volume, true); } //======================================================================= @@ -1830,8 +1878,8 @@ void SMDS_Mesh::RemoveVolume(const SMDS_MeshVolume * volume) bool SMDS_Mesh::RemoveFromParent() { - if (myParent==NULL) return false; - else return (myParent->RemoveSubMesh(this)); + if (myParent==NULL) return false; + else return (myParent->RemoveSubMesh(this)); } //======================================================================= @@ -1841,20 +1889,20 @@ bool SMDS_Mesh::RemoveFromParent() bool SMDS_Mesh::RemoveSubMesh(const SMDS_Mesh * aMesh) { - bool found = false; + bool found = false; - list::iterator itmsh=myChildren.begin(); - for (; itmsh!=myChildren.end() && !found; itmsh++) - { - SMDS_Mesh * submesh = *itmsh; - if (submesh == aMesh) - { - found = true; - myChildren.erase(itmsh); - } - } + list::iterator itmsh=myChildren.begin(); + for (; itmsh!=myChildren.end() && !found; itmsh++) + { + SMDS_Mesh * submesh = *itmsh; + if (submesh == aMesh) + { + found = true; + myChildren.erase(itmsh); + } + } - return found; + return found; } //======================================================================= @@ -1874,10 +1922,10 @@ bool SMDS_Mesh::ChangeElementNodes(const SMDS_MeshElement * element, bool Ok = false; SMDS_MeshCell* cell = dynamic_cast((SMDS_MeshElement*) element); if (cell) - { - Ok = cell->vtkOrder(nodes, nbnodes); - Ok = cell->ChangeNodes(nodes, nbnodes); - } + { + Ok = cell->vtkOrder(nodes, nbnodes); + Ok = cell->ChangeNodes(nodes, nbnodes); + } if ( Ok ) { // update InverseElements diff --git a/src/SMDS/SMDS_Mesh.hxx b/src/SMDS/SMDS_Mesh.hxx index de397bf10..bc3c74012 100644 --- a/src/SMDS/SMDS_Mesh.hxx +++ b/src/SMDS/SMDS_Mesh.hxx @@ -576,14 +576,22 @@ public: virtual SMDS_MeshFace* AddPolygonalFace (const std::vector & nodes); + virtual SMDS_MeshFace* AddQuadPolygonalFaceWithID(const std::vector & nodes_ids, + const int ID); + + virtual SMDS_MeshFace* AddQuadPolygonalFaceWithID(const std::vector & nodes, + const int ID); + + virtual SMDS_MeshFace* AddQuadPolygonalFace(const std::vector & nodes); + virtual SMDS_MeshVolume* AddPolyhedralVolumeWithID - (const std::vector & nodes_ids, - const std::vector & quantities, - const int ID); + (const std::vector & nodes_ids, + const std::vector & quantities, + const int ID); virtual SMDS_MeshVolume* AddPolyhedralVolumeWithID - (const std::vector & nodes, - const std::vector & quantities, + (const std::vector & nodes, + const std::vector & quantities, const int ID); virtual SMDS_MeshVolume* AddPolyhedralVolume diff --git a/src/SMDS/SMDS_MeshCell.cxx b/src/SMDS/SMDS_MeshCell.cxx index 2232f6829..e629a2f5b 100644 --- a/src/SMDS/SMDS_MeshCell.cxx +++ b/src/SMDS/SMDS_MeshCell.cxx @@ -56,7 +56,7 @@ VTKCellType SMDS_MeshCell::toVtkType (SMDSAbs_EntityType smdsType) vtkTypes[ SMDSEntity_Quad_Quadrangle ] = VTK_QUADRATIC_QUAD; vtkTypes[ SMDSEntity_BiQuad_Quadrangle ] = VTK_BIQUADRATIC_QUAD; vtkTypes[ SMDSEntity_Polygon ] = VTK_POLYGON; - //vtkTypes[ SMDSEntity_Quad_Polygon ] = ; + vtkTypes[ SMDSEntity_Quad_Polygon ] = VTK_QUADRATIC_POLYGON; vtkTypes[ SMDSEntity_Tetra ] = VTK_TETRA; vtkTypes[ SMDSEntity_Quad_Tetra ] = VTK_QUADRATIC_TETRA; vtkTypes[ SMDSEntity_Pyramid ] = VTK_PYRAMID; @@ -166,12 +166,14 @@ const std::vector< int >& SMDS_MeshCell::toVtkOrder(SMDSAbs_EntityType smdsType) //================================================================================ /*! - * \brief Return indices to reverse an SMDS cell of given type + * \brief Return indices to reverse an SMDS cell of given type. + * nbNodes is useful for polygons * Usage: reverseIDs[i] = forwardIDs[ indices[ i ]] */ //================================================================================ -const std::vector& SMDS_MeshCell::reverseSmdsOrder(SMDSAbs_EntityType smdsType) +const std::vector& SMDS_MeshCell::reverseSmdsOrder(SMDSAbs_EntityType smdsType, + const size_t nbNodes) { static std::vector< std::vector< int > > reverseInterlaces; if ( reverseInterlaces.empty() ) @@ -256,6 +258,31 @@ const std::vector& SMDS_MeshCell::reverseSmdsOrder(SMDSAbs_EntityType smdsT reverseInterlaces[SMDSEntity_Hexagonal_Prism].assign( &ids[0], &ids[0]+12 ); } } + + if ( smdsType == SMDSEntity_Polygon ) + { + if ( reverseInterlaces[ smdsType ].size() != nbNodes ) + { + reverseInterlaces[ smdsType ].resize( nbNodes ); + for ( size_t i = 0; i < nbNodes; ++i ) + reverseInterlaces[ smdsType ][i] = nbNodes - i - 1; + } + } + else if ( smdsType == SMDSEntity_Quad_Polygon ) + { + if ( reverseInterlaces[ smdsType ].size() != nbNodes ) + { + // e.g. for 8 nodes: [ 0, 3,2,1, 7,6,5,4 ] + reverseInterlaces[ smdsType ].resize( nbNodes ); + size_t pos = 0; + reverseInterlaces[ smdsType ][pos++] = 0; + for ( int i = nbNodes / 2 - 1; i > 0 ; --i ) // 3,2,1 + reverseInterlaces[ smdsType ][pos++] = i; + for ( int i = nbNodes - 1; i >= nbNodes / 2; --i ) // 7,6,5,4 + reverseInterlaces[ smdsType ][pos++] = i; + } + } + return reverseInterlaces[smdsType]; } @@ -266,7 +293,8 @@ const std::vector& SMDS_MeshCell::reverseSmdsOrder(SMDSAbs_EntityType smdsT */ //================================================================================ -const std::vector& SMDS_MeshCell::interlacedSmdsOrder(SMDSAbs_EntityType smdsType) +const std::vector& SMDS_MeshCell::interlacedSmdsOrder(SMDSAbs_EntityType smdsType, + const size_t nbNodes) { static std::vector< std::vector< int > > interlace; if ( interlace.empty() ) @@ -278,15 +306,28 @@ const std::vector& SMDS_MeshCell::interlacedSmdsOrder(SMDSAbs_EntityType sm } { const int ids[] = {0,3,1,4,2,5,6}; - interlace[SMDSEntity_Quad_Triangle].assign( &ids[0], &ids[0]+6 ); + interlace[SMDSEntity_Quad_Triangle ].assign( &ids[0], &ids[0]+6 ); interlace[SMDSEntity_BiQuad_Triangle].assign( &ids[0], &ids[0]+7 ); } { const int ids[] = {0,4,1,5,2,6,3,7,8}; - interlace[SMDSEntity_Quad_Quadrangle].assign( &ids[0], &ids[0]+8 ); + interlace[SMDSEntity_Quad_Quadrangle ].assign( &ids[0], &ids[0]+8 ); interlace[SMDSEntity_BiQuad_Quadrangle].assign( &ids[0], &ids[0]+9 ); } } + + if ( smdsType == SMDSEntity_Quad_Polygon ) + { + if ( interlace[smdsType].size() != nbNodes ) + { + interlace[smdsType].resize( nbNodes ); + for ( size_t i = 0; i < nbNodes / 2; ++i ) + { + interlace[smdsType][i*2+0] = i; + interlace[smdsType][i*2+1] = i + nbNodes / 2; + } + } + } return interlace[smdsType]; } diff --git a/src/SMDS/SMDS_MeshCell.hxx b/src/SMDS/SMDS_MeshCell.hxx index 85cc7475e..d56f7b5de 100644 --- a/src/SMDS/SMDS_MeshCell.hxx +++ b/src/SMDS/SMDS_MeshCell.hxx @@ -45,10 +45,12 @@ public: static const std::vector& fromVtkOrder(VTKCellType vtkType); static const std::vector& fromVtkOrder(SMDSAbs_EntityType smdsType); - static const std::vector& reverseSmdsOrder(SMDSAbs_EntityType smdsType); - static const std::vector& interlacedSmdsOrder(SMDSAbs_EntityType smdsType); + static const std::vector& reverseSmdsOrder(SMDSAbs_EntityType smdsType, + const size_t nbNodes=0); + static const std::vector& interlacedSmdsOrder(SMDSAbs_EntityType smdsType, + const size_t nbNodes=0); - template< class VECT > + template< class VECT > // interlacedIDs[i] = smdsIDs[ indices[ i ]] static void applyInterlace( const std::vector& interlace, VECT & data) { if ( interlace.empty() ) return; @@ -57,6 +59,15 @@ public: tmpData[i] = data[ interlace[i] ]; data.swap( tmpData ); } + template< class VECT > // interlacedIDs[ indices[ i ]] = smdsIDs[i] + static void applyInterlaceRev( const std::vector& interlace, VECT & data) + { + if ( interlace.empty() ) return; + VECT tmpData( data.size() ); + for ( size_t i = 0; i < data.size(); ++i ) + tmpData[ interlace[i] ] = data[i]; + data.swap( tmpData ); + } static int nbCells; diff --git a/src/SMDS/SMDS_MeshInfo.hxx b/src/SMDS/SMDS_MeshInfo.hxx index fa49ecd24..5c22d7f9b 100644 --- a/src/SMDS/SMDS_MeshInfo.hxx +++ b/src/SMDS/SMDS_MeshInfo.hxx @@ -56,7 +56,7 @@ public: inline int NbQuadrangles(SMDSAbs_ElementOrder order = ORDER_ANY) const; int NbBiQuadTriangles() const { return myNbBiQuadTriangles; } int NbBiQuadQuadrangles() const { return myNbBiQuadQuadrangles; } - int NbPolygons() const { return myNbPolygons; } + inline int NbPolygons(SMDSAbs_ElementOrder order = ORDER_ANY) const; inline int NbVolumes (SMDSAbs_ElementOrder order = ORDER_ANY) const; inline int NbTetras (SMDSAbs_ElementOrder order = ORDER_ANY) const; @@ -90,7 +90,7 @@ private: int myNbEdges , myNbQuadEdges ; int myNbTriangles , myNbQuadTriangles, myNbBiQuadTriangles ; int myNbQuadrangles, myNbQuadQuadrangles, myNbBiQuadQuadrangles; - int myNbPolygons; + int myNbPolygons , myNbQuadPolygons; int myNbTetras , myNbQuadTetras ; int myNbHexas , myNbQuadHexas, myNbTriQuadHexas; @@ -110,7 +110,7 @@ inline SMDS_MeshInfo::SMDS_MeshInfo(): myNbEdges (0), myNbQuadEdges (0), myNbTriangles (0), myNbQuadTriangles (0), myNbBiQuadTriangles(0), myNbQuadrangles(0), myNbQuadQuadrangles(0), myNbBiQuadQuadrangles(0), - myNbPolygons (0), + myNbPolygons (0), myNbQuadPolygons (0), myNbTetras (0), myNbQuadTetras (0), myNbHexas (0), myNbQuadHexas (0), myNbTriQuadHexas(0), myNbPyramids (0), myNbQuadPyramids(0), @@ -193,15 +193,16 @@ inline SMDS_MeshInfo::SMDS_MeshInfo(): inline SMDS_MeshInfo& // operator= SMDS_MeshInfo::operator=(const SMDS_MeshInfo& other) { for ( int i=0; iGetType(), el->NbNodes()) ]); } inline void // addWithPoly -SMDS_MeshInfo::addWithPoly(const SMDS_MeshElement* el) -{ - if ( el->IsPoly() ) - ++( el->GetType()==SMDSAbs_Face ? myNbPolygons : myNbPolyhedrons ); - else - add(el); +SMDS_MeshInfo::addWithPoly(const SMDS_MeshElement* el) { + switch ( el->GetEntityType() ) { + case SMDSEntity_Polygon: ++myNbPolygons; break; + case SMDSEntity_Quad_Polygon: ++myNbQuadPolygons; break; + case SMDSEntity_Polyhedra: ++myNbPolyhedrons; break; + default: add(el); + } } inline void // RemoveEdge SMDS_MeshInfo::RemoveEdge(const SMDS_MeshElement* el) { if ( el->IsQuadratic() ) --myNbQuadEdges; else --myNbEdges; } inline void // RemoveFace -SMDS_MeshInfo::RemoveFace(const SMDS_MeshElement* el) -{ if ( el->IsPoly() ) --myNbPolygons; else remove( el ); } +SMDS_MeshInfo::RemoveFace(const SMDS_MeshElement* el) { + switch ( el->GetEntityType() ) { + case SMDSEntity_Polygon: --myNbPolygons; break; + case SMDSEntity_Quad_Polygon: --myNbQuadPolygons; break; + default: remove(el); + } +} inline void // RemoveVolume SMDS_MeshInfo::RemoveVolume(const SMDS_MeshElement* el) @@ -242,7 +249,7 @@ SMDS_MeshInfo::NbEdges (SMDSAbs_ElementOrder order) const inline int // NbFaces SMDS_MeshInfo::NbFaces (SMDSAbs_ElementOrder order) const -{ return NbTriangles(order)+NbQuadrangles(order)+(order == ORDER_QUADRATIC ? 0 : myNbPolygons); } +{ return NbTriangles(order)+NbQuadrangles(order)+(order == ORDER_ANY ? myNbPolygons+myNbQuadPolygons : order == ORDER_LINEAR ? myNbPolygons : myNbQuadPolygons ); } inline int // NbTriangles SMDS_MeshInfo::NbTriangles (SMDSAbs_ElementOrder order) const @@ -252,6 +259,10 @@ inline int // NbQuadrangles SMDS_MeshInfo::NbQuadrangles(SMDSAbs_ElementOrder order) const { return order == ORDER_ANY ? myNbQuadrangles+myNbQuadQuadrangles+myNbBiQuadQuadrangles : order == ORDER_LINEAR ? myNbQuadrangles : myNbQuadQuadrangles+myNbBiQuadQuadrangles; } +inline int // NbPolygons +SMDS_MeshInfo::NbPolygons(SMDSAbs_ElementOrder order) const +{ return order == ORDER_ANY ? myNbPolygons+myNbQuadPolygons : order == ORDER_LINEAR ? myNbPolygons : myNbQuadPolygons; } + inline int // NbVolumes SMDS_MeshInfo::NbVolumes (SMDSAbs_ElementOrder order) const { return NbTetras(order) + NbHexas(order) + NbPyramids(order) + NbPrisms(order) + NbHexPrisms(order) + (order == ORDER_QUADRATIC ? 0 : myNbPolyhedrons); } @@ -283,7 +294,7 @@ SMDS_MeshInfo::NbElements(SMDSAbs_ElementType type) const switch (type) { case SMDSAbs_All: for ( int i=1+index( SMDSAbs_Node,1 ); iIsQuadratic() ? 2 : 1; - const SMDS_MeshNode* n1 = nodes[di*0]; - const SMDS_MeshNode* n2 = nodes[di*1]; - const SMDS_MeshNode* n3 = nodes[di*2]; + const int di = myVolume->IsQuadratic() ? 2 : 1; + const int nbN = ( myFaceNbNodes/di <= 4 && !IsPoly()) ? 3 : myFaceNbNodes/di; // nb nodes to check - SMDS_ElemIteratorPtr eIt = n1->GetInverseElementIterator( SMDSAbs_Volume ); - SMDS_ElemIteratorPtr nIt; - while ( eIt->more() ) { + SMDS_ElemIteratorPtr eIt = nodes[0]->GetInverseElementIterator( SMDSAbs_Volume ); + while ( eIt->more() ) + { const SMDS_MeshElement* vol = eIt->next(); - if ( vol != myVolume && - vol->GetNodeIndex( n2 ) >= 0 && - vol->GetNodeIndex( n3 ) >= 0 ) + if ( vol == myVolume ) + continue; + int iN; + for ( iN = 1; iN < nbN; ++iN ) + if ( vol->GetNodeIndex( nodes[ iN*di ]) < 0 ) + break; + if ( iN == nbN ) // nbN nodes are shared with vol { + // if ( vol->IsPoly() || vol->NbFaces() > 6 ) // vol is polyhed or hex prism + // { + // int nb = myFaceNbNodes; + // if ( myVolume->GetEntityType() != vol->GetEntityType() ) + // nb -= ( GetCenterNodeIndex(0) > 0 ); + // set faceNodes( nodes, nodes + nb ); + // if ( SMDS_VolumeTool( vol ).GetFaceIndex( faceNodes ) < 0 ) + // continue; + // } if ( otherVol ) *otherVol = vol; return !isFree; } diff --git a/src/SMDS/SMDS_VtkCellIterator.cxx b/src/SMDS/SMDS_VtkCellIterator.cxx index 987ca65bf..d050097fb 100644 --- a/src/SMDS/SMDS_VtkCellIterator.cxx +++ b/src/SMDS/SMDS_VtkCellIterator.cxx @@ -71,75 +71,73 @@ SMDS_VtkCellIteratorToUNV::SMDS_VtkCellIteratorToUNV(SMDS_Mesh* mesh, int vtkCel vtkUnstructuredGrid* grid = _mesh->getGrid(); grid->GetCellPoints((vtkIdType)_cellId, (vtkIdType&)_nbNodes, pts); _vtkIdList->SetNumberOfIds(_nbNodes); - int *ids = 0; + const int *ids = 0; switch (_type) { - case SMDSEntity_Quad_Edge: - { - static int id[] = { 0, 2, 1 }; - ids = id; - break; - } - case SMDSEntity_Quad_Triangle: - case SMDSEntity_BiQuad_Triangle: - { - static int id[] = { 0, 3, 1, 4, 2, 5 }; - ids = id; - _nbNodes = 6; - break; - } - case SMDSEntity_Quad_Quadrangle: - case SMDSEntity_BiQuad_Quadrangle: - { - static int id[] = { 0, 4, 1, 5, 2, 6, 3, 7 }; - ids = id; - _nbNodes = 8; - break; - } - case SMDSEntity_Quad_Tetra: - { - static int id[] = { 0, 4, 1, 5, 2, 6, 7, 8, 9, 3 }; - ids = id; - break; - } - case SMDSEntity_Quad_Pyramid: - { - static int id[] = { 0, 5, 1, 6, 2, 7, 3, 8, 9, 10, 11, 12, 4 }; - ids = id; - break; - } - case SMDSEntity_Penta: - { - static int id[] = { 0, 2, 1, 3, 5, 4 }; - ids = id; - break; - } - case SMDSEntity_Quad_Penta: - { - static int id[] = { 0, 8, 2, 7, 1, 6, 12, 14, 13, 3, 11, 5, 10, 4, 9 }; - ids = id; - break; - } - case SMDSEntity_Quad_Hexa: - case SMDSEntity_TriQuad_Hexa: - { - static int id[] = { 0, 8, 1, 9, 2, 10, 3, 11, 16, 17, 18, 19, 4, 12, 5, 13, 6, 14, 7, 15 }; - ids = id; - _nbNodes = 20; - break; - } - case SMDSEntity_Polygon: - case SMDSEntity_Quad_Polygon: - case SMDSEntity_Polyhedra: - case SMDSEntity_Quad_Polyhedra: - default: - { - // static int id[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, - // 25, 26, 27, 28, 29 }; - // ids = id; - // break; - } + case SMDSEntity_Quad_Edge: + { + static int id[] = { 0, 2, 1 }; + ids = id; + break; + } + case SMDSEntity_Quad_Triangle: + case SMDSEntity_BiQuad_Triangle: + { + static int id[] = { 0, 3, 1, 4, 2, 5 }; + ids = id; + _nbNodes = 6; + break; + } + case SMDSEntity_Quad_Quadrangle: + case SMDSEntity_BiQuad_Quadrangle: + { + static int id[] = { 0, 4, 1, 5, 2, 6, 3, 7 }; + ids = id; + _nbNodes = 8; + break; } + case SMDSEntity_Quad_Tetra: + { + static int id[] = { 0, 4, 1, 5, 2, 6, 7, 8, 9, 3 }; + ids = id; + break; + } + case SMDSEntity_Quad_Pyramid: + { + static int id[] = { 0, 5, 1, 6, 2, 7, 3, 8, 9, 10, 11, 12, 4 }; + ids = id; + break; + } + case SMDSEntity_Penta: + { + static int id[] = { 0, 2, 1, 3, 5, 4 }; + ids = id; + break; + } + case SMDSEntity_Quad_Penta: + { + static int id[] = { 0, 8, 2, 7, 1, 6, 12, 14, 13, 3, 11, 5, 10, 4, 9 }; + ids = id; + break; + } + case SMDSEntity_Quad_Hexa: + case SMDSEntity_TriQuad_Hexa: + { + static int id[] = { 0, 8, 1, 9, 2, 10, 3, 11, 16, 17, 18, 19, 4, 12, 5, 13, 6, 14, 7, 15 }; + ids = id; + _nbNodes = 20; + break; + } + case SMDSEntity_Polygon: + case SMDSEntity_Quad_Polygon: + case SMDSEntity_Polyhedra: + case SMDSEntity_Quad_Polyhedra: + default: + const std::vector& i = SMDS_MeshCell::interlacedSmdsOrder(aType, _nbNodes); + if ( !i.empty() ) + ids = & i[0]; + } + if ( ids ) for (int i = 0; i < _nbNodes; i++) _vtkIdList->SetId(i, pts[ids[i]]); @@ -176,34 +174,34 @@ SMDS_VtkCellIteratorPolyH::SMDS_VtkCellIteratorPolyH(SMDS_Mesh* mesh, int vtkCel _nbNodes = _vtkIdList->GetNumberOfIds(); switch (_type) { - case SMDSEntity_Polyhedra: - { - //MESSAGE("SMDS_VtkCellIterator Polyhedra"); - vtkIdType nFaces = 0; - vtkIdType* ptIds = 0; - grid->GetFaceStream(_cellId, nFaces, ptIds); - int id = 0; - _nbNodesInFaces = 0; - for (int i = 0; i < nFaces; i++) - { - int nodesInFace = ptIds[id]; // nodeIds in ptIds[id+1 .. id+nodesInFace] - _nbNodesInFaces += nodesInFace; - id += (nodesInFace + 1); - } - _vtkIdList->SetNumberOfIds(_nbNodesInFaces); - id = 0; - int n = 0; - for (int i = 0; i < nFaces; i++) - { - int nodesInFace = ptIds[id]; // nodeIds in ptIds[id+1 .. id+nodesInFace] - for (int k = 1; k <= nodesInFace; k++) - _vtkIdList->SetId(n++, ptIds[id + k]); - id += (nodesInFace + 1); - } - break; - } - default: - assert(0); + case SMDSEntity_Polyhedra: + { + //MESSAGE("SMDS_VtkCellIterator Polyhedra"); + vtkIdType nFaces = 0; + vtkIdType* ptIds = 0; + grid->GetFaceStream(_cellId, nFaces, ptIds); + int id = 0; + _nbNodesInFaces = 0; + for (int i = 0; i < nFaces; i++) + { + int nodesInFace = ptIds[id]; // nodeIds in ptIds[id+1 .. id+nodesInFace] + _nbNodesInFaces += nodesInFace; + id += (nodesInFace + 1); + } + _vtkIdList->SetNumberOfIds(_nbNodesInFaces); + id = 0; + int n = 0; + for (int i = 0; i < nFaces; i++) + { + int nodesInFace = ptIds[id]; // nodeIds in ptIds[id+1 .. id+nodesInFace] + for (int k = 1; k <= nodesInFace; k++) + _vtkIdList->SetId(n++, ptIds[id + k]); + id += (nodesInFace + 1); + } + break; + } + default: + assert(0); } } diff --git a/src/SMDS/SMDS_VtkFace.cxx b/src/SMDS/SMDS_VtkFace.cxx index cd281e01a..0a772f53b 100644 --- a/src/SMDS/SMDS_VtkFace.cxx +++ b/src/SMDS/SMDS_VtkFace.cxx @@ -85,6 +85,15 @@ void SMDS_VtkFace::initPoly(const std::vector& nodeIds, SMDS_Mesh* me mesh->setMyModified(); } +void SMDS_VtkFace::initQuadPoly(const std::vector& nodeIds, SMDS_Mesh* mesh) +{ + SMDS_MeshFace::init(); + vtkUnstructuredGrid* grid = mesh->getGrid(); + myMeshId = mesh->getMeshId(); + myVtkID = grid->InsertNextLinkedCell(VTK_QUADRATIC_POLYGON, nodeIds.size(), (vtkIdType*) &nodeIds[0]); + mesh->setMyModified(); +} + bool SMDS_VtkFace::ChangeNodes(const SMDS_MeshNode* nodes[], const int nbNodes) { vtkUnstructuredGrid* grid = SMDS_Mesh::_meshList[myMeshId]->getGrid(); @@ -111,26 +120,28 @@ void SMDS_VtkFace::Print(std::ostream & OS) const int SMDS_VtkFace::NbEdges() const { - // TODO quadratic polygons ? vtkUnstructuredGrid* grid = SMDS_Mesh::_meshList[myMeshId]->getGrid(); vtkIdType aVtkType = grid->GetCellType(this->myVtkID); int nbEdges = 3; switch (aVtkType) { - case VTK_TRIANGLE: - case VTK_QUADRATIC_TRIANGLE: - case VTK_BIQUADRATIC_TRIANGLE: - nbEdges = 3; - break; - case VTK_QUAD: - case VTK_QUADRATIC_QUAD: - case VTK_BIQUADRATIC_QUAD: - nbEdges = 4; - break; - case VTK_POLYGON: - default: - nbEdges = grid->GetCell(myVtkID)->GetNumberOfPoints(); - break; + case VTK_TRIANGLE: + case VTK_QUADRATIC_TRIANGLE: + case VTK_BIQUADRATIC_TRIANGLE: + nbEdges = 3; + break; + case VTK_QUAD: + case VTK_QUADRATIC_QUAD: + case VTK_BIQUADRATIC_QUAD: + nbEdges = 4; + break; + case VTK_QUADRATIC_POLYGON: + nbEdges = grid->GetCell(myVtkID)->GetNumberOfPoints() / 2; + break; + case VTK_POLYGON: + default: + nbEdges = grid->GetCell(myVtkID)->GetNumberOfPoints(); + break; } return nbEdges; } @@ -186,6 +197,7 @@ bool SMDS_VtkFace::IsQuadratic() const { case VTK_QUADRATIC_TRIANGLE: case VTK_QUADRATIC_QUAD: + case VTK_QUADRATIC_POLYGON: case VTK_BIQUADRATIC_QUAD: case VTK_BIQUADRATIC_TRIANGLE: return true; @@ -199,7 +211,7 @@ bool SMDS_VtkFace::IsPoly() const { vtkUnstructuredGrid* grid = SMDS_Mesh::_meshList[myMeshId]->getGrid(); vtkIdType aVtkType = grid->GetCellType(this->myVtkID); - return (aVtkType == VTK_POLYGON); + return ( aVtkType == VTK_POLYGON || aVtkType == VTK_QUADRATIC_POLYGON ); } bool SMDS_VtkFace::IsMediumNode(const SMDS_MeshNode* node) const @@ -209,33 +221,36 @@ bool SMDS_VtkFace::IsMediumNode(const SMDS_MeshNode* node) const int rankFirstMedium = 0; switch (aVtkType) { - case VTK_QUADRATIC_TRIANGLE: - case VTK_BIQUADRATIC_TRIANGLE: - rankFirstMedium = 3; // medium nodes are of rank 3,4,5 - break; - case VTK_QUADRATIC_QUAD: - case VTK_BIQUADRATIC_QUAD: - rankFirstMedium = 4; // medium nodes are of rank 4,5,6,7 - break; - default: - //MESSAGE("wrong element type " << aVtkType); - return false; + case VTK_QUADRATIC_TRIANGLE: + case VTK_BIQUADRATIC_TRIANGLE: + rankFirstMedium = 3; // medium nodes are of rank 3,4,5 + break; + case VTK_QUADRATIC_QUAD: + case VTK_BIQUADRATIC_QUAD: + rankFirstMedium = 4; // medium nodes are of rank 4,5,6,7 + break; + case VTK_QUADRATIC_POLYGON: + rankFirstMedium = grid->GetCell(myVtkID)->GetNumberOfPoints() / 2; + break; + default: + //MESSAGE("wrong element type " << aVtkType); + return false; } vtkIdType npts = 0; vtkIdType* pts = 0; grid->GetCellPoints(myVtkID, npts, pts); vtkIdType nodeId = node->getVtkId(); for (int rank = 0; rank < npts; rank++) + { + if (pts[rank] == nodeId) { - if (pts[rank] == nodeId) - { - //MESSAGE("rank " << rank << " is medium node " << (rank < rankFirstMedium)); - if (rank < rankFirstMedium) - return false; - else - return true; - } + //MESSAGE("rank " << rank << " is medium node " << (rank < rankFirstMedium)); + if (rank < rankFirstMedium) + return false; + else + return true; } + } //throw SALOME_Exception(LOCALIZED("node does not belong to this element")); MESSAGE("======================================================"); MESSAGE("= IsMediumNode: node does not belong to this element ="); @@ -248,8 +263,17 @@ int SMDS_VtkFace::NbCornerNodes() const vtkUnstructuredGrid* grid = SMDS_Mesh::_meshList[myMeshId]->getGrid(); int nbPoints = grid->GetCell(myVtkID)->GetNumberOfPoints(); vtkIdType aVtkType = grid->GetCellType(myVtkID); - if ( aVtkType != VTK_POLYGON ) - return nbPoints <= 4 ? nbPoints : nbPoints / 2; + switch ( aVtkType ) + { + case VTK_POLYGON: + break; + case VTK_QUADRATIC_POLYGON: + nbPoints /= 2; + break; + default: + if ( nbPoints > 4 ) + nbPoints /= 2; + } return nbPoints; } @@ -273,7 +297,8 @@ SMDSAbs_GeometryType SMDS_VtkFace::GetGeomType() const case VTK_QUADRATIC_QUAD: case VTK_BIQUADRATIC_QUAD: return SMDSGeom_QUADRANGLE; - case VTK_POLYGON: return SMDSGeom_POLYGON; + case VTK_POLYGON: + case VTK_QUADRATIC_POLYGON: return SMDSGeom_POLYGON; default:; } return SMDSGeom_NONE; diff --git a/src/SMDS/SMDS_VtkFace.hxx b/src/SMDS/SMDS_VtkFace.hxx index 351c905f9..235a9c2d8 100644 --- a/src/SMDS/SMDS_VtkFace.hxx +++ b/src/SMDS/SMDS_VtkFace.hxx @@ -34,6 +34,7 @@ public: ~SMDS_VtkFace(); void init(const std::vector& nodeIds, SMDS_Mesh* mesh); void initPoly(const std::vector& nodeIds, SMDS_Mesh* mesh); + void initQuadPoly(const std::vector& nodeIds, SMDS_Mesh* mesh); bool ChangeNodes(const SMDS_MeshNode* nodes[], const int nbNodes); void ChangeApex(SMDS_MeshNode* node); // to use only for tmp triangles diff --git a/src/SMESH/SMESH_Mesh.cxx b/src/SMESH/SMESH_Mesh.cxx index 4b3444adf..4ba42c977 100644 --- a/src/SMESH/SMESH_Mesh.cxx +++ b/src/SMESH/SMESH_Mesh.cxx @@ -1783,10 +1783,10 @@ int SMESH_Mesh::NbBiQuadQuadrangles() const throw(SALOME_Exception) */ //================================================================================ -int SMESH_Mesh::NbPolygons() const throw(SALOME_Exception) +int SMESH_Mesh::NbPolygons(SMDSAbs_ElementOrder order) const throw(SALOME_Exception) { Unexpect aCatch(SalomeException); - return _myMeshDS->GetMeshInfo().NbPolygons(); + return _myMeshDS->GetMeshInfo().NbPolygons(order); } //================================================================================ diff --git a/src/SMESH/SMESH_Mesh.hxx b/src/SMESH/SMESH_Mesh.hxx index 4878dc4f9..5221ab7d2 100644 --- a/src/SMESH/SMESH_Mesh.hxx +++ b/src/SMESH/SMESH_Mesh.hxx @@ -283,7 +283,7 @@ class SMESH_EXPORT SMESH_Mesh int NbQuadrangles(SMDSAbs_ElementOrder order = ORDER_ANY) const throw(SALOME_Exception); int NbBiQuadQuadrangles() const throw(SALOME_Exception); int NbBiQuadTriangles() const throw(SALOME_Exception); - int NbPolygons() const throw(SALOME_Exception); + int NbPolygons(SMDSAbs_ElementOrder order = ORDER_ANY) const throw(SALOME_Exception); int NbVolumes(SMDSAbs_ElementOrder order = ORDER_ANY) const throw(SALOME_Exception); int NbTetras(SMDSAbs_ElementOrder order = ORDER_ANY) const throw(SALOME_Exception); diff --git a/src/SMESH/SMESH_MeshEditor.cxx b/src/SMESH/SMESH_MeshEditor.cxx index b45e0117b..18666319f 100644 --- a/src/SMESH/SMESH_MeshEditor.cxx +++ b/src/SMESH/SMESH_MeshEditor.cxx @@ -137,6 +137,40 @@ void SMESH_MeshEditor::ClearLastCreated() myLastCreatedElems.Clear(); } +//================================================================================ +/*! + * \brief Initializes members by an existing element + * \param [in] elem - the source element + * \param [in] basicOnly - if true, does not set additional data of Ball and Polyhedron + */ +//================================================================================ + +SMESH_MeshEditor::ElemFeatures& +SMESH_MeshEditor::ElemFeatures::Init( const SMDS_MeshElement* elem, bool basicOnly ) +{ + if ( elem ) + { + myType = elem->GetType(); + if ( myType == SMDSAbs_Face || myType == SMDSAbs_Volume ) + { + myIsPoly = elem->IsPoly(); + if ( myIsPoly ) + { + myIsQuad = elem->IsQuadratic(); + if ( myType == SMDSAbs_Volume && !basicOnly ) + { + vector quant = static_cast( elem )->GetQuantities(); + myPolyhedQuantities.swap( quant ); + } + } + } + else if ( myType == SMDSAbs_Ball && !basicOnly ) + { + myBallDiameter = static_cast(elem)->GetDiameter(); + } + } + return *this; +} //======================================================================= /*! @@ -146,18 +180,16 @@ void SMESH_MeshEditor::ClearLastCreated() SMDS_MeshElement* SMESH_MeshEditor::AddElement(const vector & node, - const SMDSAbs_ElementType type, - const bool isPoly, - const int ID, - const double ballDiameter) + const ElemFeatures& features) { - //MESSAGE("AddElement " <= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], ID); else e = mesh->AddFace (node[0], node[1], node[2] ); @@ -190,14 +222,21 @@ SMESH_MeshEditor::AddElement(const vector & node, else e = mesh->AddFace (node[0], node[1], node[2], node[3], node[4], node[5], node[6], node[7], node[8] ); } - } else { + } + else if ( !features.myIsQuad ) + { if ( ID >= 1 ) e = mesh->AddPolygonalFaceWithID(node, ID); else e = mesh->AddPolygonalFace (node ); } + else if ( nbnode % 2 == 0 ) // just a protection + { + if ( ID >= 1 ) e = mesh->AddQuadPolygonalFaceWithID(node, ID); + else e = mesh->AddQuadPolygonalFace (node ); + } break; case SMDSAbs_Volume: - if ( !isPoly ) { + if ( !features.myIsPoly ) { if (nbnode == 4) { if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3], ID); else e = mesh->AddVolume (node[0], node[1], node[2], node[3] ); @@ -285,6 +324,16 @@ SMESH_MeshEditor::AddElement(const vector & node, node[24],node[25],node[26] ); } } + else if ( !features.myIsQuad ) + { + if ( ID >= 1 ) e = mesh->AddPolyhedralVolumeWithID(node, features.myPolyhedQuantities, ID); + else e = mesh->AddPolyhedralVolume (node, features.myPolyhedQuantities ); + } + else + { + // if ( ID >= 1 ) e = mesh->AddQuadPolyhedralVolumeWithID(node, features.myPolyhedQuantities,ID); + // else e = mesh->AddQuadPolyhedralVolume (node, features.myPolyhedQuantities ); + } break; case SMDSAbs_Edge: @@ -307,12 +356,12 @@ SMESH_MeshEditor::AddElement(const vector & node, case SMDSAbs_Node: if ( ID >= 1 ) e = mesh->AddNodeWithID(node[0]->X(), node[0]->Y(), node[0]->Z(), ID); - else e = mesh->AddNode (node[0]->X(), node[0]->Y(), node[0]->Z()); + else e = mesh->AddNode (node[0]->X(), node[0]->Y(), node[0]->Z() ); break; case SMDSAbs_Ball: - if ( ID >= 1 ) e = mesh->AddBallWithID(node[0], ballDiameter, ID); - else e = mesh->AddBall (node[0], ballDiameter); + if ( ID >= 1 ) e = mesh->AddBallWithID(node[0], features.myBallDiameter, ID); + else e = mesh->AddBall (node[0], features.myBallDiameter ); break; default:; @@ -327,10 +376,8 @@ SMESH_MeshEditor::AddElement(const vector & node, */ //======================================================================= -SMDS_MeshElement* SMESH_MeshEditor::AddElement(const vector & nodeIDs, - const SMDSAbs_ElementType type, - const bool isPoly, - const int ID) +SMDS_MeshElement* SMESH_MeshEditor::AddElement(const vector & nodeIDs, + const ElemFeatures& features) { vector nodes; nodes.reserve( nodeIDs.size() ); @@ -341,7 +388,7 @@ SMDS_MeshElement* SMESH_MeshEditor::AddElement(const vector & nodeIDs else return 0; } - return AddElement( nodes, type, isPoly, ID ); + return AddElement( nodes, features ); } //======================================================================= @@ -1100,12 +1147,12 @@ bool SMESH_MeshEditor::Reorient (const SMDS_MeshElement * theElem) else // other elements { vector nodes( theElem->begin_nodes(), theElem->end_nodes() ); - const std::vector& interlace = SMDS_MeshCell::reverseSmdsOrder( geomType ); + const std::vector& interlace = SMDS_MeshCell::reverseSmdsOrder( geomType, nodes.size() ); if ( interlace.empty() ) { - std::reverse( nodes.begin(), nodes.end() ); // polygon + std::reverse( nodes.begin(), nodes.end() ); // obsolete, just in case } - else if ( interlace.size() > 1 ) + else { SMDS_MeshCell::applyInterlace( interlace, nodes ); } @@ -4326,7 +4373,7 @@ void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement* elem, } else { - const vector& ind = SMDS_MeshCell::reverseSmdsOrder( baseType ); + const vector& ind = SMDS_MeshCell::reverseSmdsOrder( baseType, nbNodes ); SMDS_MeshCell::applyInterlace( ind, itNN ); SMDS_MeshCell::applyInterlace( ind, prevNod ); SMDS_MeshCell::applyInterlace( ind, nextNod ); @@ -4379,6 +4426,17 @@ void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement* elem, iOpposSame = ( iSameNode - 2 < 0 ? iSameNode + 2 : iSameNode - 2 ); } + if ( baseType == SMDSEntity_Polygon ) + { + if ( nbNodes == 3 ) baseType = SMDSEntity_Triangle; + else if ( nbNodes == 4 ) baseType = SMDSEntity_Quadrangle; + } + else if ( baseType == SMDSEntity_Quad_Polygon ) + { + if ( nbNodes == 6 ) baseType = SMDSEntity_Quad_Triangle; + else if ( nbNodes == 8 ) baseType = SMDSEntity_Quad_Quadrangle; + } + // make new elements for (int iStep = 0; iStep < nbSteps; iStep++ ) { @@ -4524,7 +4582,7 @@ void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement* elem, break; } case SMDSEntity_Quad_Triangle: // sweep (Bi)Quadratic TRIANGLE ---> - case SMDSEntity_BiQuad_Triangle: /* ??? */ { + case SMDSEntity_BiQuad_Triangle: /* ??? */ { if ( nbDouble+nbSame != 3 ) break; if(nbSame==0) { // ---> pentahedron with 15 nodes @@ -4652,7 +4710,7 @@ void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement* elem, { if ( baseType != SMDSEntity_Polygon ) { - const std::vector& ind = SMDS_MeshCell::interlacedSmdsOrder(baseType); + const std::vector& ind = SMDS_MeshCell::interlacedSmdsOrder(baseType,nbNodes); SMDS_MeshCell::applyInterlace( ind, prevNod ); SMDS_MeshCell::applyInterlace( ind, nextNod ); SMDS_MeshCell::applyInterlace( ind, midlNod ); @@ -4677,21 +4735,30 @@ void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement* elem, quantities.push_back( nbNodes ); // side faces - for (int iface = 0; iface < nbNodes; iface++) + // 3--6--2 + // | | + // 7 5 + // | | + // 0--4--1 + const int iQuad = elem->IsQuadratic(); + for (int iface = 0; iface < nbNodes; iface += 1+iQuad ) { - const int prevNbNodes = polyedre_nodes.size(); - int inextface = (iface+1) % nbNodes; - polyedre_nodes.push_back( prevNod[inextface] ); - polyedre_nodes.push_back( prevNod[iface] ); - if ( prevNod[iface] != nextNod[iface] ) + const int prevNbNodes = polyedre_nodes.size(); // to detect degenerated face + int inextface = (iface+1+iQuad) % nbNodes; + int imid = (iface+1) % nbNodes; + polyedre_nodes.push_back( prevNod[inextface] ); // 0 + if ( iQuad ) polyedre_nodes.push_back( prevNod[imid] ); // 4 + polyedre_nodes.push_back( prevNod[iface] ); // 1 + if ( prevNod[iface] != nextNod[iface] ) // 1 != 2 { - if ( midlNod[ iface ]) polyedre_nodes.push_back( midlNod[ iface ]); - polyedre_nodes.push_back( nextNod[iface] ); + if ( midlNod[ iface ]) polyedre_nodes.push_back( midlNod[ iface ]); // 5 + polyedre_nodes.push_back( nextNod[iface] ); // 2 } - if ( prevNod[inextface] != nextNod[inextface] ) + if ( iQuad ) polyedre_nodes.push_back( nextNod[imid] ); // 6 + if ( prevNod[inextface] != nextNod[inextface] ) // 0 != 3 { - polyedre_nodes.push_back( nextNod[inextface] ); - if ( midlNod[ inextface ]) polyedre_nodes.push_back( midlNod[ inextface ]); + polyedre_nodes.push_back( nextNod[inextface] ); // 3 + if ( midlNod[ inextface ]) polyedre_nodes.push_back( midlNod[ inextface ]);// 7 } const int nbFaceNodes = polyedre_nodes.size() - prevNbNodes; if ( nbFaceNodes > 2 ) @@ -4701,7 +4768,7 @@ void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement* elem, } aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities); - } // // try to create a polyherdal prism + } // try to create a polyherdal prism if ( aNewElem ) { newElems.push_back( aNewElem ); @@ -4752,13 +4819,14 @@ void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap & mapNewNodes, const SMDS_MeshElement* el = 0; SMDSAbs_ElementType highType = SMDSAbs_Edge; // count most complex elements only while ( eIt->more() && nbInitElems < 2 ) { - el = eIt->next(); - SMDSAbs_ElementType type = el->GetType(); + const SMDS_MeshElement* e = eIt->next(); + SMDSAbs_ElementType type = e->GetType(); if ( type == SMDSAbs_Volume || type < highType ) continue; if ( type > highType ) { nbInitElems = 0; highType = type; } + el = e; nbInitElems += elemSet.count(el); } if ( nbInitElems < 2 ) { @@ -4774,6 +4842,8 @@ void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap & mapNewNodes, // Make a ceiling for each element ie an equal element of last new nodes. // Find free links of faces - make edges and sweep them into faces. + ElemFeatures polyFace( SMDSAbs_Face, /*isPoly=*/true ), anyFace; + TTElemOfElemListMap::iterator itElem = newElemsMap.begin(); TElemOfVecOfNnlmiMap::iterator itElemNodes = elemNewNodesMap.begin(); for ( ; itElem != newElemsMap.end(); itElem++, itElemNodes++ ) @@ -4877,7 +4947,7 @@ void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap & mapNewNodes, // sweep free links into faces - if ( hasFreeLinks ) { + if ( hasFreeLinks ) { list & newVolumes = itElem->second; int iVol, volNb, nbVolumesByStep = newVolumes.size() / nbSteps; @@ -4911,11 +4981,12 @@ void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap & mapNewNodes, freeInd.push_back( iF ); // find source edge of a free face iF vector commonNodes; // shared by the initial and free faces - commonNodes.resize( initNodeSet.size(), NULL ); // avoid spoiling memory - std::set_intersection( faceNodeSet.begin(), faceNodeSet.end(), - initNodeSet.begin(), initNodeSet.end(), - commonNodes.begin()); - if ( (*v)->IsQuadratic() ) + vector::iterator lastCommom; + commonNodes.resize( nbNodes, 0 ); + lastCommom = std::set_intersection( faceNodeSet.begin(), faceNodeSet.end(), + initNodeSet.begin(), initNodeSet.end(), + commonNodes.begin()); + if ( std::distance( commonNodes.begin(), lastCommom ) == 3 ) srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1],commonNodes[2])); else srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1])); @@ -4931,10 +5002,11 @@ void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap & mapNewNodes, if ( freeInd.empty() ) continue; - // create faces for all steps; + // create wall faces for all steps; // if such a face has been already created by sweep of edge, // assure that its orientation is OK - for ( int iStep = 0; iStep < nbSteps; iStep++ ) { + for ( int iStep = 0; iStep < nbSteps; iStep++ ) + { vTool.Set( *v, /*ignoreCentralNodes=*/false ); vTool.SetExternalNormal(); const int nextShift = vTool.IsForward() ? +1 : -1; @@ -5061,7 +5133,7 @@ void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap & mapNewNodes, if ( f ) aMesh->ChangeElementNodes( f, &polygon_nodes[0], nbn ); else - AddElement(polygon_nodes, SMDSAbs_Face, polygon_nodes.size()>4); + AddElement( polygon_nodes, polyFace.SetQuad( (*v)->IsQuadratic() )); } } @@ -5088,36 +5160,21 @@ void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap & mapNewNodes, aFaceLastNodes.erase( vecNewNodes.back()->second.back() ); iF = lastVol.GetFaceIndex( aFaceLastNodes ); } - if ( iF >= 0 ) { + if ( iF >= 0 ) + { lastVol.SetExternalNormal(); const SMDS_MeshNode** nodes = lastVol.GetFaceNodes( iF ); - int nbn = lastVol.NbFaceNodes( iF ); - // we do not use this->AddElement() because nodes are interlaced + const int nbn = lastVol.NbFaceNodes( iF ); vector nodeVec( nodes, nodes+nbn ); if ( !hasFreeLinks || !aMesh->FindElement( nodeVec, SMDSAbs_Face, /*noMedium=*/false) ) { - if ( nbn == 3 ) - myLastCreatedElems.Append(aMesh->AddFace( nodes[0], nodes[1], nodes[2] )); - - else if ( nbn == 4 ) - myLastCreatedElems.Append(aMesh->AddFace( nodes[0], nodes[1], nodes[2], nodes[3])); - - else if ( nbn == 6 && isQuadratic ) - myLastCreatedElems.Append(aMesh->AddFace( nodes[0], nodes[2], nodes[4], - nodes[1], nodes[3], nodes[5])); - else if ( nbn == 7 && isQuadratic ) - myLastCreatedElems.Append(aMesh->AddFace( nodes[0], nodes[2], nodes[4], - nodes[1], nodes[3], nodes[5], nodes[6])); - else if ( nbn == 8 && isQuadratic ) - myLastCreatedElems.Append(aMesh->AddFace( nodes[0], nodes[2], nodes[4], nodes[6], - nodes[1], nodes[3], nodes[5], nodes[7])); - else if ( nbn == 9 && isQuadratic ) - myLastCreatedElems.Append(aMesh->AddFace( nodes[0], nodes[2], nodes[4], nodes[6], - nodes[1], nodes[3], nodes[5], nodes[7], - nodes[8])); - else - myLastCreatedElems.Append(aMesh->AddPolygonalFace( nodeVec )); + const vector& interlace = + SMDS_MeshCell::interlacedSmdsOrder( elem->GetEntityType(), nbn ); + SMDS_MeshCell::applyInterlaceRev( interlace, nodeVec ); + + if ( const SMDS_MeshElement* face = AddElement( nodeVec, anyFace.Init( elem ))) + myLastCreatedElems.Append( face ); while ( srcElements.Length() < myLastCreatedElems.Length() ) srcElements.Append( elem ); @@ -5181,7 +5238,6 @@ SMESH_MeshEditor::RotationSweep(TIDSortedElemSet theElemSets[2], SMDS_ElemIteratorPtr itN = elem->nodesIterator(); while ( itN->more() ) { - // check if a node has been already sweeped const SMDS_MeshNode* node = cast2Node( itN->next() ); gp_XYZ aXYZ( node->X(), node->Y(), node->Z() ); @@ -5189,6 +5245,7 @@ SMESH_MeshEditor::RotationSweep(TIDSortedElemSet theElemSets[2], aXYZ.Coord( coord[0], coord[1], coord[2] ); bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol ); + // check if a node has been already sweeped TNodeOfNodeListMapItr nIt = mapNewNodes.insert( make_pair( node, list() )).first; list& listNewNodes = nIt->second; @@ -6551,10 +6608,12 @@ SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems, groupPostfix = "transformed"; } - SMESH_MeshEditor targetMeshEditor( theTargetMesh ); SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0; SMESHDS_Mesh* aMesh = GetMeshDS(); + SMESH_MeshEditor targetMeshEditor( theTargetMesh ); + SMESH_MeshEditor* editor = theTargetMesh ? & targetMeshEditor : theCopy ? this : 0; + SMESH_MeshEditor::ElemFeatures elemType; // map old node to new one TNodeNodeMap nodeMap; @@ -6586,70 +6645,68 @@ SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems, // loop on elements to transform nodes : first orphan nodes then elems TIDSortedElemSet::iterator itElem; - TIDSortedElemSet *elements[] = {&orphanNode, &theElems }; + TIDSortedElemSet *elements[] = { &orphanNode, &theElems }; for (int i=0; i<2; i++) - for ( itElem = elements[i]->begin(); itElem != elements[i]->end(); itElem++ ) { - const SMDS_MeshElement* elem = *itElem; - if ( !elem ) - continue; - - // loop on elem nodes - SMDS_ElemIteratorPtr itN = elem->nodesIterator(); - while ( itN->more() ) { - - const SMDS_MeshNode* node = cast2Node( itN->next() ); - // check if a node has been already transformed - pair n2n_isnew = - nodeMap.insert( make_pair ( node, node )); - if ( !n2n_isnew.second ) + for ( itElem = elements[i]->begin(); itElem != elements[i]->end(); itElem++ ) + { + const SMDS_MeshElement* elem = *itElem; + if ( !elem ) continue; + // loop on elem nodes double coord[3]; - coord[0] = node->X(); - coord[1] = node->Y(); - coord[2] = node->Z(); - theTrsf.Transforms( coord[0], coord[1], coord[2] ); - if ( theTargetMesh ) { - const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] ); - n2n_isnew.first->second = newNode; - myLastCreatedNodes.Append(newNode); - srcNodes.Append( node ); - } - else if ( theCopy ) { - const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] ); - n2n_isnew.first->second = newNode; - myLastCreatedNodes.Append(newNode); - srcNodes.Append( node ); - } - else { - aMesh->MoveNode( node, coord[0], coord[1], coord[2] ); - // node position on shape becomes invalid - const_cast< SMDS_MeshNode* > ( node )->SetPosition - ( SMDS_SpacePosition::originSpacePosition() ); - } + SMDS_ElemIteratorPtr itN = elem->nodesIterator(); + while ( itN->more() ) + { + const SMDS_MeshNode* node = cast2Node( itN->next() ); + // check if a node has been already transformed + pair n2n_isnew = + nodeMap.insert( make_pair ( node, node )); + if ( !n2n_isnew.second ) + continue; - // keep inverse elements - if ( !theCopy && !theTargetMesh && needReverse ) { - SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator(); - while ( invElemIt->more() ) { - const SMDS_MeshElement* iel = invElemIt->next(); - inverseElemSet.insert( iel ); + node->GetXYZ( coord ); + theTrsf.Transforms( coord[0], coord[1], coord[2] ); + if ( theTargetMesh ) { + const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] ); + n2n_isnew.first->second = newNode; + myLastCreatedNodes.Append(newNode); + srcNodes.Append( node ); + } + else if ( theCopy ) { + const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] ); + n2n_isnew.first->second = newNode; + myLastCreatedNodes.Append(newNode); + srcNodes.Append( node ); + } + else { + aMesh->MoveNode( node, coord[0], coord[1], coord[2] ); + // node position on shape becomes invalid + const_cast< SMDS_MeshNode* > ( node )->SetPosition + ( SMDS_SpacePosition::originSpacePosition() ); + } + + // keep inverse elements + if ( !theCopy && !theTargetMesh && needReverse ) { + SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator(); + while ( invElemIt->more() ) { + const SMDS_MeshElement* iel = invElemIt->next(); + inverseElemSet.insert( iel ); + } } } - } - } + } // loop on elems in { &orphanNode, &theElems }; // either create new elements or reverse mirrored ones if ( !theCopy && !needReverse && !theTargetMesh ) return PGroupIDs(); - TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin(); - for ( ; invElemIt != inverseElemSet.end(); invElemIt++ ) - theElems.insert( *invElemIt ); + theElems.insert( inverseElemSet.begin(),inverseElemSet.end() ); // Replicate or reverse elements std::vector iForw; + vector nodes; for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) { const SMDS_MeshElement* elem = *itElem; @@ -6659,123 +6716,45 @@ SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems, int nbNodes = elem->NbNodes(); if ( geomType == SMDSGeom_NONE ) continue; // node - switch ( geomType ) { + nodes.resize( nbNodes ); - case SMDSGeom_POLYGON: // ---------------------- polygon + if ( geomType == SMDSGeom_POLYHEDRA ) // ------------------ polyhedral volume + { + const SMDS_VtkVolume* aPolyedre = dynamic_cast( elem ); + if (!aPolyedre) + continue; + nodes.clear(); + bool allTransformed = true; + int nbFaces = aPolyedre->NbFaces(); + for (int iface = 1; iface <= nbFaces && allTransformed; iface++) { - vector poly_nodes (nbNodes); - int iNode = 0; - SMDS_ElemIteratorPtr itN = elem->nodesIterator(); - while (itN->more()) { - const SMDS_MeshNode* node = - static_cast(itN->next()); + int nbFaceNodes = aPolyedre->NbFaceNodes(iface); + for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) + { + const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode); TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node); - if (nodeMapIt == nodeMap.end()) - break; // not all nodes transformed - if (needReverse) { - // reverse mirrored faces and volumes - poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second; - } else { - poly_nodes[iNode] = (*nodeMapIt).second; - } - iNode++; - } - if ( iNode != nbNodes ) - continue; // not all nodes transformed - - if ( theTargetMesh ) { - myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes)); - srcElems.Append( elem ); - } - else if ( theCopy ) { - myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes)); - srcElems.Append( elem ); - } - else { - aMesh->ChangePolygonNodes(elem, poly_nodes); - } - } - break; - - case SMDSGeom_POLYHEDRA: // ------------------ polyhedral volume - { - const SMDS_VtkVolume* aPolyedre = - dynamic_cast( elem ); - if (!aPolyedre) { - MESSAGE("Warning: bad volumic element"); - continue; - } - - vector poly_nodes; poly_nodes.reserve( nbNodes ); - vector quantities; quantities.reserve( nbNodes ); - - bool allTransformed = true; - int nbFaces = aPolyedre->NbFaces(); - for (int iface = 1; iface <= nbFaces && allTransformed; iface++) { - int nbFaceNodes = aPolyedre->NbFaceNodes(iface); - for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) { - const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode); - TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node); - if (nodeMapIt == nodeMap.end()) { - allTransformed = false; // not all nodes transformed - } else { - poly_nodes.push_back((*nodeMapIt).second); - } - if ( needReverse && allTransformed ) - std::reverse( poly_nodes.end() - nbFaceNodes, poly_nodes.end() ); - } - quantities.push_back(nbFaceNodes); - } - if ( !allTransformed ) - continue; // not all nodes transformed - - if ( theTargetMesh ) { - myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities)); - srcElems.Append( elem ); - } - else if ( theCopy ) { - myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities)); - srcElems.Append( elem ); - } - else { - aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities); - } - } - break; - - case SMDSGeom_BALL: // -------------------- Ball - { - if ( !theCopy && !theTargetMesh ) continue; - - TNodeNodeMap::iterator nodeMapIt = nodeMap.find( elem->GetNode(0) ); - if (nodeMapIt == nodeMap.end()) - continue; // not all nodes transformed - - double diameter = static_cast(elem)->GetDiameter(); - if ( theTargetMesh ) { - myLastCreatedElems.Append(aTgtMesh->AddBall( nodeMapIt->second, diameter )); - srcElems.Append( elem ); - } - else { - myLastCreatedElems.Append(aMesh->AddBall( nodeMapIt->second, diameter )); - srcElems.Append( elem ); + if ( nodeMapIt == nodeMap.end() ) + allTransformed = false; // not all nodes transformed + else + nodes.push_back((*nodeMapIt).second); } + if ( needReverse && allTransformed ) + std::reverse( nodes.end() - nbFaceNodes, nodes.end() ); } - break; - - default: // ----------------------- Regular elements - + if ( !allTransformed ) + continue; // not all nodes transformed + } + else // ----------------------- the rest element types + { while ( iForw.size() < nbNodes ) iForw.push_back( iForw.size() ); - const std::vector& iRev = SMDS_MeshCell::reverseSmdsOrder( elem->GetEntityType() ); - const std::vector& i = needReverse ? iRev : iForw; + const vector& iRev = SMDS_MeshCell::reverseSmdsOrder( elem->GetEntityType(), nbNodes ); + const vector& i = needReverse ? iRev : iForw; // find transformed nodes - vector nodes(nbNodes); int iNode = 0; SMDS_ElemIteratorPtr itN = elem->nodesIterator(); while ( itN->more() ) { - const SMDS_MeshNode* node = - static_cast( itN->next() ); + const SMDS_MeshNode* node = static_cast( itN->next() ); TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node ); if ( nodeMapIt == nodeMap.end() ) break; // not all nodes transformed @@ -6783,27 +6762,24 @@ SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems, } if ( iNode != nbNodes ) continue; // not all nodes transformed + } - if ( theTargetMesh ) { - if ( SMDS_MeshElement* copy = - targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) { - myLastCreatedElems.Append( copy ); - srcElems.Append( elem ); - } - } - else if ( theCopy ) { - if ( AddElement( nodes, elem->GetType(), elem->IsPoly() )) - srcElems.Append( elem ); - } - else { - // reverse element as it was reversed by transformation - if ( nbNodes > 2 ) - aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes ); - } - } // switch ( geomType ) + if ( editor ) { + // copy in this or a new mesh + if ( editor->AddElement( nodes, elemType.Init( elem, /*basicOnly=*/false ))) + srcElems.Append( elem ); + } + else { + // reverse element as it was reversed by transformation + if ( nbNodes > 2 ) + aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes ); + } } // loop on elements + if ( editor && editor != this ) + myLastCreatedElems = editor->myLastCreatedElems; + PGroupIDs newGroupIDs; if ( ( theMakeGroups && theCopy ) || @@ -7032,7 +7008,7 @@ void SMESH_MeshEditor::FindCoincidentNodes (TIDSortedNodeSet & theNodes, //======================================================================= //function : SimplifyFace -//purpose : +//purpose : split a chain of nodes into several closed chains //======================================================================= int SMESH_MeshEditor::SimplifyFace (const vector& faceNodes, @@ -7164,29 +7140,34 @@ void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes) } // Change element nodes or remove an element + set nodeSet; + vector< const SMDS_MeshNode*> curNodes, uniqueNodes; + vector iRepl; + ElemFeatures elemType; + set::iterator eIt = elems.begin(); - for ( ; eIt != elems.end(); eIt++ ) { + for ( ; eIt != elems.end(); eIt++ ) + { const SMDS_MeshElement* elem = *eIt; - //MESSAGE(" ---- inverse elem on node to remove " << elem->GetID()); int nbNodes = elem->NbNodes(); int aShapeId = FindShape( elem ); - set nodeSet; - vector< const SMDS_MeshNode*> curNodes( nbNodes ), uniqueNodes( nbNodes ); + nodeSet.clear(); + curNodes.resize( nbNodes ); + uniqueNodes.resize( nbNodes ); + iRepl.resize( nbNodes ); int iUnique = 0, iCur = 0, nbRepl = 0; - vector iRepl( nbNodes ); // get new seq of nodes SMDS_ElemIteratorPtr itN = elem->nodesIterator(); - while ( itN->more() ) { - const SMDS_MeshNode* n = - static_cast( itN->next() ); + while ( itN->more() ) + { + const SMDS_MeshNode* n = static_cast( itN->next() ); TNodeNodeMap::iterator nnIt = nodeNodeMap.find( n ); if ( nnIt != nodeNodeMap.end() ) { // n sticks n = (*nnIt).second; - // BUG 0020185: begin - { + { ////////// BUG 0020185: begin bool stopRecur = false; set nodesRecur; nodesRecur.insert(n); @@ -7202,8 +7183,7 @@ void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes) else stopRecur = true; } - } - // BUG 0020185: end + } ////////// BUG 0020185: end } curNodes[ iCur ] = n; bool isUnique = nodeSet.insert( n ).second; @@ -7218,56 +7198,54 @@ void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes) bool isOk = true; int nbUniqueNodes = nodeSet.size(); - //MESSAGE("nbNodes nbUniqueNodes " << nbNodes << " " << nbUniqueNodes); - if ( nbNodes != nbUniqueNodes ) { // some nodes stick - // Polygons and Polyhedral volumes - if (elem->IsPoly()) { - - if (elem->GetType() == SMDSAbs_Face) { - // Polygon - vector face_nodes (nbNodes); - int inode = 0; - for (; inode < nbNodes; inode++) { - face_nodes[inode] = curNodes[inode]; - } + if ( nbNodes != nbUniqueNodes ) // some nodes stick + { + if (elem->IsPoly()) // Polygons and Polyhedral volumes + { + if (elem->GetType() == SMDSAbs_Face) // Polygon + { + elemType.Init( elem ); + const bool isQuad = elemType.myIsQuad; + if ( isQuad ) + SMDS_MeshCell::applyInterlace // interlace medium and corner nodes + ( SMDS_MeshCell::interlacedSmdsOrder( SMDSEntity_Quad_Polygon, nbNodes ), curNodes ); + // a polygon can divide into several elements vector polygons_nodes; vector quantities; - int nbNew = SimplifyFace(face_nodes, polygons_nodes, quantities); - if (nbNew > 0) { - inode = 0; - for (int iface = 0; iface < nbNew; iface++) { - int nbNodes = quantities[iface]; - vector poly_nodes (nbNodes); - for (int ii = 0; ii < nbNodes; ii++, inode++) { - poly_nodes[ii] = polygons_nodes[inode]; + int nbNew = SimplifyFace( curNodes, polygons_nodes, quantities ); + if (nbNew > 0) + { + vector face_nodes; + int inode = 0; + for (int iface = 0; iface < nbNew; iface++) + { + int nbNewNodes = quantities[iface]; + face_nodes.assign( polygons_nodes.begin() + inode, + polygons_nodes.begin() + inode + nbNewNodes ); + inode += nbNewNodes; + if ( isQuad ) // check if a result elem is a valid quadratic polygon + { + bool isValid = ( nbNewNodes % 2 == 0 ); + for ( int i = 0; i < nbNewNodes && isValid; ++i ) + isValid = ( elem->IsMediumNode( face_nodes[i]) == bool( i % 2 )); + elemType.SetQuad( isValid ); + if ( isValid ) // put medium nodes after corners + SMDS_MeshCell::applyInterlaceRev + ( SMDS_MeshCell::interlacedSmdsOrder( SMDSEntity_Quad_Polygon, + nbNewNodes ), face_nodes ); } - SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes); - myLastCreatedElems.Append(newElem); - if (aShapeId) + SMDS_MeshElement* newElem = AddElement( face_nodes, elemType ); + if ( aShapeId ) aMesh->SetMeshElementOnShape(newElem, aShapeId); } - - MESSAGE("ChangeElementNodes MergeNodes Polygon"); - //aMesh->ChangeElementNodes(elem, &polygons_nodes[inode], quantities[nbNew - 1]); - vector polynodes(polygons_nodes.begin()+inode,polygons_nodes.end()); - int quid =0; - if (nbNew > 0) quid = nbNew - 1; - vector newquant(quantities.begin()+quid, quantities.end()); - const SMDS_MeshElement* newElem = 0; - newElem = aMesh->AddPolyhedralVolume(polynodes, newquant); - myLastCreatedElems.Append(newElem); - if ( aShapeId && newElem ) - aMesh->SetMeshElementOnShape( newElem, aShapeId ); - rmElemIds.push_back(elem->GetID()); - } - else { - rmElemIds.push_back(elem->GetID()); } + rmElemIds.push_back(elem->GetID()); - } - else if (elem->GetType() == SMDSAbs_Volume) { - // Polyhedral volume + } // Polygon + + else if (elem->GetType() == SMDSAbs_Volume) // Polyhedral volume + { if (nbUniqueNodes < 4) { rmElemIds.push_back(elem->GetID()); } @@ -7302,16 +7280,15 @@ void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes) } if (quantities.size() > 3) - { - MESSAGE("ChangeElementNodes MergeNodes Polyhedron"); - //aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities); - const SMDS_MeshElement* newElem = 0; - newElem = aMesh->AddPolyhedralVolume(poly_nodes, quantities); - myLastCreatedElems.Append(newElem); - if ( aShapeId && newElem ) - aMesh->SetMeshElementOnShape( newElem, aShapeId ); - rmElemIds.push_back(elem->GetID()); - } + { + //aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities); + const SMDS_MeshElement* newElem = + aMesh->AddPolyhedralVolume(poly_nodes, quantities); + myLastCreatedElems.Append(newElem); + if ( aShapeId && newElem ) + aMesh->SetMeshElementOnShape( newElem, aShapeId ); + rmElemIds.push_back(elem->GetID()); + } } else { rmElemIds.push_back(elem->GetID()); @@ -7710,51 +7687,19 @@ void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes) } // if ( nbNodes != nbUniqueNodes ) // some nodes stick - if ( isOk ) { // the elem remains valid after sticking nodes - if (elem->IsPoly() && elem->GetType() == SMDSAbs_Volume) - { - // Change nodes of polyedre - const SMDS_VtkVolume* aPolyedre = - dynamic_cast( elem ); - if (aPolyedre) { - int nbFaces = aPolyedre->NbFaces(); - - vector poly_nodes; - vector quantities (nbFaces); - - for (int iface = 1; iface <= nbFaces; iface++) { - int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface); - quantities[iface - 1] = nbFaceNodes; - - for (inode = 1; inode <= nbFaceNodes; inode++) { - const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode); - - TNodeNodeMap::iterator nnIt = nodeNodeMap.find( curNode ); - if (nnIt != nodeNodeMap.end()) { // curNode sticks - curNode = (*nnIt).second; - } - poly_nodes.push_back(curNode); - } - } - aMesh->ChangePolyhedronNodes( elem, poly_nodes, quantities ); - } - } - else // replace non-polyhedron elements - { - const SMDSAbs_ElementType etyp = elem->GetType(); - const int elemId = elem->GetID(); - const bool isPoly = (elem->GetEntityType() == SMDSEntity_Polygon); - uniqueNodes.resize(nbUniqueNodes); + if ( isOk ) // the non-poly elem remains valid after sticking nodes + { + elemType.Init( elem ).SetID( elem->GetID() ); - SMESHDS_SubMesh * sm = aShapeId > 0 ? aMesh->MeshElements(aShapeId) : 0; + SMESHDS_SubMesh * sm = aShapeId > 0 ? aMesh->MeshElements(aShapeId) : 0; + aMesh->RemoveFreeElement(elem, sm, /*fromGroups=*/false); - aMesh->RemoveFreeElement(elem, sm, /*fromGroups=*/false); - SMDS_MeshElement* newElem = this->AddElement(uniqueNodes, etyp, isPoly, elemId); - if ( sm && newElem ) - sm->AddElement( newElem ); - if ( elem != newElem ) - ReplaceElemInGroups( elem, newElem, aMesh ); - } + uniqueNodes.resize(nbUniqueNodes); + SMDS_MeshElement* newElem = this->AddElement( uniqueNodes, elemType ); + if ( sm && newElem ) + sm->AddElement( newElem ); + if ( elem != newElem ) + ReplaceElemInGroups( elem, newElem, aMesh ); } else { // Remove invalid regular element or invalid polygon @@ -7768,6 +7713,7 @@ void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes) Remove( rmElemIds, false ); Remove( rmNodeIds, true ); + return; } @@ -8996,7 +8942,7 @@ namespace //======================================================================= /*! - * \brief Convert elements contained in a submesh to quadratic + * \brief Convert elements contained in a sub-mesh to quadratic * \return int - nb of checked elements */ //======================================================================= @@ -9519,6 +9465,8 @@ int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh * theSm, { int nbElem = 0; SMESHDS_Mesh* meshDS = GetMeshDS(); + ElemFeatures elemType; + vector nodes; while( theItr->more() ) { @@ -9526,11 +9474,11 @@ int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh * theSm, nbElem++; if( elem && elem->IsQuadratic()) { - int id = elem->GetID(); - int nbCornerNodes = elem->NbCornerNodes(); - SMDSAbs_ElementType aType = elem->GetType(); + // get elem data + int nbCornerNodes = elem->NbCornerNodes(); + nodes.assign( elem->begin_nodes(), elem->end_nodes() ); - vector nodes( elem->begin_nodes(), elem->end_nodes() ); + elemType.Init( elem, /*basicOnly=*/false ).SetID( elem->GetID() ).SetQuad( false ); //remove a quadratic element if ( !theSm || !theSm->Contains( elem )) @@ -9538,13 +9486,13 @@ int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh * theSm, meshDS->RemoveFreeElement( elem, theSm, /*fromGroups=*/false ); // remove medium nodes - for ( unsigned i = nbCornerNodes; i < nodes.size(); ++i ) + for ( size_t i = nbCornerNodes; i < nodes.size(); ++i ) if ( nodes[i]->NbInverseElements() == 0 ) meshDS->RemoveFreeNode( nodes[i], theSm ); // add a linear element nodes.resize( nbCornerNodes ); - SMDS_MeshElement * newElem = AddElement( nodes, aType, false, id ); + SMDS_MeshElement * newElem = AddElement( nodes, elemType ); ReplaceElemInGroups(elem, newElem, meshDS); if( theSm && newElem ) theSm->AddElement( newElem ); @@ -10135,11 +10083,15 @@ SMESH_MeshEditor::SewSideElements (TIDSortedElemSet& theSide1, if ( aResult != SEW_OK) return aResult; - list< int > nodeIDsToRemove/*, elemIDsToRemove*/; + list< int > nodeIDsToRemove; + vector< const SMDS_MeshNode*> nodes; + ElemFeatures elemType; + // loop on nodes replacement map TNodeNodeMap::iterator nReplaceMapIt = nReplaceMap.begin(), nnIt; for ( ; nReplaceMapIt != nReplaceMap.end(); nReplaceMapIt++ ) - if ( (*nReplaceMapIt).first != (*nReplaceMapIt).second ) { + if ( (*nReplaceMapIt).first != (*nReplaceMapIt).second ) + { const SMDS_MeshNode* nToRemove = (*nReplaceMapIt).first; nodeIDsToRemove.push_back( nToRemove->GetID() ); // loop on elements sharing nToRemove @@ -10148,11 +10100,10 @@ SMESH_MeshEditor::SewSideElements (TIDSortedElemSet& theSide1, const SMDS_MeshElement* e = invElemIt->next(); // get a new suite of nodes: make replacement int nbReplaced = 0, i = 0, nbNodes = e->NbNodes(); - vector< const SMDS_MeshNode*> nodes( nbNodes ); + nodes.resize( nbNodes ); SMDS_ElemIteratorPtr nIt = e->nodesIterator(); while ( nIt->more() ) { - const SMDS_MeshNode* n = - static_cast( nIt->next() ); + const SMDS_MeshNode* n = static_cast( nIt->next() ); nnIt = nReplaceMap.find( n ); if ( nnIt != nReplaceMap.end() ) { nbReplaced++; @@ -10164,21 +10115,17 @@ SMESH_MeshEditor::SewSideElements (TIDSortedElemSet& theSide1, // elemIDsToRemove.push_back( e->GetID() ); // else if ( nbReplaced ) + { + elemType.Init( e, /*basicOnly=*/false ).SetID( e->GetID() ); + aMesh->RemoveElement( e ); + + if ( SMDS_MeshElement* newElem = this->AddElement( nodes, elemType )) { - SMDSAbs_ElementType etyp = e->GetType(); - SMDS_MeshElement* newElem = this->AddElement(nodes, etyp, false); - if (newElem) - { - myLastCreatedElems.Append(newElem); - AddToSameGroups(newElem, e, aMesh); - int aShapeId = e->getshapeId(); - if ( aShapeId ) - { - aMesh->SetMeshElementOnShape( newElem, aShapeId ); - } - } - aMesh->RemoveElement(e); + AddToSameGroups( newElem, e, aMesh ); + if ( int aShapeId = e->getshapeId() ) + aMesh->SetMeshElementOnShape( newElem, aShapeId ); } + } } } @@ -10408,44 +10355,19 @@ void SMESH_MeshEditor::DoubleElements( const TIDSortedElemSet& theElements ) // duplicate elements - if ( type == SMDSAbs_Ball ) - { - SMDS_UnstructuredGrid* vtkGrid = mesh->getGrid(); - while ( elemIt->more() ) - { - const SMDS_MeshElement* elem = elemIt->next(); - if ( elem->GetType() != SMDSAbs_Ball ) - continue; - if (( elem = mesh->AddBall( elem->GetNode(0), - vtkGrid->GetBallDiameter( elem->getVtkId() )))) - myLastCreatedElems.Append( elem ); - } - } - else + ElemFeatures elemType; + + vector< const SMDS_MeshNode* > nodes; + while ( elemIt->more() ) { - vector< const SMDS_MeshNode* > nodes; - while ( elemIt->more() ) - { - const SMDS_MeshElement* elem = elemIt->next(); - if ( elem->GetType() != type ) - continue; + const SMDS_MeshElement* elem = elemIt->next(); + if ( elem->GetType() != type ) + continue; - nodes.assign( elem->begin_nodes(), elem->end_nodes() ); + elemType.Init( elem, /*basicOnly=*/false ); + nodes.assign( elem->begin_nodes(), elem->end_nodes() ); - if ( type == SMDSAbs_Volume && elem->GetVtkType() == VTK_POLYHEDRON ) - { - std::vector quantities = - static_cast< const SMDS_VtkVolume* >( elem )->GetQuantities(); - elem = mesh->AddPolyhedralVolume( nodes, quantities ); - } - else - { - AddElement( nodes, type, elem->IsPoly() ); - elem = 0; // myLastCreatedElems is already filled - } - if ( elem ) - myLastCreatedElems.Append( elem ); - } + AddElement( nodes, elemType ); } } @@ -10476,7 +10398,7 @@ bool SMESH_MeshEditor::DoubleNodes( const TIDSortedElemSet& theElems, return false; bool res = false; - std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode; + TNodeNodeMap anOldNodeToNewNode; // duplicate elements and nodes res = doubleNodes( aMeshDS, theElems, theNodesNot, anOldNodeToNewNode, true ); // replce nodes by duplications @@ -10496,16 +10418,18 @@ bool SMESH_MeshEditor::DoubleNodes( const TIDSortedElemSet& theElems, */ //================================================================================ -bool SMESH_MeshEditor::doubleNodes( SMESHDS_Mesh* theMeshDS, - const TIDSortedElemSet& theElems, - const TIDSortedElemSet& theNodesNot, - std::map< const SMDS_MeshNode*, - const SMDS_MeshNode* >& theNodeNodeMap, - const bool theIsDoubleElem ) +bool SMESH_MeshEditor::doubleNodes(SMESHDS_Mesh* theMeshDS, + const TIDSortedElemSet& theElems, + const TIDSortedElemSet& theNodesNot, + TNodeNodeMap& theNodeNodeMap, + const bool theIsDoubleElem ) { MESSAGE("doubleNodes"); - // iterate on through element and duplicate them (by nodes duplication) + // iterate through element and duplicate them (by nodes duplication) bool res = false; + std::vector newNodes; + ElemFeatures elemType; + TIDSortedElemSet::const_iterator elemItr = theElems.begin(); for ( ; elemItr != theElems.end(); ++elemItr ) { @@ -10513,19 +10437,21 @@ bool SMESH_MeshEditor::doubleNodes( SMESHDS_Mesh* theMeshDS, if (!anElem) continue; - bool isDuplicate = false; // duplicate nodes to duplicate element - std::vector newNodes( anElem->NbNodes() ); + bool isDuplicate = false; + newNodes.resize( anElem->NbNodes() ); SMDS_ElemIteratorPtr anIter = anElem->nodesIterator(); int ind = 0; while ( anIter->more() ) { - - SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next(); - SMDS_MeshNode* aNewNode = aCurrNode; - if ( theNodeNodeMap.find( aCurrNode ) != theNodeNodeMap.end() ) - aNewNode = (SMDS_MeshNode*)theNodeNodeMap[ aCurrNode ]; - else if ( theIsDoubleElem && theNodesNot.find( aCurrNode ) == theNodesNot.end() ) + const SMDS_MeshNode* aCurrNode = static_cast( anIter->next() ); + const SMDS_MeshNode* aNewNode = aCurrNode; + TNodeNodeMap::iterator n2n = theNodeNodeMap.find( aCurrNode ); + if ( n2n != theNodeNodeMap.end() ) + { + aNewNode = n2n->second; + } + else if ( theIsDoubleElem && !theNodesNot.count( aCurrNode )) { // duplicate node aNewNode = theMeshDS->AddNode( aCurrNode->X(), aCurrNode->Y(), aCurrNode->Z() ); @@ -10540,9 +10466,9 @@ bool SMESH_MeshEditor::doubleNodes( SMESHDS_Mesh* theMeshDS, continue; if ( theIsDoubleElem ) - AddElement(newNodes, anElem->GetType(), anElem->IsPoly()); + AddElement( newNodes, elemType.Init( anElem, /*basicOnly=*/false )); else - theMeshDS->ChangeElementNodes( anElem, &newNodes[ 0 ], anElem->NbNodes() ); + theMeshDS->ChangeElementNodes( anElem, &newNodes[ 0 ], newNodes.size() ); res = true; } @@ -12273,7 +12199,8 @@ bool SMESH_MeshEditor::Make2DMeshFrom3D() SMESHDS_Mesh* aMesh = GetMeshDS(); if (!aMesh) return false; - //bool res = false; + + ElemFeatures faceType( SMDSAbs_Face ); int nbFree = 0, nbExisted = 0, nbCreated = 0; SMDS_VolumeIteratorPtr vIt = aMesh->volumesIterator(); while(vIt->more()) @@ -12281,8 +12208,8 @@ bool SMESH_MeshEditor::Make2DMeshFrom3D() const SMDS_MeshVolume* volume = vIt->next(); SMDS_VolumeTool vTool( volume, /*ignoreCentralNodes=*/false ); vTool.SetExternalNormal(); - //const bool isPoly = volume->IsPoly(); const int iQuad = volume->IsQuadratic(); + faceType.SetQuad( iQuad ); for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ ) { if (!vTool.IsFreeFace(iface)) @@ -12294,22 +12221,27 @@ bool SMESH_MeshEditor::Make2DMeshFrom3D() int inode = 0; for ( ; inode < nbFaceNodes; inode += iQuad+1) nodes.push_back(faceNodes[inode]); - if (iQuad) { // add medium nodes + + if (iQuad) // add medium nodes + { for ( inode = 1; inode < nbFaceNodes; inode += 2) nodes.push_back(faceNodes[inode]); if ( nbFaceNodes == 9 ) // bi-quadratic quad nodes.push_back(faceNodes[8]); } // add new face based on volume nodes - if (aMesh->FindElement( nodes, SMDSAbs_Face, /*noMedium=*/false) ) { - nbExisted++; - continue; // face already exsist + if (aMesh->FindElement( nodes, SMDSAbs_Face, /*noMedium=*/false) ) + { + nbExisted++; // face already exsist + } + else + { + AddElement( nodes, faceType.SetPoly( nbFaceNodes/(iQuad+1) > 4 )); + nbCreated++; } - AddElement(nodes, SMDSAbs_Face, ( !iQuad && nbFaceNodes/(iQuad+1) > 4 )); - nbCreated++; } } - return ( nbFree==(nbExisted+nbCreated) ); + return ( nbFree == ( nbExisted + nbCreated )); } namespace @@ -12371,9 +12303,11 @@ int SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements, SMDS_VolumeTool vTool; TIDSortedElemSet avoidSet; const TIDSortedElemSet emptySet, *elemSet = aroundElements ? &elements : &emptySet; - int inode; + size_t inode; typedef vector TConnectivity; + TConnectivity tgtNodes; + ElemFeatures elemKind( missType ); SMDS_ElemIteratorPtr eIt; if (elements.empty()) eIt = aMesh->elementsIterator(elemType); @@ -12383,6 +12317,7 @@ int SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements, { const SMDS_MeshElement* elem = eIt->next(); const int iQuad = elem->IsQuadratic(); + elemKind.SetQuad( iQuad ); // ------------------------------------------------------------------------------------ // 1. For an elem, get present bnd elements and connectivities of missing bnd elements @@ -12400,7 +12335,7 @@ int SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements, ( !aroundElements || elements.count( otherVol ))) continue; const SMDS_MeshNode** nn = vTool.GetFaceNodes(iface); - const int nbFaceNodes = vTool.NbFaceNodes (iface); + const size_t nbFaceNodes = vTool.NbFaceNodes (iface); if ( missType == SMDSAbs_Edge ) // boundary edges { nodes.resize( 2+iQuad ); @@ -12480,17 +12415,17 @@ int SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements, if ( targetMesh != myMesh ) // instead of making a map of nodes in this mesh and targetMesh, // we create nodes with same IDs. - for ( int i = 0; i < missingBndElems.size(); ++i ) + for ( size_t i = 0; i < missingBndElems.size(); ++i ) { TConnectivity& srcNodes = missingBndElems[i]; - TConnectivity nodes( srcNodes.size() ); - for ( inode = 0; inode < nodes.size(); ++inode ) - nodes[inode] = getNodeWithSameID( tgtMeshDS, srcNodes[inode] ); - if ( aroundElements && tgtEditor.GetMeshDS()->FindElement( nodes, + tgtNodes.resize( srcNodes.size() ); + for ( inode = 0; inode < srcNodes.size(); ++inode ) + tgtNodes[inode] = getNodeWithSameID( tgtMeshDS, srcNodes[inode] ); + if ( aroundElements && tgtEditor.GetMeshDS()->FindElement( tgtNodes, missType, /*noMedium=*/false)) continue; - tgtEditor.AddElement(nodes, missType, !iQuad && nodes.size()/(iQuad+1)>4); + tgtEditor.AddElement( tgtNodes, elemKind.SetPoly( tgtNodes.size()/(iQuad+1) > 4 )); ++nbAddedBnd; } else @@ -12501,16 +12436,16 @@ int SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements, missType, /*noMedium=*/false)) continue; - SMDS_MeshElement* elem = - tgtEditor.AddElement(nodes, missType, !iQuad && nodes.size()/(iQuad+1)>4); - ++nbAddedBnd; + SMDS_MeshElement* newElem = + tgtEditor.AddElement( nodes, elemKind.SetPoly( nodes.size()/(iQuad+1) > 4 )); + nbAddedBnd += bool( newElem ); // try to set a new element to a shape if ( myMesh->HasShapeToMesh() ) { bool ok = true; set< pair > mediumShapes; - const int nbN = nodes.size() / (iQuad+1 ); + const size_t nbN = nodes.size() / (iQuad+1 ); for ( inode = 0; inode < nbN && ok; ++inode ) { pair i_stype = @@ -12530,7 +12465,7 @@ int SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements, } } if ( ok && mediumShapes.begin()->first == missShapeType ) - aMesh->SetMeshElementOnShape( elem, mediumShapes.begin()->second ); + aMesh->SetMeshElementOnShape( newElem, mediumShapes.begin()->second ); } } @@ -12541,15 +12476,15 @@ int SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements, for ( int i = 0 ; i < presentBndElems.size(); ++i ) { const SMDS_MeshElement* e = presentBndElems[i]; - TConnectivity nodes( e->NbNodes() ); + tgtNodes.resize( e->NbNodes() ); for ( inode = 0; inode < nodes.size(); ++inode ) - nodes[inode] = getNodeWithSameID( tgtMeshDS, e->GetNode(inode) ); - presentEditor->AddElement(nodes, e->GetType(), e->IsPoly()); + tgtNodes[inode] = getNodeWithSameID( tgtMeshDS, e->GetNode(inode) ); + presentEditor->AddElement( tgtNodes, elemKind.Init( e )); } else // store present elements to add them to a group for ( int i = 0 ; i < presentBndElems.size(); ++i ) { - presentEditor->myLastCreatedElems.Append(presentBndElems[i]); + presentEditor->myLastCreatedElems.Append( presentBndElems[i] ); } } // loop on given elements @@ -12576,10 +12511,10 @@ int SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements, while (eIt->more()) { const SMDS_MeshElement* elem = eIt->next(); - TConnectivity nodes( elem->NbNodes() ); - for ( inode = 0; inode < nodes.size(); ++inode ) - nodes[inode] = getNodeWithSameID( tgtMeshDS, elem->GetNode(inode) ); - tgtEditor.AddElement(nodes, elemType, elem->IsPoly()); + tgtNodes.resize( elem->NbNodes() ); + for ( inode = 0; inode < tgtNodes.size(); ++inode ) + tgtNodes[inode] = getNodeWithSameID( tgtMeshDS, elem->GetNode(inode) ); + tgtEditor.AddElement( tgtNodes, elemKind.Init( elem )); tgtEditor.myLastCreatedElems.Clear(); } diff --git a/src/SMESH/SMESH_MeshEditor.hxx b/src/SMESH/SMESH_MeshEditor.hxx index 25c01f81d..cbe9466de 100644 --- a/src/SMESH/SMESH_MeshEditor.hxx +++ b/src/SMESH/SMESH_MeshEditor.hxx @@ -73,21 +73,49 @@ public: void ClearLastCreated(); SMESH_ComputeErrorPtr & GetError() { return myError; } + // -------------------------------------------------------------------------------- + struct ElemFeatures //!< Features of element to create + { + SMDSAbs_ElementType myType; + bool myIsPoly, myIsQuad; + int myID; + double myBallDiameter; + std::vector myPolyhedQuantities; + + ElemFeatures( SMDSAbs_ElementType type=SMDSAbs_All, bool isPoly=false, bool isQuad=false ) + :myType( type ), myIsPoly(isPoly), myIsQuad(isQuad), myID(-1), myBallDiameter(0) {} + + ElemFeatures& Init( SMDSAbs_ElementType type, bool isPoly=false, bool isQuad=false ) + { myType = type; myIsPoly = isPoly; myIsQuad = isQuad; return *this; } + + ElemFeatures& Init( const SMDS_MeshElement* elem, bool basicOnly=true ); + + ElemFeatures& Init( double diameter ) + { myType = SMDSAbs_Ball; myBallDiameter = diameter; return *this; } + + ElemFeatures& Init( vector& quanities, bool isQuad=false ) + { myType = SMDSAbs_Volume; myIsPoly = 1; myIsQuad = isQuad; + myPolyhedQuantities.swap( quanities ); return *this; } + + ElemFeatures& Init( const vector& quanities, bool isQuad=false ) + { myType = SMDSAbs_Volume; myIsPoly = 1; myIsQuad = isQuad; + myPolyhedQuantities = quanities; return *this; } + + ElemFeatures& SetPoly(bool isPoly) { myIsPoly = isPoly; return *this; } + ElemFeatures& SetQuad(bool isQuad) { myIsQuad = isQuad; return *this; } + ElemFeatures& SetID (int ID) { myID = ID; return *this; } + }; + /*! * \brief Add element */ SMDS_MeshElement* AddElement(const std::vector & nodes, - const SMDSAbs_ElementType type, - const bool isPoly, - const int ID = -1, - const double ballDiameter=0.); + const ElemFeatures& features); /*! * \brief Add element */ - SMDS_MeshElement* AddElement(const std::vector & nodeIDs, - const SMDSAbs_ElementType type, - const bool isPoly, - const int ID = -1); + SMDS_MeshElement* AddElement(const std::vector & nodeIDs, + const ElemFeatures& features); int Remove (const std::list< int >& theElemIDs, const bool isNodes); // Remove a node or an element. @@ -741,11 +769,11 @@ public: void LinearAngleVariation(const int NbSteps, list& theAngles); - bool doubleNodes( SMESHDS_Mesh* theMeshDS, - const TIDSortedElemSet& theElems, - const TIDSortedElemSet& theNodesNot, - std::map< const SMDS_MeshNode*, const SMDS_MeshNode* >& theNodeNodeMap, - const bool theIsDoubleElem ); + bool doubleNodes( SMESHDS_Mesh* theMeshDS, + const TIDSortedElemSet& theElems, + const TIDSortedElemSet& theNodesNot, + TNodeNodeMap& theNodeNodeMap, + const bool theIsDoubleElem ); void copyPosition( const SMDS_MeshNode* from, const SMDS_MeshNode* to ); diff --git a/src/SMESH/SMESH_MesherHelper.cxx b/src/SMESH/SMESH_MesherHelper.cxx index 7537bf8a8..294882ac2 100644 --- a/src/SMESH/SMESH_MesherHelper.cxx +++ b/src/SMESH/SMESH_MesherHelper.cxx @@ -1996,26 +1996,28 @@ SMDS_MeshFace* SMESH_MesherHelper::AddPolygonalFace (const vectorAddPolygonalFaceWithID(nodes, id); else elem = meshDS->AddPolygonalFace(nodes); } - else { - vector newNodes; + else + { + vector newNodes( nodes.size() * 2 ); + newNodes = nodes; for ( int i = 0; i < nodes.size(); ++i ) { const SMDS_MeshNode* n1 = nodes[i]; const SMDS_MeshNode* n2 = nodes[(i+1)%nodes.size()]; const SMDS_MeshNode* n12 = GetMediumNode( n1, n2, force3d, TopAbs_FACE ); - newNodes.push_back( n1 ); newNodes.push_back( n12 ); } if(id) - elem = meshDS->AddPolygonalFaceWithID(newNodes, id); + elem = meshDS->AddQuadPolygonalFaceWithID(newNodes, id); else - elem = meshDS->AddPolygonalFace(newNodes); + elem = meshDS->AddQuadPolygonalFace(newNodes); } if ( mySetElemOnShape && myShapeID > 0 ) meshDS->SetMeshElementOnShape( elem, myShapeID ); diff --git a/src/SMESHClient/SMESH_Client.cxx b/src/SMESHClient/SMESH_Client.cxx index 6787e0043..f360512c6 100644 --- a/src/SMESHClient/SMESH_Client.cxx +++ b/src/SMESHClient/SMESH_Client.cxx @@ -244,6 +244,33 @@ namespace } + //======================================================================= + //function : AddQaudPolygonsWithID + //======================================================================= + inline void AddQuadPolygonsWithID(SMDS_Mesh* theMesh, + SMESH::log_array_var& theSeq, + CORBA::Long theId) + { + const SMESH::long_array& anIndexes = theSeq[theId].indexes; + CORBA::Long anIndexId = 0, aNbElems = theSeq[theId].number; + + for (CORBA::Long anElemId = 0; anElemId < aNbElems; anElemId++) { + int aFaceId = anIndexes[anIndexId++]; + + int aNbNodes = anIndexes[anIndexId++]; + std::vector nodes_ids (aNbNodes); + for (int i = 0; i < aNbNodes; i++) { + nodes_ids[i] = anIndexes[anIndexId++]; + } + + SMDS_MeshElement* anElem = theMesh->AddQuadPolygonalFaceWithID(nodes_ids, aFaceId); + if (!anElem) + EXCEPTION(runtime_error, "SMDS_Mesh::FindElement - cannot AddQaudPolygonalFaceWithID for ID = " + << anElemId); + } + } + + //======================================================================= //function : AddTetrasWithID //======================================================================= @@ -903,6 +930,7 @@ SMESH_Client::Update(bool theIsClear) case SMESH::ADD_QUADEDGE : AddQuadEdgesWithID ( mySMDSMesh, aSeq, anId ); break; case SMESH::ADD_QUADTRIANGLE : AddQuadTriasWithID ( mySMDSMesh, aSeq, anId ); break; case SMESH::ADD_QUADQUADRANGLE : AddQuadQuadsWithID ( mySMDSMesh, aSeq, anId ); break; + case SMESH::ADD_QUADPOLYGON : AddQuadPolygonsWithID( mySMDSMesh, aSeq, anId ); break; case SMESH::ADD_QUADTETRAHEDRON : AddQuadTetrasWithID ( mySMDSMesh, aSeq, anId ); break; case SMESH::ADD_QUADPYRAMID : AddQuadPiramidsWithID( mySMDSMesh, aSeq, anId ); break; case SMESH::ADD_QUADPENTAHEDRON : AddQuadPentasWithID ( mySMDSMesh, aSeq, anId ); break; diff --git a/src/SMESHDS/SMESHDS_Command.cxx b/src/SMESHDS/SMESHDS_Command.cxx index 4fbd5464e..b22079e6a 100644 --- a/src/SMESHDS/SMESHDS_Command.cxx +++ b/src/SMESHDS/SMESHDS_Command.cxx @@ -295,6 +295,28 @@ void SMESHDS_Command::AddPolygonalFace (const int ElementID, myNumber++; } +//======================================================================= +//function : AddQuadPolygonalFace +//purpose : +//======================================================================= +void SMESHDS_Command::AddQuadPolygonalFace (const int ElementID, + const std::vector& nodes_ids) +{ + if ( myType != SMESHDS_AddQuadPolygon) { + MESSAGE("SMESHDS_Command::AddQuadraticPolygonalFace : Bad Type"); + return; + } + myIntegers.push_back(ElementID); + + int i, nbNodes = nodes_ids.size(); + myIntegers.push_back(nbNodes); + for (i = 0; i < nbNodes; i++) { + myIntegers.push_back(nodes_ids[i]); + } + + myNumber++; +} + //======================================================================= //function : AddPolyhedralVolume //purpose : diff --git a/src/SMESHDS/SMESHDS_Command.hxx b/src/SMESHDS/SMESHDS_Command.hxx index e52e4b7ac..583cebe4a 100644 --- a/src/SMESHDS/SMESHDS_Command.hxx +++ b/src/SMESHDS/SMESHDS_Command.hxx @@ -57,6 +57,8 @@ class SMESHDS_EXPORT SMESHDS_Command int idnode9, int idnode10, int idnode11, int idnode12); void AddPolygonalFace (const int ElementID, const std::vector& nodes_ids); + void AddQuadPolygonalFace (const int ElementID, + const std::vector& nodes_ids); void AddPolyhedralVolume (const int ElementID, const std::vector& nodes_ids, const std::vector& quantities); diff --git a/src/SMESHDS/SMESHDS_CommandType.hxx b/src/SMESHDS/SMESHDS_CommandType.hxx index a53532ddf..c355386e5 100644 --- a/src/SMESHDS/SMESHDS_CommandType.hxx +++ b/src/SMESHDS/SMESHDS_CommandType.hxx @@ -49,6 +49,7 @@ enum SMESHDS_CommandType { SMESHDS_AddQuadEdge, SMESHDS_AddQuadTriangle, SMESHDS_AddQuadQuadrangle, + SMESHDS_AddQuadPolygon, SMESHDS_AddQuadTetrahedron, SMESHDS_AddQuadPyramid, SMESHDS_AddQuadPentahedron, diff --git a/src/SMESHDS/SMESHDS_Mesh.cxx b/src/SMESHDS/SMESHDS_Mesh.cxx index dc1e094b0..d4a018b10 100644 --- a/src/SMESHDS/SMESHDS_Mesh.cxx +++ b/src/SMESHDS/SMESHDS_Mesh.cxx @@ -213,7 +213,7 @@ void SMESHDS_Mesh::MoveNode(const SMDS_MeshNode *n, double x, double y, double z //======================================================================= //function : ChangeElementNodes -//purpose : +//purpose : Changed nodes of an element provided that nb of nodes does not change //======================================================================= bool SMESHDS_Mesh::ChangeElementNodes(const SMDS_MeshElement * elem, @@ -708,9 +708,9 @@ SMDS_MeshFace* SMESHDS_Mesh::AddPolygonalFaceWithID (const std::vector& nod return anElem; } -SMDS_MeshFace* SMESHDS_Mesh::AddPolygonalFaceWithID - (const std::vector& nodes, - const int ID) +SMDS_MeshFace* +SMESHDS_Mesh::AddPolygonalFaceWithID (const std::vector& nodes, + const int ID) { SMDS_MeshFace *anElem = SMDS_Mesh::AddPolygonalFaceWithID(nodes, ID); if (anElem) { @@ -724,8 +724,8 @@ SMDS_MeshFace* SMESHDS_Mesh::AddPolygonalFaceWithID return anElem; } -SMDS_MeshFace* SMESHDS_Mesh::AddPolygonalFace - (const std::vector& nodes) +SMDS_MeshFace* +SMESHDS_Mesh::AddPolygonalFace (const std::vector& nodes) { SMDS_MeshFace *anElem = SMDS_Mesh::AddPolygonalFace(nodes); if (anElem) { @@ -739,6 +739,53 @@ SMDS_MeshFace* SMESHDS_Mesh::AddPolygonalFace return anElem; } + +//======================================================================= +//function : AddQuadPolygonalFace +//purpose : +//======================================================================= +SMDS_MeshFace* SMESHDS_Mesh::AddQuadPolygonalFaceWithID (const std::vector& nodes_ids, + const int ID) +{ + SMDS_MeshFace *anElem = SMDS_Mesh::AddQuadPolygonalFaceWithID(nodes_ids, ID); + if (anElem) { + myScript->AddQuadPolygonalFace(ID, nodes_ids); + } + return anElem; +} + +SMDS_MeshFace* +SMESHDS_Mesh::AddQuadPolygonalFaceWithID (const std::vector& nodes, + const int ID) +{ + SMDS_MeshFace *anElem = SMDS_Mesh::AddQuadPolygonalFaceWithID(nodes, ID); + if (anElem) { + int i, len = nodes.size(); + std::vector nodes_ids (len); + for (i = 0; i < len; i++) { + nodes_ids[i] = nodes[i]->GetID(); + } + myScript->AddQuadPolygonalFace(ID, nodes_ids); + } + return anElem; +} + +SMDS_MeshFace* +SMESHDS_Mesh::AddQuadPolygonalFace (const std::vector& nodes) +{ + SMDS_MeshFace *anElem = SMDS_Mesh::AddQuadPolygonalFace(nodes); + if (anElem) { + int i, len = nodes.size(); + std::vector nodes_ids (len); + for (i = 0; i < len; i++) { + nodes_ids[i] = nodes[i]->GetID(); + } + myScript->AddQuadPolygonalFace(anElem->GetID(), nodes_ids); + } + return anElem; +} + + //======================================================================= //function : AddPolyhedralVolume //purpose : diff --git a/src/SMESHDS/SMESHDS_Mesh.hxx b/src/SMESHDS/SMESHDS_Mesh.hxx index d7cf62597..6ec2d3d9c 100644 --- a/src/SMESHDS/SMESHDS_Mesh.hxx +++ b/src/SMESHDS/SMESHDS_Mesh.hxx @@ -511,6 +511,14 @@ public: virtual SMDS_MeshFace* AddPolygonalFace (const std::vector& nodes); + virtual SMDS_MeshFace* AddQuadPolygonalFaceWithID(const std::vector & nodes_ids, + const int ID); + + virtual SMDS_MeshFace* AddQuadPolygonalFaceWithID(const std::vector & nodes, + const int ID); + + virtual SMDS_MeshFace* AddQuadPolygonalFace(const std::vector & nodes); + virtual SMDS_MeshVolume* AddPolyhedralVolumeWithID (const std::vector& nodes_ids, const std::vector& quantities, diff --git a/src/SMESHDS/SMESHDS_Script.cxx b/src/SMESHDS/SMESHDS_Script.cxx index 5a5dac83b..e01109c3f 100644 --- a/src/SMESHDS/SMESHDS_Script.cxx +++ b/src/SMESHDS/SMESHDS_Script.cxx @@ -255,6 +255,19 @@ void SMESHDS_Script::AddPolygonalFace (int NewFaceID, const std::vector& no getCommand(SMESHDS_AddPolygon)->AddPolygonalFace(NewFaceID, nodes_ids); } +//======================================================================= +//function : AddQuadPolygonalFace +//purpose : +//======================================================================= +void SMESHDS_Script::AddQuadPolygonalFace(int NewFaceID, const std::vector& nodes_ids) +{ + if(myIsEmbeddedMode){ + myIsModified = true; + return; + } + getCommand(SMESHDS_AddQuadPolygon)->AddQuadPolygonalFace(NewFaceID, nodes_ids); +} + //======================================================================= //function : AddPolyhedralVolume //purpose : diff --git a/src/SMESHDS/SMESHDS_Script.hxx b/src/SMESHDS/SMESHDS_Script.hxx index 72f7a4495..3401ca6ac 100644 --- a/src/SMESHDS/SMESHDS_Script.hxx +++ b/src/SMESHDS/SMESHDS_Script.hxx @@ -64,6 +64,8 @@ class SMESHDS_EXPORT SMESHDS_Script void AddPolygonalFace (const int NewFaceID, const std::vector& nodes_ids); + void AddQuadPolygonalFace (const int NewFaceID, + const std::vector& nodes_ids); void AddPolyhedralVolume (const int NewVolID, const std::vector& nodes_ids, const std::vector& quantities); diff --git a/src/SMESHGUI/SMESHGUI.cxx b/src/SMESHGUI/SMESHGUI.cxx index 5e507fc13..e434b8c4f 100644 --- a/src/SMESHGUI/SMESHGUI.cxx +++ b/src/SMESHGUI/SMESHGUI.cxx @@ -532,7 +532,6 @@ namespace { format = "CGNS"; notSupportedElemTypes.push_back( SMESH::Entity_Ball ); - notSupportedElemTypes.push_back( SMESH::Entity_BiQuad_Triangle ); } else if ( isSAUV ) { @@ -543,6 +542,7 @@ namespace notSupportedElemTypes.push_back( SMESH::Entity_TriQuad_Hexa ); notSupportedElemTypes.push_back( SMESH::Entity_Hexagonal_Prism ); notSupportedElemTypes.push_back( SMESH::Entity_Polygon ); + notSupportedElemTypes.push_back( SMESH::Entity_Quad_Polygon ); notSupportedElemTypes.push_back( SMESH::Entity_Polyhedra ); } else if ( isGMF ) @@ -2079,7 +2079,7 @@ bool SMESHGUI::automaticUpdate( SMESH::SMESH_IDSource_ptr theMesh, long nbEdges = info[SMDSEntity_Edge] + info[SMDSEntity_Quad_Edge]; long nbFaces = info[SMDSEntity_Triangle] + info[SMDSEntity_Quad_Triangle] + info[SMDSEntity_BiQuad_Triangle] + info[SMDSEntity_Quadrangle] + info[SMDSEntity_Quad_Quadrangle] + info[SMDSEntity_BiQuad_Quadrangle] + - info[SMDSEntity_Polygon]; + info[SMDSEntity_Polygon] + info[SMDSEntity_Quad_Polygon]; long nbVolumes = info[SMDSEntity_Tetra] + info[SMDSEntity_Quad_Tetra] + info[SMDSEntity_Hexa] + info[SMDSEntity_Quad_Hexa] + info[SMDSEntity_TriQuad_Hexa] + info[SMDSEntity_Pyramid] + info[SMDSEntity_Quad_Pyramid] + @@ -3274,6 +3274,7 @@ bool SMESHGUI::OnGUIEvent( int theCommandID ) case SMESHOp::OpBiQuadraticTriangle: case SMESHOp::OpQuadraticQuadrangle: case SMESHOp::OpBiQuadraticQuadrangle: + case SMESHOp::OpQuadraticPolygon: case SMESHOp::OpQuadraticTetrahedron: case SMESHOp::OpQuadraticPyramid: case SMESHOp::OpQuadraticPentahedron: @@ -3286,15 +3287,16 @@ bool SMESHGUI::OnGUIEvent( int theCommandID ) SMDSAbs_EntityType type = SMDSEntity_Last; switch (theCommandID) { - case SMESHOp::OpQuadraticEdge: type = SMDSEntity_Quad_Edge; break; - case SMESHOp::OpQuadraticTriangle: type = SMDSEntity_Quad_Triangle; break; - case SMESHOp::OpBiQuadraticTriangle: type = SMDSEntity_BiQuad_Triangle; break; - case SMESHOp::OpQuadraticQuadrangle: type = SMDSEntity_Quad_Quadrangle; break; - case SMESHOp::OpBiQuadraticQuadrangle: type = SMDSEntity_BiQuad_Quadrangle; break; - case SMESHOp::OpQuadraticTetrahedron: type = SMDSEntity_Quad_Tetra; break; - case SMESHOp::OpQuadraticPyramid: type = SMDSEntity_Quad_Pyramid; break; - case SMESHOp::OpQuadraticPentahedron: type = SMDSEntity_Quad_Penta; break; - case SMESHOp::OpQuadraticHexahedron: type = SMDSEntity_Quad_Hexa; break; + case SMESHOp::OpQuadraticEdge: type = SMDSEntity_Quad_Edge; break; + case SMESHOp::OpQuadraticTriangle: type = SMDSEntity_Quad_Triangle; break; + case SMESHOp::OpBiQuadraticTriangle: type = SMDSEntity_BiQuad_Triangle; break; + case SMESHOp::OpQuadraticQuadrangle: type = SMDSEntity_Quad_Quadrangle; break; + case SMESHOp::OpBiQuadraticQuadrangle: type = SMDSEntity_BiQuad_Quadrangle; break; + case SMESHOp::OpQuadraticPolygon: type = SMDSEntity_Quad_Polygon; break; + case SMESHOp::OpQuadraticTetrahedron: type = SMDSEntity_Quad_Tetra; break; + case SMESHOp::OpQuadraticPyramid: type = SMDSEntity_Quad_Pyramid; break; + case SMESHOp::OpQuadraticPentahedron: type = SMDSEntity_Quad_Penta; break; + case SMESHOp::OpQuadraticHexahedron: type = SMDSEntity_Quad_Hexa; break; case SMESHOp::OpTriQuadraticHexahedron: type = SMDSEntity_TriQuad_Hexa; break; default: break; } @@ -3909,6 +3911,7 @@ void SMESHGUI::initialize( CAM_Application* app ) createSMESHAction( SMESHOp::OpBiQuadraticTriangle, "BIQUADRATIC_TRIANGLE", "ICON_DLG_BIQUADRATIC_TRIANGLE" ); createSMESHAction( SMESHOp::OpQuadraticQuadrangle, "QUADRATIC_QUADRANGLE", "ICON_DLG_QUADRATIC_QUADRANGLE" ); createSMESHAction( SMESHOp::OpBiQuadraticQuadrangle, "BIQUADRATIC_QUADRANGLE", "ICON_DLG_BIQUADRATIC_QUADRANGLE" ); + createSMESHAction( SMESHOp::OpQuadraticPolygon, "QUADRATIC_POLYGON", "ICON_DLG_QUADRATIC_POLYGON" ); createSMESHAction( SMESHOp::OpQuadraticTetrahedron, "QUADRATIC_TETRAHEDRON", "ICON_DLG_QUADRATIC_TETRAHEDRON" ); createSMESHAction( SMESHOp::OpQuadraticPyramid, "QUADRATIC_PYRAMID", "ICON_DLG_QUADRATIC_PYRAMID" ); createSMESHAction( SMESHOp::OpQuadraticPentahedron, "QUADRATIC_PENTAHEDRON", "ICON_DLG_QUADRATIC_PENTAHEDRON" ); @@ -4139,6 +4142,7 @@ void SMESHGUI::initialize( CAM_Application* app ) createMenu( SMESHOp::OpBiQuadraticTriangle , addId, -1 ); createMenu( SMESHOp::OpQuadraticQuadrangle, addId, -1 ); createMenu( SMESHOp::OpBiQuadraticQuadrangle, addId, -1 ); + createMenu( SMESHOp::OpQuadraticPolygon, addId, -1 ); createMenu( SMESHOp::OpQuadraticTetrahedron, addId, -1 ); createMenu( SMESHOp::OpQuadraticPyramid, addId, -1 ); createMenu( SMESHOp::OpQuadraticPentahedron, addId, -1 ); @@ -4276,6 +4280,7 @@ void SMESHGUI::initialize( CAM_Application* app ) createTool( SMESHOp::OpBiQuadraticTriangle, addNonElemTb ); createTool( SMESHOp::OpQuadraticQuadrangle, addNonElemTb ); createTool( SMESHOp::OpBiQuadraticQuadrangle, addNonElemTb ); + createTool( SMESHOp::OpQuadraticPolygon, addNonElemTb ); createTool( SMESHOp::OpQuadraticTetrahedron, addNonElemTb ); createTool( SMESHOp::OpQuadraticPyramid, addNonElemTb ); createTool( SMESHOp::OpQuadraticPentahedron, addNonElemTb ); diff --git a/src/SMESHGUI/SMESHGUI_AddMeshElementDlg.cxx b/src/SMESHGUI/SMESHGUI_AddMeshElementDlg.cxx index 44cba417c..a93494cc3 100644 --- a/src/SMESHGUI/SMESHGUI_AddMeshElementDlg.cxx +++ b/src/SMESHGUI/SMESHGUI_AddMeshElementDlg.cxx @@ -214,12 +214,13 @@ namespace SMESH SetVisibility(true, theActor->GetFacesOriented(), false); } - void SetBallPosition(SMESH_Actor* theActor,TVTKIds& theIds, double theDiameter) { + void SetBallPosition(SMESH_Actor* theActor,TVTKIds& theIds, double theDiameter) + { vtkUnstructuredGrid *aGrid = theActor->GetUnstructuredGrid(); myBallPolyData->Reset(); myBallPolyData->DeleteCells(); myBallPolyData->SetPoints(aGrid->GetPoints()); - + vtkDataArray* aScalars = vtkDataArray::CreateDataArray(VTK_DOUBLE); aScalars->SetNumberOfComponents(1); aScalars->SetNumberOfTuples(theIds.size()); @@ -235,7 +236,7 @@ namespace SMESH aScalars->SetTuple(anId,&d); anIds->Reset(); } - + anIds->Delete(); myBallPolyData->Modified(); SetVisibility (false, false, true); @@ -582,6 +583,13 @@ void SMESHGUI_AddMeshElementDlg::ClickOnApply() tr( "SMESH_BUT_YES" ), tr( "SMESH_BUT_NO" ), 0, 1 ); if ( res == 1 ) return; } + SMESH::SMESH_GroupOnFilter_var aFilterGroup = SMESH::SMESH_GroupOnFilter::_narrow( myGroups[idx-1] ); + if ( !aFilterGroup->_is_nil() ) { + int res = SUIT_MessageBox::question( this, tr( "SMESH_WRN_WARNING" ), + tr( "MESH_FILTER_GRP_CHOSEN" ).arg( aGroupName ), + tr( "SMESH_BUT_YES" ), tr( "SMESH_BUT_NO" ), 0, 1 ); + if ( res == 1 ) return; + } aGroup = myGroups[idx-1]; } } @@ -590,16 +598,19 @@ void SMESHGUI_AddMeshElementDlg::ClickOnApply() SMESH::long_array_var anIdList = new SMESH::long_array; anIdList->length( 1 ); anIdList[0] = -1; - const bool onlyNodesInMesh = ( myMesh->NbElements() == 0 ); + //const bool onlyNodesInMesh = ( myMesh->NbElements() == 0 ); + int nbElemsBefore = 0; switch (myElementType) { case SMDSAbs_0DElement: + nbElemsBefore = myMesh->Nb0DElements(); anIdList->length( anArrayOfIndices->length() ); for ( size_t i = 0; i < anArrayOfIndices->length(); ++i ) anIdList[i] = aMeshEditor->Add0DElement(anArrayOfIndices[i]); break; case SMDSAbs_Ball: if ( myGeomType == SMDSEntity_Ball ) { + nbElemsBefore = myMesh->NbBalls(); anIdList->length( anArrayOfIndices->length() ); for ( size_t i = 0; i < anArrayOfIndices->length(); ++i ) anIdList[i] = aMeshEditor->AddBall(anArrayOfIndices[i], @@ -607,21 +618,24 @@ void SMESHGUI_AddMeshElementDlg::ClickOnApply() } break; case SMDSAbs_Edge: + nbElemsBefore = myMesh->NbEdges(); anIdList[0] = aMeshEditor->AddEdge(anArrayOfIndices.inout()); break; case SMDSAbs_Face: + nbElemsBefore = myMesh->NbFaces(); if ( myIsPoly ) anIdList[0] = aMeshEditor->AddPolygonalFace(anArrayOfIndices.inout()); else anIdList[0] = aMeshEditor->AddFace(anArrayOfIndices.inout()); break; default: + nbElemsBefore = myMesh->NbVolumes(); anIdList[0] = aMeshEditor->AddVolume(anArrayOfIndices.inout()); break; } if ( anIdList[0] > 0 && addToGroup && !aGroupName.isEmpty() ) { SMESH::SMESH_Group_var aGroupUsed; if ( aGroup->_is_nil() ) { - // create new group + // create new group aGroupUsed = SMESH::AddGroup( myMesh, (SMESH::ElementType)myElementType, aGroupName ); if ( !aGroupUsed->_is_nil() ) { myGroups.append(SMESH::SMESH_GroupBase::_duplicate(aGroupUsed)); @@ -629,7 +643,8 @@ void SMESHGUI_AddMeshElementDlg::ClickOnApply() } } else { - SMESH::SMESH_GroupOnGeom_var aGeomGroup = SMESH::SMESH_GroupOnGeom::_narrow( aGroup ); + SMESH::SMESH_GroupOnGeom_var aGeomGroup = SMESH::SMESH_GroupOnGeom::_narrow( aGroup ); + SMESH::SMESH_GroupOnFilter_var aFilterGroup = SMESH::SMESH_GroupOnFilter::_narrow( aGroup ); if ( !aGeomGroup->_is_nil() ) { aGroupUsed = myMesh->ConvertToStandalone( aGeomGroup ); if ( !aGroupUsed->_is_nil() && idx > 0 ) { @@ -637,6 +652,13 @@ void SMESHGUI_AddMeshElementDlg::ClickOnApply() SMESHGUI::GetSMESHGUI()->getApp()->updateObjectBrowser(); } } + else if ( !aFilterGroup->_is_nil() ) { + aGroupUsed = myMesh->ConvertToStandalone( aFilterGroup ); + if ( !aGroupUsed->_is_nil() && idx > 0 ) { + myGroups[idx-1] = SMESH::SMESH_GroupBase::_duplicate(aGroupUsed); + SMESHGUI::GetSMESHGUI()->getApp()->updateObjectBrowser(); + } + } else aGroupUsed = SMESH::SMESH_Group::_narrow( aGroup ); } @@ -650,8 +672,24 @@ void SMESHGUI_AddMeshElementDlg::ClickOnApply() mySelectionMgr->setSelectedObjects( aList, false ); mySimulation->SetVisibility(false); - if ( onlyNodesInMesh ) - myActor->SetRepresentation( SMESH_Actor::eEdge ); // wireframe + // if ( onlyNodesInMesh ) + // myActor->SetRepresentation( SMESH_Actor::eEdge ); // wireframe + if ( nbElemsBefore == 0 ) + { + // 1st element of the type has been added, update actor to show this entity + unsigned int aMode = myActor->GetEntityMode(); + switch ( myElementType ) { + case SMDSAbs_Edge: + myActor->SetRepresentation(SMESH_Actor::eEdge); + myActor->SetEntityMode( aMode |= SMESH_Actor::eEdges ); break; + case SMDSAbs_Face: + myActor->SetRepresentation(SMESH_Actor::eSurface); + myActor->SetEntityMode( aMode |= SMESH_Actor::eFaces ); break; + case SMDSAbs_Volume: + myActor->SetRepresentation(SMESH_Actor::eSurface); + myActor->SetEntityMode( aMode |= SMESH_Actor::eVolumes ); break; + } + } SMESH::UpdateView(); buttonOk->setEnabled(false); diff --git a/src/SMESHGUI/SMESHGUI_AddQuadraticElementDlg.cxx b/src/SMESHGUI/SMESHGUI_AddQuadraticElementDlg.cxx index 10ada7bd0..5cfddb9ce 100644 --- a/src/SMESHGUI/SMESHGUI_AddQuadraticElementDlg.cxx +++ b/src/SMESHGUI/SMESHGUI_AddQuadraticElementDlg.cxx @@ -95,13 +95,39 @@ namespace { + + // Define the sequences of ids + static int FirstEdgeIds[] = {0}; + static int LastEdgeIds[] = {1}; + + static int FirstTriangleIds[] = {0,1,2}; + static int LastTriangleIds[] = {1,2,0}; + + static int FirstQuadrangleIds[] = {0,1,2,3}; + static int LastQuadrangleIds[] = {1,2,3,0}; + + static int FirstTetrahedronIds[] = {0,1,2,3,3,3}; + static int LastTetrahedronIds[] = {1,2,0,0,1,2}; + + static int FirstPyramidIds[] = {0,1,2,3,4,4,4,4}; + static int LastPyramidIds[] = {1,2,3,0,0,1,2,3}; + + static int FirstPentahedronIds[] = {0,1,2,3,4,5,0,1,2}; + static int LastPentahedronIds[] = {1,2,0,4,5,3,3,4,5}; + + static int FirstHexahedronIds[] = {0,1,2,3,4,5,6,7,0,1,2,3}; + static int LastHexahedronIds[] = {1,2,3,0,5,6,7,4,4,5,6,7}; + + static vector FirstPolygonIds; + static vector LastPolygonIds; + void ReverseConnectivity( std::vector & ids, SMDSAbs_EntityType type, bool toReverse, // inverse element bool toVtkOrder ) // smds connectivity to vtk one { if ( toReverse ) // first reverse smds order { - const std::vector& index = SMDS_MeshCell::reverseSmdsOrder(type); + const std::vector& index = SMDS_MeshCell::reverseSmdsOrder(type, ids.size()); SMDS_MeshCell::applyInterlace( index, ids ); } if ( toVtkOrder ) // from smds to vtk connectivity @@ -113,7 +139,8 @@ namespace } namespace SMESH { - class TElementSimulationQuad { + class TElementSimulationQuad + { SalomeApp_Application* myApplication; SUIT_ViewWindow* myViewWindow; SVTK_ViewWindow* myVTKViewWindow; @@ -148,7 +175,7 @@ namespace SMESH myPreviewActor->PickableOff(); myPreviewActor->VisibilityOff(); myPreviewActor->SetMapper(myMapper); - + QColor ffc, bfc; int delta; vtkProperty* myProp = vtkProperty::New(); @@ -249,35 +276,12 @@ namespace SMESH myGrid->Delete(); -// myProp->Delete(); -// myBackProp->Delete(); + // myProp->Delete(); + // myBackProp->Delete(); } }; } - -// Define the sequences of ids -static int FirstEdgeIds[] = {0}; -static int LastEdgeIds[] = {1}; - -static int FirstTriangleIds[] = {0,1,2}; -static int LastTriangleIds[] = {1,2,0}; - -static int FirstQuadrangleIds[] = {0,1,2,3}; -static int LastQuadrangleIds[] = {1,2,3,0}; - -static int FirstTetrahedronIds[] = {0,1,2,3,3,3}; -static int LastTetrahedronIds[] = {1,2,0,0,1,2}; - -static int FirstPyramidIds[] = {0,1,2,3,4,4,4,4}; -static int LastPyramidIds[] = {1,2,3,0,0,1,2,3}; - -static int FirstPentahedronIds[] = {0,1,2,3,4,5,0,1,2}; -static int LastPentahedronIds[] = {1,2,0,4,5,3,3,4,5}; - -static int FirstHexahedronIds[] = {0,1,2,3,4,5,6,7,0,1,2,3}; -static int LastHexahedronIds[] = {1,2,3,0,5,6,7,4,4,5,6,7}; - /*! \class BusyLocker \brief Simple 'busy state' flag locker. @@ -335,7 +339,6 @@ SMESHGUI_AddQuadraticElementDlg::SMESHGUI_AddQuadraticElementDlg( SMESHGUI* theM mySMESHGUI( theModule ), mySelectionMgr( SMESH::GetSelectionMgr( theModule ) ), myGeomType( theType ), - //myType( theType ), myBusy( false ) { setModal( false ); @@ -359,6 +362,9 @@ SMESHGUI_AddQuadraticElementDlg::SMESHGUI_AddQuadraticElementDlg( SMESHGUI* theM case SMDSEntity_Quad_Quadrangle: anElementName = QString("QUADRATIC_QUADRANGLE"); break; + case SMDSEntity_Quad_Polygon: + anElementName = QString("QUADRATIC_POLYGON"); + break; case SMDSEntity_BiQuad_Quadrangle: anElementName = QString("BIQUADRATIC_QUADRANGLE"); break; @@ -561,6 +567,11 @@ void SMESHGUI_AddQuadraticElementDlg::Init() myNbCenterNodes = 1; myHelpFileName = "adding_quadratic_elements_page.html#?"; //Adding_quadrangles break; + case SMDSEntity_Quad_Polygon: + aNumRows = 5; + myNbCorners = 0; // no limit + myHelpFileName = "adding_quadratic_elements_page.html#?"; //Adding_polygons + break; case SMDSEntity_Quad_Tetra: aNumRows = 6; myNbCorners = 4; @@ -689,6 +700,7 @@ bool SMESHGUI_AddQuadraticElementDlg::ClickOnApply() break; case SMDSEntity_Quad_Triangle: case SMDSEntity_Quad_Quadrangle: + case SMDSEntity_Quad_Polygon: case SMDSEntity_BiQuad_Triangle: case SMDSEntity_BiQuad_Quadrangle: case SMDSEntity_Quad_Tetra: @@ -716,7 +728,7 @@ bool SMESHGUI_AddQuadraticElementDlg::ClickOnApply() if ( myReverseCB->isChecked()) ReverseConnectivity( anIds, myGeomType, /*toReverse=*/true, /*toVtkOrder=*/false ); - int aNumberOfIds = anIds.size(); + int aNumberOfIds = anIds.size(); SMESH::long_array_var anArrayOfIdeces = new SMESH::long_array; anArrayOfIdeces->length( aNumberOfIds ); @@ -739,7 +751,14 @@ bool SMESHGUI_AddQuadraticElementDlg::ClickOnApply() SMESH::SMESH_GroupOnGeom_var aGeomGroup = SMESH::SMESH_GroupOnGeom::_narrow( myGroups[idx-1] ); if ( !aGeomGroup->_is_nil() ) { int res = SUIT_MessageBox::question( this, tr( "SMESH_WRN_WARNING" ), - tr( "MESH_STANDALONE_GRP_CHOSEN" ).arg( aGroupName ), + tr( "MESH_GEOM_GRP_CHOSEN" ).arg( aGroupName ), + tr( "SMESH_BUT_YES" ), tr( "SMESH_BUT_NO" ), 0, 1 ); + if ( res == 1 ) return false; + } + SMESH::SMESH_GroupOnFilter_var aFilterGroup = SMESH::SMESH_GroupOnFilter::_narrow( myGroups[idx-1] ); + if ( !aFilterGroup->_is_nil() ) { + int res = SUIT_MessageBox::question( this, tr( "SMESH_WRN_WARNING" ), + tr( "MESH_FILTER_GRP_CHOSEN" ).arg( aGroupName ), tr( "SMESH_BUT_YES" ), tr( "SMESH_BUT_NO" ), 0, 1 ); if ( res == 1 ) return false; } @@ -748,24 +767,31 @@ bool SMESHGUI_AddQuadraticElementDlg::ClickOnApply() } SMESH::ElementType anElementType; - long anElemId = -1; + long anElemId = -1, nbElemsBefore = 0; SMESH::SMESH_MeshEditor_var aMeshEditor = myMesh->GetMeshEditor(); switch (myGeomType) { case SMDSEntity_Quad_Edge: anElementType = SMESH::EDGE; + nbElemsBefore = myMesh->NbEdges(); anElemId = aMeshEditor->AddEdge(anArrayOfIdeces.inout()); break; case SMDSEntity_Quad_Triangle: case SMDSEntity_Quad_Quadrangle: case SMDSEntity_BiQuad_Triangle: case SMDSEntity_BiQuad_Quadrangle: anElementType = SMESH::FACE; + nbElemsBefore = myMesh->NbFaces(); anElemId = aMeshEditor->AddFace(anArrayOfIdeces.inout()); break; + case SMDSEntity_Quad_Polygon: + anElementType = SMESH::FACE; + nbElemsBefore = myMesh->NbFaces(); + anElemId = aMeshEditor->AddQuadPolygonalFace(anArrayOfIdeces.inout()); break; case SMDSEntity_Quad_Tetra: case SMDSEntity_Quad_Pyramid: case SMDSEntity_Quad_Penta: case SMDSEntity_Quad_Hexa: case SMDSEntity_TriQuad_Hexa: anElementType = SMESH::VOLUME; + nbElemsBefore = myMesh->NbVolumes(); anElemId = aMeshEditor->AddVolume(anArrayOfIdeces.inout()); break; default: break; } @@ -781,7 +807,8 @@ bool SMESHGUI_AddQuadraticElementDlg::ClickOnApply() } } else { - SMESH::SMESH_GroupOnGeom_var aGeomGroup = SMESH::SMESH_GroupOnGeom::_narrow( aGroup ); + SMESH::SMESH_GroupOnGeom_var aGeomGroup = SMESH::SMESH_GroupOnGeom::_narrow( aGroup ); + SMESH::SMESH_GroupOnFilter_var aFilterGroup = SMESH::SMESH_GroupOnFilter::_narrow( aGroup ); if ( !aGeomGroup->_is_nil() ) { aGroupUsed = myMesh->ConvertToStandalone( aGeomGroup ); if ( !aGroupUsed->_is_nil() && idx > 0 ) { @@ -789,6 +816,13 @@ bool SMESHGUI_AddQuadraticElementDlg::ClickOnApply() SMESHGUI::GetSMESHGUI()->getApp()->updateObjectBrowser(); } } + else if ( !aFilterGroup->_is_nil() ) { + aGroupUsed = myMesh->ConvertToStandalone( aFilterGroup ); + if ( !aGroupUsed->_is_nil() && idx > 0 ) { + myGroups[idx-1] = SMESH::SMESH_GroupBase::_duplicate(aGroupUsed); + SMESHGUI::GetSMESHGUI()->getApp()->updateObjectBrowser(); + } + } else aGroupUsed = SMESH::SMESH_Group::_narrow( aGroup ); } @@ -801,6 +835,23 @@ bool SMESHGUI_AddQuadraticElementDlg::ClickOnApply() } } + if ( nbElemsBefore == 0 ) + { + // 1st element of the type has been added, update actor to show this entity + unsigned int aMode = myActor->GetEntityMode(); + switch ( anElementType ) { + case SMESH::EDGE: + myActor->SetRepresentation(SMESH_Actor::eEdge); + myActor->SetEntityMode( aMode |= SMESH_Actor::eEdges ); break; + case SMESH::FACE: + myActor->SetRepresentation(SMESH_Actor::eSurface); + myActor->SetEntityMode( aMode |= SMESH_Actor::eFaces ); break; + case SMESH::VOLUME: + myActor->SetRepresentation(SMESH_Actor::eSurface); + myActor->SetEntityMode( aMode |= SMESH_Actor::eVolumes ); break; + } + } + SALOME_ListIO aList; aList.Append( myActor->getIO() ); mySelector->ClearIndex(); mySelectionMgr->setSelectedObjects( aList, false ); @@ -1007,6 +1058,7 @@ void SMESHGUI_AddQuadraticElementDlg::SelectionIntoArgument() anElementType = SMESH::EDGE; break; case SMDSEntity_Quad_Triangle: case SMDSEntity_Quad_Quadrangle: + case SMDSEntity_Quad_Polygon: case SMDSEntity_BiQuad_Triangle: case SMDSEntity_BiQuad_Quadrangle: anElementType = SMESH::FACE; break; @@ -1269,6 +1321,44 @@ void SMESHGUI_AddQuadraticElementDlg::UpdateTable( bool theConersValidity ) { QStringList aListCorners = myCornerNodes->text().split(" ", QString::SkipEmptyParts); + if ( myGeomType == SMDSEntity_Quad_Polygon ) // POLYGON + { + if ( aListCorners.count() < 3 ) + theConersValidity = false; + + if ( aListCorners.count() != myTable->rowCount() && theConersValidity ) + { + // adjust nb of rows for the polygon + int oldNbRows = myTable->rowCount(); + myTable->setRowCount( aListCorners.count() ); + for ( int row = oldNbRows; row < myTable->rowCount(); row++ ) + { + myTable->setItem( row, 0, new QTableWidgetItem( "" ) ); + myTable->item( row, 0 )->setFlags(0); + + IdEditItem* anEditItem = new IdEditItem( "" ); + anEditItem->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsEnabled); + myTable->setItem(row, 1, anEditItem); + + myTable->setItem( row, 2, new QTableWidgetItem( "" ) ); + myTable->item( row, 2 )->setFlags(0); + } + myNbCorners = aListCorners.count(); + + // fill FirstPolygonIds and LastPolygonIds + FirstPolygonIds.resize( aListCorners.count() ); + LastPolygonIds .resize( aListCorners.count() ); + for ( int i = 0; i < aListCorners.count(); ++i ) + { + FirstPolygonIds[i] = i; + LastPolygonIds [i] = i+1; + } + LastPolygonIds.back() = 0; + + myNbCorners = aListCorners.count(); + } + } + if ( aListCorners.count() == myNbCorners && theConersValidity ) { myTable->setEnabled( true ); @@ -1295,6 +1385,10 @@ void SMESHGUI_AddQuadraticElementDlg::UpdateTable( bool theConersValidity ) aFirstColIds = FirstQuadrangleIds; aLastColIds = LastQuadrangleIds; break; + case SMDSEntity_Quad_Polygon: + aFirstColIds = & FirstPolygonIds[0]; + aLastColIds = & LastPolygonIds[0]; + break; case SMDSEntity_Quad_Tetra: aFirstColIds = FirstTetrahedronIds; aLastColIds = LastTetrahedronIds; diff --git a/src/SMESHGUI/SMESHGUI_DisplayEntitiesDlg.h b/src/SMESHGUI/SMESHGUI_DisplayEntitiesDlg.h index b042f8add..0f98bda2d 100644 --- a/src/SMESHGUI/SMESHGUI_DisplayEntitiesDlg.h +++ b/src/SMESHGUI/SMESHGUI_DisplayEntitiesDlg.h @@ -39,7 +39,7 @@ public: private: void InverseEntityMode( unsigned int& theOutputMode, - unsigned int theMode ); + unsigned int theMode ); private slots: void onOk(); diff --git a/src/SMESHGUI/SMESHGUI_FilterDlg.cxx b/src/SMESHGUI/SMESHGUI_FilterDlg.cxx index e84876d44..afbfd6861 100755 --- a/src/SMESHGUI/SMESHGUI_FilterDlg.cxx +++ b/src/SMESHGUI/SMESHGUI_FilterDlg.cxx @@ -1740,7 +1740,7 @@ static QList entityTypes( const int theType ) typeIds.append( SMDSEntity_Quad_Quadrangle ); typeIds.append( SMDSEntity_BiQuad_Quadrangle ); typeIds.append( SMDSEntity_Polygon ); - //typeIds.append( SMDSEntity_Quad_Polygon ); + typeIds.append( SMDSEntity_Quad_Polygon ); break; case SMESH::VOLUME: typeIds.append( SMDSEntity_Tetra ); diff --git a/src/SMESHGUI/SMESHGUI_MeshInfo.cxx b/src/SMESHGUI/SMESHGUI_MeshInfo.cxx index 4d834c905..f997d9a70 100644 --- a/src/SMESHGUI/SMESHGUI_MeshInfo.cxx +++ b/src/SMESHGUI/SMESHGUI_MeshInfo.cxx @@ -306,11 +306,13 @@ SMESHGUI_MeshInfo::SMESHGUI_MeshInfo( QWidget* parent ) QLabel* a2DQuaBiQuad = createField(); QLabel* a2DPolLab = new QLabel( tr( "POLYGONS_LAB" ), this ); QLabel* a2DPolTotal = createField(); + QLabel* a2DPolLin = createField(); + QLabel* a2DPolQuad = createField(); myWidgets[ index++ ] << a2DLine; myWidgets[ index++ ] << a2DLab << a2DTotal << a2DLin << a2DQuad << a2DBiQuad; myWidgets[ index++ ] << a2DTriLab << a2DTriTotal << a2DTriLin << a2DTriQuad << a2DTriBiQuad; myWidgets[ index++ ] << a2DQuaLab << a2DQuaTotal << a2DQuaLin << a2DQuaQuad << a2DQuaBiQuad; - myWidgets[ index++ ] << a2DPolLab << a2DPolTotal; + myWidgets[ index++ ] << a2DPolLab << a2DPolTotal << a2DPolLin << a2DPolQuad; // ... 3D elements QWidget* a3DLine = createLine(); @@ -414,6 +416,8 @@ SMESHGUI_MeshInfo::SMESHGUI_MeshInfo( QWidget* parent ) l->addWidget( a2DQuaBiQuad, 17, 4 ); l->addWidget( a2DPolLab, 18, 0 ); l->addWidget( a2DPolTotal, 18, 1 ); + l->addWidget( a2DPolLin, 18, 2 ); + l->addWidget( a2DPolQuad, 18, 3 ); l->addWidget( a3DLine, 19, 1, 1, 4 ); l->addWidget( a3DLab, 20, 0 ); l->addWidget( a3DTotal, 20, 1 ); @@ -503,8 +507,9 @@ void SMESHGUI_MeshInfo::showInfo( SMESH::SMESH_IDSource_ptr obj ) myWidgets[i1D][iQuadratic]->setProperty( "text", QString::number( info[SMDSEntity_Quad_Edge] ) ); long nbTriangles = info[SMDSEntity_Triangle] + info[SMDSEntity_Quad_Triangle] + info[SMDSEntity_BiQuad_Triangle]; long nbQuadrangles = info[SMDSEntity_Quadrangle] + info[SMDSEntity_Quad_Quadrangle] + info[SMDSEntity_BiQuad_Quadrangle]; + long nb2DPolygons = info[SMDSEntity_Polygon] + info[SMDSEntity_Quad_Polygon]; long nb2DLinear = info[SMDSEntity_Triangle] + info[SMDSEntity_Quadrangle] + info[SMDSEntity_Polygon]; - long nb2DQuadratic = info[SMDSEntity_Quad_Triangle] + info[SMDSEntity_Quad_Quadrangle]; + long nb2DQuadratic = info[SMDSEntity_Quad_Triangle] + info[SMDSEntity_Quad_Quadrangle] + info[SMDSEntity_Quad_Polygon]; long nb2DBiQuadratic = info[SMDSEntity_BiQuad_Triangle] + info[SMDSEntity_BiQuad_Quadrangle]; long nb2DTotal = nb2DLinear + nb2DQuadratic + nb2DBiQuadratic; @@ -520,7 +525,9 @@ void SMESHGUI_MeshInfo::showInfo( SMESH::SMESH_IDSource_ptr obj ) myWidgets[i2DQuadrangles][iLinear] ->setProperty( "text", QString::number( info[SMDSEntity_Quadrangle] ) ); myWidgets[i2DQuadrangles][iQuadratic] ->setProperty( "text", QString::number( info[SMDSEntity_Quad_Quadrangle] ) ); myWidgets[i2DQuadrangles][iBiQuadratic] ->setProperty( "text", QString::number( info[SMDSEntity_BiQuad_Quadrangle] ) ); - myWidgets[i2DPolygons][iTotal] ->setProperty( "text", QString::number( info[SMDSEntity_Polygon] ) ); + myWidgets[i2DPolygons][iTotal] ->setProperty( "text", QString::number( nb2DPolygons )); + myWidgets[i2DPolygons][iLinear] ->setProperty( "text", QString::number( info[SMDSEntity_Polygon] ) ); + myWidgets[i2DPolygons][iQuadratic] ->setProperty( "text", QString::number( info[SMDSEntity_Quad_Polygon] ) ); long nbTetrahedrons = info[SMDSEntity_Tetra] + info[SMDSEntity_Quad_Tetra]; long nbHexahedrons = info[SMDSEntity_Hexa] + info[SMDSEntity_Quad_Hexa] + info[SMDSEntity_TriQuad_Hexa]; long nbPyramids = info[SMDSEntity_Pyramid] + info[SMDSEntity_Quad_Pyramid]; @@ -583,6 +590,8 @@ void SMESHGUI_MeshInfo::showInfo( SMESH::SMESH_IDSource_ptr obj ) myWidgets[i2DQuadrangles][iLinear] ->setProperty( "text", "?" ); myWidgets[i2DQuadrangles][iQuadratic] ->setProperty( "text", "?" ); myWidgets[i2DQuadrangles][iBiQuadratic] ->setProperty( "text", "?" ); + myWidgets[i2DPolygons][iLinear] ->setProperty( "text", "?" ); + myWidgets[i2DPolygons][iQuadratic] ->setProperty( "text", "?" ); myWidgets[i2DPolygons][iTotal] ->setProperty( "text", "?" ); myWidgets[iNb][iTotal] ->setProperty( "text", "?" ); myWidgets[iNb][iLinear] ->setProperty( "text", "?" ); @@ -712,6 +721,8 @@ void SMESHGUI_MeshInfo::clear() myWidgets[i2DQuadrangles][iLinear] ->setProperty( "text", QString::number( 0 ) ); myWidgets[i2DQuadrangles][iQuadratic] ->setProperty( "text", QString::number( 0 ) ); myWidgets[i2DQuadrangles][iBiQuadratic] ->setProperty( "text", QString::number( 0 ) ); + myWidgets[i2DPolygons][iLinear] ->setProperty( "text", QString::number( 0 ) ); + myWidgets[i2DPolygons][iQuadratic] ->setProperty( "text", QString::number( 0 ) ); myWidgets[i2DPolygons][iTotal] ->setProperty( "text", QString::number( 0 ) ); myWidgets[i3D][iTotal] ->setProperty( "text", QString::number( 0 ) ); myWidgets[i3D][iLinear] ->setProperty( "text", QString::number( 0 ) ); @@ -836,6 +847,8 @@ void SMESHGUI_MeshInfo::saveInfo( QTextStream &out ) out << QString( SPACING_INFO*3, ' ' ) << tr( "BI_QUADRATIC_LAB" ) << ": " << ( myWidgets[i2DQuadrangles][iBiQuadratic]->property( "text" ) ).toString() << "\n"; out << QString( SPACING_INFO*2, ' ' ) << tr( "POLYGONS_LAB" ) << "\n"; out << QString( SPACING_INFO*3, ' ' ) << tr( "TOTAL_LAB" ) << ": " << ( myWidgets[i2DPolygons][iTotal]->property( "text" ) ).toString() << "\n"; + out << QString( SPACING_INFO*3, ' ' ) << tr( "LINEAR_LAB" ) << ": " << ( myWidgets[i2DPolygons][iLinear]->property( "text" ) ).toString() << "\n"; + out << QString( SPACING_INFO*3, ' ' ) << tr( "QUADRATIC_LAB" ) << ": " << ( myWidgets[i2DPolygons][iQuadratic]->property( "text" ) ).toString() << "\n"; out << QString( SPACING_INFO, ' ' ) << tr( "3D_LAB" ) << "\n"; out << QString( SPACING_INFO*2, ' ' ) << tr( "TOTAL_LAB" ) << ": " << ( myWidgets[i3D][iTotal]->property( "text" ) ).toString() << "\n"; out << QString( SPACING_INFO*2, ' ' ) << tr( "LINEAR_LAB" ) << ": " << ( myWidgets[i3D][iLinear]->property( "text" ) ).toString() << "\n"; diff --git a/src/SMESHGUI/SMESHGUI_Operations.h b/src/SMESHGUI/SMESHGUI_Operations.h index c9b3a2f58..cd28f8bd5 100644 --- a/src/SMESHGUI/SMESHGUI_Operations.h +++ b/src/SMESHGUI/SMESHGUI_Operations.h @@ -145,6 +145,7 @@ namespace SMESHOp { OpQuadraticPentahedron = 4107, // MENU MODIFICATION - ADD - QUADRATIC PENTAHEDRON OpQuadraticHexahedron = 4108, // MENU MODIFICATION - ADD - QUADRATIC HEXAHEDRON OpTriQuadraticHexahedron = 4109, // MENU MODIFICATION - ADD - TRIQUADRATIC HEXAHEDRON + OpQuadraticPolygon = 4110, // MENU MODIFICATION - ADD - QUADRATIC POLYGON OpRemoveNodes = 4200, // MENU MODIFICATION - REMOVE - NODE OpRemoveElements = 4201, // MENU MODIFICATION - REMOVE - ELEMENTS OpRemoveOrphanNodes = 4202, // MENU MODIFICATION - REMOVE - ORPHAN NODES diff --git a/src/SMESHGUI/SMESH_images.ts b/src/SMESHGUI/SMESH_images.ts index ead04a882..c13a65eb6 100644 --- a/src/SMESHGUI/SMESH_images.ts +++ b/src/SMESHGUI/SMESH_images.ts @@ -219,6 +219,10 @@ ICON_DLG_BIQUADRATIC_QUADRANGLE mesh_biquad_quadrangle.png + + ICON_DLG_QUADRATIC_POLYGON + mesh_quad_polygon.png + ICON_DLG_QUADRATIC_TETRAHEDRON mesh_quad_tetrahedron.png diff --git a/src/SMESHGUI/SMESH_msg_en.ts b/src/SMESHGUI/SMESH_msg_en.ts index 28302f1b4..45b444feb 100644 --- a/src/SMESHGUI/SMESH_msg_en.ts +++ b/src/SMESHGUI/SMESH_msg_en.ts @@ -792,6 +792,10 @@ MEN_POLYGON Polygon + + MEN_QUADRATIC_POLYGON + Quadratic Polygon + MEN_POLYHEDRON Polyhedron @@ -1127,8 +1131,13 @@ Please, select a mesh and try again Please enter a name of new group to be created or choose an existing one. - MESH_STANDALONE_GRP_CHOSEN + MESH_GEOM_GRP_CHOSEN Group on geometry is chosen: %1. +Do you want to convert it to the standalone group? + + + MESH_FILTER_GRP_CHOSEN + Group on filter is chosen: %1. Do you want to convert it to the standalone group? @@ -1225,6 +1234,14 @@ Please enter correct values and try again SMESH_ADD_POLYGON_TITLE Add Polygon + + SMESH_ADD_QUADRATIC_POLYGON + Add Quadratic polygon + + + SMESH_ADD_QUADRATIC_POLYGON_TITLE + Add Quadratic Polygon + SMESH_ADD_PENTA Add pentahedron @@ -3224,6 +3241,10 @@ Use Display Entity menu command to show them. STB_POLYGON Polygon + + STB_QUADRATIC_POLYGON + Quadratic Polygon + STB_POLYHEDRON Polyhedron @@ -3880,6 +3901,10 @@ Use Display Entity menu command to show them. TOP_POLYGON Polygon + + TOP_QUADRATIC_POLYGON + Quadratic Polygon + TOP_POLYHEDRON Polyhedron diff --git a/src/SMESHUtils/SMESH_MAT2d.cxx b/src/SMESHUtils/SMESH_MAT2d.cxx index dcde99881..b2c7a912e 100644 --- a/src/SMESHUtils/SMESH_MAT2d.cxx +++ b/src/SMESHUtils/SMESH_MAT2d.cxx @@ -859,7 +859,7 @@ namespace } // associate branchIDs and the input branch vector (arg) - vector< const SMESH_MAT2d::Branch* > branchByID( branchEdges.size() ); + vector< const SMESH_MAT2d::Branch* > branchByID( branchEdges.size(), 0 ); int nbBranches = 0; for ( size_t i = 0; i < branchEdges.size(); ++i ) { @@ -912,28 +912,24 @@ namespace { edgeInd += dInd; - if ( edgeInd < 0 || - edgeInd >= (int) branchEdges[ brID ].size() || - branchEdges[ brID ][ edgeInd ] != bndSegs[ i ]._edge ) + if (( edgeInd < 0 || + edgeInd >= (int) branchEdges[ brID ].size() ) || + ( branchEdges[ brID ][ edgeInd ] != bndSegs[ i ]._edge && + branchEdges[ brID ][ edgeInd ]->twin() != bndSegs[ i ]._edge )) { - if ( bndSegs[ i ]._branchID < 0 && - branchEdges[ brID ].back() == bndSegs[ i ]._edge ) + if ( bndSegs[ i ]._branchID < 0 ) { - edgeInd = branchEdges[ brID ].size() - 1; dInd = -1; + for ( edgeInd = branchEdges[ brID ].size() - 1; edgeInd > 0; --edgeInd ) + if ( branchEdges[ brID ][ edgeInd ]->twin() == bndSegs[ i ]._edge ) + break; } - else if ( bndSegs[ i ]._branchID > 0 && - branchEdges[ brID ].front() == bndSegs[ i ]._edge ) + else // bndSegs[ i ]._branchID > 0 { - edgeInd = 0; dInd = +1; - } - else - { for ( edgeInd = 0; edgeInd < branchEdges[ brID ].size(); ++edgeInd ) if ( branchEdges[ brID ][ edgeInd ] == bndSegs[ i ]._edge ) break; - dInd = bndSegs[ i ]._branchID > 0 ? +1 : -1; } } } @@ -942,7 +938,7 @@ namespace // no MA edge, bndSeg corresponds to an end point of a branch if ( bndPoints._maEdges.empty() ) { - // should not get here according to algo design + // should not get here according to algo design??? edgeInd = 0; } else @@ -1037,7 +1033,7 @@ void SMESH_MAT2d::MedialAxis::getPoints( const Branch& branch, //================================================================================ /*! * \brief Returns a BranchPoint corresponding to a given point on a geom EDGE - * \param [in] iGeomEdge - index of geom EDGE within a vector passed at construction + * \param [in] iGeomEdge - index of geom EDGE within a vector passed at MA construction * \param [in] u - parameter of the point on EDGE curve * \param [out] p - the found BranchPoint * \return bool - is OK @@ -1052,7 +1048,7 @@ bool SMESH_MAT2d::Boundary::getBranchPoint( const std::size_t iEdge, return false; const BndPoints& points = _pointsPerEdge[ iEdge ]; - const bool edgeReverse = ( points._params[0] > points._params.back() ); + const bool edgeReverse = ( points._params[0] > points._params.back() ); if ( u < ( edgeReverse ? points._params.back() : points._params[0] )) u = edgeReverse ? points._params.back() : points._params[0]; @@ -1071,13 +1067,29 @@ bool SMESH_MAT2d::Boundary::getBranchPoint( const std::size_t iEdge, while ( points._params[i ] > u ) --i; while ( points._params[i+1] < u ) ++i; } + double edgeParam = ( u - points._params[i] ) / ( points._params[i+1] - points._params[i] ); + if ( !points._maEdges[ i ].second ) // no branch at the EDGE end + { + if ( i < points._maEdges.size() / 2 ) // near 1st point + { + while ( i < points._maEdges.size()-1 && !points._maEdges[ i ].second ) + ++i; + edgeParam = edgeReverse; + } + else // near last point + { + while ( i > 0 && !points._maEdges[ i ].second ) + --i; + edgeParam = !edgeReverse; + } + } const std::pair< const Branch*, int >& maE = points._maEdges[ i ]; bool maReverse = ( maE.second < 0 ); p._branch = maE.first; - p._iEdge = maE.second - 1; // countered from 1 to store sign + p._iEdge = ( maReverse ? -maE.second : maE.second ) - 1; // countered from 1 to store sign p._edgeParam = maReverse ? ( 1. - edgeParam ) : edgeParam; return true; @@ -1244,6 +1256,8 @@ bool SMESH_MAT2d::Branch::getBoundaryPoints(std::size_t iMAEdge, { if ( iMAEdge > _maEdges.size() ) return false; + if ( iMAEdge == _maEdges.size() ) + iMAEdge = _maEdges.size() - 1; size_t iGeom1 = getGeomEdge( _maEdges[ iMAEdge ] ); size_t iGeom2 = getGeomEdge( _maEdges[ iMAEdge ]->twin() ); @@ -1277,6 +1291,8 @@ bool SMESH_MAT2d::Branch::getParameter(const BranchPoint & p, double & u ) const { if ( p._iEdge > _params.size()-1 ) return false; + if ( p._iEdge == _params.size()-1 ) + return u = 1.; u = ( _params[ p._iEdge ] * ( 1 - p._edgeParam ) + _params[ p._iEdge+1 ] * p._edgeParam ); diff --git a/src/SMESH_I/SMESH_Gen_i.cxx b/src/SMESH_I/SMESH_Gen_i.cxx index 824655a87..81d0e15c1 100644 --- a/src/SMESH_I/SMESH_Gen_i.cxx +++ b/src/SMESH_I/SMESH_Gen_i.cxx @@ -2422,6 +2422,7 @@ SMESH_Gen_i::ConcatenateCommon(const SMESH::ListOfIDSources& theMeshesArray, ::SMESH_MeshEditor aNewEditor(&aLocMesh); SMESH::ListOfGroups_var aListOfGroups; + ::SMESH_MeshEditor::ElemFeatures elemType; std::vector aNodesArray; // loop on sub-meshes @@ -2476,31 +2477,12 @@ SMESH_Gen_i::ConcatenateCommon(const SMESH::ListOfIDSources& theMeshesArray, } // creates a corresponding element on existent nodes in new mesh - aNewElem = 0; - switch ( anElem->GetEntityType() ) - { - case SMDSEntity_Polyhedra: - if ( const SMDS_VtkVolume* aVolume = - dynamic_cast (anElem)) - { - aNewElem = aNewMeshDS->AddPolyhedralVolume( aNodesArray, - aVolume->GetQuantities() ); - } - break; - case SMDSEntity_Ball: - if ( const SMDS_BallElement* aBall = - dynamic_cast (anElem)) - { - aNewElem = aNewEditor.AddElement( aNodesArray, SMDSAbs_Ball, - /*isPoly=*/false, /*id=*/0, - aBall->GetDiameter() ); - } - break; - case SMDSEntity_Node: - break; - default: - aNewElem = aNewEditor.AddElement( aNodesArray, anElem->GetType(), anElem->IsPoly() ); - } + if ( anElem->GetType() == SMDSAbs_Node ) + aNewElem = 0; + else + aNewElem = + aNewEditor.AddElement( aNodesArray, elemType.Init( anElem, /*basicOnly=*/false )); + if ( aNewElem ) elemsMap.insert( make_pair( anElem, aNewElem )); @@ -2737,6 +2719,7 @@ SMESH::SMESH_Mesh_ptr SMESH_Gen_i::CopyMesh(SMESH::SMESH_IDSource_ptr meshPart, } SMESHDS_Mesh* newMeshDS = newMesh_i->GetImpl().GetMeshDS(); ::SMESH_MeshEditor editor( &newMesh_i->GetImpl() ); + ::SMESH_MeshEditor::ElemFeatures elemType; // 3. Get elements to copy @@ -2808,30 +2791,12 @@ SMESH::SMESH_Mesh_ptr SMESH_Gen_i::CopyMesh(SMESH::SMESH_IDSource_ptr meshPart, // add elements if ( elem->GetType() != SMDSAbs_Node ) { - int ID = toKeepIDs ? elem->GetID() : 0; - const SMDS_MeshElement * newElem; - switch ( elem->GetEntityType() ) { - case SMDSEntity_Polyhedra: - if ( toKeepIDs ) - newElem = editor.GetMeshDS()-> - AddPolyhedralVolumeWithID( nodes, - static_cast(elem)->GetQuantities(), - ID); - else - newElem = editor.GetMeshDS()-> - AddPolyhedralVolume( nodes, - static_cast(elem)->GetQuantities()); - break; - case SMDSEntity_Ball: - newElem = editor.AddElement( nodes, SMDSAbs_Ball, false, ID, - static_cast(elem)->GetDiameter()); - break; - default: - newElem = editor.AddElement( nodes,elem->GetType(),elem->IsPoly(),ID); + elemType.Init( elem, /*basicOnly=*/false ); + if ( toKeepIDs ) elemType.SetID( elem->GetID() ); + const SMDS_MeshElement * newElem = editor.AddElement( nodes, elemType ); if ( toCopyGroups && !toKeepIDs ) e2eMapByType[ elem->GetType() ].insert( make_pair( elem, newElem )); - } } } // while ( srcElemIt->more() ) diff --git a/src/SMESH_I/SMESH_MeshEditor_i.cxx b/src/SMESH_I/SMESH_MeshEditor_i.cxx index e469b7039..06481f54b 100644 --- a/src/SMESH_I/SMESH_MeshEditor_i.cxx +++ b/src/SMESH_I/SMESH_MeshEditor_i.cxx @@ -154,20 +154,11 @@ namespace MeshEditor_I { } // creates a corresponding element on copied nodes - SMDS_MeshElement* anElemCopy = 0; - if ( anElem->IsPoly() && anElem->GetType() == SMDSAbs_Volume ) - { - const SMDS_VtkVolume* ph = - dynamic_cast (anElem); - if ( ph ) - anElemCopy = _myMeshDS->AddPolyhedralVolumeWithID - (anElemNodesID, ph->GetQuantities(),anElem->GetID()); - } - else { - anElemCopy = ::SMESH_MeshEditor(this).AddElement( anElemNodesID, - anElem->GetType(), - anElem->IsPoly() ); - } + ::SMESH_MeshEditor::ElemFeatures elemType; + elemType.Init( anElem, /*basicOnly=*/false ); + elemType.SetID( anElem->GetID() ); + SMDS_MeshElement* anElemCopy = + ::SMESH_MeshEditor(this).AddElement( anElemNodesID, elemType ); return anElemCopy; } //!< Copy a node @@ -535,7 +526,7 @@ TPreviewMesh * SMESH_MeshEditor_i::getPreviewMesh(SMDSAbs_ElementType previewEle SMESH::MeshPreviewStruct* SMESH_MeshEditor_i::GetPreviewData() throw (SALOME::SALOME_Exception) -{ +{ SMESH_TRY; const bool hasBadElems = ( getEditor().GetError() && getEditor().GetError()->HasBadElems() ); @@ -557,7 +548,7 @@ SMESH::MeshPreviewStruct* SMESH_MeshEditor_i::GetPreviewData() myPreviewData = new SMESH::MeshPreviewStruct(); myPreviewData->nodesXYZ.length(aMeshDS->NbNodes()); - + SMDSAbs_ElementType previewType = SMDSAbs_All; if ( !hasBadElems ) if (TPreviewMesh * aPreviewMesh = dynamic_cast< TPreviewMesh* >( getEditor().GetMesh() )) { @@ -577,7 +568,10 @@ SMESH::MeshPreviewStruct* SMESH_MeshEditor_i::GetPreviewData() while ( itMeshElems->more() ) { const SMDS_MeshElement* aMeshElem = itMeshElems->next(); - SMDS_NodeIteratorPtr itElemNodes = aMeshElem->nodeIterator(); + SMDS_NodeIteratorPtr itElemNodes = + (( aMeshElem->GetEntityType() == SMDSEntity_Quad_Polygon ) ? + aMeshElem->interlacedNodesIterator() : + aMeshElem->nodeIterator() ); while ( itElemNodes->more() ) { const SMDS_MeshNode* aMeshNode = itElemNodes->next(); int aNodeID = aMeshNode->GetID(); @@ -1059,6 +1053,7 @@ CORBA::Long SMESH_MeshEditor_i::AddFace(const SMESH::long_array & IDsOfNodes) * AddPolygonalFace */ //============================================================================= + CORBA::Long SMESH_MeshEditor_i::AddPolygonalFace (const SMESH::long_array & IDsOfNodes) throw (SALOME::SALOME_Exception) { @@ -1082,6 +1077,35 @@ CORBA::Long SMESH_MeshEditor_i::AddPolygonalFace (const SMESH::long_array & IDsO return 0; } +//============================================================================= +/*! + * AddQuadPolygonalFace + */ +//============================================================================= + +CORBA::Long SMESH_MeshEditor_i::AddQuadPolygonalFace (const SMESH::long_array & IDsOfNodes) + throw (SALOME::SALOME_Exception) +{ + SMESH_TRY; + initData(); + + int NbNodes = IDsOfNodes.length(); + std::vector nodes (NbNodes); + for (int i = 0; i < NbNodes; i++) + nodes[i] = getMeshDS()->FindNode(IDsOfNodes[i]); + + const SMDS_MeshElement* elem = getMeshDS()->AddQuadPolygonalFace(nodes); + + // Update Python script + TPythonDump() <<"faceID = "<GetID() : 0; + + SMESH_CATCH( SMESH::throwCorbaException ); + return 0; +} + //============================================================================= /*! * Create volume, either linear and quadratic (this is determed diff --git a/src/SMESH_I/SMESH_MeshEditor_i.hxx b/src/SMESH_I/SMESH_MeshEditor_i.hxx index ec9ae9861..2cdf9fa61 100644 --- a/src/SMESH_I/SMESH_MeshEditor_i.hxx +++ b/src/SMESH_I/SMESH_MeshEditor_i.hxx @@ -117,6 +117,8 @@ public: throw (SALOME::SALOME_Exception); CORBA::Long AddPolygonalFace(const SMESH::long_array & IDsOfNodes) throw (SALOME::SALOME_Exception); + CORBA::Long AddQuadPolygonalFace(const SMESH::long_array & IDsOfNodes) + throw (SALOME::SALOME_Exception); CORBA::Long AddVolume(const SMESH::long_array & IDsOfNodes) throw (SALOME::SALOME_Exception); CORBA::Long AddPolyhedralVolume(const SMESH::long_array & IDsOfNodes, diff --git a/src/SMESH_I/SMESH_Mesh_i.cxx b/src/SMESH_I/SMESH_Mesh_i.cxx index 03420b0e4..060329f4c 100644 --- a/src/SMESH_I/SMESH_Mesh_i.cxx +++ b/src/SMESH_I/SMESH_Mesh_i.cxx @@ -3765,13 +3765,13 @@ CORBA::Long SMESH_Mesh_i::NbBiQuadQuadrangles()throw(SALOME::SALOME_Exception) return _impl->NbBiQuadQuadrangles(); } -CORBA::Long SMESH_Mesh_i::NbPolygons()throw(SALOME::SALOME_Exception) +CORBA::Long SMESH_Mesh_i::NbPolygons(SMESH::ElementOrder order) throw(SALOME::SALOME_Exception) { Unexpect aCatch(SALOME_SalomeException); if ( _preMeshInfo ) - return _preMeshInfo->NbPolygons(); + return _preMeshInfo->NbPolygons((SMDSAbs_ElementOrder) order); - return _impl->NbPolygons(); + return _impl->NbPolygons((SMDSAbs_ElementOrder)order); } CORBA::Long SMESH_Mesh_i::NbFacesOfOrder(SMESH::ElementOrder order) @@ -4851,6 +4851,7 @@ SMESH_Mesh_i::MakeGroupsOfBadInputElements( int theSubShapeID, THROW_SALOME_CORBA_EXCEPTION( "empty group name",SALOME::BAD_PARAM ); SMESH::ListOfGroups_var groups = new SMESH::ListOfGroups; + ::SMESH_MeshEditor::ElemFeatures elemType; // submesh by subshape id if ( !_impl->HasShapeToMesh() ) theSubShapeID = 1; @@ -4883,7 +4884,7 @@ SMESH_Mesh_i::MakeGroupsOfBadInputElements( int theSubShapeID, if ( elem ) { ::SMESH_MeshEditor editor( _impl ); - elem = editor.AddElement( nodes, elem->GetType(), elem->IsPoly() ); + elem = editor.AddElement( nodes, elemType.Init( elem )); } } if ( elem ) diff --git a/src/SMESH_I/SMESH_Mesh_i.hxx b/src/SMESH_I/SMESH_Mesh_i.hxx index 45d01b10e..24874a03a 100644 --- a/src/SMESH_I/SMESH_Mesh_i.hxx +++ b/src/SMESH_I/SMESH_Mesh_i.hxx @@ -315,7 +315,7 @@ public: CORBA::Long NbBiQuadQuadrangles() throw (SALOME::SALOME_Exception); - CORBA::Long NbPolygons() + CORBA::Long NbPolygons(SMESH::ElementOrder order=SMESH::ORDER_ANY) throw (SALOME::SALOME_Exception); CORBA::Long NbVolumes() diff --git a/src/SMESH_SWIG/smeshBuilder.py b/src/SMESH_SWIG/smeshBuilder.py index 07d46509b..22e31b4ee 100644 --- a/src/SMESH_SWIG/smeshBuilder.py +++ b/src/SMESH_SWIG/smeshBuilder.py @@ -2242,11 +2242,11 @@ class Mesh: def NbBiQuadQuadrangles(self): return self.mesh.NbBiQuadQuadrangles() - ## Returns the number of polygons in the mesh + ## Returns the number of polygons of given order in the mesh # @return an integer value # @ingroup l1_meshinfo - def NbPolygons(self): - return self.mesh.NbPolygons() + def NbPolygons(self, elementOrder = SMESH.ORDER_ANY): + return self.mesh.NbPolygons(elementOrder) ## Returns the number of volumes in the mesh # @return an integer value @@ -2367,7 +2367,7 @@ class Mesh: ## Returns the type of mesh element # @return the value from SMESH::ElementType enumeration # @ingroup l1_meshinfo - def GetElementType(self, id, iselem): + def GetElementType(self, id, iselem=True): return self.mesh.GetElementType(id, iselem) ## Returns the geometric type of mesh element @@ -2455,24 +2455,22 @@ class Mesh: def GetElementPosition(self,ElemID): return self.mesh.GetElementPosition(ElemID) - ## If the given element is a node, returns the ID of shape - # \n If there is no node for the given ID - returns -1 - # @return an integer value + ## Returns the ID of the shape, on which the given node was generated. + # @return an integer value > 0 or -1 if there is no node for the given + # ID or the node is not assigned to any geometry # @ingroup l1_meshinfo def GetShapeID(self, id): return self.mesh.GetShapeID(id) - ## Returns the ID of the result shape after - # FindShape() from SMESH_MeshEditor for the given element - # \n If there is no element for the given ID - returns -1 - # @return an integer value + ## Returns the ID of the shape, on which the given element was generated. + # @return an integer value > 0 or -1 if there is no element for the given + # ID or the element is not assigned to any geometry # @ingroup l1_meshinfo def GetShapeIDForElem(self,id): return self.mesh.GetShapeIDForElem(id) - ## Returns the number of nodes for the given element - # \n If there is no element for the given ID - returns -1 - # @return an integer value + ## Returns the number of nodes of the given element + # @return an integer value > 0 or -1 if there is no element for the given ID # @ingroup l1_meshinfo def GetElemNbNodes(self, id): return self.mesh.GetElemNbNodes(id) @@ -2498,7 +2496,7 @@ class Mesh: ## Returns true if the given node is the medium node in one of quadratic elements # @ingroup l1_meshinfo - def IsMediumNodeOfAnyElem(self, nodeID, elementType): + def IsMediumNodeOfAnyElem(self, nodeID, elementType = SMESH.ALL ): return self.mesh.IsMediumNodeOfAnyElem(nodeID, elementType) ## Returns the number of edges for the given element @@ -2756,6 +2754,14 @@ class Mesh: def AddPolygonalFace(self, IdsOfNodes): return self.editor.AddPolygonalFace(IdsOfNodes) + ## Adds a quadratic polygonal face to the mesh by the list of node IDs + # @param IdsOfNodes the list of node IDs for creation of the element; + # corner nodes follow first. + # @return the Id of the new face + # @ingroup l2_modif_add + def AddQuadPolygonalFace(self, IdsOfNodes): + return self.editor.AddQuadPolygonalFace(IdsOfNodes) + ## Creates both simple and quadratic volume (this is determined # by the number of given nodes). # @param IDsOfNodes the list of node IDs for creation of the element. @@ -3990,8 +3996,8 @@ class Mesh: ## Creates a symmetrical copy of mesh elements # @param IDsOfElements list of elements ids # @param Mirror is AxisStruct or geom object(point, line, plane) - # @param theMirrorType is POINT, AXIS or PLANE - # If the Mirror is a geom object this parameter is unnecessary + # @param theMirrorType smeshBuilder.POINT, smeshBuilder.AXIS or smeshBuilder.PLANE + # If the Mirror is a geom object this parameter is unnecessary # @param Copy allows to copy element (Copy is 1) or to replace with its mirroring (Copy is 0) # @param MakeGroups forces the generation of new groups from existing ones (if Copy) # @return list of created groups (SMESH_GroupBase) if MakeGroups=True, empty list otherwise @@ -4012,8 +4018,8 @@ class Mesh: ## Creates a new mesh by a symmetrical copy of mesh elements # @param IDsOfElements the list of elements ids # @param Mirror is AxisStruct or geom object (point, line, plane) - # @param theMirrorType is POINT, AXIS or PLANE - # If the Mirror is a geom object this parameter is unnecessary + # @param theMirrorType smeshBuilder.POINT, smeshBuilder.AXIS or smeshBuilder.PLANE + # If the Mirror is a geom object this parameter is unnecessary # @param MakeGroups to generate new groups from existing ones # @param NewMeshName a name of the new mesh to create # @return instance of Mesh class @@ -4033,8 +4039,8 @@ class Mesh: ## Creates a symmetrical copy of the object # @param theObject mesh, submesh or group # @param Mirror AxisStruct or geom object (point, line, plane) - # @param theMirrorType is POINT, AXIS or PLANE - # If the Mirror is a geom object this parameter is unnecessary + # @param theMirrorType smeshBuilder.POINT, smeshBuilder.AXIS or smeshBuilder.PLANE + # If the Mirror is a geom object this parameter is unnecessary # @param Copy allows copying the element (Copy is 1) or replacing it with its mirror (Copy is 0) # @param MakeGroups forces the generation of new groups from existing ones (if Copy) # @return list of created groups (SMESH_GroupBase) if MakeGroups=True, empty list otherwise @@ -4055,8 +4061,8 @@ class Mesh: ## Creates a new mesh by a symmetrical copy of the object # @param theObject mesh, submesh or group # @param Mirror AxisStruct or geom object (point, line, plane) - # @param theMirrorType POINT, AXIS or PLANE - # If the Mirror is a geom object this parameter is unnecessary + # @param theMirrorType smeshBuilder.POINT, smeshBuilder.AXIS or smeshBuilder.PLANE + # If the Mirror is a geom object this parameter is unnecessary # @param MakeGroups forces the generation of new groups from existing ones # @param NewMeshName the name of the new mesh to create # @return instance of Mesh class @@ -4420,8 +4426,9 @@ class Mesh: ## Creates Duplicates given elements, i.e. creates new elements based on the # same nodes as the given ones. # @param theElements - container of elements to duplicate. It can be a Mesh, - # sub-mesh, group, filter or a list of element IDs. - # @param theGroupName - a name of group to contain the generated elements. + # sub-mesh, group, filter or a list of element IDs. If \a theElements is + # a Mesh, elements of highest dimension are duplicated + # @param theGroupName - a name of group to contain the generated elements. # If a group with such a name already exists, the new elements # are added to the existng group, else a new group is created. # If \a theGroupName is empty, new elements are not added diff --git a/src/StdMeshers/StdMeshers_Import_1D.cxx b/src/StdMeshers/StdMeshers_Import_1D.cxx index b5e9a567a..083f055f2 100644 --- a/src/StdMeshers/StdMeshers_Import_1D.cxx +++ b/src/StdMeshers/StdMeshers_Import_1D.cxx @@ -841,6 +841,7 @@ void StdMeshers_Import_1D::importMesh(const SMESH_Mesh* srcMesh, // 1. Copy mesh + SMESH_MeshEditor::ElemFeatures elemType; vector newNodes; const SMESHDS_Mesh* srcMeshDS = srcMesh->GetMeshDS(); SMDS_ElemIteratorPtr eIt = srcMeshDS->elementsIterator(); @@ -865,7 +866,7 @@ void StdMeshers_Import_1D::importMesh(const SMESH_Mesh* srcMesh, tgtMeshDS->FindElement( newNodes, elem->GetType(), /*noMedium=*/false ); if ( !newElem ) { - newElem = additor.AddElement( newNodes, elem->GetType(), elem->IsPoly()); + newElem = additor.AddElement( newNodes, elemType.Init( elem, /*basicOnly=*/false )); tgtSubMesh->AddElement( newElem ); } if ( toCopyGroups ) diff --git a/src/StdMeshers/StdMeshers_Import_1D2D.cxx b/src/StdMeshers/StdMeshers_Import_1D2D.cxx index 196814b78..60b776254 100644 --- a/src/StdMeshers/StdMeshers_Import_1D2D.cxx +++ b/src/StdMeshers/StdMeshers_Import_1D2D.cxx @@ -454,7 +454,7 @@ bool StdMeshers_Import_1D2D::Compute(SMESH_Mesh & theMesh, const TopoDS_Shape & if ( geomNorm * meshNorm < 0 ) SMDS_MeshCell::applyInterlace - ( SMDS_MeshCell::reverseSmdsOrder( face->GetEntityType() ), newNodes ); + ( SMDS_MeshCell::reverseSmdsOrder( face->GetEntityType(), newNodes.size() ), newNodes ); } // make a new face diff --git a/src/StdMeshers/StdMeshers_QuadFromMedialAxis_1D2D.cxx b/src/StdMeshers/StdMeshers_QuadFromMedialAxis_1D2D.cxx index a6d372d5f..4ac71c0b8 100644 --- a/src/StdMeshers/StdMeshers_QuadFromMedialAxis_1D2D.cxx +++ b/src/StdMeshers/StdMeshers_QuadFromMedialAxis_1D2D.cxx @@ -29,6 +29,7 @@ #include "SMESH_Gen.hxx" #include "SMESH_MAT2d.hxx" #include "SMESH_Mesh.hxx" +#include "SMESH_MeshEditor.hxx" #include "SMESH_MesherHelper.hxx" #include "SMESH_ProxyMesh.hxx" #include "SMESH_subMesh.hxx" @@ -124,6 +125,34 @@ bool StdMeshers_QuadFromMedialAxis_1D2D::CheckHypothesis(SMESH_Mesh& aMe namespace { + typedef map< const SMDS_MeshNode*, list< const SMDS_MeshNode* > > TMergeMap; + + //================================================================================ + /*! + * \brief Sinuous face + */ + struct SinuousFace + { + FaceQuadStruct::Ptr _quad; + vector< TopoDS_Edge > _edges; + vector< TopoDS_Edge > _sinuSide[2], _shortSide[2]; + vector< TopoDS_Edge > _sinuEdges; + int _nbWires; + list< int > _nbEdgesInWire; + TMergeMap _nodesToMerge; + + SinuousFace( const TopoDS_Face& f ): _quad( new FaceQuadStruct ) + { + list< TopoDS_Edge > edges; + _nbWires = SMESH_Block::GetOrderedEdges (f, edges, _nbEdgesInWire); + _edges.assign( edges.begin(), edges.end() ); + + _quad->side.resize( 4 ); + _quad->face = f; + } + const TopoDS_Face& Face() const { return _quad->face; } + }; + //================================================================================ /*! * \brief Temporary mesh @@ -136,6 +165,18 @@ namespace } }; + //================================================================================ + /*! + * \brief Return a member of a std::pair + */ + //================================================================================ + + template< typename T > + T& get( std::pair< T, T >& thePair, bool is2nd ) + { + return is2nd ? thePair.second : thePair.first; + } + //================================================================================ /*! * \brief Select two EDGEs from a map, either mapped to least values or to max values @@ -331,36 +372,42 @@ namespace //================================================================================ /*! * \brief Find EDGEs to discretize using projection from MA - * \param [in] theFace - the FACE to be meshed - * \param [in] theWire - ordered EDGEs of the FACE - * \param [out] theSinuEdges - the EDGEs to discretize using projection from MA - * \param [out] theShortEdges - other EDGEs + * \param [in,out] theSinuFace - the FACE to be meshed * \return bool - OK or not * - * Is separate all EDGEs into four sides of a quadrangle connected in the order: + * It separates all EDGEs into four sides of a quadrangle connected in the order: * theSinuEdges[0], theShortEdges[0], theSinuEdges[1], theShortEdges[1] */ //================================================================================ bool getSinuousEdges( SMESH_MesherHelper& theHelper, - const TopoDS_Face& theFace, - list& theWire, - vector theSinuEdges[2], - vector theShortEdges[2]) + SinuousFace& theSinuFace) { + vector * theSinuEdges = & theSinuFace._sinuSide [0]; + vector * theShortEdges = & theSinuFace._shortSide[0]; theSinuEdges[0].clear(); theSinuEdges[1].clear(); theShortEdges[0].clear(); theShortEdges[1].clear(); - - vector allEdges( theWire.begin(), theWire.end() ); + + vector & allEdges = theSinuFace._edges; const size_t nbEdges = allEdges.size(); - if ( nbEdges < 4 ) + if ( nbEdges < 4 && theSinuFace._nbWires == 1 ) + return false; + + if ( theSinuFace._nbWires == 2 ) // ring + { + size_t nbOutEdges = theSinuFace._nbEdgesInWire.front(); + theSinuEdges[0].assign ( allEdges.begin(), allEdges.begin() + nbOutEdges ); + theSinuEdges[1].assign ( allEdges.begin() + nbOutEdges, allEdges.end() ); + return true; + } + if ( theSinuFace._nbWires > 2 ) return false; // create MedialAxis to find short edges by analyzing MA branches double minSegLen = getMinSegLen( theHelper, allEdges ); - SMESH_MAT2d::MedialAxis ma( theFace, allEdges, minSegLen ); + SMESH_MAT2d::MedialAxis ma( theSinuFace.Face(), allEdges, minSegLen * 3 ); // in an initial request case, theFace represents a part of a river with almost parallel banks // so there should be two branch points @@ -430,6 +477,10 @@ namespace !vCommon.IsSame( theHelper.IthVertex( 1, theSinuEdges[0].back() ))) theShortEdges[0].swap( theShortEdges[1] ); + theSinuFace._sinuEdges = theSinuEdges[0]; + theSinuFace._sinuEdges.insert( theSinuFace._sinuEdges.end(), + theSinuEdges[1].begin(), theSinuEdges[1].end() ); + return ( theShortEdges[0].size() > 0 && theShortEdges[1].size() > 0 && theSinuEdges [0].size() > 0 && theSinuEdges [1].size() > 0 ); @@ -437,17 +488,17 @@ namespace // therefor we use a complex criterion to find TWO short non-sinuous EDGEs // and the rest EDGEs will be treated as sinuous. // A short edge should have the following features: - // a) straight - // b) short - // c) with convex corners at ends - // d) far from the other short EDGE + // a) straight + // b) short + // c) with convex corners at ends + // d) far from the other short EDGE - // vector< double > isStraightEdge( nbEdges, 0 ); // criterion value + // vector< double > isStraightEdge( nbEdges, 0 ); // criterion value - // // a0) evaluate continuity - // const double contiWgt = 0.5; // weight of continuity in the criterion - // multimap< int, TopoDS_Edge > continuity; - // for ( size_t i = 0; i < nbEdges; ++I ) + // // a0) evaluate continuity + // const double contiWgt = 0.5; // weight of continuity in the criterion + // multimap< int, TopoDS_Edge > continuity; + // for ( size_t i = 0; i < nbEdges; ++I ) // { // BRepAdaptor_Curve curve( allEdges[i] ); // GeomAbs_Shape C = GeomAbs_CN; @@ -604,21 +655,21 @@ namespace bool divideMA( SMESH_MesherHelper& theHelper, const SMESH_MAT2d::MedialAxis& theMA, - const vector& theSinuEdges, - const size_t theSinuSide0Size, + const SinuousFace& theSinuFace, SMESH_Algo* the1dAlgo, vector& theMAParams ) { // check if all EDGEs of one size are meshed, then MA discretization is not needed SMESH_Mesh* mesh = theHelper.GetMesh(); size_t nbComputedEdges[2] = { 0, 0 }; - for ( size_t i = 1; i < theSinuEdges.size(); ++i ) - { - bool isComputed = ( ! mesh->GetSubMesh( theSinuEdges[i] )->IsEmpty() ); - nbComputedEdges[ i < theSinuSide0Size ] += isComputed; - } - if ( nbComputedEdges[0] == theSinuSide0Size || - nbComputedEdges[1] == theSinuEdges.size() - theSinuSide0Size ) + for ( size_t iS = 0; iS < 2; ++iS ) + for ( size_t i = 0; i < theSinuFace._sinuSide[iS].size(); ++i ) + { + bool isComputed = ( ! mesh->GetSubMesh( theSinuFace._sinuSide[iS][i] )->IsEmpty() ); + nbComputedEdges[ iS ] += isComputed; + } + if ( nbComputedEdges[0] == theSinuFace._sinuSide[0].size() || + nbComputedEdges[1] == theSinuFace._sinuSide[1].size() ) return true; // discretization is not needed @@ -631,13 +682,13 @@ namespace // cout << "Write " << file << endl; // look for a most local hyps assigned to theSinuEdges - TopoDS_Edge edge = theSinuEdges[0]; + TopoDS_Edge edge = theSinuFace._sinuEdges[0]; int mostSimpleShape = (int) getHypShape( mesh, edge ); - for ( size_t i = 1; i < theSinuEdges.size(); ++i ) + for ( size_t i = 1; i < theSinuFace._sinuEdges.size(); ++i ) { - int shapeType = (int) getHypShape( mesh, theSinuEdges[i] ); + int shapeType = (int) getHypShape( mesh, theSinuFace._sinuEdges[i] ); if ( shapeType > mostSimpleShape ) - edge = theSinuEdges[i]; + edge = theSinuFace._sinuEdges[i]; } SMESH_Algo* algo = the1dAlgo; @@ -664,14 +715,13 @@ namespace //================================================================================ /*! - * \brief Modifies division parameters on MA to make them coincide with projections - * of VERTEXes to MA for a given pair of opposite EDGEs + * \brief Select division parameters on MA and make them coincide at ends with + * projections of VERTEXes to MA for a given pair of opposite EDGEs * \param [in] theEdgePairInd - index of the EDGE pair * \param [in] theDivPoints - the BranchPoint's dividing MA into parts each * corresponding to a unique pair of opposite EDGEs - * \param [in,out] theMAParams - the MA division parameters to modify - * \param [in,out] theParBeg - index of the 1st division point for the given EDGE pair - * \param [in,out] theParEnd - index of the last division point for the given EDGE pair + * \param [in] theMAParams - the MA division parameters + * \param [out] theSelectedMAParams - the selected MA parameters * \return bool - is OK */ //================================================================================ @@ -686,11 +736,49 @@ namespace theSelectedMAParams = theMAParams; return true; } - if ( theEdgePairInd > theDivPoints.size() ) + if ( theEdgePairInd > theDivPoints.size() || theMAParams.empty() ) return false; - // TODO - return false; + // find a range of params to copy + + double par1 = 0; + size_t iPar1 = 0; + if ( theEdgePairInd > 0 ) + { + const SMESH_MAT2d::BranchPoint& bp = theDivPoints[ theEdgePairInd-1 ]; + bp._branch->getParameter( bp, par1 ); + while ( theMAParams[ iPar1 ] < par1 ) ++iPar1; + if ( par1 - theMAParams[ iPar1-1 ] < theMAParams[ iPar1 ] - par1 ) + --iPar1; + } + + double par2 = 1; + size_t iPar2 = theMAParams.size() - 1; + if ( theEdgePairInd < theDivPoints.size() ) + { + const SMESH_MAT2d::BranchPoint& bp = theDivPoints[ theEdgePairInd ]; + bp._branch->getParameter( bp, par2 ); + iPar2 = iPar1; + while ( theMAParams[ iPar2 ] < par2 ) ++iPar2; + if ( par2 - theMAParams[ iPar2-1 ] < theMAParams[ iPar2 ] - par2 ) + --iPar2; + } + + theSelectedMAParams.assign( theMAParams.begin() + iPar1, + theMAParams.begin() + iPar2 + 1 ); + + // adjust theSelectedMAParams to fit between par1 and par2 + + double d = par1 - theSelectedMAParams[0]; + double f = ( par2 - par1 ) / ( theSelectedMAParams.back() - theSelectedMAParams[0] ); + + for ( size_t i = 0; i < theSelectedMAParams.size(); ++i ) + { + theSelectedMAParams[i] += d; + theSelectedMAParams[i] = par1 + ( theSelectedMAParams[i] - par1 ) * f; + } + + return true; } //-------------------------------------------------------------------------------- @@ -701,9 +789,14 @@ namespace double _u; int _edgeInd; // index in theSinuEdges vector - NodePoint(const SMDS_MeshNode* n=0 ): _node(n), _u(0), _edgeInd(-1) {} + NodePoint(): _node(0), _u(0), _edgeInd(-1) {} + NodePoint(const SMDS_MeshNode* n, double u, size_t iEdge ): _node(n), _u(u), _edgeInd(iEdge) {} NodePoint(double u, size_t iEdge) : _node(0), _u(u), _edgeInd(iEdge) {} NodePoint(const SMESH_MAT2d::BoundaryPoint& p) : _node(0), _u(p._param), _edgeInd(p._edgeIndex) {} + gp_Pnt Point(const vector< Handle(Geom_Curve) >& curves) const + { + return curves[ _edgeInd ]->Value( _u ); + } }; //================================================================================ @@ -726,11 +819,12 @@ namespace double f,l; BRep_Tool::Range( theSinuEdges[ theNodePnt._edgeInd ], f,l ); + const double tol = 1e-3 * ( l - f ); TopoDS_Vertex V; - if ( Abs( f - theNodePnt._u )) + if ( Abs( f - theNodePnt._u ) < tol ) V = SMESH_MesherHelper::IthVertex( 0, theSinuEdges[ theNodePnt._edgeInd ], /*CumOri=*/false); - else if ( Abs( l - theNodePnt._u )) + else if ( Abs( l - theNodePnt._u ) < tol ) V = SMESH_MesherHelper::IthVertex( 1, theSinuEdges[ theNodePnt._edgeInd ], /*CumOri=*/false); if ( !V.IsNull() ) @@ -752,21 +846,25 @@ namespace * \brief Add to the map of NodePoint's those on VERTEXes * \param [in,out] theHelper - the helper * \param [in] theMA - Medial Axis + * \param [in] theMinSegLen - minimal segment length * \param [in] theDivPoints - projections of VERTEXes to MA * \param [in] theSinuEdges - the sinuous EDGEs * \param [in] theSideEdgeIDs - indices of sinuous EDGEs per side * \param [in] theIsEdgeComputed - is sinuous EGDE is meshed * \param [in,out] thePointsOnE - the map to fill + * \param [out] theNodes2Merge - the map of nodes to merge */ //================================================================================ bool projectVertices( SMESH_MesherHelper& theHelper, + //const double theMinSegLen, const SMESH_MAT2d::MedialAxis& theMA, const vector< SMESH_MAT2d::BranchPoint >& theDivPoints, const vector& theSinuEdges, - //const vector< int > theSideEdgeIDs[2], + const vector< Handle(Geom_Curve) >& theCurves, const vector< bool >& theIsEdgeComputed, - map< double, pair< NodePoint, NodePoint > > & thePointsOnE) + map< double, pair< NodePoint, NodePoint > > & thePointsOnE, + TMergeMap& theNodes2Merge) { if ( theDivPoints.empty() ) return true; @@ -784,29 +882,85 @@ namespace if ( !branch.getBoundaryPoints( theDivPoints[i], bp[0], bp[1] )) return false; - NodePoint np[2] = { NodePoint( bp[0] ), - NodePoint( bp[1] ) }; + NodePoint np[2] = { NodePoint( bp[0] ), + NodePoint( bp[1] )}; bool isVertex[2] = { findVertex( np[0], theSinuEdges, meshDS ), findVertex( np[1], theSinuEdges, meshDS )}; map< double, pair< NodePoint, NodePoint > >::iterator u2NP = thePointsOnE.insert( make_pair( uMA, make_pair( np[0], np[1]))).first; + if ( !isVertex[0] && !isVertex[1] ) return false; // error if ( isVertex[0] && isVertex[1] ) continue; + const size_t iVertex = isVertex[0] ? 0 : 1; + const size_t iNode = 1 - iVertex; - bool isOppComputed = theIsEdgeComputed[ np[ isVertex[0] ]._edgeInd ]; - + bool isOppComputed = theIsEdgeComputed[ np[ iNode ]._edgeInd ]; if ( !isOppComputed ) continue; // a VERTEX is projected on a meshed EDGE; there are two options: - // - a projected point is joined with a closet node if a strip between this and neighbor - // projection is wide enough; joining is done by setting the same node to the BoundaryPoint - // - a neighbor projection is merged this this one if it too close; a node of deleted + // 1) a projected point is joined with a closet node if a strip between this and neighbor + // projection is WIDE enough; joining is done by creating a node coincident with the + // existing node which will be merged together after all; + // 2) a neighbor projection is merged with this one if it is TOO CLOSE; a node of deleted // projection is set to the BoundaryPoint of this projection + // evaluate distance to neighbor projections + const double rShort = 0.2; + bool isShortPrev[2], isShortNext[2]; + map< double, pair< NodePoint, NodePoint > >::iterator u2NPPrev = u2NP, u2NPNext = u2NP; + --u2NPPrev; ++u2NPNext; + for ( int iS = 0; iS < 2; ++iS ) // side with Vertex and side with Nodes + { + NodePoint np = get( u2NP->second, iS ); + NodePoint npPrev = get( u2NPPrev->second, iS ); + NodePoint npNext = get( u2NPNext->second, iS ); + gp_Pnt p = np .Point( theCurves ); + gp_Pnt pPrev = npPrev.Point( theCurves ); + gp_Pnt pNext = npNext.Point( theCurves ); + double distPrev = p.Distance( pPrev ); + double distNext = p.Distance( pNext ); + double r = distPrev / ( distPrev + distNext ); + isShortPrev[iS] = ( r < rShort ); + isShortNext[iS] = (( 1 - r ) > ( 1 - rShort )); + } + + map< double, pair< NodePoint, NodePoint > >::iterator u2NPClose; + if (( isShortPrev[0] && isShortPrev[1] ) || // option 2) -> remove a too close projection + ( isShortNext[0] && isShortNext[1] )) + { + u2NPClose = isShortPrev[0] ? u2NPPrev : u2NPNext; + NodePoint& npProj = get( u2NP->second, iNode ); // NP of VERTEX projection + NodePoint npCloseN = get( u2NPClose->second, iNode); // NP close to npProj + NodePoint npCloseV = get( u2NPClose->second, iVertex); // NP close to VERTEX + if ( !npCloseV._node ) + { + npProj = npCloseN; + thePointsOnE.erase( isShortPrev[0] ? u2NPPrev : u2NPNext ); + continue; + } + else + { + // can't remove the neighbor projection as it is also from VERTEX, -> option 1) + } + } + // else option 1) - wide enough -> "duplicate" existing node + { + u2NPClose = isShortPrev[ iNode ] ? u2NPPrev : u2NPNext; + NodePoint& npProj = get( u2NP->second, iNode ); // NP of VERTEX projection + NodePoint& npCloseN = get( u2NPClose->second, iNode ); // NP close to npProj + // npProj._edgeInd = npCloseN._edgeInd; + // npProj._u = npCloseN._u + 1e-3 * Abs( get( u2NPPrev->second, iNode )._u - + // get( u2NPNext->second, iNode )._u ); + gp_Pnt p = npProj.Point( theCurves ); + npProj._node = meshDS->AddNode( p.X(), p.Y(), p.Z() ); + meshDS->SetNodeOnEdge( npProj._node, theSinuEdges[ npProj._edgeInd ], npProj._u ); + + theNodes2Merge[ npCloseN._node ].push_back( npProj._node ); + } } return true; } @@ -816,6 +970,7 @@ namespace * \brief Divide the sinuous EDGEs by projecting the division point of Medial * Axis to the EGDEs * \param [in] theHelper - the helper + * \param [in] theMinSegLen - minimal segment length * \param [in] theMA - the Medial Axis * \param [in] theMAParams - parameters of division points of \a theMA * \param [in] theSinuEdges - the EDGEs to make nodes on @@ -825,10 +980,10 @@ namespace //================================================================================ bool computeSinuEdges( SMESH_MesherHelper& theHelper, + double /*theMinSegLen*/, SMESH_MAT2d::MedialAxis& theMA, vector& theMAParams, - const vector& theSinuEdges, - const size_t theSinuSide0Size) + SinuousFace& theSinuFace) { if ( theMA.getBranches().size() != 1 ) return false; @@ -842,6 +997,7 @@ namespace SMESHDS_Mesh* meshDS = theHelper.GetMeshDS(); double f,l; + const vector< TopoDS_Edge >& theSinuEdges = theSinuFace._sinuEdges; vector< Handle(Geom_Curve) > curves ( theSinuEdges.size() ); vector< int > edgeIDs( theSinuEdges.size() ); vector< bool > isComputed( theSinuEdges.size() ); @@ -854,8 +1010,23 @@ namespace SMESH_subMesh* sm = mesh->GetSubMesh( theSinuEdges[i] ); edgeIDs [i] = sm->GetId(); isComputed[i] = ( !sm->IsEmpty() ); - // if ( isComputed[i] ) - // hasComputed = true; + if ( isComputed[i] ) + { + TopAbs_ShapeEnum shape = getHypShape( mesh, theSinuEdges[i] ); + if ( shape == TopAbs_SHAPE || shape <= TopAbs_FACE ) + { + // EDGE computed using global hypothesis -> clear it + bool hasComputedFace = false; + PShapeIteratorPtr faceIt = theHelper.GetAncestors( theSinuEdges[i], *mesh, TopAbs_FACE ); + while ( const TopoDS_Shape* face = faceIt->next() ) + if (( !face->IsSame( theSinuFace.Face())) && + ( hasComputedFace = !mesh->GetSubMesh( *face )->IsEmpty() )) + break; + if ( !hasComputedFace ) + sm->ComputeStateEngine( SMESH_subMesh::CLEAN ); + isComputed[i] = false; + } + } } const SMESH_MAT2d::Branch& branch = theMA.getBranches()[0]; @@ -907,7 +1078,7 @@ namespace branch.getParameter( brp, maParamLast ); map< double, const SMDS_MeshNode* >::iterator u2n = nodeParams.begin(), u2nEnd = --nodeParams.end(); - TMAPar2NPoints::iterator pos, end = pointsOnE.end(); + TMAPar2NPoints::iterator end = pointsOnE.end(), pos = end; TMAPar2NPoints::iterator & hint = (maParamLast > maParam1st) ? end : pos; for ( ++u2n; u2n != u2nEnd; ++u2n ) { @@ -918,7 +1089,7 @@ namespace if ( !branch.getParameter( brp, maParam )) return false; - npN = NodePoint( u2n->second ); + npN = NodePoint( u2n->second, u2n->first, iEdgeComputed ); npB = NodePoint( bndPnt ); pos = pointsOnE.insert( hint, make_pair( maParam, make_pair( np0, np1 ))); } @@ -950,7 +1121,8 @@ namespace ++iEdgePair; } - if ( !projectVertices( theHelper, theMA, divPoints, theSinuEdges, isComputed, pointsOnE )) + if ( !projectVertices( theHelper, theMA, divPoints, theSinuEdges, curves, + isComputed, pointsOnE, theSinuFace._nodesToMerge )) return false; // create nodes @@ -1115,6 +1287,29 @@ namespace return true; } + //================================================================================ + /*! + * \brief Remove temporary node + */ + //================================================================================ + + void mergeNodes( SMESH_MesherHelper& theHelper, + SinuousFace& theSinuFace ) + { + SMESH_MeshEditor editor( theHelper.GetMesh() ); + SMESH_MeshEditor::TListOfListOfNodes nodesGroups; + + TMergeMap::iterator n2nn = theSinuFace._nodesToMerge.begin(); + for ( ; n2nn != theSinuFace._nodesToMerge.end(); ++n2nn ) + { + nodesGroups.push_back( list< const SMDS_MeshNode* >() ); + list< const SMDS_MeshNode* > & group = nodesGroups.back(); + + group.push_back( n2nn->first ); + group.splice( group.end(), n2nn->second ); + } + editor.MergeNodes( nodesGroups ); + } } // namespace @@ -1181,7 +1376,7 @@ bool StdMeshers_QuadFromMedialAxis_1D2D::computeQuads( SMESH_MesherHelper& StdMeshers_Quadrangle_2D::myProxyMesh.reset(); StdMeshers_Quadrangle_2D::myHelper = 0; - + return ok; } @@ -1200,37 +1395,49 @@ bool StdMeshers_QuadFromMedialAxis_1D2D::Compute(SMESH_Mesh& theMesh, TopoDS_Face F = TopoDS::Face( theShape ); if ( F.Orientation() >= TopAbs_INTERNAL ) F.Orientation( TopAbs_FORWARD ); - list< TopoDS_Edge > edges; - list< int > nbEdgesInWire; - int nbWire = SMESH_Block::GetOrderedEdges (F, edges, nbEdgesInWire); + SinuousFace sinuFace( F ); + + _progress = 0.01; - vector< TopoDS_Edge > sinuSide[2], shortSide[2]; - if ( nbWire == 1 && getSinuousEdges( helper, F, edges, sinuSide, shortSide )) + if ( getSinuousEdges( helper, sinuFace )) { - vector< TopoDS_Edge > sinuEdges = sinuSide[0]; - sinuEdges.insert( sinuEdges.end(), sinuSide[1].begin(), sinuSide[1].end() ); - if ( sinuEdges.size() > 2 ) - return error(COMPERR_BAD_SHAPE, "Not yet supported case" ); + _progress = 0.2; - double minSegLen = getMinSegLen( helper, sinuEdges ); - SMESH_MAT2d::MedialAxis ma( F, sinuEdges, minSegLen, /*ignoreCorners=*/true ); + // if ( sinuFace._sinuEdges.size() > 2 ) + // return error(COMPERR_BAD_SHAPE, "Not yet supported case" ); + + double minSegLen = getMinSegLen( helper, sinuFace._sinuEdges ); + SMESH_MAT2d::MedialAxis ma( F, sinuFace._sinuEdges, minSegLen, /*ignoreCorners=*/true ); if ( !_regular1D ) _regular1D = new Algo1D( _studyId, _gen ); _regular1D->SetSegmentLength( minSegLen ); vector maParams; - if ( ! divideMA( helper, ma, sinuEdges, sinuSide[0].size(), _regular1D, maParams )) + if ( ! divideMA( helper, ma, sinuFace, _regular1D, maParams )) return error(COMPERR_BAD_SHAPE); - if ( !computeShortEdges( helper, shortSide[0], _regular1D ) || - !computeShortEdges( helper, shortSide[1], _regular1D )) + _progress = 0.4; + + if ( !computeShortEdges( helper, sinuFace._shortSide[0], _regular1D ) || + !computeShortEdges( helper, sinuFace._shortSide[1], _regular1D )) return error("Failed to mesh short edges"); - if ( !computeSinuEdges( helper, ma, maParams, sinuEdges, sinuSide[0].size() )) + _progress = 0.6; + + if ( !computeSinuEdges( helper, minSegLen, ma, maParams, sinuFace )) return error("Failed to mesh sinuous edges"); - return computeQuads( helper, F, sinuSide, shortSide ); + _progress = 0.8; + + bool ok = computeQuads( helper, F, sinuFace._sinuSide, sinuFace._shortSide ); + + if ( ok ) + mergeNodes( helper, sinuFace ); + + _progress = 1.; + + return ok; } return error(COMPERR_BAD_SHAPE, "Not implemented so far"); diff --git a/src/StdMeshersGUI/StdMeshersGUI_DistrPreview.cxx b/src/StdMeshersGUI/StdMeshersGUI_DistrPreview.cxx index 90005331a..0d567e4fb 100644 --- a/src/StdMeshersGUI/StdMeshersGUI_DistrPreview.cxx +++ b/src/StdMeshersGUI/StdMeshersGUI_DistrPreview.cxx @@ -106,7 +106,7 @@ StdMeshersGUI_DistrPreview::StdMeshersGUI_DistrPreview( QWidget* p, StdMeshers:: myDistr->attach( this ); QPen distrPen = QPen( Qt::blue, 1 ); QwtSymbol* distrSymbol = new QwtSymbol( QwtSymbol::XCross, QBrush( Qt::blue ), - QPen( Qt::blue ), QSize( 5, 5 ) ); + QPen( Qt::blue ), QSize( 5, 5 ) ); myDistr->setPen( distrPen ); myDistr->setSymbol( distrSymbol ); if( Plot2d_QwtLegendLabel* anItem = getLegendLabel( myDistr ) ) { diff --git a/src/StdMeshersGUI/StdMeshersGUI_ObjectReferenceParamWdg.h b/src/StdMeshersGUI/StdMeshersGUI_ObjectReferenceParamWdg.h index 63eb5de65..03706a8fe 100644 --- a/src/StdMeshersGUI/StdMeshersGUI_ObjectReferenceParamWdg.h +++ b/src/StdMeshersGUI/StdMeshersGUI_ObjectReferenceParamWdg.h @@ -57,7 +57,7 @@ public: StdMeshersGUI_ObjectReferenceParamWdg( SUIT_SelectionFilter* filter, QWidget* parent, bool multiSelection=false - /* ,bool stretch=true*/); + /* ,bool stretch=true*/); StdMeshersGUI_ObjectReferenceParamWdg( SMESH::MeshObjectType objType, QWidget* parent, bool multiSelection=false); -- 2.30.2