From e7e45ad8cb4d23a1709cccd4f6c6858e7409ee8a Mon Sep 17 00:00:00 2001 From: eap Date: Thu, 22 Jan 2009 13:43:10 +0000 Subject: [PATCH] Merge from BR_V5_IMP_P8 --- doc/salome/gui/SMESH/images/a-maxsize1d.png | Bin 0 -> 11689 bytes doc/salome/gui/SMESH/images/cutgroups.png | Bin 12582 -> 16273 bytes doc/salome/gui/SMESH/images/dimgroup_0d.png | Bin 0 -> 2680 bytes doc/salome/gui/SMESH/images/dimgroup_1d.png | Bin 0 -> 2394 bytes doc/salome/gui/SMESH/images/dimgroup_2d.png | Bin 0 -> 8089 bytes doc/salome/gui/SMESH/images/dimgroup_dlg.png | Bin 0 -> 18647 bytes doc/salome/gui/SMESH/images/dimgroup_src.png | Bin 0 -> 23123 bytes doc/salome/gui/SMESH/images/dimgroup_tui1.png | Bin 0 -> 31664 bytes doc/salome/gui/SMESH/images/dimgroup_tui2.png | Bin 0 -> 8678 bytes doc/salome/gui/SMESH/images/extrusion1.png | Bin 32820 -> 21458 bytes doc/salome/gui/SMESH/images/extrusion2.png | Bin 32997 -> 21556 bytes .../gui/SMESH/images/extrusionalongaline1.png | Bin 20814 -> 14477 bytes .../gui/SMESH/images/extrusionalongaline2.png | Bin 20997 -> 14477 bytes doc/salome/gui/SMESH/images/free_faces.png | Bin 0 -> 16147 bytes doc/salome/gui/SMESH/images/free_nodes.png | Bin 0 -> 8524 bytes .../gui/SMESH/images/intersectgroups.png | Bin 12920 -> 14614 bytes .../gui/SMESH/images/mesh_precompute.png | Bin 0 -> 1145 bytes .../gui/SMESH/images/preview_mesh_1D.png | Bin 0 -> 8824 bytes .../gui/SMESH/images/preview_mesh_2D.png | Bin 0 -> 29776 bytes .../gui/SMESH/images/preview_tmp_data.png | Bin 0 -> 5352 bytes .../gui/SMESH/images/removeelements.png | Bin 11456 -> 8235 bytes doc/salome/gui/SMESH/images/removenodes.png | Bin 11166 -> 7986 bytes doc/salome/gui/SMESH/images/revolution1.png | Bin 33178 -> 19489 bytes doc/salome/gui/SMESH/images/revolution2.png | Bin 33226 -> 19487 bytes doc/salome/gui/SMESH/images/rotation.png | Bin 31432 -> 17643 bytes doc/salome/gui/SMESH/images/smoothing.png | Bin 22675 -> 14129 bytes doc/salome/gui/SMESH/images/symmetry1.png | Bin 25972 -> 15073 bytes doc/salome/gui/SMESH/images/symmetry2.png | Bin 30446 -> 17111 bytes doc/salome/gui/SMESH/images/symmetry3.png | Bin 30359 -> 17096 bytes doc/salome/gui/SMESH/images/translation1.png | Bin 26419 -> 16412 bytes doc/salome/gui/SMESH/images/translation2.png | Bin 23982 -> 13573 bytes doc/salome/gui/SMESH/images/uniongroups.png | Bin 12648 -> 13153 bytes .../gui/SMESH/input/1d_meshing_hypo.doc | 16 + doc/salome/gui/SMESH/input/about_hypo.doc | 1 + .../SMESH/input/about_quality_controls.doc | 10 +- .../gui/SMESH/input/creating_groups.doc | 54 + doc/salome/gui/SMESH/input/editing_groups.doc | 16 +- doc/salome/gui/SMESH/input/extrusion.doc | 1 + doc/salome/gui/SMESH/input/free_faces.doc | 17 + doc/salome/gui/SMESH/input/free_nodes.doc | 16 + doc/salome/gui/SMESH/input/index.doc | 2 +- doc/salome/gui/SMESH/input/preview_meshes.doc | 36 + .../gui/SMESH/input/tui_grouping_elements.doc | 77 +- .../gui/SMESH/input/tui_quality_controls.doc | 136 +- .../input/using_operations_on_groups.doc | 30 +- idl/Makefile.am | 3 +- idl/SMESH_BasicHypothesis.idl | 38 + idl/SMESH_Filter.idl | 53 +- idl/SMESH_Gen.idl | 38 +- idl/SMESH_Mesh.idl | 74 +- idl/SMESH_MeshEditor.idl | 45 +- resources/Makefile.am | 7 +- resources/SalomeApp.xml | 13 +- resources/StdMeshers.xml | 13 +- resources/mesh_extractGroup.png | Bin 0 -> 588 bytes resources/mesh_free_faces.png | Bin 0 -> 1084 bytes resources/mesh_free_nodes.png | Bin 0 -> 770 bytes resources/mesh_precompute.png | Bin 0 -> 1145 bytes src/Controls/Makefile.am | 6 +- src/Controls/SMESH_Controls.cxx | 303 ++++ src/Controls/SMESH_ControlsDef.hxx | 94 + src/OBJECT/SMESH_Actor.cxx | 118 +- src/OBJECT/SMESH_Actor.h | 9 +- src/OBJECT/SMESH_ActorDef.h | 7 +- src/OBJECT/SMESH_DeviceActor.cxx | 20 +- src/SMDS/SMDSAbs_ElementType.hxx | 20 + src/SMESH/SMESH_Algo.cxx | 78 +- src/SMESH/SMESH_Algo.hxx | 23 +- src/SMESH/SMESH_Gen.cxx | 127 +- src/SMESH/SMESH_Gen.hxx | 37 +- src/SMESH/SMESH_Hypothesis.hxx | 22 +- src/SMESH/SMESH_Mesh.cxx | 97 +- src/SMESH/SMESH_Mesh.hxx | 17 +- src/SMESH/SMESH_MeshEditor.cxx | 150 +- src/SMESH/SMESH_MeshEditor.hxx | 21 + src/SMESHGUI/SMESHGUI.cxx | 207 ++- src/SMESHGUI/SMESHGUI.h | 3 + src/SMESHGUI/SMESHGUI_ComputeDlg.cxx | 711 ++++++-- src/SMESHGUI/SMESHGUI_ComputeDlg.h | 128 +- .../SMESHGUI_ExtrusionAlongPathDlg.cxx | 50 +- src/SMESHGUI/SMESHGUI_ExtrusionAlongPathDlg.h | 4 + src/SMESHGUI/SMESHGUI_ExtrusionDlg.cxx | 173 +- src/SMESHGUI/SMESHGUI_ExtrusionDlg.h | 14 +- src/SMESHGUI/SMESHGUI_Filter.cxx | 28 +- src/SMESHGUI/SMESHGUI_FilterDlg.cxx | 279 ++- src/SMESHGUI/SMESHGUI_GroupDlg.cxx | 101 +- src/SMESHGUI/SMESHGUI_GroupDlg.h | 6 +- src/SMESHGUI/SMESHGUI_GroupOpDlg.cxx | 985 ++++++++--- src/SMESHGUI/SMESHGUI_GroupOpDlg.h | 167 +- src/SMESHGUI/SMESHGUI_Hypotheses.cxx | 35 +- src/SMESHGUI/SMESHGUI_Hypotheses.h | 5 +- src/SMESHGUI/SMESHGUI_MeshOp.cxx | 55 +- .../SMESHGUI_Preferences_ScalarBarDlg.cxx | 4 +- src/SMESHGUI/SMESHGUI_RemoveElementsDlg.cxx | 31 +- src/SMESHGUI/SMESHGUI_RemoveElementsDlg.h | 4 + src/SMESHGUI/SMESHGUI_RemoveNodesDlg.cxx | 34 +- src/SMESHGUI/SMESHGUI_RemoveNodesDlg.h | 4 + src/SMESHGUI/SMESHGUI_RevolutionDlg.cxx | 167 +- src/SMESHGUI/SMESHGUI_RevolutionDlg.h | 16 + src/SMESHGUI/SMESHGUI_RotationDlg.cxx | 35 +- src/SMESHGUI/SMESHGUI_RotationDlg.h | 4 + src/SMESHGUI/SMESHGUI_Selection.cxx | 26 + src/SMESHGUI/SMESHGUI_Selection.h | 1 + src/SMESHGUI/SMESHGUI_SmoothingDlg.cxx | 100 +- src/SMESHGUI/SMESHGUI_SmoothingDlg.h | 8 +- src/SMESHGUI/SMESHGUI_SymmetryDlg.cxx | 34 +- src/SMESHGUI/SMESHGUI_SymmetryDlg.h | 6 +- src/SMESHGUI/SMESHGUI_TranslationDlg.cxx | 35 +- src/SMESHGUI/SMESHGUI_TranslationDlg.h | 4 + src/SMESHGUI/SMESHGUI_Utils.cxx | 46 +- src/SMESHGUI/SMESHGUI_Utils.h | 14 + src/SMESHGUI/SMESH_images.ts | 18 +- src/SMESHGUI/SMESH_msg_en.ts | 267 ++- src/SMESH_I/Makefile.am | 2 +- src/SMESH_I/SMESH_2smeshpy.cxx | 331 +++- src/SMESH_I/SMESH_2smeshpy.hxx | 64 +- src/SMESH_I/SMESH_DumpPython.cxx | 17 +- src/SMESH_I/SMESH_Filter_i.cxx | 235 ++- src/SMESH_I/SMESH_Filter_i.hxx | 87 + src/SMESH_I/SMESH_Gen_i.cxx | 321 +++- src/SMESH_I/SMESH_Gen_i.hxx | 25 +- src/SMESH_I/SMESH_Group_i.cxx | 25 +- src/SMESH_I/SMESH_MeshEditor_i.cxx | 143 +- src/SMESH_I/SMESH_MeshEditor_i.hxx | 12 +- src/SMESH_I/SMESH_Mesh_i.cxx | 600 ++++++- src/SMESH_I/SMESH_Mesh_i.hxx | 33 +- src/SMESH_I/SMESH_PythonDump.hxx | 11 +- src/SMESH_SWIG/Makefile.am | 3 +- src/SMESH_SWIG/ex30_groupsOp.py | 73 + src/SMESH_SWIG/ex31_dimGroup.py | 47 + src/SMESH_SWIG/smeshDC.py | 168 +- src/StdMeshers/Makefile.am | 8 +- src/StdMeshers/StdMeshers_Arithmetic1D.cxx | 15 +- src/StdMeshers/StdMeshers_Arithmetic1D.hxx | 7 +- src/StdMeshers/StdMeshers_AutomaticLength.cxx | 35 +- src/StdMeshers/StdMeshers_AutomaticLength.hxx | 9 +- .../StdMeshers_CompositeHexa_3D.cxx | 1526 +++++++++++++++++ .../StdMeshers_CompositeHexa_3D.hxx | 61 + src/StdMeshers/StdMeshers_Deflection1D.cxx | 14 +- src/StdMeshers/StdMeshers_Deflection1D.hxx | 10 +- src/StdMeshers/StdMeshers_Hexa_3D.cxx | 15 +- .../StdMeshers_LayerDistribution.cxx | 13 +- .../StdMeshers_LayerDistribution.hxx | 7 +- src/StdMeshers/StdMeshers_LengthFromEdges.cxx | 13 +- src/StdMeshers/StdMeshers_LengthFromEdges.hxx | 8 +- src/StdMeshers/StdMeshers_LocalLength.cxx | 15 +- src/StdMeshers/StdMeshers_LocalLength.hxx | 8 +- src/StdMeshers/StdMeshers_MaxElementArea.cxx | 15 +- src/StdMeshers/StdMeshers_MaxElementArea.hxx | 7 +- .../StdMeshers_MaxElementVolume.cxx | 14 +- .../StdMeshers_MaxElementVolume.hxx | 9 +- src/StdMeshers/StdMeshers_MaxLength.cxx | 242 +++ src/StdMeshers/StdMeshers_MaxLength.hxx | 71 + .../StdMeshers_NotConformAllowed.cxx | 16 +- .../StdMeshers_NotConformAllowed.hxx | 7 +- src/StdMeshers/StdMeshers_NumberOfLayers.cxx | 16 +- src/StdMeshers/StdMeshers_NumberOfLayers.hxx | 7 +- .../StdMeshers_NumberOfSegments.cxx | 16 +- .../StdMeshers_NumberOfSegments.hxx | 7 +- .../StdMeshers_ProjectionSource1D.cxx | 14 +- .../StdMeshers_ProjectionSource1D.hxx | 7 +- .../StdMeshers_ProjectionSource2D.cxx | 17 +- .../StdMeshers_ProjectionSource2D.hxx | 9 +- .../StdMeshers_ProjectionSource3D.cxx | 17 +- .../StdMeshers_ProjectionSource3D.hxx | 9 +- src/StdMeshers/StdMeshers_Propagation.cxx | 4 +- src/StdMeshers/StdMeshers_Propagation.hxx | 10 +- .../StdMeshers_QuadranglePreference.cxx | 17 +- .../StdMeshers_QuadranglePreference.hxx | 9 +- src/StdMeshers/StdMeshers_QuadraticMesh.cxx | 17 +- src/StdMeshers/StdMeshers_QuadraticMesh.hxx | 9 +- src/StdMeshers/StdMeshers_Regular_1D.cxx | 58 +- src/StdMeshers/StdMeshers_Regular_1D.hxx | 8 +- .../StdMeshers_SegmentLengthAroundVertex.cxx | 17 +- .../StdMeshers_SegmentLengthAroundVertex.hxx | 9 +- src/StdMeshers/StdMeshers_StartEndLength.cxx | 17 +- src/StdMeshers/StdMeshers_StartEndLength.hxx | 9 +- .../StdMeshers_TrianglePreference.cxx | 17 +- .../StdMeshers_TrianglePreference.hxx | 9 +- .../StdMeshersGUI_StdHypothesisCreator.cxx | 77 +- .../StdMeshersGUI_StdHypothesisCreator.h | 2 + src/StdMeshersGUI/StdMeshers_images.ts | 8 + src/StdMeshersGUI/StdMeshers_msg_en.ts | 12 + src/StdMeshers_I/Makefile.am | 7 +- src/StdMeshers_I/StdMeshers_MaxLength_i.cxx | 204 +++ src/StdMeshers_I/StdMeshers_MaxLength_i.hxx | 84 + src/StdMeshers_I/StdMeshers_i.cxx | 6 +- 187 files changed, 9629 insertions(+), 1096 deletions(-) create mode 100644 doc/salome/gui/SMESH/images/a-maxsize1d.png create mode 100644 doc/salome/gui/SMESH/images/dimgroup_0d.png create mode 100644 doc/salome/gui/SMESH/images/dimgroup_1d.png create mode 100644 doc/salome/gui/SMESH/images/dimgroup_2d.png create mode 100644 doc/salome/gui/SMESH/images/dimgroup_dlg.png create mode 100644 doc/salome/gui/SMESH/images/dimgroup_src.png create mode 100644 doc/salome/gui/SMESH/images/dimgroup_tui1.png create mode 100644 doc/salome/gui/SMESH/images/dimgroup_tui2.png create mode 100644 doc/salome/gui/SMESH/images/free_faces.png create mode 100644 doc/salome/gui/SMESH/images/free_nodes.png create mode 100644 doc/salome/gui/SMESH/images/mesh_precompute.png create mode 100644 doc/salome/gui/SMESH/images/preview_mesh_1D.png create mode 100644 doc/salome/gui/SMESH/images/preview_mesh_2D.png create mode 100644 doc/salome/gui/SMESH/images/preview_tmp_data.png create mode 100644 doc/salome/gui/SMESH/input/free_faces.doc create mode 100644 doc/salome/gui/SMESH/input/free_nodes.doc create mode 100644 doc/salome/gui/SMESH/input/preview_meshes.doc create mode 100755 resources/mesh_extractGroup.png create mode 100644 resources/mesh_free_faces.png create mode 100644 resources/mesh_free_nodes.png create mode 100644 resources/mesh_precompute.png create mode 100755 src/SMESH_SWIG/ex30_groupsOp.py create mode 100755 src/SMESH_SWIG/ex31_dimGroup.py create mode 100644 src/StdMeshers/StdMeshers_CompositeHexa_3D.cxx create mode 100644 src/StdMeshers/StdMeshers_CompositeHexa_3D.hxx create mode 100644 src/StdMeshers/StdMeshers_MaxLength.cxx create mode 100644 src/StdMeshers/StdMeshers_MaxLength.hxx create mode 100644 src/StdMeshers_I/StdMeshers_MaxLength_i.cxx create mode 100644 src/StdMeshers_I/StdMeshers_MaxLength_i.hxx diff --git a/doc/salome/gui/SMESH/images/a-maxsize1d.png b/doc/salome/gui/SMESH/images/a-maxsize1d.png new file mode 100644 index 0000000000000000000000000000000000000000..c2ddd0c37b31f409bb10dcfe2a1c94bb9527fe8f GIT binary patch literal 11689 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 IejN0_0GQDXkpKVy literal 12582 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 bLFt<2SWQA{VEN251=95p?O>g=f7-tRzwi4~ literal 0 HcmV?d00001 diff --git a/doc/salome/gui/SMESH/images/dimgroup_1d.png b/doc/salome/gui/SMESH/images/dimgroup_1d.png new file mode 100644 index 0000000000000000000000000000000000000000..23af4a75d08b829302be90d99e32f796cedf4953 GIT binary patch literal 2394 zcma);Yf#eL8pi*iuu(Bhw+Kq6;3X}@=(5dAA}UDUEiXwL7@lmW8R{vcQc^90Hg&2s}&XGnVu6i2ucdHVg(Ckb#S9}|(XU3Z*f2sKf=4}75^Ee1NSfT=( zuU0~cTYGdk$F3Ly^WJ!X+NsZ=mX$vPZ5>xbQ-2D2Pz@E9{sdG#&t=00u^Lr#cfNt?lGkOQ-#^;zv;b&+ z{wPV1&e4b|LvGh6%HpJpHm<+$PgNF?zGU|1FI}z#ajqZOsqxB+WHz+9b1GTEUU;oy z65}og8JMh$aQlIGSq%)(KP5i3UwQe{0V>q6tG9otaW4e((bJ&sm7HxZ15&V4UG`%k z?ruYt*_JyLY_e7c;F7M%$JCj1IB@Q_9Dp6}N?qg^g;7E~!t0~tGP;u<+R#Yn&tC{| z>rdC#M@|0=)3bjezN~(?WA})W02ER9r?JWb`7opHIJY;Si6jOhViFp>4z9&>ca_Gi zs>p2ib0MQ`>g-Q5fbBce20I>ebtFG(GHN&FnL$}cntdld+)CPx^Rirul*p?-;%QO; zgK9j-I}Y~pn`HV>wkShIiiKch=Gu?=q8nA|v!G_fdtp9Zp$In8#X{<|GJ@La5H6eC zvqk3`;h4}N+a}&3jb3fHdhN6V9m@0wzZi*ukL$9mZ@trz`#ki@LCV4t@)1oGw78GHivelHp)DOBY9!^k#dO0~ z7@h1xlcPO40@cG68%r-pe%){eOG&)><%9O!NV1LsFocjsEm&Z5q!gGzjPtc$D7H8E?pWKACTsu8+uB$C@6236d$x*44b z?Wpc{toj)8E^tf^D2$L4#Vxl>;7sT>i@zMVu@y$|TsIQequPV+>D;t_TL#+JwJFaa z^7ojA6}o}pMJ(Y6rm-V2mh)*OzkIm(WzcsIjg2dhpifFgGnmyTrG+JL*9=>Iq;#w0 zU*pjy?;%qW({dob4MlOc&-glmHYsg@y^WoR9Q5USXozsDC=cnO1UM|Z(~$rq6)=eU z1?_@oVJF}k=_Q-<;8G_hQoohUVh)60WgK%}9ya5qH43V^J{FB)6?Qt9XZ5!W-h^IK zmy20w)c(j0wM2U;IMJK4ED`d$YpyO68d%KqJJxDKULN+g4hrg7lZHMM@jZYCa-Tv` z#*ESg>f~GP0&1Jya`|l*ll)PrCd_Tk^R*e`tIgf*f(F&&TQ7|Dd&b>a37pZ?@uKY3 zC^k}b-d)Arm`2gl7~9@3#M<*kz-ZDWM0O3}h)wG3%|`EZ5kd9hn-;7#sUmsOG98^3`aN0W4;i(!}IU>2(r&Sr?KZ5@{) zl~MCb#>OjgcWk6pd`7Z)T`8eaNE2t4IllPr_qEDfuN)qeV{;`el8`ImB1G|__U#RO zs{8b7^JiYj@K(8fLfneeQSsrH27Ebqh3Nc|M~kS(7Vk_3tF2sfLxi{k7^z7C!xvk} zvADr96Pq4p)ge8;M)z-a&26-$!L6lpBpyp32P57~KI~gKx%=6ClPGBKRSh2?@d_aKOZehJrt4+T7XUYr7CZRJ^}{aYqYRdY|oF z5xx6~#pkVlfAmPjzItnk3XG|;&5s#QCg}|4|D(TB5|-*c`4pCn=gDO)!S&Zj?De_u z9FJJgc|mMI;i%K$ZOP+rV1qffDp98pS5*+@YbhfeMgV(G4#u`gs_wQ71uS1-rRx-; z3lT}h7oBE|!*HB6=~MSHyJR}bYwFAmAFS80VA`Yb(bwiaA!r(?x_tdgP_44<;NusC!6Jo?LPyhe` literal 0 HcmV?d00001 diff --git a/doc/salome/gui/SMESH/images/dimgroup_2d.png b/doc/salome/gui/SMESH/images/dimgroup_2d.png new file mode 100644 index 0000000000000000000000000000000000000000..6ca49a6a9157d1e18176b2408877be28708ed9a8 GIT binary patch literal 8089 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 z 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

T0$r&v)k^e~x!Q+=CuatomH;=qws>J<(PwoVOz& zn@{y0oYj`v&$p-QFCMEWJ0*q27SInso%Zi-rO4d)}NBtZ0A^g!{8j3_C;|&@4d}qmY=##N0;lVj1bM;)LF3L z=$b*l<+s|6(-f%nfyQ3!ctWXNxbLXHpfeerU7J$AD!H)}Stb7+z5JI9ZN*=@sBgRz zhh-xOy#JXJ(yvfc{?TdvF?*o3=;_MDc^~9aw~O*cg+`7=wt98%gm=t8Z@haDWm{J+ zAD&0G`)%NLRWG-lgl&?hOX<2E|-gLESY1vU|D*q$Od%mVf`(@m1 zuZPBmo5XSt+PIasDfQn}fFX0!bNmlWmFja{FlwC@GRpjM&qKjy&T&{3^6?IzB(xqc zbywtxsXYlHiWkn$Cx6`--bVBkXGjYvFFTa+7~%(EUSA+*4fZ= z1Up3?rH5$!VFiszwemgw+*qgUGIs7goQX61@ufOMr=VIZsULT%{Vv6obu*i8cWp|x zRi3&z{AT5tz2Q;olvSUgkp88>3C@ZbU0D$?WuzODWImQqC3Yw6v5Mj(XXQ zRw5DXY8;7hVmG3HvC!rgKh>jB>u;7}&vEb1t1V%DTwpzL@^`a=@MVb4n^s0^(8DoB z_ouoi$a-!VJ!{wC&K0>&HHY=3VcP7|cLHOKQurR{`0Hxv}};gfN~Hu(Tl6pVpdjt2+VT9k#IoYiAqe2xn+5uy8d(S#C_(#{)|G&!Tdwo<4zH zZy>p~zj-xYbbXdx#>F7^ucE%>v3hZh&f&#dpa8?VIGlEDjiiYAAkR3i8K>BmNqar{ z4vzbZx5Xj|_an03?n-xR8PGj-@Sl3kgDK0qky_zN74ly0qEojcw(d_#pJdB-#Ojl< zC_A(wBw?gXPqJH;5NMk|_!_IZc6M%tmE5}YDEv7_ahj--L~fm3+!+xz$>zShwcGuii4NCe zjnc_*(O0Bl`K^j8bzctnF)0iAGS7J{o9MXgS{ZE9E-aCtd#_e`F65|ln=_b7vnYnh zH{qd;jOEc?SkaNh6I644Sb z7!6;9zj1OmL^{H0{QMc0i5vguE;)T+ZLmpQxJX zTl6T{Y;K7458I`m&v^!dU1Kglz+mgX9Or{j7U+22XP*UojAPrWn z37BX$G7f9+_pVt{RgLHCT;Z5~!gI`}wX-HD1&;ER&Xn^r6CZ-@udnjumK&4&EW(~m zrWIZh>k3XI@Naq_AGme8mTIuxF4@OwK+v$Lm+?x3Ob)S7@_DzfbFQt@t_072hQz>^ z{FbN7jsi7T`C0Qa3KBJNWG9!`w^#GW55u<)=@|&&-H!D@qiKV45 zb0-I|>oexr83kKeO=_9+9GdJWP-0o5s?9F$t-000ss+_+Hb9W;Re!}xAf6(EC<0uy~AqRki|J6A~^E)y+q%^*Jf>79y{A; zw`COx9VXwZoSCTC0Nl~%)pm~2yNPzmteJxXnq|%mLH2)jxKnN8L}?C>jL3d+-cAsg zR%eAsToeTLDJn2df@|=k<0ywu@XKdxCeH+Ch-gtSm61F|Un3<&FrbI?`xpPKhgk;~ zM#?$22W3!SB>tmUfh7Lp66FRA-{!vST&yq|Kt_f(CWMf%o0gZ!^fHE`g!` zMU?~@b736hHrnbci8a4A;)7uG%c&N_jhB3C7uHq%Lpi^zj4Nf&5>wp~1 z!RZIvSXx<)hz(@h)A#A%@w-+feI5%O+GPcK$%|dVV2K~nb6X3SuR?Jw(yjCFQkg!O z{E4>!i%KZKHr2b@A?3WsI2BjmT0&x@spQ`HPDV>mff}cu6AqA9c#Guo>UPMGq2t=y z+8g~nV%~!~$>k>)I8Hol?i@T`Gw$hFc_ugPGb7=h=t~fv8C`K$z$c^y;IUt< zysZz+Han$%9DYmftFR#X=Xm36g9QQNU@+L1Ij-?vL;1so+x$)D@niAra$mq zgDy9J1BWjBUDir~KE{--C^*!KU>BLvAX`7poUYxV`Onm2Y1J!l6_W`9p~)#cZePg~ zDVveD9Jt#bXxRbX-7~iOMIZA-P6wC~Hn1 zhD$vdS!l(Kp1=27=wx{Q1JWT$QH$kRW)Ms#76~CQ=SIkU+PW8{K5G5=pUWaQ{*59v z_-G>{RGlZrLbE07M^g0{h>FtZOvb+_4^-Q32aso}^Ps3A{v_dyNb0Cm zeARlQghCTJ+79QF*}~nzFP1v8(0T3Q+Z}Ac_}QkqwQEBytNGl1t{_kz^6x;uRDV@C zwF>7dt)9`L&WAd&JQ0$EWyAG~#hUey6dvCAGn?uhcfXt4OHu!w69$>Ts)G|`{#$U| zt?+oV(mqWWvn605Op4TQVJ)iO*+gCKgwZPGe8w|KHD)0_$li%5={VVnA%-%`3d0U* zI>d$WT|O?8bS0jMg&pa*FrUl+Rh2t+QfY5_w1dVaFevEvtvq==yFR^kJTMmL|V zg}dHQI;NE>(S-I80z(D(;okI7rj-_8U)xO7Qj7UD{n zO%9VcW&TGfI(~)Z?R|(!?bM*6cv%HULuCo16$?UO-`8J;W3FO311mLt?;8n9w9&tm z^`Rix+gg8|!QHCrIu(x-();{i!)b!>!B{2-*;SkH$6em{k5nsK=;-zb3+^Va0e#r$ z=j4F#R8b5K8N`!nwq+tX6^7Zbu~Z|F+StR|;~*gO>K|P+NA`3DXLq#Np7h}n$Q>9M zS{PK1A&2*Gg?3Cze;l)a*>)M=nuw$MAz6<-)iIEy8&;8HE7-Idc-#3{;q~7S9)(+t zF22bcjQ#+jmQ-3!Spz`Z-I9Oy1W<676NZV_+SY=^XvU2VX9tWI-v1(2 z-=yhn)$vJDzffSGC;NncX@>fZWk<0t1CljZ`%Q-Gp6yb!KGj?nT@n3-cvk!K6X_NT zO+7CsliSZ^G>deo_lNnzYx5yU-@?5zsb^7^uglXj?Za@0jGp27&YH#0iEN;1rS{j}$zCS+3&|zOrxHDSRd$k1d?85%125b#So9 zXt~LMq1X^@bOUK4%bTlEg0e&-;vt>~|3ysi#IN`F$)LvZmP6g4-g#*Y3MiSiN&{XV zevh1Df=io~Q~q`B?$MVS?3Nc?$Y>YnV9ay{lfeX7{)BT4J*&Qh$u{IgDN7_8-fy`= zf2!Y5*UX4jJb_3dF9IT5O6{Gp@7kg8Gk9UgC*;35Rl&A0zcIGPftySfiE@cSXbICcThDtxJs}k?=F3y88F9)x0#H&c z>7EMvdV`vw80L4h3k8j5Wv{z4y`jCURqLc`vh>~Cl!ZlKZ{1@KF8ACOV*(gN!A2<* zg7rHGvY@U_vf}I4&u)-NCmjtJCqxJdK=5Dc?+H#5FGVhUa4?N~e{8OgmvB~1S5SXA z?lissI&{ro$)M&*0vWsy{T&t;oC_0eLBR4(d_;fK5B;+`X0;ixB)xN|`+Tz}_xg$9 z*U`0P83cv>-$0u7>eHb7foF6fdYBwRVo_Q{d~<9>Kf6TOxWT0{i{^?W;`hHj}lQ%u0YG;Ll_MBMImi- z2$Su3#^$*Rx%pY5;)Qpg{42~YpPY?KAB>d63(!HEd#gd&$F%YCgbRXGc`eZ4^<5$= zLj*p%ugVL;@@ZN8LfbbaOK<<<4qb5*AAxzD^=p@?1$?L1@Y+2^ULW0GgIJR_b+(}y zqB!`LF^tPuE095)K6U%IxQxU4$%-B2U-D_J5ZL)nv|1$YmP>IWJHq!kVVN|N>=~>| zKNrR{e^>#6l=Lvu)iH%Ud1ysR7(&Pqq5fY;So8SU{m43irl1)YpkFg&ejLfl=l1y8q@j!`4UhR0FS@K6$7Ej_86U2*4rtW=0 zC$JHNinz7QSb?;z z`xbyfNOinK_@;6zBYO_42{~VyZEHW+`elYl<<_9Yzv-GIp&TbJ{xb}IybC$%}6 z+?-fjnHMw#5=^~r%}^Ou7(#B4Cy*xeH+oA_Rc!4Q4Uajj1K>HAI-Vi7U*R4i38j2EBt1=#Sa{1wdW^Jzp68_9Qeu_NUyUu@k^0?foB4 zleI?KMF1#!Yul}*b)jaJ`4gs0KF}7;A4KDhNSz>~Pa(Y+{~3iMKnW1!wtB^BgBpAL zlBX*ajcSH2V?rRPL$eQ`l8yiuV~p9Sm1F|BVwK(KnT9gOQ-zuhPYG$&0e5+h@OL?1 zqKqI|w2k4YRO2luenq`sJz+kp!@5ncX2=iggi=8AA2gL(2X&n$^4fek7+|bHH$bwC zZbc$M%th*V6j63H;`l)Xz^3hs z=KW^;Cx)3#n07LB$^q#s7*HTP+olVYL4oI!8*b`xJ0_Cj1;4+N)N3dr34=hC@Eq6? z$pnHD&VKP{=}g3XvPr)gJjJ~#ptAtMO584Jk(D@MDvw2^lb~$tbfWp>S_x;DLxSju zVfpH3N#x#)_3KF1%KAVt2POgDHdT@eCP?G)?o}L}Aq&K?LiAs5+z7ggRzB+CTcGWB zP3Bw$CGQa{vk&V8iB;Kzf&gXVCckn<7B8nEOAuf{CEL)l-f~(%0|Rlz8RAeoRjUoX ze(_y;Ep%45#zrQwmJCKk?&J=X{i;(twK0a?>xhqNT zRTQ3nNYfo#zJ8inzGRnk0yaO9Oka7c3CArFML;i=v7n9f{-1O7|DB$hIdX$`ZWtR# zQ$0ZmjN1t)mO>Fg@UsDL+%2m9Q~2KqD}jELl?GM9t_l_KEC5GJ7Z_Ej@cB<@jIlO4 z-I^Y0vS#*PM2k=`TeQ_AqZtPd!5EfbfjAC9n&4(M1>hmTPBTNLfFEe#`;4S3qGpkx zLp)$5G7O@*4WT9Hn?2q^83aInro#_6BBRk zN2vq@01;gQ!A{r>8cfYAsm?S}0u6fat6*qh`>kz(xctLiXkb#Z;rn-zz}L%kg@H^A z7|-yE06a^w&7fEmVBj+egP+$OJ8!&^g87oC7(s(~09Dij>Oc^2WQc|ru%btyYCzI@s~C$2tOUBWudM$D z58(yS^Su}lil=MBvw)i6hrk7jVfeonAn7D*Gjt%`L~9u=6v%Jp#3KNJ26V8vZWb=u zh)@8s5$AyHi3cYMF9=GHOk|-iJ2a@P8hb5&Qe&?20i2)-25hGG2?jFzH~&9BRK^~6 ZSOz#)N^M>boD$7uYIwz*wj4gi4l4f8f9z{Y%{z3u3V z`SsXM#lREu_u2p6SPEQuegMEzfGYTvo?rfc=S>TA4!fW`)}ZyLz-N_gwc&F+ z&Guid!YMkKa0vH*u|(p6i9dl`Ii49m!Hy2>fus?Tw>~=ZnpNm1<_jmZrvkT2SWdbW zXFN?*NxmoTVqH0m_OJ3ab$nafq_`9)%dY4+mh1VuW}(JT<}ir=k>3B`KM2LIL?TRo z&rPi&2SNioY2P4mQe1VkI#zrIlGkMXVUGGzNK$83m|bk)Ym%zardgtgiM`G+Lj1^8 zEW_3htV<50&`mtRu6&c0xEuh;vu{wcCSx@Eackce5`!3|kRc7rReY^AoDl6j?xgff zZqlh_>hE5Zs$N)`!sBG#PF;tYwas7r7K8{5tEX$PkQTzmDV2f&EMpdQGLCIc5h`c+ zTVfP<)pDQx+dE$Du9jK4{Afv*4S01XzHc@0x0LpCfF}0K+RnH46!n+7OJ>DIN~I68 z=x9eoV?f`%mF-&Vh1u6$f{r1?58fZV<(pzYn$stNBE+}qcbuPJh* zFZ^CNdnW9_r1$u$-1O@&r-Or^x`Z+^;5AE3^py+|@HHn;)sP#g|J%o$D=)15?Hl zV6|$qw~N0Qe`3qjITWO_D0{87^`Lnc=-Dbp+1V5HW;9{!r!)?*h+ccxouP8V#X&{e zqEHzxtss9g&zhpJK)*~vtgE_C(+is7&y3U*aTExcVfN4vCq;Ib`WxLcgws%ia{ZZX z;o;;jgkh=c)|Fb$gxO`z1qo%(8Epa!_wgo;(}Q&5rWiATHn*{%CS`iK#ZYbfaj+DY zKz)fIm2f}=Y6ooddeo;73mNLbZfHp*P^unJkWHS!6b+NDS0(qbT=@~iJX{B6DNna` zkjWW9K+db=e%ABuea)uKVf_jxP>d;`U;v2VP2gU9dpt;9K*}EQXzUf;!J{x+He3@! z@cut6y1N~jquEF2f+W%RQC<+D-SPgel)Df6&kT}{=a`m4odVwD)zW>o^CDvX^T^c^ zXMPISHKLGkA;ceXj1T}JoMj$Z1h@ZCr9y>!g+p~F(B6<>4IB#za)TS~=DiP*8Y!IZ z!x^?_8VX&eR{wZzE-&9cAgQ+#L;>b2gkh++$nECtuo@5hY zP}jf)TQ)#~sg-Q;xdCH{7fa0=7;N8=^AlydrTcYN?#~_WIX%gT4RGHT*T=8h_ews0 zQlIJN2Gh2#hIljE#WyngRqwdbAjNXzUf4G;zEpS;~cU+>q|#>_&SWj!=!w^^8)-iBp}ritD2T)M)lixbj0o zZ?M~CQ6vbX*cTAbNLeWym}_n!D=1*76cYS}^V?e2flL}K5q#9}$Ey7ZaI!Fe zB->ynJqZXlWyv~&KZAo7AG=QK9rDU41g{~)I=roVe3G17?1hi{R$ms3ciTKn793->l zqcmXX+x~+Rw2_v9C1=g5K^9Z* zMDdj5uz%cQ!RiG=@uHYy48b-7BD}S1gtgL3|v1qD8o2NEZMf->z;b4xn_krwoFNsAL?4{VmY% zhjsbmfkox*C{MkeA4U=cXQERTzZcCp`n9I!rt^!+p`PC?WE2o7%14$g8;(2T6l&GW zjQwjGyPsXujt4#PcRhseS+zX^oX*Fk`r(1w`?yT zCLy?hG5mD$*Jm$->(CmXyPNlTalmg_)hJRab&X6KTcWdf6|-apviOwcBipu{c(Ep% zL-Bv?tty%MKL!*v0stnb@y&~ohpHxC6pB*4*<6b#aBh%#h^Xzk`pW&K+kVb%?;>jB z;gNhw>Ek2O_BbrQ=6q<$u%L2$)k7xGak`sCPAKgLQCVY8&;-4c&Y)ME0i}Ys>ws}% z1E!2I!}2&AL0^2ED|xm^j&XX%yqH*CmKJgs;W+C~W-L<+%^HSs{V_ zPJNbmsyVF=do>{w!R&^UK#JeIfX3dd#Vdo?N%exPpU|Ap*-sapWHLh?6q!tUq({V5 zd_tj7D0M`U@=Mt0e^akYgrK#Xtv}88r@{Xsx$crZ&p#b5YwR6jJ+;>^YIE`rr2ZL8 z03|n=SCKON^AaDKX?8N;o3%9LHC*?`OF2i(%2Df5YV}M1`uJ9~tG16wfd}(yJGZZ+ z2`9^f2Sq!u0XO9y>4y`L>;D+}5g;P*MS=S4Wq&LnTTTm}af;}~rGHB= z_sTvKUXt;#DYyXvD?Sb$Lx~e7=;(}cAQ(IlwhY%=!9>nXh!fw{AKA2WGta zn7ZvuU;3urisLa?iDMbob+aIK;dSm=thGR~szJzN=-}Q8tR1OnyB6J{2NkTSDzGvN z?~zdX`uWsRO$+BM9Qw@6KKod`eDf5%2jH^(d|5E^;H6d8&$XNPkov~#ORBR_z2a5i zi^bAB=!)KLXP$+V9j=o~)_vuHe?LB|+ze;!l(dv_k-xA^W#JeWYUW59yTX4E6e-q~ z*L<6bdDTl5iU#9jEra_#Vv~47Wm781Z`okWI*H{}b9x!;y)EEH`7dOs$_Qe(dBlZkyH3&K@sIx zkF_?zB)@oHFx#^ErG~jS&?TtFQt1vEqnwOC>TS%g0TbyhJb)_>Yd>5bwG?d>q2!sa zH(uVJ6J?OshAPxatxUmKn*Q+#Am+M###wV#<#2YW83sEPMI7ai6|q2XM2Y~a7#ChgZqbw7k&iLP+z)lA2$f1UZ*ZAyV~6E(Lf_^V zJ`@`%&%)+wvXN$Pn|-*up0Q6Ea??oZ>DRKy>5vQOK?6R3pc_faJ;zL%^N4pWv;MTH zOz1{e+%<;6FnhS=`K;?vI^?6|sgJ5<**GPSPBxN@tCA9=N-tic|{7yet3d~3U1o~ zK1_F3!n2ivU&yMN9w)$O`*OvE<$qRb0KcBRwyRo?Hnf!#?oZ#(#sX)F;g=u~J^64YV z%R{WAv7$E!sD!qH2W;9!oP0OXZ(LzG0Tac8;4ZWo)={hLtW5VwDn)D@OaOGL0qaSumdFgnCD&eTGoSoXkKdblHf)wdP?UuTU z02mXGgkXzw7G(xE$<@zT_&TJi0V*LV^h<(B|G5|@7fu9AE#KD1F|l1W6ddIi@z%o= z!S3TBelnqCz(~2#!^epLNc{uj0$`Rc)*4Ak_ z`KS_3r(8kGc52g1oUQ#LQ;Nf#OH*%|19UQ0G>NaqXnLPrkl6j5N&YHh+IHdHMbwi_ zY0wE~wWC&Ovvv;An1?P8?B-Sw(B&Sb*`9NF@)+1QOeYKbDtP-|!N)(#R{~xBoiU0D zJ)4Zw7QWrcmJKOUlL=3W1JsyDJXPkTJEx}1pL;R9?BL~cK^ck{=5j}RcU&WeZ0ZL5 zpk;-;lc^da4`)4(a6G)&M*nF6p2H#xO zd6qQS?bEu3W80v)n7&itWz7PLvMSCmvCZwt0imZ17{q<97e%v3bLyFT(ivgIqzy{o z1TVY%2MR)x%leyp`;`qe({;4(KfL*6Nu$sAjNJRFhHvt79?+tpzT=_SZ_i=Us}WK| zTfKaOA682Jv2XICN|GT}sR!j=_iZiBc8@>`2ch&o2~Ih;8STt*OI=8Dtw5~QlI6YH zITu4#`D=&N_m)U)O?i^wTZR6Ff?{TVhs_mEIt!6fS)ci@WSF&u-?KF3R3@TsM0ssD zSc4*yBnntN8y%D4)Z!myFR@Mb)?m=;^f4n^%E%gj#a+_m1gE0k4Te7&o1(k@T<;_T zlOF2>t1Xq1S#{0K@Ba!FctKmL$5|ay#M=_`MteZda*&i>NM$N#Wx@I3hGshu+LmUW ze|@;Y8Z)7e;Frc@DCq{?BEXLa0wVBJ3glz03czbX6jS~JY-H6n^}+=| zLu4Nc01BFV3@77rwn&M+V-)we=c-VhBsApK?-I)la_(V>`+Ag(M3jn!wVazt2H*K}0QALKHWY`{O;z-tS z|7t^ml8^0A%DdC^QD+8$EwmTp4A8=N3q=-Wm|!)25$QB4wyC}v_RDx78Cqk_9-)Ge zzr$`~?UehS`%%xh^Ry?{=mAGiGlD!JV82-x3w~T%VNCkty0}0)gR-#_K8JNUx^tjW zcJ<_ER`U`yuie{1ny!P3I?3i5A=G?7*JJ*@EI|<2&K+U-Rh< zE-)#eZu^@P%4huP!NQK)jbSo97MEs%;YeYPW@{}h?=eB4*4#?`{->)zo8P5Uhbxcd z--))_S*eNcRyn1dswXLFa9~ezF4q`JpOV1WeF1(4Mt||nNdm9Jd&|t>`2=C2q3?v) zE%UPt+#^r#(`+?$x0HG)^__})c{`-37pji6 zi!*fu^YmJG4SfZ2!p1BaTbUFgKNWLQw#RYTuW=50!0l)Yw=J<1{y^Zr!Q!>mMMd@daJ+7q5Pk^mOa z$xGG-o&We;%htDodcXl5Fv2iBzfzh0zo!=FsnZ}6c%Xc~VfrNXn(+?3deVLOdCC&> z#n9v2x4RJqTNX;K*85&h-*NP?wAdQ@io%m3)8{800?EThkma5a zg}%349sI%oXID7H>UA~-t-ox)%!M22+j1B1STkGG4wbDzr=l|4YJ2Cjtzih|%{@-gB;gf?s z=<Gfy=g?TPd+W zJ6p?>E)LHg7PWe+coZ-v?!zZ~VYAuWdDAWif2NSm(kHrh^Up>hoGn9@O3qcS`6^;} zhPH}(kCtv9W6n+@v^5o~o?dYznPTDxIcyn}tA386PWEwOA2Q|unv`quS zs|&3jZ|>Ts(*gy=na=h}|9cL&J*s`l*v6DWgVlG($NkKyFTbGhEZlxdbg{` zzvbCY##DRGFQ4K9+Iu5Baf&ZPb3=ooP3656X^X!=@P8+by8#o-iM?NsI3Wh(i{<7? z=GYx+i)_hU@r7T;8at$imfpj=0^_XwBaMh>beSMzZsP(h-$pN5o7p^z?pS$70sg3-HKo>;UZf9mC|M) zxlRM~RVxJWHy`?q_*{>XWvv!8RZ)lY0t>T`^U4`$J~^)}U93LB^4tz4oOZ^(fBxNp{L?_iOd;h-rTT zXfMvV(+j@q0$x6vVp(=TEH?ZRoFI#SRIrx6QH*+Ih*M5A1fwe7!-wi-1E9#&BO)S`;kn8T+YfgUP&LRjP4*-<)Ba2GPy4}1>nd2VcbxrhoN{?}f9W@v z_1kDY=pm@*+;2p(iN!94EP;D6^MS}}Dquw0!;&g!3kz<=4=`;PuvRiXeb)BpUC__= z6C$^$rIuLD_Si!q?M%5Y9Qn;YkC{QLlKw7-6wx3YjIN?h{Kf~ZN;u5f7%bsLAGwig znC$f2V0*8T9e zosnzE8&l{8+0UkvjZbT+b)Z_`3^Hs5PK4j9yqdt5Q%WEOR& zPF2^UNppW~&)tsl9Fi+KYD+oqI1&cj&MluIPn{wO40I44F#IZ}5*2|G8qWV}Rv@Ra zn&ufkAw~$wW8J6)^`QEi7n2W*t>i}KZXLW*XIMNd>6fLDwsk_5gL$^Z#U(r088nDsW z%_DK7T;RLB_Sb_UK0j`$_4Ni5p+;KIClY>#C*`Zn&HTyo_rQD`)0Lw6L?q^VK2IPNntK6XJT643f<=s}5@=u`2Fi%i}*eC~X zH42yTQIrThB;7p+RMS+Go5Xyf@uaJvPid|SL~AU}w_On0M5jMu)=_l8%8{9TV`1}r zkK6DXrRejg)2j|7G^uBJHd`uw{7o6XoBZPwyUAH{COsc0YVxnPf2M0-;_QnApV7Pt zGA9+Y+Xk2J+q>g?xm%u2EBXgp-!mr&)#=@=BK4+b735BEEP=iW<+T_$ybD;iNXR5yWXtL`CagZW)wrneE;ODij)>w^osfI zsjm3WO)H;-y;a(se(J1gD|!x7FcxL`v>PnzoLe?~V2$3}r#@7-;}c3BfWW7a!3T_4 zCKOtk*2oI+KNC8vTz63ym8RbOd2vz7Q)4$&BCW6K6B!sI5hr&H)Yo~w(bqg-lgu+; zNx1DrW5hW7uKNG=0z{lk5&fi_8F&9*zL_ogetTD9?$o}F_W!>E>bd?(Q+VjP%C;pB z2M=GSrH5?oXrq|3NpXuM8ko|Y)ppNGYMsVEnsf~1duA#1x-AnZ2H zh%u*>4d^4Q3O&RR57_EIHAsK#^%dL0K>~GTC7gh24yjG$@?7Z!$jM>ORmfyG=rM8` zQ5`#g5C$jX$Tz0@NB+xM>+`VEQcSOHi_bLSB^Re6-*x_db- zO}#Qx22B~Sm5gm!1rDo+xum>OOqA@gyVgj4y#R#lVhtzU{`dv(TjT-6F?Ak5k{dZB zcIihD+gIFKlshA!bn}GViMOEZ1H`YS7vQpfmh3q58QuS7PSq45#RfK&%eKL3H@#LlLrdvpy)bwr>nw$`tgQ#SULCSTE7 zK&oo{1epzbtxFUN?&;gsLI9X8ot~IVS!RyAmSGGJu^UbPo%BRPu(6jey!*DwXAM;U zr``;D$2S%J`^kV>l1cU~T>L3xKpX<4p>CAJk0t-u#mZFejOsK6QNGn!%r+KV+9y?t z29yD#KcI0LKBAs%onn!hj0L3_^bTfsQ!{T?8MZt1J^xqfD`oRGOS~pJ=hyhg=-Xr6 z^7|f~chg@O0Y`O2sPLPe@S6-Lum&iKz;WBpU4p(KrUp%{7?WG?D&8t{Gx@|Ygh9?H ztHbfmO4r7UcIzddTKXcgaX5i7+m6ZBDbw=o`{Edtr69OBNB|iReL@~=3ip9;fRzOp zs!)82st}BAEL=3XfHZlt$F}fs%Pk>DeU;O_C|Mz+!m#JlGyhMn{9@I@4GJ8KWA-`0Ag6I3qSBO zX6T*G%JT!vO>vuY#NQglCGj9o;Ne*CgaAKVz=8)1<%5m!2ly-ln(SBc!q7(G(6L)j zmF=tdtwU*n#U-CK(AI=i&I&{6p-(shGSFm#{v15-i3S7}3bIYME2b+#{*8CzkNt6&Zgd_F zA9%AnB@8ET3{~`$qTbMRd8^Eh<>x!KQzNzHCS-CJ+;!diLOzO1 z_#{_s=j>-<=pR9L*IS~6Ta(VHO7jl8(w9Z{f5ykK>Uf3A-`F=qek&!C3Ow(- zPGxtMiG{KQw)o;GvAAsY;Fb5ZVun)QUJ8Ih>$OA z8}kNe{asLfUoNumqf5h>oLRSeV^t*Z$rfV}`ziqelZ!IXe-*0nyf7n?&!Ad2p#>D{ zi%ouEoVkGg1=}5$Z)E))JYk3rwva&DQ|V~yfBVYWPX#JJDdrJY(zbWkdGC=A7FGJ$ zp))MGg_*PuJT)%%1O68h@YbVDu0>rd^D`#2qTbnGE0^_?zT3qZO}nn?X0Ket=3k^2 zyC>gRvMGTt&tH>fD#J;%yca-n+jaI)TizO&o6dVQ(`*;MS?rKRoxlbfP>b8ahluSz zepD*kgl^Xn;8DO`fGufm&oSEY3M&bQ+6!(*u^4MPWjl$)8ddRpYLVh};yaE} z$l006h_)^rtvzFJKD`}Qb@NFbiPyk|DBHrXSQfwac74Hv%yr|C{h8QQ%8$coIw^6n@Ca`alY9Pv}Nq&UjE4E)#4iUSu;Iy}wulamsm z7NTAoJ{pDRGZw!r(Oc{cAO-_`knbiGr;J7<56IkcnFY9NXt)3Mmf+`5OZ~L_Rn}qi z2J`?r99w99c6iq;haGYTEH;@C5*s))_j@yO+RwTeU>P*)pGxn&-hHRH;`c0*MPHZ@ z;b@4!<j4D3i$$g`ovtSq!&k;lbzYQ)4q_Y{5wIV-ewjP|+ z{ev!9>Js5&gHx{MyW9oB2USm%Kvu6tUHm^Tv|ewvTcop7NNR`AcBpodGDI;I$l7(W zW&DP%3Ld4qxG0Wm(>S+}^YK2DU!rC}0xP%w-Bd5Oo5{c>)@!lgF?VOf602$1E9e#*kcd zYr0LIfXZ7rEgl-lEOo)Dz?cJf`WONdtIr<;VLv5v5DLRlPon=(4ETK&gApL3+^T0Y zc|88B6@64xpaHGgP)3t;>(6&5m(%`<(;k??qP{l*j(S^oG~u6&S@C{sXNj!}XxSs% zN~9?7%MG-iU+K*2LAQR1ytNinv?>$0IKG11v_ z9FE(QbkOlxoD9GG-!4`Ia%sRpY?$6HU4U%|*^p)<1K@B$z5>3Z5p?+MhNyz{Z=~mf zujJ(>SW7@n^K*3}JcFk6Kd0d#0iPq9Rts-l z<-Btz7GX3j6HP5#rDtf#ho%{2CmM>}W^?E3W}`t2S!6OB&6SAm#heK@mp-vMQv5J& zX~qDcipT!r*3&uqWj>>zy_=QSsr1a~A}$JYs&R=vDw z2a#MV>qSSpQU#38*W-kGj0~yDb(Y4VJpYC@$$&WZ_M4vs9vljAX@2g6(!@OpRFq4HCvwm z{?~31D;lKu4&l{UB6D=zg3K!1o?ulo3#|2S^x{?~_(_*Lp(cR6mZyYP{j8VZ!u-|G z?)lp2hJO-TGd?oXv)t^Z9h{|Yp$9ML6vT@H^MX<5lSJhzeF_Y{nd{B6 z9-*RFUbLt7C9@EB*mw4Ke4^1ecJ0Me_mYx{T&)M$wg@hXD3|pKuhbk2aIHuFfx1C;hloi#c{K! zvtM4pcv&1~bemrh;@`Pi!bhSsAAO%Almr+T%xQDkx+_xMvD5r2R!mO#R7&1^|`5M=d;c@(V*sefFdg55reR4pZ?8|3Oeo89`WL4v-wd zi)nnM*N+$NhS00(DJ@j?<|`ZNSfmlZ`}aYW z>9>+Z`7N@!5iU~Zbf!=PcUppTY=9k=N0sh1jFw`2x+q?x&N6|GLi-t4`TldHr};j` z2?;Czl2JW2pW&?y<=YYiS%yr(vPhPz-NrHLeA7bs!6}7+U=y`@i=?Ad#Y>=y{d#zd zLx$%a4FP6nQOf)X0s>B5au~DuKb6KL*=D-01?#+30y4JILZZ&z{Y!J_w2p0AAUcj` z$m_6=T|Gf7p6dyYRT5}xv(-z)xS(Z2=3g~U9{rYqUi1D(=;o&=1 z!ua4sn`Pm0dd?cXGaqU`&!)h&`gPWZ#NdZweA3`7bsf4*jWQ#c3~t{Nf%U?6M+RguPt$G zlT|@PR4)T%p{r!>t0fol!W$nzlDV-bS+OJcN$y9<9Bt;)DBoe-wt#hgR_uJ^-sax_ zjbso0Ie08}udJw3=ktG_Ll0U0B*}6-lXnZahZS(H2A%lSFh7|}zeq*9Z1PW;xqzjK51;UwS(eN8&w7n}sZs+u%(q^KQS&)M^Po?ixcz`sZga zk-gDSQ{1>%QY`DIxhXHC3lpF=q=^ND*;etuN)3c+$k_OqiT=EOZtt-BTxl=L)X6BD zUC@1C`h;0z5a(%I2KxDMEZ{llVk|22b`JflhTwCe@%QLCIW46wA*>I7oQz<@Ga*q4 zMv@wW?8b+UK=1;Z@V}jXFD83A!6$sOO@n+X7Y$P=rNmeyZx94whl@;npRk_xe_Ux$ zni!jJjq_KIKk2?AyD2Wr=A&TCgi8iJ<}ujJ{sT@UVHRRXI$ERtvuUoRZ6yn? zIC~5F7*I=nz7PZ#{ia~Hoj{9Ucz18~PD6xnVLeNrccEFTcOpnJuw&~ffr8fy=l{aQ z0&~zYzEetzm6@`@ zn@WY}C*{AXMC9<~o?Z%^9>>w=B#SAX8GLvYEbaNDP_eOO(^2n6H3MsBN+x>f$h9v< zi!FnbqIqyHqgJ9)1~dQjpW8H8YeWwVhe7=f+AXTGOv|U8;G{vEPJK`6(-fM{h;9K4 z#Xavk5pB{C!7DyMHP2k=z$zwDlaTr^+5c=QVD`i!Kovh?k?3rk#)G-%0(@UI<|!(= zjpyj-mLJP5n;eK#PqYaiB41=x;vs@e%KV;RzFoZUKlif^NSI~QUAd!!@?HNllB}(M;J%0b%7D z`zhHq!>c9%fD9579gd!SZ=r`UQJjTWjet_WKTLEyRPQ?Q$Ev`W0!4&j^U1f9%L6Vx zr}uhJ4Pp%!m+pbLbFIDE9@Z5K?45s*_PYOU55>P_qw2i86&Vryh8mrWl94;VDc9-A zoN@KUTgETaAi&8eB-7(8rgLJL3T`gMLKLnMnOOmFt5LuO0Ldu_NBfSez*5<>cz3Tw z;qUH#s=JN9vF68aig>xEo(KGm(!;SF!g?P^pF+FwiATc1i0rGW+A7;vSdPii(EB_v zhikKrMHm_qk0WrW77u`{EYXY9iPSd*-~rmVPQz#w@$K%MPy${lC`LquZSc~u6ZEOk zGrQ*aSnnr?WlU@rT=B8J!s?2dXU!Kq@~oJiR_inmx!#+uwg%){k}G z_pG}T5tRu6T4UnD0W-nrWU8eUtOb(0MC-=-;3i&4Kv#eq2b+ezZ$Jfw6V z{r(pQ9W-6p{mG;MgS|>KT3>_=B+Z!9{WxwYb7*BG7W?7g-1J8gMTf86xq?G6aBxZf zH~j~z)-&yIWxeYF|3E= z`oNUZ2*1mnZ2u~IV~l8s)a7}jeb=~A>11bzr65qA`alJusj&l|N|0jiCVUQg?yab< z!zE%a6Rq+1Gx#9VH2-C61e1Ic=VI2cbRWTPs9bKv5%9satoV_7qHo#V!Gi*J= z;u{xecFp!xz<_2IqeD^{364XOBmV|s%MFOkL9}2!y*An^+HmQj)PB%d$=y3+xAW5F zxooA)*vOi-hmDJ_6A#^{6zmOH5}!uWU`#%>_%O4mOsJI+2h2dxN-+}eNhnempm)HO zLsAn{%e$>fTKHvm|$o zrnw75D&kp%fomhO2X0{y3 zH|A!QSeiR5L_{=fZS`u6H6S#n@idn*hIs+-6n`Qxk5{=0F0tGf2lMNU$q<&aYLlGM ziNOV0N*Sy$)MF!#o`YfuZTQmGYWh&r3%+MGX4VTNd>?6qO;gg5%cD2MKc7WfZ#cV* z4D_%y(qcWi^m#*V>8fX#ph!4?1!?6>H-}^R1wUI`9_rute^7Q}>sI2BC&or`yE=|D z%kDEQd)pSE#N*T1&8e^96gS{qQ5=8mfNW~YYDiHxZ+RJw_9T?jQYe0TWy`h2%$GU4 zS?D4oc-TJ)i1}x0N+RD$u^`3E3(mgh$C3B^y1XS^FM9sSikCW1Q81tot`an^1`+;4 z`HV5(v(boYY)(yAo+lsIkY&@t=UTX0 z`Z3AxReT@sGEELiXSkjG0k^@+L2e2QhD9gT(>%zpzp_*>#v+a4EJf4Emggq>J!9)^ zySRQEL|e0Kl~x7B2djGq4sJ?Y8klDrBx1{XJf0XCM}IWcwC?-I1xeq0az+R^ji3R2 zupAhFm*+FFP7@nrt5~gvnpu1Vp6L8H*sK?!=4*d$)hK^lDiH_|s>mSR#as|sC1Gxd zJ-9$&GI48v&!1v0hQTAmV+U=ISPabYMH_xG;UG0jz_S5HQ%%cUMuAkZ;aNc{b;?76dx~9wEYq4~0?tW0ke8XP>up)V& zmV%LfQw&B3`oaMf-k7gsW+sM5dYaDgN4aS634|P6kW?bnV?v%@U+JWvfqSkyL1JfN zmhnl9lHK^Ukri73NaZ*tDc{v+9D^qj`Krz0rCHS}i@^fj9xzTqF%lUuuhlPPm`45I z-Ra+%# z03d(Xd<;44{c~oSmif0HiSZ`uzviOP=6eC70Ti3! zKcc5E4Y@b?m&K;ILNhS8wGhgN#De_+mfE)P`AHt?TxbOk#UC5RJOyIqT`PTaWSN49 zGl`(SX3BtOsnjpa?gok60r^H_ekZ&fS`b;S#Y&E()MG=;hQV}u*7e+@DD#+eb8v!| zkl%Z_)rK?;a^wEiasB8h?oW;A<`Twmy$dG?Oo9f|IP<{2@F-bvY0lVKDj&QpwtH|G zn|uD3J_54=c;JZJ^_;f?BM3QOx+;UDf$zb&`WU_RwS!E-p>NR>Jp3-=nDL!auR^>t zg(@j_-pkh_T4vi)BfsUk1^J;3WYe{96kIe5BTK&Rr3uJ>m50AvgE3~es7+6b67=sf|Pqw79g?8D*<3#atb-1lJjn8=MCjfhL53n(<8P zQKa89K`carnnBS6$>pK;YjKQnB~=r_3h^`r^OMsyN@ve0$aldl+bi!&zm%@i#tvC4-n?2KdrY^C zbuR+gI{i;om^-^=5mLz*eyk<&ZlViUpW-i|BKkm1T(aUYlH)|-TVDig&DKWa?#9oy z&g}k<(tZjAg)q>FL!k`tMY{VF6FyaJ*zoOXhuB3yC;}uN-f-a75TIH@>oUJ3RS`6s z6A<4^<{h8`+tT^ugW~w)ASnEcWAPC(r`ldx9|KpP`=6RE`u|mn$7CKM^)8i&ky}c( zC5!{1m>zhrr}eSn7)UP4Xt;TcNv0Ytl+VXhtLUPNrMP(u&ika};LjxxlPpdLQEF~I zl|MWRsM`$oxh4WBO@ZD#`Sh{ALpKHguNOdSmsqV{M=;SJ9FJ3s?edH_r?JpK?=P6T zuCjv(Y}MH*?$TJoC%i!BGMWsfv4p?VsD5PCp#sK`zO1#(ikFnl_0j+Q*#mnpP3|;* z_SL8SD%zh9l$g+3maY3o_@Cmu<{;m`* zc^z5qZYL_@mC^ulODi6`MFPpAC+GO{t>VEdnj8VyXk6h8UGZptMr1|K;n1qNb^~OB zL}sD%lBRV018R_rzB7|8sjJ}P6x|kUQXgsIgBS2nV&RG zA;>0_6!}+2#unAFTd2g4lGR}@JN3vbZ!5Z@0FlhlDn7}9fdfxqnNNmPe-mnIQ$Z% zk(zQ;bJA8l7m0rF>Q3RSb|?hzcoe2~MWk6f<2fb#MKhvoNFLO+_5{(*axDP>PYj2W zu`QKvpHylYqm9&_qllyQU>QR(<>`SX_2a3Ec>kxcuYQa2`QBebx*I{nrMo*MmhO-g zkzQItkP==>Eh){?EFcX6OQ&=!v4oU>^a7$tNeF%(-`_vrdtLm<>|8T*o;mk9_kGU9 zR=!w#*p(uyEAK2XeCnX~5J;RD^(DYPFsY)*^-4fL7r-l-ULPYFR?wj4?@LUbr+J<_ z8@*+kizTqa1`l_Rep55ap2y9(;UM)GpRS}CNegy64mPg#OJ_F5mJ1bjx#%DwDo~ZV z{BI?nFWXifIS61FCyztGKMqQx;qU?{McsBw{|N?$Wl^M0{u0760qyr~Xp@nH0mgDx zifAmtvXINc@b6g<^}%M%`zJ??Nt$l)+O)^JMOa*llL?=~h?(9q2;6Lo=(0|8p)9RT zy)dEu8vxjMdM>gaU;Io({LJmH-SR&)8?JEui99UQ zIL4hmz##=wgTUf=btg97$U-FnzHXSYo0ZCOIr+HWV`{fv2bJj@0~N&y0+a9$((nm@ z^^#gNBex)kk=Kc8md|uwv*1kH$>Z!Rgin6{*fr_SJ0=uBYeKG4spg>Je%3Byh3d^4 zh91EVa1Rq9Qlf?RR@vUK8;e&n&IQLGeUAK32xrTK2rhV-#T|HW5pHx{fyL0*zxxD3 z3)-U<_}ExnZf&3|TA~+qSru1o8He76X0|l5V;IXdaVdJRBv994=0-w)-J6R$8!+av z5&Tr>yduIt67l`q-8F58qA_Px@^{R83vILsz{8!1f^7VoQr2~|!z!&fR(DUX97 z>1l&zyh0i^A^S(g4r<`H5&kIz;i+b*ar#d*8Dj^eu926G0Wl4SpA1K4Zog_(hDq_= z%Brf|lP2>8BW4l9^VNGuvEMvYSf7)tw)hjDG!+l^Wl~#zUIJt@Wq@f-!0hoX*|$P1 z4H7U8s14B(!QW2fJGu?);OJp1`e1f;_jBLpZxnRixbTuZyK?_e^vUzJ8B3I&6`;9} z3J`ZrWGn$POQ@IUZ!CaSzgZo|2n!+AkyHtwQ(2#?BZI~Fql?ze-wGRy{=*1i@YsDd zNu^1AgY2MoZYJKmH8d9|GWxaem;7J4~kk3M+VEPpb>w!cK_M*rSj1zF`czj_|1*tGd}OSP1xSo7i*Wvon$Y;Or6lBu z_U+aN2^7!>AU8D99fvy>ETRDzhC{TkYiyu9{XvlGe>#ecLn*)wZxYw)g0@Q#y9|h4 zjWa?5eN(k|cq?W8aH#oBPsfq+6$4|p<&T;Z7Y4WEJ-DFuV-xm~u2=CL30&yl01wj7 zaFR1|E?JzT=$7{ByXf3|fIyTyOTH$sWLGiT*--<(yBvZ%9jk{!t7}K|_aT9%*5nBB zYH!GKud`u+_r{v4Ow~_{1C0WO3ICmsz6M9U3rPi_GZg_|k~%I)CCL>JXsc$V>`7Dc zu~$)J_#c;p|hzK_#Z`PqQ&v9!Jn~=(RSPd8r7#Yl_UhL~hqC7;kx=^Vnc?*!h8a za)kM)7cat^qt)WEc;XXgp*#OAVH)iriXI;Y!As=dw!lq7tcfr zbwwTA^z4)FeWc7M8i9YBwQtuu2BPgJ8m+sOM=ZY@pU1v1`}-~Ofd4~%q}j6}6~OUL zbup}n6lT0c0&xqq^9t#YljdL6yh$y;4q+K2uDu;4#TnFSjn~mx+%9m;=|?Yn@;7Ag zN}5A22a&xZtH@J1V&`-(%-9huV`3QiYyfoFqT{mn7?iTy*eB;C&pREISSg^U7P}`Q z>V`A_Wy*4*>pf-wwehp7QyY59!hI{ zoWDq`8$~^|6U`iRd{pf6Ma*74m54VzE1UgDFwRwL6jk6bw#!R?ITBi`Rtj&BXOev( zIx-#IgA4P3mKV#Qo-QzxJbT&icpug5x1|Qw*5R9qMLyMvm5UoDA9$Iv3s2+dA;yJ8 zM47{0fT@|p)wq1^#0~1Jb+ZS=Y=IB9fqm24>SC}lgKpud*xFUyp~#Y`&-s4YLQQNi z*oG`~d1g%wJl|QYmO_9C&)kRqjr%9gi~Ui)=h&2;n5q>t4EOCveD%>)N#f>|Ga$U| zh-3y^pPHkxPpCydGQSx0;gRy!i{Ke}UNZFJXLNxVQ26HrQ2K+vNT!P<5F;O!XF77N zx!zsBL;%FPdOZV>>ogbxQ-(VMtg5}-5az8o*BQzGdfvR~w1RzBbCJW3-jU{qeuSvf zJ}lnkn3==QzbSAysyKlo9wkagZeoFCbHc6ru?u`;T?RBPF&M zn__9W3+AzTU>UJN^e>20MQysrHuveG^?sQ|M(TApW2 zu`aWJ{LkNx_`{9LRIK&=4Vr=EO)?2wB#l(>yhd#H?ulsi$n<;5OKu-mg`=m5N)NUKk~ENe&1wdqe@$ltWAP+J0!VANFo@>F0P5?NP^I-%a`*2ic@|_1<+%pNTXY4Awf7;c+1^)Y%`u^cN znFmCBI<*fbyO<)J2EP3uI#hn+h1q-cF!0(%PJsnpAAD}Q!QD%xEXBacxHRSzReW%% z^5lUz@Au?(IJE*Hjo4)^;P3!!S6f@OO+Q6h;*W?QfA9Q){j`W2^+M1@_q$e81Xt~* zht&^!3gAYBFvUu8uT?3=>7>(BuMUWLrFzfLe$RHC>9H8Am`Q&ALx3>mx7DhL$K^As zJiNVht2{bRemHg1_@zm%KO|YW{*x?PC$=U|}RQCbwpiz1V$$d|79b=;hofU*e{XuY<+|32DAitk&pF7iEiD*yd+0OsM}18BHHWe z@XaR~Euu4pe4ZYno+3sjt&7cLo7%yYHi8D7d7|G4s&nQ|F}Ffa8`t4 zck}(+7_ZEd*cJP@~&n*$I`l?q)DHdhiw_n zI|E^HqNp${2%{JP@Q6L#GDu1DPXY!TYrW-pE@J`ZQ=0KvW)Y^7< zx+HpAH{#kJVnCI*wD{2sMWDf(^!k{2Z4)45g)84ueqLf`4wDj(Yb?&P;Kl9hf|RM` zCXY-&nSiAA-Xq9}SUCQP-d+*Oidm3Zm8M?G61Zh!Gc{d%d6o z2;Z1kb(2)H3>x<&;bWaYPICjOe^fkm;-q)`Ql8DvZv1AB&(3`6OrssP&sUdM!`W9N zK04{jMFv&hpijp{&R$;_Lx@_jZ!fcoS8m%?og+MI7~*8q;#m;DHE5^q2pr*cxp8rE z93;V0Vz~^+*{~H~x$i`A=g4FBlq%be)xiG8dCpks({0CqY;dwGa#*Qk(xoY4ZsG4N z1B1;#sND|UgOV|Ib`O_Zqe``9su^ekvz!RO3X{Uo?hadri8-ULHO5a4qva<`XDrx= zAn}9KnPdkmh=h6I(kK4sOq%%mMlA6^^n2c8ayBkRw#DW+V3WoNi`<)Ch-#d`wM9kj-zy0ki7t;kG-^d z$30o0ic&5GaIIJCnP~VMr5plge)|?u=Ym>enVY!A<%hC%rCI8!4t4@QeY+ax%WG*W zt`@^OPgGV8ccTS0&ewNe^Kt1Xw5!KQ{aa&#B=*a7Y*5!QU*SMkDkcV+ba7e)fORNI zLaFI_JVaUwv0+NfL$%q$&vt`%rWG+BeNS{IgTDPhD4;FyQ0>5dxWe*y{w8TmcjKl2 z>y!-6Jzho~J)6h;f(1vK6^}crt19u-oAdoAU#G_?N-KazR{)q_FjLM0F)RH+Oblvd z1xyJYDygT2lbe!c^H6;bWksJs$w>dlPv}K;PAXT@C0!YJtsu8E!2&TYdD1IN!Hhml zEBan{Vh|?0A2Nu2$*l+sv&;-4?E=r1n_LU1H44h-yKzXGK|tCcDTGZzT_h`KI6g7X zyy6ixVOQ}(c!jUi!9L|Jy&h^ajdXb^W$my$WBrH)cg8>13M`ip;EVRGP{mU%@r$O6 zNp}v4&N)$`6MZ_8TYF>djOF)%j`kFY5Ae$IZnEO(VHUMz_Mx#;zOEY)Zhr*0(J&j< zV3lJot4b*UkNhW2)U}RpXPAkJWry7fAZ1RnO>ek%R{2+5&$H*J9JUQ^e{FxlslMxyU7lQ})eABgZ3SYe_rfl&4b0SLR^O+HcO0;QT-PeP(&HZyylRNG^wq`Z zvg{M3x-fREwpw!;L230Eb}IGUvmvk}mjMskL(o{_Xv%hV3LSFSQmfNm9}ld?F8A%h z$2TVrUD)KUy_`PQczY8!I#you?ZF!mTzi}Xm%K{uYctfDD5FZC3g4%>>blDBKBo*d z!n>PYPk|-XG}Ijllq|mM~RLtdT%@+YNFQv97h7@vY z#|c(CeEsc$yan^eYGXbs`Omig!0p8iG9pcezLpNzVKUbDNlK^1!eJOZpty{N3vZ3Z zd|U(?-qKv6C+Q!@m@ic%Nh}-;Be5Abg@OQ1fyMs*gWR8hJqd`Eur_$-;7se#}1lk{UQ{Do}7gcL;Rq5pK^d-^=OKjV|j zm`wi#wpPMP#f`;!+r*OOR^#eIOe?CqPga~&Lx3R3Yh;cAQo3yb38@7-7?<|&lQCPrrWztlL}k(4+aE4Bhs;9kBH zc6;9d^r_G5Z zSn7)ww^le+QyLNU7HzyOB{S}f3EKK_5FP9Dg(k?Q<2H98rvPt{Kp>b><_l@J&=E|= z;h^(S<T}-lnkHsv;&-Dw0i4b(|3b?{+tyupnM95($XeM;tGgNy84HWkvL}r))dicMdC}hHH(%3ELqco>_*$~d(uUyH2B`Ahe6WQ zoj!MAmOihzUAH2Da8Wm#RKZTSj9$(X{n#&t?zeK8n*Z`Vs*v=b8WVtIE=;Pl*7GA( z{T5B!sA%UGO6M`(RJ=|UJQhHprM$N;pcSXJc@B403 z0TAq*^Kv^#3DGrH4G{`!{9`|~-(`B^mWs?gcZuCI;r#rg8ddn4c*q~Df0fTbv46ONKk;YSI%E9{oSF^QQSr!iyR7fu z;-nqN1RcECSZ(W#JmrGP+?Tm5UQC}-rydY-lu9}BQpR3aNB&ZMf@7wi2LjGI zvx5B6xZvsFo(z~7A86zaX!(Ka=9Zq!^Dx`OqnNnP_RoB4luX+^tV?-?U8 zwiP~)Bi|WR_p7PV0h3SI!F^sCd6A=-hJKY>iHZU@$UfV=y9%wCED~z2Ss%smgh&Rc zxHH;Q>UKCCgEVAS8o4BcoEw0N#$Q6S@{({x(t+EFMNF5S)AcvI+eLo zot7(gMl!fs1L$-1a6rRI0 zeR<-Q5N!%adQb9t+B-~rxzBq4Lj$Q&QZQ%U!r$GihO{Px#Ajpt-SaFSNan8$7c*f`_^IJdOkAu$bS11BuA=VpOadJh^e-#6w-vn6`zcvP{ zszTNGN$VOM6=h@)D|09z87UO2M?Kg*eezAJFk=eKSA7FtX2XmTvO#3EjA`K6_m}!; zgo}yYW8i|7>YltgDrldK%Q^3l6Aq%^BrRL=745e#XV5jlK^BvPWX)FL( z*^4?u9_PybQJfHJ@fE7DQS-YrlQH!1#y$ zk4^;*$JR&qpR5;P)DBa#;E$gZFpZUB8>_m2<_z&m=@%I$%b{d_sc!PoR46xEC_Bp% zD1=i#7e4cW{4SDN$mK=eST{4wXrzB%*@j#!a}PMD+f1yb3d#|ubA(FV2hZz05K0>h zNgLGgqL&Gws&W4GT`K$5;OS68xAAk8T&o^@iTYCE&46d&CnW4#IUblV@5r(|&FiqC z{hpB3kciP_!(3Fu!wN*y0$(C zEtYU^3{>h&6!3jM;?c9Pj~&xd`XBu~ME0nXW^{P$b-EpDrN&W5b6pWsWqF7rk|6@P!3bI z0u6kw6@bD~yuQ%9{AFW1ZRCwM??rzInm`LIQV1&-SG}B8Aa%Ix_wArv`yA{a+NRT( zG)hY)aY*WZH@_E$R*Qb|klU9(J&ppI5mc;FL7EaKla*yEw)X1RbsUg25%~BFXmyq( zPxwl*YKzI*M!U*nilIB;lOLNW?|HGX2lo^U*T~B9`Cn~3WT!Vv6B8n34KY3imto4^ zzKdkfu+f&mvy4b}Ip!mkHfz!tjtn_!n2vOO<@Bu&RyT9w__0M{R%&dzK%lS+@lOMn z!K2WeY9CD`X6wwAC;d6MU=drey_DapoK)eQ-UFkg|nfFP4i z`{3MZWp1ZxW}K#ngpFwieYZZR1;u_g@Qp-GcMfry8(uhBgYIi^Mf4ZssO}IxXpd!3&>U_j5 z7xP?HyUOQ{K!+5*mLTlthL`Z|r-IheL1#<-&BiwZh3l%CCp!10_p_&jqcPtSv}qP$ z>#oRxCrvks;nX#D2>SV^z@475CD&wUPR$*qIO2i5pzYC9kg*rcsz2HuP>Wrpbw)U0!G7 zDAPE{*M;@LuQnp)!S2(_BmFH8phgGrPO^flj*BxnP0lRH2>zC|p#J-?*00po#|oui z*vbWrjg>L4-JS4za&)6@N0R^RWLfo6xB|(mN3;Jx(ofKDze_r^@3Qe5j190tk&rl+ zY~IX1FJRiO<%R)K>}kU|ZU^(SIPNs%G6KQ=*{S7+KD~&wb)lxcKgP%J5EYs2<3+vM3UHYr5?U^8AMF9b8a-=4C0514=T9GMOjfKA`2# zcj`{*&Py^kdO9h@gMo6!tdaqQ(<~^UgX>#jH}Rza>w3A+dZms1wCBlhPLI{gEgbK8 zeSa0B^TiOI^HAZ1^Kk=H_uv3SSEGRr`{L!vgO+E>1l&qDZB;&1XqHu+pmm0$C!=s6ZB+$a08vVh#q@)iRg9mY`S(_aE&D3 zs|QpFX2n&$hr=1^zdpVjc>oerDk1mK2^se^RgmLC&aG^=S9gk4)5&R-mLIZy@ra4M z8@Sf_CZwJbM=2&9@A^lB-qye#%Qq@NnXhBi^6)1q9zde0FQF!VRra zu9v?OmUYAN5JGBhtR*K^ujgU#^n*0!z*ESXAM?pZa!<|c96su0G_AVBgT@oBOAYW% z3+8UMloJy8OQgR)oIJxBEG|Kt<1lZz=YYDUU-+wN=XH#kf7suteii7mkD(n74tkOFNrP6sg63py}T-Z5%+FVI~tk`p?1H>jAD|(Zn;v*nKb_RZ9KQM@ofmDVikz2+& z<#eGhtVP8;=lrlgoxxJH9AR&(@)OJE)l>XVoBKWV+vw5D%ue5SQu7|_eb4G$DR6hU zinqa>rF!rx+S=OR)&SK)XTc{a9w;hyl6_b1-EQ}7&)km(w zVzra>HEex!L-ea|`mt|FgT1I}vjr~GZDMS>Z*Plb|8B#?n$a(8^PC6K1-985Zu?Xt z$Uvg4$`(cUCa$GQJI|7~tYd91sxXOP76D>HY{8~{8f$G*E0)jgi|6LLR&s-$pnnd^ zKNUTGtodA_QG9qQN%(qTbYyiVxhs}HZCc1pX3KSfZpi5R>dC^(r;6$L;zxfiw?yD78G;S#FlCE(w z=@yhVlQ!8-6<3Hh$z;Y)WuDPaaq7yreMVe&;Rg&}S^FuJaCn6g! zaTotpCk#9NPu1zt|;ZJS*@lQUy?~}_hzO$i=6r{=Q=-*Zs3AD z4jGapYg{f?A9OCa*LsEGp10p;wr zd%uqnuJY-AqSg#v>BZXdU~(DdLhWg{u6Zu7mmDO8kfsEo>(O0eT_$^hKv!yT1p3z) z!}dyz$r5_f8cHI5pJ|T_Pk=9kFwXLwlD*bD5RrCGs5 zdQ=^$O1P1A2x^vRQqPFW^fW%8hZ}0?Dkbe(*ZR4o*%a?#5>LN}T`t%A{UF8jHF#bq z>y$sDc$=4I9eVep`|?HZ^{(*N&&j6CU@MuNXbrG%N!%zxm?-jwVWG2P>GNFYR}08j z=a22-Hx~l$l`5$t8sk9eb|kClFLHmV(YCdBrqr+=k!T~6g4o%`nejJLXfAE$wAG*b z0nRwAH}xkzkPx`7**Hee4_Wf(SIYJ0hh6=cQ*wtp?EbcQ{4Wn4aUFO}W~O_KG(6;^ z^T_w7HUty+Q8#07*LL3`syc*A%u+ByRa^}S1Mw32roRM9+Ss3J?G3M7H5DNG8mZ18E9q+a9#c=AEt$i1{rp&&$q*mK%NIB~} zH$7K||HtPHyb#mXEg~k2LiHVu-R4O$iQ$AqD4ZQk+ASq8la1;)h-YiqJu zwe2l6O{9oaiLAVvg1>n`C@a$}fD04_M)B*;M=cY6nkn*&z8+rU%3hjSY~QGIYsSH?3fr?PXa=IM^{@-G=-=OPJMu3ReCo|6iMw0dL zFiho;zzgC*0is1FAw>sS3O&wa;i+$M?Y1fOSwhE-ihHTf0Rd=F4e}G~Wr3Fe7ar6c zOc3CPQ1UW)%_`?IXO18UJywx?)b-;u9b4-QX+@FCV{hSUd?n;+xZMv)Tiit+xdzUr z%won~o&p~vr6tWUNxe^^(sv4XWwzL-tezfTQ3}Cb{*VpB7m;q!b}j?*0BZF@7aGn^C6FM(>3b|x^f0nmujq^1 zHW`i;c?7iZEMb=N1ws0{Y7pnRm@5TpZY{9Q<0qd3v^(L;V8ZX-3IX=MP@%K#9}CGw z1ReJ)v;+47r9kxAiGqExiQE$RZ7TR|s))R2ogUv9ZrjlG#vdzOVs|QE+k)XGS@W z(sclc+lEXhN-+f^m+t*)Lf0rP1yU$B%^F;Yx!ai~!D#*tjceY7wTQLi7@8Ta_6h$A zk$JT3*;wZEx{7Gyaf(_o9pMn#-Rk3i53A{C$=2AT=&=k_=$Q845l#LiJU*rdk0Deq z$2{b?E_BDnct2h=$U8Vb_9j@|_Z`rCZos*rOmjYc@0cnkFvHHoO1FDzMNN*p*@}~1ICynJg z<>bO}>C+8W210PWO6~T8ngQjt7S5aiZvMZ3njqbV>+E@kF)HjsS#p_owzuxS@+z#e zIX?l4aMj?tK(Pkn@5W$J+|hx~e9I+lybO}ZHRgUNbF6(zEWYdBGhk1kJ6)uSi&V(L zM~lmk86!phzTvHOtjnR!ceMI5A2w(+mY2!IR^6G-h49xBvO2lr@dWjCy@z6*iFgm0 zo+b8RR-=uCbol;$(4h8-S4k0`645ntP7X*S3o)&AUX^rXY&?|8iG^-4+c<;Kw0pT- z>Go!d4ZoWWa1Gxwlm%u#HuFMPIm)2%j!rDh-16pyIf?yTrXJ9!69NbErXq@gGGQg2 z?6;1W2wUI&+n?pOKIBie3Y<=1968yUK`}u=MG0~VqHcQp%@O&KuHnm^Hk0pRgS<(i zqIuTb>;YSi-%_db2+y=BnuY&19a^y8#KVwFW+IiFOmd0Y-3IUZ9rXErhh)K(H6bwsf9)x=sx>Ln58}db9X?l&1QcOAE&aKgH>r z41DuC+9*Z1Zp+b#zuEBeXgNa@b8W@e$W47y#H-+4SS%6qW|7KGE;G#t96rwa z935HkH8raN?2?G})AF7@(>F_sZX~F#WDNm($BHZMi7HeaLs`sz*7^<3!J859LqWqx zYwJbCTJ8u}?{}n}9VinhCE~=Gy4sD>QZ$$}#(sp*InVPiM6Ge&c+~FuF6B8DXxrptOEG zsibyz-TBwc{ip8lNo}0z`+`;lZFjski^f)89z@()gA8rh$S-*Gx;k2^>L^o{HMk|u z&zvoC7=#>94inukN~1ayCA;HVp5ZEmWyz;O#VJ7-Z=K^`1}_r3V4}o8nB|RXfuq_t z6@VkLCj~chCxl-O1tBkNK=UF01q*TeoS&oT2CIX{SL8BSZ}$H;`Ru?wofYt0+kymE z(c`B#VJy7Qi6L}RTgr3bO2?p$IH+9-?BKYY-Xjds!nqQSZi&-UsI)s5PkA9du*#xV z1nW3S38-@4DqaI!O~V6>8TkH<{ycEdj}wZ>(gxOaR&2S#|J1eKZ$;tivQwa!yf`BKJ3CbjB@e>GEoZ=_E98tbJy*fT6kYEo3Tg3qHs zyPLi(i1*Qzq{0EOLl5U(cdckbXXcBc?tTVfsWc1@w50Q)1k0pue=qkcwK)`={Mj4r zu)pHUyybBJiQ6}=z|gIIl=P9K^T-t)pg2p`*Ak~v`ve$Cm2)p$sPMxT==yd|@mmn9 zFV}fj9KqL5N?q}j*eeeb@>lA`%Y|AH^mci)?DAmBF0k88@o1p+1*KDsWvRCj1G%AV z{H$`+O8KLG=!nd^c)Zl)>`+V3#H7h<_#m%YUDr=yj&PQ)L$kv_v9eE3X(&Lg2IXJO zD=(h?s0*BW>}sw`?>c4j2Y4{ z>u^p{E?h$ls8t6lY7jjS#S-*4OU;ce)j;FChpQYUHV(1;L__bVSWH87%$A>W=ORSoaRpJ|mX%i!?aC|LQ+E7W@xR3>lo* zC+X;v(TrBmw_&Zl1g;dz9Ow#q{)RX39&G$_SwG{6%Hr7`OUF-_Kj_?rx4Ew#0YEGc z*Onz(dqko0NrAD)TxEsyLp@Y==&ryD)sNPg0E5%`=JhOdt$iWP)0o+Ttiy_5tiKho zY7>sCue9wF{*8|r=W@=OeR0FQ;!gzgn}1OCWpK2~1NK}5ODWrc#O;0~Q>^P+*_t}) z9ry`-@seX1O^IGPQgK*3r6c-Th^4u`EBGReQcre*kJE5^^dpG3I-7;lEM?;>j#6_G zu$}LL?NodB16~_ggNvly%yf0@Jlub%S6ZN%qvk|gU8BtrTY9^1doe+<_z-Zf43X9B z?qLnN(|o_rzKHKLc<1W~mAcYZ{(dKrG%OrF=`t<6cMGwmcAa2+Td7}2UISj}C5SLM zH@lteXLu48uVQ3$V{g27WuC~{b0YXuYN9j}^m28$MsNtJR0JCrRu5sA>wK;^&z0;| zbE2i<$qJYURp>o(T?VZ~EQM3FH!vUCHl8j+NaUIZ{k|C>G&bq88M0x<#g;Vnn;LOpT^{VW7adefya=!d25 zg%EG6W|R5J!5!#o!hknCTbNFhMwc58rAz*Y7<7N~8n8X=Z=VI`L!|}2bTTMaz&<{z zB~NojzX&GS&y1!Ndgo^7R&jJ-sT&_Y6jO-KqOy#PEOw^_&<)nfmVi37*u+yQViBKt z^IB6%I{?@0xrqt*-ukRy=~^(XiOcKjVKhaOc`EC zm@-RbEy7KsJd5mU$qk(zw$+%T^#oucQOd4hg|>9^<^!>DNjyc7rsyzRbWeT1ZhTw? z=L#W|ugvm1cbao)OTd(MUV1i`jtHla@zWZ@uhKy|Ni@e5{Z&+tr$o`4XM5p-i+6y* zW=ne`18N@&>=GSdRbNExpjGbY=_%yRMgtR}-&|Mxd36~5X7@{P+D@H;hnTR7dW1~L z9oCru)0O)>*}FCid3!`#<-SwglUEgKr383UUTx~hVqXBi69j{U1D}P-KKLCfk;lax$_Y2;Wd8_@V)B$msv);ZWb$o>}lQq1rA@H zfL{=RAe9Ct0u)6mWYE_4Ac?DCy%tTIfhsPM(;`*{$Zonlr&e-4%htcC z4ao7W04GenAo1+?P(Q;zw1v}gEeJYak`4BF1agxf#V=?XLcbI@+F;OWiRG<9l*0<_ zYG%1km52paKK_mgFy|MV$DReu2n3ERE%uZrh#;5ud^kT27zZZ3HC14bad=p(>Zwnu z4h<&oRV^_7d|USZjKa}h-;=F3(U2isbk^bMDsWAI%ROyIm;$o?$549JfYiJcXTxWJ zbiFLDan${1Q9-XpEu!H0(mZ)Yppeedb7W$&{LxcQ$A;*CCd|^b1(kSpX1em45>yXY z!S6Y%m(<5TCkpSnOnO7wKIy^{i~PY2`cYS|wwl2?+x0Be*E>UqCqdw}m%muERJGHl zRkN4>tX}6P^@!1P0KgfHjRZ=Tqklr}Ex9G;|DOj1g_bH98-KMYWdm*#Np0!{#bbH$ z2&t!~qEA_~Is zLA7$@YZnLCY{$It2cU&_W;xtu4a30gP85x%v8LYU2rO8<7g42lT~wof{YyOMM)CK` z#5iws27}(bRNcR^+RUDMr9stv;kkxPK(>RMop-puS8#c}BAB6>rmlB{r`I{o{JlUr zZJ2#VPKA4bLW!aDAc|OxgLw>EV(fR6%JidL!S?iU6_detFjns6J3iuQbRn!RVU!py zo-;cA)B`cy(a-USQ>gTe)m3>>{*;(-NS)jnc@}ulx|CC4FbwR0^sIN!HrIeiLZRQb zBZ$-7;rv0mD6ggX6Z#)@i#)#M%~(Z2)z>>Lv7B_c*C~;|BDj)d^UYr}U@eW08mvJ= z1aZDCw9a|I6G^BuG@jnbt9B2E->O=D zajM6pW_~>@^Nm%fF5%Wg<%oNVqn{SyS{E4?3M`A98c+_i5VjL+<2#Kc_?0@@pz)gB z^i<)43Rze)1rsfHJ6ztM9vC@U?KD4qcf^=sU|PZ!bfyZxQsBd=vEQTsQYB0U($V9i z)!rpP3@+|FI`edvIni_)pswANQ5p}9*oi>wZ>mfQqH&yb#MjM{zjS3SUyaDjeU!|J zRidlMUOA2Ne=&KQKQ$NL$pS0@@>X~gU-=7^#Y*fO&1%`=bR+%s_Ltl5w8U?Y^N|O& z=dX_P^7errqr9Gsd`xE)c0Nc6Q{?qQI-#KmBh}y?!ne0YCb^o$tORN?4n>t4GT-l+ z#2mIOHMQ(QpZv9^j+B-O=6Y)ggm3@duL1Jl;knV=1V`(IoMnD>2r8^an?v?IvVF7875D}K{kWvJH z`~Cm@@4e4+p8MQ$?#!H-`JB0P=AHyS9aR!SdO{2g3=(xUB?Al$OgOsP;$xwE^!MDo z&^H2aHLx#weCfZ2smNUrgn_|~p{}H06jXRpw37d+=Bdi$agM)1P zW}H>6mVe1W8DxcK@&CIvCiYH9F$#yKr>AdIrsI9YMgPiRFm;v-;ysmQ`OA(Wic?{u z^H^My(*h918?x=VLia$wHP~wu`AgCu|DK_V>$JJj5(|1`FZcHF9FGa%__hOlujl5b z_I|OvnWu(O43OBg5}Lnh3;y@;1JCE`2^dFD|0_?wBKbR|=T;l6SX494rp0f%xa_Xt znUj;ee`64`pL{92+I~7NyLO236vrEb4s2SQ;f`zNj3C!FRkHr>7f4irk?Ks=8)0)x z{L2aTiHTbSn!SI^

diff --git a/doc/salome/gui/SMESH/input/free_faces.doc b/doc/salome/gui/SMESH/input/free_faces.doc new file mode 100644 index 000000000..4a87b992a --- /dev/null +++ b/doc/salome/gui/SMESH/input/free_faces.doc @@ -0,0 +1,17 @@ +/*! + +\page free_faces_page Free faces + +\n This mesh quality control highlights faces which are connected +less than to two mesh volume elements. Free faces are shown with a color differs from +the color of shared faces. + +\image html free_faces.png +
In this picture some volume mesh element are removed as +a result some faces become connected only to one +volume. i.e. become free. + +
See Also a sample TUI Script of a +\ref tui_free_faces "Free Faces quality control" operation. + +*/ diff --git a/doc/salome/gui/SMESH/input/free_nodes.doc b/doc/salome/gui/SMESH/input/free_nodes.doc new file mode 100644 index 000000000..13f314309 --- /dev/null +++ b/doc/salome/gui/SMESH/input/free_nodes.doc @@ -0,0 +1,16 @@ +/*! + +\page free_nodes_page Free nodes + +\n This mesh quality control highlights nodes which are not connected +to any mesh element. Free nodes are shown with a color differs from +the color of nodes. + +\image html free_nodes.png +
In this picture some nodes don't connected to a mesh element as +a result of deleting elements and adding several isolated nodes. + +
See Also a sample TUI Script of a +\ref tui_free_nodes "Free Nodes quality control" operation. + +*/ diff --git a/doc/salome/gui/SMESH/input/index.doc b/doc/salome/gui/SMESH/input/index.doc index 7e40add11..cea4b5462 100644 --- a/doc/salome/gui/SMESH/input/index.doc +++ b/doc/salome/gui/SMESH/input/index.doc @@ -23,4 +23,4 @@ Almost all mesh module functionalities are accessible via \image html image7.jpg "Example of MESH module usage for engineering tasks" -*/ \ No newline at end of file +*/ diff --git a/doc/salome/gui/SMESH/input/preview_meshes.doc b/doc/salome/gui/SMESH/input/preview_meshes.doc new file mode 100644 index 000000000..92a4cca27 --- /dev/null +++ b/doc/salome/gui/SMESH/input/preview_meshes.doc @@ -0,0 +1,36 @@ +/*! + +\page preview_meshes_page Preview and Compute meshes + +Before whole mesh computation it is allowed to see the mesh preview. +When mesh object is already created and all hypotheses assigned, +select your mesh in the Object Browser. From the +\b Mesh menu select \b Preview or click "Preview" button of the +toolbar or activate "Preview" item from pop-up menu. + +\image html mesh_precompute.png +
"Preview" button
+ +The Mesh Preview dialog box appears. In this dialog box you can select +preview mode 1D mesh or 2D mesh depending on assigned +hypotheses to mesh. + +The 1D mesh preview shows as nodes computed on geometry edges + +\image html preview_mesh_1D.png + +The 2D mesh preview shows edge mesh elements, computed on geometry faces + +\image html preview_mesh_2D.png + +Pressing Compute button leads to whole mesh computation +process. +During exit from Preview dialog box, the question about storage temporary +created mesh elements appers: + +\image html preview_tmp_data.png + +Note, that computed temporary mesh elements can be reused during next +mesh computation process. + +*/ diff --git a/doc/salome/gui/SMESH/input/tui_grouping_elements.doc b/doc/salome/gui/SMESH/input/tui_grouping_elements.doc index 8b9f6391c..e03433f1c 100644 --- a/doc/salome/gui/SMESH/input/tui_grouping_elements.doc +++ b/doc/salome/gui/SMESH/input/tui_grouping_elements.doc @@ -123,8 +123,8 @@ salome.sg.updateObjBrowser(1) \image html editing_groups2.png
-\anchor tui_union_of_two_groups -

Union of two groups

+\anchor tui_union_of_groups +

Union of groups

\code import SMESH_mechanic @@ -141,7 +141,7 @@ anIds = mesh.GetIdsFromFilter(aFilter) print "Criterion: Area > 20, Nb = ", len( anIds ) # create a group by adding elements with area > 20 -aGroup1 = mesh.CreateEmptyGroup(SMESH.FACE, "Area > 20") +aGroup1 = mesh.CreateEmptyGroup(smesh.FACE, "Area > 20") aGroup1.Add(anIds) # Criterion : AREA = 20 @@ -157,8 +157,9 @@ aGroup2 = mesh.CreateEmptyGroup( smesh.FACE, "Area = 20" ) aGroup2.Add(anIds) # create union group : area >= 20 -aGroup3 = mesh.UnionGroups(aGroup1, aGroup2, "Area >= 20") +aGroup3 = mesh.UnionListOfGroups([aGroup1, aGroup2], "Area >= 20") print "Criterion: Area >= 20, Nb = ", len(aGroup3.GetListOfID()) +# Please note that also there is UnionGroups() method which works with two groups only # Criterion : AREA < 20 aFilter = smesh.GetFilter(smesh.FACE, smesh.FT_Area, smesh.FT_LessThan, 20.) @@ -172,7 +173,7 @@ aGroup4 = mesh.CreateEmptyGroup(smesh.FACE, "Area < 20") aGroup4.Add(anIds) # create union group : area >= 20 and area < 20 -aGroup5 = mesh.UnionGroups(aGroup3, aGroup4, "Any Area") +aGroup5 = mesh.UnionListOfGroups([aGroup3, aGroup4], "Any Area") print "Criterion: Any Area, Nb = ", len(aGroup5.GetListOfID()) salome.sg.updateObjBrowser(1) @@ -185,8 +186,8 @@ salome.sg.updateObjBrowser(1) \image html union_groups3.png
-\anchor tui_intersection_of_two_groups -

Intersection of two groups

+\anchor tui_intersection_of_groups +

Intersection of groups

\code import SMESH_mechanic @@ -203,7 +204,7 @@ anIds = mesh.GetIdsFromFilter(aFilter) print "Criterion: Area > 20, Nb = ", len(anIds) # create a group by adding elements with area > 20 -aGroup1 = mesh.CreateEmptyGroup(SMESH.FACE, "Area > 20") +aGroup1 = mesh.CreateEmptyGroup(smesh.FACE, "Area > 20") aGroup1.Add(anIds) # Criterion : AREA < 60 @@ -214,12 +215,13 @@ anIds = mesh.GetIdsFromFilter(aFilter) print "Criterion: Area < 60, Nb = ", len(anIds) # create a group by adding elements with area < 60 -aGroup2 = mesh.CreateEmptyGroup(SMESH.FACE, "Area < 60") +aGroup2 = mesh.CreateEmptyGroup(smesh.FACE, "Area < 60") aGroup2.Add(anIds) # create an intersection of groups : 20 < area < 60 -aGroup3 = mesh.IntersectGroups(aGroup1, aGroup2, "20 < Area < 60") +aGroup3 = mesh.IntersectListOfGroups([aGroup1, aGroup2], "20 < Area < 60") print "Criterion: 20 < Area < 60, Nb = ", len(aGroup3.GetListOfID()) +# Please note that also there is IntersectGroups() method which works with two groups only salome.sg.updateObjBrowser(1) \endcode @@ -231,8 +233,8 @@ salome.sg.updateObjBrowser(1) \image html intersect_groups3.png
-\anchor tui_cut_of_two_groups -

Cut of two groups

+\anchor tui_cut_of_groups +

Cut of groups

\code import SMESH_mechanic @@ -264,6 +266,7 @@ aGroupTool = mesh.MakeGroupByIds("Area < 60", smesh.FACE, anIds) # create a cut of groups : area >= 60 aGroupRes = mesh.CutGroups(aGroupMain, aGroupTool, "Area >= 60") print "Criterion: Area >= 60, Nb = ", len(aGroupRes.GetListOfID()) +# Please note that also there is CutListOfGroups() method which works with lists of groups of any lengths salome.sg.updateObjBrowser(1) \endcode @@ -274,4 +277,54 @@ salome.sg.updateObjBrowser(1) \image html cut_groups3.png +
+\anchor tui_create_dim_group +

Creating groups of entities from existing groups of superior dimensions

+ +\code +import SMESH_mechanic + +smesh = SMESH_mechanic.smesh +mesh = SMESH_mechanic.mesh +salome = SMESH_mechanic.salome + +# Criterion : AREA > 100 +aFilter = smesh.GetFilter(smesh.FACE, smesh.FT_Area, smesh.FT_MoreThan, 100.) + +anIds = mesh.GetIdsFromFilter(aFilter) + +print "Criterion: Area > 100, Nb = ", len(anIds) + +# create a group by adding elements with area > 100 +aSrcGroup1 = mesh.MakeGroupByIds("Area > 100", smesh.FACE, anIds) + +# Criterion : AREA < 30 +aFilter = smesh.GetFilter(smesh.FACE, smesh.FT_Area, smesh.FT_LessThan, 30.) + +anIds = mesh.GetIdsFromFilter(aFilter) + +print "Criterion: Area < 30, Nb = ", len(anIds) + +# create a group by adding elements with area < 30 +aSrcGroup2 = mesh.MakeGroupByIds("Area < 30", smesh.FACE, anIds) + +# Create group of edges using source groups of faces +aGrp = mesh.CreateDimGroup( [aSrcGroup1, aSrcGroup2], smesh.EDGE, "Edges" ) + +# Create group of nodes using source groups of faces +aGrp = mesh.CreateDimGroup( [aSrcGroup1, aSrcGroup2], smesh.NODE, "Nodes" ) + +salome.sg.updateObjBrowser(1) +\endcode + +\image html dimgroup_tui1.png +
Source groups of faces<\center> + +\image html dimgroup_tui2.png +
Result groups of edges and nodes<\center> + + + + + */ \ No newline at end of file diff --git a/doc/salome/gui/SMESH/input/tui_quality_controls.doc b/doc/salome/gui/SMESH/input/tui_quality_controls.doc index e1b8b700e..57d52c69e 100644 --- a/doc/salome/gui/SMESH/input/tui_quality_controls.doc +++ b/doc/salome/gui/SMESH/input/tui_quality_controls.doc @@ -189,6 +189,140 @@ for i in range(len(aBorders)): salome.sg.updateObjBrowser(1) \endcode +
+\anchor tui_free_nodes +

Free Nodes

+ +\code +import salome +import geompy + +import smesh + +# create box +box = geompy.MakeBox(0., 0., 0., 100., 200., 300.) +idbox = geompy.addToStudy(box, "box") + +# create a mesh +mesh = smesh.Mesh(box, "Mesh_free_nodes") +algo = mesh.Segment() +algo.NumberOfSegments(10) +algo = mesh.Triangle(smesh.MEFISTO) +algo.MaxElementArea(150.) +mesh.Compute() + +# Remove some elements to obtain free nodes +# Criterion : AREA < 80. +area_margin = 80. + +aFilter = smesh.GetFilter(smesh.FACE, smesh.FT_Area, smesh.FT_LessThan, area_margin) + +anIds = mesh.GetIdsFromFilter(aFilter) + +mesh.RemoveElements(anIds) + +# criterion : free nodes +aFilter = smesh.GetFilter(smesh.NODE, smesh.FT_FreeNodes) +anNodeIds = mesh.GetIdsFromFilter(aFilter) + +# create a group +aGroup = mesh.CreateEmptyGroup(smesh.NODE, "Free_nodes") +aGroup.Add(anNodeIds) + +# print the result +print "Criterion: Free nodes Nb = ", len(anNodeIds) +j = 1 +for i in range(len(anNodeIds)): + if j > 20: j = 1; print "" + print anNodeIds[i], + j = j + 1 + pass +print "" + +salome.sg.updateObjBrowser(1) +\endcode + + +
+\anchor tui_free_faces +

Free Faces

+ +\code +import salome +import geompy + +####### GEOM part ######## + +Box_1 = geompy.MakeBoxDXDYDZ(200, 200, 200) +Box_1_vertex_6 = geompy.GetSubShape(Box_1, [6]) +Box_1 = geompy.GetMainShape(Box_1_vertex_6) +Box_1_vertex_16 = geompy.GetSubShape(Box_1, [16]) +Box_1 = geompy.GetMainShape(Box_1_vertex_16) +Box_1_vertex_11 = geompy.GetSubShape(Box_1, [11]) +Box_1 = geompy.GetMainShape(Box_1_vertex_11) +Plane_1 = geompy.MakePlaneThreePnt(Box_1_vertex_6, Box_1_vertex_16, Box_1_vertex_11, 2000) +Partition_1 = geompy.MakePartition([Box_1], [Plane_1], [], [], geompy.ShapeType["SOLID"], 0, [], 0) + +Box_1_vertex_19 = geompy.GetSubShape(Box_1, [19]) +Box_1_vertex_21 = geompy.GetSubShape(Box_1, [21]) +Plane_2 = geompy.MakePlaneThreePnt(Box_1_vertex_16, Box_1_vertex_19, Box_1_vertex_21, 2000) + +geompy.addToStudy( Box_1, "Box_1" ) +geompy.addToStudyInFather( Box_1, Box_1_vertex_6, "Box_1:vertex_6" ) +geompy.addToStudyInFather( Box_1, Box_1_vertex_16, "Box_1:vertex_16" ) +geompy.addToStudyInFather( Box_1, Box_1_vertex_11, "Box_1:vertex_11" ) +geompy.addToStudy( Plane_1, "Plane_1" ) +geompy.addToStudy( Partition_1, "Partition_1" ) +geompy.addToStudyInFather( Box_1, Box_1_vertex_19, "Box_1:vertex_19" ) +geompy.addToStudyInFather( Box_1, Box_1_vertex_21, "Box_1:vertex_21" ) +geompy.addToStudy( Plane_2, "Plane_2" ) + +###### SMESH part ###### +import smesh + +import StdMeshers +import NETGENPlugin + +Mesh_1 = smesh.Mesh(Partition_1) +Regular_1D = Mesh_1.Segment() +Max_Size_1 = Regular_1D.MaxSize(34.641) +MEFISTO_2D = Mesh_1.Triangle() +Tetrahedron_Netgen = Mesh_1.Tetrahedron(algo=smesh.NETGEN) +isDone = Mesh_1.Compute() + +# create a group of free faces +aFilter = smesh.GetFilter(smesh.FACE, smesh.FT_FreeFaces ) +aFaceIds = Mesh_1.GetIdsFromFilter(aFilter) + +aGroup = Mesh_1.CreateEmptyGroup(smesh.FACE, "Free_faces") +aGroup.Add(aFaceIds) + +# print the result +print "Criterion: Free nodes Nb = ", len(anNodeIds) +j = 1 +for i in range(len(aFaceIds)): + if j > 20: j = 1; print "" + print anNodeIds[i], + j = j + 1 + pass +print "" + +#filter faces from plane 2 +aFilter = smesh.GetFilter(smesh.FACE, smesh.FT_BelongToPlane, Plane_2) +aFaceIds = Mesh_1.GetIdsFromFilter(aFilter) +aGroup.Remove(aFaceIds) + +# create a group of shared faces (located on partition boundary inside box) +aFilter = smesh.GetFilter(smesh.FACE, smesh.FT_BelongToPlane, Plane_1) +aFaceIds = Mesh_1.GetIdsFromFilter(aFilter) + +aGroup = Mesh_1.CreateEmptyGroup(smesh.FACE, "Shared_faces") +aGroup.Add(aFaceIds) + +salome.sg.updateObjBrowser(1) +\endcode + +
\anchor tui_length_2d

Length 2D

@@ -572,4 +706,4 @@ aGroup.Add(anIds) salome.sg.updateObjBrowser(1) \endcode -*/ \ No newline at end of file +*/ diff --git a/doc/salome/gui/SMESH/input/using_operations_on_groups.doc b/doc/salome/gui/SMESH/input/using_operations_on_groups.doc index 12267df2b..916061733 100644 --- a/doc/salome/gui/SMESH/input/using_operations_on_groups.doc +++ b/doc/salome/gui/SMESH/input/using_operations_on_groups.doc @@ -13,13 +13,13 @@ belong to one and the same mesh.
\anchor union_anchor -

Union of two groups

+

Union of groups

This operation allows to create a new group in such a way that all mesh elements that are present in the initial groups will be added to the new one. -To union two groups: +To union groups:
  1. In the \b Mesh menu select the Union Groups item. The following dialog box will appear: @@ -27,7 +27,7 @@ dialog box will appear: \image html uniongroups.png In this dialog box you should specify the name of the resulting group -and two groups which will be united. +and set of groups which will be united. For example, we have two groups Group1 and Group2. \n The result of their \b Union will be Group12: @@ -45,17 +45,17 @@ For example, we have two groups Group1 and Group2.
See Also a sample TUI Script of a -\ref tui_union_of_two_groups "Union of two Groups" operation. +\ref tui_union_of_groups "Union of Groups" operation.
\anchor intersection_anchor -

Intersection of two groups

+

Intersection of groups

This operation allows to create a new group in such a way that all -mesh elements that are present in both initial groups are added to the +mesh elements that are present in all initial groups together are added to the new one. -To intersect two groups: +To intersect groups:
  1. In the \b Mesh menu select the Intersect Groups item. The following dialog box will appear: @@ -63,7 +63,7 @@ following dialog box will appear: \image html intersectgroups.png In this dialog box you should specify the name of the resulting group -and two groups which will be intersected. +and set of groups which will be intersected. For example, we have two groups Group1 and Group2. \n The result of their \b Intersection will be Group12a: @@ -81,17 +81,17 @@ For example, we have two groups Group1 and Group2.
See Also a sample TUI Script of an -\ref tui_intersection_of_two_groups "Intersection of two Groups" operation. +\ref tui_intersection_of_groups "Intersection of Groups" operation.
\anchor cut_anchor -

Cut of two groups

+

Cut of groups

This operation allows to create a new group in such a way that all -mesh elements that are present in the main group but are absent in the -tool group are added to the new one. +mesh elements that are present in the main groups but are absent in the +tool groups are added to the new one. -To cut two groups: +To cut groups:
  1. In the \b Mesh menu select the Cut Groups item. The following dialog box will appear: @@ -99,7 +99,7 @@ following dialog box will appear: \image html cutgroups.png In this dialog box you should specify the name of the resulting group -and two groups which will be cut. +and groups which will be cut. For example, we have two groups Group1 and Group2. \n The result of their \b Cut will be Group12b: @@ -118,6 +118,6 @@ group.
See Also a sample TUI Script of a -\ref tui_cut_of_two_groups "Cut of two Groups" operation. +\ref tui_cut_of_groups "Cut of Groups" operation. */ \ No newline at end of file diff --git a/idl/Makefile.am b/idl/Makefile.am index d1048dbef..a1d468cb5 100644 --- a/idl/Makefile.am +++ b/idl/Makefile.am @@ -66,7 +66,8 @@ libSalomeIDLSMESH_la_LDFLAGS = -no-undefined -version-info=0:0:0 libSalomeIDLSMESH_la_LIBADD = \ @CORBA_LIBS@ \ $(MED_LDFLAGS) -lSalomeIDLMED \ - $(GEOM_LDFLAGS) -lSalomeIDLGEOM + $(GEOM_LDFLAGS) -lSalomeIDLGEOM \ + $(KERNEL_LDFLAGS) -lSalomeIDLKernel # These variables defines the building process of CORBA files OMNIORB_IDL = @OMNIORB_IDL@ diff --git a/idl/SMESH_BasicHypothesis.idl b/idl/SMESH_BasicHypothesis.idl index 832a07208..9c428ba14 100644 --- a/idl/SMESH_BasicHypothesis.idl +++ b/idl/SMESH_BasicHypothesis.idl @@ -72,6 +72,44 @@ module StdMeshers double GetPrecision(); }; + /*! + * StdMeshers_MaxLength: interface of "Max length" hypothesis + */ + interface StdMeshers_MaxLength : SMESH::SMESH_Hypothesis + { + /*! + * Sets parameter value + */ + void SetLength(in double length) + raises (SALOME::SALOME_Exception); + /*! + * Returns parameter value + */ + double GetLength(); + /*! + * Returns true if preestemated length is defined + */ + boolean HavePreestimatedLength(); + /*! + * Returns preestemated length + */ + double GetPreestimatedLength(); + /*! + * Sets preestemated length + */ + void SetPreestimatedLength(in double length); + /*! + * Sets boolean parameter enabling/desabling usage of length computed + * basing on size of bounding box of shape to mesh + */ + void SetUsePreestimatedLength(in boolean toUse); + /*! + * Returns value of boolean parameter enabling/desabling usage of length computed + * basing on size of bounding box of shape to mesh + */ + boolean GetUsePreestimatedLength(); + }; + /*! * StdMeshers_AutomaticLength: interface of "Automatic length" hypothesis */ diff --git a/idl/SMESH_Filter.idl b/idl/SMESH_Filter.idl index 5e1694021..83c1d43d2 100644 --- a/idl/SMESH_Filter.idl +++ b/idl/SMESH_Filter.idl @@ -48,6 +48,8 @@ module SMESH FT_Volume3D, FT_FreeBorders, FT_FreeEdges, + FT_FreeNodes, + FT_FreeFaces, FT_MultiConnection, FT_MultiConnection2D, FT_Length, @@ -59,6 +61,9 @@ module SMESH FT_LyingOnGeom, FT_RangeOfIds, FT_BadOrientedVolume, + FT_LinearOrQuadratic, + FT_GroupColor, + FT_ElemGeomType, FT_LessThan, FT_MoreThan, FT_EqualTo, @@ -125,7 +130,7 @@ module SMESH typedef sequence Values; Values GetValues(); }; - + /*! * Predicates are intended for verification of criteria, * must return bool value by mesh id @@ -241,7 +246,6 @@ module SMESH * Verify whether 2D mesh element has free edges( i.e. edges connected to one face only ) */ interface FreeEdges: Predicate - { struct Border { @@ -252,6 +256,17 @@ module SMESH Borders GetBorders(); }; + /*! + * Logical functor (predicate) "Free nodes". + * Verify whether mesh has free nodes( i.e. nodes are not connected to any element ) + */ + interface FreeNodes: Predicate{}; + + /*! + * Logical functor (predicate) "Free faces". + * Verify whether 2D mesh element is free ( i.e. connected to one volume only ) + */ + interface FreeFaces: Predicate{}; /*! * Abstract logical functor (predicate) "RangeOfIds". @@ -303,6 +318,33 @@ module SMESH interface LogicalAND: LogicalBinary{}; interface LogicalOR : LogicalBinary{}; + /*! + * Logical functor (predicate) "Is element Linear or Quadratic". + * Verify whether a mesh element is linear + */ + interface LinearOrQuadratic: Predicate { + void SetElementType( in ElementType theType ); + }; + + /*! + * Functor "Group Color" + * Returns color of group to which mesh element belongs to + */ + interface GroupColor : Predicate{ + void SetElementType( in ElementType theType ); + void SetColorStr( in string theColor ); + string GetColorStr(); + }; + + /*! + * Functor "Element geometry type" + * Returns is element has indicated geometry type + */ + interface ElemGeomType : Predicate{ + void SetElementType ( in ElementType theType ); + void SetGeometryType( in GeometryType theType ); + }; + /*! * Filter */ @@ -319,6 +361,7 @@ module SMESH * ThresholdStr - Threshold value defined as string. Used for: * 1. Diaposon of identifiers. Example: "1,2,3,5-10,12,27-29" * 2. BelongToGeom predicate for storing name of shape + * 3. GroupColor predicate for storing group color "0.2;0;0.5" * ThresholdID - One more threshold value defined as string. Used for: * 1. BelongToGeom predicate for storing id of shape * Tolerance - Tolerance is used for comparators (EqualTo comparision) and for @@ -423,10 +466,16 @@ module SMESH FreeBorders CreateFreeBorders(); FreeEdges CreateFreeEdges(); + FreeNodes CreateFreeNodes(); + FreeFaces CreateFreeFaces(); RangeOfIds CreateRangeOfIds(); BadOrientedVolume CreateBadOrientedVolume(); + LinearOrQuadratic CreateLinearOrQuadratic(); + + GroupColor CreateGroupColor(); + ElemGeomType CreateElemGeomType(); /*! * Create comparators ( predicates ) diff --git a/idl/SMESH_Gen.idl b/idl/SMESH_Gen.idl index 584522f4f..e28b3a163 100644 --- a/idl/SMESH_Gen.idl +++ b/idl/SMESH_Gen.idl @@ -21,8 +21,7 @@ // // File : SMESH_Gen.idl // Author : Paul RASCLE, EDF -// $Header$ -// + #ifndef _SMESH_GEN_IDL_ #define _SMESH_GEN_IDL_ @@ -151,16 +150,30 @@ module SMESH raises ( SALOME::SALOME_Exception ); /*! - * Return a hypothesis holding parameter values corresponding to the mesh - * existing on the given geometry. + * Return a hypothesis holding parameter values corresponding either to the mesh + * existing on the given geometry or to size of the geometry. * The returned hypothesis may be the one existing in a study and used * to compute the mesh, or a temporary one created just to pass parameter - * values + * values. */ SMESH_Hypothesis GetHypothesisParameterValues( in string theHypName, in string theLibName, in SMESH_Mesh theMesh, - in GEOM::GEOM_Object theGeom) + in GEOM::GEOM_Object theGeom, + in boolean byMesh) + raises ( SALOME::SALOME_Exception ); + + /*! + * Sets number of segments per diagonal of boundary box of geometry by which + * default segment length of appropriate 1D hypotheses is defined + */ + void SetBoundaryBoxSegmentation( in long theNbSegments ); + + /*! + * Set the object name + */ + void SetName( in string theObjectIOR, + in string theObjectName ) raises ( SALOME::SALOME_Exception ); /*! @@ -174,7 +187,7 @@ module SMESH raises ( SALOME::SALOME_Exception ); /*! - * Create a empty mesh object + * Create an empty mesh object */ SMESH_Mesh CreateEmptyMesh() raises ( SALOME::SALOME_Exception ); @@ -221,6 +234,17 @@ module SMESH in GEOM::GEOM_Object theSubObject ) raises ( SALOME::SALOME_Exception ); + /*! + * Calculate Mesh as preview till indicated dimension + * First, verify list of hypothesis associated with the subShape. + * Return mesh preview structure + */ + MeshPreviewStruct Precompute( in SMESH_Mesh theMesh, + in GEOM::GEOM_Object theSubObject, + in Dimension theDimension, + inout long_array theShapesId ) + raises ( SALOME::SALOME_Exception ); + /*! * Return errors of hypotheses definintion * algo_error_array is empty if everything is OK diff --git a/idl/SMESH_Mesh.idl b/idl/SMESH_Mesh.idl index e41154e2c..9b5b3477e 100644 --- a/idl/SMESH_Mesh.idl +++ b/idl/SMESH_Mesh.idl @@ -21,8 +21,8 @@ // // File : SMESH_Mesh.idl // Author : Paul RASCLE, EDF -// $Header$ // + #ifndef _SMESH_MESH_IDL_ #define _SMESH_MESH_IDL_ @@ -114,6 +114,23 @@ module SMESH FACE, VOLUME }; + + /*! + * Enumeration for element geometry type, like in SMDS + */ + enum GeometryType + { + Geom_POINT, + Geom_EDGE, + Geom_TRIANGLE, + Geom_QUADRANGLE, + Geom_POLYGON, + Geom_TETRA, + Geom_PYRAMID, + Geom_HEXA, + Geom_PENTA, + Geom_POLYHEDRA + }; /*! * ElementOrder points out entities of what order are requested @@ -228,6 +245,12 @@ module SMESH void Clear() raises (SALOME::SALOME_Exception); + /*! + * Remove all nodes and elements of submesh + */ + void ClearSubMesh(in long ShapeID) + raises (SALOME::SALOME_Exception); + /*! * Get the subMesh object associated to a subShape. The subMesh object * gives access to nodes and elements IDs. @@ -292,6 +315,15 @@ module SMESH in SMESH_GroupBase aGroup2, in string name ) raises (SALOME::SALOME_Exception); + + /*! + * Union of list of groups + * New group is created. All mesh elements that are + * present in initial groups are added to the new one + */ + SMESH_Group UnionListOfGroups (in ListOfGroups aListOfGroups, + in string name ) + raises (SALOME::SALOME_Exception); /*! * Intersection of two groups @@ -302,6 +334,15 @@ module SMESH in SMESH_GroupBase aGroup2, in string name ) raises (SALOME::SALOME_Exception); + + /*! + * Intersection of list of groups + * New group is created. All mesh elements that are + * present in all initial groups simultaneously are added to the new one. + */ + SMESH_Group IntersectListOfGroups (in ListOfGroups aListOfGroups, + in string name) + raises (SALOME::SALOME_Exception); /*! * Cut of two groups @@ -309,8 +350,35 @@ module SMESH * main group but do not present in tool group are added to the new one */ SMESH_Group CutGroups (in SMESH_GroupBase aMainGroup, - in SMESH_GroupBase aToolGroup, - in string name ) + in SMESH_GroupBase aToolGroup, + in string name ) + raises (SALOME::SALOME_Exception); + + /*! + * Cut of lists of groups + * New group is created. All mesh elements that are present in + * main groups but do not present in tool groups are added to the new one + */ + SMESH_Group CutListOfGroups (in ListOfGroups aMainGroups, + in ListOfGroups aToolGroups, + in string name) + raises (SALOME::SALOME_Exception); + + /*! + * Create groups of entities from existing groups of superior dimensions + * New group is created. System + * 1) extracts all nodes from each group, + * 2) combines all elements of specified dimension laying on these nodes. + */ + SMESH_Group CreateDimGroup( in ListOfGroups aListOfGroups, + in ElementType anElemType, + in string name ) + raises (SALOME::SALOME_Exception); + + /*! + * Convert group on geometry into standalone group + */ + SMESH_Group ConvertToStandalone( in SMESH_GroupOnGeom theGeomGroup ) raises (SALOME::SALOME_Exception); /*! diff --git a/idl/SMESH_MeshEditor.idl b/idl/SMESH_MeshEditor.idl index 5da298ac4..bba45665b 100644 --- a/idl/SMESH_MeshEditor.idl +++ b/idl/SMESH_MeshEditor.idl @@ -20,8 +20,8 @@ // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // // File : SMESH_MeshEditor.idl -// $Header$ // + #ifndef _SMESH_MESHEDITOR_IDL_ #define _SMESH_MESHEDITOR_IDL_ @@ -576,6 +576,49 @@ module SMESH * not creared - returns empty list */ long_array GetLastCreatedElems(); + + /*! + * \brief Creates a hole in a mesh by doubling the nodes of some particular elements + * \param theNodes - identifiers of nodes to be doubled + * \param theModifiedElems - identifiers of elements to be updated by the new (doubled) + * nodes. If list of element identifiers is empty then nodes are doubled but + * they not assigned to elements + * \return TRUE if operation has been completed successfully, FALSE otherwise + * \sa DoubleNode(), DoubleNodeGroup(), DoubleNodeGroups() + */ + boolean DoubleNodes( in long_array theNodes, in long_array theModifiedElems ); + + /*! + * \brief Creates a hole in a mesh by doubling the nodes of some particular elements + * This method provided for convenience works as DoubleNodes() described above. + * \param theNodeId - identifier of node to be doubled. + * \param theModifiedElems - identifiers of elements to be updated. + * \return TRUE if operation has been completed successfully, FALSE otherwise + * \sa DoubleNodes(), DoubleNodeGroup(), DoubleNodeGroups() + */ + boolean DoubleNode( in long theNodeId, in long_array theModifiedElems ); + + /*! + * \brief Creates a hole in a mesh by doubling the nodes of some particular elements + * This method provided for convenience works as DoubleNodes() described above. + * \param theNodes - group of nodes to be doubled. + * \param theModifiedElems - group of elements to be updated. + * \return TRUE if operation has been completed successfully, FALSE otherwise + * \sa DoubleNode(), DoubleNodes(), DoubleNodeGroups() + */ + boolean DoubleNodeGroup( in SMESH_GroupBase theNodes, + in SMESH_GroupBase theModifiedElems ); + + /*! + \brief Creates a hole in a mesh by doubling the nodes of some particular elements + This method provided for convenience works as DoubleNodes() described above. + \param theNodes - list of groups of nodes to be doubled + \param theModifiedElems - list of groups of elements to be updated. + \return TRUE if operation has been completed successfully, FALSE otherwise + \sa DoubleNode(), DoubleNodeGroup(), DoubleNodes() + */ + boolean DoubleNodeGroups( in ListOfGroups theNodes, + in ListOfGroups theModifiedElems ); }; }; diff --git a/resources/Makefile.am b/resources/Makefile.am index 5c804268b..2ebd83edf 100644 --- a/resources/Makefile.am +++ b/resources/Makefile.am @@ -23,7 +23,6 @@ # Author : Patrick GOLDBRONN (CEA) # Date : 28/06/2001 # Modified by : Alexander BORODIN (OCN) - autotools usage -# $Header$ # include $(top_srcdir)/adm_local/unix/make_common_starter.am @@ -58,6 +57,7 @@ dist_salomeres_DATA = \ mesh_length_2d.png \ mesh_free_edges.png \ mesh_free_edges_2d.png \ + mesh_free_nodes.png \ mesh_multi_edges.png \ mesh_multi_edges_2d.png \ mesh_line_n.png \ @@ -162,7 +162,10 @@ dist_salomeres_DATA = \ mesh_tree_hypo_projection_2d.png \ mesh_build_compound.png \ mesh_node_to_point.png \ - mesh_tree_mesh_partial.png + mesh_tree_mesh_partial.png \ + mesh_extractGroup.png \ + mesh_precompute.png \ + mesh_free_faces.png # VSR: little trick to avoid putting if SMESHCatalog.xml to the distribution archive nodist_salomeres_SCRIPTS = SMESHCatalog.xml diff --git a/resources/SalomeApp.xml b/resources/SalomeApp.xml index 0390e89a7..6a8d6d34d 100644 --- a/resources/SalomeApp.xml +++ b/resources/SalomeApp.xml @@ -46,9 +46,9 @@ - - - + + + @@ -57,15 +57,16 @@ - - + + - + +
diff --git a/resources/StdMeshers.xml b/resources/StdMeshers.xml index 54fb82fe8..4adf93e83 100644 --- a/resources/StdMeshers.xml +++ b/resources/StdMeshers.xml @@ -44,6 +44,11 @@ icon-id="mesh_hypo_length.png" dim="1"/> + + diff --git a/resources/mesh_extractGroup.png b/resources/mesh_extractGroup.png new file mode 100755 index 0000000000000000000000000000000000000000..39ad763957b5045859134f318b9e3f4d547ca718 GIT binary patch literal 588 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 theId ); + const SMDSAbs_ElementType anElemType = anElem->GetType(); + if ( !anElem || (myType != SMDSAbs_All && anElemType != myType) ) + return false; + const int aNbNode = anElem->NbNodes(); + bool isOk = false; + switch( anElemType ) + { + case SMDSAbs_Node: + isOk = (myGeomType == SMDSGeom_POINT); + break; + + case SMDSAbs_Edge: + isOk = (myGeomType == SMDSGeom_EDGE); + break; + + case SMDSAbs_Face: + if ( myGeomType == SMDSGeom_TRIANGLE ) + isOk = (!anElem->IsPoly() && aNbNode == 3); + else if ( myGeomType == SMDSGeom_QUADRANGLE ) + isOk = (!anElem->IsPoly() && aNbNode == 4); + else if ( myGeomType == SMDSGeom_POLYGON ) + isOk = anElem->IsPoly(); + break; + + case SMDSAbs_Volume: + if ( myGeomType == SMDSGeom_TETRA ) + isOk = (!anElem->IsPoly() && aNbNode == 4); + else if ( myGeomType == SMDSGeom_PYRAMID ) + isOk = (!anElem->IsPoly() && aNbNode == 5); + else if ( myGeomType == SMDSGeom_PENTA ) + isOk = (!anElem->IsPoly() && aNbNode == 6); + else if ( myGeomType == SMDSGeom_HEXA ) + isOk = (!anElem->IsPoly() && aNbNode == 8); + else if ( myGeomType == SMDSGeom_POLYHEDRA ) + isOk = anElem->IsPoly(); + break; + default: break; + } + return isOk; +} + +void ElemGeomType::SetType( SMDSAbs_ElementType theType ) +{ + myType = theType; +} + +SMDSAbs_ElementType ElemGeomType::GetType() const +{ + return myType; +} + +void ElemGeomType::SetGeomType( SMDSAbs_GeometryType theType ) +{ + myGeomType = theType; +} + +SMDSAbs_GeometryType ElemGeomType::GetGeomType() const +{ + return myGeomType; +} + /* Class : RangeOfIds Description : Predicate for Range of Ids. diff --git a/src/Controls/SMESH_ControlsDef.hxx b/src/Controls/SMESH_ControlsDef.hxx index abc5117cd..d692a6e5d 100644 --- a/src/Controls/SMESH_ControlsDef.hxx +++ b/src/Controls/SMESH_ControlsDef.hxx @@ -38,6 +38,7 @@ #include #include #include +#include #include "SMDSAbs_ElementType.hxx" #include "SMDS_MeshNode.hxx" @@ -382,7 +383,23 @@ namespace SMESH{ const SMDS_Mesh* myMesh; }; typedef boost::shared_ptr FreeEdgesPtr; + + + /* + Class : FreeNodes + Description : Predicate for free nodes + */ + class SMESHCONTROLS_EXPORT FreeNodes: public virtual Predicate{ + public: + FreeNodes(); + virtual void SetMesh( const SMDS_Mesh* theMesh ); + virtual bool IsSatisfy( long theNodeId ); + virtual SMDSAbs_ElementType GetType() const; + protected: + const SMDS_Mesh* myMesh; + }; + /* Class : RangeOfIds @@ -696,6 +713,83 @@ namespace SMESH{ typedef boost::shared_ptr ElementsOnShapePtr; + /* + Class : FreeFaces + Description : Predicate for free faces + */ + class SMESHCONTROLS_EXPORT FreeFaces: public virtual Predicate{ + public: + FreeFaces(); + virtual void SetMesh( const SMDS_Mesh* theMesh ); + virtual bool IsSatisfy( long theElementId ); + virtual SMDSAbs_ElementType GetType() const; + + private: + const SMDS_Mesh* myMesh; + }; + + /* + Class : LinearOrQuadratic + Description : Predicate for free faces + */ + class SMESHCONTROLS_EXPORT LinearOrQuadratic: public virtual Predicate{ + public: + LinearOrQuadratic(); + virtual void SetMesh( const SMDS_Mesh* theMesh ); + virtual bool IsSatisfy( long theElementId ); + void SetType( SMDSAbs_ElementType theType ); + virtual SMDSAbs_ElementType GetType() const; + + private: + const SMDS_Mesh* myMesh; + SMDSAbs_ElementType myType; + }; + typedef boost::shared_ptr LinearOrQuadraticPtr; + + /* + Class : GroupColor + Description : Functor for check color of group to whic mesh element belongs to + */ + class SMESHCONTROLS_EXPORT GroupColor: public virtual Predicate{ + public: + GroupColor(); + virtual void SetMesh( const SMDS_Mesh* theMesh ); + virtual bool IsSatisfy( long theElementId ); + void SetType( SMDSAbs_ElementType theType ); + virtual SMDSAbs_ElementType GetType() const; + void SetColorStr( const TCollection_AsciiString& ); + void GetColorStr( TCollection_AsciiString& ) const; + + private: + typedef std::set< long > TIDs; + + Quantity_Color myColor; + SMDSAbs_ElementType myType; + TIDs myIDs; + }; + typedef boost::shared_ptr GroupColorPtr; + + /* + Class : ElemGeomType + Description : Predicate to check element geometry type + */ + class SMESHCONTROLS_EXPORT ElemGeomType: public virtual Predicate{ + public: + ElemGeomType(); + virtual void SetMesh( const SMDS_Mesh* theMesh ); + virtual bool IsSatisfy( long theElementId ); + void SetType( SMDSAbs_ElementType theType ); + virtual SMDSAbs_ElementType GetType() const; + void SetGeomType( SMDSAbs_GeometryType theType ); + virtual SMDSAbs_GeometryType GetGeomType() const; + + private: + const SMDS_Mesh* myMesh; + SMDSAbs_ElementType myType; + SMDSAbs_GeometryType myGeomType; + }; + typedef boost::shared_ptr ElemGeomTypePtr; + /* FILTER */ diff --git a/src/OBJECT/SMESH_Actor.cxx b/src/OBJECT/SMESH_Actor.cxx index 7be22f7c5..49d838bac 100644 --- a/src/OBJECT/SMESH_Actor.cxx +++ b/src/OBJECT/SMESH_Actor.cxx @@ -23,8 +23,8 @@ // File : SMESH_Actor.cxx // Author : Nicolas REJNERI // Module : SMESH -// $Header$ -// + + #include "SMESH_ActorDef.h" #include "SMESH_ActorUtils.h" #include "SMESH_DeviceActor.h" @@ -153,6 +153,27 @@ SMESH_ActorDef::SMESH_ActorDef() aFilter->RegisterCellsWithType(VTK_QUADRATIC_TRIANGLE); aFilter->RegisterCellsWithType(VTK_QUADRATIC_QUAD); + my2DExtProp = vtkProperty::New(); + my2DExtProp->DeepCopy(mySurfaceProp); + SMESH::GetColor( "SMESH", "fill_color", anRGB[0], anRGB[1], anRGB[2], QColor( 0, 170, 255 ) ); + anRGB[0] = 1 - anRGB[0]; + anRGB[1] = 1 - anRGB[1]; + anRGB[2] = 1 - anRGB[2]; + my2DExtProp->SetColor(anRGB[0],anRGB[1],anRGB[2]); + + my2DExtActor = SMESH_DeviceActor::New(); + my2DExtActor->SetUserMatrix(aMatrix); + my2DExtActor->PickableOff(); + my2DExtActor->SetProperty(my2DExtProp); + my2DExtActor->SetBackfaceProperty(my2DExtProp); + my2DExtActor->SetRepresentation(SMESH_DeviceActor::eInsideframe); + aFilter = my2DExtActor->GetExtractUnstructuredGrid(); + aFilter->RegisterCellsWithType(VTK_TRIANGLE); + aFilter->RegisterCellsWithType(VTK_POLYGON); + aFilter->RegisterCellsWithType(VTK_QUAD); + aFilter->RegisterCellsWithType(VTK_QUADRATIC_TRIANGLE); + aFilter->RegisterCellsWithType(VTK_QUADRATIC_QUAD); + my3DActor = SMESH_DeviceActor::New(); my3DActor->SetUserMatrix(aMatrix); my3DActor->PickableOff(); @@ -196,7 +217,7 @@ SMESH_ActorDef::SMESH_ActorDef() my1DProp->DeepCopy(myEdgeProp); my1DProp->SetLineWidth(aLineWidth + aLineWidthInc); my1DProp->SetPointSize(aPointSize); - + my1DExtProp = vtkProperty::New(); my1DExtProp->DeepCopy(myEdgeProp); anRGB[0] = 1 - anRGB[0]; @@ -235,7 +256,26 @@ SMESH_ActorDef::SMESH_ActorDef() myNodeActor->SetRepresentation(SMESH_DeviceActor::ePoint); aFilter = myNodeActor->GetExtractUnstructuredGrid(); aFilter->SetModeOfExtraction(VTKViewer_ExtractUnstructuredGrid::ePoints); - + + myNodeExtProp = vtkProperty::New(); + myNodeExtProp->DeepCopy(myNodeProp); + anRGB[0] = 1 - anRGB[0]; + anRGB[1] = 1 - anRGB[1]; + anRGB[2] = 1 - anRGB[2]; + myNodeExtProp->SetColor(anRGB[0],anRGB[1],anRGB[2]); + myNodeExtProp->SetPointSize(aPointSize); + + myNodeExtActor = SMESH_DeviceActor::New(); + myNodeExtActor->SetUserMatrix(aMatrix); + myNodeExtActor->SetStoreClippingMapping(true); + myNodeExtActor->PickableOff(); + myNodeExtActor->SetHighlited(true); + myNodeExtActor->SetVisibility(false); + myNodeExtActor->SetProperty(myNodeExtProp); + myNodeExtActor->SetRepresentation(SMESH_DeviceActor::ePoint); + aFilter = myNodeExtActor->GetExtractUnstructuredGrid(); + aFilter->SetModeOfExtraction(VTKViewer_ExtractUnstructuredGrid::ePoints); + aFilter->RegisterCellsWithType(VTK_VERTEX); //Definition of Pickable and Highlitable engines //---------------------------------------------- @@ -393,7 +433,8 @@ SMESH_ActorDef::~SMESH_ActorDef() myPreselectProp->Delete(); myNodeProp->Delete(); - + myNodeExtProp->Delete(); + my1DProp->Delete(); my1DActor->Delete(); @@ -401,11 +442,15 @@ SMESH_ActorDef::~SMESH_ActorDef() my1DExtActor->Delete(); my2DActor->Delete(); + my2DExtProp->Delete(); + my2DExtActor->Delete(); my3DActor->Delete(); myNodeActor->Delete(); myBaseActor->Delete(); + myNodeExtActor->Delete(); + myHighlitableActor->Delete(); //Deleting of pints numbering pipeline @@ -581,6 +626,14 @@ SetControlMode(eControl theMode, aFunctor.reset(new SMESH::Controls::FreeEdges()); myControlActor = my2DActor; break; + case eFreeNodes: + aFunctor.reset(new SMESH::Controls::FreeNodes()); + myControlActor = myNodeActor; + break; + case eFreeFaces: + aFunctor.reset(new SMESH::Controls::FreeFaces()); + myControlActor = my2DActor; + break; case eMultiConnection: aFunctor.reset(new SMESH::Controls::MultiConnection()); myControlActor = my1DActor; @@ -662,10 +715,16 @@ SetControlMode(eControl theMode, if(aNbCells){ myControlMode = theMode; switch(myControlMode){ + case eFreeNodes: + myNodeExtActor->SetExtControlMode(aFunctor); + break; case eFreeEdges: case eFreeBorders: my1DExtActor->SetExtControlMode(aFunctor); break; + case eFreeFaces: + my2DExtActor->SetExtControlMode(aFunctor); + break; case eLength2D: case eMultiConnection2D: my1DExtActor->SetExtControlMode(aFunctor,myScalarBarActor,myLookupTable); @@ -682,6 +741,7 @@ SetControlMode(eControl theMode, switch(myControlMode){ case eLength2D: case eFreeEdges: + case eFreeFaces: case eMultiConnection2D: //SetEntityMode(eEdges); SetEntityMode(eFaces); @@ -709,15 +769,18 @@ void SMESH_ActorDef::AddToRender(vtkRenderer* theRenderer){ theRenderer->AddActor(myNodeActor); theRenderer->AddActor(myBaseActor); + + theRenderer->AddActor(myNodeExtActor); my3DActor->AddToRender(theRenderer); my2DActor->AddToRender(theRenderer); + my2DExtActor->AddToRender(theRenderer); theRenderer->AddActor(my1DActor); theRenderer->AddActor(my1DExtActor); theRenderer->AddActor(myHighlitableActor); - + theRenderer->AddActor2D(myScalarBarActor); myPtsSelectVisiblePoints->SetRenderer(theRenderer); @@ -733,12 +796,15 @@ void SMESH_ActorDef::RemoveFromRender(vtkRenderer* theRenderer){ theRenderer->RemoveActor(myNodeActor); theRenderer->RemoveActor(myBaseActor); + theRenderer->RemoveActor(myNodeExtActor); + theRenderer->RemoveActor(myHighlitableActor); theRenderer->RemoveActor(my1DActor); theRenderer->RemoveActor(my1DExtActor); my2DActor->RemoveFromRender(theRenderer); + my2DExtActor->RemoveFromRender(theRenderer); my3DActor->RemoveFromRender(theRenderer); theRenderer->RemoveActor(myScalarBarActor); @@ -761,24 +827,29 @@ bool SMESH_ActorDef::Init(TVisualObjPtr theVisualObj, myNodeActor->Init(myVisualObj,myImplicitBoolean); myBaseActor->Init(myVisualObj,myImplicitBoolean); - + myHighlitableActor->Init(myVisualObj,myImplicitBoolean); + + myNodeExtActor->Init(myVisualObj,myImplicitBoolean); my1DActor->Init(myVisualObj,myImplicitBoolean); my1DExtActor->Init(myVisualObj,myImplicitBoolean); my2DActor->Init(myVisualObj,myImplicitBoolean); + my2DExtActor->Init(myVisualObj,myImplicitBoolean); my3DActor->Init(myVisualObj,myImplicitBoolean); my1DActor->GetMapper()->SetLookupTable(myLookupTable); my1DExtActor->GetMapper()->SetLookupTable(myLookupTable); my2DActor->GetMapper()->SetLookupTable(myLookupTable); + my2DExtActor->GetMapper()->SetLookupTable(myLookupTable); my3DActor->GetMapper()->SetLookupTable(myLookupTable); vtkFloatingPointType aFactor, aUnits; my2DActor->GetPolygonOffsetParameters(aFactor,aUnits); my2DActor->SetPolygonOffsetParameters(aFactor,aUnits*0.75); + my2DExtActor->SetPolygonOffsetParameters(aFactor,aUnits*0.5); SUIT_ResourceMgr* mgr = SUIT_Session::session()->resourceMgr(); if( !mgr ) @@ -825,13 +896,16 @@ void SMESH_ActorDef::SetTransform(VTKViewer_Transform* theTransform){ myNodeActor->SetTransform(theTransform); myBaseActor->SetTransform(theTransform); - + myHighlitableActor->SetTransform(theTransform); + myNodeExtActor->SetTransform(theTransform); + my1DActor->SetTransform(theTransform); my1DExtActor->SetTransform(theTransform); my2DActor->SetTransform(theTransform); + my2DExtActor->SetTransform(theTransform); my3DActor->SetTransform(theTransform); Modified(); @@ -886,6 +960,7 @@ void SMESH_ActorDef::SetShrinkFactor(vtkFloatingPointType theValue){ my1DExtActor->SetShrinkFactor(theValue); my2DActor->SetShrinkFactor(theValue); + my2DExtActor->SetShrinkFactor(theValue); my3DActor->SetShrinkFactor(theValue); Modified(); @@ -900,6 +975,7 @@ void SMESH_ActorDef::SetShrink(){ my1DExtActor->SetShrink(); my2DActor->SetShrink(); + my2DExtActor->SetShrink(); my3DActor->SetShrink(); myIsShrunk = true; @@ -915,6 +991,7 @@ void SMESH_ActorDef::UnShrink(){ my1DExtActor->UnShrink(); my2DActor->UnShrink(); + my2DExtActor->UnShrink(); my3DActor->UnShrink(); myIsShrunk = false; @@ -951,10 +1028,13 @@ void SMESH_ActorDef::SetVisibility(int theMode, bool theIsUpdateRepersentation){ myNodeActor->VisibilityOff(); myBaseActor->VisibilityOff(); + myNodeExtActor->VisibilityOff(); + my1DActor->VisibilityOff(); my1DExtActor->VisibilityOff(); my2DActor->VisibilityOff(); + my2DExtActor->VisibilityOff(); my3DActor->VisibilityOff(); myScalarBarActor->VisibilityOff(); @@ -964,13 +1044,19 @@ void SMESH_ActorDef::SetVisibility(int theMode, bool theIsUpdateRepersentation){ if(GetVisibility()){ if(theIsUpdateRepersentation) SetRepresentation(GetRepresentation()); - + if(myControlMode != eNone){ switch(myControlMode){ + case eFreeNodes: + myNodeExtActor->VisibilityOn(); + break; case eFreeEdges: case eFreeBorders: my1DExtActor->VisibilityOn(); break; + case eFreeFaces: + my2DExtActor->VisibilityOn(); + break; case eLength2D: case eMultiConnection2D: my1DExtActor->VisibilityOn(); @@ -1117,6 +1203,7 @@ void SMESH_ActorDef::SetRepresentation(int theMode){ myPickableActor = myBaseActor; myNodeActor->SetVisibility(false); + myNodeExtActor->SetVisibility(false); vtkProperty *aProp = NULL, *aBackProp = NULL; SMESH_DeviceActor::EReperesent aReperesent = SMESH_DeviceActor::EReperesent(-1); switch(myRepresentation){ @@ -1141,12 +1228,15 @@ void SMESH_ActorDef::SetRepresentation(int theMode){ my2DActor->SetProperty(aProp); my2DActor->SetBackfaceProperty(aBackProp); my2DActor->SetRepresentation(aReperesent); + + my2DExtActor->SetRepresentation(aReperesent); my3DActor->SetProperty(aProp); my3DActor->SetBackfaceProperty(aBackProp); my3DActor->SetRepresentation(aReperesent); my1DExtActor->SetVisibility(false); + my2DExtActor->SetVisibility(false); switch(myControlMode){ case eLength: @@ -1331,6 +1421,7 @@ void SMESH_ActorDef::SetSufaceColor(vtkFloatingPointType r,vtkFloatingPointType void SMESH_ActorDef::GetSufaceColor(vtkFloatingPointType& r,vtkFloatingPointType& g,vtkFloatingPointType& b){ ::GetColor(mySurfaceProp,r,g,b); + my2DExtProp->SetColor(1.0-r,1.0-g,1.0-b); } void SMESH_ActorDef::SetBackSufaceColor(vtkFloatingPointType r,vtkFloatingPointType g,vtkFloatingPointType b){ @@ -1355,6 +1446,7 @@ void SMESH_ActorDef::GetEdgeColor(vtkFloatingPointType& r,vtkFloatingPointType& void SMESH_ActorDef::SetNodeColor(vtkFloatingPointType r,vtkFloatingPointType g,vtkFloatingPointType b){ myNodeProp->SetColor(r,g,b); + myNodeExtProp->SetColor(1.0-r,1.0-g,1.0-b); Modified(); } @@ -1398,6 +1490,7 @@ void SMESH_ActorDef::SetLineWidth(vtkFloatingPointType theVal){ void SMESH_ActorDef::SetNodeSize(vtkFloatingPointType theVal){ myNodeProp->SetPointSize(theVal); + myNodeExtProp->SetPointSize(theVal); myHighlightProp->SetPointSize(theVal); myPreselectProp->SetPointSize(theVal); @@ -1431,11 +1524,14 @@ SetImplicitFunctionUsed(bool theIsImplicitFunctionUsed) myBaseActor->SetImplicitFunctionUsed(theIsImplicitFunctionUsed); myHighlitableActor->SetImplicitFunctionUsed(theIsImplicitFunctionUsed); + + myNodeExtActor->SetImplicitFunctionUsed(theIsImplicitFunctionUsed); my1DActor->SetImplicitFunctionUsed(theIsImplicitFunctionUsed); my1DExtActor->SetImplicitFunctionUsed(theIsImplicitFunctionUsed); my2DActor->SetImplicitFunctionUsed(theIsImplicitFunctionUsed); + my2DExtActor->SetImplicitFunctionUsed(theIsImplicitFunctionUsed); my3DActor->SetImplicitFunctionUsed(theIsImplicitFunctionUsed); } @@ -1597,7 +1693,7 @@ void SMESH_ActorDef::UpdateScalarBar() else aScalarBarTitleProp->ItalicOff(); - if ( f.underline() ) + if ( f.overline() ) aScalarBarTitleProp->ShadowOn(); else aScalarBarTitleProp->ShadowOff(); @@ -1632,7 +1728,7 @@ void SMESH_ActorDef::UpdateScalarBar() else aScalarBarLabelProp->ItalicOff(); - if( f.underline() ) + if( f.overline() ) aScalarBarLabelProp->ShadowOn(); else aScalarBarLabelProp->ShadowOff(); diff --git a/src/OBJECT/SMESH_Actor.h b/src/OBJECT/SMESH_Actor.h index 94a9e0408..df02e86e4 100644 --- a/src/OBJECT/SMESH_Actor.h +++ b/src/OBJECT/SMESH_Actor.h @@ -23,8 +23,7 @@ // File : SMESH_Actor.h // Author : Nicolas REJNERI // Module : SMESH -// $Header$ -// + #ifndef SMESH_ACTOR_H #define SMESH_ACTOR_H @@ -95,9 +94,9 @@ class SMESHOBJECT_EXPORT SMESH_Actor: public SALOME_Actor virtual void SetFacesOriented(bool theIsFacesOriented) = 0; virtual bool GetFacesOriented() = 0; - enum eControl{eNone, eLength, eLength2D, eFreeBorders, eFreeEdges, eMultiConnection, - eArea, eTaper, eAspectRatio, eMinimumAngle, eWarping, eSkew, - eAspectRatio3D, eMultiConnection2D, eVolume3D}; + enum eControl{eNone, eLength, eLength2D, eFreeBorders, eFreeEdges, eFreeNodes, + eFreeFaces, eMultiConnection, eArea, eTaper, eAspectRatio, + eMinimumAngle, eWarping, eSkew, eAspectRatio3D, eMultiConnection2D, eVolume3D}; virtual void SetControlMode(eControl theMode) = 0; virtual eControl GetControlMode() = 0; diff --git a/src/OBJECT/SMESH_ActorDef.h b/src/OBJECT/SMESH_ActorDef.h index d1e43ff23..619f0096a 100644 --- a/src/OBJECT/SMESH_ActorDef.h +++ b/src/OBJECT/SMESH_ActorDef.h @@ -23,8 +23,8 @@ // File : SMESH_ActorDef.h // Author : Nicolas REJNERI // Module : SMESH -// $Header$ // + #ifndef SMESH_ACTORDEF_H #define SMESH_ACTORDEF_H @@ -215,10 +215,15 @@ class SMESH_ActorDef : public SMESH_Actor SMESH_DeviceActor* myHighlitableActor; eControl myControlMode; + vtkProperty* my2DExtProp; SMESH_DeviceActor* my2DActor; + SMESH_DeviceActor* my2DExtActor; SMESH_DeviceActor* my3DActor; SMESH_DeviceActor* myControlActor; + vtkProperty* myNodeExtProp; + SMESH_DeviceActor* myNodeExtActor; + vtkProperty* my1DProp; SMESH_DeviceActor* my1DActor; vtkProperty* my1DExtProp; diff --git a/src/OBJECT/SMESH_DeviceActor.cxx b/src/OBJECT/SMESH_DeviceActor.cxx index 64a1a15fb..c24f10bfc 100644 --- a/src/OBJECT/SMESH_DeviceActor.cxx +++ b/src/OBJECT/SMESH_DeviceActor.cxx @@ -23,8 +23,8 @@ // File : SMESH_DeviceActor.cxx // Author : // Module : SMESH -// $Header$ // + #include "SMESH_DeviceActor.h" #include "SMESH_ExtractGeometry.h" #include "SMESH_ControlsDef.hxx" @@ -483,13 +483,15 @@ SMESH_DeviceActor myVisualObj->UpdateFunctor(theFunctor); using namespace SMESH::Controls; - if(FreeBorders* aFreeBorders = dynamic_cast(theFunctor.get())){ + if ( dynamic_cast(theFunctor.get()) || + dynamic_cast(theFunctor.get()) ) { + Predicate* aFreePredicate = dynamic_cast(theFunctor.get()); myExtractUnstructuredGrid->SetModeOfChanging(VTKViewer_ExtractUnstructuredGrid::eAdding); vtkUnstructuredGrid* aGrid = myVisualObj->GetUnstructuredGrid(); vtkIdType aNbCells = aGrid->GetNumberOfCells(); for( vtkIdType i = 0; i < aNbCells; i++ ){ vtkIdType anObjId = myVisualObj->GetElemObjId(i); - if(aFreeBorders->IsSatisfy(anObjId)) + if(aFreePredicate->IsSatisfy(anObjId)) myExtractUnstructuredGrid->RegisterCell(i); } if(!myExtractUnstructuredGrid->IsCellsRegistered()) @@ -542,6 +544,18 @@ SMESH_DeviceActor SetUnstructuredGrid(aDataSet); aDataSet->Delete(); + }else if(FreeNodes* aFreeNodes = dynamic_cast(theFunctor.get())){ + myExtractUnstructuredGrid->SetModeOfChanging(VTKViewer_ExtractUnstructuredGrid::eAdding); + vtkUnstructuredGrid* aGrid = myVisualObj->GetUnstructuredGrid(); + vtkIdType aNbCells = aGrid->GetNumberOfCells(); + for( vtkIdType i = 0; i < aNbCells; i++ ){ + vtkIdType anObjId = myVisualObj->GetNodeObjId(i); + if(aFreeNodes->IsSatisfy(anObjId)) + myExtractUnstructuredGrid->RegisterCell(i); + } + if(!myExtractUnstructuredGrid->IsCellsRegistered()) + myExtractUnstructuredGrid->RegisterCell(-1); + SetUnstructuredGrid(myVisualObj->GetUnstructuredGrid()); } } diff --git a/src/SMDS/SMDSAbs_ElementType.hxx b/src/SMDS/SMDSAbs_ElementType.hxx index 314c7895e..a76772e3f 100644 --- a/src/SMDS/SMDSAbs_ElementType.hxx +++ b/src/SMDS/SMDSAbs_ElementType.hxx @@ -39,6 +39,26 @@ enum SMDSAbs_ElementType SMDSAbs_NbElementTypes }; +/*! enumeration for element geometry type */ +enum SMDSAbs_GeometryType +{ + // 0D element + SMDSGeom_POINT, + // 1D element + SMDSGeom_EDGE, + // 2D element + SMDSGeom_TRIANGLE, + SMDSGeom_QUADRANGLE, + SMDSGeom_POLYGON, + // 3D element + SMDSGeom_TETRA, + SMDSGeom_PYRAMID, + SMDSGeom_PENTA, + SMDSGeom_HEXA, + SMDSGeom_POLYHEDRA, +}; + + enum SMDSAbs_ElementOrder { ORDER_ANY, /*! entities of any order */ ORDER_LINEAR, /*! entities of 1st order */ diff --git a/src/SMESH/SMESH_Algo.cxx b/src/SMESH/SMESH_Algo.cxx index b22ef6343..b68acbe1c 100644 --- a/src/SMESH/SMESH_Algo.cxx +++ b/src/SMESH/SMESH_Algo.cxx @@ -23,8 +23,8 @@ // File : SMESH_Algo.cxx // Author : Paul RASCLE, EDF // Module : SMESH -// $Header$ // + #include "SMESH_Algo.hxx" #include "SMESH_Comment.hxx" #include "SMESH_Gen.hxx" @@ -285,12 +285,7 @@ bool SMESH_Algo::IsReversedSubMesh (const TopoDS_Face& theFace, //================================================================================ /*! - * \brief Initialize my parameter values by the mesh built on the geometry - * \param theMesh - the built mesh - * \param theShape - the geometry of interest - * \retval bool - true if parameter values have been successfully defined - * - * Just return false as the algorithm does not hold parameters values + * \brief Just return false as the algorithm does not hold parameters values */ //================================================================================ @@ -299,7 +294,10 @@ bool SMESH_Algo::SetParametersByMesh(const SMESH_Mesh* /*theMesh*/, { return false; } - +bool SMESH_Algo::SetParametersByElementSize(double, const SMESH_Mesh*) +{ + return false; +} //================================================================================ /*! * \brief Fill vector of node parameters on geometrical edge, including vertex nodes @@ -359,6 +357,70 @@ bool SMESH_Algo::GetNodeParamOnEdge(const SMESHDS_Mesh* theMesh, return theParams.size() > 1; } +//================================================================================ +/*! + * \brief Fill vector of node parameters on geometrical edge, including vertex nodes + * \param theMesh - The mesh containing nodes + * \param theEdge - The geometrical edge of interest + * \param theParams - The resulting vector of sorted node parameters + * \retval bool - false if not all parameters are OK + */ +//================================================================================ + +bool SMESH_Algo::GetSortedNodesOnEdge(const SMESHDS_Mesh* theMesh, + const TopoDS_Edge& theEdge, + const bool ignoreMediumNodes, + map< double, const SMDS_MeshNode* > & theNodes) +{ + theNodes.clear(); + + if ( !theMesh || theEdge.IsNull() ) + return false; + + SMESHDS_SubMesh * eSubMesh = theMesh->MeshElements( theEdge ); + if ( !eSubMesh || !eSubMesh->GetElements()->more() ) + return false; // edge is not meshed + + int nbNodes = 0; + set < double > paramSet; + if ( eSubMesh ) + { + // loop on nodes of an edge: sort them by param on edge + SMDS_NodeIteratorPtr nIt = eSubMesh->GetNodes(); + while ( nIt->more() ) + { + const SMDS_MeshNode* node = nIt->next(); + if ( ignoreMediumNodes ) { + SMDS_ElemIteratorPtr elemIt = node->GetInverseElementIterator(); + if ( elemIt->more() && elemIt->next()->IsMediumNode( node )) + continue; + } + const SMDS_PositionPtr& pos = node->GetPosition(); + if ( pos->GetTypeOfPosition() != SMDS_TOP_EDGE ) + return false; + const SMDS_EdgePosition* epos = + static_cast(node->GetPosition().get()); + theNodes.insert( make_pair( epos->GetUParameter(), node )); + ++nbNodes; + } + } + // add vertex nodes + TopoDS_Vertex v1, v2; + TopExp::Vertices(theEdge, v1, v2); + const SMDS_MeshNode* n1 = VertexNode( v1, (SMESHDS_Mesh*) theMesh ); + const SMDS_MeshNode* n2 = VertexNode( v2, (SMESHDS_Mesh*) theMesh ); + Standard_Real f, l; + BRep_Tool::Range(theEdge, f, l); + if ( v1.Orientation() != TopAbs_FORWARD ) + std::swap( f, l ); + if ( n1 && ++nbNodes ) + theNodes.insert( make_pair( f, n1 )); + if ( n2 && ++nbNodes ) + theNodes.insert( make_pair( l, n2 )); + + return theNodes.size() == nbNodes; +} + //================================================================================ /*! * \brief Make filter recognize only compatible hypotheses diff --git a/src/SMESH/SMESH_Algo.hxx b/src/SMESH/SMESH_Algo.hxx index 0e2ab7c22..806b3d0f2 100644 --- a/src/SMESH/SMESH_Algo.hxx +++ b/src/SMESH/SMESH_Algo.hxx @@ -23,8 +23,8 @@ // File : SMESH_Algo.hxx // Author : Paul RASCLE, EDF // Module : SMESH -// $Header$ // + #ifndef _SMESH_ALGO_HXX_ #define _SMESH_ALGO_HXX_ @@ -41,6 +41,7 @@ #include #include #include +#include class SMESH_Gen; class SMESH_Mesh; @@ -162,12 +163,10 @@ public: bool InitCompatibleHypoFilter( SMESH_HypoFilter & theFilter, const bool ignoreAuxiliary) const; /*! - * \brief Initialize my parameter values by the mesh built on the geometry - * - * Just return false as the algorithm does not hold parameters values + * \brief Just return false as the algorithm does not hold parameters values */ - virtual bool SetParametersByMesh(const SMESH_Mesh* theMesh, - const TopoDS_Shape& theShape); + virtual bool SetParametersByMesh(const SMESH_Mesh* theMesh, const TopoDS_Shape& theShape); + virtual bool SetParametersByElementSize(double elemLenght, const SMESH_Mesh* theMesh=0); /*! * \brief return compute error */ @@ -241,6 +240,18 @@ public: static bool GetNodeParamOnEdge(const SMESHDS_Mesh* theMesh, const TopoDS_Edge& theEdge, std::vector< double > & theParams); + /*! + * \brief Fill map of node parameter on geometrical edge to node it-self + * \param theMesh - The mesh containing nodes + * \param theEdge - The geometrical edge of interest + * \param theNodes - The resulting map + * \param ignoreMediumNodes - to store medium nodes of quadratic elements or not + * \retval bool - false if not all parameters are OK + */ + static bool GetSortedNodesOnEdge(const SMESHDS_Mesh* theMesh, + const TopoDS_Edge& theEdge, + const bool ignoreMediumNodes, + std::map< double, const SMDS_MeshNode* > & theNodes); /*! * \brief Find out elements orientation on a geometrical face * \param theFace - The face correctly oriented in the shape being meshed diff --git a/src/SMESH/SMESH_Gen.cxx b/src/SMESH/SMESH_Gen.cxx index f065be2c0..955e1335d 100644 --- a/src/SMESH/SMESH_Gen.cxx +++ b/src/SMESH/SMESH_Gen.cxx @@ -23,8 +23,7 @@ // File : SMESH_Gen.cxx // Author : Paul RASCLE, EDF // Module : SMESH -// $Header$ -// + #include "SMESH_Gen.hxx" #include "SMESH_subMesh.hxx" #include "SMESH_HypoFilter.hxx" @@ -54,6 +53,7 @@ SMESH_Gen::SMESH_Gen() MESSAGE("SMESH_Gen::SMESH_Gen"); _localId = 0; _hypId = 0; + _segmentation = 10; } //============================================================================= @@ -128,9 +128,11 @@ SMESH_Mesh* SMESH_Gen::CreateMesh(int theStudyId, bool theIsEmbeddedMode) */ //============================================================================= -bool SMESH_Gen::Compute(SMESH_Mesh & aMesh, - const TopoDS_Shape & aShape, - const bool anUpward) +bool SMESH_Gen::Compute(SMESH_Mesh & aMesh, + const TopoDS_Shape & aShape, + const bool anUpward, + const ::MeshDimension aDim, + TSetOfInt* aShapesId) { MESSAGE("SMESH_Gen::Compute"); @@ -154,16 +156,27 @@ bool SMESH_Gen::Compute(SMESH_Mesh & aMesh, SMESH_subMesh* smToCompute = smIt->next(); // do not mesh vertices of a pseudo shape - if ( !aMesh.HasShapeToMesh() && - smToCompute->GetSubShape().ShapeType() == TopAbs_VERTEX ) + const TopAbs_ShapeEnum aShType = smToCompute->GetSubShape().ShapeType(); + if ( !aMesh.HasShapeToMesh() && aShType == TopAbs_VERTEX ) continue; + // check for preview dimension limitations + if ( aShapesId && GetShapeDim( aShType ) > (int)aDim ) + { + // clear compute state to not show previous compute errors + // if preview invoked less dimension less than previous + smToCompute->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE ); + continue; + } + if (smToCompute->GetComputeState() == SMESH_subMesh::READY_TO_COMPUTE) smToCompute->ComputeStateEngine( SMESH_subMesh::COMPUTE ); // we check all the submeshes here and detect if any of them failed to compute if (smToCompute->GetComputeState() == SMESH_subMesh::FAILED_TO_COMPUTE) ret = false; + else if ( aShapesId ) + aShapesId->insert( smToCompute->GetId() ); } return ret; } @@ -183,7 +196,12 @@ bool SMESH_Gen::Compute(SMESH_Mesh & aMesh, continue; const TopoDS_Shape& aSubShape = smToCompute->GetSubShape(); - if ( GetShapeDim( aSubShape ) < 1 ) break; + const int aShapeDim = GetShapeDim( aSubShape ); + if ( aShapeDim < 1 ) break; + + // check for preview dimension limitations + if ( aShapesId && aShapeDim > (int)aDim ) + continue; SMESH_Algo* algo = GetAlgo( aMesh, aSubShape ); if ( algo && !algo->NeedDescretBoundary() ) @@ -191,7 +209,11 @@ bool SMESH_Gen::Compute(SMESH_Mesh & aMesh, if ( algo->SupportSubmeshes() ) smWithAlgoSupportingSubmeshes.push_back( smToCompute ); else + { smToCompute->ComputeStateEngine( SMESH_subMesh::COMPUTE ); + if ( aShapesId ) + aShapesId->insert( smToCompute->GetId() ); + } } } // ------------------------------------------------------------ @@ -218,8 +240,14 @@ bool SMESH_Gen::Compute(SMESH_Mesh & aMesh, SMESH_subMesh* smToCompute = smIt->next(); const TopoDS_Shape& aSubShape = smToCompute->GetSubShape(); - if ( aSubShape.ShapeType() == TopAbs_VERTEX ) continue; - + const int aShapeDim = GetShapeDim( aSubShape ); + //if ( aSubShape.ShapeType() == TopAbs_VERTEX ) continue; + if ( aShapeDim < 1 ) continue; + + // check for preview dimension limitations + if ( aShapesId && GetShapeDim( aSubShape.ShapeType() ) > (int)aDim ) + continue; + SMESH_HypoFilter filter( SMESH_HypoFilter::IsAlgo() ); filter .And( SMESH_HypoFilter::IsApplicableTo( aSubShape )) @@ -228,8 +256,8 @@ bool SMESH_Gen::Compute(SMESH_Mesh & aMesh, if ( SMESH_Algo* subAlgo = (SMESH_Algo*) aMesh.GetHypothesis( aSubShape, filter, true )) { SMESH_Hypothesis::Hypothesis_Status status; if ( subAlgo->CheckHypothesis( aMesh, aSubShape, status )) - // mesh a lower smToCompute - Compute( aMesh, aSubShape ); + // mesh a lower smToCompute starting from vertices + Compute( aMesh, aSubShape, /*anUpward=*/true, aDim, aShapesId ); } } } @@ -238,12 +266,21 @@ bool SMESH_Gen::Compute(SMESH_Mesh & aMesh, // ---------------------------------------------------------- for ( subIt = smWithAlgoSupportingSubmeshes.rbegin(); subIt != subEnd; ++subIt ) if ( sm->GetComputeState() == SMESH_subMesh::READY_TO_COMPUTE) + { + const TopAbs_ShapeEnum aShType = sm->GetSubShape().ShapeType(); + // check for preview dimension limitations + if ( aShapesId && GetShapeDim( aShType ) > (int)aDim ) + continue; + sm->ComputeStateEngine( SMESH_subMesh::COMPUTE ); + if ( aShapesId ) + aShapesId->insert( sm->GetId() ); + } // ----------------------------------------------- // mesh the rest subshapes starting from vertices // ----------------------------------------------- - ret = Compute( aMesh, aShape, /*anUpward=*/true ); + ret = Compute( aMesh, aShape, /*anUpward=*/true, aDim, aShapesId ); } MESSAGE( "VSR - SMESH_Gen::Compute() finished, OK = " << ret); @@ -665,35 +702,35 @@ StudyContextStruct *SMESH_Gen::GetStudyContext(int studyId) return myStudyContext; } -//============================================================================= -/*! - * - */ -//============================================================================= +// //============================================================================= +// /*! +// * +// */ +// //============================================================================= -void SMESH_Gen::Save(int studyId, const char *aUrlOfFile) -{ -} +// void SMESH_Gen::Save(int studyId, const char *aUrlOfFile) +// { +// } -//============================================================================= -/*! - * - */ -//============================================================================= +// //============================================================================= +// /*! +// * +// */ +// //============================================================================= -void SMESH_Gen::Load(int studyId, const char *aUrlOfFile) -{ -} +// void SMESH_Gen::Load(int studyId, const char *aUrlOfFile) +// { +// } -//============================================================================= -/*! - * - */ -//============================================================================= +// //============================================================================= +// /*! +// * +// */ +// //============================================================================= -void SMESH_Gen::Close(int studyId) -{ -} +// void SMESH_Gen::Close(int studyId) +// { +// } //============================================================================= /*! @@ -707,14 +744,14 @@ int SMESH_Gen::GetShapeDim(const TopAbs_ShapeEnum & aShapeType) if ( dim.empty() ) { dim.resize( TopAbs_SHAPE, -1 ); - dim[ TopAbs_COMPOUND ] = 3; - dim[ TopAbs_COMPSOLID ] = 3; - dim[ TopAbs_SOLID ] = 3; - dim[ TopAbs_SHELL ] = 3; - dim[ TopAbs_FACE ] = 2; - dim[ TopAbs_WIRE ] = 1; - dim[ TopAbs_EDGE ] = 1; - dim[ TopAbs_VERTEX ] = 0; + dim[ TopAbs_COMPOUND ] = MeshDim_3D; + dim[ TopAbs_COMPSOLID ] = MeshDim_3D; + dim[ TopAbs_SOLID ] = MeshDim_3D; + dim[ TopAbs_SHELL ] = MeshDim_3D; + dim[ TopAbs_FACE ] = MeshDim_2D; + dim[ TopAbs_WIRE ] = MeshDim_1D; + dim[ TopAbs_EDGE ] = MeshDim_1D; + dim[ TopAbs_VERTEX ] = MeshDim_0D; } return dim[ aShapeType ]; } diff --git a/src/SMESH/SMESH_Gen.hxx b/src/SMESH/SMESH_Gen.hxx index 9d1b40561..855138ee8 100644 --- a/src/SMESH/SMESH_Gen.hxx +++ b/src/SMESH/SMESH_Gen.hxx @@ -23,8 +23,8 @@ // File : SMESH_Gen.hxx // Author : Paul RASCLE, EDF // Module : SMESH -// $Header$ // + #ifndef _SMESH_GEN_HXX_ #define _SMESH_GEN_HXX_ @@ -44,6 +44,7 @@ #include #include +#include class SMESHDS_Document; @@ -56,6 +57,8 @@ typedef struct studyContextStruct SMESHDS_Document * myDocument; } StudyContextStruct; +typedef std::set TSetOfInt; + class SMESH_EXPORT SMESH_Gen { public: @@ -68,16 +71,26 @@ class SMESH_EXPORT SMESH_Gen /*! * \brief Computes aMesh on aShape * \param anUpward - compute from vertices up to more complex shape (internal usage) + * \param aDim - upper level dimension of the mesh computation + * \param aShapesId - list of shapes with computed mesh entities (elements or nodes) * \retval bool - true if none submesh failed to compute */ - bool Compute(::SMESH_Mesh & aMesh, - const TopoDS_Shape & aShape, - const bool anUpward=false); + bool Compute(::SMESH_Mesh & aMesh, + const TopoDS_Shape & aShape, + const bool anUpward=false, + const ::MeshDimension aDim=::MeshDim_3D, + TSetOfInt* aShapesId=0); bool CheckAlgoState(SMESH_Mesh& aMesh, const TopoDS_Shape& aShape); // notify on bad state of attached algos, return false // if Compute() would fail because of some algo bad state + /*! + * \brief Sets number of segments per diagonal of boundary box of geometry by which + * default segment length of appropriate 1D hypotheses is defined + */ + void SetBoundaryBoxSegmentation( int theNbSegments ) { _segmentation = theNbSegments; } + int GetBoundaryBoxSegmentation() const { return _segmentation; } struct TAlgoStateError { @@ -109,13 +122,13 @@ class SMESH_EXPORT SMESH_Gen // inherited methods from SALOMEDS::Driver - void Save(int studyId, const char *aUrlOfFile); - void Load(int studyId, const char *aUrlOfFile); - void Close(int studyId); - const char *ComponentDataType(); +// void Save(int studyId, const char *aUrlOfFile); +// void Load(int studyId, const char *aUrlOfFile); +// void Close(int studyId); +// const char *ComponentDataType(); - const char *IORToLocalPersistentID(const char *IORString, bool & IsAFile); - const char *LocalPersistentIDToIOR(const char *aLocalPersistentID); +// const char *IORToLocalPersistentID(const char *IORString, bool & IsAFile); +// const char *LocalPersistentIDToIOR(const char *aLocalPersistentID); int GetANewId(); @@ -132,6 +145,10 @@ class SMESH_EXPORT SMESH_Gen // hypotheses managing int _hypId; + + // number of segments per diagonal of boundary box of geometry by which + // default segment length of appropriate 1D hypotheses is defined + int _segmentation; }; #endif diff --git a/src/SMESH/SMESH_Hypothesis.hxx b/src/SMESH/SMESH_Hypothesis.hxx index 355f166a4..366ffeab1 100644 --- a/src/SMESH/SMESH_Hypothesis.hxx +++ b/src/SMESH/SMESH_Hypothesis.hxx @@ -23,8 +23,8 @@ // File : SMESH_Hypothesis.hxx // Author : Paul RASCLE, EDF // Module : SMESH -// $Header$ // + #ifndef _SMESH_HYPOTHESIS_HXX_ #define _SMESH_HYPOTHESIS_HXX_ @@ -36,6 +36,14 @@ class SMESH_Gen; class TopoDS_Shape; class SMESH_Mesh; +enum MeshDimension // dimension of mesh +{ + MeshDim_0D = 0, + MeshDim_1D, + MeshDim_2D, + MeshDim_3D +}; + class SMESH_EXPORT SMESH_Hypothesis: public SMESHDS_Hypothesis { public: @@ -71,12 +79,18 @@ public: /*! * \brief Initialize my parameter values by the mesh built on the geometry - * \param theMesh - the built mesh - * \param theShape - the geometry of interest - * \retval bool - true if parameter values have been successfully defined + * \param theMesh - the built mesh + * \param theShape - the geometry of interest + * \retval bool - true if parameter values have been successfully defined */ virtual bool SetParametersByMesh(const SMESH_Mesh* theMesh, const TopoDS_Shape& theShape)=0; + /*! + * \brief Initialize my parameter values by linear size of mesh element. + * \retval bool - true if parameter values have been successfully defined + */ + virtual bool SetParametersByElementSize(double elemLenght, const SMESH_Mesh* theMesh=0)=0; + /*! * \brief Return true if me is an auxiliary hypothesis * \retval bool - auxiliary or not diff --git a/src/SMESH/SMESH_Mesh.cxx b/src/SMESH/SMESH_Mesh.cxx index 4479c7de8..5f29eb32c 100644 --- a/src/SMESH/SMESH_Mesh.cxx +++ b/src/SMESH/SMESH_Mesh.cxx @@ -23,7 +23,6 @@ // File : SMESH_Mesh.cxx // Author : Paul RASCLE, EDF // Module : SMESH -// $Header$ // #include "SMESH_Mesh.hxx" #include "SMESH_subMesh.hxx" @@ -50,7 +49,9 @@ #include "DriverSTL_R_SMDS_Mesh.h" #undef _Precision_HeaderFile +#include #include +#include #include #include #include @@ -95,6 +96,7 @@ SMESH_Mesh::SMESH_Mesh(int theLocalId, _myMeshDS = theDocument->GetMesh(_idDoc); _isShapeToMesh = false; _isAutoColor = false; + _shapeDiagonal = 0.0; _myMeshDS->ShapeToMesh( PseudoShape() ); } @@ -155,6 +157,8 @@ void SMESH_Mesh::ShapeToMesh(const TopoDS_Shape & aShape) // clear SMESHDS TopoDS_Shape aNullShape; _myMeshDS->ShapeToMesh( aNullShape ); + + _shapeDiagonal = 0.0; } // set a new geometry @@ -202,6 +206,33 @@ const TopoDS_Solid& SMESH_Mesh::PseudoShape() return aSolid; } +//======================================================================= +/*! + * \brief Return diagonal size of bounding box of a shape + */ +//======================================================================= + +double SMESH_Mesh::GetShapeDiagonalSize(const TopoDS_Shape & aShape) +{ + Bnd_Box Box; + BRepBndLib::Add(aShape, Box); + return sqrt( Box.SquareExtent() ); +} + +//======================================================================= +/*! + * \brief Return diagonal size of bounding box of shape to mesh + */ +//======================================================================= + +double SMESH_Mesh::GetShapeDiagonalSize() const +{ + if ( _shapeDiagonal == 0. && _isShapeToMesh ) + const_cast(this)->_shapeDiagonal = GetShapeDiagonalSize( GetShapeToMesh() ); + + return _shapeDiagonal; +} + //======================================================================= /*! * \brief Remove all nodes and elements @@ -265,6 +296,32 @@ void SMESH_Mesh::Clear() // } } +//======================================================================= +/*! + * \brief Remove all nodes and elements of indicated shape + */ +//======================================================================= + +void SMESH_Mesh::ClearSubMesh(const int theShapeId) +{ + // clear sub-meshes; get ready to re-compute as a side-effect + if ( SMESH_subMesh *sm = GetSubMeshContaining( theShapeId ) ) + { + SMESH_subMeshIteratorPtr smIt = sm->getDependsOnIterator(/*includeSelf=*/true, + /*complexShapeFirst=*/false); + while ( smIt->more() ) + { + sm = smIt->next(); + TopAbs_ShapeEnum shapeType = sm->GetSubShape().ShapeType(); + if ( shapeType == TopAbs_VERTEX || shapeType < TopAbs_SOLID ) + // all other shapes depends on vertices so they are already cleaned + sm->ComputeStateEngine( SMESH_subMesh::CLEAN ); + // to recompute even if failed + sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE ); + } + } +} + //======================================================================= //function : UNVToMesh //purpose : @@ -1453,3 +1510,41 @@ SMDSAbs_ElementType SMESH_Mesh::GetElementType( const int id, const bool iselem { return _myMeshDS->GetElementType( id, iselem ); } + +//============================================================================= +/*! + * \brief Convert group on geometry into standalone group + */ +//============================================================================= + +SMESH_Group* SMESH_Mesh::ConvertToStandalone ( int theGroupID ) +{ + SMESH_Group* aGroup = 0; + std::map < int, SMESH_Group * >::iterator itg = _mapGroup.find( theGroupID ); + if ( itg == _mapGroup.end() ) + return aGroup; + + SMESH_Group* anOldGrp = (*itg).second; + SMESHDS_GroupBase* anOldGrpDS = anOldGrp->GetGroupDS(); + if ( !anOldGrp || !anOldGrpDS ) + return aGroup; + + // create new standalone group + aGroup = new SMESH_Group (theGroupID, this, anOldGrpDS->GetType(), anOldGrp->GetName() ); + _mapGroup[theGroupID] = aGroup; + + SMESHDS_Group* aNewGrpDS = dynamic_cast( aGroup->GetGroupDS() ); + GetMeshDS()->RemoveGroup( anOldGrpDS ); + GetMeshDS()->AddGroup( aNewGrpDS ); + + // add elements (or nodes) into new created group + SMDS_ElemIteratorPtr anItr = anOldGrpDS->GetElements(); + while ( anItr->more() ) + aNewGrpDS->Add( (anItr->next())->GetID() ); + + // remove old group + delete anOldGrp; + + return aGroup; +} + diff --git a/src/SMESH/SMESH_Mesh.hxx b/src/SMESH/SMESH_Mesh.hxx index 2d2808a37..91ae67eda 100644 --- a/src/SMESH/SMESH_Mesh.hxx +++ b/src/SMESH/SMESH_Mesh.hxx @@ -23,7 +23,6 @@ // File : SMESH_Mesh.hxx // Author : Paul RASCLE, EDF // Module : SMESH -// $Header$ // #ifndef _SMESH_MESH_HXX_ #define _SMESH_MESH_HXX_ @@ -75,6 +74,14 @@ public: * \brief Return true if there is a geometry to be meshed, not PseudoShape() */ bool HasShapeToMesh() const { return _isShapeToMesh; } + /*! + * \brief Return diagonal size of bounding box of shape to mesh. + */ + double GetShapeDiagonalSize() const; + /*! + * \brief Return diagonal size of bounding box of a shape. + */ + static double GetShapeDiagonalSize(const TopoDS_Shape & aShape); /*! * \brief Return a solid which is returned by GetShapeToMesh() if * a real geometry to be meshed was not set @@ -86,6 +93,11 @@ public: */ void Clear(); + /*! + * \brief Remove all nodes and elements of indicated shape + */ + void ClearSubMesh(const int theShapeId); + int UNVToMesh(const char* theFileName); /*! * consult DriverMED_R_SMESHDS_Mesh::ReadStatus for returned value @@ -230,6 +242,7 @@ public: void RemoveGroup (const int theGroupID); + SMESH_Group* ConvertToStandalone ( int theGroupID ); SMDSAbs_ElementType GetElementType( const int id, const bool iselem ); @@ -253,6 +266,8 @@ protected: SMESH_Gen * _gen; bool _isAutoColor; + + double _shapeDiagonal; //!< diagonal size of bounding box of shape to mesh TopTools_IndexedDataMapOfShapeListOfShape _mapAncestors; diff --git a/src/SMESH/SMESH_MeshEditor.cxx b/src/SMESH/SMESH_MeshEditor.cxx index 487646ed9..063f68819 100644 --- a/src/SMESH/SMESH_MeshEditor.cxx +++ b/src/SMESH/SMESH_MeshEditor.cxx @@ -90,22 +90,6 @@ struct TNodeXYZ : public gp_XYZ { TNodeXYZ( const SMDS_MeshNode* n ):gp_XYZ( n->X(), n->Y(), n->Z() ) {} }; -typedef pair< const SMDS_MeshNode*, const SMDS_MeshNode* > NLink; - -//======================================================================= -/*! - * \brief A sorted pair of nodes - */ -//======================================================================= - -struct TLink: public NLink -{ - TLink(const SMDS_MeshNode* n1, const SMDS_MeshNode* n2 ):NLink( n1, n2 ) - { if ( n1->GetID() < n2->GetID() ) std::swap( first, second ); } - TLink(const NLink& link ):NLink( link ) - { if ( first->GetID() < second->GetID() ) std::swap( first, second ); } -}; - //======================================================================= //function : SMESH_MeshEditor //purpose : @@ -1479,10 +1463,10 @@ bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet & theElems, // 1. map of elements with their linkIDs // 2. map of linkIDs with their elements - map< TLink, list< const SMDS_MeshElement* > > mapLi_listEl; - map< TLink, list< const SMDS_MeshElement* > >::iterator itLE; - map< const SMDS_MeshElement*, set< TLink > > mapEl_setLi; - map< const SMDS_MeshElement*, set< TLink > >::iterator itEL; + map< SMESH_TLink, list< const SMDS_MeshElement* > > mapLi_listEl; + map< SMESH_TLink, list< const SMDS_MeshElement* > >::iterator itLE; + map< const SMDS_MeshElement*, set< SMESH_TLink > > mapEl_setLi; + map< const SMDS_MeshElement*, set< SMESH_TLink > >::iterator itEL; TIDSortedElemSet::iterator itElem; for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) { @@ -1501,7 +1485,7 @@ bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet & theElems, // fill maps for ( i = 0; i < 3; i++ ) { - TLink link( aNodes[i], aNodes[i+1] ); + SMESH_TLink link( aNodes[i], aNodes[i+1] ); // check if elements sharing a link can be fused itLE = mapLi_listEl.find( link ); if ( itLE != mapLi_listEl.end() ) { @@ -1527,7 +1511,7 @@ bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet & theElems, int nbElems = (*itLE).second.size(); if ( nbElems < 2 ) { const SMDS_MeshElement* elem = (*itLE).second.front(); - TLink link = (*itLE).first; + SMESH_TLink link = (*itLE).first; mapEl_setLi[ elem ].erase( link ); if ( mapEl_setLi[ elem ].empty() ) mapEl_setLi.erase( elem ); @@ -1553,11 +1537,11 @@ bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet & theElems, // search elements to fuse starting from startElem or links of elements // fused earlyer - startLinks - list< TLink > startLinks; + list< SMESH_TLink > startLinks; while ( startElem || !startLinks.empty() ) { while ( !startElem && !startLinks.empty() ) { // Get an element to start, by a link - TLink linkId = startLinks.front(); + SMESH_TLink linkId = startLinks.front(); startLinks.pop_front(); itLE = mapLi_listEl.find( linkId ); if ( itLE != mapLi_listEl.end() ) { @@ -1573,15 +1557,15 @@ bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet & theElems, if ( startElem ) { // Get candidates to be fused const SMDS_MeshElement *tr1 = startElem, *tr2 = 0, *tr3 = 0; - const TLink *link12, *link13; + const SMESH_TLink *link12, *link13; startElem = 0; ASSERT( mapEl_setLi.find( tr1 ) != mapEl_setLi.end() ); - set< TLink >& setLi = mapEl_setLi[ tr1 ]; + set< SMESH_TLink >& setLi = mapEl_setLi[ tr1 ]; ASSERT( !setLi.empty() ); - set< TLink >::iterator itLi; + set< SMESH_TLink >::iterator itLi; for ( itLi = setLi.begin(); itLi != setLi.end(); itLi++ ) { - const TLink & link = (*itLi); + const SMESH_TLink & link = (*itLi); itLE = mapLi_listEl.find( link ); if ( itLE == mapLi_listEl.end() ) continue; @@ -1602,10 +1586,10 @@ bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet & theElems, } // add other links of elem to list of links to re-start from - set< TLink >& links = mapEl_setLi[ elem ]; - set< TLink >::iterator it; + set< SMESH_TLink >& links = mapEl_setLi[ elem ]; + set< SMESH_TLink >::iterator it; for ( it = links.begin(); it != links.end(); it++ ) { - const TLink& link2 = (*it); + const SMESH_TLink& link2 = (*it); if ( link2 != link ) startLinks.push_back( link2 ); } @@ -2462,9 +2446,8 @@ void SMESH_MeshEditor::Smooth (TIDSortedElemSet & theElems, // fix nodes on mesh boundary if ( checkBoundaryNodes ) { - typedef pair TLink; - map< TLink, int > linkNbMap; // how many times a link encounters in elemsOnFace - map< TLink, int >::iterator link_nb; + map< NLink, int > linkNbMap; // how many times a link encounters in elemsOnFace + map< NLink, int >::iterator link_nb; // put all elements links to linkNbMap list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin(); for ( ; elemIt != elemsOnFace.end(); ++elemIt ) { @@ -2476,7 +2459,7 @@ void SMESH_MeshEditor::Smooth (TIDSortedElemSet & theElems, const SMDS_MeshNode* curNode, *prevNode = elem->GetNode( nbn ); for ( int iN = 0; iN < nbn; ++iN ) { curNode = elem->GetNode( iN ); - TLink link; + NLink link; if ( curNode < prevNode ) link = make_pair( curNode , prevNode ); else link = make_pair( prevNode , curNode ); prevNode = curNode; @@ -7547,8 +7530,8 @@ SMESH_MeshEditor::FindMatchingNodes(set& theSide1, if ( theSecondNode1 != theSecondNode2 ) nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 )); - set< TLink > linkSet; // set of nodes where order of nodes is ignored - linkSet.insert( TLink( theFirstNode1, theSecondNode1 )); + set< SMESH_TLink > linkSet; // set of nodes where order of nodes is ignored + linkSet.insert( SMESH_TLink( theFirstNode1, theSecondNode1 )); list< NLink > linkList[2]; linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 )); @@ -7663,8 +7646,8 @@ SMESH_MeshEditor::FindMatchingNodes(set& theSide1, for ( int i = 0; i < nbN; i++ ) { const SMDS_MeshNode* n2 = f0->GetNode( i ); - pair< set< TLink >::iterator, bool > iter_isnew = - linkSet.insert( TLink( n1, n2 )); + pair< set< SMESH_TLink >::iterator, bool > iter_isnew = + linkSet.insert( SMESH_TLink( n1, n2 )); if ( !iter_isnew.second ) { // already in a set: no need to process linkSet.erase( iter_isnew.first ); } @@ -7684,3 +7667,92 @@ SMESH_MeshEditor::FindMatchingNodes(set& theSide1, return SEW_OK; } + +/*! + \brief Creates a hole in a mesh by doubling the nodes of some particular elements + \param theNodes - identifiers of nodes to be doubled + \param theModifiedElems - identifiers of elements to be updated by the new (doubled) + nodes. If list of element identifiers is empty then nodes are doubled but + they not assigned to elements + \return TRUE if operation has been completed successfully, FALSE otherwise +*/ +bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes, + const std::list< int >& theListOfModifiedElems ) +{ + myLastCreatedElems.Clear(); + myLastCreatedNodes.Clear(); + + if ( theListOfNodes.size() == 0 ) + return false; + + SMESHDS_Mesh* aMeshDS = GetMeshDS(); + if ( !aMeshDS ) + return false; + + // iterate through nodes and duplicate them + + std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode; + + std::list< int >::const_iterator aNodeIter; + for ( aNodeIter = theListOfNodes.begin(); aNodeIter != theListOfNodes.end(); ++aNodeIter ) + { + int aCurr = *aNodeIter; + SMDS_MeshNode* aNode = (SMDS_MeshNode*)aMeshDS->FindNode( aCurr ); + if ( !aNode ) + continue; + + // duplicate node + + const SMDS_MeshNode* aNewNode = aMeshDS->AddNode( aNode->X(), aNode->Y(), aNode->Z() ); + if ( aNewNode ) + { + anOldNodeToNewNode[ aNode ] = aNewNode; + myLastCreatedNodes.Append( aNewNode ); + } + } + + // Create map of new nodes for modified elements + + std::map< SMDS_MeshElement*, vector > anElemToNodes; + + std::list< int >::const_iterator anElemIter; + for ( anElemIter = theListOfModifiedElems.begin(); + anElemIter != theListOfModifiedElems.end(); ++anElemIter ) + { + int aCurr = *anElemIter; + SMDS_MeshElement* anElem = (SMDS_MeshElement*)aMeshDS->FindElement( aCurr ); + if ( !anElem ) + continue; + + vector aNodeArr( anElem->NbNodes() ); + + SMDS_ElemIteratorPtr anIter = anElem->nodesIterator(); + int ind = 0; + while ( anIter->more() ) + { + SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next(); + if ( aCurr && anOldNodeToNewNode.find( aCurrNode ) != anOldNodeToNewNode.end() ) + { + const SMDS_MeshNode* aNewNode = anOldNodeToNewNode[ aCurrNode ]; + aNodeArr[ ind++ ] = aNewNode; + } + else + aNodeArr[ ind++ ] = aCurrNode; + } + anElemToNodes[ anElem ] = aNodeArr; + } + + // Change nodes of elements + + std::map< SMDS_MeshElement*, vector >::iterator + anElemToNodesIter = anElemToNodes.begin(); + for ( ; anElemToNodesIter != anElemToNodes.end(); ++anElemToNodesIter ) + { + const SMDS_MeshElement* anElem = anElemToNodesIter->first; + vector aNodeArr = anElemToNodesIter->second; + if ( anElem ) + aMeshDS->ChangeElementNodes( anElem, &aNodeArr[ 0 ], anElem->NbNodes() ); + } + + return true; +} diff --git a/src/SMESH/SMESH_MeshEditor.hxx b/src/SMESH/SMESH_MeshEditor.hxx index 6e9819e27..ccab3fbb6 100644 --- a/src/SMESH/SMESH_MeshEditor.hxx +++ b/src/SMESH/SMESH_MeshEditor.hxx @@ -47,6 +47,24 @@ typedef std::map > TElemOfElemListMap; typedef std::map TNodeNodeMap; + +typedef pair< const SMDS_MeshNode*, const SMDS_MeshNode* > NLink; + +//======================================================================= +/*! + * \brief A sorted pair of nodes + */ +//======================================================================= + +struct SMESH_TLink: public NLink +{ + SMESH_TLink(const SMDS_MeshNode* n1, const SMDS_MeshNode* n2 ):NLink( n1, n2 ) + { if ( n1->GetID() < n2->GetID() ) std::swap( first, second ); } + SMESH_TLink(const NLink& link ):NLink( link ) + { if ( first->GetID() < second->GetID() ) std::swap( first, second ); } +}; + + class SMDS_MeshFace; class SMDS_MeshNode; class gp_Ax1; @@ -509,6 +527,9 @@ public: const SMESH_SequenceOfElemPtr& GetLastCreatedNodes() const { return myLastCreatedNodes; } const SMESH_SequenceOfElemPtr& GetLastCreatedElems() const { return myLastCreatedElems; } + + bool DoubleNodes( const std::list< int >& theListOfNodes, + const std::list< int >& theListOfModifiedElems ); private: diff --git a/src/SMESHGUI/SMESHGUI.cxx b/src/SMESHGUI/SMESHGUI.cxx index 6b962be03..c8189a49a 100644 --- a/src/SMESHGUI/SMESHGUI.cxx +++ b/src/SMESHGUI/SMESHGUI.cxx @@ -771,6 +771,10 @@ aTitle = QObject::tr( "MULTI_BORDERS" ); aControl = SMESH_Actor::eMultiConnection; break; + case 6005: + aTitle = QObject::tr( "FREE_NODES" ); + aControl = SMESH_Actor::eFreeNodes; + break; case 6019: aTitle = QObject::tr( "MULTI2D_BORDERS" ); aControl = SMESH_Actor::eMultiConnection2D; @@ -807,6 +811,10 @@ aTitle = QObject::tr( "SMESH_VOLUME" ); aControl = SMESH_Actor::eVolume3D; break; + case 6021: + aTitle = QObject::tr( "FREE_FACES" ); + aControl = SMESH_Actor::eFreeFaces; + break; } anActor->SetControlMode(aControl); anActor->GetScalarBarActor()->SetTitle(aTitle.toLatin1().data()); @@ -1061,6 +1069,11 @@ SalomeApp_Module( "SMESH" ) { CORBA::Boolean anIsEmbeddedMode; myComponentSMESH = SMESH_Client::GetSMESHGen(getApp()->orb(),anIsEmbeddedMode); + + // 0019923: EDF 765 SMESH : default values of hypothesis + SUIT_ResourceMgr* aResourceMgr = SMESH::GetResourceMgr(this); + int nbSeg = aResourceMgr->integerValue( "SMESH", "segmentation" ); + myComponentSMESH->SetBoundaryBoxSegmentation( nbSeg ); } myActiveDialogBox = 0; @@ -1564,21 +1577,17 @@ bool SMESHGUI::OnGUIEvent( int theCommandID ) } case 701: // COMPUTE MESH + case 711: // PRECOMPUTE MESH { if (checkLock(aStudy)) break; - - startOperation( 701 ); + startOperation( theCommandID ); } break; - case 702: // Create mesh - startOperation( 702 ); - break; - case 703: // Create sub-mesh - startOperation( 703 ); - break; + case 702: // Create mesh + case 703: // Create sub-mesh case 704: // Edit mesh/sub-mesh - startOperation( 704 ); + startOperation( theCommandID ); break; case 710: // Build compound mesh { @@ -1880,6 +1889,36 @@ bool SMESHGUI::OnGUIEvent( int theCommandID ) break; } + case 815: // Edit GEOM GROUP as standalone + { + if ( !vtkwnd ) + { + SUIT_MessageBox::warning( desktop(), tr( "SMESH_WRN_WARNING" ), + tr( "NOT_A_VTK_VIEWER" ) ); + break; + } + + if(checkLock(aStudy)) break; + EmitSignalDeactivateDialog(); + + LightApp_SelectionMgr *aSel = SMESHGUI::selectionMgr(); + SALOME_ListIO selected; + if( aSel ) + aSel->selectedObjects( selected ); + + SALOME_ListIteratorOfListIO It (selected); + for ( ; It.More(); It.Next() ) + { + SMESH::SMESH_GroupOnGeom_var aGroup = + SMESH::IObjectToInterface(It.Value()); + if (!aGroup->_is_nil()) { + SMESHGUI_GroupDlg *aDlg = new SMESHGUI_GroupDlg( this, aGroup, true ); + aDlg->show(); + } + } + break; + } + case 810: // Union Groups case 811: // Intersect groups case 812: // Cut groups @@ -1896,12 +1935,28 @@ bool SMESHGUI::OnGUIEvent( int theCommandID ) EmitSignalDeactivateDialog(); - int aMode; - if ( theCommandID == 810 ) aMode = SMESHGUI_GroupOpDlg::UNION; - else if ( theCommandID == 811 ) aMode = SMESHGUI_GroupOpDlg::INTERSECT; - else aMode = SMESHGUI_GroupOpDlg::CUT; + SMESHGUI_GroupOpDlg* aDlg = 0; + if ( theCommandID == 810 ) + aDlg = new SMESHGUI_UnionGroupsDlg( this ); + else if ( theCommandID == 811 ) + aDlg = new SMESHGUI_IntersectGroupsDlg( this ); + else + aDlg = new SMESHGUI_CutGroupsDlg( this ); + + aDlg->show(); + + break; + } + + case 814: // Create groups of entities from existing groups of superior dimensions + { + if ( checkLock( aStudy ) ) + break; + + EmitSignalDeactivateDialog(); + SMESHGUI_GroupOpDlg* aDlg = new SMESHGUI_DimGroupDlg( this ); + aDlg->show(); - ( new SMESHGUI_GroupOpDlg( this, aMode ) )->show(); break; } @@ -2022,7 +2077,7 @@ bool SMESHGUI::OnGUIEvent( int theCommandID ) if( aSel ) aSel->selectedObjects( selected ); - bool isAny = false; // iss there any appropriate object selected + bool isAny = false; // is there any appropriate object selected SALOME_ListIteratorOfListIO It( selected ); for ( ; It.More(); It.Next() ) @@ -2050,14 +2105,7 @@ bool SMESHGUI::OnGUIEvent( int theCommandID ) newName = LightApp_NameDlg::getName(desktop(), newName); if ( !newName.isEmpty() ) { - //old source: aStudy->renameIObject( IObject, newName ); - aName->SetValue( newName.toLatin1().constData() ); - - // if current object is group update group's name - SMESH::SMESH_GroupBase_var aGroup = - SMESH::IObjectToInterface(IObject); - if (!aGroup->_is_nil() ) - aGroup->SetName( newName.toLatin1().constData() ); + SMESHGUI::GetSMESHGen()->SetName(obj->GetIOR().c_str(), newName.toLatin1().data()); updateObjBrowser(); } @@ -2390,7 +2438,9 @@ bool SMESHGUI::OnGUIEvent( int theCommandID ) case 6002: case 6003: case 6004: + case 6005: case 6009: + case 6021: if ( vtkwnd ) { LightApp_SelectionMgr* mgr = selectionMgr(); @@ -2596,23 +2646,28 @@ void SMESHGUI::initialize( CAM_Application* app ) createSMESHAction( 703, "CREATE_SUBMESH", "ICON_DLG_ADD_SUBMESH" ); createSMESHAction( 704, "EDIT_MESHSUBMESH","ICON_DLG_EDIT_MESH" ); createSMESHAction( 710, "BUILD_COMPOUND", "ICON_BUILD_COMPOUND" ); + createSMESHAction( 711, "PRECOMPUTE", "ICON_PRECOMPUTE" ); createSMESHAction( 806, "CREATE_GEO_GROUP","ICON_CREATE_GEO_GROUP" ); createSMESHAction( 801, "CREATE_GROUP", "ICON_CREATE_GROUP" ); createSMESHAction( 802, "CONSTRUCT_GROUP", "ICON_CONSTRUCT_GROUP" ); createSMESHAction( 803, "EDIT_GROUP", "ICON_EDIT_GROUP" ); + createSMESHAction( 815, "EDIT_GEOMGROUP_AS_GROUP", "ICON_EDIT_GROUP" ); createSMESHAction( 804, "ADD" ); createSMESHAction( 805, "REMOVE" ); createSMESHAction( 810, "UN_GROUP", "ICON_UNION" ); createSMESHAction( 811, "INT_GROUP", "ICON_INTERSECT" ); createSMESHAction( 812, "CUT_GROUP", "ICON_CUT" ); + createSMESHAction( 814, "UNDERLYING_ELEMS","ICON_UNDERLYING_ELEMS" ); createSMESHAction( 813, "DEL_GROUP", "ICON_DEL_GROUP" ); createSMESHAction( 900, "ADV_INFO", "ICON_ADV_INFO" ); createSMESHAction( 902, "STD_INFO", "ICON_STD_INFO" ); createSMESHAction( 903, "WHAT_IS", "ICON_WHAT_IS" ); createSMESHAction( 6001, "LENGTH", "ICON_LENGTH", 0, true ); createSMESHAction( 6002, "FREE_EDGE", "ICON_FREE_EDGE", 0, true ); + createSMESHAction( 6021, "FREE_FACES", "ICON_FREE_FACES", 0, true ); createSMESHAction( 6003, "FREE_BORDER", "ICON_FREE_EDGE_2D", 0, true ); createSMESHAction( 6004, "CONNECTION", "ICON_CONNECTION", 0, true ); + createSMESHAction( 6005, "FREE_NODE", "ICON_FREE_NODE", 0, true ); createSMESHAction( 6011, "AREA", "ICON_AREA", 0, true ); createSMESHAction( 6012, "TAPER", "ICON_TAPER", 0, true ); createSMESHAction( 6013, "ASPECT", "ICON_ASPECT", 0, true ); @@ -2731,16 +2786,20 @@ void SMESHGUI::initialize( CAM_Application* app ) createMenu( 710, meshId, -1 ); createMenu( separator(), meshId, -1 ); createMenu( 701, meshId, -1 ); + createMenu( 711, meshId, -1 ); createMenu( separator(), meshId, -1 ); createMenu( 801, meshId, -1 ); createMenu( 806, meshId, -1 ); createMenu( 802, meshId, -1 ); createMenu( 803, meshId, -1 ); + createMenu( 815, meshId, -1 ); createMenu( separator(), meshId, -1 ); createMenu( 810, meshId, -1 ); createMenu( 811, meshId, -1 ); createMenu( 812, meshId, -1 ); createMenu( separator(), meshId, -1 ); + createMenu( 814, meshId, -1 ); + createMenu( separator(), meshId, -1 ); createMenu( 813, meshId, -1 ); createMenu( separator(), meshId, -1 ); createMenu( 900, meshId, -1 ); @@ -2752,6 +2811,7 @@ void SMESHGUI::initialize( CAM_Application* app ) createMenu( 6001, ctrlId, -1 ); createMenu( 6004, ctrlId, -1 ); createMenu( separator(), ctrlId, -1 ); + createMenu( 6005, ctrlId, -1 ); createMenu( 6002, ctrlId, -1 ); createMenu( 6018, ctrlId, -1 ); createMenu( 6019, ctrlId, -1 ); @@ -2764,6 +2824,7 @@ void SMESHGUI::initialize( CAM_Application* app ) createMenu( separator(), ctrlId, -1 ); createMenu( 6017, ctrlId, -1 ); createMenu( 6009, ctrlId, -1 ); + createMenu( 6021, ctrlId, -1 ); createMenu( separator(), ctrlId, -1 ); createMenu( 400, addId, -1 ); @@ -2826,11 +2887,13 @@ void SMESHGUI::initialize( CAM_Application* app ) createTool( 710, meshTb ); createTool( separator(), meshTb ); createTool( 701, meshTb ); + createTool( 711, meshTb ); createTool( separator(), meshTb ); createTool( 801, meshTb ); createTool( 806, meshTb ); createTool( 802, meshTb ); createTool( 803, meshTb ); + //createTool( 815, meshTb ); createTool( separator(), meshTb ); createTool( 900, meshTb ); createTool( 902, meshTb ); @@ -2841,6 +2904,7 @@ void SMESHGUI::initialize( CAM_Application* app ) createTool( 6003, ctrlTb ); createTool( 6004, ctrlTb ); createTool( separator(), ctrlTb ); + createTool( 6005, ctrlTb ); createTool( 6002, ctrlTb ); createTool( 6018, ctrlTb ); createTool( 6019, ctrlTb ); @@ -2853,6 +2917,7 @@ void SMESHGUI::initialize( CAM_Application* app ) createTool( separator(), ctrlTb ); createTool( 6017, ctrlTb ); createTool( 6009, ctrlTb ); + createTool( 6021, ctrlTb ); createTool( separator(), ctrlTb ); createTool( 400, addRemTb ); @@ -2929,12 +2994,15 @@ void SMESHGUI::initialize( CAM_Application* app ) createPopupItem( 150, OB, mesh, "&& selcount=1 && isImported" ); // FILE INFORMATION createPopupItem( 703, OB, mesh, "&& isComputable"); // CREATE_SUBMESH - createPopupItem( 703, OB, subMesh, "&& isComputable" ); // CREATE_SUBMESH + //createPopupItem( 703, OB, subMesh, "&& isComputable" ); // CREATE_SUBMESH createPopupItem( 704, OB, mesh, "&& isComputable"); // EDIT_MESHSUBMESH createPopupItem( 704, OB, subMesh, "&& isComputable" ); // EDIT_MESHSUBMESH createPopupItem( 803, OB, group ); // EDIT_GROUP + createPopupItem( 815, OB, group, "&& groupType = 'GroupOnGeom'" ); // EDIT_GROUP + popupMgr()->insert( separator(), -1, 0 ); createPopupItem( 701, OB, mesh, "&& isComputable" ); // COMPUTE + createPopupItem( 711, OB, mesh, "&& isComputable" ); // PRECOMPUTE createPopupItem( 214, OB, mesh_group ); // UPDATE createPopupItem( 900, OB, mesh_group ); // ADV_INFO createPopupItem( 902, OB, mesh ); // STD_INFO @@ -2964,6 +3032,7 @@ void SMESHGUI::initialize( CAM_Application* app ) createPopupItem( 803, View, group ); // EDIT_GROUP createPopupItem( 804, View, elems ); // ADD createPopupItem( 805, View, elems ); // REMOVE + popupMgr()->insert( separator(), -1, 0 ); createPopupItem( 214, View, mesh_group ); // UPDATE createPopupItem( 900, View, mesh_group ); // ADV_INFO @@ -3091,6 +3160,7 @@ void SMESHGUI::initialize( CAM_Application* app ) // Controls //------------------------------------------------- QString + aMeshInVtkHasNodes = aMeshInVTK + "&&" + hasNodes, aMeshInVtkHasEdges = aMeshInVTK + "&&" + hasEdges, aMeshInVtkHasFaces = aMeshInVTK + "&&" + hasFaces, aMeshInVtkHasVolumes = aMeshInVTK + "&&" + hasVolumes; @@ -3116,8 +3186,12 @@ void SMESHGUI::initialize( CAM_Application* app ) popupMgr()->insert( separator(), anId, -1 ); + popupMgr()->insert( action( 6005 ), anId, -1 ); // FREE_NODE + popupMgr()->setRule( action( 6005 ), aMeshInVtkHasNodes, QtxPopupMgr::VisibleRule ); + popupMgr()->setRule( action( 6005 ), "controlMode = 'eFreeNodes'", QtxPopupMgr::ToggleRule ); + popupMgr()->insert( action( 6002 ), anId, -1 ); // FREE_EDGE - popupMgr()->setRule( action( 6002 ), aMeshInVtkHasFaces, QtxPopupMgr::VisibleRule ); + popupMgr()->setRule( action( 6002 ), aMeshInVtkHasEdges, QtxPopupMgr::VisibleRule ); popupMgr()->setRule( action( 6002 ), "controlMode = 'eFreeEdges'", QtxPopupMgr::ToggleRule ); popupMgr()->insert( action( 6018 ), anId, -1 ); // LENGTH_2D @@ -3162,6 +3236,11 @@ void SMESHGUI::initialize( CAM_Application* app ) popupMgr()->setRule( action( 6009 ), aMeshInVtkHasVolumes, QtxPopupMgr::VisibleRule ); popupMgr()->setRule( action( 6009 ), "controlMode = 'eVolume3D'", QtxPopupMgr::ToggleRule ); + popupMgr()->insert( action( 6021 ), anId, -1 ); // FREE_FACE + popupMgr()->setRule( action( 6021 ), aMeshInVtkHasFaces /*aMeshInVtkHasVolumes*/, + QtxPopupMgr::VisibleRule ); + popupMgr()->setRule( action( 6021 ), "controlMode = 'eFreeFaces'", QtxPopupMgr::ToggleRule ); + popupMgr()->insert( separator(), anId, -1 ); popupMgr()->insert( action( 201 ), anId, -1 ); // SCALAR_BAR_PROP @@ -3330,6 +3409,7 @@ void SMESHGUI::onViewManagerActivated( SUIT_ViewManager* mgr ) void SMESHGUI::createPreferences() { + // General tab ------------------------------------------------------------------------ int genTab = addPreference( tr( "PREF_TAB_GENERAL" ) ); int updateGroup = addPreference( tr( "PREF_GROUP_UPDATE" ), genTab ); @@ -3378,6 +3458,14 @@ void SMESHGUI::createPreferences() setPreferenceProperty( notifyMode, "strings", modes ); setPreferenceProperty( notifyMode, "indexes", indices ); + int segGroup = addPreference( tr( "PREF_GROUP_SEGMENT_LENGTH" ), genTab ); + setPreferenceProperty( segGroup, "columns", 2 ); + int segLen = addPreference( tr( "PREF_SEGMENT_LENGTH" ), segGroup, LightApp_Preferences::IntSpin, + "SMESH", "segmentation" ); + setPreferenceProperty( segLen, "min", 1 ); + setPreferenceProperty( segLen, "max", 10000000 ); + + // Mesh tab ------------------------------------------------------------------------ int meshTab = addPreference( tr( "PREF_TAB_MESH" ) ); int nodeGroup = addPreference( tr( "PREF_GROUP_NODES" ), meshTab ); setPreferenceProperty( nodeGroup, "columns", 2 ); @@ -3420,6 +3508,7 @@ void SMESHGUI::createPreferences() addPreference( tr( "PREF_ORIENTATION_3D_VECTORS" ), orientGroup, LightApp_Preferences::Bool, "SMESH", "orientation_3d_vectors" ); + // Selection tab ------------------------------------------------------------------------ int selTab = addPreference( tr( "PREF_TAB_SELECTION" ) ); int selGroup = addPreference( tr( "PREF_GROUP_SELECTION" ), selTab ); @@ -3448,27 +3537,16 @@ void SMESHGUI::createPreferences() addPreference( tr( "PREF_ELEMENTS" ), precSelGroup, LightApp_Preferences::Double, "SMESH", "selection_precision_element" ); addPreference( tr( "PREF_OBJECTS" ), precSelGroup, LightApp_Preferences::Double, "SMESH", "selection_precision_object" ); + // Scalar Bar tab ------------------------------------------------------------------------ int sbarTab = addPreference( tr( "SMESH_SCALARBAR" ) ); int fontGr = addPreference( tr( "SMESH_FONT_SCALARBAR" ), sbarTab ); setPreferenceProperty( fontGr, "columns", 2 ); - int tfont = addPreference( tr( "SMESH_TITLE" ), fontGr, LightApp_Preferences::Font, "SMESH", "scalar_bar_title_font" ); + addVtkFontPref( tr( "SMESH_TITLE" ), fontGr, "scalar_bar_title_font" ); addPreference( tr( "PREF_TITLE_COLOR" ), fontGr, LightApp_Preferences::Color, "SMESH", "scalar_bar_title_color" ); - int lfont = addPreference( tr( "SMESH_LABELS" ), fontGr, LightApp_Preferences::Font, "SMESH", "scalar_bar_label_font" ); - addPreference( tr( "PREF_LABELS_COLOR" ), fontGr, LightApp_Preferences::Color, "SMESH", "scalar_bar_label_color" ); - - QStringList fam; - fam.append( tr( "SMESH_FONT_ARIAL" ) ); - fam.append( tr( "SMESH_FONT_COURIER" ) ); - fam.append( tr( "SMESH_FONT_TIMES" ) ); - int wflag = ( QtxFontEdit::Family | QtxFontEdit::Scripting ); - setPreferenceProperty( tfont, "families", fam ); - setPreferenceProperty( tfont, "system", false ); - setPreferenceProperty( tfont, "widget_flags", wflag ); - setPreferenceProperty( lfont, "families", fam ); - setPreferenceProperty( lfont, "system", false ); - setPreferenceProperty( lfont, "widget_flags", wflag ); + addVtkFontPref( tr( "SMESH_LABELS" ), fontGr, "scalar_bar_label_font" ); + addPreference( tr( "PREF_LABELS_COLOR" ), fontGr, LightApp_Preferences::Color, "SMESH", "scalar_bar_label_color" ); int colorsLabelsGr = addPreference( tr( "SMESH_LABELS_COLORS_SCALARBAR" ), sbarTab ); setPreferenceProperty( colorsLabelsGr, "columns", 2 ); @@ -3535,7 +3613,7 @@ void SMESHGUI::createPreferences() void SMESHGUI::preferencesChanged( const QString& sect, const QString& name ) { - if( sect=="SMESH" ){ + if( sect=="SMESH" ) { float sbX1,sbY1,sbW,sbH; float aTol = 1.00000009999999; std::string aWarning; @@ -3551,7 +3629,7 @@ void SMESHGUI::preferencesChanged( const QString& sect, const QString& name ) if(sbX1+sbW > aTol){ aWarning = "Origin and Size Vertical: X+Width > 1\n"; sbX1=0.01; - sbW=0.05; + sbW=0.08; aResourceMgr->setValue("SMESH", "scalar_bar_vertical_x", sbX1); aResourceMgr->setValue("SMESH", "scalar_bar_vertical_width", sbW); } @@ -3570,8 +3648,8 @@ void SMESHGUI::preferencesChanged( const QString& sect, const QString& name ) sbW = aResourceMgr->doubleValue("SMESH", "scalar_bar_horizontal_width", sbW); if(sbX1+sbW > aTol){ aWarning = "Origin and Size Horizontal: X+Width > 1\n"; - sbX1=0.01; - sbW=0.05; + sbX1=0.1; + sbW=0.08; aResourceMgr->setValue("SMESH", "scalar_bar_horizontal_x", sbX1); aResourceMgr->setValue("SMESH", "scalar_bar_horizontal_width", sbW); } @@ -3582,11 +3660,15 @@ void SMESHGUI::preferencesChanged( const QString& sect, const QString& name ) if(sbY1+sbH > aTol){ aWarning = "Origin and Size Horizontal: Y+Height > 1\n"; sbY1=0.01; - sbH=0.05; + sbH=0.08; aResourceMgr->setValue("SMESH", "scalar_bar_horizontal_y", sbY1); aResourceMgr->setValue("SMESH", "scalar_bar_horizontal_height",sbH); } } + else if ( name == "segmentation" ) { + int nbSeg = aResourceMgr->integerValue( "SMESH", "segmentation" ); + myComponentSMESH->SetBoundaryBoxSegmentation( nbSeg ); + } if(aWarning.size() != 0){ aWarning += "The default values are applied instead."; @@ -3672,6 +3754,9 @@ LightApp_Operation* SMESHGUI::createOperation( const int id ) const case 704: // Edit mesh/sub-mesh op = new SMESHGUI_MeshOp( false ); break; + case 711: // Precompute mesh + op = new SMESHGUI_PrecomputeOp(); + break; case 806: // Create group on geom op = new SMESHGUI_GroupOnShapeOp(); break; @@ -4175,3 +4260,35 @@ void SMESHGUI::restoreVisualParameters (int savePoint) } } } + +/*! + \brief Adds preferences for dfont of VTK viewer + \param label label + \param pIf group identifier + \param param parameter + \return identifier of preferences +*/ +int SMESHGUI::addVtkFontPref( const QString& label, const int pId, const QString& param ) +{ + int tfont = addPreference( label, pId, LightApp_Preferences::Font, "VISU", param ); + + setPreferenceProperty( tfont, "mode", QtxFontEdit::Custom ); + + QStringList fam; + fam.append( tr( "SMESH_FONT_ARIAL" ) ); + fam.append( tr( "SMESH_FONT_COURIER" ) ); + fam.append( tr( "SMESH_FONT_TIMES" ) ); + + setPreferenceProperty( tfont, "fonts", fam ); + + int f = QtxFontEdit::Family | QtxFontEdit::Bold | QtxFontEdit::Italic | QtxFontEdit::Shadow; + setPreferenceProperty( tfont, "features", f ); + + return tfont; +} + + + + + + diff --git a/src/SMESHGUI/SMESHGUI.h b/src/SMESHGUI/SMESHGUI.h index ae56d0a3c..d8cb5eb97 100644 --- a/src/SMESHGUI/SMESHGUI.h +++ b/src/SMESHGUI/SMESHGUI.h @@ -149,6 +149,9 @@ protected: private: void OnEditDelete(); + int addVtkFontPref( const QString& label, + const int pId, + const QString& param ); private : static SMESH::SMESH_Gen_var myComponentSMESH; diff --git a/src/SMESHGUI/SMESHGUI_ComputeDlg.cxx b/src/SMESHGUI/SMESHGUI_ComputeDlg.cxx index 6c28ac700..9a6f5dbdc 100644 --- a/src/SMESHGUI/SMESHGUI_ComputeDlg.cxx +++ b/src/SMESHGUI/SMESHGUI_ComputeDlg.cxx @@ -51,8 +51,10 @@ #include #include #include +#include // SALOME KERNEL includes +#include #include // OCCT includes @@ -85,10 +87,6 @@ // VTK includes #include -// IDL includes -#include -#include CORBA_SERVER_HEADER(SMESH_Gen) - // STL includes #include #include @@ -791,7 +789,8 @@ void SMESHGUI_MeshInfosBox::SetInfoByMesh(SMESH::SMESH_Mesh_var mesh) */ //======================================================================= -SMESHGUI_ComputeDlg::SMESHGUI_ComputeDlg(): SMESHGUI_Dialog( 0, false, true, Close/* | Help*/ ) +SMESHGUI_ComputeDlg::SMESHGUI_ComputeDlg( QWidget* parent ) + : SMESHGUI_Dialog( parent, false, true, Close/* | Help*/ ) { QVBoxLayout* aDlgLay = new QVBoxLayout (mainFrame()); aDlgLay->setMargin( 0 ); @@ -804,6 +803,16 @@ SMESHGUI_ComputeDlg::SMESHGUI_ComputeDlg(): SMESHGUI_Dialog( 0, false, true, Clo aDlgLay->setStretchFactor(aMainFrame, 1); } +// ========================================================================================= +/*! + * \brief Destructor + */ +//======================================================================= + +SMESHGUI_ComputeDlg::~SMESHGUI_ComputeDlg() +{ +} + //======================================================================= // function : createMainFrame() // purpose : Create frame containing dialog's fields @@ -921,37 +930,33 @@ QFrame* SMESHGUI_ComputeDlg::createMainFrame (QWidget* theParent) */ //================================================================================ -SMESHGUI_ComputeOp::SMESHGUI_ComputeOp() +SMESHGUI_BaseComputeOp::SMESHGUI_BaseComputeOp() + : SMESHGUI_Operation(), + myCompDlg( 0 ) { - myDlg = new SMESHGUI_ComputeDlg; myTShapeDisplayer = new SMESH::TShapeDisplayer(); myBadMeshDisplayer = 0; //myHelpFileName = "/files/about_meshes.htm"; // V3 myHelpFileName = "about_meshes_page.html"; // V4 - - // connect signals and slots - connect(myDlg->myShowBtn, SIGNAL (clicked()), SLOT(onPreviewShape())); - connect(myDlg->myPublishBtn, SIGNAL (clicked()), SLOT(onPublishShape())); - connect(myDlg->myBadMeshBtn, SIGNAL (clicked()), SLOT(onShowBadMesh())); - connect(table(), SIGNAL(itemSelectionChanged()), SLOT(currentCellChanged())); - connect(table(), SIGNAL(currentCellChanged(int,int,int,int)), SLOT(currentCellChanged())); } -//======================================================================= -// function : startOperation() -// purpose : Init dialog fields, connect signals and slots, show dialog -//======================================================================= +//================================================================================ +/*! + * \brief Start operation + * \purpose Init dialog fields, connect signals and slots, show dialog + */ +//================================================================================ -void SMESHGUI_ComputeOp::startOperation() +void SMESHGUI_BaseComputeOp::startOperation() { - SMESHGUI_Operation::startOperation(); - - // check selection + // create compute dialog if not created before + computeDlg(); myMesh = SMESH::SMESH_Mesh::_nil(); myMainShape = GEOM::GEOM_Object::_nil(); + // check selection LightApp_SelectionMgr *Sel = selectionMgr(); SALOME_ListIO selected; Sel->selectedObjects( selected ); @@ -964,16 +969,28 @@ void SMESHGUI_ComputeOp::startOperation() return; } - Handle(SALOME_InteractiveObject) IObject = selected.First(); - myMesh = SMESH::GetMeshByIO(IObject); + myIObject = selected.First(); + myMesh = SMESH::GetMeshByIO(myIObject); if (myMesh->_is_nil()) { SUIT_MessageBox::warning(desktop(), tr("SMESH_WRN_WARNING"), tr("SMESH_WRN_NO_AVAILABLE_DATA")); onCancel(); - return; + } + myMainShape = myMesh->GetShapeToMesh(); + SMESHGUI_Operation::startOperation(); +} + +//================================================================================ +/*! + * \brief computeMesh() +*/ +//================================================================================ + +void SMESHGUI_BaseComputeOp::computeMesh() +{ // COMPUTE MESH SMESH::MemoryReserve aMemoryReserve; @@ -984,12 +1001,11 @@ void SMESHGUI_ComputeOp::startOperation() bool computeFailed = true, memoryLack = false; _PTR(SObject) aMeshSObj = SMESH::FindSObject(myMesh); - myMainShape = myMesh->GetShapeToMesh(); bool hasShape = myMesh->HasShapeToMesh(); bool shapeOK = myMainShape->_is_nil() ? !hasShape : hasShape; if ( shapeOK && aMeshSObj ) { - myDlg->myMeshName->setText( aMeshSObj->GetName().c_str() ); + myCompDlg->myMeshName->setText( aMeshSObj->GetName().c_str() ); SMESH::SMESH_Gen_var gen = getSMESHGUI()->GetSMESHGen(); SMESH::algo_error_array_var errors = gen->GetAlgoState(myMesh,myMainShape); if ( errors->length() > 0 ) { @@ -1032,7 +1048,7 @@ void SMESHGUI_ComputeOp::startOperation() #if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100 OCC_CATCH_SIGNALS; #endif - SMESH::Update(IObject, true); + SMESH::Update(myIObject, true); } catch (...) { #ifdef _DEBUG_ @@ -1046,77 +1062,119 @@ void SMESHGUI_ComputeOp::startOperation() } } } - Sel->setSelectedObjects( selected ); + LightApp_SelectionMgr *Sel = selectionMgr(); + if ( Sel ) + { + SALOME_ListIO selected; + selected.Append( myIObject ); + Sel->setSelectedObjects( selected ); + } } } if ( memoryLack ) aMemoryReserve.release(); - myDlg->setWindowTitle(tr( computeFailed ? "SMESH_WRN_COMPUTE_FAILED" : "SMESH_COMPUTE_SUCCEED")); - myDlg->myMemoryLackGroup->hide(); + myCompDlg->setWindowTitle(tr( computeFailed ? "SMESH_WRN_COMPUTE_FAILED" : "SMESH_COMPUTE_SUCCEED")); // SHOW ERRORS - + bool noCompError = ( !aCompErrors.operator->() || aCompErrors->length() == 0 ); bool noHypoError = ( aHypErrors.isEmpty() ); - if ( memoryLack ) + SUIT_ResourceMgr* resMgr = SMESH::GetResourceMgr( SMESHGUI::GetSMESHGUI() ); + int aNotifyMode = resMgr->integerValue( "SMESH", "show_result_notification" ); + + bool isShowResultDlg = true; + switch( aNotifyMode ) { + case 0: // show the mesh computation result dialog NEVER + isShowResultDlg = false; + commit(); + break; + case 1: // show the mesh computation result dialog if there are some errors + if ( memoryLack || !noCompError || !noHypoError ) + isShowResultDlg = true; + else + { + isShowResultDlg = false; + commit(); + } + break; + default: // show the result dialog after each mesh computation + isShowResultDlg = true; + } + + // SHOW RESULTS + if ( isShowResultDlg ) + showComputeResult( memoryLack, noCompError,aCompErrors, noHypoError, aHypErrors ); +} + +void SMESHGUI_BaseComputeOp::showComputeResult( const bool theMemoryLack, + const bool theNoCompError, + SMESH::compute_error_array_var& theCompErrors, + const bool theNoHypoError, + const QString& theHypErrors ) +{ + bool hasShape = myMesh->HasShapeToMesh(); + SMESHGUI_ComputeDlg* aCompDlg = computeDlg(); + aCompDlg->myMemoryLackGroup->hide(); + + if ( theMemoryLack ) { - myDlg->myMemoryLackGroup->show(); - myDlg->myFullInfo->hide(); - myDlg->myBriefInfo->hide(); - myDlg->myHypErrorGroup->hide(); - myDlg->myCompErrorGroup->hide(); + aCompDlg->myMemoryLackGroup->show(); + aCompDlg->myFullInfo->hide(); + aCompDlg->myBriefInfo->hide(); + aCompDlg->myHypErrorGroup->hide(); + aCompDlg->myCompErrorGroup->hide(); } - else if ( noCompError && noHypoError ) + else if ( theNoCompError && theNoHypoError ) { - myDlg->myFullInfo->SetInfoByMesh( myMesh ); - myDlg->myFullInfo->show(); - myDlg->myBriefInfo->hide(); - myDlg->myHypErrorGroup->hide(); - myDlg->myCompErrorGroup->hide(); + aCompDlg->myFullInfo->SetInfoByMesh( myMesh ); + aCompDlg->myFullInfo->show(); + aCompDlg->myBriefInfo->hide(); + aCompDlg->myHypErrorGroup->hide(); + aCompDlg->myCompErrorGroup->hide(); } else { - QTableWidget* tbl = myDlg->myTable; - myDlg->myBriefInfo->SetInfoByMesh( myMesh ); - myDlg->myBriefInfo->show(); - myDlg->myFullInfo->hide(); + QTableWidget* tbl = aCompDlg->myTable; + aCompDlg->myBriefInfo->SetInfoByMesh( myMesh ); + aCompDlg->myBriefInfo->show(); + aCompDlg->myFullInfo->hide(); - if ( noHypoError ) { - myDlg->myHypErrorGroup->hide(); + if ( theNoHypoError ) { + aCompDlg->myHypErrorGroup->hide(); } else { - myDlg->myHypErrorGroup->show(); - myDlg->myHypErrorLabel->setText( aHypErrors ); + aCompDlg->myHypErrorGroup->show(); + aCompDlg->myHypErrorLabel->setText( theHypErrors ); } - if ( noCompError ) { - myDlg->myCompErrorGroup->hide(); + if ( theNoCompError ) { + aCompDlg->myCompErrorGroup->hide(); } else { - myDlg->myCompErrorGroup->show(); + aCompDlg->myCompErrorGroup->show(); if ( !hasShape ) { - myDlg->myPublishBtn->hide(); - myDlg->myShowBtn->hide(); + aCompDlg->myPublishBtn->hide(); + aCompDlg->myShowBtn->hide(); } else { - myDlg->myPublishBtn->show(); - myDlg->myShowBtn->show(); + aCompDlg->myPublishBtn->show(); + aCompDlg->myShowBtn->show(); } // fill table of errors - tbl->setRowCount( aCompErrors->length() ); + tbl->setRowCount( theCompErrors->length() ); if ( !hasShape ) tbl->hideColumn( COL_SHAPE ); else tbl->showColumn( COL_SHAPE ); tbl->setColumnWidth( COL_ERROR, 200 ); bool hasBadMesh = false; - for ( int row = 0; row < aCompErrors->length(); ++row ) + for ( int row = 0; row < theCompErrors->length(); ++row ) { - SMESH::ComputeError & err = aCompErrors[ row ]; + SMESH::ComputeError & err = theCompErrors[ row ]; QString text = err.algoName.in(); if ( !tbl->item( row, COL_ALGO ) ) tbl->setItem( row, COL_ALGO, new QTableWidgetItem( text ) ); @@ -1150,31 +1208,16 @@ void SMESHGUI_ComputeOp::startOperation() tbl->resizeColumnToContents( COL_SHAPE ); if ( hasBadMesh ) - myDlg->myBadMeshBtn->show(); + aCompDlg->myBadMeshBtn->show(); else - myDlg->myBadMeshBtn->hide(); + aCompDlg->myBadMeshBtn->hide(); tbl->setCurrentCell(0,0); currentCellChanged(); // to update buttons } } - SUIT_ResourceMgr* resMgr = SMESH::GetResourceMgr( SMESHGUI::GetSMESHGUI() ); - int aNotifyMode = resMgr->integerValue( "SMESH", "show_result_notification" ); - - switch( aNotifyMode ) { - case 0: // show the mesh computation result dialog NEVER - commit(); - break; - case 1: // show the mesh computation result dialog if there are some errors - if ( memoryLack || !noCompError || !noHypoError ) - myDlg->show(); - else - commit(); - break; - default: // show the result dialog after each mesh computation - myDlg->show(); - } - + // show dialog and wait, becase Compute can be invoked from Preview operation + aCompDlg->exec(); } //================================================================================ @@ -1183,10 +1226,11 @@ void SMESHGUI_ComputeOp::startOperation() */ //================================================================================ -void SMESHGUI_ComputeOp::stopOperation() +void SMESHGUI_BaseComputeOp::stopOperation() { SMESHGUI_Operation::stopOperation(); - myTShapeDisplayer->SetVisibility( false ); + if ( myTShapeDisplayer ) + myTShapeDisplayer->SetVisibility( false ); if ( myBadMeshDisplayer ) { myBadMeshDisplayer->SetVisibility( false ); // delete it in order not to have problems at its destruction when the viewer @@ -1194,6 +1238,7 @@ void SMESHGUI_ComputeOp::stopOperation() delete myBadMeshDisplayer; myBadMeshDisplayer = 0; } + myIObject.Nullify(); } //================================================================================ @@ -1202,7 +1247,7 @@ void SMESHGUI_ComputeOp::stopOperation() */ //================================================================================ -void SMESHGUI_ComputeOp::onPublishShape() +void SMESHGUI_BaseComputeOp::onPublishShape() { GEOM::GEOM_Gen_var geomGen = SMESH::GetGEOMGen(); SALOMEDS::Study_var study = SMESHGUI::GetSMESHGen()->GetCurrentStudy(); @@ -1251,7 +1296,7 @@ void SMESHGUI_ComputeOp::onPublishShape() */ //================================================================================ -void SMESHGUI_ComputeOp::onShowBadMesh() +void SMESHGUI_BaseComputeOp::onShowBadMesh() { myTShapeDisplayer->SetVisibility( false ); QList rows; @@ -1284,7 +1329,7 @@ void SMESHGUI_ComputeOp::onShowBadMesh() */ //================================================================================ -void SMESHGUI_ComputeOp::currentCellChanged() +void SMESHGUI_BaseComputeOp::currentCellChanged() { myTShapeDisplayer->SetVisibility( false ); if ( myBadMeshDisplayer ) @@ -1314,9 +1359,9 @@ void SMESHGUI_ComputeOp::currentCellChanged() if ( !table()->item(row, COL_BAD_MESH)->text().isEmpty() ) hasBadMesh = true; } - myDlg->myPublishBtn->setEnabled( publishEnable ); - myDlg->myShowBtn ->setEnabled( showEnable ); - myDlg->myBadMeshBtn->setEnabled( hasBadMesh && ( nbSelected == 1 )); + myCompDlg->myPublishBtn->setEnabled( publishEnable ); + myCompDlg->myShowBtn ->setEnabled( showEnable ); + myCompDlg->myBadMeshBtn->setEnabled( hasBadMesh && ( nbSelected == 1 )); } //================================================================================ @@ -1325,7 +1370,7 @@ void SMESHGUI_ComputeOp::currentCellChanged() */ //================================================================================ -void SMESHGUI_ComputeOp::onPreviewShape() +void SMESHGUI_BaseComputeOp::onPreviewShape() { if ( myTShapeDisplayer ) { @@ -1353,13 +1398,97 @@ void SMESHGUI_ComputeOp::onPreviewShape() */ //================================================================================ -SMESHGUI_ComputeOp::~SMESHGUI_ComputeOp() +SMESHGUI_BaseComputeOp::~SMESHGUI_BaseComputeOp() { + delete myCompDlg; + myCompDlg = 0; delete myTShapeDisplayer; if ( myBadMeshDisplayer ) delete myBadMeshDisplayer; } +//================================================================================ +/*! + * \brief Gets dialog of compute operation + * \retval SMESHGUI_ComputeDlg* - pointer to dialog of this operation + */ +//================================================================================ + +SMESHGUI_ComputeDlg* SMESHGUI_BaseComputeOp::computeDlg() const +{ + if ( !myCompDlg ) + { + SMESHGUI_BaseComputeOp* me = (SMESHGUI_BaseComputeOp*)this; + me->myCompDlg = new SMESHGUI_ComputeDlg( desktop() ); + // connect signals and slots + connect(myCompDlg->myShowBtn, SIGNAL (clicked()), SLOT(onPreviewShape())); + connect(myCompDlg->myPublishBtn, SIGNAL (clicked()), SLOT(onPublishShape())); + connect(myCompDlg->myBadMeshBtn, SIGNAL (clicked()), SLOT(onShowBadMesh())); + + QTableWidget* aTable = me->table(); + connect(aTable, SIGNAL(itemSelectionChanged()), SLOT(currentCellChanged())); + connect(aTable, SIGNAL(currentCellChanged(int,int,int,int)), SLOT(currentCellChanged())); + } + return myCompDlg; +} + +//================================================================================ +/*! + * \brief Return a table + */ +//================================================================================ + +QTableWidget* SMESHGUI_BaseComputeOp::table() +{ + return myCompDlg->myTable; +} + + +//================================================================================ +/*! + * \brief Constructor +*/ +//================================================================================ + +SMESHGUI_ComputeOp::SMESHGUI_ComputeOp() + : SMESHGUI_BaseComputeOp() +{ +} + + +//================================================================================ +/*! + * \brief Desctructor +*/ +//================================================================================ + +SMESHGUI_ComputeOp::~SMESHGUI_ComputeOp() +{ +} + +//================================================================================ +/*! + * \brief perform it's intention action: compute mesh + */ +//================================================================================ + +void SMESHGUI_ComputeOp::startOperation() +{ + SMESHGUI_BaseComputeOp::startOperation(); + computeMesh(); +} + +//================================================================================ +/*! + * \brief perform it's intention action: compute mesh + */ +//================================================================================ + +bool SMESHGUI_ComputeOp::onApply() +{ + return true; +} + //================================================================================ /*! * \brief Gets dialog of this operation @@ -1369,27 +1498,415 @@ SMESHGUI_ComputeOp::~SMESHGUI_ComputeOp() LightApp_Dialog* SMESHGUI_ComputeOp::dlg() const { - return myDlg; + return computeDlg(); } //================================================================================ /*! - * \brief perform it's intention action: compute mesh + * \brief Constructor +*/ +//================================================================================ + +SMESHGUI_PrecomputeOp::SMESHGUI_PrecomputeOp() + : SMESHGUI_BaseComputeOp(), + myDlg( 0 ), + myActiveDlg( 0 ), + myPreviewDisplayer( 0 ) +{ + myHelpFileName = "preview_meshes_page.html"; // V4 +} + +//================================================================================ +/*! + * \brief Destructor */ //================================================================================ -bool SMESHGUI_ComputeOp::onApply() +SMESHGUI_PrecomputeOp::~SMESHGUI_PrecomputeOp() +{ + delete myDlg; + myDlg = 0; + myActiveDlg = 0; + if ( myPreviewDisplayer ) + delete myPreviewDisplayer; + myPreviewDisplayer = 0; +} + +//================================================================================ +/*! + * \brief Gets current dialog of this operation + * \retval LightApp_Dialog* - pointer to dialog of this operation + */ +//================================================================================ + +LightApp_Dialog* SMESHGUI_PrecomputeOp::dlg() const +{ + return myActiveDlg; +} + +//================================================================================ +/*! + * \brief perform it's intention action: prepare data + */ +//================================================================================ + +void SMESHGUI_PrecomputeOp::startOperation() +{ + if ( !myDlg ) + { + myDlg = new SMESHGUI_PrecomputeDlg( desktop() ); + + // connect signals + connect( myDlg, SIGNAL( preview() ), this, SLOT( onPreview() ) ); + } + myActiveDlg = myDlg; + + // connect signal to compute dialog. which will be shown after Compute mesh operation + SMESHGUI_ComputeDlg* cmpDlg = computeDlg(); + if ( cmpDlg ) + { + // disconnect signals + disconnect( cmpDlg, SIGNAL( dlgOk() ), this, SLOT( onOk() ) ); + disconnect( cmpDlg, SIGNAL( dlgApply() ), this, SLOT( onApply() ) ); + disconnect( cmpDlg, SIGNAL( dlgCancel() ), this, SLOT( onCancel() ) ); + disconnect( cmpDlg, SIGNAL( dlgClose() ), this, SLOT( onCancel() ) ); + disconnect( cmpDlg, SIGNAL( dlgHelp() ), this, SLOT( onHelp() ) ); + + // connect signals + if( cmpDlg->testButtonFlags( QtxDialog::OK ) ) + connect( cmpDlg, SIGNAL( dlgOk() ), this, SLOT( onOk() ) ); + if( cmpDlg->testButtonFlags( QtxDialog::Apply ) ) + connect( cmpDlg, SIGNAL( dlgApply() ), this, SLOT( onApply() ) ); + if( cmpDlg->testButtonFlags( QtxDialog::Help ) ) + connect( cmpDlg, SIGNAL( dlgHelp() ), this, SLOT( onHelp() ) ); + if( cmpDlg->testButtonFlags( QtxDialog::Cancel ) ) + connect( cmpDlg, SIGNAL( dlgCancel() ), this, SLOT( onCancel() ) ); + if( cmpDlg->testButtonFlags( QtxDialog::Close ) ) + connect( cmpDlg, SIGNAL( dlgClose() ), this, SLOT( onCancel() ) ); + } + + SMESHGUI_BaseComputeOp::startOperation(); + + myDlg->show(); +} + +//================================================================================ +/*! + * \brief Stops operation + */ +//================================================================================ + +void SMESHGUI_PrecomputeOp::stopOperation() +{ + if ( myPreviewDisplayer ) + { + myPreviewDisplayer->SetVisibility( false ); + delete myPreviewDisplayer; + myPreviewDisplayer = 0; + } + myMapShapeId.clear(); + SMESHGUI_BaseComputeOp::stopOperation(); +} + +//================================================================================ +/*! + * \brief perform it's intention action: reinitialise dialog + */ +//================================================================================ + +void SMESHGUI_PrecomputeOp::resumeOperation() { + if ( myActiveDlg == myDlg ) + initDialog(); + SMESHGUI_BaseComputeOp::resumeOperation(); +} + +void SMESHGUI_PrecomputeOp::initDialog() +{ + QList modes; + QMap modeMap; + _PTR(SObject) aHypRoot; + _PTR(GenericAttribute) anAttr; + int aPart = SMESH::Tag_RefOnAppliedAlgorithms; + + _PTR(SObject) pMesh = studyDS()->FindObjectID( myIObject->getEntry() ); + if ( pMesh && pMesh->FindSubObject( aPart, aHypRoot ) ) + { + _PTR(ChildIterator) anIter = + SMESH::GetActiveStudyDocument()->NewChildIterator( aHypRoot ); + for ( ; anIter->More(); anIter->Next() ) + { + _PTR(SObject) anObj = anIter->Value(); + _PTR(SObject) aRefObj; + if ( anObj->ReferencedObject( aRefObj ) ) + anObj = aRefObj; + else + continue; + + if ( anObj->FindAttribute( anAttr, "AttributeName" ) ) + { + CORBA::Object_var aVar = _CAST(SObject,anObj)->GetObject(); + if ( CORBA::is_nil( aVar ) ) + continue; + + SMESH::SMESH_Algo_var algo = SMESH::SMESH_3D_Algo::_narrow( aVar ); + if ( !algo->_is_nil() ) + { + modeMap[ SMESH::DIM_1D ] = 0; + modeMap[ SMESH::DIM_2D ] = 0; + } + else + { + algo = SMESH::SMESH_2D_Algo::_narrow( aVar ); + if ( !algo->_is_nil() ) + modeMap[ SMESH::DIM_2D ] = 0; + } + } + } + } + if ( modeMap.contains( SMESH::DIM_1D ) ) + modes.append( SMESH::DIM_1D ); + if ( modeMap.contains( SMESH::DIM_2D ) ) + modes.append( SMESH::DIM_2D ); + + myDlg->setPreviewModes( modes ); +} + +//================================================================================ +/*! + * \brief perform it's intention action: + */ +//================================================================================ + +bool SMESHGUI_PrecomputeOp::onApply() +{ + QObject* obj = sender(); + if ( obj != myDlg && myActiveDlg == myDlg ) + return true; // just return from error messages + if ( myActiveDlg == myDlg ) + { + myDlg->hide(); + myMapShapeId.clear(); + myActiveDlg = computeDlg(); + computeMesh(); + } + return true; } //================================================================================ /*! - * \brief Return a table + * \brief perform it's intention action: compute mesh */ //================================================================================ -QTableWidget* SMESHGUI_ComputeOp::table() +void SMESHGUI_PrecomputeOp::onCancel() +{ + QObject* curDlg = sender(); + if ( curDlg == computeDlg() ) + { + if ( myActiveDlg == myDlg ) // return from error messages + myDlg->show(); + + return; + } + + if ( myActiveDlg == myDlg && !myMesh->_is_nil() && myMapShapeId.count() ) + { + // ask to remove already computed mesh elements + if ( SUIT_MessageBox::question( desktop(), tr( "SMESH_WARNING" ), + tr( "CLEAR_SUBMESH_QUESTION" ), + tr( "SMESH_BUT_DELETE" ), tr( "SMESH_BUT_NO" ), 0, 1 ) == 0 ) + { + // remove all submeshes for collected shapes + QMap::const_iterator it = myMapShapeId.constBegin(); + for ( ; it != myMapShapeId.constEnd(); ++it ) + myMesh->ClearSubMesh( *it ); + } + } + myMapShapeId.clear(); + SMESHGUI_BaseComputeOp::onCancel(); +} + +//================================================================================ +/*! + * \brief perform it's intention action: preview mesh + */ +//================================================================================ + +void SMESHGUI_PrecomputeOp::onPreview() +{ + if ( !myDlg || myMesh->_is_nil() || myMainShape->_is_nil() ) + return; + + _PTR(SObject) aMeshSObj = SMESH::FindSObject(myMesh); + if ( !aMeshSObj ) + return; + // Compute preview of mesh, + // i.e. compute mesh till indicated dimension + int dim = myDlg->getPreviewMode(); + + SMESH::MemoryReserve aMemoryReserve; + + SMESH::compute_error_array_var aCompErrors; + QString aHypErrors; + + bool computeFailed = true, memoryLack = false; + + SMESHGUI_ComputeDlg* aCompDlg = computeDlg(); + aCompDlg->myMeshName->setText( aMeshSObj->GetName().c_str() ); + + SMESHGUI* gui = getSMESHGUI(); + SMESH::SMESH_Gen_var gen = gui->GetSMESHGen(); + SMESH::algo_error_array_var errors = gen->GetAlgoState(myMesh,myMainShape); + if ( errors->length() > 0 ) { + aHypErrors = SMESH::GetMessageOnAlgoStateErrors( errors.in() ); + } + + SUIT_OverrideCursor aWaitCursor; + + SVTK_ViewWindow* view = SMESH::GetViewWindow( gui ); + if ( myPreviewDisplayer ) delete myPreviewDisplayer; + myPreviewDisplayer = new SMESHGUI_MeshEditPreview( view ); + + SMESH::long_array_var aShapesId = new SMESH::long_array(); + try { +#if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100 + OCC_CATCH_SIGNALS; +#endif + + SMESH::MeshPreviewStruct_var previewData = + gen->Precompute(myMesh, myMainShape, (SMESH::Dimension)dim, aShapesId); + SMESH::MeshPreviewStruct* previewRes = previewData._retn(); + if ( previewRes && previewRes->nodesXYZ.length() > 0 ) + { + computeFailed = false; + myPreviewDisplayer->SetData( previewRes ); + // append shape indeces with computed mesh entities + for ( int i = 0, n = aShapesId->length(); i < n; i++ ) + myMapShapeId[ aShapesId[ i ] ] = 0; + } + else + myPreviewDisplayer->SetVisibility(false); + } + catch(const SALOME::SALOME_Exception & S_ex){ + memoryLack = true; + myPreviewDisplayer->SetVisibility(false); + } + + try { +#if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100 + OCC_CATCH_SIGNALS; +#endif + aCompErrors = gen->GetComputeErrors( myMesh, myMainShape ); + // check if there are memory problems + for ( int i = 0; (i < aCompErrors->length()) && !memoryLack; ++i ) + memoryLack = ( aCompErrors[ i ].code == SMESH::COMPERR_MEMORY_PB ); + } + catch(const SALOME::SALOME_Exception & S_ex){ + memoryLack = true; + } + + if ( memoryLack ) + aMemoryReserve.release(); + + bool noCompError = ( !aCompErrors.operator->() || aCompErrors->length() == 0 ); + bool noHypoError = ( aHypErrors.isEmpty() ); + + SUIT_ResourceMgr* resMgr = SMESH::GetResourceMgr( gui ); + int aNotifyMode = resMgr->integerValue( "SMESH", "show_result_notification" ); + + bool isShowError = true; + switch( aNotifyMode ) { + case 0: // show the mesh computation result dialog NEVER + isShowError = false; + break; + case 1: // show the mesh computation result dialog if there are some errors + default: // show the result dialog after each mesh computation + if ( !computeFailed && !memoryLack && noCompError && noHypoError ) + isShowError = false; + break; + } + + aWaitCursor.suspend(); + // SHOW ERRORS + if ( isShowError ) + { + myDlg->hide(); + aCompDlg->setWindowTitle(tr( computeFailed ? "SMESH_WRN_COMPUTE_FAILED" : "SMESH_COMPUTE_SUCCEED")); + showComputeResult( memoryLack, noCompError, aCompErrors, noHypoError, aHypErrors ); + } +} + + +//================================================================================ +/*! + * \brief Constructor +*/ +//================================================================================ + +SMESHGUI_PrecomputeDlg::SMESHGUI_PrecomputeDlg( QWidget* parent ) + : SMESHGUI_Dialog( parent, false, false, OK | Cancel | Help ) +{ + setWindowTitle( tr( "CAPTION" ) ); + + setButtonText( OK, tr( "COMPUTE" ) ); + QFrame* main = mainFrame(); + + QVBoxLayout* layout = new QVBoxLayout( main ); + + QFrame* frame = new QFrame( main ); + layout->setMargin(0); layout->setSpacing(0); + layout->addWidget( frame ); + + QHBoxLayout* frameLay = new QHBoxLayout( frame ); + frameLay->setMargin(0); frameLay->setSpacing(SPACING); + + myPreviewMode = new QtxComboBox( frame ); + frameLay->addWidget( myPreviewMode ); + + myPreviewBtn = new QPushButton( tr( "PREVIEW" ), frame ); + frameLay->addWidget( myPreviewBtn ); + + connect( myPreviewBtn, SIGNAL( clicked( bool ) ), this, SIGNAL( preview() ) ); +} + +//================================================================================ +/*! + * \brief Destructor +*/ +//================================================================================ + +SMESHGUI_PrecomputeDlg::~SMESHGUI_PrecomputeDlg() +{ +} + +//================================================================================ +/*! + * \brief Sets available preview modes +*/ +//================================================================================ + +void SMESHGUI_PrecomputeDlg::setPreviewModes( const QList& theModes ) +{ + myPreviewMode->clear(); + QList::const_iterator it = theModes.constBegin(); + for ( int i = 0; it != theModes.constEnd(); ++it, i++ ) + { + QString mode = QString( "PREVIEW_%1" ).arg( *it ); + myPreviewMode->addItem( tr( mode.toLatin1().data() ) ); + myPreviewMode->setId( i, *it ); + } + myPreviewBtn->setEnabled( !theModes.isEmpty() ); +} + +//================================================================================ +/*! + * \brief Returns current preview mesh mode +*/ +//================================================================================ + +int SMESHGUI_PrecomputeDlg::getPreviewMode() const { - return myDlg->myTable; + return myPreviewMode->currentId(); } diff --git a/src/SMESHGUI/SMESHGUI_ComputeDlg.h b/src/SMESHGUI/SMESHGUI_ComputeDlg.h index c7a6f0e74..5ec969cc7 100644 --- a/src/SMESHGUI/SMESHGUI_ComputeDlg.h +++ b/src/SMESHGUI/SMESHGUI_ComputeDlg.h @@ -31,29 +31,82 @@ #include "SMESHGUI_Dialog.h" #include "SMESHGUI_Operation.h" +// SALOME GUI includes +#include + // Qt includes +#include +#include #include // IDL includes #include +#include CORBA_SERVER_HEADER(SMESH_Gen) #include CORBA_SERVER_HEADER(SMESH_Mesh) class QFrame; class QPushButton; class QTableWidget; class QLabel; +class QtxComboBox; class SMESHGUI_ComputeDlg; +class SMESHGUI_PrecomputeDlg; class SMESHGUI_MeshEditPreview; +class SMESH::compute_error_array; + namespace SMESH { class TShapeDisplayer; } +/*! + * \brief Base operation to compute a mesh and show computation errors + */ +class SMESHGUI_EXPORT SMESHGUI_BaseComputeOp: public SMESHGUI_Operation +{ + Q_OBJECT + +public: + SMESHGUI_BaseComputeOp(); + virtual ~SMESHGUI_BaseComputeOp(); + +protected: + virtual void startOperation(); + virtual void stopOperation(); + + SMESHGUI_ComputeDlg* computeDlg() const; + void computeMesh(); + void showComputeResult( const bool, + const bool, + SMESH::compute_error_array_var&, + const bool, + const QString& ); + +protected slots: + void onPreviewShape(); + void onPublishShape(); + void onShowBadMesh(); + void currentCellChanged(); + +private: + QTableWidget* table(); + +private: + QPointer myCompDlg; + +protected: + SMESH::SMESH_Mesh_var myMesh; + GEOM::GEOM_Object_var myMainShape; + SMESH::TShapeDisplayer* myTShapeDisplayer; + SMESHGUI_MeshEditPreview* myBadMeshDisplayer; + Handle(SALOME_InteractiveObject) myIObject; +}; + /*! * \brief Operation to compute a mesh and show computation errors */ -class SMESHGUI_EXPORT SMESHGUI_ComputeOp: public SMESHGUI_Operation +class SMESHGUI_EXPORT SMESHGUI_ComputeOp: public SMESHGUI_BaseComputeOp { Q_OBJECT @@ -63,28 +116,45 @@ public: virtual LightApp_Dialog* dlg() const; +protected: + virtual void startOperation(); + +protected slots: + virtual bool onApply(); +}; + +/*! + * \brief Operation to preview and compute a mesh and show computation errors + */ +class SMESHGUI_EXPORT SMESHGUI_PrecomputeOp: public SMESHGUI_BaseComputeOp +{ + Q_OBJECT + +public: + SMESHGUI_PrecomputeOp(); + virtual ~SMESHGUI_PrecomputeOp(); + + virtual LightApp_Dialog* dlg() const; + protected: virtual void startOperation(); virtual void stopOperation(); + virtual void resumeOperation(); + + virtual void initDialog(); protected slots: virtual bool onApply(); + virtual void onCancel(); private slots: - void onPreviewShape(); - void onPublishShape(); - void onShowBadMesh(); - void currentCellChanged(); + void onPreview(); private: - QTableWidget* table(); - - SMESHGUI_ComputeDlg* myDlg; - - SMESH::SMESH_Mesh_var myMesh; - GEOM::GEOM_Object_var myMainShape; - SMESH::TShapeDisplayer* myTShapeDisplayer; - SMESHGUI_MeshEditPreview* myBadMeshDisplayer; + QMap< int, int > myMapShapeId; + QPointer myActiveDlg; + QPointer myDlg; + SMESHGUI_MeshEditPreview* myPreviewDisplayer; }; /*! @@ -143,9 +213,10 @@ class SMESHGUI_EXPORT SMESHGUI_ComputeDlg : public SMESHGUI_Dialog Q_OBJECT public: - SMESHGUI_ComputeDlg(); + SMESHGUI_ComputeDlg( QWidget* ); + virtual ~SMESHGUI_ComputeDlg(); -private: +protected: QFrame* createMainFrame( QWidget* ); QLabel* myMeshName; @@ -161,7 +232,32 @@ private: SMESHGUI_MeshInfosBox* myBriefInfo; SMESHGUI_MeshInfosBox* myFullInfo; - friend class SMESHGUI_ComputeOp; + friend class SMESHGUI_BaseComputeOp; + friend class SMESHGUI_PrecomputeOp; +}; + +/*! + * \brief Dialog to preview and compute a mesh and show computation errors + */ + +class SMESHGUI_EXPORT SMESHGUI_PrecomputeDlg : public SMESHGUI_Dialog +{ + Q_OBJECT + +public: + SMESHGUI_PrecomputeDlg( QWidget* ); + virtual ~SMESHGUI_PrecomputeDlg(); + + void setPreviewModes( const QList& ); + int getPreviewMode() const; + +signals: + void preview(); + +private: + QPushButton* myPreviewBtn; + QtxComboBox* myPreviewMode; }; + #endif // SMESHGUI_COMPUTEDLG_H diff --git a/src/SMESHGUI/SMESHGUI_ExtrusionAlongPathDlg.cxx b/src/SMESHGUI/SMESHGUI_ExtrusionAlongPathDlg.cxx index 621ec92b2..8044fe73b 100644 --- a/src/SMESHGUI/SMESHGUI_ExtrusionAlongPathDlg.cxx +++ b/src/SMESHGUI/SMESHGUI_ExtrusionAlongPathDlg.cxx @@ -32,6 +32,7 @@ #include "SMESHGUI_MeshUtils.h" #include "SMESHGUI_SpinBox.h" #include "SMESHGUI_IdValidator.h" +#include "SMESHGUI_FilterDlg.h" #include #include @@ -109,7 +110,8 @@ private: SMESHGUI_ExtrusionAlongPathDlg::SMESHGUI_ExtrusionAlongPathDlg( SMESHGUI* theModule ) : QDialog( SMESH::GetDesktop( theModule ) ), mySMESHGUI( theModule ), - mySelectionMgr( SMESH::GetSelectionMgr( theModule ) ) + mySelectionMgr( SMESH::GetSelectionMgr( theModule ) ), + myFilterDlg( 0 ) { SUIT_ResourceMgr* mgr = SMESH::GetResourceMgr( mySMESHGUI ); QPixmap edgeImage ( mgr->loadPixmap("SMESH", tr("ICON_DLG_EDGE"))); @@ -164,6 +166,8 @@ SMESHGUI_ExtrusionAlongPathDlg::SMESHGUI_ExtrusionAlongPathDlg( SMESHGUI* theMod ElementsLineEdit = new QLineEdit(GroupArguments); ElementsLineEdit->setValidator(myIdValidator); + QPushButton* filterBtn = new QPushButton( tr( "SMESH_BUT_FILTER" ), GroupArguments ); + connect(filterBtn, SIGNAL(clicked()), this, SLOT(setFilters())); // Controls for the whole mesh selection MeshCheck = new QCheckBox(tr("SMESH_SELECT_WHOLE_MESH"), GroupArguments); @@ -272,11 +276,12 @@ SMESHGUI_ExtrusionAlongPathDlg::SMESHGUI_ExtrusionAlongPathDlg( SMESHGUI* theMod GroupArgumentsLayout->addWidget(ElementsLab, 0, 0); GroupArgumentsLayout->addWidget(SelectElementsButton, 0, 1); GroupArgumentsLayout->addWidget(ElementsLineEdit, 0, 2); - GroupArgumentsLayout->addWidget(MeshCheck, 1, 0, 1, 3); - GroupArgumentsLayout->addWidget(PathGrp, 2, 0, 1, 3); - GroupArgumentsLayout->addWidget(BasePointGrp, 3, 0, 1, 3); - GroupArgumentsLayout->addWidget(AnglesGrp, 4, 0, 1, 3); - GroupArgumentsLayout->addWidget(MakeGroupsCheck, 5, 0, 1, 3); + GroupArgumentsLayout->addWidget(filterBtn, 0, 3); + GroupArgumentsLayout->addWidget(MeshCheck, 1, 0, 1, 4); + GroupArgumentsLayout->addWidget(PathGrp, 2, 0, 1, 4); + GroupArgumentsLayout->addWidget(BasePointGrp, 3, 0, 1, 4); + GroupArgumentsLayout->addWidget(AnglesGrp, 4, 0, 1, 4); + GroupArgumentsLayout->addWidget(MakeGroupsCheck, 5, 0, 1, 4); /***************************************************************/ // common buttons group box @@ -382,6 +387,10 @@ SMESHGUI_ExtrusionAlongPathDlg::SMESHGUI_ExtrusionAlongPathDlg( SMESHGUI* theMod SMESHGUI_ExtrusionAlongPathDlg::~SMESHGUI_ExtrusionAlongPathDlg() { // no need to delete child widgets, Qt does it all for us + if ( myFilterDlg != 0 ) { + myFilterDlg->setParent( 0 ); + delete myFilterDlg; + } } //================================================================================= @@ -693,8 +702,11 @@ void SMESHGUI_ExtrusionAlongPathDlg::reject() disconnect(mySelectionMgr, 0, this, 0); mySelectionMgr->clearFilters(); //mySelectionMgr->clearSelected(); - SMESH::SetPickable(); // ??? - SMESH::SetPointRepresentation(false); + if (SMESH::GetCurrentVtkView()) { + SMESH::RemoveFilters(); // PAL6938 -- clean all mesh entity filters + SMESH::SetPointRepresentation(false); + SMESH::SetPickable(); + } if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI )) aViewWindow->SetSelectionMode(ActorSelection); mySMESHGUI->ResetState(); @@ -1199,3 +1211,25 @@ void SMESHGUI_ExtrusionAlongPathDlg::keyPressEvent( QKeyEvent* e ) ClickOnHelp(); } } + +//================================================================================= +// function : setFilters() +// purpose : SLOT. Called when "Filter" button pressed. +//================================================================================= +void SMESHGUI_ExtrusionAlongPathDlg::setFilters() +{ + if ( !myFilterDlg ) + { + QList types; + types.append( SMESH::EDGE ); + types.append( SMESH::FACE ); + myFilterDlg = new SMESHGUI_FilterDlg( mySMESHGUI, types ); + } + myFilterDlg->Init( Elements1dRB->isChecked() ? SMESH::EDGE : SMESH::FACE ); + + myFilterDlg->SetSelection(); + myFilterDlg->SetMesh( myMesh ); + myFilterDlg->SetSourceWg( ElementsLineEdit ); + + myFilterDlg->show(); +} diff --git a/src/SMESHGUI/SMESHGUI_ExtrusionAlongPathDlg.h b/src/SMESHGUI/SMESHGUI_ExtrusionAlongPathDlg.h index 4e1aed8c3..9ca43c0d1 100644 --- a/src/SMESHGUI/SMESHGUI_ExtrusionAlongPathDlg.h +++ b/src/SMESHGUI/SMESHGUI_ExtrusionAlongPathDlg.h @@ -50,6 +50,7 @@ class SMESHGUI; class SMESH_Actor; class SMESHGUI_IdValidator; class SMESHGUI_SpinBox; +class SMESHGUI_FilterDlg; class SVTK_Selector; class LightApp_SelectionMgr; class SUIT_SelectionFilter; @@ -134,6 +135,8 @@ private: QString myHelpFileName; + SMESHGUI_FilterDlg* myFilterDlg; + protected slots: void reject(); @@ -150,6 +153,7 @@ private slots: void onSelectMesh(); void OnAngleAdded(); void OnAngleRemoved(); + void setFilters(); }; #endif // SMESHGUI_EXTRUSIONALONGPATHDLG_H diff --git a/src/SMESHGUI/SMESHGUI_ExtrusionDlg.cxx b/src/SMESHGUI/SMESHGUI_ExtrusionDlg.cxx index 75bffe091..a6f1a1cca 100644 --- a/src/SMESHGUI/SMESHGUI_ExtrusionDlg.cxx +++ b/src/SMESHGUI/SMESHGUI_ExtrusionDlg.cxx @@ -32,6 +32,7 @@ #include "SMESHGUI_MeshUtils.h" #include "SMESHGUI_SpinBox.h" #include "SMESHGUI_IdValidator.h" +#include "SMESHGUI_FilterDlg.h" #include #include @@ -55,6 +56,7 @@ // OCCT includes #include #include +#include // Qt includes #include @@ -86,7 +88,8 @@ SMESHGUI_ExtrusionDlg::SMESHGUI_ExtrusionDlg (SMESHGUI* theModule) : QDialog( SMESH::GetDesktop( theModule ) ), mySMESHGUI( theModule ), - mySelectionMgr( SMESH::GetSelectionMgr( theModule ) ) + mySelectionMgr( SMESH::GetSelectionMgr( theModule ) ), + myFilterDlg( 0 ) { QPixmap image0 (SMESH::GetResourceMgr( mySMESHGUI )->loadPixmap("SMESH", tr("ICON_DLG_EDGE"))); QPixmap image1 (SMESH::GetResourceMgr( mySMESHGUI )->loadPixmap("SMESH", tr("ICON_DLG_TRIANGLE"))); @@ -159,22 +162,39 @@ SMESHGUI_ExtrusionDlg::SMESHGUI_ExtrusionDlg (SMESHGUI* theModule) LineEditElements = new QLineEdit(GroupArguments); LineEditElements->setValidator(myIdValidator); + QPushButton* filterBtn = new QPushButton( tr( "SMESH_BUT_FILTER" ), GroupArguments ); + connect(filterBtn, SIGNAL(clicked()), this, SLOT(setFilters())); // Control for the whole mesh selection CheckBoxMesh = new QCheckBox(tr("SMESH_SELECT_WHOLE_MESH"), GroupArguments); - // Controls for vector selection + //Control for the Distance selection + TextLabelDistance = new QLabel(tr("SMESH_DISTANCE"), GroupArguments); + TextLabelVector = new QLabel(tr("SMESH_VECTOR"), GroupArguments); - - TextLabelDx = new QLabel(tr("SMESH_DX"), GroupArguments); + TextLabelDx = new QLabel(tr("SMESH_X"), GroupArguments); SpinBox_Dx = new SMESHGUI_SpinBox(GroupArguments); - - TextLabelDy = new QLabel(tr("SMESH_DY"), GroupArguments); + + TextLabelDy = new QLabel(tr("SMESH_Y"), GroupArguments); SpinBox_Dy = new SMESHGUI_SpinBox(GroupArguments); - TextLabelDz = new QLabel(tr("SMESH_DZ"), GroupArguments); + TextLabelDz = new QLabel(tr("SMESH_Z"), GroupArguments); SpinBox_Dz = new SMESHGUI_SpinBox(GroupArguments); + // Controls for vector selection + + SelectVectorButton = new QPushButton(GroupArguments); + SelectVectorButton->setIcon(image2); + + TextLabelVx = new QLabel(tr("SMESH_DX"), GroupArguments); + SpinBox_Vx = new SMESHGUI_SpinBox(GroupArguments); + + TextLabelVy = new QLabel(tr("SMESH_DY"), GroupArguments); + SpinBox_Vy = new SMESHGUI_SpinBox(GroupArguments); + + TextLabelVz = new QLabel(tr("SMESH_DZ"), GroupArguments); + SpinBox_Vz = new SMESHGUI_SpinBox(GroupArguments); + // Controls for nb. steps defining TextLabelNbSteps = new QLabel(tr("SMESH_NUMBEROFSTEPS"), GroupArguments); SpinBox_NbSteps = new QSpinBox(GroupArguments); @@ -184,18 +204,27 @@ SMESHGUI_ExtrusionDlg::SMESHGUI_ExtrusionDlg (SMESHGUI* theModule) GroupArgumentsLayout->addWidget(TextLabelElements, 0, 0); GroupArgumentsLayout->addWidget(SelectElementsButton, 0, 1); - GroupArgumentsLayout->addWidget(LineEditElements, 0, 2, 1, 6); + GroupArgumentsLayout->addWidget(LineEditElements, 0, 2, 1, 5); + GroupArgumentsLayout->addWidget(filterBtn, 0, 7); GroupArgumentsLayout->addWidget(CheckBoxMesh, 1, 0, 1, 8); - GroupArgumentsLayout->addWidget(TextLabelVector, 2, 0); + GroupArgumentsLayout->addWidget(TextLabelDistance, 2, 0); GroupArgumentsLayout->addWidget(TextLabelDx, 2, 2); GroupArgumentsLayout->addWidget(SpinBox_Dx, 2, 3); GroupArgumentsLayout->addWidget(TextLabelDy, 2, 4); GroupArgumentsLayout->addWidget(SpinBox_Dy, 2, 5); GroupArgumentsLayout->addWidget(TextLabelDz, 2, 6); GroupArgumentsLayout->addWidget(SpinBox_Dz, 2, 7); - GroupArgumentsLayout->addWidget(TextLabelNbSteps, 3, 0); - GroupArgumentsLayout->addWidget(SpinBox_NbSteps, 3, 2, 1, 6); - GroupArgumentsLayout->addWidget(MakeGroupsCheck, 4, 0, 1, 8); + GroupArgumentsLayout->addWidget(TextLabelVector, 3, 0); + GroupArgumentsLayout->addWidget(SelectVectorButton, 3, 1); + GroupArgumentsLayout->addWidget(TextLabelVx, 3, 2); + GroupArgumentsLayout->addWidget(SpinBox_Vx, 3, 3); + GroupArgumentsLayout->addWidget(TextLabelVy, 3, 4); + GroupArgumentsLayout->addWidget(SpinBox_Vy, 3, 5); + GroupArgumentsLayout->addWidget(TextLabelVz, 3, 6); + GroupArgumentsLayout->addWidget(SpinBox_Vz, 3, 7); + GroupArgumentsLayout->addWidget(TextLabelNbSteps, 4, 0); + GroupArgumentsLayout->addWidget(SpinBox_NbSteps, 4, 2, 1, 6); + GroupArgumentsLayout->addWidget(MakeGroupsCheck, 5, 0, 1, 8); /***************************************************************/ SMESHGUI_ExtrusionDlgLayout->addWidget(ConstructorsBox); @@ -203,10 +232,14 @@ SMESHGUI_ExtrusionDlg::SMESHGUI_ExtrusionDlg (SMESHGUI* theModule) SMESHGUI_ExtrusionDlgLayout->addWidget(GroupButtons); /* Initialisations */ + SpinBox_Vx->RangeStepAndValidator(-1, 1, 0.01, 3); + SpinBox_Vy->RangeStepAndValidator(-1, 1, 0.01, 3); + SpinBox_Vz->RangeStepAndValidator(-1, 1, 0.01, 3); + SpinBox_Dx->RangeStepAndValidator(COORD_MIN, COORD_MAX, 10.0, 3); SpinBox_Dy->RangeStepAndValidator(COORD_MIN, COORD_MAX, 10.0, 3); SpinBox_Dz->RangeStepAndValidator(COORD_MIN, COORD_MAX, 10.0, 3); - + SpinBox_NbSteps->setRange(1, 999999); RadioButton1->setChecked(true); @@ -239,12 +272,16 @@ SMESHGUI_ExtrusionDlg::SMESHGUI_ExtrusionDlg (SMESHGUI* theModule) connect(buttonHelp, SIGNAL(clicked()), this, SLOT(ClickOnHelp())); // to update state of the Ok & Apply buttons + connect(SpinBox_Vx, SIGNAL(valueChanged(double)), SLOT(CheckIsEnable())); + connect(SpinBox_Vy, SIGNAL(valueChanged(double)), SLOT(CheckIsEnable())); + connect(SpinBox_Vz, SIGNAL(valueChanged(double)), SLOT(CheckIsEnable())); connect(SpinBox_Dx, SIGNAL(valueChanged(double)), SLOT(CheckIsEnable())); connect(SpinBox_Dy, SIGNAL(valueChanged(double)), SLOT(CheckIsEnable())); connect(SpinBox_Dz, SIGNAL(valueChanged(double)), SLOT(CheckIsEnable())); connect(GroupConstructors, SIGNAL(buttonClicked(int)), SLOT(ConstructorsClicked(int))); connect(SelectElementsButton, SIGNAL(clicked()), this, SLOT(SetEditCurrentArgument())); + connect(SelectVectorButton, SIGNAL(clicked()), this, SLOT(SetEditCurrentArgument())); connect(mySMESHGUI, SIGNAL(SignalDeactivateActiveDialog()), this, SLOT(DeactivateActiveDialog())); connect(mySelectionMgr, SIGNAL(currentSelectionChanged()), this, SLOT(SelectionIntoArgument())); /* to close dialog if study change */ @@ -264,6 +301,10 @@ SMESHGUI_ExtrusionDlg::SMESHGUI_ExtrusionDlg (SMESHGUI* theModule) //================================================================================= SMESHGUI_ExtrusionDlg::~SMESHGUI_ExtrusionDlg() { + if ( myFilterDlg != 0 ) { + myFilterDlg->setParent( 0 ); + delete myFilterDlg; + } } //================================================================================= @@ -285,6 +326,9 @@ void SMESHGUI_ExtrusionDlg::Init (bool ResetControls) SpinBox_Dx->SetValue(0); SpinBox_Dy->SetValue(0); SpinBox_Dz->SetValue(0); + SpinBox_Vx->SetValue(0); + SpinBox_Vy->SetValue(0); + SpinBox_Vz->SetValue(0); CheckBoxMesh->setChecked(false); onSelectMesh(false); @@ -299,9 +343,10 @@ void SMESHGUI_ExtrusionDlg::Init (bool ResetControls) //================================================================================= void SMESHGUI_ExtrusionDlg::CheckIsEnable() { - double aX = SpinBox_Dx->GetValue(); - double aY = SpinBox_Dy->GetValue(); - double aZ = SpinBox_Dz->GetValue(); + + double aX = SpinBox_Vx->GetValue()*SpinBox_Dx->GetValue(); + double aY = SpinBox_Vy->GetValue()*SpinBox_Dy->GetValue(); + double aZ = SpinBox_Vz->GetValue()*SpinBox_Dz->GetValue(); double aModule = sqrt(aX*aX + aY*aY + aZ*aZ); bool anIsEnable = myNbOkElements > 0 && aModule > 1.0E-38; @@ -341,7 +386,7 @@ void SMESHGUI_ExtrusionDlg::ConstructorsClicked (int constructorId) } } - myEditCurrentArgument = LineEditElements; + myEditCurrentArgument = (QWidget*)LineEditElements; LineEditElements->setFocus(); if (CheckBoxMesh->isChecked()) @@ -360,11 +405,17 @@ bool SMESHGUI_ExtrusionDlg::ClickOnApply() return false; if (myNbOkElements) { - + + gp_XYZ aNormale(SpinBox_Vx->GetValue(), + SpinBox_Vy->GetValue(), + SpinBox_Vz->GetValue()); + + aNormale /= aNormale.Modulus(); + SMESH::DirStruct aVector; - aVector.PS.x = SpinBox_Dx->GetValue(); - aVector.PS.y = SpinBox_Dy->GetValue(); - aVector.PS.z = SpinBox_Dz->GetValue(); + aVector.PS.x = SpinBox_Dx->GetValue()*aNormale.X(); + aVector.PS.y = SpinBox_Dy->GetValue()*aNormale.Y(); + aVector.PS.z = SpinBox_Dz->GetValue()*aNormale.Z(); long aNbSteps = (long)SpinBox_NbSteps->value(); @@ -410,8 +461,11 @@ void SMESHGUI_ExtrusionDlg::ClickOnCancel() disconnect(mySelectionMgr, 0, this, 0); mySelectionMgr->clearFilters(); //mySelectionMgr->clearSelected(); - SMESH::SetPickable(); // ??? - SMESH::SetPointRepresentation(false); + if (SMESH::GetCurrentVtkView()) { + SMESH::RemoveFilters(); // PAL6938 -- clean all mesh entity filters + SMESH::SetPointRepresentation(false); + SMESH::SetPickable(); + } if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI )) aViewWindow->SetSelectionMode(ActorSelection); mySMESHGUI->ResetState(); @@ -514,15 +568,15 @@ void SMESHGUI_ExtrusionDlg::SelectionIntoArgument() // clear myActor = 0; myIO.Nullify(); - QString aString = ""; + QString aString = ""; // set busy flag - myBusy = true; - - myEditCurrentArgument->setText(aString); - myNbOkElements = 0; - myBusy = false; - + if(myEditCurrentArgument == (QWidget*)LineEditElements) { + myBusy = true; + LineEditElements->setText(aString); + myNbOkElements = 0; + myBusy = false; + } // get selected mesh SALOME_ListIO aList; mySelectionMgr->selectedObjects(aList, SVTK_Viewer::Type()); @@ -537,7 +591,7 @@ void SMESHGUI_ExtrusionDlg::SelectionIntoArgument() myIO = IO; myActor = SMESH::FindActorByObject(myMesh); - if (myEditCurrentArgument == LineEditElements) { + if (myEditCurrentArgument == (QWidget*)LineEditElements) { int aNbElements = 0; // MakeGroups is available if there are groups @@ -595,12 +649,32 @@ void SMESHGUI_ExtrusionDlg::SelectionIntoArgument() return; myNbOkElements = true; + + myBusy = true; + ((QLineEdit*)myEditCurrentArgument)->setText(aString); + myBusy = false; } + else if(myEditCurrentArgument == (QWidget*)SpinBox_Vx){ + TColStd_IndexedMapOfInteger aMapIndex; + mySelector->GetIndex(IO,aMapIndex); + int aNbElements = aMapIndex.Extent(); + SMDS_Mesh* aMesh = myActor ? myActor->GetObject()->GetMesh() : 0; - myBusy = true; - myEditCurrentArgument->setText(aString); - myBusy = false; + if(aNbElements != 1 || !aMesh) + return; + + const SMDS_MeshFace* face = dynamic_cast(aMesh->FindElement(aMapIndex(aNbElements))); + + if (!face) + return; + gp_XYZ aNormale = SMESH::getNormale(face); + SpinBox_Vx->SetValue(aNormale.X()); + SpinBox_Vy->SetValue(aNormale.Y()); + SpinBox_Vz->SetValue(aNormale.Z()); + + } + // OK CheckIsEnable(); } @@ -618,7 +692,7 @@ void SMESHGUI_ExtrusionDlg::SetEditCurrentArgument() mySelectionMgr->clearFilters(); if (send == SelectElementsButton) { - myEditCurrentArgument = LineEditElements; + myEditCurrentArgument = (QWidget*)LineEditElements; if (CheckBoxMesh->isChecked()) { if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI )) aViewWindow->SetSelectionMode(ActorSelection); @@ -637,7 +711,12 @@ void SMESHGUI_ExtrusionDlg::SetEditCurrentArgument() } } } - + else if (send == SelectVectorButton){ + myEditCurrentArgument = (QWidget*)SpinBox_Vx; + if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI )) + aViewWindow->SetSelectionMode(FaceSelection); + } + myEditCurrentArgument->setFocus(); connect(mySelectionMgr, SIGNAL(currentSelectionChanged()), this, SLOT(SelectionIntoArgument())); SelectionIntoArgument(); @@ -755,3 +834,25 @@ void SMESHGUI_ExtrusionDlg::keyPressEvent( QKeyEvent* e ) ClickOnHelp(); } } + +//================================================================================= +// function : setFilters() +// purpose : SLOT. Called when "Filter" button pressed. +//================================================================================= +void SMESHGUI_ExtrusionDlg::setFilters() +{ + if ( !myFilterDlg ) + { + QList types; + types.append( SMESH::EDGE ); + types.append( SMESH::FACE ); + myFilterDlg = new SMESHGUI_FilterDlg( mySMESHGUI, types ); + } + myFilterDlg->Init( GetConstructorId() ? SMESH::FACE : SMESH::EDGE ); + + myFilterDlg->SetSelection(); + myFilterDlg->SetMesh( myMesh ); + myFilterDlg->SetSourceWg( LineEditElements ); + + myFilterDlg->show(); +} diff --git a/src/SMESHGUI/SMESHGUI_ExtrusionDlg.h b/src/SMESHGUI/SMESHGUI_ExtrusionDlg.h index 84d4587a9..ee3ec9cb5 100644 --- a/src/SMESHGUI/SMESHGUI_ExtrusionDlg.h +++ b/src/SMESHGUI/SMESHGUI_ExtrusionDlg.h @@ -52,6 +52,7 @@ class SMESHGUI; class SMESH_Actor; class SMESHGUI_IdValidator; class SMESHGUI_SpinBox; +class SMESHGUI_FilterDlg; class SVTK_Selector; class LightApp_SelectionMgr; class SUIT_SelectionFilter; @@ -77,7 +78,7 @@ private: SMESHGUI* mySMESHGUI; /* Current SMESHGUI object */ SMESHGUI_IdValidator* myIdValidator; LightApp_SelectionMgr* mySelectionMgr; /* User shape selection */ - QLineEdit* myEditCurrentArgument; /* Current LineEdit */ + QWidget* myEditCurrentArgument; /* Current argument editor */ int myNbOkElements; /* to check when elements are defined */ SVTK_Selector* mySelector; @@ -100,12 +101,20 @@ private: QLineEdit* LineEditElements; QCheckBox* CheckBoxMesh; QLabel* TextLabelVector; + QLabel* TextLabelDistance; + QPushButton* SelectVectorButton; QLabel* TextLabelDx; SMESHGUI_SpinBox* SpinBox_Dx; QLabel* TextLabelDy; SMESHGUI_SpinBox* SpinBox_Dy; QLabel* TextLabelDz; SMESHGUI_SpinBox* SpinBox_Dz; + QLabel* TextLabelVx; + SMESHGUI_SpinBox* SpinBox_Vx; + QLabel* TextLabelVy; + SMESHGUI_SpinBox* SpinBox_Vy; + QLabel* TextLabelVz; + SMESHGUI_SpinBox* SpinBox_Vz; QLabel* TextLabelNbSteps; QSpinBox* SpinBox_NbSteps; QCheckBox* MakeGroupsCheck; @@ -118,6 +127,8 @@ private: QString myHelpFileName; + SMESHGUI_FilterDlg* myFilterDlg; + private slots: void ConstructorsClicked( int ); void CheckIsEnable(); @@ -131,6 +142,7 @@ private slots: void ActivateThisDialog(); void onTextChange( const QString& ); void onSelectMesh( bool ); + void setFilters(); }; #endif // SMESHGUI_EXTRUSIONDLG_H diff --git a/src/SMESHGUI/SMESHGUI_Filter.cxx b/src/SMESHGUI/SMESHGUI_Filter.cxx index a022365c8..e6d12feec 100755 --- a/src/SMESHGUI/SMESHGUI_Filter.cxx +++ b/src/SMESHGUI/SMESHGUI_Filter.cxx @@ -82,17 +82,18 @@ bool SMESHGUI_PredicateFilter::IsValid( const int theCellId ) const return false; SMDS_Mesh* aMesh = anActor->GetObject()->GetMesh(); - SMESH::ElementType anElemType = myPred->GetElementType(); - int aMeshId = anElemType == SMESH::NODE ? anActor->GetNodeObjId( theCellId ) - : anActor->GetElemObjId( theCellId ); + SMDSAbs_ElementType anElemType = (SMDSAbs_ElementType)myPred->GetElementType(); + int aMeshId = anElemType == SMDSAbs_Node ? anActor->GetNodeObjId( theCellId ) + : anActor->GetElemObjId( theCellId ); // if type of element != type of predicate return true because // this predicate is not intended for filtering sush elements - const SMDS_MeshElement* anElem = anElemType == SMESH::NODE ? aMesh->FindNode( aMeshId ) - : aMesh->FindElement( aMeshId ); - if ( anElem != 0 && anElem->GetType() != (SMDSAbs_ElementType)myPred->GetElementType() ) - return true; - + const SMDS_MeshElement* anElem = anElemType == SMDSAbs_Node ? aMesh->FindNode( aMeshId ) + : aMesh->FindElement( aMeshId ); + // here we guess that predicate element type can not be All in case of node selection + if ( !anElem || (anElemType != SMDSAbs_All && anElem->GetType() != anElemType) ) + return false; + return myPred->IsSatisfy( aMeshId ); } @@ -110,14 +111,15 @@ bool SMESHGUI_PredicateFilter::IsObjValid( const int theObjId ) const return false; SMDS_Mesh* aMesh = anActor->GetObject()->GetMesh(); - SMESH::ElementType anElemType = myPred->GetElementType(); + SMDSAbs_ElementType anElemType = (SMDSAbs_ElementType)myPred->GetElementType(); // if type of element != type of predicate return true because // this predicate is not intended for filtering sush elements - const SMDS_MeshElement* anElem = anElemType == SMESH::NODE ? aMesh->FindNode( theObjId ) - : aMesh->FindElement( theObjId ); - if ( anElem != 0 && anElem->GetType() != (SMDSAbs_ElementType)myPred->GetElementType() ) - return true; + const SMDS_MeshElement* anElem = anElemType == SMDSAbs_Node ? aMesh->FindNode( theObjId ) + : aMesh->FindElement( theObjId ); + // here we guess that predicate element type can not be All in case of node selection + if ( !anElem || (anElemType != SMDSAbs_All && anElem->GetType() != anElemType) ) + return false; return myPred->IsSatisfy( theObjId ); } diff --git a/src/SMESHGUI/SMESHGUI_FilterDlg.cxx b/src/SMESHGUI/SMESHGUI_FilterDlg.cxx index 9491e8de6..1235ce71e 100755 --- a/src/SMESHGUI/SMESHGUI_FilterDlg.cxx +++ b/src/SMESHGUI/SMESHGUI_FilterDlg.cxx @@ -47,6 +47,8 @@ #include #include #include +#include +#include #include #include @@ -699,8 +701,6 @@ void SMESHGUI_FilterTable::Init (const QList& theTypes) if (myTables.isEmpty()) { - int aType = theTypes.first(); - // create main layout QVBoxLayout* aMainLay = new QVBoxLayout(this); aMainLay->setMargin( 0 ); @@ -730,8 +730,14 @@ void SMESHGUI_FilterTable::Init (const QList& theTypes) mySwitchTableGrpLayout->setMargin(0); mySwitchTableGrpLayout->setSpacing(0); - myTables[ aType ] = createTable(mySwitchTableGrp, aType); - mySwitchTableGrpLayout->addWidget(myTables[ aType ]); + QList::const_iterator typeIt = theTypes.begin(); + for ( ; typeIt != theTypes.end(); ++typeIt ) { + Table* aTable = createTable(mySwitchTableGrp, *typeIt); + myTables[ *typeIt ] = aTable; + mySwitchTableGrpLayout->addWidget(aTable); + if ( typeIt != theTypes.begin() ) + aTable->hide(); + } // create buttons myAddBtn = new QPushButton(tr("ADD"), myTableGrp); @@ -899,41 +905,43 @@ bool SMESHGUI_FilterTable::IsValid (const bool theMess, const int theEntityType) for (int i = 0, n = aTable->rowCount(); i < n; i++) { int aCriterion = GetCriterionType(i, aType); - - if (aCriterion == SMESH::FT_RangeOfIds || + QString errMsg; + if (aCriterion == SMESH::FT_GroupColor ) { + QtxColorButton* clrBtn = qobject_cast(aTable->cellWidget(i, 2)); + if (clrBtn && !clrBtn->color().isValid()) + errMsg = tr( "GROUPCOLOR_ERROR" ); + } else if (aCriterion == SMESH::FT_ElemGeomType ) { + QtxComboBox* typeBox = qobject_cast(aTable->cellWidget(i, 2)); + if (typeBox && typeBox->currentId() == -1) + errMsg = tr( "ERROR" ); + } else if (aCriterion == SMESH::FT_RangeOfIds || aCriterion == SMESH::FT_BelongToGeom || aCriterion == SMESH::FT_BelongToPlane || aCriterion == SMESH::FT_BelongToCylinder || aCriterion == SMESH::FT_BelongToGenSurface || aCriterion == SMESH::FT_LyingOnGeom) { - if (aTable->text(i, 2).isEmpty()) { - if (theMess) - SUIT_MessageBox::information(SMESHGUI::desktop(), tr("SMESH_INSUFFICIENT_DATA"), - tr("ERROR")); - return false; - } - } else { + if (aTable->text(i, 2).isEmpty()); + errMsg = tr( "ERROR" ); + } + else { bool aRes = false; bool isSignalsBlocked = aTable->signalsBlocked(); aTable->blockSignals(true); double aThreshold = (int)aTable->text(i, 2).toDouble(&aRes); aTable->blockSignals(isSignalsBlocked); - if (!aRes && aTable->isEditable(i, 2)) { - if (theMess) - SUIT_MessageBox::information(SMESHGUI::desktop(), tr("SMESH_INSUFFICIENT_DATA"), - tr("ERROR")); - return false; - } + if (!aRes && aTable->isEditable(i, 2)) + errMsg = tr( "ERROR" ); else if (aType == SMESH::EDGE && GetCriterionType(i, aType) == SMESH::FT_MultiConnection && aThreshold == 1) - { - if (theMess) - SUIT_MessageBox::information(SMESHGUI::desktop(), tr("SMESH_INSUFFICIENT_DATA"), - tr("MULTIEDGES_ERROR")); - return false; - } + errMsg = tr( "MULTIEDGES_ERROR" ); + } + + if (!errMsg.isEmpty()) { + if (theMess) + SUIT_MessageBox::information(SMESHGUI::desktop(), tr("SMESH_INSUFFICIENT_DATA"), errMsg ); + return false; } QTableWidgetItem* anItem = aTable->item(i, 0); @@ -1012,12 +1020,28 @@ void SMESHGUI_FilterTable::GetCriterion (const int theRow, int aCriterionType = GetCriterionType(theRow, aType); - if ( aCriterionType != SMESH::FT_RangeOfIds && - aCriterionType != SMESH::FT_BelongToGeom && - aCriterionType != SMESH::FT_BelongToPlane && - aCriterionType != SMESH::FT_BelongToCylinder && - aCriterionType != SMESH::FT_BelongToGenSurface && - aCriterionType != SMESH::FT_LyingOnGeom) + if ( aCriterionType == SMESH::FT_GroupColor ) + { + QtxColorButton* clrBtn = qobject_cast(aTable->cellWidget(theRow, 2)); + if ( clrBtn ) + { + const QColor qClr = clrBtn->color(); + QString clrStr = QString( "%1;%2;%3" ). + arg( qClr.red()/256. ).arg( qClr.green()/256. ).arg( qClr.blue()/256. ); + theCriterion.ThresholdStr = clrStr.toLatin1().constData(); + } + } + else if ( aCriterionType == SMESH::FT_ElemGeomType ) { + QtxComboBox* typeBox = qobject_cast(aTable->cellWidget(theRow, 2)); + if ( typeBox ) + theCriterion.Threshold = (double)typeBox->currentId(); + } + else if ( aCriterionType != SMESH::FT_RangeOfIds && + aCriterionType != SMESH::FT_BelongToGeom && + aCriterionType != SMESH::FT_BelongToPlane && + aCriterionType != SMESH::FT_BelongToCylinder && + aCriterionType != SMESH::FT_BelongToGenSurface && + aCriterionType != SMESH::FT_LyingOnGeom) { theCriterion.Compare = ((ComboItem*)aTable->item(theRow, 1))->value(); theCriterion.Threshold = aTable->item(theRow, 2)->text().toDouble(); @@ -1063,7 +1087,28 @@ void SMESHGUI_FilterTable::SetCriterion (const int theRow, else aTable->setEditable(false, theRow, 4); - if (theCriterion.Type != SMESH::FT_RangeOfIds && + if (theCriterion.Type == SMESH::FT_GroupColor ) + { + QtxColorButton* clrBtn = qobject_cast(aTable->cellWidget(theRow, 2)); + if ( clrBtn ) + { + QColor qClr; + QString clrStr( theCriterion.ThresholdStr ); + QStringList clrVals = clrStr.split( ";" ); + if ( clrVals.count() > 2 ) + qClr.setRgb( (int)256*clrVals[0].toDouble(), + (int)256*clrVals[1].toDouble(), + (int)256*clrVals[2].toDouble() ); + clrBtn->setColor( qClr ); + } + } + else if (theCriterion.Type == SMESH::FT_ElemGeomType ) + { + QtxComboBox* typeBox = qobject_cast(aTable->cellWidget(theRow, 2)); + if ( typeBox ) + typeBox->setCurrentId( (int)(theCriterion.Threshold + 0.5) ); + } + else if (theCriterion.Type != SMESH::FT_RangeOfIds && theCriterion.Type != SMESH::FT_BelongToGeom && theCriterion.Type != SMESH::FT_BelongToPlane && theCriterion.Type != SMESH::FT_BelongToCylinder && @@ -1071,7 +1116,10 @@ void SMESHGUI_FilterTable::SetCriterion (const int theRow, theCriterion.Type != SMESH::FT_LyingOnGeom && theCriterion.Type != SMESH::FT_FreeBorders && theCriterion.Type != SMESH::FT_FreeEdges && - theCriterion.Type != SMESH::FT_BadOrientedVolume) + theCriterion.Type != SMESH::FT_FreeNodes && + theCriterion.Type != SMESH::FT_FreeFaces && + theCriterion.Type != SMESH::FT_BadOrientedVolume && + theCriterion.Type != SMESH::FT_LinearOrQuadratic) aTable->item( theRow, 2 )->setText(QString("%1").arg(theCriterion.Threshold, 0, 'g', 15)); else { @@ -1222,12 +1270,15 @@ void SMESHGUI_FilterTable::updateAdditionalWidget() } ComboItem* anItem = ((ComboItem*)aTable->item(aRow, 0)); + int aCriterion = GetCriterionType(aRow); bool toEnable = ((ComboItem*)aTable->item(aRow, 1))->value() == SMESH::FT_EqualTo && - GetCriterionType(aRow) != SMESH::FT_BelongToGeom && - GetCriterionType(aRow) != SMESH::FT_LyingOnGeom && - GetCriterionType(aRow) != SMESH::FT_RangeOfIds && - GetCriterionType(aRow) != SMESH::FT_FreeEdges && - GetCriterionType(aRow) != SMESH::FT_BadOrientedVolume; + aCriterion != SMESH::FT_BelongToGeom && + aCriterion != SMESH::FT_LyingOnGeom && + aCriterion != SMESH::FT_RangeOfIds && + aCriterion != SMESH::FT_FreeEdges && + aCriterion != SMESH::FT_FreeFaces && + aCriterion != SMESH::FT_BadOrientedVolume; + if (!myAddWidgets.contains(anItem)) { myAddWidgets[ anItem ] = new AdditionalWidget(myWgStack); @@ -1287,6 +1338,34 @@ void SMESHGUI_FilterTable::onCurrentChanged (int theRow, int theCol) emit CurrentChanged(theRow, theCol); } +//======================================================================= +// name : geomTypes +// Purpose : returns available geometry types of elements +//======================================================================= +static QList geomTypes( const int theType ) +{ + QList typeIds; + if ( theType == SMESH::NODE ) + typeIds.append( SMESH::Geom_POINT ); + if ( theType == SMESH::ALL || theType == SMESH::EDGE ) + typeIds.append( SMESH::Geom_EDGE ); + if ( theType == SMESH::ALL || theType == SMESH::FACE ) + { + typeIds.append( SMESH::Geom_TRIANGLE ); + typeIds.append( SMESH::Geom_QUADRANGLE ); + typeIds.append( SMESH::Geom_POLYGON ); + } + if ( theType == SMESH::ALL || theType == SMESH::VOLUME ) + { + typeIds.append( SMESH::Geom_TETRA ); + typeIds.append( SMESH::Geom_PYRAMID ); + typeIds.append( SMESH::Geom_HEXA ); + typeIds.append( SMESH::Geom_PENTA ); + typeIds.append( SMESH::Geom_POLYHEDRA ); + } + return typeIds; +} + //======================================================================= // name : SMESHGUI_FilterTable::onCriterionChanged() // Purpose : Provides reaction on change of criterion @@ -1298,10 +1377,47 @@ void SMESHGUI_FilterTable::onCriterionChanged (const int row, const int col, con ComboItem* aCompareItem = (ComboItem*)aTable->item(row, 1); int aCriterionType = GetCriterionType(row); + QtxColorButton* clrBtn = qobject_cast(aTable->cellWidget(row, 2)); + QtxComboBox* typeBox = qobject_cast(aTable->cellWidget(row, 2)); + + if ( (aCriterionType == SMESH::FT_GroupColor && !clrBtn) || + (aCriterionType == SMESH::FT_ElemGeomType && !typeBox) ) + { + bool isSignalsBlocked = aTable->signalsBlocked(); + aTable->blockSignals( true ); + if ( aCriterionType == SMESH::FT_GroupColor ) + aTable->setCellWidget( row, 2, new QtxColorButton( aTable ) ); + else { + QtxComboBox* typeBox = new QtxComboBox( aTable ); + aTable->setCellWidget( row, 2, typeBox ); + QList typeIds = geomTypes( aType ); + QList::const_iterator anIter = typeIds.begin(); + for ( int i = 0; anIter != typeIds.end(); ++anIter, ++i) { + QString typeKey = QString( "GEOM_TYPE_%1" ).arg( *anIter ); + typeBox->addItem( tr( typeKey.toLatin1().data() ) ); + typeBox->setId( i, *anIter ); + } + } + aTable->blockSignals( isSignalsBlocked ); + } + else if ( (aCriterionType != SMESH::FT_GroupColor && clrBtn) || + (aCriterionType != SMESH::FT_ElemGeomType && typeBox) ) + { + bool isSignalsBlocked = aTable->signalsBlocked(); + aTable->blockSignals( true ); + aTable->setCellWidget( row, 2, 0 ); + aTable->setItem( row, 2, new QTableWidgetItem() ); + aTable->blockSignals( isSignalsBlocked ); + } - if (aType == SMESH::EDGE && aCriterionType == SMESH::FT_FreeBorders || - aType == SMESH::FACE && aCriterionType == SMESH::FT_FreeEdges || - aType == SMESH::VOLUME && aCriterionType == SMESH::FT_BadOrientedVolume) + if (aType == SMESH::NODE && aCriterionType == SMESH::FT_FreeNodes || + aType == SMESH::EDGE && aCriterionType == SMESH::FT_FreeBorders || + aType == SMESH::FACE && (aCriterionType == SMESH::FT_FreeEdges || + aCriterionType == SMESH::FT_FreeFaces) || + aType == SMESH::VOLUME && aCriterionType == SMESH::FT_BadOrientedVolume || + aCriterionType == SMESH::FT_LinearOrQuadratic || + aCriterionType == SMESH::FT_GroupColor || + aCriterionType == SMESH::FT_ElemGeomType) { bool isSignalsBlocked = aTable->signalsBlocked(); aTable->blockSignals( true ); @@ -1309,8 +1425,8 @@ void SMESHGUI_FilterTable::onCriterionChanged (const int row, const int col, con if (aCompareItem->count() > 0) aCompareItem->clear(); aTable->setEditable(false, row, 1); - aTable->setEditable(false, row, 2); - + aTable->setEditable(aCriterionType == SMESH::FT_GroupColor || + aCriterionType == SMESH::FT_ElemGeomType, row, 2); aTable->blockSignals( isSignalsBlocked ); } else if (aCriterionType == SMESH::FT_RangeOfIds || @@ -1328,6 +1444,12 @@ void SMESHGUI_FilterTable::onCriterionChanged (const int row, const int col, con if (!aTable->isEditable(row, 2)) aTable->setEditable(true, row, 2); } + else if (aCriterionType == SMESH::FT_GroupColor || + aCriterionType == SMESH::FT_ElemGeomType) + { + if (!aTable->isEditable(row, 2)) + aTable->setEditable(true, row, 2); + } else { if (aCompareItem->count() != 3) @@ -1505,6 +1627,7 @@ const QMap& SMESHGUI_FilterTable::getSupportedTypes() const aTypes[ SMESH::EDGE ] = tr("EDGES"); aTypes[ SMESH::FACE ] = tr("FACES"); aTypes[ SMESH::VOLUME ] = tr("VOLUMES"); + aTypes[ SMESH::ALL ] = tr("ELEMENTS"); } return aTypes; @@ -1527,6 +1650,8 @@ const QMap& SMESHGUI_FilterTable::getCriteria (const int theType) aCriteria[ SMESH::FT_BelongToCylinder ] = tr("BELONG_TO_CYLINDER"); aCriteria[ SMESH::FT_BelongToGenSurface ] = tr("BELONG_TO_GENSURFACE"); aCriteria[ SMESH::FT_LyingOnGeom ] = tr("LYING_ON_GEOM"); + aCriteria[ SMESH::FT_FreeNodes ] = tr("FREE_NODES"); + aCriteria[ SMESH::FT_GroupColor ] = tr("GROUP_COLOR"); } return aCriteria; } @@ -1544,6 +1669,9 @@ const QMap& SMESHGUI_FilterTable::getCriteria (const int theType) aCriteria[ SMESH::FT_BelongToCylinder ] = tr("BELONG_TO_CYLINDER"); aCriteria[ SMESH::FT_BelongToGenSurface ] = tr("BELONG_TO_GENSURFACE"); aCriteria[ SMESH::FT_LyingOnGeom ] = tr("LYING_ON_GEOM"); + aCriteria[ SMESH::FT_LinearOrQuadratic ] = tr("LINEAR"); + aCriteria[ SMESH::FT_GroupColor ] = tr("GROUP_COLOR"); + aCriteria[ SMESH::FT_ElemGeomType ] = tr("GEOM_TYPE"); } return aCriteria; } @@ -1567,6 +1695,10 @@ const QMap& SMESHGUI_FilterTable::getCriteria (const int theType) aCriteria[ SMESH::FT_LyingOnGeom ] = tr("LYING_ON_GEOM"); aCriteria[ SMESH::FT_Length2D ] = tr("LENGTH2D"); aCriteria[ SMESH::FT_MultiConnection2D ] = tr("MULTI2D_BORDERS"); + aCriteria[ SMESH::FT_FreeFaces ] = tr("FREE_FACES"); + aCriteria[ SMESH::FT_LinearOrQuadratic ] = tr("LINEAR"); + aCriteria[ SMESH::FT_GroupColor ] = tr("GROUP_COLOR"); + aCriteria[ SMESH::FT_ElemGeomType ] = tr("GEOM_TYPE"); } return aCriteria; } @@ -1581,12 +1713,25 @@ const QMap& SMESHGUI_FilterTable::getCriteria (const int theType) aCriteria[ SMESH::FT_LyingOnGeom ] = tr("LYING_ON_GEOM"); aCriteria[ SMESH::FT_BadOrientedVolume ] = tr("BAD_ORIENTED_VOLUME"); aCriteria[ SMESH::FT_Volume3D ] = tr("VOLUME_3D"); + aCriteria[ SMESH::FT_LinearOrQuadratic ] = tr("LINEAR"); + aCriteria[ SMESH::FT_GroupColor ] = tr("GROUP_COLOR"); + aCriteria[ SMESH::FT_ElemGeomType ] = tr("GEOM_TYPE"); } return aCriteria; } - else + else // SMESH::ALL { static QMap aCriteria; + if (aCriteria.isEmpty()) + { + aCriteria[ SMESH::FT_RangeOfIds ] = tr("RANGE_OF_IDS"); + aCriteria[ SMESH::FT_BelongToGeom ] = tr("BELONG_TO_GEOM"); + aCriteria[ SMESH::FT_LyingOnGeom ] = tr("LYING_ON_GEOM"); + aCriteria[ SMESH::FT_LinearOrQuadratic ] = tr("LINEAR"); + aCriteria[ SMESH::FT_GroupColor ] = tr("GROUP_COLOR"); + aCriteria[ SMESH::FT_ElemGeomType ] = tr("GEOM_TYPE"); + } + return aCriteria; } } @@ -2034,15 +2179,15 @@ QWidget* SMESHGUI_FilterDlg::createSourceGroup (QWidget* theParent) QRadioButton* aMeshBtn = new QRadioButton(tr("MESH"), aBox); QRadioButton* aSelBtn = new QRadioButton(tr("SELECTION"), aBox); - QRadioButton* aGrpBtn = new QRadioButton(tr("CURRENT_GROUP"), aBox); + QRadioButton* aDlgBtn = new QRadioButton(tr("CURRENT_DIALOG"),aBox); aLay->addWidget(aMeshBtn); aLay->addWidget(aSelBtn); - aLay->addWidget(aGrpBtn); + aLay->addWidget(aDlgBtn); mySourceGrp->addButton(aMeshBtn, Mesh); mySourceGrp->addButton(aSelBtn, Selection); - mySourceGrp->addButton(aGrpBtn, Dialog); + mySourceGrp->addButton(aDlgBtn, Dialog); aSelBtn->setChecked(true); @@ -2354,6 +2499,7 @@ Selection_Mode SMESHGUI_FilterDlg::getSelMode (const int theType) const case SMESH::EDGE : return EdgeSelection; case SMESH::FACE : return FaceSelection; case SMESH::VOLUME : return VolumeSelection; + case SMESH::ALL : return CellSelection; default : return ActorSelection; } @@ -2483,10 +2629,9 @@ void SMESHGUI_FilterDlg::SetSourceWg (QWidget* theWg) void SMESHGUI_FilterDlg::SetMesh (SMESH::SMESH_Mesh_var theMesh) { myMesh = theMesh; - if ( myMesh->_is_nil() ) { - myButtons[BTN_OK]->setEnabled(false); - myButtons[BTN_Apply]->setEnabled(false); - } + const bool isEnable = !(myMesh->_is_nil()); + myButtons[BTN_OK]->setEnabled(isEnable); + myButtons[BTN_Apply]->setEnabled(isEnable); } //======================================================================= @@ -2829,13 +2974,14 @@ void SMESHGUI_FilterDlg::onSelectionDone() } } + int aCriterionType = myTable->GetCriterionType(aRow); if (aList.Extent() != 1 || !myTable->CurrentCell(aRow, aCol) || - myTable->GetCriterionType(aRow) != SMESH::FT_BelongToGeom && - myTable->GetCriterionType(aRow) != SMESH::FT_BelongToPlane && - myTable->GetCriterionType(aRow) != SMESH::FT_BelongToCylinder && - myTable->GetCriterionType(aRow) != SMESH::FT_BelongToGenSurface && - myTable->GetCriterionType(aRow) != SMESH::FT_LyingOnGeom) + aCriterionType != SMESH::FT_BelongToGeom && + aCriterionType != SMESH::FT_BelongToPlane && + aCriterionType != SMESH::FT_BelongToCylinder && + aCriterionType != SMESH::FT_BelongToGenSurface && + aCriterionType != SMESH::FT_LyingOnGeom) return; Handle(SALOME_InteractiveObject) anIO = aList.First(); @@ -2888,23 +3034,24 @@ void SMESHGUI_FilterDlg::updateSelection() int aRow, aCol; + int aCriterionType = myTable->GetCriterionType(aRow); if (myTable->CurrentCell(aRow, aCol) && - (myTable->GetCriterionType(aRow) == SMESH::FT_BelongToGeom || - myTable->GetCriterionType(aRow) == SMESH::FT_BelongToPlane || - myTable->GetCriterionType(aRow) == SMESH::FT_BelongToCylinder || - myTable->GetCriterionType(aRow) == SMESH::FT_BelongToGenSurface || - myTable->GetCriterionType(aRow) == SMESH::FT_LyingOnGeom)) { + (aCriterionType == SMESH::FT_BelongToGeom || + aCriterionType == SMESH::FT_BelongToPlane || + aCriterionType == SMESH::FT_BelongToCylinder || + aCriterionType == SMESH::FT_BelongToGenSurface || + aCriterionType == SMESH::FT_LyingOnGeom)) { - if (myTable->GetCriterionType(aRow) == SMESH::FT_BelongToGeom || - myTable->GetCriterionType(aRow) == SMESH::FT_BelongToGenSurface || - myTable->GetCriterionType(aRow) == SMESH::FT_LyingOnGeom) { + if (aCriterionType == SMESH::FT_BelongToGeom || + aCriterionType == SMESH::FT_BelongToGenSurface || + aCriterionType == SMESH::FT_LyingOnGeom) { mySelectionMgr->installFilter(new GEOM_SelectionFilter( aStudy, true )); - } else if (myTable->GetCriterionType(aRow) == SMESH::FT_BelongToPlane) { + } else if (aCriterionType == SMESH::FT_BelongToPlane) { mySelectionMgr->installFilter(new GEOM_FaceFilter( aStudy, StdSelect_Plane ) ); - } else if (myTable->GetCriterionType(aRow) == SMESH::FT_BelongToCylinder) { + } else if (aCriterionType == SMESH::FT_BelongToCylinder) { mySelectionMgr->installFilter(new GEOM_FaceFilter( aStudy, StdSelect_Cylinder ) ); } myIsSelectionChanged = true; diff --git a/src/SMESHGUI/SMESHGUI_GroupDlg.cxx b/src/SMESHGUI/SMESHGUI_GroupDlg.cxx index fda56e52a..352215c95 100644 --- a/src/SMESHGUI/SMESHGUI_GroupDlg.cxx +++ b/src/SMESHGUI/SMESHGUI_GroupDlg.cxx @@ -127,7 +127,8 @@ SMESHGUI_GroupDlg::SMESHGUI_GroupDlg( SMESHGUI* theModule, // purpose : //================================================================================= SMESHGUI_GroupDlg::SMESHGUI_GroupDlg( SMESHGUI* theModule, - SMESH::SMESH_GroupBase_ptr theGroup ) + SMESH::SMESH_GroupBase_ptr theGroup, + const bool theIsConvert ) : QDialog( SMESH::GetDesktop( theModule ) ), mySMESHGUI( theModule ), mySelectionMgr( SMESH::GetSelectionMgr( theModule ) ), @@ -137,7 +138,7 @@ SMESHGUI_GroupDlg::SMESHGUI_GroupDlg( SMESHGUI* theModule, { initDialog( false ); if ( !theGroup->_is_nil() ) - init( theGroup ); + init( theGroup, theIsConvert ); else { mySelectSubMesh->setEnabled( false ); @@ -511,7 +512,8 @@ void SMESHGUI_GroupDlg::init (SMESH::SMESH_Mesh_ptr theMesh) // function : Init() // purpose : //================================================================================= -void SMESHGUI_GroupDlg::init (SMESH::SMESH_GroupBase_ptr theGroup) +void SMESHGUI_GroupDlg::init (SMESH::SMESH_GroupBase_ptr theGroup, + const bool theIsConvert) { restoreShowEntityMode(); myMesh = theGroup->GetMesh(); @@ -538,23 +540,27 @@ void SMESHGUI_GroupDlg::init (SMESH::SMESH_GroupBase_ptr theGroup) myTypeGroup->button(aType)->setChecked(true); myGroup = SMESH::SMESH_Group::_narrow( theGroup ); + myGroupOnGeom = SMESH::SMESH_GroupOnGeom::_narrow( theGroup ); - if (!myGroup->_is_nil()) - { - // NPAL19389: create a group with a selection in another group - // set actor of myMesh, if it is visible, else set - // actor of myGroup, if it is visible, else try - // any visible actor of group or submesh of myMesh - // commented, because an attempt to set selection on not displayed cells leads to error - //SetAppropriateActor(); - myActor = SMESH::FindActorByObject(myMesh); - if ( !myActor ) - myActor = SMESH::FindActorByObject(myGroup); - SMESH::SetPickable(myActor); + if (myGroup->_is_nil() && myGroupOnGeom->_is_nil()) + return; + + // NPAL19389: create a group with a selection in another group + // set actor of myMesh, if it is visible, else set + // actor of theGroup, if it is visible, else try + // any visible actor of group or submesh of myMesh + // commented, because an attempt to set selection on not displayed cells leads to error + //SetAppropriateActor(); + myActor = SMESH::FindActorByObject(myMesh); + if ( !myActor ) + myActor = SMESH::FindActorByObject(theGroup); + SMESH::SetPickable(myActor); - myGrpTypeGroup->button(0)->setChecked(true); - onGrpTypeChanged(0); + int grpType = (!myGroup->_is_nil() ? 0 : (theIsConvert ? 0 : 1)); + myGrpTypeGroup->button(grpType)->setChecked(true); + onGrpTypeChanged(grpType); + if ( grpType == 0 ) { myCurrentLineEdit = 0; myElements->clear(); setSelectionMode(aType); @@ -563,8 +569,8 @@ void SMESHGUI_GroupDlg::init (SMESH::SMESH_GroupBase_ptr theGroup) setShowEntityMode(); // depends on myTypeId myIdList.clear(); - if (!myGroup->IsEmpty()) { - SMESH::long_array_var anElements = myGroup->GetListOfID(); + if (!theGroup->IsEmpty()) { + SMESH::long_array_var anElements = theGroup->GetListOfID(); int k = anElements->length(); for (int i = 0; i < k; i++) { myIdList.append(anElements[i]); @@ -575,39 +581,21 @@ void SMESHGUI_GroupDlg::init (SMESH::SMESH_GroupBase_ptr theGroup) } else { - myGroupOnGeom = SMESH::SMESH_GroupOnGeom::_narrow( theGroup ); - - if ( !myGroupOnGeom->_is_nil() ) + QString aShapeName( "" ); + _PTR(Study) aStudy = SMESH::GetActiveStudyDocument(); + GEOM::GEOM_Object_var aGroupShape = myGroupOnGeom->GetShape(); + if (!aGroupShape->_is_nil()) { - // NPAL19389: create a group with a selection in another group - // set actor of myMesh, if it is visible, else set - // actor of myGroupOnGeom, if it is visible, else try - // any visible actor of group or submesh of myMesh - // commented, because an attempt to set selection on not displayed cells leads to error - //SetAppropriateActor(); - myActor = SMESH::FindActorByObject(myMesh); - if ( !myActor ) - myActor = SMESH::FindActorByObject(myGroupOnGeom); - SMESH::SetPickable(myActor); - - myGrpTypeGroup->button(1)->setChecked(true); - onGrpTypeChanged(1); - - QString aShapeName( "" ); - _PTR(Study) aStudy = SMESH::GetActiveStudyDocument(); - GEOM::GEOM_Object_var aGroupShape = myGroupOnGeom->GetShape(); - if (!aGroupShape->_is_nil()) - { - _PTR(SObject) aGroupShapeSO = aStudy->FindObjectID(aGroupShape->GetStudyEntry()); - aShapeName = aGroupShapeSO->GetName().c_str(); - } - myGeomGroupLine->setText( aShapeName ); - myNameChanged = true; - myName->blockSignals(true); - myName->setText( "Group On " + aShapeName); - myName->blockSignals(false); + _PTR(SObject) aGroupShapeSO = aStudy->FindObjectID(aGroupShape->GetStudyEntry()); + aShapeName = aGroupShapeSO->GetName().c_str(); } + myGeomGroupLine->setText( aShapeName ); + myNameChanged = true; + myName->blockSignals(true); + myName->setText( "Group On " + aShapeName); + myName->blockSignals(false); } + updateButtons(); } //================================================================================= @@ -756,6 +744,17 @@ bool SMESHGUI_GroupDlg::onApply() mySelectionMgr->clearSelected(); + if (myGroup->_is_nil()) { // creation or conversion + // check if group on geometry is not null + if (!CORBA::is_nil(myGroupOnGeom)) { + if (myMesh->_is_nil()) + return false; + myGroup = myMesh->ConvertToStandalone( myGroupOnGeom ); + // nullify pointer, because object become dead + myGroupOnGeom = SMESH::SMESH_GroupOnGeom::_nil(); + } + } + if (myGroup->_is_nil()) { // creation if (myMesh->_is_nil()) return false; @@ -1564,8 +1563,8 @@ void SMESHGUI_GroupDlg::onAdd() SALOME_ListIteratorOfListIO anIt (aList); for ( ; anIt.More(); anIt.Next()) { - SMESH::SMESH_Group_var aGroup = - SMESH::IObjectToInterface(anIt.Value()); + SMESH::SMESH_GroupBase_var aGroup = + SMESH::IObjectToInterface(anIt.Value()); if (!aGroup->_is_nil()) { // check if mesh is the same if (aGroup->GetType() == aType && aGroup->GetMesh()->GetId() == myMesh->GetId()) { diff --git a/src/SMESHGUI/SMESHGUI_GroupDlg.h b/src/SMESHGUI/SMESHGUI_GroupDlg.h index 52e9c7e45..39a417887 100644 --- a/src/SMESHGUI/SMESHGUI_GroupDlg.h +++ b/src/SMESHGUI/SMESHGUI_GroupDlg.h @@ -70,7 +70,8 @@ public: SMESHGUI_GroupDlg( SMESHGUI*, SMESH::SMESH_Mesh_ptr = SMESH::SMESH_Mesh::_nil() ); SMESHGUI_GroupDlg( SMESHGUI*, - SMESH::SMESH_GroupBase_ptr ); + SMESH::SMESH_GroupBase_ptr, + const bool theIsConvert = false ); ~SMESHGUI_GroupDlg(); static QString GetDefaultName( const QString& ); @@ -113,7 +114,8 @@ private slots: private: void initDialog( bool ); void init( SMESH::SMESH_Mesh_ptr ); - void init( SMESH::SMESH_GroupBase_ptr ); + void init( SMESH::SMESH_GroupBase_ptr, + const bool theIsConvert = false ); void closeEvent( QCloseEvent* ); void enterEvent( QEvent* ); void hideEvent( QHideEvent* ); /* ESC key */ diff --git a/src/SMESHGUI/SMESHGUI_GroupOpDlg.cxx b/src/SMESHGUI/SMESHGUI_GroupOpDlg.cxx index d0bad44ee..44cdfdf94 100644 --- a/src/SMESHGUI/SMESHGUI_GroupOpDlg.cxx +++ b/src/SMESHGUI/SMESHGUI_GroupOpDlg.cxx @@ -53,6 +53,11 @@ #include #include #include +#include +#include +#include +#include +#include #define SPACING 6 #define MARGIN 11 @@ -62,32 +67,17 @@ * Description : Perform boolean operations on groups */ -//======================================================================= -// name : SMESHGUI_GroupOpDlg::SMESHGUI_GroupOpDlg -// Purpose : Constructor -//======================================================================= -SMESHGUI_GroupOpDlg::SMESHGUI_GroupOpDlg( SMESHGUI* theModule, const int theMode ) +/*! + \brief Constructor + \param theModule pointer on module instance +*/ +SMESHGUI_GroupOpDlg::SMESHGUI_GroupOpDlg( SMESHGUI* theModule ) : QDialog( SMESH::GetDesktop( theModule ) ), mySMESHGUI( theModule ), mySelectionMgr( SMESH::GetSelectionMgr( theModule ) ) { setModal(false); - myMode = theMode; - - if (myMode == UNION) { - setWindowTitle(tr("UNION_OF_TWO_GROUPS")); - myHelpFileName = "using_operations_on_groups_page.html#union_anchor"; - } - else if (myMode == INTERSECT) { - setWindowTitle(tr("INTERSECTION_OF_TWO_GROUPS")); - myHelpFileName = "using_operations_on_groups_page.html#intersection_anchor"; - } - else { - setWindowTitle(tr("CUT_OF_TWO_GROUPS")); - myHelpFileName = "using_operations_on_groups_page.html#cut_anchor"; - } - mySelector = (SMESH::GetViewWindow( mySMESHGUI ))->GetSelector(); QVBoxLayout* aDlgLay = new QVBoxLayout (this); @@ -103,11 +93,12 @@ SMESHGUI_GroupOpDlg::SMESHGUI_GroupOpDlg( SMESHGUI* theModule, const int theMode Init(); } -//======================================================================= -// name : SMESHGUI_GroupOpDlg::createMainFrame -// Purpose : Create frame containing dialog's input fields -//======================================================================= -QWidget* SMESHGUI_GroupOpDlg::createMainFrame (QWidget* theParent) +/*! + \brief Creates frame containing dialog's input fields + \param theParent parent widget + \return pointer on created widget +*/ +QWidget* SMESHGUI_GroupOpDlg::createMainFrame( QWidget* theParent ) { QWidget* aMainGrp = new QWidget(theParent); QVBoxLayout* aLay = new QVBoxLayout(aMainGrp); @@ -127,46 +118,64 @@ QWidget* SMESHGUI_GroupOpDlg::createMainFrame (QWidget* theParent) aNameGrpLayout->addWidget(myNameEdit); // ------------------------------------------------------ - QGroupBox* anArgGrp = new QGroupBox(tr("ARGUMENTS"), aMainGrp); - QGridLayout* anArgGrpLayout = new QGridLayout(anArgGrp); - anArgGrpLayout->setMargin(MARGIN); - anArgGrpLayout->setSpacing(SPACING); + myArgGrp = new QGroupBox(tr("ARGUMENTS"), aMainGrp); - QLabel* aObj1Lab = new QLabel(myMode == CUT ? tr("MAIN_OBJECT") :tr("OBJECT_1"), anArgGrp); - myBtn1 = new QPushButton(anArgGrp); - myEdit1 = new QLineEdit(anArgGrp); - myEdit1->setAlignment( Qt::AlignLeft ); - QLabel* aObj2Lab = new QLabel(myMode == CUT ? tr("TOOL_OBJECT") :tr("OBJECT_2"), anArgGrp); - myBtn2 = new QPushButton(anArgGrp); - myEdit2 = new QLineEdit(anArgGrp); - myEdit2->setAlignment( Qt::AlignLeft ); - - myEdit1->setReadOnly(true); - myEdit2->setReadOnly(true); + // ------------------------------------------------------ + + QGroupBox* aColorBox = new QGroupBox(tr( "SMESH_SET_COLOR" ), this); + QHBoxLayout* aColorBoxLayout = new QHBoxLayout(aColorBox); + aColorBoxLayout->setMargin(MARGIN); + aColorBoxLayout->setSpacing(SPACING); - QPixmap aPix (SMESH::GetResourceMgr( mySMESHGUI )->loadPixmap("SMESH", tr("ICON_SELECT"))); - myBtn1->setIcon(aPix); - myBtn2->setIcon(aPix); + QLabel* aColorLab = new QLabel(tr( "SMESH_CHECK_COLOR" ), aColorBox ); + myColorBtn = new QtxColorButton(aColorBox); + myColorBtn->setSizePolicy( QSizePolicy::MinimumExpanding, + myColorBtn->sizePolicy().verticalPolicy() ); - anArgGrpLayout->addWidget(aObj1Lab, 0, 0); - anArgGrpLayout->addWidget(myBtn1, 0, 1); - anArgGrpLayout->addWidget(myEdit1, 0, 2); - anArgGrpLayout->addWidget(aObj2Lab, 1, 0); - anArgGrpLayout->addWidget(myBtn2, 1, 1); - anArgGrpLayout->addWidget(myEdit2, 1, 2); + aColorBoxLayout->addWidget(aColorLab); + aColorBoxLayout->addWidget(myColorBtn); // ------------------------------------------------------ - aLay->addWidget(aNameGrp); - aLay->addWidget(anArgGrp); + aLay->addWidget( aNameGrp ); + aLay->addWidget( myArgGrp ); + aLay->addWidget( aColorBox ); return aMainGrp; } -//======================================================================= -// name : SMESHGUI_GroupOpDlg::createButtonFrame -// Purpose : Create frame containing buttons -//======================================================================= +/*! + \brief Gets pointer on arguments group box + \return pointer on arguments group box +*/ +QGroupBox* SMESHGUI_GroupOpDlg::getArgGrp() const +{ + return myArgGrp; +} + +/*! + \brief Sets help file name + \param theFName help file name +*/ +void SMESHGUI_GroupOpDlg::setHelpFileName( const QString& theFName ) +{ + myHelpFileName = theFName; +} + +/*! + \brief Gets pointer to the module instance + \return pointer to the module instance +*/ +SMESHGUI* SMESHGUI_GroupOpDlg::getSMESHGUI() const +{ + return mySMESHGUI; +} + +/*! + \brief Create frame containing buttons + \param theParent parent widget + \return pointer to the created frame +*/ QWidget* SMESHGUI_GroupOpDlg::createButtonFrame (QWidget* theParent) { QGroupBox* aFrame = new QGroupBox(theParent); @@ -197,75 +206,95 @@ QWidget* SMESHGUI_GroupOpDlg::createButtonFrame (QWidget* theParent) return aFrame; } -//======================================================================= -// name : SMESHGUI_GroupOpDlg::~SMESHGUI_GroupOpDlg -// Purpose : Destructor -//======================================================================= +/*! + \brief Destructor +*/ SMESHGUI_GroupOpDlg::~SMESHGUI_GroupOpDlg() { } -//======================================================================= -// name : SMESHGUI_GroupOpDlg::Init -// Purpose : Init dialog fields, connect signals and slots, show dialog -//======================================================================= +/*! + \brief Init dialog fields, connect signals and slots, show dialog +*/ void SMESHGUI_GroupOpDlg::Init() { mySMESHGUI->SetActiveDialogBox((QDialog*)this); - myFocusWg = myEdit1; - - myGroup1 = SMESH::SMESH_GroupBase::_nil(); - myGroup2 = SMESH::SMESH_GroupBase::_nil(); - + // selection and SMESHGUI connect(mySelectionMgr, SIGNAL(currentSelectionChanged()), SLOT(onSelectionDone())); connect(mySMESHGUI, SIGNAL(SignalDeactivateActiveDialog()), SLOT(onDeactivate())); connect(mySMESHGUI, SIGNAL(SignalCloseAllDialogs()), SLOT(ClickOnClose())); - connect(myBtn1, SIGNAL(clicked()), this, SLOT(onFocusChanged())); - connect(myBtn2, SIGNAL(clicked()), this, SLOT(onFocusChanged())); - // set selection mode if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI )) aViewWindow->SetSelectionMode(ActorSelection); mySelectionMgr->installFilter(new SMESH_TypeFilter (GROUP)); } -//======================================================================= -// name : SMESHGUI_GroupOpDlg::isValid -// Purpose : Verify validity of input data -//======================================================================= -bool SMESHGUI_GroupOpDlg::isValid() +/*! + \brief Validate list of groups used for operation. Checks whether they corresponds + to the same face and have one type + \param theListGrp input list of groups + \return TRUE if groups are valid, FALSE otherwise +*/ +bool SMESHGUI_GroupOpDlg::isValid( const QList& theListGrp ) { - // Verify validity of group name - if (myNameEdit->text() == "") { - SUIT_MessageBox::information(this, tr("SMESH_INSUFFICIENT_DATA"), - tr("EMPTY_NAME")); + if ( theListGrp.isEmpty() ) + { + SUIT_MessageBox::information( this, tr("SMESH_INSUFFICIENT_DATA"), + tr("INCORRECT_ARGUMENTS") ); return false; } - // Verufy wheter arguments speciffiyed - if (myGroup1->_is_nil() || myGroup2->_is_nil()) { - SUIT_MessageBox::information(this, tr("SMESH_INSUFFICIENT_DATA"), - tr("INCORRECT_ARGUMENTS")); - return false; - } + int aMeshId = -1, aGrpType = -1; + QList::const_iterator anIter; + for ( anIter = theListGrp.begin(); anIter != theListGrp.end(); ++anIter ) + { + SMESH::SMESH_GroupBase_var aGrp = *anIter; + if ( CORBA::is_nil( aGrp ) ) + continue; // nonsence + + SMESH::SMESH_Mesh_var aMesh = aGrp->GetMesh(); + if ( CORBA::is_nil( aMesh ) ) + continue; + + // mesh id + int aCurrId = aMesh->GetId(); + if ( aMeshId == -1 ) + aMeshId = aCurrId; + else + { + if ( aMeshId != aCurrId ) + { + aMeshId = -1; // different meshes + break; + } + } - // Verify whether arguments belongs to same mesh - SMESH::SMESH_Mesh_ptr aMesh1 = myGroup1->GetMesh(); - SMESH::SMESH_Mesh_ptr aMesh2 = myGroup2->GetMesh(); + // group type + int aCurrType = aGrp->GetType(); + if ( aGrpType == -1 ) + aGrpType = aCurrType; + else + { + if ( aGrpType != aCurrType ) + { + aGrpType = -1; // different types + break; + } + } - int aMeshId1 = !aMesh1->_is_nil() ? aMesh1->GetId() : -1; - int aMeshId2 = !aMesh2->_is_nil() ? aMesh2->GetId() : -1; + } - if (aMeshId1 != aMeshId2 || aMeshId1 == -1) { + if ( aMeshId == -1 ) + { SUIT_MessageBox::information(this, tr("SMESH_INSUFFICIENT_DATA"), tr("DIFF_MESHES")); return false; } - // Verify whether groups have same types of entities - if (myGroup1->GetType() != myGroup2->GetType()) { + if ( aGrpType == -1 ) + { SUIT_MessageBox::information(this, tr("SMESH_INSUFFICIENT_DATA"), tr("DIFF_TYPES")); return false; @@ -274,63 +303,33 @@ bool SMESHGUI_GroupOpDlg::isValid() return true; } -//======================================================================= -// name : SMESHGUI_GroupOpDlg::onApply -// Purpose : SLOT called when "Apply" button pressed. -//======================================================================= -bool SMESHGUI_GroupOpDlg::onApply() -{ - if (!isValid() || mySMESHGUI->isActiveStudyLocked()) - return false; - - SMESH::SMESH_Mesh_ptr aMesh = myGroup1->GetMesh(); - QString aName = myNameEdit->text(); - SMESH::SMESH_Group_ptr aNewGrp = SMESH::SMESH_Group::_nil(); - - if (myMode == UNION) aNewGrp = aMesh->UnionGroups(myGroup1, myGroup2, aName.toLatin1().data()); - else if (myMode == INTERSECT) aNewGrp = aMesh->IntersectGroups(myGroup1, myGroup2, aName.toLatin1().data()); - else aNewGrp = aMesh->CutGroups(myGroup1, myGroup2, aName.toLatin1().data()); - - if (!aNewGrp->_is_nil()) { - mySMESHGUI->updateObjBrowser(true); - reset(); - return true; - } else { - SUIT_MessageBox::critical(this, tr("SMESH_ERROR"), - tr("SMESH_OPERATION_FAILED")); - return false; - } -} - -//======================================================================= -// name : SMESHGUI_GroupOpDlg::onOk -// Purpose : SLOT called when "Ok" button pressed. -//======================================================================= +/*! + \brief SLOT called when "Ok" button pressed performs operation and closes dialog box +*/ void SMESHGUI_GroupOpDlg::onOk() { - if (onApply()) + if ( onApply() ) onClose(); } -//======================================================================= -// name : SMESHGUI_GroupOpDlg::onClose -// Purpose : SLOT called when "Close" button pressed. Close dialog -//======================================================================= +/*! + \brief SLOT called when "Close" button pressed closes dialog +*/ void SMESHGUI_GroupOpDlg::onClose() { if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI )) aViewWindow->SetSelectionMode(ActorSelection); - disconnect(mySelectionMgr, 0, this, 0); - disconnect(mySMESHGUI, 0, this, 0); + disconnect( mySelectionMgr, 0, this, 0 ); + disconnect( mySMESHGUI, 0, this, 0 ); mySMESHGUI->ResetState(); mySelectionMgr->clearFilters(); + reset(); reject(); } -//================================================================================= -// function : onHelp() -// purpose : -//================================================================================= +/*! + \brief SLOT called when "Help" button pressed shows "Help" page +*/ void SMESHGUI_GroupOpDlg::onHelp() { LightApp_Application* app = (LightApp_Application*)(SUIT_Session::session()->activeApplication()); @@ -351,54 +350,108 @@ void SMESHGUI_GroupOpDlg::onHelp() } } -//======================================================================= -// name : SMESHGUI_GroupOpDlg::onSelectionDone -// Purpose : SLOT called when selection changed -//======================================================================= -void SMESHGUI_GroupOpDlg::onSelectionDone() +/*! + \brief Gets list of currently selected groups from selection manager + \param theOutList out list of groups + \param theOutNames out list of group of group names + \return TRUE if operation theOutList is not empty, FALSE otherwise +*/ +bool SMESHGUI_GroupOpDlg::getSelectedGroups( QList& theOutList, + QStringList& theOutNames ) { - if (myFocusWg == myEdit1) - myGroup1 = SMESH::SMESH_GroupBase::_nil(); - else - myGroup2 = SMESH::SMESH_GroupBase::_nil(); + theOutList.clear(); - myFocusWg->setText(""); + theOutList.clear(); + theOutNames.clear(); - SALOME_ListIO aList; - mySelectionMgr->selectedObjects(aList); - - if (aList.Extent() == 1) { + SALOME_ListIO aListIO; + mySelectionMgr->selectedObjects( aListIO ); + SALOME_ListIteratorOfListIO anIter ( aListIO ); + for ( ; anIter.More(); anIter.Next()) + { SMESH::SMESH_GroupBase_var aGroup = - SMESH::IObjectToInterface(aList.First()); - - if (!aGroup->_is_nil()) + SMESH::IObjectToInterface(anIter.Value()); + if ( !aGroup->_is_nil()) { - myFocusWg->setText(aGroup->GetName()); - myFocusWg->setCursorPosition( 0 ); - - if (myFocusWg == myEdit1) - myGroup1 = aGroup; - else - myGroup2 = aGroup; + theOutList.append( aGroup ); + theOutNames.append( aGroup->GetName() ); } } + + return theOutList.count() > 0; +} + +/*! + \brief Converts QT-list of group to the list acceptable by IDL interface + \param theIn input list + \return list acceptable by IDL interface +*/ +SMESH::ListOfGroups* SMESHGUI_GroupOpDlg::convert( + const QList& theIn ) +{ + SMESH::ListOfGroups_var aList = new SMESH::ListOfGroups(); + aList->length( theIn.count() ); + + QList::const_iterator anIter = theIn.begin(); + for ( int i = 0; anIter != theIn.end(); ++anIter, ++i ) + aList[ i ] = *anIter; + + return aList._retn(); +} + +/*! + \brief Get color to be assigned to group + \return color to be assigned to group +*/ +SALOMEDS::Color SMESHGUI_GroupOpDlg::getColor() const +{ + QColor aQColor = myColorBtn->color(); + + SALOMEDS::Color aColor; + aColor.R = (float)aQColor.red() / 255.0; + aColor.G = (float)aQColor.green() / 255.0; + aColor.B = (float)aQColor.blue() / 255.0; + + return aColor; } -//======================================================================= -// name : SMESHGUI_GroupOpDlg::onDeactivate -// Purpose : SLOT called when dialog must be deativated -//======================================================================= +/*! + \brief SLOT, called when selection is changed. Current implementation does + nothing. The method should be redefined in derived classes to update + corresponding GUI controls +*/ +void SMESHGUI_GroupOpDlg::onSelectionDone() +{ +} + +/*! + \brief Calls onSelectionDone() and setVisible() method of base class + \param visible the visible state of the dialog +*/ +void SMESHGUI_GroupOpDlg::setVisible( bool visible ) +{ + if ( visible ) + { + onSelectionDone(); + resize( minimumSizeHint().width(), sizeHint().height() ); + } + QDialog::setVisible( visible ); +} + +/*! + \brief SLOT called when dialog must be deativated +*/ void SMESHGUI_GroupOpDlg::onDeactivate() { setEnabled(false); mySelectionMgr->clearFilters(); } -//======================================================================= -// name : SMESHGUI_GroupOpDlg::enterEvent -// Purpose : Event filter -//======================================================================= -void SMESHGUI_GroupOpDlg::enterEvent (QEvent*) +/*! + \brief Event filter updates selection mode and selection filter. This virtual method + is redefined from the base class it is called when dialog obtains input focus +*/ +void SMESHGUI_GroupOpDlg::enterEvent(QEvent*) { mySMESHGUI->EmitSignalDeactivateDialog(); setEnabled(true); @@ -407,43 +460,49 @@ void SMESHGUI_GroupOpDlg::enterEvent (QEvent*) mySelectionMgr->installFilter(new SMESH_TypeFilter (GROUP)); } -//======================================================================= -// name : SMESHGUI_GroupOpDlg::closeEvent -// purpose : -//======================================================================= -void SMESHGUI_GroupOpDlg::closeEvent (QCloseEvent*) +/*! + \brief Provides reaction on close event, closes the dialog box +*/ +void SMESHGUI_GroupOpDlg::closeEvent(QCloseEvent*) { onClose(); } -//======================================================================= -// name : SMESHGUI_GroupOpDlg::onFocusChanged -// Purpose : SLOT. Called when "Select" button pressed. -//======================================================================= -void SMESHGUI_GroupOpDlg::onFocusChanged() -{ - const QObject* aSender = sender(); - myFocusWg = aSender == myBtn1 ? myEdit1 : myEdit2; - onSelectionDone(); -} - -//======================================================================= -// name : SMESHGUI_GroupOpDlg::reset -// Purpose : Rest state of dialog -//======================================================================= +/*! + \brief Resets state of the dialog, initializes its fields with default value, etc. + Usually called by onApply() slot to reinitialize dialog fields. This virtual method + should be redefined in derived class to update its own fileds +*/ void SMESHGUI_GroupOpDlg::reset() { myNameEdit->setText(""); - myEdit1->setText(""); - myEdit2->setText(""); - myFocusWg = myEdit1; myNameEdit->setFocus(); } -//================================================================================= -// function : keyPressEvent() -// purpose : -//================================================================================= +/*! + \brief Gets name of group to be created + \return name of group to be created + \sa setName() +*/ +QString SMESHGUI_GroupOpDlg::getName() const +{ + return myNameEdit->text(); +} + +/*! + \brief Sets name of group to be created + \param theName name of group to be created + \sa getName() +*/ +void SMESHGUI_GroupOpDlg::setName( const QString& theName ) +{ + myNameEdit->setText( theName ); +} + +/*! + \brief Provides reaction on “F1” button pressing + \param e key press event +*/ void SMESHGUI_GroupOpDlg::keyPressEvent( QKeyEvent* e ) { QDialog::keyPressEvent( e ); @@ -455,3 +514,535 @@ void SMESHGUI_GroupOpDlg::keyPressEvent( QKeyEvent* e ) onHelp(); } } + +/*! + \brief This virtual slot does nothing and should be redefined in derived classes + \return return false; +*/ +bool SMESHGUI_GroupOpDlg::onApply() +{ + return false; +} + +// === === === === === === === === === === === === === === === === === === === === === + +/*! + \brief Constructor + \param theModule module +*/ +SMESHGUI_UnionGroupsDlg::SMESHGUI_UnionGroupsDlg( SMESHGUI* theModule ) +: SMESHGUI_GroupOpDlg( theModule ) +{ + setWindowTitle(tr("UNION_OF_GROUPS")); + setHelpFileName( "using_operations_on_groups_page.html#union_anchor" ); + + QGroupBox* anArgGrp = getArgGrp(); + myListWg = new QListWidget( anArgGrp ); + + QHBoxLayout* aLay = new QHBoxLayout( anArgGrp ); + aLay->addWidget( myListWg ); +} + +/*! + \brief Destructor +*/ +SMESHGUI_UnionGroupsDlg::~SMESHGUI_UnionGroupsDlg() +{ +} + +/*! + \brief This virtual method redefined from the base class resets state + of the dialog, initializes its fields with default value, etc. +*/ +void SMESHGUI_UnionGroupsDlg::reset() +{ + SMESHGUI_GroupOpDlg::reset(); + myListWg->clear(); + myGroups.clear(); +} + +/*! + \brief SLOT called when apply button is pressed performs operation + \return TRUE if operation has been completed successfully, FALSE otherwise +*/ +bool SMESHGUI_UnionGroupsDlg::onApply() +{ + if ( getSMESHGUI()->isActiveStudyLocked()) + return false; + + // Verify validity of group name + if ( getName() == "" ) + { + SUIT_MessageBox::information(this, tr("SMESH_INSUFFICIENT_DATA"), + SMESHGUI_GroupOpDlg::tr("EMPTY_NAME")); + return false; + } + + if ( !isValid( myGroups ) ) + return false; + + SMESH::SMESH_Mesh_var aMesh = myGroups.first()->GetMesh(); + QString aName = getName(); + + bool aRes = false; + try + { + SMESH::ListOfGroups_var aList = convert( myGroups ); + SMESH::SMESH_Group_var aNewGrp = + aMesh->UnionListOfGroups( aList, aName.toLatin1().constData() ); + if ( !CORBA::is_nil( aNewGrp ) ) + { + aNewGrp->SetColor( getColor() ); + aRes = true; + } + } + catch( ... ) + { + aRes = false; + } + + if ( aRes ) + { + getSMESHGUI()->updateObjBrowser(true); + reset(); + return true; + } + else + { + SUIT_MessageBox::critical(this, tr("SMESH_ERROR"), + tr("SMESH_OPERATION_FAILED")); + return false; + } +} + +/*! + \brief SLOT, called when selection is changed, updates corresponding GUI controls +*/ +void SMESHGUI_UnionGroupsDlg::onSelectionDone() +{ + QStringList aNames; + getSelectedGroups( myGroups, aNames ); + myListWg->clear(); + myListWg->addItems( aNames ); +} + +// === === === === === === === === === === === === === === === === === === === === === + +/*! + \brief Constructor + \param theModule module +*/ +SMESHGUI_IntersectGroupsDlg::SMESHGUI_IntersectGroupsDlg( SMESHGUI* theModule ) +: SMESHGUI_GroupOpDlg( theModule ) +{ + setWindowTitle(tr("INTERSECTION_OF_GROUPS")); + setHelpFileName( "using_operations_on_groups_page.html#intersection_anchor" ); + + QGroupBox* anArgGrp = getArgGrp(); + myListWg = new QListWidget( anArgGrp ); + + QHBoxLayout* aLay = new QHBoxLayout( anArgGrp ); + aLay->addWidget( myListWg ); +} + +/*! + \brief Destructor +*/ +SMESHGUI_IntersectGroupsDlg::~SMESHGUI_IntersectGroupsDlg() +{ +} + +/*! + \brief This virtual method redefined from the base class resets state + of the dialog, initializes its fields with default value, etc. +*/ +void SMESHGUI_IntersectGroupsDlg::reset() +{ + SMESHGUI_GroupOpDlg::reset(); + myListWg->clear(); + myGroups.clear(); +} + +/*! + \brief SLOT called when apply button is pressed performs operation + \return TRUE if operation has been completed successfully, FALSE otherwise +*/ +bool SMESHGUI_IntersectGroupsDlg::onApply() +{ + if ( getSMESHGUI()->isActiveStudyLocked()) + return false; + + // Verify validity of group name + if ( getName() == "" ) + { + SUIT_MessageBox::information(this, tr("SMESH_INSUFFICIENT_DATA"), + SMESHGUI_GroupOpDlg::tr("EMPTY_NAME")); + return false; + } + + if ( !isValid( myGroups ) ) + return false; + + SMESH::SMESH_Mesh_var aMesh = myGroups.first()->GetMesh(); + QString aName = getName(); + + bool aRes = false; + try + { + SMESH::ListOfGroups_var aList = convert( myGroups ); + SMESH::SMESH_Group_var aNewGrp = + aMesh->IntersectListOfGroups( aList, aName.toLatin1().constData() ); + if ( !CORBA::is_nil( aNewGrp ) ) + { + aNewGrp->SetColor( getColor() ); + aRes = true; + } + } + catch( ... ) + { + aRes = false; + } + + if ( aRes ) + { + getSMESHGUI()->updateObjBrowser(true); + reset(); + return true; + } + else + { + SUIT_MessageBox::critical(this, tr("SMESH_ERROR"), + tr("SMESH_OPERATION_FAILED")); + return false; + } +} + +/*! + \brief SLOT, called when selection is changed, updates corresponding GUI controls +*/ +void SMESHGUI_IntersectGroupsDlg::onSelectionDone() +{ + QStringList aNames; + getSelectedGroups( myGroups, aNames ); + myListWg->clear(); + myListWg->addItems( aNames ); +} + +// === === === === === === === === === === === === === === === === === === === === === + +/*! + \brief Constructor + \param theModule module +*/ +SMESHGUI_CutGroupsDlg::SMESHGUI_CutGroupsDlg( SMESHGUI* theModule ) +: SMESHGUI_GroupOpDlg( theModule ) +{ + setWindowTitle(tr("CUT_OF_GROUPS")); + setHelpFileName( "using_operations_on_groups_page.html#cut_anchor" ); + + QGroupBox* anArgGrp = getArgGrp(); + + QPixmap aPix (SMESH::GetResourceMgr( getSMESHGUI() )->loadPixmap("SMESH", tr("ICON_SELECT"))); + + // frame 1 + QFrame* aFrame1 = new QFrame( anArgGrp ); + QLabel* aLbl1 = new QLabel( tr("MAIN_OBJECT"), aFrame1 ); + aLbl1->setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed ) ); + myBtn1 = new QPushButton( aFrame1 ); + myBtn1->setIcon(aPix); + myListWg1 = new QListWidget( aFrame1 ); + + QGridLayout* aLay1 = new QGridLayout( aFrame1 ); + aLay1->setSpacing( SPACING ); + aLay1->addWidget( aLbl1, 0, 0 ); + aLay1->addWidget( myBtn1, 0, 1 ); + aLay1->addWidget( myListWg1, 1, 0, 1, 2 ); + //QSpacerItem* aHSpacer1 = new QSpacerItem( 0, 0, QSizePolicy::Expanding, QSizePolicy::Minimum ); + //aLay1->addItem( aHSpacer1, 0, 2 ); + + + // frame 2 + QFrame* aFrame2 = new QFrame( anArgGrp ); + QLabel* aLbl2 = new QLabel( tr("TOOL_OBJECT"), aFrame2 ); + aLbl2->setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed ) ); + myBtn2 = new QPushButton( aFrame2 ); + myBtn2->setIcon(aPix); + myListWg2 = new QListWidget( aFrame2 ); + + QGridLayout* aLay2 = new QGridLayout( aFrame2 ); + aLay2->setSpacing( SPACING ); + aLay2->addWidget( aLbl2, 0, 0 ); + aLay2->addWidget( myBtn2, 0, 1 ); + aLay2->addWidget( myListWg2, 1, 0, 1, 2 ); + //QSpacerItem* aHSpacer2 = new QSpacerItem( 0, 0, QSizePolicy::Expanding, QSizePolicy::Minimum ); + //aLay2->addItem( aHSpacer2, 0, 2 ); + + // create button group + + QButtonGroup* aGrp = new QButtonGroup( anArgGrp ); + aGrp->addButton( myBtn1, 0 ); + aGrp->addButton( myBtn2, 1 ); + myBtn1->setCheckable( true ); + myBtn2->setCheckable( true ); + aGrp->setExclusive( true ); + myBtn1->setChecked( true ); + + // fill layout + QHBoxLayout* aLay = new QHBoxLayout( anArgGrp ); + aLay->setSpacing( SPACING ); + aLay->addWidget( aFrame1 ); + aLay->addWidget( aFrame2 ); +} + +/*! + \brief Destructor +*/ +SMESHGUI_CutGroupsDlg::~SMESHGUI_CutGroupsDlg() +{ +} + +/*! + \brief This virtual method redefined from the base class resets state + of the dialog, initializes its fields with default value, etc. +*/ +void SMESHGUI_CutGroupsDlg::reset() +{ + SMESHGUI_GroupOpDlg::reset(); + + myListWg1->clear(); + myGroups1.clear(); + + myListWg2->clear(); + myGroups2.clear(); +} + +/*! + \brief SLOT called when apply button is pressed performs operation + \return TRUE if operation has been completed successfully, FALSE otherwise +*/ +bool SMESHGUI_CutGroupsDlg::onApply() +{ + if ( getSMESHGUI()->isActiveStudyLocked()) + return false; + + // Verify validity of group name + if ( getName() == "" ) + { + SUIT_MessageBox::information(this, tr("SMESH_INSUFFICIENT_DATA"), + SMESHGUI_GroupOpDlg::tr("EMPTY_NAME")); + return false; + } + + if ( myGroups1.isEmpty() || myGroups2.isEmpty() ) + { + SUIT_MessageBox::information( this, tr("SMESH_INSUFFICIENT_DATA"), + SMESHGUI_GroupOpDlg::tr("INCORRECT_ARGUMENTS") ); + return false; + } + + QList aGroups = myGroups1; + QList::iterator anIter; + for ( anIter = myGroups2.begin(); anIter != myGroups2.end(); ++anIter ) + aGroups.append( *anIter ); + + if ( !isValid( aGroups ) ) + return false; + + SMESH::SMESH_Mesh_var aMesh = myGroups1.first()->GetMesh(); + QString aName = getName(); + + bool aRes = false; + try + { + SMESH::ListOfGroups_var aList1 = convert( myGroups1 ); + SMESH::ListOfGroups_var aList2 = convert( myGroups2 ); + SMESH::SMESH_Group_var aNewGrp = + aMesh->CutListOfGroups( aList1, aList2, aName.toLatin1().constData() ); + if ( !CORBA::is_nil( aNewGrp ) ) + { + aNewGrp->SetColor( getColor() ); + aRes = true; + } + } + catch( ... ) + { + aRes = false; + } + + if ( aRes ) + { + getSMESHGUI()->updateObjBrowser(true); + reset(); + return true; + } + else + { + SUIT_MessageBox::critical(this, tr("SMESH_ERROR"), + tr("SMESH_OPERATION_FAILED")); + return false; + } +} + +/*! + \brief SLOT, called when selection is changed, updates corresponding GUI controls +*/ +void SMESHGUI_CutGroupsDlg::onSelectionDone() +{ + QStringList aNames; + if ( myBtn2->isChecked() ) + { + getSelectedGroups( myGroups2, aNames ); + myListWg2->clear(); + myListWg2->addItems( aNames ); + } + else + { + getSelectedGroups( myGroups1, aNames ); + myListWg1->clear(); + myListWg1->addItems( aNames ); + } +} + +// === === === === === === === === === === === === === === === === === === === === === + +/*! + \brief Constructor + \param theModule module +*/ +SMESHGUI_DimGroupDlg::SMESHGUI_DimGroupDlg( SMESHGUI* theModule ) +: SMESHGUI_GroupOpDlg( theModule ) +{ + setWindowTitle( tr( "CREATE_GROUP_OF_UNDERLYING_ELEMS" ) ); + setHelpFileName( "creating_groups_page.html#gui_create_dim_group" ); + + QGroupBox* anArgGrp = getArgGrp(); + + QLabel* aLbl = new QLabel( tr( "ELEMENTS_TYPE" ), anArgGrp ); + + myCombo = new QComboBox( anArgGrp ); + static QStringList anItems; + if ( anItems.isEmpty() ) + { + anItems.append( tr( "NODE" ) ); + anItems.append( tr( "EDGE" ) ); + anItems.append( tr( "FACE" ) ); + anItems.append( tr( "VOLUME" ) ); + } + myCombo->addItems( anItems ); + myCombo->setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed ) ); + + myListWg = new QListWidget( anArgGrp ); + + // layout + QGridLayout* aLay = new QGridLayout( anArgGrp ); + aLay->setSpacing( SPACING ); + aLay->addWidget( aLbl, 0, 0 ); + aLay->addWidget( myCombo, 0, 1 ); + aLay->addWidget( myListWg, 1, 0, 1, 2 ); +} + +/*! + \brief Destructor +*/ +SMESHGUI_DimGroupDlg::~SMESHGUI_DimGroupDlg() +{ +} + +/*! + \brief This virtual method redefined from the base class resets state + of the dialog, initializes its fields with default value, etc. +*/ +void SMESHGUI_DimGroupDlg::reset() +{ + SMESHGUI_GroupOpDlg::reset(); + myListWg->clear(); + myGroups.clear(); +} + +/*! + \brief Gets elements type + \return elements type + \sa setElementType() +*/ +SMESH::ElementType SMESHGUI_DimGroupDlg::getElementType() const +{ + return (SMESH::ElementType)( myCombo->currentIndex() + 1 ); +} + +/*! + \brief Sets elements type + \param theElemType elements type + \sa getElementType() +*/ +void SMESHGUI_DimGroupDlg::setElementType( const SMESH::ElementType& theElemType ) +{ + myCombo->setCurrentIndex( theElemType - 1 ); +} + +/*! + \brief SLOT called when apply button is pressed performs operation + \return TRUE if operation has been completed successfully, FALSE otherwise +*/ +bool SMESHGUI_DimGroupDlg::onApply() +{ + if ( getSMESHGUI()->isActiveStudyLocked()) + return false; + + // Verify validity of group name + if ( getName() == "" ) + { + SUIT_MessageBox::information(this, tr("SMESH_INSUFFICIENT_DATA"), + SMESHGUI_GroupOpDlg::tr("EMPTY_NAME")); + return false; + } + + if ( !isValid( myGroups ) ) + return false; + + SMESH::SMESH_Mesh_var aMesh = myGroups.first()->GetMesh(); + QString aName = getName(); + + bool aRes = false; + try + { + SMESH::ListOfGroups_var aList = convert( myGroups ); + SMESH::ElementType anElemType = getElementType(); + SMESH::SMESH_Group_var aNewGrp = + aMesh->CreateDimGroup( aList, anElemType, aName.toLatin1().constData() ); + if ( !CORBA::is_nil( aNewGrp ) ) + { + aNewGrp->SetColor( getColor() ); + aRes = true; + } + } + catch( ... ) + { + aRes = false; + } + + if ( aRes ) + { + getSMESHGUI()->updateObjBrowser(true); + reset(); + return true; + } + else + { + SUIT_MessageBox::critical(this, tr("SMESH_ERROR"), + tr("SMESH_OPERATION_FAILED")); + return false; + } +} + +/*! + \brief SLOT, called when selection is changed, updates corresponding GUI controls +*/ +void SMESHGUI_DimGroupDlg::onSelectionDone() +{ + QStringList aNames; + getSelectedGroups( myGroups, aNames ); + myListWg->clear(); + myListWg->addItems( aNames ); +} + + diff --git a/src/SMESHGUI/SMESHGUI_GroupOpDlg.h b/src/SMESHGUI/SMESHGUI_GroupOpDlg.h index 289cc953e..fda94dd01 100644 --- a/src/SMESHGUI/SMESHGUI_GroupOpDlg.h +++ b/src/SMESHGUI/SMESHGUI_GroupOpDlg.h @@ -37,6 +37,10 @@ #include CORBA_SERVER_HEADER(SMESH_Group) class QPushButton; +class QtxColorButton; +class QComboBox; +class QListWidget; +class QGroupBox; class QLineEdit; class SMESHGUI; class LightApp_SelectionMgr; @@ -52,14 +56,37 @@ class SMESHGUI_EXPORT SMESHGUI_GroupOpDlg : public QDialog Q_OBJECT public: - enum { UNION, INTERSECT, CUT }; + //enum { UNION, INTERSECT, CUT }; public: - SMESHGUI_GroupOpDlg( SMESHGUI*, const int ); + SMESHGUI_GroupOpDlg( SMESHGUI* ); virtual ~SMESHGUI_GroupOpDlg(); void Init(); - + +protected slots: + + virtual bool onApply(); + virtual void onSelectionDone(); + virtual void setVisible ( bool visible ); + +protected: + + virtual void reset(); + + QString getName() const; + void setName( const QString& theName ); + + QGroupBox* getArgGrp() const; + void setHelpFileName( const QString& theFName ); + SMESHGUI* getSMESHGUI() const; + bool isValid( const QList& theListGrp ); + bool getSelectedGroups( QList& theOutList, + QStringList& theOutNames ); + SMESH::ListOfGroups* convert( const QList& ); + + SALOMEDS::Color getColor() const; + private: void closeEvent( QCloseEvent* ); void enterEvent( QEvent* ); @@ -67,20 +94,15 @@ private: private slots: void onOk(); - bool onApply(); void onClose(); void onHelp(); void onDeactivate(); - void onSelectionDone(); - void onFocusChanged(); private: QWidget* createButtonFrame( QWidget* ); QWidget* createMainFrame ( QWidget* ); - bool isValid(); - void reset(); - + private: QPushButton* myOkBtn; QPushButton* myApplyBtn; @@ -88,22 +110,129 @@ private: QPushButton* myHelpBtn; QLineEdit* myNameEdit; - QLineEdit* myEdit1; - QLineEdit* myEdit2; - QPushButton* myBtn1; - QPushButton* myBtn2; + QGroupBox* myArgGrp; + QtxColorButton* myColorBtn; SMESHGUI* mySMESHGUI; LightApp_SelectionMgr* mySelectionMgr; - int myMode; SVTK_Selector* mySelector; - QLineEdit* myFocusWg; - - SMESH::SMESH_GroupBase_var myGroup1; - SMESH::SMESH_GroupBase_var myGroup2; - QString myHelpFileName; }; +/* + Class : SMESHGUI_UnionGroupsDlg + Description : Perform union of several groups +*/ + +class SMESHGUI_EXPORT SMESHGUI_UnionGroupsDlg : public SMESHGUI_GroupOpDlg +{ + Q_OBJECT + +public: + + SMESHGUI_UnionGroupsDlg( SMESHGUI* ); + virtual ~SMESHGUI_UnionGroupsDlg(); + +protected slots: + virtual bool onApply(); + virtual void onSelectionDone(); + +protected: + virtual void reset(); + +private: + QListWidget* myListWg; + QList myGroups; +}; + +/* + Class : SMESHGUI_IntersectGroupsDlg + Description : Perform intersection of several groups +*/ + +class SMESHGUI_EXPORT SMESHGUI_IntersectGroupsDlg : public SMESHGUI_GroupOpDlg +{ + Q_OBJECT + +public: + + SMESHGUI_IntersectGroupsDlg( SMESHGUI* ); + virtual ~SMESHGUI_IntersectGroupsDlg(); + +protected slots: + virtual bool onApply(); + virtual void onSelectionDone(); + +protected: + virtual void reset(); + +private: + QListWidget* myListWg; + QList myGroups; +}; + +/* + Class : SMESHGUI_CutGroupsDlg + Description : Perform cut of several groups +*/ + +class SMESHGUI_EXPORT SMESHGUI_CutGroupsDlg : public SMESHGUI_GroupOpDlg +{ + Q_OBJECT + +public: + + SMESHGUI_CutGroupsDlg( SMESHGUI* ); + virtual ~SMESHGUI_CutGroupsDlg(); + +protected slots: + virtual bool onApply(); + virtual void onSelectionDone(); + +protected: + virtual void reset(); + +private: + QPushButton* myBtn1; + QPushButton* myBtn2; + QListWidget* myListWg1; + QListWidget* myListWg2; + QList myGroups1; + QList myGroups2; +}; + +/* + Class : SMESHGUI_DimGroupDlg + Description : Dialog for creating groups of entities from existing + groups of superior dimensions +*/ + +class SMESHGUI_EXPORT SMESHGUI_DimGroupDlg : public SMESHGUI_GroupOpDlg +{ + Q_OBJECT + +public: + + SMESHGUI_DimGroupDlg( SMESHGUI* ); + virtual ~SMESHGUI_DimGroupDlg(); + + SMESH::ElementType getElementType() const; + void setElementType( const SMESH::ElementType& theElemType ); + +protected: + virtual void reset(); + +protected slots: + virtual bool onApply(); + virtual void onSelectionDone(); + +private: + QComboBox* myCombo; + QListWidget* myListWg; + QList myGroups; +}; + #endif // SMESHGUI_GROUPOPDLG_H + + diff --git a/src/SMESHGUI/SMESHGUI_Hypotheses.cxx b/src/SMESHGUI/SMESHGUI_Hypotheses.cxx index be4bffe15..4ebd58629 100644 --- a/src/SMESHGUI/SMESHGUI_Hypotheses.cxx +++ b/src/SMESHGUI/SMESHGUI_Hypotheses.cxx @@ -62,14 +62,18 @@ SMESHGUI_GenericHypothesisCreator::~SMESHGUI_GenericHypothesisCreator() { } +void SMESHGUI_GenericHypothesisCreator::setInitParamsHypothesis(SMESH::SMESH_Hypothesis_ptr hyp) +{ + if ( !CORBA::is_nil( hyp ) && hypType() == hyp->GetName() ) + myInitParamsHypo = SMESH::SMESH_Hypothesis::_duplicate( hyp ); +} + void SMESHGUI_GenericHypothesisCreator::create( SMESH::SMESH_Hypothesis_ptr initParamsHyp, const QString& theHypName, QWidget* parent) { MESSAGE( "Creation of hypothesis with initial params" ); - - if ( !CORBA::is_nil( initParamsHyp ) && hypType() == initParamsHyp->GetName() ) - myInitParamsHypo = SMESH::SMESH_Hypothesis::_duplicate( initParamsHyp ); + setInitParamsHypothesis( initParamsHyp ); create( false, theHypName, parent ); } @@ -248,6 +252,11 @@ QFrame* SMESHGUI_GenericHypothesisCreator::buildStdFrame() } void SMESHGUI_GenericHypothesisCreator::onValueChanged() +{ + valueChanged( (QWidget*) sender() ); +} + +void SMESHGUI_GenericHypothesisCreator::valueChanged( QWidget* ) { } @@ -337,13 +346,29 @@ SMESH::SMESH_Hypothesis_var SMESHGUI_GenericHypothesisCreator::hypothesis() cons return myHypo; } -SMESH::SMESH_Hypothesis_var SMESHGUI_GenericHypothesisCreator::initParamsHypothesis() const +//================================================================================ +/*! + * \brief Return hypothesis containing initial parameters + * \param strictly - if true, always return myInitParamsHypo, + * else, return myInitParamsHypo only in creation mode and if it + * is non-nil + */ +//================================================================================ + +SMESH::SMESH_Hypothesis_var SMESHGUI_GenericHypothesisCreator::initParamsHypothesis(const bool strictly) const { - if ( CORBA::is_nil( myInitParamsHypo )) + if ( strictly ) + return myInitParamsHypo; + if ( !isCreation() || CORBA::is_nil( myInitParamsHypo )) return myHypo; return myInitParamsHypo; } +bool SMESHGUI_GenericHypothesisCreator::hasInitParamsHypothesis() const +{ + return !CORBA::is_nil( myInitParamsHypo ); +} + QString SMESHGUI_GenericHypothesisCreator::hypType() const { return myHypType; diff --git a/src/SMESHGUI/SMESHGUI_Hypotheses.h b/src/SMESHGUI/SMESHGUI_Hypotheses.h index 20377c1e8..1a1978a41 100644 --- a/src/SMESHGUI/SMESHGUI_Hypotheses.h +++ b/src/SMESHGUI/SMESHGUI_Hypotheses.h @@ -55,6 +55,7 @@ public: void create( bool, const QString&, QWidget* ); void edit( SMESH::SMESH_Hypothesis_ptr, const QString&, QWidget* ); + void setInitParamsHypothesis(SMESH::SMESH_Hypothesis_ptr); virtual bool checkParams() const = 0; virtual void onReject(); @@ -76,7 +77,8 @@ protected: typedef QList ListOfWidgets; SMESH::SMESH_Hypothesis_var hypothesis() const; - SMESH::SMESH_Hypothesis_var initParamsHypothesis() const; + SMESH::SMESH_Hypothesis_var initParamsHypothesis(const bool strict=false) const; + bool hasInitParamsHypothesis() const; const ListOfWidgets& widgets() const; ListOfWidgets& changeWidgets(); QtxDialog* dlg() const; @@ -92,6 +94,7 @@ protected: virtual QWidget* getCustomWidget( const StdParam&, QWidget*, const int ) const; virtual bool getParamFromCustomWidget( StdParam&, QWidget* ) const; + virtual void valueChanged( QWidget* ); virtual QString caption() const; virtual QPixmap icon() const; virtual QString type() const; diff --git a/src/SMESHGUI/SMESHGUI_MeshOp.cxx b/src/SMESHGUI/SMESHGUI_MeshOp.cxx index d51170140..ec08a297e 100644 --- a/src/SMESHGUI/SMESHGUI_MeshOp.cxx +++ b/src/SMESHGUI/SMESHGUI_MeshOp.cxx @@ -894,13 +894,14 @@ SMESHGUI_MeshOp::getInitParamsHypothesis( const QString& aHypType, !myIsMesh : myDlg->selectedObject( SMESHGUI_MeshDlg::Obj ).count(':') > nbColonsInMeshEntry; + // get mesh and geom object + SMESH::SMESH_Mesh_var aMeshVar = SMESH::SMESH_Mesh::_nil(); + GEOM::GEOM_Object_var aGeomVar = GEOM::GEOM_Object::_nil(); + + QString anEntry; if ( isSubMesh ) { - // get mesh and geom object - SMESH::SMESH_Mesh_var aMeshVar = SMESH::SMESH_Mesh::_nil(); - GEOM::GEOM_Object_var aGeomVar = GEOM::GEOM_Object::_nil(); - - QString anEntry = myDlg->selectedObject + anEntry = myDlg->selectedObject ( myToCreate ? SMESHGUI_MeshDlg::Mesh : SMESHGUI_MeshDlg::Obj ); if ( _PTR(SObject) pObj = studyDS()->FindObjectID( anEntry.toLatin1().data() )) { @@ -921,13 +922,35 @@ SMESHGUI_MeshOp::getInitParamsHypothesis( const QString& aHypType, } } } - - if ( !aMeshVar->_is_nil() && !aGeomVar->_is_nil() ) - return SMESHGUI::GetSMESHGen()->GetHypothesisParameterValues( aHypType.toLatin1().data(), - aServerLib.toLatin1().data(), - aMeshVar, - aGeomVar ); } + else // mesh + { + if ( !myToCreate ) // mesh to edit can be selected + { + anEntry = myDlg->selectedObject( SMESHGUI_MeshDlg::Obj ); + if ( _PTR(SObject) pMesh = studyDS()->FindObjectID( anEntry.toLatin1().data() )) + { + aMeshVar = SMESH::SMESH_Mesh::_narrow( _CAST( SObject,pMesh )->GetObject() ); + if ( !aMeshVar->_is_nil() ) + aGeomVar = SMESH::GetShapeOnMeshOrSubMesh( pMesh ); + } + } + if ( aGeomVar->_is_nil() ) { + anEntry = myDlg->selectedObject( SMESHGUI_MeshDlg::Geom ); + if ( _PTR(SObject) pGeom = studyDS()->FindObjectID( anEntry.toLatin1().data() )) + { + aGeomVar= GEOM::GEOM_Object::_narrow( _CAST( SObject,pGeom )->GetObject() ); + } + } + } + + if ( (!isSubMesh || !aMeshVar->_is_nil()) && !aGeomVar->_is_nil() ) + return SMESHGUI::GetSMESHGen()->GetHypothesisParameterValues( aHypType.toLatin1().data(), + aServerLib.toLatin1().data(), + aMeshVar, + aGeomVar, + /*byMesh = */isSubMesh); + return SMESH::SMESH_Hypothesis::_nil(); } @@ -1039,8 +1062,7 @@ void SMESHGUI_MeshOp::createHypothesis (const int theDim, // Create hypothesis if (aCreator) { - // When create or edit a submesh, try to initialize a new hypothesis - // with values used to mesh a subshape + // Get parameters appropriate to initialize a new hypothesis SMESH::SMESH_Hypothesis_var initParamHyp = getInitParamsHypothesis(theTypeName, aData->ServerLibName); myDlg->setEnabled( false ); @@ -1089,7 +1111,11 @@ void SMESHGUI_MeshOp::onEditHyp( const int theHypType, const int theIndex ) SMESHGUI_GenericHypothesisCreator* aCreator = SMESH::GetHypothesisCreator( aHyp->GetName() ); if ( aCreator ) { + // Get initial parameters + SMESH::SMESH_Hypothesis_var initParamHyp = + getInitParamsHypothesis( aHyp->GetName(), aHyp->GetLibName()); myDlg->setEnabled( false ); + aCreator->setInitParamsHypothesis( initParamHyp ); aCreator->edit( aHyp.in(), aHypItem.second, dlg() ); myDlg->setEnabled( true ); } @@ -1497,6 +1523,9 @@ bool SMESHGUI_MeshOp::createSubMesh( QString& theMess ) // create sub-mesh SMESH::SMESH_subMesh_var aSubMeshVar = aMeshVar->GetSubMesh( aGeomVar, aName.toLatin1().data() ); + _PTR(SObject) aSubMeshSO = SMESH::FindSObject( aSubMeshVar.in() ); + if ( aSubMeshSO ) + SMESH::SetName( aSubMeshSO, aName.toLatin1().data() ); for ( int aDim = SMESH::DIM_0D; aDim <= SMESH::DIM_3D; aDim++ ) { diff --git a/src/SMESHGUI/SMESHGUI_Preferences_ScalarBarDlg.cxx b/src/SMESHGUI/SMESHGUI_Preferences_ScalarBarDlg.cxx index 6744fc747..a6d44e57a 100644 --- a/src/SMESHGUI/SMESHGUI_Preferences_ScalarBarDlg.cxx +++ b/src/SMESHGUI/SMESHGUI_Preferences_ScalarBarDlg.cxx @@ -314,7 +314,7 @@ SMESHGUI_Preferences_ScalarBarDlg::SMESHGUI_Preferences_ScalarBarDlg( SMESHGUI* myTitleBoldCheck->setChecked ( f.bold() ); myTitleItalicCheck->setChecked( f.italic() ); - myTitleShadowCheck->setChecked( f.underline() ); + myTitleShadowCheck->setChecked( f.overline() ); } QColor labelColor = mgr->colorValue("SMESH", "scalar_bar_label_color", @@ -332,7 +332,7 @@ SMESHGUI_Preferences_ScalarBarDlg::SMESHGUI_Preferences_ScalarBarDlg( SMESHGUI* myLabelsBoldCheck ->setChecked( f.bold() ); myLabelsItalicCheck->setChecked( f.italic() ); - myLabelsShadowCheck->setChecked( f.underline() ); + myLabelsShadowCheck->setChecked( f.overline() ); } int aNbColors = mgr->integerValue("SMESH", "scalar_bar_num_colors", 64); diff --git a/src/SMESHGUI/SMESHGUI_RemoveElementsDlg.cxx b/src/SMESHGUI/SMESHGUI_RemoveElementsDlg.cxx index 3a9a9ca46..118d2d17c 100644 --- a/src/SMESHGUI/SMESHGUI_RemoveElementsDlg.cxx +++ b/src/SMESHGUI/SMESHGUI_RemoveElementsDlg.cxx @@ -31,6 +31,7 @@ #include "SMESHGUI_VTKUtils.h" #include "SMESHGUI_MeshUtils.h" #include "SMESHGUI_IdValidator.h" +#include "SMESHGUI_FilterDlg.h" #include #include @@ -81,7 +82,8 @@ SMESHGUI_RemoveElementsDlg mySelector(SMESH::GetViewWindow(theModule)->GetSelector()), mySelectionMgr(SMESH::GetSelectionMgr(theModule)), mySMESHGUI(theModule), - myBusy(false) + myBusy(false), + myFilterDlg(0) { setModal( false ); setAttribute( Qt::WA_DeleteOnClose, true ); @@ -120,10 +122,13 @@ SMESHGUI_RemoveElementsDlg SelectButtonC1A1->setIcon(image1); LineEditC1A1 = new QLineEdit(GroupC1); LineEditC1A1->setValidator(new SMESHGUI_IdValidator(this)); + QPushButton* filterBtn = new QPushButton( tr( "SMESH_BUT_FILTER" ), GroupC1 ); + connect(filterBtn, SIGNAL(clicked()), this, SLOT(setFilters())); GroupC1Layout->addWidget(TextLabelC1A1); GroupC1Layout->addWidget(SelectButtonC1A1); GroupC1Layout->addWidget(LineEditC1A1); + GroupC1Layout->addWidget(filterBtn ); /***************************************************************/ GroupButtons = new QGroupBox(this); @@ -165,6 +170,11 @@ SMESHGUI_RemoveElementsDlg //================================================================================= SMESHGUI_RemoveElementsDlg::~SMESHGUI_RemoveElementsDlg() { + if ( myFilterDlg ) { + myFilterDlg->setParent( 0 ); + delete myFilterDlg; + myFilterDlg = 0; + } } //================================================================================= @@ -253,10 +263,13 @@ void SMESHGUI_RemoveElementsDlg::ClickOnOk() //================================================================================= void SMESHGUI_RemoveElementsDlg::ClickOnCancel() { + if (SMESH::GetCurrentVtkView()) + SMESH::RemoveFilters(); // PAL6938 -- clean all mesh entity filters //mySelectionMgr->clearSelected(); if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI )) aViewWindow->SetSelectionMode(ActorSelection); disconnect(mySelectionMgr, 0, this, 0); + mySelectionMgr->clearFilters(); mySMESHGUI->ResetState(); reject(); } @@ -487,3 +500,19 @@ void SMESHGUI_RemoveElementsDlg::keyPressEvent( QKeyEvent* e ) ClickOnHelp(); } } + +//================================================================================= +// function : setFilters() +// purpose : SLOT. Called when "Filter" button pressed. +//================================================================================= +void SMESHGUI_RemoveElementsDlg::setFilters() +{ + if ( !myFilterDlg ) + myFilterDlg = new SMESHGUI_FilterDlg( mySMESHGUI, SMESH::ALL ); + + myFilterDlg->SetSelection(); + myFilterDlg->SetMesh( myMesh ); + myFilterDlg->SetSourceWg( LineEditC1A1 ); + + myFilterDlg->show(); +} diff --git a/src/SMESHGUI/SMESHGUI_RemoveElementsDlg.h b/src/SMESHGUI/SMESHGUI_RemoveElementsDlg.h index e8797937b..7138acfe5 100644 --- a/src/SMESHGUI/SMESHGUI_RemoveElementsDlg.h +++ b/src/SMESHGUI/SMESHGUI_RemoveElementsDlg.h @@ -43,6 +43,7 @@ class QPushButton; class QRadioButton; class SMESHGUI; +class SMESHGUI_FilterDlg; class SMESH_Actor; class SVTK_Selector; class LightApp_SelectionMgr; @@ -92,6 +93,8 @@ private: QString myHelpFileName; + SMESHGUI_FilterDlg* myFilterDlg; + private slots: void ClickOnOk(); void ClickOnCancel(); @@ -102,6 +105,7 @@ private slots: void DeactivateActiveDialog(); void ActivateThisDialog(); void onTextChange( const QString& ); + void setFilters(); }; #endif // SMESHGUI_REMOVEELEMENTSDLG_H diff --git a/src/SMESHGUI/SMESHGUI_RemoveNodesDlg.cxx b/src/SMESHGUI/SMESHGUI_RemoveNodesDlg.cxx index 796f8be07..bf218290a 100644 --- a/src/SMESHGUI/SMESHGUI_RemoveNodesDlg.cxx +++ b/src/SMESHGUI/SMESHGUI_RemoveNodesDlg.cxx @@ -31,6 +31,7 @@ #include "SMESHGUI_VTKUtils.h" #include "SMESHGUI_MeshUtils.h" #include "SMESHGUI_IdValidator.h" +#include "SMESHGUI_FilterDlg.h" #include #include @@ -81,7 +82,8 @@ SMESHGUI_RemoveNodesDlg mySelector(SMESH::GetViewWindow(theModule)->GetSelector()), mySelectionMgr(SMESH::GetSelectionMgr(theModule)), mySMESHGUI(theModule), - myBusy(false) + myBusy(false), + myFilterDlg(0) { setModal( false ); setAttribute( Qt::WA_DeleteOnClose, true ); @@ -120,10 +122,13 @@ SMESHGUI_RemoveNodesDlg SelectButtonC1A1->setIcon(image1); LineEditC1A1 = new QLineEdit(GroupC1); LineEditC1A1->setValidator(new SMESHGUI_IdValidator(this)); + QPushButton* filterBtn = new QPushButton( tr( "SMESH_BUT_FILTER" ), GroupC1 ); + connect(filterBtn, SIGNAL(clicked()), this, SLOT(setFilters())); GroupC1Layout->addWidget(TextLabelC1A1); GroupC1Layout->addWidget(SelectButtonC1A1); GroupC1Layout->addWidget(LineEditC1A1); + GroupC1Layout->addWidget(filterBtn ); /***************************************************************/ GroupButtons = new QGroupBox(this); @@ -165,6 +170,11 @@ SMESHGUI_RemoveNodesDlg //================================================================================= SMESHGUI_RemoveNodesDlg::~SMESHGUI_RemoveNodesDlg() { + if ( myFilterDlg ) { + myFilterDlg->setParent( 0 ); + delete myFilterDlg; + myFilterDlg = 0; + } } //================================================================================= @@ -258,10 +268,14 @@ void SMESHGUI_RemoveNodesDlg::ClickOnOk() void SMESHGUI_RemoveNodesDlg::ClickOnCancel() { //mySelectionMgr->clearSelected(); - SMESH::SetPointRepresentation(false); + if (SMESH::GetCurrentVtkView()) { + SMESH::RemoveFilters(); // PAL6938 -- clean all mesh entity filters + SMESH::SetPointRepresentation(false); + } if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI )) aViewWindow->SetSelectionMode(ActorSelection); disconnect(mySelectionMgr, 0, this, 0); + mySelectionMgr->clearFilters(); mySMESHGUI->ResetState(); reject(); } @@ -493,3 +507,19 @@ void SMESHGUI_RemoveNodesDlg::keyPressEvent( QKeyEvent* e ) ClickOnHelp(); } } + +//================================================================================= +// function : setFilters() +// purpose : SLOT. Called when "Filter" button pressed. +//================================================================================= +void SMESHGUI_RemoveNodesDlg::setFilters() +{ + if ( !myFilterDlg ) + myFilterDlg = new SMESHGUI_FilterDlg( mySMESHGUI, SMESH::NODE ); + + myFilterDlg->SetSelection(); + myFilterDlg->SetMesh( myMesh ); + myFilterDlg->SetSourceWg( LineEditC1A1 ); + + myFilterDlg->show(); +} diff --git a/src/SMESHGUI/SMESHGUI_RemoveNodesDlg.h b/src/SMESHGUI/SMESHGUI_RemoveNodesDlg.h index 90550b2da..e26e963d3 100644 --- a/src/SMESHGUI/SMESHGUI_RemoveNodesDlg.h +++ b/src/SMESHGUI/SMESHGUI_RemoveNodesDlg.h @@ -43,6 +43,7 @@ class QPushButton; class QRadioButton; class SMESHGUI; +class SMESHGUI_FilterDlg; class SMESH_Actor; class SVTK_Selector; class LightApp_SelectionMgr; @@ -91,6 +92,8 @@ private: QLineEdit* LineEditC1A1; QString myHelpFileName; + + SMESHGUI_FilterDlg* myFilterDlg; private slots: void ClickOnOk(); @@ -102,6 +105,7 @@ private slots: void DeactivateActiveDialog(); void ActivateThisDialog(); void onTextChange( const QString& ); + void setFilters(); }; #endif // SMESHGUI_REMOVENODESDLG_H diff --git a/src/SMESHGUI/SMESHGUI_RevolutionDlg.cxx b/src/SMESHGUI/SMESHGUI_RevolutionDlg.cxx index bcddfdede..15119eca4 100644 --- a/src/SMESHGUI/SMESHGUI_RevolutionDlg.cxx +++ b/src/SMESHGUI/SMESHGUI_RevolutionDlg.cxx @@ -33,6 +33,7 @@ #include "SMESHGUI_MeshUtils.h" #include "SMESHGUI_IdValidator.h" #include "SMESHGUI_MeshEditPreview.h" +#include "SMESHGUI_FilterDlg.h" #include #include @@ -72,6 +73,7 @@ #include #include #include +#include // IDL includes #include @@ -88,7 +90,9 @@ SMESHGUI_RevolutionDlg::SMESHGUI_RevolutionDlg( SMESHGUI* theModule ) : QDialog( SMESH::GetDesktop( theModule ) ), mySMESHGUI( theModule ), - mySelectionMgr( SMESH::GetSelectionMgr( theModule ) ) + mySelectionMgr( SMESH::GetSelectionMgr( theModule ) ), + myVectorDefinition(NONE_SELECT), + myFilterDlg( 0 ) { mySimulation = new SMESHGUI_MeshEditPreview(SMESH::GetViewWindow( mySMESHGUI )); @@ -139,6 +143,8 @@ SMESHGUI_RevolutionDlg::SMESHGUI_RevolutionDlg( SMESHGUI* theModule ) LineEditElements = new QLineEdit(GroupArguments); LineEditElements->setValidator(myIdValidator); + QPushButton* filterBtn = new QPushButton( tr( "SMESH_BUT_FILTER" ), GroupArguments ); + connect(filterBtn, SIGNAL(clicked()), this, SLOT(setFilters())); // Control for the whole mesh selection CheckBoxMesh = new QCheckBox(tr("SMESH_SELECT_WHOLE_MESH"), GroupArguments); @@ -231,13 +237,14 @@ SMESHGUI_RevolutionDlg::SMESHGUI_RevolutionDlg( SMESHGUI* theModule ) GroupArgumentsLayout->addWidget(TextLabelElements, 0, 0); GroupArgumentsLayout->addWidget(SelectElementsButton, 0, 1); GroupArgumentsLayout->addWidget(LineEditElements, 0, 2); - GroupArgumentsLayout->addWidget(CheckBoxMesh, 1, 0, 1, 3); - GroupArgumentsLayout->addWidget(GroupAxis, 2, 0, 1, 3); - GroupArgumentsLayout->addWidget(GroupAngleBox, 3, 0, 1, 3); + GroupArgumentsLayout->addWidget(filterBtn, 0, 3); + GroupArgumentsLayout->addWidget(CheckBoxMesh, 1, 0, 1, 4); + GroupArgumentsLayout->addWidget(GroupAxis, 2, 0, 1, 4); + GroupArgumentsLayout->addWidget(GroupAngleBox, 3, 0, 1, 4); GroupArgumentsLayout->addWidget(TextLabelTolerance, 4, 0, 1, 2); - GroupArgumentsLayout->addWidget(SpinBox_Tolerance, 4, 2); - GroupArgumentsLayout->addWidget(CheckBoxPreview, 5, 0, 1, 3); - GroupArgumentsLayout->addWidget(MakeGroupsCheck, 6, 0, 1, 3); + GroupArgumentsLayout->addWidget(SpinBox_Tolerance, 4, 2, 1, 2); + GroupArgumentsLayout->addWidget(CheckBoxPreview, 5, 0, 1, 4); + GroupArgumentsLayout->addWidget(MakeGroupsCheck, 6, 0, 1, 4); /***************************************************************/ GroupButtons = new QGroupBox(this); @@ -305,6 +312,12 @@ SMESHGUI_RevolutionDlg::SMESHGUI_RevolutionDlg( SMESHGUI* theModule ) Init(); + /*Create menu to vector selection*/ + SelectVectorMenu = new QMenu(this); + myMenuActions[SelectVectorMenu->addAction( tr( "MEN_POINT_SELECT" ) )] = POINT_SELECT; + myMenuActions[SelectVectorMenu->addAction( tr( "MEN_FACE_SELECT" ) )] = FACE_SELECT; + connect( SelectVectorMenu, SIGNAL( triggered( QAction* ) ), SLOT( onSelectVectorMenu( QAction* ) ) ); + /* signals and slots connections */ connect(buttonOk, SIGNAL(clicked()), this, SLOT(ClickOnOk())); connect(buttonCancel, SIGNAL(clicked()), this, SLOT(ClickOnCancel())); @@ -314,7 +327,7 @@ SMESHGUI_RevolutionDlg::SMESHGUI_RevolutionDlg( SMESHGUI* theModule ) connect(SelectElementsButton, SIGNAL(clicked()), this, SLOT(SetEditCurrentArgument())); connect(SelectPointButton, SIGNAL(clicked()), this, SLOT(SetEditCurrentArgument())); - connect(SelectVectorButton, SIGNAL(clicked()), this, SLOT(SetEditCurrentArgument())); + connect(SelectVectorButton, SIGNAL(clicked()), this, SLOT(onSelectVectorButton())); connect(SpinBox_X, SIGNAL(valueChanged(double)), this, SLOT(toDisplaySimulation())); connect(SpinBox_Y, SIGNAL(valueChanged(double)), this, SLOT(toDisplaySimulation())); @@ -348,6 +361,11 @@ SMESHGUI_RevolutionDlg::SMESHGUI_RevolutionDlg( SMESHGUI* theModule ) SMESHGUI_RevolutionDlg::~SMESHGUI_RevolutionDlg() { delete mySimulation; + if ( myFilterDlg ) { + myFilterDlg->setParent( 0 ); + delete myFilterDlg; + myFilterDlg = 0; + } } //================================================================================= @@ -515,7 +533,10 @@ void SMESHGUI_RevolutionDlg::ClickOnCancel() disconnect(mySelectionMgr, 0, this, 0); mySelectionMgr->clearFilters(); //mySelectionMgr->clearSelected(); - SMESH::SetPointRepresentation(false); + if (SMESH::GetCurrentVtkView()) { + SMESH::RemoveFilters(); // PAL6938 -- clean all mesh entity filters + SMESH::SetPointRepresentation(false); + } if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI )) aViewWindow->SetSelectionMode(ActorSelection); mySMESHGUI->ResetState(); @@ -729,30 +750,57 @@ void SMESHGUI_RevolutionDlg::SelectionIntoArgument() myNbOkElements = true; } else { - aNbUnits = SMESH::GetNameOfSelectedNodes(mySelector, IO, aString); - if (aNbUnits != 1) - return; SMDS_Mesh* aMesh = myActor->GetObject()->GetMesh(); if (!aMesh) return; - const SMDS_MeshNode * n = aMesh->FindNode(aString.toInt()); - if (!n) + bool isNodeSelected = (myEditCurrentArgument == (QWidget*)SpinBox_X || + (myEditCurrentArgument == (QWidget*)SpinBox_DX && + myVectorDefinition==POINT_SELECT)); + + bool isFaceSelected = (myEditCurrentArgument == (QWidget*)SpinBox_DX && + myVectorDefinition==FACE_SELECT); + + if(isNodeSelected) { + aNbUnits = SMESH::GetNameOfSelectedNodes(mySelector, IO, aString); + } + else if(isFaceSelected){ + aNbUnits = SMESH::GetNameOfSelectedElements(mySelector, IO, aString); + } + + if (aNbUnits != 1) return; - double x = n->X(); - double y = n->Y(); - double z = n->Z(); - - if (myEditCurrentArgument == (QWidget*)SpinBox_X) { - SpinBox_X->SetValue(x); - SpinBox_Y->SetValue(y); - SpinBox_Z->SetValue(z); - } else if (myEditCurrentArgument == (QWidget*)SpinBox_DX) { - SpinBox_DX->SetValue(x - SpinBox_X->GetValue()); - SpinBox_DY->SetValue(y - SpinBox_Y->GetValue()); - SpinBox_DZ->SetValue(z - SpinBox_Z->GetValue()); + if(isNodeSelected) { + const SMDS_MeshNode * n = aMesh->FindNode(aString.toInt()); + if (!n) + return; + + double x = n->X(); + double y = n->Y(); + double z = n->Z(); + + if (myEditCurrentArgument == (QWidget*)SpinBox_X) { + SpinBox_X->SetValue(x); + SpinBox_Y->SetValue(y); + SpinBox_Z->SetValue(z); + } else if (myEditCurrentArgument == (QWidget*)SpinBox_DX) { + SpinBox_DX->SetValue(x - SpinBox_X->GetValue()); + SpinBox_DY->SetValue(y - SpinBox_Y->GetValue()); + SpinBox_DZ->SetValue(z - SpinBox_Z->GetValue()); + } + } + else if(isFaceSelected){ + const SMDS_MeshFace* face = dynamic_cast(aMesh->FindElement(aString.toInt())); + if (!face) + return; + + gp_XYZ aNormale = SMESH::getNormale(face); + SpinBox_DX->SetValue(aNormale.X()); + SpinBox_DY->SetValue(aNormale.Y()); + SpinBox_DZ->SetValue(aNormale.Z()); + } } @@ -808,12 +856,6 @@ void SMESHGUI_RevolutionDlg::SetEditCurrentArgument() SMESH::SetPointRepresentation(true); if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI )) aViewWindow->SetSelectionMode(NodeSelection); - } else if (send == SelectVectorButton) { - myEditCurrentArgument = (QWidget*)SpinBox_DX; - SMESH::SetPointRepresentation(true); - if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI )) - aViewWindow->SetSelectionMode(NodeSelection); - } else { } myEditCurrentArgument->setFocus(); @@ -1051,3 +1093,64 @@ void SMESHGUI_RevolutionDlg::onDisplaySimulation(bool toDisplayPreview) mySimulation->SetVisibility(false); } } + +//================================================================================= +// function : onSelectVectorButton() +// purpose : [slot] +//================================================================================= +void SMESHGUI_RevolutionDlg::onSelectVectorButton(){ + if(SelectVectorMenu) { + SelectVectorMenu->exec( QCursor::pos() ); + } +} + +//================================================================================= +// function : onSelectVectorMenu() +// purpose : [slot] +//================================================================================= +void SMESHGUI_RevolutionDlg::onSelectVectorMenu( QAction* action){ + if(!action) + return; + + switch(myMenuActions[action]) { + case POINT_SELECT: + SMESH::SetPointRepresentation(true); + if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI )) + aViewWindow->SetSelectionMode(NodeSelection); + break; + + case FACE_SELECT: + SMESH::SetPointRepresentation(false); + if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI )) + aViewWindow->SetSelectionMode(FaceSelection); + break; + } + + myVectorDefinition = myMenuActions[action]; + myEditCurrentArgument = (QWidget*)SpinBox_DX; + myEditCurrentArgument->setFocus(); + connect(mySelectionMgr, SIGNAL(currentSelectionChanged()), this, SLOT(SelectionIntoArgument())); + SelectionIntoArgument(); +} + +//================================================================================= +// function : setFilters() +// purpose : SLOT. Called when "Filter" button pressed. +//================================================================================= +void SMESHGUI_RevolutionDlg::setFilters() +{ + if ( !myFilterDlg ) + { + QList types; + types.append( SMESH::EDGE ); + types.append( SMESH::FACE ); + myFilterDlg = new SMESHGUI_FilterDlg( mySMESHGUI, types ); + } + myFilterDlg->Init( GetConstructorId() ? SMESH::FACE : SMESH::EDGE ); + + myFilterDlg->SetSelection(); + myFilterDlg->SetMesh( myMesh ); + myFilterDlg->SetSourceWg( LineEditElements ); + + myFilterDlg->show(); +} diff --git a/src/SMESHGUI/SMESHGUI_RevolutionDlg.h b/src/SMESHGUI/SMESHGUI_RevolutionDlg.h index ecd9a3bfd..3502596f1 100644 --- a/src/SMESHGUI/SMESHGUI_RevolutionDlg.h +++ b/src/SMESHGUI/SMESHGUI_RevolutionDlg.h @@ -31,6 +31,7 @@ // Qt includes #include +#include // IDL includes #include @@ -47,12 +48,15 @@ class QSpinBox; class SMESHGUI_IdValidator; class SMESHGUI_SpinBox; class SMESHGUI; +class SMESHGUI_FilterDlg; class SMESH_Actor; class SVTK_Selector; class LightApp_SelectionMgr; class SMESH_LogicalFilter; class SALOME_Actor; class SMESHGUI_MeshEditPreview; +class QMenu; +class QAction; //================================================================================= // class : SMESHGUI_RevolutionDlg @@ -67,6 +71,8 @@ public: ~SMESHGUI_RevolutionDlg(); private: + enum {NONE_SELECT, POINT_SELECT, FACE_SELECT}; + void Init( bool = true); void closeEvent( QCloseEvent* ); void enterEvent( QEvent* ); /* mouse enter the QWidget */ @@ -135,9 +141,16 @@ private: QSpinBox* SpinBox_NbSteps; QLabel* TextLabelTolerance; SMESHGUI_SpinBox* SpinBox_Tolerance; + + QMenu* SelectVectorMenu; + QMap myMenuActions; + int myVectorDefinition; + QString myHelpFileName; + SMESHGUI_FilterDlg* myFilterDlg; + private slots: void ConstructorsClicked( int ); void ClickOnOk(); @@ -153,6 +166,9 @@ private slots: void onVectorChanged(); void toDisplaySimulation(); void onDisplaySimulation( bool ); + void onSelectVectorMenu( QAction* ); + void onSelectVectorButton(); + void setFilters(); }; #endif // SMESHGUI_REVOLUTIONDLG_H diff --git a/src/SMESHGUI/SMESHGUI_RotationDlg.cxx b/src/SMESHGUI/SMESHGUI_RotationDlg.cxx index 09ee60688..a2f5460f5 100644 --- a/src/SMESHGUI/SMESHGUI_RotationDlg.cxx +++ b/src/SMESHGUI/SMESHGUI_RotationDlg.cxx @@ -32,6 +32,7 @@ #include "SMESHGUI_VTKUtils.h" #include "SMESHGUI_MeshUtils.h" #include "SMESHGUI_IdValidator.h" +#include "SMESHGUI_FilterDlg.h" #include #include @@ -89,7 +90,8 @@ enum { MOVE_ELEMS_BUTTON = 0, COPY_ELEMS_BUTTON, MAKE_MESH_BUTTON }; //!< action SMESHGUI_RotationDlg::SMESHGUI_RotationDlg( SMESHGUI* theModule ) : QDialog( SMESH::GetDesktop( theModule ) ), mySMESHGUI( theModule ), - mySelectionMgr( SMESH::GetSelectionMgr( theModule ) ) + mySelectionMgr( SMESH::GetSelectionMgr( theModule ) ), + myFilterDlg(0) { QPixmap image0 (SMESH::GetResourceMgr( mySMESHGUI )->loadPixmap("SMESH", tr("ICON_DLG_MESH_ROTATION"))); QPixmap image1 (SMESH::GetResourceMgr( mySMESHGUI )->loadPixmap("SMESH", tr("ICON_SELECT"))); @@ -130,6 +132,8 @@ SMESHGUI_RotationDlg::SMESHGUI_RotationDlg( SMESHGUI* theModule ) SelectElementsButton->setIcon(image1); LineEditElements = new QLineEdit(GroupArguments); LineEditElements->setValidator(myIdValidator); + QPushButton* filterBtn = new QPushButton( tr( "SMESH_BUT_FILTER" ), GroupArguments ); + connect(filterBtn, SIGNAL(clicked()), this, SLOT(setFilters())); // Control for the whole mesh selection CheckBoxMesh = new QCheckBox(tr("SMESH_SELECT_WHOLE_MESH"), GroupArguments); @@ -209,7 +213,8 @@ SMESHGUI_RotationDlg::SMESHGUI_RotationDlg( SMESHGUI* theModule ) GroupArgumentsLayout->addWidget(TextLabelElements, 0, 0); GroupArgumentsLayout->addWidget(SelectElementsButton, 0, 1); - GroupArgumentsLayout->addWidget(LineEditElements, 0, 2, 1, 2); + GroupArgumentsLayout->addWidget(LineEditElements, 0, 2, 1, 1); + GroupArgumentsLayout->addWidget(filterBtn, 0, 3); GroupArgumentsLayout->addWidget(CheckBoxMesh, 1, 0, 1, 4); GroupArgumentsLayout->addWidget(GroupAxis, 2, 0, 1, 4); GroupArgumentsLayout->addWidget(TextLabelAngle, 3, 0, 1, 2); @@ -310,6 +315,11 @@ SMESHGUI_RotationDlg::SMESHGUI_RotationDlg( SMESHGUI* theModule ) //================================================================================= SMESHGUI_RotationDlg::~SMESHGUI_RotationDlg() { + if ( myFilterDlg ) { + myFilterDlg->setParent( 0 ); + delete myFilterDlg; + myFilterDlg = 0; + } } //================================================================================= @@ -431,7 +441,10 @@ void SMESHGUI_RotationDlg::ClickOnCancel() disconnect(mySelectionMgr, 0, this, 0); mySelectionMgr->clearFilters(); //mySelectionMgr->clearSelected(); - SMESH::SetPointRepresentation(false); + if (SMESH::GetCurrentVtkView()) { + SMESH::RemoveFilters(); // PAL6938 -- clean all mesh entity filters + SMESH::SetPointRepresentation(false); + } if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI )) aViewWindow->SetSelectionMode(ActorSelection); mySMESHGUI->ResetState(); @@ -909,3 +922,19 @@ void SMESHGUI_RotationDlg::keyPressEvent( QKeyEvent* e ) ClickOnHelp(); } } + +//================================================================================= +// function : setFilters() +// purpose : SLOT. Called when "Filter" button pressed. +//================================================================================= +void SMESHGUI_RotationDlg::setFilters() +{ + if ( !myFilterDlg ) + myFilterDlg = new SMESHGUI_FilterDlg( mySMESHGUI, SMESH::ALL ); + + myFilterDlg->SetSelection(); + myFilterDlg->SetMesh( myMesh ); + myFilterDlg->SetSourceWg( LineEditElements ); + + myFilterDlg->show(); +} diff --git a/src/SMESHGUI/SMESHGUI_RotationDlg.h b/src/SMESHGUI/SMESHGUI_RotationDlg.h index eefe467f2..de192b80b 100644 --- a/src/SMESHGUI/SMESHGUI_RotationDlg.h +++ b/src/SMESHGUI/SMESHGUI_RotationDlg.h @@ -47,6 +47,7 @@ class SMESHGUI; class SMESH_Actor; class SMESHGUI_IdValidator; class SMESHGUI_SpinBox; +class SMESHGUI_FilterDlg; class SVTK_Selector; class LightApp_SelectionMgr; class SMESH_LogicalFilter; @@ -127,6 +128,8 @@ private: QString myHelpFileName; + SMESHGUI_FilterDlg* myFilterDlg; + private slots: void ClickOnOk(); void ClickOnCancel(); @@ -140,6 +143,7 @@ private slots: void onSelectMesh( bool ); void onVectorChanged(); void onActionClicked( int ); + void setFilters(); }; #endif // SMESHGUI_ROTATIONDLG_H diff --git a/src/SMESHGUI/SMESHGUI_Selection.cxx b/src/SMESHGUI/SMESHGUI_Selection.cxx index e7686db20..e0e63d4cc 100644 --- a/src/SMESHGUI/SMESHGUI_Selection.cxx +++ b/src/SMESHGUI/SMESHGUI_Selection.cxx @@ -116,6 +116,7 @@ QVariant SMESHGUI_Selection::parameter( const int ind, const QString& p ) const else if ( p=="hasReference" ) val = QVariant( hasReference( ind ) ); else if ( p=="isImported" ) val = QVariant( isImported( ind ) ); else if ( p=="facesOrientationMode" ) val = QVariant( facesOrientationMode( ind ) ); + else if ( p=="groupType" ) val = QVariant( groupType( ind ) ); if( val.isValid() ) return val; @@ -239,6 +240,7 @@ QString SMESHGUI_Selection::controlMode( int ind ) const case SMESH_Actor::eLength2D: return "eLength2D"; case SMESH_Actor::eFreeEdges: return "eFreeEdges"; case SMESH_Actor::eFreeBorders: return "eFreeBorders"; + case SMESH_Actor::eFreeFaces: return "eFreeFaces"; case SMESH_Actor::eMultiConnection: return "eMultiConnection"; case SMESH_Actor::eMultiConnection2D: return "eMultiConnection2D"; case SMESH_Actor::eArea: return "eArea"; @@ -523,3 +525,27 @@ bool SMESHGUI_Selection::isImported( const int ind ) const */ return res; } + +//======================================================================= +//function : groupType +//purpose : +//======================================================================= + +QString SMESHGUI_Selection::groupType( int ind ) const +{ + QString e = entry( ind ); + _PTR(SObject) SO = SMESH::GetActiveStudyDocument()->FindObjectID( e.toLatin1().constData() ); + QString type; + if( SO ) + { + CORBA::Object_var obj = SMESH::SObjectToObject( SO ); + + SMESH::SMESH_Group_var aGroup = SMESH::SMESH_Group::_narrow( obj ); + SMESH::SMESH_GroupOnGeom_var aGroupOnGeom = SMESH::SMESH_GroupOnGeom::_narrow( obj ); + if( !aGroup->_is_nil() ) + type = QString( "Group" ); + else if ( !aGroupOnGeom->_is_nil() ) + type = QString( "GroupOnGeom" ); + } + return type; +} diff --git a/src/SMESHGUI/SMESHGUI_Selection.h b/src/SMESHGUI/SMESHGUI_Selection.h index 8822b65fc..72ed58cb4 100644 --- a/src/SMESHGUI/SMESHGUI_Selection.h +++ b/src/SMESHGUI/SMESHGUI_Selection.h @@ -65,6 +65,7 @@ public: virtual QList entityMode( int ) const; virtual QString controlMode( int ) const; virtual QString facesOrientationMode( int ) const; + virtual QString groupType( int ) const; SMESH_Actor* getActor( int ) const; diff --git a/src/SMESHGUI/SMESHGUI_SmoothingDlg.cxx b/src/SMESHGUI/SMESHGUI_SmoothingDlg.cxx index 9ff91bc15..e38bf7713 100644 --- a/src/SMESHGUI/SMESHGUI_SmoothingDlg.cxx +++ b/src/SMESHGUI/SMESHGUI_SmoothingDlg.cxx @@ -32,6 +32,7 @@ #include "SMESHGUI_MeshUtils.h" #include "SMESHGUI_SpinBox.h" #include "SMESHGUI_IdValidator.h" +#include "SMESHGUI_FilterDlg.h" #include #include @@ -89,7 +90,8 @@ SMESHGUI_SmoothingDlg::SMESHGUI_SmoothingDlg( SMESHGUI* theModule ) : QDialog( SMESH::GetDesktop( theModule ) ), mySMESHGUI( theModule ), - mySelectionMgr( SMESH::GetSelectionMgr( theModule ) ) + mySelectionMgr( SMESH::GetSelectionMgr( theModule ) ), + myFilterDlg(0) { QPixmap image0 (SMESH::GetResourceMgr( mySMESHGUI )->loadPixmap("SMESH", tr("ICON_DLG_SMOOTHING"))); QPixmap image1 (SMESH::GetResourceMgr( mySMESHGUI )->loadPixmap("SMESH", tr("ICON_SELECT"))); @@ -133,6 +135,8 @@ SMESHGUI_SmoothingDlg::SMESHGUI_SmoothingDlg( SMESHGUI* theModule ) LineEditElements = new QLineEdit(GroupArguments); LineEditElements->setValidator(myIdValidator); + QPushButton* filterElemBtn = new QPushButton( tr( "SMESH_BUT_FILTER" ), GroupArguments ); + connect(filterElemBtn, SIGNAL(clicked()), this, SLOT(setElemFilters())); // Control for the whole mesh selection CheckBoxMesh = new QCheckBox(tr("SMESH_SELECT_WHOLE_MESH"), GroupArguments); @@ -145,6 +149,8 @@ SMESHGUI_SmoothingDlg::SMESHGUI_SmoothingDlg( SMESHGUI* theModule ) LineEditNodes = new QLineEdit(GroupArguments); LineEditNodes->setValidator(myIdValidator); + QPushButton* filterNodeBtn = new QPushButton( tr( "SMESH_BUT_FILTER" ), GroupArguments ); + connect(filterNodeBtn, SIGNAL(clicked()), this, SLOT(setNodeFilters())); // Controls for method selection TextLabelMethod = new QLabel(tr("METHOD"), GroupArguments); @@ -167,17 +173,19 @@ SMESHGUI_SmoothingDlg::SMESHGUI_SmoothingDlg( SMESHGUI* theModule ) GroupArgumentsLayout->addWidget(TextLabelElements, 0, 0); GroupArgumentsLayout->addWidget(SelectElementsButton, 0, 1); GroupArgumentsLayout->addWidget(LineEditElements, 0, 2); - GroupArgumentsLayout->addWidget(CheckBoxMesh, 1, 0, 1, 3); + GroupArgumentsLayout->addWidget(filterElemBtn, 0, 3); + GroupArgumentsLayout->addWidget(CheckBoxMesh, 1, 0, 1, 4); GroupArgumentsLayout->addWidget(TextLabelNodes, 2, 0); GroupArgumentsLayout->addWidget(SelectNodesButton, 2, 1); GroupArgumentsLayout->addWidget(LineEditNodes, 2, 2); + GroupArgumentsLayout->addWidget(filterNodeBtn, 2, 3); GroupArgumentsLayout->addWidget(TextLabelMethod, 3, 0); - GroupArgumentsLayout->addWidget(ComboBoxMethod, 3, 2); + GroupArgumentsLayout->addWidget(ComboBoxMethod, 3, 2, 1, 2); GroupArgumentsLayout->addWidget(TextLabelLimit, 4, 0); - GroupArgumentsLayout->addWidget(SpinBox_IterationLimit, 4, 2); + GroupArgumentsLayout->addWidget(SpinBox_IterationLimit, 4, 2, 1, 2); GroupArgumentsLayout->addWidget(TextLabelAspectRatio, 5, 0); - GroupArgumentsLayout->addWidget(SpinBox_AspectRatio, 5, 2); - GroupArgumentsLayout->addWidget(CheckBoxParametric, 6, 0, 1, 3); + GroupArgumentsLayout->addWidget(SpinBox_AspectRatio, 5, 2, 1, 2); + GroupArgumentsLayout->addWidget(CheckBoxParametric, 6, 0, 1, 4); /***************************************************************/ GroupButtons = new QGroupBox(this); @@ -273,6 +281,10 @@ SMESHGUI_SmoothingDlg::SMESHGUI_SmoothingDlg( SMESHGUI* theModule ) SMESHGUI_SmoothingDlg::~SMESHGUI_SmoothingDlg() { // no need to delete child widgets, Qt does it all for us + if ( myFilterDlg != 0 ) { + myFilterDlg->setParent( 0 ); + delete myFilterDlg; + } } //================================================================================= @@ -382,8 +394,11 @@ void SMESHGUI_SmoothingDlg::ClickOnCancel() disconnect(mySelectionMgr, 0, this, 0); mySelectionMgr->clearFilters(); //mySelectionMgr->clearSelected(); - SMESH::SetPickable(); // ??? - SMESH::SetPointRepresentation(false); + if (SMESH::GetCurrentVtkView()) { + SMESH::RemoveFilters(); // PAL6938 -- clean all mesh entity filters + SMESH::SetPointRepresentation(false); + SMESH::SetPickable(); + } if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI )) aViewWindow->SetSelectionMode(ActorSelection); mySMESHGUI->ResetState(); @@ -494,9 +509,13 @@ void SMESHGUI_SmoothingDlg::SelectionIntoArgument() QString aString = ""; myBusy = true; - if (myEditCurrentArgument == (QWidget*)LineEditElements) { - LineEditElements->setText(aString); - myNbOkElements = 0; + if (myEditCurrentArgument == LineEditElements || + myEditCurrentArgument == LineEditNodes) { + myEditCurrentArgument->setText(aString); + if (myEditCurrentArgument == LineEditElements) + myNbOkElements = 0; + else + myNbOkNodes = 0; buttonOk->setEnabled(false); buttonApply->setEnabled(false); myActor = 0; @@ -591,9 +610,9 @@ void SMESHGUI_SmoothingDlg::SelectionIntoArgument() // OK if (myEditCurrentArgument == LineEditElements) - myNbOkElements = true; + myNbOkElements = aNbUnits; else if (myEditCurrentArgument == LineEditNodes) - myNbOkNodes = true; + myNbOkNodes = aNbUnits; if (myNbOkElements && (myNbOkNodes || LineEditNodes->text().trimmed().isEmpty())) { buttonOk->setEnabled(true); @@ -719,8 +738,10 @@ void SMESHGUI_SmoothingDlg::onSelectMesh (bool toSelectMesh) else TextLabelElements->setText(tr("SMESH_ID_ELEMENTS")); - if (myEditCurrentArgument != LineEditElements) { + if (myEditCurrentArgument != LineEditElements && + myEditCurrentArgument != LineEditNodes) { LineEditElements->clear(); + LineEditNodes->clear(); return; } @@ -732,14 +753,15 @@ void SMESHGUI_SmoothingDlg::onSelectMesh (bool toSelectMesh) aViewWindow->SetSelectionMode(ActorSelection); // mySelectionMgr->setSelectionModes(ActorSelection); mySelectionMgr->installFilter(myMeshOrSubMeshOrGroupFilter); - LineEditElements->setReadOnly(true); - LineEditElements->setValidator(0); + myEditCurrentArgument->setReadOnly(true); + myEditCurrentArgument->setValidator(0); } else { if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI )) - aViewWindow->SetSelectionMode(FaceSelection); - LineEditElements->setReadOnly(false); + aViewWindow->SetSelectionMode(myEditCurrentArgument == LineEditElements ? FaceSelection + : NodeSelection ); + myEditCurrentArgument->setReadOnly(false); LineEditElements->setValidator(myIdValidator); - onTextChange(LineEditElements->text()); + onTextChange(myEditCurrentArgument->text()); } SelectionIntoArgument(); @@ -760,3 +782,43 @@ void SMESHGUI_SmoothingDlg::keyPressEvent( QKeyEvent* e ) ClickOnHelp(); } } + +//================================================================================= +// function : setFilters() +// purpose : activate filter dialog +//================================================================================= +void SMESHGUI_SmoothingDlg::setFilters( const bool theIsElem ) +{ + if ( !myFilterDlg ) + { + QList types; + types.append( SMESH::NODE ); + types.append( SMESH::ALL ); + myFilterDlg = new SMESHGUI_FilterDlg( mySMESHGUI, types ); + } + myFilterDlg->Init( theIsElem ? SMESH::ALL : SMESH::NODE ); + + myFilterDlg->SetSelection(); + myFilterDlg->SetMesh( myMesh ); + myFilterDlg->SetSourceWg( theIsElem ? LineEditElements : LineEditNodes ); + + myFilterDlg->show(); +} + +//================================================================================= +// function : setElemFilters() +// purpose : SLOT. Called when element "Filter" button pressed. +//================================================================================= +void SMESHGUI_SmoothingDlg::setElemFilters() +{ + setFilters( true ); +} + +//================================================================================= +// function : setNodeFilters() +// purpose : SLOT. Called when node "Filter" button pressed. +//================================================================================= +void SMESHGUI_SmoothingDlg::setNodeFilters() +{ + setFilters( false ); +} diff --git a/src/SMESHGUI/SMESHGUI_SmoothingDlg.h b/src/SMESHGUI/SMESHGUI_SmoothingDlg.h index d63bdd88a..c01dfc1c7 100644 --- a/src/SMESHGUI/SMESHGUI_SmoothingDlg.h +++ b/src/SMESHGUI/SMESHGUI_SmoothingDlg.h @@ -44,9 +44,10 @@ class QRadioButton; class QComboBox; class QCheckBox; class QSpinBox; +class SMESHGUI; class SMESHGUI_IdValidator; class SMESHGUI_SpinBox; -class SMESHGUI; +class SMESHGUI_FilterDlg; class SMESH_Actor; class SVTK_Selector; class LightApp_SelectionMgr; @@ -70,6 +71,7 @@ private: void enterEvent( QEvent* ); /* mouse enter the QWidget */ void hideEvent( QHideEvent* ); /* ESC key */ void keyPressEvent( QKeyEvent* ); + void setFilters( const bool theIsElem ); SMESHGUI* mySMESHGUI; /* Current SMESHGUI object */ SMESHGUI_IdValidator* myIdValidator; @@ -111,6 +113,8 @@ private: QString myHelpFileName; + SMESHGUI_FilterDlg* myFilterDlg; + private slots: void ClickOnOk(); void ClickOnCancel(); @@ -122,6 +126,8 @@ private slots: void ActivateThisDialog(); void onTextChange( const QString& ); void onSelectMesh( bool ); + void setElemFilters(); + void setNodeFilters(); }; #endif // SMESHGUI_SMOOTHINGDLG_H diff --git a/src/SMESHGUI/SMESHGUI_SymmetryDlg.cxx b/src/SMESHGUI/SMESHGUI_SymmetryDlg.cxx index 2d4559317..7f0c6d0fe 100644 --- a/src/SMESHGUI/SMESHGUI_SymmetryDlg.cxx +++ b/src/SMESHGUI/SMESHGUI_SymmetryDlg.cxx @@ -32,6 +32,7 @@ #include "SMESHGUI_VTKUtils.h" #include "SMESHGUI_MeshUtils.h" #include "SMESHGUI_IdValidator.h" +#include "SMESHGUI_FilterDlg.h" #include #include @@ -90,7 +91,8 @@ enum { MOVE_ELEMS_BUTTON = 0, COPY_ELEMS_BUTTON, MAKE_MESH_BUTTON }; //!< action SMESHGUI_SymmetryDlg::SMESHGUI_SymmetryDlg( SMESHGUI* theModule ) : QDialog( SMESH::GetDesktop( theModule ) ), mySMESHGUI( theModule ), - mySelectionMgr( SMESH::GetSelectionMgr( theModule ) ) + mySelectionMgr( SMESH::GetSelectionMgr( theModule ) ), + myFilterDlg(0) { QPixmap image0 (SMESH::GetResourceMgr( mySMESHGUI )->loadPixmap("SMESH", tr("ICON_SMESH_SYMMETRY_POINT"))); QPixmap image1 (SMESH::GetResourceMgr( mySMESHGUI )->loadPixmap("SMESH", tr("ICON_SMESH_SYMMETRY_AXIS"))); @@ -141,6 +143,8 @@ SMESHGUI_SymmetryDlg::SMESHGUI_SymmetryDlg( SMESHGUI* theModule ) SelectElementsButton->setIcon(image3); LineEditElements = new QLineEdit(GroupArguments); LineEditElements->setValidator(myIdValidator); + QPushButton* filterBtn = new QPushButton( tr( "SMESH_BUT_FILTER" ), GroupArguments ); + connect(filterBtn, SIGNAL(clicked()), this, SLOT(setFilters())); // Control for the whole mesh selection CheckBoxMesh = new QCheckBox(tr("SMESH_SELECT_WHOLE_MESH"), GroupArguments); @@ -218,7 +222,8 @@ SMESHGUI_SymmetryDlg::SMESHGUI_SymmetryDlg( SMESHGUI* theModule ) // layout GroupArgumentsLayout->addWidget(TextLabelElements, 0, 0); GroupArgumentsLayout->addWidget(SelectElementsButton, 0, 1); - GroupArgumentsLayout->addWidget(LineEditElements, 0, 2, 1, 2); + GroupArgumentsLayout->addWidget(LineEditElements, 0, 2, 1, 1); + GroupArgumentsLayout->addWidget(filterBtn, 0, 3); GroupArgumentsLayout->addWidget(CheckBoxMesh, 1, 0, 1, 4); GroupArgumentsLayout->addWidget(GroupMirror, 2, 0, 1, 4); GroupArgumentsLayout->addWidget(ActionBox, 3, 0, 3, 3); @@ -317,6 +322,10 @@ SMESHGUI_SymmetryDlg::SMESHGUI_SymmetryDlg( SMESHGUI* theModule ) //================================================================================= SMESHGUI_SymmetryDlg::~SMESHGUI_SymmetryDlg() { + if ( myFilterDlg != 0 ) { + myFilterDlg->setParent( 0 ); + delete myFilterDlg; + } } //================================================================================= @@ -520,7 +529,10 @@ void SMESHGUI_SymmetryDlg::ClickOnCancel() disconnect(mySelectionMgr, 0, this, 0); mySelectionMgr->clearFilters(); //mySelectionMgr->clearSelected(); - SMESH::SetPointRepresentation(false); + if (SMESH::GetCurrentVtkView()) { + SMESH::RemoveFilters(); // PAL6938 -- clean all mesh entity filters + SMESH::SetPointRepresentation(false); + } if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI )) aViewWindow->SetSelectionMode(ActorSelection); mySMESHGUI->ResetState(); @@ -1007,3 +1019,19 @@ void SMESHGUI_SymmetryDlg::keyPressEvent( QKeyEvent* e ) ClickOnHelp(); } } + +//================================================================================= +// function : setFilters() +// purpose : SLOT. Called when "Filter" button pressed. +//================================================================================= +void SMESHGUI_SymmetryDlg::setFilters() +{ + if ( !myFilterDlg ) + myFilterDlg = new SMESHGUI_FilterDlg( mySMESHGUI, SMESH::ALL ); + + myFilterDlg->SetSelection(); + myFilterDlg->SetMesh( myMesh ); + myFilterDlg->SetSourceWg( LineEditElements ); + + myFilterDlg->show(); +} diff --git a/src/SMESHGUI/SMESHGUI_SymmetryDlg.h b/src/SMESHGUI/SMESHGUI_SymmetryDlg.h index ed6b08c9d..fc18a65be 100644 --- a/src/SMESHGUI/SMESHGUI_SymmetryDlg.h +++ b/src/SMESHGUI/SMESHGUI_SymmetryDlg.h @@ -43,9 +43,10 @@ class QLineEdit; class QPushButton; class QRadioButton; class QCheckBox; +class SMESHGUI; class SMESHGUI_IdValidator; class SMESHGUI_SpinBox; -class SMESHGUI; +class SMESHGUI_FilterDlg; class SMESH_Actor; class SVTK_Selector; class LightApp_SelectionMgr; @@ -128,6 +129,8 @@ private: QString myHelpFileName; + SMESHGUI_FilterDlg* myFilterDlg; + private slots: void ConstructorsClicked( int ); void ClickOnOk(); @@ -142,6 +145,7 @@ private slots: void onSelectMesh( bool ); void onVectorChanged(); void onActionClicked( int ); + void setFilters(); }; #endif // SMESHGUI_SYMMETRYDLG_H diff --git a/src/SMESHGUI/SMESHGUI_TranslationDlg.cxx b/src/SMESHGUI/SMESHGUI_TranslationDlg.cxx index eb5ad0eb3..b148a5315 100644 --- a/src/SMESHGUI/SMESHGUI_TranslationDlg.cxx +++ b/src/SMESHGUI/SMESHGUI_TranslationDlg.cxx @@ -32,6 +32,7 @@ #include "SMESHGUI_VTKUtils.h" #include "SMESHGUI_MeshUtils.h" #include "SMESHGUI_IdValidator.h" +#include "SMESHGUI_FilterDlg.h" #include #include @@ -107,7 +108,8 @@ private: SMESHGUI_TranslationDlg::SMESHGUI_TranslationDlg( SMESHGUI* theModule ) : QDialog( SMESH::GetDesktop( theModule ) ), mySMESHGUI( theModule ), - mySelectionMgr( SMESH::GetSelectionMgr( theModule ) ) + mySelectionMgr( SMESH::GetSelectionMgr( theModule ) ), + myFilterDlg(0) { QPixmap image0 (SMESH::GetResourceMgr( mySMESHGUI )->loadPixmap("SMESH", tr("ICON_SMESH_TRANSLATION_POINTS"))); QPixmap image1 (SMESH::GetResourceMgr( mySMESHGUI )->loadPixmap("SMESH", tr("ICON_SMESH_TRANSLATION_VECTOR"))); @@ -153,6 +155,8 @@ SMESHGUI_TranslationDlg::SMESHGUI_TranslationDlg( SMESHGUI* theModule ) SelectElementsButton->setIcon(image2); LineEditElements = new QLineEdit(GroupArguments); LineEditElements->setValidator(myIdValidator); + QPushButton* filterBtn = new QPushButton( tr( "SMESH_BUT_FILTER" ), GroupArguments ); + connect(filterBtn, SIGNAL(clicked()), this, SLOT(setFilters())); // Control for the whole mesh selection CheckBoxMesh = new QCheckBox(tr("SMESH_SELECT_WHOLE_MESH"), GroupArguments); @@ -208,7 +212,8 @@ SMESHGUI_TranslationDlg::SMESHGUI_TranslationDlg( SMESHGUI* theModule ) // layout GroupArgumentsLayout->addWidget(TextLabelElements, 0, 0); GroupArgumentsLayout->addWidget(SelectElementsButton, 0, 1); - GroupArgumentsLayout->addWidget(LineEditElements, 0, 2, 1, 6); + GroupArgumentsLayout->addWidget(LineEditElements, 0, 2, 1, 5); + GroupArgumentsLayout->addWidget(filterBtn, 0, 7); GroupArgumentsLayout->addWidget(CheckBoxMesh, 1, 0, 1, 8); GroupArgumentsLayout->addWidget(TextLabel1, 2, 0); GroupArgumentsLayout->addWidget(SelectButton1, 2, 1); @@ -318,6 +323,11 @@ SMESHGUI_TranslationDlg::SMESHGUI_TranslationDlg( SMESHGUI* theModule ) //================================================================================= SMESHGUI_TranslationDlg::~SMESHGUI_TranslationDlg() { + if ( myFilterDlg ) { + myFilterDlg->setParent( 0 ); + delete myFilterDlg; + myFilterDlg = 0; + } } //================================================================================= @@ -504,7 +514,10 @@ void SMESHGUI_TranslationDlg::ClickOnCancel() disconnect(mySelectionMgr, 0, this, 0); mySelectionMgr->clearFilters(); //mySelectionMgr->clearSelected(); - SMESH::SetPointRepresentation(false); + if (SMESH::GetCurrentVtkView()) { + SMESH::RemoveFilters(); // PAL6938 -- clean all mesh entity filters + SMESH::SetPointRepresentation(false); + } if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI )) aViewWindow->SetSelectionMode( ActorSelection ); mySMESHGUI->ResetState(); @@ -957,3 +970,19 @@ void SMESHGUI_TranslationDlg::keyPressEvent( QKeyEvent* e ) ClickOnHelp(); } } + +//================================================================================= +// function : setFilters() +// purpose : SLOT. Called when "Filter" button pressed. +//================================================================================= +void SMESHGUI_TranslationDlg::setFilters() +{ + if ( !myFilterDlg ) + myFilterDlg = new SMESHGUI_FilterDlg( mySMESHGUI, SMESH::ALL ); + + myFilterDlg->SetSelection(); + myFilterDlg->SetMesh( myMesh ); + myFilterDlg->SetSourceWg( LineEditElements ); + + myFilterDlg->show(); +} diff --git a/src/SMESHGUI/SMESHGUI_TranslationDlg.h b/src/SMESHGUI/SMESHGUI_TranslationDlg.h index d9324720d..c551faeee 100644 --- a/src/SMESHGUI/SMESHGUI_TranslationDlg.h +++ b/src/SMESHGUI/SMESHGUI_TranslationDlg.h @@ -46,6 +46,7 @@ class QCheckBox; class SMESHGUI; class SMESHGUI_IdValidator; class SMESHGUI_SpinBox; +class SMESHGUI_FilterDlg; class SMESH_Actor; class SVTK_Selector; class LightApp_SelectionMgr; @@ -124,6 +125,8 @@ private: QLineEdit* LineEditNewMesh; QString myHelpFileName; + + SMESHGUI_FilterDlg* myFilterDlg; private slots: void ConstructorsClicked( int ); @@ -138,6 +141,7 @@ private slots: void onTextChange( const QString& ); void onSelectMesh( bool ); void onActionClicked( int ); + void setFilters(); }; #endif // SMESHGUI_TRANSLATIONDLG_H diff --git a/src/SMESHGUI/SMESHGUI_Utils.cxx b/src/SMESHGUI/SMESHGUI_Utils.cxx index 1bfe56991..33eb25b96 100644 --- a/src/SMESHGUI/SMESHGUI_Utils.cxx +++ b/src/SMESHGUI/SMESHGUI_Utils.cxx @@ -25,9 +25,11 @@ // SMESH includes // #include "SMESHGUI_Utils.h" - #include "SMESHGUI.h" +#include +#include + // SALOME GUI includes #include #include @@ -41,6 +43,10 @@ #include +// OCC includes +#include +#include + namespace SMESH { SUIT_Desktop* @@ -131,12 +137,7 @@ namespace SMESH _PTR(Study) aStudy = GetActiveStudyDocument(); if (aStudy->GetProperties()->IsLocked()) return; - _PTR(StudyBuilder) aBuilder = aStudy->NewBuilder(); - _PTR(GenericAttribute) anAttr = - aBuilder->FindOrCreateAttribute(theSObject, "AttributeName"); - _PTR(AttributeName) aName = anAttr; - if (aName) - aName->SetValue(theName.toLatin1().data()); + SMESHGUI::GetSMESHGen()->SetName(theSObject->GetIOR().c_str(), theName.toLatin1().data()); } void SetValue (_PTR(SObject) theSObject, const QString& theValue) @@ -305,4 +306,35 @@ namespace SMESH arg(theHelpFileName)); } } + + //======================================================================= + /** + Return normale to a given face + */ + //======================================================================= + gp_XYZ getNormale( const SMDS_MeshFace* theFace ) + { + gp_XYZ n; + int aNbNode = theFace->NbNodes(); + TColgp_Array1OfXYZ anArrOfXYZ(1,4); + SMDS_ElemIteratorPtr aNodeItr = theFace->nodesIterator(); + int i = 1; + for ( ; aNodeItr->more() && i <= 4; i++ ) { + SMDS_MeshNode* aNode = (SMDS_MeshNode*)aNodeItr->next(); + anArrOfXYZ.SetValue(i, gp_XYZ( aNode->X(), aNode->Y(), aNode->Z() ) ); + } + + gp_XYZ q1 = anArrOfXYZ.Value(2) - anArrOfXYZ.Value(1); + gp_XYZ q2 = anArrOfXYZ.Value(3) - anArrOfXYZ.Value(1); + n = q1 ^ q2; + if ( aNbNode > 3 ) { + gp_XYZ q3 = anArrOfXYZ.Value(4) - anArrOfXYZ.Value(1); + n += q2 ^ q3; + } + double len = n.Modulus(); + if ( len > 0 ) + n /= len; + return n; + } + } // end of namespace SMESH diff --git a/src/SMESHGUI/SMESHGUI_Utils.h b/src/SMESHGUI/SMESHGUI_Utils.h index f534da8f7..77f26e3e1 100644 --- a/src/SMESHGUI/SMESHGUI_Utils.h +++ b/src/SMESHGUI/SMESHGUI_Utils.h @@ -39,6 +39,9 @@ #include #include +//OCC includes +#include + class SUIT_ViewWindow; class SUIT_Desktop; class SUIT_Study; @@ -53,6 +56,8 @@ class SalomeApp_Study; class SalomeApp_Module; class LightApp_SelectionMgr; +class SMDS_MeshFace; + namespace SMESH { SMESHGUI_EXPORT @@ -158,6 +163,15 @@ SMESHGUI_EXPORT SMESHGUI_EXPORT void ShowHelpFile( const QString& ); + + /*! + * \brief Return the normal to a face + * \param theFace - input face + * \retval gp_XYZ - normal to a face + */ +SMESHGUI_EXPORT + gp_XYZ getNormale( const SMDS_MeshFace* theFace ); + } #endif // SMESHGUI_UTILS_H diff --git a/src/SMESHGUI/SMESH_images.ts b/src/SMESHGUI/SMESH_images.ts index 910dea132..0319ce689 100644 --- a/src/SMESHGUI/SMESH_images.ts +++ b/src/SMESHGUI/SMESH_images.ts @@ -57,6 +57,10 @@ ICON_COMPUTE mesh_compute.png + + ICON_PRECOMPUTE + mesh_precompute.png + ICON_CONNECTION mesh_multi_edges.png @@ -237,10 +241,18 @@ ICON_FREE_EDGE mesh_free_edges.png - + ICON_FREE_EDGE_2D mesh_free_edges_2d.png + + ICON_FREE_NODE + mesh_free_nodes.png + + + ICON_FREE_FACES + mesh_free_faces.png + ICON_HYPO mesh_hypo_length.png @@ -425,5 +437,9 @@ ICON_CLEAR_MESH mesh_clear.png + + ICON_UNDERLYING_ELEMS + mesh_extractGroup.png + diff --git a/src/SMESHGUI/SMESH_msg_en.ts b/src/SMESHGUI/SMESH_msg_en.ts index 6f78f00e4..3b17d35f9 100644 --- a/src/SMESHGUI/SMESH_msg_en.ts +++ b/src/SMESHGUI/SMESH_msg_en.ts @@ -177,6 +177,10 @@ MEN_COMPUTE Compute + + MEN_PRECOMPUTE + Preview + MEN_CONNECTION Borders at Multi-Connection @@ -269,6 +273,10 @@ MEN_EDIT_GROUP Edit Group + + MEN_EDIT_GEOMGROUP_AS_GROUP + Edit Group as Standalone + MEN_EDIT_HYPO Edit Hypothesis @@ -321,6 +329,14 @@ MEN_FREE_EDGE Free Edges + + MEN_FREE_NODE + Free Nodes + + + MEN_FREE_FACES + Free Faces + MEN_GLOBAL_HYPO Global Hypothesis @@ -609,6 +625,10 @@ MEN_UN_GROUP Union Groups + + MEN_UNDERLYING_ELEMS + Group of underlying entities + MEN_UPDATE Update @@ -1035,6 +1055,10 @@ so that the application may crash. Do you wish to continue visualization?SMESH_EDIT_GROUP_TITLE Edit Group + + SMESH_EDIT_GEOMGROUP_AS_GROUP_TITLE + Edit Group as Standalone + SMESH_EDIT_HYPOTHESES Hypotheses Assignation @@ -1935,6 +1959,10 @@ Consider saving your work before application crash STB_COMPUTE Compute + + STB_PRECOMPUTE + Preview + STB_CONNECTION Borders at Multi-Connection @@ -2015,6 +2043,10 @@ Consider saving your work before application crash STB_EDIT_GROUP Edit Group + + STB_EDIT_GEOMGROUP_AS_GROUP + Edit Group as Standalone + STB_EDIT_HYPO Edit Hypothesis @@ -2059,6 +2091,16 @@ Consider saving your work before application crash STB_FREE_EDGE Free Edges + + STB_FREE_NODE + Free Nodes + + + + + STB_FREE_FACES + Free Faces + STB_GLOBAL_HYPO Global Hypothesis @@ -2299,6 +2341,10 @@ Consider saving your work before application crash STB_UN_GROUP Union Groups + + STB_UNDERLYING_ELEMS + Create groups of entities from existing groups of superior dimensions + STB_UPDATE Update @@ -2395,6 +2441,10 @@ Consider saving your work before application crash TOP_COMPUTE Compute + + TOP_PRECOMPUTE + Preview + TOP_CONNECTION Borders at Multi-Connection @@ -2475,6 +2525,10 @@ Consider saving your work before application crash TOP_EDIT_GROUP Edit Group + + TOP_EDIT_GEOMGROUP_AS_GROUP + Edit Group as Standalone + TOP_EDIT_HYPO Edit Hypothesis @@ -2519,6 +2573,16 @@ Consider saving your work before application crash TOP_FREE_EDGE Free Edges + + TOP_FREE_NODE + Free Nodes + + + + + TOP_FREE_FACES + Free Faces + TOP_GLOBAL_HYPO Global Hypothesis @@ -2759,6 +2823,10 @@ Consider saving your work before application crash TOP_UN_GROUP Union Groups + + TOP_UNDERLYING_ELEMS + Create groups of entities from existing groups of superior dimensions + TOP_UPDATE Update @@ -2843,6 +2911,14 @@ Please, create VTK viewer and try again PREF_AUTO_GROUPS Automatically create groups for MED export + + PREF_GROUP_SEGMENT_LENGTH + Segment length + + + PREF_SEGMENT_LENGTH + Segmentation of diagonal of boundary box of geometry + PREF_AUTO_UPDATE Automatic update @@ -3120,6 +3196,38 @@ Please, create VTK viewer and try again Show bad Mesh + + SMESHGUI_PrecomputeDlg + + CAPTION + Preview and Compute mesh + + + PREVIEW + Preview + + + PREVIEW_1 + 1D Mesh + + + PREVIEW_2 + 2D Mesh + + + COMPUTE + Compute + + + + SMESHGUI_PrecomputeOp + + CLEAR_SUBMESH_QUESTION + A temporary submeshes on the selected geometry + created during preview operation. + Do you want to remove all this submeshes? + + SMESHGUI_ConvToQuadDlg @@ -3395,8 +3503,8 @@ Please select a groups and try again Please select valid object and try again - CURRENT_GROUP - Current Group + CURRENT_DIALOG + Current Dialog EDGES_TLT @@ -3685,6 +3793,16 @@ Please enter correct value and try again FREE_EDGES Free edges + + FREE_NODES + Free nodes + + + + + FREE_FACES + Free faces + ID ID @@ -3697,6 +3815,10 @@ Please enter correct value and try again LENGTH Length + + LENGTH2D + Length 2D + LESS_THAN Less than @@ -3716,6 +3838,11 @@ Please enter correct value and try again MULTIEDGES_ERROR Threshold value of borders at multi-connections can not be equal 1 +Please enter correct value and try again + + + GROUPCOLOR_ERROR + Color of group can not be undefied Please enter correct value and try again @@ -3770,6 +3897,66 @@ Please enter correct value and try again WARPING Warping + + LINEAR + Linear + + + GROUP_COLOR + Color of Group + + + ELEMENTS + Elements + + + GEOM_TYPE + Geomtry type + + + GEOM_TYPE_0 + + + + GEOM_TYPE_0 + Point + + + GEOM_TYPE_1 + Edge + + + GEOM_TYPE_2 + Triangle + + + GEOM_TYPE_3 + Quadrangle + + + GEOM_TYPE_4 + Polygon + + + GEOM_TYPE_5 + Tetrahedron + + + GEOM_TYPE_6 + Pyramid + + + GEOM_TYPE_7 + Hexahedron + + + GEOM_TYPE_8 + Pentahedron + + + GEOM_TYPE_9 + Polyhedra + SMESHGUI_GroupOpDlg @@ -3777,10 +3964,6 @@ Please enter correct value and try again ARGUMENTS Arguments - - CUT_OF_TWO_GROUPS - Cut of two groups - DIFF_MESHES Arguments of operation are not correctly specified @@ -3803,14 +3986,6 @@ Please specify non-empty name and try again Arguments of operation are not specified Please specify them and try again - - INTERSECTION_OF_TWO_GROUPS - Intersection of two groups - - - MAIN_OBJECT - Main object - NAME Name @@ -3836,6 +4011,62 @@ Please specify them and try again Union of two groups + + SMESHGUI_UnionGroupsDlg + + UNION_OF_GROUPS + Union of groups + + + + SMESHGUI_DimGroupDlg + + CREATE_GROUP_OF_UNDERLYING_ELEMS + Create group of underlying entities + + + ELEMENTS_TYPE + Elements type + + + NODE + Node + + + EDGE + Edge + + + FACE + Face + + + VOLUME + Volume + + + + SMESHGUI_IntersectGroupsDlg + + INTERSECTION_OF_GROUPS + Intersection of groups + + + + SMESHGUI_CutGroupsDlg + + CUT_OF_GROUPS + Cut of groups + + + MAIN_OBJECT + Main object + + + TOOL_OBJECT + Tool object + + SMESHGUI_MakeNodeAtPointDlg @@ -4251,6 +4482,14 @@ It is impossible to read point coordinates from file TOTAL_ANGLE Total Angle + + MEN_POINT_SELECT + Select Point + + + MEN_FACE_SELECT + Select Plane + SMESHGUI_SewingDlg diff --git a/src/SMESH_I/Makefile.am b/src/SMESH_I/Makefile.am index 243d207b0..35200fa1c 100644 --- a/src/SMESH_I/Makefile.am +++ b/src/SMESH_I/Makefile.am @@ -24,7 +24,6 @@ # Author : Paul RASCLE, EDF # Modified by : Alexander BORODIN (OCN) - autotools usage # Module : SMESH -# $Header$ # include $(top_srcdir)/adm_local/unix/make_common_starter.am @@ -120,6 +119,7 @@ libSMESHEngine_la_LDFLAGS = \ -lSalomeGenericObj \ $(MED_LDFLAGS) \ -lMEDWrapper_V2_2 \ + -lSalomeIDLMED \ $(CAS_LDPATH) \ -lTKCDF \ -lTKBO \ diff --git a/src/SMESH_I/SMESH_2smeshpy.cxx b/src/SMESH_I/SMESH_2smeshpy.cxx index 4340ab41b..0a7e57e86 100644 --- a/src/SMESH_I/SMESH_2smeshpy.cxx +++ b/src/SMESH_I/SMESH_2smeshpy.cxx @@ -20,11 +20,7 @@ // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // // SMESH SMESH_I : idl implementation based on 'SMESH' unit's calsses -// File : SMESH_2D_Algo_i.hxx -// Author : Paul RASCLE, EDF -// Module : SMESH -// $Header$ - +// // File : SMESH_2smeshpy.cxx // Created : Fri Nov 18 13:20:10 2005 // Author : Edward AGAPOV (eap) @@ -45,8 +41,10 @@ IMPLEMENT_STANDARD_HANDLE (_pyObject ,Standard_Transient); IMPLEMENT_STANDARD_HANDLE (_pyCommand ,Standard_Transient); IMPLEMENT_STANDARD_HANDLE (_pyGen ,_pyObject); IMPLEMENT_STANDARD_HANDLE (_pyMesh ,_pyObject); +IMPLEMENT_STANDARD_HANDLE (_pySubMesh ,_pyObject); IMPLEMENT_STANDARD_HANDLE (_pyMeshEditor ,_pyObject); IMPLEMENT_STANDARD_HANDLE (_pyHypothesis ,_pyObject); +IMPLEMENT_STANDARD_HANDLE (_pyFilterManager ,_pyObject); IMPLEMENT_STANDARD_HANDLE (_pyAlgorithm ,_pyHypothesis); IMPLEMENT_STANDARD_HANDLE (_pyComplexParamHypo,_pyHypothesis); IMPLEMENT_STANDARD_HANDLE (_pyNumberOfSegmentsHyp,_pyHypothesis); @@ -55,8 +53,10 @@ IMPLEMENT_STANDARD_RTTIEXT(_pyObject ,Standard_Transient); IMPLEMENT_STANDARD_RTTIEXT(_pyCommand ,Standard_Transient); IMPLEMENT_STANDARD_RTTIEXT(_pyGen ,_pyObject); IMPLEMENT_STANDARD_RTTIEXT(_pyMesh ,_pyObject); +IMPLEMENT_STANDARD_RTTIEXT(_pySubMesh ,_pyObject); IMPLEMENT_STANDARD_RTTIEXT(_pyMeshEditor ,_pyObject); IMPLEMENT_STANDARD_RTTIEXT(_pyHypothesis ,_pyObject); +IMPLEMENT_STANDARD_RTTIEXT(_pyFilterManager ,_pyObject); IMPLEMENT_STANDARD_RTTIEXT(_pyAlgorithm ,_pyHypothesis); IMPLEMENT_STANDARD_RTTIEXT(_pyComplexParamHypo,_pyHypothesis); IMPLEMENT_STANDARD_RTTIEXT(_pyNumberOfSegmentsHyp,_pyHypothesis); @@ -119,9 +119,10 @@ namespace { TCollection_AsciiString SMESH_2smeshpy::ConvertScript(const TCollection_AsciiString& theScript, - Resource_DataMapOfAsciiStringAsciiString& theEntry2AccessorMethod) + Resource_DataMapOfAsciiStringAsciiString& theEntry2AccessorMethod, + Resource_DataMapOfAsciiStringAsciiString& theObjectNames) { - theGen = new _pyGen( theEntry2AccessorMethod ); + theGen = new _pyGen( theEntry2AccessorMethod, theObjectNames ); // split theScript into separate commands int from = 1, end = theScript.Length(), to; @@ -132,11 +133,13 @@ SMESH_2smeshpy::ConvertScript(const TCollection_AsciiString& theScript, theGen->AddCommand( theScript.SubString( from, to - 1 )); from = to + 1; } + // finish conversion theGen->Flush(); #ifdef DUMP_CONVERSION MESSAGE_BEGIN ( std::endl << " ######## RESULT ######## " << std::endl<< std::endl ); #endif + // reorder commands after conversion list< Handle(_pyCommand) >::iterator cmd; bool orderChanges; @@ -172,9 +175,11 @@ SMESH_2smeshpy::ConvertScript(const TCollection_AsciiString& theScript, */ //================================================================================ -_pyGen::_pyGen(Resource_DataMapOfAsciiStringAsciiString& theEntry2AccessorMethod) +_pyGen::_pyGen(Resource_DataMapOfAsciiStringAsciiString& theEntry2AccessorMethod, + Resource_DataMapOfAsciiStringAsciiString& theObjectNames) : _pyObject( new _pyCommand( TPythonDump::SMESHGenName(), 0 )), - myID2AccessorMethod( theEntry2AccessorMethod ) + myID2AccessorMethod( theEntry2AccessorMethod ), + myObjectNames( theObjectNames ) { myNbCommands = 0; myHasPattern = false; @@ -220,18 +225,43 @@ Handle(_pyCommand) _pyGen::AddCommand( const TCollection_AsciiString& theCommand this->Process( aCommand ); return aCommand; } + + // SMESH_subMesh method? + map< _pyID, Handle(_pySubMesh) >::iterator id_subMesh = mySubMeshes.find( objID ); + if ( id_subMesh != mySubMeshes.end() ) { + id_subMesh->second->Process( aCommand ); + return aCommand; + } + // SMESH_Mesh method? map< _pyID, Handle(_pyMesh) >::iterator id_mesh = myMeshes.find( objID ); if ( id_mesh != myMeshes.end() ) { + // check for mesh editor object if ( aCommand->GetMethod() == "GetMeshEditor" ) { // MeshEditor creation _pyID editorID = aCommand->GetResultValue(); Handle(_pyMeshEditor) editor = new _pyMeshEditor( aCommand ); myMeshEditors.insert( make_pair( editorID, editor )); return aCommand; + } + // check for SubMesh objects + else if ( aCommand->GetMethod() == "GetSubMesh" ) { // SubMesh creation + _pyID subMeshID = aCommand->GetResultValue(); + Handle(_pySubMesh) subMesh = new _pySubMesh( aCommand ); + mySubMeshes.insert( make_pair( subMeshID, subMesh )); } id_mesh->second->Process( aCommand ); return aCommand; } + + //SMESH_FilterManager method? + if ( theCommand.Search( "aFilterManager" ) != -1 ) { + if ( theCommand.Search( "CreateFilterManager" ) != -1 ) + myFilterManager = new _pyFilterManager( aCommand ); + else if ( !myFilterManager.IsNull() ) + myFilterManager->Process( aCommand ); + return aCommand; + } + // SMESH_MeshEditor method? map< _pyID, Handle(_pyMeshEditor) >::iterator id_editor = myMeshEditors.find( objID ); if ( id_editor != myMeshEditors.end() ) { @@ -296,6 +326,7 @@ void _pyGen::Process( const Handle(_pyCommand)& theCommand ) // Compute( mesh, geom ) // mesh creation TCollection_AsciiString method = theCommand->GetMethod(); + if ( method == "CreateMesh" || method == "CreateEmptyMesh") { Handle(_pyMesh) mesh = new _pyMesh( theCommand ); @@ -320,6 +351,15 @@ void _pyGen::Process( const Handle(_pyCommand)& theCommand ) // CreateHypothesis() if ( method == "CreateHypothesis" ) { + // issue 199929, remove standard library name (default parameter) + const TCollection_AsciiString & aLibName = theCommand->GetArg( 2 ); + if ( aLibName.Search( "StdMeshersEngine" ) != -1 ) { + // keep first argument + TCollection_AsciiString arg = theCommand->GetArg( 1 ); + theCommand->RemoveArgs(); + theCommand->SetArg( 1, arg ); + } + myHypos.push_back( _pyHypothesis::NewHypothesis( theCommand )); return; } @@ -385,6 +425,12 @@ void _pyGen::Process( const Handle(_pyCommand)& theCommand ) void _pyGen::Flush() { + // create empty command + myLastCommand = new _pyCommand(); + + if ( !myFilterManager.IsNull() ) + myFilterManager->Flush(); + map< _pyID, Handle(_pyMesh) >::iterator id_mesh = myMeshes.begin(); for ( ; id_mesh != myMeshes.end(); ++id_mesh ) if ( ! id_mesh->second.IsNull() ) @@ -398,6 +444,14 @@ void _pyGen::Flush() if ( !(*hyp)->IsWrapped() ) (*hyp)->GetCreationCmd()->SetObject( SMESH_2smeshpy::GenName() ); } + + map< _pyID, Handle(_pySubMesh) >::iterator id_subMesh = mySubMeshes.begin(); + for ( ; id_subMesh != mySubMeshes.end(); ++id_subMesh ) + if ( ! id_subMesh->second.IsNull() ) + id_subMesh->second->Flush(); + + myLastCommand->SetOrderNb( ++myNbCommands ); + myCommands.push_back( myLastCommand ); } //================================================================================ @@ -474,12 +528,32 @@ Handle(_pyHypothesis) _pyGen::FindAlgo( const _pyID& theGeom, const _pyID& theMe if ( !hyp->IsNull() && (*hyp)->IsAlgo() && theHypothesis->CanBeCreatedBy( (*hyp)->GetAlgoType() ) && - (*hyp)->GetGeom() == theGeom && + (*hyp)->GetGeom() == theGeom && (*hyp)->GetMesh() == theMesh ) return *hyp; return 0; } +//================================================================================ +/*! + * \brief Find subMesh by ID (entry) + * \param theSubMeshID - The subMesh ID + * \retval Handle(_pySubMesh) - The found subMesh + */ +//================================================================================ + +Handle(_pySubMesh) _pyGen::FindSubMesh( const _pyID& theSubMeshID ) +{ + map< _pyID, Handle(_pySubMesh) >::iterator id_subMesh = mySubMeshes.begin(); + for ( ; id_subMesh != mySubMeshes.end(); ++id_subMesh ) { + Handle(_pySubMesh) sm = id_subMesh->second; + if ( !id_subMesh->second.IsNull() && theSubMeshID == id_subMesh->second->GetID() ) + return sm; + } + return Handle(_pySubMesh)(); +} + + //================================================================================ /*! * \brief Change order of commands in the script @@ -515,20 +589,57 @@ void _pyGen::ExchangeCommands( Handle(_pyCommand) theCmd1, Handle(_pyCommand) th void _pyGen::SetCommandAfter( Handle(_pyCommand) theCmd, Handle(_pyCommand) theAfterCmd ) { -#ifdef _DEBUG_ -//cout << "SET\t" << theAfterCmd->GetString() << endl << "BEFORE\t" << theCmd->GetString() << endl<::iterator pos; pos = find( myCommands.begin(), myCommands.end(), theCmd ); myCommands.erase( pos ); - pos = find( myCommands.begin(), myCommands.end(), theAfterCmd ); - myCommands.insert( ++pos, theCmd ); + pos = find( myCommands.begin(), myCommands.end(), theOtherCmd ); + myCommands.insert( (theIsAfter ? ++pos : pos), theCmd ); int i = 1; for ( pos = myCommands.begin(); pos != myCommands.end(); ++pos) (*pos)->SetOrderNb( i++ ); } +//================================================================================ +/*! + * \brief Set command be last in list of commands + * \param theCmd - Command to be last + */ +//================================================================================ + +Handle(_pyCommand)& _pyGen::GetLastCommand() +{ + return myLastCommand; +} + //================================================================================ /*! * \brief Set method to access to object wrapped with python class @@ -542,6 +653,28 @@ void _pyGen::SetAccessorMethod(const _pyID& theID, const char* theMethod ) myID2AccessorMethod.Bind( theID, (char*) theMethod ); } +//================================================================================ +/*! + * \brief Generated new ID for object and assign with existing name + * \param theID - ID of existing object + */ +//================================================================================ + +_pyID _pyGen::GenerateNewID( const _pyID& theID ) +{ + int index = 1; + _pyID aNewID; + do { + aNewID = theID + _pyID( ":" ) + _pyID( index++ ); + } + while ( myObjectNames.IsBound( aNewID ) ); + + myObjectNames.Bind( aNewID, myObjectNames.IsBound( theID ) + ? (myObjectNames.Find( theID ) + _pyID( "_" ) + _pyID( index-1 )) + : _pyID( "A" ) + aNewID ); + return aNewID; +} + //================================================================================ /*! * \brief Find out type of geom group @@ -665,7 +798,11 @@ void _pyMesh::Process( const Handle(_pyCommand)& theCommand ) const TCollection_AsciiString method = theCommand->GetMethod(); // ---------------------------------------------------------------------- if ( method == "GetSubMesh" ) { - mySubmeshes.push_back( theCommand ); + Handle(_pySubMesh) subMesh = theGen->FindSubMesh( theCommand->GetResultValue() ); + if ( !subMesh.IsNull() ) { + subMesh->SetCreator( this ); + mySubmeshes.push_back( subMesh ); + } } // ---------------------------------------------------------------------- else if ( method == "AddHypothesis" ) { // mesh.AddHypothesis(geom, HYPO ) @@ -688,7 +825,13 @@ void _pyMesh::Process( const Handle(_pyCommand)& theCommand ) theCommand->SetArg( 1, grp ); } else { - AddMeshAccess( theCommand ); + _pyID type = theCommand->GetArg( 1 ); + _pyID name = theCommand->GetArg( 2 ); + theCommand->SetMethod( "GroupOnGeom" ); + theCommand->RemoveArgs(); + theCommand->SetArg( 1, grp ); + theCommand->SetArg( 2, name ); + theCommand->SetArg( 3, type ); } } // ---------------------------------------------------------------------- @@ -766,7 +909,7 @@ bool _pyMesh::NeedMeshAccess( const Handle(_pyCommand)& theCommand ) "GetNodeInverseElements","GetShapeID","GetShapeIDForElem","GetElemNbNodes", "GetElemNode","IsMediumNode","IsMediumNodeOfAnyElem","ElemNbEdges","ElemNbFaces", "IsPoly","IsQuadratic","BaryCenter","GetHypothesisList", "SetAutoColor", "GetAutoColor", - "Clear" + "Clear", "ConvertToStandalone" ,"" }; // <- mark of end sameMethods.Insert( names ); } @@ -782,20 +925,43 @@ bool _pyMesh::NeedMeshAccess( const Handle(_pyCommand)& theCommand ) void _pyMesh::Flush() { - list < Handle(_pyCommand) >::iterator cmd, cmd2; + list < Handle(_pyCommand) >::iterator cmd; // try to convert algo addition like this: // mesh.AddHypothesis(geom, ALGO ) --> ALGO = mesh.Algo() for ( cmd = myAddHypCmds.begin(); cmd != myAddHypCmds.end(); ++cmd ) { Handle(_pyCommand) addCmd = *cmd; + _pyID algoID = addCmd->GetArg( 2 ); Handle(_pyHypothesis) algo = theGen->FindHyp( algoID ); if ( algo.IsNull() || !algo->IsAlgo() ) continue; - // try to convert + + // check and create new algorithm instance if it is already wrapped + if ( algo->IsWrapped() ) { + _pyID localAlgoID = theGen->GenerateNewID( algoID ); + TCollection_AsciiString aNewCmdStr = localAlgoID + + TCollection_AsciiString( " = " ) + theGen->GetID() + + TCollection_AsciiString( ".CreateHypothesis( \"" ) + algo->GetAlgoType() + + TCollection_AsciiString( "\" )" ); + + Handle(_pyCommand) newCmd = theGen->AddCommand( aNewCmdStr ); + Handle(_pyAlgorithm) newAlgo = Handle(_pyAlgorithm)::DownCast(theGen->FindHyp( localAlgoID )); + if ( !newAlgo.IsNull() ) { + newAlgo->Assign( algo, this->GetID() ); + newAlgo->SetCreationCmd( newCmd ); + algo = newAlgo; + // set algorithm creation + theGen->SetCommandBefore( newCmd, addCmd ); + } + else + newCmd->Clear(); + } _pyID geom = addCmd->GetArg( 1 ); bool isLocalAlgo = ( geom != GetGeom() ); + + // try to convert if ( algo->Addition2Creation( addCmd, this->GetID() )) // OK { // wrapped algo is created atfer mesh creation @@ -806,12 +972,14 @@ void _pyMesh::Flush() addCmd->SetArg( addCmd->GetNbArgs() + 1, TCollection_AsciiString( "geom=" ) + geom ); // sm = mesh.GetSubMesh(geom, name) --> sm = ALGO.GetSubMesh() - for ( cmd2 = mySubmeshes.begin(); cmd2 != mySubmeshes.end(); ++cmd2 ) { - Handle(_pyCommand) subCmd = *cmd2; + list < Handle(_pySubMesh) >::iterator smIt; + for ( smIt = mySubmeshes.begin(); smIt != mySubmeshes.end(); ++smIt ) { + Handle(_pySubMesh) subMesh = *smIt; + Handle(_pyCommand) subCmd = subMesh->GetCreationCmd(); if ( geom == subCmd->GetArg( 1 )) { subCmd->SetObject( algo->GetID() ); subCmd->RemoveArgs(); - addCmd->AddDependantCmd( subCmd ); + subMesh->SetCreator( algo ); } } } @@ -1014,6 +1182,13 @@ Handle(_pyHypothesis) _pyHypothesis::NewHypothesis( const Handle(_pyCommand)& th // i.e. convertion result will be "locallength = regular1d.LocalLength()" hyp->AddArgMethod( "SetLength" ); } + else if ( hypType == "MaxLength" ) { + // set algo's method creating hyp, and algo type + hyp->SetConvMethodAndType( "MaxSize", "Regular_1D"); + // set method whose 1 arg will become the 1-st arg of hyp creation command + // i.e. convertion result will be "maxsize = regular1d.MaxSize()" + hyp->AddArgMethod( "SetLength" ); + } else if ( hypType == "NumberOfSegments" ) { hyp = new _pyNumberOfSegmentsHyp( theCreationCmd ); hyp->SetConvMethodAndType( "NumberOfSegments", "Regular_1D"); @@ -1188,6 +1363,8 @@ bool _pyHypothesis::Addition2Creation( const Handle(_pyCommand)& theCmd, algo = theGen->FindAlgo( myGeom, theMesh, this ); if ( algo.IsNull() ) return false; + // attach hypothesis creation command to be after algo creation command + // because it can be new created instance of algorithm algo->GetCreationCmd()->AddDependantCmd( theCmd ); } myIsWrapped = true; @@ -1206,7 +1383,10 @@ bool _pyHypothesis::Addition2Creation( const Handle(_pyCommand)& theCmd, } // set a new creation command GetCreationCmd()->Clear(); + // replace creation command by wrapped instance + // please note, that hypothesis attaches to algo creation command (see upper) SetCreationCmd( theCmd ); + // clear commands setting arg values list < Handle(_pyCommand) >::iterator argCmd = myArgCommands.begin(); @@ -1297,6 +1477,30 @@ void _pyHypothesis::ClearAllCommands() ( *cmd )->Clear(); } + +//================================================================================ +/*! + * \brief Assign fields of theOther to me except myIsWrapped + */ +//================================================================================ + +void _pyHypothesis::Assign( const Handle(_pyHypothesis)& theOther, + const _pyID& theMesh ) +{ + myIsWrapped = false; + myMesh = theMesh; + + // myCreationCmd = theOther->myCreationCmd; + myIsAlgo = theOther->myIsAlgo; + myGeom = theOther->myGeom; + myType2CreationMethod = theOther->myType2CreationMethod; + myArgs = theOther->myArgs; + myArgMethods = theOther->myArgMethods; + myNbArgsByMethod = theOther->myNbArgsByMethod; + myArgCommands = theOther->myArgCommands; + myUnknownCommands = theOther->myUnknownCommands; +} + //================================================================================ /*! * \brief Remember hypothesis parameter values @@ -1386,9 +1590,9 @@ void _pyLayerDistributionHypo::Process( const Handle(_pyCommand)& theCommand) //================================================================================ /*! * \brief - * \param theAdditionCmd - - * \param theMesh - - * \retval bool - + * \param theAdditionCmd - command to be converted + * \param theMesh - mesh instance + * \retval bool - status */ //================================================================================ @@ -2071,3 +2275,78 @@ _pyID _pyObject::FatherID(const _pyID & childID) return childID.SubString( 1, colPos-1 ); return ""; } + +//================================================================================ +/*! + * \brief FilterManager creates only if at least one command invoked + */ +//================================================================================ + +_pyFilterManager::_pyFilterManager(const Handle(_pyCommand)& theCreationCmd): + _pyObject( theCreationCmd ), + myCmdCount( 0 ) +{ +} + +//================================================================================ +/*! + * \brief count invoked commands + */ +//================================================================================ + +void _pyFilterManager::Process( const Handle(_pyCommand)& /*theCommand*/) +{ + myCmdCount++; +} + +//================================================================================ +/*! + * \brief Clear creatin command if no commands invoked + */ +//================================================================================ + +void _pyFilterManager::Flush() +{ + if ( !myCmdCount ) + GetCreationCmd()->Clear(); +} + + +//================================================================================ +/*! + * \brief SubMesh creation can be moved to the end of engine commands + */ +//================================================================================ + +_pySubMesh::_pySubMesh(const Handle(_pyCommand)& theCreationCmd): + _pyObject( theCreationCmd ), + myCmdCount( 0 ) +{ +} + +//================================================================================ +/*! + * \brief count invoked commands + */ +//================================================================================ + +void _pySubMesh::Process( const Handle(_pyCommand)& theCommand ) +{ + myCmdCount++; + GetCreationCmd()->AddDependantCmd( theCommand ); +} + +//================================================================================ +/*! + * \brief Clear creatin command if no commands invoked + */ +//================================================================================ + +void _pySubMesh::Flush() +{ + if ( !myCmdCount ) // move to the end of all commands + theGen->GetLastCommand()->AddDependantCmd( GetCreationCmd() ); + else if ( !myCreator.IsNull() ) + // move to be just after creator + myCreator->GetCreationCmd()->AddDependantCmd( GetCreationCmd() ); +} diff --git a/src/SMESH_I/SMESH_2smeshpy.hxx b/src/SMESH_I/SMESH_2smeshpy.hxx index bbe368e72..eac87deca 100644 --- a/src/SMESH_I/SMESH_2smeshpy.hxx +++ b/src/SMESH_I/SMESH_2smeshpy.hxx @@ -65,15 +65,19 @@ class _pyCommand; class _pyObject; class _pyGen; class _pyMesh; +class _pySubMesh; class _pyHypothesis; class _pyAlgorithm; +class _pyFilterManager; DEFINE_STANDARD_HANDLE (_pyCommand ,Standard_Transient); DEFINE_STANDARD_HANDLE (_pyObject ,Standard_Transient); DEFINE_STANDARD_HANDLE (_pyGen ,_pyObject); DEFINE_STANDARD_HANDLE (_pyMesh ,_pyObject); +DEFINE_STANDARD_HANDLE (_pySubMesh ,_pyObject); DEFINE_STANDARD_HANDLE (_pyMeshEditor,_pyObject); DEFINE_STANDARD_HANDLE (_pyHypothesis,_pyObject); +DEFINE_STANDARD_HANDLE (_pyFilterManager,_pyObject); DEFINE_STANDARD_HANDLE (_pyAlgorithm ,_pyHypothesis); typedef TCollection_AsciiString _pyID; @@ -173,7 +177,8 @@ public: class _pyGen: public _pyObject { public: - _pyGen(Resource_DataMapOfAsciiStringAsciiString& theEntry2AccessorMethod); + _pyGen(Resource_DataMapOfAsciiStringAsciiString& theEntry2AccessorMethod, + Resource_DataMapOfAsciiStringAsciiString& theObjectNames); //~_pyGen(); Handle(_pyCommand) AddCommand( const TCollection_AsciiString& theCommand ); void Process( const Handle(_pyCommand)& theCommand ); @@ -181,21 +186,35 @@ public: Handle(_pyHypothesis) FindHyp( const _pyID& theHypID ); Handle(_pyHypothesis) FindAlgo( const _pyID& theGeom, const _pyID& theMesh, const Handle(_pyHypothesis)& theHypothesis); + Handle(_pySubMesh) FindSubMesh( const _pyID& theSubMeshID ); void ExchangeCommands( Handle(_pyCommand) theCmd1, Handle(_pyCommand) theCmd2 ); void SetCommandAfter( Handle(_pyCommand) theCmd, Handle(_pyCommand) theAfterCmd ); + void SetCommandBefore( Handle(_pyCommand) theCmd, Handle(_pyCommand) theBeforeCmd ); + Handle(_pyCommand)& GetLastCommand(); std::list< Handle(_pyCommand) >& GetCommands() { return myCommands; } void SetAccessorMethod(const _pyID& theID, const char* theMethod ); bool AddMeshAccessorMethod( Handle(_pyCommand) theCmd ) const; bool AddAlgoAccessorMethod( Handle(_pyCommand) theCmd ) const; const char* AccessorMethod() const; + _pyID GenerateNewID( const _pyID& theID ); + +private: + void setNeighbourCommand( Handle(_pyCommand)& theCmd, + Handle(_pyCommand)& theOtherCmd, + const bool theIsAfter ); + private: std::map< _pyID, Handle(_pyMesh) > myMeshes; + std::map< _pyID, Handle(_pySubMesh) > mySubMeshes; std::map< _pyID, Handle(_pyMeshEditor) > myMeshEditors; std::list< Handle(_pyHypothesis) > myHypos; std::list< Handle(_pyCommand) > myCommands; int myNbCommands; bool myHasPattern; Resource_DataMapOfAsciiStringAsciiString& myID2AccessorMethod; + Resource_DataMapOfAsciiStringAsciiString& myObjectNames; + Handle(_pyCommand) myLastCommand; + Handle(_pyFilterManager) myFilterManager; DEFINE_STANDARD_RTTI (_pyGen) }; @@ -210,7 +229,7 @@ class _pyMesh: public _pyObject { std::list< Handle(_pyHypothesis) > myHypos; std::list< Handle(_pyCommand) > myAddHypCmds; - std::list< Handle(_pyCommand) > mySubmeshes; + std::list< Handle(_pySubMesh) > mySubmeshes; bool myHasEditor; public: _pyMesh(const Handle(_pyCommand) creationCmd); @@ -299,12 +318,14 @@ public: { return myType2CreationMethod.find( algoType ) != myType2CreationMethod.end(); } const TCollection_AsciiString& GetCreationMethod(const TCollection_AsciiString& algoType) const { return myType2CreationMethod.find( algoType )->second; } - bool IsWrappable(const _pyID& theMesh) { return !myIsWrapped && myMesh == theMesh; } + virtual bool IsWrappable(const _pyID& theMesh) { return !myIsWrapped && myMesh == theMesh; } virtual bool Addition2Creation( const Handle(_pyCommand)& theAdditionCmd, const _pyID& theMesh); static Handle(_pyHypothesis) NewHypothesis( const Handle(_pyCommand)& theCreationCmd); void Process( const Handle(_pyCommand)& theCommand); void Flush(); + virtual void Assign( const Handle(_pyHypothesis)& theOther, + const _pyID& theMesh ); DEFINE_STANDARD_RTTI (_pyHypothesis) }; @@ -321,6 +342,7 @@ public: virtual bool Addition2Creation( const Handle(_pyCommand)& theAdditionCmd, const _pyID& theMesh); const char* AccessorMethod() const { return "GetAlgorithm()"; } + virtual bool IsWrappable(const _pyID& theMesh) { return !myIsWrapped; } DEFINE_STANDARD_RTTI (_pyAlgorithm) }; @@ -392,4 +414,40 @@ public: }; DEFINE_STANDARD_HANDLE (_pySegmentLengthAroundVertexHyp, _pyHypothesis); +// ------------------------------------------------------------------------------------- +/*! + * \brief FilterManager creates only if at least one command invoked + */ +// ------------------------------------------------------------------------------------- +class _pyFilterManager: public _pyObject +{ +public: + _pyFilterManager(const Handle(_pyCommand)& theCreationCmd); + void Process( const Handle(_pyCommand)& theCommand); + virtual void Flush(); + + DEFINE_STANDARD_RTTI (_pyFilterManager) +private: + int myCmdCount; +}; + +// ------------------------------------------------------------------------------------- +/*! + * \brief SubMesh creation can be moved to the end of engine commands + */ +// ------------------------------------------------------------------------------------- +class _pySubMesh: public _pyObject +{ +public: + _pySubMesh(const Handle(_pyCommand)& theCreationCmd); + void Process( const Handle(_pyCommand)& theCommand); + virtual void Flush(); + void SetCreator( const Handle(_pyObject)& theCreator ) { myCreator = theCreator; } + + DEFINE_STANDARD_RTTI (_pyFilterManager) +private: + int myCmdCount; + Handle(_pyObject) myCreator; +}; + #endif diff --git a/src/SMESH_I/SMESH_DumpPython.cxx b/src/SMESH_I/SMESH_DumpPython.cxx index e7a7a2952..ad409b786 100644 --- a/src/SMESH_I/SMESH_DumpPython.cxx +++ b/src/SMESH_I/SMESH_DumpPython.cxx @@ -61,10 +61,10 @@ namespace SMESH { if(--myCounter == 0){ SMESH_Gen_i* aSMESHGen = SMESH_Gen_i::GetSMESHGen(); + std::string aString = myStream.str(); + TCollection_AsciiString aCollection(Standard_CString(aString.c_str())); SALOMEDS::Study_ptr aStudy = aSMESHGen->GetCurrentStudy(); - if(!aStudy->_is_nil()){ - std::string aString = myStream.str(); - TCollection_AsciiString aCollection(Standard_CString(aString.c_str())); + if(!aStudy->_is_nil() && !aCollection.IsEmpty()){ aSMESHGen->AddToPythonScript(aStudy->StudyId(),aCollection); if(MYDEBUG) MESSAGE(aString); } @@ -226,6 +226,7 @@ namespace SMESH case FT_Area: myStream<< "aArea"; break; case FT_FreeBorders: myStream<< "aFreeBorders"; break; case FT_FreeEdges: myStream<< "aFreeEdges"; break; + case FT_FreeNodes: myStream<< "aFreeNodes"; break; case FT_MultiConnection: myStream<< "aMultiConnection"; break; case FT_MultiConnection2D:myStream<< "aMultiConnection2D";break; case FT_Length: myStream<< "aLength"; break; @@ -686,7 +687,7 @@ TCollection_AsciiString SMESH_Gen_i::DumpPython_impl // Some objects are wrapped with python classes and // Resource_DataMapOfAsciiStringAsciiString holds methods returning wrapped objects Resource_DataMapOfAsciiStringAsciiString anEntry2AccessorMethod; - aScript = SMESH_2smeshpy::ConvertScript( aScript, anEntry2AccessorMethod ); + aScript = SMESH_2smeshpy::ConvertScript( aScript, anEntry2AccessorMethod, theObjectNames ); // Find entries to be replaced by names Handle(TColStd_HSequenceOfInteger) aSeq = FindEntries(aScript); @@ -834,8 +835,6 @@ TCollection_AsciiString SMESH_Gen_i::DumpPython_impl // Set object names anUpdatedScript += "\n\t## set object names"; - anUpdatedScript += helper + " \n\tisGUIMode = " + isPublished; - anUpdatedScript += "\n\tif isGUIMode and salome.sg.hasDesktop():"; // anUpdatedScript += "\n\t\tsmeshgui = salome.ImportComponentGUI(\"SMESH\")"; // anUpdatedScript += "\n\t\tsmeshgui.Init(theStudy._get_StudyId())"; // anUpdatedScript += "\n"; @@ -854,13 +853,14 @@ TCollection_AsciiString SMESH_Gen_i::DumpPython_impl aName = theObjectNames.Find(anEntry); aGUIName = theNames.Find(anEntry); mapEntries.Bind(anEntry, aName); - anUpdatedScript += helper + "\n\t\t" + aSmeshpy + ".SetName(" + aName; + anUpdatedScript += helper + "\n\t" + aSMESHGen + ".SetName(" + aName; if ( anEntry2AccessorMethod.IsBound( anEntry ) ) anUpdatedScript += helper + "." + anEntry2AccessorMethod( anEntry ); anUpdatedScript += helper + ", '" + aGUIName + "')"; } } - anUpdatedScript += "\n\n\t\tsalome.sg.updateObjBrowser(0)"; + anUpdatedScript += "\n\tif salome.sg.hasDesktop():"; + anUpdatedScript += "\n\t\tsalome.sg.updateObjBrowser(0)"; // ----------------------------------------------------------------- // store visual properties of displayed objects @@ -876,7 +876,6 @@ TCollection_AsciiString SMESH_Gen_i::DumpPython_impl CORBA::string_free(script); } } - anUpdatedScript += "\n\n\tpass\n"; // ----------------------------------------------------------------- diff --git a/src/SMESH_I/SMESH_Filter_i.cxx b/src/SMESH_I/SMESH_Filter_i.cxx index 9c352a483..189e6cbcc 100644 --- a/src/SMESH_I/SMESH_Filter_i.cxx +++ b/src/SMESH_I/SMESH_Filter_i.cxx @@ -1281,6 +1281,36 @@ FunctorType FreeEdges_i::GetFunctorType() return SMESH::FT_FreeEdges; } +/* + Class : FreeFaces_i + Description : Predicate for free faces +*/ +FreeFaces_i::FreeFaces_i() +{ + myPredicatePtr.reset(new Controls::FreeFaces()); + myFunctorPtr = myPredicatePtr; +} + +FunctorType FreeFaces_i::GetFunctorType() +{ + return SMESH::FT_FreeFaces; +} + +/* + Class : FreeNodes_i + Description : Predicate for free nodes +*/ +FreeNodes_i::FreeNodes_i() +{ + myPredicatePtr.reset(new Controls::FreeNodes()); + myFunctorPtr = myPredicatePtr; +} + +FunctorType FreeNodes_i::GetFunctorType() +{ + return SMESH::FT_FreeNodes; +} + /* Class : RangeOfIds_i Description : Predicate for Range of Ids. @@ -1329,6 +1359,94 @@ FunctorType RangeOfIds_i::GetFunctorType() return SMESH::FT_RangeOfIds; } +/* + Class : LinearOrQuadratic_i + Description : Predicate to verify whether a mesh element is linear +*/ +LinearOrQuadratic_i::LinearOrQuadratic_i() +{ + myLinearOrQuadraticPtr.reset(new Controls::LinearOrQuadratic()); + myFunctorPtr = myPredicatePtr = myLinearOrQuadraticPtr; +} + +void LinearOrQuadratic_i::SetElementType(ElementType theType) +{ + myLinearOrQuadraticPtr->SetType(SMDSAbs_ElementType(theType)); + TPythonDump()<SetColorStr( + TCollection_AsciiString( (Standard_CString)theColor ) ); + TPythonDump()<GetColorStr( aStr ); + return CORBA::string_dup( aStr.ToCString() ); +} + +void GroupColor_i::SetElementType(ElementType theType) +{ + myGroupColorPtr->SetType(SMDSAbs_ElementType(theType)); + TPythonDump()<SetType(SMDSAbs_ElementType(theType)); + TPythonDump()<SetGeomType(SMDSAbs_GeometryType(theType)); + TPythonDump()<GetGeomType();; +} + +FunctorType ElemGeomType_i::GetFunctorType() +{ + return SMESH::FT_ElemGeomType; +} + /* Class : Comparator_i Description : Base class for comparators @@ -1761,6 +1879,22 @@ FreeEdges_ptr FilterManager_i::CreateFreeEdges() return anObj._retn(); } +FreeFaces_ptr FilterManager_i::CreateFreeFaces() +{ + SMESH::FreeFaces_i* aServant = new SMESH::FreeFaces_i(); + SMESH::FreeFaces_var anObj = aServant->_this(); + TPythonDump()<_this(); + TPythonDump()<_this(); + TPythonDump()<_this(); + TPythonDump()<_this(); + TPythonDump()<length(); theCriteria->length( i + 1 ); @@ -2141,6 +2298,33 @@ static inline bool getCriteria( Predicate_i* thePred, theCriteria[ theCriteria->length() - 1 ].BinaryOp = aFType; return getCriteria( aPred2, theCriteria ); } + case FT_GroupColor: + { + CORBA::ULong i = theCriteria->length(); + theCriteria->length( i + 1 ); + + theCriteria[ i ] = createCriterion(); + + GroupColor_i* aPred = dynamic_cast( thePred ); + theCriteria[ i ].Type = aFType; + theCriteria[ i ].TypeOfElement = aPred->GetElementType(); + theCriteria[ i ].ThresholdStr = aPred->GetColorStr(); + + return true; + } + case FT_ElemGeomType: + { + CORBA::ULong i = theCriteria->length(); + theCriteria->length( i + 1 ); + + theCriteria[ i ] = createCriterion(); + + ElemGeomType_i* aPred = dynamic_cast( thePred ); + theCriteria[ i ].Type = aFType; + theCriteria[ i ].TypeOfElement = aPred->GetElementType(); + theCriteria[ i ].Threshold = (double)aPred->GetGeometryType(); + return true; + } case FT_Undefined: return false; @@ -2255,6 +2439,12 @@ CORBA::Boolean Filter_i::SetCriteria( const SMESH::Filter::Criteria& theCriteria case SMESH::FT_FreeEdges: aPredicate = aFilterMgr->CreateFreeEdges(); break; + case SMESH::FT_FreeFaces: + aPredicate = aFilterMgr->CreateFreeFaces(); + break; + case SMESH::FT_FreeNodes: + aPredicate = aFilterMgr->CreateFreeNodes(); + break; case SMESH::FT_BelongToGeom: { SMESH::BelongToGeom_ptr tmpPred = aFilterMgr->CreateBelongToGeom(); @@ -2302,6 +2492,29 @@ CORBA::Boolean Filter_i::SetCriteria( const SMESH::Filter::Criteria& theCriteria aPredicate = aFilterMgr->CreateBadOrientedVolume(); } break; + case SMESH::FT_LinearOrQuadratic: + { + SMESH::LinearOrQuadratic_ptr tmpPred = aFilterMgr->CreateLinearOrQuadratic(); + tmpPred->SetElementType( aTypeOfElem ); + aPredicate = tmpPred; + break; + } + case SMESH::FT_GroupColor: + { + SMESH::GroupColor_ptr tmpPred = aFilterMgr->CreateGroupColor(); + tmpPred->SetElementType( aTypeOfElem ); + tmpPred->SetColorStr( aThresholdStr ); + aPredicate = tmpPred; + break; + } + case SMESH::FT_ElemGeomType: + { + SMESH::ElemGeomType_ptr tmpPred = aFilterMgr->CreateElemGeomType(); + tmpPred->SetElementType( aTypeOfElem ); + tmpPred->SetGeometryType( (GeometryType)(aThreshold + 0.5) ); + aPredicate = tmpPred; + break; + } default: continue; @@ -2513,16 +2726,21 @@ static inline LDOMString toString( CORBA::Long theType ) case FT_RangeOfIds : return "Range of IDs"; case FT_FreeBorders : return "Free borders"; case FT_FreeEdges : return "Free edges"; + case FT_FreeFaces : return "Free faces"; + case FT_FreeNodes : return "Free nodes"; case FT_MultiConnection : return "Borders at multi-connections"; case FT_MultiConnection2D: return "Borders at multi-connections 2D"; case FT_Length : return "Length"; - case FT_Length2D : return "Length2D"; + case FT_Length2D : return "Length 2D"; case FT_LessThan : return "Less than"; case FT_MoreThan : return "More than"; case FT_EqualTo : return "Equal to"; case FT_LogicalNOT : return "Not"; case FT_LogicalAND : return "And"; case FT_LogicalOR : return "Or"; + case FT_GroupColor : return "Color of Group"; + case FT_LinearOrQuadratic : return "Linear or Quadratic"; + case FT_ElemGeomType : return "Element geomtry type"; case FT_Undefined : return ""; default : return ""; } @@ -2548,6 +2766,8 @@ static inline SMESH::FunctorType toFunctorType( const LDOMString& theStr ) else if ( theStr.equals( "Lying on Geom" ) ) return FT_LyingOnGeom; else if ( theStr.equals( "Free borders" ) ) return FT_FreeBorders; else if ( theStr.equals( "Free edges" ) ) return FT_FreeEdges; + else if ( theStr.equals( "Free faces" ) ) return FT_FreeFaces; + else if ( theStr.equals( "Free nodes" ) ) return FT_FreeNodes; else if ( theStr.equals( "Borders at multi-connections" ) ) return FT_MultiConnection; // else if ( theStr.equals( "Borders at multi-connections 2D" ) ) return FT_MultiConnection2D; else if ( theStr.equals( "Length" ) ) return FT_Length; @@ -2560,6 +2780,9 @@ static inline SMESH::FunctorType toFunctorType( const LDOMString& theStr ) else if ( theStr.equals( "Not" ) ) return FT_LogicalNOT; else if ( theStr.equals( "And" ) ) return FT_LogicalAND; else if ( theStr.equals( "Or" ) ) return FT_LogicalOR; + else if ( theStr.equals( "Color of Group" ) ) return FT_GroupColor; + else if ( theStr.equals( "Linear or Quadratic" ) ) return FT_LinearOrQuadratic; + else if ( theStr.equals( "Element geomtry type" ) ) return FT_ElemGeomType; else if ( theStr.equals( "" ) ) return FT_Undefined; else return FT_Undefined; } @@ -2832,7 +3055,7 @@ Filter_ptr FilterLibrary_i::Copy( const char* theFilterName ) } else aCriterion.ThresholdStr = str.GetString(); - + aCriteria.push_back( aCriterion ); } diff --git a/src/SMESH_I/SMESH_Filter_i.hxx b/src/SMESH_I/SMESH_Filter_i.hxx index c5b0bacbd..3b654e880 100644 --- a/src/SMESH_I/SMESH_Filter_i.hxx +++ b/src/SMESH_I/SMESH_Filter_i.hxx @@ -520,6 +520,32 @@ namespace SMESH Controls::FreeEdgesPtr myFreeEdgesPtr; }; + + /* + Class : FreeFaces_i + Description : Predicate for free faces + */ + class SMESH_I_EXPORT FreeFaces_i: public virtual POA_SMESH::FreeFaces, + public virtual Predicate_i + { + public: + FreeFaces_i(); + FunctorType GetFunctorType(); + }; + + + /* + Class : FreeNodes_i + Description : Predicate for free nodes + */ + class SMESH_I_EXPORT FreeNodes_i: public virtual POA_SMESH::FreeNodes, + public virtual Predicate_i + { + public: + FreeNodes_i(); + FunctorType GetFunctorType(); + }; + /* Class : RangeOfIds_i @@ -540,6 +566,60 @@ namespace SMESH protected: Controls::RangeOfIdsPtr myRangeOfIdsPtr; }; + + /* + Class : LinearOrQuadratic_i + Description : Verify whether a mesh element is linear + */ + class SMESH_I_EXPORT LinearOrQuadratic_i: public virtual POA_SMESH::LinearOrQuadratic, + public virtual Predicate_i + { + public: + LinearOrQuadratic_i(); + FunctorType GetFunctorType(); + void SetElementType( ElementType theType ); + + private: + Controls::LinearOrQuadraticPtr myLinearOrQuadraticPtr; + }; + + /* + Class : GroupColor_i + Description : Functor for check color of group to whic mesh element belongs to + */ + class SMESH_I_EXPORT GroupColor_i: public virtual POA_SMESH::GroupColor, + public virtual Predicate_i + { + public: + GroupColor_i(); + FunctorType GetFunctorType(); + + void SetElementType( ElementType theType ); + void SetColorStr( const char* theColor ); + char* GetColorStr(); + + private: + Controls::GroupColorPtr myGroupColorPtr; + }; + + /* + Class : ElemGeomType_i + Description : Functor for check element geometry type + */ + class SMESH_I_EXPORT ElemGeomType_i: public virtual POA_SMESH::ElemGeomType, + public virtual Predicate_i + { + public: + ElemGeomType_i(); + FunctorType GetFunctorType(); + + void SetElementType ( ElementType theType ); + void SetGeometryType( GeometryType theType ); + GeometryType GetGeometryType() const; + + private: + Controls::ElemGeomTypePtr myElemGeomTypePtr; + }; /* Class : Comparator_i @@ -815,11 +895,18 @@ namespace SMESH FreeBorders_ptr CreateFreeBorders(); FreeEdges_ptr CreateFreeEdges(); + FreeNodes_ptr CreateFreeNodes(); + FreeFaces_ptr CreateFreeFaces(); RangeOfIds_ptr CreateRangeOfIds(); BadOrientedVolume_ptr CreateBadOrientedVolume(); + LinearOrQuadratic_ptr CreateLinearOrQuadratic(); + GroupColor_ptr CreateGroupColor(); + + ElemGeomType_ptr CreateElemGeomType(); + LessThan_ptr CreateLessThan(); MoreThan_ptr CreateMoreThan(); EqualTo_ptr CreateEqualTo(); diff --git a/src/SMESH_I/SMESH_Gen_i.cxx b/src/SMESH_I/SMESH_Gen_i.cxx index be5e68111..4cb5b667b 100644 --- a/src/SMESH_I/SMESH_Gen_i.cxx +++ b/src/SMESH_I/SMESH_Gen_i.cxx @@ -23,7 +23,6 @@ // File : SMESH_Gen_i.cxx // Author : Paul RASCLE, EDF // Module : SMESH -// $Header$ // #include #include @@ -133,6 +132,9 @@ SALOME_NamingService* SMESH_Gen_i::myNS = NULL; SALOME_LifeCycleCORBA* SMESH_Gen_i::myLCC = NULL; SMESH_Gen_i* SMESH_Gen_i::mySMESHGen = NULL; + +const int nbElemPerDiagonal = 10; + //============================================================================= /*! * GetServant [ static ] @@ -640,14 +642,15 @@ SMESH::SMESH_Hypothesis_ptr SMESH_Gen_i::CreateHypothesis( const char* theHypNam //================================================================================ /*! - * \brief Return hypothesis of given type holding parameter values of the existing mesh - * \param theHypType - hypothesis type name - * \param theLibName - plugin library name - * \param theMesh - The mesh of interest - * \param theGeom - The shape to get parameter values from - * \retval SMESH::SMESH_Hypothesis_ptr - The returned hypothesis may be the one existing - * in a study and used to compute the mesh, or a temporary one created just to pass - * parameter values + * \brief Return a hypothesis holding parameter values corresponding either to the mesh + * existing on the given geometry or to size of the geometry. + * \param theHypType - hypothesis type name + * \param theLibName - plugin library name + * \param theMesh - The mesh of interest + * \param theGeom - The shape to get parameter values from + * \retval SMESH::SMESH_Hypothesis_ptr - The returned hypothesis may be the one existing + * in a study and used to compute the mesh, or a temporary one created just to pass + * parameter values */ //================================================================================ @@ -655,11 +658,12 @@ SMESH::SMESH_Hypothesis_ptr SMESH_Gen_i::GetHypothesisParameterValues (const char* theHypType, const char* theLibName, SMESH::SMESH_Mesh_ptr theMesh, - GEOM::GEOM_Object_ptr theGeom) - throw ( SALOME::SALOME_Exception ) + GEOM::GEOM_Object_ptr theGeom, + CORBA::Boolean byMesh) + throw ( SALOME::SALOME_Exception ) { Unexpect aCatch(SALOME_SalomeException); - if ( CORBA::is_nil( theMesh ) ) + if ( CORBA::is_nil( theMesh ) && byMesh ) THROW_SALOME_CORBA_EXCEPTION( "bad Mesh reference", SALOME::BAD_PARAM ); if ( CORBA::is_nil( theGeom ) ) THROW_SALOME_CORBA_EXCEPTION( "bad shape object reference", SALOME::BAD_PARAM ); @@ -671,11 +675,11 @@ SMESH_Gen_i::GetHypothesisParameterValues (const char* theHypType, // get mesh and shape SMESH_Mesh_i* meshServant = SMESH::DownCast( theMesh ); TopoDS_Shape shape = GeomObjectToShape( theGeom ); - if ( !meshServant || shape.IsNull() ) + if ( !meshServant && byMesh || shape.IsNull() ) return SMESH::SMESH_Hypothesis::_nil(); - ::SMESH_Mesh& mesh = meshServant->GetImpl(); + ::SMESH_Mesh* mesh = meshServant ? &meshServant->GetImpl() : (::SMESH_Mesh*)0; - if ( mesh.NbNodes() == 0 ) // empty mesh + if ( byMesh && mesh->NbNodes() == 0 ) // empty mesh return SMESH::SMESH_Hypothesis::_nil(); // create a temporary hypothesis to know its dimention @@ -685,37 +689,64 @@ SMESH_Gen_i::GetHypothesisParameterValues (const char* theHypType, return SMESH::SMESH_Hypothesis::_nil(); ::SMESH_Hypothesis* hyp = hypServant->GetImpl(); - // look for a hypothesis of theHypType used to mesh the shape - if ( myGen.GetShapeDim( shape ) == hyp->GetDim() ) - { - // check local shape - SMESH::ListOfHypothesis_var aHypList = theMesh->GetHypothesisList( theGeom ); - int nbLocalHyps = aHypList->length(); - for ( int i = 0; i < nbLocalHyps; i++ ) - if ( strcmp( theHypType, aHypList[i]->GetName() ) == 0 ) // FOUND local! - return SMESH::SMESH_Hypothesis::_duplicate( aHypList[i] ); - // check super shapes - TopTools_ListIteratorOfListOfShape itShape( mesh.GetAncestors( shape )); - while ( nbLocalHyps == 0 && itShape.More() ) { - GEOM::GEOM_Object_ptr geomObj = ShapeToGeomObject( itShape.Value() ); - if ( ! CORBA::is_nil( geomObj )) { - SMESH::ListOfHypothesis_var aHypList = theMesh->GetHypothesisList( geomObj ); - nbLocalHyps = aHypList->length(); - for ( int i = 0; i < nbLocalHyps; i++ ) - if ( strcmp( theHypType, aHypList[i]->GetName() ) == 0 ) // FOUND global! - return SMESH::SMESH_Hypothesis::_duplicate( aHypList[i] ); + if ( byMesh ) { + // look for a hypothesis of theHypType used to mesh the shape + if ( myGen.GetShapeDim( shape ) == hyp->GetDim() ) + { + // check local shape + SMESH::ListOfHypothesis_var aHypList = theMesh->GetHypothesisList( theGeom ); + int nbLocalHyps = aHypList->length(); + for ( int i = 0; i < nbLocalHyps; i++ ) + if ( strcmp( theHypType, aHypList[i]->GetName() ) == 0 ) // FOUND local! + return SMESH::SMESH_Hypothesis::_duplicate( aHypList[i] ); + // check super shapes + TopTools_ListIteratorOfListOfShape itShape( mesh->GetAncestors( shape )); + while ( nbLocalHyps == 0 && itShape.More() ) { + GEOM::GEOM_Object_ptr geomObj = ShapeToGeomObject( itShape.Value() ); + if ( ! CORBA::is_nil( geomObj )) { + SMESH::ListOfHypothesis_var aHypList = theMesh->GetHypothesisList( geomObj ); + nbLocalHyps = aHypList->length(); + for ( int i = 0; i < nbLocalHyps; i++ ) + if ( strcmp( theHypType, aHypList[i]->GetName() ) == 0 ) // FOUND global! + return SMESH::SMESH_Hypothesis::_duplicate( aHypList[i] ); + } + itShape.Next(); } - itShape.Next(); + } + + // let the temporary hypothesis find out some how parameter values by mesh + if ( hyp->SetParametersByMesh( mesh, shape )) + return SMESH::SMESH_Hypothesis::_duplicate( tmpHyp ); + } + else { + double diagonal = 0; + if ( mesh ) + diagonal = mesh->GetShapeDiagonalSize(); + else + diagonal = ::SMESH_Mesh::GetShapeDiagonalSize( shape ); + double elemSize = diagonal / myGen.GetBoundaryBoxSegmentation(); + if ( elemSize > 0 ) { + // let the temporary hypothesis initialize it's values + if ( hyp->SetParametersByElementSize( elemSize, mesh )) + return SMESH::SMESH_Hypothesis::_duplicate( tmpHyp ); } } - // let the temporary hypothesis find out some how parameter values - if ( hyp->SetParametersByMesh( &mesh, shape )) - return SMESH::SMESH_Hypothesis::_duplicate( tmpHyp ); - return SMESH::SMESH_Hypothesis::_nil(); } +//============================================================================= +/*! + * Sets number of segments per diagonal of boundary box of geometry by which + * default segment length of appropriate 1D hypotheses is defined + */ +//============================================================================= + +void SMESH_Gen_i::SetBoundaryBoxSegmentation( CORBA::Long theNbSegments ) +{ + myGen.SetBoundaryBoxSegmentation( int( theNbSegments )); +} + //============================================================================= /*! * SMESH_Gen_i::CreateMesh @@ -1363,6 +1394,193 @@ CORBA::Boolean SMESH_Gen_i::Compute( SMESH::SMESH_Mesh_ptr theMesh, return false; } +//============================================================================= +/*! + * SMESH_Gen_i::Precompute + * + * Compute mesh as preview till indicated dimension on shape + */ +//============================================================================= + +SMESH::MeshPreviewStruct* SMESH_Gen_i::Precompute( SMESH::SMESH_Mesh_ptr theMesh, + GEOM::GEOM_Object_ptr theShapeObject, + SMESH::Dimension theDimension, + SMESH::long_array& theShapesId) + throw ( SALOME::SALOME_Exception ) +{ + Unexpect aCatch(SALOME_SalomeException); + if(MYDEBUG) MESSAGE( "SMESH_Gen_i::Precompute" ); + + if ( CORBA::is_nil( theShapeObject ) && theMesh->HasShapeToMesh()) + THROW_SALOME_CORBA_EXCEPTION( "bad shape object reference", + SALOME::BAD_PARAM ); + + if ( CORBA::is_nil( theMesh ) ) + THROW_SALOME_CORBA_EXCEPTION( "bad Mesh reference", + SALOME::BAD_PARAM ); + + SMESH::MeshPreviewStruct_var result = new SMESH::MeshPreviewStruct; + try { + // get mesh servant + SMESH_Mesh_i* meshServant = dynamic_cast( GetServant( theMesh ).in() ); + ASSERT( meshServant ); + if ( meshServant ) { + // NPAL16168: "geometrical group edition from a submesh don't modifiy mesh computation" + meshServant->CheckGeomGroupModif(); + // get local TopoDS_Shape + TopoDS_Shape myLocShape; + if(theMesh->HasShapeToMesh()) + myLocShape = GeomObjectToShape( theShapeObject ); + else + return result._retn();; + + // call implementation compute + ::SMESH_Mesh& myLocMesh = meshServant->GetImpl(); + TSetOfInt shapeIds; + ::MeshDimension aDim = (MeshDimension)theDimension; + if ( myGen.Compute( myLocMesh, myLocShape, false, aDim, &shapeIds ) ) + { + int nbShapeId = shapeIds.size(); + theShapesId.length( nbShapeId ); + // iterates on shapes and collect mesh entities into mesh preview + TSetOfInt::const_iterator idIt = shapeIds.begin(); + TSetOfInt::const_iterator idEnd = shapeIds.end(); + std::map< int, int > mapOfShIdNb; + std::set< SMESH_TLink > setOfEdge; + std::list< SMDSAbs_ElementType > listOfElemType; + typedef map TNode2LocalIDMap; + typedef TNode2LocalIDMap::iterator TNodeLocalID; + TNode2LocalIDMap mapNode2LocalID; + list< TNodeLocalID > connectivity; + int i, nbConnNodes = 0; + std::set< const SMESH_subMesh* > setOfVSubMesh; + // iterates on shapes + for ( ; idIt != idEnd; idIt++ ) + { + if ( mapOfShIdNb.find( *idIt ) != mapOfShIdNb.end() ) + continue; + SMESH_subMesh* sm = myLocMesh.GetSubMeshContaining(*idIt); + if ( !sm || !sm->IsMeshComputed() ) + continue; + + const TopoDS_Shape& aSh = sm->GetSubShape(); + const int shDim = myGen.GetShapeDim( aSh ); + if ( shDim < 1 || shDim > theDimension ) + continue; + + mapOfShIdNb[ *idIt ] = 0; + theShapesId[ mapOfShIdNb.size() - 1 ] = *idIt; + + SMESHDS_SubMesh* smDS = sm->GetSubMeshDS(); + if ( !smDS ) continue; + + if ( theDimension == SMESH::DIM_2D ) + { + SMDS_ElemIteratorPtr faceIt = smDS->GetElements(); + while ( faceIt->more() ) + { + const SMDS_MeshElement* face = faceIt->next(); + int aNbNode = face->NbNodes(); + if ( aNbNode > 4 ) + aNbNode /= 2; // do not take into account additional middle nodes + + SMDS_MeshNode* node1 = (SMDS_MeshNode*)face->GetNode( 1 ); + for ( int nIndx = 1; nIndx <= aNbNode; nIndx++ ) + { + SMDS_MeshNode* node2 = (SMDS_MeshNode*)face->GetNode( nIndx < aNbNode ? nIndx+1 : 1 ); + if ( setOfEdge.insert( SMESH_TLink ( node1, node2 ) ).second ) + { + listOfElemType.push_back( SMDSAbs_Edge ); + connectivity.push_back + ( mapNode2LocalID.insert( make_pair( node1, ++nbConnNodes)).first ); + connectivity.push_back + ( mapNode2LocalID.insert( make_pair( node2, ++nbConnNodes)).first ); + } + node1 = node2; + } + } + } + else if ( theDimension == SMESH::DIM_1D ) + { + SMDS_NodeIteratorPtr nodeIt = smDS->GetNodes(); + while ( nodeIt->more() ) + { + listOfElemType.push_back( SMDSAbs_Node ); + connectivity.push_back + ( mapNode2LocalID.insert( make_pair( nodeIt->next(), ++nbConnNodes)).first ); + } + // add corner nodes by first vertex from edge + SMESH_subMeshIteratorPtr edgeSmIt = + sm->getDependsOnIterator(/*includeSelf*/false, + /*complexShapeFirst*/false); + while ( edgeSmIt->more() ) + { + SMESH_subMesh* vertexSM = edgeSmIt->next(); + // check that vertex is not already treated + if ( !setOfVSubMesh.insert( vertexSM ).second ) + continue; + if ( vertexSM->GetSubShape().ShapeType() != TopAbs_VERTEX ) + continue; + + const SMESHDS_SubMesh* vertexSmDS = vertexSM->GetSubMeshDS(); + SMDS_NodeIteratorPtr nodeIt = vertexSmDS->GetNodes(); + while ( nodeIt->more() ) + { + listOfElemType.push_back( SMDSAbs_Node ); + connectivity.push_back + ( mapNode2LocalID.insert( make_pair( nodeIt->next(), ++nbConnNodes)).first ); + } + } + } + } + + // fill node coords and assign local ids to the nodes + int nbNodes = mapNode2LocalID.size(); + result->nodesXYZ.length( nbNodes ); + TNodeLocalID node2ID = mapNode2LocalID.begin(); + for ( i = 0; i < nbNodes; ++i, ++node2ID ) { + node2ID->second = i; + const SMDS_MeshNode* node = (const SMDS_MeshNode*) node2ID->first; + result->nodesXYZ[i].x = node->X(); + result->nodesXYZ[i].y = node->Y(); + result->nodesXYZ[i].z = node->Z(); + } + // fill connectivity + result->elementConnectivities.length( nbConnNodes ); + list< TNodeLocalID >::iterator connIt = connectivity.begin(); + for ( i = 0; i < nbConnNodes; ++i, ++connIt ) { + result->elementConnectivities[i] = (*connIt)->second; + } + + // fill element types + result->elementTypes.length( listOfElemType.size() ); + std::list< SMDSAbs_ElementType >::const_iterator typeIt = listOfElemType.begin(); + std::list< SMDSAbs_ElementType >::const_iterator typeEnd = listOfElemType.end(); + for ( i = 0; typeIt != typeEnd; ++i, ++typeIt ) + { + SMDSAbs_ElementType elemType = *typeIt; + result->elementTypes[i].SMDS_ElementType = (SMESH::ElementType)elemType; + result->elementTypes[i].isPoly = false; + result->elementTypes[i].nbNodesInElement = elemType == SMDSAbs_Edge ? 2 : 1; + } + + // correct number of shapes + theShapesId.length( mapOfShIdNb.size() ); + } + } + } + catch ( std::bad_alloc ) { + INFOS( "Precompute(): lack of memory" ); + } + catch ( SALOME_Exception& S_ex ) { + INFOS( "Precompute(): catch exception "<< S_ex.what() ); + } + catch ( ... ) { + INFOS( "Precompute(): unknown exception " ); + } + return result._retn(); +} + //================================================================================ /*! * \brief Return geometrical object the given element is built on @@ -3537,9 +3755,9 @@ bool SMESH_Gen_i::Load( SALOMEDS::SComponent_ptr theComponent, // "Nodes on Faces" - ID of node on face // "Face U positions" - U parameter of node on face // "Face V positions" - V parameter of node on face - char* aEid_DSName = "Nodes on Edges"; - char* aEu_DSName = "Edge positions"; - char* aFu_DSName = "Face U positions"; + const char* aEid_DSName = "Nodes on Edges"; + const char* aEu_DSName = "Edge positions"; + const char* aFu_DSName = "Face U positions"; //char* aFid_DSName = "Nodes on Faces"; //char* aFv_DSName = "Face V positions"; @@ -3957,6 +4175,25 @@ CORBA::Long SMESH_Gen_i::GetObjectId(CORBA::Object_ptr theObject) return 0; } +//============================================================================= +/*! + * SMESH_Gen_i::SetName + * + * Set a new object name + */ +//============================================================================= +void SMESH_Gen_i::SetName(const char* theIOR, + const char* theName) +{ + if ( theIOR && strcmp( theIOR, "" ) ) { + CORBA::Object_var anObject = GetORB()->string_to_object( theIOR ); + SALOMEDS::SObject_var aSO = ObjectToSObject( myCurrentStudy, anObject ); + if ( !aSO->_is_nil() ) { + SetName( aSO, theName ); + } + } +} + //============================================================================= /*! * SMESHEngine_factory diff --git a/src/SMESH_I/SMESH_Gen_i.hxx b/src/SMESH_I/SMESH_Gen_i.hxx index 452065cd6..defaaf37d 100644 --- a/src/SMESH_I/SMESH_Gen_i.hxx +++ b/src/SMESH_I/SMESH_Gen_i.hxx @@ -23,7 +23,6 @@ // File : SMESH_Gen_i.hxx // Author : Paul RASCLE, EDF // Module : SMESH -// $Header$ // #ifndef _SMESH_GEN_I_HXX_ #define _SMESH_GEN_I_HXX_ @@ -175,6 +174,10 @@ public: // ***************************************** // Interface methods // ***************************************** + // Set a new Mesh object name + void SetName(const char* theIOR, + const char* theName); + //GEOM::GEOM_Gen_ptr SetGeomEngine( const char* containerLoc ); void SetGeomEngine( GEOM::GEOM_Gen_ptr geomcompo ); @@ -197,9 +200,16 @@ public: SMESH::SMESH_Hypothesis_ptr GetHypothesisParameterValues (const char* theHypType, const char* theLibName, SMESH::SMESH_Mesh_ptr theMesh, - GEOM::GEOM_Object_ptr theGeom) + GEOM::GEOM_Object_ptr theGeom, + CORBA::Boolean byMesh) throw ( SALOME::SALOME_Exception ); + /*! + * Sets number of segments per diagonal of boundary box of geometry by which + * default segment length of appropriate 1D hypotheses is defined + */ + void SetBoundaryBoxSegmentation( CORBA::Long theNbSegments ); + // Create empty mesh on a shape SMESH::SMESH_Mesh_ptr CreateMesh( GEOM::GEOM_Object_ptr theShapeObject ) throw ( SALOME::SALOME_Exception ); @@ -236,6 +246,17 @@ public: CORBA::Boolean IsReadyToCompute( SMESH::SMESH_Mesh_ptr theMesh, GEOM::GEOM_Object_ptr theShapeObject ) throw ( SALOME::SALOME_Exception ); + + /*! + * Calculate Mesh as preview till indicated dimension on shape + * First, verify list of hypothesis associated with the subShape. + * Return mesh preview structure + */ + SMESH::MeshPreviewStruct* Precompute( SMESH::SMESH_Mesh_ptr theMesh, + GEOM::GEOM_Object_ptr theSubObject, + SMESH::Dimension theDimension, + SMESH::long_array& theShapesId ) + throw ( SALOME::SALOME_Exception ); // Returns errors of hypotheses definintion SMESH::algo_error_array* GetAlgoState( SMESH::SMESH_Mesh_ptr theMesh, diff --git a/src/SMESH_I/SMESH_Group_i.cxx b/src/SMESH_I/SMESH_Group_i.cxx index f818def66..045e691b9 100644 --- a/src/SMESH_I/SMESH_Group_i.cxx +++ b/src/SMESH_I/SMESH_Group_i.cxx @@ -23,7 +23,6 @@ // File : SMESH_Group_i.cxx // Author : Sergey ANIKIN, OCC // Module : SMESH -// $Header$ // #include "SMESH_Group_i.hxx" #include "SMESH_Mesh_i.hxx" @@ -118,20 +117,24 @@ SMESHDS_GroupBase* SMESH_GroupBase_i::GetGroupDS() const void SMESH_GroupBase_i::SetName( const char* theName ) { - // Update Python script - TPythonDump() << _this() << ".SetName( '" << theName << "' )"; - // Perform renaming ::SMESH_Group* aGroup = GetSmeshGroup(); - if (aGroup) { - aGroup->SetName(theName); - - // Update group name in a study - SMESH_Gen_i* aGen = myMeshServant->GetGen(); - aGen->SetName( aGen->ObjectToSObject( aGen->GetCurrentStudy(), _this() ), theName ); + if (!aGroup) { + MESSAGE("can't set name of a vague group"); return; } - MESSAGE("can't set name of a vague group"); + + if ( aGroup->GetName() && !strcmp( aGroup->GetName(), theName ) ) + return; // nothing to rename + + aGroup->SetName(theName); + + // Update group name in a study + SMESH_Gen_i* aGen = myMeshServant->GetGen(); + aGen->SetName( aGen->ObjectToSObject( aGen->GetCurrentStudy(), _this() ), theName ); + + // Update Python script + TPythonDump() << _this() << ".SetName( '" << theName << "' )"; } //============================================================================= diff --git a/src/SMESH_I/SMESH_MeshEditor_i.cxx b/src/SMESH_I/SMESH_MeshEditor_i.cxx index 3e9a3fca7..9592ab843 100644 --- a/src/SMESH_I/SMESH_MeshEditor_i.cxx +++ b/src/SMESH_I/SMESH_MeshEditor_i.cxx @@ -23,8 +23,7 @@ // File : SMESH_MeshEditor_i.cxx // Author : Nicolas REJNERI // Module : SMESH -// $Header$ -// + #include "SMESH_MeshEditor_i.hxx" #include "SMDS_MeshEdge.hxx" @@ -3603,9 +3602,9 @@ SMESH::SMESH_Mesh_ptr SMESH_MeshEditor_i::makeMesh(const char* theMeshName) //======================================================================= //function : DumpGroupsList -//purpose : +//purpose : //======================================================================= -void SMESH_MeshEditor_i::DumpGroupsList(TPythonDump & theDumpPython, +void SMESH_MeshEditor_i::DumpGroupsList(TPythonDump & theDumpPython, const SMESH::ListOfGroups * theGroupList) { bool isDumpGroupList = theGroupList && theGroupList->length() > 0; @@ -3613,3 +3612,139 @@ void SMESH_MeshEditor_i::DumpGroupsList(TPythonDump & theDumpPython, theDumpPython << theGroupList << " = "; } } + +//================================================================================ +/*! + \brief Creates a hole in a mesh by doubling the nodes of some particular elements + \param theNodes - identifiers of nodes to be doubled + \param theModifiedElems - identifiers of elements to be updated by the new (doubled) + nodes. If list of element identifiers is empty then nodes are doubled but + they not assigned to elements + \return TRUE if operation has been completed successfully, FALSE otherwise + \sa DoubleNode(), DoubleNodeGroup(), DoubleNodeGroups() +*/ +//================================================================================ + +CORBA::Boolean SMESH_MeshEditor_i::DoubleNodes( const SMESH::long_array& theNodes, + const SMESH::long_array& theModifiedElems ) +{ + initData(); + + ::SMESH_MeshEditor aMeshEditor( myMesh ); + list< int > aListOfNodes; + int i, n; + for ( i = 0, n = theNodes.length(); i < n; i++ ) + aListOfNodes.push_back( theNodes[ i ] ); + + list< int > aListOfElems; + for ( i = 0, n = theModifiedElems.length(); i < n; i++ ) + aListOfElems.push_back( theModifiedElems[ i ] ); + + bool aResult = aMeshEditor.DoubleNodes( aListOfNodes, aListOfElems ); + + storeResult( aMeshEditor) ; + + return aResult; +} + +//================================================================================ +/*! + \brief Creates a hole in a mesh by doubling the nodes of some particular elements + This method provided for convenience works as DoubleNodes() described above. + \param theNodeId - identifier of node to be doubled. + \param theModifiedElems - identifiers of elements to be updated. + \return TRUE if operation has been completed successfully, FALSE otherwise + \sa DoubleNodes(), DoubleNodeGroup(), DoubleNodeGroups() +*/ +//================================================================================ + +CORBA::Boolean SMESH_MeshEditor_i::DoubleNode( CORBA::Long theNodeId, + const SMESH::long_array& theModifiedElems ) +{ + SMESH::long_array_var aNodes = new SMESH::long_array; + aNodes->length( 1 ); + aNodes[ 0 ] = theNodeId; + return DoubleNodes( aNodes, theModifiedElems ); +} + +//================================================================================ +/*! + \brief Creates a hole in a mesh by doubling the nodes of some particular elements + This method provided for convenience works as DoubleNodes() described above. + \param theNodes - group of nodes to be doubled. + \param theModifiedElems - group of elements to be updated. + \return TRUE if operation has been completed successfully, FALSE otherwise + \sa DoubleNode(), DoubleNodes(), DoubleNodeGroups() +*/ +//================================================================================ + +CORBA::Boolean SMESH_MeshEditor_i::DoubleNodeGroup( + SMESH::SMESH_GroupBase_ptr theNodes, + SMESH::SMESH_GroupBase_ptr theModifiedElems ) +{ + if ( CORBA::is_nil( theNodes ) && theNodes->GetType() != SMESH::NODE ) + return false; + + SMESH::long_array_var aNodes = theNodes->GetListOfID(); + SMESH::long_array_var aModifiedElems; + if ( !CORBA::is_nil( theModifiedElems ) ) + aModifiedElems = theModifiedElems->GetListOfID(); + else + { + aModifiedElems = new SMESH::long_array; + aModifiedElems->length( 0 ); + } + + return DoubleNodes( aNodes, aModifiedElems ); +} + +//================================================================================ +/*! + \brief Creates a hole in a mesh by doubling the nodes of some particular elements + This method provided for convenience works as DoubleNodes() described above. + \param theNodes - list of groups of nodes to be doubled + \param theModifiedElems - list of groups of elements to be updated. + \return TRUE if operation has been completed successfully, FALSE otherwise + \sa DoubleNode(), DoubleNodeGroup(), DoubleNodes() +*/ +//================================================================================ + +CORBA::Boolean SMESH_MeshEditor_i::DoubleNodeGroups( + const SMESH::ListOfGroups& theNodes, + const SMESH::ListOfGroups& theModifiedElems ) +{ + initData(); + + ::SMESH_MeshEditor aMeshEditor( myMesh ); + + std::list< int > aNodes; + int i, n, j, m; + for ( i = 0, n = theNodes.length(); i < n; i++ ) + { + SMESH::SMESH_GroupBase_var aGrp = theNodes[ i ]; + if ( !CORBA::is_nil( aGrp ) && aGrp->GetType() == SMESH::NODE ) + { + SMESH::long_array_var aCurr = aGrp->GetListOfID(); + for ( j = 0, m = aCurr->length(); j < m; j++ ) + aNodes.push_back( aCurr[ j ] ); + } + } + + std::list< int > anElems; + for ( i = 0, n = theModifiedElems.length(); i < n; i++ ) + { + SMESH::SMESH_GroupBase_var aGrp = theModifiedElems[ i ]; + if ( !CORBA::is_nil( aGrp ) && aGrp->GetType() != SMESH::NODE ) + { + SMESH::long_array_var aCurr = aGrp->GetListOfID(); + for ( j = 0, m = aCurr->length(); j < m; j++ ) + anElems.push_back( aCurr[ j ] ); + } + } + + bool aResult = aMeshEditor.DoubleNodes( aNodes, anElems ); + + storeResult( aMeshEditor) ; + + return aResult; +} diff --git a/src/SMESH_I/SMESH_MeshEditor_i.hxx b/src/SMESH_I/SMESH_MeshEditor_i.hxx index 609acfdce..eff6e21e4 100644 --- a/src/SMESH_I/SMESH_MeshEditor_i.hxx +++ b/src/SMESH_I/SMESH_MeshEditor_i.hxx @@ -23,7 +23,6 @@ // File : SMESH_MeshEditor_i.hxx // Author : Nicolas REJNERI // Module : SMESH -// $Header$ // #ifndef _SMESH_MESHEDITOR_I_HXX_ #define _SMESH_MESHEDIOTR_I_HXX_ @@ -418,7 +417,18 @@ class SMESH_MeshEditor_i: public POA_SMESH::SMESH_MeshEditor * \retval int - mesh ID */ int GetMeshId() const { return myMesh->GetId(); } + + CORBA::Boolean DoubleNodes( const SMESH::long_array& theNodes, + const SMESH::long_array& theModifiedElems ); + + CORBA::Boolean DoubleNode( CORBA::Long theNodeId, + const SMESH::long_array& theModifiedElems ); + + CORBA::Boolean DoubleNodeGroup( SMESH::SMESH_GroupBase_ptr theNodes, + SMESH::SMESH_GroupBase_ptr theModifiedElems ); + CORBA::Boolean DoubleNodeGroups( const SMESH::ListOfGroups& theNodes, + const SMESH::ListOfGroups& theModifiedElems); private: //!< private methods diff --git a/src/SMESH_I/SMESH_Mesh_i.cxx b/src/SMESH_I/SMESH_Mesh_i.cxx index cc5e79fbb..f38ecd1fc 100644 --- a/src/SMESH_I/SMESH_Mesh_i.cxx +++ b/src/SMESH_I/SMESH_Mesh_i.cxx @@ -23,7 +23,6 @@ // File : SMESH_Mesh_i.cxx // Author : Paul RASCLE, EDF // Module : SMESH -// $Header$ // #include "SMESH_Mesh_i.hxx" @@ -208,6 +207,24 @@ void SMESH_Mesh_i::Clear() throw (SALOME::SALOME_Exception) TPythonDump() << _this() << ".Clear()"; } +//================================================================================ +/*! + * \brief Remove all nodes and elements for indicated shape + */ +//================================================================================ + +void SMESH_Mesh_i::ClearSubMesh(CORBA::Long ShapeID) + throw (SALOME::SALOME_Exception) +{ + Unexpect aCatch(SALOME_SalomeException); + try { + _impl->ClearSubMesh( ShapeID ); + } + catch(SALOME_Exception & S_ex) { + THROW_SALOME_CORBA_EXCEPTION(S_ex.what(), SALOME::BAD_PARAM); + } +} + //============================================================================= /*! * @@ -921,6 +938,85 @@ SMESH::SMESH_Group_ptr SMESH_Mesh_i::UnionGroups( SMESH::SMESH_GroupBase_ptr the } } +//============================================================================= +/*! + \brief Union list of groups. New group is created. All mesh elements that are + present in initial groups are added to the new one. + \param theGroups list of groups + \param theName name of group to be created + \return pointer on the group +*/ +//============================================================================= +SMESH::SMESH_Group_ptr SMESH_Mesh_i::UnionListOfGroups(const SMESH::ListOfGroups& theGroups, + const char* theName ) +throw (SALOME::SALOME_Exception) +{ + if ( !theName ) + return SMESH::SMESH_Group::_nil(); + + try + { + NCollection_Map< int > anIds; + SMESH::ElementType aType = SMESH::ALL; + for ( int g = 0, n = theGroups.length(); g < n; g++ ) + { + SMESH::SMESH_GroupBase_var aGrp = theGroups[ g ]; + if ( CORBA::is_nil( aGrp ) ) + continue; + + // check type + SMESH::ElementType aCurrType = aGrp->GetType(); + if ( aType == SMESH::ALL ) + aType = aCurrType; + else + { + if ( aType != aCurrType ) + return SMESH::SMESH_Group::_nil(); + } + + // unite ids + SMESH::long_array_var aCurrIds = aGrp->GetListOfID(); + for ( int i = 0, n = aCurrIds->length(); i < n; i++ ) + { + int aCurrId = aCurrIds[ i ]; + anIds.Add( aCurrId ); + } + } + + // Create group + SMESH::SMESH_Group_var aResGrp = CreateGroup( aType, theName ); + if ( aResGrp->_is_nil() ) + return SMESH::SMESH_Group::_nil(); + + // Create array of identifiers + SMESH::long_array_var aResIds = new SMESH::long_array; + aResIds->length( anIds.Extent() ); + + NCollection_Map< int >::Iterator anIter( anIds ); + for ( int i = 0; anIter.More(); anIter.Next(), i++ ) + { + aResIds[ i ] = anIter.Value(); + } + aResGrp->Add( aResIds ); + + // Clear python lines, created by CreateGroup() and Add() + SALOMEDS::Study_ptr aStudy = _gen_i->GetCurrentStudy(); + _gen_i->RemoveLastFromPythonScript( aStudy->StudyId() ); + _gen_i->RemoveLastFromPythonScript( aStudy->StudyId() ); + + // Update Python script + + TPythonDump() << aResGrp << " = " << _this() << ".UnionListOfGroups( " + << &theGroups << ", '" << theName << "' )"; + + return aResGrp._retn(); + } + catch( ... ) + { + return SMESH::SMESH_Group::_nil(); + } +} + //============================================================================= /*! IntersectGroups * New group is created. All mesh elements that are @@ -975,6 +1071,100 @@ SMESH::SMESH_Group_ptr SMESH_Mesh_i::IntersectGroups( SMESH::SMESH_GroupBase_ptr return aResGrp._retn(); } +//============================================================================= +/*! + \brief Intersect list of groups. New group is created. All mesh elements that + are present in all initial groups simultaneously are added to the new one. + \param theGroups list of groups + \param theName name of group to be created + \return pointer on the group +*/ +//============================================================================= +SMESH::SMESH_Group_ptr SMESH_Mesh_i::IntersectListOfGroups( + const SMESH::ListOfGroups& theGroups, const char* theName ) +throw (SALOME::SALOME_Exception) +{ + if ( !theName ) + return SMESH::SMESH_Group::_nil(); + + try + { + NCollection_DataMap< int, int > anIdToCount; + SMESH::ElementType aType = SMESH::ALL; + for ( int g = 0, n = theGroups.length(); g < n; g++ ) + { + SMESH::SMESH_GroupBase_var aGrp = theGroups[ g ]; + if ( CORBA::is_nil( aGrp ) ) + continue; + + // check type + SMESH::ElementType aCurrType = aGrp->GetType(); + if ( aType == SMESH::ALL ) + aType = aCurrType; + else + { + if ( aType != aCurrType ) + return SMESH::SMESH_Group::_nil(); + } + + // calculates number of occurance ids in groups + SMESH::long_array_var aCurrIds = aGrp->GetListOfID(); + for ( int i = 0, n = aCurrIds->length(); i < n; i++ ) + { + int aCurrId = aCurrIds[ i ]; + if ( !anIdToCount.IsBound( aCurrId ) ) + anIdToCount.Bind( aCurrId, 1 ); + else + anIdToCount( aCurrId ) = anIdToCount( aCurrId ) + 1; + } + } + + // create map of ids + int nbGrp = theGroups.length(); + NCollection_Map< int > anIds; + NCollection_DataMap< int, int >::Iterator anIter( anIdToCount ); + for ( ; anIter.More(); anIter.Next() ) + { + int aCurrId = anIter.Key(); + int aCurrNb = anIter.Value(); + if ( aCurrNb == nbGrp ) + anIds.Add( aCurrId ); + } + + // Create group + SMESH::SMESH_Group_var aResGrp = CreateGroup( aType, theName ); + if ( aResGrp->_is_nil() ) + return SMESH::SMESH_Group::_nil(); + + // Create array of identifiers + SMESH::long_array_var aResIds = new SMESH::long_array; + aResIds->length( anIds.Extent() ); + + NCollection_Map< int >::Iterator aListIter( anIds ); + for ( int i = 0; aListIter.More(); aListIter.Next(), i++ ) + { + aResIds[ i ] = aListIter.Value(); + } + aResGrp->Add( aResIds ); + + // Clear python lines, created by CreateGroup() and Add() + SALOMEDS::Study_ptr aStudy = _gen_i->GetCurrentStudy(); + _gen_i->RemoveLastFromPythonScript( aStudy->StudyId() ); + _gen_i->RemoveLastFromPythonScript( aStudy->StudyId() ); + + // Update Python script + + TPythonDump() << aResGrp << " = " << _this() << ".IntersectListOfGroups( " + << &theGroups << ", '" << theName << "' )"; + + return aResGrp._retn(); + } + catch( ... ) + { + return SMESH::SMESH_Group::_nil(); + } +} + //============================================================================= /*! CutGroups * New group is created. All mesh elements that are present in @@ -1003,7 +1193,6 @@ SMESH::SMESH_Group_ptr SMESH_Mesh_i::CutGroups( SMESH::SMESH_GroupBase_ptr theGr for ( int i2 = 0, n2 = anIds2->length(); i2 < n2; i2++ ) aMap2.Add( anIds2[ i2 ] ); - TColStd_SequenceOfInteger aSeq; for ( int i1 = 0, n1 = anIds1->length(); i1 < n1; i1++ ) if ( !aMap2.Contains( anIds1[ i1 ] ) ) @@ -1030,6 +1219,281 @@ SMESH::SMESH_Group_ptr SMESH_Mesh_i::CutGroups( SMESH::SMESH_GroupBase_ptr theGr return aResGrp._retn(); } +//============================================================================= +/*! + \brief Cut lists of groups. New group is created. All mesh elements that are + present in main groups but do not present in tool groups are added to the new one + \param theMainGroups list of main groups + \param theToolGroups list of tool groups + \param theName name of group to be created + \return pointer on the group +*/ +//============================================================================= +SMESH::SMESH_Group_ptr SMESH_Mesh_i::CutListOfGroups( + const SMESH::ListOfGroups& theMainGroups, + const SMESH::ListOfGroups& theToolGroups, + const char* theName ) + throw (SALOME::SALOME_Exception) +{ + if ( !theName ) + return SMESH::SMESH_Group::_nil(); + + try + { + NCollection_Map< int > aToolIds; + SMESH::ElementType aType = SMESH::ALL; + int g, n; + // iterate through tool groups + for ( g = 0, n = theToolGroups.length(); g < n; g++ ) + { + SMESH::SMESH_GroupBase_var aGrp = theToolGroups[ g ]; + if ( CORBA::is_nil( aGrp ) ) + continue; + + // check type + SMESH::ElementType aCurrType = aGrp->GetType(); + if ( aType == SMESH::ALL ) + aType = aCurrType; + else + { + if ( aType != aCurrType ) + return SMESH::SMESH_Group::_nil(); + } + + // unite tool ids + SMESH::long_array_var aCurrIds = aGrp->GetListOfID(); + for ( int i = 0, n = aCurrIds->length(); i < n; i++ ) + { + int aCurrId = aCurrIds[ i ]; + aToolIds.Add( aCurrId ); + } + } + + NCollection_Map< int > anIds; // result + + // Iterate through main group + for ( g = 0, n = theMainGroups.length(); g < n; g++ ) + { + SMESH::SMESH_GroupBase_var aGrp = theMainGroups[ g ]; + if ( CORBA::is_nil( aGrp ) ) + continue; + + // check type + SMESH::ElementType aCurrType = aGrp->GetType(); + if ( aType == SMESH::ALL ) + aType = aCurrType; + else + { + if ( aType != aCurrType ) + return SMESH::SMESH_Group::_nil(); + } + + // unite tool ids + SMESH::long_array_var aCurrIds = aGrp->GetListOfID(); + for ( int i = 0, n = aCurrIds->length(); i < n; i++ ) + { + int aCurrId = aCurrIds[ i ]; + if ( !aToolIds.Contains( aCurrId ) ) + anIds.Add( aCurrId ); + } + } + + // Create group + SMESH::SMESH_Group_var aResGrp = CreateGroup( aType, theName ); + if ( aResGrp->_is_nil() ) + return SMESH::SMESH_Group::_nil(); + + // Create array of identifiers + SMESH::long_array_var aResIds = new SMESH::long_array; + aResIds->length( anIds.Extent() ); + + NCollection_Map< int >::Iterator anIter( anIds ); + for ( int i = 0; anIter.More(); anIter.Next(), i++ ) + { + aResIds[ i ] = anIter.Value(); + } + aResGrp->Add( aResIds ); + + // Clear python lines, created by CreateGroup() and Add() + SALOMEDS::Study_ptr aStudy = _gen_i->GetCurrentStudy(); + _gen_i->RemoveLastFromPythonScript( aStudy->StudyId() ); + _gen_i->RemoveLastFromPythonScript( aStudy->StudyId() ); + + // Update Python script + + TPythonDump() << aResGrp << " = " << _this() << ".CutListOfGroups( " + << &theMainGroups << ", " << &theToolGroups << ", '" + << theName << "' )"; + + return aResGrp._retn(); + } + catch( ... ) + { + return SMESH::SMESH_Group::_nil(); + } +} + +//============================================================================= +/*! + \brief Create groups of entities from existing groups of superior dimensions + System + 1) extract all nodes from each group, + 2) combine all elements of specified dimension laying on these nodes. + \param theGroups list of source groups + \param theElemType dimension of elements + \param theName name of new group + \return pointer on new group +*/ +//============================================================================= +SMESH::SMESH_Group_ptr SMESH_Mesh_i::CreateDimGroup( + const SMESH::ListOfGroups& theGroups, + SMESH::ElementType theElemType, + const char* theName ) + throw (SALOME::SALOME_Exception) +{ + SMESHDS_Mesh* aMeshDS = _impl->GetMeshDS(); + + if ( !theName || !aMeshDS ) + return SMESH::SMESH_Group::_nil(); + + SMDSAbs_ElementType anElemType = (SMDSAbs_ElementType)theElemType; + + try + { + // Create map of nodes from all groups + + NCollection_Map< int > aNodeMap; + + for ( int g = 0, n = theGroups.length(); g < n; g++ ) + { + SMESH::SMESH_GroupBase_var aGrp = theGroups[ g ]; + if ( CORBA::is_nil( aGrp ) ) + continue; + + SMESH::ElementType aType = aGrp->GetType(); + if ( aType == SMESH::ALL ) + continue; + else if ( aType == SMESH::NODE ) + { + SMESH::long_array_var aCurrIds = aGrp->GetListOfID(); + for ( int i = 0, n = aCurrIds->length(); i < n; i++ ) + { + int aCurrId = aCurrIds[ i ]; + const SMDS_MeshNode* aNode = aMeshDS->FindNode( aCurrId ); + if ( aNode ) + aNodeMap.Add( aNode->GetID() ); + } + } + else + { + SMESH::long_array_var aCurrIds = aGrp->GetListOfID(); + for ( int i = 0, n = aCurrIds->length(); i < n; i++ ) + { + int aCurrId = aCurrIds[ i ]; + const SMDS_MeshElement* anElem = aMeshDS->FindElement( aCurrId ); + if ( !anElem ) + continue; + SMDS_ElemIteratorPtr aNodeIter = anElem->nodesIterator(); + while( aNodeIter->more() ) + { + const SMDS_MeshNode* aNode = + dynamic_cast( aNodeIter->next() ); + if ( aNode ) + aNodeMap.Add( aNode->GetID() ); + } + } + } + } + + // Get result identifiers + + NCollection_Map< int > aResultIds; + if ( theElemType == SMESH::NODE ) + { + NCollection_Map< int >::Iterator aNodeIter( aNodeMap ); + for ( ; aNodeIter.More(); aNodeIter.Next() ) + aResultIds.Add( aNodeIter.Value() ); + } + else + { + // Create list of elements of given dimension constructed on the nodes + NCollection_Map< int > anElemList; + NCollection_Map< int >::Iterator aNodeIter( aNodeMap ); + for ( ; aNodeIter.More(); aNodeIter.Next() ) + { + const SMDS_MeshElement* aNode = + dynamic_cast( aMeshDS->FindNode( aNodeIter.Value() ) ); + if ( !aNode ) + continue; + + SMDS_ElemIteratorPtr anElemIter = aNode->elementsIterator( anElemType ); + while( anElemIter->more() ) + { + const SMDS_MeshElement* anElem = + dynamic_cast( anElemIter->next() ); + if ( anElem && anElem->GetType() == anElemType ) + anElemList.Add( anElem->GetID() ); + } + } + + // check whether all nodes of elements are present in nodes map + NCollection_Map< int >::Iterator anIter( anElemList ); + for ( ; anIter.More(); anIter.Next() ) + { + const SMDS_MeshElement* anElem = aMeshDS->FindElement( anIter.Value() ); + if ( !anElem ) + continue; + + bool isOk = true; + SMDS_ElemIteratorPtr aNodeIter = anElem->nodesIterator(); + while( aNodeIter->more() ) + { + const SMDS_MeshNode* aNode = + dynamic_cast( aNodeIter->next() ); + if ( !aNode || !aNodeMap.Contains( aNode->GetID() ) ) + { + isOk = false; + break; + } + } + if ( isOk ) + aResultIds.Add( anElem->GetID() ); + } + } + + // Create group + + SMESH::SMESH_Group_var aResGrp = CreateGroup( theElemType, theName ); + if ( aResGrp->_is_nil() ) + return SMESH::SMESH_Group::_nil(); + + // Create array of identifiers + SMESH::long_array_var aResIds = new SMESH::long_array; + aResIds->length( aResultIds.Extent() ); + + NCollection_Map< int >::Iterator aResIter( aResultIds ); + for ( int i = 0; aResIter.More(); aResIter.Next(), i++ ) + aResIds[ i ] = aResIter.Value(); + aResGrp->Add( aResIds ); + + // Remove strings corresponding to group creation + SALOMEDS::Study_ptr aStudy = _gen_i->GetCurrentStudy(); + _gen_i->RemoveLastFromPythonScript( aStudy->StudyId() ); + _gen_i->RemoveLastFromPythonScript( aStudy->StudyId() ); + + // Update Python script + + TPythonDump() << aResGrp << " = " << _this() << ".CreateDimGroup( " + << &theGroups << ", " << theElemType << ", '" << theName << "' )"; + + return aResGrp._retn(); + } + catch( ... ) + { + return SMESH::SMESH_Group::_nil(); + } +} + //================================================================================ /*! * \brief Return group items of a group present in a study @@ -1163,6 +1627,74 @@ void SMESH_Mesh_i::CheckGeomGroupModif() } } +//============================================================================= +/*! + * \brief Create standalone group instead if group on geometry + * + */ +//============================================================================= + +SMESH::SMESH_Group_ptr SMESH_Mesh_i::ConvertToStandalone( SMESH::SMESH_GroupOnGeom_ptr theGroup ) +{ + SMESH::SMESH_Group_var aGroup; + if ( theGroup->_is_nil() ) + return aGroup._retn(); + + Unexpect aCatch(SALOME_SalomeException); + + SMESH_GroupBase_i* aGroupToRem = + dynamic_cast( SMESH_Gen_i::GetServant( theGroup ).in() ); + if ( !aGroupToRem ) + return aGroup._retn(); + + int anId = aGroupToRem->GetLocalID(); + if ( !_impl->ConvertToStandalone( anId ) ) + return aGroup._retn(); + + SMESH_GroupBase_i* aGroupImpl; + aGroupImpl = new SMESH_Group_i( SMESH_Gen_i::GetPOA(), this, anId ); + + + // remove old instance of group from own map + _mapGroups.erase( anId ); + + SALOMEDS::StudyBuilder_var builder; + SALOMEDS::SObject_var aGroupSO; + SALOMEDS::Study_ptr aStudy = _gen_i->GetCurrentStudy(); + if ( !aStudy->_is_nil() ) { + builder = aStudy->NewBuilder(); + aGroupSO = _gen_i->ObjectToSObject( aStudy, theGroup ); + if ( !aGroupSO->_is_nil() ) { + + // remove reference to geometry + SALOMEDS::ChildIterator_var chItr = aStudy->NewChildIterator(aGroupSO); + for ( ; chItr->More(); chItr->Next() ) + // Remove group's child SObject + builder->RemoveObject( chItr->Value() ); + + // Update Python script + TPythonDump() << aGroupSO << " = " << _this() << ".ConvertToStandalone( " + << aGroupSO << " )"; + } + } + + // PAL7962: san -- To ensure correct mapping of servant and correct reference counting in GenericObj_i + SMESH_Gen_i::GetPOA()->activate_object( aGroupImpl ); + aGroupImpl->Register(); + // PAL7962: san -- To ensure correct mapping of servant and correct reference counting in GenericObj_i + + // remember new group in own map + aGroup = SMESH::SMESH_Group::_narrow( aGroupImpl->_this() ); + _mapGroups[anId] = SMESH::SMESH_GroupBase::_duplicate( aGroup ); + + // register CORBA object for persistence + //int nextId = _gen_i->RegisterObject( aGroup ); + //if(MYDEBUG) MESSAGE( "Add group to map with id = "<< nextId); + builder->SetIOR( aGroupSO, _gen_i->GetORB()->object_to_string( aGroup ) ); + + return aGroup._retn(); +} + //============================================================================= /*! * @@ -1522,22 +2054,14 @@ void SMESH_Mesh_i::ExportToMED (const char* file, { Unexpect aCatch(SALOME_SalomeException); - // Update Python script - TPythonDump() << _this() << ".ExportToMED( '" - << file << "', " << auto_groups << ", " << theVersion << " )"; - // Perform Export PrepareForWriting(file); - char* aMeshName = "Mesh"; + const char* aMeshName = "Mesh"; SALOMEDS::Study_ptr aStudy = _gen_i->GetCurrentStudy(); if ( !aStudy->_is_nil() ) { SALOMEDS::SObject_var aMeshSO = _gen_i->ObjectToSObject( aStudy, _this() ); if ( !aMeshSO->_is_nil() ) { aMeshName = aMeshSO->GetName(); - //SCRUTE(file); - //SCRUTE(aMeshName); - //SCRUTE(aMeshSO->GetID()); - // asv : 27.10.04 : fix of 6903: check for StudyLocked before adding attributes if ( !aStudy->GetProperties()->IsLocked() ) { @@ -1556,6 +2080,16 @@ void SMESH_Mesh_i::ExportToMED (const char* file, } } } + // Update Python script + // set name of mesh before export + TPythonDump() << _gen_i << ".SetName(" << _this() << ", '" << aMeshName << "')"; + + // check names of groups + checkGroupNames(); + + TPythonDump() << _this() << ".ExportToMED( '" + << file << "', " << auto_groups << ", " << theVersion << " )"; + _impl->ExportMED( file, aMeshName, auto_groups, theVersion ); } @@ -1572,6 +2106,8 @@ void SMESH_Mesh_i::ExportDAT (const char *file) Unexpect aCatch(SALOME_SalomeException); // Update Python script + // check names of groups + checkGroupNames(); TPythonDump() << _this() << ".ExportDAT( '" << file << "' )"; // Perform Export @@ -1585,6 +2121,8 @@ void SMESH_Mesh_i::ExportUNV (const char *file) Unexpect aCatch(SALOME_SalomeException); // Update Python script + // check names of groups + checkGroupNames(); TPythonDump() << _this() << ".ExportUNV( '" << file << "' )"; // Perform Export @@ -1598,6 +2136,8 @@ void SMESH_Mesh_i::ExportSTL (const char *file, const bool isascii) Unexpect aCatch(SALOME_SalomeException); // Update Python script + // check names of groups + checkGroupNames(); TPythonDump() << _this() << ".ExportSTL( '" << file << "', " << isascii << " )"; // Perform Export @@ -2534,3 +3074,41 @@ SALOME_MED::MedFileInfo* SMESH_Mesh_i::GetMEDFileInfo() } return res._retn(); } + +//============================================================================= +/*! + * \brief Check and correct names of mesh groups + */ +//============================================================================= + +void SMESH_Mesh_i::checkGroupNames() +{ + int nbGrp = NbGroups(); + if ( !nbGrp ) + return; + + SALOMEDS::Study_ptr aStudy = _gen_i->GetCurrentStudy(); + if ( aStudy->_is_nil() ) + return; // nothing to do + + SMESH::ListOfGroups* grpList = 0; + // avoid dump of "GetGroups" + { + // store python dump into a local variable inside local scope + SMESH::TPythonDump pDump; // do not delete this line of code + grpList = GetGroups(); + } + + for ( int gIndx = 0; gIndx < nbGrp; gIndx++ ) { + SMESH::SMESH_GroupBase_ptr aGrp = (*grpList)[ gIndx ]; + if ( !aGrp ) + continue; + SALOMEDS::SObject_var aGrpSO = _gen_i->ObjectToSObject( aStudy, aGrp ); + if ( aGrpSO->_is_nil() ) + continue; + // correct name of the mesh group if necessary + const char* guiName = aGrpSO->GetName(); + if ( strcmp(guiName, aGrp->GetName()) ) + aGrp->SetName( guiName ); + } +} diff --git a/src/SMESH_I/SMESH_Mesh_i.hxx b/src/SMESH_I/SMESH_Mesh_i.hxx index c820281e5..a0cd6a7d9 100644 --- a/src/SMESH_I/SMESH_Mesh_i.hxx +++ b/src/SMESH_I/SMESH_Mesh_i.hxx @@ -23,7 +23,6 @@ // File : SMESH_Mesh_i.hxx // Author : Paul RASCLE, EDF // Module : SMESH -// $Header$ // #ifndef _SMESH_MESH_I_HXX_ #define _SMESH_MESH_I_HXX_ @@ -76,6 +75,9 @@ public: void Clear() throw (SALOME::SALOME_Exception); + void ClearSubMesh(CORBA::Long ShapeID) + throw (SALOME::SALOME_Exception); + SMESH::Hypothesis_Status AddHypothesis(GEOM::GEOM_Object_ptr aSubShapeObject, SMESH::SMESH_Hypothesis_ptr anHyp) throw (SALOME::SALOME_Exception); @@ -117,17 +119,38 @@ public: SMESH::SMESH_GroupBase_ptr theGroup2, const char* theName ) throw (SALOME::SALOME_Exception); + + SMESH::SMESH_Group_ptr UnionListOfGroups( const SMESH::ListOfGroups& theGroups, + const char* theName) + throw (SALOME::SALOME_Exception); SMESH::SMESH_Group_ptr IntersectGroups( SMESH::SMESH_GroupBase_ptr theGroup1, SMESH::SMESH_GroupBase_ptr theGroup2, const char* theName ) throw (SALOME::SALOME_Exception); + + SMESH::SMESH_Group_ptr IntersectListOfGroups( const SMESH::ListOfGroups& theGroups, + const char* theName ) + throw (SALOME::SALOME_Exception); SMESH::SMESH_Group_ptr CutGroups( SMESH::SMESH_GroupBase_ptr theGroup1, SMESH::SMESH_GroupBase_ptr theGroup2, - const char* theName ) + const char* theName ) throw (SALOME::SALOME_Exception); + SMESH::SMESH_Group_ptr CutListOfGroups( const SMESH::ListOfGroups& theMainGroups, + const SMESH::ListOfGroups& theToolGroups, + const char* theName ) + throw (SALOME::SALOME_Exception); + + SMESH::SMESH_Group_ptr CreateDimGroup( const SMESH::ListOfGroups& theGroups, + SMESH::ElementType theElemType, + const char* theName ) + throw (SALOME::SALOME_Exception); + + + SMESH::SMESH_Group_ptr ConvertToStandalone( SMESH::SMESH_GroupOnGeom_ptr theGeomGroup ); + // SMESH::string_array* GetLog(CORBA::Boolean clearAfterGet) // throw (SALOME::SALOME_Exception); @@ -448,6 +471,12 @@ public: std::map _mapSubMesh_i; //NRI std::map _mapSubMesh; //NRI +private: + /*! + * Check and correct names of mesh groups + */ + void checkGroupNames(); + private: static int myIdGenerator; diff --git a/src/SMESH_I/SMESH_PythonDump.hxx b/src/SMESH_I/SMESH_PythonDump.hxx index c1a2be4e1..1ea9f59ff 100644 --- a/src/SMESH_I/SMESH_PythonDump.hxx +++ b/src/SMESH_I/SMESH_PythonDump.hxx @@ -55,14 +55,15 @@ public: */ static TCollection_AsciiString ConvertScript(const TCollection_AsciiString& theScript, - Resource_DataMapOfAsciiStringAsciiString& theEntry2AccessorMethod); + Resource_DataMapOfAsciiStringAsciiString& theEntry2AccessorMethod, + Resource_DataMapOfAsciiStringAsciiString& theObjectNames); /*! * \brief Return the name of the python file wrapping IDL API * \retval TCollection_AsciiString - The file name */ - static char* SmeshpyName() { return "smesh"; } - static char* GenName() { return "smesh.smesh"; } + static const char* SmeshpyName() { return "smesh"; } + static const char* GenName() { return "smesh.smesh"; } }; namespace SMESH @@ -152,8 +153,8 @@ namespace SMESH TPythonDump& operator<<(const SMESH::ListOfGroups * theList); - static char* SMESHGenName() { return "smeshgen"; } - static char* MeshEditorName() { return "mesh_editor"; } + static const char* SMESHGenName() { return "smeshgen"; } + static const char* MeshEditorName() { return "mesh_editor"; } /*! * \brief Return marker of long string literal beginning diff --git a/src/SMESH_SWIG/Makefile.am b/src/SMESH_SWIG/Makefile.am index 0f2b6cb14..7b6ef9fe4 100644 --- a/src/SMESH_SWIG/Makefile.am +++ b/src/SMESH_SWIG/Makefile.am @@ -23,7 +23,6 @@ # Author : Nicolas REJNERI, Paul RASCLE # Modified by : Alexander BORODIN (OCN) - autotools usage # Module : SMESH -# $Header$ # include $(top_srcdir)/adm_local/unix/make_common_starter.am @@ -58,6 +57,8 @@ dist_salomescript_DATA= \ ex24_cylinder.py \ ex29_refine.py \ ex30_tepal.py \ + ex30_groupsOp.py \ + ex31_dimGroup.py \ SMESH_test.py\ SMESH_test0.py\ SMESH_test1.py \ diff --git a/src/SMESH_SWIG/ex30_groupsOp.py b/src/SMESH_SWIG/ex30_groupsOp.py new file mode 100755 index 000000000..af892e7ff --- /dev/null +++ b/src/SMESH_SWIG/ex30_groupsOp.py @@ -0,0 +1,73 @@ + +import sys +import salome +import geompy +import math +import SALOMEDS +import SMESH +import smesh + +salome.salome_init() +aStudyId = salome.myStudy._get_StudyId() + +geompy.init_geom(salome.myStudy) +global Face_1 +Face_1 = geompy.MakeFaceHW(100, 100, 1) +geompy.addToStudy( Face_1, "Face_1" ) + +#smesh.smesh.SetCurrentStudy(aStudyId) +import StdMeshers +pattern = smesh.GetPattern() +Mesh_1 = smesh.Mesh(Face_1) +Regular_1D = Mesh_1.Segment() +Nb_Segments_1 = Regular_1D.NumberOfSegments(10) +Nb_Segments_1.SetDistrType( 0 ) +Quadrangle_2D = Mesh_1.Quadrangle() +isDone = Mesh_1.Compute() + +# groups creation + +aListOfElems = [ 52, 53, 54, 55, 56, 57, + 62, 63, 64, 65, 66, 67, + 72, 73, 74, 75, 76, 77, + 82, 83, 84, 85, 86, 87 ] + +aRedGroup = Mesh_1.GetMesh().CreateGroup( smesh.FACE, "Red" ) +aRedGroup.Add( aListOfElems ); +aRedGroup.SetColor( SALOMEDS.Color( 1, 0, 0 ) ) + +aListOfElems = [ 55, 56, 57, 58, 59, + 65, 66, 67, 68, 69, + 75, 76, 77, 78, 79, + 85, 86, 87, 88, 89, + 95, 96, 97, 98, 99, + 105, 106, 107, 108, 109, + 115, 116, 117, 118, 119, + 125, 126, 127, 128, 129 ] + +aGreenGroup = Mesh_1.GetMesh().CreateGroup( smesh.FACE, "Green" ) +aGreenGroup.Add( aListOfElems ); +aGreenGroup.SetColor( SALOMEDS.Color( 0, 1, 0 ) ) + +aListOfElems = [ 63, 64, 65, 66, 67, 68, + 73, 74, 75, 76, 77, 78, + 83, 84, 85, 86, 87, 88, + 93, 94, 95, 96, 97, 98, + 103, 104, 105, 106, 107, 108, + 113, 114, 115, 116, 117, 118 ] + +aBlueGroup = Mesh_1.GetMesh().CreateGroup( smesh.FACE, "Blue" ) +aBlueGroup.Add( aListOfElems ); +aBlueGroup.SetColor( SALOMEDS.Color( 0, 0, 1 ) ) + +# UnionListOfGroups() +aUnGrp = Mesh_1.UnionListOfGroups([aRedGroup, aGreenGroup, aBlueGroup], "UnionGrp" ) + +# IntersectListOfGroups() +aIntGrp=Mesh_1.IntersectListOfGroups([aRedGroup, aGreenGroup, aBlueGroup], "IntGrp" ) + +# CutListOfGroups() +aCutGrp=Mesh_1.CutListOfGroups([aRedGroup],[aGreenGroup,aBlueGroup],"CutGrp") + +salome.sg.updateObjBrowser( 1 ) + diff --git a/src/SMESH_SWIG/ex31_dimGroup.py b/src/SMESH_SWIG/ex31_dimGroup.py new file mode 100755 index 000000000..13cd9cf26 --- /dev/null +++ b/src/SMESH_SWIG/ex31_dimGroup.py @@ -0,0 +1,47 @@ +import sys +import salome +import geompy +import math +import SALOMEDS +import SMESH +import smesh + +salome.salome_init() +aStudyId = salome.myStudy._get_StudyId() + +geompy.init_geom(salome.myStudy) + +geompy.init_geom(salome.myStudy) +global Box_1 +Box_1 = geompy.MakeBoxDXDYDZ(200, 200, 200) +geompy.addToStudy( Box_1, "Box_1" ) + +#smesh.smesh.SetCurrentStudy(theStudy) +import StdMeshers +Mesh_1 = smesh.Mesh(Box_1) +Regular_1D = Mesh_1.Segment() +Nb_Segments_1 = Regular_1D.NumberOfSegments(10) +Nb_Segments_1.SetDistrType( 0 ) +Quadrangle_2D = Mesh_1.Quadrangle() +Hexa_3D = Mesh_1.Hexahedron() +isDone = Mesh_1.Compute() + +### CreateDimGroup() + +aListOf3d_1=range(721,821) + +aGrp3D_1=Mesh_1.GetMesh().CreateGroup( smesh.VOLUME, "Src 3D 1" ) +aGrp3D_1.Add( aListOf3d_1 ) + +aListOf3d_2=range(821, 921) +aGrp3D_2=Mesh_1.GetMesh().CreateGroup( smesh.VOLUME, "Src 3D 2" ) +aGrp3D_2.Add( aListOf3d_2 ) + +aGrp2D = Mesh_1.CreateDimGroup( [aGrp3D_1, aGrp3D_2], smesh.FACE, "Faces" ) + +aGrp1D = Mesh_1.CreateDimGroup( [aGrp3D_1, aGrp3D_2], smesh.EDGE, "Edges" ) + +aGrp0D = Mesh_1.CreateDimGroup( [aGrp3D_1, aGrp3D_2], smesh.NODE, "Nodes" ) + +salome.sg.updateObjBrowser( 1 ) + diff --git a/src/SMESH_SWIG/smeshDC.py b/src/SMESH_SWIG/smeshDC.py index db8a34ccd..e956e3c43 100644 --- a/src/SMESH_SWIG/smeshDC.py +++ b/src/SMESH_SWIG/smeshDC.py @@ -175,18 +175,6 @@ def GetName(obj): attr = sobj.FindAttribute("AttributeName")[1] return attr.Value() -## Sets a name to the object -def SetName(obj, name): - if isinstance( obj, Mesh ): - obj = obj.GetMesh() - elif isinstance( obj, Mesh_Algorithm ): - obj = obj.GetAlgorithm() - ior = salome.orb.object_to_string(obj) - sobj = salome.myStudy.FindObjectIOR(ior) - if not sobj is None: - attr = sobj.FindAttribute("AttributeName")[1] - attr.SetValue(name) - ## Prints error message if a hypothesis was not assigned. def TreatHypoStatus(status, hypName, geomName, isAlgo): if isAlgo: @@ -317,6 +305,19 @@ class smeshDC(SMESH._objref_SMESH_Gen): # From SMESH_Gen interface: # ------------------------ + ## Sets the given name to the object + # @param obj the object to rename + # @param name a new object name + # @ingroup l1_auxiliary + def SetName(self, obj, name): + print "obj_name = ", name + if isinstance( obj, Mesh ): + obj = obj.GetMesh() + elif isinstance( obj, Mesh_Algorithm ): + obj = obj.GetAlgorithm() + ior = salome.orb.object_to_string(obj) + SMESH._objref_SMESH_Gen.SetName(self, ior, name) + ## Sets the current mode # @ingroup l1_auxiliary def SetEmbeddedMode( self,theMode ): @@ -406,6 +407,13 @@ class smeshDC(SMESH._objref_SMESH_Gen): def GetPattern(self): return SMESH._objref_SMESH_Gen.GetPattern(self) + ## Sets number of segments per diagonal of boundary box of geometry by which + # default segment length of appropriate 1D hypotheses is defined. + # Default value is 10 + # @ingroup l1_auxiliary + def SetBoundaryBoxSegmentation(self, nbSegments): + SMESH._objref_SMESH_Gen.SetBoundaryBoxSegmentation(self,nbSegments) + # Filtering. Auxiliary functions: # ------------------------------ @@ -477,7 +485,8 @@ class smeshDC(SMESH._objref_SMESH_Gen): else: print "Error: The treshold should be a string." return None - elif CritType in [FT_FreeBorders, FT_FreeEdges, FT_BadOrientedVolume]: + elif CritType in [FT_FreeBorders, FT_FreeEdges, FT_BadOrientedVolume, FT_FreeNodes, + FT_FreeFaces, FT_ElemGeomType, FT_GroupColor]: # At this point the treshold is unnecessary if aTreshold == FT_LogicalNOT: aCriterion.UnaryOp = self.EnumToLong(FT_LogicalNOT) @@ -560,6 +569,12 @@ class smeshDC(SMESH._objref_SMESH_Gen): else: print "Error: given parameter is not numerucal functor type." + ## Creates hypothesis + # @param + # @param + # @return created hypothesis instance + def CreateHypothesis(self, theHType, theLibName="libStdMeshersEngine.so"): + return SMESH._objref_SMESH_Gen.CreateHypothesis(self, theHType, theLibName ) import omniORB #Registering the new proxy for SMESH_Gen @@ -603,9 +618,9 @@ class Mesh: else: self.mesh = self.smeshpyD.CreateEmptyMesh() if name != 0: - SetName(self.mesh, name) + self.smeshpyD.SetName(self.mesh, name) elif obj != 0: - SetName(self.mesh, GetName(obj)) + self.smeshpyD.SetName(self.mesh, GetName(obj)) if not self.geom: self.geom = self.mesh.GetShapeToMesh() @@ -636,7 +651,7 @@ class Mesh: # @param name a new name of the mesh # @ingroup l2_construct def SetName(self, name): - SetName(self.GetMesh(), name) + self.smeshpyD.SetName(self.GetMesh(), name) ## Gets the subMesh object associated to a \a theSubObject geometrical object. # The subMesh object gives access to the IDs of nodes and elements. @@ -931,6 +946,16 @@ class Mesh: smeshgui.SetMeshIcon( salome.ObjectToID( self.mesh ), False, True ) salome.sg.updateObjBrowser(1) + ## Removes all nodes and elements of indicated shape + # @ingroup l2_construct + def ClearSubMesh(self, geomId): + self.mesh.ClearSubMesh(geomId) + if salome.sg.hasDesktop(): + smeshgui = salome.ImportComponentGUI("SMESH") + smeshgui.Init(salome.myStudyId) + smeshgui.SetMeshIcon( salome.ObjectToID( self.mesh ), False, True ) + salome.sg.updateObjBrowser(1) + ## Computes a tetrahedral mesh using AutomaticLength + MEFISTO + NETGEN # @param fineness [0,-1] defines mesh fineness # @return True or False @@ -1245,7 +1270,15 @@ class Mesh: # @ingroup l2_grps_operon def UnionGroups(self, group1, group2, name): return self.mesh.UnionGroups(group1, group2, name) - + + ## Produces a union list of groups + # New group is created. All mesh elements that are present in + # initial groups are added to the new one + # @return an instance of SMESH_Group + # @ingroup l2_grps_operon + def UnionListOfGroups(self, groups, name): + return self.mesh.UnionListOfGroups(groups, name) + ## Prodices an intersection of two groups # A new group is created. All mesh elements that are common # for the two initial groups are added to the new one. @@ -1253,15 +1286,45 @@ class Mesh: # @ingroup l2_grps_operon def IntersectGroups(self, group1, group2, name): return self.mesh.IntersectGroups(group1, group2, name) + + ## Produces an intersection of groups + # New group is created. All mesh elements that are present in all + # initial groups simultaneously are added to the new one + # @return an instance of SMESH_Group + # @ingroup l2_grps_operon + def IntersectListOfGroups(self, groups, name): + return self.mesh.IntersectListOfGroups(groups, name) ## Produces a cut of two groups # A new group is created. All mesh elements that are present in # the main group but are not present in the tool group are added to the new one # @return an instance of SMESH_Group # @ingroup l2_grps_operon - def CutGroups(self, mainGroup, toolGroup, name): - return self.mesh.CutGroups(mainGroup, toolGroup, name) + def CutGroups(self, main_group, tool_group, name): + return self.mesh.CutGroups(main_group, tool_group, name) + + ## Produces a cut of groups + # A new group is created. All mesh elements that are present in main groups + # but do not present in tool groups are added to the new one + # @return an instance of SMESH_Group + # @ingroup l2_grps_operon + def CutListOfGroups(self, main_groups, tool_groups, name): + return self.mesh.CutListOfGroups(main_groups, tool_groups, name) + + ## Produces a group of elements with specified element type using list of existing groups + # A new group is created. System + # 1) extract all nodes on which groups elements are built + # 2) combine all elements of specified dimension laying on these nodes + # @return an instance of SMESH_Group + # @ingroup l2_grps_operon + def CreateDimGroup(self, groups, elem_type, name): + return self.mesh.CreateDimGroup(groups, elem_type, name) + + ## Convert group on geom into standalone group + # @ingroup l2_grps_delete + def ConvertToStandalone(self, group): + return self.mesh.ConvertToStandalone(group) # Get some info about mesh: # ------------------------ @@ -2718,6 +2781,43 @@ class Mesh: # @ingroup l1_auxiliary def GetLastCreatedElems(self): return self.editor.GetLastCreatedElems() + + ## Creates a hole in a mesh by doubling the nodes of some particular elements + # @param theNodes identifiers of nodes to be doubled + # @param theModifiedElems identifiers of elements to be updated by the new (doubled) + # nodes. If list of element identifiers is empty then nodes are doubled but + # they not assigned to elements + # @return TRUE if operation has been completed successfully, FALSE otherwise + # @ingroup l2_modif_edit + def DoubleNodes(self, theNodes, theModifiedElems): + return self.editor.DoubleNodes(theNodes, theModifiedElems) + + ## Creates a hole in a mesh by doubling the nodes of some particular elements + # This method provided for convenience works as DoubleNodes() described above. + # @param theNodes identifiers of node to be doubled + # @param theModifiedElems identifiers of elements to be updated + # @return TRUE if operation has been completed successfully, FALSE otherwise + # @ingroup l2_modif_edit + def DoubleNode(self, theNodeId, theModifiedElems): + return self.editor.DoubleNode(theNodeId, theModifiedElems) + + ## Creates a hole in a mesh by doubling the nodes of some particular elements + # This method provided for convenience works as DoubleNodes() described above. + # @param theNodes group of nodes to be doubled + # @param theModifiedElems group of elements to be updated. + # @return TRUE if operation has been completed successfully, FALSE otherwise + # @ingroup l2_modif_edit + def DoubleNodeGroup(self, theNodes, theModifiedElems): + return self.editor.DoubleNodeGroup(theNodes, theModifiedElems) + + ## Creates a hole in a mesh by doubling the nodes of some particular elements + # This method provided for convenience works as DoubleNodes() described above. + # @param theNodes list of groups of nodes to be doubled + # @param theModifiedElems list of groups of elements to be updated. + # @return TRUE if operation has been completed successfully, FALSE otherwise + # @ingroup l2_modif_edit + def DoubleNodeGroups(self, theNodes, theModifiedElems): + return self.editor.DoubleNodeGroups(theNodes, theModifiedElems) ## The mother class to define algorithm, it is not recommended to use it directly. # @@ -2838,7 +2938,7 @@ class Mesh_Algorithm: ## Sets the name to the algorithm def SetName(self, name): - SetName(self.algo, name) + self.mesh.smeshpyD.SetName(self.algo, name) ## Gets the id of the algorithm def GetId(self): @@ -2901,7 +3001,7 @@ class Mesh_Algorithm: s = "," i = i + 1 pass - SetName(hypo, hyp + a) + self.mesh.smeshpyD.SetName(hypo, hyp + a) pass status = self.mesh.mesh.AddHypothesis(self.geom, hypo) TreatHypoStatus( status, GetName(hypo), GetName(self.geom), 0 ) @@ -2951,6 +3051,32 @@ class Mesh_Segment(Mesh_Algorithm): return IsEqual(hyp.GetPrecision(), args[1]) return False + ## Defines "MaxSize" hypothesis to cut an edge into segments not longer than given value + # @param length is optional maximal allowed length of segment, if it is omitted + # the preestimated length is used that depends on geometry size + # @param UseExisting if ==true - searches for an existing hypothesis created with + # the same parameters, else (default) - create a new one + # @return an instance of StdMeshers_MaxLength hypothesis + # @ingroup l3_hypos_1dhyps + def MaxSize(self, length=0.0, UseExisting=0): + hyp = self.Hypothesis("MaxLength", [length], UseExisting=UseExisting) + if length > 0.0: + # set given length + hyp.SetLength(length) + if not UseExisting: + # set preestimated length + gen = self.mesh.smeshpyD + initHyp = gen.GetHypothesisParameterValues("MaxLength", "libStdMeshersEngine.so", + self.mesh.GetMesh(), self.mesh.GetShape(), + False) # <- byMesh + preHyp = initHyp._narrow(StdMeshers.StdMeshers_MaxLength) + if preHyp: + hyp.SetPreestimatedLength( preHyp.GetPreestimatedLength() ) + pass + pass + hyp.SetUsePreestimatedLength( length == 0.0 ) + return hyp + ## Defines "NumberOfSegments" hypothesis to cut an edge in a fixed number of segments # @param n for the number of segments that cut an edge # @param s for the scale factor (optional) diff --git a/src/StdMeshers/Makefile.am b/src/StdMeshers/Makefile.am index ddf7bd64f..8b86e0958 100644 --- a/src/StdMeshers/Makefile.am +++ b/src/StdMeshers/Makefile.am @@ -66,7 +66,9 @@ salomeinclude_HEADERS = \ StdMeshers_UseExisting_1D2D.hxx \ StdMeshers_QuadToTriaAdaptor.hxx \ SMESH_StdMeshers.hxx \ - StdMeshers_TrianglePreference.hxx + StdMeshers_TrianglePreference.hxx \ + StdMeshers_CompositeHexa_3D.hxx \ + StdMeshers_MaxLength.hxx # Libraries targets @@ -109,7 +111,9 @@ dist_libStdMeshers_la_SOURCES = \ StdMeshers_CompositeSegment_1D.cxx \ StdMeshers_UseExisting_1D2D.cxx \ StdMeshers_QuadToTriaAdaptor.cxx \ - StdMeshers_TrianglePreference.cxx + StdMeshers_TrianglePreference.cxx \ + StdMeshers_CompositeHexa_3D.cxx \ + StdMeshers_MaxLength.cxx # additionnal information to compil and link file diff --git a/src/StdMeshers/StdMeshers_Arithmetic1D.cxx b/src/StdMeshers/StdMeshers_Arithmetic1D.cxx index f13cf571b..5b63f922b 100644 --- a/src/StdMeshers/StdMeshers_Arithmetic1D.cxx +++ b/src/StdMeshers/StdMeshers_Arithmetic1D.cxx @@ -23,7 +23,6 @@ // File : StdMeshers_Arithmetic1D.cxx // Author : Damien COQUERET, OCC // Module : SMESH -// $Header$ // #include "StdMeshers_Arithmetic1D.hxx" @@ -196,3 +195,17 @@ bool StdMeshers_Arithmetic1D::SetParametersByMesh(const SMESH_Mesh* theMesh, } return nbEdges; } + +//================================================================================ +/*! + * \brief Initialize my parameter values by linear size of mesh element. + * \retval bool - true if parameter values have been successfully defined + */ +//================================================================================ + +bool StdMeshers_Arithmetic1D::SetParametersByElementSize(double elemLenght, + const SMESH_Mesh* /*mesh*/) +{ + return bool( _begLength = _endLength = elemLenght ); +} + diff --git a/src/StdMeshers/StdMeshers_Arithmetic1D.hxx b/src/StdMeshers/StdMeshers_Arithmetic1D.hxx index 04c136503..fb8075d1c 100644 --- a/src/StdMeshers/StdMeshers_Arithmetic1D.hxx +++ b/src/StdMeshers/StdMeshers_Arithmetic1D.hxx @@ -23,7 +23,6 @@ // File : StdMeshers_Arithmetic1D.hxx // Author : Damien COQUERET, OCC // Module : SMESH -// $Header$ // #ifndef _SMESH_ARITHMETIC1D_HXX_ #define _SMESH_ARITHMETIC1D_HXX_ @@ -57,6 +56,12 @@ public: */ virtual bool SetParametersByMesh(const SMESH_Mesh* theMesh, const TopoDS_Shape& theShape); + /*! + * \brief Initialize my parameter values by linear size of mesh element. + * \retval bool - true if parameter values have been successfully defined + */ + virtual bool SetParametersByElementSize( double elemLenght, const SMESH_Mesh* theMesh=0); + protected: double _begLength, _endLength; }; diff --git a/src/StdMeshers/StdMeshers_AutomaticLength.cxx b/src/StdMeshers/StdMeshers_AutomaticLength.cxx index 8e2fab30c..3e91de780 100644 --- a/src/StdMeshers/StdMeshers_AutomaticLength.cxx +++ b/src/StdMeshers/StdMeshers_AutomaticLength.cxx @@ -23,7 +23,6 @@ // File : StdMeshers_AutomaticLength.cxx // Author : Edward AGAPOV, OCC // Module : SMESH -// $Header$ // #include "StdMeshers_AutomaticLength.hxx" @@ -367,3 +366,37 @@ bool StdMeshers_AutomaticLength::SetParametersByMesh(const SMESH_Mesh* theMesh return nbEdges; } + +//================================================================================ +/*! + * \brief Initialize my parameter values by linear size of mesh element. + * \retval bool - true if parameter values have been successfully defined + */ +//================================================================================ + +bool StdMeshers_AutomaticLength::SetParametersByElementSize(double elemLenght, + const SMESH_Mesh* theMesh) +{ + return false; + + // assure the base automatic length is stored in _TShapeToLength +// GetLength( theMesh, elemLenght ); + +// // find maximal edge length +// double maxLen = 0; +// map::iterator +// tshape_length = _TShapeToLength.begin(), slEnd = _TShapeToLength.end(); +// for ( ; tshape_length != slEnd; ++tshape_length ) +// if ( tshape_length->second > maxLen ) +// maxLen = tshape_length->second; + +// // automatic length for longest element +// double autoLen = GetLength( theMesh, maxLen ); + +// // elemLenght = autoLen / (theCoarseConst + theFineConst * _fineness) --> +// _fineness = ( autoLen / elemLenght - theCoarseConst ) / theFineConst; + +// return true; +} + + diff --git a/src/StdMeshers/StdMeshers_AutomaticLength.hxx b/src/StdMeshers/StdMeshers_AutomaticLength.hxx index 387c8b58e..1ce7d30d5 100644 --- a/src/StdMeshers/StdMeshers_AutomaticLength.hxx +++ b/src/StdMeshers/StdMeshers_AutomaticLength.hxx @@ -23,8 +23,7 @@ // File : StdMeshers_AutomaticLength.hxx // Author : Edward AGAPOV, OCC // Module : SMESH -// $Header$ -// + #ifndef _SMESH_AutomaticLength_HXX_ #define _SMESH_AutomaticLength_HXX_ @@ -96,6 +95,12 @@ public: */ virtual bool SetParametersByMesh(const SMESH_Mesh* theMesh, const TopoDS_Shape& theShape); + /*! + * \brief Initialize my parameter values by linear size of mesh element. + * \retval bool - true if parameter values have been successfully defined + */ + virtual bool SetParametersByElementSize( double elemLenght, const SMESH_Mesh* theMesh=0); + protected: std::map _TShapeToLength; const SMESH_Mesh* _mesh; diff --git a/src/StdMeshers/StdMeshers_CompositeHexa_3D.cxx b/src/StdMeshers/StdMeshers_CompositeHexa_3D.cxx new file mode 100644 index 000000000..42acee19e --- /dev/null +++ b/src/StdMeshers/StdMeshers_CompositeHexa_3D.cxx @@ -0,0 +1,1526 @@ +// SMESH SMESH : implementaion of SMESH idl descriptions +// +// Copyright (C) 2003 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, +// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// File : StdMeshers_CompositeHexa_3D.cxx +// Module : SMESH +// Created : Tue Nov 25 11:04:59 2008 +// Author : Edward AGAPOV (eap) + +#include "StdMeshers_CompositeHexa_3D.hxx" + +#include "SMDS_Mesh.hxx" +#include "SMDS_MeshNode.hxx" +#include "SMDS_SetIterator.hxx" +#include "SMESH_Block.hxx" +#include "SMESH_Comment.hxx" +#include "SMESH_ComputeError.hxx" +#include "SMESH_Mesh.hxx" +#include "SMESH_MeshEditor.hxx" +#include "SMESH_MesherHelper.hxx" +#include "SMESH_subMesh.hxx" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + + +#ifdef _DEBUG_ + +// #define DEB_FACES +// #define DEB_GRID +#define DUMP_VERT(msg,V) \ +// { TopoDS_Vertex v = V; gp_Pnt p = BRep_Tool::Pnt(v);\ +// cout << msg << "( "<< p.X()<<", "<& edges); + _FaceSide* GetSide(const int i); + const _FaceSide* GetSide(const int i) const; + int size() { return myChildren.size(); } + int NbVertices() const; + TopoDS_Vertex FirstVertex() const; + TopoDS_Vertex LastVertex() const; + TopoDS_Vertex Vertex(int i) const; + bool Contain( const _FaceSide& side, int* which=0 ) const; + bool Contain( const TopoDS_Vertex& vertex ) const; + void AppendSide( const _FaceSide& side ); + void SetBottomSide( int i ); + int GetNbSegments(SMESH_Mesh& mesh) const; + bool StoreNodes(SMESH_Mesh& mesh, vector& myGrid, bool reverse ); + void SetID(EQuadSides id) { myID = id; } + static inline const TopoDS_TShape* ptr(const TopoDS_Shape& theShape) + { return theShape.TShape().operator->(); } + void Dump() const; + +private: + + + TopoDS_Edge myEdge; + list< _FaceSide > myChildren; + int myNbChildren; + + //set myVertices; + TopTools_MapOfShape myVertices; + + EQuadSides myID; // debug +}; +//================================================================================ +/*! + * \brief Class corresponding to a meshed composite face of a box. + * Provides simplified access to it's sub-mesh data. + */ +class _QuadFaceGrid +{ + typedef list< _QuadFaceGrid > TChildren; +public: + _QuadFaceGrid(); + +public: //** Methods to find and orient faces of 6 sides of the box **// + + //!< initialization + bool Init(const TopoDS_Face& f); + + //!< try to unite self with other face + bool AddContinuousFace( const _QuadFaceGrid& f ); + + //!< Try to set the side as bottom hirizontal side + bool SetBottomSide(const _FaceSide& side, int* sideIndex=0); + + //!< Return face adjacent to i-th side of this face + _QuadFaceGrid* FindAdjacentForSide(int i, vector<_QuadFaceGrid>& faces) const; // (0 TChildIterator; + + TChildIterator GetChildren() const + { return TChildIterator( myChildren.begin(), myChildren.end()); } + +public: //** Loading and access to mesh **// + + //!< Load nodes of a mesh + bool LoadGrid( SMESH_Mesh& mesh ); + + //!< Return number of segments on the hirizontal sides + int GetNbHoriSegments(SMESH_Mesh& mesh, bool withBrothers=false) const; + + //!< Return number of segments on the vertical sides + int GetNbVertSegments(SMESH_Mesh& mesh, bool withBrothers=false) const; + + //!< Return a node by its position + const SMDS_MeshNode* GetNode(int iHori, int iVert) const; + + //!< Return node coordinates by its position + gp_XYZ GetXYZ(int iHori, int iVert) const; + +public: //** Access to member fields **// + + //!< Return i-th face side (0IsOK() ); } + + bool loadCompositeGrid(SMESH_Mesh& mesh); + + bool fillGrid(SMESH_Mesh& theMesh, + vector & theGrid, + const _Indexer& theIndexer, + int theX, + int theY); + + bool locateChildren(); + + void setBrothers( set< _QuadFaceGrid* >& notLocatedBrothers ); + + TopoDS_Face myFace; + _FaceSide mySides; + bool myReverse; + + TChildren myChildren; + + _QuadFaceGrid* myLeftBottomChild; + _QuadFaceGrid* myRightBrother; + _QuadFaceGrid* myUpBrother; + + _Indexer myIndexer; + vector myGrid; + + SMESH_ComputeErrorPtr myError; + + EBoxSides myID; // debug +}; + +//================================================================================ +/*! + * \brief Constructor + */ +//================================================================================ + +StdMeshers_CompositeHexa_3D::StdMeshers_CompositeHexa_3D(int hypId, int studyId, SMESH_Gen* gen) + :SMESH_3D_Algo(hypId, studyId, gen) +{ + _name = "CompositeHexa_3D"; + _shapeType = (1 << TopAbs_SHELL) | (1 << TopAbs_SOLID); // 1 bit /shape type +} + +//================================================================================ +/*! + * \brief always return true + */ +//================================================================================ + +bool StdMeshers_CompositeHexa_3D::CheckHypothesis(SMESH_Mesh& aMesh, + const TopoDS_Shape& aShape, + Hypothesis_Status& aStatus) +{ + aStatus = HYP_OK; + return true; +} + +//================================================================================ +/*! + * \brief Computes hexahedral mesh on a box with composite sides + * \param aMesh - mesh to compute + * \param aShape - shape to mesh + * \retval bool - succes sign + */ +//================================================================================ + +bool StdMeshers_CompositeHexa_3D::Compute(SMESH_Mesh& theMesh, + const TopoDS_Shape& theShape) +{ + SMESH_MesherHelper helper( theMesh ); + _quadraticMesh = helper.IsQuadraticSubMesh( theShape ); + helper.SetElementsOnShape( true ); + + // ------------------------- + // Try to find 6 side faces + // ------------------------- + vector< _QuadFaceGrid > boxFaces; boxFaces.reserve( 6 ); + TopExp_Explorer exp; + int iFace, nbFaces = 0; + for ( exp.Init(theShape, TopAbs_FACE); exp.More(); exp.Next(), ++nbFaces ) + { + _QuadFaceGrid f; + if ( !f.Init( TopoDS::Face( exp.Current() ))) + return error (COMPERR_BAD_SHAPE); + bool isContinuous = false; + for ( int i=0; i < boxFaces.size() && !isContinuous; ++i ) + isContinuous = boxFaces[ i ].AddContinuousFace( f ); + if ( !isContinuous ) + boxFaces.push_back( f ); + } + // Check what we have + if ( boxFaces.size() != 6 && nbFaces != 6) + return error + (COMPERR_BAD_SHAPE, + SMESH_Comment("Can't find 6 sides of a box. Number of found sides - ")<FindAdjacentForSide( Q_BOTTOM, boxFaces ); + fLeft = fBottom->FindAdjacentForSide( Q_RIGHT, boxFaces ); + fBack = fBottom->FindAdjacentForSide( Q_TOP, boxFaces ); + fRight = fBottom->FindAdjacentForSide( Q_LEFT, boxFaces ); + // check the found + if ( !fFront || !fBack || !fLeft || !fRight ) + return error(COMPERR_BAD_SHAPE); + // top face + fTop = 0; + for ( int i=1; i < boxFaces.size() && !fTop; ++i ) { + fTop = & boxFaces[ i ]; + if ( fTop==fFront || fTop==fLeft || fTop==fBack || fTop==fRight ) + fTop = 0; + } + // set bottom of the top side + if ( !fTop->SetBottomSide( fFront->GetSide( Q_TOP ) )) { + if ( !fFront->IsComplex() ) + return error( ERR_LI("Error in StdMeshers_CompositeHexa_3D::Compute()")); + else { + _QuadFaceGrid::TChildIterator chIt = fFront->GetChildren(); + while ( chIt.more() ) { + const _QuadFaceGrid& frontChild = chIt.next(); + if ( fTop->SetBottomSide( frontChild.GetSide( Q_TOP ))) + break; + } + } + } + if ( !fTop ) + return error(COMPERR_BAD_SHAPE); + + fBottom->SetID( B_BOTTOM ); + fBack ->SetID( B_BACK ); + fLeft ->SetID( B_LEFT ); + fFront ->SetID( B_FRONT ); + fRight ->SetID( B_RIGHT ); + fTop ->SetID( B_TOP ); + + // orient bottom egde of faces along axes of the unit box + fBottom->ReverseEdges(); + fBack ->ReverseEdges(); + fLeft ->ReverseEdges(); + + // ------------------------------------------ + // Fill columns of nodes with existing nodes + // ------------------------------------------ + + // let faces load their grids + if ( !fBottom->LoadGrid( theMesh )) return error( fBottom->GetError() ); + if ( !fBack ->LoadGrid( theMesh )) return error( fBack ->GetError() ); + if ( !fLeft ->LoadGrid( theMesh )) return error( fLeft ->GetError() ); + if ( !fFront ->LoadGrid( theMesh )) return error( fFront ->GetError() ); + if ( !fRight ->LoadGrid( theMesh )) return error( fRight ->GetError() ); + if ( !fTop ->LoadGrid( theMesh )) return error( fTop ->GetError() ); + + int x, xSize = fBottom->GetNbHoriSegments(theMesh) + 1, X = xSize - 1; + int y, ySize = fBottom->GetNbVertSegments(theMesh) + 1, Y = ySize - 1; + int z, zSize = fFront ->GetNbVertSegments(theMesh) + 1, Z = zSize - 1; + _Indexer colIndex( xSize, ySize ); + vector< vector< const SMDS_MeshNode* > > columns( colIndex.size() ); + + // fill node columns by front and back box sides + for ( x = 0; x < xSize; ++x ) { + vector< const SMDS_MeshNode* >& column0 = columns[ colIndex( x, 0 )]; + vector< const SMDS_MeshNode* >& column1 = columns[ colIndex( x, Y )]; + column0.resize( zSize ); + column1.resize( zSize ); + for ( z = 0; z < zSize; ++z ) { + column0[ z ] = fFront->GetNode( x, z ); + column1[ z ] = fBack ->GetNode( x, z ); + } + } + // fill node columns by left and right box sides + for ( y = 1; y < ySize-1; ++y ) { + vector< const SMDS_MeshNode* >& column0 = columns[ colIndex( 0, y )]; + vector< const SMDS_MeshNode* >& column1 = columns[ colIndex( X, y )]; + column0.resize( zSize ); + column1.resize( zSize ); + for ( z = 0; z < zSize; ++z ) { + column0[ z ] = fLeft ->GetNode( y, z ); + column1[ z ] = fRight->GetNode( y, z ); + } + } + // get nodes from top and bottom box sides + for ( x = 1; x < xSize-1; ++x ) { + for ( y = 1; y < ySize-1; ++y ) { + vector< const SMDS_MeshNode* >& column = columns[ colIndex( x, y )]; + column.resize( zSize ); + column.front() = fBottom->GetNode( x, y ); + column.back() = fTop ->GetNode( x, y ); + } + } + + // ---------------------------- + // Add internal nodes of a box + // ---------------------------- + // projection points of internal nodes on box subshapes by which + // coordinates of internal nodes are computed + vector pointsOnShapes( SMESH_Block::ID_Shell ); + + // projections on vertices are constant + pointsOnShapes[ SMESH_Block::ID_V000 ] = fBottom->GetXYZ( 0, 0 ); + pointsOnShapes[ SMESH_Block::ID_V100 ] = fBottom->GetXYZ( X, 0 ); + pointsOnShapes[ SMESH_Block::ID_V010 ] = fBottom->GetXYZ( 0, Y ); + pointsOnShapes[ SMESH_Block::ID_V110 ] = fBottom->GetXYZ( X, Y ); + pointsOnShapes[ SMESH_Block::ID_V001 ] = fTop->GetXYZ( 0, 0 ); + pointsOnShapes[ SMESH_Block::ID_V101 ] = fTop->GetXYZ( X, 0 ); + pointsOnShapes[ SMESH_Block::ID_V011 ] = fTop->GetXYZ( 0, Y ); + pointsOnShapes[ SMESH_Block::ID_V111 ] = fTop->GetXYZ( X, Y ); + + for ( x = 1; x < xSize-1; ++x ) + { + gp_XYZ params; // normalized parameters of internal node within a unit box + params.SetCoord( 1, x / double(X) ); + for ( y = 1; y < ySize-1; ++y ) + { + params.SetCoord( 2, y / double(Y) ); + // column to fill during z loop + vector< const SMDS_MeshNode* >& column = columns[ colIndex( x, y )]; + // points projections on horizontal edges + pointsOnShapes[ SMESH_Block::ID_Ex00 ] = fBottom->GetXYZ( x, 0 ); + pointsOnShapes[ SMESH_Block::ID_Ex10 ] = fBottom->GetXYZ( x, Y ); + pointsOnShapes[ SMESH_Block::ID_E0y0 ] = fBottom->GetXYZ( 0, y ); + pointsOnShapes[ SMESH_Block::ID_E1y0 ] = fBottom->GetXYZ( X, y ); + pointsOnShapes[ SMESH_Block::ID_Ex01 ] = fTop->GetXYZ( x, 0 ); + pointsOnShapes[ SMESH_Block::ID_Ex11 ] = fTop->GetXYZ( x, Y ); + pointsOnShapes[ SMESH_Block::ID_E0y1 ] = fTop->GetXYZ( 0, y ); + pointsOnShapes[ SMESH_Block::ID_E1y1 ] = fTop->GetXYZ( X, y ); + // points projections on horizontal faces + pointsOnShapes[ SMESH_Block::ID_Fxy0 ] = fBottom->GetXYZ( x, y ); + pointsOnShapes[ SMESH_Block::ID_Fxy1 ] = fTop ->GetXYZ( x, y ); + for ( z = 1; z < zSize-1; ++z ) // z loop + { + params.SetCoord( 3, z / double(Z) ); + // point projections on vertical edges + pointsOnShapes[ SMESH_Block::ID_E00z ] = fFront->GetXYZ( 0, z ); + pointsOnShapes[ SMESH_Block::ID_E10z ] = fFront->GetXYZ( X, z ); + pointsOnShapes[ SMESH_Block::ID_E01z ] = fBack->GetXYZ( 0, z ); + pointsOnShapes[ SMESH_Block::ID_E11z ] = fBack->GetXYZ( X, z ); + // point projections on vertical faces + pointsOnShapes[ SMESH_Block::ID_Fx0z ] = fFront->GetXYZ( x, z ); + pointsOnShapes[ SMESH_Block::ID_Fx1z ] = fBack ->GetXYZ( x, z ); + pointsOnShapes[ SMESH_Block::ID_F0yz ] = fLeft ->GetXYZ( y, z ); + pointsOnShapes[ SMESH_Block::ID_F1yz ] = fRight->GetXYZ( y, z ); + + // compute internal node coordinates + gp_XYZ coords; + SMESH_Block::ShellPoint( params, pointsOnShapes, coords ); + column[ z ] = helper.AddNode( coords.X(), coords.Y(), coords.Z() ); + +#ifdef DEB_GRID + // debug + //cout << "----------------------------------------------------------------------"<& col00 = columns[ colIndex( x, y )]; + vector< const SMDS_MeshNode* >& col10 = columns[ colIndex( x+1, y )]; + vector< const SMDS_MeshNode* >& col01 = columns[ colIndex( x, y+1 )]; + vector< const SMDS_MeshNode* >& col11 = columns[ colIndex( x+1, y+1 )]; + for ( z = 0; z < zSize-1; ++z ) + { + // bottom face normal of a hexa mush point outside the volume + helper.AddVolume(col00[z], col01[z], col11[z], col10[z], + col00[z+1], col01[z+1], col11[z+1], col10[z+1]); + } + } + } + return true; +} + +//================================================================================ +/*! + * \brief constructor of non-initialized _QuadFaceGrid + */ +//================================================================================ + +_QuadFaceGrid::_QuadFaceGrid(): + myReverse(false), myRightBrother(0), myUpBrother(0), myIndexer(0,0), myID(B_UNDEFINED) +{ +} + +//================================================================================ +/*! + * \brief Initialization + */ +//================================================================================ + +bool _QuadFaceGrid::Init(const TopoDS_Face& f) +{ + myFace = f; + mySides = _FaceSide(); + myReverse = false; + myLeftBottomChild = myRightBrother = myUpBrother = 0; + myChildren.clear(); + myGrid.clear(); + //if ( myFace.Orientation() != TopAbs_FORWARD ) + //myFace.Reverse(); + + TopoDS_Vertex V; + list< TopoDS_Edge > edges; + list< int > nbEdgesInWire; + int nbWire = SMESH_Block::GetOrderedEdges (myFace, V, edges, nbEdgesInWire); + if ( nbWire != 1 ) + return false; + + list< TopoDS_Edge >::iterator edgeIt = edges.begin(); + if ( nbEdgesInWire.front() == 4 ) // exactly 4 edges + { + for ( ; edgeIt != edges.end(); ++edgeIt ) + mySides.AppendSide( _FaceSide( *edgeIt )); + } + else if ( nbEdgesInWire.front() > 4 ) { // more than 4 edges - try to unite some + list< TopoDS_Edge > sideEdges; + while ( !edges.empty()) { + sideEdges.clear(); + sideEdges.splice( sideEdges.end(), edges, edges.begin());// edges.front()->sideEdges.back() + while ( !edges.empty() ) { + if ( SMESH_Algo::IsContinuous( sideEdges.back(), edges.front() )) { + sideEdges.splice( sideEdges.end(), edges, edges.begin()); + } + else if ( SMESH_Algo::IsContinuous( sideEdges.front(), edges.back() )) { + sideEdges.splice( sideEdges.begin(), edges, --edges.end()); + } + else { + break; + } + } + mySides.AppendSide( _FaceSide( sideEdges )); + } + } + if (mySides.size() != 4) + return false; + +#ifdef _DEBUG_ + mySides.GetSide( Q_BOTTOM )->SetID( Q_BOTTOM ); + mySides.GetSide( Q_RIGHT )->SetID( Q_RIGHT ); + mySides.GetSide( Q_TOP )->SetID( Q_TOP ); + mySides.GetSide( Q_LEFT )->SetID( Q_LEFT ); +#endif + + return true; +} + +//================================================================================ +/*! + * \brief Try to unite self with other ordinary face + */ +//================================================================================ + +bool _QuadFaceGrid::AddContinuousFace( const _QuadFaceGrid& other ) +{ + for ( int i = 0; i < 4; ++i ) { + const _FaceSide& otherSide = other.GetSide( i ); + int iMyCommon; + if ( mySides.Contain( otherSide, &iMyCommon ) ) { + // check if normals of two faces are collinear at all vertices of a otherSide + const double angleTol = PI / 180 / 2; + int iV, nbV = otherSide.NbVertices(), nbCollinear = 0; + for ( iV = 0; iV < nbV; ++iV ) + { + TopoDS_Vertex v = otherSide.Vertex( iV ); + gp_Vec n1, n2; + if ( !GetNormal( v, n1 ) || !other.GetNormal( v, n2 )) + continue; + if ( n1 * n2 < 0 ) + n1.Reverse(); + if ( n1.Angle(n2) < angleTol ) + nbCollinear++; + else + break; + } + if ( nbCollinear > 1 ) { // this face becomes composite if not yet is + DUMP_VERT("Cont 1", mySides.GetSide(iMyCommon)->FirstVertex()); + DUMP_VERT("Cont 2", mySides.GetSide(iMyCommon)->LastVertex()); + DUMP_VERT("Cont 3", otherSide.FirstVertex()); + DUMP_VERT("Cont 4", otherSide.LastVertex()); + if ( myChildren.empty() ) { + myChildren.push_back( *this ); + myFace.Nullify(); + } + myChildren.push_back( other ); + int otherBottomIndex = ( 4 + i - iMyCommon + 2 ) % 4; + myChildren.back().SetBottomSide( other.GetSide( otherBottomIndex )); + // collect vertices in mySides + mySides.AppendSide( other.GetSide(0) ); + mySides.AppendSide( other.GetSide(1) ); + mySides.AppendSide( other.GetSide(2) ); + mySides.AppendSide( other.GetSide(3) ); + return true; + } + } + } + return false; +} + +//================================================================================ +/*! + * \brief Try to set the side as bottom hirizontal side + */ +//================================================================================ + +bool _QuadFaceGrid::SetBottomSide(const _FaceSide& bottom, int* sideIndex) +{ + myLeftBottomChild = myRightBrother = myUpBrother = 0; + + int myBottomIndex; + if ( myChildren.empty() ) + { + if ( mySides.Contain( bottom, &myBottomIndex )) { + mySides.SetBottomSide( myBottomIndex ); + if ( sideIndex ) + *sideIndex = myBottomIndex; + return true; + } + } + else + { + TChildren::iterator childFace = myChildren.begin(), childEnd = myChildren.end(); + for ( ; childFace != childEnd; ++childFace ) + { + if ( childFace->SetBottomSide( bottom, &myBottomIndex )) + { + TChildren::iterator orientedCild = childFace; + for ( childFace = myChildren.begin(); childFace != childEnd; ++childFace ) { + if ( childFace != orientedCild ) + childFace->SetBottomSide( childFace->GetSide( myBottomIndex )); + } + if ( sideIndex ) + *sideIndex = myBottomIndex; + return true; + } + } + } + return false; +} + +//================================================================================ +/*! + * \brief Return face adjacent to i-th side of this face, (0& faces) const +{ + for ( int iF = 0; iF < faces.size(); ++iF ) { + _QuadFaceGrid* f = &faces[ iF ]; + if ( f != this && f->SetBottomSide( GetSide( i ))) + return f; + } + return (_QuadFaceGrid*) 0; +} + +//================================================================================ +/*! + * \brief Return i-th side + */ +//================================================================================ + +const _FaceSide& _QuadFaceGrid::GetSide(int i) const +{ + if ( myChildren.empty() ) + return *mySides.GetSide(i); + + _QuadFaceGrid* me = const_cast<_QuadFaceGrid*>(this); + if ( !me->locateChildren() || !myLeftBottomChild ) + return *mySides.GetSide(i); + + const _QuadFaceGrid* child = myLeftBottomChild; + switch ( i ){ + case Q_BOTTOM: + case Q_LEFT: + break; + case Q_RIGHT: + while ( child->myRightBrother ) + child = child->myRightBrother; + break; + case Q_TOP: + while ( child->myUpBrother ) + child = child->myUpBrother; + break; + default: ; + } + return child->GetSide( i ); +} + +//================================================================================ +/*! + * \brief Reverse edges in order to have them oriented along axes of the unit box + */ +//================================================================================ + +void _QuadFaceGrid::ReverseEdges(/*int e1, int e2*/) +{ + myReverse = !myReverse; + +// #ifdef DEB_FACES +// if ( !myFace.IsNull() ) +// TopAbs::Print(myFace.Orientation(), cout); +// #endif + + if ( myChildren.empty() ) + { +// mySides.GetSide( e1 )->Reverse(); +// mySides.GetSide( e2 )->Reverse(); + DumpVertices(); + } + else + { + DumpVertices(); + TChildren::iterator child = myChildren.begin(), childEnd = myChildren.end(); + for ( ; child != childEnd; ++child ) + child->ReverseEdges( /*e1, e2*/ ); + } +} + +//================================================================================ +/*! + * \brief Load nodes of a mesh + */ +//================================================================================ + +bool _QuadFaceGrid::LoadGrid( SMESH_Mesh& mesh ) +{ + if ( !myChildren.empty() ) + { + // Let child faces load their grids + TChildren::iterator child = myChildren.begin(), childEnd = myChildren.end(); + for ( ; child != childEnd; ++child ) { + child->SetID( myID ); + if ( !child->LoadGrid( mesh ) ) + return error( child->GetError() ); + } + // Fill myGrid with nodes of patches + return loadCompositeGrid( mesh ); + } + + // --------------------------------------- + // Fill myGrid with nodes bound to myFace + // --------------------------------------- + + if ( !myGrid.empty() ) + return true; + + myIndexer._xSize = 1 + mySides.GetSide( Q_BOTTOM )->GetNbSegments( mesh ); + myIndexer._ySize = 1 + mySides.GetSide( Q_LEFT )->GetNbSegments( mesh ); + + myGrid.resize( myIndexer.size() ); + + // strore nodes bound to the bottom edge + mySides.GetSide( Q_BOTTOM )->StoreNodes( mesh, myGrid, myReverse ); + + // store the rest nodes row by row + + SMESHDS_SubMesh* faceSubMesh = mesh.GetSubMesh( myFace )->GetSubMeshDS(); + + SMDS_MeshNode dummy(0,0,0); + const SMDS_MeshElement* firstQuad = &dummy;// most left face above the last row of found nodes + + int nbFoundNodes = myIndexer._xSize; + while ( nbFoundNodes != myGrid.size() ) + { + // first and last nodes of the last filled row of nodes + const SMDS_MeshNode* n1down = myGrid[ nbFoundNodes - myIndexer._xSize ]; + const SMDS_MeshNode* n2down = myGrid[ nbFoundNodes - myIndexer._xSize + 1]; + const SMDS_MeshNode* n1downLast = myGrid[ nbFoundNodes-1 ]; + + // find the first face above the row by the first two left nodes + // + // n1up n2up + // o---o + // | | + // o---o o o o o + //n1down n2down + // + TIDSortedElemSet emptySet, avoidSet; + avoidSet.insert( firstQuad ); + firstQuad = SMESH_MeshEditor::FindFaceInSet( n1down, n2down, emptySet, avoidSet); + if ( firstQuad && !faceSubMesh->Contains( firstQuad )) { + avoidSet.insert( firstQuad ); + firstQuad = SMESH_MeshEditor::FindFaceInSet( n1down, n2down, emptySet, avoidSet); + } + if ( !firstQuad || !faceSubMesh->Contains( firstQuad )) + return error(ERR_LI("Error in _QuadFaceGrid::LoadGrid()")); + + // find the node of quad bound to the left geom edge + int i2down = firstQuad->GetNodeIndex( n2down ); + const SMDS_MeshNode* n1up = firstQuad->GetNode(( i2down+2 ) % 4 ); + myGrid[ nbFoundNodes++ ] = n1up; + // the 4-the node of the first quad + int i1down = firstQuad->GetNodeIndex( n1down ); + const SMDS_MeshNode* n2up = firstQuad->GetNode(( i1down+2 ) % 4 ); + myGrid[ nbFoundNodes++ ] = n2up; + + n1down = n2down; + n1up = n2up; + const SMDS_MeshElement* quad = firstQuad; + + // find the rest nodes by remaining faces above the row + // + // n1up + // o---o--o + // | | | -> + // o---o--o o o o + // n1downLast + // + while ( n1down != n1downLast ) + { + // next face + avoidSet.clear(); avoidSet.insert( quad ); + quad = SMESH_MeshEditor::FindFaceInSet( n1down, n1up, emptySet, avoidSet ); + if ( !quad || quad->NbNodes() % 4 > 0) + return error(ERR_LI("Error in _QuadFaceGrid::LoadGrid()")); + + // next node + if ( quad->GetNode( i1down ) != n1down ) // check already found index + i1down = quad->GetNodeIndex( n1down ); + n2up = quad->GetNode(( i1down+2 ) % 4 ); + myGrid[ nbFoundNodes++ ] = n2up; + + n1down = myGrid[ nbFoundNodes - myIndexer._xSize - 1 ]; + n1up = n2up; + } + } + + DumpGrid(); // debug + + return true; +} + +//================================================================================ +/*! + * \brief Find out mutual location of children: find their right and up brothers + */ +//================================================================================ + +bool _QuadFaceGrid::locateChildren() +{ + if ( myLeftBottomChild ) + return true; + + TChildren::iterator child = myChildren.begin(), childEnd = myChildren.end(); + + // find a child sharing it's first bottom vertex with no other brother + myLeftBottomChild = 0; + for ( ; !myLeftBottomChild && child != childEnd; ++child ) + { + TopoDS_Vertex leftVertex = child->GetSide( Q_BOTTOM ).FirstVertex(); + bool sharedVertex = false; + TChildren::iterator otherChild = myChildren.begin(); + for ( ; otherChild != childEnd && !sharedVertex; ++otherChild ) + if ( otherChild != child ) + sharedVertex = otherChild->mySides.Contain( leftVertex ); + if ( !sharedVertex ) { + myLeftBottomChild = & (*child); + DUMP_VERT("0 left bottom Vertex: ",leftVertex ); + } + } + if (!myLeftBottomChild) + return error(ERR_LI("Error in locateChildren()")); + + set< _QuadFaceGrid* > notLocatedChilren; + for (child = myChildren.begin() ; child != childEnd; ++child ) + notLocatedChilren.insert( & (*child)); + + // connect myLeftBottomChild to it's right and upper brothers + notLocatedChilren.erase( myLeftBottomChild ); + myLeftBottomChild->setBrothers( notLocatedChilren ); + if ( !notLocatedChilren.empty() ) + return error(ERR_LI("Error in locateChildren()")); + + return true; +} + +//================================================================================ +/*! + * \brief Fill myGrid with nodes of patches + */ +//================================================================================ + +bool _QuadFaceGrid::loadCompositeGrid(SMESH_Mesh& mesh) +{ + // Find out mutual location of children: find their right and up brothers + if ( !locateChildren() ) + return false; + + // Load nodes according to mutual location of children + + // grid size + myIndexer._xSize = 1 + myLeftBottomChild->GetNbHoriSegments(mesh, /*withBrothers=*/true); + myIndexer._ySize = 1 + myLeftBottomChild->GetNbVertSegments(mesh, /*withBrothers=*/true); + + myGrid.resize( myIndexer.size() ); + + int fromX = myReverse ? myIndexer._xSize : 0; + if (!myLeftBottomChild->fillGrid( mesh, myGrid, myIndexer, fromX, 0 )) + return error( myLeftBottomChild->GetError() ); + + DumpGrid(); + + return true; +} + +//================================================================================ +/*! + * \brief Find right an upper brothers among notLocatedBrothers + */ +//================================================================================ + +void _QuadFaceGrid::setBrothers( set< _QuadFaceGrid* >& notLocatedBrothers ) +{ + if ( !notLocatedBrothers.empty() ) + { + // find right brother + TopoDS_Vertex rightVertex = GetSide( Q_BOTTOM ).LastVertex(); + DUMP_VERT("1 right bottom Vertex: ",rightVertex ); + set< _QuadFaceGrid* >::iterator brIt, brEnd = notLocatedBrothers.end(); + for ( brIt = notLocatedBrothers.begin(); !myRightBrother && brIt != brEnd; ++brIt ) + { + _QuadFaceGrid* brother = *brIt; + TopoDS_Vertex brotherLeftVertex = brother->GetSide( Q_BOTTOM ).FirstVertex(); + DUMP_VERT( "brother left bottom: ", brotherLeftVertex ); + if ( rightVertex.IsSame( brotherLeftVertex )) { + myRightBrother = brother; + notLocatedBrothers.erase( myRightBrother ); + } + } + // find upper brother + TopoDS_Vertex upVertex = GetSide( Q_LEFT ).FirstVertex(); + DUMP_VERT("1 left up Vertex: ",upVertex); + brIt = notLocatedBrothers.begin(), brEnd = notLocatedBrothers.end(); + for ( ; !myUpBrother && brIt != brEnd; ++brIt ) + { + _QuadFaceGrid* brother = *brIt; + TopoDS_Vertex brotherLeftVertex = brother->GetSide( Q_BOTTOM ).FirstVertex(); + DUMP_VERT("brother left bottom: ", brotherLeftVertex); + if ( upVertex.IsSame( brotherLeftVertex )) { + myUpBrother = brother; + notLocatedBrothers.erase( myUpBrother ); + } + } + // recursive call + if ( myRightBrother ) + myRightBrother->setBrothers( notLocatedBrothers ); + if ( myUpBrother ) + myUpBrother->setBrothers( notLocatedBrothers ); + } +} + +//================================================================================ +/*! + * \brief Store nodes of a simple face into grid starting from (x,y) position + */ +//================================================================================ + +bool _QuadFaceGrid::fillGrid(SMESH_Mesh& theMesh, + vector & theGrid, + const _Indexer& theIndexer, + int theX, + int theY) +{ + if ( myGrid.empty() && !LoadGrid( theMesh )) + return false; + + // store my own grid in the global grid + + int fromX = myReverse ? theX - myIndexer._xSize: theX; + + for ( int i = 0, x = fromX; i < myIndexer._xSize; ++i, ++x ) + for ( int j = 0, y = theY; j < myIndexer._ySize; ++j, ++y ) + theGrid[ theIndexer( x, y )] = myGrid[ myIndexer( i, j )]; + + // store grids of my right and upper brothers + + if ( myRightBrother ) + { + if ( myReverse ) + fromX += 1; + else + fromX += myIndexer._xSize - 1; + if ( !myRightBrother->fillGrid( theMesh, theGrid, theIndexer, fromX, theY )) + return error( myRightBrother->GetError() ); + } + if ( myUpBrother ) + { + if ( !myUpBrother->fillGrid( theMesh, theGrid, theIndexer, + theX, theY + myIndexer._ySize - 1)) + return error( myUpBrother->GetError() ); + } + return true; +} + +//================================================================================ +/*! + * \brief Return number of segments on the hirizontal sides + */ +//================================================================================ + +int _QuadFaceGrid::GetNbHoriSegments(SMESH_Mesh& mesh, bool withBrothers) const +{ + int nbSegs = 0; + if ( myLeftBottomChild ) + { + nbSegs += myLeftBottomChild->GetNbHoriSegments( mesh, true ); + } + else + { + nbSegs = mySides.GetSide( Q_BOTTOM )->GetNbSegments(mesh); + if ( withBrothers && myRightBrother ) + nbSegs += myRightBrother->GetNbHoriSegments( mesh, withBrothers ); + } + return nbSegs; +} + +//================================================================================ +/*! + * \brief Return number of segments on the vertical sides + */ +//================================================================================ + +int _QuadFaceGrid::GetNbVertSegments(SMESH_Mesh& mesh, bool withBrothers) const +{ + int nbSegs = 0; + if ( myLeftBottomChild ) + { + nbSegs += myLeftBottomChild->GetNbVertSegments( mesh, true ); + } + else + { + nbSegs = mySides.GetSide( Q_LEFT )->GetNbSegments(mesh); + if ( withBrothers && myUpBrother ) + nbSegs += myUpBrother->GetNbVertSegments( mesh, withBrothers ); + } + return nbSegs; +} + +//================================================================================ +/*! + * \brief Return a node by its position + */ +//================================================================================ + +const SMDS_MeshNode* _QuadFaceGrid::GetNode(int iHori, int iVert) const +{ + return myGrid[ myIndexer( iHori, iVert )]; +} + +//================================================================================ +/*! + * \brief Return node coordinates by its position + */ +//================================================================================ + +gp_XYZ _QuadFaceGrid::GetXYZ(int iHori, int iVert) const +{ + const SMDS_MeshNode* n = myGrid[ myIndexer( iHori, iVert )]; + return gp_XYZ( n->X(), n->Y(), n->Z() ); +} + +//================================================================================ +/*! + * \brief Return normal to the face at vertex v + */ +//================================================================================ + +bool _QuadFaceGrid::GetNormal( const TopoDS_Vertex& v, gp_Vec& n ) const +{ + if ( myChildren.empty() ) + { + if ( mySides.Contain( v )) { + try { + gp_Pnt2d uv = BRep_Tool::Parameters( v, myFace ); + BRepAdaptor_Surface surface( myFace ); + gp_Pnt p; gp_Vec d1u, d1v; + surface.D1( uv.X(), uv.Y(), p, d1u, d1v ); + n = d1u.Crossed( d1v ); + return true; + } + catch (Standard_Failure) { + return false; + } + } + } + else + { + TChildren::const_iterator child = myChildren.begin(), childEnd = myChildren.end(); + for ( ; child != childEnd; ++child ) + if ( child->GetNormal( v, n )) + return true; + } + return false; +} + +//================================================================================ +/*! + * \brief Dumps coordinates of grid nodes + */ +//================================================================================ + +void _QuadFaceGrid::DumpGrid() const +{ +#ifdef DEB_GRID + const char* names[] = { "B_BOTTOM", "B_RIGHT", "B_TOP", "B_LEFT", "B_FRONT", "B_BACK" }; + cout << "****** Face " << names[ myID ] << endl; + + if ( myChildren.empty() || !myGrid.empty() ) + { + cout << "x size: " << myIndexer._xSize << "; y size: " << myIndexer._ySize << endl; + for ( int y = 0; y < myIndexer._ySize; ++y ) { + cout << "-- row " << y << endl; + for ( int x = 0; x < myIndexer._xSize; ++x ) { + const SMDS_MeshNode* n = myGrid[ myIndexer( x, y ) ]; + cout << x << " ( " << n->X() << ", " << n->Y() << ", " << n->Z() << " )" << endl; + } + } + } + else + { + cout << "Nb children: " << myChildren.size() << endl; + TChildren::const_iterator child = myChildren.begin(), childEnd = myChildren.end(); + for ( int i=0; child != childEnd; ++child, ++i ) { + cout << " *** SUBFACE " << i+1 << endl; + ((_QuadFaceGrid&)(*child)).SetID( myID ); + child->DumpGrid(); + } + } +#endif +} + +//================================================================================ +/*! + * \brief Dump vertices + */ +//================================================================================ + +void _QuadFaceGrid::DumpVertices() const +{ +#ifdef DEB_FACES + cout << "****** Face "; + const char* names[] = { "B_BOTTOM", "B_RIGHT", "B_TOP", "B_LEFT", "B_FRONT", "B_BACK" }; + if ( myID >= B_BOTTOM && myID < B_BACK ) + cout << names[ myID ] << endl; + else + cout << "UNDEFINED" << endl; + + if ( myChildren.empty() ) + { + for ( int i = 0; i < 4; ++i ) + { + cout << " Side "; mySides.GetSide( i )->Dump(); + } + } + else + { + cout << "-- Nb children: " << myChildren.size() << endl; + TChildren::const_iterator child = myChildren.begin(), childEnd = myChildren.end(); + for ( int i=0; child != childEnd; ++child, ++i ) { + cout << " *** SUBFACE " << i+1 << endl; + ((_QuadFaceGrid&)(*child)).SetID( myID ); + child->DumpVertices(); + } + } +#endif +} + +//======================================================================= +//function : _FaceSide +//purpose : copy constructor +//======================================================================= + +_FaceSide::_FaceSide(const _FaceSide& other) +{ + myEdge = other.myEdge; + myChildren = other.myChildren; + myNbChildren = other.myNbChildren; + myVertices.Assign( other.myVertices ); + myID = other.myID; +} + +//================================================================================ +/*! + * \brief Construct a face side of one edge + */ +//================================================================================ + +_FaceSide::_FaceSide(const TopoDS_Edge& edge): + myEdge( edge ), myNbChildren(0) +{ + if ( !edge.IsNull() ) + for ( TopExp_Explorer exp( edge, TopAbs_VERTEX ); exp.More(); exp.Next() ) + //myVertices.insert( ptr ( exp.Current() )); + myVertices.Add( exp.Current() ); +} + +//================================================================================ +/*! + * \brief Construct a face side of several edges + */ +//================================================================================ + +_FaceSide::_FaceSide(const list& edges): + myNbChildren(0) +{ + list::const_iterator edge = edges.begin(), eEnd = edges.end(); + for ( ; edge != eEnd; ++edge ) { + myChildren.push_back( _FaceSide( *edge )); + myNbChildren++; +// myVertices.insert( myChildren.back().myVertices.begin(), +// myChildren.back().myVertices.end() ); + myVertices.Add( myChildren.back().FirstVertex() ); + myVertices.Add( myChildren.back().LastVertex() ); + myChildren.back().SetID( Q_CHILD ); // not to splice them + } +} + +//======================================================================= +//function : GetSide +//purpose : +//======================================================================= + +_FaceSide* _FaceSide::GetSide(const int i) +{ + if ( i >= myNbChildren ) + return 0; + + list< _FaceSide >::iterator side = myChildren.begin(); + if ( i ) + std::advance( side, i ); + return & (*side); +} + +//======================================================================= +//function : GetSide +//purpose : +//======================================================================= + +const _FaceSide* _FaceSide::GetSide(const int i) const +{ + return const_cast< _FaceSide* >(this)->GetSide(i); +} + +//======================================================================= +//function : NbVertices +//purpose : return nb of vertices in the side +//======================================================================= + +int _FaceSide::NbVertices() const +{ + if ( myChildren.empty() ) + return myVertices.Extent(); +// return myVertices.size(); + + return myNbChildren + 1; +} + +//======================================================================= +//function : FirstVertex +//purpose : +//======================================================================= + +TopoDS_Vertex _FaceSide::FirstVertex() const +{ + if ( myChildren.empty() ) + return TopExp::FirstVertex( myEdge, Standard_True ); + + return myChildren.front().FirstVertex(); +} + +//======================================================================= +//function : LastVertex +//purpose : +//======================================================================= + +TopoDS_Vertex _FaceSide::LastVertex() const +{ + if ( myChildren.empty() ) + return TopExp::LastVertex( myEdge, Standard_True ); + + return myChildren.back().LastVertex(); +} + +//======================================================================= +//function : Vertex +//purpose : +//======================================================================= + +TopoDS_Vertex _FaceSide::Vertex(int i) const +{ + if ( myChildren.empty() ) + return i ? LastVertex() : FirstVertex(); + + if ( i >= myNbChildren ) + return myChildren.back().LastVertex(); + + return GetSide(i)->FirstVertex(); +} + +//======================================================================= +//function : Contain +//purpose : +//======================================================================= + +bool _FaceSide::Contain( const _FaceSide& side, int* which ) const +{ + if ( !which || myChildren.empty() ) + { + if ( which ) + *which = 0; + int nbCommon = 0; +// set::iterator v, vEnd = side.myVertices.end(); +// for ( v = side.myVertices.begin(); v != vEnd; ++v ) +// nbCommon += ( myVertices.find( *v ) != myVertices.end() ); + TopTools_MapIteratorOfMapOfShape vIt ( side.myVertices ); + for ( ; vIt.More(); vIt.Next() ) + nbCommon += ( myVertices.Contains( vIt.Key() )); + return (nbCommon > 1); + } + list< _FaceSide >::const_iterator mySide = myChildren.begin(), sideEnd = myChildren.end(); + for ( int i = 0; mySide != sideEnd; ++mySide, ++i ) { + if ( mySide->Contain( side )) { + *which = i; + return true; + } + } + return false; +} + +//======================================================================= +//function : Contain +//purpose : +//======================================================================= + +bool _FaceSide::Contain( const TopoDS_Vertex& vertex ) const +{ + return myVertices.Contains( vertex ); +// return myVertices.find( ptr( vertex )) != myVertices.end(); +} + +//======================================================================= +//function : AppendSide +//purpose : +//======================================================================= + +void _FaceSide::AppendSide( const _FaceSide& side ) +{ + if ( !myEdge.IsNull() ) + { + myChildren.push_back( *this ); + myNbChildren = 1; + myEdge.Nullify(); + } + myChildren.push_back( side ); + myNbChildren++; + //myVertices.insert( side.myVertices.begin(), side.myVertices.end() ); + TopTools_MapIteratorOfMapOfShape vIt ( side.myVertices ); + for ( ; vIt.More(); vIt.Next() ) + myVertices.Add( vIt.Key() ); + + myID = Q_PARENT; + myChildren.back().SetID( EQuadSides( myNbChildren-1 )); +} + +//======================================================================= +//function : SetBottomSide +//purpose : +//======================================================================= + +void _FaceSide::SetBottomSide( int i ) +{ + if ( i > 0 && myID == Q_PARENT ) { + list< _FaceSide >::iterator sideEnd, side = myChildren.begin(); + std::advance( side, i ); + myChildren.splice( myChildren.begin(), myChildren, side, myChildren.end() ); + + side = myChildren.begin(), sideEnd = myChildren.end(); + for ( int i = 0; side != sideEnd; ++side, ++i ) { + side->SetID( EQuadSides(i) ); + side->SetBottomSide(i); + } + } +} + +//======================================================================= +//function : GetNbSegments +//purpose : +//======================================================================= + +int _FaceSide::GetNbSegments(SMESH_Mesh& mesh) const +{ + int nb = 0; + if ( myChildren.empty() ) + { + nb = mesh.GetSubMesh(myEdge)->GetSubMeshDS()->NbElements(); + } + else + { + list< _FaceSide >::const_iterator side = myChildren.begin(), sideEnd = myChildren.end(); + for ( ; side != sideEnd; ++side ) + nb += side->GetNbSegments(mesh); + } + return nb; +} + +//======================================================================= +//function : StoreNodes +//purpose : +//======================================================================= + +bool _FaceSide::StoreNodes(SMESH_Mesh& mesh, + vector& myGrid, + bool reverse ) +{ + list< TopoDS_Edge > edges; + if ( myChildren.empty() ) + { + edges.push_back( myEdge ); + } + else + { + list< _FaceSide >::const_iterator side = myChildren.begin(), sideEnd = myChildren.end(); + for ( ; side != sideEnd; ++side ) + if ( reverse ) + edges.push_front( side->myEdge ); + else + edges.push_back ( side->myEdge ); + } + int nbNodes = 0; + list< TopoDS_Edge >::iterator edge = edges.begin(), eEnd = edges.end(); + for ( ; edge != eEnd; ++edge ) + { + map< double, const SMDS_MeshNode* > nodes; + bool ok = SMESH_Algo::GetSortedNodesOnEdge( mesh.GetMeshDS(), + *edge, + /*ignoreMediumNodes=*/true, + nodes); + if ( !ok ) return false; + + bool forward = ( edge->Orientation() == TopAbs_FORWARD ); + if ( reverse ) forward = !forward; + if ( forward ) + { + map< double, const SMDS_MeshNode* >::iterator u_node, nEnd = nodes.end(); + for ( u_node = nodes.begin(); u_node != nEnd; ++u_node ) + myGrid[ nbNodes++ ] = u_node->second; + } + else + { + map< double, const SMDS_MeshNode* >::reverse_iterator u_node, nEnd = nodes.rend(); + for ( u_node = nodes.rbegin(); u_node != nEnd; ++u_node ) + myGrid[ nbNodes++ ] = u_node->second; + } + nbNodes--; // node on vertex present in two adjacent edges + } + return nbNodes > 0; +} + +//======================================================================= +//function : Dump +//purpose : dump end vertices +//======================================================================= + +void _FaceSide::Dump() const +{ + if ( myChildren.empty() ) + { + const char* sideNames[] = { "Q_BOTTOM", "Q_RIGHT", "Q_TOP", "Q_LEFT", "Q_CHILD", "Q_PARENT" }; + if ( myID >= Q_BOTTOM && myID < Q_PARENT ) + cout << sideNames[ myID ] << endl; + else + cout << "" << endl; + TopoDS_Vertex f = FirstVertex(); + TopoDS_Vertex l = LastVertex(); + gp_Pnt pf = BRep_Tool::Pnt(f); + gp_Pnt pl = BRep_Tool::Pnt(l); + cout << "\t ( "<< ptr( f ) << " - " << ptr( l )<< " )" + << "\t ( "<< pf.X()<<", "<::const_iterator side = myChildren.begin(), sideEnd = myChildren.end(); + for ( ; side != sideEnd; ++side ) { + side->Dump(); + cout << "\t"; + } + } +} diff --git a/src/StdMeshers/StdMeshers_CompositeHexa_3D.hxx b/src/StdMeshers/StdMeshers_CompositeHexa_3D.hxx new file mode 100644 index 000000000..09b687fc1 --- /dev/null +++ b/src/StdMeshers/StdMeshers_CompositeHexa_3D.hxx @@ -0,0 +1,61 @@ +// SMESH SMESH : implementaion of SMESH idl descriptions +// +// Copyright (C) 2003 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, +// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// +// +// File : StdMeshers_CompositeBlock_3D.hxx +// Module : SMESH + +#ifndef _SMESH_CompositeSegment_1D_HXX_ +#define _SMESH_CompositeSegment_1D_HXX_ + +#include "SMESH_StdMeshers.hxx" +#include "SMESH_3D_Algo.hxx" + +class SMESH_Mesh; +class StdMeshers_FaceSide; +class TopoDS_Edge; +class TopoDS_Face; + +/*! + * \brief Computes hexahedral mesh on a box with composite sides + * + * The algorithm expects faces of a box to be meshed with quadrangles so that + * opposite box sides have equal number of quadrangles. + */ +class STDMESHERS_EXPORT StdMeshers_CompositeHexa_3D: public SMESH_3D_Algo +{ +public: + StdMeshers_CompositeHexa_3D(int hypId, int studyId, SMESH_Gen* gen); + //virtual ~StdMeshers_CompositeHexa_3D(); + + virtual bool Compute(SMESH_Mesh& aMesh, + const TopoDS_Shape& aShape); + + virtual bool CheckHypothesis(SMESH_Mesh& aMesh, + const TopoDS_Shape& aShape, + Hypothesis_Status& aStatus); + +private: + // private fields +}; + +#endif diff --git a/src/StdMeshers/StdMeshers_Deflection1D.cxx b/src/StdMeshers/StdMeshers_Deflection1D.cxx index 3ded9bc29..98e3b4905 100644 --- a/src/StdMeshers/StdMeshers_Deflection1D.cxx +++ b/src/StdMeshers/StdMeshers_Deflection1D.cxx @@ -22,7 +22,6 @@ // SMESH StdMeshers_Deflection1D : implementaion of SMESH idl descriptions // File : StdMeshers_Deflection1D.cxx // Module : SMESH -// $Header$ // #include "StdMeshers_Deflection1D.hxx" #include "utilities.h" @@ -221,3 +220,16 @@ bool StdMeshers_Deflection1D::SetParametersByMesh(const SMESH_Mesh* theMesh, } return nbEdges; } + +//================================================================================ +/*! + * \brief Initialize my parameter values by linear size of mesh element. + * \retval bool - true if parameter values have been successfully defined + */ +//================================================================================ + +bool StdMeshers_Deflection1D::SetParametersByElementSize(double /*elemLenght*/, + const SMESH_Mesh* /*theMesh*/) +{ + return false; +} diff --git a/src/StdMeshers/StdMeshers_Deflection1D.hxx b/src/StdMeshers/StdMeshers_Deflection1D.hxx index c61820bf7..47b863046 100644 --- a/src/StdMeshers/StdMeshers_Deflection1D.hxx +++ b/src/StdMeshers/StdMeshers_Deflection1D.hxx @@ -22,8 +22,8 @@ // SMESH StdMeshers : implementaion of SMESH idl descriptions // File : StdMeshers_Deflection1D.hxx // Module : SMESH -// $Header$ // + #ifndef _StdMeshers_Deflection1D_HXX_ #define _StdMeshers_Deflection1D_HXX_ @@ -55,7 +55,13 @@ class STDMESHERS_EXPORT StdMeshers_Deflection1D:public SMESH_Hypothesis */ virtual bool SetParametersByMesh(const SMESH_Mesh* theMesh, const TopoDS_Shape& theShape); - protected: + /*! + * \brief Initialize my parameter values by linear size of mesh element. + * \retval bool - true if parameter values have been successfully defined + */ + virtual bool SetParametersByElementSize( double elemLenght, const SMESH_Mesh* theMesh=0); + +protected: double _value; }; diff --git a/src/StdMeshers/StdMeshers_Hexa_3D.cxx b/src/StdMeshers/StdMeshers_Hexa_3D.cxx index 5673c46ff..b36acde9a 100644 --- a/src/StdMeshers/StdMeshers_Hexa_3D.cxx +++ b/src/StdMeshers/StdMeshers_Hexa_3D.cxx @@ -24,13 +24,13 @@ // Moved here from SMESH_Hexa_3D.cxx // Author : Paul RASCLE, EDF // Module : SMESH -// $Header$ // #include "StdMeshers_Hexa_3D.hxx" -#include "StdMeshers_Quadrangle_2D.hxx" +#include "StdMeshers_CompositeHexa_3D.hxx" #include "StdMeshers_FaceSide.hxx" #include "StdMeshers_Penta_3D.hxx" #include "StdMeshers_Prism_3D.hxx" +#include "StdMeshers_Quadrangle_2D.hxx" #include "SMESH_Gen.hxx" #include "SMESH_Mesh.hxx" @@ -214,7 +214,7 @@ bool StdMeshers_Hexa_3D::Compute(SMESH_Mesh & aMesh, //Unexpect aCatch(SalomeException); MESSAGE("StdMeshers_Hexa_3D::Compute"); SMESHDS_Mesh * meshDS = aMesh.GetMeshDS(); - + // 0. - shape and face mesh verification // 0.1 - shape must be a solid (or a shell) with 6 faces @@ -224,8 +224,13 @@ bool StdMeshers_Hexa_3D::Compute(SMESH_Mesh & aMesh, ASSERT(aSubMesh); meshFaces.push_back(aSubMesh); } - if (meshFaces.size() != 6) - return error(COMPERR_BAD_SHAPE, TComm(meshFaces.size())<<" instead of 6 faces in a block"); + if (meshFaces.size() != 6) { + //return error(COMPERR_BAD_SHAPE, TComm(meshFaces.size())<<" instead of 6 faces in a block"); + static StdMeshers_CompositeHexa_3D compositeHexa(-10, 0, aMesh.GetGen()); + if ( !compositeHexa.Compute( aMesh, aShape )) + return error( compositeHexa.GetComputeError() ); + return true; + } // 0.2 - is each face meshed with Quadrangle_2D? (so, with a wire of 4 edges) diff --git a/src/StdMeshers/StdMeshers_LayerDistribution.cxx b/src/StdMeshers/StdMeshers_LayerDistribution.cxx index d2edfc6ac..7b0331380 100644 --- a/src/StdMeshers/StdMeshers_LayerDistribution.cxx +++ b/src/StdMeshers/StdMeshers_LayerDistribution.cxx @@ -23,7 +23,6 @@ // File : StdMeshers_LayerDistribution.cxx // Author : Edward AGAPOV // Module : SMESH -// $Header$ // #include "StdMeshers_LayerDistribution.hxx" @@ -145,3 +144,15 @@ bool StdMeshers_LayerDistribution::SetParametersByMesh(const SMESH_Mesh* , { return false; } +//================================================================================ +/*! + * \brief Initialize my parameter values by linear size of mesh element. + * \retval bool - true if parameter values have been successfully defined + */ +//================================================================================ + +bool StdMeshers_LayerDistribution::SetParametersByElementSize(double elemLenght, + const SMESH_Mesh* theMesh) +{ + return myHyp ? myHyp->SetParametersByElementSize(elemLenght,theMesh) : false; +} diff --git a/src/StdMeshers/StdMeshers_LayerDistribution.hxx b/src/StdMeshers/StdMeshers_LayerDistribution.hxx index 94825cb10..4b170a2df 100644 --- a/src/StdMeshers/StdMeshers_LayerDistribution.hxx +++ b/src/StdMeshers/StdMeshers_LayerDistribution.hxx @@ -23,7 +23,6 @@ // File : StdMeshers_LayerDistribution.hxx // Author : Edward AGAPOV // Module : SMESH -// $Header$ // #ifndef _SMESH_LayerDistribution_HXX_ #define _SMESH_LayerDistribution_HXX_ @@ -83,6 +82,12 @@ public: */ virtual bool SetParametersByMesh(const SMESH_Mesh* theMesh, const TopoDS_Shape& theShape); + /*! + * \brief Initialize my parameter values by linear size of mesh element. + * \retval bool - true if parameter values have been successfully defined + */ + virtual bool SetParametersByElementSize( double elemLenght, const SMESH_Mesh* theMesh=0); + protected: SMESH_Hypothesis* myHyp; std::string mySavedHyp; diff --git a/src/StdMeshers/StdMeshers_LengthFromEdges.cxx b/src/StdMeshers/StdMeshers_LengthFromEdges.cxx index fafe044f3..abe6060e7 100644 --- a/src/StdMeshers/StdMeshers_LengthFromEdges.cxx +++ b/src/StdMeshers/StdMeshers_LengthFromEdges.cxx @@ -24,7 +24,6 @@ // Moved here from SMESH_LengthFromEdges.cxx // Author : Paul RASCLE, EDF // Module : SMESH -// $Header$ // #include "StdMeshers_LengthFromEdges.hxx" @@ -152,3 +151,15 @@ bool StdMeshers_LengthFromEdges::SetParametersByMesh(const SMESH_Mesh* /*theMesh { return false; } +//================================================================================ +/*! + * \brief Initialize my parameter values by linear size of mesh element. + * \retval bool - true if parameter values have been successfully defined + */ +//================================================================================ + +bool StdMeshers_LengthFromEdges::SetParametersByElementSize(double /*elemLenght*/, + const SMESH_Mesh* /*theMesh*/) +{ + return true; +} diff --git a/src/StdMeshers/StdMeshers_LengthFromEdges.hxx b/src/StdMeshers/StdMeshers_LengthFromEdges.hxx index c281759a6..6d3c02c62 100644 --- a/src/StdMeshers/StdMeshers_LengthFromEdges.hxx +++ b/src/StdMeshers/StdMeshers_LengthFromEdges.hxx @@ -24,8 +24,8 @@ // Moved here from SMESH_LengthFromEdges.hxx // Author : Paul RASCLE, EDF // Module : SMESH -// $Header$ // + #ifndef _SMESH_LENGTHFROMEDGES_HXX_ #define _SMESH_LENGTHFROMEDGES_HXX_ @@ -61,6 +61,12 @@ public: */ virtual bool SetParametersByMesh(const SMESH_Mesh* theMesh, const TopoDS_Shape& theShape); + /*! + * \brief Initialize my parameter values by linear size of mesh element. + * \retval bool - true if parameter values have been successfully defined + */ + virtual bool SetParametersByElementSize( double elemLenght, const SMESH_Mesh* theMesh=0); + protected: int _mode; }; diff --git a/src/StdMeshers/StdMeshers_LocalLength.cxx b/src/StdMeshers/StdMeshers_LocalLength.cxx index c1123e13d..a13811153 100644 --- a/src/StdMeshers/StdMeshers_LocalLength.cxx +++ b/src/StdMeshers/StdMeshers_LocalLength.cxx @@ -24,8 +24,8 @@ // Moved here from SMESH_LocalLength.cxx // Author : Paul RASCLE, EDF // Module : SMESH -// $Header$ // + #include "StdMeshers_LocalLength.hxx" #include "SMESH_Mesh.hxx" @@ -234,3 +234,16 @@ bool StdMeshers_LocalLength::SetParametersByMesh(const SMESH_Mesh* theMesh, return nbEdges; } +//================================================================================ +/*! + * \brief Initialize my parameter values by linear size of mesh element. + * \retval bool - true if parameter values have been successfully defined + */ +//================================================================================ + +bool StdMeshers_LocalLength::SetParametersByElementSize(double elemLenght, + const SMESH_Mesh* /*theMesh*/) +{ + return bool( _length = elemLenght ); +} + diff --git a/src/StdMeshers/StdMeshers_LocalLength.hxx b/src/StdMeshers/StdMeshers_LocalLength.hxx index 1bdba1e58..a46a30521 100644 --- a/src/StdMeshers/StdMeshers_LocalLength.hxx +++ b/src/StdMeshers/StdMeshers_LocalLength.hxx @@ -24,8 +24,8 @@ // Moved here from SMESH_LocalLength.hxx // Author : Paul RASCLE, EDF // Module : SMESH -// $Header$ // + #ifndef _SMESH_LOCALLENGTH_HXX_ #define _SMESH_LOCALLENGTH_HXX_ @@ -59,6 +59,12 @@ class STDMESHERS_EXPORT StdMeshers_LocalLength: public SMESH_Hypothesis */ virtual bool SetParametersByMesh(const SMESH_Mesh* theMesh, const TopoDS_Shape& theShape); + /*! + * \brief Initialize my parameter values by linear size of mesh element. + * \retval bool - true if parameter values have been successfully defined + */ + virtual bool SetParametersByElementSize( double elemLenght, const SMESH_Mesh* theMesh=0); + protected: double _length; double _precision; diff --git a/src/StdMeshers/StdMeshers_MaxElementArea.cxx b/src/StdMeshers/StdMeshers_MaxElementArea.cxx index f91be37a6..21fd6ea54 100644 --- a/src/StdMeshers/StdMeshers_MaxElementArea.cxx +++ b/src/StdMeshers/StdMeshers_MaxElementArea.cxx @@ -24,8 +24,8 @@ // Moved here from SMESH_MaxElementArea.cxx // Author : Paul RASCLE, EDF // Module : SMESH -// $Header$ // + #include "StdMeshers_MaxElementArea.hxx" #include "SMESH_ControlsDef.hxx" @@ -185,3 +185,16 @@ bool StdMeshers_MaxElementArea::SetParametersByMesh(const SMESH_Mesh* theMesh, } return _maxArea > 0; } +//================================================================================ +/*! + * \brief Initialize my parameter values by linear size of mesh element. + * \retval bool - true if parameter values have been successfully defined + */ +//================================================================================ + +bool StdMeshers_MaxElementArea::SetParametersByElementSize(double elemLenght, + const SMESH_Mesh* /*theMesh*/) +{ + return bool( _maxArea = elemLenght*elemLenght ); +} + diff --git a/src/StdMeshers/StdMeshers_MaxElementArea.hxx b/src/StdMeshers/StdMeshers_MaxElementArea.hxx index 950103c5d..17bd01815 100644 --- a/src/StdMeshers/StdMeshers_MaxElementArea.hxx +++ b/src/StdMeshers/StdMeshers_MaxElementArea.hxx @@ -24,7 +24,6 @@ // Moved here from SMESH_MaxElementArea.hxx // Author : Paul RASCLE, EDF // Module : SMESH -// $Header$ // #ifndef _SMESH_MAXELEMENTAREA_HXX_ #define _SMESH_MAXELEMENTAREA_HXX_ @@ -57,6 +56,12 @@ public: */ virtual bool SetParametersByMesh(const SMESH_Mesh* theMesh, const TopoDS_Shape& theShape); + /*! + * \brief Initialize my parameter values by linear size of mesh element. + * \retval bool - true if parameter values have been successfully defined + */ + virtual bool SetParametersByElementSize( double elemLenght, const SMESH_Mesh* theMesh=0); + protected: double _maxArea; }; diff --git a/src/StdMeshers/StdMeshers_MaxElementVolume.cxx b/src/StdMeshers/StdMeshers_MaxElementVolume.cxx index eba432e47..1fd721b2c 100644 --- a/src/StdMeshers/StdMeshers_MaxElementVolume.cxx +++ b/src/StdMeshers/StdMeshers_MaxElementVolume.cxx @@ -24,7 +24,6 @@ // Moved here from SMESH_MaxElementVolume.cxx // Author : Paul RASCLE, EDF // Module : SMESH -// $Header$ // #include "StdMeshers_MaxElementVolume.hxx" @@ -197,3 +196,16 @@ bool StdMeshers_MaxElementVolume::SetParametersByMesh(const SMESH_Mesh* theMes } return _maxVolume > 0; } +//================================================================================ +/*! + * \brief Initialize my parameter values by linear size of mesh element. + * \retval bool - true if parameter values have been successfully defined + */ +//================================================================================ + +bool StdMeshers_MaxElementVolume::SetParametersByElementSize(double elemLenght, + const SMESH_Mesh* /*theMesh*/) +{ + return bool( _maxVolume = elemLenght*elemLenght*elemLenght ); +} + diff --git a/src/StdMeshers/StdMeshers_MaxElementVolume.hxx b/src/StdMeshers/StdMeshers_MaxElementVolume.hxx index e51d448ab..d63eb4d4f 100644 --- a/src/StdMeshers/StdMeshers_MaxElementVolume.hxx +++ b/src/StdMeshers/StdMeshers_MaxElementVolume.hxx @@ -24,8 +24,7 @@ // Moved here from SMESH_MaxElementVolume.hxx // Author : Paul RASCLE, EDF // Module : SMESH -// $Header$ -// + #ifndef _SMESH_MAXELEMENTVOLUME_HXX_ #define _SMESH_MAXELEMENTVOLUME_HXX_ @@ -59,6 +58,12 @@ public: */ virtual bool SetParametersByMesh(const SMESH_Mesh* theMesh, const TopoDS_Shape& theShape); + /*! + * \brief Initialize my parameter values by linear size of mesh element. + * \retval bool - true if parameter values have been successfully defined + */ + virtual bool SetParametersByElementSize( double elemLenght, const SMESH_Mesh* theMesh=0); + protected: double _maxVolume; }; diff --git a/src/StdMeshers/StdMeshers_MaxLength.cxx b/src/StdMeshers/StdMeshers_MaxLength.cxx new file mode 100644 index 000000000..aa34f81d8 --- /dev/null +++ b/src/StdMeshers/StdMeshers_MaxLength.cxx @@ -0,0 +1,242 @@ +// SMESH SMESH : implementaion of SMESH idl descriptions +// +// Copyright (C) 2003 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, +// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// File : StdMeshers_MaxLength.cxx +// Module : SMESH + +#include "StdMeshers_MaxLength.hxx" + +#include "SMESH_Mesh.hxx" +#include "SMESH_Algo.hxx" + +#include "utilities.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +//============================================================================= +/*! + * + */ +//============================================================================= + +StdMeshers_MaxLength::StdMeshers_MaxLength(int hypId, int studyId, SMESH_Gen * gen) + :SMESH_Hypothesis(hypId, studyId, gen) +{ + _length = 1.; + _preestimated = 0.; + _preestimation = false; + _name = "MaxLength"; + _param_algo_dim = 1; // is used by SMESH_Regular_1D +} + +//============================================================================= +/*! + * + */ +//============================================================================= + +StdMeshers_MaxLength::~StdMeshers_MaxLength() +{ +} + +//============================================================================= +/*! + * + */ +//============================================================================= + +void StdMeshers_MaxLength::SetLength(double length) throw(SALOME_Exception) +{ + if (length <= 0) + throw SALOME_Exception(LOCALIZED("length must be positive")); + if ( _length != length ) { + _length = length; + NotifySubMeshesHypothesisModification(); + } +} + +//============================================================================= +/*! + * + */ +//============================================================================= + +double StdMeshers_MaxLength::GetLength() const +{ + return ( _preestimation && _preestimated > 0. ) ? _preestimated : _length; +} + +//================================================================================ +/*! + * \brief Sets boolean parameter enabling/desabling usage of length computed + * basing on size of bounding box of shape to mesh + */ +//================================================================================ + +void StdMeshers_MaxLength::SetUsePreestimatedLength(bool toUse) +{ + if ( toUse != _preestimation ) + { + _preestimation = toUse; + // this parameter is just to help the user + //NotifySubMeshesHypothesisModification(); + } +} + +//================================================================================ +/*! + * \brief Store preestemated length + */ +//================================================================================ + +void StdMeshers_MaxLength::SetPreestimatedLength(double length) +{ + if ( length > 0 ) + _preestimated = length; +} + +//================================================================================ +/*! + * \brief Returns value of boolean parameter enabling/desabling usage of length computed + * basing on size of bounding box of shape to mesh + */ +//================================================================================ + +bool StdMeshers_MaxLength::GetUsePreestimatedLength() const +{ + return _preestimation; +} + +//============================================================================= +/*! + * + */ +//============================================================================= + +ostream & StdMeshers_MaxLength::SaveTo(ostream & save) +{ + save << _length << " " << _preestimated << " " << _preestimation; + return save; +} + +//============================================================================= +/*! + * + */ +//============================================================================= + +istream & StdMeshers_MaxLength::LoadFrom(istream & load) +{ + bool isOK = true; + double a; + + isOK = (load >> a); + if (isOK) + _length = a; + else + load.clear(ios::badbit | load.rdstate()); + + isOK = (load >> a); + if (isOK) + _preestimated = a; + else + load.clear(ios::badbit | load.rdstate()); + + bool pre; + isOK = (load >> pre); + if ( isOK ) + _preestimation = pre; + else + load.clear(ios::badbit | load.rdstate()); + + return load; +} + +//================================================================================ +/*! + * \brief Initialize segment length by the mesh built on the geometry + * \param theMesh - the built mesh + * \param theShape - the geometry of interest + * \retval bool - true if parameter values have been successfully defined + */ +//================================================================================ + +bool StdMeshers_MaxLength::SetParametersByMesh(const SMESH_Mesh* theMesh, + const TopoDS_Shape& theShape) +{ + if ( !theMesh || theShape.IsNull() ) + return false; + + _length = 0.; + + Standard_Real UMin, UMax; + TopLoc_Location L; + + int nbEdges = 0; + TopTools_IndexedMapOfShape edgeMap; + TopExp::MapShapes( theShape, TopAbs_EDGE, edgeMap ); + for ( int iE = 1; iE <= edgeMap.Extent(); ++iE ) + { + const TopoDS_Edge& edge = TopoDS::Edge( edgeMap( iE )); + Handle(Geom_Curve) C = BRep_Tool::Curve( edge, L, UMin, UMax ); + GeomAdaptor_Curve AdaptCurve(C); + + vector< double > params; + SMESHDS_Mesh* aMeshDS = const_cast< SMESH_Mesh* >( theMesh )->GetMeshDS(); + if ( SMESH_Algo::GetNodeParamOnEdge( aMeshDS, edge, params )) + { + for ( int i = 1; i < params.size(); ++i ) + _length += GCPnts_AbscissaPoint::Length( AdaptCurve, params[ i-1 ], params[ i ]); + nbEdges += params.size() - 1; + } + } + if ( nbEdges ) + _length /= nbEdges; + + return nbEdges; +} +//================================================================================ +/*! + * \brief Initialize my parameter values by linear size of mesh element. + * \retval bool - true if parameter values have been successfully defined + */ +//================================================================================ + +bool StdMeshers_MaxLength::SetParametersByElementSize(double elemLenght, + const SMESH_Mesh* /*theMesh*/) +{ + _preestimation = ( elemLenght > 0.); + if ( _preestimation ) + _preestimated = elemLenght; + return bool( _length = elemLenght ); +} + diff --git a/src/StdMeshers/StdMeshers_MaxLength.hxx b/src/StdMeshers/StdMeshers_MaxLength.hxx new file mode 100644 index 000000000..507706bb0 --- /dev/null +++ b/src/StdMeshers/StdMeshers_MaxLength.hxx @@ -0,0 +1,71 @@ +// SMESH SMESH : implementaion of SMESH idl descriptions +// +// Copyright (C) 2003 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, +// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com + +// File : StdMeshers_MaxLength.hxx +// Module : SMESH + +#ifndef _SMESH_MaxLength_HXX_ +#define _SMESH_MaxLength_HXX_ + +#include "SMESH_StdMeshers.hxx" + +#include "SMESH_Hypothesis.hxx" +#include "Utils_SALOME_Exception.hxx" + +class STDMESHERS_EXPORT StdMeshers_MaxLength: public SMESH_Hypothesis +{ + public: + StdMeshers_MaxLength(int hypId, int studyId, SMESH_Gen * gen); + virtual ~ StdMeshers_MaxLength(); + + void SetLength(double length) throw(SALOME_Exception); + double GetLength() const; + + bool HavePreestimatedLength() const { return _preestimated > 0.; } + double GetPreestimatedLength() const { return _preestimated; } + void SetPreestimatedLength(double length); + + void SetUsePreestimatedLength(bool toUse); + bool GetUsePreestimatedLength() const; + + virtual std::ostream & SaveTo(std::ostream & save); + virtual std::istream & LoadFrom(std::istream & load); + + /*! + * \brief Initialize segment length by the mesh built on the geometry + * \param theMesh - the built mesh + * \param theShape - the geometry of interest + * \retval bool - true if parameter values have been successfully defined + */ + virtual bool SetParametersByMesh(const SMESH_Mesh* theMesh, const TopoDS_Shape& theShape); + + /*! + * \brief Initialize my parameter values by linear size of mesh element. + * \retval bool - true if parameter values have been successfully defined + */ + virtual bool SetParametersByElementSize( double elemLenght, const SMESH_Mesh* theMesh=0); + + protected: + double _length, _preestimated; + bool _preestimation; +}; + +#endif diff --git a/src/StdMeshers/StdMeshers_NotConformAllowed.cxx b/src/StdMeshers/StdMeshers_NotConformAllowed.cxx index fa8d2f4b4..9325c334b 100644 --- a/src/StdMeshers/StdMeshers_NotConformAllowed.cxx +++ b/src/StdMeshers/StdMeshers_NotConformAllowed.cxx @@ -23,7 +23,6 @@ // File : StdMeshers_NotConformAllowed.cxx // Author : Paul RASCLE, EDF // Module : SMESH -// $Header$ // #include "StdMeshers_NotConformAllowed.hxx" #include "utilities.h" @@ -110,5 +109,18 @@ istream & operator >> (istream & load, StdMeshers_NotConformAllowed & hyp) bool StdMeshers_NotConformAllowed::SetParametersByMesh(const SMESH_Mesh* /*theMesh*/, const TopoDS_Shape& /*theShape*/) { - return false; + return true; } +//================================================================================ +/*! + * \brief Initialize my parameter values by linear size of mesh element. + * \retval bool - true if parameter values have been successfully defined + */ +//================================================================================ + +bool StdMeshers_NotConformAllowed::SetParametersByElementSize(double /*elemLenght*/, + const SMESH_Mesh* /*theMesh*/) +{ + return true; +} + diff --git a/src/StdMeshers/StdMeshers_NotConformAllowed.hxx b/src/StdMeshers/StdMeshers_NotConformAllowed.hxx index e83d3ac7f..4c2423b14 100644 --- a/src/StdMeshers/StdMeshers_NotConformAllowed.hxx +++ b/src/StdMeshers/StdMeshers_NotConformAllowed.hxx @@ -23,7 +23,6 @@ // File : StdMeshers_NotConformAllowed.hxx // Author : Paul RASCLE, EDF // Module : SMESH -// $Header$ // #ifndef _StdMeshers_NotConformAllowed_HXX_ #define _StdMeshers_NotConformAllowed_HXX_ @@ -55,6 +54,12 @@ public: */ virtual bool SetParametersByMesh(const SMESH_Mesh* theMesh, const TopoDS_Shape& theShape); + /*! + * \brief Initialize my parameter values by linear size of mesh element. + * \retval bool - true if parameter values have been successfully defined + */ + virtual bool SetParametersByElementSize( double elemLenght, const SMESH_Mesh* theMesh=0); + }; #endif diff --git a/src/StdMeshers/StdMeshers_NumberOfLayers.cxx b/src/StdMeshers/StdMeshers_NumberOfLayers.cxx index fc8ff0742..df8fc7dba 100644 --- a/src/StdMeshers/StdMeshers_NumberOfLayers.cxx +++ b/src/StdMeshers/StdMeshers_NumberOfLayers.cxx @@ -23,11 +23,11 @@ // File : StdMeshers_NumberOfLayers.cxx // Author : Edward AGAPOV // Module : SMESH -// $Header$ // #include "StdMeshers_NumberOfLayers.hxx" +#include "SMESH_Mesh.hxx" #include "utilities.h" using namespace std; @@ -159,3 +159,17 @@ bool StdMeshers_NumberOfLayers::SetParametersByMesh(const SMESH_Mesh* , { return false; } + +//================================================================================ +/*! + * \brief Initialize my parameter values by linear size of mesh element. + * \retval bool - true if parameter values have been successfully defined + */ +//================================================================================ + +bool StdMeshers_NumberOfLayers::SetParametersByElementSize(double elemLenght, + const SMESH_Mesh* theMesh) +{ + return bool( theMesh ? _nbLayers = int( theMesh->GetShapeDiagonalSize() / elemLenght/ 2.) : 0); +} + diff --git a/src/StdMeshers/StdMeshers_NumberOfLayers.hxx b/src/StdMeshers/StdMeshers_NumberOfLayers.hxx index 22714d0a9..5b9f06955 100644 --- a/src/StdMeshers/StdMeshers_NumberOfLayers.hxx +++ b/src/StdMeshers/StdMeshers_NumberOfLayers.hxx @@ -23,7 +23,6 @@ // File : StdMeshers_NumberOfLayers.hxx // Author : Edward AGAPOV // Module : SMESH -// $Header$ // #ifndef _SMESH_NumberOfLayers_HXX_ #define _SMESH_NumberOfLayers_HXX_ @@ -74,6 +73,12 @@ public: */ virtual bool SetParametersByMesh(const SMESH_Mesh* theMesh, const TopoDS_Shape& theShape); + /*! + * \brief Initialize my parameter values by linear size of mesh element. + * \retval bool - true if parameter values have been successfully defined + */ + virtual bool SetParametersByElementSize( double elemLenght, const SMESH_Mesh* theMesh=0); + protected: int _nbLayers; }; diff --git a/src/StdMeshers/StdMeshers_NumberOfSegments.cxx b/src/StdMeshers/StdMeshers_NumberOfSegments.cxx index 978e1f56b..e96083c64 100644 --- a/src/StdMeshers/StdMeshers_NumberOfSegments.cxx +++ b/src/StdMeshers/StdMeshers_NumberOfSegments.cxx @@ -24,7 +24,6 @@ // Moved here from SMESH_NumberOfSegments.cxx // Author : Paul RASCLE, EDF // Module : SMESH -// $Header$ // #include "StdMeshers_NumberOfSegments.hxx" @@ -64,7 +63,7 @@ StdMeshers_NumberOfSegments::StdMeshers_NumberOfSegments(int hypId, int studyId, SMESH_Gen * gen) : SMESH_Hypothesis(hypId, studyId, gen), - _numberOfSegments(1), + _numberOfSegments(15),//issue 19923 _distrType(DT_Regular), _scaleFactor(1.), _convMode(1) //cut negative by default @@ -683,3 +682,16 @@ bool StdMeshers_NumberOfSegments::SetParametersByMesh(const SMESH_Mesh* theMes return nbEdges; } +//================================================================================ +/*! + * \brief Initialize my parameter values by linear size of mesh element. + * \retval bool - true if parameter values have been successfully defined + */ +//================================================================================ + +bool StdMeshers_NumberOfSegments::SetParametersByElementSize(double elemLenght, + const SMESH_Mesh* /*theMesh*/) +{ + return false; +} + diff --git a/src/StdMeshers/StdMeshers_NumberOfSegments.hxx b/src/StdMeshers/StdMeshers_NumberOfSegments.hxx index 750adcc1f..595893e2a 100644 --- a/src/StdMeshers/StdMeshers_NumberOfSegments.hxx +++ b/src/StdMeshers/StdMeshers_NumberOfSegments.hxx @@ -24,7 +24,6 @@ // Moved here from SMESH_NumberOfSegments.hxx // Author : Paul RASCLE, EDF // Module : SMESH -// $Header$ // #ifndef _SMESH_NUMBEROFSEGMENTS_HXX_ #define _SMESH_NUMBEROFSEGMENTS_HXX_ @@ -171,6 +170,12 @@ public: */ virtual bool SetParametersByMesh(const SMESH_Mesh* theMesh, const TopoDS_Shape& theShape); + /*! + * \brief Initialize my parameter values by linear size of mesh element. + * \retval bool - true if parameter values have been successfully defined + */ + virtual bool SetParametersByElementSize( double elemLenght, const SMESH_Mesh* theMesh=0); + virtual std::ostream & SaveTo(std::ostream & save); virtual std::istream & LoadFrom(std::istream & load); friend std::ostream& operator << (std::ostream & save, StdMeshers_NumberOfSegments & hyp); diff --git a/src/StdMeshers/StdMeshers_ProjectionSource1D.cxx b/src/StdMeshers/StdMeshers_ProjectionSource1D.cxx index c7f2e76c9..6e74ca1e0 100644 --- a/src/StdMeshers/StdMeshers_ProjectionSource1D.cxx +++ b/src/StdMeshers/StdMeshers_ProjectionSource1D.cxx @@ -23,7 +23,6 @@ // File : StdMeshers_ProjectionSource1D.cxx // Author : Edward AGAPOV // Module : SMESH -// $Header$ // #include "StdMeshers_ProjectionSource1D.hxx" @@ -229,3 +228,16 @@ void StdMeshers_ProjectionSource1D::RestoreParams(const TopoDS_Shape& s1, _sourceMesh = mesh; } +//================================================================================ +/*! + * \brief Initialize my parameter values by linear size of mesh element. + * \retval bool - true if parameter values have been successfully defined + */ +//================================================================================ + +bool StdMeshers_ProjectionSource1D::SetParametersByElementSize(double /*elemLenght*/, + const SMESH_Mesh* /*theMesh*/) +{ + return false; +} + diff --git a/src/StdMeshers/StdMeshers_ProjectionSource1D.hxx b/src/StdMeshers/StdMeshers_ProjectionSource1D.hxx index 29c75ea8e..e734049f7 100644 --- a/src/StdMeshers/StdMeshers_ProjectionSource1D.hxx +++ b/src/StdMeshers/StdMeshers_ProjectionSource1D.hxx @@ -23,7 +23,6 @@ // File : StdMeshers_ProjectionSource1D.hxx // Author : Edward AGAPOV // Module : SMESH -// $Header$ // #ifndef _SMESH_ProjectionSource1D_HXX_ #define _SMESH_ProjectionSource1D_HXX_ @@ -137,6 +136,12 @@ public: */ virtual bool SetParametersByMesh(const SMESH_Mesh* theMesh, const TopoDS_Shape& theShape); + /*! + * \brief Initialize my parameter values by linear size of mesh element. + * \retval bool - true if parameter values have been successfully defined + */ + virtual bool SetParametersByElementSize( double elemLenght, const SMESH_Mesh* theMesh=0); + protected: TopoDS_Shape _sourceEdge; diff --git a/src/StdMeshers/StdMeshers_ProjectionSource2D.cxx b/src/StdMeshers/StdMeshers_ProjectionSource2D.cxx index a33f7d70d..6301c9e19 100644 --- a/src/StdMeshers/StdMeshers_ProjectionSource2D.cxx +++ b/src/StdMeshers/StdMeshers_ProjectionSource2D.cxx @@ -23,8 +23,7 @@ // File : StdMeshers_ProjectionSource2D.cxx // Author : Edward AGAPOV // Module : SMESH -// $Header$ -// + #include "StdMeshers_ProjectionSource2D.hxx" #include "SMESH_Mesh.hxx" @@ -296,3 +295,17 @@ void StdMeshers_ProjectionSource2D::RestoreParams(const TopoDS_Shape& s1, _targetVertex2 = TopoDS::Vertex( s5 ); _sourceMesh = mesh; } + +//================================================================================ +/*! + * \brief Initialize my parameter values by linear size of mesh element. + * \retval bool - true if parameter values have been successfully defined + */ +//================================================================================ + +bool StdMeshers_ProjectionSource2D::SetParametersByElementSize(double /*elemLenght*/, + const SMESH_Mesh* /*theMesh*/) +{ + return false; +} + diff --git a/src/StdMeshers/StdMeshers_ProjectionSource2D.hxx b/src/StdMeshers/StdMeshers_ProjectionSource2D.hxx index 56cc92c09..18c01c806 100644 --- a/src/StdMeshers/StdMeshers_ProjectionSource2D.hxx +++ b/src/StdMeshers/StdMeshers_ProjectionSource2D.hxx @@ -23,8 +23,7 @@ // File : StdMeshers_ProjectionSource2D.hxx // Author : Edward AGAPOV // Module : SMESH -// $Header$ -// + #ifndef _SMESH_ProjectionSource2D_HXX_ #define _SMESH_ProjectionSource2D_HXX_ @@ -147,6 +146,12 @@ public: */ virtual bool SetParametersByMesh(const SMESH_Mesh* theMesh, const TopoDS_Shape& theShape); + /*! + * \brief Initialize my parameter values by linear size of mesh element. + * \retval bool - true if parameter values have been successfully defined + */ + virtual bool SetParametersByElementSize( double elemLenght, const SMESH_Mesh* theMesh=0); + protected: TopoDS_Shape _sourceFace; diff --git a/src/StdMeshers/StdMeshers_ProjectionSource3D.cxx b/src/StdMeshers/StdMeshers_ProjectionSource3D.cxx index 190094542..6e5cf4630 100644 --- a/src/StdMeshers/StdMeshers_ProjectionSource3D.cxx +++ b/src/StdMeshers/StdMeshers_ProjectionSource3D.cxx @@ -23,8 +23,7 @@ // File : StdMeshers_ProjectionSource3D.cxx // Author : Edward AGAPOV // Module : SMESH -// $Header$ -// + #include "StdMeshers_ProjectionSource3D.hxx" #include "utilities.h" @@ -296,3 +295,17 @@ void StdMeshers_ProjectionSource3D::RestoreParams(const TopoDS_Shape& s1, _targetVertex2 = TopoDS::Vertex( s5 ); _sourceMesh = mesh; } + +//================================================================================ +/*! + * \brief Initialize my parameter values by linear size of mesh element. + * \retval bool - true if parameter values have been successfully defined + */ +//================================================================================ + +bool StdMeshers_ProjectionSource3D::SetParametersByElementSize(double /*elemLenght*/, + const SMESH_Mesh* /*theMesh*/) +{ + return false; +} + diff --git a/src/StdMeshers/StdMeshers_ProjectionSource3D.hxx b/src/StdMeshers/StdMeshers_ProjectionSource3D.hxx index 0334f85f7..e2fcb5278 100644 --- a/src/StdMeshers/StdMeshers_ProjectionSource3D.hxx +++ b/src/StdMeshers/StdMeshers_ProjectionSource3D.hxx @@ -23,8 +23,7 @@ // File : StdMeshers_ProjectionSource3D.hxx // Author : Edward AGAPOV // Module : SMESH -// $Header$ -// + #ifndef _SMESH_ProjectionSource3D_HXX_ #define _SMESH_ProjectionSource3D_HXX_ @@ -139,6 +138,12 @@ public: */ virtual bool SetParametersByMesh(const SMESH_Mesh* theMesh, const TopoDS_Shape& theShape); + /*! + * \brief Initialize my parameter values by linear size of mesh element. + * \retval bool - true if parameter values have been successfully defined + */ + virtual bool SetParametersByElementSize( double elemLenght, const SMESH_Mesh* theMesh=0); + protected: TopoDS_Shape _sourceShape; diff --git a/src/StdMeshers/StdMeshers_Propagation.cxx b/src/StdMeshers/StdMeshers_Propagation.cxx index 3b381ebb5..55c102f1b 100644 --- a/src/StdMeshers/StdMeshers_Propagation.cxx +++ b/src/StdMeshers/StdMeshers_Propagation.cxx @@ -22,8 +22,7 @@ // SMESH SMESH : implementaion of SMESH idl descriptions // File : StdMeshers_Propagation.cxx // Module : SMESH -// $Header$ -// + #include "StdMeshers_Propagation.hxx" #include "utilities.h" @@ -97,6 +96,7 @@ ostream & operator << (ostream & save, StdMeshers_Propagation & hyp) { return istream & operator >> (istream & load, StdMeshers_Propagation & hyp) { return hyp.LoadFrom(load); } bool StdMeshers_Propagation::SetParametersByMesh(const SMESH_Mesh*, const TopoDS_Shape& ) { return false; } +bool StdMeshers_Propagation::SetParametersByElementSize(double,const SMESH_Mesh*) { return false; } void StdMeshers_Propagation::SetPropagationMgr(SMESH_subMesh* subMesh) { PropagationMgr::Set( subMesh ); } /*! * \brief Return an edge from which hypotheses are propagated from diff --git a/src/StdMeshers/StdMeshers_Propagation.hxx b/src/StdMeshers/StdMeshers_Propagation.hxx index 12abb1a83..b57ee92be 100644 --- a/src/StdMeshers/StdMeshers_Propagation.hxx +++ b/src/StdMeshers/StdMeshers_Propagation.hxx @@ -22,8 +22,7 @@ // SMESH SMESH : implementaion of SMESH idl descriptions // File : StdMeshers_Propagation.hxx // Module : SMESH -// $Header$ -// + #ifndef _SMESH_PROPAGATION_HXX_ #define _SMESH_PROPAGATION_HXX_ @@ -80,5 +79,12 @@ class STDMESHERS_EXPORT StdMeshers_Propagation:public SMESH_Hypothesis * Just return false as this hypothesis does not have parameters values */ virtual bool SetParametersByMesh(const SMESH_Mesh* theMesh, const TopoDS_Shape& theShape); + + /*! + * \brief Initialize my parameter values by linear size of mesh element. + * \retval bool - true if parameter values have been successfully defined + */ + virtual bool SetParametersByElementSize( double elemLenght, const SMESH_Mesh* theMesh=0); + }; #endif diff --git a/src/StdMeshers/StdMeshers_QuadranglePreference.cxx b/src/StdMeshers/StdMeshers_QuadranglePreference.cxx index e7ace7e77..4b09c904c 100644 --- a/src/StdMeshers/StdMeshers_QuadranglePreference.cxx +++ b/src/StdMeshers/StdMeshers_QuadranglePreference.cxx @@ -22,8 +22,7 @@ // SMESH StdMeshers_QuadranglePreference : implementaion of SMESH idl descriptions // File : StdMeshers_QuadranglePreference.cxx // Module : SMESH -// $Header$ -// + #include "StdMeshers_QuadranglePreference.hxx" #include "utilities.h" @@ -113,3 +112,17 @@ bool StdMeshers_QuadranglePreference::SetParametersByMesh(const SMESH_Mesh* /*th { return false; } + +//================================================================================ +/*! + * \brief Initialize my parameter values by linear size of mesh element. + * \retval bool - true if parameter values have been successfully defined + */ +//================================================================================ + +bool StdMeshers_QuadranglePreference::SetParametersByElementSize(double /*elemLenght*/, + const SMESH_Mesh* /*theMesh*/) +{ + return false; +} + diff --git a/src/StdMeshers/StdMeshers_QuadranglePreference.hxx b/src/StdMeshers/StdMeshers_QuadranglePreference.hxx index eb309a981..9ff059fbb 100644 --- a/src/StdMeshers/StdMeshers_QuadranglePreference.hxx +++ b/src/StdMeshers/StdMeshers_QuadranglePreference.hxx @@ -22,8 +22,7 @@ // SMESH StdMeshers : implementaion of SMESH idl descriptions // File : StdMeshers_QuadranglePreference.hxx // Module : SMESH -// $Header$ -// + #ifndef _StdMeshers_QuadranglePreference_HXX_ #define _StdMeshers_QuadranglePreference_HXX_ @@ -59,6 +58,12 @@ class STDMESHERS_EXPORT StdMeshers_QuadranglePreference:public SMESH_Hypothesis */ virtual bool SetParametersByMesh(const SMESH_Mesh* theMesh, const TopoDS_Shape& theShape); + /*! + * \brief Initialize my parameter values by linear size of mesh element. + * \retval bool - true if parameter values have been successfully defined + */ + virtual bool SetParametersByElementSize( double elemLenght, const SMESH_Mesh* theMesh=0); + }; #endif diff --git a/src/StdMeshers/StdMeshers_QuadraticMesh.cxx b/src/StdMeshers/StdMeshers_QuadraticMesh.cxx index ceb91050e..193b9d75e 100644 --- a/src/StdMeshers/StdMeshers_QuadraticMesh.cxx +++ b/src/StdMeshers/StdMeshers_QuadraticMesh.cxx @@ -22,8 +22,7 @@ // SMESH StdMeshers_QuadraticMesh : implementaion of SMESH idl descriptions // File : StdMeshers_QuadraticMesh.cxx // Module : SMESH -// $Header$ -// + #include "StdMeshers_QuadraticMesh.hxx" #include "utilities.h" @@ -108,3 +107,17 @@ bool StdMeshers_QuadraticMesh::SetParametersByMesh(const SMESH_Mesh*, const Topo { return false; } + +//================================================================================ +/*! + * \brief Initialize my parameter values by linear size of mesh element. + * \retval bool - true if parameter values have been successfully defined + */ +//================================================================================ + +bool StdMeshers_QuadraticMesh::SetParametersByElementSize(double /*elemLenght*/, + const SMESH_Mesh* /*theMesh*/) +{ + return false; +} + diff --git a/src/StdMeshers/StdMeshers_QuadraticMesh.hxx b/src/StdMeshers/StdMeshers_QuadraticMesh.hxx index e37264019..f30ebac3f 100644 --- a/src/StdMeshers/StdMeshers_QuadraticMesh.hxx +++ b/src/StdMeshers/StdMeshers_QuadraticMesh.hxx @@ -22,8 +22,7 @@ // SMESH StdMeshers : implementaion of SMESH idl descriptions // File : StdMeshers_QuadraticMesh.hxx // Module : SMESH -// $Header$ -// + #ifndef _StdMeshers_QuadraticMesh_HXX_ #define _StdMeshers_QuadraticMesh_HXX_ @@ -61,6 +60,12 @@ class STDMESHERS_EXPORT StdMeshers_QuadraticMesh:public SMESH_Hypothesis */ virtual bool SetParametersByMesh(const SMESH_Mesh* theMesh, const TopoDS_Shape& theShape); + /*! + * \brief Initialize my parameter values by linear size of mesh element. + * \retval bool - true if parameter values have been successfully defined + */ + virtual bool SetParametersByElementSize( double elemLenght, const SMESH_Mesh* theMesh=0); + }; #endif diff --git a/src/StdMeshers/StdMeshers_Regular_1D.cxx b/src/StdMeshers/StdMeshers_Regular_1D.cxx index f1692228c..ee4aa86e7 100644 --- a/src/StdMeshers/StdMeshers_Regular_1D.cxx +++ b/src/StdMeshers/StdMeshers_Regular_1D.cxx @@ -24,19 +24,19 @@ // Moved here from SMESH_Regular_1D.cxx // Author : Paul RASCLE, EDF // Module : SMESH -// $Header$ -// + #include "StdMeshers_Regular_1D.hxx" #include "StdMeshers_Distribution.hxx" -#include "StdMeshers_LocalLength.hxx" -#include "StdMeshers_NumberOfSegments.hxx" #include "StdMeshers_Arithmetic1D.hxx" -#include "StdMeshers_StartEndLength.hxx" -#include "StdMeshers_Deflection1D.hxx" #include "StdMeshers_AutomaticLength.hxx" -#include "StdMeshers_SegmentLengthAroundVertex.hxx" +#include "StdMeshers_Deflection1D.hxx" +#include "StdMeshers_LocalLength.hxx" +#include "StdMeshers_MaxLength.hxx" +#include "StdMeshers_NumberOfSegments.hxx" #include "StdMeshers_Propagation.hxx" +#include "StdMeshers_SegmentLengthAroundVertex.hxx" +#include "StdMeshers_StartEndLength.hxx" #include "SMESH_Gen.hxx" #include "SMESH_Mesh.hxx" @@ -80,6 +80,7 @@ StdMeshers_Regular_1D::StdMeshers_Regular_1D(int hypId, int studyId, _shapeType = (1 << TopAbs_EDGE); _compatibleHypothesis.push_back("LocalLength"); + _compatibleHypothesis.push_back("MaxLength"); _compatibleHypothesis.push_back("NumberOfSegments"); _compatibleHypothesis.push_back("StartEndLength"); _compatibleHypothesis.push_back("Deflection1D"); @@ -145,14 +146,28 @@ bool StdMeshers_Regular_1D::CheckHypothesis const StdMeshers_LocalLength * hyp = dynamic_cast (theHyp); ASSERT(hyp); - //_value[ BEG_LENGTH_IND ] = _value[ END_LENGTH_IND ] = hyp->GetLength(); _value[ BEG_LENGTH_IND ] = hyp->GetLength(); - _value[ END_LENGTH_IND ] = hyp->GetPrecision(); + _value[ PRECISION_IND ] = hyp->GetPrecision(); ASSERT( _value[ BEG_LENGTH_IND ] > 0 ); _hypType = LOCAL_LENGTH; aStatus = SMESH_Hypothesis::HYP_OK; } + else if (hypName == "MaxLength") + { + const StdMeshers_MaxLength * hyp = + dynamic_cast (theHyp); + ASSERT(hyp); + _value[ BEG_LENGTH_IND ] = hyp->GetLength(); + if ( hyp->GetUsePreestimatedLength() ) { + if ( int nbSeg = aMesh.GetGen()->GetBoundaryBoxSegmentation() ) + _value[ BEG_LENGTH_IND ] = aMesh.GetShapeDiagonalSize() / nbSeg; + } + ASSERT( _value[ BEG_LENGTH_IND ] > 0 ); + _hypType = MAX_LENGTH; + aStatus = SMESH_Hypothesis::HYP_OK; + } + else if (hypName == "NumberOfSegments") { const StdMeshers_NumberOfSegments * hyp = @@ -225,11 +240,11 @@ bool StdMeshers_Regular_1D::CheckHypothesis StdMeshers_AutomaticLength * hyp = const_cast (dynamic_cast (theHyp)); ASSERT(hyp); - //_value[ BEG_LENGTH_IND ] = _value[ END_LENGTH_IND ] = hyp->GetLength( &aMesh, aShape ); - _value[ BEG_LENGTH_IND ] = hyp->GetLength( &aMesh, aShape ); - _value[ END_LENGTH_IND ] = Precision::Confusion(); // ?? or set to zero? + _value[ BEG_LENGTH_IND ] = _value[ END_LENGTH_IND ] = hyp->GetLength( &aMesh, aShape ); +// _value[ BEG_LENGTH_IND ] = hyp->GetLength( &aMesh, aShape ); +// _value[ END_LENGTH_IND ] = Precision::Confusion(); // ?? or set to zero? ASSERT( _value[ BEG_LENGTH_IND ] > 0 ); - _hypType = LOCAL_LENGTH; + _hypType = MAX_LENGTH; aStatus = SMESH_Hypothesis::HYP_OK; } else @@ -412,11 +427,6 @@ static void compensateError(double a1, double an, void StdMeshers_Regular_1D::SetEventListener(SMESH_subMesh* subMesh) { -// static VertexEventListener listener; -// SMESH_subMeshIteratorPtr smIt = subMesh->getDependsOnIterator(false,false); -// while (smIt->more()) { -// subMesh->SetEventListener( &listener, 0, smIt->next() ); -// } StdMeshers_Propagation::SetPropagationMgr( subMesh ); } @@ -566,10 +576,18 @@ bool StdMeshers_Regular_1D::computeInternalParameters(SMESH_Mesh & theMesh, switch( _hypType ) { case LOCAL_LENGTH: + case MAX_LENGTH: case NB_SEGMENTS: { double eltSize = 1; - if ( _hypType == LOCAL_LENGTH ) + if ( _hypType == MAX_LENGTH ) + { + double nbseg = ceil(theLength / _value[ BEG_LENGTH_IND ]); // integer sup + if (nbseg <= 0) + nbseg = 1; // degenerated edge + eltSize = theLength / nbseg; + } + else if ( _hypType == LOCAL_LENGTH ) { // Local Length hypothesis double nbseg = ceil(theLength / _value[ BEG_LENGTH_IND ]); // integer sup @@ -600,7 +618,7 @@ bool StdMeshers_Regular_1D::computeInternalParameters(SMESH_Mesh & theMesh, } if (!isFound) // not found by meshed edge in the propagation chain, use precision { - double aPrecision = _value[ END_LENGTH_IND ]; + double aPrecision = _value[ PRECISION_IND ]; double nbseg_prec = ceil((theLength / _value[ BEG_LENGTH_IND ]) - aPrecision); if (nbseg_prec == (nbseg - 1)) nbseg--; } diff --git a/src/StdMeshers/StdMeshers_Regular_1D.hxx b/src/StdMeshers/StdMeshers_Regular_1D.hxx index 87fd34a20..8e31aabac 100644 --- a/src/StdMeshers/StdMeshers_Regular_1D.hxx +++ b/src/StdMeshers/StdMeshers_Regular_1D.hxx @@ -24,8 +24,7 @@ // Moved here from SMESH_Regular_1D.hxx // Author : Paul RASCLE, EDF // Module : SMESH -// $Header$ -// + #ifndef _SMESH_REGULAR_1D_HXX_ #define _SMESH_REGULAR_1D_HXX_ @@ -95,13 +94,14 @@ protected: StdMeshers_SegmentLengthAroundVertex* getVertexHyp(SMESH_Mesh & theMesh, const TopoDS_Vertex & theV); - enum HypothesisType { LOCAL_LENGTH, NB_SEGMENTS, BEG_END_LENGTH, DEFLECTION, ARITHMETIC_1D, NONE }; + enum HypothesisType { LOCAL_LENGTH, MAX_LENGTH, NB_SEGMENTS, BEG_END_LENGTH, DEFLECTION, ARITHMETIC_1D, NONE }; enum ValueIndex { SCALE_FACTOR_IND = 0, BEG_LENGTH_IND = 0, END_LENGTH_IND = 1, - DEFLECTION_IND = 0 + DEFLECTION_IND = 0, + PRECISION_IND = 0 }; enum IValueIndex { diff --git a/src/StdMeshers/StdMeshers_SegmentLengthAroundVertex.cxx b/src/StdMeshers/StdMeshers_SegmentLengthAroundVertex.cxx index 297ff481d..44fe4ae43 100644 --- a/src/StdMeshers/StdMeshers_SegmentLengthAroundVertex.cxx +++ b/src/StdMeshers/StdMeshers_SegmentLengthAroundVertex.cxx @@ -22,8 +22,7 @@ // SMESH SMESH : implementaion of SMESH idl descriptions // File : StdMeshers_SegmentLengthAroundVertex.cxx // Module : SMESH -// $Header$ -// + #include "StdMeshers_SegmentLengthAroundVertex.hxx" #include "SMESH_Mesh.hxx" @@ -201,3 +200,17 @@ bool StdMeshers_SegmentLengthAroundVertex::SetParametersByMesh(const SMESH_Mesh* return nbSegs; } + +//================================================================================ +/*! + * \brief Initialize my parameter values by linear size of mesh element. + * \retval bool - true if parameter values have been successfully defined + */ +//================================================================================ + +bool StdMeshers_SegmentLengthAroundVertex::SetParametersByElementSize(double, + const SMESH_Mesh*) +{ + return false; +} + diff --git a/src/StdMeshers/StdMeshers_SegmentLengthAroundVertex.hxx b/src/StdMeshers/StdMeshers_SegmentLengthAroundVertex.hxx index 73784b0e8..f77f15dd1 100644 --- a/src/StdMeshers/StdMeshers_SegmentLengthAroundVertex.hxx +++ b/src/StdMeshers/StdMeshers_SegmentLengthAroundVertex.hxx @@ -23,8 +23,7 @@ // File : StdMeshers_SegmentLengthAroundVertex.hxx // Author : Paul RASCLE, EDF // Module : SMESH -// $Header$ -// + #ifndef _SMESH_SegmentLengthAroundVertex_HXX_ #define _SMESH_SegmentLengthAroundVertex_HXX_ @@ -60,6 +59,12 @@ class STDMESHERS_EXPORT StdMeshers_SegmentLengthAroundVertex:public SMESH_Hypoth */ virtual bool SetParametersByMesh(const SMESH_Mesh* theMesh, const TopoDS_Shape& theShape); + /*! + * \brief Initialize my parameter values by linear size of mesh element. + * \retval bool - true if parameter values have been successfully defined + */ + virtual bool SetParametersByElementSize( double elemLenght, const SMESH_Mesh* theMesh=0); + protected: double _length; }; diff --git a/src/StdMeshers/StdMeshers_StartEndLength.cxx b/src/StdMeshers/StdMeshers_StartEndLength.cxx index 9b07f5fb0..0177576cf 100644 --- a/src/StdMeshers/StdMeshers_StartEndLength.cxx +++ b/src/StdMeshers/StdMeshers_StartEndLength.cxx @@ -22,8 +22,7 @@ // SMESH StdMeshers_StartEndLength : implementaion of SMESH idl descriptions // File : StdMeshers_StartEndLength.cxx // Module : SMESH -// $Header$ -// + #include "StdMeshers_StartEndLength.hxx" #include "SMESH_Algo.hxx" @@ -197,3 +196,17 @@ bool StdMeshers_StartEndLength::SetParametersByMesh(const SMESH_Mesh* theMesh, } return nbEdges; } + +//================================================================================ +/*! + * \brief Initialize my parameter values by linear size of mesh element. + * \retval bool - true if parameter values have been successfully defined + */ +//================================================================================ + +bool StdMeshers_StartEndLength::SetParametersByElementSize(double elemLenght, + const SMESH_Mesh* /*theMesh*/) +{ + return bool(_begLength = _endLength = elemLenght ); +} + diff --git a/src/StdMeshers/StdMeshers_StartEndLength.hxx b/src/StdMeshers/StdMeshers_StartEndLength.hxx index 9a3e3a898..94b609139 100644 --- a/src/StdMeshers/StdMeshers_StartEndLength.hxx +++ b/src/StdMeshers/StdMeshers_StartEndLength.hxx @@ -22,8 +22,7 @@ // SMESH StdMeshers : implementaion of SMESH idl descriptions // File : StdMeshers_StartEndLength.hxx // Module : SMESH -// $Header$ -// + #ifndef _STDMESHERS_STARTENDLENGTH_HXX_ #define _STDMESHERS_STARTENDLENGTH_HXX_ @@ -56,6 +55,12 @@ class STDMESHERS_EXPORT StdMeshers_StartEndLength:public SMESH_Hypothesis */ virtual bool SetParametersByMesh(const SMESH_Mesh* theMesh, const TopoDS_Shape& theShape); + /*! + * \brief Initialize my parameter values by linear size of mesh element. + * \retval bool - true if parameter values have been successfully defined + */ + virtual bool SetParametersByElementSize( double elemLenght, const SMESH_Mesh* theMesh=0); + protected: double _begLength, _endLength; }; diff --git a/src/StdMeshers/StdMeshers_TrianglePreference.cxx b/src/StdMeshers/StdMeshers_TrianglePreference.cxx index 3e645b8d0..5d21cf90e 100644 --- a/src/StdMeshers/StdMeshers_TrianglePreference.cxx +++ b/src/StdMeshers/StdMeshers_TrianglePreference.cxx @@ -22,8 +22,7 @@ // SMESH StdMeshers_TrianglePreference // File : StdMeshers_TrianglePreference.cxx // Module : SMESH -// $Header$ -// + #include "StdMeshers_TrianglePreference.hxx" #include "utilities.h" @@ -113,3 +112,17 @@ bool StdMeshers_TrianglePreference::SetParametersByMesh(const SMESH_Mesh* /*theM { return false; } + +//================================================================================ +/*! + * \brief Initialize my parameter values by linear size of mesh element. + * \retval bool - true if parameter values have been successfully defined + */ +//================================================================================ + +bool StdMeshers_TrianglePreference::SetParametersByElementSize(double /*elemLenght*/, + const SMESH_Mesh* /*theMesh*/) +{ + return false; +} + diff --git a/src/StdMeshers/StdMeshers_TrianglePreference.hxx b/src/StdMeshers/StdMeshers_TrianglePreference.hxx index c0eccf5d4..16963b093 100644 --- a/src/StdMeshers/StdMeshers_TrianglePreference.hxx +++ b/src/StdMeshers/StdMeshers_TrianglePreference.hxx @@ -22,8 +22,7 @@ // SMESH StdMeshers : implementaion of SMESH idl descriptions // File : StdMeshers_TrianglePreference.hxx // Module : SMESH -// $Header$ -// + #ifndef _StdMeshers_TrianglePreference_HXX_ #define _StdMeshers_TrianglePreference_HXX_ @@ -58,6 +57,12 @@ class STDMESHERS_EXPORT StdMeshers_TrianglePreference:public SMESH_Hypothesis */ virtual bool SetParametersByMesh(const SMESH_Mesh* theMesh, const TopoDS_Shape& theShape); + /*! + * \brief Initialize my parameter values by linear size of mesh element. + * \retval bool - true if parameter values have been successfully defined + */ + virtual bool SetParametersByElementSize( double elemLenght, const SMESH_Mesh* theMesh=0); + }; #endif diff --git a/src/StdMeshersGUI/StdMeshersGUI_StdHypothesisCreator.cxx b/src/StdMeshersGUI/StdMeshersGUI_StdHypothesisCreator.cxx index 6fbffbb5d..ca8e3a684 100644 --- a/src/StdMeshersGUI/StdMeshersGUI_StdHypothesisCreator.cxx +++ b/src/StdMeshersGUI/StdMeshersGUI_StdHypothesisCreator.cxx @@ -46,6 +46,7 @@ #include #include #include +#include const double VALUE_MAX = 1.0e+15, // COORD_MAX VALUE_MAX_2 = VALUE_MAX * VALUE_MAX, @@ -92,7 +93,7 @@ QWidget* StdMeshersGUI_StdHypothesisCreator::getWidgetForParam( int i ) const if ( i < myCustomWidgets.count() ) { QList::const_iterator anIt = myCustomWidgets.begin(); QList::const_iterator aLast = myCustomWidgets.end(); - for ( int j = 0 ; !w && anIt != aLast; ++anIt ) + for ( int j = 0 ; !w && anIt != aLast; ++anIt, ++j ) if ( i == j ) w = *anIt; } @@ -409,6 +410,19 @@ QString StdMeshersGUI_StdHypothesisCreator::storeParams() const h->SetLength( params[0].myValue.toDouble() ); h->SetPrecision( params[1].myValue.toDouble() ); } + else if( hypType()=="MaxLength" ) + { + StdMeshers::StdMeshers_MaxLength_var h = + StdMeshers::StdMeshers_MaxLength::_narrow( hypothesis() ); + + h->SetLength( params[0].myValue.toDouble() ); + h->SetUsePreestimatedLength( widget< QCheckBox >( 1 )->isChecked() ); + if ( !h->HavePreestimatedLength() && !h->_is_equivalent( initParamsHypothesis() )) { + StdMeshers::StdMeshers_MaxLength_var hInit = + StdMeshers::StdMeshers_MaxLength::_narrow( initParamsHypothesis() ); + h->SetPreestimatedLength( hInit->GetPreestimatedLength() ); + } + } else if( hypType()=="SegmentLengthAroundVertex" ) { StdMeshers::StdMeshers_SegmentLengthAroundVertex_var h = @@ -559,6 +573,39 @@ bool StdMeshersGUI_StdHypothesisCreator::stdParams( ListOfStdParams& p ) const item.myValue = h->GetPrecision(); p.append( item ); } + else if( hypType()=="MaxLength" ) + { + StdMeshers::StdMeshers_MaxLength_var h = + StdMeshers::StdMeshers_MaxLength::_narrow( hyp ); + // try to set a right preestimated length to edited hypothesis + bool noPreestimatedAtEdition = false; + if ( !isCreation() ) { + StdMeshers::StdMeshers_MaxLength_var initHyp = + StdMeshers::StdMeshers_MaxLength::_narrow( initParamsHypothesis(true) ); + noPreestimatedAtEdition = + ( initHyp->_is_nil() || !initHyp->HavePreestimatedLength() ); + if ( !noPreestimatedAtEdition ) + h->SetPreestimatedLength( initHyp->GetPreestimatedLength() ); + } + + item.myName = tr("SMESH_LOCAL_LENGTH_PARAM"); + item.myValue = h->GetLength(); + p.append( item ); + customWidgets()->append(0); + + item.myName = tr("SMESH_USE_PREESTIMATED_LENGTH"); + p.append( item ); + QCheckBox* aQCheckBox = new QCheckBox(dlg()); + if ( !noPreestimatedAtEdition && h->HavePreestimatedLength() ) { + aQCheckBox->setChecked( h->GetUsePreestimatedLength() ); + connect( aQCheckBox, SIGNAL( stateChanged(int) ), this, SLOT( onValueChanged() ) ); + } + else { + aQCheckBox->setChecked( false ); + aQCheckBox->setEnabled( false ); + } + customWidgets()->append( aQCheckBox ); + } else if( hypType()=="SegmentLengthAroundVertex" ) { StdMeshers::StdMeshers_SegmentLengthAroundVertex_var h = @@ -741,6 +788,11 @@ void StdMeshersGUI_StdHypothesisCreator::attuneStdWidget (QWidget* w, const int) { sb->RangeStepAndValidator( VALUE_SMALL, VALUE_MAX, 1.0, 6 ); } + else if( hypType()=="MaxLength" && sb ) + { + sb->RangeStepAndValidator( VALUE_SMALL, VALUE_MAX, 1.0, 6 ); + sb->setEnabled( !widget< QCheckBox >( 1 )->isChecked() ); + } else if( hypType()=="MaxElementArea" && sb ) { sb->RangeStepAndValidator( VALUE_SMALL_2, VALUE_MAX_2, 1.0, 6 ); @@ -828,6 +880,7 @@ QString StdMeshersGUI_StdHypothesisCreator::hypTypeName( const QString& t ) cons types.insert( "NumberOfLayers", "NUMBER_OF_LAYERS" ); types.insert( "LayerDistribution", "LAYER_DISTRIBUTION" ); types.insert( "SegmentLengthAroundVertex", "SEGMENT_LENGTH_AROUND_VERTEX" ); + types.insert( "MaxLength", "MAX_LENGTH" ); } QString res; @@ -879,6 +932,10 @@ bool StdMeshersGUI_StdHypothesisCreator::getParamFromCustomWidget( StdParam & pa return true; } } + if ( hypType() == "MaxLength" ) { + param.myValue = ""; + return true; + } if ( widget->inherits( "StdMeshersGUI_ObjectReferenceParamWdg" )) { // show only 1st reference value @@ -913,3 +970,21 @@ void StdMeshersGUI_StdHypothesisCreator::onReject() deactivateObjRefParamWdg( customWidgets() ); } } + +//================================================================================ +/*! + * \brief + */ +//================================================================================ + +void StdMeshersGUI_StdHypothesisCreator::valueChanged( QWidget* paramWidget) +{ + if ( hypType() == "MaxLength" && paramWidget == getWidgetForParam(1) ) { + getWidgetForParam(0)->setEnabled( !widget< QCheckBox >( 1 )->isChecked() ); + if ( !getWidgetForParam(0)->isEnabled() ) { + StdMeshers::StdMeshers_MaxLength_var h = + StdMeshers::StdMeshers_MaxLength::_narrow( initParamsHypothesis() ); + widget< QtxDoubleSpinBox >( 0 )->setValue( h->GetPreestimatedLength() ); + } + } +} diff --git a/src/StdMeshersGUI/StdMeshersGUI_StdHypothesisCreator.h b/src/StdMeshersGUI/StdMeshersGUI_StdHypothesisCreator.h index 1f8bd3a35..8d45eb94d 100644 --- a/src/StdMeshersGUI/StdMeshersGUI_StdHypothesisCreator.h +++ b/src/StdMeshersGUI/StdMeshersGUI_StdHypothesisCreator.h @@ -60,6 +60,8 @@ protected: virtual ListOfWidgets* customWidgets() const; virtual void onReject(); + virtual void valueChanged( QWidget* ); + template T* widget(int i) const { return dynamic_cast< T* >( getWidgetForParam( i )); diff --git a/src/StdMeshersGUI/StdMeshers_images.ts b/src/StdMeshersGUI/StdMeshers_images.ts index be82bf040..132661aa0 100644 --- a/src/StdMeshersGUI/StdMeshers_images.ts +++ b/src/StdMeshersGUI/StdMeshers_images.ts @@ -49,6 +49,10 @@ ICON_DLG_LOCAL_LENGTH mesh_hypo_length.png + + ICON_DLG_MAX_LENGTH + mesh_hypo_length.png + ICON_DLG_MAX_ELEMENT_AREA mesh_hypo_area.png @@ -153,6 +157,10 @@ ICON_SMESH_TREE_HYPO_LocalLength mesh_tree_hypo_length.png + + ICON_SMESH_TREE_HYPO_MaxLength + mesh_tree_hypo_length.png + ICON_SMESH_TREE_HYPO_MaxElementArea mesh_tree_hypo_area.png diff --git a/src/StdMeshersGUI/StdMeshers_msg_en.ts b/src/StdMeshersGUI/StdMeshers_msg_en.ts index a100c9c90..f11a5d675 100644 --- a/src/StdMeshersGUI/StdMeshers_msg_en.ts +++ b/src/StdMeshersGUI/StdMeshers_msg_en.ts @@ -149,6 +149,18 @@ SMESH_LOCAL_LENGTH_TITLE Hypothesis Construction + + SMESH_MAX_LENGTH_HYPOTHESIS + Max Length + + + SMESH_USE_PREESTIMATED_LENGTH + Use preestimated length + + + SMESH_MAX_LENGTH_TITLE + Hypothesis Construction + SMESH_MAX_ELEMENT_AREA_HYPOTHESIS Max. Element Area diff --git a/src/StdMeshers_I/Makefile.am b/src/StdMeshers_I/Makefile.am index adb145bef..526d71fc5 100644 --- a/src/StdMeshers_I/Makefile.am +++ b/src/StdMeshers_I/Makefile.am @@ -24,8 +24,7 @@ # Author : Julia DOROVSKIKH # Modified by : Alexander BORODIN (OCN) - autotools usage # Module : SMESH -# $Header$ -# + include $(top_srcdir)/adm_local/unix/make_common_starter.am # header files @@ -60,6 +59,7 @@ salomeinclude_HEADERS = \ StdMeshers_SegmentLengthAroundVertex_i.hxx \ StdMeshers_UseExisting_1D2D_i.hxx \ StdMeshers_TrianglePreference_i.hxx \ + StdMeshers_MaxLength_i.hxx \ SMESH_StdMeshers_I.hxx # Libraries targets @@ -96,7 +96,8 @@ dist_libStdMeshersEngine_la_SOURCES = \ StdMeshers_SegmentAroundVertex_0D_i.cxx \ StdMeshers_SegmentLengthAroundVertex_i.cxx \ StdMeshers_UseExisting_1D2D_i.cxx \ - StdMeshers_TrianglePreference_i.cxx + StdMeshers_TrianglePreference_i.cxx \ + StdMeshers_MaxLength_i.cxx # additionnal information to compil and link file libStdMeshersEngine_la_CPPFLAGS = \ diff --git a/src/StdMeshers_I/StdMeshers_MaxLength_i.cxx b/src/StdMeshers_I/StdMeshers_MaxLength_i.cxx new file mode 100644 index 000000000..bbed6c448 --- /dev/null +++ b/src/StdMeshers_I/StdMeshers_MaxLength_i.cxx @@ -0,0 +1,204 @@ +// SMESH SMESH_I : idl implementation based on 'SMESH' unit's calsses +// +// Copyright (C) 2003 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, +// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// File : StdMeshers_MaxLength_i.cxx +// Module : SMESH + +#include "StdMeshers_MaxLength_i.hxx" +#include "SMESH_Gen_i.hxx" +#include "SMESH_Gen.hxx" +#include "SMESH_PythonDump.hxx" + +#include "Utils_CorbaException.hxx" +#include "utilities.h" + +#include + +using namespace std; + +//============================================================================= +/*! + * StdMeshers_MaxLength_i::StdMeshers_MaxLength_i + * + * Constructor + */ +//============================================================================= + +StdMeshers_MaxLength_i::StdMeshers_MaxLength_i( PortableServer::POA_ptr thePOA, + int theStudyId, + ::SMESH_Gen* theGenImpl ) + : SALOME::GenericObj_i( thePOA ), + SMESH_Hypothesis_i( thePOA ) +{ + myBaseImpl = new ::StdMeshers_MaxLength( theGenImpl->GetANewId(), + theStudyId, + theGenImpl ); +} + +//============================================================================= +/*! + * StdMeshers_MaxLength_i::~StdMeshers_MaxLength_i + * + * Destructor + */ +//============================================================================= + +StdMeshers_MaxLength_i::~StdMeshers_MaxLength_i() +{ +} + +//============================================================================= +/*! + * StdMeshers_MaxLength_i::SetLength + * + * Set length + */ +//============================================================================= +void StdMeshers_MaxLength_i::SetLength( CORBA::Double theLength ) + throw ( SALOME::SALOME_Exception ) +{ + ASSERT( myBaseImpl ); + try { + this->GetImpl()->SetLength( theLength ); + } + catch ( SALOME_Exception& S_ex ) { + THROW_SALOME_CORBA_EXCEPTION( S_ex.what(), + SALOME::BAD_PARAM ); + } + + // Update Python script + SMESH::TPythonDump() << _this() << ".SetLength( " << theLength << " )"; +} + +//============================================================================= +/*! + * Sets preestimation flag + */ +//============================================================================= +void StdMeshers_MaxLength_i::SetUsePreestimatedLength( CORBA::Boolean toUse ) + throw ( SALOME::SALOME_Exception ) +{ + ASSERT( myBaseImpl ); + try { + this->GetImpl()->SetUsePreestimatedLength( toUse ); + } + catch ( SALOME_Exception& S_ex ) { + THROW_SALOME_CORBA_EXCEPTION( S_ex.what(), + SALOME::BAD_PARAM ); + } + + // this is an internal kitchen call - no Python dump + // Update Python script + //SMESH::TPythonDump() << _this() << ".SetUsePreestimatedLength( " << toUse << " )"; +} + +//============================================================================= +/*! + * Sets preestimation length + */ +//============================================================================= +void StdMeshers_MaxLength_i::SetPreestimatedLength( CORBA::Double theLength ) +{ + ASSERT( myBaseImpl ); + try { + this->GetImpl()->SetPreestimatedLength( theLength ); + } + catch ( SALOME_Exception& S_ex ) { + THROW_SALOME_CORBA_EXCEPTION( S_ex.what(), + SALOME::BAD_PARAM ); + } + // this is an internal kitchen call - no Python dump + // Update Python script + //SMESH::TPythonDump() << _this() << ".SetPreestimatedLength( " << toUse << " )"; +} + +//============================================================================= +/*! + * StdMeshers_MaxLength_i::GetLength + * + * Get length + */ +//============================================================================= +CORBA::Double StdMeshers_MaxLength_i::GetLength() +{ + ASSERT( myBaseImpl ); + return this->GetImpl()->GetLength(); +} + +//============================================================================= +/*! + * StdMeshers_MaxLength_i::GetPreestimatedLength + */ +//============================================================================= +CORBA::Double StdMeshers_MaxLength_i::GetPreestimatedLength() +{ + ASSERT( myBaseImpl ); + return this->GetImpl()->GetPreestimatedLength(); +} + +//============================================================================= +/*! + * Returns preestimation flag + */ +//============================================================================= +CORBA::Boolean StdMeshers_MaxLength_i::GetUsePreestimatedLength() +{ + ASSERT( myBaseImpl ); + return this->GetImpl()->GetUsePreestimatedLength(); +} + +//================================================================================ +/*! + * \brief Returns true if preestemated length is defined + */ +//================================================================================ + +CORBA::Boolean StdMeshers_MaxLength_i::HavePreestimatedLength() +{ + ASSERT( myBaseImpl ); + return this->GetImpl()->HavePreestimatedLength(); +} + +//============================================================================= +/*! + * StdMeshers_MaxLength_i::GetImpl + * + * Get implementation + */ +//============================================================================= +::StdMeshers_MaxLength* StdMeshers_MaxLength_i::GetImpl() +{ + return ( ::StdMeshers_MaxLength* )myBaseImpl; +} + +//================================================================================ +/*! + * \brief Verify whether hypothesis supports given entity type + * \param type - dimension (see SMESH::Dimension enumeration) + * \retval CORBA::Boolean - TRUE if dimension is supported, FALSE otherwise + * + * Verify whether hypothesis supports given entity type (see SMESH::Dimension enumeration) + */ +//================================================================================ +CORBA::Boolean StdMeshers_MaxLength_i::IsDimSupported( SMESH::Dimension type ) +{ + return type == SMESH::DIM_1D; +} diff --git a/src/StdMeshers_I/StdMeshers_MaxLength_i.hxx b/src/StdMeshers_I/StdMeshers_MaxLength_i.hxx new file mode 100644 index 000000000..715da7a23 --- /dev/null +++ b/src/StdMeshers_I/StdMeshers_MaxLength_i.hxx @@ -0,0 +1,84 @@ +// SMESH SMESH_I : idl implementation based on 'SMESH' unit's calsses +// +// Copyright (C) 2003 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, +// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// File : StdMeshers_MaxLength_i.hxx +// Module : SMESH + +#ifndef _SMESH_MaxLength_I_HXX_ +#define _SMESH_MaxLength_I_HXX_ + +#include "SMESH_StdMeshers_I.hxx" + +#include +#include CORBA_SERVER_HEADER(SMESH_BasicHypothesis) + +#include "SMESH_Hypothesis_i.hxx" +#include "StdMeshers_MaxLength.hxx" + +class SMESH_Gen; + +// ====================================================== +// Local Length hypothesis +// ====================================================== +class STDMESHERS_I_EXPORT StdMeshers_MaxLength_i: + public virtual POA_StdMeshers::StdMeshers_MaxLength, + public virtual SMESH_Hypothesis_i +{ +public: + // Constructor + StdMeshers_MaxLength_i( PortableServer::POA_ptr thePOA, + int theStudyId, + ::SMESH_Gen* theGenImpl ); + // Destructor + virtual ~StdMeshers_MaxLength_i(); + + // Set length + void SetLength( CORBA::Double theLength ) + throw ( SALOME::SALOME_Exception ); + // Set precision + + // Sets preestimation flag + void SetUsePreestimatedLength( CORBA::Boolean toUse) + throw ( SALOME::SALOME_Exception ); + + // Get length + CORBA::Double GetLength(); + + // Returns true if preestemated length is defined + CORBA::Boolean HavePreestimatedLength(); + + CORBA::Double GetPreestimatedLength(); + + // Sets preestemated length + void SetPreestimatedLength(CORBA::Double theLength); + + // Returns preestimation flag + CORBA::Boolean GetUsePreestimatedLength(); + + // Get implementation + ::StdMeshers_MaxLength* GetImpl(); + + // Verify whether hypothesis supports given entity type + CORBA::Boolean IsDimSupported( SMESH::Dimension type ); +}; + +#endif + diff --git a/src/StdMeshers_I/StdMeshers_i.cxx b/src/StdMeshers_I/StdMeshers_i.cxx index e1b534eb6..8d73b56d8 100644 --- a/src/StdMeshers_I/StdMeshers_i.cxx +++ b/src/StdMeshers_I/StdMeshers_i.cxx @@ -23,8 +23,7 @@ // File : StdMeshers_i.cxx // Author : Julia DOROVSKIKH // Module : SMESH -// $Header$ -// + #include "SMESH_StdMeshers_I.hxx" #include "SMESH_Gen_i.hxx" @@ -51,6 +50,7 @@ #include "StdMeshers_NumberOfLayers_i.hxx" #include "StdMeshers_LayerDistribution_i.hxx" #include "StdMeshers_SegmentLengthAroundVertex_i.hxx" +#include "StdMeshers_MaxLength_i.hxx" #include "StdMeshers_Regular_1D_i.hxx" #include "StdMeshers_MEFISTO_2D_i.hxx" @@ -87,6 +87,8 @@ STDMESHERS_I_EXPORT // Hypotheses if (strcmp(aHypName, "LocalLength") == 0) aCreator = new StdHypothesisCreator_i; + else if (strcmp(aHypName, "MaxLength") == 0) + aCreator = new StdHypothesisCreator_i; else if (strcmp(aHypName, "NumberOfSegments") == 0) aCreator = new StdHypothesisCreator_i; else if (strcmp(aHypName, "LengthFromEdges") == 0) -- 2.39.2