From 9a54694a0ab1e5cbc558a35c4606ceea4f7af2ef Mon Sep 17 00:00:00 2001 From: vsr Date: Tue, 12 Feb 2013 14:37:44 +0000 Subject: [PATCH] Merge from V6_main 11/02/2013 --- configure.ac | 1 + doc/salome/Makefile.am | 2 +- doc/salome/examples/3dmesh.py | 72 + doc/salome/examples/Makefile.am | 180 ++ doc/salome/examples/cartesian_algo.py | 42 + doc/salome/examples/creating_meshes_ex01.py | 28 + doc/salome/examples/creating_meshes_ex02.py | 39 + doc/salome/examples/creating_meshes_ex03.py | 57 + doc/salome/examples/creating_meshes_ex04.py | 54 + doc/salome/examples/creating_meshes_ex05.py | 31 + doc/salome/examples/creating_meshes_ex06.py | 106 + doc/salome/examples/creating_meshes_ex07.py | 73 + doc/salome/examples/creating_meshes_ex08.py | 40 + .../examples/defining_hypotheses_ex01.py | 30 + .../examples/defining_hypotheses_ex02.py | 40 + .../examples/defining_hypotheses_ex03.py | 37 + .../examples/defining_hypotheses_ex04.py | 37 + .../examples/defining_hypotheses_ex05.py | 38 + .../examples/defining_hypotheses_ex06.py | 30 + .../examples/defining_hypotheses_ex07.py | 29 + .../examples/defining_hypotheses_ex08.py | 35 + .../examples/defining_hypotheses_ex09.py | 45 + .../examples/defining_hypotheses_ex10.py | 76 + .../examples/defining_hypotheses_ex11.py | 31 + .../examples/defining_hypotheses_ex12.py | 36 + .../examples/defining_hypotheses_ex13.py | 34 + .../examples/defining_hypotheses_ex14.py | 26 + .../examples/defining_hypotheses_ex15.py | 47 + .../examples/defining_hypotheses_ex16.py | 43 + .../examples/defining_hypotheses_ex17.py | 40 + doc/salome/examples/filters_ex01.py | 8 + doc/salome/examples/filters_ex02.py | 10 + doc/salome/examples/filters_ex03.py | 11 + doc/salome/examples/filters_ex04.py | 8 + doc/salome/examples/filters_ex05.py | 8 + doc/salome/examples/filters_ex06.py | 8 + doc/salome/examples/filters_ex07.py | 12 + doc/salome/examples/filters_ex08.py | 10 + doc/salome/examples/filters_ex09.py | 14 + doc/salome/examples/filters_ex10.py | 14 + doc/salome/examples/filters_ex11.py | 10 + doc/salome/examples/filters_ex12.py | 8 + doc/salome/examples/filters_ex13.py | 10 + doc/salome/examples/filters_ex14.py | 9 + doc/salome/examples/filters_ex15.py | 7 + doc/salome/examples/filters_ex16.py | 21 + doc/salome/examples/filters_ex17.py | 16 + doc/salome/examples/filters_ex18.py | 8 + doc/salome/examples/filters_ex19.py | 8 + doc/salome/examples/filters_ex20.py | 8 + doc/salome/examples/filters_ex21.py | 8 + doc/salome/examples/filters_ex22.py | 8 + doc/salome/examples/filters_ex23.py | 10 + doc/salome/examples/filters_ex24.py | 12 + doc/salome/examples/filters_ex25.py | 10 + doc/salome/examples/filters_ex26.py | 8 + doc/salome/examples/filters_ex27.py | 8 + doc/salome/examples/filters_ex28.py | 12 + doc/salome/examples/filters_ex29.py | 8 + doc/salome/examples/filters_ex30.py | 12 + doc/salome/examples/filters_ex31.py | 12 + doc/salome/examples/filters_ex32.py | 10 + doc/salome/examples/filters_ex33.py | 17 + doc/salome/examples/filters_ex34.py | 14 + doc/salome/examples/filters_ex35.py | 19 + doc/salome/examples/filters_ex36.py | 13 + doc/salome/examples/generate_flat_elements.py | 57 + doc/salome/examples/grouping_elements_ex01.py | 21 + doc/salome/examples/grouping_elements_ex02.py | 39 + doc/salome/examples/grouping_elements_ex03.py | 39 + doc/salome/examples/grouping_elements_ex04.py | 43 + doc/salome/examples/grouping_elements_ex05.py | 52 + doc/salome/examples/grouping_elements_ex06.py | 36 + doc/salome/examples/grouping_elements_ex07.py | 34 + doc/salome/examples/grouping_elements_ex08.py | 35 + doc/salome/examples/measurements_ex01.py | 48 + doc/salome/examples/measurements_ex02.py | 22 + doc/salome/examples/modifying_meshes_ex01.py | 11 + doc/salome/examples/modifying_meshes_ex02.py | 15 + doc/salome/examples/modifying_meshes_ex03.py | 42 + doc/salome/examples/modifying_meshes_ex04.py | 15 + doc/salome/examples/modifying_meshes_ex05.py | 15 + doc/salome/examples/modifying_meshes_ex06.py | 18 + doc/salome/examples/modifying_meshes_ex07.py | 15 + doc/salome/examples/modifying_meshes_ex08.py | 19 + doc/salome/examples/modifying_meshes_ex09.py | 32 + doc/salome/examples/modifying_meshes_ex10.py | 56 + doc/salome/examples/modifying_meshes_ex11.py | 10 + doc/salome/examples/modifying_meshes_ex12.py | 10 + doc/salome/examples/modifying_meshes_ex13.py | 13 + doc/salome/examples/modifying_meshes_ex14.py | 9 + doc/salome/examples/modifying_meshes_ex15.py | 43 + doc/salome/examples/modifying_meshes_ex16.py | 44 + doc/salome/examples/modifying_meshes_ex17.py | 44 + doc/salome/examples/modifying_meshes_ex18.py | 44 + doc/salome/examples/modifying_meshes_ex19.py | 35 + doc/salome/examples/modifying_meshes_ex20.py | 9 + doc/salome/examples/modifying_meshes_ex21.py | 27 + doc/salome/examples/modifying_meshes_ex22.py | 26 + doc/salome/examples/modifying_meshes_ex23.py | 126 + doc/salome/examples/modifying_meshes_ex24.py | 21 + doc/salome/examples/modifying_meshes_ex25.py | 130 + doc/salome/examples/modifying_meshes_ex26.py | 45 + doc/salome/examples/notebook_smesh.py | 39 + doc/salome/examples/prism_3d_algo.py | 73 + doc/salome/examples/quality_controls_ex01.py | 41 + doc/salome/examples/quality_controls_ex02.py | 44 + doc/salome/examples/quality_controls_ex03.py | 43 + doc/salome/examples/quality_controls_ex04.py | 39 + doc/salome/examples/quality_controls_ex05.py | 48 + doc/salome/examples/quality_controls_ex06.py | 73 + doc/salome/examples/quality_controls_ex07.py | 19 + doc/salome/examples/quality_controls_ex08.py | 23 + doc/salome/examples/quality_controls_ex09.py | 17 + doc/salome/examples/quality_controls_ex10.py | 15 + doc/salome/examples/quality_controls_ex11.py | 44 + doc/salome/examples/quality_controls_ex12.py | 44 + doc/salome/examples/quality_controls_ex13.py | 30 + doc/salome/examples/quality_controls_ex14.py | 30 + doc/salome/examples/quality_controls_ex15.py | 30 + doc/salome/examples/quality_controls_ex16.py | 31 + doc/salome/examples/quality_controls_ex17.py | 31 + doc/salome/examples/quality_controls_ex18.py | 30 + doc/salome/examples/quality_controls_ex19.py | 30 + doc/salome/examples/quality_controls_ex20.py | 31 + doc/salome/examples/quality_controls_ex21.py | 32 + doc/salome/examples/quality_controls_ex22.py | 30 + doc/salome/examples/testme.py | 28 + .../examples/transforming_meshes_ex01.py | 15 + .../examples/transforming_meshes_ex02.py | 15 + .../examples/transforming_meshes_ex03.py | 26 + .../examples/transforming_meshes_ex04.py | 13 + .../examples/transforming_meshes_ex05.py | 10 + .../examples/transforming_meshes_ex06.py | 73 + .../examples/transforming_meshes_ex07.py | 38 + .../examples/transforming_meshes_ex08.py | 36 + .../examples/transforming_meshes_ex09.py | 37 + .../examples/transforming_meshes_ex10.py | 31 + .../examples/transforming_meshes_ex11.py | 66 + .../examples/transforming_meshes_ex12.py | 108 + .../examples/transforming_meshes_ex13.py | 43 + doc/salome/examples/use_existing_faces.py | 109 + doc/salome/examples/viewing_meshes_ex01.py | 76 + doc/salome/examples/viewing_meshes_ex02.py | 45 + doc/salome/gui/SMESH/doxyfile.in | 2 +- doc/salome/gui/SMESH/images/addinfo_group.png | Bin 20564 -> 16939 bytes doc/salome/gui/SMESH/images/addinfo_mesh.png | Bin 39855 -> 38255 bytes .../gui/SMESH/images/addinfo_submesh.png | Bin 15335 -> 14102 bytes .../gui/SMESH/images/advanced_mesh_infos.png | Bin 33649 -> 32397 bytes doc/salome/gui/SMESH/images/eleminfo1.png | Bin 21263 -> 25423 bytes doc/salome/gui/SMESH/images/eleminfo2.png | Bin 42074 -> 34840 bytes doc/salome/gui/SMESH/images/pref21.png | Bin 85160 -> 87299 bytes .../gui/SMESH/images/prism_needs_hyps.png | Bin 0 -> 19373 bytes doc/salome/gui/SMESH/images/prism_ok_ko.png | Bin 0 -> 4164 bytes doc/salome/gui/SMESH/images/prism_stack.png | Bin 0 -> 20898 bytes .../gui/SMESH/images/prism_tui_sample.png | Bin 0 -> 42506 bytes .../gui/SMESH/images/scalar_bar_dlg.png | Bin 22098 -> 33252 bytes doc/salome/gui/SMESH/input/about_hypo.doc | 6 +- doc/salome/gui/SMESH/input/about_meshes.doc | 7 +- .../gui/SMESH/input/basic_meshing_algos.doc | 4 +- .../SMESH/input/constructing_submeshes.doc | 4 +- doc/salome/gui/SMESH/input/extrusion.doc | 2 +- doc/salome/gui/SMESH/input/mesh_infos.doc | 63 +- .../gui/SMESH/input/mesh_preferences.doc | 14 +- doc/salome/gui/SMESH/input/prism_3d_algo.doc | 76 +- .../gui/SMESH/input/projection_algos.doc | 59 +- doc/salome/gui/SMESH/input/scalar_bar.doc | 10 +- .../gui/SMESH/input/smeshpy_interface.doc | 77 +- .../gui/SMESH/input/tui_cartesian_algo.doc | 46 +- .../gui/SMESH/input/tui_creating_meshes.doc | 276 +-- .../SMESH/input/tui_defining_hypotheses.doc | 704 +----- doc/salome/gui/SMESH/input/tui_filters.doc | 462 +--- .../input/tui_generate_flat_elements.doc | 59 +- .../gui/SMESH/input/tui_grouping_elements.doc | 323 +-- .../gui/SMESH/input/tui_measurements.doc | 79 +- .../gui/SMESH/input/tui_modifying_meshes.doc | 954 +------- .../gui/SMESH/input/tui_notebook_smesh.doc | 42 +- .../gui/SMESH/input/tui_prism_3d_algo.doc | 10 + .../gui/SMESH/input/tui_quality_controls.doc | 819 +------ .../SMESH/input/tui_transforming_meshes.doc | 551 +---- .../SMESH/input/tui_use_existing_faces.doc | 113 +- .../gui/SMESH/input/tui_viewing_meshes.doc | 130 +- .../gui/SMESH/input/use_existing_algos.doc | 5 +- idl/SMESH_Filter.idl | 2 +- idl/SMESH_Mesh.idl | 23 +- resources/SalomeApp.xml.in | 8 + src/Controls/SMESH_Controls.cxx | 278 ++- src/Controls/SMESH_ControlsDef.hxx | 50 +- src/Driver/Driver_Mesh.h | 1 + src/DriverGMF/libmesh5.c | 2098 ++++++++--------- src/DriverGMF/libmesh5.h | 188 +- src/DriverMED/DriverMED_R_SMESHDS_Mesh.cxx | 24 +- src/DriverMED/Makefile.am | 3 +- src/OBJECT/SMESH_Actor.cxx | 369 +-- src/OBJECT/SMESH_Actor.h | 8 + src/OBJECT/SMESH_ActorDef.h | 7 + src/OBJECT/SMESH_ActorUtils.cxx | 18 +- src/OBJECT/SMESH_ActorUtils.h | 15 +- src/OBJECT/SMESH_CellLabelActor.cxx | 65 +- src/OBJECT/SMESH_CellLabelActor.h | 13 +- src/OBJECT/SMESH_DeviceActor.cxx | 26 +- src/OBJECT/SMESH_NodeLabelActor.cxx | 46 +- src/OBJECT/SMESH_NodeLabelActor.h | 14 +- src/OBJECT/SMESH_Object.cxx | 23 +- src/OBJECT/SMESH_Object.h | 4 + src/OBJECT/SMESH_ObjectDef.h | 7 +- src/OBJECT/SMESH_PreviewActorsCollection.cxx | 4 +- src/OBJECT/SMESH_SVTKActor.cxx | 38 +- src/PluginUtils/GeomSelectionTools.cxx | 4 +- src/SMDS/ObjectPool.hxx | 25 +- src/SMDS/SMDS_Mesh.cxx | 75 +- src/SMDS/SMDS_MeshGroup.cxx | 10 +- src/SMDS/SMDS_MeshGroup.hxx | 2 +- src/SMDS/SMDS_MeshNode.cxx | 3 +- src/SMDS/SMDS_UnstructuredGrid.cxx | 17 +- src/SMDS/SMDS_UnstructuredGrid.hxx | 4 +- src/SMDS/SMDS_VtkEdge.cxx | 4 +- src/SMDS/SMDS_VtkEdge.hxx | 4 +- src/SMESH/Makefile.am | 1 + src/SMESH/SMESH_Algo.cxx | 39 +- src/SMESH/SMESH_Algo.hxx | 27 +- src/SMESH/SMESH_Gen.cxx | 36 +- src/SMESH/SMESH_Hypothesis.cxx | 12 +- src/SMESH/SMESH_Hypothesis.hxx | 5 +- src/SMESH/SMESH_Mesh.cxx | 18 +- src/SMESH/SMESH_Mesh.hxx | 1 - src/SMESH/SMESH_MeshEditor.cxx | 126 +- src/SMESH/SMESH_MesherHelper.cxx | 301 ++- src/SMESH/SMESH_MesherHelper.hxx | 51 +- src/SMESH/SMESH_Pattern.cxx | 8 +- src/SMESH/SMESH_Pattern.hxx | 6 +- src/SMESH/SMESH_subMesh.cxx | 68 +- src/SMESH/SMESH_subMesh.hxx | 7 +- src/SMESH/memoire.h | 2 +- src/SMESHDS/SMESHDS_Document.cxx | 16 +- src/SMESHDS/SMESHDS_Document.hxx | 4 +- src/SMESHDS/SMESHDS_GroupOnFilter.cxx | 220 +- src/SMESHDS/SMESHDS_GroupOnFilter.hxx | 26 +- src/SMESHDS/SMESHDS_SubMesh.cxx | 4 +- src/SMESHDS/SMESH_Controls.hxx | 3 + src/SMESHGUI/SMESHGUI.cxx | 77 +- src/SMESHGUI/SMESHGUI.h | 7 +- src/SMESHGUI/SMESHGUI_BuildCompoundDlg.cxx | 2 - src/SMESHGUI/SMESHGUI_ComputeDlg.cxx | 74 +- src/SMESHGUI/SMESHGUI_ComputeDlg.h | 22 +- src/SMESHGUI/SMESHGUI_GEOMGenUtils.cxx | 6 +- src/SMESHGUI/SMESHGUI_GroupDlg.cxx | 26 +- src/SMESHGUI/SMESHGUI_GroupOnShapeDlg.cxx | 16 +- src/SMESHGUI/SMESHGUI_Hypotheses.cxx | 31 +- src/SMESHGUI/SMESHGUI_Hypotheses.h | 1 + src/SMESHGUI/SMESHGUI_HypothesesUtils.cxx | 12 +- src/SMESHGUI/SMESHGUI_MergeDlg.cxx | 2 +- src/SMESHGUI/SMESHGUI_MeshInfo.cxx | 1006 ++++++-- src/SMESHGUI/SMESHGUI_MeshInfo.h | 26 +- src/SMESHGUI/SMESHGUI_MeshOp.cxx | 32 +- .../SMESHGUI_Preferences_ScalarBarDlg.cxx | 116 +- .../SMESHGUI_Preferences_ScalarBarDlg.h | 4 +- src/SMESHGUI/SMESHGUI_Selection.cxx | 2 +- src/SMESHGUI/SMESHGUI_ShapeByMeshDlg.cxx | 162 +- src/SMESHGUI/SMESHGUI_ShapeByMeshDlg.h | 2 +- src/SMESHGUI/SMESHGUI_VTKUtils.cxx | 79 +- src/SMESHGUI/SMESHGUI_VTKUtils.h | 3 + src/SMESHGUI/SMESH_msg_en.ts | 165 +- src/SMESHGUI/SMESH_msg_fr.ts | 127 +- src/SMESHUtils/Makefile.am | 4 +- src/SMESHUtils/SMESH_Block.cxx | 10 +- src/SMESHUtils/SMESH_Block.hxx | 4 +- src/SMESHUtils/SMESH_TryCatch.cxx | 33 + src/SMESHUtils/SMESH_TryCatch.hxx | 109 + src/SMESHUtils/SMESH_TypeDefs.hxx | 3 + src/SMESH_I/Makefile.am | 4 - src/SMESH_I/SMESH_2smeshpy.cxx | 8 +- src/SMESH_I/SMESH_DumpPython.cxx | 99 +- src/SMESH_I/SMESH_Filter_i.cxx | 27 +- src/SMESH_I/SMESH_Filter_i.hxx | 5 +- src/SMESH_I/SMESH_Gen_i.cxx | 349 +-- src/SMESH_I/SMESH_Gen_i.hxx | 21 +- src/SMESH_I/SMESH_Gen_i_1.cxx | 239 +- src/SMESH_I/SMESH_Group_i.cxx | 78 +- src/SMESH_I/SMESH_Group_i.hxx | 6 +- src/SMESH_I/SMESH_Hypothesis_i.cxx | 121 +- src/SMESH_I/SMESH_MEDMesh_i.cxx | 66 +- src/SMESH_I/SMESH_MeshEditor_i.cxx | 100 +- src/SMESH_I/SMESH_MeshEditor_i.hxx | 1 + src/SMESH_I/SMESH_Mesh_i.cxx | 1123 +++++---- src/SMESH_I/SMESH_Mesh_i.hxx | 28 +- src/SMESH_I/SMESH_NoteBook.cxx | 44 +- src/SMESH_I/SMESH_PreMeshInfo.cxx | 84 +- src/SMESH_I/SMESH_PreMeshInfo.hxx | 5 +- src/SMESH_I/smeshpy.py | 97 - src/SMESH_SWIG/smeshDC.py | 142 +- src/SMESH_SWIG_WITHIHM/libSMESH_Swig.cxx | 227 +- src/StdMeshers/StdMeshers_Cartesian_3D.cxx | 2 +- .../StdMeshers_CompositeHexa_3D.cxx | 3 +- src/StdMeshers/StdMeshers_FaceSide.cxx | 146 +- src/StdMeshers/StdMeshers_FaceSide.hxx | 21 +- src/StdMeshers/StdMeshers_Hexa_3D.cxx | 20 +- src/StdMeshers/StdMeshers_Prism_3D.cxx | 1786 +++++++++----- src/StdMeshers/StdMeshers_Prism_3D.hxx | 184 +- .../StdMeshers_ProjectionSource2D.cxx | 3 +- src/StdMeshers/StdMeshers_ProjectionUtils.cxx | 86 +- src/StdMeshers/StdMeshers_ProjectionUtils.hxx | 17 +- src/StdMeshers/StdMeshers_Projection_1D2D.cxx | 8 +- src/StdMeshers/StdMeshers_Projection_2D.cxx | 197 +- src/StdMeshers/StdMeshers_Projection_3D.cxx | 24 +- src/StdMeshers/StdMeshers_Quadrangle_2D.cxx | 307 ++- src/StdMeshers/StdMeshers_Quadrangle_2D.hxx | 44 +- src/StdMeshers/StdMeshers_RadialPrism_3D.cxx | 16 +- .../StdMeshersGUI_StdHypothesisCreator.cxx | 4 +- .../StdMeshersGUI_SubShapeSelectorWdg.cxx | 24 +- .../StdMeshers_ImportSource1D_i.cxx | 11 +- .../StdMeshers_ImportSource2D_i.cxx | 9 +- .../StdMeshers_LayerDistribution_i.cxx | 11 +- src/StdMeshers_I/StdMeshers_ObjRefUlils.cxx | 16 +- src/Tools/MeshCut/MeshCut_Maillage.cxx | 6 +- src/Tools/YamsPlug/monYamsPlugDialog.py | 9 +- .../padder/meshjob/impl/MeshJobManager_i.cxx | 6 +- .../padder/meshjob/impl/MeshJobManager_i.hxx | 4 +- .../meshjob/impl/SPADDERPluginTester_i.hxx | 4 +- 319 files changed, 12834 insertions(+), 9233 deletions(-) create mode 100644 doc/salome/examples/3dmesh.py create mode 100644 doc/salome/examples/Makefile.am create mode 100644 doc/salome/examples/cartesian_algo.py create mode 100644 doc/salome/examples/creating_meshes_ex01.py create mode 100644 doc/salome/examples/creating_meshes_ex02.py create mode 100644 doc/salome/examples/creating_meshes_ex03.py create mode 100644 doc/salome/examples/creating_meshes_ex04.py create mode 100644 doc/salome/examples/creating_meshes_ex05.py create mode 100644 doc/salome/examples/creating_meshes_ex06.py create mode 100644 doc/salome/examples/creating_meshes_ex07.py create mode 100644 doc/salome/examples/creating_meshes_ex08.py create mode 100644 doc/salome/examples/defining_hypotheses_ex01.py create mode 100644 doc/salome/examples/defining_hypotheses_ex02.py create mode 100644 doc/salome/examples/defining_hypotheses_ex03.py create mode 100644 doc/salome/examples/defining_hypotheses_ex04.py create mode 100644 doc/salome/examples/defining_hypotheses_ex05.py create mode 100644 doc/salome/examples/defining_hypotheses_ex06.py create mode 100644 doc/salome/examples/defining_hypotheses_ex07.py create mode 100644 doc/salome/examples/defining_hypotheses_ex08.py create mode 100644 doc/salome/examples/defining_hypotheses_ex09.py create mode 100644 doc/salome/examples/defining_hypotheses_ex10.py create mode 100644 doc/salome/examples/defining_hypotheses_ex11.py create mode 100644 doc/salome/examples/defining_hypotheses_ex12.py create mode 100644 doc/salome/examples/defining_hypotheses_ex13.py create mode 100644 doc/salome/examples/defining_hypotheses_ex14.py create mode 100644 doc/salome/examples/defining_hypotheses_ex15.py create mode 100644 doc/salome/examples/defining_hypotheses_ex16.py create mode 100644 doc/salome/examples/defining_hypotheses_ex17.py create mode 100644 doc/salome/examples/filters_ex01.py create mode 100644 doc/salome/examples/filters_ex02.py create mode 100644 doc/salome/examples/filters_ex03.py create mode 100644 doc/salome/examples/filters_ex04.py create mode 100644 doc/salome/examples/filters_ex05.py create mode 100644 doc/salome/examples/filters_ex06.py create mode 100644 doc/salome/examples/filters_ex07.py create mode 100644 doc/salome/examples/filters_ex08.py create mode 100644 doc/salome/examples/filters_ex09.py create mode 100644 doc/salome/examples/filters_ex10.py create mode 100644 doc/salome/examples/filters_ex11.py create mode 100644 doc/salome/examples/filters_ex12.py create mode 100644 doc/salome/examples/filters_ex13.py create mode 100644 doc/salome/examples/filters_ex14.py create mode 100644 doc/salome/examples/filters_ex15.py create mode 100644 doc/salome/examples/filters_ex16.py create mode 100644 doc/salome/examples/filters_ex17.py create mode 100644 doc/salome/examples/filters_ex18.py create mode 100644 doc/salome/examples/filters_ex19.py create mode 100644 doc/salome/examples/filters_ex20.py create mode 100644 doc/salome/examples/filters_ex21.py create mode 100644 doc/salome/examples/filters_ex22.py create mode 100644 doc/salome/examples/filters_ex23.py create mode 100644 doc/salome/examples/filters_ex24.py create mode 100644 doc/salome/examples/filters_ex25.py create mode 100644 doc/salome/examples/filters_ex26.py create mode 100644 doc/salome/examples/filters_ex27.py create mode 100644 doc/salome/examples/filters_ex28.py create mode 100644 doc/salome/examples/filters_ex29.py create mode 100644 doc/salome/examples/filters_ex30.py create mode 100644 doc/salome/examples/filters_ex31.py create mode 100644 doc/salome/examples/filters_ex32.py create mode 100644 doc/salome/examples/filters_ex33.py create mode 100644 doc/salome/examples/filters_ex34.py create mode 100644 doc/salome/examples/filters_ex35.py create mode 100644 doc/salome/examples/filters_ex36.py create mode 100644 doc/salome/examples/generate_flat_elements.py create mode 100644 doc/salome/examples/grouping_elements_ex01.py create mode 100644 doc/salome/examples/grouping_elements_ex02.py create mode 100644 doc/salome/examples/grouping_elements_ex03.py create mode 100644 doc/salome/examples/grouping_elements_ex04.py create mode 100644 doc/salome/examples/grouping_elements_ex05.py create mode 100644 doc/salome/examples/grouping_elements_ex06.py create mode 100644 doc/salome/examples/grouping_elements_ex07.py create mode 100644 doc/salome/examples/grouping_elements_ex08.py create mode 100644 doc/salome/examples/measurements_ex01.py create mode 100644 doc/salome/examples/measurements_ex02.py create mode 100644 doc/salome/examples/modifying_meshes_ex01.py create mode 100644 doc/salome/examples/modifying_meshes_ex02.py create mode 100644 doc/salome/examples/modifying_meshes_ex03.py create mode 100644 doc/salome/examples/modifying_meshes_ex04.py create mode 100644 doc/salome/examples/modifying_meshes_ex05.py create mode 100644 doc/salome/examples/modifying_meshes_ex06.py create mode 100644 doc/salome/examples/modifying_meshes_ex07.py create mode 100644 doc/salome/examples/modifying_meshes_ex08.py create mode 100644 doc/salome/examples/modifying_meshes_ex09.py create mode 100644 doc/salome/examples/modifying_meshes_ex10.py create mode 100644 doc/salome/examples/modifying_meshes_ex11.py create mode 100644 doc/salome/examples/modifying_meshes_ex12.py create mode 100644 doc/salome/examples/modifying_meshes_ex13.py create mode 100644 doc/salome/examples/modifying_meshes_ex14.py create mode 100644 doc/salome/examples/modifying_meshes_ex15.py create mode 100644 doc/salome/examples/modifying_meshes_ex16.py create mode 100644 doc/salome/examples/modifying_meshes_ex17.py create mode 100644 doc/salome/examples/modifying_meshes_ex18.py create mode 100644 doc/salome/examples/modifying_meshes_ex19.py create mode 100644 doc/salome/examples/modifying_meshes_ex20.py create mode 100644 doc/salome/examples/modifying_meshes_ex21.py create mode 100644 doc/salome/examples/modifying_meshes_ex22.py create mode 100644 doc/salome/examples/modifying_meshes_ex23.py create mode 100644 doc/salome/examples/modifying_meshes_ex24.py create mode 100644 doc/salome/examples/modifying_meshes_ex25.py create mode 100644 doc/salome/examples/modifying_meshes_ex26.py create mode 100644 doc/salome/examples/notebook_smesh.py create mode 100644 doc/salome/examples/prism_3d_algo.py create mode 100644 doc/salome/examples/quality_controls_ex01.py create mode 100644 doc/salome/examples/quality_controls_ex02.py create mode 100644 doc/salome/examples/quality_controls_ex03.py create mode 100644 doc/salome/examples/quality_controls_ex04.py create mode 100644 doc/salome/examples/quality_controls_ex05.py create mode 100644 doc/salome/examples/quality_controls_ex06.py create mode 100644 doc/salome/examples/quality_controls_ex07.py create mode 100644 doc/salome/examples/quality_controls_ex08.py create mode 100644 doc/salome/examples/quality_controls_ex09.py create mode 100644 doc/salome/examples/quality_controls_ex10.py create mode 100644 doc/salome/examples/quality_controls_ex11.py create mode 100644 doc/salome/examples/quality_controls_ex12.py create mode 100644 doc/salome/examples/quality_controls_ex13.py create mode 100644 doc/salome/examples/quality_controls_ex14.py create mode 100644 doc/salome/examples/quality_controls_ex15.py create mode 100644 doc/salome/examples/quality_controls_ex16.py create mode 100644 doc/salome/examples/quality_controls_ex17.py create mode 100644 doc/salome/examples/quality_controls_ex18.py create mode 100644 doc/salome/examples/quality_controls_ex19.py create mode 100644 doc/salome/examples/quality_controls_ex20.py create mode 100644 doc/salome/examples/quality_controls_ex21.py create mode 100644 doc/salome/examples/quality_controls_ex22.py create mode 100755 doc/salome/examples/testme.py create mode 100644 doc/salome/examples/transforming_meshes_ex01.py create mode 100644 doc/salome/examples/transforming_meshes_ex02.py create mode 100644 doc/salome/examples/transforming_meshes_ex03.py create mode 100644 doc/salome/examples/transforming_meshes_ex04.py create mode 100644 doc/salome/examples/transforming_meshes_ex05.py create mode 100644 doc/salome/examples/transforming_meshes_ex06.py create mode 100644 doc/salome/examples/transforming_meshes_ex07.py create mode 100644 doc/salome/examples/transforming_meshes_ex08.py create mode 100644 doc/salome/examples/transforming_meshes_ex09.py create mode 100644 doc/salome/examples/transforming_meshes_ex10.py create mode 100644 doc/salome/examples/transforming_meshes_ex11.py create mode 100644 doc/salome/examples/transforming_meshes_ex12.py create mode 100644 doc/salome/examples/transforming_meshes_ex13.py create mode 100644 doc/salome/examples/use_existing_faces.py create mode 100644 doc/salome/examples/viewing_meshes_ex01.py create mode 100644 doc/salome/examples/viewing_meshes_ex02.py create mode 100644 doc/salome/gui/SMESH/images/prism_needs_hyps.png create mode 100644 doc/salome/gui/SMESH/images/prism_ok_ko.png create mode 100644 doc/salome/gui/SMESH/images/prism_stack.png create mode 100644 doc/salome/gui/SMESH/images/prism_tui_sample.png create mode 100644 doc/salome/gui/SMESH/input/tui_prism_3d_algo.doc create mode 100644 src/SMESHUtils/SMESH_TryCatch.cxx create mode 100644 src/SMESHUtils/SMESH_TryCatch.hxx delete mode 100644 src/SMESH_I/smeshpy.py diff --git a/configure.ac b/configure.ac index c45c59f18..98147ad58 100644 --- a/configure.ac +++ b/configure.ac @@ -537,6 +537,7 @@ AC_OUTPUT([ \ doc/docutils/Makefile \ doc/docutils/conf.py \ doc/salome/Makefile \ + doc/salome/examples/Makefile \ doc/salome/gui/Makefile \ doc/salome/gui/SMESH/Makefile \ doc/salome/gui/SMESH/doxyfile \ diff --git a/doc/salome/Makefile.am b/doc/salome/Makefile.am index 8bf9f392d..10bcc3f25 100644 --- a/doc/salome/Makefile.am +++ b/doc/salome/Makefile.am @@ -23,7 +23,7 @@ # Modified by : Alexander BORODIN (OCN) - autotools usage # $Header: # -SUBDIRS = tui gui +SUBDIRS = tui gui examples SUBDIRSTUI = tui SUBDIRSGUI = gui diff --git a/doc/salome/examples/3dmesh.py b/doc/salome/examples/3dmesh.py new file mode 100644 index 000000000..bd6d3b4cc --- /dev/null +++ b/doc/salome/examples/3dmesh.py @@ -0,0 +1,72 @@ +# 3d mesh generation + +from geompy import * +import smesh + +### +# Geometry: an assembly of a box, a cylinder and a truncated cone +# meshed with tetrahedral +### + +# Define values +name = "ex21_lamp" +cote = 60 +section = 20 +size = 200 +radius_1 = 80 +radius_2 = 40 +height = 100 + +# Build a box +box = MakeBox(-cote, -cote, -cote, +cote, +cote, +cote) + +# Build a cylinder +pt1 = MakeVertex(0, 0, cote/3) +di1 = MakeVectorDXDYDZ(0, 0, 1) +cyl = MakeCylinder(pt1, di1, section, size) + +# Build a truncated cone +pt2 = MakeVertex(0, 0, size) +cone = MakeCone(pt2, di1, radius_1, radius_2, height) + +# Fuse +box_cyl = MakeFuse(box, cyl) +piece = MakeFuse(box_cyl, cone) + +# Add to the study +addToStudy(piece, name) + +# Create a group of faces +group = CreateGroup(piece, ShapeType["FACE"]) +group_name = name + "_grp" +addToStudy(group, group_name) +group.SetName(group_name) + +# Add faces to the group +faces = SubShapeAllIDs(piece, ShapeType["FACE"]) +UnionIDs(group, faces) + +### +# Create a mesh +### + +# Define a mesh on a geometry +tetra = smesh.Mesh(piece, name) + +# Define 1D hypothesis +algo1d = tetra.Segment() +algo1d.LocalLength(10) + +# Define 2D hypothesis +algo2d = tetra.Triangle() +algo2d.LengthFromEdges() + +# Define 3D hypothesis +algo3d = tetra.Tetrahedron() +algo3d.MaxElementVolume(100) + +# Compute the mesh +tetra.Compute() + +# Create a groupe of faces +tetra.Group(group) diff --git a/doc/salome/examples/Makefile.am b/doc/salome/examples/Makefile.am new file mode 100644 index 000000000..930edd9fc --- /dev/null +++ b/doc/salome/examples/Makefile.am @@ -0,0 +1,180 @@ +# Copyright (C) 2007-2012 CEA/DEN, EDF R&D, OPEN CASCADE +# +# 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 : Makefile +# Author : Alexander KOVALEV (Open Cascade NN) +# Modified by : +# Module : doc +# +include $(top_srcdir)/adm_local/unix/make_common_starter.am + +pyexamplesdir = $(docdir)/examples/SMESH + +BAD_TESTS = + +GOOD_TESTS = \ + 3dmesh.py \ + cartesian_algo.py \ + creating_meshes_ex01.py \ + creating_meshes_ex02.py \ + creating_meshes_ex03.py \ + creating_meshes_ex04.py \ + creating_meshes_ex05.py \ + creating_meshes_ex06.py \ + creating_meshes_ex07.py \ + creating_meshes_ex08.py \ + defining_hypotheses_ex01.py \ + defining_hypotheses_ex02.py \ + defining_hypotheses_ex03.py \ + defining_hypotheses_ex04.py \ + defining_hypotheses_ex05.py \ + defining_hypotheses_ex06.py \ + defining_hypotheses_ex07.py \ + defining_hypotheses_ex08.py \ + defining_hypotheses_ex09.py \ + defining_hypotheses_ex10.py \ + defining_hypotheses_ex11.py \ + defining_hypotheses_ex12.py \ + defining_hypotheses_ex13.py \ + defining_hypotheses_ex14.py \ + defining_hypotheses_ex15.py \ + defining_hypotheses_ex16.py \ + defining_hypotheses_ex17.py \ + filters_ex01.py \ + filters_ex02.py \ + filters_ex03.py \ + filters_ex04.py \ + filters_ex05.py \ + filters_ex06.py \ + filters_ex07.py \ + filters_ex08.py \ + filters_ex09.py \ + filters_ex10.py \ + filters_ex11.py \ + filters_ex12.py \ + filters_ex13.py \ + filters_ex14.py \ + filters_ex15.py \ + filters_ex16.py \ + filters_ex17.py \ + filters_ex18.py \ + filters_ex19.py \ + filters_ex20.py \ + filters_ex21.py \ + filters_ex22.py \ + filters_ex23.py \ + filters_ex24.py \ + filters_ex25.py \ + filters_ex26.py \ + filters_ex27.py \ + filters_ex28.py \ + filters_ex29.py \ + filters_ex30.py \ + filters_ex31.py \ + filters_ex32.py \ + filters_ex33.py \ + filters_ex34.py \ + filters_ex35.py \ + filters_ex36.py \ + generate_flat_elements.py \ + grouping_elements_ex01.py \ + grouping_elements_ex02.py \ + grouping_elements_ex03.py \ + grouping_elements_ex04.py \ + grouping_elements_ex05.py \ + grouping_elements_ex06.py \ + grouping_elements_ex07.py \ + grouping_elements_ex08.py \ + measurements_ex01.py \ + measurements_ex02.py \ + modifying_meshes_ex01.py \ + modifying_meshes_ex02.py \ + modifying_meshes_ex03.py \ + modifying_meshes_ex04.py \ + modifying_meshes_ex05.py \ + modifying_meshes_ex06.py \ + modifying_meshes_ex07.py \ + modifying_meshes_ex08.py \ + modifying_meshes_ex09.py \ + modifying_meshes_ex10.py \ + modifying_meshes_ex11.py \ + modifying_meshes_ex12.py \ + modifying_meshes_ex13.py \ + modifying_meshes_ex14.py \ + modifying_meshes_ex15.py \ + modifying_meshes_ex16.py \ + modifying_meshes_ex17.py \ + modifying_meshes_ex18.py \ + modifying_meshes_ex19.py \ + modifying_meshes_ex20.py \ + modifying_meshes_ex21.py \ + modifying_meshes_ex22.py \ + modifying_meshes_ex23.py \ + modifying_meshes_ex24.py \ + modifying_meshes_ex25.py \ + modifying_meshes_ex26.py \ + notebook_smesh.py \ + prism_3d_algo.py \ + quality_controls_ex01.py \ + quality_controls_ex02.py \ + quality_controls_ex03.py \ + quality_controls_ex04.py \ + quality_controls_ex05.py \ + quality_controls_ex06.py \ + quality_controls_ex07.py \ + quality_controls_ex08.py \ + quality_controls_ex09.py \ + quality_controls_ex10.py \ + quality_controls_ex11.py \ + quality_controls_ex12.py \ + quality_controls_ex13.py \ + quality_controls_ex14.py \ + quality_controls_ex15.py \ + quality_controls_ex16.py \ + quality_controls_ex17.py \ + quality_controls_ex18.py \ + quality_controls_ex19.py \ + quality_controls_ex20.py \ + quality_controls_ex21.py \ + quality_controls_ex22.py \ + transforming_meshes_ex01.py \ + transforming_meshes_ex02.py \ + transforming_meshes_ex03.py \ + transforming_meshes_ex04.py \ + transforming_meshes_ex05.py \ + transforming_meshes_ex06.py \ + transforming_meshes_ex07.py \ + transforming_meshes_ex08.py \ + transforming_meshes_ex09.py \ + transforming_meshes_ex10.py \ + transforming_meshes_ex11.py \ + transforming_meshes_ex12.py \ + transforming_meshes_ex13.py \ + use_existing_faces.py \ + viewing_meshes_ex01.py \ + viewing_meshes_ex02.py + +pyexamples_SCRIPTS = $(BAD_TESTS) $(GOOD_TESTS) + +EXTRA_DIST += $(pyexamples_SCRIPTS) testme.py + +check-local: + @for f in $(GOOD_TESTS) ; do \ + python $(top_srcdir)/doc/salome/examples/testme.py $(top_srcdir)/doc/salome/examples/$$f || exit 1; \ + done diff --git a/doc/salome/examples/cartesian_algo.py b/doc/salome/examples/cartesian_algo.py new file mode 100644 index 000000000..b15455f28 --- /dev/null +++ b/doc/salome/examples/cartesian_algo.py @@ -0,0 +1,42 @@ +# Usage of Body Fitting algorithm + +from smesh import * +SetCurrentStudy(salome.myStudy) + +# create a sphere +sphere = geompy.MakeSphereR( 50 ) +geompy.addToStudy( sphere, "sphere" ) + +# create a mesh and assign a "Body Fitting" algo +mesh = Mesh( sphere ) +cartAlgo = mesh.BodyFitted() + +# define a cartesian grid using Coordinates +coords = range(-100,100,10) +cartHyp = cartAlgo.SetGrid( coords,coords,coords, 1000000) + +# compute the mesh +mesh.Compute() +print "nb hexahedra",mesh.NbHexas() +print "nb tetrahedra",mesh.NbTetras() +print "nb polyhedra",mesh.NbPolyhedrons() +print + +# define the grid by setting constant spacing +cartHyp = cartAlgo.SetGrid( "10","10","10", 1000000) + +mesh.Compute() +print "nb hexahedra",mesh.NbHexas() +print "nb tetrahedra",mesh.NbTetras() +print "nb polyhedra",mesh.NbPolyhedrons() + + +# define the grid by setting different spacing in 2 sub-ranges of geometry +spaceFuns = ["5","10+10*t"] +cartAlgo.SetGrid( [spaceFuns, [0.5]], [spaceFuns, [0.5]], [spaceFuns, [0.25]], 10 ) + +mesh.Compute() +print "nb hexahedra",mesh.NbHexas() +print "nb tetrahedra",mesh.NbTetras() +print "nb polyhedra",mesh.NbPolyhedrons() +print diff --git a/doc/salome/examples/creating_meshes_ex01.py b/doc/salome/examples/creating_meshes_ex01.py new file mode 100644 index 000000000..0b93356c4 --- /dev/null +++ b/doc/salome/examples/creating_meshes_ex01.py @@ -0,0 +1,28 @@ +# Construction of a Mesh + +import geompy +import smesh + +# create a box +box = geompy.MakeBox(0., 0., 0., 100., 200., 300.) +idbox = geompy.addToStudy(box, "box") + +# create a mesh +tetra = smesh.Mesh(box, "MeshBox") + +algo1D = tetra.Segment() +algo1D.NumberOfSegments(7) + +algo2D = tetra.Triangle() +algo2D.MaxElementArea(800.) + +algo3D = tetra.Tetrahedron() +algo3D.MaxElementVolume(900.) + +# compute the mesh +ret = tetra.Compute() +if ret == 0: + print "problem when computing the mesh" +else: + print "mesh computed" + pass diff --git a/doc/salome/examples/creating_meshes_ex02.py b/doc/salome/examples/creating_meshes_ex02.py new file mode 100644 index 000000000..c541b4add --- /dev/null +++ b/doc/salome/examples/creating_meshes_ex02.py @@ -0,0 +1,39 @@ +# Construction of a Submesh + +from geompy import * +import smesh + +# create a box +box = MakeBoxDXDYDZ(10., 10., 10.) +addToStudy(box, "Box") + +# select one edge of the box for definition of a local hypothesis +p5 = MakeVertex(5., 0., 0.) +EdgeX = GetEdgeNearPoint(box, p5) +addToStudyInFather(box, EdgeX, "Edge [0,0,0 - 10,0,0]") + +# create a hexahedral mesh on the box +quadra = smesh.Mesh(box, "Box : quadrangle 2D mesh") + +# create a regular 1D algorithm for the faces +algo1D = quadra.Segment() + +# define "NumberOfSegments" hypothesis to cut +# all the edges in a fixed number of segments +algo1D.NumberOfSegments(4) + +# create a quadrangle 2D algorithm for the faces +quadra.Quadrangle() + +# construct a submesh on the edge with a local hypothesis +algo_local = quadra.Segment(EdgeX) + +# define "Arithmetic1D" hypothesis to cut the edge in several segments with increasing arithmetic length +algo_local.Arithmetic1D(1, 4) + +# define "Propagation" hypothesis that propagates all other hypotheses +# on all edges of the opposite side in case of quadrangular faces +algo_local.Propagation() + +# compute the mesh +quadra.Compute() diff --git a/doc/salome/examples/creating_meshes_ex03.py b/doc/salome/examples/creating_meshes_ex03.py new file mode 100644 index 000000000..7b219f3a6 --- /dev/null +++ b/doc/salome/examples/creating_meshes_ex03.py @@ -0,0 +1,57 @@ +# Change priority of submeshes in Mesh + +import salome +import geompy +import smesh +import SMESH + +Box_1 = geompy.MakeBoxDXDYDZ(200, 200, 200) +[Face_1,Face_2,Face_3,Face_4,Face_5,Face_6] = geompy.SubShapeAllSorted(Box_1, geompy.ShapeType["FACE"]) + +# create Mesh object on Box shape +Mesh_1 = smesh.Mesh(Box_1) + +# assign mesh algorithms +Regular_1D = Mesh_1.Segment() +Nb_Segments_1 = Regular_1D.NumberOfSegments(20) +Nb_Segments_1.SetDistrType( 0 ) +MEFISTO_2D = Mesh_1.Triangle() +Max_Element_Area_1 = MEFISTO_2D.MaxElementArea(1200) +Tetrahedron = Mesh_1.Tetrahedron() +Max_Element_Volume_1 = Tetrahedron.MaxElementVolume(40000) + +# create submesh and assign algorithms on Face_1 +Regular_1D_1 = Mesh_1.Segment(geom=Face_1) +Nb_Segments_2 = Regular_1D_1.NumberOfSegments(4) +Nb_Segments_2.SetDistrType( 0 ) +MEFISTO_2D_1 = Mesh_1.Triangle(algo=smesh.MEFISTO,geom=Face_1) +Length_From_Edges_2D = MEFISTO_2D_1.LengthFromEdges() +SubMesh_1 = MEFISTO_2D_1.GetSubMesh() + +# create submesh and assign algorithms on Face_2 +Regular_1D_2 = Mesh_1.Segment(geom=Face_2) +Nb_Segments_3 = Regular_1D_2.NumberOfSegments(8) +Nb_Segments_3.SetDistrType( 0 ) +MEFISTO_2D_2 = Mesh_1.Triangle(algo=smesh.MEFISTO,geom=Face_2) +Length_From_Edges_2D_1 = MEFISTO_2D_2.LengthFromEdges() +SubMesh_2 = MEFISTO_2D_2.GetSubMesh() + +# create submesh and assign algorithms on Face_3 +Regular_1D_3 = Mesh_1.Segment(geom=Face_3) +Nb_Segments_4 = Regular_1D_3.NumberOfSegments(12) +Nb_Segments_4.SetDistrType( 0 ) +MEFISTO_2D_3 = Mesh_1.Triangle(algo=smesh.MEFISTO,geom=Face_3) +Length_From_Edges_2D_2 = MEFISTO_2D_3.LengthFromEdges() +SubMesh_3 = MEFISTO_2D_3.GetSubMesh() + +# check exisiting submesh priority order +[ [ SubMesh_1, SubMesh_3, SubMesh_2 ] ] = Mesh_1.GetMeshOrder() +# set new submesh order +isDone = Mesh_1.SetMeshOrder( [ [ SubMesh_1, SubMesh_2, SubMesh_3 ] ]) +# compute mesh +isDone = Mesh_1.Compute() + +# clear mesh result and compute with other submesh order +Mesh_1.Clear() +isDone = Mesh_1.SetMeshOrder( [ [ SubMesh_2, SubMesh_1, SubMesh_3 ] ]) +isDone = Mesh_1.Compute() diff --git a/doc/salome/examples/creating_meshes_ex04.py b/doc/salome/examples/creating_meshes_ex04.py new file mode 100644 index 000000000..33106c775 --- /dev/null +++ b/doc/salome/examples/creating_meshes_ex04.py @@ -0,0 +1,54 @@ +# Editing of a mesh + +import geompy +import smesh + +def PrintMeshInfo(theMesh): + aMesh = theMesh.GetMesh() + print "Information about mesh:" + print "Number of nodes : ", aMesh.NbNodes() + print "Number of edges : ", aMesh.NbEdges() + print "Number of faces : ", aMesh.NbFaces() + print "Number of volumes : ", aMesh.NbVolumes() + pass + +# create a box +box = geompy.MakeBox(0., 0., 0., 20., 20., 20.) +geompy.addToStudy(box, "box") + +# select one edge of the box for definition of a local hypothesis +subShapeList = geompy.SubShapeAll(box, geompy.ShapeType["EDGE"]) +edge = subShapeList[0] +name = geompy.SubShapeName(edge, box) +geompy.addToStudyInFather(box, edge, name) + +# create a mesh +tria = smesh.Mesh(box, "Mesh 2D") +algo1D = tria.Segment() +hyp1 = algo1D.NumberOfSegments(3) +algo2D = tria.Triangle() +hyp2 = algo2D.MaxElementArea(10.) + +# create a sub-mesh +algo_local = tria.Segment(edge) +hyp3 = algo_local.Arithmetic1D(1, 6) +hyp4 = algo_local.Propagation() + +# compute the mesh +tria.Compute() +PrintMeshInfo(tria) + +# remove a local hypothesis +mesh = tria.GetMesh() +mesh.RemoveHypothesis(edge, hyp4) + +# compute the mesh +tria.Compute() +PrintMeshInfo(tria) + +# change the value of the 2D hypothesis +hyp2.SetMaxElementArea(2.) + +# compute the mesh +tria.Compute() +PrintMeshInfo(tria) diff --git a/doc/salome/examples/creating_meshes_ex05.py b/doc/salome/examples/creating_meshes_ex05.py new file mode 100644 index 000000000..6ba410307 --- /dev/null +++ b/doc/salome/examples/creating_meshes_ex05.py @@ -0,0 +1,31 @@ +# Export of a Mesh + +import geompy +import smesh + +# create a box +box = geompy.MakeBox(0., 0., 0., 100., 200., 300.) +idbox = geompy.addToStudy(box, "box") + +# create a mesh +tetra = smesh.Mesh(box, "MeshBox") + +algo1D = tetra.Segment() +algo1D.NumberOfSegments(7) + +algo2D = tetra.Triangle() +algo2D.MaxElementArea(800.) + +algo3D = tetra.Tetrahedron() +algo3D.MaxElementVolume(900.) + +# compute the mesh +tetra.Compute() + +# export the mesh in a MED file +tetra.ExportMED("/tmp/meshMED.med", 0) + +# export a group in a MED file +face = geompy.SubShapeAll( box, geompy.ShapeType["FACE"])[0] # a box side +group = tetra.GroupOnGeom( face, "face group" ) # group of 2D elements on the +tetra.ExportMED("/tmp/groupMED.med", meshPart=group) diff --git a/doc/salome/examples/creating_meshes_ex06.py b/doc/salome/examples/creating_meshes_ex06.py new file mode 100644 index 000000000..96b2a29c7 --- /dev/null +++ b/doc/salome/examples/creating_meshes_ex06.py @@ -0,0 +1,106 @@ +# Creating a hexahedral mesh on a cylinder. +# Note: it is a copy of 'ex24_cylinder.py' from SMESH_SWIG + +import math + +import geompy +import smesh +import salome +geo = geompy + +# Parameters +# ---------- + +radius = 50 +height = 200 + +# Build a cylinder +# ---------------- + +base = geo.MakeVertex(0, 0, 0) +direction = geo.MakeVectorDXDYDZ(0, 0, 1) + +cylinder = geo.MakeCylinder(base, direction, radius, height) + +geo.addToStudy(cylinder, "cylinder") + +# Build blocks +# ------------ + +size = radius/2.0 + +box_rot = geo.MakeBox(-size, -size, 0, +size, +size, height) +box_axis = geo.MakeLine(base, direction) +box = geo.MakeRotation(box_rot, box_axis, math.pi/4) + +hole = geo.MakeCut(cylinder, box) + +plane_trim = 2000 + +plane_a = geo.MakePlane(base, geo.MakeVectorDXDYDZ(1, 0, 0), plane_trim) +plane_b = geo.MakePlane(base, geo.MakeVectorDXDYDZ(0, 1, 0), plane_trim) + +blocks_part = geo.MakePartition([hole], [plane_a, plane_b], [], [], geo.ShapeType["SOLID"]) +blocks_list = [box] + geo.SubShapeAll(blocks_part, geo.ShapeType["SOLID"]) +blocks_all = geo.MakeCompound(blocks_list) +blocks = geo.MakeGlueFaces(blocks_all, 0.0001) + +geo.addToStudy(blocks, "cylinder:blocks") + +# Build geometric groups +# ---------------------- + +def group(name, shape, type, base=None, direction=None): + t = geo.ShapeType[type] + g = geo.CreateGroup(shape, t) + + geo.addToStudy(g, name) + g.SetName(name) + + if base!=None: + l = geo.GetShapesOnPlaneWithLocationIDs(shape, t, direction, base, geo.GEOM.ST_ON) + geo.UnionIDs(g, l) + + return g + +group_a = group("baseA", blocks, "FACE", base, direction) + +base_b = geo.MakeVertex(0, 0, height) +group_b = group("baseB", blocks, "FACE", base_b, direction) + +group_1 = group("limit", blocks, "SOLID") +group_1_all = geo.SubShapeAllIDs(blocks, geo.ShapeType["SOLID"]) +geo.UnionIDs(group_1, group_1_all) +group_1_box = geo.GetBlockNearPoint(blocks, base) +geo.DifferenceList(group_1, [group_1_box]) + +# Mesh the blocks with hexahedral +# ------------------------------- + +smesh.SetCurrentStudy(salome.myStudy) + +def discretize(x, y, z, n, s=blocks): + p = geo.MakeVertex(x, y, z) + e = geo.GetEdgeNearPoint(s, p) + a = hexa.Segment(e) + a.NumberOfSegments(n) + a.Propagation() + +hexa = smesh.Mesh(blocks) + +hexa_1d = hexa.Segment() +hexa_1d.NumberOfSegments(1) + +discretize(+radius , +radius, 0, 5) +discretize(-radius , +radius, 0, 8) +discretize((radius+size)/2, 0, 0, 10) +discretize( +radius, 0, height/2, 20) + +hexa.Quadrangle() +hexa.Hexahedron() + +hexa.Compute() + +hexa.Group(group_a) +hexa.Group(group_b) +hexa.Group(group_1) diff --git a/doc/salome/examples/creating_meshes_ex07.py b/doc/salome/examples/creating_meshes_ex07.py new file mode 100644 index 000000000..3140acee8 --- /dev/null +++ b/doc/salome/examples/creating_meshes_ex07.py @@ -0,0 +1,73 @@ +# Building a compound of meshes +# Note: it is a copy of 'SMESH_BuildCompound.py' from SMESH_SWIG + +import salome +import geompy +import smesh + +## create a bottom box +Box_inf = geompy.MakeBox(0., 0., 0., 200., 200., 50.) + +# get a top face +Psup1=geompy.MakeVertex(100., 100., 50.) +Fsup1=geompy.GetFaceNearPoint(Box_inf, Psup1) +# get a bottom face +Pinf1=geompy.MakeVertex(100., 100., 0.) +Finf1=geompy.GetFaceNearPoint(Box_inf, Pinf1) + +## create a top box +Box_sup = geompy.MakeBox(100., 100., 50., 200., 200., 100.) + +# get a top face +Psup2=geompy.MakeVertex(150., 150., 100.) +Fsup2=geompy.GetFaceNearPoint(Box_sup, Psup2) +# get a bottom face +Pinf2=geompy.MakeVertex(150., 150., 50.) +Finf2=geompy.GetFaceNearPoint(Box_sup, Pinf2) + +## Publish in the study +geompy.addToStudy(Box_inf, "Box_inf") +geompy.addToStudyInFather(Box_inf, Fsup1, "Fsup") +geompy.addToStudyInFather(Box_inf, Finf1, "Finf") + +geompy.addToStudy(Box_sup, "Box_sup") +geompy.addToStudyInFather(Box_sup, Fsup2, "Fsup") +geompy.addToStudyInFather(Box_sup, Finf2, "Finf") + +smesh.SetCurrentStudy(salome.myStudy) + +## create a bottom mesh +Mesh_inf = smesh.Mesh(Box_inf, "Mesh_inf") +algo1D_1=Mesh_inf.Segment() +algo1D_1.NumberOfSegments(10) +algo2D_1=Mesh_inf.Quadrangle() +algo3D_1=Mesh_inf.Hexahedron() +Mesh_inf.Compute() + +# create a group on the top face +Gsup1=Mesh_inf.Group(Fsup1, "Sup") +# create a group on the bottom face +Ginf1=Mesh_inf.Group(Finf1, "Inf") + +## create a top mesh +Mesh_sup = smesh.Mesh(Box_sup, "Mesh_sup") +algo1D_2=Mesh_sup.Segment() +algo1D_2.NumberOfSegments(5) +algo2D_2=Mesh_sup.Quadrangle() +algo3D_2=Mesh_sup.Hexahedron() +Mesh_sup.Compute() + +# create a group on the top face +Gsup2=Mesh_sup.Group(Fsup2, "Sup") +# create a group on the bottom face +Ginf2=Mesh_sup.Group(Finf2, "Inf") + +## create compounds +# create a compound of two meshes with renaming groups with the same names and +# merging of elements with the given tolerance +Compound1 = smesh.smesh.Concatenate([Mesh_inf.GetMesh(), Mesh_sup.GetMesh()], 0, 1, 1e-05) +smesh.SetName(Compound1, 'Compound_with_RenamedGrps_and_MergeElems') +# create a compound of two meshes with uniting groups with the same names and +# creating groups of all elements +Compound2 = smesh.smesh.Concatenate([Mesh_inf.GetMesh(), Mesh_sup.GetMesh()], 1, 0, 1e-05, True) +smesh.SetName(Compound2, 'Compound_with_UniteGrps_and_GrpsOfAllElems') diff --git a/doc/salome/examples/creating_meshes_ex08.py b/doc/salome/examples/creating_meshes_ex08.py new file mode 100644 index 000000000..a76e8d175 --- /dev/null +++ b/doc/salome/examples/creating_meshes_ex08.py @@ -0,0 +1,40 @@ +# Mesh Copying + +from smesh import * +SetCurrentStudy(salome.myStudy) + +# make geometry of a box +box = geompy.MakeBoxDXDYDZ(100,100,100) +face = geompy.SubShapeAllSorted(box, geompy.ShapeType["FACE"])[0] + +# generate 3D mesh +mesh = Mesh(box) +localAlgo = mesh.Triangle(face) +mesh.AutomaticHexahedralization() + +# objects to copy +fGroup = mesh.GroupOnGeom( face, "2D on face") +nGroup = mesh.GroupOnGeom( face, "nodes on face", NODE) +subMesh = localAlgo.GetSubMesh() + +# make a new mesh by copying different parts of the mesh + +# 1. copy the whole mesh +newMesh = CopyMesh( mesh, "whole mesh copy") + +# 2. copy a group of 2D elements along with groups +newMesh = CopyMesh( fGroup, "face group copy with groups",toCopyGroups=True) + +# 3. copy a group of nodes with preseving their ids +newMesh = CopyMesh( nGroup, "node group copy", toKeepIDs=True) + +# 4. copy some faces +faceIds = fGroup.GetIDs()[-10:] +newMesh = CopyMesh( mesh.GetIDSource( faceIds, FACE ), "some faces copy") + +# 5. copy some nodes +nodeIds = nGroup.GetIDs()[-10:] +newMesh = CopyMesh( mesh.GetIDSource( nodeIds, NODE), "some nodes copy") + +# 6. copy a sub-mesh +newMesh = CopyMesh( subMesh, "submesh copy" ) diff --git a/doc/salome/examples/defining_hypotheses_ex01.py b/doc/salome/examples/defining_hypotheses_ex01.py new file mode 100644 index 000000000..6efb1cfb9 --- /dev/null +++ b/doc/salome/examples/defining_hypotheses_ex01.py @@ -0,0 +1,30 @@ +# Arithmetic 1D + +import geompy +import smesh + +# create a box +box = geompy.MakeBoxDXDYDZ(10., 10., 10.) +geompy.addToStudy(box, "Box") + +# create a hexahedral mesh on the box +hexa = smesh.Mesh(box, "Box : hexahedrical mesh") + +# create a Regular 1D algorithm for edges +algo1D = hexa.Segment() + +# optionally reverse node distribution on certain edges +allEdges = geompy.SubShapeAllSortedIDs( box, geompy.ShapeType["EDGE"]) +reversedEdges = [ allEdges[0], allEdges[4] ] + +# define "Arithmetic1D" hypothesis to cut all edges in several segments with increasing arithmetic length +algo1D.Arithmetic1D(1, 4, reversedEdges) + +# create a quadrangle 2D algorithm for faces +hexa.Quadrangle() + +# create a hexahedron 3D algorithm for solids +hexa.Hexahedron() + +# compute the mesh +hexa.Compute() diff --git a/doc/salome/examples/defining_hypotheses_ex02.py b/doc/salome/examples/defining_hypotheses_ex02.py new file mode 100644 index 000000000..b0726a1ca --- /dev/null +++ b/doc/salome/examples/defining_hypotheses_ex02.py @@ -0,0 +1,40 @@ +# Deflection 1D and Number of Segments + +import geompy +import smesh + +# create a face from arc and straight segment +px = geompy.MakeVertex(100., 0. , 0. ) +py = geompy.MakeVertex(0. , 100., 0. ) +pz = geompy.MakeVertex(0. , 0. , 100.) + +exy = geompy.MakeEdge(px, py) +arc = geompy.MakeArc(py, pz, px) + +wire = geompy.MakeWire([exy, arc]) + +isPlanarFace = 1 +face1 = geompy.MakeFace(wire, isPlanarFace) +geompy.addToStudy(face1,"Face1") + +# get edges from the face +e_straight,e_arc = geompy.SubShapeAll(face1, geompy.ShapeType["EDGE"]) +geompy.addToStudyInFather(face1, e_arc, "Arc Edge") + +# create hexahedral mesh +hexa = smesh.Mesh(face1, "Face : triangle mesh") + +# define "NumberOfSegments" hypothesis to cut a straight edge in a fixed number of segments +algo1D = hexa.Segment() +algo1D.NumberOfSegments(6) + +# define "MaxElementArea" hypothesis +algo2D = hexa.Triangle() +algo2D.MaxElementArea(70.0) + +# define a local "Deflection1D" hypothesis on the arc +algo_local = hexa.Segment(e_arc) +algo_local.Deflection1D(1.0) + +# compute the mesh +hexa.Compute() diff --git a/doc/salome/examples/defining_hypotheses_ex03.py b/doc/salome/examples/defining_hypotheses_ex03.py new file mode 100644 index 000000000..cfb1ca86c --- /dev/null +++ b/doc/salome/examples/defining_hypotheses_ex03.py @@ -0,0 +1,37 @@ +# Start and End Length + +from geompy import * +import smesh + +# create a box +box = MakeBoxDXDYDZ(10., 10., 10.) +addToStudy(box, "Box") + +# get one edge of the box to put local hypothesis on +p5 = MakeVertex(5., 0., 0.) +EdgeX = GetEdgeNearPoint(box, p5) +addToStudyInFather(box, EdgeX, "Edge [0,0,0 - 10,0,0]") + +# create a hexahedral mesh on the box +hexa = smesh.Mesh(box, "Box : hexahedrical mesh") + +# set algorithms +algo1D = hexa.Segment() +hexa.Quadrangle() +hexa.Hexahedron() + +# define "NumberOfSegments" hypothesis to cut an edge in a fixed number of segments +algo1D.NumberOfSegments(4) + +# create a local hypothesis +algo_local = hexa.Segment(EdgeX) + +# define "StartEndLength" hypothesis to cut an edge in several segments with increasing geometric length +algo_local.StartEndLength(1, 6) + +# define "Propagation" hypothesis that propagates all other hypothesis +# on all edges on the opposite side in case of quadrangular faces +algo_local.Propagation() + +# compute the mesh +hexa.Compute() diff --git a/doc/salome/examples/defining_hypotheses_ex04.py b/doc/salome/examples/defining_hypotheses_ex04.py new file mode 100644 index 000000000..0a17f5ca1 --- /dev/null +++ b/doc/salome/examples/defining_hypotheses_ex04.py @@ -0,0 +1,37 @@ +# Local Length + +from geompy import * +import smesh + +# create a box +box = MakeBoxDXDYDZ(10., 10., 10.) +addToStudy(box, "Box") + +# get one edge of the box to put local hypothesis on +p5 = MakeVertex(5., 0., 0.) +EdgeX = GetEdgeNearPoint(box, p5) +addToStudyInFather(box, EdgeX, "Edge [0,0,0 - 10,0,0]") + +# create a hexahedral mesh on the box +hexa = smesh.Mesh(box, "Box : hexahedrical mesh") + +# set algorithms +algo1D = hexa.Segment() +hexa.Quadrangle() +hexa.Hexahedron() + +# define "NumberOfSegments" hypothesis to cut all edges in a fixed number of segments +algo1D.NumberOfSegments(4) + +# create a sub-mesh +algo_local = hexa.Segment(EdgeX) + +# define "LocalLength" hypothesis to cut an edge in several segments with the same length +algo_local.LocalLength(2.) + +# define "Propagation" hypothesis that propagates all other hypothesis +# on all edges on the opposite side in case of quadrangular faces +algo_local.Propagation() + +# compute the mesh +hexa.Compute() diff --git a/doc/salome/examples/defining_hypotheses_ex05.py b/doc/salome/examples/defining_hypotheses_ex05.py new file mode 100644 index 000000000..fcf03d0d6 --- /dev/null +++ b/doc/salome/examples/defining_hypotheses_ex05.py @@ -0,0 +1,38 @@ +# Maximum Element Area + +import geompy +import smesh +import salome + +# create a face +px = geompy.MakeVertex(100., 0. , 0. ) +py = geompy.MakeVertex(0. , 100., 0. ) +pz = geompy.MakeVertex(0. , 0. , 100.) + +vxy = geompy.MakeVector(px, py) +arc = geompy.MakeArc(py, pz, px) +wire = geompy.MakeWire([vxy, arc]) + +isPlanarFace = 1 +face = geompy.MakeFace(wire, isPlanarFace) + +# add the face in the study +id_face = geompy.addToStudy(face, "Face to be meshed") + +# create a mesh +tria_mesh = smesh.Mesh(face, "Face : triangulation") + +# define 1D meshing: +algo = tria_mesh.Segment() +algo.NumberOfSegments(20) + +# define 2D meshing: + +# assign triangulation algorithm +algo = tria_mesh.Triangle() + +# apply "Max Element Area" hypothesis to each triangle +algo.MaxElementArea(100) + +# compute the mesh +tria_mesh.Compute() diff --git a/doc/salome/examples/defining_hypotheses_ex06.py b/doc/salome/examples/defining_hypotheses_ex06.py new file mode 100644 index 000000000..24bc4da39 --- /dev/null +++ b/doc/salome/examples/defining_hypotheses_ex06.py @@ -0,0 +1,30 @@ +# Maximum Element Volume + +import geompy +import smesh + +# create a cylinder +cyl = geompy.MakeCylinderRH(30., 50.) +geompy.addToStudy(cyl, "cyl") + +# create a mesh on the cylinder +tetra = smesh.Mesh(cyl, "Cylinder : tetrahedrical mesh") + +# assign algorithms +algo1D = tetra.Segment() +algo2D = tetra.Triangle() +algo3D = tetra.Tetrahedron() + +# assign 1D and 2D hypotheses +algo1D.NumberOfSegments(7) +algo2D.MaxElementArea(150.) + +# assign Max Element Volume hypothesis +algo3D.MaxElementVolume(200.) + +# compute the mesh +ret = tetra.Compute() +if ret == 0: + print "probleme when computing the mesh" +else: + print "Computation succeded" diff --git a/doc/salome/examples/defining_hypotheses_ex07.py b/doc/salome/examples/defining_hypotheses_ex07.py new file mode 100644 index 000000000..59d7521a2 --- /dev/null +++ b/doc/salome/examples/defining_hypotheses_ex07.py @@ -0,0 +1,29 @@ +# Length from Edges + +import geompy +import smesh + +# create sketchers +sketcher1 = geompy.MakeSketcher("Sketcher:F 0 0:TT 70 0:TT 70 70:TT 0 70:WW") +sketcher2 = geompy.MakeSketcher("Sketcher:F 20 20:TT 50 20:TT 50 50:TT 20 50:WW") + +# create a face from two wires +isPlanarFace = 1 +face1 = geompy.MakeFaces([sketcher1, sketcher2], isPlanarFace) +geompy.addToStudy(face1, "Face1") + +# create a mesh +tria = smesh.Mesh(face1, "Face : triangle 2D mesh") + +# Define 1D meshing +algo1D = tria.Segment() +algo1D.NumberOfSegments(2) + +# create and assign the algorithm for 2D meshing with triangles +algo2D = tria.Triangle() + +# create and assign "LengthFromEdges" hypothesis to build triangles based on the length of the edges taken from the wire +algo2D.LengthFromEdges() + +# compute the mesh +tria.Compute() diff --git a/doc/salome/examples/defining_hypotheses_ex08.py b/doc/salome/examples/defining_hypotheses_ex08.py new file mode 100644 index 000000000..438773427 --- /dev/null +++ b/doc/salome/examples/defining_hypotheses_ex08.py @@ -0,0 +1,35 @@ +# Propagation + +from geompy import * +import smesh + +# create a box +box = MakeBoxDXDYDZ(10., 10., 10.) +addToStudy(box, "Box") + +# get one edge of the box to put local hypothesis on +p5 = MakeVertex(5., 0., 0.) +EdgeX = GetEdgeNearPoint(box, p5) +addToStudyInFather(box, EdgeX, "Edge [0,0,0 - 10,0,0]") + +# create a hexahedral mesh on the box +hexa = smesh.Mesh(box, "Box : hexahedrical mesh") + +# set global algorithms and hypotheses +algo1D = hexa.Segment() +hexa.Quadrangle() +hexa.Hexahedron() +algo1D.NumberOfSegments(4) + +# create a sub-mesh with local 1D hypothesis and propagation +algo_local = hexa.Segment(EdgeX) + +# define "Arithmetic1D" hypothesis to cut an edge in several segments with increasing length +algo_local.Arithmetic1D(1, 4) + +# define "Propagation" hypothesis that propagates all other 1D hypotheses +# from all edges on the opposite side of a face in case of quadrangular faces +algo_local.Propagation() + +# compute the mesh +hexa.Compute() diff --git a/doc/salome/examples/defining_hypotheses_ex09.py b/doc/salome/examples/defining_hypotheses_ex09.py new file mode 100644 index 000000000..9956e4ba5 --- /dev/null +++ b/doc/salome/examples/defining_hypotheses_ex09.py @@ -0,0 +1,45 @@ +# Defining Meshing Algorithms + +import geompy +import smesh + +# create a box +box = geompy.MakeBoxDXDYDZ(10., 10., 10.) +geompy.addToStudy(box, "Box") + +# 1. Create a hexahedral mesh on the box +hexa = smesh.Mesh(box, "Box : hexahedrical mesh") + +# create a Regular 1D algorithm for edges +algo1D = hexa.Segment() + +# create a quadrangle 2D algorithm for faces +algo2D = hexa.Quadrangle() + +# create a hexahedron 3D algorithm for solids +algo3D = hexa.Hexahedron() + +# define hypotheses +algo1D.Arithmetic1D(1, 4) + +# compute the mesh +hexa.Compute() + +# 2. Create a tetrahedral mesh on the box +tetra = smesh.Mesh(box, "Box : tetrahedrical mesh") + +# create a Regular 1D algorithm for edges +algo1D = tetra.Segment() + +# create a Mefisto 2D algorithm for faces +algo2D = tetra.Triangle() + +# create a 3D algorithm for solids +algo3D = tetra.Tetrahedron() + +# define hypotheses +algo1D.Arithmetic1D(1, 4) +algo2D.LengthFromEdges() + +# compute the mesh +tetra.Compute() diff --git a/doc/salome/examples/defining_hypotheses_ex10.py b/doc/salome/examples/defining_hypotheses_ex10.py new file mode 100644 index 000000000..644908be2 --- /dev/null +++ b/doc/salome/examples/defining_hypotheses_ex10.py @@ -0,0 +1,76 @@ +# Projection Algorithms + +# Project prisms from one meshed box to another mesh on the same box + +from smesh import * + +# Prepare geometry + +# Create a parallelepiped +box = geompy.MakeBoxDXDYDZ(200, 100, 70) +geompy.addToStudy( box, "box" ) + +# Get geom faces to mesh with triangles in the 1ts and 2nd meshes +faces = geompy.SubShapeAll(box, geompy.ShapeType["FACE"]) +# 2 adjacent faces of the box +f1 = faces[2] +f2 = faces[0] +# face opposite to f2 +f2opp = faces[1] + +# Get vertices used to specify how to associate sides of faces at projection +[v1F1, v2F1] = geompy.SubShapeAll(f1, geompy.ShapeType["VERTEX"])[:2] +[v1F2, v2F2] = geompy.SubShapeAll(f2, geompy.ShapeType["VERTEX"])[:2] +geompy.addToStudyInFather( box, v1F1, "v1F1" ) +geompy.addToStudyInFather( box, v2F1, "v2F1" ) +geompy.addToStudyInFather( box, v1F2, "v1F2" ) +geompy.addToStudyInFather( box, v2F2, "v2F2" ) + +# Make group of 3 edges of f1 and f2 +edgesF1 = geompy.CreateGroup(f1, geompy.ShapeType["EDGE"]) +geompy.UnionList( edgesF1, geompy.SubShapeAll(f1, geompy.ShapeType["EDGE"])[:3]) +edgesF2 = geompy.CreateGroup(f2, geompy.ShapeType["EDGE"]) +geompy.UnionList( edgesF2, geompy.SubShapeAll(f2, geompy.ShapeType["EDGE"])[:3]) +geompy.addToStudyInFather( box, edgesF1, "edgesF1" ) +geompy.addToStudyInFather( box, edgesF2, "edgesF2" ) + + +# Make the source mesh with prisms +src_mesh = Mesh(box, "Source mesh") +src_mesh.Segment().NumberOfSegments(9,10) +src_mesh.Quadrangle() +src_mesh.Hexahedron() +src_mesh.Triangle(f1) # triangular sumbesh +src_mesh.Compute() + + +# Mesh the box using projection algoritms + +# Define the same global 1D and 2D hypotheses +tgt_mesh = Mesh(box, "Target mesh") +tgt_mesh.Segment().NumberOfSegments(9,10,UseExisting=True) +tgt_mesh.Quadrangle() + +# Define Projection 1D algorithm to project 1d mesh elements from group edgesF2 to edgesF1 +# It is actually not needed, just a demonstration +proj1D = tgt_mesh.Projection1D( edgesF1 ) +# each vertex must be at the end of a connected group of edges (or a sole edge) +proj1D.SourceEdge( edgesF2, src_mesh, v2F1, v2F2 ) + +# Define 2D hypotheses to project triangles from f1 face of the source mesh to +# f2 face in the target mesh. Vertices specify how to associate sides of faces +proj2D = tgt_mesh.Projection2D( f2 ) +proj2D.SourceFace( f1, src_mesh, v1F1, v1F2, v2F1, v2F2 ) + +# 2D hypotheses to project triangles from f2 of target mesh to the face opposite to f2. +# Association of face sides is default +proj2D = tgt_mesh.Projection2D( f2opp ) +proj2D.SourceFace( f2 ) + +# 3D hypotheses to project prisms from the source to the target mesh +proj3D = tgt_mesh.Projection3D() +proj3D.SourceShape3D( box, src_mesh, v1F1, v1F2, v2F1, v2F2 ) +tgt_mesh.Compute() + +# Move the source mesh to visualy compare the two meshes +src_mesh.TranslateObject( src_mesh, MakeDirStruct( 210, 0, 0 ), Copy=False) diff --git a/doc/salome/examples/defining_hypotheses_ex11.py b/doc/salome/examples/defining_hypotheses_ex11.py new file mode 100644 index 000000000..be5504778 --- /dev/null +++ b/doc/salome/examples/defining_hypotheses_ex11.py @@ -0,0 +1,31 @@ +# Projection 1D2D + +# Project triangles from one meshed face to another mesh on the same box + +from smesh import * + +# Prepare geometry + +# Create a box +box = geompy.MakeBoxDXDYDZ(100, 100, 100) + +# Get geom faces to mesh with triangles in the 1ts and 2nd meshes +faces = geompy.SubShapeAll(box, geompy.ShapeType["FACE"]) +# 2 adjacent faces of the box +Face_1 = faces[2] +Face_2 = faces[0] + +geompy.addToStudy( box, 'box' ) +geompy.addToStudyInFather( box, Face_1, 'Face_1' ) +geompy.addToStudyInFather( box, Face_2, 'Face_2' ) + +# Make the source mesh with Netgem2D +src_mesh = Mesh(Face_1, "Source mesh") +src_mesh.Segment().NumberOfSegments(15) +src_mesh.Triangle() +src_mesh.Compute() + +# Mesh the target mesh using the algoritm Projection1D2D +tgt_mesh = smesh.Mesh(Face_2, "Target mesh") +tgt_mesh.Projection1D2D().SourceFace(Face_1,src_mesh) +tgt_mesh.Compute() diff --git a/doc/salome/examples/defining_hypotheses_ex12.py b/doc/salome/examples/defining_hypotheses_ex12.py new file mode 100644 index 000000000..dd891a73e --- /dev/null +++ b/doc/salome/examples/defining_hypotheses_ex12.py @@ -0,0 +1,36 @@ +# 1D Mesh with Fixed Points example + +import salome +import geompy +import smesh +import StdMeshers + +# Create face and explode it on edges +face = geompy.MakeFaceHW(100, 100, 1) +edges = geompy.SubShapeAllSorted(face, geompy.ShapeType["EDGE"]) +geompy.addToStudy( face, "Face" ) + +# get the first edge from exploded result +edge1 = geompy.GetSubShapeID(face, edges[0]) + +# Define Mesh on previously created face +Mesh_1 = smesh.Mesh(face) + +# Create Fixed Point 1D hypothesis and define parameters. +# Note: values greater than 1.0 and less than 0.0 are not taken into account; +# duplicated values are removed. Also, if not specified explicitly, values 0.0 and 1.0 +# add added automatically. +# The number of segments should correspond to the number of points (NbSeg = NbPnt-1); +# extra values of segments splitting parameter are not taken into account, +# while missing values are considered to be equal to 1. +Fixed_points_1D_1 = smesh.CreateHypothesis('FixedPoints1D') +Fixed_points_1D_1.SetPoints( [ 1.1, 0.9, 0.5, 0.0, 0.5, -0.3 ] ) +Fixed_points_1D_1.SetNbSegments( [ 3, 1, 2 ] ) +Fixed_points_1D_1.SetReversedEdges( [edge1] ) + +# Add hypothesis to mesh and define 2D parameters +Mesh_1.AddHypothesis(Fixed_points_1D_1) +Regular_1D = Mesh_1.Segment() +Quadrangle_2D = Mesh_1.Quadrangle() +# Compute mesh +Mesh_1.Compute() diff --git a/doc/salome/examples/defining_hypotheses_ex13.py b/doc/salome/examples/defining_hypotheses_ex13.py new file mode 100644 index 000000000..283984916 --- /dev/null +++ b/doc/salome/examples/defining_hypotheses_ex13.py @@ -0,0 +1,34 @@ +# Radial Quadrangle 1D2D example + +from smesh import * + +SetCurrentStudy(salome.myStudy) + +# Create face from the wire and add to study +Face = geompy.MakeSketcher("Sketcher:F 0 0:TT 20 0:R 90:C 20 90:WF", [0, 0, 0, 1, 0, 0, 0, 0, 1]) +geompy.addToStudy(Face,"Face") +edges = geompy.SubShapeAllSorted(Face, geompy.ShapeType["EDGE"]) +circle, radius1, radius2 = edges +geompy.addToStudyInFather(Face, radius1,"radius1") +geompy.addToStudyInFather(Face, radius2,"radius2") +geompy.addToStudyInFather(Face, circle,"circle") + + +# Define geometry for mesh, and Radial Quadrange algorithm +mesh = smesh.Mesh(Face) +radial_Quad_algo = mesh.Quadrangle(algo=RADIAL_QUAD) + +# The Radial Quadrange algorithm can work without any hypothesis +# In this case it uses "Default Nb of Segments" preferences parameter to discretize edges +mesh.Compute() + +# The Radial Quadrange uses global or local 1d hypotheses if it does +# not have its own hypotheses. +# Define global hypotheses to discretize radial edges and a local one for circular edge +global_Nb_Segments = mesh.Segment().NumberOfSegments(5) +local_Nb_Segments = mesh.Segment(circle).NumberOfSegments(10) +mesh.Compute() + +# Define own parameters of Radial Quadrange algorithm +radial_Quad_algo.NumberOfLayers( 4 ) +mesh.Compute() diff --git a/doc/salome/examples/defining_hypotheses_ex14.py b/doc/salome/examples/defining_hypotheses_ex14.py new file mode 100644 index 000000000..6c93e3d27 --- /dev/null +++ b/doc/salome/examples/defining_hypotheses_ex14.py @@ -0,0 +1,26 @@ +# Quadrangle Parameters example 1 (meshing a face with 3 edges) + +from smesh import * +SetCurrentStudy(salome.myStudy) + +# Get 1/4 part from the disk face. +Box_1 = geompy.MakeBoxDXDYDZ(100, 100, 100) +Disk_1 = geompy.MakeDiskR(100, 1) +Common_1 = geompy.MakeCommon(Disk_1, Box_1) +geompy.addToStudy( Disk_1, "Disk_1" ) +geompy.addToStudy( Box_1, "Box_1" ) +geompy.addToStudy( Common_1, "Common_1" ) + +# Set the Geometry for meshing +Mesh_1 = smesh.Mesh(Common_1) + + +# Define 1D hypothesis and compute the mesh +Regular_1D = Mesh_1.Segment() +Nb_Segments_1 = Regular_1D.NumberOfSegments(10) +Nb_Segments_1.SetDistrType( 0 ) + +# Create Quadrangle parameters and define the Base Vertex. +Quadrangle_2D = Mesh_1.Quadrangle().TriangleVertex( 8 ) + +Mesh_1.Compute() diff --git a/doc/salome/examples/defining_hypotheses_ex15.py b/doc/salome/examples/defining_hypotheses_ex15.py new file mode 100644 index 000000000..a08dfbfae --- /dev/null +++ b/doc/salome/examples/defining_hypotheses_ex15.py @@ -0,0 +1,47 @@ +# Quadrangle Parameters example 2 (using different types) + +import geompy +import smesh +import StdMeshers + +# Make quadrangle face and explode it on edges. +Vertex_1 = geompy.MakeVertex(0, 0, 0) +Vertex_2 = geompy.MakeVertex(40, 0, 0) +Vertex_3 = geompy.MakeVertex(40, 30, 0) +Vertex_4 = geompy.MakeVertex(0, 30, 0) +Quadrangle_Face_1 = geompy.MakeQuad4Vertices(Vertex_1, Vertex_4, Vertex_3, Vertex_2) +[Edge_1,Edge_2,Edge_3,Edge_4] = geompy.SubShapeAllSorted(Quadrangle_Face_1, geompy.ShapeType["EDGE"]) +geompy.addToStudy( Vertex_1, "Vertex_1" ) +geompy.addToStudy( Vertex_2, "Vertex_2" ) +geompy.addToStudy( Vertex_3, "Vertex_3" ) +geompy.addToStudy( Vertex_4, "Vertex_4" ) +geompy.addToStudy( Quadrangle_Face_1, "Quadrangle Face_1" ) +geompy.addToStudyInFather( Quadrangle_Face_1, Edge_2, "Edge_2" ) + +# Set the Geometry for meshing +Mesh_1 = smesh.Mesh(Quadrangle_Face_1) + +# Create Quadrangle parameters and +# define the Type as Quadrangle Preference +Quadrangle_Parameters_1 = smesh.CreateHypothesis('QuadrangleParams') +Quadrangle_Parameters_1.SetQuadType( StdMeshers.QUAD_QUADRANGLE_PREF ) + +# Define other hypotheses and algorithms +Regular_1D = Mesh_1.Segment() +Nb_Segments_1 = Regular_1D.NumberOfSegments(4) +Nb_Segments_1.SetDistrType( 0 ) +status = Mesh_1.AddHypothesis(Quadrangle_Parameters_1) +Quadrangle_2D = Mesh_1.Quadrangle() + +# Define submesh on one edge to provide different number of segments +Regular_1D_1 = Mesh_1.Segment(geom=Edge_2) +Nb_Segments_2 = Regular_1D_1.NumberOfSegments(10) +Nb_Segments_2.SetDistrType( 0 ) +SubMesh_1 = Regular_1D_1.GetSubMesh() + +# Compute mesh (with Quadrangle Preference type) +isDone = Mesh_1.Compute() + +# Change type to Reduced and compute again +Quadrangle_Parameters_1.SetQuadType( StdMeshers.QUAD_REDUCED ) +isDone = Mesh_1.Compute() diff --git a/doc/salome/examples/defining_hypotheses_ex16.py b/doc/salome/examples/defining_hypotheses_ex16.py new file mode 100644 index 000000000..493034020 --- /dev/null +++ b/doc/salome/examples/defining_hypotheses_ex16.py @@ -0,0 +1,43 @@ +# "Use Existing Elements" example + +from smesh import * +SetCurrentStudy(salome.myStudy) + +# Make a patritioned box + +box = geompy.MakeBoxDXDYDZ(100,100,100) + +N = geompy.MakeVectorDXDYDZ( 1,0,0 ) +O = geompy.MakeVertex( 50,0,0 ) +plane = geompy.MakePlane( O, N, 200 ) # plane YOZ + +shape2boxes = geompy.MakeHalfPartition( box, plane ) +boxes = geompy.SubShapeAllSorted(shape2boxes, geompy.ShapeType["SOLID"]) + +geompy.addToStudy( boxes[0], "boxes[0]") +geompy.addToStudy( boxes[1], "boxes[1]") +midFace0 = geompy.SubShapeAllSorted(boxes[0], geompy.ShapeType["FACE"])[5] +geompy.addToStudyInFather( boxes[0], midFace0, "middle Face") +midFace1 = geompy.SubShapeAllSorted(boxes[1], geompy.ShapeType["FACE"])[0] +geompy.addToStudyInFather( boxes[1], midFace1, "middle Face") + +# Mesh one of boxes with quadrangles. It is a source mesh + +srcMesh = Mesh(boxes[0], "source mesh") # box coloser to CS origin +nSeg1 = srcMesh.Segment().NumberOfSegments(4) +srcMesh.Quadrangle() +srcMesh.Compute() +srcFaceGroup = srcMesh.GroupOnGeom( midFace0, "src faces", FACE ) + +# Import faces from midFace0 to the target mesh + +tgtMesh = Mesh(boxes[1], "target mesh") +importAlgo = tgtMesh.UseExisting2DElements(midFace1) +import2hyp = importAlgo.SourceFaces( [srcFaceGroup] ) +tgtMesh.Segment().NumberOfSegments(3) +tgtMesh.Quadrangle() +tgtMesh.Compute() + +# Import the whole source mesh with groups +import2hyp.SetCopySourceMesh(True,True) +tgtMesh.Compute() diff --git a/doc/salome/examples/defining_hypotheses_ex17.py b/doc/salome/examples/defining_hypotheses_ex17.py new file mode 100644 index 000000000..dc3ee9bc8 --- /dev/null +++ b/doc/salome/examples/defining_hypotheses_ex17.py @@ -0,0 +1,40 @@ +# Viscous layers construction + +from smesh import * +SetCurrentStudy(salome.myStudy) + +X = geompy.MakeVectorDXDYDZ( 1,0,0 ) +O = geompy.MakeVertex( 100,50,50 ) +plane = geompy.MakePlane( O, X, 200 ) # plane YZ + +box = geompy.MakeBoxDXDYDZ(200,100,100) + +shape = geompy.MakeHalfPartition( box, plane ) + +faces = geompy.SubShapeAllSorted(shape, geompy.ShapeType["FACE"]) +face1 = faces[1] +ignoreFaces = [ faces[0], faces[-1]] + +geompy.addToStudy( shape, "shape" ) +geompy.addToStudyInFather( shape, face1, "face1") + + +mesh = Mesh(shape, "CFD") + +mesh.Segment().NumberOfSegments( 4 ) + +mesh.Triangle() +mesh.Quadrangle(face1) +mesh.Compute() +algo3D = mesh.Tetrahedron() + +thickness = 20 +numberOfLayers = 10 +stretchFactor = 1.5 +layersHyp = algo3D.ViscousLayers(thickness,numberOfLayers,stretchFactor,ignoreFaces) + +mesh.Compute() + +mesh.MakeGroup("Tetras",VOLUME,FT_ElemGeomType,"=",Geom_TETRA) +mesh.MakeGroup("Pyras",VOLUME,FT_ElemGeomType,"=",Geom_PYRAMID) +mesh.MakeGroup("Prims",VOLUME,FT_ElemGeomType,"=",Geom_PENTA) diff --git a/doc/salome/examples/filters_ex01.py b/doc/salome/examples/filters_ex01.py new file mode 100644 index 000000000..986904774 --- /dev/null +++ b/doc/salome/examples/filters_ex01.py @@ -0,0 +1,8 @@ +# Aspect ratio + +# create mesh +from SMESH_mechanic import * +# get faces with aspect ratio > 6.5 +filter = smesh.GetFilter(smesh.FACE, smesh.FT_AspectRatio, smesh.FT_MoreThan, 6.5) +ids = mesh.GetIdsFromFilter(filter) +print "Number of faces with aspect ratio > 6.5:", len(ids) diff --git a/doc/salome/examples/filters_ex02.py b/doc/salome/examples/filters_ex02.py new file mode 100644 index 000000000..f69217398 --- /dev/null +++ b/doc/salome/examples/filters_ex02.py @@ -0,0 +1,10 @@ +# Aspect ratio 3D + +# create mesh with volumes +from SMESH_mechanic import * +mesh.Tetrahedron() +mesh.Compute() +# get volumes with aspect ratio < 2.0 +filter = smesh.GetFilter(smesh.VOLUME, smesh.FT_AspectRatio3D, smesh.FT_LessThan, 2.0) +ids = mesh.GetIdsFromFilter(filter) +print "Number of volumes with aspect ratio < 2.0:", len(ids) diff --git a/doc/salome/examples/filters_ex03.py b/doc/salome/examples/filters_ex03.py new file mode 100644 index 000000000..5afe3a44e --- /dev/null +++ b/doc/salome/examples/filters_ex03.py @@ -0,0 +1,11 @@ +# Warping angle + +# create mesh +from SMESH_mechanic import * +# get faces with warping angle = 2.0e-13 with tolerance 5.0e-14 +criterion = smesh.GetCriterion(smesh.FACE, smesh.FT_Warping, smesh.FT_EqualTo, 2.0e-13) +criterion.Tolerance = 5.0e-14 +filter = smesh.CreateFilterManager().CreateFilter() +filter.SetCriteria([criterion]) +ids = mesh.GetIdsFromFilter(filter) +print "Number of faces with warping angle = 2.0e-13 (tolerance 5.0e-14):", len(ids) diff --git a/doc/salome/examples/filters_ex04.py b/doc/salome/examples/filters_ex04.py new file mode 100644 index 000000000..d4d31a76c --- /dev/null +++ b/doc/salome/examples/filters_ex04.py @@ -0,0 +1,8 @@ +# Minimum angle + +# create mesh +from SMESH_mechanic import * +# get faces with minimum angle > 75 +filter = smesh.GetFilter(smesh.FACE, smesh.FT_MinimumAngle,">", 75) +ids = mesh.GetIdsFromFilter(filter) +print "Number of faces with minimum angle > 75:", len(ids) diff --git a/doc/salome/examples/filters_ex05.py b/doc/salome/examples/filters_ex05.py new file mode 100644 index 000000000..b15225194 --- /dev/null +++ b/doc/salome/examples/filters_ex05.py @@ -0,0 +1,8 @@ +# Taper + +# create mesh +from SMESH_mechanic import * +# get faces with taper < 1.e-15 +filter = smesh.GetFilter(smesh.FACE, smesh.FT_Taper, smesh.FT_LessThan, 1.e-15) +ids = mesh.GetIdsFromFilter(filter) +print "Number of faces with taper < 1.e-15:", len(ids) diff --git a/doc/salome/examples/filters_ex06.py b/doc/salome/examples/filters_ex06.py new file mode 100644 index 000000000..0f609a569 --- /dev/null +++ b/doc/salome/examples/filters_ex06.py @@ -0,0 +1,8 @@ +# Skew + +# create mesh +from SMESH_mechanic import * +# get faces with skew > 50 +filter = smesh.GetFilter(smesh.FACE, smesh.FT_Skew, smesh.FT_MoreThan, 50) +ids = mesh.GetIdsFromFilter(filter) +print "Number of faces with skew > 50:", len(ids) diff --git a/doc/salome/examples/filters_ex07.py b/doc/salome/examples/filters_ex07.py new file mode 100644 index 000000000..723d8d282 --- /dev/null +++ b/doc/salome/examples/filters_ex07.py @@ -0,0 +1,12 @@ +# Area + +# create mesh +from SMESH_mechanic import * +# get faces with area > 60 and < 90 +criterion1 = smesh.GetCriterion(smesh.FACE, smesh.FT_Area, smesh.FT_MoreThan, 60,\ + smesh.FT_Undefined, smesh.FT_LogicalAND) +criterion2 = smesh.GetCriterion(smesh.FACE, smesh.FT_Area, smesh.FT_LessThan, 90) +filter = smesh.CreateFilterManager().CreateFilter() +filter.SetCriteria([criterion1,criterion2]) +ids = mesh.GetIdsFromFilter(filter) +print "Number of faces with area in range (60,90):", len(ids) diff --git a/doc/salome/examples/filters_ex08.py b/doc/salome/examples/filters_ex08.py new file mode 100644 index 000000000..2bc96b672 --- /dev/null +++ b/doc/salome/examples/filters_ex08.py @@ -0,0 +1,10 @@ +# Volume + +# create mesh with volumes +from SMESH_mechanic import * +mesh.Tetrahedron() +mesh.Compute() +# get volumes faces with volume > 100 +filter = smesh.GetFilter(smesh.VOLUME, smesh.FT_Volume3D, smesh.FT_MoreThan, 100) +ids = mesh.GetIdsFromFilter(filter) +print "Number of volumes with volume > 100:", len(ids) diff --git a/doc/salome/examples/filters_ex09.py b/doc/salome/examples/filters_ex09.py new file mode 100644 index 000000000..0d045b7b7 --- /dev/null +++ b/doc/salome/examples/filters_ex09.py @@ -0,0 +1,14 @@ +# Free borders + +# create mesh +import geompy, smesh, StdMeshers +face = geompy.MakeFaceHW(100, 100, 1) +geompy.addToStudy( face, "quadrangle" ) +mesh = smesh.Mesh(face) +mesh.Segment().NumberOfSegments(10) +mesh.Triangle().MaxElementArea(25) +mesh.Compute() +# get all free borders +filter = smesh.GetFilter(smesh.EDGE, smesh.FT_FreeBorders) +ids = mesh.GetIdsFromFilter(filter) +print "Number of edges on free borders:", len(ids) diff --git a/doc/salome/examples/filters_ex10.py b/doc/salome/examples/filters_ex10.py new file mode 100644 index 000000000..bbbdd9889 --- /dev/null +++ b/doc/salome/examples/filters_ex10.py @@ -0,0 +1,14 @@ +# Free edges + +# create mesh +import geompy, smesh, StdMeshers +face = geompy.MakeFaceHW(100, 100, 1) +geompy.addToStudy( face, "quadrangle" ) +mesh = smesh.Mesh(face) +mesh.Segment().NumberOfSegments(10) +mesh.Triangle().MaxElementArea(25) +mesh.Compute() +# get all faces with free edges +filter = smesh.GetFilter(smesh.FACE, smesh.FT_FreeEdges) +ids = mesh.GetIdsFromFilter(filter) +print "Number of faces with free edges:", len(ids) diff --git a/doc/salome/examples/filters_ex11.py b/doc/salome/examples/filters_ex11.py new file mode 100644 index 000000000..4d754bc00 --- /dev/null +++ b/doc/salome/examples/filters_ex11.py @@ -0,0 +1,10 @@ +# Free nodes + +# create mesh +from SMESH_mechanic import * +# add node +mesh.AddNode(0,0,0) +# get all free nodes +filter = smesh.GetFilter(smesh.NODE, smesh.FT_FreeNodes) +ids = mesh.GetIdsFromFilter(filter) +print "Number of free nodes:", len(ids) diff --git a/doc/salome/examples/filters_ex12.py b/doc/salome/examples/filters_ex12.py new file mode 100644 index 000000000..dfb0f40ba --- /dev/null +++ b/doc/salome/examples/filters_ex12.py @@ -0,0 +1,8 @@ +# Free faces + +# create mesh +from SMESH_mechanic import * +# get all free faces +filter = smesh.GetFilter(smesh.FACE, smesh.FT_FreeFaces) +ids = mesh.GetIdsFromFilter(filter) +print "Number of free faces:", len(ids) diff --git a/doc/salome/examples/filters_ex13.py b/doc/salome/examples/filters_ex13.py new file mode 100644 index 000000000..d5415e20a --- /dev/null +++ b/doc/salome/examples/filters_ex13.py @@ -0,0 +1,10 @@ +# Bare border faces + +# create mesh +from SMESH_mechanic import * +# remove some faces to have faces with bare borders +mesh.RemoveElements( mesh.GetElementsByType(FACE)[0:5] ) +# get all faces bare borders +filter = smesh.GetFilter(smesh.FACE, smesh.FT_BareBorderFace) +ids = mesh.GetIdsFromFilter(filter) +print "Faces with bare borders:", ids diff --git a/doc/salome/examples/filters_ex14.py b/doc/salome/examples/filters_ex14.py new file mode 100644 index 000000000..45c356cdf --- /dev/null +++ b/doc/salome/examples/filters_ex14.py @@ -0,0 +1,9 @@ +# Coplanar faces + +# create mesh +from SMESH_mechanic import * +faceID = mesh.GetElementsByType(FACE)[0] +# get all faces co-planar to the first face with tolerance 5 degrees +filter = smesh.GetFilter(smesh.FACE, smesh.FT_CoplanarFaces,faceID,Tolerance=5.0) +ids = mesh.GetIdsFromFilter(filter) +print "Number of faces coplanar with the first one:", len(ids) diff --git a/doc/salome/examples/filters_ex15.py b/doc/salome/examples/filters_ex15.py new file mode 100644 index 000000000..2044c6048 --- /dev/null +++ b/doc/salome/examples/filters_ex15.py @@ -0,0 +1,7 @@ +# Over-constrained faces +# create mesh +from SMESH_mechanic import * +# get all over-constrained faces +filter = smesh.GetFilter(smesh.FACE, smesh.FT_OverConstrainedFace) +ids = mesh.GetIdsFromFilter(filter) +print "Over-constrained faces:", ids diff --git a/doc/salome/examples/filters_ex16.py b/doc/salome/examples/filters_ex16.py new file mode 100644 index 000000000..3c7159d9f --- /dev/null +++ b/doc/salome/examples/filters_ex16.py @@ -0,0 +1,21 @@ +# Double edges, Double faces, Double volumes + +from smesh import * +# make a mesh on a box +box = geompy.MakeBoxDXDYDZ(100,100,100) +mesh = Mesh( box, "Box" ) +mesh.Segment().NumberOfSegments(10) +mesh.Quadrangle() +mesh.Hexahedron() +mesh.Compute() +# copy all elements with translation and Merge nodes +mesh.TranslateObject( mesh, MakeDirStruct( 10,0,0), Copy=True ) +mesh.MergeNodes( mesh.FindCoincidentNodes(1e-7) ) +# create filters to find equal elements +equalEdgesFilter = GetFilter(SMESH.EDGE, FT_EqualEdges) +equalFacesFilter = GetFilter(SMESH.FACE, FT_EqualFaces) +equalVolumesFilter = GetFilter(SMESH.VOLUME, FT_EqualVolumes) +# get equal elements +print "Number of equal edges:", len( mesh.GetIdsFromFilter( equalEdgesFilter )) +print "Number of equal faces:", len( mesh.GetIdsFromFilter( equalFacesFilter )) +print "Number of equal volumes:", len( mesh.GetIdsFromFilter( equalVolumesFilter )) diff --git a/doc/salome/examples/filters_ex17.py b/doc/salome/examples/filters_ex17.py new file mode 100644 index 000000000..b79f4a74d --- /dev/null +++ b/doc/salome/examples/filters_ex17.py @@ -0,0 +1,16 @@ +# Double nodes + +from smesh import * +# make a mesh on a box +box = geompy.MakeBoxDXDYDZ(100,100,100) +mesh = Mesh( box, "Box" ) +mesh.Segment().NumberOfSegments(10) +mesh.Quadrangle() +mesh.Hexahedron() +mesh.Compute() +# copy all elements with translation +mesh.TranslateObject( mesh, MakeDirStruct( 10,0,0), Copy=True ) +# create filters to find nodes equal within tolerance of 1e-5 +filter = GetFilter(SMESH.NODE, FT_EqualNodes, Tolerance=1e-5) +# get equal nodes +print "Number of equal nodes:", len( mesh.GetIdsFromFilter( filter )) diff --git a/doc/salome/examples/filters_ex18.py b/doc/salome/examples/filters_ex18.py new file mode 100644 index 000000000..30158e28b --- /dev/null +++ b/doc/salome/examples/filters_ex18.py @@ -0,0 +1,8 @@ +# Borders at multi-connection + +# create mesh +from SMESH_mechanic import * +# get border edges with number of connected faces = 5 +filter = smesh.GetFilter(smesh.EDGE, smesh.FT_MultiConnection, 5) +ids = mesh.GetIdsFromFilter(filter) +print "Number of border edges with 5 faces connected:", len(ids) diff --git a/doc/salome/examples/filters_ex19.py b/doc/salome/examples/filters_ex19.py new file mode 100644 index 000000000..41b7cc762 --- /dev/null +++ b/doc/salome/examples/filters_ex19.py @@ -0,0 +1,8 @@ +# Borders at multi-connection 2D + +# create mesh +from SMESH_mechanic import * +# get faces which consist of edges belonging to 2 mesh elements +filter = smesh.GetFilter(smesh.FACE, smesh.FT_MultiConnection2D, 2) +ids = mesh.GetIdsFromFilter(filter) +print "Number of faces consisting of edges belonging to 2 faces:", len(ids) diff --git a/doc/salome/examples/filters_ex20.py b/doc/salome/examples/filters_ex20.py new file mode 100644 index 000000000..37227c49d --- /dev/null +++ b/doc/salome/examples/filters_ex20.py @@ -0,0 +1,8 @@ +# Length + +# create mesh +from SMESH_mechanic import * +# get edges with length > 14 +filter = smesh.GetFilter(smesh.EDGE, smesh.FT_Length, smesh.FT_MoreThan, 14) +ids = mesh.GetIdsFromFilter(filter) +print "Number of edges with length > 14:", len(ids) diff --git a/doc/salome/examples/filters_ex21.py b/doc/salome/examples/filters_ex21.py new file mode 100644 index 000000000..0882fe294 --- /dev/null +++ b/doc/salome/examples/filters_ex21.py @@ -0,0 +1,8 @@ +# Length 2D + +# create mesh +from SMESH_mechanic import * +# get all faces that have edges with length > 14 +filter = smesh.GetFilter(smesh.FACE, smesh.FT_Length2D, smesh.FT_MoreThan, 14) +ids = mesh.GetIdsFromFilter(filter) +print "Number of faces with maximum edge length > 14:", len(ids) diff --git a/doc/salome/examples/filters_ex22.py b/doc/salome/examples/filters_ex22.py new file mode 100644 index 000000000..f65421786 --- /dev/null +++ b/doc/salome/examples/filters_ex22.py @@ -0,0 +1,8 @@ +# Element Diameter 2D + +# create mesh +from SMESH_mechanic import * +# get all faces that have elements with length > 10 +filter = smesh.GetFilter(smesh.FACE, smesh.FT_MaxElementLength2D, smesh.FT_MoreThan, 10) +ids = mesh.GetIdsFromFilter(filter) +print "Number of faces with maximum element length > 10:", len(ids) diff --git a/doc/salome/examples/filters_ex23.py b/doc/salome/examples/filters_ex23.py new file mode 100644 index 000000000..848f8d92c --- /dev/null +++ b/doc/salome/examples/filters_ex23.py @@ -0,0 +1,10 @@ +# Element Diameter 3D + +# create mesh with volumes +from SMESH_mechanic import * +mesh.Tetrahedron() +mesh.Compute() +# get all volumes that have elements with length > 10 +filter = smesh.GetFilter(smesh.VOLUME, smesh.FT_MaxElementLength3D, smesh.FT_MoreThan, 10) +ids = mesh.GetIdsFromFilter(filter) +print "Number of volumes with maximum element length > 10:", len(ids) diff --git a/doc/salome/examples/filters_ex24.py b/doc/salome/examples/filters_ex24.py new file mode 100644 index 000000000..036ba037e --- /dev/null +++ b/doc/salome/examples/filters_ex24.py @@ -0,0 +1,12 @@ +# Bare border volumes + +# create mesh +from SMESH_mechanic import * +mesh.Tetrahedron() +mesh.Compute() +# remove some volumes to have volumes with bare borders +mesh.RemoveElements( mesh.GetElementsByType(VOLUME)[0:5] ) +# get all volumes with bare borders +filter = smesh.GetFilter(smesh.VOLUME, smesh.FT_BareBorderVolume) +ids = mesh.GetIdsFromFilter(filter) +print "Volumes with bare borders:", ids diff --git a/doc/salome/examples/filters_ex25.py b/doc/salome/examples/filters_ex25.py new file mode 100644 index 000000000..7e4489848 --- /dev/null +++ b/doc/salome/examples/filters_ex25.py @@ -0,0 +1,10 @@ +# Over-constrained volumes + +# create mesh +from SMESH_mechanic import * +mesh.Tetrahedron() +mesh.Compute() +# get all over-constrained volumes +filter = smesh.GetFilter(smesh.VOLUME, smesh.FT_OverConstrainedVolume) +ids = mesh.GetIdsFromFilter(filter) +print "Over-constrained volumes:", ids diff --git a/doc/salome/examples/filters_ex26.py b/doc/salome/examples/filters_ex26.py new file mode 100644 index 000000000..3c5ce2965 --- /dev/null +++ b/doc/salome/examples/filters_ex26.py @@ -0,0 +1,8 @@ +# Belong to Geom + +# create mesh +from SMESH_mechanic import * +# get all faces which nodes lie on the face sub_face3 +filter = smesh.GetFilter(smesh.FACE, smesh.FT_BelongToGeom, sub_face3) +ids = mesh.GetIdsFromFilter(filter) +print "Number of faces which nodes lie on sub_face3:", len(ids) diff --git a/doc/salome/examples/filters_ex27.py b/doc/salome/examples/filters_ex27.py new file mode 100644 index 000000000..10067ea07 --- /dev/null +++ b/doc/salome/examples/filters_ex27.py @@ -0,0 +1,8 @@ +# Lying on Geom + +# create mesh +from SMESH_mechanic import * +# get all faces at least one node of each lies on the face sub_face3 +filter = smesh.GetFilter(smesh.FACE, smesh.FT_LyingOnGeom, sub_face3) +ids = mesh.GetIdsFromFilter(filter) +print "Number of faces at least one node of each lies on sub_face3:", len(ids) diff --git a/doc/salome/examples/filters_ex28.py b/doc/salome/examples/filters_ex28.py new file mode 100644 index 000000000..032b966a5 --- /dev/null +++ b/doc/salome/examples/filters_ex28.py @@ -0,0 +1,12 @@ +# Belong to Plane + +# create mesh +from SMESH_mechanic import * +# create plane +import geompy +plane_1 = geompy.MakePlane(p3,seg1,2000) +geompy.addToStudy(plane_1, "plane_1") +# get all nodes which lie on the plane \a plane_1 +filter = smesh.GetFilter(smesh.NODE, smesh.FT_BelongToPlane, plane_1) +ids = mesh.GetIdsFromFilter(filter) +print "Number of nodes which lie on the plane plane_1:", len(ids) diff --git a/doc/salome/examples/filters_ex29.py b/doc/salome/examples/filters_ex29.py new file mode 100644 index 000000000..c256724b3 --- /dev/null +++ b/doc/salome/examples/filters_ex29.py @@ -0,0 +1,8 @@ +# Belong to Cylinder + +# create mesh +from SMESH_mechanic import * +# get all faces which lie on the cylindrical face \a sub_face1 +filter = smesh.GetFilter(smesh.FACE, smesh.FT_BelongToCylinder, sub_face1) +ids = mesh.GetIdsFromFilter(filter) +print "Number of faces which lie on the cylindrical surface sub_face1:", len(ids) diff --git a/doc/salome/examples/filters_ex30.py b/doc/salome/examples/filters_ex30.py new file mode 100644 index 000000000..19c213810 --- /dev/null +++ b/doc/salome/examples/filters_ex30.py @@ -0,0 +1,12 @@ +# Belong to Surface + +# create mesh +from SMESH_mechanic import * +# create b-spline +spline_1 = geompy.MakeInterpol([p4,p6,p3,p1]) +surface_1 = geompy.MakePrismVecH( spline_1, vz, 70.0 ) +geompy.addToStudy(surface_1, "surface_1") +# get all nodes which lie on the surface \a surface_1 +filter = smesh.GetFilter(smesh.NODE, smesh.FT_BelongToGenSurface, surface_1) +ids = mesh.GetIdsFromFilter(filter) +print "Number of nodes which lie on the surface surface_1:", len(ids) diff --git a/doc/salome/examples/filters_ex31.py b/doc/salome/examples/filters_ex31.py new file mode 100644 index 000000000..a20f7d708 --- /dev/null +++ b/doc/salome/examples/filters_ex31.py @@ -0,0 +1,12 @@ +# Range of IDs + +# create mesh +from SMESH_mechanic import * +# get nodes with identifiers [5-10] and [15-30] +criterion1 = smesh.GetCriterion(smesh.NODE, smesh.FT_RangeOfIds, Treshold="5-10",\ + BinaryOp=smesh.FT_LogicalOR) +criterion2 = smesh.GetCriterion(smesh.NODE, smesh.FT_RangeOfIds, Treshold="15-30") +filter = smesh.CreateFilterManager().CreateFilter() +filter.SetCriteria([criterion1,criterion2]) +ids = mesh.GetIdsFromFilter(filter) +print "Number of nodes in ranges [5-10] and [15-30]:", len(ids) diff --git a/doc/salome/examples/filters_ex32.py b/doc/salome/examples/filters_ex32.py new file mode 100644 index 000000000..726ca153f --- /dev/null +++ b/doc/salome/examples/filters_ex32.py @@ -0,0 +1,10 @@ +# Badly oriented volume + +# create mesh with volumes +from SMESH_mechanic import * +mesh.Tetrahedron() +mesh.Compute() +# get all badly oriented volumes +filter = smesh.GetFilter(smesh.VOLUME, smesh.FT_BadOrientedVolume) +ids = mesh.GetIdsFromFilter(filter) +print "Number of badly oriented volumes:", len(ids) diff --git a/doc/salome/examples/filters_ex33.py b/doc/salome/examples/filters_ex33.py new file mode 100644 index 000000000..2fbaab03e --- /dev/null +++ b/doc/salome/examples/filters_ex33.py @@ -0,0 +1,17 @@ +# Linear / quadratic + +# create mesh +from SMESH_mechanic import * +# get number of linear and quadratic edges +filter_linear = smesh.GetFilter(smesh.EDGE, smesh.FT_LinearOrQuadratic) +filter_quadratic = smesh.GetFilter(smesh.EDGE, smesh.FT_LinearOrQuadratic, smesh.FT_LogicalNOT) +ids_linear = mesh.GetIdsFromFilter(filter_linear) +ids_quadratic = mesh.GetIdsFromFilter(filter_quadratic) +print "Number of linear edges:", len(ids_linear), "; number of quadratic edges:", len(ids_quadratic) +# convert mesh to quadratic +print "Convert to quadratic..." +mesh.ConvertToQuadratic(True) +# get number of linear and quadratic edges +ids_linear = mesh.GetIdsFromFilter(filter_linear) +ids_quadratic = mesh.GetIdsFromFilter(filter_quadratic) +print "Number of linear edges:", len(ids_linear), "; number of quadratic edges:", len(ids_quadratic) diff --git a/doc/salome/examples/filters_ex34.py b/doc/salome/examples/filters_ex34.py new file mode 100644 index 000000000..8e63056b4 --- /dev/null +++ b/doc/salome/examples/filters_ex34.py @@ -0,0 +1,14 @@ +# Group color + +# create mesh +from SMESH_mechanic import * +# create group of edges +all_edges = mesh.GetElementsByType(smesh.EDGE) +grp = mesh.MakeGroupByIds("edges group", smesh.EDGE, all_edges[:len(all_edges)/4]) +import SALOMEDS +c = SALOMEDS.Color(0.1, 0.5, 1.0) +grp.SetColor(c) +# get number of the edges not belonging to the group with the given color +filter = smesh.GetFilter(smesh.EDGE, smesh.FT_GroupColor, c, smesh.FT_LogicalNOT) +ids = mesh.GetIdsFromFilter(filter) +print "Number of edges not beloging to the group with color (0.1, 0.5, 1.0):", len(ids) diff --git a/doc/salome/examples/filters_ex35.py b/doc/salome/examples/filters_ex35.py new file mode 100644 index 000000000..369d7323a --- /dev/null +++ b/doc/salome/examples/filters_ex35.py @@ -0,0 +1,19 @@ +# Geometry type + +# create mesh with volumes +from SMESH_mechanic import * +mesh.Tetrahedron() +mesh.Compute() +# get all triangles, quadrangles, tetrahedrons, pyramids +filter_tri = smesh.GetFilter(smesh.FACE, smesh.FT_ElemGeomType, smesh.Geom_TRIANGLE) +filter_qua = smesh.GetFilter(smesh.FACE, smesh.FT_ElemGeomType, smesh.Geom_QUADRANGLE) +filter_tet = smesh.GetFilter(smesh.VOLUME, smesh.FT_ElemGeomType, smesh.Geom_TETRA) +filter_pyr = smesh.GetFilter(smesh.VOLUME, smesh.FT_ElemGeomType, smesh.Geom_PYRAMID) +ids_tri = mesh.GetIdsFromFilter(filter_tri) +ids_qua = mesh.GetIdsFromFilter(filter_qua) +ids_tet = mesh.GetIdsFromFilter(filter_tet) +ids_pyr = mesh.GetIdsFromFilter(filter_pyr) +print "Number of triangles:", len(ids_tri) +print "Number of quadrangles:", len(ids_qua) +print "Number of tetrahedrons:", len(ids_tet) +print "Number of pyramids:", len(ids_pyr) diff --git a/doc/salome/examples/filters_ex36.py b/doc/salome/examples/filters_ex36.py new file mode 100644 index 000000000..7675bc9f6 --- /dev/null +++ b/doc/salome/examples/filters_ex36.py @@ -0,0 +1,13 @@ +# Combine filters with Criterion structures using of "criteria". + +# create mesh +from SMESH_mechanic import * +# get all the quadrangle faces ... +criterion1 = smesh.GetCriterion(smesh.FACE, smesh.FT_ElemGeomType, smesh.Geom_QUADRANGLE, smesh.FT_LogicalAND) +# ... AND do NOT get those from sub_face3 +criterion2 = smesh.GetCriterion(smesh.FACE, smesh.FT_BelongToGeom, sub_face3, smesh.FT_LogicalNOT) +filter = smesh.CreateFilterManager().CreateFilter() +filter.SetCriteria([criterion1,criterion2]) +ids = mesh.GetIdsFromFilter(filter) + +myGroup = mesh.MakeGroupByIds("Quads_on_cylindrical_faces",smesh.FACE,ids) diff --git a/doc/salome/examples/generate_flat_elements.py b/doc/salome/examples/generate_flat_elements.py new file mode 100644 index 000000000..a23c200a4 --- /dev/null +++ b/doc/salome/examples/generate_flat_elements.py @@ -0,0 +1,57 @@ +# Double nodes on groups boundaries + +# This example represents an iron cable (a thin cylinder) in a concrete bloc (a big cylinder). +# The big cylinder is defined by two geometric volumes. + +import geompy +import smesh +import SMESH + +# geometry + +O = geompy.MakeVertex(0, 0, 0) +OX = geompy.MakeVectorDXDYDZ(1, 0, 0) +OY = geompy.MakeVectorDXDYDZ(0, 1, 0) +OZ = geompy.MakeVectorDXDYDZ(0, 0, 1) +Vertex_1 = geompy.MakeVertex(50, 0, 0) +Cylinder_1 = geompy.MakeCylinder(O, OX, 10, 500) +Cylinder_2 = geompy.MakeCylinder(Vertex_1, OX, 100, 400) +Vertex_2 = geompy.MakeVertex(-200, -200, -200) +Vertex_3 = geompy.MakeVertex(250, 200, 200) +Box_1 = geompy.MakeBoxTwoPnt(Vertex_2, Vertex_3) +Fuse_1 = geompy.MakeFuse(Cylinder_1, Cylinder_2) +Partition_1 = geompy.MakePartition([Fuse_1], [Cylinder_1, Box_1], [], [], geompy.ShapeType["SOLID"], 0, [], 0) +[Solid_1,Solid_2] = geompy.GetShapesOnShape(Cylinder_1, Partition_1, geompy.ShapeType["SOLID"], geompy.GEOM.ST_IN) +[Solid_3,Solid_4] = geompy.GetShapesOnShape(Cylinder_2, Partition_1, geompy.ShapeType["SOLID"], geompy.GEOM.ST_IN) +Vertex_4 = geompy.MakeVertex(450, 0, 0) +Vertex_5 = geompy.MakeVertex(500, 0, 0) +Vertex_6 = geompy.MakeVertex(550, 0, 0) +vec1 = geompy.MakeVector(Vertex_4, Vertex_5) +vec2 = geompy.MakeVector(Vertex_5, Vertex_6) +[Face_1] = geompy.GetShapesOnPlane(Partition_1, geompy.ShapeType["FACE"], vec1, geompy.GEOM.ST_ON) +[Face_2] = geompy.GetShapesOnPlane(Partition_1, geompy.ShapeType["FACE"], vec2, geompy.GEOM.ST_ON) + +# meshing (we have linear tetrahedrons here, but other elements are OK) + +Mesh_1 = smesh.Mesh(Partition_1) +Regular_1D = Mesh_1.Segment() +Nb_Segments_1 = Regular_1D.NumberOfSegments(15) +MEFISTO_2D = Mesh_1.Triangle(algo=smesh.MEFISTO) +Length_From_Edges_2D = MEFISTO_2D.LengthFromEdges() +ALGO3D = Mesh_1.Tetrahedron() +isDone = Mesh_1.Compute() + +# relevant groups of volumes and faces + +Solid_1_1 = Mesh_1.GroupOnGeom(Solid_1,'Solid_1',SMESH.VOLUME) +Solid_2_1 = Mesh_1.GroupOnGeom(Solid_2,'Solid_2',SMESH.VOLUME) +Solid_3_1 = Mesh_1.GroupOnGeom(Solid_3,'Solid_3',SMESH.VOLUME) +Solid_4_1 = Mesh_1.GroupOnGeom(Solid_4,'Solid_4',SMESH.VOLUME) +Face_1_1 = Mesh_1.GroupOnGeom(Face_1,'Face_1',SMESH.FACE) +Face_2_1 = Mesh_1.GroupOnGeom(Face_2,'Face_2',SMESH.FACE) + +# Building of flat elements + +Mesh_1.DoubleNodesOnGroupBoundaries([Solid_1_1, Solid_2_1, Solid_3_1, Solid_4_1], 1) + +Mesh_1.CreateFlatElementsOnFacesGroups([Face_1_1, Face_2_1]) diff --git a/doc/salome/examples/grouping_elements_ex01.py b/doc/salome/examples/grouping_elements_ex01.py new file mode 100644 index 000000000..d0971d621 --- /dev/null +++ b/doc/salome/examples/grouping_elements_ex01.py @@ -0,0 +1,21 @@ +# Create a Standalone Group + +import SMESH_mechanic + +smesh = SMESH_mechanic.smesh +mesh = SMESH_mechanic.mesh +salome = SMESH_mechanic.salome + +# Get ids of all faces with area > 100 +aFilter = smesh.GetFilter(smesh.FACE, smesh.FT_Area, smesh.FT_MoreThan, 100.) + +anIds = mesh.GetIdsFromFilter(aFilter) + +# create a group consisting of faces with area > 100 +aGroup1 = mesh.MakeGroupByIds("Area > 100", smesh.FACE, anIds) + +# create a group that contains all nodes from the mesh +aGroup2 = mesh.CreateEmptyGroup(smesh.NODE, "all nodes") +aGroup2.AddFrom(mesh.mesh) + +salome.sg.updateObjBrowser(1) diff --git a/doc/salome/examples/grouping_elements_ex02.py b/doc/salome/examples/grouping_elements_ex02.py new file mode 100644 index 000000000..228248d7f --- /dev/null +++ b/doc/salome/examples/grouping_elements_ex02.py @@ -0,0 +1,39 @@ +# Create a Group on Geometry + +import salome +import geompy +import smesh + +# create a box +box = geompy.MakeBox(0., 0., 0., 100., 100., 100.) +geompy.addToStudy(box, "box") + +# add the first face of the box to the study +subShapeList = geompy.SubShapeAll(box, geompy.ShapeType["FACE"]) +face = subShapeList[0] +geompy.addToStudyInFather(box, face, "face 1") + +# create group of edges on the face +aGeomGroupE = geompy.CreateGroup(face, geompy.ShapeType["EDGE"]) +geompy.AddObject(aGeomGroupE, 3) +geompy.AddObject(aGeomGroupE, 6) +geompy.AddObject(aGeomGroupE, 8) +geompy.AddObject(aGeomGroupE, 10) +geompy.addToStudyInFather(face, aGeomGroupE, "Group of Edges") + +# create quadrangle 2D mesh on the box +quadra = smesh.Mesh(box, "Box : quadrangle 2D mesh") +algo1D = quadra.Segment() +quadra.Quadrangle() +algo1D.NumberOfSegments(7) + +# compute the mesh +quadra.Compute() + +# create SMESH group on the face with name "SMESHGroup1" +aSmeshGroup1 = quadra.GroupOnGeom(face, "SMESHGroup1") + +# create SMESH group on with default name +aSmeshGroup2 = quadra.GroupOnGeom(aGeomGroupE) + +salome.sg.updateObjBrowser(1) diff --git a/doc/salome/examples/grouping_elements_ex03.py b/doc/salome/examples/grouping_elements_ex03.py new file mode 100644 index 000000000..05fb69d57 --- /dev/null +++ b/doc/salome/examples/grouping_elements_ex03.py @@ -0,0 +1,39 @@ +# Create a Group on Filter + +from smesh import * +SetCurrentStudy(salome.myStudy) + +box = geompy.MakeBoxDXDYDZ(10,10,10) + +# make a mesh with quadrangles of different area in range [1,16] +mesh = Mesh(box,"Quad mesh") +hyp1D = mesh.Segment().StartEndLength( 1, 4 ) +mesh.Quadrangle() +mesh.Compute() + +# create a group on filter selecting faces of medium size +critaria = [ \ + GetCriterion(FACE, FT_Area, ">", 1.1, BinaryOp=FT_LogicalAND ), + GetCriterion(FACE, FT_Area, "<", 15.0 ) + ] +filt = GetFilterFromCriteria( critaria ) +filtGroup = mesh.GroupOnFilter( FACE, "group on filter", filt ) +print "Group on filter contains %s elemens" % filtGroup.Size() + +# group on filter is updated if the mesh is modified +hyp1D.SetStartLength( 2.5 ) +hyp1D.SetEndLength( 2.5 ) +mesh.Compute() +print "After mesh change, group on filter contains %s elemens" % filtGroup.Size() + +# set a new filter defining the group +filt2 = GetFilter( FACE, FT_RangeOfIds, "1-50" ) +filtGroup.SetFilter( filt2 ) +print "With a new filter, group on filter contains %s elemens" % filtGroup.Size() + +# group is updated at modification of the filter +filt2.SetCriteria( [ GetCriterion( FACE, FT_RangeOfIds, "1-70" )]) +filtIDs3 = filtGroup.GetIDs() +print "After filter modification, group on filter contains %s elemens" % filtGroup.Size() + +salome.sg.updateObjBrowser(1) diff --git a/doc/salome/examples/grouping_elements_ex04.py b/doc/salome/examples/grouping_elements_ex04.py new file mode 100644 index 000000000..730a2ca6b --- /dev/null +++ b/doc/salome/examples/grouping_elements_ex04.py @@ -0,0 +1,43 @@ +# Edit a Group + +import SMESH_mechanic + +smesh = SMESH_mechanic.smesh +mesh = SMESH_mechanic.mesh +salome = SMESH_mechanic.salome + +# Get ids of all faces with area > 35 +aFilter = smesh.GetFilter(smesh.FACE, smesh.FT_Area, smesh.FT_MoreThan, 35.) + +anIds = mesh.GetIdsFromFilter(aFilter) + +print "Criterion: Area > 35, Nb = ", len(anIds) + +# create a group by adding elements with area > 35 +aGroup = mesh.CreateEmptyGroup(smesh.FACE, "Area > 35") +aGroup.Add(anIds) + +# Get ids of all faces with area > 40 +aFilter = smesh.GetFilter(smesh.FACE, smesh.FT_Area, smesh.FT_MoreThan, 40.) + +anIds = mesh.GetIdsFromFilter(aFilter) + +print "Criterion: Area > 40, Nb = ", len(anIds) + +# create a group of elements with area [35; 40] by removing elements with area > 40 from group aGroup +aGroup.Remove(anIds) + +# print the result +aGroupElemIDs = aGroup.GetListOfID() + +print "Criterion: 35 < Area < 40, Nb = ", len(aGroupElemIDs) + +j = 1 +for i in range(len(aGroupElemIDs)): + if j > 20: j = 1; print "" + print aGroupElemIDs[i], + j = j + 1 + pass +print "" + +salome.sg.updateObjBrowser(1) diff --git a/doc/salome/examples/grouping_elements_ex05.py b/doc/salome/examples/grouping_elements_ex05.py new file mode 100644 index 000000000..90453fed1 --- /dev/null +++ b/doc/salome/examples/grouping_elements_ex05.py @@ -0,0 +1,52 @@ +# Union of groups + +import SMESH_mechanic + +smesh = SMESH_mechanic.smesh +mesh = SMESH_mechanic.mesh +salome = SMESH_mechanic.salome + +# Criterion : AREA > 20 +aFilter = smesh.GetFilter(smesh.FACE, smesh.FT_Area, smesh.FT_MoreThan, 20.) + +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.Add(anIds) + +# Criterion : AREA = 20 +aFilter = smesh.GetFilter(smesh.FACE, smesh.FT_Area, smesh.FT_EqualTo, 20.) + +anIds = mesh.GetIdsFromFilter(aFilter) + +print "Criterion: Area = 20, Nb = ", len( anIds ) + +# create a group by adding elements with area = 20 +aGroup2 = mesh.CreateEmptyGroup( smesh.FACE, "Area = 20" ) + +aGroup2.Add(anIds) + +# create union group : 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.) + +anIds = mesh.GetIdsFromFilter(aFilter) + +print "Criterion: Area < 20, Nb = ", len(anIds) + +# create a group by adding elements with area < 20 +aGroup4 = mesh.CreateEmptyGroup(smesh.FACE, "Area < 20") +aGroup4.Add(anIds) + +# create union group : area >= 20 and area < 20 +aGroup5 = mesh.UnionListOfGroups([aGroup3, aGroup4], "Any Area") +print "Criterion: Any Area, Nb = ", len(aGroup5.GetListOfID()) + +salome.sg.updateObjBrowser(1) diff --git a/doc/salome/examples/grouping_elements_ex06.py b/doc/salome/examples/grouping_elements_ex06.py new file mode 100644 index 000000000..cc8146fb9 --- /dev/null +++ b/doc/salome/examples/grouping_elements_ex06.py @@ -0,0 +1,36 @@ +# Intersection of groups + +import SMESH_mechanic + +smesh = SMESH_mechanic.smesh +mesh = SMESH_mechanic.mesh +salome = SMESH_mechanic.salome + +# Criterion : AREA > 20 +aFilter = smesh.GetFilter(smesh.FACE, smesh.FT_Area, smesh.FT_MoreThan, 20.) + +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.Add(anIds) + +# Criterion : AREA < 60 +aFilter = smesh.GetFilter(smesh.FACE, smesh.FT_Area, smesh.FT_LessThan, 60.) + +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.Add(anIds) + +# create an intersection of groups : 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) diff --git a/doc/salome/examples/grouping_elements_ex07.py b/doc/salome/examples/grouping_elements_ex07.py new file mode 100644 index 000000000..5bcccd0c7 --- /dev/null +++ b/doc/salome/examples/grouping_elements_ex07.py @@ -0,0 +1,34 @@ +# Cut of groups + +import SMESH_mechanic + +smesh = SMESH_mechanic.smesh +mesh = SMESH_mechanic.mesh +salome = SMESH_mechanic.salome + +# Criterion : AREA > 20 +aFilter = smesh.GetFilter(smesh.FACE, smesh.FT_Area, smesh.FT_MoreThan, 20.) + +anIds = mesh.GetIdsFromFilter(aFilter) + +print "Criterion: Area > 20, Nb = ", len(anIds) + +# create a group by adding elements with area > 20 +aGroupMain = mesh.MakeGroupByIds("Area > 20", smesh.FACE, anIds) + +# Criterion : AREA < 60 +aFilter = smesh.GetFilter(smesh.FACE, smesh.FT_Area, smesh.FT_LessThan, 60.) + +anIds = mesh.GetIdsFromFilter(aFilter) + +print "Criterion: Area < 60, Nb = ", len(anIds) + +# create a group by adding elements with area < 60 +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) diff --git a/doc/salome/examples/grouping_elements_ex08.py b/doc/salome/examples/grouping_elements_ex08.py new file mode 100644 index 000000000..a86ec6317 --- /dev/null +++ b/doc/salome/examples/grouping_elements_ex08.py @@ -0,0 +1,35 @@ +# Creating groups of entities from existing groups of superior dimensions + +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) diff --git a/doc/salome/examples/measurements_ex01.py b/doc/salome/examples/measurements_ex01.py new file mode 100644 index 000000000..967754709 --- /dev/null +++ b/doc/salome/examples/measurements_ex01.py @@ -0,0 +1,48 @@ +# Minimum Distance + +import smesh +from SMESH_mechanic import mesh as mesh1 +from SMESH_test1 import mesh as mesh2 + +mesh1.Compute() +mesh2.Compute() + +# compute min distance from mesh1 to the origin (not available yet) +smesh.MinDistance(mesh1) + +# compute min distance from node 10 of mesh1 to the origin +smesh.MinDistance(mesh1, id1=10) +# ... or +mesh1.MinDistance(10) + +# compute min distance between nodes 10 and 20 of mesh1 +smesh.MinDistance(mesh1, id1=10, id2=20) +# ... or +mesh1.MinDistance(10, 20) + +# compute min distance from element 100 of mesh1 to the origin (not available yet) +smesh.MinDistance(mesh1, id1=100, isElem1=True) +# ... or +mesh1.MinDistance(100, isElem1=True) + +# compute min distance between elements 100 and 200 of mesh1 (not available yet) +smesh.MinDistance(mesh1, id1=100, id2=200, isElem1=True, isElem2=True) +# ... or +mesh1.MinDistance(100, 200, True, True) + +# compute min distance from element 100 to node 20 of mesh1 (not available yet) +smesh.MinDistance(mesh1, id1=100, id2=20, isElem1=True) +# ... or +mesh1.MinDistance(100, 20, True) + +# compute min distance from mesh1 to mesh2 (not available yet) +smesh.MinDistance(mesh1, mesh2) + +# compute min distance from node 10 of mesh1 to node 20 of mesh2 +smesh.MinDistance(mesh1, mesh2, 10, 20) + +# compute min distance from node 10 of mesh1 to element 200 of mesh2 (not available yet) +smesh.MinDistance(mesh1, mesh2, 10, 200, isElem2=True) + +# etc... + diff --git a/doc/salome/examples/measurements_ex02.py b/doc/salome/examples/measurements_ex02.py new file mode 100644 index 000000000..3333bc0e5 --- /dev/null +++ b/doc/salome/examples/measurements_ex02.py @@ -0,0 +1,22 @@ +# Bounding Box + +import smesh +from SMESH_mechanic import mesh as mesh1 +from SMESH_test1 import mesh as mesh2 + +mesh1.Compute() +mesh2.Compute() + +# compute bounding box for mesh1 +mesh1.BoundingBox() + +# compute bounding box for list of nodes of mesh1 +mesh1.BoundingBox([363, 364, 370, 371, 372, 373, 379, 380, 381]) + +# compute bounding box for list of elements of mesh1 +mesh1.BoundingBox([363, 364, 370, 371, 372, 373, 379, 380, 381], isElem=True) + +# compute common bounding box of mesh1 and mesh2 +smesh.BoundingBox([mesh1, mesh2]) + +# etc... diff --git a/doc/salome/examples/modifying_meshes_ex01.py b/doc/salome/examples/modifying_meshes_ex01.py new file mode 100644 index 000000000..ee183d708 --- /dev/null +++ b/doc/salome/examples/modifying_meshes_ex01.py @@ -0,0 +1,11 @@ +# Add Node + +import smesh + +mesh = smesh.Mesh() + +# add node +new_id = mesh.AddNode(50, 10, 0) +print "" +if new_id == 0: print "KO node addition." +else: print "New Node has been added with ID ", new_id diff --git a/doc/salome/examples/modifying_meshes_ex02.py b/doc/salome/examples/modifying_meshes_ex02.py new file mode 100644 index 000000000..c99bf2aff --- /dev/null +++ b/doc/salome/examples/modifying_meshes_ex02.py @@ -0,0 +1,15 @@ +# Add 0D Element + +import smesh + +mesh = smesh.Mesh() + +# add node +node_id = mesh.AddNode(50, 10, 0) + +# add 0D Element +new_id = mesh.Add0DElement(node_id) + +print "" +if new_id == 0: print "KO node addition." +else: print "New 0D Element has been added with ID ", new_id diff --git a/doc/salome/examples/modifying_meshes_ex03.py b/doc/salome/examples/modifying_meshes_ex03.py new file mode 100644 index 000000000..19b423e03 --- /dev/null +++ b/doc/salome/examples/modifying_meshes_ex03.py @@ -0,0 +1,42 @@ +# Add 0D Element on Element Nodes + +import smesh, SMESH, geompy + +# create a geometry +box = geompy.MakeBoxDXDYDZ( 10, 10, 10 ) +face = geompy.SubShapeAll( box, geompy.ShapeType["FACE"])[0] + +# make 3D mesh +mesh = smesh.Mesh( box ) +mesh.AutomaticHexahedralization(0) + +# create 0D elements on all nodes of the mesh +res = mesh.Add0DElementsToAllNodes( mesh ) + +# find 0D elements on all nodes of the mesh, all found nodes are added to a new group +groupName = "0Dmesh" +res = mesh.Add0DElementsToAllNodes( mesh, groupName ) +mesh.RemoveGroupWithContents( res ) # remove all found 0D elements + +# create 0D elements on all nodes of a sub-mesh, with group creation +groupName = "0Dsubmesh" +submesh = mesh.GetSubMesh( face, "faceSM") +res = mesh.Add0DElementsToAllNodes( submesh, groupName ) + +# create 0D elements on all nodes of a group +group = mesh.Group( face, "faceGroup" ) +res = mesh.Add0DElementsToAllNodes( group ) + +# remove all 0D elements +mesh.RemoveElements( mesh.GetIdsFromFilter( smesh.GetFilter( SMESH.ELEM0D, + SMESH.FT_ElemGeomType, + "=",SMESH.Geom_POINT ))) + +# create 0D elements on all nodes of some elements +res = mesh.Add0DElementsToAllNodes( mesh.GetElementsId() ) + +mesh.RemoveElements( mesh.GetElementsByType( SMESH.ELEM0D )) + +# create 0D elements on some nodes +nodes = range(1,10) +res = mesh.Add0DElementsToAllNodes( mesh.GetIDSource( nodes, SMESH.NODE )) diff --git a/doc/salome/examples/modifying_meshes_ex04.py b/doc/salome/examples/modifying_meshes_ex04.py new file mode 100644 index 000000000..5aad0f551 --- /dev/null +++ b/doc/salome/examples/modifying_meshes_ex04.py @@ -0,0 +1,15 @@ +# Add Edge + +import SMESH_mechanic + +mesh = SMESH_mechanic.mesh +print "" + +# add node +n1 = mesh.AddNode(50, 10, 0) +if n1 == 0: print "KO node addition." + +# add edge +e1 = mesh.AddEdge([n1, 38]) +if e1 == 0: print "KO edge addition." +else: print "New Edge has been added with ID ", e1 diff --git a/doc/salome/examples/modifying_meshes_ex05.py b/doc/salome/examples/modifying_meshes_ex05.py new file mode 100644 index 000000000..bd1e1438b --- /dev/null +++ b/doc/salome/examples/modifying_meshes_ex05.py @@ -0,0 +1,15 @@ +# Add Triangle + +import SMESH_mechanic + +mesh = SMESH_mechanic.mesh +print "" + +# add node +n1 = mesh.AddNode(50, 10, 0) +if n1 == 0: print "KO node addition." + +# add triangle +t1 = mesh.AddFace([n1, 38, 39]) +if t1 == 0: print "KO triangle addition." +else: print "New Triangle has been added with ID ", t1 diff --git a/doc/salome/examples/modifying_meshes_ex06.py b/doc/salome/examples/modifying_meshes_ex06.py new file mode 100644 index 000000000..b05c88089 --- /dev/null +++ b/doc/salome/examples/modifying_meshes_ex06.py @@ -0,0 +1,18 @@ +# Add Quadrangle + +import SMESH_mechanic + +mesh = SMESH_mechanic.mesh +print "" + +# add node +n1 = mesh.AddNode(50, 10, 0) +if n1 == 0: print "KO node addition." + +n2 = mesh.AddNode(40, 20, 0) +if n2 == 0: print "KO node addition." + +# add quadrangle +q1 = mesh.AddFace([n2, n1, 38, 39]) +if q1 == 0: print "KO quadrangle addition." +else: print "New Quadrangle has been added with ID ", q1 diff --git a/doc/salome/examples/modifying_meshes_ex07.py b/doc/salome/examples/modifying_meshes_ex07.py new file mode 100644 index 000000000..5dfa8da03 --- /dev/null +++ b/doc/salome/examples/modifying_meshes_ex07.py @@ -0,0 +1,15 @@ +# Add Tetrahedron + +import SMESH_mechanic + +mesh = SMESH_mechanic.mesh +print "" + +# add node +n1 = mesh.AddNode(50, 10, 0) +if n1 == 0: print "KO node addition." + +# add tetrahedron +t1 = mesh.AddVolume([n1, 38, 39, 246]) +if t1 == 0: print "KO tetrahedron addition." +else: print "New Tetrahedron has been added with ID ", t1 diff --git a/doc/salome/examples/modifying_meshes_ex08.py b/doc/salome/examples/modifying_meshes_ex08.py new file mode 100644 index 000000000..4cfa89ee4 --- /dev/null +++ b/doc/salome/examples/modifying_meshes_ex08.py @@ -0,0 +1,19 @@ +# Add Hexahedron + +import SMESH_mechanic + +mesh = SMESH_mechanic.mesh +print "" + +# add nodes +nId1 = mesh.AddNode(50, 10, 0) +nId2 = mesh.AddNode(47, 12, 0) +nId3 = mesh.AddNode(50, 10, 10) +nId4 = mesh.AddNode(47, 12, 10) + +if nId1 == 0 or nId2 == 0 or nId3 == 0 or nId4 == 0: print "KO node addition." + +# add hexahedron +vId = mesh.AddVolume([nId2, nId1, 38, 39, nId4, nId3, 245, 246]) +if vId == 0: print "KO Hexahedron addition." +else: print "New Hexahedron has been added with ID ", vId diff --git a/doc/salome/examples/modifying_meshes_ex09.py b/doc/salome/examples/modifying_meshes_ex09.py new file mode 100644 index 000000000..2fd91114d --- /dev/null +++ b/doc/salome/examples/modifying_meshes_ex09.py @@ -0,0 +1,32 @@ +# Add Polygon + +import math +import salome + +import smesh + +# create an empty mesh structure +mesh = smesh.Mesh() + +# a method to build a polygonal mesh element with angles: +def MakePolygon (a_mesh, x0, y0, z0, radius, nb_vert): + al = 2.0 * math.pi / nb_vert + node_ids = [] + + # Create nodes for a polygon + for ii in range(nb_vert): + nid = mesh.AddNode(x0 + radius * math.cos(ii*al), + y0 + radius * math.sin(ii*al), + z0) + node_ids.append(nid) + pass + + # Create a polygon + return mesh.AddPolygonalFace(node_ids) + +# Create three polygons +f1 = MakePolygon(mesh, 0, 0, 0, 30, 13) +f2 = MakePolygon(mesh, 0, 0, 10, 21, 9) +f3 = MakePolygon(mesh, 0, 0, 20, 13, 6) + +salome.sg.updateObjBrowser(1) diff --git a/doc/salome/examples/modifying_meshes_ex10.py b/doc/salome/examples/modifying_meshes_ex10.py new file mode 100644 index 000000000..7f36728c1 --- /dev/null +++ b/doc/salome/examples/modifying_meshes_ex10.py @@ -0,0 +1,56 @@ +# Add Polyhedron + +import salome +import math + +# create an empty mesh structure +mesh = smesh.Mesh() + +# Create nodes for 12-hedron with pentagonal faces +al = 2 * math.pi / 5.0 +cosal = math.cos(al) +aa = 13 +rr = aa / (2.0 * math.sin(al/2.0)) +dr = 2.0 * rr * cosal +r1 = rr + dr +dh = rr * math.sqrt(2.0 * (1.0 - cosal * (1.0 + 2.0 * cosal))) +hh = 2.0 * dh - dr * (rr*(cosal - 1) + (rr + dr)*(math.cos(al/2) - 1)) / dh + +dd = [] # top +cc = [] # below top +bb = [] # above bottom +aa = [] # bottom + +for i in range(5): + cos_bot = math.cos(i*al) + sin_bot = math.sin(i*al) + + cos_top = math.cos(i*al + al/2.0) + sin_top = math.sin(i*al + al/2.0) + + nd = mesh.AddNode(rr * cos_top, rr * sin_top, hh ) # top + nc = mesh.AddNode(r1 * cos_top, r1 * sin_top, hh - dh) # below top + nb = mesh.AddNode(r1 * cos_bot, r1 * sin_bot, dh) # above bottom + na = mesh.AddNode(rr * cos_bot, rr * sin_bot, 0) # bottom + dd.append(nd) # top + cc.append(nc) # below top + bb.append(nb) # above bottom + aa.append(na) # bottom + pass + +# Create a polyhedral volume (12-hedron with pentagonal faces) +MeshEditor.AddPolyhedralVolume([dd[0], dd[1], dd[2], dd[3], dd[4], # top + dd[0], cc[0], bb[1], cc[1], dd[1], # - + dd[1], cc[1], bb[2], cc[2], dd[2], # - + dd[2], cc[2], bb[3], cc[3], dd[3], # - below top + dd[3], cc[3], bb[4], cc[4], dd[4], # - + dd[4], cc[4], bb[0], cc[0], dd[0], # - + aa[4], bb[4], cc[4], bb[0], aa[0], # . + aa[3], bb[3], cc[3], bb[4], aa[4], # . + aa[2], bb[2], cc[2], bb[3], aa[3], # . above bottom + aa[1], bb[1], cc[1], bb[2], aa[2], # . + aa[0], bb[0], cc[0], bb[1], aa[1], # . + aa[0], aa[1], aa[2], aa[3], aa[4]], # bottom + [5,5,5,5,5,5,5,5,5,5,5,5]) + +salome.sg.updateObjBrowser(1) diff --git a/doc/salome/examples/modifying_meshes_ex11.py b/doc/salome/examples/modifying_meshes_ex11.py new file mode 100644 index 000000000..6ba78c331 --- /dev/null +++ b/doc/salome/examples/modifying_meshes_ex11.py @@ -0,0 +1,10 @@ +# Removing Nodes + +import SMESH_mechanic + +mesh = SMESH_mechanic.mesh + +# remove nodes #246 and #255 +res = mesh.RemoveNodes([246, 255]) +if res == 1: print "Nodes removing is OK!" +else: print "KO nodes removing." diff --git a/doc/salome/examples/modifying_meshes_ex12.py b/doc/salome/examples/modifying_meshes_ex12.py new file mode 100644 index 000000000..5437b3815 --- /dev/null +++ b/doc/salome/examples/modifying_meshes_ex12.py @@ -0,0 +1,10 @@ +# Removing Elements + +import SMESH_mechanic + +mesh = SMESH_mechanic.mesh + +# remove three elements: #850, #859 and #814 +res = mesh.RemoveElements([850, 859, 814]) +if res == 1: print "Elements removing is OK!" +else: print "KO Elements removing." diff --git a/doc/salome/examples/modifying_meshes_ex13.py b/doc/salome/examples/modifying_meshes_ex13.py new file mode 100644 index 000000000..4189b852b --- /dev/null +++ b/doc/salome/examples/modifying_meshes_ex13.py @@ -0,0 +1,13 @@ +# Removing Orphan Nodes + +import SMESH_mechanic + +mesh = SMESH_mechanic.mesh + +# add orphan nodes +mesh.AddNode(0,0,0) +mesh.AddNode(1,1,1) +# remove just created orphan nodes +res = mesh.RemoveOrphanNodes() +if res == 1: print "Removed %d nodes!" % res +else: print "KO nodes removing." diff --git a/doc/salome/examples/modifying_meshes_ex14.py b/doc/salome/examples/modifying_meshes_ex14.py new file mode 100644 index 000000000..7bb10fd9f --- /dev/null +++ b/doc/salome/examples/modifying_meshes_ex14.py @@ -0,0 +1,9 @@ +# Renumbering Nodes and Elements + +import SMESH_mechanic + +mesh = SMESH_mechanic.mesh + +mesh.RenumberNodes() + +mesh.RenumberElements() diff --git a/doc/salome/examples/modifying_meshes_ex15.py b/doc/salome/examples/modifying_meshes_ex15.py new file mode 100644 index 000000000..49676d0ee --- /dev/null +++ b/doc/salome/examples/modifying_meshes_ex15.py @@ -0,0 +1,43 @@ +# Moving Nodes + +from geompy import * +from smesh import * + +box = MakeBoxDXDYDZ(200, 200, 200) + +mesh = Mesh( box ) +mesh.Segment().AutomaticLength(0.1) +mesh.Quadrangle() +mesh.Compute() + +# find node at (0,0,0) +node000 = None +for vId in SubShapeAllIDs( box, ShapeType["VERTEX"]): + if node000: break + nodeIds = mesh.GetSubMeshNodesId( vId, True ) + for node in nodeIds: + xyz = mesh.GetNodeXYZ( node ) + if xyz[0] == 0 and xyz[1] == 0 and xyz[2] == 0 : + node000 = node + pass + pass + pass + +if not node000: + raise "node000 not found" + +# find node000 using the tested function +n = mesh.FindNodeClosestTo( -1,-1,-1 ) +if not n == node000: + raise "FindNodeClosestTo() returns " + str( n ) + " != " + str( node000 ) + +# move node000 to a new location +x,y,z = -10, -10, -10 +n = mesh.MoveNode( n,x,y,z ) +if not n: + raise "MoveNode() returns " + n + +# check the coordinates of the node000 +xyz = mesh.GetNodeXYZ( node000 ) +if not ( xyz[0] == x and xyz[1] == y and xyz[2] == z) : + raise "Wrong coordinates: " + str( xyz ) + " != " + str( [x,y,z] ) diff --git a/doc/salome/examples/modifying_meshes_ex16.py b/doc/salome/examples/modifying_meshes_ex16.py new file mode 100644 index 000000000..6567dff19 --- /dev/null +++ b/doc/salome/examples/modifying_meshes_ex16.py @@ -0,0 +1,44 @@ +# Diagonal Inversion + +import salome +import smesh + +# create an empty mesh structure +mesh = smesh.Mesh() + +# create the following mesh: +# .----.----.----. +# | /| /| /| +# | / | / | / | +# | / | / | / | +# |/ |/ |/ | +# .----.----.----. + +bb = [0, 0, 0, 0] +tt = [0, 0, 0, 0] +ff = [0, 0, 0, 0, 0, 0] + +bb[0] = mesh.AddNode( 0., 0., 0.) +bb[1] = mesh.AddNode(10., 0., 0.) +bb[2] = mesh.AddNode(20., 0., 0.) +bb[3] = mesh.AddNode(30., 0., 0.) + +tt[0] = mesh.AddNode( 0., 15., 0.) +tt[1] = mesh.AddNode(10., 15., 0.) +tt[2] = mesh.AddNode(20., 15., 0.) +tt[3] = mesh.AddNode(30., 15., 0.) + +ff[0] = mesh.AddFace([bb[0], bb[1], tt[1]]) +ff[1] = mesh.AddFace([bb[0], tt[1], tt[0]]) +ff[2] = mesh.AddFace([bb[1], bb[2], tt[2]]) +ff[3] = mesh.AddFace([bb[1], tt[2], tt[1]]) +ff[4] = mesh.AddFace([bb[2], bb[3], tt[3]]) +ff[5] = mesh.AddFace([bb[2], tt[3], tt[2]]) + +# inverse the diagonal bb[1] - tt[2] +print "\nDiagonal inversion ... ", +res = mesh.InverseDiag(bb[1], tt[2]) +if not res: print "failed!" +else: print "done." + +salome.sg.updateObjBrowser(1) diff --git a/doc/salome/examples/modifying_meshes_ex17.py b/doc/salome/examples/modifying_meshes_ex17.py new file mode 100644 index 000000000..732953ab2 --- /dev/null +++ b/doc/salome/examples/modifying_meshes_ex17.py @@ -0,0 +1,44 @@ +# Uniting two Triangles + +import salome +import smesh + +# create an empty mesh structure +mesh = smesh.Mesh() + +# create the following mesh: +# .----.----.----. +# | /| /| /| +# | / | / | / | +# | / | / | / | +# |/ |/ |/ | +# .----.----.----. + +bb = [0, 0, 0, 0] +tt = [0, 0, 0, 0] +ff = [0, 0, 0, 0, 0, 0] + +bb[0] = mesh.AddNode( 0., 0., 0.) +bb[1] = mesh.AddNode(10., 0., 0.) +bb[2] = mesh.AddNode(20., 0., 0.) +bb[3] = mesh.AddNode(30., 0., 0.) + +tt[0] = mesh.AddNode( 0., 15., 0.) +tt[1] = mesh.AddNode(10., 15., 0.) +tt[2] = mesh.AddNode(20., 15., 0.) +tt[3] = mesh.AddNode(30., 15., 0.) + +ff[0] = mesh.AddFace([bb[0], bb[1], tt[1]]) +ff[1] = mesh.AddFace([bb[0], tt[1], tt[0]]) +ff[2] = mesh.AddFace([bb[1], bb[2], tt[2]]) +ff[3] = mesh.AddFace([bb[1], tt[2], tt[1]]) +ff[4] = mesh.AddFace([bb[2], bb[3], tt[3]]) +ff[5] = mesh.AddFace([bb[2], tt[3], tt[2]]) + +# delete the diagonal bb[1] - tt[2] +print "\nUnite two triangles ... ", +res = mesh.DeleteDiag(bb[1], tt[2]) +if not res: print "failed!" +else: print "done." + +salome.sg.updateObjBrowser(1) diff --git a/doc/salome/examples/modifying_meshes_ex18.py b/doc/salome/examples/modifying_meshes_ex18.py new file mode 100644 index 000000000..9f7393022 --- /dev/null +++ b/doc/salome/examples/modifying_meshes_ex18.py @@ -0,0 +1,44 @@ +# Uniting a Set of Triangles + +import salome +import smesh + +# create an empty mesh structure +mesh = smesh.Mesh() + +# create the following mesh: +# .----.----.----. +# | /| /| /| +# | / | / | / | +# | / | / | / | +# |/ |/ |/ | +# .----.----.----. + +bb = [0, 0, 0, 0] +tt = [0, 0, 0, 0] +ff = [0, 0, 0, 0, 0, 0] + +bb[0] = mesh.AddNode( 0., 0., 0.) +bb[1] = mesh.AddNode(10., 0., 0.) +bb[2] = mesh.AddNode(20., 0., 0.) +bb[3] = mesh.AddNode(30., 0., 0.) + +tt[0] = mesh.AddNode( 0., 15., 0.) +tt[1] = mesh.AddNode(10., 15., 0.) +tt[2] = mesh.AddNode(20., 15., 0.) +tt[3] = mesh.AddNode(30., 15., 0.) + +ff[0] = mesh.AddFace([bb[0], bb[1], tt[1]]) +ff[1] = mesh.AddFace([bb[0], tt[1], tt[0]]) +ff[2] = mesh.AddFace([bb[1], bb[2], tt[2]]) +ff[3] = mesh.AddFace([bb[1], tt[2], tt[1]]) +ff[4] = mesh.AddFace([bb[2], bb[3], tt[3]]) +ff[5] = mesh.AddFace([bb[2], tt[3], tt[2]]) + +# unite a set of triangles +print "\nUnite a set of triangles ... ", +res = mesh.TriToQuad([ff[2], ff[3], ff[4], ff[5]], smesh.FT_MinimumAngle, 60.) +if not res: print "failed!" +else: print "done." + +salome.sg.updateObjBrowser(1) diff --git a/doc/salome/examples/modifying_meshes_ex19.py b/doc/salome/examples/modifying_meshes_ex19.py new file mode 100644 index 000000000..c3eaf4977 --- /dev/null +++ b/doc/salome/examples/modifying_meshes_ex19.py @@ -0,0 +1,35 @@ +# Orientation + +import salome +import smesh + +# create an empty mesh structure +mesh = smesh.Mesh() + +# build five quadrangles: +dx = 10 +dy = 20 + +n1 = mesh.AddNode(0.0 * dx, 0, 0) +n2 = mesh.AddNode(1.0 * dx, 0, 0) +n3 = mesh.AddNode(2.0 * dx, 0, 0) +n4 = mesh.AddNode(3.0 * dx, 0, 0) +n5 = mesh.AddNode(4.0 * dx, 0, 0) +n6 = mesh.AddNode(5.0 * dx, 0, 0) +n7 = mesh.AddNode(0.0 * dx, dy, 0) +n8 = mesh.AddNode(1.0 * dx, dy, 0) +n9 = mesh.AddNode(2.0 * dx, dy, 0) +n10 = mesh.AddNode(3.0 * dx, dy, 0) +n11 = mesh.AddNode(4.0 * dx, dy, 0) +n12 = mesh.AddNode(5.0 * dx, dy, 0) + +f1 = mesh.AddFace([n1, n2, n8 , n7 ]) +f2 = mesh.AddFace([n2, n3, n9 , n8 ]) +f3 = mesh.AddFace([n3, n4, n10, n9 ]) +f4 = mesh.AddFace([n4, n5, n11, n10]) +f5 = mesh.AddFace([n5, n6, n12, n11]) + +# Change the orientation of the second and the fourth faces. +mesh.Reorient([2, 4]) + +salome.sg.updateObjBrowser(1) diff --git a/doc/salome/examples/modifying_meshes_ex20.py b/doc/salome/examples/modifying_meshes_ex20.py new file mode 100644 index 000000000..aa52da784 --- /dev/null +++ b/doc/salome/examples/modifying_meshes_ex20.py @@ -0,0 +1,9 @@ +# Cutting Quadrangles + +import SMESH_mechanic + +smesh = SMESH_mechanic.smesh +mesh = SMESH_mechanic.mesh + +# cut two quadrangles: 405 and 406 +mesh.QuadToTri([405, 406], smesh.FT_MinimumAngle) diff --git a/doc/salome/examples/modifying_meshes_ex21.py b/doc/salome/examples/modifying_meshes_ex21.py new file mode 100644 index 000000000..ece705c7d --- /dev/null +++ b/doc/salome/examples/modifying_meshes_ex21.py @@ -0,0 +1,27 @@ +# Smoothing + +import salome +import geompy + +import SMESH_mechanic + +smesh = SMESH_mechanic.smesh +mesh = SMESH_mechanic.mesh + +# select the top face +faces = geompy.SubShapeAllSorted(SMESH_mechanic.shape_mesh, geompy.ShapeType["FACE"]) +face = faces[3] +geompy.addToStudyInFather(SMESH_mechanic.shape_mesh, face, "face planar with hole") + +# create a group of faces to be smoothed +GroupSmooth = mesh.GroupOnGeom(face, "Group of faces (smooth)", smesh.FACE) + +# perform smoothing + +# boolean SmoothObject(Object, IDsOfFixedNodes, MaxNbOfIterations, MaxAspectRatio, Method) +res = mesh.SmoothObject(GroupSmooth, [], 20, 2., smesh.CENTROIDAL_SMOOTH) +print "\nSmoothing ... ", +if not res: print "failed!" +else: print "done." + +salome.sg.updateObjBrowser(1) diff --git a/doc/salome/examples/modifying_meshes_ex22.py b/doc/salome/examples/modifying_meshes_ex22.py new file mode 100644 index 000000000..e9dcb3c96 --- /dev/null +++ b/doc/salome/examples/modifying_meshes_ex22.py @@ -0,0 +1,26 @@ +# Extrusion + +import salome +import geompy + +import SMESH_mechanic + +smesh = SMESH_mechanic.smesh +mesh = SMESH_mechanic.mesh + +# select the top face +faces = geompy.SubShapeAllSorted(SMESH_mechanic.shape_mesh, geompy.ShapeType["FACE"]) +face = faces[7] +geompy.addToStudyInFather(SMESH_mechanic.shape_mesh, face, "face circular top") + +# create a vector for extrusion +point = smesh.PointStruct(0., 0., 5.) +vector = smesh.DirStruct(point) + +# create a group to be extruded +GroupTri = mesh.GroupOnGeom(face, "Group of faces (extrusion)", smesh.FACE) + +# perform extrusion of the group +mesh.ExtrusionSweepObject(GroupTri, vector, 5) + +salome.sg.updateObjBrowser(1) diff --git a/doc/salome/examples/modifying_meshes_ex23.py b/doc/salome/examples/modifying_meshes_ex23.py new file mode 100644 index 000000000..a789b76f0 --- /dev/null +++ b/doc/salome/examples/modifying_meshes_ex23.py @@ -0,0 +1,126 @@ +# Extrusion along a Path + +import math +import salome + +# Geometry +import geompy + +# 1. Create points +points = [[0, 0], [50, 30], [50, 110], [0, 150], [-80, 150], [-130, 70], [-130, -20]] + +iv = 1 +vertices = [] +for point in points: + vert = geompy.MakeVertex(point[0], point[1], 0) + geompy.addToStudy(vert, "Vertex_" + `iv`) + vertices.append(vert) + iv += 1 + pass + +# 2. Create edges and wires +Edge_straight = geompy.MakeEdge(vertices[0], vertices[4]) +Edge_bezierrr = geompy.MakeBezier(vertices) +Wire_polyline = geompy.MakePolyline(vertices) +Edge_Circle = geompy.MakeCircleThreePnt(vertices[0], vertices[1], vertices[2]) + +geompy.addToStudy(Edge_straight, "Edge_straight") +geompy.addToStudy(Edge_bezierrr, "Edge_bezierrr") +geompy.addToStudy(Wire_polyline, "Wire_polyline") +geompy.addToStudy(Edge_Circle , "Edge_Circle") + +# 3. Explode wire on edges, as they will be used for mesh extrusion +Wire_polyline_edges = geompy.SubShapeAll(Wire_polyline, geompy.ShapeType["EDGE"]) +for ii in range(len(Wire_polyline_edges)): + geompy.addToStudyInFather(Wire_polyline, Wire_polyline_edges[ii], "Edge_" + `ii + 1`) + pass + +# Mesh +import smesh + +# Mesh the given shape with the given 1d hypothesis +def Mesh1D(shape1d, nbSeg, name): + mesh1d_tool = smesh.Mesh(shape1d, name) + algo = mesh1d_tool.Segment() + hyp = algo.NumberOfSegments(nbSeg) + isDone = mesh1d_tool.Compute() + if not isDone: print 'Mesh ', name, ': computation failed' + return mesh1d_tool + +# Create a mesh with six nodes, seven edges and two quadrangle faces +def MakeQuadMesh2(mesh_name): + quad_1 = smesh.Mesh(name = mesh_name) + + # six nodes + n1 = quad_1.AddNode(0, 20, 10) + n2 = quad_1.AddNode(0, 40, 10) + n3 = quad_1.AddNode(0, 40, 30) + n4 = quad_1.AddNode(0, 20, 30) + n5 = quad_1.AddNode(0, 0, 30) + n6 = quad_1.AddNode(0, 0, 10) + + # seven edges + quad_1.AddEdge([n1, n2]) # 1 + quad_1.AddEdge([n2, n3]) # 2 + quad_1.AddEdge([n3, n4]) # 3 + quad_1.AddEdge([n4, n1]) # 4 + quad_1.AddEdge([n4, n5]) # 5 + quad_1.AddEdge([n5, n6]) # 6 + quad_1.AddEdge([n6, n1]) # 7 + + # two quadrangle faces + quad_1.AddFace([n1, n2, n3, n4]) # 8 + quad_1.AddFace([n1, n4, n5, n6]) # 9 + return [quad_1, [1,2,3,4,5,6,7], [8,9]] + +# Path meshes +Edge_straight_mesh = Mesh1D(Edge_straight, 7, "Edge_straight") +Edge_bezierrr_mesh = Mesh1D(Edge_bezierrr, 7, "Edge_bezierrr") +Wire_polyline_mesh = Mesh1D(Wire_polyline, 3, "Wire_polyline") +Edge_Circle_mesh = Mesh1D(Edge_Circle , 8, "Edge_Circle") + +# Initial meshes (to be extruded) +[quad_1, ee_1, ff_1] = MakeQuadMesh2("quad_1") +[quad_2, ee_2, ff_2] = MakeQuadMesh2("quad_2") +[quad_3, ee_3, ff_3] = MakeQuadMesh2("quad_3") +[quad_4, ee_4, ff_4] = MakeQuadMesh2("quad_4") +[quad_5, ee_5, ff_5] = MakeQuadMesh2("quad_5") +[quad_6, ee_6, ff_6] = MakeQuadMesh2("quad_6") +[quad_7, ee_7, ff_7] = MakeQuadMesh2("quad_7") + +# ExtrusionAlongPath +# IDsOfElements, PathMesh, PathShape, NodeStart, +# HasAngles, Angles, HasRefPoint, RefPoint +refPoint = smesh.PointStruct(0, 0, 0) +a10 = 10.0*math.pi/180.0 +a45 = 45.0*math.pi/180.0 + +# 1. Extrusion of two mesh edges along a straight path +error = quad_1.ExtrusionAlongPath([1,2], Edge_straight_mesh, Edge_straight, 1, + 0, [], 0, refPoint) + +# 2. Extrusion of one mesh edge along a curved path +error = quad_2.ExtrusionAlongPath([2], Edge_bezierrr_mesh, Edge_bezierrr, 1, + 0, [], 0, refPoint) + +# 3. Extrusion of one mesh edge along a curved path with usage of angles +error = quad_3.ExtrusionAlongPath([2], Edge_bezierrr_mesh, Edge_bezierrr, 1, + 1, [a45, a45, a45, 0, -a45, -a45, -a45], 0, refPoint) + +# 4. Extrusion of one mesh edge along the path, which is a part of a meshed wire +error = quad_4.ExtrusionAlongPath([4], Wire_polyline_mesh, Wire_polyline_edges[0], 1, + 1, [a10, a10, a10], 0, refPoint) + +# 5. Extrusion of two mesh faces along the path, which is a part of a meshed wire +error = quad_5.ExtrusionAlongPath(ff_5 , Wire_polyline_mesh, Wire_polyline_edges[2], 4, + 0, [], 0, refPoint) + +# 6. Extrusion of two mesh faces along a closed path +error = quad_6.ExtrusionAlongPath(ff_6 , Edge_Circle_mesh, Edge_Circle, 1, + 0, [], 0, refPoint) + +# 7. Extrusion of two mesh faces along a closed path with usage of angles +error = quad_7.ExtrusionAlongPath(ff_7, Edge_Circle_mesh, Edge_Circle, 1, + 1, [a45, -a45, a45, -a45, a45, -a45, a45, -a45], 0, refPoint) + +salome.sg.updateObjBrowser(1) diff --git a/doc/salome/examples/modifying_meshes_ex24.py b/doc/salome/examples/modifying_meshes_ex24.py new file mode 100644 index 000000000..d07a7ca5b --- /dev/null +++ b/doc/salome/examples/modifying_meshes_ex24.py @@ -0,0 +1,21 @@ +# Revolution + +import math +import SMESH + +import SMESH_mechanic + +mesh = SMESH_mechanic.mesh +smesh = SMESH_mechanic.smesh + +# create a group of faces to be revolved +FacesRotate = [492, 493, 502, 503] +GroupRotate = mesh.CreateEmptyGroup(SMESH.FACE,"Group of faces (rotate)") +GroupRotate.Add(FacesRotate) + +# define revolution angle and axis +angle45 = 45 * math.pi / 180 +axisXYZ = SMESH.AxisStruct(-38.3128, -73.3658, -23.321, -13.3402, -13.3265, 6.66632) + +# perform revolution of an object +mesh.RotationSweepObject(GroupRotate, axisXYZ, angle45, 4, 1e-5) diff --git a/doc/salome/examples/modifying_meshes_ex25.py b/doc/salome/examples/modifying_meshes_ex25.py new file mode 100644 index 000000000..e8801e003 --- /dev/null +++ b/doc/salome/examples/modifying_meshes_ex25.py @@ -0,0 +1,130 @@ +# Pattern Mapping + +import geompy +import smesh + +# define the geometry +Box_1 = geompy.MakeBoxDXDYDZ(200., 200., 200.) +geompy.addToStudy(Box_1, "Box_1") + +faces = geompy.SubShapeAll(Box_1, geompy.ShapeType["FACE"]) +Face_1 = faces[0] +Face_2 = faces[1] + +geompy.addToStudyInFather(Box_1, Face_1, "Face_1") +geompy.addToStudyInFather(Box_1, Face_2, "Face_2") + +# build a quadrangle mesh 3x3 on Face_1 +Mesh_1 = smesh.Mesh(Face_1) +algo1D = Mesh_1.Segment() +algo1D.NumberOfSegments(3) +Mesh_1.Quadrangle() + +isDone = Mesh_1.Compute() +if not isDone: print 'Mesh Mesh_1 : computation failed' + +# build a triangle mesh on Face_2 +Mesh_2 = smesh.Mesh(Face_2) + +algo1D = Mesh_2.Segment() +algo1D.NumberOfSegments(1) +algo2D = Mesh_2.Triangle() +algo2D.MaxElementArea(240) + +isDone = Mesh_2.Compute() +if not isDone: print 'Mesh Mesh_2 : computation failed' + +# create a 2d pattern +pattern = smesh.GetPattern() + +isDone = pattern.LoadFromFace(Mesh_2.GetMesh(), Face_2, 0) +if (isDone != 1): print 'LoadFromFace :', pattern.GetErrorCode() + +# apply the pattern to a face of the first mesh +facesToSplit = Mesh_1.GetElementsByType(smesh.SMESH.FACE) +print "Splitting %d rectangular face(s) to %d triangles..."%(len(facesToSplit), 2*len(facesToSplit)) +pattern.ApplyToMeshFaces(Mesh_1.GetMesh(), facesToSplit, 0, 0) +isDone = pattern.MakeMesh(Mesh_1.GetMesh(), 0, 0) +if (isDone != 1): print 'MakeMesh :', pattern.GetErrorCode() + +# create quadrangle mesh +Mesh_3 = smesh.Mesh(Box_1) +Mesh_3.Segment().NumberOfSegments(1) +Mesh_3.Quadrangle() +Mesh_3.Hexahedron() +isDone = Mesh_3.Compute() +if not isDone: print 'Mesh Mesh_3 : computation failed' + +# create a 3d pattern (hexahedrons) +pattern_hexa = smesh.GetPattern() + +smp_hexa = """!!! Nb of points: +15 + 0 0 0 !- 0 + 1 0 0 !- 1 + 0 1 0 !- 2 + 1 1 0 !- 3 + 0 0 1 !- 4 + 1 0 1 !- 5 + 0 1 1 !- 6 + 1 1 1 !- 7 + 0.5 0 0.5 !- 8 + 0.5 0 1 !- 9 + 0.5 0.5 0.5 !- 10 + 0.5 0.5 1 !- 11 + 1 0 0.5 !- 12 + 1 0.5 0.5 !- 13 + 1 0.5 1 !- 14 + !!! Indices of points of 4 elements: + 8 12 5 9 10 13 14 11 + 0 8 9 4 2 10 11 6 + 2 10 11 6 3 13 14 7 + 0 1 12 8 2 3 13 10""" + +pattern_hexa.LoadFromFile(smp_hexa) + +# apply the pattern to a mesh +volsToSplit = Mesh_3.GetElementsByType(smesh.SMESH.VOLUME) +print "Splitting %d hexa volume(s) to %d hexas..."%(len(volsToSplit), 4*len(volsToSplit)) +pattern_hexa.ApplyToHexahedrons(Mesh_3.GetMesh(), volsToSplit,0,3) +isDone = pattern_hexa.MakeMesh(Mesh_3.GetMesh(), True, True) +if (isDone != 1): print 'MakeMesh :', pattern_hexa.GetErrorCode() + +# create one more quadrangle mesh +Mesh_4 = smesh.Mesh(Box_1) +Mesh_4.Segment().NumberOfSegments(1) +Mesh_4.Quadrangle() +Mesh_4.Hexahedron() +isDone = Mesh_4.Compute() +if not isDone: print 'Mesh Mesh_4 : computation failed' + +# create another 3d pattern (pyramids) +pattern_pyra = smesh.GetPattern() + +smp_pyra = """!!! Nb of points: +9 + 0 0 0 !- 0 + 1 0 0 !- 1 + 0 1 0 !- 2 + 1 1 0 !- 3 + 0 0 1 !- 4 + 1 0 1 !- 5 + 0 1 1 !- 6 + 1 1 1 !- 7 + 0.5 0.5 0.5 !- 8 + !!! Indices of points of 6 elements: + 0 1 5 4 8 + 7 5 1 3 8 + 3 2 6 7 8 + 2 0 4 6 8 + 0 2 3 1 8 + 4 5 7 6 8""" + +pattern_pyra.LoadFromFile(smp_pyra) + +# apply the pattern to a face mesh +volsToSplit = Mesh_4.GetElementsByType(smesh.SMESH.VOLUME) +print "Splitting %d hexa volume(s) to %d hexas..."%(len(volsToSplit), 6*len(volsToSplit)) +pattern_pyra.ApplyToHexahedrons(Mesh_4.GetMesh(), volsToSplit,1,0) +isDone = pattern_pyra.MakeMesh(Mesh_4.GetMesh(), True, True) +if (isDone != 1): print 'MakeMesh :', pattern_pyra.GetErrorCode() diff --git a/doc/salome/examples/modifying_meshes_ex26.py b/doc/salome/examples/modifying_meshes_ex26.py new file mode 100644 index 000000000..aa8cb4379 --- /dev/null +++ b/doc/salome/examples/modifying_meshes_ex26.py @@ -0,0 +1,45 @@ +# Convert mesh to/from quadratic + +import geompy +import smesh + +# create sphere of radius 100 + +Sphere = geompy.MakeSphereR( 100 ) +geompy.addToStudy( Sphere, "Sphere" ) + +# create simple trihedral mesh + +Mesh = smesh.Mesh(Sphere) +Regular_1D = Mesh.Segment() +Nb_Segments = Regular_1D.NumberOfSegments(5) +MEFISTO_2D = Mesh.Triangle() +Tetrahedron = Mesh.Tetrahedron() + +# compute mesh + +isDone = Mesh.Compute() + +# convert to quadratic +# theForce3d = 1; this results in the medium node lying at the +# middle of the line segments connecting start and end node of a mesh +# element + +Mesh.ConvertToQuadratic( theForce3d=1 ) + +# revert back to the non-quadratic mesh + +Mesh.ConvertFromQuadratic() + +# convert to quadratic +# theForce3d = 0; this results in the medium node lying at the +# geometrical edge from which the mesh element is built + +Mesh.ConvertToQuadratic( theForce3d=0 ) + +# to convert not the whole mesh but a sub-mesh, provide it as +# an additional argument to the functions: +# Mesh.ConvertToQuadratic( 0, subMesh ) +# Mesh.ConvertFromQuadratic( subMesh ) +# +# Note that the mesh becomes non-conformal at conversion of sub-mesh. diff --git a/doc/salome/examples/notebook_smesh.py b/doc/salome/examples/notebook_smesh.py new file mode 100644 index 000000000..9cccc7b5b --- /dev/null +++ b/doc/salome/examples/notebook_smesh.py @@ -0,0 +1,39 @@ +# Using SALOME NoteBook + +import geompy +import smesh +import salome_notebook + +# set variables +notebook = salome_notebook.notebook +notebook.set("Length", 100) +notebook.set("Width", 200) +notebook.set("Offset", 50) + +notebook.set("NbSegments", 7) +notebook.set("MaxElementArea", 800) +notebook.set("MaxElementVolume", 900) + +# create a box +box = geompy.MakeBoxDXDYDZ("Length", "Width", 300) +idbox = geompy.addToStudy(box, "Box") + +# create a mesh +tetra = smesh.Mesh(box, "MeshBox") + +algo1D = tetra.Segment() +algo1D.NumberOfSegments("NbSegments") + +algo2D = tetra.Triangle() +algo2D.MaxElementArea("MaxElementArea") + +algo3D = tetra.Tetrahedron() +algo3D.MaxElementVolume("MaxElementVolume") + +# compute the mesh +ret = tetra.Compute() + +# translate the mesh +point = smesh.PointStruct("Offset", 0., 0.) +vector = smesh.DirStruct(point) +tetra.TranslateObject(tetra, vector, 0) diff --git a/doc/salome/examples/prism_3d_algo.py b/doc/salome/examples/prism_3d_algo.py new file mode 100644 index 000000000..df18d0fcb --- /dev/null +++ b/doc/salome/examples/prism_3d_algo.py @@ -0,0 +1,73 @@ +# Use 3D extrusion meshing algorithm + +import salome, smesh, SMESH, geompy + +salome.salome_init() +smesh.SetCurrentStudy( salome.myStudy ) + +OX = geompy.MakeVectorDXDYDZ(1,0,0) +OY = geompy.MakeVectorDXDYDZ(0,1,0) +OZ = geompy.MakeVectorDXDYDZ(0,0,1) + +# Y ^ Make geometry of a "pipe" with the following base (cross section). +# | Big central quadrangles will be meshed with triangles, walls +# of the pipe will be meshed with quadrilaterals +# +--+--+--+--+--+--+ +# | | | | | | | +# +--+--+--+--+--+--+ +# | | | | | +# +--+ | +--+ +# | | | | | +# +--+-----+-----+--+ +# | | | | | +# +--+ | +--+ +# | | | | | +# +--+--+--+--+--+--+ +# | | | | | | | --> +# +--+--+--+--+--+--+ X + +quadBig = geompy.MakeFaceHW( 20,20, 1 ) +quadBig = geompy.MakeTranslation( quadBig, 15,15,0 ) +quadSmall = geompy.MakeFaceHW( 10,10, 1 ) +smallQuads1 = geompy.MakeMultiTranslation1D( quadSmall, OX, 10, 3 ) +smallQuads2 = geompy.MakeMultiTranslation1D( quadSmall, OY, 10, 3 ) +smallQuads2 = geompy.SubShapeAllSortedCentres( smallQuads2, geompy.ShapeType["FACE"])[1:] + +base = geompy.MakeCompound( smallQuads2 + [smallQuads1, quadBig]) +axis = geompy.MakeLine( geompy.MakeVertex( 25,25,0), OZ ) +base = geompy.MultiRotate1DNbTimes( base, axis, 4) +base = geompy.MakePartition( [base], theName="base") +path = geompy.MakeSketcher("Sketcher:F 0 0:TT 0 100:R 0:C -90 180:T 0 -150",[0,0,0, 0,-1,0, 1,0,0]) + +# Make the pipe, each quadrangle of the base turns into a prism with composite wall faces +pipe = geompy.MakePipe( base, path ) +prisms = geompy.MakePartition( [pipe], theName="prisms") + + +# get base faces of the prism to define sub-mesh on them +smallQuad = geompy.GetFaceNearPoint( prisms, geompy.MakeVertex( 0,0,0 ), "smallQuad") +bigQuad = geompy.GetFaceNearPoint( prisms, geompy.MakeVertex( 15,15,0 ), "bigQuad") + + +mesh = smesh.Mesh( prisms ) + +# assign Global hypotheses + +# 1D algorithm and hypothesis for vertical division +mesh.Segment().NumberOfSegments(15) + +# Extrusion 3D algo +mesh.Prism() + +# assign Local hypotheses + +# 1D and 2D algos and hyps to mesh smallQuad with quadrilaterals +mesh.Segment(smallQuad).LocalLength( 3 ) +mesh.Quadrangle(smallQuad) + +# 1D and 2D algos and hyps to mesh bigQuad with triangles +mesh.Segment(bigQuad).LocalLength( 3 ) +mesh.Triangle(bigQuad) + +# compute the mesh +mesh.Compute() diff --git a/doc/salome/examples/quality_controls_ex01.py b/doc/salome/examples/quality_controls_ex01.py new file mode 100644 index 000000000..ed4dc244e --- /dev/null +++ b/doc/salome/examples/quality_controls_ex01.py @@ -0,0 +1,41 @@ +# Free Borders + +import salome +import geompy + +import smesh + +# create open shell: a box without one plane +box = geompy.MakeBox(0., 0., 0., 20., 20., 15.) +FaceList = geompy.SubShapeAll(box, geompy.ShapeType["FACE"]) +FaceList.remove(FaceList[5]) +box = geompy.MakeShell(FaceList) +idbox = geompy.addToStudy(box, "box") + +# create a mesh +mesh = smesh.Mesh(box, "Mesh_free_borders") +algo = mesh.Segment() +algo.NumberOfSegments(5) +algo = mesh.Triangle() +algo.MaxElementArea(20.) +mesh.Compute() + +# criterion : free borders +aFilter = smesh.GetFilter(smesh.EDGE, smesh.FT_FreeBorders) +anIds = mesh.GetIdsFromFilter(aFilter) + +# print the result +print "Criterion: Free borders Nb = ", len(anIds) +j = 1 +for i in range(len(anIds)): + if j > 20: j = 1; print "" + print anIds[i], + j = j + 1 + pass +print "" + +# create a group +aGroup = mesh.CreateGroup(SMESH.EDGE, "Free borders") +aGroup.Add(anIds) + +salome.sg.updateObjBrowser(1) diff --git a/doc/salome/examples/quality_controls_ex02.py b/doc/salome/examples/quality_controls_ex02.py new file mode 100644 index 000000000..7b1f55e6f --- /dev/null +++ b/doc/salome/examples/quality_controls_ex02.py @@ -0,0 +1,44 @@ +# Borders at Multiconnection + +import salome +import geompy + +import smesh +import SMESH + +# create open shell: a box without one plane +box = geompy.MakeBox(0., 0., 0., 20., 20., 15.) +FaceList = geompy.SubShapeAll(box, geompy.ShapeType["FACE"]) +FaceList.remove(FaceList[5]) +box = geompy.MakeShell(FaceList) +idbox = geompy.addToStudy(box, "box") + +# create a mesh +mesh = smesh.Mesh(box, "Mesh_borders_at_multi-connections") +algo = mesh.Segment() +algo.NumberOfSegments(5) +algo = mesh.Triangle() +algo.MaxElementArea(20.) +mesh.Compute() + +# Criterion : Borders at multi-connection +nb_conn = 2 + +aFilter = smesh.GetFilter(smesh.EDGE, smesh.FT_MultiConnection, smesh.FT_EqualTo, nb_conn) +anIds = mesh.GetIdsFromFilter(aFilter) + +# print the result +print "Criterion: Borders at multi-connections Nb = ", len(anIds) +j = 1 +for i in range(len(anIds)): + if j > 20: j = 1; print "" + print anIds[i], + j = j + 1 + pass +print "" + +# create a group +aGroup = mesh.CreateGroup(SMESH.EDGE, "Borders at multi-connections") +aGroup.Add(anIds) + +salome.sg.updateObjBrowser(1) diff --git a/doc/salome/examples/quality_controls_ex03.py b/doc/salome/examples/quality_controls_ex03.py new file mode 100644 index 000000000..8cb409866 --- /dev/null +++ b/doc/salome/examples/quality_controls_ex03.py @@ -0,0 +1,43 @@ +# Length 1D + +import salome +import geompy + +import smesh + +# create open shell: a box without one plane +box = geompy.MakeBox(0., 0., 0., 20., 20., 15.) +FaceList = geompy.SubShapeAll(box, geompy.ShapeType["FACE"]) +FaceList.remove(FaceList[5]) +box = geompy.MakeShell(FaceList) +idbox = geompy.addToStudy(box, "box") + +# create a mesh +mesh = smesh.Mesh(box, "Mesh_Length_1D") +algo = mesh.Segment() +algo.NumberOfSegments(5) +algo = mesh.Triangle() +algo.MaxElementArea(20.) +mesh.Compute() + +# Criterion : Length > 3. +length_margin = 3. + +aFilter = smesh.GetFilter(smesh.EDGE, smesh.FT_Length, smesh.FT_MoreThan, length_margin) +anIds = mesh.GetIdsFromFilter(aFilter) + +# print the result +print "Criterion: Edges length > ", length_margin, " Nb = ", len(anIds) +j = 1 +for i in range(len(anIds)): + if j > 20: j = 1; print "" + print anIds[i], + j = j + 1 + pass +print "" + +# create a group +aGroup = mesh.CreateGroup(SMESH.EDGE, "Edges with length > " + `length_margin`) +aGroup.Add(anIds) + +salome.sg.updateObjBrowser(1) diff --git a/doc/salome/examples/quality_controls_ex04.py b/doc/salome/examples/quality_controls_ex04.py new file mode 100644 index 000000000..d26eb4d82 --- /dev/null +++ b/doc/salome/examples/quality_controls_ex04.py @@ -0,0 +1,39 @@ +# Free Edges + +import SMESH_mechanic + +smesh = SMESH_mechanic.smesh +mesh = SMESH_mechanic.mesh +salome = SMESH_mechanic.salome + +aFilterMgr = smesh.CreateFilterManager() + +# Remove some elements to obtain free edges +# Criterion : AREA > 95. +area_margin = 95. + +aFilter = smesh.GetFilter(smesh.FACE, smesh.FT_Area, smesh.FT_MoreThan, area_margin) + +anIds = mesh.GetIdsFromFilter(aFilter) + +mesh.RemoveElements(anIds) + +# Criterion : Free Edges +aBorders = mesh.GetFreeBorders() + +# create groups +aGroupF = mesh.CreateEmptyGroup(smesh.FACE, "Faces with free edges") +aGroupN = mesh.CreateEmptyGroup(smesh.NODE, "Nodes on free edges") + +# fill groups with elements, corresponding to the criterion +print "" +print "Criterion: Free edges Nb = ", len(aBorders) +for i in range(len(aBorders)): + aBorder = aBorders[i] + print "Face # ", aBorder.myElemId, " : Edge between nodes (", + print aBorder.myPnt1, ", ", aBorder.myPnt2, ")" + + aGroupF.Add([aBorder.myElemId]) + aGroupN.Add([aBorder.myPnt1, aBorder.myPnt2]) + +salome.sg.updateObjBrowser(1) diff --git a/doc/salome/examples/quality_controls_ex05.py b/doc/salome/examples/quality_controls_ex05.py new file mode 100644 index 000000000..90c7c0451 --- /dev/null +++ b/doc/salome/examples/quality_controls_ex05.py @@ -0,0 +1,48 @@ +# Free Nodes + +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) diff --git a/doc/salome/examples/quality_controls_ex06.py b/doc/salome/examples/quality_controls_ex06.py new file mode 100644 index 000000000..2fe67abf6 --- /dev/null +++ b/doc/salome/examples/quality_controls_ex06.py @@ -0,0 +1,73 @@ +# Free Faces + +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 + +Mesh_1 = smesh.Mesh(Partition_1) +Regular_1D = Mesh_1.Segment() +Max_Size_1 = Regular_1D.MaxSize(34.641) +MEFISTO_2D = Mesh_1.Triangle() +Tetrahedronn = Mesh_1.Tetrahedron() +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 faces Nb = ", len(aFaceIds) +j = 1 +for i in range(len(aFaceIds)): + if j > 20: j = 1; print "" + print aFaceIds[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) diff --git a/doc/salome/examples/quality_controls_ex07.py b/doc/salome/examples/quality_controls_ex07.py new file mode 100644 index 000000000..a2be02932 --- /dev/null +++ b/doc/salome/examples/quality_controls_ex07.py @@ -0,0 +1,19 @@ +# Bare border faces + +from smesh import * +SetCurrentStudy(salome.myStudy) + +box = geompy.MakeBoxDXDYDZ(100, 100, 100) +geompy.addToStudy( box, "box" ) + +mesh = smesh.Mesh(box) +mesh.Segment().NumberOfSegments(3) +mesh.Quadrangle() +mesh.Compute() + +# remove 2 faces +allFaces = mesh.GetElementsByType(FACE) +mesh.RemoveElements( allFaces[0:2]) + +bareGroup = mesh.MakeGroup("bare faces", FACE, FT_BareBorderFace) +assert(bareGroup.Size() == 3) diff --git a/doc/salome/examples/quality_controls_ex08.py b/doc/salome/examples/quality_controls_ex08.py new file mode 100644 index 000000000..77e7e4c94 --- /dev/null +++ b/doc/salome/examples/quality_controls_ex08.py @@ -0,0 +1,23 @@ +# Bare border volumes + +from smesh import * +SetCurrentStudy(salome.myStudy) + +box = geompy.MakeBoxDXDYDZ(100, 30, 10) +# the smallest face of the box +face = geompy.SubShapeAllSorted( box, geompy.ShapeType["FACE"])[0] + +geompy.addToStudy( box, "box" ) +geompy.addToStudyInFather( box, face, "face" ) + +mesh = Mesh(box) +mesh.AutomaticHexahedralization(); + +# remove half of mesh faces from the smallest face +faceFaces = mesh.GetSubMeshElementsId(face) +faceToRemove = faceFaces[: len(faceFaces)/2] +mesh.RemoveElements( faceToRemove ) + +# make a group of volumes missing the removed faces +bareGroup = mesh.MakeGroup("bare volumes", VOLUME, FT_BareBorderVolume) +assert(bareGroup.Size() == len( faceToRemove)) diff --git a/doc/salome/examples/quality_controls_ex09.py b/doc/salome/examples/quality_controls_ex09.py new file mode 100644 index 000000000..c4ca44e80 --- /dev/null +++ b/doc/salome/examples/quality_controls_ex09.py @@ -0,0 +1,17 @@ +# Over-constrained faces + +from smesh import * +SetCurrentStudy(salome.myStudy) + +mesh = Mesh() +faceFilter = GetFilter(FACE,FT_OverConstrainedFace) + +#make an edge +n1 = mesh.AddNode(0,0,0) +n2 = mesh.AddNode(10,0,0) +edge = mesh.AddEdge([n1,n2]) +assert( not mesh.GetIdsFromFilter( faceFilter )) + +# make faces +mesh.ExtrusionSweep([edge], MakeDirStruct(0,7,0), 5) +assert( 2 == len( mesh.GetIdsFromFilter( faceFilter ))) diff --git a/doc/salome/examples/quality_controls_ex10.py b/doc/salome/examples/quality_controls_ex10.py new file mode 100644 index 000000000..49ef2e72a --- /dev/null +++ b/doc/salome/examples/quality_controls_ex10.py @@ -0,0 +1,15 @@ +# Over-constrained volumes + +from smesh import * +SetCurrentStudy(salome.myStudy) + +mesh = Mesh() +volumeFilter = GetFilter(VOLUME,FT_OverConstrainedVolume) + +# make volumes by extrusion of one face +n1 = mesh.AddNode(0,0,0) +n2 = mesh.AddNode(10,0,0) +edge = mesh.AddEdge([n1,n2]) +mesh.ExtrusionSweep([edge], MakeDirStruct(0,7,0), 1) +mesh.ExtrusionSweep( mesh.GetElementsByType(FACE), MakeDirStruct(0,0,5), 7) +assert( 2 == len( mesh.GetIdsFromFilter( volumeFilter ))) diff --git a/doc/salome/examples/quality_controls_ex11.py b/doc/salome/examples/quality_controls_ex11.py new file mode 100644 index 000000000..ca955b6ab --- /dev/null +++ b/doc/salome/examples/quality_controls_ex11.py @@ -0,0 +1,44 @@ +# Length 2D + +import salome +import geompy + +import smesh + +# create open shell: a box without one plane +box = geompy.MakeBox(0., 0., 0., 20., 20., 15.) +FaceList = geompy.SubShapeAll(box, geompy.ShapeType["FACE"]) +FaceList.remove(FaceList[5]) +box = geompy.MakeShell(FaceList) +idbox = geompy.addToStudy(box, "box") + +# create a mesh +mesh = smesh.Mesh(box, "Mesh_Length_2D") +algo = mesh.Segment() +algo.NumberOfSegments(5) +algo = mesh.Triangle() +algo.MaxElementArea(20.) +mesh.Compute() + +# Criterion : Length 2D > 5.7 +length_margin = 5.7 + +aFilter = smesh.GetFilter(smesh.FACE, smesh.FT_Length2D, smesh.FT_MoreThan, length_margin) + +anIds = mesh.GetIdsFromFilter(aFilter) + +# print the result +print "Criterion: Edges length 2D > ", length_margin, " Nb = ", len(anIds) +j = 1 +for i in range(len(anIds)): + if j > 20: j = 1; print "" + print anIds[i], + j = j + 1 + pass +print "" + +# create a group +aGroup = mesh.CreateEmptyGroup(smesh.FACE, "Faces with length 2D > " + `length_margin`) +aGroup.Add(anIds) + +salome.sg.updateObjBrowser(1) diff --git a/doc/salome/examples/quality_controls_ex12.py b/doc/salome/examples/quality_controls_ex12.py new file mode 100644 index 000000000..28a0192c5 --- /dev/null +++ b/doc/salome/examples/quality_controls_ex12.py @@ -0,0 +1,44 @@ +# Borders at Multiconnection 2D + +import salome +import geompy + +import smesh + +# create a compound of two glued boxes +box1 = geompy.MakeBox(0., 0., 0., 20., 20., 15.) +box2 = geompy.MakeTranslation(box1, 0., 20., 0) +comp = geompy.MakeCompound([box1, box2]) +box = geompy.MakeGlueFaces(comp, 0.000001) +idbox = geompy.addToStudy(box, "box") + +# create a mesh +mesh = smesh.Mesh(box, "Box compound : 2D triangle mesh") +algo = mesh.Segment() +algo.NumberOfSegments(5) +algo = mesh.Triangle() +algo.MaxElementArea(20.) +mesh.Compute() + +# Criterion : MULTI-CONNECTION 2D = 3 +nb_conn = 3 + +aFilter = smesh.GetFilter(smesh.FACE, smesh.FT_MultiConnection2D, smesh.FT_EqualTo, nb_conn) + +anIds = mesh.GetIdsFromFilter(aFilter) + +# print the result +print "Criterion: Borders at multi-connection 2D = ", nb_conn, " Nb = ", len(anIds) +j = 1 +for i in range(len(anIds)): + if j > 20: j = 1; print "" + print anIds[i], + j = j + 1 + pass +print "" + +# create a group +aGroup = mesh.CreateEmptyGroup(smesh.FACE, "Borders at multi-connection 2D = " + `nb_conn`) +aGroup.Add(anIds) + +salome.sg.updateObjBrowser(1) diff --git a/doc/salome/examples/quality_controls_ex13.py b/doc/salome/examples/quality_controls_ex13.py new file mode 100644 index 000000000..1673fc737 --- /dev/null +++ b/doc/salome/examples/quality_controls_ex13.py @@ -0,0 +1,30 @@ +# Area + +import SMESH_mechanic + +smesh = SMESH_mechanic.smesh +mesh = SMESH_mechanic.mesh +salome = SMESH_mechanic.salome + +# Criterion : AREA > 100. +area_margin = 100. + +aFilter = smesh.GetFilter(smesh.FACE, smesh.FT_Area, smesh.FT_MoreThan, area_margin) + +anIds = mesh.GetIdsFromFilter(aFilter) + +# print the result +print "Criterion: Area > ", area_margin, " Nb = ", len(anIds) +j = 1 +for i in range(len(anIds)): + if j > 20: j = 1; print "" + print anIds[i], + j = j + 1 + pass +print "" + +# create a group +aGroup = mesh.CreateEmptyGroup(smesh.FACE, "Area > " + `area_margin`) +aGroup.Add(anIds) + +salome.sg.updateObjBrowser(1) diff --git a/doc/salome/examples/quality_controls_ex14.py b/doc/salome/examples/quality_controls_ex14.py new file mode 100644 index 000000000..379affdbd --- /dev/null +++ b/doc/salome/examples/quality_controls_ex14.py @@ -0,0 +1,30 @@ +# Taper + +import SMESH_mechanic + +smesh = SMESH_mechanic.smesh +mesh = SMESH_mechanic.mesh +salome = SMESH_mechanic.salome + +# Criterion : Taper > 3e-20 +taper_margin = 3e-20 + +aFilter = smesh.GetFilter(smesh.FACE, smesh.FT_Taper, smesh.FT_MoreThan, taper_margin) + +anIds = mesh.GetIdsFromFilter(aFilter) + +# print the result +print "Criterion: Taper > ", taper_margin, " Nb = ", len(anIds) +j = 1 +for i in range(len(anIds)): + if j > 20: j = 1; print "" + print anIds[i], + j = j + 1 + pass +print "" + +# create a group +aGroup = mesh.CreateEmptyGroup(smesh.FACE, "Taper > " + `taper_margin`) +aGroup.Add(anIds) + +salome.sg.updateObjBrowser(1) diff --git a/doc/salome/examples/quality_controls_ex15.py b/doc/salome/examples/quality_controls_ex15.py new file mode 100644 index 000000000..5ca56db0b --- /dev/null +++ b/doc/salome/examples/quality_controls_ex15.py @@ -0,0 +1,30 @@ +# Aspect Ratio + +import SMESH_mechanic + +smesh = SMESH_mechanic.smesh +mesh = SMESH_mechanic.mesh +salome = SMESH_mechanic.salome + +# Criterion : ASPECT RATIO > 1.8 +ar_margin = 1.8 + +aFilter = smesh.GetFilter(smesh.FACE, smesh.FT_AspectRatio, smesh.FT_MoreThan, ar_margin) + +anIds = mesh.GetIdsFromFilter(aFilter) + +# print the result +print "Criterion: Aspect Ratio > ", ar_margin, " Nb = ", len(anIds) +j = 1 +for i in range(len(anIds)): + if j > 20: j = 1; print "" + print anIds[i], + j = j + 1 + pass +print "" + +# create a group +aGroup = mesh.CreateEmptyGroup(smesh.FACE, "Aspect Ratio > " + `ar_margin`) +aGroup.Add(anIds) + +salome.sg.updateObjBrowser(1) diff --git a/doc/salome/examples/quality_controls_ex16.py b/doc/salome/examples/quality_controls_ex16.py new file mode 100644 index 000000000..a20f38f7b --- /dev/null +++ b/doc/salome/examples/quality_controls_ex16.py @@ -0,0 +1,31 @@ +# Minimum Angle + +import SMESH_mechanic + +smesh = SMESH_mechanic.smesh +mesh = SMESH_mechanic.mesh +salome = SMESH_mechanic.salome + +# Criterion : MINIMUM ANGLE < 35. +min_angle = 35. + +aFilter = smesh.GetFilter(smesh.FACE, smesh.FT_MinimumAngle, smesh.FT_LessThan, min_angle) + +anIds = mesh.GetIdsFromFilter(aFilter) + +# print the result +print "Criterion: Minimum Angle < ", min_angle, " Nb = ", len(anIds) +j = 1 +for i in range(len(anIds)): + if j > 20: j = 1; print "" + print anIds[i], + j = j + 1 + pass +print "" + +# create a group +aGroup = mesh.CreateEmptyGroup(smesh.FACE, "Minimum Angle < " + `min_angle`) + +aGroup.Add(anIds) + +salome.sg.updateObjBrowser(1) diff --git a/doc/salome/examples/quality_controls_ex17.py b/doc/salome/examples/quality_controls_ex17.py new file mode 100644 index 000000000..fcc596c75 --- /dev/null +++ b/doc/salome/examples/quality_controls_ex17.py @@ -0,0 +1,31 @@ +# Warping + +import SMESH_mechanic + +smesh = SMESH_mechanic.smesh +mesh = SMESH_mechanic.mesh +salome = SMESH_mechanic.salome + +# Criterion : WARP ANGLE > 1e-15 +wa_margin = 1e-15 + +aFilter = smesh.GetFilter(smesh.FACE, smesh.FT_Warping, smesh.FT_MoreThan, wa_margin) + +anIds = mesh.GetIdsFromFilter(aFilter) + +# print the result +print "Criterion: Warp > ", wa_margin, " Nb = ", len(anIds) +j = 1 +for i in range(len(anIds)): + if j > 20: j = 1; print "" + print anIds[i], + j = j + 1 + pass +print "" + +# create a group +aGroup = mesh.CreateEmptyGroup(smesh.FACE, "Warp > " + `wa_margin`) + +aGroup.Add(anIds) + +salome.sg.updateObjBrowser(1) diff --git a/doc/salome/examples/quality_controls_ex18.py b/doc/salome/examples/quality_controls_ex18.py new file mode 100644 index 000000000..42e4b30e8 --- /dev/null +++ b/doc/salome/examples/quality_controls_ex18.py @@ -0,0 +1,30 @@ +# Skew + +import SMESH_mechanic + +smesh = SMESH_mechanic.smesh +mesh = SMESH_mechanic.mesh +salome = SMESH_mechanic.salome + +# Criterion : Skew > 38. +skew_margin = 38. + +aFilter = smesh.GetFilter(smesh.FACE, smesh.FT_Skew, smesh.FT_MoreThan, skew_margin) + +anIds = mesh.GetIdsFromFilter(aFilter) + +# print the result +print "Criterion: Skew > ", skew_margin, " Nb = ", len(anIds) +j = 1 +for i in range(len(anIds)): + if j > 20: j = 1; print "" + print anIds[i], + j = j + 1 + pass +print "" + +# create a group +aGroup = mesh.CreateEmptyGroup(smesh.FACE, "Skew > " + `skew_margin`) +aGroup.Add(anIds) + +salome.sg.updateObjBrowser(1) diff --git a/doc/salome/examples/quality_controls_ex19.py b/doc/salome/examples/quality_controls_ex19.py new file mode 100644 index 000000000..abe195200 --- /dev/null +++ b/doc/salome/examples/quality_controls_ex19.py @@ -0,0 +1,30 @@ +# Element Diameter 2D + +import SMESH_mechanic + +smesh = SMESH_mechanic.smesh +mesh = SMESH_mechanic.mesh +salome = SMESH_mechanic.salome + +# Criterion : ELEMENT DIAMETER 2D > 10 +mel_2d_margin = 10 + +aFilter = smesh.GetFilter(smesh.FACE, smesh.FT_MaxElementLength2D, smesh.FT_MoreThan, mel_2d_margin) + +anIds = mesh.GetIdsFromFilter(aFilter) + +# print the result +print "Criterion: Element Diameter 2D Ratio > ", mel_2d_margin, " Nb = ", len(anIds) +j = 1 +for i in range(len(anIds)): + if j > 20: j = 1; print "" + print anIds[i], + j = j + 1 + pass +print "" + +# create a group +aGroup = mesh.CreateEmptyGroup(smesh.FACE, "Element Diameter 2D > " + `mel_2d_margin`) +aGroup.Add(anIds) + +salome.sg.updateObjBrowser(1) diff --git a/doc/salome/examples/quality_controls_ex20.py b/doc/salome/examples/quality_controls_ex20.py new file mode 100644 index 000000000..9e332e0dc --- /dev/null +++ b/doc/salome/examples/quality_controls_ex20.py @@ -0,0 +1,31 @@ +# Aspect Ratio 3D + +import SMESH_mechanic_tetra + +smesh = SMESH_mechanic_tetra.smesh +mesh = SMESH_mechanic_tetra.mesh +salome = SMESH_mechanic_tetra.salome + +# Criterion : ASPECT RATIO 3D > 4.5 +ar_margin = 4.5 + +aFilter = smesh.GetFilter(smesh.VOLUME, smesh.FT_AspectRatio3D, smesh.FT_MoreThan, ar_margin) + +anIds = mesh.GetIdsFromFilter(aFilter) + +# print the result +print "Criterion: Aspect Ratio 3D > ", ar_margin, " Nb = ", len(anIds) +j = 1 +for i in range(len(anIds)): + if j > 20: j = 1; print "" + print anIds[i], + j = j + 1 + pass +print "" + +# create a group +aGroup = mesh.CreateEmptyGroup(smesh.VOLUME, "Aspect Ratio 3D > " + `ar_margin`) + +aGroup.Add(anIds) + +salome.sg.updateObjBrowser(1) diff --git a/doc/salome/examples/quality_controls_ex21.py b/doc/salome/examples/quality_controls_ex21.py new file mode 100644 index 000000000..833ffff81 --- /dev/null +++ b/doc/salome/examples/quality_controls_ex21.py @@ -0,0 +1,32 @@ +# Volume + +import SMESH_mechanic_tetra + +smesh = SMESH_mechanic_tetra.smesh +mesh = SMESH_mechanic_tetra.mesh +salome = SMESH_mechanic_tetra.salome + +# Criterion : VOLUME < 7. +volume_margin = 7. + +aFilter = smesh.GetFilter(smesh.VOLUME, smesh.FT_Volume3D, smesh.FT_LessThan, volume_margin) + +anIds = mesh.GetIdsFromFilter(aFilter) + +# print the result +print "" +print "Criterion: Volume < ", volume_margin, " Nb = ", len(anIds) +j = 1 +for i in range(len(anIds)): + if j > 20: j = 1; print "" + print anIds[i], + j = j + 1 + pass +print "" + +# create a group +aGroup = mesh.CreateEmptyGroup(smesh.VOLUME, "Volume < " + `volume_margin`) + +aGroup.Add(anIds) + +salome.sg.updateObjBrowser(1) diff --git a/doc/salome/examples/quality_controls_ex22.py b/doc/salome/examples/quality_controls_ex22.py new file mode 100644 index 000000000..5264b1ade --- /dev/null +++ b/doc/salome/examples/quality_controls_ex22.py @@ -0,0 +1,30 @@ +# Element Diameter 3D + +import SMESH_mechanic_tetra + +smesh = SMESH_mechanic_tetra.smesh +mesh = SMESH_mechanic_tetra.mesh +salome = SMESH_mechanic_tetra.salome + +# Criterion : ELEMENT DIAMETER 3D > 10 +mel_3d_margin = 10 + +aFilter = smesh.GetFilter(smesh.FACE, smesh.FT_MaxElementLength3D, smesh.FT_MoreThan, mel_3d_margin) + +anIds = mesh.GetIdsFromFilter(aFilter) + +# print the result +print "Criterion: Element Diameter 3D Ratio > ", mel_3d_margin, " Nb = ", len(anIds) +j = 1 +for i in range(len(anIds)): + if j > 20: j = 1; print "" + print anIds[i], + j = j + 1 + pass +print "" + +# create a group +aGroup = mesh.CreateEmptyGroup(smesh.FACE, "Element Diameter 3D > " + `mel_3d_margin`) +aGroup.Add(anIds) + +salome.sg.updateObjBrowser(1) diff --git a/doc/salome/examples/testme.py b/doc/salome/examples/testme.py new file mode 100755 index 000000000..b1328b596 --- /dev/null +++ b/doc/salome/examples/testme.py @@ -0,0 +1,28 @@ +#!/usr/bin/env python + +import unittest, sys + +class SalomeSession(object): + def __init__(self, script): + import runSalome + sys.argv = ["runSalome.py"] + sys.argv += ["--terminal"] + sys.argv += ["--modules=GEOM,MED,SMESH"] + sys.argv += ["--execute=%s" % script] + clt, d = runSalome.main() + self.port = d['port'] + return + + def __del__(self): + port = self.port + import killSalomeWithPort + killSalomeWithPort.killMyPort(port) + return + pass + +class MyTest(unittest.TestCase): + def testFunction(self): + SalomeSession(sys.argv[1]) + pass + +unittest.main(argv=sys.argv[:1]) diff --git a/doc/salome/examples/transforming_meshes_ex01.py b/doc/salome/examples/transforming_meshes_ex01.py new file mode 100644 index 000000000..0ea75cc85 --- /dev/null +++ b/doc/salome/examples/transforming_meshes_ex01.py @@ -0,0 +1,15 @@ +# Translation + +import SMESH_mechanic + +smesh = SMESH_mechanic.smesh +mesh = SMESH_mechanic.mesh + +# define translation vector +point = smesh.PointStruct(-150., -150., 0.) +vector =smesh.DirStruct(point) + +# translate a mesh +doCopy = 1 + +mesh.Translate([], vector, doCopy) diff --git a/doc/salome/examples/transforming_meshes_ex02.py b/doc/salome/examples/transforming_meshes_ex02.py new file mode 100644 index 000000000..f96a6bb41 --- /dev/null +++ b/doc/salome/examples/transforming_meshes_ex02.py @@ -0,0 +1,15 @@ +# Rotation + +import math + +import SMESH_mechanic + +smesh = SMESH_mechanic.smesh +mesh = SMESH_mechanic.mesh + +# define rotation axis and angle +axisXYZ = smesh.AxisStruct(0., 0., 0., 5., 5., 20.) +angle270 = 1.5 * math.pi + +# rotate a mesh +mesh.Rotate([], axisXYZ, angle270, 1) diff --git a/doc/salome/examples/transforming_meshes_ex03.py b/doc/salome/examples/transforming_meshes_ex03.py new file mode 100644 index 000000000..da8105a67 --- /dev/null +++ b/doc/salome/examples/transforming_meshes_ex03.py @@ -0,0 +1,26 @@ +# Scale + +import geompy +Box = geompy.MakeBoxDXDYDZ(200, 200, 200) +f = geompy.SubShapeAllSorted(Box, geompy.ShapeType["FACE"]) + +import smesh,SMESH +import StdMeshers +Mesh1 = smesh.Mesh(f[0]) +Regular_1D = Mesh1.Segment() +Nb_Segments_1 = Regular_1D.NumberOfSegments(3) +Nb_Segments_1.SetDistrType( 0 ) +Quadrangle_2D = Mesh1.Quadrangle() +isDone = Mesh1.Compute() + +#Perform scale opration for the whole mesh and creation of a new mesh +newMesh = Mesh1.ScaleMakeMesh(Mesh1,SMESH.PointStruct(100,100,200),[0.5,0.3,0.7],True,"ScaledMesh") + +#Perform scale operation for the whole mesh and copy elements +Mesh1.Scale(Mesh1,SMESH.PointStruct(200,100,100),[0.5,0.5,0.5],True,True) + +#Perform scale opration for two edges and move elements +Mesh1.Scale([1,2],SMESH.PointStruct(-100,100,100),[0.8,1.0,0.7],False) + +#Perform scale opration for one face and move elements +Mesh1.Scale([21],SMESH.PointStruct(0,200,200),[0.7,0.7,0.7],False) diff --git a/doc/salome/examples/transforming_meshes_ex04.py b/doc/salome/examples/transforming_meshes_ex04.py new file mode 100644 index 000000000..ea7c72f54 --- /dev/null +++ b/doc/salome/examples/transforming_meshes_ex04.py @@ -0,0 +1,13 @@ +# Symmetry + +import math + +import SMESH_mechanic + +smesh = SMESH_mechanic.smesh +mesh = SMESH_mechanic.mesh + +# create a symmetrical copy of the mesh mirrored through a point +axis = SMESH.AxisStruct(0, 0, 0, 0, 0, 0) + +mesh.Mirror([], axis, smesh.POINT, 1) diff --git a/doc/salome/examples/transforming_meshes_ex05.py b/doc/salome/examples/transforming_meshes_ex05.py new file mode 100644 index 000000000..f99d50b6a --- /dev/null +++ b/doc/salome/examples/transforming_meshes_ex05.py @@ -0,0 +1,10 @@ +# Merging Nodes + +import SMESH_mechanic +mesh = SMESH_mechanic.mesh + +# merge nodes +Tolerance = 25.0 + +GroupsOfNodes = mesh.FindCoincidentNodes(Tolerance) +mesh.MergeNodes(GroupsOfNodes) diff --git a/doc/salome/examples/transforming_meshes_ex06.py b/doc/salome/examples/transforming_meshes_ex06.py new file mode 100644 index 000000000..fe8c91db3 --- /dev/null +++ b/doc/salome/examples/transforming_meshes_ex06.py @@ -0,0 +1,73 @@ +# Merging Elements + +import salome +import geompy +import smesh + +# create a face to be meshed +px = geompy.MakeVertex(100., 0. , 0. ) +py = geompy.MakeVertex(0. , 100., 0. ) +pz = geompy.MakeVertex(0. , 0. , 100.) + +vxy = geompy.MakeVector(px, py) +arc = geompy.MakeArc(py, pz, px) + +wire = geompy.MakeWire([vxy, arc]) +isPlanarFace = 1 + +face1 = geompy.MakeFace(wire, isPlanarFace) +id_face1 = geompy.addToStudy(face1, "Face1") + +# create a circle to be an extrusion path +px1 = geompy.MakeVertex( 100., 100., 0.) +py1 = geompy.MakeVertex(-100., -100., 0.) +pz1 = geompy.MakeVertex( 0., 0., 50.) + +circle = geompy.MakeCircleThreePnt(py1, pz1, px1) +id_circle = geompy.addToStudy(circle, "Path") + +# create a 2D mesh on the face +trias = smesh.Mesh(face1, "Face : 2D mesh") + +algo1D = trias.Segment() +algo1D.NumberOfSegments(6) +algo2D = trias.Triangle() +algo2D.LengthFromEdges() + +trias.Compute() + +# create a path mesh +circlemesh = smesh.Mesh(circle, "Path mesh") +algo = circlemesh.Segment() +algo.NumberOfSegments(10) +circlemesh.Compute() + +# extrusion of the mesh +trias.ExtrusionAlongPath([], circlemesh, circle, + 1, 0, [], 0, smesh.PointStruct(0, 0, 0)) + +# merge nodes +print "Number of nodes before MergeNodes:", +trias.NbNodes() +tolerance = 0.001 +array_of_nodes_groups = trias.FindCoincidentNodes(tolerance) + +trias.MergeNodes(array_of_nodes_groups) + +print "Number of nodes after MergeNodes:", trias.NbNodes() +print "" +print "Number of elements before MergeEqualElements:" +print "Edges : ", trias.NbEdges() +print "Triangles : ", trias.NbTriangles() +print "Quadrangles: ", trias.NbQuadrangles() +print "Volumes : ", trias.NbVolumes() + +# merge elements +trias.MergeEqualElements() +print "Number of elements after MergeEqualElements:" +print "Edges : ", trias.NbEdges() +print "Triangles : ", trias.NbTriangles() +print "Quadrangles: ", trias.NbQuadrangles() +print "Volumes : ", trias.NbVolumes() + +salome.sg.updateObjBrowser(1) diff --git a/doc/salome/examples/transforming_meshes_ex07.py b/doc/salome/examples/transforming_meshes_ex07.py new file mode 100644 index 000000000..bb42d33eb --- /dev/null +++ b/doc/salome/examples/transforming_meshes_ex07.py @@ -0,0 +1,38 @@ +# Sew Meshes Border to Side + +import geompy +import smesh + +# create two faces of a box +box1 = geompy.MakeBox(0., 0., -10., 30., 20., 25.) +facesList1 = geompy.SubShapeAll(box1, geompy.ShapeType["FACE"]) +face1 = facesList1[2] + +box2 = geompy.MakeBox(0., 5., 0., 20., 20., 15.) +facesList2 = geompy.SubShapeAll(box2, geompy.ShapeType["FACE"]) +face2 = facesList2[1] + +edgesList = geompy.SubShapeAll(face2, geompy.ShapeType["EDGE"]) +edge1 = edgesList[2] + +aComp = geompy.MakeCompound([face1, face2]) +geompy.addToStudy(aComp, "Two faces") + +# create a mesh on two faces +mesh = smesh.Mesh(aComp, "Two faces : quadrangle mesh") + +algo1D = mesh.Segment() +algo1D.NumberOfSegments(9) +algo2D = mesh.Quadrangle() + +algo_local = mesh.Segment(edge1) +algo_local.Arithmetic1D(1, 4) +algo_local.Propagation() + +mesh.Compute() + +# sew border to side +# FirstNodeIDOnFreeBorder, SecondNodeIDOnFreeBorder, LastNodeIDOnFreeBorder, +# FirstNodeIDOnSide, LastNodeIDOnSide, +# CreatePolygons, CreatePolyedrs +mesh.SewBorderToSide(5, 45, 6, 113, 109, 0, 0) diff --git a/doc/salome/examples/transforming_meshes_ex08.py b/doc/salome/examples/transforming_meshes_ex08.py new file mode 100644 index 000000000..e028735a0 --- /dev/null +++ b/doc/salome/examples/transforming_meshes_ex08.py @@ -0,0 +1,36 @@ +# Sew Conform Free Borders + +import geompy +import smesh + +# create two faces of the box +box1 = geompy.MakeBox(0., 0., -10., 20., 20., 15.) +facesList1 = geompy.SubShapeAll(box1, geompy.ShapeType["FACE"]) +face1 = facesList1[2] + +box2 = geompy.MakeBox(0., 5., 0., 20., 20., 15.) +facesList2 = geompy.SubShapeAll(box2, geompy.ShapeType["FACE"]) +face2 = facesList2[1] + +edgesList = geompy.SubShapeAll(face2, geompy.ShapeType["EDGE"]) +edge1 = edgesList[2] + +aComp = geompy.MakeCompound([face1, face2]) +geompy.addToStudy(aComp, "Two faces") + +# create a mesh on two faces +mesh = smesh.Mesh(aComp, "Two faces : quadrangle mesh") + +algo1D = mesh.Segment() +algo1D.NumberOfSegments(9) +algo2D = mesh.Quadrangle() + +algo_local = mesh.Segment(edge1) +algo_local.Arithmetic1D(1, 4) +algo_local.Propagation() + +mesh.Compute() + +# sew conform free borders +# FirstNodeID1, SecondNodeID1, LastNodeID1, FirstNodeID2, SecondNodeID2 +mesh.SewConformFreeBorders(5, 45, 6, 3, 24) diff --git a/doc/salome/examples/transforming_meshes_ex09.py b/doc/salome/examples/transforming_meshes_ex09.py new file mode 100644 index 000000000..5f92fd1ad --- /dev/null +++ b/doc/salome/examples/transforming_meshes_ex09.py @@ -0,0 +1,37 @@ +# Sew Free Borders + +import geompy +import smesh + +# create two faces of the box +box1 = geompy.MakeBox(0., 0., 0., 20., 20., 15.) +facesList1 = geompy.SubShapeAll(box1, geompy.ShapeType["FACE"]) +face1 = facesList1[2] + +box2 = geompy.MakeBox(0., 5., 0., 20., 20., 15.) +facesList2 = geompy.SubShapeAll(box2, geompy.ShapeType["FACE"]) +face2 = facesList2[1] + +edgesList = geompy.SubShapeAll(face2, geompy.ShapeType["EDGE"]) +edge1 = edgesList[2] + +aComp = geompy.MakeCompound([face1, face2]) +geompy.addToStudy(aComp, "Two faces") + +# create a mesh on two faces +mesh = smesh.Mesh(aComp, "Two faces : quadrangle mesh") + +algo1D = mesh.Segment() +algo1D.NumberOfSegments(4) +algo2D = mesh.Quadrangle() + +algo_local = mesh.Segment(edge1) +algo_local.Arithmetic1D(1, 4) +algo_local.Propagation() + +mesh.Compute() + +# sew free borders +# FirstNodeID1, SecondNodeID1, LastNodeID1, +# FirstNodeID2, SecondNodeID2, LastNodeID2, CreatePolygons, CreatePolyedrs +mesh.SewFreeBorders(6, 21, 5, 1, 12, 3, 0, 0) diff --git a/doc/salome/examples/transforming_meshes_ex10.py b/doc/salome/examples/transforming_meshes_ex10.py new file mode 100644 index 000000000..c54aca660 --- /dev/null +++ b/doc/salome/examples/transforming_meshes_ex10.py @@ -0,0 +1,31 @@ +# Sew Side Elements + +import geompy +import smesh + +# create two boxes +box1 = geompy.MakeBox(0., 0., 0., 10., 10., 10.) +box2 = geompy.MakeBox(0., 15., 0., 20., 25., 10.) + +EdgesList = geompy.SubShapeAll(box2, geompy.ShapeType["EDGE"]) + +aComp = geompy.MakeCompound([box1, box2]) +geompy.addToStudy(aComp, "Two boxes") + +# create a mesh on two boxes +mesh = smesh.Mesh(aComp, "Two faces : quadrangle mesh") + +algo1D = mesh.Segment() +algo1D.NumberOfSegments(2) +algo2D = mesh.Quadrangle() + +algo_local = mesh.Segment(EdgesList[8]) +algo_local.NumberOfSegments(4) +algo_local.Propagation() + +mesh.Compute() + +# sew side elements +# IDsOfSide1Elements, IDsOfSide2Elements, +# NodeID1OfSide1ToMerge, NodeID1OfSide2ToMerge, NodeID2OfSide1ToMerge, NodeID2OfSide2ToMerge +mesh.SewSideElements([69, 70, 71, 72], [91, 92, 89, 90], 8, 38, 23, 58) diff --git a/doc/salome/examples/transforming_meshes_ex11.py b/doc/salome/examples/transforming_meshes_ex11.py new file mode 100644 index 000000000..55fbe8f28 --- /dev/null +++ b/doc/salome/examples/transforming_meshes_ex11.py @@ -0,0 +1,66 @@ +# Duplicate nodes + +import salome +import smesh +import SMESH_test1 + +mesh = SMESH_test1.mesh + +# Compute mesh +mesh.Compute() + +# Without the duplication of border elements + +# Nodes to duplicate +nodes1 = mesh.CreateEmptyGroup( smesh.NODE, 'nodes1' ) +nodes1.Add( [ 289, 278, 302, 285 ] ) + +# Group of faces to replace nodes with new ones +faces1 = mesh.CreateEmptyGroup( smesh.FACE, 'faces1' ) +faces1.Add( [ 519, 556, 557 ] ) + +# Duplicate nodes +print "\nMesh before the first nodes duplication:" +print "Nodes : ", mesh.NbNodes() +print "Edges : ", mesh.NbEdges() +print "Triangles : ", mesh.NbTriangles() + +groupOfCreatedNodes = mesh.DoubleNodeGroup(nodes1, faces1, theMakeGroup=True) +print "New nodes:", groupOfCreatedNodes.GetIDs() + +print "\nMesh after the first nodes duplication:" +print "Nodes : ", mesh.NbNodes() +print "Edges : ", mesh.NbEdges() +print "Triangles : ", mesh.NbTriangles() + +# With the duplication of border elements + +# Edges to duplicate +edges = mesh.CreateEmptyGroup( smesh.EDGE, 'edges' ) +edges.Add( [ 29, 30, 31 ] ) + +# Nodes not to duplicate +nodes2 = mesh.CreateEmptyGroup( smesh.NODE, 'nodes2' ) +nodes2.Add( [ 32, 5 ] ) + +# Group of faces to replace nodes with new ones +faces2 = mesh.CreateEmptyGroup( smesh.FACE, 'faces2' ) +faces2.Add( [ 576, 578, 580 ] ) + +# Duplicate nodes +print "\nMesh before the second nodes duplication:" +print "Nodes : ", mesh.NbNodes() +print "Edges : ", mesh.NbEdges() +print "Triangles : ", mesh.NbTriangles() + +groupOfNewEdges = mesh.DoubleNodeElemGroup( edges, nodes2, faces2, theMakeGroup=True ) +print "New edges:", groupOfNewEdges.GetIDs() + +print "\nMesh after the second nodes duplication:" +print "Nodes : ", mesh.NbNodes() +print "Edges : ", mesh.NbEdges() +print "Triangles : ", mesh.NbTriangles() + +# Update object browser +if salome.sg.hasDesktop(): + salome.sg.updateObjBrowser(0) diff --git a/doc/salome/examples/transforming_meshes_ex12.py b/doc/salome/examples/transforming_meshes_ex12.py new file mode 100644 index 000000000..0380cc363 --- /dev/null +++ b/doc/salome/examples/transforming_meshes_ex12.py @@ -0,0 +1,108 @@ +# Create boundary elements + +from smesh import * +SetCurrentStudy(salome.myStudy) + +box = geompy.MakeBoxDXDYDZ(100, 100, 100) +gFaces = geompy.SubShapeAllSorted(box, geompy.ShapeType["FACE"]) +f1,f2 = gFaces[0],gFaces[1] +geompy.addToStudy(box,"box") +geompy.addToStudyInFather(box,f1,"face1") +geompy.addToStudyInFather(box,f2,"face2") + +twoFaces = geompy.MakeCompound([f1,f2]) + +## ----------- +## +## 2D from 3D +## +## ----------- +dim = SMESH.BND_2DFROM3D + +init_mesh = Mesh(box, "box") +init_mesh.AutomaticHexahedralization() # it makes 3 x 3 x 3 hexahedrons + +# remove some faces +faces = init_mesh.GetElementsByType( SMESH.FACE ) +nb_faces = len( faces ) +rm_face = faces[ : nb_faces/2] +init_mesh.RemoveElements( rm_face ) + +# restore boundary in this mesh +mesh = CopyMesh( init_mesh, "2D from 3D") +groupName = "bnd 2D" +nb, new_mesh, new_group = mesh.MakeBoundaryElements(dim, groupName) + +# restore boundary (only) in other mesh +meshName = "2D boundary of " + init_mesh.GetName() +nb, new_mesh, new_group = init_mesh.MakeBoundaryElements(dim, groupName, meshName) + +# restore boundary in mesh copy +meshName = init_mesh.GetName() + " + boundary" +nb, new_mesh, new_group = init_mesh.MakeBoundaryElements(dim, groupName, meshName, toCopyAll=True) + + +## ----------- +## +## 1D from 2D +## +## ----------- +dim = SMESH.BND_1DFROM2D + +init_mesh = Mesh(f1, "2D mesh") +init_mesh.AutomaticHexahedralization() + +# remove some edges +edges = init_mesh.GetElementsByType( SMESH.EDGE ) +nb_edges = len( edges ) +rm_edge = edges[ : nb_edges/2] +init_mesh.RemoveElements( rm_edge ) + + +# restore boundary edges in this mesh +mesh = CopyMesh( init_mesh, "1D from 2D") +groupName = "bnd 1D" +nb, new_mesh, new_group = mesh.MakeBoundaryElements(dim, groupName) + +# restore boundary edges (only) in other mesh +meshName = "1D boundary of " + init_mesh.GetName() +nb, new_mesh, new_group = init_mesh.MakeBoundaryElements(dim, groupName, meshName) + +# restore boundary edges in mesh copy +meshName = init_mesh.GetName() + " + boundary" +nb, new_mesh, new_group = init_mesh.MakeBoundaryElements(dim, groupName, meshName, toCopyAll=True) + + + +## ------------------ +## +## 1D from 2D GROUPS +## +## ------------------ +dim = SMESH.BND_1DFROM3D + +init_mesh = Mesh(box, "box") +init_mesh.AutomaticHexahedralization() # it makes 3 x 3 x 3 hexahedrons +# remove all edges +rm_edges = init_mesh.GetElementsByType( SMESH.EDGE ) +init_mesh.RemoveElements( rm_edges ) + +# make groups of faces +fGroup1 = init_mesh.Group( f1, "f1" ) +fGroup2 = init_mesh.Group( f2, "f2" ) + +# make 1D boundary around groups in this mesh +mesh = CopyMesh( init_mesh, "1D from 2D groups", toCopyGroups=True) +groups = mesh.GetGroups() +nb, new_mesh, new_group = mesh.MakeBoundaryElements(dim, groupName,groups=groups) + +# make 1D boundary (only) in other mesh +meshName = "boundary from groups of " + init_mesh.GetName() +groups = init_mesh.GetGroups() +nb, new_mesh, new_group = init_mesh.MakeBoundaryElements(dim, groupName, meshName,groups=groups) + +# make 1D boundary in mesh copy +meshName = init_mesh.GetName() + " + boundary from groups" +nb, new_mesh, new_group = init_mesh.MakeBoundaryElements(dim, groupName, meshName, + groups=groups, toCopyAll=True) + diff --git a/doc/salome/examples/transforming_meshes_ex13.py b/doc/salome/examples/transforming_meshes_ex13.py new file mode 100644 index 000000000..0126b7108 --- /dev/null +++ b/doc/salome/examples/transforming_meshes_ex13.py @@ -0,0 +1,43 @@ +# Reorient faces by vector + +import smesh, geompy, SMESH + +# create a geometry consisting of two faces +box = geompy.MakeBoxDXDYDZ( 10, 10, 10 ) +faces = geompy.SubShapeAllSorted( box, geompy.ShapeType["FACE"]) + +shape = geompy.MakeCompound( faces[:2] ) +faces = geompy.SubShapeAll( shape, geompy.ShapeType["FACE"] ) +geompy.addToStudy( shape, "shape") +geompy.addToStudyInFather( shape, faces[0], "faces[0]") +geompy.addToStudyInFather( shape, faces[1], "faces[1]") + +# create a 2D mesh +mesh = smesh.Mesh( shape, "test_Reorient2D") +mesh.AutomaticHexahedralization(0.5) +localAlgo = mesh.Segment(faces[0]) +localAlgo.NumberOfSegments( 11 ) +mesh.Compute() +group = mesh.Group( faces[1] ) + +vec = geompy.MakeVectorDXDYDZ( 1, 1, 1 ) + +# Each of arguments of Reorient2D() function can be of different types: +# +# 2DObject - the whole mesh +# Direction - a GEOM object (vector) +# FaceOrPoint - an ID of face +mesh.Reorient2D( mesh, vec, mesh.NbElements() ) +# +# 2DObject - a sub-mesh +# Direction - components of a vector +# FaceOrPoint - a GEOM object (vertex) +mesh.Reorient2D( localAlgo.GetSubMesh(), [ 1, -1, 1 ], geompy.GetFirstVertex( vec )) +# +# 2DObject - a group of faces +# Direction - a SMESH.DirStruct structure +# FaceOrPoint - coordinates of a point +mesh.Reorient2D( group, smesh.MakeDirStruct( -10, 1, 10 ), [0,0,0]) +# +# FaceOrPoint - a SMESH.PointStruct structure +mesh.Reorient2D( localAlgo.GetSubMesh().GetIDs(), [10,1,0], SMESH.PointStruct(0,0,0)) diff --git a/doc/salome/examples/use_existing_faces.py b/doc/salome/examples/use_existing_faces.py new file mode 100644 index 000000000..12b5a9a56 --- /dev/null +++ b/doc/salome/examples/use_existing_faces.py @@ -0,0 +1,109 @@ +# Use existing faces algorithm + +import smesh, geompy +import numpy as np + +# define my 2D algorithm +def my2DMeshing( geomFace ): + + # find gravity center of geomFace + gcXYZ = geompy.PointCoordinates( geompy.MakeCDG( geomFace )) + + # define order and orientation of edges + sortedEdges = [] + geomEdges = geompy.SubShapeAll( geomFace, geompy.ShapeType["EDGE"]) + sortedEdges.append(( geomEdges.pop(0), True )) + while geomEdges: + prevEdge_rev = sortedEdges[ -1 ] + prevVV = geompy.SubShapeAll( prevEdge_rev[0], geompy.ShapeType["VERTEX"]) + prevV2 = prevVV[ prevEdge_rev[1] ] + found = False + for iE in range( len( geomEdges )): + v1,v2 = geompy.SubShapeAll( geomEdges[ iE ], geompy.ShapeType["VERTEX"]) + same1,same2 = [( geompy.MinDistance( prevV2, v ) < 1e-7 ) for v in [v1,v2] ] + if not same1 and not same2: continue + sortedEdges.append(( geomEdges.pop( iE ), same1 )) + found = True + break + assert found + sortedEdges.reverse() + + # put nodes on edges in a right order + nodes = [] + for edge, isForward in sortedEdges: + v1,v2 = geompy.SubShapeAll( edge, geompy.ShapeType["VERTEX"]) + edgeNodes = mesh.GetSubMeshNodesId( v2, all=False ) + \ + mesh.GetSubMeshNodesId( edge, all=False ) + \ + mesh.GetSubMeshNodesId( v1, all=False ) + if not isForward: edgeNodes.reverse() + nodes.extend( edgeNodes[:-1] ) + + # create nodes inside the geomFace + r1 = 0.6 + r2 = 1 - r1 + nodesInside = [] + for n in nodes: + nXYZ = mesh.GetNodeXYZ( n ) + newXYZ = np.add( np.multiply( r1, gcXYZ ), np.multiply( r2, nXYZ )) + nodesInside.append( mesh.AddNode( newXYZ[0], newXYZ[1], newXYZ[2] )) + mesh.SetNodeOnFace( nodesInside[-1], geomFace, 0, 0 ) + + # find out orientation of faces to create + # geomFace normal + faceNorm = geompy.GetNormal( geomFace ) + v1,v2 = [ geompy.PointCoordinates( v ) \ + for v in geompy.SubShapeAll( faceNorm, geompy.ShapeType["VERTEX"]) ] + faceNormXYZ = np.subtract( v2, v1 ) + outDirXYZ = np.subtract( v1, [ 50, 50, 50 ] ) + if np.dot( faceNormXYZ, outDirXYZ ) < 0: # reversed face + faceNormXYZ = np.multiply( -1., faceNormXYZ ) + # mesh face normal + e1 = np.subtract( mesh.GetNodeXYZ( nodes[0] ), mesh.GetNodeXYZ( nodes[1] )) + e2 = np.subtract( mesh.GetNodeXYZ( nodes[0] ), mesh.GetNodeXYZ( nodesInside[0] )) + meshNorm = np.cross( e1, e2 ) + # faces orientation + reverse = ( np.dot( faceNormXYZ, meshNorm ) < 0 ) + + # create mesh faces + iN = len( nodes ) + while iN: + n1, n2, n3, n4 = nodes[iN-1], nodes[iN-2], nodesInside[iN-2], nodesInside[iN-1] + iN -= 1 + if reverse: + f = mesh.AddFace( [n1, n2, n3, n4] ) + else: + f = mesh.AddFace( [n4, n3, n2, n1] ) + # new faces must be assigned to geometry to allow 3D algorithm finding them + mesh.SetMeshElementOnShape( f, geomFace ) + + if reverse: + nodesInside.reverse() + polygon = mesh.AddPolygonalFace( nodesInside ) + mesh.SetMeshElementOnShape( polygon, geomFace ) + + return + +# create geometry and get faces to mesh with my2DMeshing() +box = geompy.MakeBoxDXDYDZ( 100, 100, 100 ) +f1 = geompy.SubShapeAll( box, geompy.ShapeType["FACE"])[0] +f2 = geompy.GetOppositeFace( box, f1 ) +geompy.addToStudy( box, "box" ) +geompy.addToStudy( f1, "f1" ) +geompy.addToStudy( f2, "f2" ) + +# compute 1D mesh +mesh = smesh.Mesh( box ) +mesh.Segment().NumberOfSegments( 5 ) +mesh.Compute() + +# compute 2D mesh +mesh.Quadrangle() +mesh.UseExistingFaces(f1) # UseExistingFaces() allows using my2DMeshing() +mesh.UseExistingFaces(f2) +my2DMeshing( f1 ) +my2DMeshing( f2 ) +assert mesh.Compute() + +# compute 3D mesh +mesh.Prism() +assert mesh.Compute() diff --git a/doc/salome/examples/viewing_meshes_ex01.py b/doc/salome/examples/viewing_meshes_ex01.py new file mode 100644 index 000000000..b2fa7df40 --- /dev/null +++ b/doc/salome/examples/viewing_meshes_ex01.py @@ -0,0 +1,76 @@ +# Viewing Mesh Infos + +import geompy +import smesh +import SMESH + +# create a box +box = geompy.MakeBox(0., 0., 0., 20., 20., 20.) +geompy.addToStudy(box, "box") +[Face_1,Face_2,Face_3,Face_4,Face_5,Face_5] = geompy.SubShapeAll(box, geompy.ShapeType["FACE"]) + +# create a mesh +tetra = smesh.Mesh(box, "MeshBox") + +algo1D = tetra.Segment() +algo1D.NumberOfSegments(3) + +algo2D = tetra.Triangle() +algo2D.MaxElementArea(10.) + +algo3D = tetra.Tetrahedron() +algo3D.MaxElementVolume(900.) + +# Creation of SubMesh +Regular_1D_1_1 = tetra.Segment(geom=Face_1) +Nb_Segments_1 = Regular_1D_1_1.NumberOfSegments(5) +Nb_Segments_1.SetDistrType( 0 ) +Quadrangle_2D = tetra.Quadrangle(geom=Face_1) +isDone = tetra.Compute() +submesh = Regular_1D_1_1.GetSubMesh() + +# compute the mesh +tetra.Compute() + +# Creation of group +group = tetra.CreateEmptyGroup( SMESH.FACE, 'Group' ) +nbAdd = group.Add( [ 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76 ] ) + +# Print information about the mesh +print "Information about mesh:" +print "Number of nodes : ", tetra.NbNodes() +print "Number of edges : ", tetra.NbEdges() +print "Number of faces : ", tetra.NbFaces() +print " triangles : ", tetra.NbTriangles() +print " quadrangles : ", tetra.NbQuadrangles() +print " polygons : ", tetra.NbPolygons() +print "Number of volumes : ", tetra.NbVolumes() +print " tetrahedrons: ", tetra.NbTetras() +print " hexahedrons : ", tetra.NbHexas() +print " prisms : ", tetra.NbPrisms() +print " pyramids : ", tetra.NbPyramids() +print " polyhedrons : ", tetra.NbPolyhedrons() + +# Get Information About Mesh by GetMeshInfo +print "\nInformation about mesh by GetMeshInfo:" +info = smesh.GetMeshInfo(tetra) +keys = info.keys(); keys.sort() +for i in keys: + print " %s : %d" % ( i, info[i] ) + pass + +# Get Information About Group by GetMeshInfo +print "\nInformation about group by GetMeshInfo:" +info = smesh.GetMeshInfo(group) +keys = info.keys(); keys.sort() +for i in keys: + print " %s : %d" % ( i, info[i] ) + pass + +# Get Information About SubMesh by GetMeshInfo +print "\nInformation about Submesh by GetMeshInfo:" +info = smesh.GetMeshInfo(submesh) +keys = info.keys(); keys.sort() +for i in keys: + print " %s : %d" % ( i, info[i] ) + pass diff --git a/doc/salome/examples/viewing_meshes_ex02.py b/doc/salome/examples/viewing_meshes_ex02.py new file mode 100644 index 000000000..de345e8a3 --- /dev/null +++ b/doc/salome/examples/viewing_meshes_ex02.py @@ -0,0 +1,45 @@ +# Find Element by Point + +import geompy +import smesh +import SMESH + +# Create a geometry to mesh +box = geompy.MakeBoxDXDYDZ(100,100,100) + +# Create a mesh +mesh = Mesh(box,"Mesh") +mesh.AutomaticHexahedralization() +mesh.Compute() + +# Create a point +x,y,z = 0, 0, 1 + +# Find all elements (except 0D ones) located at the point +all_elems_except_0D = mesh.FindElementsByPoint(x,y,z) +assert( len(all_elems_except_0D) == 4) + +# Find nodes at the point +nodes = mesh.FindElementsByPoint(x,y,z, SMESH.NODE ) +assert( len(nodes) == 0) +assert( len( mesh.FindElementsByPoint(x,y,0, SMESH.NODE)) == 1) + +# Find an edge at the point +edges = mesh.FindElementsByPoint(x,y,z, SMESH.EDGE ) +assert( len(edges) == 1) + +# Find faces at the point +edges = mesh.FindElementsByPoint(x,y,z, SMESH.FACE ) +assert( len(edges) == 2) + +# Find a volume at the point +vols = mesh.FindElementsByPoint(x,y,z, SMESH.VOLUME ) +assert( len(vols) == 1) + +# Find 0D elements at the point +elems0d = mesh.FindElementsByPoint(x,y,z, SMESH.ELEM0D ) +assert( len(elems0d) == 0) + +# Find edges within a group +group1D = mesh.MakeGroupByIds("1D", SMESH.EDGE, [1,2] ) +edges = mesh.FindElementsByPoint(x,y,z, SMESH.EDGE, group1D ) diff --git a/doc/salome/gui/SMESH/doxyfile.in b/doc/salome/gui/SMESH/doxyfile.in index bceb23d55..a6a5fc1f1 100755 --- a/doc/salome/gui/SMESH/doxyfile.in +++ b/doc/salome/gui/SMESH/doxyfile.in @@ -42,7 +42,7 @@ INPUT = @srcdir@/input @top_srcdir@/src/Tools/padder/doc/input FILE_PATTERNS = *.doc EXCLUDE = IMAGE_PATH = @srcdir@/images @top_srcdir@/src/Tools/padder/doc/images -EXAMPLE_PATH = @top_srcdir@/src/SMESH_SWIG +EXAMPLE_PATH = @top_srcdir@/src/SMESH_SWIG @top_srcdir@/doc/salome/examples #--------------------------------------------------------------------------- #HTML related options diff --git a/doc/salome/gui/SMESH/images/addinfo_group.png b/doc/salome/gui/SMESH/images/addinfo_group.png index 9f26c9af88f70617eaee9ac2522efc44905e36f0..c9ac74a06414ad4abc493fdb87dff660332798d0 100644 GIT binary patch literal 16939 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 literal 20564 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 literal 39855 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 diff --git a/doc/salome/gui/SMESH/images/addinfo_submesh.png b/doc/salome/gui/SMESH/images/addinfo_submesh.png index 4811c9902d3052cd6896c47741feabf980dd6d73..f41ba29049495b47e81035e392562814c8363c3b 100644 GIT binary patch literal 14102 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 LN44s~vp4?@U6wd* literal 15335 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 Q@IqcFswkApnSA~~0DmaVkpKVy diff --git a/doc/salome/gui/SMESH/images/advanced_mesh_infos.png b/doc/salome/gui/SMESH/images/advanced_mesh_infos.png index ddd305f587eea02b9848081d71b84d483cc3c9f4..3471144a1b068ab6de1db00ad7b3def1722ece3b 100755 GIT binary patch literal 32397 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 ZyvQ#e{%-~H;!yDGto#MJ7cvHS{tt)+7vul{ literal 33649 zcma&N1yq#bx&}Icf`Ejiv?wLr9ZE_g-CYt=(xn2@Al)Sm0@B^xl0$cQ=K%L(@3Yt4 z=bm%+x~%0|$jl$}{ongO^-iFIoCF#QAqoTnL6iI-stAF=IY1!rbk7jMUr54TV<3=M z5J}PZ$}Y)!^Uf~HDmN|1hi8(9F|ndjAIvjQ0=~Ygk$#~qhEpCCP`pGtDy{JIb)x9F z&U81LtfLSKYQ{l;{)jee5@bAz}0{PFb#bgP8VhRV`++OXAN1B6u_8{kxxOhdl-r=e;cCDp_cfQQ)lfr5 zN3YB0{qEz#P3jC!BoU|8)Km~3RVy4>i@Cy?tw2La;U5EaD1@rTSVq>KbH zP~iN4PFJ$2T2eyGaWSBR^NTrw8ICFnUPhc9CtdNSUE|Hu=_+!Zof$<#MMVo`5lKAs zAHg(ewKy|Q>Ek))vPeujW)})vjHa=e=UPsF>vC?C!|1llhNf?cyawx*ZyYV2via8> zcR7E;i5~Y#nU02I+!IKW-&>!_Z9+$@$h1Tiu#*&n>1iLJb-S<$Ywqya*J5TOpCy(V z>0ImZx^{L^1xk#E3TNcm=UpY-$8^U*VbK~!0vij5j^`>WYSxa>?52X1{LeZmZW}5b zzRsFBQc5qRq)I2ghEDnx@{$mRVx!*^+CQhRO{@x^av(^SQq>;_*c|$aw^rfu{C3aB zc%~}&ofv&SW5?_#%Y)1-zd*{^?@F!Q1+atTtpQ$!W ze-~^%K^-t@E30P8G-KfLwQ!s7Zs?wBIw$jMDr-&Z=4Qzg5#foEtifs>xa(Y(*S#H# zLeAH%GL7G9X*CI*A%&4P;Sk`69@MpEq&bZgck3%B?u4tbv-p)MM!MIfDaDATZ66M} z3#pA|e5C2OH^4og=!_t1{xv)QW=Cc5{8*dFx$;~kqst)HLzWJw>$NiFG>-1gH_o8N znm2zahe+=f+|kn0nZuKVn;q7-bg_oAGRmDdg;C|dIBic&x%B-F^}FV__|Qk+rD4_~ zt|9Zuj+`)sfgyR~iucn8x#4ADDLldyGz%k^OGmrTVHJdy&Je}>Ls3CWL~I?8%Ck?I z5*akoJ>8K(*Y`4TkS008Vq;uZYuJ2+&Aw#*i>83VRjIHHMSk5dix4Vod`7+2+!Ty< z-l_DlJcU9W?pd0VLR_n`L6JhmBYiGDsZgqWmIjhtZ>Nr|QUharz6N3r8e9~`)8~8K zu@YW^f$j*_BLyv;;$jx5aGA(f<0$O3w$(}z8s=-WS00Gf<*n^8hCU z^Ww&Y6&7&52+jQ6t?Ag5P-d8UeOyo*4sYu+j4q5AR#26?vr}JHyc+}c+;`%bxJ=Wt zkDr6W(MT^r1)H7pR3_A72>mt6k`L+J_1P5+xkARM1q~LV4-)>d{-3tZUUM)6r(qDU z3Re*|`J}e8nLnd##AC0*G2dI4RzW?rQ+Bwv;H=d|@DeQ6W?+0*SZ$<^q}3$o7Q-^H zU6ZW)b+RksxN-i&Aji>(zfe?MO4oR)=hlYe!18l<@h7v#nrCnCxjnInLKFWk>(JCB zelL=M2+CO`b5O#ZyCus`!r88yDB0b8A`>@tHn>kPV-z0=6?I} z1O>&_N`Y@?M>?=JeMLi{pc+3;Os*AWd11! z=>;v#+oeT4(l>N`Ndy?@?*qR(S9K{WD)t2h-fgdcY}ssHw_9&}tD81XW;F9D`e1*1 zv!wfDiT<*;_iL_Q+EX&39+I0chHNR^DZf|39X6*=+CPqKYBk)#V)VlF(z9xQHeX(D z7~7LS-0bB_9lOjFDn#R{@)ifbEs(N)P3ZqCDE096*8ckL)*MoYK{%-7Jfl}FyAJze zy;8*J?MTL67psl~`ct{fmLr7>PE*LW6_iaj+$7_$@W| z;DRDWAS|vih@?50LSUcvpb4(x!j{6#hQD^&gymDEMbpjp%Rujr<-HO3P;pr&H(FN> zwP}Z{_=#Dg-u}Thwpa1QK6sfK(G}8WM|LAo@w#6#B~Ue;wt{kfBH8eg!>fCtkyNju9ZaGM+ZHiy;p|q3c5U>M+(pX*)!Ok(^HM0q+rPvb^t`a8IqBnM8{V^X}xh6k$bkUU~VqL~b^)YjZz+WuVje zd6CvAT}zAr_2|oS)nOzSeDnS75B91oR8bLp4J04w431at6fD1h6;PIpuQy2JcvnxokV#zB^7jD(`V1ltgewkTXbf={|QbX*BGA>mU z@AB0BQnljDHeC-%O-}FaTF$KYvmiO*#qL-l4UXR1C&}xKF*N7*mC&y0q5@u%pxs5^Pf%)dvdkQo- z8_)uouzePL~{8&b5*w+$pTb>DV&c1}(4jg8KSMJFqU zP$9T!A$iR2eHfx`ee!&F#jm+O(bup*qt-_5%0S9cTq6q?a>#sMpq)rVuxD z*Ypjy=pe$~LV4Dbq9$th?ZNQe-&5wK&S~SbKPsE?RLS&kcQ}T%4QM<2U83cJNb&>( z{t_tGo}GFhZy&$nEM`S3ee23o@S&GQpZ#SISHXyd@)^d-`u;<(L}7JyjQ<;?6{cU6 zmDH5o9~LJsYFu4bx3J$?s*woX5nrw7(_)<2ZXRVDvfotU80ThIIp)+<{Or#Sb8x2IQFwB>o4RyD6szyX%uzY*)HEhqWY@UL=L+}kzDvEiD9BKZo->sb=- zr>mSXYJ5UG5NfZlU8ZInc)B}Y2}$hjTPawuS2#kK_S4r=7Uk^ZFRQer`bDxwz6$$= zmskDPtwi?|4lId^mCmm?!nM0f$J&cw=p3 zbS&XFOfj04!=e(8jG7^C^yK5GGm0#Hw%4V#IwEw?Am6MpVwOG8?q@{I^r{meSj5Y;$&A9GWTn zhG-%5&dj^TDmyh9n9CN%IIn=a{QA$R)bHXp{=)gf`O4)?9|vQ}E|q>peOvK9uB~kF zk@u3OzSib<(~?l8MbqnwvER6Sm?#`Mxh_?dBjFEB@j<1H`5{|MnS8U4b5X2IvH8B^ zf-Or|&__H|!qTX}RUKb(sC#wkU@&qVPdh{?V6rQ0aELUS#|5h~1pyrD85l&nI(??a z+iNDT>Z*-GTNP-|UwJ<8a9jTkVbRNwQAn}a)kxTT@f?P+PbmY@AZr_$mo zR%m)yJH2CmcQUih`c1*Bc6#A}+0@J=F6tF|tZ|m3AG-m3FT%n9QT$F~fkqx>!xx^r zu-fbQ8m2f9g`q*0mv&5w{~@1QO&NXvpm3rOO)U6z6YkdQW~aK!Y1(J*%RD0&ZLhiK zBR;Q`w;zp6n9ICa%)=9YHd1l#z+5XV9A_iohuMbmffZl)8QrU1?Puh_zfw4m`~HD{ zGzR|H7j|ZXm2(vH|BTFz>;6f2OUw8xD=Vvub<`4zr5sEfbwFXCY^VdeNM2L|=GG#Kgb>?=ya$+Scdq@?dk+XBeZK9A@$G@SqX& zTbI<-)a;2Rq{>NtI%n#GefMBxWuYS!wW(z5V^^N=y93PLJ-$Z0TpHsO96uyObOpFaUQ?&-vXm$G(>&AB(a}pg zD{dl}8nRMSzw{Qpd@OJ%(j*4oRAoEh*zq#pXSc{mRwz`wNXpaw)vWw};J9si|Rwg}btyYX=8IiI z9@P7pnkwhw!rdK4*4~@HH#82G9RgcT@IKm$HmluCb%$J?jman6uYBPYxBktMy0>Rl z_hq{+B!TV9zCVs$t1iUG*{dJyqgv;!#=V)!e(j6xUis6OMN<8fwceM{5lv;%T35t^ zT?Jt0yky>{s#J_aj8junKci;3Pfyv{SOWt>mgc4%UWST$czDEfd6R-43QEcsH|jL2 z-Qk;?Y2H)<0x7kp8}@5GFD?#eoID& zt*x!!4(99Cri$wv*RB6pUKUGPR~vSskb1-Hoc0$?7`5h)pFJOZ zIfS)?j1F2FcFe{xut0l;`b5smHbb4|I~g zzZoK~&gblNdvnkG9gTI`*wn?$M$5UA?a3Q$)nFgXZ0MR!5Y>hEsINDgFSLcjT4J zU3cZhctJroSil&YVs{H$jHcNyU_56Oz|=XH!Z*Ol7Ot6B%arVcDBkUQz=(2ncMDrsZm#A|L6I-n5ijsbQ0bU(0q?Cj!m~mvuR?anr?RJ zDrO2Ecr1R6Z4ZR2(5f^FHqCEcrSuxV7I;IVhOY*@yW;`pO{psEXO?zy;`B!+dCkX{ zq*AB~XHw2loHCO=VNrW~P!G2?Rr*Fea|FiEO%vbI(cw1X2>n_=FiS;AHL1)2pN9JZ0KCr~M$XdSEa3 z`uhHih#JxkkP0Mw^Rib2NVPIL0PfrnwYj67dQNM-~JrGm%4h~Xsam9fi zIa+C{#`|TfMJVl-nvs$5Y-b`k#^$&28uyeS2cakNlm&|{M~dM8ykBvp{5582n-B_>&r4~;YcLuW^^)J5S>(ragOUDV z03b+9jSmgo>-}*A?6#PXf8P3;0sFJ*j~MPb=x#X$VAKZ@edPeo*(XrS=>FV*HKC_x zpk-n(CYC|-mjaCi48cNYb8k-utgAZs{D49D3BUjJ>8;sNaz1cwQx|1)I5{~14jHi% z?tbCt==`#8gpZFuQ)$_~F_`p`1_zW8r}d2JL;VeO#!ICuo#xiAqAqr^-kB*iHFfXG z0!b^gx{Sk(?qkxgt9$>$-v0jfi3waiJv}cN*bOL87dsIN|Wwk0RgXAUq?!G34IsO%&4e{zU`iqS5Q#ME~^x1 z9;xFO5Fp^RdbvtU=nue_D3eq5C0BEmmF&58Gy2l`5mckfia?9grWL?6*sP`l@gFl} zbn=yHqoqtzs^{?)I;o17v3Ai^T#|QGpGx z2E_bRr`(r<+a^j|r@=Lm7(AbPWez^xN>ID=x#LLr!7L0B6!Mj8>gwz%*HHkulqHcX zUtT`=rkD+2F*{%61=okd39Kcucb|0`pFVvmOA^+3x0w!)#AUDft_pkJECXWUu@%6%N#rwwGcRTo44C2_+aMi8q<*O)m`ZqoSs;n>a7& z0V!a|y(G4T35waG`FXeTwKa|jGE~JmI-T=_DQ$F-1G}A|(Pym@C8^ODs3|H6_r;X4 z%z+)wX~#b3I$u-Ie652D5^B}2s(S?CCmIcP5eKuk$wR@#3J-pWoYxgq?_ z;3-7{D!DK2PY^p|s=fokp|CpK|MG%YQZ_+EnjU6b+2;$ayPKcJ3j;mFOwSAmxZI*n zi70y;2+GcaWuA>(84vuMn8B0XXcBC?y18O?pWKt`2gpHB5MbaY&Dzvq}9Q*8lO}Fx3bIb#*Gs{KRI7Xdk=;)>$0WY+hJf<7G zu20r0ETKaUg8ck*4WCDTiGePUDkLP-baydJX!Q1wgGsX@V4=}{6-W%OMUVD2Kh*8{ zdM@jk3Ijkj9K&`;v!x%e1gIGRslJL&V-}%w{QSw_5Nu*%nc-A{!3PIum(!gS^zy=T zro`MsHgbT>d&LfLDS05ovK;}k$fWWoWcSCO%sC9dz{l?n*=D1S;j>$LA}{0dJ$el% zH5JCrQ_CacVg(PN;IVW!>`ym`%?1-Wo;W^#ZDsHh0SS!)c79~BC?k5xV$k-4(`xGL zi1}J!Nt5APPXz9y5bUU(AHYLLSC>8P%C0Mvs5?tC3R2^CPRrDIhJ}Pq%v|EVlb;Le z>FfI?5l#xb*)3_f*(n@I;j5lhFDonCnk*s$?^>#a>aGHMkq+KN%x(J>mrj-0{US{y zilg)C(O(e^yUTfJZ14#p-blD?XUAED?&jyFuC#nZAQtjUo-Q{#ZF>VX``0W0>~vTy zpop>3j+ewZ>v6}Wnv-*yn)#Z=5o+@se5yID8Ja` z+1uAATmogY7^i`_T^GF7iWIyyR_uMw4&P*qJX zn+1NriZrf9g?XPk8}>!Now!&k@z%YErzaEsRu(=6F)%RraxgdDFgH1b*8-D&)!X1o z$n}|cSn!rU&Fkiq-#Wn6Y{lODyW5fNFELe0v@v`0^>IE(81_poZ~#Xog7FyCtE@Eq zPH1Ba+ICBMc~gd9nkxCqF{yFTk6PN5`X;54Y(3;29IxAlMZ`fbdRP8OLlmg_4CO!lvo&2OvvN zS{8@NyoJ08*lcoyMMM(#oEgF06#tnU91I0_S#I2m<#0mF$hgrH@dg64?$7x651?ie zSWQrZ@tLZ6;=WaOu5WCJhm#7p>=soI%x2~0Le2dL|s`ucLW2@5GH>1WTL)#TsNYt;FE8p{FpM_=0?zkxKNw7c7j zu@dj*qyjZ{Bw%Qm4knr$h-&Ya4-38_C;zszqz_73s`~T%BXBBkhQV48F#hH%Q9l;? z+4fi=F{jn@$Bhqk$H~0&;)|CrKY%wsu5ai$Fd|CzTjA@R4~J5m7hK!h-~8higO;Oo zIsF8i1L&@QM#T=Skyh&M?62;NDB5F1yoeAL7mtjOHvgv3IY=v{XV24&8LI>(o1q;p z1o#msq;c)uw)_79$ftP#1Q4z#<)5L}*sr4i9#>ca8{#`$12<&-J;1jz;<5Wwhx{82|Tz3rcosi1Or^D1 zadktt_nkwnM4tIG6u<8ynG)rWyQ&b-ycIy(Oib*%I$i~bq5^3V@{;9ye;iX1lu55C z8CWX`P=9~_Bq##_C*4N3NB^sO(aSQy2dnx?Fx6?ML^%B4lEt*kMS5>ye0={_{X7M) z%i{TgWS%J9M)y*qZuE`eBt7f-{|!ZKRZD1hTbb1Vd{sI8-PYOZhg(v#ls5c;ol^B% z?O{X9CJ`XFTV*YjNz^DF^a&zPs}^(iN2$UBd<~RcGOsIxN8`ZI$cV=a#{Eb*N3$d$ z+Kp~8ak_4SK(@t0g#f#JH|;6uezw(G(tO_sfU0k<)`7vx>eu$%s1o*@#eggzDbJb< zg`6*H%ezv$F05za0s;fcsi?XdJb=j| zLF*alv~@m#jPGdG<#$+9(9i?`_!oSDIozCW`{AdcG9$;s*%Cba#81YqQv7Y+{lD-6i0#z=1TnUv9vzPw|8}N50S}X7D;63_RXE zQ!~u)AarlG8iU6DTcL6R%K9!FnP!Fp1QQQW9Ng+)zxBSAWl^EWY(ew`wj?V)+NZf1 zJO10fa*vzsT-?|s8LDV0%G=Asl9St4pnC)Az~gfC3c#)YLW66C`N(&Z{#X^762<%h zk&s`mf6RX*3L5cZlcuyZ)SiBjk`gXbJiVB;$yA_;=W#I2K4CK(c(efYPh$rm&l{c1 zD;>iL*nR-+6`z+!v$wbZclV4~z$yB4bEw>_-Az1-dTXYV4%pVlW@cjmGTkorByDY(Gcqz{T_{#m4MvOw zZI|A0TFtfeajBNAOyB}~{+;hB_6vg6pX4I6G0kQ@0u2{8md2*WCvnX%KQ%p1+`OrN zRoea^cX9MO-;HV8AyA5xeZ}<#DBJamGwG+qaoX4xq!HZs1{~tW%)ib5?};G#>8|k z-d}J5P7L%+-h{=1`=J1;1k-1+|Jlzmtgl>de?})Ob8_*qMs{S0qWWrX0F%W7P@{na zf!sZ+T8TBPT1OSHrZsyna{An2p$e5$H3YsVSl+BnlP3>6c`dDjNz%v74jwjV`_50d zz|#SrAr7ct%^|HwrSBt;Yym*EPl z`_F!k7n|djouMT-3ohKbV*ycEBX89P<}X*?6>mFr`Dn zD!nges6^L)Mu-0jNQA!4hV=Mp#fXWD_EcyX;DTs?Eg~ZFZ-1{&oG%A}qvw)X*ljmG z@&6`Y=o1G#Jw1-kk4-LqPshZrudmPBHoCgHZn*iHn3$P8ded|B^L9>7#eW!qD+=f( z764lX1xz1Aw3YFErHymoALamu_{+|CAfry*ABW8$UTbRKyx)>;8)+UV$i2P2vZaY6)N;wM7#YKm$UJ^hr@Fv@1;(|m%kopFgSlSNCDofec;tod zz7)+OlNU@<^lFzt0i)QVh2rAjmAQ-<*7<+Qbu63&J^!e0MU94*mNl+-XlNrLH;ueS z=<5ObyhgK^XXW{S#{?F_P>2WYxch8pI`|P0GCYyQLkUe5s>lTy*zw&OQ{4}0a}`U7 zTP7!C!LLYu!f-%iA#i)&^FuB!E?nH)BBP=Z-l?kM?ax#eI`WZ=P9z$0_OHtG4wTIBZE6~)GO!+TuJgA>`P9ie-h$_)PMJg5U~`}#=y+Auvt9EDha2}Jm*wmI z3=@-&)s2Ww*wY(DjqEKzTqNEq%o7$i&Z2vNf>uMnc?x+ zS5;fq8?1|7rwowggF=P2ON^x3+ zjF0`HCjKjkAVi3ZA+bz)LkVnV>ZOKHA>x@4fBz~>7HM^N2IF7fEcxB$CsyZET@P^T|_pRxVW7|DSUJxh4uCI znb6(oW^W-#z4PHl7~etOKlj4#-E9D5=H}+v8L_~xTisgfncONGNaR3u#&Aw`-5}T) zO0r};-6j?@?sVhj#@kqPb8}N=Ca9?Gc)v!>0e9BlLok8^ zmh+=gH83CpVlx5(H+B$d*uW5~g#kMOFdCJTBHJI!usvJNl;(Ls0A#iyPy|n&JYfbK zD}8Tl$fo)3hj`}lYPirwAa&}y3dB}K(Wu?Pqx4HbVq6~^T%gn9I?!*F{stOK>)yXvCtVFH`;O0)mrzuQLt zWX1ooM!48mJ6`)bMj9`KD07hMJu@INe(lKiTJH?mpfStrKYA%GhUFTs-@In1qyv4{ zWFVfW{q=3BI%^!ykZ{08kD}7||7w-Mp&|Is9rphWj`c^34|Z3zwo71KT77Ao>+2e< zS-f;_-;%SwKB>A7P1q_Lc@9k53=#iPmOpRi>zvqx^r}DWRL%lx3gm!+fZREf0l86O z18tHsu|WcimMTl@L-slV+z=8ryv&iQCm-i$k1KVh|2Yu^0u0hFTxp z0j%XkbfREj*#A-0c)?+fwplLundlPmykBEGkS)xqjJLvh)hjE8uix}z)ndkDL1s=r?$Qt;VdtBUYfbxx*L*1;3InDSte(Tf*{XO966!_;4S7i~$leJ+H3m z>Dtx{$AdW@Vq#)j2ZzEx4UGGaca}4eo8_hKlB|c&60)kQDhSBolr?hx{P_u0ZRm>A zYNpt?AOyznqi6EyZ%buk0jUAe^*9z2yjnuAva(h$Ge&mznrg?_^Y{i#aGR!UDrdBs zLf!Mmqc&8Jt7U&kL)jXxLzyMCDut)&q%2S}@E>jaF>*O za@WvM@iO5t6$zhH2q@5`G&2*E(yeu|4$@FcA*M9INrwT!<#F7>0d20Jv?y`UV1kw4w9_4e%jw_(YWvI69fvF$g?H;O7nJ zrg;X%#l?w*H#PyoA^`+MsQ8TR)b?MSVe3qfK`7|t%x-7qsSlf{k0BL!#z;${Tnp)W zc>%7c8xvDhAX)`v#{cTdg*b(Hd$FYXx>8le9Z)7^4KN zIUOzxUJ7~0pG}&h6LY`2z1V+b{g0U(pnxu}BmGy`*QKugrjOm)Ywq?<5|<4XOX*(d zK9JSEzRIMrH9DQ7`E_QbL`2enU<`(rmzP~%@;z+$3kd0(*>nR2{;Vb1ESDMVai@cs zUU{JhQIMeVRUJa|N=ZOBlmx;3#E!~itfD0tfzaWB@6&5+2ud|(a{G)I1r_yM8T5lI zm<*E_;;8Ih>y6s>R`YIpSayGeKai9R_BIq;6ciU1=#D{ChrRhvF+kciUFnX`ve^B{ zX?{lBy86c`g}^C>&<$pz9LBp{P8I5={n;u6V4R7_$b`6FgPogjGpBrdsutVu9XPl) z&F7pDpgVKHgTH(@6?{xxojpM%ch1fx#n7omg2WwoK%m$k1?ndz8HA;KmP@sON8a>9%K)zNin*k$_z2)!UjM@QyMu@=O#oCAup!4(bU z?QLze9s`w?EeS(OX_&^2}Aq_44FUQ?Uj;h|}c3l5MU?e||g6PzJ$uDcP zDA>J$o>gw1_A@nSsSWFL+&3>4BpSz?fZ+tIJ9|2<<~b=aM-gMv74r5r4-XKZX$Lb& z8JV>tn`VP`B03xMG%l?)xm=OV5y+!N#dW(ZHyfq`(QW$DE6pk^JumjI?Jy7y2)~AgqTStGuI_us zplP|fxs4WSaUm`U`~oWBb{4-Ie2y$g5-O zLekQjNpEyoTieqOMc5(nA`yeyR}^x>ZifetFeXlK^1wOa|9?5&KLWmQTAN5BqM7w6 zHowU`_WKksg+QM7FZY(64=`lB>2Qii3zvzO+;_eA-(~gxc^P91L$=rWXeuCqBv<0} zQ+bRCMa89rnao%xyn;o^KjQ-*fn3s1Se@*@(b~?a>$=L_Eq61$nTpRMi+s0bV3Gu7 z_n+E5+s_6S9)_?5ttMkL9asWMSuDB=`=8`wVk(*VcR;LzT{@7!h6D)dxB;>OE)e~h zoZ^ozc|${kivY|Kgxwm<-f%##OJl}M8$ zm8(EA(Em^HTg3B!1&oxwUjnDV!-b1)9^ije^&s9Xv8x{zynFr?x$O+I%lMr3 zURfC749j|kfpBhVYpdt`pQjt=AX){Tus{CV8Vp>Y0QWq}Mh67gZD0nZH#1ytrXvE` zfP|h`{4qQ{IX%5zy2FU)F`@$aK(A5e3;17&@1*y}I*@D-arc4MM%*~H7Bki?|7|PS(JvB!+B=VA`Ohc%udHLd!&H=!uz>#c>t8c( zlSXx8B;6QyxQVJzyHmd@)_p9QT1V}>5AGA;6>4KY|NS!R z>ocP<=8OL$6a8{qum_ zDrlzT$e^9aZbh_mT`5xO>azJkwnVpa3z*U(KjzHg5fBJ$FCmW_3J8hC@n!aSV3<0r zbRe&+thgMtBDt;vQV;9`=;HRc`g46);(cf7w-3HE9T*(^25>Gw;EoUK4>?<3sK(3qZI4JHbd-Rb9OYtOFRH%K*mPW2gdHXyRgid3m|( z#Z@$zc)g zIy;gn4g$?SZ|EJg;djG5SaZ$UZB?M}`UNiMe1tO~`T%Ae-7;ATL&3IXv7Drb02gsA zN4D@JSsnXR$&WYI_Cz5GLjURsGpzMa`|#;zC8--G|3|)}iPqBKdOB5QP1JaMW;*#> zV{f6cUa=8%gXtA7Zz8FH8#B0ylUIGYV#3TtIWXb0wYAl+H>5TO5=3?0VQ+TR?`)H|=M2=jF6z~Qi04;&E2P;2l0=iN^aF!TI9h4$3>g-0T zs$0iJu}#L3``npS-U=BsHF;meSKG{@zXL`b0JV*EKIa4D9S5cBizFMkXBZf{|CYrF zH|lxcaX=z$L`Q)@y*WRW05G6RqcrRFI4W1`unAI{3^42~lgQqyog)^E2hpyvh07cX zP|T-THiU;*oHKY^Sb%`mUY6{w=)YzGz_<2|yrRyIkI4ZCb#`_JJtzU#vr$yCE2qOk zHY*=&&_;DvOy^GsR?Fpu5Ypw-1SewOra|4T+nBtG|1D?PB@vOep{U$98>3FT0&JLv zz&p}2K4QpAdsB19Ji(uh@t1W*Nu!Gf$e@;SU zAai_sx)2aQcRqUk$vowXjUX-1>tto4jmx(d`X98mY?>#INe?mIF=;YSxuDGG__TX* z_@RoJ4asFSlq(=8$PmO%kF$JnfZMCMwBLY+4@w5^-M@Oj<-hfQi)(~G%wQXnTN^H? zUY{eE!>%*2X*sWg$8<#tCsww%du!}gAGsrtzbaaXjUtDX2QI|TcNau}>%!~zj#Acu ztlOj?5AO$qXyypOsFo?DF8HJW!(gnpx@HBllUEx_Hr(LZbPJQM=B9ap5sRe$@v5|t zkmtZ|yMDMh5Tftn)q_1mk-wMz7=oR?^16Ex8CR^6lMxpa>plCtoJG2stP+pfD3Wr$q8jg^T_4LjMqZ&&{!oaj< z^Sq|GxWCrBX@g@h__E>f(zCg+pkNEQm%xNDyoX&wlCNRUAz=O?Cufv4CN{Rr?c4&i zhG!@!@Pyt59><;d4c8k3(n^^ zG$b$b-w<_$k@UBUAl2{H#5FZ`lzunj2eUkLb&kP8W_JkyZkgSOtiTs14z91{hrJU4 zN3sP2KK%Z!3#Z4tqi3$Y`;&u}mrFFgYSNKRV_z=bYsosQ@Ci#Fb9It@ZoZY~yAjwD z|8%UDe0%1(d&qY994H9Y-|Fu*H3@;JQSk~}D7?`+Z>T+#HK~~bU<0b#;5>2S(qj*_ zspc)>-ndT`da>DwpYcXm90px};ep%z&_pk-2?pOX z;1xmiB>Xfh9*n=Cd|&}l7Vb|&VBFHa%G9t5(9Ny>@=SOtxwyutfh{Y37Lx#p-uF7e zvL^?}f#~(>S3d=&?MHL=U&nNUsW;_!K_Gw1`-%g&fCAjxe_Vu>edI@vtO&#QmpZ4- z3YR8Xsww}q~T{DV~fX|eEcBK|NRR3lZH)a z)7dg-Nj(bT86j8a&%7?{7mop`)9oVFVi^9seFZ$&5GXSfjO_GrPT?^eBq7y`D=-2t zJq}@;Ow*M#w7pDYc^sF2f8bMNyDVJYP%;Eu57VRcRx7y~tJ0Ts?V&_m0RaK;K$-6E z%L15xxNUwwedp-N0kT!_^&n;dU8uCyCZ^ zRc}JI&a1iYPM#o@Vc4!6y;$J8A`Rz1`B2zhL{p*<8W89gET8ANA)gl-BzLNmLBpL@ ztR5+`5d!%_-7Q0vWZ?v>YoGDO-gNsR-W|HUynJxy=)}tEDj3*m8yX5r;d3rCA9*d8 z${*Bl^03B?N*rz`|9K(S( z2`&UexfMY9!L-XCkl`2_8q$*_YQ$HX+)w8Ze}H+uKHV5J>ZarS+J(2vGzcP_p1coW zILvj~4?nNC*mO6x$eQ%BsCwb?90REWS{fVIbn@#ZCo{g4ux@V{68NIR(Cad!^wYkGif3QgBJ(qVVWw-^N=WlDr@FnM32LL40(!2=8_DPa;3 z_`zxbdonsY8trhmE$`iC^PP-Tg#YF7?h60|N<0U@6Uu8Gckyfv+?6yY&n(w&&UbTi z#%SlfAMRvQcyamo_#jl^3q8PGhirkdMBvI;m&e2>C(CGRCZ5y+4*)QS=yL!Trof^2 zt=HV-zUWIJ*;EHcLS6xU@b!HH0bDHrkTW{E{%Q*)eT-;LL`wN6MD41^) zcS8gdIt?)YI9IRrQ*K^v_&=ZLd3D|QIU2~0P20QBo;*SPS;r7F5Yn}316HKGob40e zD8NbMt-l$4cGQBrr5X(uS!3H*)!w(&=+(D?ztw`7MUZUB#52QzEgQ?AC9a|pQzi?T z3!pic7Z0H`pwWtpi9H3gpwlIXzz=sgUJ*kTH_^o-NUYfm6#%2h$31Vt|A0s5RLwEU zJ&>PIIhL4%Vf8oteP0;?n<*wf5mF0wd763EU5vLj_|llq$%(zmbV@U({lYMuKGd@Q z3hI3aHN7Pr;(6WzoDy!Qz4-s9v-6JUdVl}_yGcVT4J48xMK+m`^@wh*(chc-D z%7YgQE%s4!X)kYcoMA^Jpo8!N#;3!Ldc*DcB;pyzvjs`M&5u`uCw(Y4dx| zhpVI+tkUE2wH_rTcsS0XNS4v`_4lhJ>rnuM>julUTUdA-Zf<6|hfiLdtCJeto$0Nz z?+s?svl9hE(AE5TZ8n-_kE}d#;>5tX*b^*Uc~2q1v=>(%P1|qhn&UJKVO> z@Lk@7E)PIXO5uoVjim?0Hhx0w*PWW9Y^HqqM;=`}?A`XjPo{5d4!YJ}iU!)^`K~vt zBv&f@l%TYv1b zffg6XCL$t2RH0%qv7)f+uByh?NKYkA=#Mqu>A5=9<%h_S_MA)V%o0}{ieZ*troqpi#gg<#ak*Qk%vo(8A!%y6%`pAJrDsuJ};*4 zNOZb1n-Wpedli|g_b&{oP!RNMpPs_aRH;2wNViL~g#}qY!l51*xQlYMb7z5`RFZRm z+f*0B2U9`o7rE?tYU9F0OlY$8&=z*p<-jjR-gS@YiE_EA$d{eg$Q!SgEw2ZL9VjOg z`2N9*=)zq1{c&>VN`PD$18LDuDGJ{*%c@E%#!+2^~ID2>id%|sU^sLP9G^fXBi?=Rl)ncp^?6m zL1CC#%^@T`s!RLUPd7R;@Q7vEIi8TGH#fbid)WZs_)|IvPli{lcLG6emw<H9unLaDqf=E}cD$||F9F#bQI?W5t&(Gg*y?H+`s=02g%4;he;w6Df)sy0s|#n!Vq;^gE~e0l zUH12RzE3R&!OSP3=6Tt_)nd!;NdlQG~AsaB+7$qga74tyX=pE?i7JgkP zu*Xw_z8uE%)aMS*J$u-+y5j;~C*C1@l$7KR#|^yOgRhW9TUs|iks^3R=uQYb&^j|X z&3b{jBAPG|y0DJ)8k2O(BZb{C9pD%~aNxk%y~b`{_5qQPA1{U8YrM1{2eCk4lkxzY zMw#8$zKF7`ZN#v`$z;Fs&>x2|`QWkgv4S)xA~s-7Dw_6ym%Q8=z6^H$0A|@k;@PS9 z!uCr{%w9x?j~qL8r`k1dpT$;P-Mc(XDX2L~ZRWX$IXsz>9p%WI^affktNc!#n1;{7 zY#RNb#d%U$Svt>g?f@c(P75<_M2N#}tAK_ifUP0`j|kGL?7iUTZNExE#XiUeY}h*k z)rG*zbJJEzuj6*~n5{#V{RFHEwzss((C4dJg_qEOj7};++K>uo6c9+Ot49{#BQlCa z_ZK8;=Zosw+}v_hUS6PABy|w4GMXbUz*oABl9Zyai9eVV|0oJAL_k&xswv4H&=di| z`}q~)WJd#9R8w;wJsqEsL$p_CspY>Mm7mzhzBOmtB#%6P8oQ4KkaVcl5!V@Y?gr(; zH%1Z+)OZtw@7zN}84R0h9>lhO{rYuN@V=$AGwl2J?xhBdgj|5OTmkKgP$7pz)6(wj zk)mw?r4M~XKN0vue`l?dV|={8O_ z?qI3#^WauXjHU5iFmqgg^XBLpX+1F|^)lpr0iEc6cwu=vhCdfm4d1IDe{0mIMC zVlaK9gv2)G3ohM&QzU#mN|9kE0S9=O*9F32TKL7U9?&T|1Za}K0I&#-(tLSR| z`861TJ8{^Aqc|~2x(wGU$g}nn^M;a=Qt}!bIV@2CT%rvYi6BlrEbtNlo+mtqGZPdR+DN&`ok1y6VPa`L@ZoqNM7GEl8 z_RB6(uW$`ySwkx<3?UosW6-?Br-b&*qm$myDtJ7g4FF*Ve*>!5u&2{(c%2oc$gp_S z9j~Y;{p2+cqQRZ9b_WCny@G=;^>VTmeRAk-=|XJ)Rx$>)tEMgbpm2?~s?aXR8=v`O z*t>DgE?==iMQAPK4bC;OgFIW+IM{^h9@YQ2y7U_hF$69zR)EEh|eQ^}uk>U7GCwIry5G{TzHv9}$CZ=YG-O4!+;C z=Zgjf{Aqc85X_1c6}ubGKsPXI0oU@;_OO9b^rC|Cjc`{~7el_1$cwbLwqh#XNJZsC z6C#wXQNBxaqN0B6eEs4VI&is@97n+}beW=d6VD85m@y3+rc%?=(w1G>ua=@;Ne?bm zjm^{3vlxjIgo1Q6>eREYSlQ;NV#;xe?|Bth2wN!_4oXl^kaLlWlTu;gP97#IgT~Cc zu71c(1+NNLttG!;``NN$Yp`-XG`^KiPEIKJBi*?IYIKOz|2!Nf&dN3Q|LrUoA&_z; zqE}I_VG$I}D6gM{%YNI#gZb)3&Oes?!FKN1Jz{j2i%rbFlb4s5B*w(lVN!GP%zn*W z43l<*#gyEI@fAun%yQ=<8Y`&ih+y^A+NOBhTT#4qrE!~rz@2_&fVPz>Cy<>1VV{Mu zg9|m$Iyg+RXG`|b`6XQYwBJ8Fe?4hG^mT+3?xWhHj+TFmO-Mkr;qv60^GZbtUxv@t z)z#rH|F^?Ha%`-b)z*d=ZBbXa=fTI1o;e33>ut>2OYdA#atw)VU_}b`(npR&YnxPo z>i|3Bg2ZET*XGTesqYr)QLUw95DP+Abmijr*S_MtUY zG)QH){PVY&W>@X3_7PXsL1N~pj`B^Z zaKkJ4pF$UAqeh4N8xoUu>a7rTwSZ-?308|f_6fv?e%b28Lj($>EM}ySN*8A)>*7Q( z9ZgsH^GG=27TfDUFJyVNw?S4$CcnJpE&${E6*`xQ49Mlnm*13@b^zW{R95bQ&Kj){ zWoBhn2~lM#ZX2kiYNChweiA6xXQZdMbJboCm)<5_L?>wfq~*W|VI@1Xan#%w$O%b@ zguItpOGRTN4PuYgsZp#>K^Q$*g_M_zU%JGOtLu*R0CfE4%;zbhDbK9&Y z;5_)k;vGkD8t1%ej_T%ySEV;2BrHs|Z5v_4-tym2rA@62K@yNZBYLyU%*-ntpFf`+ zXbedW2AoSpzvaZ4GnW`9fyu}`rIJLz~_la z+ad}z%?E2H*e8s)+?A5Vtx~*AH2|%ES5QzHl8nclqUOIGZ!_$@hqcA@FLYyIzh1j` zjcvON!op0Ide6B=sowv~#33W#M#1$z9uUFq1?yvW6gC%q{(Aad;2Vnl5^@k+cd%+p zJoOwW5??>mSxz-B4p!Flm?!|hucuyr^tC%VVHifwy5CfW z?eG8I_@OxC>lPlP(rkooKyoOYJo^%i4VDGO3(9k_vHjV?KbVrY9{8Z!`|QTa6>e6^ z$3wUSWZN_#N40s$BNnj!O{dI#1V=Yx-ZXtKkMRH-a87G9)YWm>)*4`}CQZU>9GRG4 z!L5X5OOJi}TSZmvbVL964LM4k$8CoJ+W9zWI&_^ODtid+aV_y3*kIJ+webuQMc3EA zfA1cN_rwP3ty`s)lzeY8QAuoPQ!2B#eEI6@nGGagc6F(DwL4a?UW0!6r2%J>prM7E z1Af&v3!I@w4GBwzTeF4`*g}4bj0A?kxH;XcIr|()y}*H{D#4i8So9T)L)S%67o1FTj=fa#S{-}>MO@SeTwAOUY@9BYrmIXRnEPPwK(yzQ&W|C zc@}`tn!-@<@$o_9Ia0<`NzyVktxVD_o%|f`srqFIR9GB~-gCrgm%LB5rgZaTTiK4# z+5_JQ8)<1*zjVJvQ{osb=n4+dQ{Ilw`FXC6PyIZQo8j#}vg4x$n9Qd}-8gy?_(?EH zpcAot7OQ}z)z*b^9c6*jWkZT8DvjDuD6{xIpF<5tKgobDotkzntij#{?Wrz7y6vWE zodW{{KF{An4uLn!>W~fJGCd>9DB0(wq?tJBPSXGp?XV#UE1 zjf|q7KGi}u$A$Q@)&Q)RS%4)GVm8L4dLD<=inepz!cov)dgOw!q#o!=q4rR z%+q24)AE(exphZ3aTd4*Y8YG0tXQ+v1CN;TO+NlAGpkJZGYW&X=taO+U= z{ZN9G8O&Rl*DEb{r+M|Z^2AacsM{GBLbHU5gA-d?S_HlAp481fschzj3Wyt34IQIm zw6tho7p`iV!$pv79v2u4R5lSK)aA?Eghnf|^Iy84r zf3GNI)LsaflEr@J+1kw{e|(cfFrN2&kzTtb$iMcUYGM1-`o>*I;;G+@e=}&l_nlJ7 z?}40}_O8G2Ofa?~j=$7q(We290iWjRvqhh#?0@iS_+5>U<*IsP(9E&7;)9tamFUND z?tVpC=B}wsIVda^m3_Mln^(TAHIKwNDmAK0Q%w;6dv`4UTrcAaXFU_=y;gOwaMtSV z(Rh`8Rix8=9fMe097CtrEf_Dv78HDV*r_ZOz1MsRD{Oa>6?C9E!MK$%wv9Lx5 z1WwBwKijci778o?w(TA=uuse_EW*L-63G@g#{k&(!_P_iexwDY_)AM28MW-JIUc}$ zvzXp)EkWxc(Ghq_K&NQ!&hVWw^71`5w`x4XL=~@=nrhRW)@tj9rh*$>6X}z72Q^+7 zOkE_*)5W(mJ=-@7FxA%8oxzvrT6>-rSas- zmpj}+bDI3axo|ls5_E9(BPB6VLPl~!$K5tIBMgqqEkxz;5t|jIzWc)?Q(c~}IE4)p z0dj%-tWA7{?Q^#Tw(*v<@-rbWA13L#cjkn>rFQZ}3zedx zBB*p+Mg?DrKMQ;R?!|F#X`u)Zk+g+zemGa*VAwZv?fcNudbEQRYIGKVn&I@zl@zqg zUrw&-u)%TU;b8BMhJ?_YNY79|Nb7odzt!}AwGHvGR}FZ<*fSSocUAwc#)nZNZ&lI{ z$)d|jM&@=>Hmi$Hv4__S*4tm^8cBn zs!ds>dA#+OS$H8ygEy@%=;=WT2_42ijrMCUOeb`tCMRQ=4jS8+5YlVAui%wq*I2;5 zBU1VPBHqHx^RHH-gNtX&TliyU$$??NW%gi^>=kAy1c!PEhY4f<1|d?Dc$JlvzkKUsM*yq ziHZ6Ih9V`UdVsqhiVRfWGWIdJwFGgLl9IBPn$sE9()05jE?b)7@2K5`y-F!Mz8<6B zZvOpSYN~@_;i+Xqvm3iw+Av(DQJ`4Q&0k4j&btW%!NO6P z%o#mVSVM1gOw406egH7tkOWy~);-2ULhIOULD&7@A3#M_oa`}P7W`WAJ*EF6O~Fp< zCMY7hUOQOxGl-2&xF~JFIv<(-YQWmb zP&$vSWe@xO9gEQ1L=Rzc#GQ!{BB2NamPoNY&=QlL?vH>^^3@UT`>Ubjx5SNIY*asb zHc-6a!*W^IssVWHx_+fZpI%V%^s(-KA$iB8fjE|+=5!t9N@J8$o<7p^9VuX|vrN9_ z5nxnAm2z+K=u)XBR*?QX#XwW8Ejccf6CwEwdp#0bnre<%z;k%vmzco3*s+h^G^!5R zc5atu8U!Al!EH~8);&YE^2eMYIsKP2+&|vm6`lLWjS?>(kX+W%KhD;eE&Iej5e-+o zhrzn_tDx+$WA8lPwSJv%v0_s@qoD9NF(*(ig5}|T`+%bQG2K+{kkC+h)K?X!3gQ}< z^ykccOUNODoGW;#(Udb zw$}2?U;EAw3m?C?UxAcrCmLz&2K(DM;ls_M zUn6#@aI|k<;-{gZ#Mj=?^;2%Aaw0GRoOso$yOlxKzd3jgas6Ilr*#!1?Vc%^`*B7&;z3dPWM*e}m(AdlBKuUA(v#QR-uC5b_ltD09x- zZd4C4FMax(;o-*_Qy@tN7>dA38)6c?yuFt?hvmOBNjm}#^g+NtU=X$ljtBRm1zC1I z|0U$92mjFRpD6U?Lg0zm9dYC4%_W=`-N(NT=Cte{FFk-!hIQ}Wolw(>C^H+>095=d z)TO_Mipb^1&tnEFlBbqmn4i0(eL{ipbxyJYmjLZu&(hMNlCO z4GgeAXtOi)ChNBu>gUc4Q}^X#rN@#3mnV;A6>mFWwu2C>2hv(s(#{NPw9N^@b;AWx zQ!F-rV~%UF-N4rdaK$W~JMOXG zk8<9i(LAp0I#X9$`|QHVMkqB{nZ<0VurWGQ@yyo%Ngc7$zv|}1+NIuSalUXHQ$ski z-t7)_U!%-C(n0YwL$#uMWP974{=x1F%C3Wt8hWexzn+`_m_#G7c_OBF%)2Q*&}b4@ZMyki|F4$nKx@c;qICUZqG)d4`D3DJ6JMMt)NOw|Q5Y9y8(x|A@D1q5t~X;- zQ~XC^^ic^pOptgeXHRrnk9-Kcp~`#bmwKIB1NB-(h%J`r_He$%+?o2Fq)f`qnPl&< zFE$6-LL%r7J|kc5g9gA2KA!(bjHjZOLOpI30>Y^pQ7p!`)KqiKNSMBlwpdEUmVW8m zK3#J0K(=`sjfmlWw{H|+3^tG03g5SbJJh-W?pPA{h?oPl$DZ_+N#%(1e6Q( z1U9pg+S}X3k*7i&^v`>f+kz`GK7RMEU5BSk57l1N>ks#nCRUM(O;0jG74a7|VjhY8 zw1m2w&mCRCGt1u7fPW=FeB&j!puwy}bMX_f1u|?hHf`FnK6$4L=#)Lh@$kZmi(P@9 zokc|dt=fHIs}s&x6h~}PYbCS6VlaNUw7*wUU0J^kynKXSg73;n>kj0q`8*rMkSCFm zSpF0BdgJEJ5f5#|;ec_{-YqHXCB1T`RGvTJ*1b3~1lSl5Q8r}elr?_X()ad0ppj#%CXhbY6mVD8Cv;SElTVmLl- zbpwgcSy@0CcG;n*n(vMsup)>(i>Vsfir!D3t`(o8^q?1A{nG1|^as&a5CAlSmv<3? z)OYVaC%$Vvy_~)uKB(^fr-j)PJyC_XA6RUM%cK-EH7hZ*+;Vq+VRoS&eI1I%=FJw) zzpbA)An(x4weJxM_BeEXC3G6y-lT}y+S+!kE;Tl01NG0OEwvm*!)I@crB5Ov2<{mU zQZ$xW4`2O_JoLpZ4?-tqPKlFR>#-?e*QH}S&-leW6tgfW)BTP1Q-{}$=$W==Ubt`m zv1FHH_7XnjQWc@x4mIg?toF^9HH0;gph^!SOr@=N`D`x#54zdtiH zLr>(?n(tQQZuY;xvOnwaFU|K}6&wHI#2PiB<+0&4y&rN!)rl_se+N_0f=RBV#3^qW+5D`HMR4xTZ_EyRSXmDVOBi+Es!fcHbV1LAoC7!rAoY8BL~av@3FP~L6x~+d zFbgeOJN>x>glYQD5)zy!+eZC`AVteDB>mplGpA@ZdT2c{BQvg=JA5FNgb?%#4gnNC^3V_XU&wyn$D^ z5n*M|s|O`eE2kK`Ee1aDky`C0L}zDbkvb+pzWFa*rSVA*HFfp!H>a51mY3>cXB^Ct z<)K_+o!wnYj&rt1kXBz5!Qub_qai4{W|o$UzRF5U-VYxh)6k%2aG2e&;^qn%kkJ=S zPFVbxMzTzj%E-tF!{JAzId(AVj~n_4TCbie`TauAT-;TY6_8<&_>gIgS}c4m*#;rM zZ7#8_d}%vR5!vH4p|HDq_Yzfs=$t=Cs#3p)~80qI#< zn(0WUf{xaJ$%4X2U@%j&f`QlKq5}QC3)~4Jz$4j;P|Vg~XvrzpL?tAg zP|;9Oc;#IvOTK#TPQVvWhuIeocNO3NU%fic1MyyqO)j0WyHNx`lqxIV z*EZ1^x1B2B>n)?$@159$FUU1Pp$PWwUUS4xDudDCFR=x<%ovubxvwsQb}N@}C@NHQvWPjX!7bizq4tf?a}$@6*0($8HYFY z0%Fi7+^^NE-+yzxg!i4*3|@pU#&v#3I;MNWQ52sV-d$SAj#hXn(=K zLLrV*OIv5~#oO@5__<&)=tS&=BORO@rviomznkZB?NI`*nQ?8^2iODSG@0L=ovcmx z4Q|H+(`n(C=))gpUjrUmnn>dLZ#9N+yL>^LnAEiu0LbKKPWfI-Y#FA0J66IzhY#|* ziqfJpKGdd3$TpkHRKHtT*zx=w1sfW{HY+;9$zS%v$!}YjpFrQKt*=k!oRj0=)*#oR z-XtVtYilczt7gvf-)2ftEd%Y}dF%W$T(5KReXx{PKHzR-Zf*$H$*iZLG5q)@?mj_> zCeoXc89&d-9Pk>zL?0wgT7ejI)8j-IpY-kvSn1A9! zcfD9X5S`uc^r~2f@|~F;|7*i=VUx?r6>xAOduc``Ow2a)?SyY5vw=#&;h)6nZyJNC z69Z8IjFJX~!uNUZHi`XRre*hyy$F7^@{$?+Y6-eU9Q?2<>zO6FsFJ3{_tWwso z=Ys%5tIw|rTfL=UFF-_>8`-Pnys0;sLOph2Mt*yrIr(DUUc&d$4*k&~WaAwOes&0@ z=+VyCyz>7n;8jo{q5InrPInFqX@+4#V?0}oceK_Xlb4ZUM0<(JLD)URFf>)$=Btk~ ztZHR#>@-hLyYP+ldzXXxhS1qK|DMjy;ad|-Bw~Tjqv%5zpH7}U>s+OE!J@i*%M8H_ zEu0qv-@U9o$GQz$FW@jzlK$y8U(jvCaDlzgem~4+y^4o2voTk79nk*bY-E8mjZr2r z_;1rzk^)!SW?5a`-3SwPc6G5n$9FsR10p_hG5+*o9OG1g;C3xUB8Z*M*G{bpqu1O1 z@GRsH0LW>5rXK~%sPJY;_!_8ZopcpTUbeP|VDaU1vyTN^W`qR=x%zLbd|4QCR1!(M z1{mz#g9lIItSv1&M+`lean@VMRcj~4#1P8>&&6g+9Xqy~R$^*$7opO`elefTtq4dBe|2 z@L$Yq85L`Nw-2qY8Z`2kcxmzcc6N7vYHxpM{wVK&!(#dPu&`mQ)W7M^8LINYpDhD1 zLs|Tyeykk7Q$LuY*7s?Rgc18vF95qG)=r7*wDt98X|fQy&VZ<^4Y!2wHJ{4F&Va&7 z%RahagBFeGsqcdp37F4cWhlQQ`>5ab62!oC-|)8slf={Og>Hf`jS};upx_ePK!C^! z_u)^GTbr64e{~mErs)!g9D|dRxR)+lig&tZ-gV$cK}Q@pj~7)@RC`_AG=cSk&UPI4Nn$cmC;T|0dLE&G)bi@PL&SUCf04f{yRH zL*#DvY|m$AMQ^nht+2;4VVxCQzKWc@J+F0+L)Mk?M&Z$%&)He=Tdmd0w$aiKUQuSe zao5YXYHl#of7@D@1b0dDFzwSEnVRtYB_$=Zc2V;Q+KxYskX&DI@n~uGjFpOjtcl5> zC|URx>~|bJn7H2h-jL)(f0Fio1||lw1AEo0;qJH6Z*(g;G_Fhpg%Bp0q=Iz(HK#=as7JI z%dDYX0za^u7|3biUU1@r{N;kc@<>7E)}u`!Qs6+a>i<|;o@Z8FhiW%P8tt>>WTUy+ zqJ;)p0p61kPXMmlbO-2Pg|AuOdfFH9l(c{dT@wQsz4Yzv`PWMzKyvFHm`K+aduc<0%t!zW zc&m~5PEkO0Caucg%Z9mL>p79JNP*eX<^COc#Ez2A__woo3ou?@ z-jitTY;A?|W?F_GyE3&iy(=S^=0I*JpFOU*vMOPX8_w?=Tj77(k{3{1j~U>DFU z9|9MI7Mx%n6cuZ=n@}t#5)hc zcR+@-{M9Q4lhpXId~s-#1bqdUxs!NxaK|dmqS`p4>dpo&nWj^Vki(RTFgX58o_ge}C>9cGna|%sR2E zZ^Q?ARTe*(&^6e-?ty?BGnLR9#?0Vaw}cK9`-gl+W~)_ej5DBH9ZtJ%TgCTqwT%%9 z63eAynN8|9*YivD73O3m-%G^6*`mp>>7-mZ%e7EEnP|PxA99^a;%R8Do83gIM5}7( zl={KIBY4Zl38VOXY4vqGiOx1oQGbo#Vy-;4R)bM9N6*S_Ac6>+`}97&C-5ymfMxNs zj_R+@Sfm^`XEjNzBPw{oUjNf?B8Ws)+`Z_V*(qWczs{?>MJu4)sTqTbE69YCLE-$v z%3vQNUHTx7AE7dA(-=O+M&pY2da*NWv-svZa3%LnRrMc4p%<=fWJsM^SYp3lo?D0| Sd?yM2$s9RxI6*?|+W!HODn0!G diff --git a/doc/salome/gui/SMESH/images/eleminfo1.png b/doc/salome/gui/SMESH/images/eleminfo1.png index 3cd439b76df0733f11f26e61b02a9d9a971e318d..3e1888ff2b8fc83798dc08683e5806637233107f 100755 GIT binary patch literal 25423 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 SErdV1L^g$P4XIwg@6=y~k>S4p diff --git a/doc/salome/gui/SMESH/images/eleminfo2.png b/doc/salome/gui/SMESH/images/eleminfo2.png index 54fe12df8603d679a5549f3e4e7f1b5f1fb434c5..ea73500bd0e4293e6c4479af4f643ddc5fef4447 100755 GIT binary patch literal 34840 zcma%iWmr{Tw=aqcA}OIFAtGJUwE-oirBe{4yE_b!5)hCs0qK-(q@+taq)WOx?%4nL zyyx6F_dfRnTLkvnYtA|17i0Oql#{^1AjUvJLBW!IA*zUiaxDY}<+?TcE%=E|*+v-( z$|Dp>(dWv}@#}wF)Rhg+e(r3UcVVJZexR**pYE?=X>3`kWnvm*m{VO>o5%dZG$t!1 z%gQhPZ*OVtV3#TrXQx1vb{~;QF^7}F4bejfPcK}2)TXB&Q8DK)Dw$afd+d5V64?{& zHuvHec`+_`X4W%nAC~3E=cBw7(V4rCaMkoteSuCPn)Z6U%C<^4A&F-$oSnW( zSQwo`TRZ%W?AFt)Jv4noLse}Hc&jpf7{VJjh2ZXdeyBTT+2DZN$+1#Pfoqz-TJ#ef z3UBL|n!mBateSr>%ugg>#zYs}lYdJc-H@R>AysGS)1~t`KrD>Z~Gyn4Sj(Gjw z0uMv;3fwv)?k&C*#t~wkY?}+Geel7GINeu)+$6 z$DBGlTC|>0i7gbqMYhT zRjp_~p4f|pP(N*FYNS=N#wC0Qb>f?7Lkd=XSVTnk`YfsOM$)fk3B?M>O@gb3WA7&` zgcMY(!w(Pa?>k_m=Z;I*&N=8j9E{<&-#K?p#qj!-$#Zd}Q8#|^&=g1h`Z%Kb{d8|= zL`=^Y>}%(E;XRGLhlE-34lINL>-YcHt$+pHdI2R3$uUIZkC@m85pqA*n>x-!dj zeA4NvgcvJQSuDNAiaML92E`O+iZ`4YJf*lsIyL8L5iD8}XLY*@ZI({K?R$!Y9J%Rwc7u|NTV~Su^^8Tu55toC zie^WY^ILUj`ex+6^|y_a2jf3<3MX!$STL<=V>Q5Y+F>#MGj`o)clvO z>@;CXtkhVlhrxK{_oSa$zvW02|6OFcAUjbf&?=|X)R{rNp~cyvm7(ALE5X=a=f;!` zchrD=N$y5NM1sQLO25w$_tkUvNe9y#J}*b6+vW;z!rk|%uQgCOJ7gj)s{2+j#n$Y+?nRpWmDOqcc;e4$5_HrkiTISRkK?>kut0P-b>*Qk z%rktwT3-qDSDUnNiI~8*YH3i;Ip{2?EWo%gAF2EVzNT0{a&w7 zd_Jt_Vscb@sVxyt(L0{okmhCF6TF4RSNdUEKB<*vCb(w6nCCa9Q)o3`iG%DH7;fV>KbRv9oQfEeldX&<{pI)j28FNad^lE=I&AX+1 zbReFlY`vt2xaP!>tQwRZEo05e>_3Boe>AlBsG{XhW`t9!GTjb)=9m))VH(@k*O9-{ zBmJ&uFY^NKX_ki7vuLMz1pbPzj1(5v#Nb^0W1&F)k*{;fmhe*6+w6yfsLspFVBV66 z)Rte#-jNcLdvue#v~*K#ZcI4)_vBq;BYc0G5BJ7;X^}~tP2A>`t$*2iMO}@(PVudU z(ikCK$MCFzI#u<(=IwjTx=lHnq^4(X19hP+UOLjtQAr`J-?u!pYZ5<hS$7t~6x|+MjV1gCvRrinlWr zvGN+8K^7Y^x6UPVFK`xLXu2v+5$-25yzZWM*AO!Z(Ywri@ zs*u-|NXaEte_$=VMrKObPABQSQu{Jn+1TFogU3+(IluqRyKHUwp2wU5AK%fdWNlbI zVy24g>XO;l5gg1noH148s!S)bPn;UuXU7eX_POo+%>-*zMXA_$z~)VXPJ>9=%%6MY zGYixAO!{cO2XnRaUxm*Nl5O9mkh@U)jxI1JE>}Kb33T<;;B78 z)tK$GBg0VQ;}%@=jVO(q^dei&6{p}V#Z>(IY}$EL0dXT_-um zBlU4V={1>K(ozolQj{|@6~uf$)R^!))O_?FBneYe+Bw>vQw;NGZV<1*bp1+mXN9I%rFa1ZL3~Q9Yjq( zKAm}y?sDumT=n>X>A;Rm%q(j*yNF7t?{4<9w(T$)ynLpg((Ns4?U|)~1k?aKsIf&a zS{C<~(aoK4-V2h&^Lk;`HoUNxA@YpHOvg4wqsKBC!>Bts;p5KNStw|Z-8an@P3!-r zOzbb+zIb7k%Bq+0i6)*e>7A<8vt&j5nY_8xZbn;MTLrh3%P|G|u7iKV$&pL5_Wd(* ztp1FG}xjneNmCTquTcDxi=rJ5fVvle=J@TV$o%XnsEVU(g}X-G{?+r_N?uo=u5 ziWKVAmB={~&Qerrk`~+ldjqk5>#GzYXH5i2u-wz~yVq;Ju3s`>_s!Z~>xp_! z=VJ1J7IKpbj^ZWse9JxL*3QtzKPyezJ=oqNRiRS;wduTVHP==!f~KH>i8G|0SAfuC z4k*2HXO6l&M@^Wzlcw3d+-k?;vX1y=dd=DRfKl*Ed(twCLh*B@L1LW4_}O(QOMzdGxx>6XSqGlANZtM`)PqSeGr-_=i1&_zbJDe-}~VKKgGOR(OiFWFTo)3 z9Fb(@6h*VHgOiPH{|yPbZ~ev!-)3^Ai+MfPpO9V2JoM;p4r!H39bO%Eqxb)QoMUW% zi$ID{DlImNIp<`x_2YLcs&B^`o}Q&!GXs=6&F3C>6Eg53q?$(h$Ic!0lPZXD1ceg2 zvoeLAI;)AL{Vv=bVU#1~^@*~=dZYMgZld0=cK;r65H{3%g?iP+)v<7AwL7oH&6$|v zKR1e4%}A4bT?U+@CNw;RYsyCvs;(7pzCf@VT^3epV=#K*&$>#Py5#c3HYINfafWCq zl9&Ouq|IUu{#AYSo@PC};1v^&8%y+^Bc(J=CR-1?T}O3{o17nn`&RZ{_zfb$h#f?_ zB-Z(?1cpqxznMDTl2VyErZ2sPQ+sXt-D`yXEoEYhsRT!@2ly+O&?L!R<*2B>Z-H*GE0FrLM;6tcTVEw$+`7xK3OcQJy3}!-z$$F?r2GUXqBT`WZ7RcFWK}NE`87~ zU=P=CN|k>4c}iSzi$$4??8czkhn~(CtKB!wO-Cf=lO?iteu^w>n0uHrMVW`>cPG}R zjw6o0zp|kn)ua`}G-@eUHO#q5NlJ-Pb789Pew3%uJLeYU8u^Fs;RR~mF9kD1AJLw> z@X)i)sayL~D*bL+TX_So_gh}?Gd;B^6syemL7&*NzkhpXz%3n>i#vm3ThqOQo<#G6YUC18(iOP;@>*l~tu-GV7oAnxOc;QKf9Yp= zhfi}glmCk%Ef~*Z?umFk3IRr1XKS&zCYdn$?4w#W9j}-DG;)!ApUSPU>`2r?jDocH zaE1L8``pe5&LRbzKC7vRMoK7Z%fxicfI6_Kd_0~|H52u{;{GMR=593+XaSQtkrFNH zPjD-xn7wfu^^n4VFpo@_F9;02lDqIa`&1G>je>+4N$S0up18oP^*=HJF1At>LP~)? z0;5(=ch|2x^m7+xQBje3FlD{g*q7<4gRwoYC-hN@R5-PAA*wl4l$1?l2U+n1Gg?DY z-Vbl<8xmcOOTw?@GAJpPJh_b&z7?L8M>&*z7_Id1>qt{>M}5S}8FB3GY&4vvC_PN0 zlCC7xup`Iy@FYIpKRo2Y=h%9!mJ_3-s!u;-W0Aa%S$k2B>uM zhfi=dj2I%#$v4Hqe8XFeeuYOQw2&Tb(e7b=H+(J2tXrvVxWmxsH0{y4FhXs&*g@zU zmG}L|<2CaZhTaX4uX(?d%Gege5)wALswzJJsdi%Le#1PH|7t$tqYy8`Lstl#&kCYKYWzP?^LG<~@}+f-sP5cv@eXG$^N{pLtR z<63I%nvn)=uLWv+wTEATLO#yzOZ#maPrhS(t@`PXnTC%sr@sbw<7@xqYgab@Ihyq7 zwCS)z^$!euyV93DIkqiV<+RrG<85n~0Vk>%o7bhgFtJZxt_eGr)s&3B{*xdP;(-*g zJC5t4dQR~!drNq~X}$X*lg+2={vZ%n1*MUSdS!D9OG}D5hD>(xf%jP0zFnaZa~Ze2 zMJ1d6ohI#gLDnPnXxic=n18e4Ba>FyS3dFQWsX((eSCEO#bsDuZYYkatl%$AO-&I^ zPn4NRSC?(9Tp4=>Qr5oWciP!kk{|f-R^n9PcSz7fuGmh?CzFp5hxYpNsyj$etG zw4N>=&^flCb>2{nofZ@jNDy#4d^(@^VEw{|#l*y9si-rGh5gMjdX?kfjuf###`I#9 z$a*=#b1molqdLn0T26N&wI+hsRdgn9y||v$)xqhqU`3n2@353tKJ})9pp&#g9?k2` z^reSP44Y3|+l#&J@@daFHR_tio&`aqV&dYzOU=~EEdO*!v(z?ESk+rN zc@)_doh(gQ-Dh{i+&afh1>W!0!xW3n; zJ5$TI> z<~h;87=5vtajv`k7hPX)$%=LiP0*r(=BmXnOmf;ZMj zE1TZoMZ;s(VL_jWMMtLE zaYKrbrv9d_Q4{}$)T5CC-DN0AGKq+oGK=xu)3pM-g*Lo=U6yK86bXXz&GGTzc)WT> z$?I9#^iN#$_4NyF=EXmJ_{jL_0p_iu;$n>|{j8SbVxw+q8XDhgsJEV;F7}_>&rBP7 zRv&JtS6EYU-?g+pSXG&d-u*PNHj(SXKAitb+SHUjM@UDuGm{5b7Ss@40f+J#L+Jl-O zI#PYf(<=WB*}wO^9r7tzQ4HwG0aB>YlOj;EoT) z-PtH&NxwEGb{b zSnjlXKZupxx!4&cDJz?|LhmokR?JrEzF1_RzLFy4H7=DUn%d7(%xozi=4;m8)wKZ0 zJeaK!m@|^EiD;$J7Ex6tg53|_oP71A1kn-t1ZO1N>z-=RDyLsyNO+W3<+u2FlDWD0 z?Y)Ef)zTcoSEM^3ic}%zG);GeD43-jsg|U~)SeTB#l)CQ(GBIRRDUp|G{23Bp1VR{ zk@kB%O6t${2@%R^(2LhwQenl#lTE>?>C1Qa@O9?(wX>YDBFWwy_n9Y(pcK?h;?DvV}s#i9? zQP7#3zi5pP{?{P8LCfLS*il)CC9Z@8>rI7=y!f&=1+d^IwhWFcQo;sxi0E|GY#k zG48+q^Nnw|YR=#BQU>~nfJ6Z|qRO9dH~g-mbUkO`$|dGwMTl%2bAepC4O`9mfcC~1 z*h8J`3UmrtDw%`yIvxiqOT9_*%ghO5&hy9-g=c|uL*P_`BFkV&J&kh_U?M}IEX~=LJbP%{6ZFWOr8mo3%B zYt#&>sj0`c<;*aWs*1|&n6sudVlJ~L8uRqH34>VwfNCHSQ;OHsLL8-K`z$oVNQuh`nBhR_EsKmt0ZQDp? z!+(Nc_h_uX-?VgLVc}(lBWd7P!}A913g?Ddp63o989SuH5!i4u2~`eosQu2y$XC-+ zOcI_i$j0k_Y^_?L(|u3ZyD?ks&JZN$}jNLUi6DUEqK!)e!&H3jbBv$cJe=TU!7c+}tBs zoiF?PQzag77~>`;CVnR24QukniR%;=5jk0m(tRN(mu@zakL;0R>DaLRaku;Fcqs$-fBlwnC`y^O=39f6r1^9M2nS`l_b2j-v0PBcge^s$pjtO)!)2*D=8!MaiR3EC7Auuo{lfq*Ul~Hv3d* z4p0q%ao|#S>^)vrPqQVh=%+TizGq0n1i0J4Nx+=R$ko*~v{}!}t_TQlpx5wMWh=M; zfD3-CF;R-;wvq!Z zDG^MfHZsA9r83EhlcyRep33SKd70-; zo3LB4q`+LhS_aF5Sh-$k)SLKNV(#70O@|1!(w;oEbjIk^wnw+LQ z8=vND!9%GWopjJMWhUWwzff(W!gJ0E zh0#MZv^UG{rhG#^!@u7i%u~qRw?*oG($dV zH$DM3LMMv(6*>-1l!e476g%d{LlnzO>W~jx-9*Bp@@1s6roiAp>4;ih_qKjmw1KXs zRM$=^!G%I0CGyX2k4jX^IBI=pv5d_5FE1~ffBoW1<`P!6?xcMB2p1(tTqK-Y_IR5A zYCh3zldhLugX&e!9kuZK4P?POx%5F{70`J1=6+FwWbnjl}+~553 z(2B(>ZY@7|q)~(ZJXXR{j!P;cto4@QFC>d3qv4^AhPGSyrUm28n>WX2>(km*_Wp&1 zPlK-<{mWTFe~Bjd7I00^KBwiSlISrGo{4U6RXk2`Bo0Xl|gPMg85P60Q3% z(F5G$fuK82(xU1da zq{iO%hiMB77U6}Q?MMkZM{E$Fa?kWhfq0hRUxs@#pRB;s)z!5vvU7gh@vy|aKg>Wn z>WA~roAf%?2rB8w=vFoQ2ofIackumFk8%4*=2sX$;e9UK4QLubT7cQU25fIWUednm zjmmp_d6-sUEX*Zm%^Fa2r`m4*h++0Rw`iP-}aZMSw@_Q6NZ)%eD_xHC1zuo3g zcju0gSy);K3r`3?>igPmdwyOt8Lurv9bVa`&-TM?ggINSz;eVLBht4Fvt?u?iYc!A z+rVFRZ0vL$YXK7nKU)=N53`|cLg-0vCU7SFf`S&OhL7NKO*!E@iy+2)^Ef+%EE}kD zFw4oqN>h|H6sHF4x4&;6SQJ+Fue&J=HpYl5#k6SeI8tLnw!VCINvPb6zv$G7#_0#O z9j85xb^wP0sl36)#um+OMFs&%=P0P7qZ7~X6|7lmdTo1hua|XgLj$&%S}vYeLN8@f zLu>gK7O|+aGfzR?VRj{gk`lExBXR$;J)oJ|#{)}V`LC+EK$VjM{Gm~58Uf5|A`o}x zIunk>CT0we-eaY7nc4Xe!F0)RYG^@CZ{l;i7^@sM#32$umk6$0k5JRm>xt*x-x#(`Ff3h21Z^uuQ=QEWE{85a zP4aIk{4ig$J$DEBCDwtdb89MoCw=H|Znx1wX6R=U&ff?f;8^e9zsDqFQ`aO-5mwjQ zB9OY7Gm=|IyLIrA#Z_Ri6VU@g?uYj1p&8 zhjK*4#Prx=j3N9%%~*mTpnSg1`T+{bZWE5sYql8YnfGX!Y6WC0_2+CTNnV${kld^X zt3z)=D}kmSl9A}zfvCkLoZ6*jIbp&}?Qioq`qK(}be93(AdrDR0lfdFOwXjrC@Cq4 zIGVJ(aqAW!KaqORiwY=!VvHYfi9F9XxRFH-As}!9rPX-6B&(8Hil13d?c^NE-=QLIN^Iqe*b=*G3)xqX|0 zo<0Bs+34~h09xu@8Lub5eS0K$zTL#8L8ic4Dbv|Bd=T(qL>S|;^p`%H#`(vZy?WT` zU!9$SaEB;z@jQBo)LyBvPxU^C&7nX|L`8whlLj~RY^u}NJCpX~Ev(02i_oiN7Xp<4 z{Z$ISe<3T&S+GYb5&VRYFLtZ$EVw(48=sW4+YgVji&gM=1{E1br-vJ6o`1uAeSKTp zWvKD}{rzQ<1QYC*dsy|`zU*qfnBCQ;b|IMhd#}bZ)JyjJwyqo2L$1$o(L%drx!=Ek zqkywgYBqlU1llO4UG1)JBBiL)4-4I~tT% z)sATZeo>IpD+v;0%mV!Uo|g8*@(?BEI;6}egsM>fYcvACSXypJJ)x^P=5m3 z=$1^K;S6=p%E|(r4*wnN+h5VXIAn-up{w)ok`fNpT=i?u&JH&^ZGVVT%{z`Day3ef z@lqv1xRS1z7}?nF*6Q>EoOM3iC}+|X3=Iv1Wfpl}xGr_a8Cm{ld-W;>7*$!&_O>-t z&L)ti|4!9bi=Dt*?z02v3v=I8L~Y;1J&*N5w4h|A;orJ|`?x4o6r zklp1Zueq(QUVs}hoMx&ISRyiIv>&_h%r`vK;@@i}bL*x3_}QuE96 zlddG8tH?E4@8WnqhmP~Hak^1ZEVK|KdO>*>OYJmC3-HD0anolaXM16G<=_rTLxfvp z6-!8osB%)!<%O;Wn0oG(Nr;7#Xj}u4)8OjbN{?My+0N7oIij>;F@=5-4Hkn}ga%oS zEYVS=ze^ApQ$At!*E;el8wm+?xGnOcih2Tyo-pB{0Sv6!m&f0hDR? zJuH-h+QZlu=Op*t+sMjjYoS-RT;}#GcyaXyu zi(~CuwwSh_o~4gCf`!hpB##&v0>Npz`{04ekGf!}T0k&tPj(IL6pIX@Z(`nm`fhYo zeW@#^$?I~De3|j9wFc~Bz?yP@q8w4)gQu@ioLlVK;D-3 z{|+q8x*cs&ArK^xCf>L40}_soroH|#68_pF)vqP89G^4Wvjqk1jDWNaeT6hdR#5Aa z=mO!w#>&bnrb+6fQT^#LDHDd#-p&qPnK=+}q;L(y6NCVho#AIF336x)dDDlE#F}5) z_2-aMghQ3J`>ZGI_16|VGJtrEAl(Bj?W?ePdwR5`s~-=QVH>pQYkg_b_x7y+8Y?J! zLr#4brv%gszER8OUq1VlXJCjx!RNv$LAp0^_efaP=yL~gu|Lq0S!S&V+t)G2ivvpo zu<SX+8OQ9Y0cKbY9>uPQ@5+d9&MGD z3SI2uV-a)E9-?>ZvqAUhZ1{+F8ylMor+3SE2Lc!54)q`wZvl*a?&0C&4^5x2Nu|uq z8KYQqmjDeG@>(=(!5%EMg;F-Rwknldz5-Hf>41PnJe;c`;_i+x>WSBz`T4%Q%(`*0 z-Hr^qqo?N=>>_l+LZ~8xrsY?+TP);~Uw%`}GXDMjHsHi;5Uuac9=g>*P066fE!AYg zG4!7Z$Q@`TE*G+(@<8&;JxJ9|^V-$Op_}%VPg%UJsmtZb%75=3U!HCK9sNNGVg{IH ze2(jFWfl|h>eWRQ{*ASC1Q@q4@4wWK#$9aR2$wL?BAfQQ5&)m*F+}{ziZLiDP7pE9 zP`$_MJgURZG!7T?nU8G2bO9Sny?+R|oE1JM&BCPy8YH-~ck%F^TU$SEXlMX3`vo>H z&Z^FYtYBNAt~B-XTu(eT6nJ27%0NZ2QSa|E3$3qG20#9oYOOg|S46iArETy33l{vE z3{51dRAnAWmwgM&Mzs?RMhRfM+lPlp`Gtto4r7)PVnk|Um&bLV76r6Sb{w<*l$$6D z3JOH?f6^9e)dPy;KB_v+efGbC69s0mlRe{V*S63$&yR2-G;fyqME` zsHdmLs9yLE4m&(Dk~%L;$`I`8=9ZQpCIjh@4Uhl_U(omo^L(733Gwsu z(^@6zPmEe0t`a)M3zz8Kiwaiar4mO)P(LFwDZ+2w;J&yOKOrTsUXY;%`P}?g6 z^Y2<@9^Ubhu@Dne-ivs>rcX9-9*&!nCd@3dt#&7*BfRYCnUkmce?>qowkhDhynoE#w|9?lUm5!E!8h9j9Yw#|IUl z39!8Gcf=Ky;!S=L|4#ytb0E`lS{rVA;X2}e|U`9nj7#Pqjx9moeTPO|d*;TeAQ8y% z8HlNl!JPbkNhvf+2mvN6H~bC=OP9TFZWuKX0@$LQqZ$Owp~#>!QY$b0)h>Q} z-lRD$pgL#^W2I*IZr{Fre0qvh^#BE~vN;e4D+^jiA$~gA79Md7*Lj?+fIk7i(E#!b zEQv6D8oBMm2`m1bSTP<|NlE0$#kX84i~$={Nvf`U+!p8@9Tl6(w80~I1tp;HqVLi{j!b0Gnps6l4LDyTWMtw1ysRi@)w#SKzj}-Br(0W&<=^9cl9O-L)GxZ~kytQw0~dD`UX*aNT5Nf7pDq@Y*{# zpx>Y-JSuow+xQ9dfiS>@YZbOFhfNZPzZj3Jfl1semnA!qXuNqvsGp-G`VO)M#q;vS z$gXB?bixD*0@mMw3><*g2GA(oK}~_U@C9~0UMd611gP8Lp`i`n*#OX|D;v7jSLfk| z0vJ?jo#%vq3+ii(SH}MS{^R+-2d8(d6P-8=8<0z^ge6v}fJGz*s{s2K0GaHYHz}_M zA_h(L)Yb1pSEWgGz8>DLFL+Zws1zGpB8b=rlmY2T#$=GFktBHZuTgibPeuj}plL&> z3rH#jTHRh3dvA1W`_>~HK+LL6+f+ZGPY2O?TYH2d0{Uy+oFI$?RC5*~jgk$!V>yib z-cg8r8ja8YE_Vmq78zq>TId_zpFWMR?+j|9`9hm{{_z$t*Juutuk3Y2Bfa%BtZLx33nEH;}`mYX4svxFm_NAIAJ)M&4wW6+@|J5CA7Y4JA;7 zQgSH0D}ta5S}#ZX!NYb0&^mi8T`H8M#nCCGIyb_7i?zto{JEXCXCC8R2b`JS%wO(Z zxCB!+sgSKJ2d+qS3czr;L6XPe1KC)PhSyK~0L2883t6%cLv_22fgzlwtT~Bi#1Ndi zhr0<)-It*R0S0Clu#+*E0YQo5vUmdlh4dh@9PrD1p^^d1!_C*Nm+MUwa9K`p>iXyE zNuH;4KYsk!-1@74ljMO~h=bxAhexYSU660&FYw47epA!%eFc&I8 zHVgee*=o8DB+dTGKfbuZ+xz?_*$Sn4(PI-qB%e zn$Wyq0B!`MR@rC31a@=Hw>gMqLv4TnHe@7uc0ef#2nvsg5PR_g9mZx1pfQ~v)n7T# z1`EL6!g)z(00nZ&R-c^yfKAHRe04E>g-1x(0yo6teq5-uMrBD3p$7&B%M%)!0T_zf ztXg9Z+=c1DDCmz!cM?dUs(Cz2P#~>N%v-3?3ptK1&E-klmMJEqCTMWfDkkXZ==>p^ zcN);hks^(1zIHo%FG567F-&QV+LHXgj2}&sN8Nzm0gfYi`St79&3~pJ2RU(}5t@y%z9c}*#RcNVyDm-?- zM8cdYPZDgvKYbAiZmoSHTcP6zXmeZvqyZ*SSe#8|NqOSLqv2LskXO_wc(Jbpt|dg= zcgU9YsoDwcL(q$UL(JIokpkF&0knF~sIk>()@e9ym^4e%7FKuwpN72jTuUHuZ6bg^ zH+N4fW7&QIiE4G&mm+XAH>dTn|h^5R`#Q zQwTi+Ncp9r^WX=*IOLZ7tZ&7|Z^;WB5Ny>RkvXgm&O+T_`Kl-7^%kAL};Yv9+f1nKfgJy0l&nHlom{sJ{4 z5nSCkoX-Jk8)_A3E=dx+O0)#KTId;trOdoliBwcncz`^mq%csR?;jsK@4E{82h159 z9DF?B0oJRixOkD%*3=u8-<_vAbqgM3a&s6X2ybgKz{6BrT*K}PHL#$iB0%3Ds)>Lq zr4AJWPQ5I8ShMx>$-T8ZIweufvvmux$cSrHxEZp&C$zlvU7DVug57GogboTT4HcCS zWOAYD5WO7~hR)+HuPbS2Z4?v~LN7d?e08#`Av{;t`P&4cKcK zmkgs+-nfT_LnnGrCipJfa{*Tw;;uuc!R4$Mb8ZBgNv>=`FhA+&YJh}*NYaIg8lcWG%UDL;Z|1#>Rx$gWQ_DCLKE$Yl;vGzk#Y zUm@hZBf4G|YB9LMpd8H7GlhIWN~5Sah@UWk^4FXA_D%tyB0K_u8_$5|0ShR~kwKS0 zBKyF|);#-Q9*c1fWqLyJ6>LmvLD@$9^Q-FAU3^7JuRB`Rj!ZDo_ogL)P_7^x_sh{# z5D<`S)`#mFfk)P(|6bZ+&|zjVSJ0eimy>t0HjhNmAK^Oy)b0rvJfiq zpL+ps0431o{MZI)K)_@^gEu9xbDxo9z?3_nir@oM1Y+C$T{8S%@0n&z$tgjAh{RBZ z(I`8*YTXCgIq*AvZEEk-f6l5ADM7#{!?A5PLuo33@%P3PNaPot^SZ&>-=YFfgweGo zH$PPV1JI@H?KuEm8o|WZlP6DR*4Cr}_KyNO%~LJzBJ{kOmD7SRtZZo+bxBpc_U~DM ze*P~O!%rayk^db;Jp3?YFPHGc#7{6R2Uf~;Ij4H0}Z+vo$jWKxLG zWi&8wq6b#(VN}TS7#)4Tv9WQTnf$-Q+17S0kaWmVo$Z+h5QJm!pEsy}EZwa3@bGxR zWqu#*NkhOeC@@X+KZE*Te12&EMm-Dw#kK7=%8+en zB-aaJ$o%m<)&n;0NG7f8)-bYP-MKe?&|hw)3q%v^C)~O*bMKa-8&GEBQcd4giL zDXKg7m~Xs><-xw?wD-osPzx>r0kSmR? z_SC3{BuA369syG#pFd*;vZeN;zurs00yzW*c@v%IZi7`iq-0t)2L=iTcz}_N8p89x zg8oj|*C$9*duOi0p;K~je1-AO{&d-g$alEAyCbLQAQ#v}*nzJDhiOEPf`g)q6!2iu z*GZEUNz*|NUmGcCef^Yx_X0+*+u>bESm#5JK%;wSHR8Y(Zew9l@$$w1 z*Ma_}ZT>2^g`GGElb8cNyuBIHVxbb30_2?keKJbAPK^B@DlgXiM+^C|1r!{naxI~R zlX%}kCb%9%ekceP(2-x}{MqfXqM(oXe^UCYX*;s8`yCRFj$BhyQ%H3hfUNW!?i?2q z^MAL>DN0t&VU3YNsw<$hsUlT^#V%w85&e$}!c)CCE5-ESZ_P_|1%-cUkCgBPz?`m4 zlT=uJY7&pln@~N%G>(F%SLK$Z(0Wum>rPi0kVXxR+X1V!-<*trnKPc^j+8Ien^l3Z zhsAGOvB|v7Z32tHSGY?+px^I+^?L6LAt;zgCg2K&Hf*i0m=nJ+0mwj2514#FxO#KN z3)A5$a&CQFsv2(2MNdFSDLpv}YZSaXw-dZPehUxN9M62jK~B~ID)`EtO`pr-amoR0 zHVq7Eckn-eSGH;&!dz6*>xS!f$8&dJ##(y4hDk%C;lT}pI0RBL1(6x-B`OAn zJMTcW<+Zqc+zWLT+$AIp1T8!jtOD@MA^tcE?!oCA0MPghp}??%z9uz7iy|IE)(t>CH!@6u74ZMZi#H<% zL+A2NK{iC%9TsJE|GPbho6)VS&SyP?a`eZE90oyXZL96U?!20ws%;fh*t$aXVoK2# zyTQs;^KD42#y22KqTzGh*QMGX-utxIvm$5%C^FV_BEM2UdgJ(_g`dK?i}6QNx_`_A zwC^(b@}!(wM0AfZ=sM0Xw|@*UyCoRtIr)z4?QFmA>hfG-Z`!OoVlUo{efJLK9PSV_ z{1ym^yg}(OhOv7%(m{wpp`jrmLv11be)Wccz`z0iQ)9nhn2H29t^vEuni5f6h35X{ z%NG=s8yaPSDqOy{Ln)+5+S{ilf z#`3Z+loC{D>*&GW-h%$JkLz*kfxb*S%XkkS__Nd<3!7E__$D?~D>k^C!%p;l6xYYc zr^4fm3lL4RQw+fNb9hWAGb^hB!U^R(MouP@68$;^Fy6g;XwPwH!V8pel5GXMhl z-=X#TAjeG9)F>emYu%2xvNpgtd_+ZcliPCg89XBJE0}a5I!@S8=CGyd_cDSpw107R zH9NE?=MAGVtAGG0SU@00+v3s#-PPXa(0C zOb$@W(b5$CArUC(;L&g{zxCkt4|q&L&jWF8+_>?&KSgYgM(c5rET(wL7wCMPE8Vr1 zZy$~)*7A9bABP9}#o~;Smlf?l^sr+j5fwdXuXAqWoe1!2)6~~REFg9Z9l40`ICYCy z$goK1263Jb9`q8Fk$oP`f5rcql%EK^4c6oPwFAyuN0mbY%9XxA+W+vIulCmUr*o!Hhl=|iE z)0EUyO5lSiKWBDfu~_LhC}V|jZy*IfaKGj_>`)1_PC_q=n<9G@P|6;BR##E+xs6Z# zv!US{n9Frji}ybpKa{yGe&Zd~Ca}34f=W7glKel~`|@zA+qT`Mgfy^Zj+GXL3?Yh= zlCe@KAsM5R5{e9&B2%U`A`%+RqNoreLzAHpktsulGNr+|&%565d*Ao_zJ2Ut|GAH2 z_s4U1mSwHq`rY?^UFUV4=XI^yw{KHUojS!UW9h5-wr#tHoi}cbq{6t2^MR}>kFdpeUT4X;YPCxyX_tn^A{fXn zmX>Z0A82W5fz8_=jS`j4f9^-u<4loU8=1qi#i={kv6zb~oBgS1x4H-Os6 zS=5aiL0l4sx3jWpEEC>C{-=N_!s+L_KV)LQOQySa+x$|L_&V{Mx!^d+YVUpNS?D^V zX<%@*-BP_#>=EGCuh$lHNiN^Sah3q&-rH>w7hep!wYH9qI^GRB*i>aJOYVtWHqDc^ z++6KAYK=5+O+Ayg$tcv zM8k`h*(BKbl(liV&Rsbnlcb~?h`l2i=to_)NFc5FcS^P!RIVf>3X&PwX|xFJ3i-Lp zOP{)`)#yr#gm*2Iv-!J3^=-c8MMcWr2OF1UWo3c(YSM07vrlxo+iG{e7^QWI=2Z@x zYAlK+7G=$XZqJ%#>R3u$)=tsTF z$S22Je>NKT=TxZ`ssZd4C+K9*4>tB4y%hf$8{+bQnWVoj$!(2Oy2#y>b%yh)1|oY*Tr z?zz%9zcEY+;4J_|OES)6Z*MP%za7xva$HBuZw?6K&a`l`mCC6GlGk}ys}c&o4Td>3MH>0`Bn^!fd=v!W zMU8~C!l3-bQZG?2n1{Uy?{uN{v4b%DdT4a;4Gmp_T^Ir*fVOF+u~4$dg~vM*$$ibX zX?py1a+UQfkHJ>zBiW{gQm;AA}n>r}I?cED_*=!8Zzof3O zPla7D5X9u**W?0)6HUQ960rreYe4CpfOFNgwI5nGQV&L+4Aq*|EuP$#7t3)t#jdJZ zUM(S*O+e8XclSwQVdy6P%a=D8bRhH*eSP>-ArDptf2;*d*C^rnKi$jOu6ga{713lY zD8)D3Xip(UTuyFZ+qQdIT6ZC7rDSGSKx7>S$;20SLp15$n%3^bsXJ+Ny74*eYK>x_ z;p}CiC1p!WM6=72U!0;GfZ>(^dY0_oAw#ib(S;6q0owzgugm88To_Z-u3;l6CkxJPHTbdNW|cv9qBwmEa!hbt+QuO1?Z9b z5+9%VuNmgg_`ySPXvyu9GJZfoq{Yq@q$uWvO@BFi}+|{;wSGhzL&>GL?oowL%9rfV%iL=46D_Rx_Z#2Brg}2KA zuL%&sjXcoj{Pr-|Ncb=qA~N$Gf;@?&l-EiLaO*Mc+l{t$iR z9v2r}Jx(%jeA?@)=JceaddiYp$8ELG0Wx+k3dMi9hq)9)amuv7ad!3f1%eoiQ+D4M zXEa}CtgEa0>??0U@DB(OEX$S!JbbtTVa27g8YZ0sLz{1*F+Uj>t+9 zRLeRNHu;IAzP!Gk8W9n}-?C4AA6kS2!NH43NR*?jYxq*YvbC>^%Gvp%*X0Qn9KtfXBQpTE%7103=6ZZZ3zoxcFMFu}ia2h>zEz zs!&~33+7vT`my0KcimB$oj3u#|9o&TOG8uBVT4ta*Qv~lYhpGq!>+U% z){0QnW7bGA(VJb;D#!Z*r7tUE51RBJm|C=Gk>i;&<#4JlRVjuR1}8@)VuXT9v}v&? zU;GwVCJOFO=m3N3w>DK6n%jNmy_|=esgQW;Y#osE+{P++x_Wvp0Jnqoxtn-Xd*iMj z70I%iv`ICt$ytM+u!cYX^huDMW4H#pzI~IfOiSO-#?b}_fntefR~A;*1r%^k#->g0 z5<_h)z^w$~Bg4L6`}Xy#S8|&N*%=uSti+_G0zjj|C~??1o)|v}4o6^F=-ZTX3?>KT zT${zGI*P-Qcu3dnwFeqDx;Cx>?q1gmYLZufjo;=&!i8q1Ys89f)E;-FdKcEgyu{rGWlY~~LR{HnKw(h2|+MEGhY>rwoDiJi1Nndg8 z7#J9uA01y|XJ<#+uVIFLw)*C-jifH(u5nLUuB)N09{k>5ev^SRSbCXrKTh`a_CA06 zcF&N+wR9sim!=ZO2OFEbFc`p6DA|by>ni$Rzzh50_tf%(1BK;xu{_W`BM_fLCcsiS zerr<#4Hvh?b+7QwkC%|UEa3#zWB4uwVJMR?t#%k)YUr^G5yJ;3$wu9{Ph`*w9yL=i8ml!)Crygc4gCP17a z2$2aj!4lRbOQ@?>t>3$8&30E1miN>~JYL+!N`)-s2Z*|iat&PS{o zONLgqh(i1U9Yv#zzFuE4dW+A73)l0*v8KGiw;XN>E0AjxUkEgz@52{~T`u~v1ed%k zqUqaq>xV&SXjqa;*@14+z z+g9RZG4jE0Ck^GTQ)ejy5)3n_4H+em`0C4u`NLK{s_Hfl`01p5kJa)Bf#B*U+!IIg zs5_|yc-^b1*=I#_9msu`C$n6r9rEb#lWdllh#6m-MYAXV3XtUL!YUOULqhL&hQ!Kp zCfVAW16TuPbq)?*1e}3qK)Zixa?%RnrzlIikG$dWo~ZcvWk^Men>X_pxjxP0U}QkZ zg$pgE=GTf;`!VGR_dCN|)K*^%?Cb6Cx5nmw;yt?=VZ$E>E#9lHF%tO96VczTD}d)s z+m2jja*=Z5eF2!FX zt3I!)s=70Y9k2{zM&SF(s+_plqlIH?s7b?T0uIATWdvcNcj!Jb8rBS$fkHPI?wn*op&`tm>m0)9s;Iwk#5?FIBfcUu+gXOTDvcAllH ze9S!o>8T{5gs}%%@K~(W{4+{eGB2<;& ztGcjgcqI7Oz%Xi%azsllWn|cafnUHwvZPaWbxLg;O7Iydv^Z2+*0+L!m?_cDx-6oiqNsF|u@{VbT$`ttJY;q5wdVu)9hZOW&X8Fwr9cHfhy)z0)|Bw~?$gkn50qX1V z71|3^+S#A5g;Yo5@m(H~%fE2@zMogJcYc~z#cBKXYv}I#yGK8NNI2bN_4P+^@Gy0x z->UbA&T}d=wS_-IIirn6joNw{V5=%Bs6jHNFIKS8^zqGVZiKexSJi5hnmhsm8M0m= zh;zMHJgShh^<&+GQyj@{p^$He7zq$}q>K`7{CDf^i z2qPvN$e)pT*+f#=$Lh~;zAJjq;J|_bC%d#sZlBshdnKE?_HrTnYsHpj5SXDd@xi&c z<(7LNAH0uk8E1(&0N7-Swz4O#Be$A7y}E)3(njNe#G+)$C9NbCTsOqYGDv&DK!Et)*qLTDmT+=$bwO~7-r|~7 z-@6Si0#C5&Ku?uy+h%+rj0;v&RG=-1j@t1>?_i0N{2eKm$}*vFdm{unWOTyC!VJ@5 zyDEH<`m2yE%N>+2?a#JAo%cnNMm$kpZaywPOIQowN)80AFRhQWd3EV)W-xW8QD^Zb zTwr7+zq|Hg4TDWb-|&)x0j?ur*Cf4n;{{kgB6TxRvdk5{8T4SIhb2sEjz*=fp39c&QM$0W^6@P4tWE5xMm*vyrKYla; zIoyelr~xZG%p1!~zmJxq99z9I|46Kj*auem{5Ks`$uba3Bo%~ad3mZX29 zo}Qocf>EQiu`y58KAk`f0)S()^u!3_xDCsoW~*ImzSO#P>i|NRsj_$W^&NHmO)eoL zV`<6kkDD)lCOmM(Ofq6RO-oCA)aL~Vs=a%6IW9@+X*?7LupM}PuExejlGKomCcW$Q z=C@>Qe@n;pG6lpV`H7(zb#ttE}n*kj^5@|ytCHG>}wcMF`5?$iUwJ$_)4DJ zJ321zOQYKf@8Z-OcTZ=9VemCBavh zs6D@cl!wZZc)+_4xrCeihZg`l$}cVUnBA8D#_TuUDJI1`G;bhd&ejrGMi)MgJ{dLq zd1u2&iPhU5O9k`Ow`Gg_BtTt&XVxaCI5keuX~&6=XhF#PCTW`@1$;%+x|HOxC8@!2hn**isWRl<&feYt*e-}^qv;!mg4$mo$18i7 zQ9w{o-@t$vg+Bwu{3@BB-q!Z)91qBs9iZ9pTUj`T!mCm>Sv52?2ws3zk@pc+@ns+r zv7^ThYU2l6)Ti zjKed(#wfmiehZRYkEA;8pxe>@BAdi@+Lhi-Jlx!Yv9bKbqm1mxV=aPLBs}H`!Cc(c z9ZpWNXbK6&GbnZZR+PGen}@va#eH_f!Xx5!g*o<`%w?d5$vW=BHz+T^AaD zAtL${AcGG%!JdT>=!`eRCZ9vukK*33#8S0*ZRpzZ=ty(7{g! zIKm{Iv^y>VK|us9pg;M=MJ|aq-yZ&1XPiYv*KYzKS+I&hZ~&ih4T)WS^pJwpx#i23 zn>_yNj7)RR`abSD4acUa{l}Zd)mQkPZ6)I_#omJT8Cclz>nXhr$mrKv9}+?UjSQv8 zwNwFtFk~LQUT{X3Fq_2VW5>gt7=+fZ6G@s<9Di{7oVxlCZGb3qOul*BQQqN_Ko$EwG3}>lauv%+x%}fUuGl!>0d+{QK>5&hNrg+8ZAKiVI;Sdw6rob z{G!>n3qb~c@GcO4-Q%z`*aFp3EMc@q03fm_g>=*d92}jDIeF!-A9Z4Uye{2nJ^2i% zxp>x_bN1WAaSF~T(BFSyTwELs-PWn!uKWqdud1!l8cXp7!x;Lr8&3NCrqie$iCZl# zJ$($ji*Pm-XcirXihmfL2n6uL8W{jke=!o2tNK4k8nVqPq$7)H+hF(9EG=&z^jh00 zqQIN;uLPEJ%Asc-3YrlDsj_<#^-5b>_+SKsJtY6gX5HM?)7|yP!ffJ+!KMDX?hZv` zOr$>zBor^C>koYLzfcq;p)?{#9WHiX<^*|$f8(k=!_pK9vkJ+Z6hmM`i2Gmxr8ZmM z+E3_qQIPz4n6HzxN2UTp^A z4y8EutlrSaD2%ZYG#H^8o~&9*$v`T`K_vGRAnN|4A{!eUF~ecIUms9@8Tj|8lOEUz z0VO{aCAR_BAVEAkcS6cYPmh8u1*@1vk;YdPNfc$V<%1e(8V3Xb2S(wbF2{{Unaa)< zn&Va-s`NaVi;K&+z&W+@%xWbizJEdhh3k=#k%VYlCm}(|e1rjG&n?x(e>S~RB&ggj z2cPMcA0Hj}hkoBVa6f^&RySn=QjV%BLxJ;v-==oAg$~aqx&I3{b>cE<)Fh5D)JjF) z-|eROq7m%*%a@BmO!axyAF0%XY?@u0c1r@%5CPSQjv_Ur-4Klum5Ux)>>mYP_kGS(wbVSra9MEM9PADVBJ zH*Bn}+x*7^EIk&o~V1%GW#dP&@B zgl%HH2I`5J{yAa|Hw4qF?AShJPz)uoGi9((wQqR5Y~Rn&)c|QMix)Fc;(zN0{s?`_ zs9K6P2I`6x$*wVwe1+gbfeRowB;+}`37yzuwt~xWL8`c*CQaJC;?=k$gWnhvFb26J zv7mq-)x<(`^r><3@O*~V9OEyqG#DN|x)zDk5q1Z3nDO}bxlY{;6ENU21^Q&Vu|Mx1 zAOso$z7*x(PHataSgG@A{fVXwRWq~r=U+)UMc-^^XQwX=t|iZ>D>(mB>>J!BU5RF4 zRn7#niZ$qP{+CY!`}j<>)LKPiSV9kqo!lzTa$IYX)!4W6G7zp|b1N91-|5XVeMZM= zWuY)C!N4dpaDOv}>8IN4Z>;-@`>AuFEsslCn3+kn6}sxq%mTWbeBF6`2w~R5OSZ|? z?6rY`0shv=$mrSY;f@ju;*S8zUt4p=(b2ZS-r(4vHTdAAr=}6MFTlfxgR>JI*4K+H z-b`X{8Y>yu@I=SSDW~qf?kYkCM=PDVSBDPKD}OKjPUV`(tsjx~?(}kx6tBA@$aUfA z%811%%ojx{zp*@}n8aCG#(u!m)U*!MgU4Krj6N{s^>$ju+`lk*#RcNlr1T0dt^nXX z0cAIK1qB7l?THn|YaZ9fRUw-W*{iWLqG1H?4ho!Gb?(J#@#46ph%rRER9C<7ycg}w zgcSG;KF1A+kNC0wUfV~J-Tv?^2ns|6!x?;Z?N|WN?Eq)Aj}UmhaM{M@pjUTegs%RKoceoHR2N zgnvpFUdl|i{bVtNp4wmb{8N5h`Ot8NhL3*N*7gwia$lehn58VgI|1Di(MXML>jk39 zpgFqqjEpg3y#ZUDLJt4z=!OvyK|Mg!Rx%PJ@NROwo^iT z&rS_HyR_lrq@C(Ep;_jI>jt)NzI}+YcfS8oeQy(O|LwfT>!stRpGR8wyozF`Qg;%z zJ-Z)%fRi!*8mU5&IS=ZqtLGCa)D{&qwdt6EfB@Xpp@<|@qwLtT9IxVBs4-<98E!(B zEF~d=6xKeoLlzYS5amFh`lhE#AU-*MsaqXhg$aYK|G*6iBXUAW&UH~igJn6SwkM1t z%ttHRM4w-XX4`)~v2XX}jO}3mOH9Hc8xg+j<$$D>XKJ^K*1WE*t@?)?2c}REUct2aQ?>euwxFX4$NS z)qv*pUEdSEq6AH$zl5-a`ApM1%wcd5FX&)LSI)_R1jtd`8=?4;siX;pmyn?h=|5Sa;V3LpJ=EO1Y-&C zO*+mncpwC7m+jVLT&#;=4wLnoa)#a-`d;_nIFt1Vx<_ArQZ>X9Ci1)UPNzl=R$PjU z3oDuZ>d*|5+m~6*nSzo)5-kmE6j;R??kf1Cn631{1dl4$9GDa6&UD9 z8~|JJa~$k@jX4F+Tiw{1)A8c5rTvg_fs0gBK>`y|bv9v@3#>F9vD)jvvc+ZSFOOXh^B{RM2o1Zu(E3W@H zw;F$3l1`K8wB-xfDO-91{M6OM&p!|5E-U+o9QB6y(v$&)A`svtb^mZGbo%QnpB`sA zbA?X5*AWbd+p!x%*2^|^c={7N2SN?({?AcYo{B2wpteX5CzGR-jEe{vy`cQN=gJo} zjNlB`XIpH8ov<4uN{+#%kl^9#P&s2xpg)ATXwY3KgWgUgIAK(}C=YpV)L&a~W9OTg z({W(6D}+k)jPktr9k_reBsi8eG>DdVp&m;2O0%=jPeB(gv^4Qe6dwb^{twaeEvu;r z-A*T0iWYb(T6m2>4%)s=zBcmk@rgsrEUmj*?>F^%2`lT1f$PihOt~Op7i!R-)ctbr zf-tI$Rg_Vb8KGYXJ`WE|K6Rix$_)&YVl!Uv7!|A?Py9Ag=#&OZBjyAIUcG|{kH7mI zwupD?-{`ycvkj{--NDhR;A*J`J*krZ+TqZ_vi-VS1K`X(Jl0)7c90uS9=e2iJ>zmH z<=75@SVjUZUslj)m`rmXV*p7TQn$1C`A{sF#&vivd6)tN1L^Ye1|yzkLAf6>8VmyS zfY%$K(xsXfEA3kAoassTL<+l~>vrRBbkA0lw>#OWs{im6eY57UAvcv88f2p^sj2<~ z3R;ZZyGzz}NmBt~P_&5M(GO!#l*g-u4Trg?Ev(#ZE99%-PJVg=*}@7(A6m!@n3N!g z+VXHjJdDts}XcfL`==?(tYkeYr}DwpNbw5lb|8E=#j{UD9e`5;B0r z5zVjgRcLrBlTQ({bdl78Ks9cL)@3I0k8}(SI9XX)F?nM7m8^@RNqznm$sx^lbxA7! z;xJWVr>2g^X|2d{GLFU7)m3E8n&Xpd7B>em)in~l7U}UO$Wmd4(z47$uO`OvF(K`6Ods?qG|DhO zkL$X~=U6#q;Ip!EK6}KaK_G{GfEss_rNE=0OM>gZ{igyhOkZ*PUa!SK0lEJIJSaOq z|3$QPIX%U-l5r};s)Xjo(RaJoD?HiO@B}k9E^a9X{;~_erhf!S^Gd3WG5D zfXt`j|JvBpL?!@%lz;DW3jNq!n2NT!eABYLR1U;ZoHUYz2nj5b+1k+G3(Mdb?0#Rq z_Jdf_+qaMI{Y0)wRPFn-h}gRiq65mBKKordYrsyxyy;VqiZ9z#*>z05y=s&ogNG^G zg=W$0s56xsYS+Qd$;kqA$BtyT9*eXXL)19EXU4RgVt}Vq*%=dyicHb;%eiXg>sKiX z`@E8(qOsdhitG#~-;@!96U0Jw=rDzsu3i~R$^L+d^B_*YuH$Og=ABv~X7V}d)Bz|M`CUoHPFQ1Vk3BjwI_H(3T zlk5JJ#qQ_MSz}n08@}*^fLH&1Wst;Cz&PM_+KSxw4>@G8cArFHQJJW#7M6E>o!3x) z&jeV4_dQ1h1q5EW#PG|1H2t$hvMntz!3>>Ses~LOBnSQpICk`5cn6=)hV9b*9nMg0 zkj7+dz}FOW>jX1~EhxbO!QwMB#th-+5BoFRtRFYh)s^U^TnxVnPzA{{WW>+7ho8T{ z!mUk%I`(J4za3r)>m!eYQd5;3%U2JY2v#6BL~ANTIvBi~h__4w2$@bpK{<@K#1aB)3?13OHWEjJZw;6gDrQs>ph3Qnta8XxNPA) z0`A6q4>NS(0TjM|6?8SQ|$!Hn{lnSz>! z4Q4Y`JCzW!oG^DF)P9A6H1M*ydBnSS`-nFB>ZF-%b~sP2r_8n2Leb93>TT6f+hRr_0D ztiTY1h?yDB@HeZN=pReaUO^D9MAe&SW%_Q*u?KShcxnjxoxu8sL2uFid_id;_3Mqn zkuU$W4*a>Y$}7e(Q?trNb(a${ArThWG)j`YXk8q2&AxM=yx*p1r%%upBDFLF=C9Z-nV~VmLM@s;fUk#@>OB ziB32p(bvrh-RzNRRdDdqKi8>6Lk7a22o6lNIFDah!i}Wp{N+->IW6@&EB`JYShh-H zu_3-AFj_=`16F5pn#1>H$O2+LI`xTPSLL^ewCR)E4+Yg;V`Nx{an1r{vkU$U6V|DJ z7cCYxj(I8^33PoJN8h8rs-nUQGXE3L-*TiI^v$iUtr@*U^S*qU1MxeiQI~#M6qmmn zv!u2N)L(*1CJciPq6v{)+to}euOEU80ESZ}J0Z9yyrP^bWw{yObZQnxdXouSE1x-l zdJHdKPS4#YNjp0TfA@A&89cI(0s-Yz!^);26ilsR#NvH29+FZ%6+k8X}LCof(Dlv{)pW`FSjrsA)#{oV}; z=3R5T5It#a(-)Wtmec9KyOjR#55k*ai8l)i78&QRQdhUpdb5s(H>ntykIQ$q2oA2^ zJNkeNEMjH1s=E5+95;4ql#L`zydr#|gj_t@^f)uZ`%J^T*-Ou!t1%75)p&`=7klkw z991~7{EYejqZa*SGUl08ABTbAEvu@we6Q&*mXFW*^OQ9KPqW1zhE{u1r=_#m8JiupC>}K1m_j6m;J}{S|XG^SB+QXS!5q9T)8%95|29!cPSjv9nmjn zwjaaS+|C7D8<247>R#kL*t~e`Ot&ls0fryR_@uR8!EoCw?Z-k2e4B|tQTW1)9qKmf z$r+*5*X0{ebc|SSGc7*d@ zd47n>uKMWNBFC`>q*-I6WSTbrt7@AN%YwDf6jSS)v}~5dj^|~cFuRx4VcwqXEW71a z4=PQ==^Ht63q!frm)(BuPb42vrmg4a5B>6~HjY^>ojhm_-A!}bCVmWC&1sxEk?ECc z*IH4r$UkUlW%pxl;-~AL*(cg<^jW|VorH~oizhhn4J(HqI;e!Vte?!E{yyLj zN2{GqddaEDjuDi9P+U5}2qm$f=P3r9u?d7bZQd)^_!+aG>0 z4AJ66=Yv(U{fa2rJ-N9 z_CuR(B2-2Om!CuOQ+lo?d*iY=_^2UZI}SJ3Ss8xKmJM%tJT!Lo zc=cGGI>p!D-@pAs!n0?A!>4=3nyn)fA3R_uE&Ym__yH4%qcuw~!)Odm*hzRt^xz~b z6xdz9$L|i;)orw{cgv%qB@Py1U%=uf<`pF;C%1PDvAM&-?MUojja$XK^Ebar?n@L; z@F{4z8@rZe0Zf}0Q0xquw%@W)JA04}Tp?d;03|;O?T)_y)JZ)93d-)g1Um1a%Aj#% z9eP#R0M61UTP{^f(_r{Q=ld!$pHO)7W)o8jm}nlL!;e(`7<32q$yqynZUn3$S}cj* z|Iu=B4h4ln;xzoW93?4HO;Efu;~cm_x^`A+YBwhr!^B1l!(1yqjCm>p`X7Z@_Zj2v zN#kE$`wZHFaCtt#K3CCg)@(Q1bYJ%85dbaHfCuDBXhMwYWd8uqnldq?LIhVwgR7y% z9nMIwqogEW zxPIb2@2o<8g5=X0hb1L>gcH=b{AI;k15!=3bQG77mMUd7T@Dv6&kdx^S}Qr zxqBd;@pcU5O}Ev;C+kBbL$k$S>rbtd#qDuZR?@ZJ{Lep=R6C&PEL-R%Y4W7HEok4? zwj1i#D?S*Mr}9Kxa9?bEPUlSV!3yiqOV5k+Uhnw(TB(8Q7K+aC6Ef4@B(85OU=7Mr zGa@mbvGjWx!vlnT>e4@dZu0se{zu_VC2N)c8ConsUa_+KS($4ggGW`j{e7;&?tTAw zq^B%#C@!cnp7A`h>k1J%ecuNZTa@n|JN5D?RBDvU;jt&qA2+b)PmD4_@_(n@zrH_}Q;qky!Cbf=&o-QC@YG)Reb3rI?LN=w7M=YQ`v zb7$t8S!>3%TUjnDoT57TY z=SlEy^GgM!hG4Jw2X|1ATZANo%d1e*eMlt8{w-cIsL4FRxr0KzR&=tKWEfpS9n&7( znPa40rGV@$`h@PO*nN?fx;e*qwOBkYEiJWzFj4q;&quaZWbYp=GQo}Va^m&{y#jSE zOPd>ZgI&Erh`-FI(hBi;M}Ic+N#tUw3btGDx;;O?t-iA|DbBqrqf)>K7vfV$Ma}M) zo=#&N`2hd-XZXz0{G#sv_(MqI@AL?iK63|g6N z3+n}S@HZ0}yG1#Y*l(LupqSv94=c;j2pUvJW?PB*RX?3HK}CzgD95wmmP%*K4bSkx z`6SWE!N^KS$oj<Pb9Kp*W&rk_JC zK-g#Tscd9_#^M_P3c23(wzYVMt7t$Tu>zWdcmQW20ywoym(Y4`&Eb}FFT5AeV4I(-{+vU zRav&WJ2-COdE42m-yf#s6t@1QQzoEsE)cNb*<7PJ5ZAD%kzRi_UmOljzTPn)@MNqqAH)%f)pI)S2|`&QhC;IiymKDza3 zrNQeF4eR}{lDWzTle6{7!VPg!C1hd+EVU&*3{on~oVH5>->3S{U(@oalhOakh`{Ho z{^i%OxVM%ugW|ODio(U^xVyy3`@lkJolQRRJ4+-zp0Oh?A0|O}L4L;e`q3IOXo*Tvr;|eg1ScMrC^H zX%hT(RouChmy%i0kMXztTZ~M^2c?Qd7JamKek}Eq>^mrDg;Qm|3fVqqjH$HX3`5%- zqHCEEleI5=5JgC$ifc~o%*PRQ}N>$j2z_5 z$l&eMX4TjB7^&}ef}MX&NN{MGJSvb;X^Xu-kFFC8xQ0<%Ha8zJ=d3A5Wi#pF4uG^JdXClD0}bwKY%H zDViTU|2VrSr7hc>dTBS4f`cXiKO_Rl>%Kwx@X$KR#(sJ#`3rv~>6Li0ZjGFUV!oG*j@R)Q9>$sY;0R2;el>0ST zk_IZcBj_~}-fhx<1|w5G%M$gr&U}1Lw4ic13miBX+>D32j)NZe>vQM zd3w%awESM9jnug5Jw^UwD&o}LwdOo)^P77}+J1s96aN%kdX{Sx>#(iF{uLQ_;YqGj zteorCHVk?xMjV$LcO8zY#p_~hy+C!3Hs>0+uB}P&!T;_(@}13*{4{08bVS)v^F@VC z{ky%c=gIE3mFu{X8p-ohFyiQiSFT}69t@W7QY;O>Q~Hw>T&bFP{=SPlfzRz9D?SD) zPgdqTlKD@iL5a`)cu_J6;H905JPX->4*lF#Es$6$&lm0-lnQRF}I}Jtg*}4h_lv-(BzN(Nfok z>ONuNMl03E&R^U489Fx*6&alsC6#4xvd~=XKuyB4JC#4m5V@Es`!aZ8ew0c0?3$^7 zKH!w=4#i}CixC&%danQSTejycExt+Ozt7#-snxQwRb%Fw#xp<^Q0lZ@QxaBD{=;#l zk!JCg7`g9J^V2(9ioMe3BL@-J>VB{Pef_W;hp*CdU}Tuk{90_ox94JR?a=U@x|A08 za@Y~8X7g)uOln=zufuMOv$Z^A^zUWasylPUIt^m*R0TZ;D^|MTalli3gA^Kux>4F6)(qOvYQ<% z)bbS$6;KVlsq;>nyW(pVxnX=COLh5X)S{j=OgoSEhxB08Iu^&s$X>|}4iUQ0*RKOc zkB4oPOqSAPdEFM!zBb)*uCE8IyVFeM?Y850>dc#^D)TxdxOMmXiTTBML+;j;2_xjo zKEc;|5~4x5`S>rD=^i@s7xKC@VEa;-`mf3vVQHI+G`vpvRfvCyXY(bLnaJ+gk|ANE z;B?H&JSQxRq5cG zO~If?)8FT`rjr(NV=e4!QYXgLai&x|WSwkBITRT7Z4I*gS?K zN`(&7{=J#fhJViOttP{hP%C>&-`YjjeGN!o>=IZGk5evr7HoOQrFX6DJQ3;R$9Awv zFDGTQ9AbX8yGhrJ*Ba+#)V(HMGqf^N!`3MG4=q1?H8hjj&Ft=19Nxlp3ZI^qLD`o6 zczjiD(nu`|{?WdnsJJ?ZCI0IWvY&G=TStkVY^?2{UOIB8ZoXK>-bIpowt*IqVrn2$ zYZuiUP~}`)hMc1vBEBGQQ5Y~f_ru!wHiAXDT z_jz0P<1UWJzxa6R==L4dttkX`|7Bh!@6tg11)U|S1JCN|cG_{?y@4;v{*JX0dr3?GLl24RtyGDxz z{VYmpm^_&us^zonz9AS-R=UHg3tyQN<_9v;*ZIjlW4^7;jOu|(xf2KTdJ>jHTfI?} z!R9&D1*OinE77c%{Q|n=34ZaxZY-EMh>JMPvzlLA`69LTqf@$~)}As_8#^gOy z`eF4~0%Lv^Kb0?XjvVvWp_fzN_QjIbZ*yi`+#4a&`JRnKvuh3R%dZI%d8O&Yo2NSl z9NjifN?Rlm_;UCd51Z#y_U9xzWfViD&(l0p9saKU5m~Ig8g#LDC5V=L_U9+|YvE&& zI&*BDYYyxEWmJ-s8D)l13&EuRb`h4v<%QlIRn7A&<4j7{EcLBlyz6`}V<`gT154X0 zoj&VR&yz(0I$9!jryJ_r50Lq#P2rTybCDLC75iblmU@l)6>o6I#-A(M;IAZ<@)<9m z4$k$s1VtLk>sk^@Zm6iZd~g#~WAX@ENg!}SR#oz_IW7$8ZjCn-rMf$Jfeg@Q8=S4; zZPh3`nKjBMFt3*P^snCw{GQ}Xxfr65Pn2Yyx6JHA=|;7wkbFODmq=`_`)KT-(LLjj zW_T!rt6-U$AN^99LGA23JgQzXlwG4R96!+A`1ot;DUVs8c+SuEKjhLHiugApZ`PIr zoo4)uOih-t3XtSt(9mf$1mDkuX=h1h3`9g}e0AEnfU7am(sdxt7}`)S_+5K3^F^gZ zs>DH5Ts%W%X-+g`Z0K%|)F-{GC-w>~+0^YzT6wq3LvCYKp@k^ur3?F3$xmyB69|?Vad&BgwL7I&8pyxQ>c*b&Y z3cEP8ag(c(-_iDDAg5xjd2U9qYo6T1lu z&Yf*!bkiDSr-d?U7nkm}1lrEouitu5K;0_|FQ>FBuL#S8Hul%5OLpcz0((Ggw0v{< z1LG$a6CqTP`1f!+UW4G@Mta-#|KY9Lkk&z#Duc~0KKzt2zlekwSw~05441a5BImYU z>s{sKxfe>jIUK9^_|Yr1nG+HcR!Rnif~aJjYu#`N$TiIJ?0@m4k8E`H;f{Z$2&cQ= zeR6JnoL+kpnr z#F5V#E*X5dzL$AlgSD;k6?e~aLJ)Bax6|${>W|LOFQ=!@L-a-dl}B7ulA&KLdwKnZ zUti&zC~VL-vhxHGXRuLFQnp~t3eUE6b{cXd6l&)X$(oxN#(YV=aKiDZb*1>5GOTQF zXxR}w$z+g5(9z$OL>D7BEi@efgD`p==z&P&JRwDY2)@$nP%kvX#&ye`SkY&zDDqjEP5#z28&m%UYJ)B&H z6zx^l(z#j%0|Sb`mVa|*O-H-C0~*~_y>tn5WRoA=+D?|8${K7U(yJKdC0fvx}iIg0mv zv~r6L4p)(}r0Ne-{He6dcAL>BgG4Q@YB=N zfA;gkB_h&Zk2e*wjf{+Z%w>%OcG=PPWR%mKhsMCo(YL(28${x3Uj#TEHdR$#y$bU1 zz>UIXCkm;puZugK(w?ZXB7d30z4E)@6|CkM?NC%!R#su1Gs5sglrqa1{-k%K34yhy zOv_D9pT$^{8C+6Co;`bb|Ni|VyRGq3)1&+$EMorPh{4e1gOy&}sl;dR5!Wy%c!kyK zchB(ZoJ5iNsj#<(o`;&S$cIg?%&e@S;<-f|_ohudsSpy$8_z2~$L+`6-Q5j)mzXdo zhui+9XNy6s%a^Zc6yHw#dMo&BnSS>59?iza2DSNN45LO@SC?qsXiPqdzA=e}gao0G zd1b#lUTV^h@TU?JC%wY|$R`x%XwNy|*Z72B6{hEkZC}6TDQ!AuFq8_*&^k0hytP~H zd)wlJN*y^`ti|bhx{t2wvhwgzQytDn;AzA!ml(+JsK|z>X&AP0;3Ea$iv-?XO zhcY$N6JGiv7x%Y2EjSL(FURHWnelM(*pm8rd87aC43hqFVzd4w`rUD-=j)sL;^Bd7 zmsqje=_tEv|W<8j6s)H4U&pv~~6zR-2iO+78&HdDx-+mkE2V9Bf>8kjw&c1HMd3JU-&f~{j6E=ot zXKQI^>seu%HI}5kb2hUZh{PPA^!e!HuZ88v@9&4dwbT7p3Qh&E~H+Ur~99MePe0|KDVI= zP77H(*|A2@OFPM9gB!a_3k!`oa?i*v3Z*R4ySa$C8m03Y8X}und|yf*k`;R z=UlR~vhJ7ro#oSuEXKoTT!PbQZ;^ZwQ64xj_Lwxmgs|u}^{sspK^M(XVzZx6%2iC# zU3{<4ofHrn+R;B#(qD zk$*M1IdNM}VJVqu+t4eBFcm8j*n7o%E`+@dpJ#bpE4uWfqn5WmJUUs`T%QCQHC_bvS+PByXmsOo z`?sCp)qH)lJDvt(>u53emecF4M|MMp=V1?hz9NAm;@-Z)y}h6r(BloGlI0cPi_=PN zgaXF$^r>w74U&3iXDDfw!VJGmne9F4 z2qPa%;54%DccJlYLL~n~+neASE!1?d*jJ(V^&UgF2$R_auR+a@T2{8S5i~D;==?XjizSow` zSO18Gg@w1L8iRHOsw+G?9l0&0e_Y?bSm8_8t}?e-|Miqgb}>%R^VT)N^TP1T>8t*h z7VqL>rWZ7?nkpBMTBkYe$YH!D88l}8CQOqDiD?w5^78S=oY&My%L(;?f>J6PZ7+JB z6WQ7Kw6k}Ae}5r_XI8XCeQ9N-eWJ{e@Bufno`@d5!zRi{?GhSF%1>IHrV**Bq2d{$ z1u6$q)8p`crZ?ZCjpgImE!Nq7n?FPQc-!@IXmxNqwf;X(K^j$hW1jtZ@*x~ z_z*^I_15+vS8KqdVj&6HI1VkU`?RR^|j{97$NEMSW%(eG5xF$JO2H6k$-m(s?SrSoo&YHX~$|O%o zCQ0e)>YE=(5r|38^jO$g3CW7e@=w(4S7L~9c6PQt8F;g}*xR(Mq_l6wMMU)5N>t8V zu0W$_y0@60eqno~v;Q!U_vBCLu-mGfZ~63f?-&)nTv^>Khqm&bp7C)4sy2~7Zis7W z>%X%(T7tfsJa7IiVfcOp-9yx`_Bi;#a$4^&{ZXjf^x1I8$-~l0$>nk)D=RAt)n%2i zEa&P%n$tu8#e@5T3)S;_a8g~UDFqKVUsgX&sy*dxXlw`w33@2-VCFWUgn@zK-oX*Y z(pR=s>YoP(p(~~7M$c!e8-+ELgt`U>RtIL1&(is;wp7cweIn;~*YrjiqA_#I9_0M% z^A*GWjq+TCK$RPaO)LX$q4O#M(0l>W$99nKeY^dc{r|_?=N`DKn4x5R+M^72P#y*v zmo5g1KeiLAYU%xhDH~Cd6)diTUwarLYF)~H*4}M#W%=HB>}haa`jkHVJcg{dc*J1@ zRrh8++d8uM2ZovWHIL-4>(XI`xw%y}FJ!v>bTU-aRq5=iF;p2!u)d2v=~B!gv)@}9&feP*z?tCvwRx#1 za@AI%Q^WA$WH>T9y6t<_R{T+#Y)S)$&#O$a|0RKpTB~nRBmV`I$vs zGXXmM`?oXGIa;Lg?pL}P>U$l>o+({gT3Wyoofhrb`vCy~?xzc1j5${6L{((?I$js_ zv9E8E7?M4D)R8b^T5EfZ5q>!Mck;oY0T&@V;Y(gVzWoj#9<2s)W;5TPg%I<^ zN;aQQ6#?Ijtx7-^tIGKqQr9le-1m(>M(!S&piCUg8;oQ1QS)c4FWkMUgW~o!Ow(57 z!~FgAS9>|@9JU@wWkrmA&^}yEvRYhUzw;vik2YS=g#$`5l=h)Q3kwS-pkxcf?edR9 zq&CM&dIjX?S_TJ8`*w~`1}Cqm*xAdT?=Z9YZdke?6Y^M+T>RUiq@nSn-ep=iEnC{2 zYff8VHv`5!(3(Qd5>X5y0GF5;agvPp<6mE-38#SAnAE>M8d0Q+>A|g%pfD|eMZfZz zr%EnFuE3yomHG7I%+8O~?3p$aY^u&CkBeU$_DB|UO)0W?v^J}Kgj__}3JMA&LJYA2 z80Pn4783}JyW|&3gfF%$inZ$ko3GC?H8eDeDuE?(>dzwqXZbQ@W^`V;(I9-|5Zh3J z^07OLmeX{A1W>6pvR%HoN5R<=d9Zm;aOS(iZT*qlmoJj|L#(*nU*-PO#^U=}RK!R~ zNZ4*^Ww~^R56$8@uIO-uQSKx=o608IJZ|n68Z& z6utBvO1Z4anJqKkpe!1ixqnX4R_~<(LkpB5}Q+#fs{tB1f;evkC)A9eHdPCcRSr z;K74-bNRCH@Hh(XuM69g68tH~rzoix<%$GGHPUOzAvsA9_r+ozzbqY5de_GEo0d^@r2*^Wh8$ z^vq0)-F6pPD_Cf^D@^(g7TW^cFLr89FD~#NKJ<-?BY5}j-HRmd5O%|kZ=fcuP8N z;LROuZ02JeHOoiL+HGlG*WG$vSM99Lmp&lO#=pLaqBXR;@k`?V5E=JLN>Z|05erbJ z>iu}nJ7n)hienPaL6U!q?tgQ|Y_~sjR56^FP0kIb<^QQBcf&N8|LBcGBIwMP_60-L zdD^E3Q3Q%fglwbv9k#mg;Lt#*jVE#q9I{X7Smh3=$WHb3%VwWyIjH=c90^NW zQ?&V8LmE>vFg+a3^5*-5pq16{%75xyCo@juu!|0C(u6(MNAkk@8!Ai(P5y09#^fZ5 zDlz9DO)x#{j~}i4hXI`^VipQdp?SvfKkYE0`sj!ngm^oVEUxq+p2I~>t>_8PbOjvF ze`LQtA@<@CCW^5rRs|GbZ_+2hb>B`8qKwiYt;Yry0g@;4EU2$_1?0$2)&&IEwJ@^t^znNnkhh zTd#kH-@7|k@3gBDvkUf6P9v5^K}UmN4L;r-2D~As_uMBxcl8iQs&Vn|6e1&zOioU6 z4+7)U{E(;;b7%1N6FRia-7yObLOVS@JwGf$pD$m~o&HW2AeR(BNUal9!g@YeGHFCy z9O9BPrXcbqC_jW)j-q*4Xs(7b z`gz)e2UPr<@Ahw}Pi@p)(C(A1oVH4l_ z_HKj*N!RPjVYNSrb`A5+o%!Jv`IyotF*^yw*Tm@fxiVE57!{?nB2H_ag)iqNQq%U_b4D5SXP5uhD+(Rs?>1eqWJ!m`4$jotd>YA9 zs4!n)C~ByKa;~5I!(QyTox_Ce+Nsw4tLzd@ZSD7E0li;F?<8Ltr`E01uUK8&+tDgB zKpp?8m!-HXEXa9D=qYk8kdcwmz_yQSIor@(WT#8bz<`l8B-5+ToFL*Q?An-`#A7v_ z=R}UU?FdR~ApP#=lX-x4x52RNymUFNv){m_i3*r@&vHhvG%2G(-k8!z+s`mVE(*+nV@tmgjXcbcsN*Bpu zqSjlt(RCr+X?{sj*yQBvOm<#g*62H}awFLRJhQLDRvS)UsaJSU=4{@2s4JZ>Y*`>(}SY9?FdS=lEFt#Fyrx)LarzqIcrA!HOq=Dn& zA;NXSoPGTy?%iZLb%kC+|AA9n#a_Q}v9lK{QWTAX!FFw#{m#_Gk1+J139N%gP@_ML zoxt3U)L7{`ZcpD5wYBBQn2`tw32E=|5Bcz?dZB%mWEbdj>_F&DN zr#yf+{Hn!dgYU{NbEg>>huNWFlLGxqd0q4 z3G>llL;6uqc8{M{uoNX?Og$P{L20=jZW(0-Tig|e(bCk8IVQ@P9^mzqOI+@LNc!y2r2nFEr#(A90|+iE?X7TO0kBG zpHksu!6C%l9G26(Vg35)o4qwj#_@IEcZJ=HsV;hE1Ys=4z~x)5_#3Eu>RzS=NI`NEk36 z_NCh*vN2{lEYGA5DZY;eBsN-B3&WeY>iQg4IxK&}L#SjC)&v*POJNTzsZagqeeoqn z9ww)p!NfeFx%XF`4NCr0R?87g@VIzw0jTf&xP2eIV3BW5bGm3)k3Y7UJz-`JA>=gq zcD;4XWjP%$Pr&+so8raa_pzSF97${mFUqIEJLfCO7iP?Nw;Br6zgvp z+r3(jQY<&=C;F<_Jdmuh3a67*l<(AMo8MRn7}7U7T6sayem%qX80&SDeFBuw zimi(`w%W>woiL5b8lskT_gCgXbK~iUN6fF=a$hE~f$)Am8@%xZ|XaUFoJxdtRb$$o6<0?1~efhB*_D0hWQI^`TF+sm{oax`X3$ z?jhnC^WC=;52lJrhrm5tcsj~vaWy;h-Dzp3W-eFa%e~s~b*o1brnDWwq^++Mg?vj( zSyT8OB71dmFfIYvz)VZ{_CJk6rvPoZzSRb47E(DS>FF&52pC9y=HZLcMGHo{) zi*uH~=>68SOds`OY;AkHui@;_B9=M7sqS#KXRhCb6G#9at-`NnFE4P`;!lg;PMkNY zF+6O(JeO}eDl_claNO2BbMBj9=f0Tw=zaS!oApPvy2T?cu@%I4XUD$2VI-f!Tr%}Jki1-dMv$WLC9Z~m zzvNztLeil|kz~&O1Hxfrp0D%zqWchpJ8tqw#}jJk9?p$Jj$osG})BdT*m)>Hqk6OVSko zPT^Cis;~d;{L$Dfk0IPwQ-1gCVHE5I)hY}~=&T2ocY@DAsupRZf?BU#%eOTYhAf{# zq+KjB+dU1io>;R7FK)`4B;zjyFdoO4PH)w-C};H<{ld5GYl6LPB?2 z0N%UN!iP1MGmA-9P4tM1S%!pzS3qDSUzrm0Y8SLAAFgOsm|%mkSf(}m=T8#2PfHsc z-LU*y0v|Ho!NgpGRbNT;zJF#7Y&A9ZkO$L;s+fklso=KHgM|I4TZ(RLi3X-T@*GS4g5B04kaP?B5vUExpF%kcv*<7i7^0E}Aw zuq&(){kl?I~eU+o?bZ~4tG1>Jxjkk#K+*F& zqecR0MF-v?j1~^$X<&!R=a}lkAV|M>fd#|@(x&}3JVh8unci6DyV%&q>%THY2S(;$ zgT_C5|0s@CFSZv-eGF`ZGiMOZ?l)H_!6bZ1p0w$y19lFf2n&3ZA^tzeqd%+AgpoV0vG*GZ{4S^|C_1>}BhAf=>-8=OiYTEk5q z3YQ0v_owq%lU$_;`6dQxX%L@8{0WyvW|ng(2*vcd9KW#eoqB zxgO0!^b$81289Yy9P;z&fE2iFmDKRMpR&EmQ&<6;z0zVb@=uLb16SvZBF#Em>bGy-_N59X0YY`T07Ety^lEBk&62dY!|S)4!Xe{%f9rOZE*P+KQ1aR zA#rv*uD3B-MBwf1O+`asNr}_CuT&ZMM%1eZFOaTEU)BkB3$yQ$t);A74D-) zK0ZFnPZJh<2!6kQ#PXWXOHp2)k)yff+HU@bH}c`h-yUh|4=6I~}X+)oU=O`0dv} zQpxtE2xzd>IPV)!$x=W$hg7481H%^?RBNi|`8&9!S7vW0C=8EH+5;a79{rL)K}R1c zHUCT2o?9CVh#iWk6X(LIQm$b4~K6WYXtQCFHHG z*{qtcxF!6s#EM2aysq8Bb%B`xyzD(=ZfR<|`lrKfF(GPiZ{K9*Nb7^_w?$@7^uICk3k|=dS@}{`H-~1|$ggdVXa{tjIXm4Qee~2?CR0 z(ysJ}djTBk1((0Ot4kklMg6JcQ`$^jP0h!kY?0^ZTRxp_V%@#_6qXg_8$?`YN(_yt z4+j_9gU;qZ-8Z_={p88VI=i)l0fAklv&KISox2T(_kj6QgNFeU(C**17T?a^LMxZ~ zZ-3YxdqdLXD^cuj|173ztPp3xj4|#OfqR{*d?z6)iX?J#S;4dm3^_|VORDn2pIBIq z57$GarKLIT*Og$)NhvAec$^tXPzf1F~&h3N+v^PW$)0^(~jysU<*_RmwlM2MbYPb74 z&8O>mW?b~Gmr^=(8Mw?URF`#o{vum&EVw>QMT38oqM_@OBclZe5PJm3$KIHZmDX`D zTy&XHH*P4oh~@FBxo)cKCVi^MKdpgOpx0+<|Peef0U z%+x#8Iqncam8H@rZNr4nhSOr=n?W}+xS2;ge+WJT2-xmSJu7krc8LBXUF?&^CLyRb z7^DOtH|~~}7Fetm_8Tge)3wUQju;GaM4TqNzvs%s-DKKgJF)rvv`fdAAhd&Oqg-&H z=lUR`?0ji!D<~<6*z5W%FUHApdx9O2l0Kom*90Nz2nPqp@-B2L2p;xv0!VxYCcNi$ zbK-SI!KmGJp(s&0uG2ojDyME4rcj7#4 zLhnL8dw1EnO+Jo=8a4~8MD3X4qaz~#a|E;lvcfRFjcIZ{Hb*S4sp=2%uCA^buK3hN zZ0e=D{UA!;{i$Y#b;--iJJDC;a%ci`0%0i*03ypsA z%W4S63)gK#yhOY*Eu|k8`9J_yW-(dL5X8?5>&&eu9rG{q3mUvATE$iPefO*5aWk$& zXhG71;@IsL2t*IjVqfs6g{}z_EJ}DGQ6pgH2j+zgdSHZf63GM3ZqXK#w z+?Tuye&RHM>vFcyRF#zmMH1nu{*yJQsARRPz3-M ztramk8A(DE4IGG2z>x`luPQ+?k_uYGn02cAYR2Eab$Iv?yZjqBc-x1+UnwrYI@d1A zg{35Tbu>aqYS2gdwDTh=dbpGDP#4;DNh? z%Xh#y-fj$*KLpkA2U^9{Wnd#`J~m^eA+|Im&WUgZ){x|$?fjfRgK)q9Vz+q^ zV6()B{Gqyr^3W5^Mc}jc8^gXpkAS$y06Nz~$};DE_%h(@C!zH5t;wqQ1O%+Q_;_D@ z%s=h*Va`K{`@@K1f4`HQ)3^u!`Y`RLOROBMsAJsTiqAh%z-9TUCKxx3MZy~n9P9uJ zIAR$?3zZ8vQHLwUTxQ`U!BBv7piPIM=Tf82pad&5RZdK3x^(3MNZ4*44Uehe z|L=Tv&8`!pKvwYP@{mNpv2RtR0+4M4ej4~^CqOQ!`h%it`02MNP6k?8G*f}$w6ZE? zvu0J%Rn8s%C(26M*+F+lp0wKj&Ye5@kgNSJRO>a5&#rX1E9a+PWDHctmQEX!ot-^d z$SqbjislyIt*_9M)&q`Bk@!n7?4JngkVR8%HiX=DchRb)JmWdkpk;ln)YMd@=aQ0I zR}R+JqNU?NEIRUY=0hrdHMGnPw(Gb4_LJK4dsZq!mh=Jlwe|HFiI(93%;A`f$ zw#Sp-9g0TJ3Nc2MND+)1)?r26kc=e;Mgk*FG_9k^E$yiZCK!Aou;o{QZLYx@g=hoN zH`>Z;;MQ%lZ|0*6VA+6I>aqOf`PIdVbR^aPg`oCA?DxMA)RjZP-gbSqy{*#bgMOa5 z`OQs+U52P6xZ%SI!!ShSLAB*f&!EUnA2`ACsv5G+|8JD`6+^-aKSa|!bM7PNciMY< zgTN9!1kJUVc5{giZi?G(qcmJyq0%d{m+2kOtJFELL$_xelcYk35R3t_g00sENP&8zH(MP*E?Lq zTAMUYTUqXoI#Vy#{AI>6HM^OOR2=D-rha!A^x@7z7 z1$gtA{`mo;pAQcFVG4pLEocMs1Nb;{S(h zk07bPpZ^z01?`WZs{;R}&R2f=Vg^5E_krGwboC+|N5@>XBK3oE2|6A8R%tR96xm44 zddCvA>$k0b@SJEvlb{t!YbFIb(f`V9W9$Em+1CCTzX%EpHY*bD{qEMgZ#O6u$LeL{ zz$z=``vy#h+_!Of>Ao&Y?ax;86jCx_kAoM>3Em37i``yjEM_!LC;V1KLm7ZooOvELMkS%^ z`0y&kj_SplEx_aG(!9X`I9S2Hd$(n1=z-|$%8ZXfo*_glOnOZXs^1A}{_D!?-^L#N z#HIdaUKMBGP5NA8H>Qz{+j1f~0eCaOW;`wDYEtmwEpY^deAQ0xHgf?`;#X~R#sN9K39|)9_czSpsIg;EemoX;g6E05GrB{X$)#Q8oupo z(s}-VjtTi%orUT_QxkShm;tZ(Z#tx=^G!zJOyr&yJ3I{y4eOvsyNOfKWh09X61?`? z2_Q=6=tZ5Vv!jKY`xac}Grvy=qfEP`dLtpu^#AycX$$VPi{;$>`~V0R0Er zqqhKgda`AsPN8{GuE?=$v&^9%)h99VF(>OskP1n_(-CC@;g><1fUJxR9h;X{=HpPJ zXMw=esncq7C!?u25Dm*EG&F}`4kU2oycRtCi8znj(Yo>~KdO)0gZksXUO6b-yf%v{ zFtjF6`GVmL865##NfAf<6ZfloJX^7@~2VG!V#=mYT^9aJ!xg4;0_Xfl7ANj5kV?6v;5~3tJUCZ=X3Z3zX6oq1|hqJ4G8o${bz`YCu)ZN zs~6yKb3TEViVDz3=-=)fYno28rx3GtB^{eraXt4-aj}1joHtz13Ci1X92rM zD&M_=>ih#1=E@O7E2%E4gdq6E_4W0=<>|vn_{6QPzg-q+l#;j0#ZCJ*TSv;Q|4V(rT zf@aRy#f9B+*8`vl;fFs*{2x%(LhytH3Z->$Fbo<@p(o!NIyKLr`NL(wm!NnV(Q>j$ zT>?4${PHptxz|BA?e=tC6wLDC^77|yBMKIluQFFC|3dcq7-eUm(NnE--8 zfX_Uq6XmlRrjVBf1(CZ^H$;k(*!Cls#9+-K0mA^rB^D}L02j$&97v*H@&vq$iOP3) zKv!Z0nP1n21J3lK>1HU+udJwL!(B@`ug1{rrZ~+m04n8y>19AM8j2Vg4h~!|FE3aU z1W15$pWq>Y!9m4=@o#S>zUnq==NChPMkLV^_k~b?fb@f)$rwB;gwz5?zYjKQ1*p%r zKi>2Hv@K z$_WaTx1!$oGuYgZxy*1NSzQ1cN(wkL}kUaHdJV?Ad32oA(8J{xmxXhI&R%&$YZ1osSAVfqk_ z?@X_2age}OnW}o9Am~yalSfm_a|Z(>6V3qUlyaT|DO72!ACncP2t@`O8Icyj$aUFl z-GTz60DUJf6S)>LzK~^tJ#m0H1x;L#163sRFfs-KrPF!ouC4jqo*v*c4?;|Y^#MXv z2i1~MM#S60@B}ZN)1;41~M&MehBP?fXtTUk=;H(y@yCZq`!Q`O-mK+o$ z?=3(v3N4LraowFnA-O+3oRE-`mIOQ59OF&!{NyY(a6vp{Lx#9Tgph*Q5&yve;1B;3 z4gT-1O7Eqfffum+@(Z&dxUvT-k}ZuA$`KDT=KcLpVLyktmo5@Kdb&s&JGCTl+z)I)E09r)b7;ph>fy*wjka-RT*-(7C7Sd{1y9YW z%N*F0a1}pV%D+0mZ=#~ky&fK(;HR-YlDuc~L*3oplPfn3i2%q3JQF=Tj8nQ>y$xH zixcpcGDE3_+WrLL5fK^rlSEz(&y6Ol znQI8AkcJx%!`FNci*n{ub&r1{15x$Y;E5NbgTA>KLC{)5HtV)4RArZ57$Agay!vLE z{ORZQPebT-+MKkXk5J&A>HnW!U{iCR93QLY+tT6&{8-vYxc-d;VfGEIO{d7vcVX?| z&<i|mP#va&Z2>x}etB-n=S;G~B@ z$h8QZ5$U%ECslTqvdJv!)te@FLXd}DJw4)cO&-T=jKf+$B5%Kc|Ni&y-$+P>g@yC; z^S|0FC_Zx>D(sf#=idQ@l!Sl)_VY0pe7di%&l;Q$XBQXm!8M5|IP+ivnEvC@;6ywG zu&}ce0xB5(*)IgkDvBkz5MR8PA8k87cLi}G&h%&rkaK*iL1xX&!lKOw6?1PTPH%Cc z^$Q{bfKURd&_w2YER35(Vd7&lvQUtOh$ckW6ub?=oSd9muNz@I`5W*i68e%02_wH6 z9kom=eZ`EEq2l$r791WP{;^>F-IYH(q`0_P-_kO)p+OMo2SQ=PQzuBO{o(e^+MK&o zjOxV@Bi)Wp?R|`c^AV(wQ-AiI_qn;bywF?*t{$A^7pU`Ga|4LJ;H3Hn20qXM_;$M1 z24fWK?uHD^=kc3oWhL5UKWJwD00&?*?7+&|nJOg29gYb0OlZeJ=6m|to-6DAs$aQ@ z!kwq2-RqzDj8{L0r~deFUih3r!+z0mP7z?SAxQXdWo6z41@vgxL~Vjk8?_*g&wY{b zzqR+?;avCq-}tArNJdeltV$v>qRgx)qX>~GBRiFqC?m4UXvt24ZGlqZM+M(O$hPzYQ%PA(N+Z)s4HX?9l_lA>Qc^ZR- zc^AZX?lf+?yZ_yp-2s;`o6fw!Adgp4;$}P{64@|+_|l}4va5AM@=3#XV-H}m>X9N# zot>S@9E)MyKOun|`n0Ro1Trt4>a_ic2~>9G<0d@KPphgb-oE94f=@+G&PyQ<6A9j- z0^odWNQNz&Y#coWOS#pxq@I37Rz`;6zI_1|;?9`;F9A$5ouB)qUvP$ta;K-PM1vcP~L%rRrj*%Nd`*l_y8QJVevUedJfsAp1;~X zd(pe3W@h@v#c_;|j_RfBig)Pb@~!EXc^7p1{m~Cq7=jw*#aomiqGk{(hV4)}&xf-lt_3 zsf01zLji0wIGyJ!$63~0==iFmBOoVdC#4LJ`Xb8w#Gd(Pgjg73KSrxZ^Y!c3&%jR2 zF!1V^dbmISx#ez(aHnyWwFb+}%$oR;O#O$8vGmtxpEBx#Z#p0;rQW;$Aq&p`}OfE9>A2tRDW;2+%aLG-<1|A-sfZ$-=qMExz{T_TIU(gOC zEmIE#E4FG7?M2(8s8s4OT&6*Pg>w|otZW{+DW+i%>15;qo<$vqTL>n zemjMFXVLbyI+#u6wB~A4;~){y_IAkv2uMRVNF+QA1|0zJ$Id+KCoPPyOZ@op<7~cl z?S+fUgZehZYON)}5BZSgE1C2Ntw>dn1T$C6`Z}$1~XD_IDy1Tmx9UYu2BAvYnmK7yxd@)hjFQPy({k*>3x3EycEBTW) zh)j?9UoJaQ4xwrLf&NYi@ZIx%ho?`U%5h&aesO(^kf>-S@J^!H@r~MZ$x1QOb*pXG zl;oC`$pt(!z3{D759@2Mt}ZjE(u|e^tz+|phsny6?fL@E|bL)}20eiVm1cO%1gzQ=L>~a(ckY457Rh z!!!I_x2jmjrSn}G3yY4vl5#LEz1T!mFnrVI%}apy8hkoC7V^|oILolm+jF*$qrmMO zA6l#j4*jZzg$_&c4b`Pkbz$s%-+XY7xlLhLXJaFQ@aT9+{Tb z)*>)oV;L?K1j8aHYP8#n?iA9Psnv^B$;ilrO=-kR zGGl0YwR=aNh^T0!N>%REyK*Y&^Hb{9f@uCwr8#gLvf2xslCjl6LZ5*BsI|3~AyA2U z1ng1BE?_WM^<<5Vh%g3NMoMgU{p;7PTMxt-m&iJOWWZ`_wjPuVTC;RQ@J<#VcNbp} zR_M98Sqb^iD}<>qG6Ryx?XDE5CpzgRk^3a~&+|UuyX8r`Au!#>V!J zj^4|0$9Uv6zcN09?2r)RR*_paHkSF|6Ob69Krice(9+Xe4wdt0SAOX0QfNlV{(?Iq z50n`S-IS|^j|&R!BqS`xMJH4=DJ2;7&UO}F8xQm@q?@#FPZ88*yqKqJa`LoPo*h1f z?lG~%(2~bjuy0Z*+LsHq?Afy?*E5%*QL34knAkdA>O6AGgJ-`R6U~6Z%Z+h0*j3uI zZZGD#%j~u?c1wD_!k_x69?M`Fz#EZ$_fuVrh`U07tfr9V{ zJ+#e_o+AY8yFAa0c=Q+mj&`6bGELbR8cKW4ZGb>kAG#Jt?W;O`zWX*Sn453Gzrjm$ zt-bQl<oc6k&LK=TL~ITM0rZ$1y3cDsOKIwVCI4ziIhuabM%ywvC!BU_PONfq?`p zLd+cu0hj??6)S_V)qR_xr>g|1 z5~=EKr>m{)6BV_7;FQ{(v>5Mnwu}`+<5&wPR@io%o163Q*r9i{G4b9#T4rWuY;xKi zvi9$lczjxuG;9%VU|<_Sq+fNb#L~&d0A}z5>{i&+nB8nC2N3I`~pw z1x)h{QZp@G-KBSif-8^%v90cSxOhEQGsH?E0AAnYkNF0jzP#Uyz1qs%lo9QKKZi%^ z=PSM7%ShE=mvLK?rb7cn0II*G(|vSBS?B2htA!K*}ce!9f6reX5gtFKG>%`~TIQ>RN;Z)Z(; zQV|=Qx$&~vW#{$AD&2JWM3q*2gRD)?7%)TNLy^$$(yxp;O;;jOItZsemKo5r;FaZU2exb3tzBp$8&Sl2uQkF|*4Hhh|jA)8_+|}EG z||QIZLq|A{!gLHr9T#VM07M21(lFt!-gOttFpck6LU}VM@H`D%QR#R0Eo>RXqeI!1s0nO{Hl!F{H zw`GJ++>At(iF8t#9PI0(La#(#5|ft#09>f#zDe#f1Cl}dyRgVy%)D!!FM5ae4|7Ic z``*2K_Z>J;g{i4!>MdSR|LD;~TopO(7sp_~rO26?ZE9+6eh7WOMKJ~*!0+3>O@J~a zreV{E1sa3uUny z3O%v*`Fr>rkdM(Jl?A;5TDN2+MQiJA9~>l3+Sx@;ZBh;@1H*rFMgr}Sp`qbT_D=br zb>>(qsyvyQd+a!LU)0wx4X@p6V#3A8$2Tc?|MmxLCcJ`zekg(fujwerKJbr?-6$TQM~X> zibfU&2d~<_A*4c>++y*Q5egg-Z&yG^Abh%~I7E7{sWG;Q79$bIJdmmvk#1rPMUNxnRQJQ~&dtlaFP=V7$s5{)8$Gk5CRX(^N#oZevk~KP z5k<2Xvlbsp6ky*2NG2 z?BT*h{jQA;<4@0M30bB+(Ot9ZVJSu;Kz@8D(UrwCt)^HzjI;@ab^V&1jp%38xTL_P zJ+scr?VK`h#>BTj2wGV6)JQu$U}T%0;-aF8uC9e`5)6HcwcEF|D)79C{KcqHw4B`N zn)NQ0-&9r%v6Bt@W8_W%Ym@4ja78B7qeL7PB&&Q^uKPSTbb1j5G71a!Jsq>04wN5L zllcW_<`lx~LVp)0ZHoi@svqU$wH3MFv>klws)k`%vGHzK(^~@bU|;gJgVUJMxszf7 zi3Dm+zU*H#8K1`2hdt=sr%&{7vqQXZHr$d{0I?<|J)(mZea8a`6)9!Kt`iZBK0ZE? zjmO=`bO$CHl*4%*;lnx|oq?df0s|`|r@W}w@BpM^#y$yb=E<=^3)-E!$}NY#Xokz~ z)HPocmCo}U$$JNERRy=g!O=0z)O2gXncl@@m;fU29-df=7l2-oS^=;>CvKVWXxwfY znn$t@5Z!Z2_*c>{3{nx&bhf^ zf%4@hUJl$?s~LWTSJd(agUC?G$HvA+di059cvCWbn*lg*iw%FMrOT?N{Y=s5r|~91 zK{^awTAc@&*GT!nT|80iN)XKl4=68l>Y8S2r(4^PJ$pI7zH`f8AJKW}z5wWiID>4M z!Jjm|U`b04dY<<_K3&#{nT_p=xA)?cZ;EuSIds)WSqLBiIlt!N!+vQIT#5ksivkXqLUd% z7TQT&I;r&1w$|AI5xX$PR$b|nM_9Fvatx=7(6NdvL7z8fkN0r=SXAdQK3mujwVFaR zaF5lEM<BVWr2rq01x}SIoAJVpTLQ#m&7KraU9@<4um577f?qPc&_8 zJ+7t2NSeokgO`r}r3FAEjb>oj`f!z^w)s<(ZOpKkSVhKEf>^?M7@53dWG+`dq2>WVWrucn5cgA~Al{o+cI$u$A!uHktz^DwD7 zAu`%sxCX8E!q<5jMH-^W{8p&pg^bH6NrMNLEm>lWziTAAjp}Zi2sdT(=FRX$Ff}wZ zU`)FN54X_^1<9qPsYl+V7O{*#b z)iBh9Wu}DH@{|F!I1uHKV15m&Q6m`?m2f9pdNK|={dW^=W4B)^G#&s07U(%cB}m#` z&LU?7?Xu$bwPv4sp45q>F+l4SI|T@QL!xr;6MmPH#6%yV_Z^`#pOrntgXBO9NY3L_1U*?SuO%hm93e+aFmUB51o(|*FF z;V$bj%L2)=JS+e_>Jfxcycr&jIJs{IrHz-I*5PhkkH2Ssx-*BGD32Czp`hDiC3;iJ zLLLJkMq_JhY6@C6LX1F$5IF_p9pX0uNB~kDXzhM>iS98%hfIYH;Rot#q#ZggGEh$l z85yBL;KGxI`A|t-ei2L-Uf|`0JmncoX%{NXUxR8j_Li1$Fn30Ouc>Td&NAgZa-nQJouRZZUPod(`dEmj4lD0r$ z9{)gQ#}0b#Yx~mNf!hKV(f$=W=8-pHW(HXkc$J+{vMlzs@16A;59D>t(BzR$EVt_-#L|U z?r{=`Ev+22UqxZdoh^lLdLYV97s;56tgLAcahkk3G~IiCO|HrK1!jFLDlT1E$8MxG zBfRFgND=$}T3Ll6DHQzNU02yuEe@^_7R({V6ok3LJ~cuF)J6RUx=_>$;~PU6nuLEh zQvdRc(?uxrSAy;5#90}4v?=J+&UO_>@J22RGd%g(1>+7p*DOu!&?_LhF5HhzjXU|qa?qUxw zX=e41Ev@d`30M{$viJSRf$-&stJV6%%)wX9uUgR-x(#%-O{Zmeor6G*jMeDzc?AS? z3mT4U_g8sBi)-@}n8q{QLVFOFK^%M7DVn;vz91O$t;dbHBqUft3aEB%+O!GjB}?i2 zeW1wP0D=cRL91I#N!3f87l+z~LF`?Pj$Vl&nj)vHybR3L7XbPrW70Xn?OGPu3kAmpd$h0+uVR4IS!u+{PzL=+ z8Y13@(lnd&-q_Dj&yf3h~Dp6}wn2$&e|nt*-dnn;5jT=+Q_q zBSjUIpV^o9&qxiSyy4rFH{RUS!w$TIV8IoYmAz1oVU#YfuV01D{`1$bHqG5qNAW3v zq|gC64IX>{{=E?Lf7+^ZErZ}|S_AN{8XG({mMnqH1lHZNqy3jj@YB@^&0Wi)Cpa~* zx2K^G>Xbzby%<$<6ShN$>A{vS#$bgl`Eai8PF>xg&`<(Sa<08n4nUNNsU^8+C{{p5 zW+N^=xS^LFg5u(9vAYtJSVmu`s2}FO%U7=0e;d{X50wZe)Xqf2sH(u@mn43>x3A9! zRHVyu*VOes^{!V-$;7enDQq_V2lxpyB4tvW)gDs$2q_mqD0}_jP1wA3E6PN}^&2;Q zAfQv=Wx}PRA}BwNFYmT(CY`W>0;pO8!o*LG^W}8GR7m;Y1dy?%cdR9N(4%r^7B7M+<2AvA7;aCn5Y-+{PpZl59*t-D`#U$s4%WX2AFj8Fk_fLZ}l0w+Y!fQj1A9RS>${Piq8z6aBlDJ)Lpnfqi8z5~} zwO0S5)zFo=4*?AkA`(OgkQ#{n{Y>lD@k>7~%muwqIu#zCbk872Nv{Hu{POcvES_{a zY^YQe&~Jg;*t*rVTNRHUJ=$I3&i3uwx6j|ds~kGC8Vs0I=fMEJn~^ResH(Z88(^0p zpaNWTU?3L*1qH4J+*L193m7WV4H3W;q6+AfA{6um2#rUiv^mzzLMJg}Bl}us9MwA0SBoD-UXHqk2Ab|W?bBj!O}gBU$!W)iVS0r>N>u)MEaLo_ppvVG z&t&J?lA5}@OZV^JSI`)?K;QSgwzd+}g_fpf*~wCuPwd0P!%i|=eEthVyEr>k!(3ir z($~8%`%~rv`hEH2Xoj(t2kNe9f?_ zp+|LJXQv(UESVCC3T%oF4i3b#lG|r)VUccR>iYTJA`JPVdwK6lKqVrGGlz4FGj@PuyD{^H%u6ilRz{nUc zA{vT@+xGqwKR~cR-zvb8AoSYiz5>hah* zz*#8qngM{6-oyP!@dEm$oo0uL2UFp@!NHWTvqZ!rgbuEF5rsf2${`!lzDA6jV#^_W z)`VJPbMqQh+jIrtOcZ!x47GB*owRTBp>ykB0wy9s>L7HU|6^dJPz1v>?DudDYYKf@ zeE9HT#Et3Fd;}Rz0)F9!@|e zWem5f0t|O>a4?=5RJA^Q*W00)ql%%Dm-Ji-c>jHwO z-LES;^YQWH0{gyYl)n@(NqMoFyh>o1D)JBkz$GJNG$!0RwI+cE#r9*!L33ml+Ugy= z$k0UdWKqpOSq81-1HWn7CYJ@eL5TxB>pz&o=YD6sQ*`2e(Ud1loEWC>l$5YT zLjpz=0mS}jPbkJPq@f{Lz=H~Lj#CxJlB}2h$>N97n6RSAGeNkY$1bNw-#lIiIRMR1 zFgmEsbU@Qd)W`Vvc-7wo=-gC@7clC~`Ox3*J3l+P$7T?&kp?GU->qU_ZS2cGPrcrLHOph93zL~k2} zzG~SK*Qny;w3FmeB)Nn30|JB==^{pH&?DMb>Nf_=Zw=@H2Fu=o=LT!zqW<<};6e~M zT~$iEVknEO>-%-ZGP*38zvnQts9ON^-w5UL;BX5 zsA-5izf5(VPE1V=czw3NhM7kWKDM>kfs~+X@=D%Cv&*jYu8^lu=gz(_=Q>KL@B}=Bx_aP|5*{ol+W2!=5w_U<=FOK@z2nyR z)^|vU-Xh-zW)~B5Z{Uagp%xn+8R>oZuB^pl>(huc$vZ-B?a*iSd1NV9KObiNV)q#H z_~^+oO~XU?nkiE6&l&>-P}Y`cyqX2Uw^K1hXyu(%>jy44ey*R^;F!Juz6=j?BIsAb z#6kvZXVg3h6o8kXUs1z(6;IK@6U?Hq8)83q#lFqS>xyoaf4eA;cXn+3DWkbv<^v~l zcfCAxhv$;h5(81oK$~oa-@R>`@2S(H%qXn?`K6~{Amb##d2m6w;d42aVg=*)?iktoI~oM`s)^70TP zDo*a@r%$1P5FrUQfr^C2*?H}bV?na+GatW<26FwOO{5a`Ab$aZDAJ-3z8Kg`@9=PX zdm$?o8dfM_GV1Qt|6P}N0;gs2ksuuab9eIQ@p@&D%HgU|qEx3OckiZ9(2oAWx`q1C z*^$07Ee<0laX$fZvy(j7^oyY0Tmm)6!}71)~l+iafR2K*xJ_SaKMNSGjvKzBO3U3@82g(zN9lP{*B99 z+x@csnW~D?fqjl<#P4f1yV z2NaT~#4dXw0Ji~tjqKY#xRuwpsCDl2Y?8r9{^F{LwFX|i!vHEKa)Bo&o$$}(%mkPc zVgZcZ5;VFDCD0-YdOtE%tngJpFaZ&NLpHKy%NCmIFvuK%Za}9^MIlK-FY4@0o`f== zDP$XNF@$SOGbCGp&7vb-UW-I}^VC?@$c2b6|lQT?}`Ib7R4B}KMq0kUhz0_HEclyP?zkq$N z+JE$EH0~&;#nS`PlLMCY&>}BTN5Pnj43VaTEt=}(B!xghKc=U9F>D>C*)05ReIFNf5-QdE(cx$aZk&2qs_$=Wp5u?Sj%@?oa<~G9sMB=PTSEAFrqutb;Q$Z{zrQgYhd*HI z7dCym;z>hoN9qDo7@y_-00)NnLny#&mx414VHG0OcBY!AU0PJfY)cfJxkJtes`lxc zE9EiM>wb&Rz|>A?Td0Use}YJCR3caT#ogR*)p>uJs3teXXSDsrR~r2bcBR>&!o23Z z;7nZYA(t0*`>V-S`Tbo;(+;McNc{`5K-QiY#D+qEwEr)(=0O$mX;K|Jw0`Ag4XE6- z&In4)`b~(=XzGR8BkK**s!b?(WEnPr1s3sdWWCraxTF53weq*WuU?e-YZ@9=oi}R& zm2h+TJ_(Hup*vXyv=Qm>1mr{uO`{hHCzJ8q>@<*NKM2nqEd{tX{v}AtEd{ttM6`8k z+t*gUdUfra-9S|qXb+ej<)FABrgFnlkBx8~tPZ?njnGf(Kj_7-(>+gt4hI3`5{wZW zq9z+GFJwDYF0ciXJ{E^)A)BVP@?MY%v@o}&UA>_pp`w5S04PcvEO*jmk)|UFkssBa zq0Udg1v$>IWA-;LJUTD#f*DRo;6{+wIvhQ8#>uIr`CgDes8vANU+#PUT8R$@3U%5#(rqCXt=Yf9o3p@!U&c~{} zYx_w?%WmgkCbCsy4fFH!^JyvqaSoP}j> z0)3ualEq&?A#`*=NYq;no!KTsBgfVyFF2mP~2R`zz`D$jo# zF)hYNF-HA!QjE0wJw8f~amZfSjm(fFp%kbQ!M5g3bO8WISU%;>P)IY#6d`x=su&qr zD>0|sFaAmcM^UDbUw-~B;zHGN+s@Bl3Hfho-a(*yB)SzB*klIaUK!BChfsFMmb71D zk^D1Fw)kh&3Su6?m_ot>h@`Frr*`{h{)%6xh!gxqxTW7JCMVLi-O5}_x@`Z`SU3q2-#+ZM}1UPsu5OzS= z2#w*DYKC~ez|pGlDCT;^Q4b0JtH!r-i7JIKNXL*uMJWSp zk296x%9|i0;$)&>WI4M=?Jq3=LhK>P5*^df(0GWP4ic}`&jJF^(xZsDLa=Xr=?mQ> z(gnKJADSerj*s1;|4|b&v2F=hl^6C*zXw%DP?%s|N@fp8|MhptZ<4wj8L9!4p%&bG zv_s=31QSf`7Q&btV+T_B(Yhk5%na5_N|a4t%H6wi+t+4~*FrV}RW6yI32%$XHOKbU zC6@KS2g<=SyH(-Y%Q2UR5ZBS28ICas?THWR-uGQQvUipuDnP$cmkr_t7(06rDOQ1j zoWK;mM+aY9dAx6YWL`Tdt)@`KPMGqr$l88~r0{fmonT8lyH$9;b6@BD9w6=es#f`q z{Z{mr`ek*=)MRtp#K)oE za@YyGk=YhqISduNn16{d622ln!@QV57kMvOhBQFy2BqZa3&sqto&JtrG|FxW&1TMR^@ zV zCayV_$5p;5=8$0x1^npSdRHXQf}cU?+dA-^#FR>A4oLkMzswXd9g!V_4kawi7gi>2 zhG5jxY;X#5;)5q;4qtopr1Uyh}}Dg z@oy7QE4xBt4YM5QxRMzYNA|na=;fdtGwiBvGteXXml$qIFdk0pz~Ho~(6Avr?{aeb zWgw*mj)QdYU18=zXV9s$>q&M}N=hY!wx|&{U8MbZ_Usu+q=071SvKp587v?1@Iw(w z0KoHloX@nDr+KIH(eFbU9O8rWbIQL5AKRa)!RkDfn40WyJup(?2MQHM?rW5n2hE?t zK4b!05dr4leYzGC(>+iksrKKfVdMWcr9G6)k}(5t0R;*K6RJ9(B`_)I$En~0*wX&_ z0OK0e()35jNU0QEWke-cA%k1ll>t z_D^VsYx{O}TXQ96UFP%OhJ8VuZ^A0TdcOT{%OL=XpZx4QuF9di2E7Ied^5H)Tjf|H@nc{%IrM_;j|;MO_4Qi7S&ND!;fjmT z%Nm-%H@^vRGr4Hlnm1b?U5-2ua^S~U!)b%AvHHO~pD0I}=FYCl7o3m2b)+Lf?hiCR zybZ#@tK+_Z<1cUV0)|?U>1#n8Mtq>T=ip+>EpaOEJ%ec)BV>Bc80?sJdEkhM*&D(q zkltmukzssQVjR`|4us&u90NH__hXlX=8qSw=3x^*$$W#{yNIYL;voeYh?M<^D#x0J zhAOW`RG-1|{Y#&Y^b3E03luqLXR+ji zadgAWvKL#;Q+hkMYP?JCO|)wQI|^fyKe_D$pw7`{9Ec=_in-V zcNuwm#Mesn=rs?aS0j}U+B)Afw~z1M-4VaK>$l6)W+Y}F5;9^Ibfmf_d~M(6GcGPF z7;(@|aIOy2G%%one4l6(y=E?Zf!o2TUybZq%1&MRpnw25L|}R)$I*k&_~R=*0@(=M zS3YQqlH3WrLGcZ`x8PRi?Vjr~0PIXjy=Q{d4&qQJz9s-vdR;hWcL^j6L^OnIbsa_73Q=cQk&hX{WW8ZdA_ADunwT{`k^uY0Luxdl``?wk5c zy?%rlm6KeIt5+FNZeW*6vqKW=f|1#unoe@`+AB6F{;W;C54l;{qEJ0~=e$6yHriRm68lMAdjxh(RvGp_O*B{p%`C z-P7I&qQzH{_*!)6{@C}atlTKx>AQAKOiUn_WicEEVS~F|#tnUid(QQ(qToSVE(CRD zShdqSpJl5ma1|dS%#i>$uo|C(Gnxo`k~K_CNqFa?oidGwz+Yl$_&Hb~P54g?bnr!* zASr77JPo(fI#^Y`(56FZ7q++vJS?=@!H|a%0Xr}S5cgp6kj1S#Ob+crBm@Fqo&mr4 zf>SF}FH9PMRG)Bla>}VO7QFESX;QubxRLP90YF~&amj7u?-D&KjHg zreGxd+avW07o?#c59^%%@gwzuwwCtsF}vlwf@4-UaHGGbv%1$M{?F7X3@1&EoA-w* zlpC%r>eGIWJJQ*z&3P$D;k4HyrCgZ(f9qA!{-|0eVUt&3=CQ$>X~ekt`A=88X#`5CS>0A+z`G zR1BgFDap|E{3G`^hs%sZ3?cy{GzKC z#3{zp=}Fne(mL|LFbVw$aT!7Vq1V%p^+e1nh6&aU9IzPalpBa7KSA_LgtTP_&VNyu zkqZ_^uuK)U>YypBLTv6xr@M?o1LrKTiN?`F12J)Nh0Mchq1cV6tcG6QhMWXD17wfy zvFkpIo15HvWni<7SlMYxRVdr(=Jqlbs@S{(WF6>6c4e$g6n1;kWA$Chwwglk?eO_s zIlxq9FwiOYg?F8Xo&74D4cKj-R64E?UWOEQh#fH(?3{Fa(qdH?(`I+8O{J^t36S__ z*yYGbm2@Z&0+DQ3b8U8%?V*U}iivwVul@agE=eo84O=Z|K2$ktJV+DNG>iMkLRzE;|Qu`w03Ws0k`)Bm=9}rOCs#zV9~|vRb*~t=nND`JyUh) z5MAyCQA+|I8KUkukmAF+0_k|yPc`QOJ^c91jU>jAYL1AIfW0Ob7P3M^67E*I=14+DSYh^JBVkvMB9HM$wB5zaclKmG z^L`cUQjl$N@#v#`W61GOHA@^k&>p$wnxm80^UN1@SKl!hmN*nP+n-lu{>=I=G`-fm z;M~CXdv%$ut#`~d*A%YRORFoiJhf%Yf@}DQA=mRoeub?a(Y~pcy{+3%sg8$9@Vj&W zG&LVj{%|ZZyJ_pA9ft?VZ|4Y1K-p>n9+4aclVnCPR3vRVNycu}8=S!`NyLkwsP@a) z8DKJ^Zpf#9g|?jfOSlq%YpKB9)iZ?27f z+vIq)|D4#B=d{L1>r?{|-$I%A)*zD@t zg`%c#EU9B=Q6)rx@k}uy+vF9^==ekxn;nq;n;J4S;yOu)HMiP})-rPM?vS zO|i1RXsEAmHD!TF=Ve$*;|w2?I~?eSWAHGOvThyPb!=iIc1{@5A&_4D(t#=v`v=J! zgfQZ)QJfUHa*XKVV6?z#*-AwcP7tF20zj6CKN>H26!GuuOAY2uVo$ydi642O|6~VI zC|Lc=zH8W>I#q=h^)AN+1BbbW2KhYuFd4^VQC3M=XEkp2UBF|H+zg@J;%<{x%L=Js zSKsM&0rZtc{u+Qnwj%l*t{)gRb7nWV!bby;A9#B?N zC)x9}2R024=|?`^h9}`(UEt^y^4HF9sjrE7Uh-dm+phKktea0!Txmm|RadKp^EFY; z|ES&r>EcCv8=Nn+8q7SD=|e)$%D0`Ezu8a)2^tqT4QTvGTd%C_=M)xH7;+g!lrOC2 z-86V4sSE8g(WGAPe5LAe|E^u+j$OOfL0OA>Ni0HF?WorG$pU_ zj8FvHKbC&3SV?lMl7#V?u2}K0m|Il*0K*b#94t(7Tu9y>iY)1kI7W80YcW!w6`;MH zl4aJev}+5Vke&&s+_>=qeRShlMMT_g4vcf4t8= zH8oMG&@_AKX~`cU373|F0xpM{0d6Fzx>qHM+!B8LOC-vK@}oBJS*z6T!kGbJ9Eh41 zQgkvB8@2bJLdw6#WFki|^dx)b#cq^D&!(rd|lS~^{S8b=bm>h8v= zDreup6|`|cs7>n&v`d5vREC!j2iCKqtumTD5O^NdlrAi1%f#y@F%tI8u$K|-McznM zx0b7`gpG|2hN>&%?^85EA%o<==ZbdEEVNfmS`D8*0xlGgFme0B*ZnBA@@b<#4%@xe zB5BxY<9-Zh+$RIMJOjL!vw|KePiy{G9TE?v1^F#w9qjGB7=Fx+8tvc`3YOw}0%@R0 zL#O@<@s?#}Wps9ol5FcxxDk=?9#)v$F5?^6&yPN&tAB)3Gy-7SBS#Q4J%qez|E>fa z=t@s?pgwCConXUWQG?>`5JaMv($eSFx%u^Md>@o?Op!F2NHEtX3@)awafHY8<*LYcq{j zp*RPUP*aE;ai%mP@z-a=xdt77;-g2aK}-=RI85P>?OR)P;V8%->P5T{{|oofF7}C7 z3CCqfp28u{EAVuVKH&TQ>WH4A788*;Aj6hfPA&Wy8G_Lfe9RNmZXa?gqNB%7Gh{OA z8hc={MNFhFb8|S^?R53@%m9gj_9CH-v4{I*B}Z(|flNXT@Cp5lGuvp%86PeJk)vfg znuEnR%)Yw%71q6YcwJmPPQYjlW<|o4;;R7Mex!@xeW0`iLr$lzZA_av8PaMKw#R|eU z6qe+5@#2=Vh}kd!R^77H4b&|jt0L#ez9y%(xMbD^KF^st%9CWC#IjL%{qG$^-ug&d zbG~k8-|fP%Zs*3B0Cmx`uX|rRS^~rI&K_*2dEcaTc;K+9`GJ;+2%3Rr%L6W5?5^k0 zbv~_$NgcHJ4V}mq$zRRym~dM~ur*%-i_7`j@ESEfd$qxNM0sC>g=%2H0!=i~G!v*) znyNqN+jT7qR;CJ5U5cIty04)dvDlW-!IP{K2>b7v+2pQAKe$$A{zlyFl0CnM4z6m` zLHWZGbq?;306#@k(W0CS?b(@Ivqrk|sqlZ#7Fo@bapP6QRuL;27?lX<{EtOSxSUU+G_To>l3MpR0+)(TR!yp><2j+rn3C(N`9qk&do3WZHW^ z%O{|lWuoGXKBkIF;T;=7O%5p0RpXESBp4+&;15^^ls=rPTUnhgQ@3}nm*JXu#JUj6 zpRL;!zRx*Hg0DwrBNvX|!x2Cv&jcwmR1~0le@|#9K@Zj`YS#tE3 zH>^;c6nIYv_yl#prc4cnB`dtW@L(sTrBOqG;+>LWnV%V*n&O~*EXVzAwB%Wg{b)Si zL2&QKdznRh$4ONRg{ptQlDrNWA2iPt?C(AgftZtQzT4-=C16>qga-qNJDT1zKfasr zhj)pV5;f@X@MrzcX3K0@n8j(Lvv(;nEFC)CQ8Xh-C?8NnsJx%roY#Ci(QxiTEMm*2!y#e(u=K^b;j|PA2^y&ac#dOydzOby&s**Ts1GO8=Ztnw-JC)6FQV~HsGMFZPnn!Q9(-jnP6@yx?F(5d{wo;W6C2QdQJc?E zOAbPUFX*B7RTI)gJz8>=Hz%b+Vu!EI*VymCp0xCTm1Iae&^ znKu<#yLrb|=a2%!i0|{Ea{$}rA;bhqmDJb2t_GMpw_PR#m&Q&{tuA~iJx-*`fSg_0`^eaoeV zq20>H20?e`{tq)-XRzzz!^{4RYeeVEHBx-$h1!}y_~x{jguj;#DkL3}kJlt|DG0n_ zSgK_Z%^RSfcaoKaN^-g`BH3U7+nl?K0^Rs5KkV)L{v^$e&@0G_Nu zs`OvAi-n(t8)uMc&FF4BJJ!7v3NnO@a4lKaX;L@Fs45vtu24UY-;$10OR?70-Jk)=jN>$Ki$4 z?{b$WKA%3+D~H_!zV1283Wde}U6tMZGIwlAVE1!<p2ixTe)ddEesA=L{j+&wL=!D>NQZiW@Q46m} zHh34CH+C~r#sutB-cIc>9=V3`MMNfI3jW)__kdECg0c7i0vLbKWdHyG diff --git a/doc/salome/gui/SMESH/images/pref21.png b/doc/salome/gui/SMESH/images/pref21.png index d30add41694f180a71e86ade80aaaa97a38877e6..d39efb580c5210d6c9bf532850c8168b05fb15c3 100755 GIT binary patch literal 87299 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

C=Zm8Y=$ttOFV8r6Go&yF4 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 JL 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

A+02w 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 VvnZ1zo?&9(?C|h$uW~z-@)uq(f7}27 literal 85160 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 D94xSa literal 0 HcmV?d00001 diff --git a/doc/salome/gui/SMESH/images/prism_stack.png b/doc/salome/gui/SMESH/images/prism_stack.png new file mode 100644 index 0000000000000000000000000000000000000000..bba633477a8b0fb1184b0c7811c98192d3f3a0b7 GIT binary patch literal 20898 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 J>&-nA{tFkT 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 literal 0 HcmV?d00001 diff --git a/doc/salome/gui/SMESH/images/scalar_bar_dlg.png b/doc/salome/gui/SMESH/images/scalar_bar_dlg.png index 59ca53065b9a06a53ae289a6b6e469f67f20bc99..564689ad96ef81e321572bb7e4a84e2d156e4f28 100755 GIT binary patch literal 33252 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 z z&@#NK$@Ry8%a&eRLb(EKD!;79C(}=L=DqZ7e)lJY{M0^we%@aIIx8$4<>JC54t*f* zY@uywq5YoCJ6A;$oGOAy;^0QVG8Y$XF<)ueA%Esf5>RV()3lo3Z+-k2ow(uoNB)a5 z-UkjFRGdm)q6*HTsi|5)1~SBK#?R`E^@PuDEz+FTgTv})RWpl#)2fMnropK^_O-R$ zHjU*ZTYjuIj7SV>yM1`l$9JWnQD?io^O`<*XBam9`eJ;;sXGhME{b-!)P2b10ZW09UYx12gd-~16rz{ z4KHEx5%>L>!9!tq0;o~F!{HSpom$Hj&vL>qzwVCp#{WK$25T9y9G?wQmNM%PB*fT) z^j+O%1wANQ&}EAdlCO$+{!x#?xFCV|?+FM9SUuoB3TGP%3Zxg(Az1(pbFv}x?5;c6 zD$JXFzGu%sxzctre{yo7sR82f(UF#|ja3Fe-{ka%wYwV*s5l90xpRHAcDRL^S+in1 z{9tjzVy3WH25wi$C>^2&b$xNe?lm*0V_;&^&6;lpR2R*`mSomL9`J&uI3JLBMk*>R zW!~!C12tS5 z5`41!A@_XINwmV#Jhoa6f!!FL@O3;r{4@dURlmToL>q8G4k;)aILhJG6nJ{RU5k2h zYh5f6^&pO^ueTTU8d~HH!SvUvx1~M+uCKD!nhWwdzR{mE4~KB~v;`C4;Nh(AJXF<>o%ezzB10mVOvkn)=IA3iaq1Y+euIoP$qrH9dwN_J0upQ*QPtrKow+gTQqx z(1>T#%XK+g9+|eXnrSZqm$S6mA}3q_2{G^cmNGzhq29;uJw8j~5ct9bKS^S>jlYVP z(8AC5ZDei4!7o6?XCh)Lp}0$^bV9|qzp0z{*YVnEq8M&A`P#=N*xff{PB1VHkI*S`MpNHGtItJQAkK-XsE23nwq_RXoAn`0%fzK zIVnOoanq9(>5Ss4iMkicfN+h-W6%1incB8^s8f6_X8?= zb&GH)Sv(@|3?oM);r%(X5yT`*mLZpl`L4X8V&!TSQqS%1n)!7JJ4eC}8~^E;%qH01 z(-r($rYkox!j@Mjyw0c@W4`y`B#i@BnXY3Z)XZhG z?sV1jWSUU2cXWJouG-MS1(C-qwikK4{Q%_pR#bus)%dCD4|_AEAx!J3{zw8Nc~Gd8 z$<40^mw*;Q(Quh;XCa7VlBuj{v^Mpix(xPrr+wDq0lP&6&eFRp*xl7q(96aXLYu`S zrP~;N6AbHH!*E>A$$eILF{#9k) z@zV03-OUgEdV_V?VLjB$uZcP@X9_?DuIB@9!-iR$=snKm>s;1D?=)+ZV`7X<^>{z6 zbkKBvwY5{XE{?X|Ht0!I>IN#g?9Ab>m_vm@$AdUIz`u(vs0DN9%k|h_iGK2fmi*b{ zZ$~YzpYU(Q36O^%G3uLoUBxLOt#?K96=h}FQef_n9~yahM2ry9;P|M!%F#O^A+JOc zI+o?J%UUNNnIv`^@Apc|#MNW#a>X+*!q#b4^X=K&Uf({Wb}Jh{*Y4B)ekb*c`Sk+-!sy6| ztGWg)m`wFXU%ua^kfT}hxP@V`HU@L3-U6mb7itri% zw2==8EjAa1etsO3atc1tAjgK6l^p2nECz-@-BjkgoMr|KZ3gC1{G+U_?1%NwpKmGO zb`K2=C7N)o7hi{5h1FnkBx;&1KxRW zGAo-m6$GeFE8={UdkEp7oJR7s?u8$n4$1(1u?lr8rFz!k)`BDg#=d;HhkYGQ>C)5F zb9H8ye+%z)JLiBX7rnD}KtLe;hPydx(We39vca1L01WMm*3Nqf2%}#A^Pn&If_$?H z+f$$c3GHhM*-(GX@1-teK2Ai*?>UizqQ{*n?eey&{K*M2QAzrdo*( zWNAt2%2uHta5=j1$A8`hKBJUo48}sVk)n1kD#;8OoUftaE=hBD0zqXyl(g?t zm_D^^M?kKZe00RlAuTn?)>933S3hsv`cgy5m$^bQt!XcRC;y`M78dZw$aozO+CoUc zfSIS>j?T_g6B9l0%w8~JwgG=5c6o}i+|Blcm*9nO?)^e-mHc$z> zob6n4Z9SKQ#-wmk(q*6vz7s8LPYRBow*iGBH3o$yId*(ZOhQadt+j~dN`&r*-o$q{ zCw7%Y+L`g_6#Nb5v)qv1uY9}hF+do+_(5kZwV;A_|IXXTC5}mRx_aM{_7azJ1x!Fj zC*!WIv3>VZK7dxXgOXvA+NGh>KL)jYXR1oQ+TH7Hq|-Z`g54YB^3qa#iLC5w``xLS z#J!;`DKG)y(^aM~=+pd$6s(Ndug>mt-66__sfV++{f9XA`%_rt=_8%u$>Bn(WquKk zQIFKeq0XUcB_8v8Z6U-i!9?Afw~ZCaS!`qZ1qB8A-LWGTsi|`ScfcLRskCEC^u#y< z?LyW5fX?mABpHvL^?6ss^Vhk;ICLwRu{%1?=Jb9kJM+2kAo(@t73J}}ZGB%qM`kD# zq2lJ|rlFzHc0GJV2?*U9K-2{8MNDDcF(o?eOEFzrD@@ERtU`DkY+cXe$|yDhaIBG} zPG8|!DCp8a`9X0Gv+rHaALkc}<=OtcgRSj* z+pv+)bB95HegXp{BayrOo)%;-ZyJ~QK#n}-G%ZM1H#A3PvcV1!?}ntg%2_VSnvXX2 z(q2kiMg1McYPNJjnf0oqi;Ih3M^_Bw=K8i?SsKg*8!zp?ccSFQ$wo6phVq1d5bP7n z?u{rzYtlKmt)=i0;S{evp8H$m#!-uf$X-+HbY^_vyTW+Y$Q00%$OhrznQm?M!Cczj z-d;gAuZi#+FXp%p}`^oG*kK$O6_AIOMZE zfeytoonZs#51wK~phVXBT789{CH}x4!f6N?F?aR&DlR1%Q zGVv~_4apW%E*(20!FL8v+LCPFp9ZKc)mtt5X4HRU%B}yr5trA0L}n(vX|$*IBSj6< z`Y8Rtu^El>slavE#J9aHr{s(KVYc_$!1A?(qa0Bm+-a7OzSSu#Xq8w^TBzk(Zf(C@yU-X3dHxy9=##Ya-T*Il&VTw01_j^VQ1Kud1o~%W zBb$BXN= zYh8`t)#Tpc85tRnxR+3uv%a4{zhGJ)Hd$ypY`?u(E4lvbxR}!y{X+5bWZU8VKu1tq zRdoWq#m2_Q9Z?Z)6 z&GH0{bmO##Im;wU*MuU03ZTOFP>=*w(M7#mlc!qIXGFtI(`@g7pZ|eS%G5MT^%w>3 zHw)(}4*|=Ux4&8!oBhTM)eZlkttx@x7qpzW+yK}CSI+s57igTpTWm8Pf7*lm$DSSv zelFmz#+HQ0?vfSs%B=MsLSEj9#|&F3D1mVzi}&eQ?Dr;Ux!WH4QkDPhxUKy;2Ej7+ z@_XV2-&h3f780cgE$u1As{`3jRFvOKzCEQ`JzSs^s)blgW1sFADZ4H~<0rgHVA`1| zdHq(P=cyGKX#M8`JuvhiBQw1RnS;X_qk2_zbTmL6E#?{~XJ<77@jPFREQhpSL~+mj zMWx=Ys3SGe*3dwJ>@f$!iz6g(339>r2u6M)atK0X)7Dd5eL6o!oREvC2QrDTFUE9t z5;hdeZ`S9a$Looe+bV@X?~}}H)uS717)2{n0|83$qw~DsHd37FJePLHLa4+hA6ei<1+$!oir>`1tH#cACj} zkwhsIrucRJ=Q-%h+Jm5h_S<7RPVU9ERp`drl5m`f@sT?}#8vIHxsHU)aH&`XUz?-< z-!5$X`v!@S82D7Wu9#rQp{`h+?WQEs=1|sl`U3&>(V>j4+62PiLsKfs9iDoxtX!YX z<^rA5GSvEClF~|XRCu`M>5dwGi`Un$($dm|`@Y;D7!v0R6eLtK^SJFb)YkfxptOm$ zy-Z!7sx%Wr0w&eG>bGiw?~=oDlo8XP^Ki9*Sv#6%+`mkYF85XH>rTLvIqFWPDi#sJ z1-!`r-Td-$mXv(^25#49pNTZh!L+)IXF|z%0e5`OVC5 z3=FPnsx?&4a_1gj2t`c(?f85=DqF``5qaC?RLhOI>@bQ=inY@Cm7GG;erlT?4*d-O zre8E$|JrD%#l!t)VG{HEi?2RXzE5^k6cngVRs*jMdJ|((Qg)Y?1d$Fw@H;$A@4~^x z*3i_<+wAD*0P-4DH8m_j=hGb`BBIWbDNk4T^e1O*a}@;*93$Q%i+kG~Vv2x7e^yM; zZ)0YA@CU3bglsc=C_}Yl2d3^tLect>qiUzk886-u_z_KWzhJfsd=+w-d zobe2`DA5q&fFfcdEdJSPzYy6HO3(}RteXIt=Ev4Ryqn9DD52t!$7VXU2F60=0*&Umz&E9!I_GqLbdla@yzs&` zI-*;M$H`w%lpSS-D2unO1@LIc6)J>DyCUF-$+G_ zReo|4)#ez@3jk99c;rZpfWyh08sRzKWfQ|=_pXD%OuyqBLmWX)QgljT01wcwyVsiR zyK_SW6CCt9gQfMA@}}RKKSD5&MF;&20LRtJ!5zz%4~*S+G!FWg<>ieNZp70W)p|6CXE?GmaC%|NGaLt>}wR{kph^@Nvzr2DDSx*Vj~3R7jMh=!QV?Qf}Cv zt$lmG95xeE8@7{st)z8(Xf!qq66dM??kQ|u7ub>rH)HNEZr~vh@;GPZP*YKH+wX|4 zD&N)$4@9I?*&m0daGOn3I2}bBrEiZb_`p5&b_$c+Tuxq@7tZHFZx(Zrobl}rq*VR` z`RZIpOy_YhH8IrH(bcIl?aYu%<3D`eccbvJd_))oVetVL7j-F+sKMd|Z*6`4F-L#+ zQDXKG!LE5C=E2qJE>I(7XS1@h<{?{H?7Ll^9**Ez>2cU4o`J>A>*L3PQbUBi`-d6>K|5r12@8_)T^t; z&?E$ldD`JI<@chZzRAgizCyqQ$Vf^Kjf_0=-Vr#*fg;@$a^De%fdZjD~w3RhfK2L z1gdkjnacqitnYci{IDo!+wiWQ-f9K=>u28YqvNJk6Yv_G#mtts1{hC5=@4E&{RBcm zA_OsarYl9&2$X)!i|1EY!vGhGOi0+=--kKuYh8Z0ALvhAukuoRi-Zs~-hAXx8dIT( zwgKfrIEU#JujK)zXLl7dD~_r;=yYU2d?didM^dl+?DGmD=|?~g_qM+W><0+RMa;&H{j;1fdp~B zbmFAXuz=n2`lKW$hms1!#6+Dnx5?Pt+~f+TMl+Up1C5lBTs&ct{4jtF>AUW@B;9Vd zl%OGmBt+os4Fxi%u^z8$-Fx3}YeBKKTpv$(WgK*SYdlq91bVeJb~EBT29&!9O%bOH z?aodBDut2b8gE zpnxL-2;4icST2rdd{Ea0V|>`Qna5Z;Esfr~yMxVgK>=_R87hI`>_4tGF$i`57GM(@ zkgj`iyll1mpNGar!Mx*vF>`Z$vsu{Pmx*%$*!7WA>gC=Zb++u0bHrJOX1zT?kfiaL zRBQA)e!7D`_CzajDqn8C5$gP2Ma2b-$^P8Q^22gER1%P z75Au6t1<)d41yh>!%C%M9|vl^*qgeKfZRA07>q>VX#JFh%GLMmHPum3VH#D2cM2Gw z{`t9g)?0JwIo$1)k&7JvT<7h9;VnzO9Q0`Mh>M9tXWj^3KlDQP_x_S+z0E z&D+M$0DC^UrK-;O5JgfO!k$mOvA~-9E9A|CtrAxZEj6iPFj8c^NXzM@>}TIt6~Gs0 z_O;U*kNqM7HUUplk;tZNlyyx!5E|zb8O+{+Z6V$IBeA8y_Wj~UWk$nwODQ!|N(!wk zVNTvfe+nw#nZ1!9lkH3LXB+ZOL(krT5N$DT{!)uq#Wv@gdz8qO$liQj6gE@qwtfAj6)v?k@fI!x8nU|N z)ZDy0WKCFArY;YJb(yc;Ucm?C0I*DV%oumg7=^yZg13jZqN=}WHVYKIcm&yyOF zr8?w%Q{X{V$=r6vKto_=W@ccpHj<|(m&*HM`E$_3^*<+(jZ1p2^Qoy`9{a5do#8d0 zbM-0GmO2Yb^oQD&TNIPG6`t@^Rtu2gz4d-bcjjw}c-%)eJvFHc*cvAFvJLPcJKhi* z7%tXvTzDvUy%ET zFR<`##r zJAa>u$M&fvn0Exesr6nAaas3gb&WsJ`CA7%ayM>VQkwv<3S(e!yjqh1#C(d&DYClq zgsmb?6bJc>*2AYf?P~ZZ6(CCqpejbfHtQ#WwvK7o421@ZO@I?E}xjF_%K3D zg*MQt%gWX$h?phnu4?kOn3gS({DdUC=#eOC^zlZzeQn{!`erFHCl%S*q94r*^YWZd z8K#H2B!y8y|CF-IVR%|VRBmv^VRkvGwx0dr1Dvk|@GMK(vA5XCVkE=tlameY4xrBi zUgZ&6pb5ay#W{o^sYfIaW|HCJwy;7tIaS*RiyT}Xk@Aawc*${*;tf`7d!#l2NwipK zT31)+mCkZ@?XCNJN{?zEGbHFD*c03r71doQMEuV~&cu0l=x4px&@!|IP>sS5l`KZO zvGMWGUqRbi+mqB(w>CEe%%6Q6j2z#WdVtTg_QJv1dJbwL=5*1%-fu&|6yFZ}_HUH| zaKddO(wd5=0AQaYN(YGf>FFtWb{si5IrtL3 zC%r6altg#`FBAR1y1MrxIv7aoK93%Ot=sECdnkz<9tt?K-Y%9eU}5{XR*Ky6Vg0;o z$5v+QA!ZrjyRh2Yt>N6$odC0)CZ?+uhgrZlcY3>SVCk>By<#JgDhE;kbVAN>Sks@~ zW;^V7jZt+1zzo#BXnQk<5U^DEa~L%7N2*fX?)Zytu4<-uTr2gAp7tx8D9b+vXGP4m z1xf}GK*0=cpe2aj$z16^vE`IX0^U3CPwF<`go+d+K0RiI$T|M&O&W*mR`&K9oec?ja?=Qta z6wK3w1-Ui$Cz5l=8YCnp0Qmr1+|CXuD{A*IAz!x9p~%|l1EOH|+|-+^Q+bSM6)fg7 zC)AqOC_$1^k{gKF?4!AOs)r)Kwx!nP`cqk}=V)6cyg-tpp#KpR6g2q{x`q0MKXnU* zXNvUVh?!_l(L?F^!sX@U`fF_rl~wM&4rc%IdB-h?29sPI31RDgKM)X{lg@jUX8C{` z>x;+X&9@*pK#LLHfTH2{qFu9DtkW5KoOPTt?O;pm?f*HXsF?xC9pptv_Nx@e-*;xX zi5Xtfee|hp)AW1$y9oI1TwBW$e-dvdLs~EcAYp|6cVY;xg})L*L{t7DhIk?LUx*>Z zPjz1%T2-g<_kPL)eQ1~T5Ni1|@#6R9DSNxrPC%_e%)9l&|07LDB;SyTw7}jpj>|SJ31fZ?zuVPCZvv$C>yOJ7G6{;@U+iq8hHNu>YOm6? z@@9zL_Ub=5<(mFEPA5oTG-5)BC>j@UBg_$wyn3UcyrTN`+Krj@NOsf2d+Hk5N=@5$$Fv@(&5^w1s!|olAKiGQX?hV3%5E zsD4V2otmlg$Ok{ac_@4cqH~<`wE8UmJLFS?F1;nZ%akKpFSDj}gr?OzZ-^YqUQ^K2 zW%h{lE&9%^zTxSrC$#=yA6`^R8xftU2uPuZ{qbWLkR*G2(M(^o8rMZ$7c%Oy6qgtu z>pg}%L~j}v^H5%02`Z|#gox8Z8F(whb%Ba0I;vE9>zJlGFSNL@kk9?ur;DwV_At@0 zu`x*j6cm|auE~Dd(3`f&tZoYx3tE9rHK_Y?>%6;8scugQOgP%XkQqBMIMP{hg-i-t z$1tikiJ)9Q1BFG0j(39Fx$tVHkOa0}Wyxk}_XQj6&oySL z^W&e`r0w;EvS)+gpuOU9SzY-*=vDj}Y>X_%XFC@c8Z}1(9d~BxjE>+$^S#MtdZt4) zR#BlT$qu_1>wBu2nwt9ht97H4vnix?JX{6pWD05*a{bE|^Tb>gX_+BLVBd6MWZ5Vt z#>S^R6GJ)m*bSJXw6dnN`9)k}SyzhyT4%hF~6o4d3KOahm^p%YXU3j=}fDVU2G zbd?mn-NO9m9GUv&gM27Ywd{>~cBm}s9$R19E~{1G*)C6*`OQU1WyD~t%=RY!lKDKZ z_0~)Zm@RqWBe$s|&AlNi-tv6qC9HiG_}Awe^{Ex_ za!_`@$FIQ3Tj*T$SfsYz#(FSFc!$WWnQI8Am!PFXFewjdU5W|m!r+%nPJ7EM-xsN2 zU}*B*e6V|Ra`f2}7gT~Wf4rLgwXxY}+y>)Wi}k({^}a>R8RxT6^CGvyY8z5?I*uzf zjh)`kVOPh;+t)Gi=6o7S>}EeQhp9eF$j=lK)`7m4BO$(O(0FWzXP(RGg~z*9SPG9& z;ov}rBe-vcrxrYjBytuKcc2 zPMil-C{>_NUx!4nW+?xsV^p3L+D6wsXWZxQVZx0bXGMxUs6~QMi?yt21)@u(doCi7hCeDH^hY z@>ttdLdFF6%#@WChKsfEZ>vR7rJO~;^AkQmoz=kOTi!lQ--5ZHMAnnlt-GKL@6AKq z_WKGMPd@k*d>F5{@DLP#>poXi(B_$2M&$lu5NEi#S`7R&2FDPYesS ztE_Wo$OgqplC&T=FIL1<9C}F07AqKZk~!Yh)pcx`=>c=2W32yjS&x6UUTm1L*${ii z8}}pOjCXvXBYw`KsVgtQ{lQ}nqa%-L_M3x^#TzS}oP#@u3dhFz=NSF@95@t)t2F%5 znF7g?{dZSc+Qh^}!zQi~NkR{AUd}dGj<2G^j^b>pho=Vo&DWjG*=KDK+fVD=pUBmu zVOO~J9_gdz3F_h~?nOvAU2=GovxLHgaVx=nX!DUpdJ8S$AMQg+jZV#v4V`n4w$j_t zv8?$%J4#vkgv)jD^=Q?E(}v$(Q2%0)?_LQua?H9wr*qfk@m}{4R4% znePMu9s8~1DXgrFg==&1D;Mj<6cJIKy*?O=3bu_ih#wk-M9j+sf!}Q=Xy)ulL$k9V zD{-1HMJxT1N;Tlm`|$(7f9kybVG+Z-q((3g`H?9wLGimsQjX37=1VINTpU8LfvWhs`dMl!wcpstdkhk0 ztDR0W#6{rlZxzQe8t;Grv0*Nm1hcnYh>FosE^ z9R*OpMs4yp1|VBq_a>^V`ciP!ny63Q@=XKH@D!KpDxVFzTzR7nzA46)&dg^AK_L3Z zVqNda>AFHEtoYd1({v3hG}~b}ofN^7OVY|voPt^5f ze}2fILIl>LF0C}4%{5KNL5h-!I*HA02It%7h&v(WO~@pMG?RK(OEL;eezE_V(^#?y z#8XxjMg{sWSTcXYox@zX4t4bI18Ofl?g3pxRowdWXiIH~PMjW{b7r(o6w$tr5I5J) zMgNl-L^?!>AktafNVM1{mp3LBBPWk42w{^Ay2ZX7#%L)F>snbP_{L#K&zy5Q3=Lm2 zlO&P2EElL|^h3L9a70Xbuw0IbJjOY`!zEj`%@saWmFPzem5Efmd6{dv&tcGcx1lsa zPD$kuIAb4+y=Ttersli%%4;-J1#6ngU^!!1h8yh#w9Fyh>qErmh7w-8_9VL`TDuw= zhZ_DlGvTQBVI0PvRn~9i$Q68deVvb4Pv-gWN^5|P((Upz%Jv1&KiCY4Y1Y+_YFDN^ zS<=mojmZu|&;5u)%Zbg)fNJ8K`AY-gspkj1(-BYl9K+1^!Md{t2hF}JtPU?x9|UZieXTk0{u4lPIv4c zA-qWd(%|u{6#_moM&}P-#p>k4c;EOwLO6N9AEgbqt?1LLnW{b$z`%>z2~abKIz#%Y zgAfp+5o6SAr7ZXG5Z)-;nv)F_V`%z=!u~1F-b|O<9v%=Xzj5ZRjk&r;00;UdT6jhI zx99IEnP)8?zE}rI6p!7_KE)wg8)ai_VX$Z1O$3fFU&~5(ruU{Amrj2BIe&AdKP-TIeqO+ R4E%-&5+bs~MS>r{{x26CgK+== literal 22098 zcmce;2UJtt+BJ%ycd3F1NN)lnN*98nNRM=c5IWLCz|aFkM2ZSZkq$vcAT;T{DMh+s zB27T)5Q=mm5bh4X?>Xl^pZ|aF9pk@ujEuox@4ePuduOd@&NZL;BpRZxNl$Z@hJ=KK zUh9^IAqmN;d=e6nJQW3SWWaT>7x;6^$58VcNy)&uCEy=2XLUVw5|Xkw+Cy7%;Q#aX zw+!`2NCJgPNWvbGkQ@Mq!WKzL;1@|qmTgE#lu}4Y&fL$azpX+-V)98#L*3ZldbMda z4yqM0H5|gb2tVur6ObgNf+REDg<(-lWTe#8@6=6SHiczY4ZpLGcsc8^3Z?vNWZI+q z=I)h;39S;;(XT!xI;;mu4&1+~ys~hwJbNTVIDO?_`FOdmC}n3{D(6F53#XaA_#1U}HTC*9ZAmoI+?`a@&~`CxJW_@eC95mAA1Dm8_I8OV;yHmsqTESv;=V&pwDaT_R82hxRLzdJZXe9~@D{=d->1;9{qI=^Rg7!sse??IVGE(jXSsM! z&9G&Al62>Zb9O%L7XiN0Lihn(jz4p(-4x)oUdvN4;BsvFFck-5Xt>p+xcnJjiPdj- z28D`5dU%g3VBQ*r-!NP4k+H_SU}p*T>QvlziySxPpL3!8}PlUx$pTVKfPWI7UsOHf~=)rnH=wW}$Tf&kj z!r*9gy(#GTh$O>b427P#U^w7sHSF>=JI!ptr>YlgjW<6t{CT)?+!Z#y5)SQj#-rgW z`%qu`xVp`^S;@hAp!Xa-Z-3DQ4B2V->6eYLD)Saj#llMVa+H9n)e;ITFdG^@HaOaD zX?#r>hyBXN$RAIJz6n{d6v2Kw-eSb?HXg}i4G?ovX2)}JN0iGVgpKs&_2YraWoLqo z0pbWYWpeyM`FIx_XazU;EW`aSLyjP;T)X*EM(i~V9-v$rpej_F*>x`&*H~y>kx{6p zS2|M>JuxM|ZnVmYD=p1R(Yr>s=p&}DHm@Qk#~&wPJsed453Y<|g|dt#1_FazKjg~2 zw&d1w3`Xn}PZ_Cg`4Q}Q%#Odp%tB{YeU{yhHv``377e&4dosq4hANtM@Hi37N5unj z=}SVzJbDq_W-WGI%NfInuZXAEA3Y0P;b^%R^+xCX`T`8i1q`bEe^d+~45(jRYacM< zq%6?M!*~NLXpeBK!2F;)bSwH`CtIx`1+sWC|PmNhX=wL%BgnL4{p$ImtKuI9T=ha-)5}rh8P^w3Qrl8x@vKIeU!3 zC}Vp{%rOplyzJZJi6NVdhoxB-5a;93(0sy^76PoW1s};6zHh(dMc9JmuG$bh#yjBy zX4Tr(Qyjm>nB6>Ag0)-vRLYub-Oos{l>6Mh;EhQiJ7(?T_TjO+uE4%f85eaUzjL@~aa1I(d3Q zN?C`%n#b#tc`d6#t z*+rHWVthT41)4BW;GN$k$|$hshX(5ZFG46`u~%7ZgoNV28I}0`lbLexd#d!KiqRbo zAQDRth!Mj%M2ZwaeN${WqThSe-OW9th4RYd(v>_$mln$K%y%q6+%6!-Z5Uo{UHm@+ zcQjbiS_MMs$6KH|Xq~U@xBmR^Fz-nh#U3pjEyo858{vx5jY>KFo`i0M?mQ%l`4t%v zTW(wm1D|qwVRI?nNsgZMVi=eYLd8mi2-a>A5P8athutfwqq4vOPy}#_h({1XQYuy( zc52}YXQx5n02M26s*Q*#FMxi-ECf^fvQn>pAOZdXPLcn<$)_jaOeMJXi)lF-A_^Z`AIN@61s7+*GNTe2=k;Y}Wk+#+6P@)t ze1>0EQDk>JLxGmMD8Wznpx@F2nOJ3)X5g^gl6uE}@4E4%*LsGO{5PJb&7Z$9m6v?1 zPo@o8S;J0fF*AJ%jf@=)xV8?3n~JTwX_f@yDm$dYZ|RjLFrzr}E{-T!q*7x*zM$5p z;ZVGFf6~)bkq3?1s?azDqQRqNucUmpr`N<2t6JwCev2vp?G?!9^(BWES>#aIXxldm zgMqx(yYsY3Wm~!PNpf%ItF|J>UIq?0lWMpsabM{W`AEuTZ-4#?xZq<81cH6&NRu-7 zQPskX zRX1ko2v10>(FzKlHg*i_?kzeC5CT?;kXg+TL6=C~ni^Ro%|!U6^_`JDMDSd&|)K~(gg0{x6ekt3Mf1i zQuxehE_DZ0c}wdPVsEA4O%(lUk#lJ%22y)Flt1#)jhO6jRL8TODXnj$$?kB3A=Rl^ zQ6O>R^wi}ACSJ=^i>2`UWYJ5s%uf~VC(rz0E+YCzYNZOvIYc8*k^NyVUr7T8fYT2FCWPeY1fxhQZe7Hum3cu;X)i(;{?KioU2kf~CHAK` zVE>rrzt__475ka`B6b_pIf~Qy@5z_9m%hYY*5^7+b%Z=UZ)<%>iaZ+zM%-T`h2LAt zNXyJN*`nQYwe?b$l#)c}&IwgDmKT|tn%yF;Xp3eMF|VTtHXzgXQIl7b{}B@6#j{4) zS;v{ad@&A84@M32XBmxY-AJhv&1|`EU0hsRu=5OFRaU2d_Bs8s0`78gtp@6Qh?Ocd zGJwpL1SHgwB2g%8Ayb?IyM5-Xl&*%0kDHMPY|NB*EjZs-YW+EdL%7m_k_Tvqd@atD zAq`*r#PYt{`LA$y^amBt6%u4xcD9+0j*crFZcgQ*+y1H6$ zbc7fRbBAm*;^J@p!E;5pmp9ipbfry(3TMB zL_J(*q8X8X`8*fK>nk%EnsIICjjoS0%cWZ0td?Qh5C~|_hhfX#i~)m%YoKPEzbx;Y zR5jPBj*is^&y~mHa1YiASK-HPM>dzX#shE}vb`UtN^tn)VxOx8YPqUrme+=#j20Jf z$vErTHZis>hX>WQpzEf_r?$LL+qKKbis?r5yge|CX<6J|*c5`st+Et&boYlm4LCCx z<RlURl=Q`&EkDq_;y7dqBip)6Lk~nCV(x`jR&(7|^#hALOB? z=t(G^itI6|dpp48rW5OXuzY_<3==6g*pY$lfWwN?o3UJbn&YFxyCr%YO+kAlfj_^u zJ;EEmgxb4Qq`c2h6=^T;Pg}nuS6CA4QB$Ee&|h!gXAl8SWpEf|wW7GMm{H1*{kmS` z%K(m6LB=+T4YRqqIh#Y3dSlIc;wrm{mtnzP$CES5UkucCguCst<7}sA;L3hxg1~OrC)ZLltN1+)*Rgo)~c*qybzbfSk{DoQtuU9 z7`HczAkB_zU#6<+AI^HN*7-}v!?|dp42QYOYahZ2a#V`;J#7gIjy>zs^E^Bq>cE^2T_VYqX+g=`$W^DP!Sw>sfA5*iFLJ)6{poQ~SQW_q5(-`bJfLr3CA$LLSg|fK@ zWz-f4zVqAB99yrM^WTDI#(1Ks?`VIzAMGrf-=0xJi@f9uii)3SQI0oMw1=Q*D7aydV$U_zo2r+Y$>C8}L6@X26SFvjuC09m0_uL*~T zH~m!XHTTUk_BCt!99vYz-z#(iU;bc`!Z+&l^^HDv6Xs$850mVZ^<3GaIps3%cWOD! zG54hxIRR5%LNX(f?yYh;y$EOSk@!T>Ee5<_je$`zx^Mv%}MbDY1wfr~~gj-%?8;vP6fHp`nC>{3Zrq%>AWG%i`weA&6Q-{BY4s z5md(PJ^Xb3F6YVt4Ln5?bvnO9aV}7kJ%6T1h)UDU1B~ii5dM8)Bj7zrpmCQ)19K#E zNjR9EWI9H#2#9kLV3YQzD~cC@D5i5dwqz^}JclYOQu-_8I@oBNWjVoCbY3q0ALg2K!ODI@wc7B_dO?+9Uzeke?k+fnF<~E zN6$J3{wK|vA8~%X9fxJ4YX@+Nh*JOAtAj6RHq=hQ{j%>L0IW+@_DyI}h|T$b_S!_9 zXqEDao(O~_6xZmCEnHLscdv1OL%d;^=E>*WH<BD72xxQwmU zf$Sf*erw_JHoEEEFvlOpb#BJ}xoTMt66yL6c>Ie6R;8xo8mH&lNUs3w5W-KINrPGW zwxW?TTh%W(Ec$t*GWz_9Y_UZ5Kp0ZEU?wsxSPB)?5a$M+qp$>+X5vS%Gf3!R8Qe<; zz?H`MS^o*ao&6quLj`EGzGnJ&W{M$>MGcgOsBh_-emqqSLAlGVNL53ep6ncjGO>Lp z&>rr;1<_(w{~S7AI=|eb;#^waS0C)yw;9D6YnC?inJ48D@Kt3}C-Tq@vu9@{%*=k<3(nV7nku^Ik&%gzX(A80yO35b}% zM(SQ(pUB~g$WGs0^QHPmLT3#6v7p)jC6P}D5Lwvv0%|#AvOr(4T};|aL1OpODUQ4E z!7o6$ypY9dF2U_90F^3;7P!q0%mB3$@>L+$5| z>sg4Jsz(YxH1sl}%72oQu3m&Rf>ZgiUk&b&m?_`4HCv$}z4+-7K){R>7!27dkwm6s z3+x>>dQ%SB+5fR&cjqJ()NFBHU7`HG^Vu4QbpXU zO7b2s&3`f~4Lq|JFeSOEG0xeDx88XyBKrQ$S3RitcdBJaMa4uvv1_1N0oE2vwmcK3 z#vqk57mQ_P$!8ou08}f}$Y;yPHN@6h@`6-;NA8WP%EmV@&0b=AmT3y!(re_a9c_QP zAa*%6myBi%d3UFc1cZG7z8bXa&JO{$F{OfvQVWG|Q^5TL1N!YQwzle$l9B~UNo-a1 z^=K)pTGZF!VQgpTdH#~#00derY3K9Z_iE0#bBb`UQ|SV;m3!_Ne6wYYx}cSx+tr{wNGVoq&L^< zyS~+6qVrtBzwL4dB8>PTfk{KdHd+_)i?8F((k5bTf!EOeHOn0rtq@Hw1+9NmVpaF5 z1lsVn1lCe=Z=yc;-c<8Zgy8;)eaT+IzTxs&J08w20CfmR7+DyfBJ8%W@<`GR7wU_f|_d)Ugb2++dp!vNQd&L72?Zk;ZPRj+pVf+(y#$SovHmiyl`6)Q);zyxhhjijRT3k z#34k3`SHWn9vQFH$4cwI*`D>yk2&aLbynkKt(Ty_ruyw_nz^Gdc?NO3W1m8M3-z5K z6>;h7d8?k(s*&<>ogWg~?@j%hmlv+4pG)v5^GZ~*lMrFba|;@N1#+Z}#e`wzX~g}e z4DqZilW)~cX^qzib&qPbvzhWgBDm|ih8%uE!*k+BD>TkLa>^2aZ&uR}S|+rG{5_uD z-rj`Nnr*W+#ih~4s01y=|YAJMIQIC_!9JWVyeW*@oJYF_ySw1vZ$9g5!2k&L*dc}9^=%TK@ zpQiaFR^I>Nsp<@}EAK#5AD`p+Wa{`tKRrQgOnJt>X(?9)d;M@ z?r+X@f`s5HVkW2+!dsd|oubqEgOca%UDaMm@5XyvwNQ*!KvJFyxmjB6ZNiR>HC4YG3uISFdSr<;Bkq&)n~7tO%S1)&2MTFJkgh45!!4L zXOIZBUt+Gs$kcRMByTl+txAR76DJo>-Y~>5K{}{+&Nrx1vROhG&kOA=0@Fp$3__I{ zYAkFYxc#v?bGxToNWbLJ`vS07@{TIAbTUe&YE^F`dnRfipLWQ{K5ZDQ)oi&Sdp@g~ zaiMj45QP$CJzjt=9t0`j%)I)%E_qWXjNEvi&d>;1-m=3d^sbx!j?WVV9=Df-ijFhs z%#Q|pQ(`=zS}Sg)8NmT_{yhq5aq;+eEuLB`kFsB;>|zx^F*Y1qsQB&9~u6-TOQ9KBRj^HXgzR1)~mA46(&Bw-XqbboAuUB9AX%mYKPP_g-9WXEQ6(C z&F<{Ed9{^Km-cBFnzVimjR*b}0g?$BMz=EVP1bX=iB6d&FOiBhGZl(-_-)e&m`zZz|jwv&sh;=}5{X30Oty1oV{Kv<5dsGZ$;YFJ2Wg+y=k&vP2b&<*(+W8)z!o3 zP0ofhc3BWg>2{7!qX7b(Fd6#lsTk}9dnGlsY@uAL#3m3`lk~G=NDzA4?d~-0PF?$f z@|!Z;t70l+&8ZIgpzV%gK4c71Vj-77mJcGs>9XEPm3Ww;6$`+R6zJ6OcP^|Bz$Jlb z9rCk{@u6A`-$LQvHv#QT;@2Ius92{VuM`qL0fz;UO8Cjq?@gx^VORd{4U_6O-~e0% zGI_|6I6^_ZsE4huFVGGow4k**0wxpB^U$GVsHFa}l78ysEN5R|{Q*T3j-?%7fn#>S z-NC4_vntC%7Xbz4X(~}sIg43v>RfrcO<#sYN&|f0e_*<9JeKT#D<2wDf`qbDT_k?A zE6C8bwweQUQi(Z#P!+E`r(ednTrCuXNe_K5^OfX!%jrSk-{9TF8+z`WcEXm4kuGZX ziSFP(pjo$>9vU*O9uo6`u+K1ADmbp8aRBUr`{RG11s?h*oL8MM2i`eoXJxeFdvZt5 zK3Yr|Qc+RC;&sQ|96}T~935{Imz1Ds&q(F(>;P&?naqAJ%n;5M1-=?eP|>*t>?vfP z=q5Dt5qZRG&A7A2-yQ>ymJjAWQi&`|bLbE(6xhEqNmOF$stT&5Jqj89RE;-%FmIOS zP9p<1x3yj-0-M@#v>r%3+p+7Ld>L*8KP;?#GOF)w;hk#cqCi*?hLi`!CnXf6ef|1X zSR!|I)uXDS;(FyTQF zcMcv`=V_N+wkJ(Vnxk}68UhcEsJN$?Tqcx)*#4~fj9eSw5V|M_H-qXOjf^*H$x={5 zvl6S@!zECo;Zm4c&Akc38qX=hwfNv&nPEI8SPV`t6ZdopkSiLsR<>3>Lxb%0AgYRI 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 diff --git a/doc/salome/gui/SMESH/input/about_hypo.doc b/doc/salome/gui/SMESH/input/about_hypo.doc index 5690ff36c..4453a7b8d 100644 --- a/doc/salome/gui/SMESH/input/about_hypo.doc +++ b/doc/salome/gui/SMESH/input/about_hypo.doc @@ -2,13 +2,13 @@ \page about_hypo_page About Hypotheses -\n \b Hypotheses represent boundary conditions which will be taken into -account at calculations of meshes or submeshes basing on geometrical +\b Hypotheses represent boundary conditions which will be taken into +account at calculations of meshes or sub-meshes basing on geometrical objects. These hypotheses allow you to manage the level of detail of the resulting meshes or submeshes: when applying different hypotheses with different parameters you can preset the quantity of meshing elements which will compose your mesh. So, it will be possible to -generate a rough or a more refined mesh or submesh. +generate a coarse or a more refined mesh or sub-mesh. In \b MESH there are the following Basic Hypotheses (to introduce them, you operate numerical values): diff --git a/doc/salome/gui/SMESH/input/about_meshes.doc b/doc/salome/gui/SMESH/input/about_meshes.doc index dc68cff59..97d14a3ec 100644 --- a/doc/salome/gui/SMESH/input/about_meshes.doc +++ b/doc/salome/gui/SMESH/input/about_meshes.doc @@ -11,10 +11,9 @@ Meshes are stored in DAT, MED, UNV, STL, CGNS, GMF and SAUVE formats and can be It is possible to \subpage constructing_meshes_page "construct meshes" on the basis of geometrical shapes produced in the GEOM module. -It is also possible to \subpage constructing_submeshes_page "construct -mesh on a part of the geometrical object", for example, a face, with -different meshing parameters than the whole mesh. - +It is also possible to +\subpage constructing_submeshes_page "construct mesh on a part of the geometrical object", +for example, a face, with different meshing parameters than the whole mesh. Several created meshes can be \subpage building_compounds_page "combined into another mesh". diff --git a/doc/salome/gui/SMESH/input/basic_meshing_algos.doc b/doc/salome/gui/SMESH/input/basic_meshing_algos.doc index ff225d080..82ee9d824 100644 --- a/doc/salome/gui/SMESH/input/basic_meshing_algos.doc +++ b/doc/salome/gui/SMESH/input/basic_meshing_algos.doc @@ -36,7 +36,7 @@ quadrangular elements.
  1. Hexahedron meshing algorithm (i,j,k) - 6-sided Volumes are split into hexahedral (cubic) elements.
  2. \subpage cartesian_algo_page
  3. -internal parts of Volumes are split into hexahedral elements forming a +- internal parts of Volumes are split into hexahedral elements forming a Cartesian grid; polyhedra and other types of elements are generated where the geometrical boundary intersects Cartesian cells. @@ -47,7 +47,7 @@ where the geometrical boundary intersects Cartesian cells. Some of 3D meshing algorithms also can generate 3D meshes from 2D meshes, working without -geometrical objects. Such algorithms are +geometrical objects. Such algorithms is
    • Hexahedron meshing algorithm (i,j,k),
    • diff --git a/doc/salome/gui/SMESH/input/constructing_submeshes.doc b/doc/salome/gui/SMESH/input/constructing_submeshes.doc index 060adae03..917fd5f65 100644 --- a/doc/salome/gui/SMESH/input/constructing_submeshes.doc +++ b/doc/salome/gui/SMESH/input/constructing_submeshes.doc @@ -4,8 +4,8 @@ Sub-mesh is a mesh on a geometrical sub-object created with algorithms and/or hypotheses other than the algorithms and hypotheses assigned to -the parent mesh on the parent object. -

      +the parent mesh on the parent geometrical object. + If a geometrical sub-object belongs to several geometrical objects having different meshes or sub-meshes, it will be meshed with the hypotheses of a sub-mesh of a lower dimension.
      diff --git a/doc/salome/gui/SMESH/input/extrusion.doc b/doc/salome/gui/SMESH/input/extrusion.doc index cb061b314..4813eee5c 100644 --- a/doc/salome/gui/SMESH/input/extrusion.doc +++ b/doc/salome/gui/SMESH/input/extrusion.doc @@ -64,7 +64,7 @@ The following dialog common for line and planar elements will appear:
    • Specify the number of steps.
    • If you activate Generate Groups check-box, the created elements contained in groups will be included into new groups named - by pattern "_extruded".
    • + by pattern "_extruded" and "_top".
  4. Click \b Apply or Apply and Close button to confirm the operation.
  5. diff --git a/doc/salome/gui/SMESH/input/mesh_infos.doc b/doc/salome/gui/SMESH/input/mesh_infos.doc index 06a02d2cc..5c526af67 100644 --- a/doc/salome/gui/SMESH/input/mesh_infos.doc +++ b/doc/salome/gui/SMESH/input/mesh_infos.doc @@ -10,8 +10,8 @@ group in the Object Browser and invoke Mesh Information item from the \b Mesh menu or click "Mesh Information" button in the toolbar. -\image html image49.png -
    "Mesh Information" button
    +
    \image html image49.png +"Mesh Information" button
    The Mesh Information dialog box provides three tab pages: - \ref advanced_mesh_infos_anchor "Base Info" - to show base @@ -27,28 +27,50 @@ for the selected mesh, sub-mesh or group object. The Base Info tab page of the dialog box provides general information on the selected object - mesh, sub-mesh or mesh group: name, type, total number of nodes and elements separately for each -type: 0D elements, edges, faces and volumes. +type: 0D elements, edges, faces, volumes, balls. -\image html advanced_mesh_infos.png -
    "Base Info" page
    +
    \image html advanced_mesh_infos.png +"Base Info" page
    \anchor mesh_element_info_anchor

    Mesh Element Information

    -The Element Info tab page of the dialog box gives basic -information about the type, coordinates and connectivity of the -selected mesh node or element. +The Element Info tab page of the dialog box gives detail +information about selected mesh node(s) or element(s), namely: -\image html eleminfo1.png -
    "Element Info" page, node information
    +- For node: + - Node ID + - Coordinates (X, Y, Z) + - Connectivity information (connected elements) + - Position on a shape (for meshes built on geometry) + - Groups information (names of groups the node belongs to) + +
    \image html eleminfo1.png +"Element Info" page, node information

    -\image html eleminfo2.png -
    "Element Info" page, element information
    + +- For element: + - Element ID + - Type (triangle, quadrangle, etc...) + - Gravity center (X, Y, Z coordinates) + - Connectivity information (connected nodes) + - Quality controls (area, aspect ration, volume, etc) + - Position on a shape (for meshes built on geometry) + - Groups information (names of groups the element belongs to) + +
    \image html eleminfo2.png +"Element Info" page, element information
    The use can either input the ID of a node or element he wants to -analyze directly in the dialog box or select the node or element in +analyze directly in the dialog box or select the node(s) or element(s) in the 3D viewer. +\note The information about the groups, the node or element belongs +to, can be shown in short or detail form. By default, for performance +reasons, this information is show in short form (group names +only). Detail information on groups can be switched on via the user +preferences, see \ref mesh_preferences_page. + \anchor mesh_addition_info_anchor

    Additional Information

    @@ -64,8 +86,8 @@ For a mesh object, the following information is shown: - Groups - Sub-meshes -\image html addinfo_mesh.png -
    "Additional Info" page, mesh information
    +
    \image html addinfo_mesh.png +"Additional Info" page, mesh information

    For a sub-mesh object, the following information is shown: @@ -73,8 +95,8 @@ For a sub-mesh object, the following information is shown: - Parent mesh - Shape -\image html addinfo_submesh.png -
    "Additional Info" page, sub-mesh information
    +
    \image html addinfo_submesh.png +"Additional Info" page, sub-mesh information

    For a group object, the following information is shown: @@ -86,8 +108,8 @@ For a group object, the following information is shown: - Color - Number of underlying nodes (for non-nodal groups) -\image html addinfo_group.png -
    "Additional Info" page, group information
    +
    \image html addinfo_group.png +"Additional Info" page, group information

    \note For the performance reasons, the number of underlying nodes is @@ -97,6 +119,9 @@ automatically calculated if the size of the group does not exceed the "Automatic nodes compute limit" set via the "Mesh information" preferences (zero value means no limit). +The button \b "Dump" allows printing the information displayed in the +dialog box to the txt file. + In case you get Mesh Information via a TUI script, the information is displayed in the Python Console. See the \ref tui_viewing_mesh_infos "TUI Example". diff --git a/doc/salome/gui/SMESH/input/mesh_preferences.doc b/doc/salome/gui/SMESH/input/mesh_preferences.doc index d2a6eb41f..a9d7f87de 100644 --- a/doc/salome/gui/SMESH/input/mesh_preferences.doc +++ b/doc/salome/gui/SMESH/input/mesh_preferences.doc @@ -73,7 +73,19 @@ mesh groups for which the number of underlying nodes is calculated automatically. If the group size exceeds the value set in the preferences, the user will have to press \em Compute button explicitly. Zero value means "no limit". By default the value is set to 100 000 mesh elements. - + +
  6. Show details on groups in element information tab - when +this option is switched off (default), only names of groups, the node +or element belongs to, are shown in the \ref mesh_element_info_anchor "Info Tab" +tab of "Mesh Information" dialog box. If this option is +switched on, the detail information on groups is shown.
  7. +
  8. Dump base information - Dump base mesh information to the +file, see \ref mesh_infos_page.
  9. +
  10. Dump element information - Dump element information to the +file, see \ref mesh_infos_page.
  11. +
  12. Dump additional information - Dump additional mesh +information to the file, see \ref mesh_infos_page.
  13. +
  14. Automatic Parameters
    • Ratio Bounding Box Diagonal / Max Size - this parameter is diff --git a/doc/salome/gui/SMESH/input/prism_3d_algo.doc b/doc/salome/gui/SMESH/input/prism_3d_algo.doc index 5589ba3a7..d68902869 100644 --- a/doc/salome/gui/SMESH/input/prism_3d_algo.doc +++ b/doc/salome/gui/SMESH/input/prism_3d_algo.doc @@ -2,23 +2,73 @@ \page prism_3d_algo_page 3D extrusion meshing algorithm -3D extrusion algorithm can be used for meshing prisms, i.e. 3D Shapes +3D extrusion algorithm can be used for meshing prisms, i.e. 3D shapes defined by two opposing faces having the same number of vertices and -edges and meshed using, for example, the \ref projection_algos_page -"2D Projection" algorithm. These two faces should be connected by -quadrangle "side" faces. +edges. These two faces should be connected by quadrangle "side" faces. -The opposing faces can be meshed with either quadrangles or triangles, -while the side faces should be meshed with quadrangles only. +The prism is allowed to have sides composed of several faces. (A prism +side is a row of faces (or one face) connecting corresponding edges of +the top and base faces). But there is a limitation that a prism +side is allowed to be split only vertically as indicated in the +picture below. -\image html image157.gif "Prism with 3D extrusion meshing". +\image html prism_ok_ko.png +In this picture, the left prism is suitable for meshing with 3D +extrusion algorithm; it has six sides two of which are split +vertically. And the right prism can't be meshed with this +algorithm because one of the prism sides is split horizontally (a +splitting edge is highlighted). -As you can see, the 3D extrusion algorithm permits to build and to -have in the same 3D mesh such elements as hexahedrons, prisms and -polyhedrons. +The algorithm can propagate 2D mesh not only between horizontal +(i.e. base and top) faces of one prism but also between faces of prisms +organized in a stack and between stacks sharing prism sides. -\note This algorithm works correctly only if the opposing faces have -the same (or similar) meshing topography. Otherwise, 3D extrusion -algorithm can fail to build mesh volumes. +\image html prism_stack.png +In this picture, four neighboring prism stacks, each comprising two prisms, +are shown. The shown sub-mesh is used by the algorithm to mesh +all the eight prisms in the stacks. + +To use 3D extrusion algorithm you need to assign algorithms +and hypotheses of lower dimension as follows. +(A sample picture below shows algorithms and hypotheses used to +mesh a cylinder with prismatic volumes). + +\image html prism_needs_hyps.png + +\b Global algorithms and hypotheses to be chosen at +\ref create_mesh_anchor "Creation of a mesh object" are: +
        +
      • 1D algorithm and hypothesis that will be applied for meshing + (logically) vertical edges of the prism (these edges connect the top and + base faces of prism). In the sample picture above these are + "Regular_1D" algorithm and "Nb. Segments_1" hypothesis.
      • +
      + +\b Local algorithms and hypotheses to be chosen at +\ref constructing_submeshes_page "Constructing sub-meshes" are: +
        +
      • 1D and 2D algorithms and hypotheses that will be applied for + meshing the top and base prism faces. These faces can be meshed + with any type of 2D elements: quadrangles, triangles, polygons or + their mix. It's enough to define a sub-mesh on either top or base + face. In the sample picture above, "BLSURF" algorithm meshes + "Face_1" base surface with triangles. (1D algorithm is not + assigned as "BLSURF" does not require divided edges to create 2D mesh.) +
      • +
      • Optionally you can define an 1D sub-mesh on some vertical edges + of stacked prisms, which will override the global 1D hypothesis mentioned + above. In the picture above the picture of Object Browser, the + vertical division is not equidistant on all the length because of + a "Number Of Segments" hypothesis with Scale Factor=3 assigned to + the highlighted edge. +
      + +\image html image157.gif + +Prism with 3D extrusion meshing. "Vertical" division is different on +neighbor edges due to local 1D hypotheses assigned. + +\sa a sample TUI Script of +\ref tui_prism_3d_algo "Use 3D extrusion meshing algorithm". */ diff --git a/doc/salome/gui/SMESH/input/projection_algos.doc b/doc/salome/gui/SMESH/input/projection_algos.doc index dcbae8db4..4cd8b81fa 100644 --- a/doc/salome/gui/SMESH/input/projection_algos.doc +++ b/doc/salome/gui/SMESH/input/projection_algos.doc @@ -16,44 +16,51 @@ The following dialog box will appear: \image html projection_1d.png -In this menu you can define the \b Name of the algorithm, the already -meshed source \b Edge and the \b Mesh (It can be omitted only when -projecting a submesh on another one from the same global Mesh). -It could also be necessary to define the orientation of edges, -which is done by indicating the Source Vertex being the first point -of the Source Edge and the Target Vertex being the first point of -the created \b Edge. +In this dialog you can define +
        +
      • the \b Name of the algorithm,
      • +
      • the already meshed Source Edge and
      • +
      • the Source Mesh (It can be omitted only when projecting + a sub-mesh on another one of the same Mesh).
      • +
      • It could also be necessary to define the orientation of edges, + which is done by indicating the Source Vertex being the + first point of the Source Edge and the Target Vertex being + the first point of the edge being meshed.
      • +

      For a group of edges, Source and Target vertices should be -shared by one edge of the group. If Source and Target -vertices are specified, the elements of the group must be adjacent. +shared by only one edge of the group. If Source and Target +vertices are specified, the edges in the group must be connected. The source and target groups must contain equal number of edges and they must form topologically equal structures. \n Projection 2D algorithm allows to define the mesh of a face -(or group of faces) by the -projection of another already meshed face (or group of faces). This -algorithm works only -if all edges of the target face have been meshed as 1D Projections of -the edges of the source face. +(or group of faces) by the projection of another already meshed face +(or group of faces). This algorithm works only if all edges of the +target face have been discretized into the same number of +segments as corresponding edges of the source face. To apply this algorithm select the face to be meshed (indicated in the field \b Geometry of Create mesh dialog box), Projection -2D in the list -of 2D algorithms and click the "Add Hypothesis" button. The -following dialog box will appear: +2D in the list of 2D algorithms and click the "Add +Hypothesis" button. The following dialog box will appear: \image html projection_2d.png -In this menu you can define the \b Name of the algorithm, the already -meshed source \b Face and the \b Mesh (It can be omitted only when -projecting a submesh on another one from the same global Mesh). -It could also be necessary to define the orientation of mesh on the -face, which is done by indicating two Source Vertices, which -belong to the same edge of the source face, and two Target -Vertices, which belong to the same edge of the created \b Face. -For groups of face, they must contain equal number of faces -and they must form topologically equal structures. +In this dialog you can define +
        +
      • the \b Name of the algorithm,
      • +
      • the already meshed Source Face and
      • +
      • the Source Mesh (It can be omitted only when + projecting a submesh on another one of the same Mesh).
      • +
      • It could also be necessary to define the orientation of mesh on + the face, which is done by indicating two Source Vertices, + which belong to the same edge of the Source Face, and + two Target Vertices, which belong to the same edge of the + face being meshed.
      • +
      +For groups of face, the groups must contain equal number of faces and +they must form topologically equal structures. \n Projection 1D-2D algorithm differs from Projection 2D algorithm in one aspect: it generates mesh segments on edges of diff --git a/doc/salome/gui/SMESH/input/scalar_bar.doc b/doc/salome/gui/SMESH/input/scalar_bar.doc index 146a7fa78..7ef8da51d 100755 --- a/doc/salome/gui/SMESH/input/scalar_bar.doc +++ b/doc/salome/gui/SMESH/input/scalar_bar.doc @@ -7,8 +7,12 @@ In this dialog you can specify the properties of the scalar bar \image html scalar_bar_dlg.png
        -
      • Scalar Range in this menu you can specify -Min value and Max value of the Scalar Bar
      • +
      • Scalar Range - in this menu you can specify +Min value and Max value of the Scalar Bar, and +also you can turn on/off Logarithmic scaling of the scalar bar.
      • + +\note Logarithmic scale is not applicable in case of +negative and zero values in the range. In such cases it is disabled.
      • Font - in this menu you can set type, face and color for the font of Title and Labels of the Scalar @@ -29,7 +33,7 @@ location (X and Y) and size (Width and side)
      • Y: ordinate of the origin (from the bottom)
      -
    • Distribution in this menu you can Show/Hide distribution histogram of the values of the Scalar Bar and specify histogram properties
    • +
    • Distribution - in this menu you can Show/Hide distribution histogram of the values of the Scalar Bar and specify histogram properties
      • Multicolor the histogram is colored as Scalar Bar
      • Monocolor the histogram is colored as selected with Distribution color selector
      • diff --git a/doc/salome/gui/SMESH/input/smeshpy_interface.doc b/doc/salome/gui/SMESH/input/smeshpy_interface.doc index b2b487954..699e5c981 100644 --- a/doc/salome/gui/SMESH/input/smeshpy_interface.doc +++ b/doc/salome/gui/SMESH/input/smeshpy_interface.doc @@ -36,80 +36,8 @@ An example below demonstrates usage of the Python API for 3d mesh generation. \anchor example_3d_mesh

        Example of 3d mesh generation:

        - -\code -from geompy import * -import smesh - -### -# Geometry: an assembly of a box, a cylinder and a truncated cone -# meshed with tetrahedral -### - -# Define values -name = "ex21_lamp" -cote = 60 -section = 20 -size = 200 -radius_1 = 80 -radius_2 = 40 -height = 100 - -# Build a box -box = MakeBox(-cote, -cote, -cote, +cote, +cote, +cote) - -# Build a cylinder -pt1 = MakeVertex(0, 0, cote/3) -di1 = MakeVectorDXDYDZ(0, 0, 1) -cyl = MakeCylinder(pt1, di1, section, size) - -# Build a truncated cone -pt2 = MakeVertex(0, 0, size) -cone = MakeCone(pt2, di1, radius_1, radius_2, height) - -# Fuse -box_cyl = MakeFuse(box, cyl) -piece = MakeFuse(box_cyl, cone) - -# Add to the study -addToStudy(piece, name) - -# Create a group of faces -group = CreateGroup(piece, ShapeType["FACE"]) -group_name = name + "_grp" -addToStudy(group, group_name) -group.SetName(group_name) - -# Add faces to the group -faces = SubShapeAllIDs(piece, ShapeType["FACE"]) -UnionIDs(group, faces) - -### -# Create a mesh -### - -# Define a mesh on a geometry -tetra = smesh.Mesh(piece, name) - -# Define 1D hypothesis -algo1d = tetra.Segment() -algo1d.LocalLength(10) - -# Define 2D hypothesis -algo2d = tetra.Triangle() -algo2d.LengthFromEdges() - -# Define 3D hypothesis -algo3d = tetra.Tetrahedron() -algo3d.MaxElementVolume(100) - -# Compute the mesh -tetra.Compute() - -# Create a groupe of faces -tetra.Group(group) - -\endcode +\include 3dmesh.py +
        Download this script Examples of Python scripts for Mesh operations are available by the following links: @@ -128,5 +56,6 @@ the following links: - \subpage tui_measurements_page - \subpage tui_generate_flat_elements_page - \subpage tui_work_on_objects_from_gui +- \subpage tui_prism_3d_algo */ diff --git a/doc/salome/gui/SMESH/input/tui_cartesian_algo.doc b/doc/salome/gui/SMESH/input/tui_cartesian_algo.doc index 3eb7f0fe2..4cc1ec654 100644 --- a/doc/salome/gui/SMESH/input/tui_cartesian_algo.doc +++ b/doc/salome/gui/SMESH/input/tui_cartesian_algo.doc @@ -1,49 +1,7 @@ /*! \page tui_cartesian_algo Usage of Body Fitting algorithm - -\code -from smesh import * -SetCurrentStudy(salome.myStudy) - -# create a sphere -sphere = geompy.MakeSphereR( 50 ) -geompy.addToStudy( sphere, "sphere" ) - -# create a mesh and assign a "Body Fitting" algo -mesh = Mesh( sphere ) -cartAlgo = mesh.BodyFitted() - -# define a cartesian grid using Coordinates -coords = range(-100,100,10) -cartHyp = cartAlgo.SetGrid( coords,coords,coords, 1000000) - -# compute the mesh -mesh.Compute() -print "nb hexahedra",mesh.NbHexas() -print "nb tetrahedra",mesh.NbTetras() -print "nb polyhedra",mesh.NbPolyhedrons() -print - -# define the grid by setting constant spacing -cartHyp = cartAlgo.SetGrid( "10","10","10", 1000000) - -mesh.Compute() -print "nb hexahedra",mesh.NbHexas() -print "nb tetrahedra",mesh.NbTetras() -print "nb polyhedra",mesh.NbPolyhedrons() - - -# define the grid by setting different spacing in 2 sub-ranges of geometry -spaceFuns = ["5","10+10*t"] -cartAlgo.SetGrid( [spaceFuns, [0.5]], [spaceFuns, [0.5]], [spaceFuns, [0.25]], 10 ) - -mesh.Compute() -print "nb hexahedra",mesh.NbHexas() -print "nb tetrahedra",mesh.NbTetras() -print "nb polyhedra",mesh.NbPolyhedrons() -print - -\endcode +\include cartesian_algo.py +Download this script */ diff --git a/doc/salome/gui/SMESH/input/tui_creating_meshes.doc b/doc/salome/gui/SMESH/input/tui_creating_meshes.doc index 24161d483..bdeeb8a7a 100644 --- a/doc/salome/gui/SMESH/input/tui_creating_meshes.doc +++ b/doc/salome/gui/SMESH/input/tui_creating_meshes.doc @@ -7,296 +7,52 @@

        Construction of a Mesh

        - -\code -import geompy -import smesh - -# create a box -box = geompy.MakeBox(0., 0., 0., 100., 200., 300.) -idbox = geompy.addToStudy(box, "box") - -# create a mesh -tetra = smesh.Mesh(box, "MeshBox") - -algo1D = tetra.Segment() -algo1D.NumberOfSegments(7) - -algo2D = tetra.Triangle() -algo2D.MaxElementArea(800.) - -algo3D = tetra.Tetrahedron() -algo3D.MaxElementVolume(900.) - -# compute the mesh -ret = tetra.Compute() -if ret == 0: - print "problem when computing the mesh" -else: - print "mesh computed" - pass -\endcode +\include creating_meshes_ex01.py +Download this script
        \anchor tui_construction_submesh

        Construction of a Submesh

        - -\code -from geompy import * -import smesh - -# create a box -box = MakeBoxDXDYDZ(10., 10., 10.) -addToStudy(box, "Box") - -# select one edge of the box for definition of a local hypothesis -p5 = MakeVertex(5., 0., 0.) -EdgeX = GetEdgeNearPoint(box, p5) -addToStudyInFather(box, EdgeX, "Edge [0,0,0 - 10,0,0]") - -# create a hexahedral mesh on the box -quadra = smesh.Mesh(box, "Box : quadrangle 2D mesh") - -# create a regular 1D algorithm for the faces -algo1D = quadra.Segment() - -# define "NumberOfSegments" hypothesis to cut -# all the edges in a fixed number of segments -algo1D.NumberOfSegments(4) - -# create a quadrangle 2D algorithm for the faces -quadra.Quadrangle() - -# construct a submesh on the edge with a local hypothesis -algo_local = quadra.Segment(EdgeX) - -# define "Arithmetic1D" hypothesis to cut the edge in several segments with increasing arithmetic length -algo_local.Arithmetic1D(1, 4) - -# define "Propagation" hypothesis that propagates all other hypotheses -# on all edges of the opposite side in case of quadrangular faces -algo_local.Propagation() - -# compute the mesh -quadra.Compute() - -\endcode +\include creating_meshes_ex02.py +Download this script

        Change priority of submeshes in Mesh

        - -\code -import salome -import geompy -import smesh -import SMESH - -Box_1 = geompy.MakeBoxDXDYDZ(200, 200, 200) -[Face_1,Face_2,Face_3,Face_4,Face_5,Face_6] = geompy.SubShapeAllSorted(Box_1, geompy.ShapeType["FACE"]) - -# create Mesh object on Box shape -Mesh_1 = smesh.Mesh(Box_1) - -# assign mesh algorithms -Regular_1D = Mesh_1.Segment() -Nb_Segments_1 = Regular_1D.NumberOfSegments(20) -Nb_Segments_1.SetDistrType( 0 ) -MEFISTO_2D = Mesh_1.Triangle() -Max_Element_Area_1 = MEFISTO_2D.MaxElementArea(1200) -Tetrahedron = Mesh_1.Tetrahedron() -Max_Element_Volume_1 = Tetrahedron.MaxElementVolume(40000) - -# create submesh and assign algorithms on Face_1 -Regular_1D_1 = Mesh_1.Segment(geom=Face_1) -Nb_Segments_2 = Regular_1D_1.NumberOfSegments(4) -Nb_Segments_2.SetDistrType( 0 ) -MEFISTO_2D_1 = Mesh_1.Triangle(algo=smesh.MEFISTO,geom=Face_1) -Length_From_Edges_2D = MEFISTO_2D_1.LengthFromEdges() -SubMesh_1 = MEFISTO_2D_1.GetSubMesh() - -# create submesh and assign algorithms on Face_2 -Regular_1D_2 = Mesh_1.Segment(geom=Face_2) -Nb_Segments_3 = Regular_1D_2.NumberOfSegments(8) -Nb_Segments_3.SetDistrType( 0 ) -MEFISTO_2D_2 = Mesh_1.Triangle(algo=smesh.MEFISTO,geom=Face_2) -Length_From_Edges_2D_1 = MEFISTO_2D_2.LengthFromEdges() -SubMesh_2 = MEFISTO_2D_2.GetSubMesh() - -# create submesh and assign algorithms on Face_3 -Regular_1D_3 = Mesh_1.Segment(geom=Face_3) -Nb_Segments_4 = Regular_1D_3.NumberOfSegments(12) -Nb_Segments_4.SetDistrType( 0 ) -MEFISTO_2D_3 = Mesh_1.Triangle(algo=smesh.MEFISTO,geom=Face_3) -Length_From_Edges_2D_2 = MEFISTO_2D_3.LengthFromEdges() -SubMesh_3 = MEFISTO_2D_3.GetSubMesh() - -# check exisiting submesh priority order -[ [ SubMesh_1, SubMesh_3, SubMesh_2 ] ] = Mesh_1.GetMeshOrder() -# set new submesh order -isDone = Mesh_1.SetMeshOrder( [ [ SubMesh_1, SubMesh_2, SubMesh_3 ] ]) -# compute mesh -isDone = Mesh_1.Compute() - -# clear mesh result and compute with other submesh order -Mesh_1.Clear() -isDone = Mesh_1.SetMeshOrder( [ [ SubMesh_2, SubMesh_1, SubMesh_3 ] ]) -isDone = Mesh_1.Compute() - -\endcode +\include creating_meshes_ex03.py +Download this script
        \anchor tui_editing_mesh

        Editing of a mesh

        - -\code -import geompy -import smesh - -def PrintMeshInfo(theMesh): - aMesh = theMesh.GetMesh() - print "Information about mesh:" - print "Number of nodes : ", aMesh.NbNodes() - print "Number of edges : ", aMesh.NbEdges() - print "Number of faces : ", aMesh.NbFaces() - print "Number of volumes : ", aMesh.NbVolumes() - pass - -# create a box -box = geompy.MakeBox(0., 0., 0., 20., 20., 20.) -geompy.addToStudy(box, "box") - -# select one edge of the box for definition of a local hypothesis -subShapeList = geompy.SubShapeAll(box, geompy.ShapeType["EDGE"]) -edge = subShapeList[0] -name = geompy.SubShapeName(edge, box) -geompy.addToStudyInFather(box, edge, name) - -# create a mesh -tria = smesh.Mesh(box, "Mesh 2D") -algo1D = tria.Segment() -hyp1 = algo1D.NumberOfSegments(3) -algo2D = tria.Triangle() -hyp2 = algo2D.MaxElementArea(10.) - -# create a sub-mesh -algo_local = tria.Segment(edge) -hyp3 = algo_local.Arithmetic1D(1, 6) -hyp4 = algo_local.Propagation() - -# compute the mesh -tria.Compute() -PrintMeshInfo(tria) - -# remove a local hypothesis -mesh = tria.GetMesh() -mesh.RemoveHypothesis(edge, hyp4) - -# compute the mesh -tria.Compute() -PrintMeshInfo(tria) - -# change the value of the 2D hypothesis -hyp2.SetMaxElementArea(2.) - -# compute the mesh -tria.Compute() -PrintMeshInfo(tria) -\endcode +\include creating_meshes_ex04.py +Download this script
        \anchor tui_export_mesh

        Export of a Mesh

        - -\code -import geompy -import smesh - -# create a box -box = geompy.MakeBox(0., 0., 0., 100., 200., 300.) -idbox = geompy.addToStudy(box, "box") - -# create a mesh -tetra = smesh.Mesh(box, "MeshBox") - -algo1D = tetra.Segment() -algo1D.NumberOfSegments(7) - -algo2D = tetra.Triangle() -algo2D.MaxElementArea(800.) - -algo3D = tetra.Tetrahedron() -algo3D.MaxElementVolume(900.) - -# compute the mesh -tetra.Compute() - -# export the mesh in a MED file -tetra.ExportMED("/tmp/meshMED.med", 0) - -# export a group in a MED file -face = geompy.SubShapeAll( box, geompy.ShapeType["FACE"])[0] # a box side -group = tetra.GroupOnGeom( face, "face group" ) # group of 2D elements on the -tetra.ExportMED("/tmp/groupMED.med", meshPart=group) -\endcode +\include creating_meshes_ex05.py +Download this script

        How to mesh a cylinder with hexahedrons?

        Here you can see an example of python script, creating a hexahedral mesh on a cylinder. And a picture below the source code of the script, demonstrating the resulting mesh. -\include ex24_cylinder.py +\include creating_meshes_ex06.py +Download this script \image html mesh_cylinder_hexa.png
        \anchor tui_building_compound

        Building a compound of meshes

        -\dontinclude SMESH_BuildCompound.py -\skipline import geompy -\until #end +\include creating_meshes_ex07.py +Download this script
        \anchor tui_copy_mesh

        Mesh Copying

        -\code -from smesh import * -SetCurrentStudy(salome.myStudy) - -# make geometry of a box -box = geompy.MakeBoxDXDYDZ(100,100,100) -face = geompy.SubShapeAllSorted(box, geompy.ShapeType["FACE"])[0] - -# generate 3D mesh -mesh = Mesh(box) -localAlgo = mesh.Triangle(face) -mesh.AutomaticHexahedralization() - -# objects to copy -fGroup = mesh.GroupOnGeom( face, "2D on face") -nGroup = mesh.GroupOnGeom( face, "nodes on face", NODE) -subMesh = localAlgo.GetSubMesh() - -# make a new mesh by copying different parts of the mesh - -# 1. copy the whole mesh -newMesh = CopyMesh( mesh, "whole mesh copy") - -# 2. copy a group of 2D elements along with groups -newMesh = CopyMesh( fGroup, "face group copy with groups",toCopyGroups=True) - -# 3. copy a group of nodes with preseving their ids -newMesh = CopyMesh( nGroup, "node group copy", toKeepIDs=True) - -# 4. copy some faces -faceIds = fGroup.GetIDs()[-10:] -newMesh = CopyMesh( mesh.GetIDSource( faceIds, FACE ), "some faces copy") - -# 5. copy some nodes -nodeIds = nGroup.GetIDs()[-10:] -newMesh = CopyMesh( mesh.GetIDSource( nodeIds, NODE), "some nodes copy") - -# 6. copy a sub-mesh -newMesh = CopyMesh( subMesh, "submesh copy" ) -\endcode +\include creating_meshes_ex08.py +Download this script */ diff --git a/doc/salome/gui/SMESH/input/tui_defining_hypotheses.doc b/doc/salome/gui/SMESH/input/tui_defining_hypotheses.doc index d9e2b31f9..3f3124db3 100644 --- a/doc/salome/gui/SMESH/input/tui_defining_hypotheses.doc +++ b/doc/salome/gui/SMESH/input/tui_defining_hypotheses.doc @@ -44,738 +44,102 @@ This page provides example codes of \ref tui_defining_meshing_algos
        \anchor tui_1d_arithmetic

        Arithmetic 1D

        - -\code -import geompy -import smesh - -# create a box -box = geompy.MakeBoxDXDYDZ(10., 10., 10.) -geompy.addToStudy(box, "Box") - -# create a hexahedral mesh on the box -hexa = smesh.Mesh(box, "Box : hexahedrical mesh") - -# create a Regular 1D algorithm for edges -algo1D = hexa.Segment() - -# optionally reverse node distribution on certain edges -allEdges = geompy.SubShapeAllSortedIDs( box, geompy.ShapeType["EDGE"]) -reversedEdges = [ allEdges[0], allEdges[4] ] - -# define "Arithmetic1D" hypothesis to cut all edges in several segments with increasing arithmetic length -algo1D.Arithmetic1D(1, 4, reversedEdges) - -# create a quadrangle 2D algorithm for faces -hexa.Quadrangle() - -# create a hexahedron 3D algorithm for solids -hexa.Hexahedron() - -# compute the mesh -hexa.Compute() -\endcode +\include defining_hypotheses_ex01.py +Download this script
        \anchor tui_deflection_1d

        Deflection 1D and Number of Segments

        - -\code -import geompy -import smesh - -# create a face from arc and straight segment -px = geompy.MakeVertex(100., 0. , 0. ) -py = geompy.MakeVertex(0. , 100., 0. ) -pz = geompy.MakeVertex(0. , 0. , 100.) - -exy = geompy.MakeEdge(px, py) -arc = geompy.MakeArc(py, pz, px) - -wire = geompy.MakeWire([exy, arc]) - -isPlanarFace = 1 -face1 = geompy.MakeFace(wire, isPlanarFace) -geompy.addToStudy(face1,"Face1") - -# get edges from the face -e_straight,e_arc = geompy.SubShapeAll(face1, geompy.ShapeType["EDGE"]) -geompy.addToStudyInFather(face1, e_arc, "Arc Edge") - -# create hexahedral mesh -hexa = smesh.Mesh(face1, "Face : triangle mesh") - -# define "NumberOfSegments" hypothesis to cut a straight edge in a fixed number of segments -algo1D = hexa.Segment() -algo1D.NumberOfSegments(6) - -# define "MaxElementArea" hypothesis -algo2D = hexa.Triangle() -algo2D.MaxElementArea(70.0) - -# define a local "Deflection1D" hypothesis on the arc -algo_local = hexa.Segment(e_arc) -algo_local.Deflection1D(1.0) - -# compute the mesh -hexa.Compute() -\endcode +\include defining_hypotheses_ex02.py +Download this script
        \anchor tui_start_and_end_length

        Start and End Length

        - -\code -from geompy import * -import smesh - -# create a box -box = MakeBoxDXDYDZ(10., 10., 10.) -addToStudy(box, "Box") - -# get one edge of the box to put local hypothesis on -p5 = MakeVertex(5., 0., 0.) -EdgeX = GetEdgeNearPoint(box, p5) -addToStudyInFather(box, EdgeX, "Edge [0,0,0 - 10,0,0]") - -# create a hexahedral mesh on the box -hexa = smesh.Mesh(box, "Box : hexahedrical mesh") - -# set algorithms -algo1D = hexa.Segment() -hexa.Quadrangle() -hexa.Hexahedron() - -# define "NumberOfSegments" hypothesis to cut an edge in a fixed number of segments -algo1D.NumberOfSegments(4) - -# create a local hypothesis -algo_local = hexa.Segment(EdgeX) - -# define "StartEndLength" hypothesis to cut an edge in several segments with increasing geometric length -algo_local.StartEndLength(1, 6) - -# define "Propagation" hypothesis that propagates all other hypothesis -# on all edges on the opposite side in case of quadrangular faces -algo_local.Propagation() - -# compute the mesh -hexa.Compute() -\endcode +\include defining_hypotheses_ex03.py +Download this script
        \anchor tui_average_length

        Local Length

        - -\code -from geompy import * -import smesh - -# create a box -box = MakeBoxDXDYDZ(10., 10., 10.) -addToStudy(box, "Box") - -# get one edge of the box to put local hypothesis on -p5 = MakeVertex(5., 0., 0.) -EdgeX = GetEdgeNearPoint(box, p5) -addToStudyInFather(box, EdgeX, "Edge [0,0,0 - 10,0,0]") - -# create a hexahedral mesh on the box -hexa = smesh.Mesh(box, "Box : hexahedrical mesh") - -# set algorithms -algo1D = hexa.Segment() -hexa.Quadrangle() -hexa.Hexahedron() - -# define "NumberOfSegments" hypothesis to cut all edges in a fixed number of segments -algo1D.NumberOfSegments(4) - -# create a sub-mesh -algo_local = hexa.Segment(EdgeX) - -# define "LocalLength" hypothesis to cut an edge in several segments with the same length -algo_local.LocalLength(2.) - -# define "Propagation" hypothesis that propagates all other hypothesis -# on all edges on the opposite side in case of quadrangular faces -algo_local.Propagation() - -# compute the mesh -hexa.Compute() -\endcode +\include defining_hypotheses_ex04.py +Download this script

        Defining 2D and 3D hypotheses


        \anchor tui_max_element_area

        Maximum Element Area

        - -\code -import geompy -import smesh -import salome - -# create a face -px = geompy.MakeVertex(100., 0. , 0. ) -py = geompy.MakeVertex(0. , 100., 0. ) -pz = geompy.MakeVertex(0. , 0. , 100.) - -vxy = geompy.MakeVector(px, py) -arc = geompy.MakeArc(py, pz, px) -wire = geompy.MakeWire([vxy, arc]) - -isPlanarFace = 1 -face = geompy.MakeFace(wire, isPlanarFace) - -# add the face in the study -id_face = geompy.addToStudy(face, "Face to be meshed") - -# create a mesh -tria_mesh = smesh.Mesh(face, "Face : triangulation") - -# define 1D meshing: -algo = tria_mesh.Segment() -algo.NumberOfSegments(20) - -# define 2D meshing: - -# assign triangulation algorithm -algo = tria_mesh.Triangle() - -# apply "Max Element Area" hypothesis to each triangle -algo.MaxElementArea(100) - -# compute the mesh -tria_mesh.Compute() -\endcode +\include defining_hypotheses_ex05.py +Download this script
        \anchor tui_max_element_volume

        Maximum Element Volume

        - -\code -import geompy -import smesh - -# create a cylinder -cyl = geompy.MakeCylinderRH(30., 50.) -geompy.addToStudy(cyl, "cyl") - -# create a mesh on the cylinder -tetra = smesh.Mesh(cyl, "Cylinder : tetrahedrical mesh") - -# assign algorithms -algo1D = tetra.Segment() -algo2D = tetra.Triangle() -algo3D = tetra.Tetrahedron() - -# assign 1D and 2D hypotheses -algo1D.NumberOfSegments(7) -algo2D.MaxElementArea(150.) - -# assign Max Element Volume hypothesis -algo3D.MaxElementVolume(200.) - -# compute the mesh -ret = tetra.Compute() -if ret == 0: - print "probleme when computing the mesh" -else: - print "Computation succeded" -\endcode +\include defining_hypotheses_ex06.py +Download this script
        \anchor tui_length_from_edges

        Length from Edges

        - -\code -import geompy -import smesh - -# create sketchers -sketcher1 = geompy.MakeSketcher("Sketcher:F 0 0:TT 70 0:TT 70 70:TT 0 70:WW") -sketcher2 = geompy.MakeSketcher("Sketcher:F 20 20:TT 50 20:TT 50 50:TT 20 50:WW") - -# create a face from two wires -isPlanarFace = 1 -face1 = geompy.MakeFaces([sketcher1, sketcher2], isPlanarFace) -geompy.addToStudy(face1, "Face1") - -# create a mesh -tria = smesh.Mesh(face1, "Face : triangle 2D mesh") - -# Define 1D meshing -algo1D = tria.Segment() -algo1D.NumberOfSegments(2) - -# create and assign the algorithm for 2D meshing with triangles -algo2D = tria.Triangle() - -# create and assign "LengthFromEdges" hypothesis to build triangles based on the length of the edges taken from the wire -algo2D.LengthFromEdges() - -# compute the mesh -tria.Compute() -\endcode +\include defining_hypotheses_ex07.py +Download this script

        Defining Additional Hypotheses


        \anchor tui_propagation

        Propagation

        - -\code -from geompy import * -import smesh - -# create a box -box = MakeBoxDXDYDZ(10., 10., 10.) -addToStudy(box, "Box") - -# get one edge of the box to put local hypothesis on -p5 = MakeVertex(5., 0., 0.) -EdgeX = GetEdgeNearPoint(box, p5) -addToStudyInFather(box, EdgeX, "Edge [0,0,0 - 10,0,0]") - -# create a hexahedral mesh on the box -hexa = smesh.Mesh(box, "Box : hexahedrical mesh") - -# set global algorithms and hypotheses -algo1D = hexa.Segment() -hexa.Quadrangle() -hexa.Hexahedron() -algo1D.NumberOfSegments(4) - -# create a sub-mesh with local 1D hypothesis and propagation -algo_local = hexa.Segment(EdgeX) - -# define "Arithmetic1D" hypothesis to cut an edge in several segments with increasing length -algo_local.Arithmetic1D(1, 4) - -# define "Propagation" hypothesis that propagates all other 1D hypotheses -# from all edges on the opposite side of a face in case of quadrangular faces -algo_local.Propagation() - -# compute the mesh -hexa.Compute() -\endcode +\include defining_hypotheses_ex08.py +Download this script
        \anchor tui_defining_meshing_algos

        Defining Meshing Algorithms

        - -\code -import geompy -import smesh - -# create a box -box = geompy.MakeBoxDXDYDZ(10., 10., 10.) -geompy.addToStudy(box, "Box") - -# 1. Create a hexahedral mesh on the box -hexa = smesh.Mesh(box, "Box : hexahedrical mesh") - -# create a Regular 1D algorithm for edges -algo1D = hexa.Segment() - -# create a quadrangle 2D algorithm for faces -algo2D = hexa.Quadrangle() - -# create a hexahedron 3D algorithm for solids -algo3D = hexa.Hexahedron() - -# define hypotheses -algo1D.Arithmetic1D(1, 4) - -# compute the mesh -hexa.Compute() - -# 2. Create a tetrahedral mesh on the box -tetra = smesh.Mesh(box, "Box : tetrahedrical mesh") - -# create a Regular 1D algorithm for edges -algo1D = tetra.Segment() - -# create a Mefisto 2D algorithm for faces -algo2D = tetra.Triangle() - -# create a 3D algorithm for solids -algo3D = tetra.Tetrahedron() - -# define hypotheses -algo1D.Arithmetic1D(1, 4) -algo2D.LengthFromEdges() - -# compute the mesh -tetra.Compute() - -\endcode +\include defining_hypotheses_ex09.py +Download this script
        \anchor tui_projection

        Projection Algorithms

        - -\code -# Project prisms from one meshed box to another mesh on the same box - -from smesh import * - -# Prepare geometry - -# Create a parallelepiped -box = geompy.MakeBoxDXDYDZ(200, 100, 70) -geompy.addToStudy( box, "box" ) - -# Get geom faces to mesh with triangles in the 1ts and 2nd meshes -faces = geompy.SubShapeAll(box, geompy.ShapeType["FACE"]) -# 2 adjacent faces of the box -f1 = faces[2] -f2 = faces[0] -# face opposite to f2 -f2opp = faces[1] - -# Get vertices used to specify how to associate sides of faces at projection -[v1F1, v2F1] = geompy.SubShapeAll(f1, geompy.ShapeType["VERTEX"])[:2] -[v1F2, v2F2] = geompy.SubShapeAll(f2, geompy.ShapeType["VERTEX"])[:2] -geompy.addToStudyInFather( box, v1F1, "v1F1" ) -geompy.addToStudyInFather( box, v2F1, "v2F1" ) -geompy.addToStudyInFather( box, v1F2, "v1F2" ) -geompy.addToStudyInFather( box, v2F2, "v2F2" ) - -# Make group of 3 edges of f1 and f2 -edgesF1 = geompy.CreateGroup(f1, geompy.ShapeType["EDGE"]) -geompy.UnionList( edgesF1, geompy.SubShapeAll(f1, geompy.ShapeType["EDGE"])[:3]) -edgesF2 = geompy.CreateGroup(f2, geompy.ShapeType["EDGE"]) -geompy.UnionList( edgesF2, geompy.SubShapeAll(f2, geompy.ShapeType["EDGE"])[:3]) -geompy.addToStudyInFather( box, edgesF1, "edgesF1" ) -geompy.addToStudyInFather( box, edgesF2, "edgesF2" ) - - -# Make the source mesh with prisms -src_mesh = Mesh(box, "Source mesh") -src_mesh.Segment().NumberOfSegments(9,10) -src_mesh.Quadrangle() -src_mesh.Hexahedron() -src_mesh.Triangle(f1) # triangular sumbesh -src_mesh.Compute() - - -# Mesh the box using projection algoritms - -# Define the same global 1D and 2D hypotheses -tgt_mesh = Mesh(box, "Target mesh") -tgt_mesh.Segment().NumberOfSegments(9,10,UseExisting=True) -tgt_mesh.Quadrangle() - -# Define Projection 1D algorithm to project 1d mesh elements from group edgesF2 to edgesF1 -# It is actually not needed, just a demonstration -proj1D = tgt_mesh.Projection1D( edgesF1 ) -# each vertex must be at the end of a connected group of edges (or a sole edge) -proj1D.SourceEdge( edgesF2, src_mesh, v2F1, v2F2 ) - -# Define 2D hypotheses to project triangles from f1 face of the source mesh to -# f2 face in the target mesh. Vertices specify how to associate sides of faces -proj2D = tgt_mesh.Projection2D( f2 ) -proj2D.SourceFace( f1, src_mesh, v1F1, v1F2, v2F1, v2F2 ) - -# 2D hypotheses to project triangles from f2 of target mesh to the face opposite to f2. -# Association of face sides is default -proj2D = tgt_mesh.Projection2D( f2opp ) -proj2D.SourceFace( f2 ) - -# 3D hypotheses to project prisms from the source to the target mesh -proj3D = tgt_mesh.Projection3D() -proj3D.SourceShape3D( box, src_mesh, v1F1, v1F2, v2F1, v2F2 ) -tgt_mesh.Compute() - -# Move the source mesh to visualy compare the two meshes -src_mesh.TranslateObject( src_mesh, MakeDirStruct( 210, 0, 0 ), Copy=False) - -\endcode +\include defining_hypotheses_ex10.py +Download this script

        Projection 1D2D

        - -\code -# Project triangles from one meshed face to another mesh on the same box - -from smesh import * - -# Prepare geometry - -# Create a box -box = geompy.MakeBoxDXDYDZ(100, 100, 100) - -# Get geom faces to mesh with triangles in the 1ts and 2nd meshes -faces = geompy.SubShapeAll(box, geompy.ShapeType["FACE"]) -# 2 adjacent faces of the box -Face_1 = faces[2] -Face_2 = faces[0] - -geompy.addToStudy( box, 'box' ) -geompy.addToStudyInFather( box, Face_1, 'Face_1' ) -geompy.addToStudyInFather( box, Face_2, 'Face_2' ) - -# Make the source mesh with Netgem2D -src_mesh = Mesh(Face_1, "Source mesh") -src_mesh.Segment().NumberOfSegments(15) -src_mesh.Triangle() -src_mesh.Compute() - -# Mesh the target mesh using the algoritm Projection1D2D -tgt_mesh = smesh.Mesh(Face_2, "Target mesh") -tgt_mesh.Projection1D2D().SourceFace(Face_1,src_mesh) -tgt_mesh.Compute() -\endcode +\include defining_hypotheses_ex11.py +Download this script
        \anchor tui_fixed_points

        1D Mesh with Fixed Points example

        - -\code -import salome -import geompy -import smesh -import StdMeshers - -# Create face and explode it on edges -face = geompy.MakeFaceHW(100, 100, 1) -edges = geompy.SubShapeAllSorted(face, geompy.ShapeType["EDGE"]) -geompy.addToStudy( face, "Face" ) - -# get the first edge from exploded result -edge1 = geompy.GetSubShapeID(face, edges[0]) - -# Define Mesh on previously created face -Mesh_1 = smesh.Mesh(face) - -# Create Fixed Point 1D hypothesis and define parameters. -# Note: values greater than 1.0 and less than 0.0 are not taken into account; -# duplicated values are removed. Also, if not specified explicitly, values 0.0 and 1.0 -# add added automatically. -# The number of segments should correspond to the number of points (NbSeg = NbPnt-1); -# extra values of segments splitting parameter are not taken into account, -# while missing values are considered to be equal to 1. -Fixed_points_1D_1 = smesh.CreateHypothesis('FixedPoints1D') -Fixed_points_1D_1.SetPoints( [ 1.1, 0.9, 0.5, 0.0, 0.5, -0.3 ] ) -Fixed_points_1D_1.SetNbSegments( [ 3, 1, 2 ] ) -Fixed_points_1D_1.SetReversedEdges( [edge1] ) - -# Add hypothesis to mesh and define 2D parameters -Mesh_1.AddHypothesis(Fixed_points_1D_1) -Regular_1D = Mesh_1.Segment() -Quadrangle_2D = Mesh_1.Quadrangle() -# Compute mesh -Mesh_1.Compute() -\endcode +\include defining_hypotheses_ex12.py +Download this script \anchor tui_radial_quadrangle

        Radial Quadrangle 1D2D example

        -\code -from smesh import * - -SetCurrentStudy(salome.myStudy) - -# Create face from the wire and add to study -Face = geompy.MakeSketcher("Sketcher:F 0 0:TT 20 0:R 90:C 20 90:WF", [0, 0, 0, 1, 0, 0, 0, 0, 1]) -geompy.addToStudy(Face,"Face") -edges = geompy.SubShapeAllSorted(Face, geompy.ShapeType["EDGE"]) -circle, radius1, radius2 = edges -geompy.addToStudyInFather(Face, radius1,"radius1") -geompy.addToStudyInFather(Face, radius2,"radius2") -geompy.addToStudyInFather(Face, circle,"circle") - - -# Define geometry for mesh, and Radial Quadrange algorithm -mesh = smesh.Mesh(Face) -radial_Quad_algo = mesh.Quadrangle(algo=RADIAL_QUAD) - -# The Radial Quadrange algorithm can work without any hypothesis -# In this case it uses "Default Nb of Segments" preferences parameter to discretize edges -mesh.Compute() - -# The Radial Quadrange uses global or local 1d hypotheses if it does -# not have its own hypotheses. -# Define global hypotheses to discretize radial edges and a local one for circular edge -global_Nb_Segments = mesh.Segment().NumberOfSegments(5) -local_Nb_Segments = mesh.Segment(circle).NumberOfSegments(10) -mesh.Compute() - -# Define own parameters of Radial Quadrange algorithm -radial_Quad_algo.NumberOfLayers( 4 ) -mesh.Compute() -\endcode +\include defining_hypotheses_ex13.py +Download this script \anchor tui_quadrangle_parameters

        Quadrangle Parameters example 1 (meshing a face with 3 edges)

        -\code -from smesh import * -SetCurrentStudy(salome.myStudy) - -# Get 1/4 part from the disk face. -Box_1 = geompy.MakeBoxDXDYDZ(100, 100, 100) -Disk_1 = geompy.MakeDiskR(100, 1) -Common_1 = geompy.MakeCommon(Disk_1, Box_1) -geompy.addToStudy( Disk_1, "Disk_1" ) -geompy.addToStudy( Box_1, "Box_1" ) -geompy.addToStudy( Common_1, "Common_1" ) - -# Set the Geometry for meshing -Mesh_1 = smesh.Mesh(Common_1) - - -# Define 1D hypothesis and compute the mesh -Regular_1D = Mesh_1.Segment() -Nb_Segments_1 = Regular_1D.NumberOfSegments(10) -Nb_Segments_1.SetDistrType( 0 ) - -# Create Quadrangle parameters and define the Base Vertex. -Quadrangle_2D = Mesh_1.Quadrangle().TriangleVertex( 8 ) - -Mesh_1.Compute() -\endcode +\include defining_hypotheses_ex14.py +Download this script

        Quadrangle Parameters example 2 (using different types)

        -\code -import geompy -import smesh -import StdMeshers - -# Make quadrangle face and explode it on edges. -Vertex_1 = geompy.MakeVertex(0, 0, 0) -Vertex_2 = geompy.MakeVertex(40, 0, 0) -Vertex_3 = geompy.MakeVertex(40, 30, 0) -Vertex_4 = geompy.MakeVertex(0, 30, 0) -Quadrangle_Face_1 = geompy.MakeQuad4Vertices(Vertex_1, Vertex_4, Vertex_3, Vertex_2) -[Edge_1,Edge_2,Edge_3,Edge_4] = geompy.SubShapeAllSorted(Quadrangle_Face_1, geompy.ShapeType["EDGE"]) -geompy.addToStudy( Vertex_1, "Vertex_1" ) -geompy.addToStudy( Vertex_2, "Vertex_2" ) -geompy.addToStudy( Vertex_3, "Vertex_3" ) -geompy.addToStudy( Vertex_4, "Vertex_4" ) -geompy.addToStudy( Quadrangle_Face_1, "Quadrangle Face_1" ) -geompy.addToStudyInFather( Quadrangle_Face_1, Edge_2, "Edge_2" ) - -# Set the Geometry for meshing -Mesh_1 = smesh.Mesh(Quadrangle_Face_1) - -# Create Quadrangle parameters and -# define the Type as Quadrangle Preference -Quadrangle_Parameters_1 = smesh.CreateHypothesis('QuadrangleParams') -Quadrangle_Parameters_1.SetQuadType( StdMeshers.QUAD_QUADRANGLE_PREF ) - -# Define other hypotheses and algorithms -Regular_1D = Mesh_1.Segment() -Nb_Segments_1 = Regular_1D.NumberOfSegments(4) -Nb_Segments_1.SetDistrType( 0 ) -status = Mesh_1.AddHypothesis(Quadrangle_Parameters_1) -Quadrangle_2D = Mesh_1.Quadrangle() - -# Define submesh on one edge to provide different number of segments -Regular_1D_1 = Mesh_1.Segment(geom=Edge_2) -Nb_Segments_2 = Regular_1D_1.NumberOfSegments(10) -Nb_Segments_2.SetDistrType( 0 ) -SubMesh_1 = Regular_1D_1.GetSubMesh() - -# Compute mesh (with Quadrangle Preference type) -isDone = Mesh_1.Compute() - -# Change type to Reduced and compute again -Quadrangle_Parameters_1.SetQuadType( StdMeshers.QUAD_REDUCED ) -isDone = Mesh_1.Compute() -\endcode +\include defining_hypotheses_ex15.py +Download this script \anchor tui_import

        "Use Existing Elements" example

        -\code - -from smesh import * -SetCurrentStudy(salome.myStudy) - -# Make a patritioned box - -box = geompy.MakeBoxDXDYDZ(100,100,100) - -N = geompy.MakeVectorDXDYDZ( 1,0,0 ) -O = geompy.MakeVertex( 50,0,0 ) -plane = geompy.MakePlane( O, N, 200 ) # plane YOZ - -shape2boxes = geompy.MakeHalfPartition( box, plane ) -boxes = geompy.SubShapeAllSorted(shape2boxes, geompy.ShapeType["SOLID"]) - -geompy.addToStudy( boxes[0], "boxes[0]") -geompy.addToStudy( boxes[1], "boxes[1]") -midFace0 = geompy.SubShapeAllSorted(boxes[0], geompy.ShapeType["FACE"])[5] -geompy.addToStudyInFather( boxes[0], midFace0, "middle Face") -midFace1 = geompy.SubShapeAllSorted(boxes[1], geompy.ShapeType["FACE"])[0] -geompy.addToStudyInFather( boxes[1], midFace1, "middle Face") - -# Mesh one of boxes with quadrangles. It is a source mesh - -srcMesh = Mesh(boxes[0], "source mesh") # box coloser to CS origin -nSeg1 = srcMesh.Segment().NumberOfSegments(4) -srcMesh.Quadrangle() -srcMesh.Compute() -srcFaceGroup = srcMesh.GroupOnGeom( midFace0, "src faces", FACE ) - -# Import faces from midFace0 to the target mesh - -tgtMesh = Mesh(boxes[1], "target mesh") -importAlgo = tgtMesh.UseExisting2DElements(midFace1) -import2hyp = importAlgo.SourceFaces( [srcFaceGroup] ) -tgtMesh.Segment().NumberOfSegments(3) -tgtMesh.Quadrangle() -tgtMesh.Compute() - -# Import the whole source mesh with groups -import2hyp.SetCopySourceMesh(True,True) -tgtMesh.Compute() -\endcode +\include defining_hypotheses_ex16.py +Download this script \anchor tui_viscous_layers

        Viscous layers construction

        -\code -from smesh import * -SetCurrentStudy(salome.myStudy) - -X = geompy.MakeVectorDXDYDZ( 1,0,0 ) -O = geompy.MakeVertex( 100,50,50 ) -plane = geompy.MakePlane( O, X, 200 ) # plane YZ - -box = geompy.MakeBoxDXDYDZ(200,100,100) - -shape = geompy.MakeHalfPartition( box, plane ) - -faces = geompy.SubShapeAllSorted(shape, geompy.ShapeType["FACE"]) -face1 = faces[1] -ignoreFaces = [ faces[0], faces[-1]] - -geompy.addToStudy( shape, "shape" ) -geompy.addToStudyInFather( shape, face1, "face1") - - -mesh = Mesh(shape, "CFD") - -mesh.Segment().NumberOfSegments( 4 ) - -mesh.Triangle() -mesh.Quadrangle(face1) -mesh.Compute() -algo3D = mesh.Tetrahedron() - -thickness = 20 -numberOfLayers = 10 -stretchFactor = 1.5 -layersHyp = algo3D.ViscousLayers(thickness,numberOfLayers,stretchFactor,ignoreFaces) - -mesh.Compute() - -mesh.MakeGroup("Tetras",VOLUME,FT_ElemGeomType,"=",Geom_TETRA) -mesh.MakeGroup("Pyras",VOLUME,FT_ElemGeomType,"=",Geom_PYRAMID) -mesh.MakeGroup("Prims",VOLUME,FT_ElemGeomType,"=",Geom_PENTA) - -\endcode +\include defining_hypotheses_ex17.py +Download this script */ diff --git a/doc/salome/gui/SMESH/input/tui_filters.doc b/doc/salome/gui/SMESH/input/tui_filters.doc index 0eb41dd28..2540f52b8 100755 --- a/doc/salome/gui/SMESH/input/tui_filters.doc +++ b/doc/salome/gui/SMESH/input/tui_filters.doc @@ -27,14 +27,8 @@ Filter 2D mesh elements (faces) according to the aspect ratio value: - functor type should be \a smesh.FT_AspectRatio - threshold is floating point value (aspect ratio) -\code -# create mesh -from SMESH_mechanic import * -# get faces with aspect ratio > 6.5 -filter = smesh.GetFilter(smesh.FACE, smesh.FT_AspectRatio, smesh.FT_MoreThan, 6.5) -ids = mesh.GetIdsFromFilter(filter) -print "Number of faces with aspect ratio > 6.5:", len(ids) -\endcode +\include filters_ex01.py +Download this script \sa \ref tui_aspect_ratio @@ -45,16 +39,8 @@ Filter 3D mesh elements (volumes) according to the aspect ratio value: - functor type is \a smesh.FT_AspectRatio3D - threshold is floating point value (aspect ratio) -\code -# create mesh with volumes -from SMESH_mechanic import * -mesh.Tetrahedron() -mesh.Compute() -# get volumes with aspect ratio < 2.0 -filter = smesh.GetFilter(smesh.VOLUME, smesh.FT_AspectRatio3D, smesh.FT_LessThan, 2.0) -ids = mesh.GetIdsFromFilter(filter) -print "Number of volumes with aspect ratio < 2.0:", len(ids) -\endcode +\include filters_ex02.py +Download this script \sa \ref tui_aspect_ratio_3d @@ -65,17 +51,8 @@ Filter 2D mesh elements (faces) according to the warping angle value: - functor type is \a smesh.FT_Warping - threshold is floating point value (warping angle) -\code -# create mesh -from SMESH_mechanic import * -# get faces with warping angle = 2.0e-13 with tolerance 5.0e-14 -criterion = smesh.GetCriterion(smesh.FACE, smesh.FT_Warping, smesh.FT_EqualTo, 2.0e-13) -criterion.Tolerance = 5.0e-14 -filter = smesh.CreateFilterManager().CreateFilter() -filter.SetCriteria([criterion]) -ids = mesh.GetIdsFromFilter(filter) -print "Number of faces with warping angle = 2.0e-13 (tolerance 5.0e-14):", len(ids) -\endcode +\include filters_ex03.py +Download this script \sa \ref tui_warping @@ -86,14 +63,8 @@ Filter 2D mesh elements (faces) according to the minimum angle value: - functor type is \a smesh.FT_MinimumAngle - threshold is floating point value (minimum angle) -\code -# create mesh -from SMESH_mechanic import * -# get faces with minimum angle > 75 -filter = smesh.GetFilter(smesh.FACE, smesh.FT_MinimumAngle,">", 75) -ids = mesh.GetIdsFromFilter(filter) -print "Number of faces with minimum angle > 75:", len(ids) -\endcode +\include filters_ex04.py +Download this script \sa \ref tui_minimum_angle @@ -104,14 +75,8 @@ Filter 2D mesh elements (faces) according to the taper value: - functor type is \a smesh.FT_Taper - threshold is floating point value (taper) -\code -# create mesh -from SMESH_mechanic import * -# get faces with taper < 1.e-15 -filter = smesh.GetFilter(smesh.FACE, smesh.FT_Taper, smesh.FT_LessThan, 1.e-15) -ids = mesh.GetIdsFromFilter(filter) -print "Number of faces with taper < 1.e-15:", len(ids) -\endcode +\include filters_ex05.py +Download this script \sa \ref tui_taper @@ -122,14 +87,8 @@ Filter 2D mesh elements (faces) according to the skew value: - functor type is \a smesh.FT_Skew - threshold is floating point value (skew) -\code -# create mesh -from SMESH_mechanic import * -# get faces with skew > 50 -filter = smesh.GetFilter(smesh.FACE, smesh.FT_Skew, smesh.FT_MoreThan, 50) -ids = mesh.GetIdsFromFilter(filter) -print "Number of faces with skew > 50:", len(ids) -\endcode +\include filters_ex06.py +Download this script \sa \ref tui_skew @@ -140,18 +99,8 @@ Filter 2D mesh elements (faces) according to the area value: - functor type is \a smesh.FT_Area - threshold is floating point value (area) -\code -# create mesh -from SMESH_mechanic import * -# get faces with area > 60 and < 90 -criterion1 = smesh.GetCriterion(smesh.FACE, smesh.FT_Area, smesh.FT_MoreThan, 60,\ - smesh.FT_Undefined, smesh.FT_LogicalAND) -criterion2 = smesh.GetCriterion(smesh.FACE, smesh.FT_Area, smesh.FT_LessThan, 90) -filter = smesh.CreateFilterManager().CreateFilter() -filter.SetCriteria([criterion1,criterion2]) -ids = mesh.GetIdsFromFilter(filter) -print "Number of faces with area in range (60,90):", len(ids) -\endcode +\include filters_ex07.py +Download this script \sa \ref tui_area @@ -162,16 +111,8 @@ Filter 3D mesh elements (volumes) according to the volume value: - functor type is \a smesh.FT_Volume3D - threshold is floating point value (volume) -\code -# create mesh with volumes -from SMESH_mechanic import * -mesh.Tetrahedron() -mesh.Compute() -# get volumes faces with volume > 100 -filter = smesh.GetFilter(smesh.VOLUME, smesh.FT_Volume3D, smesh.FT_MoreThan, 100) -ids = mesh.GetIdsFromFilter(filter) -print "Number of volumes with volume > 100:", len(ids) -\endcode +\include filters_ex08.py +Download this script \sa \ref tui_volume @@ -182,20 +123,8 @@ Filter 1D mesh elements (edges) which represent free borders of a mesh: - functor type is \a smesh.FT_FreeBorders - threshold value is not required -\code -# create mesh -import geompy, smesh, StdMeshers -face = geompy.MakeFaceHW(100, 100, 1) -geompy.addToStudy( face, "quadrangle" ) -mesh = smesh.Mesh(face) -mesh.Segment().NumberOfSegments(10) -mesh.Triangle().MaxElementArea(25) -mesh.Compute() -# get all free borders -filter = smesh.GetFilter(smesh.EDGE, smesh.FT_FreeBorders) -ids = mesh.GetIdsFromFilter(filter) -print "Number of edges on free borders:", len(ids) -\endcode +\include filters_ex09.py +Download this script \sa \ref tui_free_borders @@ -207,20 +136,8 @@ element of mesh only: - functor type is \a smesh.FT_FreeEdges - threshold value is not required -\code -# create mesh -import geompy, smesh, StdMeshers -face = geompy.MakeFaceHW(100, 100, 1) -geompy.addToStudy( face, "quadrangle" ) -mesh = smesh.Mesh(face) -mesh.Segment().NumberOfSegments(10) -mesh.Triangle().MaxElementArea(25) -mesh.Compute() -# get all faces with free edges -filter = smesh.GetFilter(smesh.FACE, smesh.FT_FreeEdges) -ids = mesh.GetIdsFromFilter(filter) -print "Number of faces with free edges:", len(ids) -\endcode +\include filters_ex10.py +Download this script \sa \ref tui_free_edges @@ -231,16 +148,8 @@ Filter free nodes: - functor type is \a smesh.FT_FreeNodes - threshold value is not required -\code -# create mesh -from SMESH_mechanic import * -# add node -mesh.AddNode(0,0,0) -# get all free nodes -filter = smesh.GetFilter(smesh.NODE, smesh.FT_FreeNodes) -ids = mesh.GetIdsFromFilter(filter) -print "Number of free nodes:", len(ids) -\endcode +\include filters_ex11.py +Download this script \sa \ref tui_free_nodes @@ -251,14 +160,8 @@ Filter free faces: - functor type is \a smesh.FT_FreeFaces - threshold value is not required -\code -# create mesh -from SMESH_mechanic import * -# get all free faces -filter = smesh.GetFilter(smesh.FACE, smesh.FT_FreeFaces) -ids = mesh.GetIdsFromFilter(filter) -print "Number of free faces:", len(ids) -\endcode +\include filters_ex12.py +Download this script \sa \ref tui_free_faces @@ -269,16 +172,8 @@ Filter faces with bare borders: - functor type is \a smesh.FT_BareBorderFace - threshold value is not required -\code -# create mesh -from SMESH_mechanic import * -# remove some faces to have faces with bare borders -mesh.RemoveElements( mesh.GetElementsByType(FACE)[0:5] ) -# get all faces bare borders -filter = smesh.GetFilter(smesh.FACE, smesh.FT_BareBorderFace) -ids = mesh.GetIdsFromFilter(filter) -print "Faces with bare borders:", ids -\endcode +\include filters_ex13.py +Download this script \sa \ref tui_bare_border_faces @@ -290,15 +185,8 @@ Filter faces with bare borders: - threshold value is the face ID - tolerance is in degrees -\code -# create mesh -from SMESH_mechanic import * -faceID = mesh.GetElementsByType(FACE)[0] -# get all faces co-planar to the first face with tolerance 5 degrees -filter = smesh.GetFilter(smesh.FACE, smesh.FT_CoplanarFaces,faceID,Tolerance=5.0) -ids = mesh.GetIdsFromFilter(filter) -print "Number of faces coplanar with the first one:", len(ids) -\endcode +\include filters_ex14.py +Download this script \section filter_over_constrained_faces Over-constrained faces @@ -307,14 +195,8 @@ Filter over-constrained faces: - functor type is \a smesh.FT_OverConstrainedFace - threshold value is not required -\code -# create mesh -from SMESH_mechanic import * -# get all over-constrained faces -filter = smesh.GetFilter(smesh.FACE, smesh.FT_OverConstrainedFace) -ids = mesh.GetIdsFromFilter(filter) -print "Over-constrained faces:", ids -\endcode +\include filters_ex15.py +Download this script \sa \ref tui_over_constrained_faces @@ -326,27 +208,8 @@ filter mesh elements basing on the same set of nodes: smesh.FT_EqualFaces or \a smesh.FT_EqualVolumes, - threshold value is not required -\code -from smesh import * -# make a mesh on a box -box = geompy.MakeBoxDXDYDZ(100,100,100) -mesh = Mesh( box, "Box" ) -mesh.Segment().NumberOfSegments(10) -mesh.Quadrangle() -mesh.Hexahedron() -mesh.Compute() -# copy all elements with translation and Merge nodes -mesh.TranslateObject( mesh, MakeDirStruct( 10,0,0), Copy=True ) -mesh.MergeNodes( mesh.FindCoincidentNodes(1e-7) ) -# create filters to find equal elements -equalEdgesFilter = GetFilter(SMESH.EDGE, FT_EqualEdges) -equalFacesFilter = GetFilter(SMESH.FACE, FT_EqualFaces) -equalVolumesFilter = GetFilter(SMESH.VOLUME, FT_EqualVolumes) -# get equal elements -print "Number of equal edges:", len( mesh.GetIdsFromFilter( equalEdgesFilter )) -print "Number of equal faces:", len( mesh.GetIdsFromFilter( equalFacesFilter )) -print "Number of equal volumes:", len( mesh.GetIdsFromFilter( equalVolumesFilter )) -\endcode +\include filters_ex16.py +Download this script \section tui_double_nodes_control Double nodes @@ -357,22 +220,8 @@ filters mesh nodes which are coincident with other nodes (within a given toleran - threshold value is not required - default tolerance is 1.0e-7 -\code -from smesh import * -# make a mesh on a box -box = geompy.MakeBoxDXDYDZ(100,100,100) -mesh = Mesh( box, "Box" ) -mesh.Segment().NumberOfSegments(10) -mesh.Quadrangle() -mesh.Hexahedron() -mesh.Compute() -# copy all elements with translation -mesh.TranslateObject( mesh, MakeDirStruct( 10,0,0), Copy=True ) -# create filters to find nodes equal within tolerance of 1e-5 -filter = GetFilter(SMESH.NODE, FT_EqualNodes, Tolerance=1e-5) -# get equal nodes -print "Number of equal nodes:", len( mesh.GetIdsFromFilter( filter )) -\endcode +\include filters_ex17.py +Download this script \section filter_borders_multiconnection Borders at multi-connection @@ -383,14 +232,8 @@ connections (faces belonging the border edges) - functor type is \a smesh.FT_MultiConnection - threshold is integer value (number of connections) -\code -# create mesh -from SMESH_mechanic import * -# get border edges with number of connected faces = 5 -filter = smesh.GetFilter(smesh.EDGE, smesh.FT_MultiConnection, 5) -ids = mesh.GetIdsFromFilter(filter) -print "Number of border edges with 5 faces connected:", len(ids) -\endcode +\include filters_ex18.py +Download this script \sa \ref tui_borders_at_multiconnection @@ -402,14 +245,8 @@ to the specified number of mesh elements - functor type is \a smesh.FT_MultiConnection2D - threshold is integer value (number of connections) -\code -# create mesh -from SMESH_mechanic import * -# get faces which consist of edges belonging to 2 mesh elements -filter = smesh.GetFilter(smesh.FACE, smesh.FT_MultiConnection2D, 2) -ids = mesh.GetIdsFromFilter(filter) -print "Number of faces consisting of edges belonging to 2 faces:", len(ids) -\endcode +\include filters_ex19.py +Download this script \sa \ref tui_borders_at_multiconnection_2d @@ -420,14 +257,8 @@ Filter 1D mesh elements (edges) according to the edge length value: - functor type should be \a smesh.FT_Length - threshold is floating point value (length) -\code -# create mesh -from SMESH_mechanic import * -# get edges with length > 14 -filter = smesh.GetFilter(smesh.EDGE, smesh.FT_Length, smesh.FT_MoreThan, 14) -ids = mesh.GetIdsFromFilter(filter) -print "Number of edges with length > 14:", len(ids) -\endcode +\include filters_ex20.py +Download this script \sa \ref tui_length_1d @@ -439,14 +270,8 @@ value of its edges: - functor type should be \a smesh.FT_Length2D - threshold is floating point value (edge length) -\code -# create mesh -from SMESH_mechanic import * -# get all faces that have edges with length > 14 -filter = smesh.GetFilter(smesh.FACE, smesh.FT_Length2D, smesh.FT_MoreThan, 14) -ids = mesh.GetIdsFromFilter(filter) -print "Number of faces with maximum edge length > 14:", len(ids) -\endcode +\include filters_ex21.py +Download this script \sa \ref tui_length_2d @@ -458,14 +283,8 @@ value of its edges and diagonals: - functor type should be \a smesh.FT_MaxElementLength2D - threshold is floating point value (edge/diagonal length) -\code -# create mesh -from SMESH_mechanic import * -# get all faces that have elements with length > 10 -filter = smesh.GetFilter(smesh.FACE, smesh.FT_MaxElementLength2D, smesh.FT_MoreThan, 10) -ids = mesh.GetIdsFromFilter(filter) -print "Number of faces with maximum element length > 10:", len(ids) -\endcode +\include filters_ex22.py +Download this script \sa \ref tui_max_element_length_2d @@ -477,16 +296,8 @@ value of its edges and diagonals: - functor type should be \a smesh.FT_MaxElementLength3D - threshold is floating point value (edge/diagonal length) -\code -# create mesh with volumes -from SMESH_mechanic import * -mesh.Tetrahedron() -mesh.Compute() -# get all volumes that have elements with length > 10 -filter = smesh.GetFilter(smesh.VOLUME, smesh.FT_MaxElementLength3D, smesh.FT_MoreThan, 10) -ids = mesh.GetIdsFromFilter(filter) -print "Number of volumes with maximum element length > 10:", len(ids) -\endcode +\include filters_ex23.py +Download this script \sa \ref tui_max_element_length_3d @@ -497,18 +308,8 @@ Filter 3D mesh elements with bare borders: - functor type is \a smesh.FT_BareBorderVolume - threshold value is not required -\code -# create mesh -from SMESH_mechanic import * -mesh.Tetrahedron() -mesh.Compute() -# remove some volumes to have volumes with bare borders -mesh.RemoveElements( mesh.GetElementsByType(VOLUME)[0:5] ) -# get all volumes with bare borders -filter = smesh.GetFilter(smesh.VOLUME, smesh.FT_BareBorderVolume) -ids = mesh.GetIdsFromFilter(filter) -print "Volumes with bare borders:", ids -\endcode +\include filters_ex24.py +Download this script \sa \ref tui_bare_border_volumes @@ -519,16 +320,8 @@ Filter over-constrained volumes: - functor type is \a smesh.FT_OverConstrainedVolume - threshold value is not required -\code -# create mesh -from SMESH_mechanic import * -mesh.Tetrahedron() -mesh.Compute() -# get all over-constrained volumes -filter = smesh.GetFilter(smesh.VOLUME, smesh.FT_OverConstrainedVolume) -ids = mesh.GetIdsFromFilter(filter) -print "Over-constrained volumes:", ids -\endcode +\include filters_ex25.py +Download this script \sa \ref tui_over_constrained_faces @@ -540,14 +333,8 @@ shape defined by threshold value: - functor type should be \a smesh.FT_BelongToGeom - threshold is geometrical object -\code -# create mesh -from SMESH_mechanic import * -# get all faces which nodes lie on the face sub_face3 -filter = smesh.GetFilter(smesh.FACE, smesh.FT_BelongToGeom, sub_face3) -ids = mesh.GetIdsFromFilter(filter) -print "Number of faces which nodes lie on sub_face3:", len(ids) -\endcode +\include filters_ex26.py +Download this script \section filter_lying_on_geom Lying on Geom @@ -557,14 +344,8 @@ shape defined by threshold value: - functor type should be \a smesh.FT_LyingOnGeom - threshold is geometrical object -\code -# create mesh -from SMESH_mechanic import * -# get all faces at least one node of each lies on the face sub_face3 -filter = smesh.GetFilter(smesh.FACE, smesh.FT_LyingOnGeom, sub_face3) -ids = mesh.GetIdsFromFilter(filter) -print "Number of faces at least one node of each lies on sub_face3:", len(ids) -\endcode +\include filters_ex27.py +Download this script \section filter_belong_to_plane Belong to Plane @@ -575,18 +356,8 @@ plane defined by threshold value with the given tolerance: - threshold is geometrical object (plane) - default tolerance is 1.0e-7 -\code -# create mesh -from SMESH_mechanic import * -# create plane -import geompy -plane_1 = geompy.MakePlane(p3,seg1,2000) -geompy.addToStudy(plane_1, "plane_1") -# get all nodes which lie on the plane \a plane_1 -filter = smesh.GetFilter(smesh.NODE, smesh.FT_BelongToPlane, plane_1) -ids = mesh.GetIdsFromFilter(filter) -print "Number of nodes which lie on the plane plane_1:", len(ids) -\endcode +\include filters_ex28.py +Download this script \section filter_belong_to_cylinder Belong to Cylinder @@ -597,14 +368,8 @@ cylindrical face defined by threshold value with the given tolerance: - threshold is geometrical object (cylindrical face) - default tolerance is 1.0e-7 -\code -# create mesh -from SMESH_mechanic import * -# get all faces which lie on the cylindrical face \a sub_face1 -filter = smesh.GetFilter(smesh.FACE, smesh.FT_BelongToCylinder, sub_face1) -ids = mesh.GetIdsFromFilter(filter) -print "Number of faces which lie on the cylindrical surface sub_face1:", len(ids) -\endcode +\include filters_ex29.py +Download this script \section filter_belong_to_surface Belong to Surface @@ -615,18 +380,8 @@ arbitrary surface defined by threshold value with the given tolerance: - threshold is geometrical object (arbitrary surface) - default tolerance is 1.0e-7 -\code -# create mesh -from SMESH_mechanic import * -# create b-spline -spline_1 = geompy.MakeInterpol([p4,p6,p3,p1]) -surface_1 = geompy.MakePrismVecH( spline_1, vz, 70.0 ) -geompy.addToStudy(surface_1, "surface_1") -# get all nodes which lie on the surface \a surface_1 -filter = smesh.GetFilter(smesh.NODE, smesh.FT_BelongToGenSurface, surface_1) -ids = mesh.GetIdsFromFilter(filter) -print "Number of nodes which lie on the surface surface_1:", len(ids) -\endcode +\include filters_ex30.py +Download this script \section filter_range_of_ids Range of IDs @@ -636,18 +391,8 @@ specified identifiers range: - functor type is \a smesh.FT_RangeOfIds - threshold is string listing required IDs and/or ranges of IDs, e.g."1,2,3,50-60,63,67,70-78" -\code -# create mesh -from SMESH_mechanic import * -# get nodes with identifiers [5-10] and [15-30] -criterion1 = smesh.GetCriterion(smesh.NODE, smesh.FT_RangeOfIds, Treshold="5-10",\ - BinaryOp=smesh.FT_LogicalOR) -criterion2 = smesh.GetCriterion(smesh.NODE, smesh.FT_RangeOfIds, Treshold="15-30") -filter = smesh.CreateFilterManager().CreateFilter() -filter.SetCriteria([criterion1,criterion2]) -ids = mesh.GetIdsFromFilter(filter) -print "Number of nodes in ranges [5-10] and [15-30]:", len(ids) -\endcode +\include filters_ex31.py +Download this script \section filter_bad_oriented_volume Badly oriented volume @@ -657,16 +402,8 @@ the point of view of MED convention. - functor type is \a smesh.FT_BadOrientedVolume - threshold is not required -\code -# create mesh with volumes -from SMESH_mechanic import * -mesh.Tetrahedron() -mesh.Compute() -# get all badly oriented volumes -filter = smesh.GetFilter(smesh.VOLUME, smesh.FT_BadOrientedVolume) -ids = mesh.GetIdsFromFilter(filter) -print "Number of badly oriented volumes:", len(ids) -\endcode +\include filters_ex32.py +Download this script \section filter_linear_or_quadratic Linear / quadratic @@ -677,23 +414,8 @@ Filter linear / quadratic mesh elements: - if unary operator is set to smesh.FT_LogicalNOT, the quadratic elements are selected, otherwise (by default) linear elements are selected -\code -# create mesh -from SMESH_mechanic import * -# get number of linear and quadratic edges -filter_linear = smesh.GetFilter(smesh.EDGE, smesh.FT_LinearOrQuadratic) -filter_quadratic = smesh.GetFilter(smesh.EDGE, smesh.FT_LinearOrQuadratic, smesh.FT_LogicalNOT) -ids_linear = mesh.GetIdsFromFilter(filter_linear) -ids_quadratic = mesh.GetIdsFromFilter(filter_quadratic) -print "Number of linear edges:", len(ids_linear), "; number of quadratic edges:", len(ids_quadratic) -# convert mesh to quadratic -print "Convert to quadratic..." -mesh.ConvertToQuadratic(True) -# get number of linear and quadratic edges -ids_linear = mesh.GetIdsFromFilter(filter_linear) -ids_quadratic = mesh.GetIdsFromFilter(filter_quadratic) -print "Number of linear edges:", len(ids_linear), "; number of quadratic edges:", len(ids_quadratic) -\endcode +\include filters_ex33.py +Download this script \section filter_group_color Group color @@ -702,20 +424,8 @@ Filter mesh entities, belonging to the group with the color defined by the thres - functor type is \a smesh.FT_GroupColor - threshold should be of SALOMEDS.Color type -\code -# create mesh -from SMESH_mechanic import * -# create group of edges -all_edges = mesh.GetElementsByType(smesh.EDGE) -grp = mesh.MakeGroupByIds("edges group", smesh.EDGE, all_edges[:len(all_edges)/4]) -import SALOMEDS -c = SALOMEDS.Color(0.1, 0.5, 1.0) -grp.SetColor(c) -# get number of the edges not belonging to the group with the given color -filter = smesh.GetFilter(smesh.EDGE, smesh.FT_GroupColor, c, smesh.FT_LogicalNOT) -ids = mesh.GetIdsFromFilter(filter) -print "Number of edges not beloging to the group with color (0.1, 0.5, 1.0):", len(ids) -\endcode +\include filters_ex34.py +Download this script \section filter_geom_type Geometry type @@ -726,25 +436,8 @@ entity type. - functor type should be \a smesh.FT_ElemGeomType - threshold is of smesh.GeometryType value -\code -# create mesh with volumes -from SMESH_mechanic import * -mesh.Tetrahedron() -mesh.Compute() -# get all triangles, quadrangles, tetrahedrons, pyramids -filter_tri = smesh.GetFilter(smesh.FACE, smesh.FT_ElemGeomType, smesh.Geom_TRIANGLE) -filter_qua = smesh.GetFilter(smesh.FACE, smesh.FT_ElemGeomType, smesh.Geom_QUADRANGLE) -filter_tet = smesh.GetFilter(smesh.VOLUME, smesh.FT_ElemGeomType, smesh.Geom_TETRA) -filter_pyr = smesh.GetFilter(smesh.VOLUME, smesh.FT_ElemGeomType, smesh.Geom_PYRAMID) -ids_tri = mesh.GetIdsFromFilter(filter_tri) -ids_qua = mesh.GetIdsFromFilter(filter_qua) -ids_tet = mesh.GetIdsFromFilter(filter_tet) -ids_pyr = mesh.GetIdsFromFilter(filter_pyr) -print "Number of triangles:", len(ids_tri) -print "Number of quadrangles:", len(ids_qua) -print "Number of tetrahedrons:", len(ids_tet) -print "Number of pyramids:", len(ids_pyr) -\endcode +\include filters_ex35.py +Download this script \section combining_filters How to combine filters with Criterion structures? @@ -752,19 +445,8 @@ Filters can be combined by making use of "criteria". Example : -\code -# create mesh -from SMESH_mechanic import * -# get all the quadrangle faces ... -criterion1 = smesh.GetCriterion(smesh.FACE, smesh.FT_ElemGeomType, smesh.Geom_QUADRANGLE, smesh.FT_LogicalAND) -# ... AND do NOT get those from sub_face3 -criterion2 = smesh.GetCriterion(smesh.FACE, smesh.FT_BelongToGeom, sub_face3, smesh.FT_LogicalNOT) -filter = smesh.CreateFilterManager().CreateFilter() -filter.SetCriteria([criterion1,criterion2]) -ids = mesh.GetIdsFromFilter(filter) - -myGroup = mesh.MakeGroupByIds("Quads_on_cylindrical_faces",smesh.FACE,ids) -\endcode +\include filters_ex36.py +Download this script */ diff --git a/doc/salome/gui/SMESH/input/tui_generate_flat_elements.doc b/doc/salome/gui/SMESH/input/tui_generate_flat_elements.doc index eaf544556..36e13d304 100644 --- a/doc/salome/gui/SMESH/input/tui_generate_flat_elements.doc +++ b/doc/salome/gui/SMESH/input/tui_generate_flat_elements.doc @@ -17,66 +17,15 @@ by flat elements. \n This example represents an iron cable (a thin cylinder) in a concrete bloc (a big cylinder). The big cylinder is defined by two geometric volumes. -\code -import geompy -import smesh -import SMESH -# geometry - -O = geompy.MakeVertex(0, 0, 0) -OX = geompy.MakeVectorDXDYDZ(1, 0, 0) -OY = geompy.MakeVectorDXDYDZ(0, 1, 0) -OZ = geompy.MakeVectorDXDYDZ(0, 0, 1) -Vertex_1 = geompy.MakeVertex(50, 0, 0) -Cylinder_1 = geompy.MakeCylinder(O, OX, 10, 500) -Cylinder_2 = geompy.MakeCylinder(Vertex_1, OX, 100, 400) -Vertex_2 = geompy.MakeVertex(-200, -200, -200) -Vertex_3 = geompy.MakeVertex(250, 200, 200) -Box_1 = geompy.MakeBoxTwoPnt(Vertex_2, Vertex_3) -Fuse_1 = geompy.MakeFuse(Cylinder_1, Cylinder_2) -Partition_1 = geompy.MakePartition([Fuse_1], [Cylinder_1, Box_1], [], [], geompy.ShapeType["SOLID"], 0, [], 0) -[Solid_1,Solid_2] = geompy.GetShapesOnShape(Cylinder_1, Partition_1, geompy.ShapeType["SOLID"], geompy.GEOM.ST_IN) -[Solid_3,Solid_4] = geompy.GetShapesOnShape(Cylinder_2, Partition_1, geompy.ShapeType["SOLID"], geompy.GEOM.ST_IN) -Vertex_4 = geompy.MakeVertex(450, 0, 0) -Vertex_5 = geompy.MakeVertex(500, 0, 0) -Vertex_6 = geompy.MakeVertex(550, 0, 0) -vec1 = geompy.MakeVector(Vertex_4, Vertex_5) -vec2 = geompy.MakeVector(Vertex_5, Vertex_6) -[Face_1] = geompy.GetShapesOnPlane(Partition_1, geompy.ShapeType["FACE"], vec1, geompy.GEOM.ST_ON) -[Face_2] = geompy.GetShapesOnPlane(Partition_1, geompy.ShapeType["FACE"], vec2, geompy.GEOM.ST_ON) - -# meshing (we have linear tetrahedrons here, but other elements are OK) - -Mesh_1 = smesh.Mesh(Partition_1) -Regular_1D = Mesh_1.Segment() -Nb_Segments_1 = Regular_1D.NumberOfSegments(15) -MEFISTO_2D = Mesh_1.Triangle(algo=smesh.MEFISTO) -Length_From_Edges_2D = MEFISTO_2D.LengthFromEdges() -ALGO3D = Mesh_1.Tetrahedron() -isDone = Mesh_1.Compute() - -# relevant groups of volumes and faces - -Solid_1_1 = Mesh_1.GroupOnGeom(Solid_1,'Solid_1',SMESH.VOLUME) -Solid_2_1 = Mesh_1.GroupOnGeom(Solid_2,'Solid_2',SMESH.VOLUME) -Solid_3_1 = Mesh_1.GroupOnGeom(Solid_3,'Solid_3',SMESH.VOLUME) -Solid_4_1 = Mesh_1.GroupOnGeom(Solid_4,'Solid_4',SMESH.VOLUME) -Face_1_1 = Mesh_1.GroupOnGeom(Face_1,'Face_1',SMESH.FACE) -Face_2_1 = Mesh_1.GroupOnGeom(Face_2,'Face_2',SMESH.FACE) - -\endcode +\include generate_flat_elements.py +Download this script \n Here, the 4 groups of volumes [Solid_1_1, Solid_2_1, Solid_3_1, Solid_4_1] constitute a partition of the mesh. -The flat elements on group boundaries and on faces are built with the following code. +The flat elements on group boundaries and on faces are built with the +2 last lines of the code above. \n If the last argument (Boolean) in DoubleNodesOnGroupBoundaries is set to 1, the flat elements are built, otherwise, there is only a duplication of the nodes. -\code -Mesh_1.DoubleNodesOnGroupBoundaries([Solid_1_1, Solid_2_1, Solid_3_1, Solid_4_1], 1) - -Mesh_1.CreateFlatElementsOnFacesGroups([Face_1_1, Face_2_1]) -\endcode - \n To observe flat element groups, save the resulting mesh on a MED file and reload it. */ diff --git a/doc/salome/gui/SMESH/input/tui_grouping_elements.doc b/doc/salome/gui/SMESH/input/tui_grouping_elements.doc index 3b769060a..d3113ab2c 100644 --- a/doc/salome/gui/SMESH/input/tui_grouping_elements.doc +++ b/doc/salome/gui/SMESH/input/tui_grouping_elements.doc @@ -5,167 +5,29 @@
        \anchor tui_create_standalone_group

        Create a Standalone Group

        - -\code -import SMESH_mechanic - -smesh = SMESH_mechanic.smesh -mesh = SMESH_mechanic.mesh -salome = SMESH_mechanic.salome - -# Get ids of all faces with area > 100 -aFilter = smesh.GetFilter(smesh.FACE, smesh.FT_Area, smesh.FT_MoreThan, 100.) - -anIds = mesh.GetIdsFromFilter(aFilter) - -# create a group consisting of faces with area > 100 -aGroup1 = mesh.MakeGroupByIds("Area > 100", smesh.FACE, anIds) - -# create a group that contains all nodes from the mesh -aGroup2 = mesh.CreateEmptyGroup(smesh.NODE, "all nodes") -aGroup2.AddFrom(mesh.mesh) - -salome.sg.updateObjBrowser(1) -\endcode +\include grouping_elements_ex01.py +Download this script \image html create_group.png
        \anchor tui_create_group_on_geometry

        Create a Group on Geometry

        - -\code -import salome -import geompy -import smesh - -# create a box -box = geompy.MakeBox(0., 0., 0., 100., 100., 100.) -geompy.addToStudy(box, "box") - -# add the first face of the box to the study -subShapeList = geompy.SubShapeAll(box, geompy.ShapeType["FACE"]) -face = subShapeList[0] -geompy.addToStudyInFather(box, face, "face 1") - -# create group of edges on the face -aGeomGroupE = geompy.CreateGroup(face, geompy.ShapeType["EDGE"]) -geompy.AddObject(aGeomGroupE, 3) -geompy.AddObject(aGeomGroupE, 6) -geompy.AddObject(aGeomGroupE, 8) -geompy.AddObject(aGeomGroupE, 10) -geompy.addToStudyInFather(face, aGeomGroupE, "Group of Edges") - -# create quadrangle 2D mesh on the box -quadra = smesh.Mesh(box, "Box : quadrangle 2D mesh") -algo1D = quadra.Segment() -quadra.Quadrangle() -algo1D.NumberOfSegments(7) - -# compute the mesh -quadra.Compute() - -# create SMESH group on the face with name "SMESHGroup1" -aSmeshGroup1 = quadra.GroupOnGeom(face, "SMESHGroup1") - -# create SMESH group on with default name -aSmeshGroup2 = quadra.GroupOnGeom(aGeomGroupE) - -salome.sg.updateObjBrowser(1) -\endcode +\include grouping_elements_ex02.py +Download this script
        \anchor tui_create_group_on_filter

        Create a Group on Filter

        - -\code -from smesh import * -SetCurrentStudy(salome.myStudy) - -box = geompy.MakeBoxDXDYDZ(10,10,10) - -# make a mesh with quadrangles of different area in range [1,16] -mesh = Mesh(box,"Quad mesh") -hyp1D = mesh.Segment().StartEndLength( 1, 4 ) -mesh.Quadrangle() -mesh.Compute() - -# create a group on filter selecting faces of medium size -critaria = [ \ - GetCriterion(FACE, FT_Area, ">", 1.1, BinaryOp=FT_LogicalAND ), - GetCriterion(FACE, FT_Area, "<", 15.0 ) - ] -filt = GetFilterFromCriteria( critaria ) -filtGroup = mesh.GroupOnFilter( FACE, "group on filter", filt ) -print "Group on filter contains %s elemens" % filtGroup.Size() - -# group on filter is updated if the mesh is modified -hyp1D.SetStartLength( 2.5 ) -hyp1D.SetEndLength( 2.5 ) -mesh.Compute() -print "After mesh change, group on filter contains %s elemens" % filtGroup.Size() - -# set a new filter defining the group -filt2 = GetFilter( FACE, FT_RangeOfIds, "1-50" ) -filtGroup.SetFilter( filt2 ) -print "With a new filter, group on filter contains %s elemens" % filtGroup.Size() - -# group is updated at modification of the filter -filt2.SetCriteria( [ GetCriterion( FACE, FT_RangeOfIds, "1-70" )]) -filtIDs3 = filtGroup.GetIDs() -print "After filter modification, group on filter contains %s elemens" % filtGroup.Size() - -salome.sg.updateObjBrowser(1) -\endcode +\include grouping_elements_ex03.py +Download this script
        \anchor tui_edit_group

        Edit a Group

        - -\code -import SMESH_mechanic - -smesh = SMESH_mechanic.smesh -mesh = SMESH_mechanic.mesh -salome = SMESH_mechanic.salome - -# Get ids of all faces with area > 35 -aFilter = smesh.GetFilter(smesh.FACE, smesh.FT_Area, smesh.FT_MoreThan, 35.) - -anIds = mesh.GetIdsFromFilter(aFilter) - -print "Criterion: Area > 35, Nb = ", len(anIds) - -# create a group by adding elements with area > 35 -aGroup = mesh.CreateEmptyGroup(smesh.FACE, "Area > 35") -aGroup.Add(anIds) - -# Get ids of all faces with area > 40 -aFilter = smesh.GetFilter(smesh.FACE, smesh.FT_Area, smesh.FT_MoreThan, 40.) - -anIds = mesh.GetIdsFromFilter(aFilter) - -print "Criterion: Area > 40, Nb = ", len(anIds) - -# create a group of elements with area [35; 40] by removing elements with area > 40 from group aGroup -aGroup.Remove(anIds) - -# print the result -aGroupElemIDs = aGroup.GetListOfID() - -print "Criterion: 35 < Area < 40, Nb = ", len(aGroupElemIDs) - -j = 1 -for i in range(len(aGroupElemIDs)): - if j > 20: j = 1; print "" - print aGroupElemIDs[i], - j = j + 1 - pass -print "" - -salome.sg.updateObjBrowser(1) -\endcode +\include grouping_elements_ex04.py +Download this script \image html editing_groups1.png @@ -174,59 +36,8 @@ salome.sg.updateObjBrowser(1)
        \anchor tui_union_of_groups

        Union of groups

        - -\code -import SMESH_mechanic - -smesh = SMESH_mechanic.smesh -mesh = SMESH_mechanic.mesh -salome = SMESH_mechanic.salome - -# Criterion : AREA > 20 -aFilter = smesh.GetFilter(smesh.FACE, smesh.FT_Area, smesh.FT_MoreThan, 20.) - -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.Add(anIds) - -# Criterion : AREA = 20 -aFilter = smesh.GetFilter(smesh.FACE, smesh.FT_Area, smesh.FT_EqualTo, 20.) - -anIds = mesh.GetIdsFromFilter(aFilter) - -print "Criterion: Area = 20, Nb = ", len( anIds ) - -# create a group by adding elements with area = 20 -aGroup2 = mesh.CreateEmptyGroup( smesh.FACE, "Area = 20" ) - -aGroup2.Add(anIds) - -# create union group : 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.) - -anIds = mesh.GetIdsFromFilter(aFilter) - -print "Criterion: Area < 20, Nb = ", len(anIds) - -# create a group by adding elements with area < 20 -aGroup4 = mesh.CreateEmptyGroup(smesh.FACE, "Area < 20") -aGroup4.Add(anIds) - -# create union group : area >= 20 and area < 20 -aGroup5 = mesh.UnionListOfGroups([aGroup3, aGroup4], "Any Area") -print "Criterion: Any Area, Nb = ", len(aGroup5.GetListOfID()) - -salome.sg.updateObjBrowser(1) -\endcode +\include grouping_elements_ex05.py +Download this script \image html union_groups1.png @@ -237,43 +48,8 @@ salome.sg.updateObjBrowser(1)
        \anchor tui_intersection_of_groups

        Intersection of groups

        - -\code -import SMESH_mechanic - -smesh = SMESH_mechanic.smesh -mesh = SMESH_mechanic.mesh -salome = SMESH_mechanic.salome - -# Criterion : AREA > 20 -aFilter = smesh.GetFilter(smesh.FACE, smesh.FT_Area, smesh.FT_MoreThan, 20.) - -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.Add(anIds) - -# Criterion : AREA < 60 -aFilter = smesh.GetFilter(smesh.FACE, smesh.FT_Area, smesh.FT_LessThan, 60.) - -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.Add(anIds) - -# create an intersection of groups : 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 +\include grouping_elements_ex06.py +Download this script \image html intersect_groups1.png @@ -284,41 +60,8 @@ salome.sg.updateObjBrowser(1)
        \anchor tui_cut_of_groups

        Cut of groups

        - -\code -import SMESH_mechanic - -smesh = SMESH_mechanic.smesh -mesh = SMESH_mechanic.mesh -salome = SMESH_mechanic.salome - -# Criterion : AREA > 20 -aFilter = smesh.GetFilter(smesh.FACE, smesh.FT_Area, smesh.FT_MoreThan, 20.) - -anIds = mesh.GetIdsFromFilter(aFilter) - -print "Criterion: Area > 20, Nb = ", len(anIds) - -# create a group by adding elements with area > 20 -aGroupMain = mesh.MakeGroupByIds("Area > 20", smesh.FACE, anIds) - -# Criterion : AREA < 60 -aFilter = smesh.GetFilter(smesh.FACE, smesh.FT_Area, smesh.FT_LessThan, 60.) - -anIds = mesh.GetIdsFromFilter(aFilter) - -print "Criterion: Area < 60, Nb = ", len(anIds) - -# create a group by adding elements with area < 60 -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 +\include grouping_elements_ex07.py +Download this script \image html cut_groups1.png @@ -329,42 +72,8 @@ salome.sg.updateObjBrowser(1)
        \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 +\include grouping_elements_ex08.py +Download this script \image html dimgroup_tui1.png
        Source groups of faces
        diff --git a/doc/salome/gui/SMESH/input/tui_measurements.doc b/doc/salome/gui/SMESH/input/tui_measurements.doc index aabf0b317..8ca283fc3 100644 --- a/doc/salome/gui/SMESH/input/tui_measurements.doc +++ b/doc/salome/gui/SMESH/input/tui_measurements.doc @@ -3,82 +3,11 @@ \page tui_measurements_page Measurements \section tui_min_distance Minimum Distance - -\code - -import smesh -from SMESH_mechanic import mesh as mesh1 -from SMESH_test1 import mesh as mesh2 - -mesh1.Compute() -mesh2.Compute() - -# compute min distance from mesh1 to the origin (not available yet) -smesh.MinDistance(mesh1) - -# compute min distance from node 10 of mesh1 to the origin -smesh.MinDistance(mesh1, id1=10) -# ... or -mesh1.MinDistance(10) - -# compute min distance between nodes 10 and 20 of mesh1 -smesh.MinDistance(mesh1, id1=10, id2=20) -# ... or -mesh1.MinDistance(10, 20) - -# compute min distance from element 100 of mesh1 to the origin (not available yet) -smesh.MinDistance(mesh1, id1=100, isElem1=True) -# ... or -mesh1.MinDistance(100, isElem1=True) - -# compute min distance between elements 100 and 200 of mesh1 (not available yet) -smesh.MinDistance(mesh1, id1=100, id2=200, isElem1=True, isElem2=True) -# ... or -mesh1.MinDistance(100, 200, True, True) - -# compute min distance from element 100 to node 20 of mesh1 (not available yet) -smesh.MinDistance(mesh1, id1=100, id2=20, isElem1=True) -# ... or -mesh1.MinDistance(100, 20, True) - -# compute min distance from mesh1 to mesh2 (not available yet) -smesh.MinDistance(mesh1, mesh2) - -# compute min distance from node 10 of mesh1 to node 20 of mesh2 -smesh.MinDistance(mesh1, mesh2, 10, 20) - -# compute min distance from node 10 of mesh1 to element 200 of mesh2 (not available yet) -smesh.MinDistance(mesh1, mesh2, 10, 200, isElem2=True) - -# etc... - -\endcode +\include measurements_ex01.py +Download this script \section tui_bounding_box Bounding Box - -\code - -import smesh -from SMESH_mechanic import mesh as mesh1 -from SMESH_test1 import mesh as mesh2 - -mesh1.Compute() -mesh2.Compute() - -# compute bounding box for mesh1 -mesh1.BoundingBox() - -# compute bounding box for list of nodes of mesh1 -mesh1.BoundingBox([363, 364, 370, 371, 372, 373, 379, 380, 381]) - -# compute bounding box for list of elements of mesh1 -mesh1.BoundingBox([363, 364, 370, 371, 372, 373, 379, 380, 381], isElem=True) - -# compute common bounding box of mesh1 and mesh2 -smesh.BoundingBox([mesh1, mesh2]) - -# etc... - -\endcode +\include measurements_ex02.py +Download this script */ diff --git a/doc/salome/gui/SMESH/input/tui_modifying_meshes.doc b/doc/salome/gui/SMESH/input/tui_modifying_meshes.doc index 977ff6e86..e7844327c 100644 --- a/doc/salome/gui/SMESH/input/tui_modifying_meshes.doc +++ b/doc/salome/gui/SMESH/input/tui_modifying_meshes.doc @@ -9,291 +9,62 @@
        \anchor tui_add_node

        Add Node

        - -\code -import smesh - -mesh = smesh.Mesh() - -# add node -new_id = mesh.AddNode(50, 10, 0) -print "" -if new_id == 0: print "KO node addition." -else: print "New Node has been added with ID ", new_id -\endcode +\include modifying_meshes_ex01.py +Download this script
        \anchor tui_add_0DElement

        Add 0D Element

        - -\code -import smesh - -mesh = smesh.Mesh() - -# add node -node_id = mesh.AddNode(50, 10, 0) - -# add 0D Element -new_id = mesh.Add0DElement(node_id) - -print "" -if new_id == 0: print "KO node addition." -else: print "New 0D Element has been added with ID ", new_id -\endcode +\include modifying_meshes_ex02.py +Download this script
        \anchor tui_add_0DElement_on_all_nodes

        Add 0D Element on Element Nodes

        - -\code -import smesh, SMESH, geompy - -# create a geometry -box = geompy.MakeBoxDXDYDZ( 10, 10, 10 ) -face = geompy.SubShapeAll( box, geompy.ShapeType["FACE"])[0] - -# make 3D mesh -mesh = smesh.Mesh( box ) -mesh.AutomaticHexahedralization(0) - -# create 0D elements on all nodes of the mesh -res = mesh.Add0DElementsToAllNodes( mesh ) - -# find 0D elements on all nodes of the mesh, all found nodes are added to a new group -groupName = "0Dmesh" -res = mesh.Add0DElementsToAllNodes( mesh, groupName ) -mesh.RemoveGroupWithContents( res ) # remove all found 0D elements - -# create 0D elements on all nodes of a sub-mesh, with group creation -groupName = "0Dsubmesh" -submesh = mesh.GetSubMesh( face, "faceSM") -res = mesh.Add0DElementsToAllNodes( submesh, groupName ) - -# create 0D elements on all nodes of a group -group = mesh.Group( face, "faceGroup" ) -res = mesh.Add0DElementsToAllNodes( group ) - -# remove all 0D elements -mesh.RemoveElements( mesh.GetIdsFromFilter( smesh.GetFilter( SMESH.ELEM0D, - SMESH.FT_ElemGeomType, - "=",SMESH.Geom_POINT ))) - -# create 0D elements on all nodes of some elements -res = mesh.Add0DElementsToAllNodes( mesh.GetElementsId() ) - -mesh.RemoveElements( mesh.GetElementsByType( SMESH.ELEM0D )) - -# create 0D elements on some nodes -nodes = range(1,10) -res = mesh.Add0DElementsToAllNodes( mesh.GetIDSource( nodes, SMESH.NODE )) - -\endcode +\include modifying_meshes_ex03.py +Download this script
        \anchor tui_add_edge

        Add Edge

        - -\code -import SMESH_mechanic - -mesh = SMESH_mechanic.mesh -print "" - -# add node -n1 = mesh.AddNode(50, 10, 0) -if n1 == 0: print "KO node addition." - -# add edge -e1 = mesh.AddEdge([n1, 38]) -if e1 == 0: print "KO edge addition." -else: print "New Edge has been added with ID ", e1 -\endcode +\include modifying_meshes_ex04.py +Download this script
        \anchor tui_add_triangle

        Add Triangle

        - -\code -import SMESH_mechanic - -mesh = SMESH_mechanic.mesh -print "" - -# add node -n1 = mesh.AddNode(50, 10, 0) -if n1 == 0: print "KO node addition." - -# add triangle -t1 = mesh.AddFace([n1, 38, 39]) -if t1 == 0: print "KO triangle addition." -else: print "New Triangle has been added with ID ", t1 -\endcode +\include modifying_meshes_ex05.py +Download this script
        \anchor tui_add_quadrangle

        Add Quadrangle

        - -\code -import SMESH_mechanic - -mesh = SMESH_mechanic.mesh -print "" - -# add node -n1 = mesh.AddNode(50, 10, 0) -if n1 == 0: print "KO node addition." - -n2 = mesh.AddNode(40, 20, 0) -if n2 == 0: print "KO node addition." - -# add quadrangle -q1 = mesh.AddFace([n2, n1, 38, 39]) -if q1 == 0: print "KO quadrangle addition." -else: print "New Quadrangle has been added with ID ", q1 -\endcode +\include modifying_meshes_ex06.py +Download this script
        \anchor tui_add_tetrahedron

        Add Tetrahedron

        - -\code -import SMESH_mechanic - -mesh = SMESH_mechanic.mesh -print "" - -# add node -n1 = mesh.AddNode(50, 10, 0) -if n1 == 0: print "KO node addition." - -# add tetrahedron -t1 = mesh.AddVolume([n1, 38, 39, 246]) -if t1 == 0: print "KO tetrahedron addition." -else: print "New Tetrahedron has been added with ID ", t1 -\endcode +\include modifying_meshes_ex07.py +Download this script
        \anchor tui_add_hexahedron

        Add Hexahedron

        - -\code -import SMESH_mechanic - -mesh = SMESH_mechanic.mesh -print "" - -# add nodes -nId1 = mesh.AddNode(50, 10, 0) -nId2 = mesh.AddNode(47, 12, 0) -nId3 = mesh.AddNode(50, 10, 10) -nId4 = mesh.AddNode(47, 12, 10) - -if nId1 == 0 or nId2 == 0 or nId3 == 0 or nId4 == 0: print "KO node addition." - -# add hexahedron -vId = mesh.AddVolume([nId2, nId1, 38, 39, nId4, nId3, 245, 246]) -if vId == 0: print "KO Hexahedron addition." -else: print "New Hexahedron has been added with ID ", vId -\endcode +\include modifying_meshes_ex08.py +Download this script
        \anchor tui_add_polygon

        Add Polygon

        - -\code -import math -import salome - -import smesh - -# create an empty mesh structure -mesh = smesh.Mesh() - -# a method to build a polygonal mesh element with angles: -def MakePolygon (a_mesh, x0, y0, z0, radius, nb_vert): - al = 2.0 * math.pi / nb_vert - node_ids = [] - - # Create nodes for a polygon - for ii in range(nb_vert): - nid = mesh.AddNode(x0 + radius * math.cos(ii*al), - y0 + radius * math.sin(ii*al), - z0) - node_ids.append(nid) - pass - - # Create a polygon - return mesh.AddPolygonalFace(node_ids) - -# Create three polygons -f1 = MakePolygon(mesh, 0, 0, 0, 30, 13) -f2 = MakePolygon(mesh, 0, 0, 10, 21, 9) -f3 = MakePolygon(mesh, 0, 0, 20, 13, 6) - -salome.sg.updateObjBrowser(1) -\endcode +\include modifying_meshes_ex09.py +Download this script
        \anchor tui_add_polyhedron

        Add Polyhedron

        - -\code -import salome -import math - -# create an empty mesh structure -mesh = smesh.Mesh() - -# Create nodes for 12-hedron with pentagonal faces -al = 2 * math.pi / 5.0 -cosal = math.cos(al) -aa = 13 -rr = aa / (2.0 * math.sin(al/2.0)) -dr = 2.0 * rr * cosal -r1 = rr + dr -dh = rr * math.sqrt(2.0 * (1.0 - cosal * (1.0 + 2.0 * cosal))) -hh = 2.0 * dh - dr * (rr*(cosal - 1) + (rr + dr)*(math.cos(al/2) - 1)) / dh - -dd = [] # top -cc = [] # below top -bb = [] # above bottom -aa = [] # bottom - -for i in range(5): - cos_bot = math.cos(i*al) - sin_bot = math.sin(i*al) - - cos_top = math.cos(i*al + al/2.0) - sin_top = math.sin(i*al + al/2.0) - - nd = mesh.AddNode(rr * cos_top, rr * sin_top, hh ) # top - nc = mesh.AddNode(r1 * cos_top, r1 * sin_top, hh - dh) # below top - nb = mesh.AddNode(r1 * cos_bot, r1 * sin_bot, dh) # above bottom - na = mesh.AddNode(rr * cos_bot, rr * sin_bot, 0) # bottom - dd.append(nd) # top - cc.append(nc) # below top - bb.append(nb) # above bottom - aa.append(na) # bottom - pass - -# Create a polyhedral volume (12-hedron with pentagonal faces) -MeshEditor.AddPolyhedralVolume([dd[0], dd[1], dd[2], dd[3], dd[4], # top - dd[0], cc[0], bb[1], cc[1], dd[1], # - - dd[1], cc[1], bb[2], cc[2], dd[2], # - - dd[2], cc[2], bb[3], cc[3], dd[3], # - below top - dd[3], cc[3], bb[4], cc[4], dd[4], # - - dd[4], cc[4], bb[0], cc[0], dd[0], # - - aa[4], bb[4], cc[4], bb[0], aa[0], # . - aa[3], bb[3], cc[3], bb[4], aa[4], # . - aa[2], bb[2], cc[2], bb[3], aa[3], # . above bottom - aa[1], bb[1], cc[1], bb[2], aa[2], # . - aa[0], bb[0], cc[0], bb[1], aa[1], # . - aa[0], aa[1], aa[2], aa[3], aa[4]], # bottom - [5,5,5,5,5,5,5,5,5,5,5,5]) - -salome.sg.updateObjBrowser(1) -\endcode +\include modifying_meshes_ex10.py +Download this script
        \anchor tui_removing_nodes_and_elements @@ -302,718 +73,97 @@ salome.sg.updateObjBrowser(1)
        \anchor tui_removing_nodes

        Removing Nodes

        - -\code -import SMESH_mechanic - -mesh = SMESH_mechanic.mesh - -# remove nodes #246 and #255 -res = mesh.RemoveNodes([246, 255]) -if res == 1: print "Nodes removing is OK!" -else: print "KO nodes removing." -\endcode +\include modifying_meshes_ex11.py +Download this script
        \anchor tui_removing_elements

        Removing Elements

        - -\code -import SMESH_mechanic - -mesh = SMESH_mechanic.mesh - -# remove three elements: #850, #859 and #814 -res = mesh.RemoveElements([850, 859, 814]) -if res == 1: print "Elements removing is OK!" -else: print "KO Elements removing." -\endcode +\include modifying_meshes_ex12.py +Download this script
        \anchor tui_removing_orphan_nodes

        Removing Orphan Nodes

        - -\code -import SMESH_mechanic - -mesh = SMESH_mechanic.mesh - -# add orphan nodes -mesh.AddNode(0,0,0) -mesh.AddNode(1,1,1) -# remove just created orphan nodes -res = mesh.RemoveOrphanNodes() -if res == 1: print "Removed %d nodes!" % res -else: print "KO nodes removing." -\endcode +\include modifying_meshes_ex13.py +Download this script
        \anchor tui_renumbering_nodes_and_elements

        Renumbering Nodes and Elements

        - -\code -import SMESH_mechanic - -mesh = SMESH_mechanic.mesh - -mesh.RenumberNodes() - -mesh.RenumberElements() -\endcode +\include modifying_meshes_ex14.py +Download this script
        \anchor tui_moving_nodes

        Moving Nodes

        - -\code -from geompy import * -from smesh import * - -box = MakeBoxDXDYDZ(200, 200, 200) - -mesh = Mesh( box ) -mesh.Segment().AutomaticLength(0.1) -mesh.Quadrangle() -mesh.Compute() - -# find node at (0,0,0) -node000 = None -for vId in SubShapeAllIDs( box, ShapeType["VERTEX"]): - if node000: break - nodeIds = mesh.GetSubMeshNodesId( vId, True ) - for node in nodeIds: - xyz = mesh.GetNodeXYZ( node ) - if xyz[0] == 0 and xyz[1] == 0 and xyz[2] == 0 : - node000 = node - pass - pass - pass - -if not node000: - raise "node000 not found" - -# find node000 using the tested function -n = mesh.FindNodeClosestTo( -1,-1,-1 ) -if not n == node000: - raise "FindNodeClosestTo() returns " + str( n ) + " != " + str( node000 ) - -# move node000 to a new location -x,y,z = -10, -10, -10 -n = mesh.MoveNode( n,x,y,z ) -if not n: - raise "MoveNode() returns " + n - -# check the coordinates of the node000 -xyz = mesh.GetNodeXYZ( node000 ) -if not ( xyz[0] == x and xyz[1] == y and xyz[2] == z) : - raise "Wrong coordinates: " + str( xyz ) + " != " + str( [x,y,z] ) -\endcode +\include modifying_meshes_ex15.py +Download this script
        \anchor tui_diagonal_inversion

        Diagonal Inversion

        - -\code -import salome -import smesh - -# create an empty mesh structure -mesh = smesh.Mesh() - -# create the following mesh: -# .----.----.----. -# | /| /| /| -# | / | / | / | -# | / | / | / | -# |/ |/ |/ | -# .----.----.----. - -bb = [0, 0, 0, 0] -tt = [0, 0, 0, 0] -ff = [0, 0, 0, 0, 0, 0] - -bb[0] = mesh.AddNode( 0., 0., 0.) -bb[1] = mesh.AddNode(10., 0., 0.) -bb[2] = mesh.AddNode(20., 0., 0.) -bb[3] = mesh.AddNode(30., 0., 0.) - -tt[0] = mesh.AddNode( 0., 15., 0.) -tt[1] = mesh.AddNode(10., 15., 0.) -tt[2] = mesh.AddNode(20., 15., 0.) -tt[3] = mesh.AddNode(30., 15., 0.) - -ff[0] = mesh.AddFace([bb[0], bb[1], tt[1]]) -ff[1] = mesh.AddFace([bb[0], tt[1], tt[0]]) -ff[2] = mesh.AddFace([bb[1], bb[2], tt[2]]) -ff[3] = mesh.AddFace([bb[1], tt[2], tt[1]]) -ff[4] = mesh.AddFace([bb[2], bb[3], tt[3]]) -ff[5] = mesh.AddFace([bb[2], tt[3], tt[2]]) - -# inverse the diagonal bb[1] - tt[2] -print "\nDiagonal inversion ... ", -res = mesh.InverseDiag(bb[1], tt[2]) -if not res: print "failed!" -else: print "done." - -salome.sg.updateObjBrowser(1) -\endcode +\include modifying_meshes_ex16.py +Download this script
        \anchor tui_uniting_two_triangles

        Uniting two Triangles

        - -\code -import salome -import smesh - -# create an empty mesh structure -mesh = smesh.Mesh() - -# create the following mesh: -# .----.----.----. -# | /| /| /| -# | / | / | / | -# | / | / | / | -# |/ |/ |/ | -# .----.----.----. - -bb = [0, 0, 0, 0] -tt = [0, 0, 0, 0] -ff = [0, 0, 0, 0, 0, 0] - -bb[0] = mesh.AddNode( 0., 0., 0.) -bb[1] = mesh.AddNode(10., 0., 0.) -bb[2] = mesh.AddNode(20., 0., 0.) -bb[3] = mesh.AddNode(30., 0., 0.) - -tt[0] = mesh.AddNode( 0., 15., 0.) -tt[1] = mesh.AddNode(10., 15., 0.) -tt[2] = mesh.AddNode(20., 15., 0.) -tt[3] = mesh.AddNode(30., 15., 0.) - -ff[0] = mesh.AddFace([bb[0], bb[1], tt[1]]) -ff[1] = mesh.AddFace([bb[0], tt[1], tt[0]]) -ff[2] = mesh.AddFace([bb[1], bb[2], tt[2]]) -ff[3] = mesh.AddFace([bb[1], tt[2], tt[1]]) -ff[4] = mesh.AddFace([bb[2], bb[3], tt[3]]) -ff[5] = mesh.AddFace([bb[2], tt[3], tt[2]]) - -# delete the diagonal bb[1] - tt[2] -print "\nUnite two triangles ... ", -res = mesh.DeleteDiag(bb[1], tt[2]) -if not res: print "failed!" -else: print "done." - -salome.sg.updateObjBrowser(1) -\endcode +\include modifying_meshes_ex17.py +Download this script
        \anchor tui_uniting_set_of_triangles

        Uniting a Set of Triangles

        - -\code -import salome -import smesh - -# create an empty mesh structure -mesh = smesh.Mesh() - -# create the following mesh: -# .----.----.----. -# | /| /| /| -# | / | / | / | -# | / | / | / | -# |/ |/ |/ | -# .----.----.----. - -bb = [0, 0, 0, 0] -tt = [0, 0, 0, 0] -ff = [0, 0, 0, 0, 0, 0] - -bb[0] = mesh.AddNode( 0., 0., 0.) -bb[1] = mesh.AddNode(10., 0., 0.) -bb[2] = mesh.AddNode(20., 0., 0.) -bb[3] = mesh.AddNode(30., 0., 0.) - -tt[0] = mesh.AddNode( 0., 15., 0.) -tt[1] = mesh.AddNode(10., 15., 0.) -tt[2] = mesh.AddNode(20., 15., 0.) -tt[3] = mesh.AddNode(30., 15., 0.) - -ff[0] = mesh.AddFace([bb[0], bb[1], tt[1]]) -ff[1] = mesh.AddFace([bb[0], tt[1], tt[0]]) -ff[2] = mesh.AddFace([bb[1], bb[2], tt[2]]) -ff[3] = mesh.AddFace([bb[1], tt[2], tt[1]]) -ff[4] = mesh.AddFace([bb[2], bb[3], tt[3]]) -ff[5] = mesh.AddFace([bb[2], tt[3], tt[2]]) - -# unite a set of triangles -print "\nUnite a set of triangles ... ", -res = mesh.TriToQuad([ff[2], ff[3], ff[4], ff[5]], smesh.FT_MinimumAngle, 60.) -if not res: print "failed!" -else: print "done." - -salome.sg.updateObjBrowser(1) -\endcode +\include modifying_meshes_ex18.py +Download this script
        \anchor tui_orientation

        Orientation

        - -\code -import salome -import smesh - -# create an empty mesh structure -mesh = smesh.Mesh() - -# build five quadrangles: -dx = 10 -dy = 20 - -n1 = mesh.AddNode(0.0 * dx, 0, 0) -n2 = mesh.AddNode(1.0 * dx, 0, 0) -n3 = mesh.AddNode(2.0 * dx, 0, 0) -n4 = mesh.AddNode(3.0 * dx, 0, 0) -n5 = mesh.AddNode(4.0 * dx, 0, 0) -n6 = mesh.AddNode(5.0 * dx, 0, 0) -n7 = mesh.AddNode(0.0 * dx, dy, 0) -n8 = mesh.AddNode(1.0 * dx, dy, 0) -n9 = mesh.AddNode(2.0 * dx, dy, 0) -n10 = mesh.AddNode(3.0 * dx, dy, 0) -n11 = mesh.AddNode(4.0 * dx, dy, 0) -n12 = mesh.AddNode(5.0 * dx, dy, 0) - -f1 = mesh.AddFace([n1, n2, n8 , n7 ]) -f2 = mesh.AddFace([n2, n3, n9 , n8 ]) -f3 = mesh.AddFace([n3, n4, n10, n9 ]) -f4 = mesh.AddFace([n4, n5, n11, n10]) -f5 = mesh.AddFace([n5, n6, n12, n11]) - -# Change the orientation of the second and the fourth faces. -mesh.Reorient([2, 4]) - -salome.sg.updateObjBrowser(1) -\endcode +\include modifying_meshes_ex19.py +Download this script
        \anchor tui_cutting_quadrangles

        Cutting Quadrangles

        - -\code -import SMESH_mechanic - -smesh = SMESH_mechanic.smesh -mesh = SMESH_mechanic.mesh - -# cut two quadrangles: 405 and 406 -mesh.QuadToTri([405, 406], smesh.FT_MinimumAngle) -\endcode +\include modifying_meshes_ex20.py +Download this script
        \anchor tui_smoothing

        Smoothing

        - -\code -import salome -import geompy - -import SMESH_mechanic - -smesh = SMESH_mechanic.smesh -mesh = SMESH_mechanic.mesh - -# select the top face -faces = geompy.SubShapeAllSorted(SMESH_mechanic.shape_mesh, geompy.ShapeType["FACE"]) -face = faces[3] -geompy.addToStudyInFather(SMESH_mechanic.shape_mesh, face, "face planar with hole") - -# create a group of faces to be smoothed -GroupSmooth = mesh.GroupOnGeom(face, "Group of faces (smooth)", smesh.FACE) - -# perform smoothing - -# boolean SmoothObject(Object, IDsOfFixedNodes, MaxNbOfIterations, MaxAspectRatio, Method) -res = mesh.SmoothObject(GroupSmooth, [], 20, 2., smesh.CENTROIDAL_SMOOTH) -print "\nSmoothing ... ", -if not res: print "failed!" -else: print "done." - -salome.sg.updateObjBrowser(1) -\endcode +\include modifying_meshes_ex21.py +Download this script
        \anchor tui_extrusion

        Extrusion

        - -\code -import salome -import geompy - -import SMESH_mechanic - -smesh = SMESH_mechanic.smesh -mesh = SMESH_mechanic.mesh - -# select the top face -faces = geompy.SubShapeAllSorted(SMESH_mechanic.shape_mesh, geompy.ShapeType["FACE"]) -face = faces[7] -geompy.addToStudyInFather(SMESH_mechanic.shape_mesh, face, "face circular top") - -# create a vector for extrusion -point = smesh.PointStruct(0., 0., 5.) -vector = smesh.DirStruct(point) - -# create a group to be extruded -GroupTri = mesh.GroupOnGeom(face, "Group of faces (extrusion)", smesh.FACE) - -# perform extrusion of the group -mesh.ExtrusionSweepObject(GroupTri, vector, 5) - -salome.sg.updateObjBrowser(1) -\endcode +\include modifying_meshes_ex22.py +Download this script
        \anchor tui_extrusion_along_path

        Extrusion along a Path

        - -\code -import math -import salome - -# Geometry -import geompy - -# 1. Create points -points = [[0, 0], [50, 30], [50, 110], [0, 150], [-80, 150], [-130, 70], [-130, -20]] - -iv = 1 -vertices = [] -for point in points: - vert = geompy.MakeVertex(point[0], point[1], 0) - geompy.addToStudy(vert, "Vertex_" + `iv`) - vertices.append(vert) - iv += 1 - pass - -# 2. Create edges and wires -Edge_straight = geompy.MakeEdge(vertices[0], vertices[4]) -Edge_bezierrr = geompy.MakeBezier(vertices) -Wire_polyline = geompy.MakePolyline(vertices) -Edge_Circle = geompy.MakeCircleThreePnt(vertices[0], vertices[1], vertices[2]) - -geompy.addToStudy(Edge_straight, "Edge_straight") -geompy.addToStudy(Edge_bezierrr, "Edge_bezierrr") -geompy.addToStudy(Wire_polyline, "Wire_polyline") -geompy.addToStudy(Edge_Circle , "Edge_Circle") - -# 3. Explode wire on edges, as they will be used for mesh extrusion -Wire_polyline_edges = geompy.SubShapeAll(Wire_polyline, geompy.ShapeType["EDGE"]) -for ii in range(len(Wire_polyline_edges)): - geompy.addToStudyInFather(Wire_polyline, Wire_polyline_edges[ii], "Edge_" + `ii + 1`) - pass - -# Mesh -import smesh - -# Mesh the given shape with the given 1d hypothesis -def Mesh1D(shape1d, nbSeg, name): - mesh1d_tool = smesh.Mesh(shape1d, name) - algo = mesh1d_tool.Segment() - hyp = algo.NumberOfSegments(nbSeg) - isDone = mesh1d_tool.Compute() - if not isDone: print 'Mesh ', name, ': computation failed' - return mesh1d_tool - -# Create a mesh with six nodes, seven edges and two quadrangle faces -def MakeQuadMesh2(mesh_name): - quad_1 = smesh.Mesh(name = mesh_name) - - # six nodes - n1 = quad_1.AddNode(0, 20, 10) - n2 = quad_1.AddNode(0, 40, 10) - n3 = quad_1.AddNode(0, 40, 30) - n4 = quad_1.AddNode(0, 20, 30) - n5 = quad_1.AddNode(0, 0, 30) - n6 = quad_1.AddNode(0, 0, 10) - - # seven edges - quad_1.AddEdge([n1, n2]) # 1 - quad_1.AddEdge([n2, n3]) # 2 - quad_1.AddEdge([n3, n4]) # 3 - quad_1.AddEdge([n4, n1]) # 4 - quad_1.AddEdge([n4, n5]) # 5 - quad_1.AddEdge([n5, n6]) # 6 - quad_1.AddEdge([n6, n1]) # 7 - - # two quadrangle faces - quad_1.AddFace([n1, n2, n3, n4]) # 8 - quad_1.AddFace([n1, n4, n5, n6]) # 9 - return [quad_1, [1,2,3,4,5,6,7], [8,9]] - -# Path meshes -Edge_straight_mesh = Mesh1D(Edge_straight, 7, "Edge_straight") -Edge_bezierrr_mesh = Mesh1D(Edge_bezierrr, 7, "Edge_bezierrr") -Wire_polyline_mesh = Mesh1D(Wire_polyline, 3, "Wire_polyline") -Edge_Circle_mesh = Mesh1D(Edge_Circle , 8, "Edge_Circle") - -# Initial meshes (to be extruded) -[quad_1, ee_1, ff_1] = MakeQuadMesh2("quad_1") -[quad_2, ee_2, ff_2] = MakeQuadMesh2("quad_2") -[quad_3, ee_3, ff_3] = MakeQuadMesh2("quad_3") -[quad_4, ee_4, ff_4] = MakeQuadMesh2("quad_4") -[quad_5, ee_5, ff_5] = MakeQuadMesh2("quad_5") -[quad_6, ee_6, ff_6] = MakeQuadMesh2("quad_6") -[quad_7, ee_7, ff_7] = MakeQuadMesh2("quad_7") - -# ExtrusionAlongPath -# IDsOfElements, PathMesh, PathShape, NodeStart, -# HasAngles, Angles, HasRefPoint, RefPoint -refPoint = smesh.PointStruct(0, 0, 0) -a10 = 10.0*math.pi/180.0 -a45 = 45.0*math.pi/180.0 - -# 1. Extrusion of two mesh edges along a straight path -error = quad_1.ExtrusionAlongPath([1,2], Edge_straight_mesh, Edge_straight, 1, - 0, [], 0, refPoint) - -# 2. Extrusion of one mesh edge along a curved path -error = quad_2.ExtrusionAlongPath([2], Edge_bezierrr_mesh, Edge_bezierrr, 1, - 0, [], 0, refPoint) - -# 3. Extrusion of one mesh edge along a curved path with usage of angles -error = quad_3.ExtrusionAlongPath([2], Edge_bezierrr_mesh, Edge_bezierrr, 1, - 1, [a45, a45, a45, 0, -a45, -a45, -a45], 0, refPoint) - -# 4. Extrusion of one mesh edge along the path, which is a part of a meshed wire -error = quad_4.ExtrusionAlongPath([4], Wire_polyline_mesh, Wire_polyline_edges[0], 1, - 1, [a10, a10, a10], 0, refPoint) - -# 5. Extrusion of two mesh faces along the path, which is a part of a meshed wire -error = quad_5.ExtrusionAlongPath(ff_5 , Wire_polyline_mesh, Wire_polyline_edges[2], 4, - 0, [], 0, refPoint) - -# 6. Extrusion of two mesh faces along a closed path -error = quad_6.ExtrusionAlongPath(ff_6 , Edge_Circle_mesh, Edge_Circle, 1, - 0, [], 0, refPoint) - -# 7. Extrusion of two mesh faces along a closed path with usage of angles -error = quad_7.ExtrusionAlongPath(ff_7, Edge_Circle_mesh, Edge_Circle, 1, - 1, [a45, -a45, a45, -a45, a45, -a45, a45, -a45], 0, refPoint) - -salome.sg.updateObjBrowser(1) -\endcode +\include modifying_meshes_ex23.py +Download this script
        \anchor tui_revolution

        Revolution

        - -\code -import math -import SMESH - -import SMESH_mechanic - -mesh = SMESH_mechanic.mesh -smesh = SMESH_mechanic.smesh - -# create a group of faces to be revolved -FacesRotate = [492, 493, 502, 503] -GroupRotate = mesh.CreateEmptyGroup(SMESH.FACE,"Group of faces (rotate)") -GroupRotate.Add(FacesRotate) - -# define revolution angle and axis -angle45 = 45 * math.pi / 180 -axisXYZ = SMESH.AxisStruct(-38.3128, -73.3658, -23.321, -13.3402, -13.3265, 6.66632) - -# perform revolution of an object -mesh.RotationSweepObject(GroupRotate, axisXYZ, angle45, 4, 1e-5) -\endcode +\include modifying_meshes_ex24.py +Download this script
        \anchor tui_pattern_mapping

        Pattern Mapping

        - -\code -import geompy -import smesh - -# define the geometry -Box_1 = geompy.MakeBoxDXDYDZ(200., 200., 200.) -geompy.addToStudy(Box_1, "Box_1") - -faces = geompy.SubShapeAll(Box_1, geompy.ShapeType["FACE"]) -Face_1 = faces[0] -Face_2 = faces[1] - -geompy.addToStudyInFather(Box_1, Face_1, "Face_1") -geompy.addToStudyInFather(Box_1, Face_2, "Face_2") - -# build a quadrangle mesh 3x3 on Face_1 -Mesh_1 = smesh.Mesh(Face_1) -algo1D = Mesh_1.Segment() -algo1D.NumberOfSegments(3) -Mesh_1.Quadrangle() - -isDone = Mesh_1.Compute() -if not isDone: print 'Mesh Mesh_1 : computation failed' - -# build a triangle mesh on Face_2 -Mesh_2 = smesh.Mesh(Face_2) - -algo1D = Mesh_2.Segment() -algo1D.NumberOfSegments(1) -algo2D = Mesh_2.Triangle() -algo2D.MaxElementArea(240) - -isDone = Mesh_2.Compute() -if not isDone: print 'Mesh Mesh_2 : computation failed' - -# create a 2d pattern -pattern = smesh.GetPattern() - -isDone = pattern.LoadFromFace(Mesh_2.GetMesh(), Face_2, 0) -if (isDone != 1): print 'LoadFromFace :', pattern.GetErrorCode() - -# apply the pattern to a face of the first mesh -facesToSplit = Mesh_1.GetElementsByType(smesh.SMESH.FACE) -print "Splitting %d rectangular face(s) to %d triangles..."%(len(facesToSplit), 2*len(facesToSplit)) -pattern.ApplyToMeshFaces(Mesh_1.GetMesh(), facesToSplit, 0, 0) -isDone = pattern.MakeMesh(Mesh_1.GetMesh(), 0, 0) -if (isDone != 1): print 'MakeMesh :', pattern.GetErrorCode() - -# create quadrangle mesh -Mesh_3 = smesh.Mesh(Box_1) -Mesh_3.Segment().NumberOfSegments(1) -Mesh_3.Quadrangle() -Mesh_3.Hexahedron() -isDone = Mesh_3.Compute() -if not isDone: print 'Mesh Mesh_3 : computation failed' - -# create a 3d pattern (hexahedrons) -pattern_hexa = smesh.GetPattern() - -smp_hexa = """!!! Nb of points: -15 - 0 0 0 !- 0 - 1 0 0 !- 1 - 0 1 0 !- 2 - 1 1 0 !- 3 - 0 0 1 !- 4 - 1 0 1 !- 5 - 0 1 1 !- 6 - 1 1 1 !- 7 - 0.5 0 0.5 !- 8 - 0.5 0 1 !- 9 - 0.5 0.5 0.5 !- 10 - 0.5 0.5 1 !- 11 - 1 0 0.5 !- 12 - 1 0.5 0.5 !- 13 - 1 0.5 1 !- 14 - !!! Indices of points of 4 elements: - 8 12 5 9 10 13 14 11 - 0 8 9 4 2 10 11 6 - 2 10 11 6 3 13 14 7 - 0 1 12 8 2 3 13 10""" - -pattern_hexa.LoadFromFile(smp_hexa) - -# apply the pattern to a mesh -volsToSplit = Mesh_3.GetElementsByType(smesh.SMESH.VOLUME) -print "Splitting %d hexa volume(s) to %d hexas..."%(len(volsToSplit), 4*len(volsToSplit)) -pattern_hexa.ApplyToHexahedrons(Mesh_3.GetMesh(), volsToSplit,0,3) -isDone = pattern_hexa.MakeMesh(Mesh_3.GetMesh(), True, True) -if (isDone != 1): print 'MakeMesh :', pattern_hexa.GetErrorCode() - -# create one more quadrangle mesh -Mesh_4 = smesh.Mesh(Box_1) -Mesh_4.Segment().NumberOfSegments(1) -Mesh_4.Quadrangle() -Mesh_4.Hexahedron() -isDone = Mesh_4.Compute() -if not isDone: print 'Mesh Mesh_4 : computation failed' - -# create another 3d pattern (pyramids) -pattern_pyra = smesh.GetPattern() - -smp_pyra = """!!! Nb of points: -9 - 0 0 0 !- 0 - 1 0 0 !- 1 - 0 1 0 !- 2 - 1 1 0 !- 3 - 0 0 1 !- 4 - 1 0 1 !- 5 - 0 1 1 !- 6 - 1 1 1 !- 7 - 0.5 0.5 0.5 !- 8 - !!! Indices of points of 6 elements: - 0 1 5 4 8 - 7 5 1 3 8 - 3 2 6 7 8 - 2 0 4 6 8 - 0 2 3 1 8 - 4 5 7 6 8""" - -pattern_pyra.LoadFromFile(smp_pyra) - -# apply the pattern to a face mesh -volsToSplit = Mesh_4.GetElementsByType(smesh.SMESH.VOLUME) -print "Splitting %d hexa volume(s) to %d hexas..."%(len(volsToSplit), 6*len(volsToSplit)) -pattern_pyra.ApplyToHexahedrons(Mesh_4.GetMesh(), volsToSplit,1,0) -isDone = pattern_pyra.MakeMesh(Mesh_4.GetMesh(), True, True) -if (isDone != 1): print 'MakeMesh :', pattern_pyra.GetErrorCode() -\endcode +\include modifying_meshes_ex25.py +Download this script
        \anchor tui_quadratic

        Convert mesh to/from quadratic

        - -\code -import geompy -import smesh - -# create sphere of radius 100 - -Sphere = geompy.MakeSphereR( 100 ) -geompy.addToStudy( Sphere, "Sphere" ) - -# create simple trihedral mesh - -Mesh = smesh.Mesh(Sphere) -Regular_1D = Mesh.Segment() -Nb_Segments = Regular_1D.NumberOfSegments(5) -MEFISTO_2D = Mesh.Triangle() -Tetrahedron = Mesh.Tetrahedron() - -# compute mesh - -isDone = Mesh.Compute() - -# convert to quadratic -# theForce3d = 1; this results in the medium node lying at the -# middle of the line segments connecting start and end node of a mesh -# element - -Mesh.ConvertToQuadratic( theForce3d=1 ) - -# revert back to the non-quadratic mesh - -Mesh.ConvertFromQuadratic() - -# convert to quadratic -# theForce3d = 0; this results in the medium node lying at the -# geometrical edge from which the mesh element is built - -Mesh.ConvertToQuadratic( theForce3d=0 ) - -# to convert not the whole mesh but a sub-mesh, provide it as -# an additional argument to the functions: -# Mesh.ConvertToQuadratic( 0, subMesh ) -# Mesh.ConvertFromQuadratic( subMesh ) -# -# Note that the mesh becomes non-conformal at conversion of sub-mesh. - -\endcode +\include modifying_meshes_ex26.py +Download this script */ diff --git a/doc/salome/gui/SMESH/input/tui_notebook_smesh.doc b/doc/salome/gui/SMESH/input/tui_notebook_smesh.doc index a300ee633..340359069 100644 --- a/doc/salome/gui/SMESH/input/tui_notebook_smesh.doc +++ b/doc/salome/gui/SMESH/input/tui_notebook_smesh.doc @@ -3,45 +3,7 @@ \page tui_notebook_smesh_page Using SALOME NoteBook \anchor tui_notebook_smesh - -\code -import geompy -import smesh -import salome_notebook - -# set variables -notebook = salome_notebook.notebook -notebook.set("Length", 100) -notebook.set("Width", 200) -notebook.set("Offset", 50) - -notebook.set("NbSegments", 7) -notebook.set("MaxElementArea", 800) -notebook.set("MaxElementVolume", 900) - -# create a box -box = geompy.MakeBoxDXDYDZ("Length", "Width", 300) -idbox = geompy.addToStudy(box, "Box") - -# create a mesh -tetra = smesh.Mesh(box, "MeshBox") - -algo1D = tetra.Segment() -algo1D.NumberOfSegments("NbSegments") - -algo2D = tetra.Triangle() -algo2D.MaxElementArea("MaxElementArea") - -algo3D = tetra.Tetrahedron() -algo3D.MaxElementVolume("MaxElementVolume") - -# compute the mesh -ret = tetra.Compute() - -# translate the mesh -point = smesh.PointStruct("Offset", 0., 0.) -vector = smesh.DirStruct(point) -tetra.TranslateObject(tetra, vector, 0) -\endcode +\include notebook_smesh.py +Download this script */ diff --git a/doc/salome/gui/SMESH/input/tui_prism_3d_algo.doc b/doc/salome/gui/SMESH/input/tui_prism_3d_algo.doc new file mode 100644 index 000000000..d0234a7ab --- /dev/null +++ b/doc/salome/gui/SMESH/input/tui_prism_3d_algo.doc @@ -0,0 +1,10 @@ +/*! + +\page tui_prism_3d_algo Use 3D extrusion meshing algorithm +\include prism_3d_algo.py +Download this script + +The result geometry and mesh is shown below +\image html prism_tui_sample.png + +*/ diff --git a/doc/salome/gui/SMESH/input/tui_quality_controls.doc b/doc/salome/gui/SMESH/input/tui_quality_controls.doc index 2991eb521..e09389d3f 100644 --- a/doc/salome/gui/SMESH/input/tui_quality_controls.doc +++ b/doc/salome/gui/SMESH/input/tui_quality_controls.doc @@ -3,822 +3,91 @@ \page tui_quality_controls_page Quality Controls \section tui_free_borders Free Borders - -\code -import salome -import geompy - -import smesh - -# create open shell: a box without one plane -box = geompy.MakeBox(0., 0., 0., 20., 20., 15.) -FaceList = geompy.SubShapeAll(box, geompy.ShapeType["FACE"]) -FaceList.remove(FaceList[5]) -box = geompy.MakeShell(FaceList) -idbox = geompy.addToStudy(box, "box") - -# create a mesh -mesh = smesh.Mesh(box, "Mesh_free_borders") -algo = mesh.Segment() -algo.NumberOfSegments(5) -algo = mesh.Triangle() -algo.MaxElementArea(20.) -mesh.Compute() - -# criterion : free borders -aFilter = smesh.GetFilter(smesh.EDGE, smesh.FT_FreeBorders) -anIds = mesh.GetIdsFromFilter(aFilter) - -# print the result -print "Criterion: Free borders Nb = ", len(anIds) -j = 1 -for i in range(len(anIds)): - if j > 20: j = 1; print "" - print anIds[i], - j = j + 1 - pass -print "" - -# create a group -aGroup = mesh.CreateGroup(SMESH.EDGE, "Free borders") -aGroup.Add(anIds) - -salome.sg.updateObjBrowser(1) -\endcode +\include quality_controls_ex01.py +Download this script \section tui_borders_at_multiconnection Borders at Multiconnection - -\code -import salome -import geompy - -import smesh -import SMESH - -# create open shell: a box without one plane -box = geompy.MakeBox(0., 0., 0., 20., 20., 15.) -FaceList = geompy.SubShapeAll(box, geompy.ShapeType["FACE"]) -FaceList.remove(FaceList[5]) -box = geompy.MakeShell(FaceList) -idbox = geompy.addToStudy(box, "box") - -# create a mesh -mesh = smesh.Mesh(box, "Mesh_borders_at_multi-connections") -algo = mesh.Segment() -algo.NumberOfSegments(5) -algo = mesh.Triangle() -algo.MaxElementArea(20.) -mesh.Compute() - -# Criterion : Borders at multi-connection -nb_conn = 2 - -aFilter = smesh.GetFilter(smesh.EDGE, smesh.FT_MultiConnection, smesh.FT_EqualTo, nb_conn) -anIds = mesh.GetIdsFromFilter(aFilter) - -# print the result -print "Criterion: Borders at multi-connections Nb = ", len(anIds) -j = 1 -for i in range(len(anIds)): - if j > 20: j = 1; print "" - print anIds[i], - j = j + 1 - pass -print "" - -# create a group -aGroup = mesh.CreateGroup(SMESH.EDGE, "Borders at multi-connections") -aGroup.Add(anIds) - -salome.sg.updateObjBrowser(1) -\endcode +\include quality_controls_ex02.py +Download this script \section tui_length_1d Length 1D - -\code -import salome -import geompy - -import smesh - -# create open shell: a box without one plane -box = geompy.MakeBox(0., 0., 0., 20., 20., 15.) -FaceList = geompy.SubShapeAll(box, geompy.ShapeType["FACE"]) -FaceList.remove(FaceList[5]) -box = geompy.MakeShell(FaceList) -idbox = geompy.addToStudy(box, "box") - -# create a mesh -mesh = smesh.Mesh(box, "Mesh_Length_1D") -algo = mesh.Segment() -algo.NumberOfSegments(5) -algo = mesh.Triangle() -algo.MaxElementArea(20.) -mesh.Compute() - -# Criterion : Length > 3. -length_margin = 3. - -aFilter = smesh.GetFilter(smesh.EDGE, smesh.FT_Length, smesh.FT_MoreThan, length_margin) -anIds = mesh.GetIdsFromFilter(aFilter) - -# print the result -print "Criterion: Edges length > ", length_margin, " Nb = ", len(anIds) -j = 1 -for i in range(len(anIds)): - if j > 20: j = 1; print "" - print anIds[i], - j = j + 1 - pass -print "" - -# create a group -aGroup = mesh.CreateGroup(SMESH.EDGE, "Edges with length > " + `length_margin`) -aGroup.Add(anIds) - -salome.sg.updateObjBrowser(1) -\endcode +\include quality_controls_ex03.py +Download this script \section tui_free_edges Free Edges - -\code -import SMESH_mechanic - -smesh = SMESH_mechanic.smesh -mesh = SMESH_mechanic.mesh -salome = SMESH_mechanic.salome - -aFilterMgr = smesh.CreateFilterManager() - -# Remove some elements to obtain free edges -# Criterion : AREA > 95. -area_margin = 95. - -aFilter = smesh.GetFilter(smesh.FACE, smesh.FT_Area, smesh.FT_MoreThan, area_margin) - -anIds = mesh.GetIdsFromFilter(aFilter) - -mesh.RemoveElements(anIds) - -# Criterion : Free Edges -aBorders = mesh.GetFreeBorders() - -# create groups -aGroupF = mesh.CreateEmptyGroup(smesh.FACE, "Faces with free edges") -aGroupN = mesh.CreateEmptyGroup(smesh.NODE, "Nodes on free edges") - -# fill groups with elements, corresponding to the criterion -print "" -print "Criterion: Free edges Nb = ", len(aBorders) -for i in range(len(aBorders)): - aBorder = aBorders[i] - print "Face # ", aBorder.myElemId, " : Edge between nodes (", - print aBorder.myPnt1, ", ", aBorder.myPnt2, ")" - - aGroupF.Add([aBorder.myElemId]) - aGroupN.Add([aBorder.myPnt1, aBorder.myPnt2]) - -salome.sg.updateObjBrowser(1) -\endcode +\include quality_controls_ex04.py +Download this script \section 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 +\include quality_controls_ex05.py +Download this script \section 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 - -Mesh_1 = smesh.Mesh(Partition_1) -Regular_1D = Mesh_1.Segment() -Max_Size_1 = Regular_1D.MaxSize(34.641) -MEFISTO_2D = Mesh_1.Triangle() -Tetrahedronn = Mesh_1.Tetrahedron() -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 faces Nb = ", len(aFaceIds) -j = 1 -for i in range(len(aFaceIds)): - if j > 20: j = 1; print "" - print aFaceIds[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 +\include quality_controls_ex06.py +Download this script \section tui_bare_border_faces Bare border faces - -\code -from smesh import * -SetCurrentStudy(salome.myStudy) - -box = geompy.MakeBoxDXDYDZ(100, 100, 100) -geompy.addToStudy( box, "box" ) - -mesh = smesh.Mesh(box) -mesh.Segment().NumberOfSegments(3) -mesh.Quadrangle() -mesh.Compute() - -# remove 2 faces -allFaces = mesh.GetElementsByType(FACE) -mesh.RemoveElements( allFaces[0:2]) - -bareGroup = mesh.MakeGroup("bare faces", FACE, FT_BareBorderFace) -assert(bareGroup.Size() == 3) -\endcode +\include quality_controls_ex07.py +Download this script \section tui_bare_border_volumes Bare border volumes - -\code -from smesh import * -SetCurrentStudy(salome.myStudy) - -box = geompy.MakeBoxDXDYDZ(100, 30, 10) -# the smallest face of the box -face = geompy.SubShapeAllSorted( box, geompy.ShapeType["FACE"])[0] - -geompy.addToStudy( box, "box" ) -geompy.addToStudyInFather( box, face, "face" ) - -mesh = Mesh(box) -mesh.AutomaticHexahedralization(); - -# remove half of mesh faces from the smallest face -faceFaces = mesh.GetSubMeshElementsId(face) -faceToRemove = faceFaces[: len(faceFaces)/2] -mesh.RemoveElements( faceToRemove ) - -# make a group of volumes missing the removed faces -bareGroup = mesh.MakeGroup("bare volumes", VOLUME, FT_BareBorderVolume) -assert(bareGroup.Size() == len( faceToRemove)) -\endcode +\include quality_controls_ex08.py +Download this script \section tui_over_constrained_faces Over-constrained faces -\code -from smesh import * -SetCurrentStudy(salome.myStudy) - -mesh = Mesh() -faceFilter = GetFilter(FACE,FT_OverConstrainedFace) - -#make an edge -n1 = mesh.AddNode(0,0,0) -n2 = mesh.AddNode(10,0,0) -edge = mesh.AddEdge([n1,n2]) -assert( not mesh.GetIdsFromFilter( faceFilter )) - -# make faces -mesh.ExtrusionSweep([edge], MakeDirStruct(0,7,0), 5) -assert( 2 == len( mesh.GetIdsFromFilter( faceFilter ))) -\endcode +\include quality_controls_ex09.py +Download this script \section tui_over_constrained_volumes Over-constrained volumes -\code -from smesh import * -SetCurrentStudy(salome.myStudy) - -mesh = Mesh() -volumeFilter = GetFilter(VOLUME,FT_OverConstrainedVolume) - -# make volumes by extrusion of one face -n1 = mesh.AddNode(0,0,0) -n2 = mesh.AddNode(10,0,0) -edge = mesh.AddEdge([n1,n2]) -mesh.ExtrusionSweep([edge], MakeDirStruct(0,7,0), 1) -mesh.ExtrusionSweep( mesh.GetElementsByType(FACE), MakeDirStruct(0,0,5), 7) -assert( 2 == len( mesh.GetIdsFromFilter( volumeFilter ))) -\endcode +\include quality_controls_ex10.py +Download this script \section tui_length_2d Length 2D - -\code -import salome -import geompy - -import smesh - -# create open shell: a box without one plane -box = geompy.MakeBox(0., 0., 0., 20., 20., 15.) -FaceList = geompy.SubShapeAll(box, geompy.ShapeType["FACE"]) -FaceList.remove(FaceList[5]) -box = geompy.MakeShell(FaceList) -idbox = geompy.addToStudy(box, "box") - -# create a mesh -mesh = smesh.Mesh(box, "Mesh_Length_2D") -algo = mesh.Segment() -algo.NumberOfSegments(5) -algo = mesh.Triangle() -algo.MaxElementArea(20.) -mesh.Compute() - -# Criterion : Length 2D > 5.7 -length_margin = 5.7 - -aFilter = smesh.GetFilter(smesh.FACE, smesh.FT_Length2D, smesh.FT_MoreThan, length_margin) - -anIds = mesh.GetIdsFromFilter(aFilter) - -# print the result -print "Criterion: Edges length 2D > ", length_margin, " Nb = ", len(anIds) -j = 1 -for i in range(len(anIds)): - if j > 20: j = 1; print "" - print anIds[i], - j = j + 1 - pass -print "" - -# create a group -aGroup = mesh.CreateEmptyGroup(smesh.FACE, "Faces with length 2D > " + `length_margin`) -aGroup.Add(anIds) - -salome.sg.updateObjBrowser(1) -\endcode +\include quality_controls_ex11.py +Download this script \section tui_borders_at_multiconnection_2d Borders at Multiconnection 2D - -\code -import salome -import geompy - -import smesh - -# create a compound of two glued boxes -box1 = geompy.MakeBox(0., 0., 0., 20., 20., 15.) -box2 = geompy.MakeTranslation(box1, 0., 20., 0) -comp = geompy.MakeCompound([box1, box2]) -box = geompy.MakeGlueFaces(comp, 0.000001) -idbox = geompy.addToStudy(box, "box") - -# create a mesh -mesh = smesh.Mesh(box, "Box compound : 2D triangle mesh") -algo = mesh.Segment() -algo.NumberOfSegments(5) -algo = mesh.Triangle() -algo.MaxElementArea(20.) -mesh.Compute() - -# Criterion : MULTI-CONNECTION 2D = 3 -nb_conn = 3 - -aFilter = smesh.GetFilter(smesh.FACE, smesh.FT_MultiConnection2D, smesh.FT_EqualTo, nb_conn) - -anIds = mesh.GetIdsFromFilter(aFilter) - -# print the result -print "Criterion: Borders at multi-connection 2D = ", nb_conn, " Nb = ", len(anIds) -j = 1 -for i in range(len(anIds)): - if j > 20: j = 1; print "" - print anIds[i], - j = j + 1 - pass -print "" - -# create a group -aGroup = mesh.CreateEmptyGroup(smesh.FACE, "Borders at multi-connection 2D = " + `nb_conn`) -aGroup.Add(anIds) - -salome.sg.updateObjBrowser(1) -\endcode +\include quality_controls_ex12.py +Download this script \section tui_area Area - -\code -import SMESH_mechanic - -smesh = SMESH_mechanic.smesh -mesh = SMESH_mechanic.mesh -salome = SMESH_mechanic.salome - -# Criterion : AREA > 100. -area_margin = 100. - -aFilter = smesh.GetFilter(smesh.FACE, smesh.FT_Area, smesh.FT_MoreThan, area_margin) - -anIds = mesh.GetIdsFromFilter(aFilter) - -# print the result -print "Criterion: Area > ", area_margin, " Nb = ", len(anIds) -j = 1 -for i in range(len(anIds)): - if j > 20: j = 1; print "" - print anIds[i], - j = j + 1 - pass -print "" - -# create a group -aGroup = mesh.CreateEmptyGroup(smesh.FACE, "Area > " + `area_margin`) -aGroup.Add(anIds) - -salome.sg.updateObjBrowser(1) -\endcode +\include quality_controls_ex13.py +Download this script \section tui_taper Taper - -\code -import SMESH_mechanic - -smesh = SMESH_mechanic.smesh -mesh = SMESH_mechanic.mesh -salome = SMESH_mechanic.salome - -# Criterion : Taper > 3e-20 -taper_margin = 3e-20 - -aFilter = smesh.GetFilter(smesh.FACE, smesh.FT_Taper, smesh.FT_MoreThan, taper_margin) - -anIds = mesh.GetIdsFromFilter(aFilter) - -# print the result -print "Criterion: Taper > ", taper_margin, " Nb = ", len(anIds) -j = 1 -for i in range(len(anIds)): - if j > 20: j = 1; print "" - print anIds[i], - j = j + 1 - pass -print "" - -# create a group -aGroup = mesh.CreateEmptyGroup(smesh.FACE, "Taper > " + `taper_margin`) -aGroup.Add(anIds) - -salome.sg.updateObjBrowser(1) -\endcode +\include quality_controls_ex14.py +Download this script \section tui_aspect_ratio Aspect Ratio - -\code -import SMESH_mechanic - -smesh = SMESH_mechanic.smesh -mesh = SMESH_mechanic.mesh -salome = SMESH_mechanic.salome - -# Criterion : ASPECT RATIO > 1.8 -ar_margin = 1.8 - -aFilter = smesh.GetFilter(smesh.FACE, smesh.FT_AspectRatio, smesh.FT_MoreThan, ar_margin) - -anIds = mesh.GetIdsFromFilter(aFilter) - -# print the result -print "Criterion: Aspect Ratio > ", ar_margin, " Nb = ", len(anIds) -j = 1 -for i in range(len(anIds)): - if j > 20: j = 1; print "" - print anIds[i], - j = j + 1 - pass -print "" - -# create a group -aGroup = mesh.CreateEmptyGroup(smesh.FACE, "Aspect Ratio > " + `ar_margin`) -aGroup.Add(anIds) - -salome.sg.updateObjBrowser(1) -\endcode +\include quality_controls_ex15.py +Download this script \section tui_minimum_angle Minimum Angle - -\code -import SMESH_mechanic - -smesh = SMESH_mechanic.smesh -mesh = SMESH_mechanic.mesh -salome = SMESH_mechanic.salome - -# Criterion : MINIMUM ANGLE < 35. -min_angle = 35. - -aFilter = smesh.GetFilter(smesh.FACE, smesh.FT_MinimumAngle, smesh.FT_LessThan, min_angle) - -anIds = mesh.GetIdsFromFilter(aFilter) - -# print the result -print "Criterion: Minimum Angle < ", min_angle, " Nb = ", len(anIds) -j = 1 -for i in range(len(anIds)): - if j > 20: j = 1; print "" - print anIds[i], - j = j + 1 - pass -print "" - -# create a group -aGroup = mesh.CreateEmptyGroup(smesh.FACE, "Minimum Angle < " + `min_angle`) - -aGroup.Add(anIds) - -salome.sg.updateObjBrowser(1) -\endcode +\include quality_controls_ex16.py +Download this script \section tui_warping Warping - -\code -import SMESH_mechanic - -smesh = SMESH_mechanic.smesh -mesh = SMESH_mechanic.mesh -salome = SMESH_mechanic.salome - -# Criterion : WARP ANGLE > 1e-15 -wa_margin = 1e-15 - -aFilter = smesh.GetFilter(smesh.FACE, smesh.FT_Warping, smesh.FT_MoreThan, wa_margin) - -anIds = mesh.GetIdsFromFilter(aFilter) - -# print the result -print "Criterion: Warp > ", wa_margin, " Nb = ", len(anIds) -j = 1 -for i in range(len(anIds)): - if j > 20: j = 1; print "" - print anIds[i], - j = j + 1 - pass -print "" - -# create a group -aGroup = mesh.CreateEmptyGroup(smesh.FACE, "Warp > " + `wa_margin`) - -aGroup.Add(anIds) - -salome.sg.updateObjBrowser(1) -\endcode +\include quality_controls_ex17.py +Download this script \section tui_skew Skew - -\code -import SMESH_mechanic - -smesh = SMESH_mechanic.smesh -mesh = SMESH_mechanic.mesh -salome = SMESH_mechanic.salome - -# Criterion : Skew > 38. -skew_margin = 38. - -aFilter = smesh.GetFilter(smesh.FACE, smesh.FT_Skew, smesh.FT_MoreThan, skew_margin) - -anIds = mesh.GetIdsFromFilter(aFilter) - -# print the result -print "Criterion: Skew > ", skew_margin, " Nb = ", len(anIds) -j = 1 -for i in range(len(anIds)): - if j > 20: j = 1; print "" - print anIds[i], - j = j + 1 - pass -print "" - -# create a group -aGroup = mesh.CreateEmptyGroup(smesh.FACE, "Skew > " + `skew_margin`) -aGroup.Add(anIds) - -salome.sg.updateObjBrowser(1) -\endcode +\include quality_controls_ex18.py +Download this script \section tui_max_element_length_2d Element Diameter 2D - -\code -import SMESH_mechanic - -smesh = SMESH_mechanic.smesh -mesh = SMESH_mechanic.mesh -salome = SMESH_mechanic.salome - -# Criterion : ELEMENT DIAMETER 2D > 10 -mel_2d_margin = 10 - -aFilter = smesh.GetFilter(smesh.FACE, smesh.FT_MaxElementLength2D, smesh.FT_MoreThan, mel_2d_margin) - -anIds = mesh.GetIdsFromFilter(aFilter) - -# print the result -print "Criterion: Element Diameter 2D Ratio > ", mel_2d_margin, " Nb = ", len(anIds) -j = 1 -for i in range(len(anIds)): - if j > 20: j = 1; print "" - print anIds[i], - j = j + 1 - pass -print "" - -# create a group -aGroup = mesh.CreateEmptyGroup(smesh.FACE, "Element Diameter 2D > " + `mel_2d_margin`) -aGroup.Add(anIds) - -salome.sg.updateObjBrowser(1) -\endcode +\include quality_controls_ex19.py +Download this script \section tui_aspect_ratio_3d Aspect Ratio 3D - -\code -import SMESH_mechanic_tetra - -smesh = SMESH_mechanic_tetra.smesh -mesh = SMESH_mechanic_tetra.mesh -salome = SMESH_mechanic_tetra.salome - -# Criterion : ASPECT RATIO 3D > 4.5 -ar_margin = 4.5 - -aFilter = smesh.GetFilter(smesh.VOLUME, smesh.FT_AspectRatio3D, smesh.FT_MoreThan, ar_margin) - -anIds = mesh.GetIdsFromFilter(aFilter) - -# print the result -print "Criterion: Aspect Ratio 3D > ", ar_margin, " Nb = ", len(anIds) -j = 1 -for i in range(len(anIds)): - if j > 20: j = 1; print "" - print anIds[i], - j = j + 1 - pass -print "" - -# create a group -aGroup = mesh.CreateEmptyGroup(smesh.VOLUME, "Aspect Ratio 3D > " + `ar_margin`) - -aGroup.Add(anIds) - -salome.sg.updateObjBrowser(1) -\endcode +\include quality_controls_ex20.py +Download this script \section tui_volume Volume - -\code -import SMESH_mechanic_tetra - -smesh = SMESH_mechanic_tetra.smesh -mesh = SMESH_mechanic_tetra.mesh -salome = SMESH_mechanic_tetra.salome - -# Criterion : VOLUME < 7. -volume_margin = 7. - -aFilter = smesh.GetFilter(smesh.VOLUME, smesh.FT_Volume3D, smesh.FT_LessThan, volume_margin) - -anIds = mesh.GetIdsFromFilter(aFilter) - -# print the result -print "" -print "Criterion: Volume < ", volume_margin, " Nb = ", len(anIds) -j = 1 -for i in range(len(anIds)): - if j > 20: j = 1; print "" - print anIds[i], - j = j + 1 - pass -print "" - -# create a group -aGroup = mesh.CreateEmptyGroup(smesh.VOLUME, "Volume < " + `volume_margin`) - -aGroup.Add(anIds) - -salome.sg.updateObjBrowser(1) -\endcode +\include quality_controls_ex21.py +Download this script \section tui_max_element_length_3d Element Diameter 3D - -\code -import SMESH_mechanic_tetra - -smesh = SMESH_mechanic_tetra.smesh -mesh = SMESH_mechanic_tetra.mesh -salome = SMESH_mechanic_tetra.salome - -# Criterion : ELEMENT DIAMETER 3D > 10 -mel_3d_margin = 10 - -aFilter = smesh.GetFilter(smesh.FACE, smesh.FT_MaxElementLength3D, smesh.FT_MoreThan, mel_3d_margin) - -anIds = mesh.GetIdsFromFilter(aFilter) - -# print the result -print "Criterion: Element Diameter 3D Ratio > ", mel_3d_margin, " Nb = ", len(anIds) -j = 1 -for i in range(len(anIds)): - if j > 20: j = 1; print "" - print anIds[i], - j = j + 1 - pass -print "" - -# create a group -aGroup = mesh.CreateEmptyGroup(smesh.FACE, "Element Diameter 3D > " + `mel_3d_margin`) -aGroup.Add(anIds) - -salome.sg.updateObjBrowser(1) -\endcode +\include quality_controls_ex22.py +Download this script */ diff --git a/doc/salome/gui/SMESH/input/tui_transforming_meshes.doc b/doc/salome/gui/SMESH/input/tui_transforming_meshes.doc index a4c6df87d..3b77fab34 100644 --- a/doc/salome/gui/SMESH/input/tui_transforming_meshes.doc +++ b/doc/salome/gui/SMESH/input/tui_transforming_meshes.doc @@ -7,580 +7,81 @@
        \anchor tui_translation

        Translation

        - -\code -import SMESH_mechanic - -smesh = SMESH_mechanic.smesh -mesh = SMESH_mechanic.mesh - -# define translation vector -point = smesh.PointStruct(-150., -150., 0.) -vector =smesh.DirStruct(point) - -# translate a mesh -doCopy = 1 - -mesh.Translate([], vector, doCopy) -\endcode +\include transforming_meshes_ex01.py +Download this script
        \anchor tui_rotation

        Rotation

        - -\code -import math - -import SMESH_mechanic - -smesh = SMESH_mechanic.smesh -mesh = SMESH_mechanic.mesh - -# define rotation axis and angle -axisXYZ = smesh.AxisStruct(0., 0., 0., 5., 5., 20.) -angle270 = 1.5 * math.pi - -# rotate a mesh -mesh.Rotate([], axisXYZ, angle270, 1) -\endcode +\include transforming_meshes_ex02.py +Download this script
        \anchor tui_scale

        Scale

        - -\code -import geompy -Box = geompy.MakeBoxDXDYDZ(200, 200, 200) -f = geompy.SubShapeAllSorted(Box, geompy.ShapeType["FACE"]) - -import smesh,SMESH -import StdMeshers -Mesh1 = smesh.Mesh(f[0]) -Regular_1D = Mesh1.Segment() -Nb_Segments_1 = Regular_1D.NumberOfSegments(3) -Nb_Segments_1.SetDistrType( 0 ) -Quadrangle_2D = Mesh1.Quadrangle() -isDone = Mesh1.Compute() - -#Perform scale opration for the whole mesh and creation of a new mesh -newMesh = Mesh1.ScaleMakeMesh(Mesh1,SMESH.PointStruct(100,100,200),[0.5,0.3,0.7],True,"ScaledMesh") - -#Perform scale operation for the whole mesh and copy elements -Mesh1.Scale(Mesh1,SMESH.PointStruct(200,100,100),[0.5,0.5,0.5],True,True) - -#Perform scale opration for two edges and move elements -Mesh1.Scale([1,2],SMESH.PointStruct(-100,100,100),[0.8,1.0,0.7],False) - -#Perform scale opration for one face and move elements -Mesh1.Scale([21],SMESH.PointStruct(0,200,200),[0.7,0.7,0.7],False) -\endcode +\include transforming_meshes_ex03.py +Download this script
        \anchor tui_symmetry

        Symmetry

        - -\code -import math - -import SMESH_mechanic - -smesh = SMESH_mechanic.smesh -mesh = SMESH_mechanic.mesh - -# create a symmetrical copy of the mesh mirrored through a point -axis = SMESH.AxisStruct(0, 0, 0, 0, 0, 0) - -mesh.Mirror([], axis, smesh.POINT, 1) -\endcode +\include transforming_meshes_ex04.py +Download this script
        \anchor tui_merging_nodes

        Merging Nodes

        - -\code -import SMESH_mechanic -mesh = SMESH_mechanic.mesh - -# merge nodes -Tolerance = 25.0 - -GroupsOfNodes = mesh.FindCoincidentNodes(Tolerance) -mesh.MergeNodes(GroupsOfNodes) -\endcode +\include transforming_meshes_ex05.py +Download this script
        \anchor tui_merging_elements

        Merging Elements

        - -\code -import salome -import geompy -import smesh - -# create a face to be meshed -px = geompy.MakeVertex(100., 0. , 0. ) -py = geompy.MakeVertex(0. , 100., 0. ) -pz = geompy.MakeVertex(0. , 0. , 100.) - -vxy = geompy.MakeVector(px, py) -arc = geompy.MakeArc(py, pz, px) - -wire = geompy.MakeWire([vxy, arc]) -isPlanarFace = 1 - -face1 = geompy.MakeFace(wire, isPlanarFace) -id_face1 = geompy.addToStudy(face1, "Face1") - -# create a circle to be an extrusion path -px1 = geompy.MakeVertex( 100., 100., 0.) -py1 = geompy.MakeVertex(-100., -100., 0.) -pz1 = geompy.MakeVertex( 0., 0., 50.) - -circle = geompy.MakeCircleThreePnt(py1, pz1, px1) -id_circle = geompy.addToStudy(circle, "Path") - -# create a 2D mesh on the face -trias = smesh.Mesh(face1, "Face : 2D mesh") - -algo1D = trias.Segment() -algo1D.NumberOfSegments(6) -algo2D = trias.Triangle() -algo2D.LengthFromEdges() - -trias.Compute() - -# create a path mesh -circlemesh = smesh.Mesh(circle, "Path mesh") -algo = circlemesh.Segment() -algo.NumberOfSegments(10) -circlemesh.Compute() - -# extrusion of the mesh -trias.ExtrusionAlongPath([], circlemesh, circle, - 1, 0, [], 0, smesh.PointStruct(0, 0, 0)) - -# merge nodes -print "Number of nodes before MergeNodes:", -trias.NbNodes() -tolerance = 0.001 -array_of_nodes_groups = trias.FindCoincidentNodes(tolerance) - -trias.MergeNodes(array_of_nodes_groups) - -print "Number of nodes after MergeNodes:", trias.NbNodes() -print "" -print "Number of elements before MergeEqualElements:" -print "Edges : ", trias.NbEdges() -print "Triangles : ", trias.NbTriangles() -print "Quadrangles: ", trias.NbQuadrangles() -print "Volumes : ", trias.NbVolumes() - -# merge elements -trias.MergeEqualElements() -print "Number of elements after MergeEqualElements:" -print "Edges : ", trias.NbEdges() -print "Triangles : ", trias.NbTriangles() -print "Quadrangles: ", trias.NbQuadrangles() -print "Volumes : ", trias.NbVolumes() - -salome.sg.updateObjBrowser(1) -\endcode +\include transforming_meshes_ex06.py +Download this script

        Sewing Meshes


        \anchor tui_sew_meshes_border_to_side

        Sew Meshes Border to Side

        - -\code -import geompy -import smesh - -# create two faces of a box -box1 = geompy.MakeBox(0., 0., -10., 30., 20., 25.) -facesList1 = geompy.SubShapeAll(box1, geompy.ShapeType["FACE"]) -face1 = facesList1[2] - -box2 = geompy.MakeBox(0., 5., 0., 20., 20., 15.) -facesList2 = geompy.SubShapeAll(box2, geompy.ShapeType["FACE"]) -face2 = facesList2[1] - -edgesList = geompy.SubShapeAll(face2, geompy.ShapeType["EDGE"]) -edge1 = edgesList[2] - -aComp = geompy.MakeCompound([face1, face2]) -geompy.addToStudy(aComp, "Two faces") - -# create a mesh on two faces -mesh = smesh.Mesh(aComp, "Two faces : quadrangle mesh") - -algo1D = mesh.Segment() -algo1D.NumberOfSegments(9) -algo2D = mesh.Quadrangle() - -algo_local = mesh.Segment(edge1) -algo_local.Arithmetic1D(1, 4) -algo_local.Propagation() - -mesh.Compute() - -# sew border to side -# FirstNodeIDOnFreeBorder, SecondNodeIDOnFreeBorder, LastNodeIDOnFreeBorder, -# FirstNodeIDOnSide, LastNodeIDOnSide, -# CreatePolygons, CreatePolyedrs -mesh.SewBorderToSide(5, 45, 6, 113, 109, 0, 0) -\endcode +\include transforming_meshes_ex07.py +Download this script
        \anchor tui_sew_conform_free_borders

        Sew Conform Free Borders

        - -\code -import geompy -import smesh - -# create two faces of the box -box1 = geompy.MakeBox(0., 0., -10., 20., 20., 15.) -facesList1 = geompy.SubShapeAll(box1, geompy.ShapeType["FACE"]) -face1 = facesList1[2] - -box2 = geompy.MakeBox(0., 5., 0., 20., 20., 15.) -facesList2 = geompy.SubShapeAll(box2, geompy.ShapeType["FACE"]) -face2 = facesList2[1] - -edgesList = geompy.SubShapeAll(face2, geompy.ShapeType["EDGE"]) -edge1 = edgesList[2] - -aComp = geompy.MakeCompound([face1, face2]) -geompy.addToStudy(aComp, "Two faces") - -# create a mesh on two faces -mesh = smesh.Mesh(aComp, "Two faces : quadrangle mesh") - -algo1D = mesh.Segment() -algo1D.NumberOfSegments(9) -algo2D = mesh.Quadrangle() - -algo_local = mesh.Segment(edge1) -algo_local.Arithmetic1D(1, 4) -algo_local.Propagation() - -mesh.Compute() - -# sew conform free borders -# FirstNodeID1, SecondNodeID1, LastNodeID1, FirstNodeID2, SecondNodeID2 -mesh.SewConformFreeBorders(5, 45, 6, 3, 24) -\endcode +\include transforming_meshes_ex08.py +Download this script
        \anchor tui_sew_free_borders

        Sew Free Borders

        - -\code -import geompy -import smesh - -# create two faces of the box -box1 = geompy.MakeBox(0., 0., 0., 20., 20., 15.) -facesList1 = geompy.SubShapeAll(box1, geompy.ShapeType["FACE"]) -face1 = facesList1[2] - -box2 = geompy.MakeBox(0., 5., 0., 20., 20., 15.) -facesList2 = geompy.SubShapeAll(box2, geompy.ShapeType["FACE"]) -face2 = facesList2[1] - -edgesList = geompy.SubShapeAll(face2, geompy.ShapeType["EDGE"]) -edge1 = edgesList[2] - -aComp = geompy.MakeCompound([face1, face2]) -geompy.addToStudy(aComp, "Two faces") - -# create a mesh on two faces -mesh = smesh.Mesh(aComp, "Two faces : quadrangle mesh") - -algo1D = mesh.Segment() -algo1D.NumberOfSegments(4) -algo2D = mesh.Quadrangle() - -algo_local = mesh.Segment(edge1) -algo_local.Arithmetic1D(1, 4) -algo_local.Propagation() - -mesh.Compute() - -# sew free borders -# FirstNodeID1, SecondNodeID1, LastNodeID1, -# FirstNodeID2, SecondNodeID2, LastNodeID2, CreatePolygons, CreatePolyedrs -mesh.SewFreeBorders(6, 21, 5, 1, 12, 3, 0, 0) -\endcode +\include transforming_meshes_ex09.py +Download this script
        \anchor tui_sew_side_elements

        Sew Side Elements

        - -\code -import geompy -import smesh - -# create two boxes -box1 = geompy.MakeBox(0., 0., 0., 10., 10., 10.) -box2 = geompy.MakeBox(0., 15., 0., 20., 25., 10.) - -EdgesList = geompy.SubShapeAll(box2, geompy.ShapeType["EDGE"]) - -aComp = geompy.MakeCompound([box1, box2]) -geompy.addToStudy(aComp, "Two boxes") - -# create a mesh on two boxes -mesh = smesh.Mesh(aComp, "Two faces : quadrangle mesh") - -algo1D = mesh.Segment() -algo1D.NumberOfSegments(2) -algo2D = mesh.Quadrangle() - -algo_local = mesh.Segment(EdgesList[8]) -algo_local.NumberOfSegments(4) -algo_local.Propagation() - -mesh.Compute() - -# sew side elements -# IDsOfSide1Elements, IDsOfSide2Elements, -# NodeID1OfSide1ToMerge, NodeID1OfSide2ToMerge, NodeID2OfSide1ToMerge, NodeID2OfSide2ToMerge -mesh.SewSideElements([69, 70, 71, 72], [91, 92, 89, 90], 8, 38, 23, 58) -\endcode +\include transforming_meshes_ex10.py +Download this script
        \anchor tui_duplicate_nodes

        Duplicate nodes

        - -\code -import salome -import smesh -import SMESH_test1 - -mesh = SMESH_test1.mesh - -# Compute mesh -mesh.Compute() - -# Without the duplication of border elements - -# Nodes to duplicate -nodes1 = mesh.CreateEmptyGroup( smesh.NODE, 'nodes1' ) -nodes1.Add( [ 289, 278, 302, 285 ] ) - -# Group of faces to replace nodes with new ones -faces1 = mesh.CreateEmptyGroup( smesh.FACE, 'faces1' ) -faces1.Add( [ 519, 556, 557 ] ) - -# Duplicate nodes -print "\nMesh before the first nodes duplication:" -print "Nodes : ", mesh.NbNodes() -print "Edges : ", mesh.NbEdges() -print "Triangles : ", mesh.NbTriangles() - -groupOfCreatedNodes = mesh.DoubleNodeGroup(nodes1, faces1, theMakeGroup=True) -print "New nodes:", groupOfCreatedNodes.GetIDs() - -print "\nMesh after the first nodes duplication:" -print "Nodes : ", mesh.NbNodes() -print "Edges : ", mesh.NbEdges() -print "Triangles : ", mesh.NbTriangles() - -# With the duplication of border elements - -# Edges to duplicate -edges = mesh.CreateEmptyGroup( smesh.EDGE, 'edges' ) -edges.Add( [ 29, 30, 31 ] ) - -# Nodes not to duplicate -nodes2 = mesh.CreateEmptyGroup( smesh.NODE, 'nodes2' ) -nodes2.Add( [ 32, 5 ] ) - -# Group of faces to replace nodes with new ones -faces2 = mesh.CreateEmptyGroup( smesh.FACE, 'faces2' ) -faces2.Add( [ 576, 578, 580 ] ) - -# Duplicate nodes -print "\nMesh before the second nodes duplication:" -print "Nodes : ", mesh.NbNodes() -print "Edges : ", mesh.NbEdges() -print "Triangles : ", mesh.NbTriangles() - -groupOfNewEdges = mesh.DoubleNodeElemGroup( edges, nodes2, faces2, theMakeGroup=True ) -print "New edges:", groupOfNewEdges.GetIDs() - -print "\nMesh after the second nodes duplication:" -print "Nodes : ", mesh.NbNodes() -print "Edges : ", mesh.NbEdges() -print "Triangles : ", mesh.NbTriangles() - -# Update object browser -if salome.sg.hasDesktop(): - salome.sg.updateObjBrowser(0) -\endcode +\include transforming_meshes_ex11.py +Download this script
        \anchor tui_make_2dmesh_from_3d

        Create boundary elements

        - -\code -from smesh import * -SetCurrentStudy(salome.myStudy) - -box = geompy.MakeBoxDXDYDZ(100, 100, 100) -gFaces = geompy.SubShapeAllSorted(box, geompy.ShapeType["FACE"]) -f1,f2 = gFaces[0],gFaces[1] -geompy.addToStudy(box,"box") -geompy.addToStudyInFather(box,f1,"face1") -geompy.addToStudyInFather(box,f2,"face2") - -twoFaces = geompy.MakeCompound([f1,f2]) - -## ----------- -## -## 2D from 3D -## -## ----------- -dim = SMESH.BND_2DFROM3D - -init_mesh = Mesh(box, "box") -init_mesh.AutomaticHexahedralization() # it makes 3 x 3 x 3 hexahedrons - -# remove some faces -faces = init_mesh.GetElementsByType( SMESH.FACE ) -nb_faces = len( faces ) -rm_face = faces[ : nb_faces/2] -init_mesh.RemoveElements( rm_face ) - -# restore boundary in this mesh -mesh = CopyMesh( init_mesh, "2D from 3D") -groupName = "bnd 2D" -nb, new_mesh, new_group = mesh.MakeBoundaryElements(dim, groupName) - -# restore boundary (only) in other mesh -meshName = "2D boundary of " + init_mesh.GetName() -nb, new_mesh, new_group = init_mesh.MakeBoundaryElements(dim, groupName, meshName) - -# restore boundary in mesh copy -meshName = init_mesh.GetName() + " + boundary" -nb, new_mesh, new_group = init_mesh.MakeBoundaryElements(dim, groupName, meshName, toCopyAll=True) - - -## ----------- -## -## 1D from 2D -## -## ----------- -dim = SMESH.BND_1DFROM2D - -init_mesh = Mesh(f1, "2D mesh") -init_mesh.AutomaticHexahedralization() - -# remove some edges -edges = init_mesh.GetElementsByType( SMESH.EDGE ) -nb_edges = len( edges ) -rm_edge = edges[ : nb_edges/2] -init_mesh.RemoveElements( rm_edge ) - - -# restore boundary edges in this mesh -mesh = CopyMesh( init_mesh, "1D from 2D") -groupName = "bnd 1D" -nb, new_mesh, new_group = mesh.MakeBoundaryElements(dim, groupName) - -# restore boundary edges (only) in other mesh -meshName = "1D boundary of " + init_mesh.GetName() -nb, new_mesh, new_group = init_mesh.MakeBoundaryElements(dim, groupName, meshName) - -# restore boundary edges in mesh copy -meshName = init_mesh.GetName() + " + boundary" -nb, new_mesh, new_group = init_mesh.MakeBoundaryElements(dim, groupName, meshName, toCopyAll=True) - - - -## ------------------ -## -## 1D from 2D GROUPS -## -## ------------------ -dim = SMESH.BND_1DFROM3D - -init_mesh = Mesh(box, "box") -init_mesh.AutomaticHexahedralization() # it makes 3 x 3 x 3 hexahedrons -# remove all edges -rm_edges = init_mesh.GetElementsByType( SMESH.EDGE ) -init_mesh.RemoveElements( rm_edges ) - -# make groups of faces -fGroup1 = init_mesh.Group( f1, "f1" ) -fGroup2 = init_mesh.Group( f2, "f2" ) - -# make 1D boundary around groups in this mesh -mesh = CopyMesh( init_mesh, "1D from 2D groups", toCopyGroups=True) -groups = mesh.GetGroups() -nb, new_mesh, new_group = mesh.MakeBoundaryElements(dim, groupName,groups=groups) - -# make 1D boundary (only) in other mesh -meshName = "boundary from groups of " + init_mesh.GetName() -groups = init_mesh.GetGroups() -nb, new_mesh, new_group = init_mesh.MakeBoundaryElements(dim, groupName, meshName,groups=groups) - -# make 1D boundary in mesh copy -meshName = init_mesh.GetName() + " + boundary from groups" -nb, new_mesh, new_group = init_mesh.MakeBoundaryElements(dim, groupName, meshName, - groups=groups, toCopyAll=True) - -\endcode +\include transforming_meshes_ex12.py +Download this script
        \anchor tui_reorient_faces

        Reorient faces by vector

        - -\code -import smesh, geompy, SMESH - -# create a geometry consisting of two faces -box = geompy.MakeBoxDXDYDZ( 10, 10, 10 ) -faces = geompy.SubShapeAllSorted( box, geompy.ShapeType["FACE"]) - -shape = geompy.MakeCompound( faces[:2] ) -faces = geompy.SubShapeAll( shape, geompy.ShapeType["FACE"] ) -geompy.addToStudy( shape, "shape") -geompy.addToStudyInFather( shape, faces[0], "faces[0]") -geompy.addToStudyInFather( shape, faces[1], "faces[1]") - -# create a 2D mesh -mesh = smesh.Mesh( shape, "test_Reorient2D") -mesh.AutomaticHexahedralization(0.5) -localAlgo = mesh.Segment(faces[0]) -localAlgo.NumberOfSegments( 11 ) -mesh.Compute() -group = mesh.Group( faces[1] ) - -vec = geompy.MakeVectorDXDYDZ( 1, 1, 1 ) - -# Each of arguments of Reorient2D() function can be of different types: -# -# 2DObject - the whole mesh -# Direction - a GEOM object (vector) -# FaceOrPoint - an ID of face -mesh.Reorient2D( mesh, vec, mesh.NbElements() ) -# -# 2DObject - a sub-mesh -# Direction - components of a vector -# FaceOrPoint - a GEOM object (vertex) -mesh.Reorient2D( localAlgo.GetSubMesh(), [ 1, -1, 1 ], geompy.GetFirstVertex( vec )) -# -# 2DObject - a group of faces -# Direction - a SMESH.DirStruct structure -# FaceOrPoint - coordinates of a point -mesh.Reorient2D( group, smesh.MakeDirStruct( -10, 1, 10 ), [0,0,0]) -# -# FaceOrPoint - a SMESH.PointStruct structure -mesh.Reorient2D( localAlgo.GetSubMesh().GetIDs(), [10,1,0], SMESH.PointStruct(0,0,0)) - -\endcode +\include transforming_meshes_ex13.py +Download this script */ diff --git a/doc/salome/gui/SMESH/input/tui_use_existing_faces.doc b/doc/salome/gui/SMESH/input/tui_use_existing_faces.doc index 0f95ac4d4..46dfe1e05 100644 --- a/doc/salome/gui/SMESH/input/tui_use_existing_faces.doc +++ b/doc/salome/gui/SMESH/input/tui_use_existing_faces.doc @@ -6,117 +6,8 @@ This sample demonstrates how to use Use existing faces algorithm, which is actulally just a stub allowing to use your own 2D algoritm implemented in Python. - -\code -import smesh, geompy -import numpy as np - -# define my 2D algorithm -def my2DMeshing( geomFace ): - - # find gravity center of geomFace - gcXYZ = geompy.PointCoordinates( geompy.MakeCDG( geomFace )) - - # define order and orientation of edges - sortedEdges = [] - geomEdges = geompy.SubShapeAll( geomFace, geompy.ShapeType["EDGE"]) - sortedEdges.append(( geomEdges.pop(0), True )) - while geomEdges: - prevEdge_rev = sortedEdges[ -1 ] - prevVV = geompy.SubShapeAll( prevEdge_rev[0], geompy.ShapeType["VERTEX"]) - prevV2 = prevVV[ prevEdge_rev[1] ] - found = False - for iE in range( len( geomEdges )): - v1,v2 = geompy.SubShapeAll( geomEdges[ iE ], geompy.ShapeType["VERTEX"]) - same1,same2 = [( geompy.MinDistance( prevV2, v ) < 1e-7 ) for v in [v1,v2] ] - if not same1 and not same2: continue - sortedEdges.append(( geomEdges.pop( iE ), same1 )) - found = True - break - assert found - sortedEdges.reverse() - - # put nodes on edges in a right order - nodes = [] - for edge, isForward in sortedEdges: - v1,v2 = geompy.SubShapeAll( edge, geompy.ShapeType["VERTEX"]) - edgeNodes = mesh.GetSubMeshNodesId( v2, all=False ) + \ - mesh.GetSubMeshNodesId( edge, all=False ) + \ - mesh.GetSubMeshNodesId( v1, all=False ) - if not isForward: edgeNodes.reverse() - nodes.extend( edgeNodes[:-1] ) - - # create nodes inside the geomFace - r1 = 0.6 - r2 = 1 - r1 - nodesInside = [] - for n in nodes: - nXYZ = mesh.GetNodeXYZ( n ) - newXYZ = np.add( np.multiply( r1, gcXYZ ), np.multiply( r2, nXYZ )) - nodesInside.append( mesh.AddNode( newXYZ[0], newXYZ[1], newXYZ[2] )) - mesh.SetNodeOnFace( nodesInside[-1], geomFace, 0, 0 ) - - # find out orientation of faces to create - # geomFace normal - faceNorm = geompy.GetNormal( geomFace ) - v1,v2 = [ geompy.PointCoordinates( v ) \ - for v in geompy.SubShapeAll( faceNorm, geompy.ShapeType["VERTEX"]) ] - faceNormXYZ = np.subtract( v2, v1 ) - outDirXYZ = np.subtract( v1, [ 50, 50, 50 ] ) - if np.dot( faceNormXYZ, outDirXYZ ) < 0: # reversed face - faceNormXYZ = np.multiply( -1., faceNormXYZ ) - # mesh face normal - e1 = np.subtract( mesh.GetNodeXYZ( nodes[0] ), mesh.GetNodeXYZ( nodes[1] )) - e2 = np.subtract( mesh.GetNodeXYZ( nodes[0] ), mesh.GetNodeXYZ( nodesInside[0] )) - meshNorm = np.cross( e1, e2 ) - # faces orientation - reverse = ( np.dot( faceNormXYZ, meshNorm ) < 0 ) - - # create mesh faces - iN = len( nodes ) - while iN: - n1, n2, n3, n4 = nodes[iN-1], nodes[iN-2], nodesInside[iN-2], nodesInside[iN-1] - iN -= 1 - if reverse: - f = mesh.AddFace( [n1, n2, n3, n4] ) - else: - f = mesh.AddFace( [n4, n3, n2, n1] ) - # new faces must be assigned to geometry to allow 3D algorithm finding them - mesh.SetMeshElementOnShape( f, geomFace ) - - if reverse: - nodesInside.reverse() - polygon = mesh.AddPolygonalFace( nodesInside ) - mesh.SetMeshElementOnShape( polygon, geomFace ) - - return - -# create geometry and get faces to mesh with my2DMeshing() -box = geompy.MakeBoxDXDYDZ( 100, 100, 100 ) -f1 = geompy.SubShapeAll( box, geompy.ShapeType["FACE"])[0] -f2 = geompy.GetOppositeFace( box, f1 ) -geompy.addToStudy( box, "box" ) -geompy.addToStudy( f1, "f1" ) -geompy.addToStudy( f2, "f2" ) - -# compute 1D mesh -mesh = smesh.Mesh( box ) -mesh.Segment().NumberOfSegments( 5 ) -mesh.Compute() - -# compute 2D mesh -mesh.Quadrangle() -mesh.UseExistingFaces(f1) # UseExistingFaces() allows using my2DMeshing() -mesh.UseExistingFaces(f2) -my2DMeshing( f1 ) -my2DMeshing( f2 ) -assert mesh.Compute() - -# compute 3D mesh -mesh.Prism() -assert mesh.Compute() - -\endcode +\include use_existing_faces.py +Download this script Resulting mesh: \image html use_existing_face_sample_mesh.png diff --git a/doc/salome/gui/SMESH/input/tui_viewing_meshes.doc b/doc/salome/gui/SMESH/input/tui_viewing_meshes.doc index fc0094e4b..06586ffea 100644 --- a/doc/salome/gui/SMESH/input/tui_viewing_meshes.doc +++ b/doc/salome/gui/SMESH/input/tui_viewing_meshes.doc @@ -5,135 +5,13 @@
        \anchor tui_viewing_mesh_infos

        Viewing Mesh Infos

        - -\code -import geompy -import smesh -import SMESH - -# create a box -box = geompy.MakeBox(0., 0., 0., 20., 20., 20.) -geompy.addToStudy(box, "box") -[Face_1,Face_2,Face_3,Face_4,Face_5,Face_5] = geompy.SubShapeAll(box, geompy.ShapeType["FACE"]) - -# create a mesh -tetra = smesh.Mesh(box, "MeshBox") - -algo1D = tetra.Segment() -algo1D.NumberOfSegments(3) - -algo2D = tetra.Triangle() -algo2D.MaxElementArea(10.) - -algo3D = tetra.Tetrahedron() -algo3D.MaxElementVolume(900.) - -# Creation of SubMesh -Regular_1D_1_1 = tetra.Segment(geom=Face_1) -Nb_Segments_1 = Regular_1D_1_1.NumberOfSegments(5) -Nb_Segments_1.SetDistrType( 0 ) -Quadrangle_2D = tetra.Quadrangle(geom=Face_1) -isDone = tetra.Compute() -submesh = Regular_1D_1_1.GetSubMesh() - -# compute the mesh -tetra.Compute() - -# Creation of group -group = tetra.CreateEmptyGroup( SMESH.FACE, 'Group' ) -nbAdd = group.Add( [ 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76 ] ) - -# Print information about the mesh -print "Information about mesh:" -print "Number of nodes : ", tetra.NbNodes() -print "Number of edges : ", tetra.NbEdges() -print "Number of faces : ", tetra.NbFaces() -print " triangles : ", tetra.NbTriangles() -print " quadrangles : ", tetra.NbQuadrangles() -print " polygons : ", tetra.NbPolygons() -print "Number of volumes : ", tetra.NbVolumes() -print " tetrahedrons: ", tetra.NbTetras() -print " hexahedrons : ", tetra.NbHexas() -print " prisms : ", tetra.NbPrisms() -print " pyramids : ", tetra.NbPyramids() -print " polyhedrons : ", tetra.NbPolyhedrons() - -# Get Information About Mesh by GetMeshInfo -print "\nInformation about mesh by GetMeshInfo:" -info = smesh.GetMeshInfo(tetra) -keys = info.keys(); keys.sort() -for i in keys: - print " %s : %d" % ( i, info[i] ) - pass - -# Get Information About Group by GetMeshInfo -print "\nInformation about group by GetMeshInfo:" -info = smesh.GetMeshInfo(group) -keys = info.keys(); keys.sort() -for i in keys: - print " %s : %d" % ( i, info[i] ) - pass - -# Get Information About SubMesh by GetMeshInfo -print "\nInformation about Submesh by GetMeshInfo:" -info = smesh.GetMeshInfo(submesh) -keys = info.keys(); keys.sort() -for i in keys: - print " %s : %d" % ( i, info[i] ) - pass -\endcode - - +\include viewing_meshes_ex01.py +Download this script
        \anchor tui_find_element_by_point

        Find Element by Point

        - -\code -import geompy -import smesh -import SMESH - -# Create a geometry to mesh -box = geompy.MakeBoxDXDYDZ(100,100,100) - -# Create a mesh -mesh = Mesh(box,"Mesh") -mesh.AutomaticHexahedralization() -mesh.Compute() - -# Create a point -x,y,z = 0, 0, 1 - -# Find all elements (except 0D ones) located at the point -all_elems_except_0D = mesh.FindElementsByPoint(x,y,z) -assert( len(all_elems_except_0D) == 4) - -# Find nodes at the point -nodes = mesh.FindElementsByPoint(x,y,z, SMESH.NODE ) -assert( len(nodes) == 0) -assert( len( mesh.FindElementsByPoint(x,y,0, SMESH.NODE)) == 1) - -# Find an edge at the point -edges = mesh.FindElementsByPoint(x,y,z, SMESH.EDGE ) -assert( len(edges) == 1) - -# Find faces at the point -edges = mesh.FindElementsByPoint(x,y,z, SMESH.FACE ) -assert( len(edges) == 2) - -# Find a volume at the point -vols = mesh.FindElementsByPoint(x,y,z, SMESH.VOLUME ) -assert( len(vols) == 1) - -# Find 0D elements at the point -elems0d = mesh.FindElementsByPoint(x,y,z, SMESH.ELEM0D ) -assert( len(elems0d) == 0) - -# Find edges within a group -group1D = mesh.MakeGroupByIds("1D", SMESH.EDGE, [1,2] ) -edges = mesh.FindElementsByPoint(x,y,z, SMESH.EDGE, group1D ) - -\endcode +\include viewing_meshes_ex02.py +Download this script */ diff --git a/doc/salome/gui/SMESH/input/use_existing_algos.doc b/doc/salome/gui/SMESH/input/use_existing_algos.doc index 3634ccf60..b568a94dd 100644 --- a/doc/salome/gui/SMESH/input/use_existing_algos.doc +++ b/doc/salome/gui/SMESH/input/use_existing_algos.doc @@ -40,7 +40,10 @@ the same groups as in the imported source mesh. Use Existing 2D Elements algorithm allows to define the mesh of a geometrical face (or group of faces) -by importing mesh faces contained in a group (or groups) from another mesh. +by importing mesh faces contained in a group (or groups) from another +(or this) mesh. 1D elements on the boundary of the geometrical face +(if not yet present) are also created by the algorithm according to be conformal +with the created 2D elements. \n To apply this algorithm select the geometrical face to be meshed (indicated in the field \b Geometry of Create mesh dialog box), Use existing 2D elements in the list of 2D algorithms and click the diff --git a/idl/SMESH_Filter.idl b/idl/SMESH_Filter.idl index 8cc7bc864..2c701fc2b 100644 --- a/idl/SMESH_Filter.idl +++ b/idl/SMESH_Filter.idl @@ -115,7 +115,7 @@ module SMESH { double GetValue( in long theElementId ); - Histogram GetHistogram( in short nbIntervals ); + Histogram GetHistogram( in short nbIntervals, in boolean isLogarithmic ); /*! * Set precision for calculation. It is a position after point which is diff --git a/idl/SMESH_Mesh.idl b/idl/SMESH_Mesh.idl index 56f465e45..33c775e38 100644 --- a/idl/SMESH_Mesh.idl +++ b/idl/SMESH_Mesh.idl @@ -110,6 +110,14 @@ module SMESH double_array params; // [U] on EDGE, [U,V] on FACE, [] on the rest shapes }; + /*! + * Element location on a shape + */ + struct ElementPosition { + long shapeID; + GEOM::shape_type shapeType; + }; + /*! * Enumeration for element type, like in SMDS */ @@ -220,6 +228,7 @@ module SMESH DRS_WARN_RENUMBER, // a MED file has overlapped ranges of element numbers, // so the numbers from the file are ignored DRS_WARN_SKIP_ELEM, // some elements were skipped due to incorrect file data + DRS_WARN_DESCENDING, // some elements were skipped due to descending connectivity DRS_FAIL // general failure (exception etc.) }; @@ -505,8 +514,6 @@ module SMESH Hypothesis_Status AddHypothesis(in GEOM::GEOM_Object aSubObject, in SMESH_Hypothesis anHyp) raises (SALOME::SALOME_Exception); -// boolean AddHypothesis(in SMESH_subMesh aSubMesh, in SMESH_Hypothesis anHyp) -// raises (SALOME::SALOME_Exception); /*! * Remove an hypothesis previouly added with AddHypothesis. @@ -514,17 +521,12 @@ module SMESH Hypothesis_Status RemoveHypothesis(in GEOM::GEOM_Object aSubObject, in SMESH_Hypothesis anHyp) raises (SALOME::SALOME_Exception); -// boolean RemoveHypothesis(in SMESH_subMesh aSubMesh, -// in SMESH_Hypothesis anHyp) -// raises (SALOME::SALOME_Exception); /*! * Get the list of hypothesis added on a sub-shape */ ListOfHypothesis GetHypothesisList(in GEOM::GEOM_Object aSubObject) raises (SALOME::SALOME_Exception); -// ListOfHypothesis GetHypothesisList(in SMESH_subMesh aSubMesh) -// raises (SALOME::SALOME_Exception); /*! * Get the log of nodes and elements added or removed since previous @@ -532,8 +534,6 @@ module SMESH * @params * - clearAfterGet : log is emptied after Get (safe if concurrents access) */ - // string_array GetLog(in boolean clearAfterGet) - // raises (SALOME::SALOME_Exception); log_array GetLog(in boolean clearAfterGet) raises (SALOME::SALOME_Exception); @@ -836,6 +836,11 @@ module SMESH */ NodePosition GetNodePosition(in long NodeID); + /*! + * \brief Return position of an element on shape + */ + ElementPosition GetElementPosition(in long ElemID); + /*! * If given element is node returns IDs of shape from position * If there is not node for given ID - returns -1 diff --git a/resources/SalomeApp.xml.in b/resources/SalomeApp.xml.in index 20be22917..efad182db 100644 --- a/resources/SalomeApp.xml.in +++ b/resources/SalomeApp.xml.in @@ -81,7 +81,11 @@ + + + + @@ -90,6 +94,10 @@ + + + + diff --git a/src/Controls/SMESH_Controls.cxx b/src/Controls/SMESH_Controls.cxx index 3e44afe28..239aa41e4 100644 --- a/src/Controls/SMESH_Controls.cxx +++ b/src/Controls/SMESH_Controls.cxx @@ -18,7 +18,6 @@ // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com -// #include "SMESH_ControlsDef.hxx" @@ -322,12 +321,12 @@ double NumericalFunctor::Round( const double & aVal ) * \param minmax - boundaries of diapason of values to divide into intervals */ //================================================================================ - void NumericalFunctor::GetHistogram(int nbIntervals, std::vector& nbEvents, std::vector& funValues, const vector& elements, - const double* minmax) + const double* minmax, + const bool isLogarithmic) { if ( nbIntervals < 1 || !myMesh || @@ -380,8 +379,15 @@ void NumericalFunctor::GetHistogram(int nbIntervals, for ( int i = 0; i < nbIntervals; ++i ) { // find end value of i-th interval - double r = (i+1) / double( nbIntervals ); - funValues[i+1] = funValues.front() * (1-r) + funValues.back() * r; + double r = (i+1) / double(nbIntervals); + if (isLogarithmic && funValues.front() > 1e-07 && funValues.back() > 1e-07) { + double logmin = log10(funValues.front()); + double lval = logmin + r * (log10(funValues.back()) - logmin); + funValues[i+1] = pow(10.0, lval); + } + else { + funValues[i+1] = funValues.front() * (1-r) + funValues.back() * r; + } // count values in the i-th interval if there are any if ( min != values.end() && *min <= funValues[i+1] ) @@ -3671,23 +3677,11 @@ ElementsOnShape::ElementsOnShape() myToler(Precision::Confusion()), myAllNodesFlag(false) { - myCurShapeType = TopAbs_SHAPE; } ElementsOnShape::~ElementsOnShape() { -} - -void ElementsOnShape::SetMesh (const SMDS_Mesh* theMesh) -{ - myMeshModifTracer.SetMesh( theMesh ); - if ( myMeshModifTracer.IsMeshModified()) - SetShape(myShape, myType); -} - -bool ElementsOnShape::IsSatisfy (long theElementId) -{ - return myIds.Contains(theElementId); + clearClassifiers(); } SMDSAbs_ElementType ElementsOnShape::GetType() const @@ -3710,169 +3704,163 @@ double ElementsOnShape::GetTolerance() const void ElementsOnShape::SetAllNodes (bool theAllNodes) { - if (myAllNodesFlag != theAllNodes) { - myAllNodesFlag = theAllNodes; - SetShape(myShape, myType); - } + myAllNodesFlag = theAllNodes; +} + +void ElementsOnShape::SetMesh (const SMDS_Mesh* theMesh) +{ + myMesh = theMesh; } void ElementsOnShape::SetShape (const TopoDS_Shape& theShape, const SMDSAbs_ElementType theType) { - myType = theType; + myType = theType; myShape = theShape; - myIds.Clear(); - - const SMDS_Mesh* myMesh = myMeshModifTracer.GetMesh(); + if ( myShape.IsNull() ) return; - if ( !myMesh ) return; - - myIds.ReSize( myMeshModifTracer.GetMesh()->GetMeshInfo().NbElements( myType )); + TopTools_IndexedMapOfShape shapesMap; + TopAbs_ShapeEnum shapeTypes[4] = { TopAbs_SOLID, TopAbs_FACE, TopAbs_EDGE, TopAbs_VERTEX }; + TopExp_Explorer sub; + for ( int i = 0; i < 4; ++i ) + { + if ( shapesMap.IsEmpty() ) + for ( sub.Init( myShape, shapeTypes[i] ); sub.More(); sub.Next() ) + shapesMap.Add( sub.Current() ); + if ( i > 0 ) + for ( sub.Init( myShape, shapeTypes[i], shapeTypes[i-1] ); sub.More(); sub.Next() ) + shapesMap.Add( sub.Current() ); + } - myShapesMap.Clear(); - addShape(myShape); + clearClassifiers(); + myClassifiers.resize( shapesMap.Extent() ); + for ( int i = 0; i < shapesMap.Extent(); ++i ) + myClassifiers[ i ] = new TClassifier( shapesMap( i+1 ), myToler ); } -void ElementsOnShape::addShape (const TopoDS_Shape& theShape) +void ElementsOnShape::clearClassifiers() { - if (theShape.IsNull() || myMeshModifTracer.GetMesh() == 0) - return; + for ( size_t i = 0; i < myClassifiers.size(); ++i ) + delete myClassifiers[ i ]; + myClassifiers.clear(); +} - if (!myShapesMap.Add(theShape)) return; +bool ElementsOnShape::IsSatisfy (long elemId) +{ + const SMDS_MeshElement* elem = + ( myType == SMDSAbs_Node ? myMesh->FindNode( elemId ) : myMesh->FindElement( elemId )); + if ( !elem || myClassifiers.empty() ) + return false; - myCurShapeType = theShape.ShapeType(); - switch (myCurShapeType) + for ( size_t i = 0; i < myClassifiers.size(); ++i ) { - case TopAbs_COMPOUND: - case TopAbs_COMPSOLID: - case TopAbs_SHELL: - case TopAbs_WIRE: + SMDS_ElemIteratorPtr aNodeItr = elem->nodesIterator(); + bool isSatisfy = myAllNodesFlag; + + gp_XYZ centerXYZ (0, 0, 0); + + while (aNodeItr->more() && (isSatisfy == myAllNodesFlag)) { - TopoDS_Iterator anIt (theShape, Standard_True, Standard_True); - for (; anIt.More(); anIt.Next()) addShape(anIt.Value()); + SMESH_TNodeXYZ aPnt ( aNodeItr->next() ); + centerXYZ += aPnt; + isSatisfy = ! myClassifiers[i]->IsOut( aPnt ); } - break; - case TopAbs_SOLID: + + // Check the center point for volumes MantisBug 0020168 + if (isSatisfy && + myAllNodesFlag && + myClassifiers[i]->ShapeType() == TopAbs_SOLID) { - myCurSC.Load(theShape); - process(); + centerXYZ /= elem->NbNodes(); + isSatisfy = ! myClassifiers[i]->IsOut( centerXYZ ); } + if ( isSatisfy ) + return true; + } + + return false; +} + +TopAbs_ShapeEnum ElementsOnShape::TClassifier::ShapeType() const +{ + return myShape.ShapeType(); +} + +bool ElementsOnShape::TClassifier::IsOut(const gp_Pnt& p) +{ + return (this->*myIsOutFun)( p ); +} + +void ElementsOnShape::TClassifier::Init (const TopoDS_Shape& theShape, double theTol) +{ + myShape = theShape; + myTol = theTol; + switch ( myShape.ShapeType() ) + { + case TopAbs_SOLID: { + mySolidClfr.Load(theShape); + myIsOutFun = & ElementsOnShape::TClassifier::isOutOfSolid; break; - case TopAbs_FACE: - { - TopoDS_Face aFace = TopoDS::Face(theShape); - BRepAdaptor_Surface SA (aFace, true); - Standard_Real - u1 = SA.FirstUParameter(), - u2 = SA.LastUParameter(), - v1 = SA.FirstVParameter(), - v2 = SA.LastVParameter(); - Handle(Geom_Surface) surf = BRep_Tool::Surface(aFace); - myCurProjFace.Init(surf, u1,u2, v1,v2); - myCurFace = aFace; - process(); - } + } + case TopAbs_FACE: { + Standard_Real u1,u2,v1,v2; + Handle(Geom_Surface) surf = BRep_Tool::Surface( TopoDS::Face( theShape )); + surf->Bounds( u1,u2,v1,v2 ); + myProjFace.Init(surf, u1,u2, v1,v2, myTol ); + myIsOutFun = & ElementsOnShape::TClassifier::isOutOfFace; break; - case TopAbs_EDGE: - { - TopoDS_Edge anEdge = TopoDS::Edge(theShape); - Standard_Real u1, u2; - Handle(Geom_Curve) curve = BRep_Tool::Curve(anEdge, u1, u2); - myCurProjEdge.Init(curve, u1, u2); - process(); - } + } + case TopAbs_EDGE: { + Standard_Real u1, u2; + Handle(Geom_Curve) curve = BRep_Tool::Curve( TopoDS::Edge(theShape), u1, u2); + myProjEdge.Init(curve, u1, u2); + myIsOutFun = & ElementsOnShape::TClassifier::isOutOfEdge; break; - case TopAbs_VERTEX: - { - TopoDS_Vertex aV = TopoDS::Vertex(theShape); - myCurPnt = BRep_Tool::Pnt(aV); - process(); - } + } + case TopAbs_VERTEX:{ + myVertexXYZ = BRep_Tool::Pnt( TopoDS::Vertex( theShape ) ); + myIsOutFun = & ElementsOnShape::TClassifier::isOutOfVertex; break; + } default: - break; + throw SALOME_Exception("Programmer error in usage of ElementsOnShape::TClassifier"); } } -void ElementsOnShape::process() +bool ElementsOnShape::TClassifier::isOutOfSolid (const gp_Pnt& p) { - const SMDS_Mesh* myMesh = myMeshModifTracer.GetMesh(); - if (myShape.IsNull() || myMesh == 0) - return; - - SMDS_ElemIteratorPtr anIter = myMesh->elementsIterator(myType); - while (anIter->more()) - process(anIter->next()); + mySolidClfr.Perform( p, myTol ); + return ( mySolidClfr.State() != TopAbs_IN && mySolidClfr.State() != TopAbs_ON ); } -void ElementsOnShape::process (const SMDS_MeshElement* theElemPtr) +bool ElementsOnShape::TClassifier::isOutOfFace (const gp_Pnt& p) { - if (myShape.IsNull()) - return; - - SMDS_ElemIteratorPtr aNodeItr = theElemPtr->nodesIterator(); - bool isSatisfy = myAllNodesFlag; - - gp_XYZ centerXYZ (0, 0, 0); - - while (aNodeItr->more() && (isSatisfy == myAllNodesFlag)) + myProjFace.Perform( p ); + if ( myProjFace.IsDone() && myProjFace.LowerDistance() <= myTol ) { - SMESH_TNodeXYZ aPnt ( aNodeItr->next() ); - centerXYZ += aPnt; - - switch (myCurShapeType) - { - case TopAbs_SOLID: - { - myCurSC.Perform(aPnt, myToler); - isSatisfy = (myCurSC.State() == TopAbs_IN || myCurSC.State() == TopAbs_ON); - } - break; - case TopAbs_FACE: - { - myCurProjFace.Perform(aPnt); - isSatisfy = (myCurProjFace.IsDone() && myCurProjFace.LowerDistance() <= myToler); - if (isSatisfy) - { - // check relatively the face - Quantity_Parameter u, v; - myCurProjFace.LowerDistanceParameters(u, v); - gp_Pnt2d aProjPnt (u, v); - BRepClass_FaceClassifier aClsf (myCurFace, aProjPnt, myToler); - isSatisfy = (aClsf.State() == TopAbs_IN || aClsf.State() == TopAbs_ON); - } - } - break; - case TopAbs_EDGE: - { - myCurProjEdge.Perform(aPnt); - isSatisfy = (myCurProjEdge.NbPoints() > 0 && myCurProjEdge.LowerDistance() <= myToler); - } - break; - case TopAbs_VERTEX: - { - isSatisfy = (myCurPnt.Distance(aPnt) <= myToler); - } - break; - default: - { - isSatisfy = false; - } - } + // check relatively to the face + Quantity_Parameter u, v; + myProjFace.LowerDistanceParameters(u, v); + gp_Pnt2d aProjPnt (u, v); + BRepClass_FaceClassifier aClsf ( TopoDS::Face( myShape ), aProjPnt, myTol ); + if ( aClsf.State() == TopAbs_IN || aClsf.State() == TopAbs_ON ) + return false; } + return true; +} - if (isSatisfy && myCurShapeType == TopAbs_SOLID) { // Check the center point for volumes MantisBug 0020168 - centerXYZ /= theElemPtr->NbNodes(); - gp_Pnt aCenterPnt (centerXYZ); - myCurSC.Perform(aCenterPnt, myToler); - if ( !(myCurSC.State() == TopAbs_IN || myCurSC.State() == TopAbs_ON)) - isSatisfy = false; - } +bool ElementsOnShape::TClassifier::isOutOfEdge (const gp_Pnt& p) +{ + myProjEdge.Perform( p ); + return ! ( myProjEdge.NbPoints() > 0 && myProjEdge.LowerDistance() <= myTol ); +} - if (isSatisfy) - myIds.Add(theElemPtr->GetID()); +bool ElementsOnShape::TClassifier::isOutOfVertex(const gp_Pnt& p) +{ + return ( myVertexXYZ.Distance( p ) > myTol ); } + TSequenceOfXYZ::TSequenceOfXYZ() {} diff --git a/src/Controls/SMESH_ControlsDef.hxx b/src/Controls/SMESH_ControlsDef.hxx index 587f5b6d6..9b9c26525 100644 --- a/src/Controls/SMESH_ControlsDef.hxx +++ b/src/Controls/SMESH_ControlsDef.hxx @@ -125,7 +125,8 @@ namespace SMESH{ std::vector& nbEvents, std::vector& funValues, const std::vector& elements, - const double* minmax=0); + const double* minmax=0, + const bool isLogarithmic = false); virtual SMDSAbs_ElementType GetType() const = 0; virtual double GetBadRate( double Value, int nbNodes ) const = 0; long GetPrecision() const; @@ -820,25 +821,36 @@ namespace SMESH{ const SMDSAbs_ElementType theType); private: - void addShape (const TopoDS_Shape& theShape); - void process(); - void process (const SMDS_MeshElement* theElem); - private: - TMeshModifTracer myMeshModifTracer; - TColStd_MapOfInteger myIds; - SMDSAbs_ElementType myType; - TopoDS_Shape myShape; - double myToler; - bool myAllNodesFlag; - - TopTools_MapOfShape myShapesMap; - TopAbs_ShapeEnum myCurShapeType; // type of current sub-shape - BRepClass3d_SolidClassifier myCurSC; // current SOLID - GeomAPI_ProjectPointOnSurf myCurProjFace; // current FACE - TopoDS_Face myCurFace; // current FACE - GeomAPI_ProjectPointOnCurve myCurProjEdge; // current EDGE - gp_Pnt myCurPnt; // current VERTEX + struct TClassifier + { + TClassifier(const TopoDS_Shape& s, double tol) { Init(s,tol); } + void Init(const TopoDS_Shape& s, double tol); + bool IsOut(const gp_Pnt& p); + TopAbs_ShapeEnum ShapeType() const; + private: + bool isOutOfSolid (const gp_Pnt& p); + bool isOutOfFace (const gp_Pnt& p); + bool isOutOfEdge (const gp_Pnt& p); + bool isOutOfVertex(const gp_Pnt& p); + + bool (TClassifier::* myIsOutFun)(const gp_Pnt& p); + BRepClass3d_SolidClassifier mySolidClfr; + GeomAPI_ProjectPointOnSurf myProjFace; + GeomAPI_ProjectPointOnCurve myProjEdge; + gp_Pnt myVertexXYZ; + TopoDS_Shape myShape; + double myTol; + }; + void clearClassifiers(); + + std::vector< TClassifier* > myClassifiers; + const SMDS_Mesh* myMesh; + SMDSAbs_ElementType myType; + TopoDS_Shape myShape; + double myToler; + bool myAllNodesFlag; + }; typedef boost::shared_ptr ElementsOnShapePtr; diff --git a/src/Driver/Driver_Mesh.h b/src/Driver/Driver_Mesh.h index fcaea2b3e..a3629e497 100644 --- a/src/Driver/Driver_Mesh.h +++ b/src/Driver/Driver_Mesh.h @@ -54,6 +54,7 @@ class MESHDRIVER_EXPORT Driver_Mesh DRS_WARN_RENUMBER, // a file has overlapped ranges of element numbers, // so the numbers from the file are ignored DRS_WARN_SKIP_ELEM, // some elements were skipped due to incorrect file data + DRS_WARN_DESCENDING, // some elements were skipped due to descending connectivity DRS_FAIL // general failure (exception etc.) }; diff --git a/src/DriverGMF/libmesh5.c b/src/DriverGMF/libmesh5.c index b16c39c93..e0892c77e 100644 --- a/src/DriverGMF/libmesh5.c +++ b/src/DriverGMF/libmesh5.c @@ -1,21 +1,21 @@ /*----------------------------------------------------------*/ -/* */ -/* LIBMESH V 5.46 */ -/* */ +/* */ +/* LIBMESH V 5.46 */ +/* */ /*----------------------------------------------------------*/ -/* */ -/* Description: handle .meshb file format I/O */ -/* Author: Loic MARECHAL */ -/* Creation date: feb 16 2007 */ -/* Last modification: apr 03 2012 */ -/* */ +/* */ +/* Description: handle .meshb file format I/O */ +/* Author: Loic MARECHAL */ +/* Creation date: feb 16 2007 */ +/* Last modification: apr 03 2012 */ +/* */ /*----------------------------------------------------------*/ /*----------------------------------------------------------*/ -/* Includes */ +/* Includes */ /*----------------------------------------------------------*/ #include @@ -29,7 +29,7 @@ /*----------------------------------------------------------*/ -/* Defines */ +/* Defines */ /*----------------------------------------------------------*/ #define Asc 1 @@ -45,124 +45,124 @@ /*----------------------------------------------------------*/ -/* Structures */ +/* Structures */ /*----------------------------------------------------------*/ typedef struct { - int typ, SolSiz, NmbWrd, NmbLin, NmbTyp, TypTab[ GmfMaxTyp ]; - long pos; - char fmt[ GmfMaxTyp*9 ]; + int typ, SolSiz, NmbWrd, NmbLin, NmbTyp, TypTab[ GmfMaxTyp ]; + long pos; + char fmt[ GmfMaxTyp*9 ]; }KwdSct; typedef struct { - int dim, ver, mod, typ, cod, pos; - long NexKwdPos, siz; - KwdSct KwdTab[ GmfMaxKwd + 1 ]; - FILE *hdl; - int *IntBuf; - float *FltBuf; - unsigned char *buf; - char FilNam[ GmfStrSiz ]; - double DblBuf[1000/8]; - unsigned char blk[ BufSiz + 1000 ]; + int dim, ver, mod, typ, cod, pos; + long NexKwdPos, siz; + KwdSct KwdTab[ GmfMaxKwd + 1 ]; + FILE *hdl; + int *IntBuf; + float *FltBuf; + unsigned char *buf; + char FilNam[ GmfStrSiz ]; + double DblBuf[1000/8]; + unsigned char blk[ BufSiz + 1000 ]; }GmfMshSct; /*----------------------------------------------------------*/ -/* Global variables */ +/* Global variables */ /*----------------------------------------------------------*/ static int GmfIniFlg=0; static GmfMshSct *GmfMshTab[ MaxMsh + 1 ]; static const char *GmfKwdFmt[ GmfMaxKwd + 1 ][4] = -{ {"Reserved", "", "", ""}, - {"MeshVersionFormatted", "", "", "i"}, - {"Reserved", "", "", ""}, - {"Dimension", "", "", "i"}, - {"Vertices", "Vertex", "i", "dri"}, - {"Edges", "Edge", "i", "iii"}, - {"Triangles", "Triangle", "i", "iiii"}, - {"Quadrilaterals", "Quadrilateral", "i", "iiiii"}, - {"Tetrahedra", "Tetrahedron", "i", "iiiii"}, - {"Prisms", "Prism", "i", "iiiiiii"}, - {"Hexahedra", "Hexahedron", "i", "iiiiiiiii"}, - {"IterationsAll", "IterationAll","","i"}, - {"TimesAll", "TimeAll","","r"}, - {"Corners", "Corner", "i", "i"}, - {"Ridges", "Ridge", "i", "i"}, - {"RequiredVertices", "RequiredVertex", "i", "i"}, - {"RequiredEdges", "RequiredEdge", "i", "i"}, - {"RequiredTriangles", "RequiredTriangle", "i", "i"}, - {"RequiredQuadrilaterals", "RequiredQuadrilateral", "i", "i"}, - {"TangentAtEdgeVertices", "TangentAtEdgeVertex", "i", "iii"}, - {"NormalAtVertices", "NormalAtVertex", "i", "ii"}, - {"NormalAtTriangleVertices", "NormalAtTriangleVertex", "i", "iii"}, - {"NormalAtQuadrilateralVertices", "NormalAtQuadrilateralVertex", "i", "iiii"}, - {"AngleOfCornerBound", "", "", "r"}, - {"TrianglesP2", "TriangleP2", "i", "iiiiiii"}, - {"EdgesP2", "EdgeP2", "i", "iiii"}, - {"SolAtPyramids", "SolAtPyramid", "i", "sr"}, - {"QuadrilateralsQ2", "QuadrilateralQ2", "i", "iiiiiiiiii"}, - {"ISolAtPyramids", "ISolAtPyramid", "i", "iiiii"}, - {"SubDomainFromGeom", "SubDomainFromGeom", "i", "iiii"}, - {"TetrahedraP2", "TetrahedronP2", "i", "iiiiiiiiiii"}, - {"Fault_NearTri", "Fault_NearTri", "i", "i"}, - {"Fault_Inter", "Fault_Inter", "i", "i"}, - {"HexahedraQ2", "HexahedronQ2", "i", "iiiiiiiiiiiiiiiiiiiiiiiiiiii"}, - {"ExtraVerticesAtEdges", "ExtraVerticesAtEdge", "i", "in"}, - {"ExtraVerticesAtTriangles", "ExtraVerticesAtTriangle", "i", "in"}, - {"ExtraVerticesAtQuadrilaterals", "ExtraVerticesAtQuadrilateral", "i", "in"}, - {"ExtraVerticesAtTetrahedra", "ExtraVerticesAtTetrahedron", "i", "in"}, - {"ExtraVerticesAtPrisms", "ExtraVerticesAtPrism", "i", "in"}, - {"ExtraVerticesAtHexahedra", "ExtraVerticesAtHexahedron", "i", "in"}, - {"VerticesOnGeometricVertices", "VertexOnGeometricVertex", "i", "iir"}, - {"VerticesOnGeometricEdges", "VertexOnGeometricEdge", "i", "iirr"}, - {"VerticesOnGeometricTriangles", "VertexOnGeometricTriangle", "i", "iirrr"}, - {"VerticesOnGeometricQuadrilaterals", "VertexOnGeometricQuadrilateral", "i", "iirrr"}, - {"EdgesOnGeometricEdges", "EdgeOnGeometricEdge", "i", "iir"}, - {"Fault_FreeEdge", "Fault_FreeEdge", "i", "i"}, - {"Polyhedra", "Polyhedron", "i", "iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii"}, - {"Polygons", "Polygon", "", "iiiiiiiii"}, - {"Fault_Overlap", "Fault_Overlap", "i", "i"}, - {"Pyramids", "Pyramid", "i", "iiiiii"}, - {"BoundingBox", "", "", "drdr"}, - {"Body","i", "drdrdrdr"}, - {"PrivateTable", "PrivateTable", "i", "i"}, - {"Fault_BadShape", "Fault_BadShape", "i", "i"}, - {"End", "", "", ""}, - {"TrianglesOnGeometricTriangles", "TriangleOnGeometricTriangle", "i", "iir"}, - {"TrianglesOnGeometricQuadrilaterals", "TriangleOnGeometricQuadrilateral", "i", "iir"}, - {"QuadrilateralsOnGeometricTriangles", "QuadrilateralOnGeometricTriangle", "i", "iir"}, - {"QuadrilateralsOnGeometricQuadrilaterals", "QuadrilateralOnGeometricQuadrilateral", "i", "iir"}, - {"Tangents", "Tangent", "i", "dr"}, - {"Normals", "Normal", "i", "dr"}, - {"TangentAtVertices", "TangentAtVertex", "i", "ii"}, - {"SolAtVertices", "SolAtVertex", "i", "sr"}, - {"SolAtEdges", "SolAtEdge", "i", "sr"}, - {"SolAtTriangles", "SolAtTriangle", "i", "sr"}, - {"SolAtQuadrilaterals", "SolAtQuadrilateral", "i", "sr"}, - {"SolAtTetrahedra", "SolAtTetrahedron", "i", "sr"}, - {"SolAtPrisms", "SolAtPrism", "i", "sr"}, - {"SolAtHexahedra", "SolAtHexahedron", "i", "sr"}, - {"DSolAtVertices", "DSolAtVertex", "i", "sr"}, - {"ISolAtVertices", "ISolAtVertex", "i", "i"}, - {"ISolAtEdges", "ISolAtEdge", "i", "ii"}, - {"ISolAtTriangles", "ISolAtTriangle", "i", "iii"}, - {"ISolAtQuadrilaterals", "ISolAtQuadrilateral", "i", "iiii"}, - {"ISolAtTetrahedra", "ISolAtTetrahedron", "i", "iiii"}, - {"ISolAtPrisms", "ISolAtPrism", "i", "iiiiii"}, - {"ISolAtHexahedra", "ISolAtHexahedron", "i", "iiiiiiii"}, - {"Iterations", "","","i"}, - {"Time", "","","r"}, - {"Fault_SmallTri", "Fault_SmallTri","i","i"}, - {"CoarseHexahedra", "CoarseHexahedron", "i", "i"} +{ {"Reserved", "", "", ""}, + {"MeshVersionFormatted", "", "", "i"}, + {"Reserved", "", "", ""}, + {"Dimension", "", "", "i"}, + {"Vertices", "Vertex", "i", "dri"}, + {"Edges", "Edge", "i", "iii"}, + {"Triangles", "Triangle", "i", "iiii"}, + {"Quadrilaterals", "Quadrilateral", "i", "iiiii"}, + {"Tetrahedra", "Tetrahedron", "i", "iiiii"}, + {"Prisms", "Prism", "i", "iiiiiii"}, + {"Hexahedra", "Hexahedron", "i", "iiiiiiiii"}, + {"IterationsAll", "IterationAll","","i"}, + {"TimesAll", "TimeAll","","r"}, + {"Corners", "Corner", "i", "i"}, + {"Ridges", "Ridge", "i", "i"}, + {"RequiredVertices", "RequiredVertex", "i", "i"}, + {"RequiredEdges", "RequiredEdge", "i", "i"}, + {"RequiredTriangles", "RequiredTriangle", "i", "i"}, + {"RequiredQuadrilaterals", "RequiredQuadrilateral", "i", "i"}, + {"TangentAtEdgeVertices", "TangentAtEdgeVertex", "i", "iii"}, + {"NormalAtVertices", "NormalAtVertex", "i", "ii"}, + {"NormalAtTriangleVertices", "NormalAtTriangleVertex", "i", "iii"}, + {"NormalAtQuadrilateralVertices", "NormalAtQuadrilateralVertex", "i", "iiii"}, + {"AngleOfCornerBound", "", "", "r"}, + {"TrianglesP2", "TriangleP2", "i", "iiiiiii"}, + {"EdgesP2", "EdgeP2", "i", "iiii"}, + {"SolAtPyramids", "SolAtPyramid", "i", "sr"}, + {"QuadrilateralsQ2", "QuadrilateralQ2", "i", "iiiiiiiiii"}, + {"ISolAtPyramids", "ISolAtPyramid", "i", "iiiii"}, + {"SubDomainFromGeom", "SubDomainFromGeom", "i", "iiii"}, + {"TetrahedraP2", "TetrahedronP2", "i", "iiiiiiiiiii"}, + {"Fault_NearTri", "Fault_NearTri", "i", "i"}, + {"Fault_Inter", "Fault_Inter", "i", "i"}, + {"HexahedraQ2", "HexahedronQ2", "i", "iiiiiiiiiiiiiiiiiiiiiiiiiiii"}, + {"ExtraVerticesAtEdges", "ExtraVerticesAtEdge", "i", "in"}, + {"ExtraVerticesAtTriangles", "ExtraVerticesAtTriangle", "i", "in"}, + {"ExtraVerticesAtQuadrilaterals", "ExtraVerticesAtQuadrilateral", "i", "in"}, + {"ExtraVerticesAtTetrahedra", "ExtraVerticesAtTetrahedron", "i", "in"}, + {"ExtraVerticesAtPrisms", "ExtraVerticesAtPrism", "i", "in"}, + {"ExtraVerticesAtHexahedra", "ExtraVerticesAtHexahedron", "i", "in"}, + {"VerticesOnGeometricVertices", "VertexOnGeometricVertex", "i", "iir"}, + {"VerticesOnGeometricEdges", "VertexOnGeometricEdge", "i", "iirr"}, + {"VerticesOnGeometricTriangles", "VertexOnGeometricTriangle", "i", "iirrr"}, + {"VerticesOnGeometricQuadrilaterals", "VertexOnGeometricQuadrilateral", "i", "iirrr"}, + {"EdgesOnGeometricEdges", "EdgeOnGeometricEdge", "i", "iir"}, + {"Fault_FreeEdge", "Fault_FreeEdge", "i", "i"}, + {"Polyhedra", "Polyhedron", "i", "iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii"}, + {"Polygons", "Polygon", "", "iiiiiiiii"}, + {"Fault_Overlap", "Fault_Overlap", "i", "i"}, + {"Pyramids", "Pyramid", "i", "iiiiii"}, + {"BoundingBox", "", "", "drdr"}, + {"Body","i", "drdrdrdr"}, + {"PrivateTable", "PrivateTable", "i", "i"}, + {"Fault_BadShape", "Fault_BadShape", "i", "i"}, + {"End", "", "", ""}, + {"TrianglesOnGeometricTriangles", "TriangleOnGeometricTriangle", "i", "iir"}, + {"TrianglesOnGeometricQuadrilaterals", "TriangleOnGeometricQuadrilateral", "i", "iir"}, + {"QuadrilateralsOnGeometricTriangles", "QuadrilateralOnGeometricTriangle", "i", "iir"}, + {"QuadrilateralsOnGeometricQuadrilaterals", "QuadrilateralOnGeometricQuadrilateral", "i", "iir"}, + {"Tangents", "Tangent", "i", "dr"}, + {"Normals", "Normal", "i", "dr"}, + {"TangentAtVertices", "TangentAtVertex", "i", "ii"}, + {"SolAtVertices", "SolAtVertex", "i", "sr"}, + {"SolAtEdges", "SolAtEdge", "i", "sr"}, + {"SolAtTriangles", "SolAtTriangle", "i", "sr"}, + {"SolAtQuadrilaterals", "SolAtQuadrilateral", "i", "sr"}, + {"SolAtTetrahedra", "SolAtTetrahedron", "i", "sr"}, + {"SolAtPrisms", "SolAtPrism", "i", "sr"}, + {"SolAtHexahedra", "SolAtHexahedron", "i", "sr"}, + {"DSolAtVertices", "DSolAtVertex", "i", "sr"}, + {"ISolAtVertices", "ISolAtVertex", "i", "i"}, + {"ISolAtEdges", "ISolAtEdge", "i", "ii"}, + {"ISolAtTriangles", "ISolAtTriangle", "i", "iii"}, + {"ISolAtQuadrilaterals", "ISolAtQuadrilateral", "i", "iiii"}, + {"ISolAtTetrahedra", "ISolAtTetrahedron", "i", "iiii"}, + {"ISolAtPrisms", "ISolAtPrism", "i", "iiiiii"}, + {"ISolAtHexahedra", "ISolAtHexahedron", "i", "iiiiiiii"}, + {"Iterations", "","","i"}, + {"Time", "","","r"}, + {"Fault_SmallTri", "Fault_SmallTri","i","i"}, + {"CoarseHexahedra", "CoarseHexahedron", "i", "i"} }; /*----------------------------------------------------------*/ -/* Prototypes of local procedures */ +/* Prototypes of local procedures */ /*----------------------------------------------------------*/ static void ScaWrd(GmfMshSct *, unsigned char *); @@ -179,299 +179,299 @@ static void ScaKwdHdr(GmfMshSct *, int); /*----------------------------------------------------------*/ -/* Open a mesh file in read or write mod */ +/* Open a mesh file in read or write mod */ /*----------------------------------------------------------*/ int GmfOpenMesh(const char *FilNam, int mod, ...) { - int i, KwdCod, res, *PtrVer, *PtrDim, MshIdx=0; - char str[ GmfStrSiz ]; - va_list VarArg; - GmfMshSct *msh; - char *ptr; - int k; - - if(!GmfIniFlg) - { - for(i=0;i<=MaxMsh;i++) - GmfMshTab[i] = NULL; - - GmfIniFlg = 1; - } - - /*---------------------*/ - /* MESH STRUCTURE INIT */ - /*---------------------*/ - - for(i=1;i<=MaxMsh;i++) - if(!GmfMshTab[i]) - { - MshIdx = i; - break; - } - - if( !MshIdx || !(msh = calloc(1, sizeof(GmfMshSct))) ) - return(0); - - /* Copy the FilNam into the structure */ - - if(strlen(FilNam) + 7 >= GmfStrSiz) + int i, KwdCod, res, *PtrVer, *PtrDim, MshIdx=0; + char str[ GmfStrSiz ]; + va_list VarArg; + GmfMshSct *msh; + char *ptr; + int k; + + if(!GmfIniFlg) + { + for(i=0;i<=MaxMsh;i++) + GmfMshTab[i] = NULL; + + GmfIniFlg = 1; + } + + /*---------------------*/ + /* MESH STRUCTURE INIT */ + /*---------------------*/ + + for(i=1;i<=MaxMsh;i++) + if(!GmfMshTab[i]) + { + MshIdx = i; + break; + } + + if( !MshIdx || !(msh = calloc(1, sizeof(GmfMshSct))) ) + return(0); + + /* Copy the FilNam into the structure */ + + if(strlen(FilNam) + 7 >= GmfStrSiz) { free (msh); - return(0); + return(0); } - strcpy(msh->FilNam, FilNam); - - /* Store the opening mod (read or write) and guess the filetype (binary or ascii) depending on the extension */ - - msh->mod = mod; - msh->buf = (unsigned char *)msh->DblBuf; - msh->FltBuf = (float *)msh->DblBuf; - msh->IntBuf = (int *)msh->DblBuf; - - k = strlen(msh->FilNam) - 6; - if(k < 0) - k = 0; - ptr = msh->FilNam+k; - if(strstr(ptr, ".meshb")) - msh->typ |= (Bin | MshFil); - else if(strstr(ptr, ".mesh")) - msh->typ |= (Asc | MshFil); - else if(strstr(ptr, ".solb")) - msh->typ |= (Bin | SolFil); - else if(strstr(ptr, ".sol")) - msh->typ |= (Asc | SolFil); - else { - free (msh); - return(0); - } - - /* Open the file in the required mod and initialyse the mesh structure */ - - if(msh->mod == GmfRead) - { - - /*-----------------------*/ - /* OPEN FILE FOR READING */ - /*-----------------------*/ - - va_start(VarArg, mod); - PtrVer = va_arg(VarArg, int *); - PtrDim = va_arg(VarArg, int *); - va_end(VarArg); - - /* Create the name string and open the file */ - - if(!(msh->hdl = fopen(msh->FilNam, "rb"))) - { - free (msh); - return(0); - } - - /* Read the endian coding tag, the mesh version and the mesh dimension (mandatory kwd) */ - - if(msh->typ & Bin) - { - fread((unsigned char *)&msh->cod, WrdSiz, 1, msh->hdl); - - if( (msh->cod != 1) && (msh->cod != 16777216) ) - { - free (msh); - return(0); - } - - ScaWrd(msh, (unsigned char *)&msh->ver); - - if( (msh->ver < 1) || (msh->ver > 3) ) - { - free (msh); - return(0); - } - - if( (msh->ver == 3) && (sizeof(long) == 4) ) - { - free (msh); - return(0); - } - - ScaWrd(msh, (unsigned char *)&KwdCod); - - if(KwdCod != GmfDimension) - { - free (msh); - return(0); - } - - GetPos(msh); - ScaWrd(msh, (unsigned char *)&msh->dim); - } - else - { - do - { - res = fscanf(msh->hdl, "%s", str); - }while( (res != EOF) && strcmp(str, "MeshVersionFormatted") ); - - if(res == EOF) - { - free (msh); - return(0); - } - - fscanf(msh->hdl, "%d", &msh->ver); - - if( (msh->ver < 1) || (msh->ver > 3) ) - { - free (msh); - return(0); - } - - do - { - res = fscanf(msh->hdl, "%s", str); - }while( (res != EOF) && strcmp(str, "Dimension") ); - - if(res == EOF) - { - free (msh); - return(0); - } - - fscanf(msh->hdl, "%d", &msh->dim); - } - - if( (msh->dim != 2) && (msh->dim != 3) ) - { - free (msh); - return(0); - } - - (*PtrVer) = msh->ver; - (*PtrDim) = msh->dim; - - /*------------*/ - /* KW READING */ - /*------------*/ - - /* Read the list of kw present in the file */ - - if(!ScaKwdTab(msh)) - { - free (msh); - return(0); - } - - GmfMshTab[ MshIdx ] = msh; - - return(MshIdx); - } - else if(msh->mod == GmfWrite) - { - - /*-----------------------*/ - /* OPEN FILE FOR WRITING */ - /*-----------------------*/ - - msh->cod = 1; - - /* Check if the user provided a valid version number and dimension */ - - va_start(VarArg, mod); - msh->ver = va_arg(VarArg, int); - msh->dim = va_arg(VarArg, int); - va_end(VarArg); - - if( (msh->ver < 1) || (msh->ver > 3) ) - { - free (msh); - return(0); - } - - if( (msh->ver == 3) && (sizeof(long) == 4) ) - { - free (msh); - return(0); - } - - if( (msh->dim != 2) && (msh->dim != 3) ) - { - free (msh); - return(0); - } - - /* Create the mesh file */ - - if(!(msh->hdl = fopen(msh->FilNam, "wb"))) - { - free (msh); - return(0); - } - - GmfMshTab[ MshIdx ] = msh; - - - /*------------*/ - /* KW WRITING */ - /*------------*/ - - /* Write the mesh version and dimension */ - - if(msh->typ & Asc) - { - fprintf(msh->hdl, "%s %d\n\n", GmfKwdFmt[ GmfVersionFormatted ][0], msh->ver); - fprintf(msh->hdl, "%s %d\n", GmfKwdFmt[ GmfDimension ][0], msh->dim); - } - else - { - RecWrd(msh, (unsigned char *)&msh->cod); - RecWrd(msh, (unsigned char *)&msh->ver); - GmfSetKwd(MshIdx, GmfDimension, 0); - RecWrd(msh, (unsigned char *)&msh->dim); - } - - return(MshIdx); - } - else - { + strcpy(msh->FilNam, FilNam); + + /* Store the opening mod (read or write) and guess the filetype (binary or ascii) depending on the extension */ + + msh->mod = mod; + msh->buf = (unsigned char *)msh->DblBuf; + msh->FltBuf = (float *)msh->DblBuf; + msh->IntBuf = (int *)msh->DblBuf; + + k = strlen(msh->FilNam) - 6; + if(k < 0) + k = 0; + ptr = msh->FilNam+k; + if(strstr(ptr, ".meshb")) + msh->typ |= (Bin | MshFil); + else if(strstr(ptr, ".mesh")) + msh->typ |= (Asc | MshFil); + else if(strstr(ptr, ".solb")) + msh->typ |= (Bin | SolFil); + else if(strstr(ptr, ".sol")) + msh->typ |= (Asc | SolFil); + else { free (msh); - return(0); + return(0); + } + + /* Open the file in the required mod and initialyse the mesh structure */ + + if(msh->mod == GmfRead) + { + + /*-----------------------*/ + /* OPEN FILE FOR READING */ + /*-----------------------*/ + + va_start(VarArg, mod); + PtrVer = va_arg(VarArg, int *); + PtrDim = va_arg(VarArg, int *); + va_end(VarArg); + + /* Create the name string and open the file */ + + if(!(msh->hdl = fopen(msh->FilNam, "rb"))) + { + free (msh); + return(0); + } + + /* Read the endian coding tag, the mesh version and the mesh dimension (mandatory kwd) */ + + if(msh->typ & Bin) + { + fread((unsigned char *)&msh->cod, WrdSiz, 1, msh->hdl); + + if( (msh->cod != 1) && (msh->cod != 16777216) ) + { + free (msh); + return(0); + } + + ScaWrd(msh, (unsigned char *)&msh->ver); + + if( (msh->ver < 1) || (msh->ver > 3) ) + { + free (msh); + return(0); + } + + if( (msh->ver == 3) && (sizeof(long) == 4) ) + { + free (msh); + return(0); + } + + ScaWrd(msh, (unsigned char *)&KwdCod); + + if(KwdCod != GmfDimension) + { + free (msh); + return(0); + } + + GetPos(msh); + ScaWrd(msh, (unsigned char *)&msh->dim); + } + else + { + do + { + res = fscanf(msh->hdl, "%s", str); + }while( (res != EOF) && strcmp(str, "MeshVersionFormatted") ); + + if(res == EOF) + { + free (msh); + return(0); + } + + fscanf(msh->hdl, "%d", &msh->ver); + + if( (msh->ver < 1) || (msh->ver > 3) ) + { + free (msh); + return(0); + } + + do + { + res = fscanf(msh->hdl, "%s", str); + }while( (res != EOF) && strcmp(str, "Dimension") ); + + if(res == EOF) + { + free (msh); + return(0); + } + + fscanf(msh->hdl, "%d", &msh->dim); + } + + if( (msh->dim != 2) && (msh->dim != 3) ) + { + free (msh); + return(0); + } + + (*PtrVer) = msh->ver; + (*PtrDim) = msh->dim; + + /*------------*/ + /* KW READING */ + /*------------*/ + + /* Read the list of kw present in the file */ + + if(!ScaKwdTab(msh)) + { + free (msh); + return(0); + } + + GmfMshTab[ MshIdx ] = msh; + + return(MshIdx); + } + else if(msh->mod == GmfWrite) + { + + /*-----------------------*/ + /* OPEN FILE FOR WRITING */ + /*-----------------------*/ + + msh->cod = 1; + + /* Check if the user provided a valid version number and dimension */ + + va_start(VarArg, mod); + msh->ver = va_arg(VarArg, int); + msh->dim = va_arg(VarArg, int); + va_end(VarArg); + + if( (msh->ver < 1) || (msh->ver > 3) ) + { + free (msh); + return(0); + } + + if( (msh->ver == 3) && (sizeof(long) == 4) ) + { + free (msh); + return(0); + } + + if( (msh->dim != 2) && (msh->dim != 3) ) + { + free (msh); + return(0); + } + + /* Create the mesh file */ + + if(!(msh->hdl = fopen(msh->FilNam, "wb"))) + { + free (msh); + return(0); + } + + GmfMshTab[ MshIdx ] = msh; + + + /*------------*/ + /* KW WRITING */ + /*------------*/ + + /* Write the mesh version and dimension */ + + if(msh->typ & Asc) + { + fprintf(msh->hdl, "%s %d\n\n", GmfKwdFmt[ GmfVersionFormatted ][0], msh->ver); + fprintf(msh->hdl, "%s %d\n", GmfKwdFmt[ GmfDimension ][0], msh->dim); + } + else + { + RecWrd(msh, (unsigned char *)&msh->cod); + RecWrd(msh, (unsigned char *)&msh->ver); + GmfSetKwd(MshIdx, GmfDimension, 0); + RecWrd(msh, (unsigned char *)&msh->dim); + } + + return(MshIdx); + } + else + { + free (msh); + return(0); } } /*----------------------------------------------------------*/ -/* Close a meshfile in the right way */ +/* Close a meshfile in the right way */ /*----------------------------------------------------------*/ int GmfCloseMesh(int MshIdx) { - int res = 1; - GmfMshSct *msh; + int res = 1; + GmfMshSct *msh; - if( (MshIdx < 1) || (MshIdx > MaxMsh) ) - return(0); + if( (MshIdx < 1) || (MshIdx > MaxMsh) ) + return(0); - msh = GmfMshTab[ MshIdx ]; - RecBlk(msh, msh->buf, 0); + msh = GmfMshTab[ MshIdx ]; + RecBlk(msh, msh->buf, 0); - /* In write down the "End" kw in write mode */ + /* In write down the "End" kw in write mode */ - if(msh->mod == GmfWrite){ - if(msh->typ & Asc) - fprintf(msh->hdl, "\n%s\n", GmfKwdFmt[ GmfEnd ][0]); - else - GmfSetKwd(MshIdx, GmfEnd, 0); - } - /* Close the file and free the mesh structure */ + if(msh->mod == GmfWrite){ + if(msh->typ & Asc) + fprintf(msh->hdl, "\n%s\n", GmfKwdFmt[ GmfEnd ][0]); + else + GmfSetKwd(MshIdx, GmfEnd, 0); + } + /* Close the file and free the mesh structure */ - if(fclose(msh->hdl)) - res = 0; + if(fclose(msh->hdl)) + res = 0; - free(msh); - GmfMshTab[ MshIdx ] = NULL; + free(msh); + GmfMshTab[ MshIdx ] = NULL; - return(res); + return(res); } @@ -481,866 +481,866 @@ int GmfCloseMesh(int MshIdx) int GmfStatKwd(int MshIdx, int KwdCod, ...) { - int i, *PtrNmbTyp, *PtrSolSiz, *TypTab; - GmfMshSct *msh; - KwdSct *kwd; - va_list VarArg; + int i, *PtrNmbTyp, *PtrSolSiz, *TypTab; + GmfMshSct *msh; + KwdSct *kwd; + va_list VarArg; - if( (MshIdx < 1) || (MshIdx > MaxMsh) ) - return(0); + if( (MshIdx < 1) || (MshIdx > MaxMsh) ) + return(0); - msh = GmfMshTab[ MshIdx ]; + msh = GmfMshTab[ MshIdx ]; - if( (KwdCod < 1) || (KwdCod > GmfMaxKwd) ) - return(0); + if( (KwdCod < 1) || (KwdCod > GmfMaxKwd) ) + return(0); - kwd = &msh->KwdTab[ KwdCod ]; + kwd = &msh->KwdTab[ KwdCod ]; - if(!kwd->NmbLin) - return(0); + if(!kwd->NmbLin) + return(0); - /* Read further arguments if this kw is a sol */ + /* Read further arguments if this kw is a sol */ - if(kwd->typ == SolKwd) - { - va_start(VarArg, KwdCod); + if(kwd->typ == SolKwd) + { + va_start(VarArg, KwdCod); - PtrNmbTyp = va_arg(VarArg, int *); - *PtrNmbTyp = kwd->NmbTyp; + PtrNmbTyp = va_arg(VarArg, int *); + *PtrNmbTyp = kwd->NmbTyp; - PtrSolSiz = va_arg(VarArg, int *); - *PtrSolSiz = kwd->SolSiz; + PtrSolSiz = va_arg(VarArg, int *); + *PtrSolSiz = kwd->SolSiz; - TypTab = va_arg(VarArg, int *); + TypTab = va_arg(VarArg, int *); - for(i=0;iNmbTyp;i++) - TypTab[i] = kwd->TypTab[i]; + for(i=0;iNmbTyp;i++) + TypTab[i] = kwd->TypTab[i]; - va_end(VarArg); - } + va_end(VarArg); + } - return(kwd->NmbLin); + return(kwd->NmbLin); } /*----------------------------------------------------------*/ -/* Set the current file position to a given kwd */ +/* Set the current file position to a given kwd */ /*----------------------------------------------------------*/ int GmfGotoKwd(int MshIdx, int KwdCod) { - GmfMshSct *msh; - KwdSct *kwd; + GmfMshSct *msh; + KwdSct *kwd; - if( (MshIdx < 1) || (MshIdx > MaxMsh) ) - return(0); + if( (MshIdx < 1) || (MshIdx > MaxMsh) ) + return(0); - msh = GmfMshTab[ MshIdx ]; + msh = GmfMshTab[ MshIdx ]; - if( (KwdCod < 1) || (KwdCod > GmfMaxKwd) ) - return(0); + if( (KwdCod < 1) || (KwdCod > GmfMaxKwd) ) + return(0); - kwd = &msh->KwdTab[ KwdCod ]; + kwd = &msh->KwdTab[ KwdCod ]; - if(!kwd->NmbLin) - return(0); + if(!kwd->NmbLin) + return(0); - return(fseek(msh->hdl, kwd->pos, SEEK_SET)); + return(fseek(msh->hdl, kwd->pos, SEEK_SET)); } /*----------------------------------------------------------*/ -/* Write the kwd and set the number of lines */ +/* Write the kwd and set the number of lines */ /*----------------------------------------------------------*/ int GmfSetKwd(int MshIdx, int KwdCod, ...) { - int i, NmbLin=0, *TypTab; - long CurPos; - va_list VarArg; - GmfMshSct *msh; - KwdSct *kwd; + int i, NmbLin=0, *TypTab; + long CurPos; + va_list VarArg; + GmfMshSct *msh; + KwdSct *kwd; - if( (MshIdx < 1) || (MshIdx > MaxMsh) ) - return(0); + if( (MshIdx < 1) || (MshIdx > MaxMsh) ) + return(0); - msh = GmfMshTab[ MshIdx ]; - RecBlk(msh, msh->buf, 0); + msh = GmfMshTab[ MshIdx ]; + RecBlk(msh, msh->buf, 0); - if( (KwdCod < 1) || (KwdCod > GmfMaxKwd) ) - return(0); + if( (KwdCod < 1) || (KwdCod > GmfMaxKwd) ) + return(0); - kwd = &msh->KwdTab[ KwdCod ]; + kwd = &msh->KwdTab[ KwdCod ]; - /* Read further arguments if this kw has a header */ + /* Read further arguments if this kw has a header */ - if(strlen(GmfKwdFmt[ KwdCod ][2])) - { - va_start(VarArg, KwdCod); - NmbLin = va_arg(VarArg, int); + if(strlen(GmfKwdFmt[ KwdCod ][2])) + { + va_start(VarArg, KwdCod); + NmbLin = va_arg(VarArg, int); - if(!strcmp(GmfKwdFmt[ KwdCod ][3], "sr")) - { - kwd->NmbTyp = va_arg(VarArg, int); - TypTab = va_arg(VarArg, int *); + if(!strcmp(GmfKwdFmt[ KwdCod ][3], "sr")) + { + kwd->NmbTyp = va_arg(VarArg, int); + TypTab = va_arg(VarArg, int *); - for(i=0;iNmbTyp;i++) - kwd->TypTab[i] = TypTab[i]; - } + for(i=0;iNmbTyp;i++) + kwd->TypTab[i] = TypTab[i]; + } - va_end(VarArg); - } + va_end(VarArg); + } - /* Setup the kwd info */ + /* Setup the kwd info */ - ExpFmt(msh, KwdCod); + ExpFmt(msh, KwdCod); - if(!kwd->typ) - return(0); - else if(kwd->typ == InfKwd) - kwd->NmbLin = 1; - else - kwd->NmbLin = NmbLin; + if(!kwd->typ) + return(0); + else if(kwd->typ == InfKwd) + kwd->NmbLin = 1; + else + kwd->NmbLin = NmbLin; - /* Store the next kwd position in binary file */ + /* Store the next kwd position in binary file */ - if( (msh->typ & Bin) && msh->NexKwdPos ) - { - CurPos = ftell(msh->hdl); - fseek(msh->hdl, msh->NexKwdPos, SEEK_SET); - SetPos(msh, CurPos); - fseek(msh->hdl, CurPos, SEEK_SET); - } + if( (msh->typ & Bin) && msh->NexKwdPos ) + { + CurPos = ftell(msh->hdl); + fseek(msh->hdl, msh->NexKwdPos, SEEK_SET); + SetPos(msh, CurPos); + fseek(msh->hdl, CurPos, SEEK_SET); + } - /* Write the header */ + /* Write the header */ - if(msh->typ & Asc) - { - fprintf(msh->hdl, "\n%s\n", GmfKwdFmt[ KwdCod ][0]); + if(msh->typ & Asc) + { + fprintf(msh->hdl, "\n%s\n", GmfKwdFmt[ KwdCod ][0]); - if(kwd->typ != InfKwd) - fprintf(msh->hdl, "%d\n", kwd->NmbLin); + if(kwd->typ != InfKwd) + fprintf(msh->hdl, "%d\n", kwd->NmbLin); - /* In case of solution field, write the extended header */ + /* In case of solution field, write the extended header */ - if(kwd->typ == SolKwd) - { - fprintf(msh->hdl, "%d ", kwd->NmbTyp); + if(kwd->typ == SolKwd) + { + fprintf(msh->hdl, "%d ", kwd->NmbTyp); - for(i=0;iNmbTyp;i++) - fprintf(msh->hdl, "%d ", kwd->TypTab[i]); + for(i=0;iNmbTyp;i++) + fprintf(msh->hdl, "%d ", kwd->TypTab[i]); - fprintf(msh->hdl, "\n\n"); - } - } - else - { - RecWrd(msh, (unsigned char *)&KwdCod); - msh->NexKwdPos = ftell(msh->hdl); - SetPos(msh, 0); + fprintf(msh->hdl, "\n\n"); + } + } + else + { + RecWrd(msh, (unsigned char *)&KwdCod); + msh->NexKwdPos = ftell(msh->hdl); + SetPos(msh, 0); - if(kwd->typ != InfKwd) - RecWrd(msh, (unsigned char *)&kwd->NmbLin); + if(kwd->typ != InfKwd) + RecWrd(msh, (unsigned char *)&kwd->NmbLin); - /* In case of solution field, write the extended header at once */ + /* In case of solution field, write the extended header at once */ - if(kwd->typ == SolKwd) - { - RecWrd(msh, (unsigned char *)&kwd->NmbTyp); + if(kwd->typ == SolKwd) + { + RecWrd(msh, (unsigned char *)&kwd->NmbTyp); - for(i=0;iNmbTyp;i++) - RecWrd(msh, (unsigned char *)&kwd->TypTab[i]); - } - } + for(i=0;iNmbTyp;i++) + RecWrd(msh, (unsigned char *)&kwd->TypTab[i]); + } + } - /* Reset write buffer position */ - msh->pos = 0; + /* Reset write buffer position */ + msh->pos = 0; - /* Estimate the total file size and check whether it crosses the 2GB threshold */ + /* Estimate the total file size and check whether it crosses the 2GB threshold */ - msh->siz += kwd->NmbLin * kwd->NmbWrd * WrdSiz; + msh->siz += kwd->NmbLin * kwd->NmbWrd * WrdSiz; - if(msh->siz > 2E9) - return(0); - else - return(kwd->NmbLin); + if(msh->siz > 2E9) + return(0); + else + return(kwd->NmbLin); } /*----------------------------------------------------------*/ -/* Read a full line from the current kwd */ +/* Read a full line from the current kwd */ /*----------------------------------------------------------*/ void GmfGetLin(int MshIdx, int KwdCod, ...) { - int i, j; - float *FltSolTab; - double *DblSolTab; - va_list VarArg; - GmfMshSct *msh = GmfMshTab[ MshIdx ]; - KwdSct *kwd = &msh->KwdTab[ KwdCod ]; - - /* Start decoding the arguments */ - - va_start(VarArg, KwdCod); - - if(kwd->typ != SolKwd) - { - int k, nb_repeat = 0; - - if(msh->ver == 1) - { - if(msh->typ & Asc) - { - for(i=0;iSolSiz;i++) - if(kwd->fmt[i] == 'r') - fscanf(msh->hdl, "%f", va_arg(VarArg, float *)); - else if(kwd->fmt[i] == 'n') { - fscanf(msh->hdl, "%d", &nb_repeat); - *(va_arg(VarArg, int *)) = nb_repeat; - for(k=0;khdl, "%d", va_arg(VarArg, int *)); - } - else - fscanf(msh->hdl, "%d", va_arg(VarArg, int *)); - } - else - { - for(i=0;iSolSiz;i++) - if(kwd->fmt[i] == 'r') - ScaWrd(msh, (unsigned char *)va_arg(VarArg, float *)); - else if(kwd->fmt[i] == 'n') { - ScaWrd(msh, (unsigned char *)&nb_repeat); - *(va_arg(VarArg, int *)) = nb_repeat; - for(k=0;ktyp & Asc) - { - for(i=0;iSolSiz;i++) - if(kwd->fmt[i] == 'r') - fscanf(msh->hdl, "%lf", va_arg(VarArg, double *)); - else if(kwd->fmt[i] == 'n') { - fscanf(msh->hdl, "%d", &nb_repeat); - *(va_arg(VarArg, int *)) = nb_repeat; - for(k=0;khdl, "%d", va_arg(VarArg, int *)); - } - else - fscanf(msh->hdl, "%d", va_arg(VarArg, int *)); - } - else - for(i=0;iSolSiz;i++) - if(kwd->fmt[i] == 'r') - ScaDblWrd(msh, (unsigned char *)va_arg(VarArg, double *)); - else if(kwd->fmt[i] == 'n') { - ScaWrd(msh, (unsigned char *)&nb_repeat); - *(va_arg(VarArg, int *)) = nb_repeat; - for(k=0;kver == 1) - { - FltSolTab = va_arg(VarArg, float *); - - if(msh->typ & Asc) - for(j=0;jSolSiz;j++) - fscanf(msh->hdl, "%f", &FltSolTab[j]); - else - ScaBlk(msh, (unsigned char *)FltSolTab, kwd->NmbWrd); - } - else - { - DblSolTab = va_arg(VarArg, double *); - - if(msh->typ & Asc) - for(j=0;jSolSiz;j++) - fscanf(msh->hdl, "%lf", &DblSolTab[j]); - else - for(j=0;jSolSiz;j++) - ScaDblWrd(msh, (unsigned char *)&DblSolTab[j]); - } - } - - va_end(VarArg); + int i, j; + float *FltSolTab; + double *DblSolTab; + va_list VarArg; + GmfMshSct *msh = GmfMshTab[ MshIdx ]; + KwdSct *kwd = &msh->KwdTab[ KwdCod ]; + + /* Start decoding the arguments */ + + va_start(VarArg, KwdCod); + + if(kwd->typ != SolKwd) + { + int k, nb_repeat = 0; + + if(msh->ver == 1) + { + if(msh->typ & Asc) + { + for(i=0;iSolSiz;i++) + if(kwd->fmt[i] == 'r') + fscanf(msh->hdl, "%f", va_arg(VarArg, float *)); + else if(kwd->fmt[i] == 'n') { + fscanf(msh->hdl, "%d", &nb_repeat); + *(va_arg(VarArg, int *)) = nb_repeat; + for(k=0;khdl, "%d", va_arg(VarArg, int *)); + } + else + fscanf(msh->hdl, "%d", va_arg(VarArg, int *)); + } + else + { + for(i=0;iSolSiz;i++) + if(kwd->fmt[i] == 'r') + ScaWrd(msh, (unsigned char *)va_arg(VarArg, float *)); + else if(kwd->fmt[i] == 'n') { + ScaWrd(msh, (unsigned char *)&nb_repeat); + *(va_arg(VarArg, int *)) = nb_repeat; + for(k=0;ktyp & Asc) + { + for(i=0;iSolSiz;i++) + if(kwd->fmt[i] == 'r') + fscanf(msh->hdl, "%lf", va_arg(VarArg, double *)); + else if(kwd->fmt[i] == 'n') { + fscanf(msh->hdl, "%d", &nb_repeat); + *(va_arg(VarArg, int *)) = nb_repeat; + for(k=0;khdl, "%d", va_arg(VarArg, int *)); + } + else + fscanf(msh->hdl, "%d", va_arg(VarArg, int *)); + } + else + for(i=0;iSolSiz;i++) + if(kwd->fmt[i] == 'r') + ScaDblWrd(msh, (unsigned char *)va_arg(VarArg, double *)); + else if(kwd->fmt[i] == 'n') { + ScaWrd(msh, (unsigned char *)&nb_repeat); + *(va_arg(VarArg, int *)) = nb_repeat; + for(k=0;kver == 1) + { + FltSolTab = va_arg(VarArg, float *); + + if(msh->typ & Asc) + for(j=0;jSolSiz;j++) + fscanf(msh->hdl, "%f", &FltSolTab[j]); + else + ScaBlk(msh, (unsigned char *)FltSolTab, kwd->NmbWrd); + } + else + { + DblSolTab = va_arg(VarArg, double *); + + if(msh->typ & Asc) + for(j=0;jSolSiz;j++) + fscanf(msh->hdl, "%lf", &DblSolTab[j]); + else + for(j=0;jSolSiz;j++) + ScaDblWrd(msh, (unsigned char *)&DblSolTab[j]); + } + } + + va_end(VarArg); } /*----------------------------------------------------------*/ -/* Write a full line from the current kwd */ +/* Write a full line from the current kwd */ /*----------------------------------------------------------*/ void GmfSetLin(int MshIdx, int KwdCod, ...) { - int i, j, pos, *IntBuf; - float *FltSolTab; - double *DblSolTab, *DblBuf; - va_list VarArg; - GmfMshSct *msh = GmfMshTab[ MshIdx ]; - KwdSct *kwd = &msh->KwdTab[ KwdCod ]; - - /* Start decoding the arguments */ - - va_start(VarArg, KwdCod); - - if(kwd->typ != SolKwd) - { - int k, nb_repeat = 0; - - if(msh->ver == 1) - { - if(msh->typ & Asc) - { - for(i=0;iSolSiz;i++) - if(kwd->fmt[i] == 'r') - fprintf(msh->hdl, "%g ", (float)va_arg(VarArg, double)); - else if(kwd->fmt[i] == 'n') { - nb_repeat = va_arg(VarArg, int); - fprintf(msh->hdl, "%d ", nb_repeat); - for(k=0;khdl, "%d ", va_arg(VarArg, int)); - } - else - fprintf(msh->hdl, "%d ", va_arg(VarArg, int)); - } - else - { - int size_of_block = kwd->SolSiz; - for(i=0;iSolSiz;i++) - if(kwd->fmt[i] == 'r') - msh->FltBuf[i] = va_arg(VarArg, double); - else if(kwd->fmt[i] == 'n') { - nb_repeat = va_arg(VarArg, int); - msh->FltBuf[i] = nb_repeat; - for(k=0;kIntBuf[i+1+k] = va_arg(VarArg, int); - size_of_block ++; - } - } - else - msh->IntBuf[i] = va_arg(VarArg, int); - - RecBlk(msh, msh->buf, size_of_block); - } - } - else - { - if(msh->typ & Asc) - { - for(i=0;iSolSiz;i++) - if(kwd->fmt[i] == 'r') - fprintf(msh->hdl, "%.15lg ", va_arg(VarArg, double)); - else if(kwd->fmt[i] == 'n') { - nb_repeat = va_arg(VarArg, int); - fprintf(msh->hdl, "%d ", nb_repeat); - for(k=0;khdl, "%d ", va_arg(VarArg, int)); - } - else - fprintf(msh->hdl, "%d ", va_arg(VarArg, int)); - } - else - { - pos = 0; - - for(i=0;iSolSiz;i++) - if(kwd->fmt[i] == 'r') - { - DblBuf = (double *)&msh->buf[ pos ]; - *DblBuf = va_arg(VarArg, double); - pos += 8; - } - else if(kwd->fmt[i] == 'n') - { - IntBuf = (int *)&msh->buf[ pos ]; - nb_repeat = va_arg(VarArg, int); - *IntBuf = nb_repeat; - pos += 4; - for(k=0;kbuf[ pos ]; - *IntBuf = va_arg(VarArg, int); - pos += 4; - } - } - else - { - IntBuf = (int *)&msh->buf[ pos ]; - *IntBuf = va_arg(VarArg, int); - pos += 4; - } - RecBlk(msh, msh->buf, pos/4); - } - } - } - else - { - if(msh->ver == 1) - { - FltSolTab = va_arg(VarArg, float *); - - if(msh->typ & Asc) - for(j=0;jSolSiz;j++) - fprintf(msh->hdl, "%g ", FltSolTab[j]); - else - RecBlk(msh, (unsigned char *)FltSolTab, kwd->NmbWrd); - } - else - { - DblSolTab = va_arg(VarArg, double *); - - if(msh->typ & Asc) - for(j=0;jSolSiz;j++) - fprintf(msh->hdl, "%.15lg ", DblSolTab[j]); - else - RecBlk(msh, (unsigned char *)DblSolTab, kwd->NmbWrd); - } - } - - va_end(VarArg); - - if(msh->typ & Asc) - fprintf(msh->hdl, "\n"); + int i, j, pos, *IntBuf; + float *FltSolTab; + double *DblSolTab, *DblBuf; + va_list VarArg; + GmfMshSct *msh = GmfMshTab[ MshIdx ]; + KwdSct *kwd = &msh->KwdTab[ KwdCod ]; + + /* Start decoding the arguments */ + + va_start(VarArg, KwdCod); + + if(kwd->typ != SolKwd) + { + int k, nb_repeat = 0; + + if(msh->ver == 1) + { + if(msh->typ & Asc) + { + for(i=0;iSolSiz;i++) + if(kwd->fmt[i] == 'r') + fprintf(msh->hdl, "%g ", (float)va_arg(VarArg, double)); + else if(kwd->fmt[i] == 'n') { + nb_repeat = va_arg(VarArg, int); + fprintf(msh->hdl, "%d ", nb_repeat); + for(k=0;khdl, "%d ", va_arg(VarArg, int)); + } + else + fprintf(msh->hdl, "%d ", va_arg(VarArg, int)); + } + else + { + int size_of_block = kwd->SolSiz; + for(i=0;iSolSiz;i++) + if(kwd->fmt[i] == 'r') + msh->FltBuf[i] = va_arg(VarArg, double); + else if(kwd->fmt[i] == 'n') { + nb_repeat = va_arg(VarArg, int); + msh->FltBuf[i] = nb_repeat; + for(k=0;kIntBuf[i+1+k] = va_arg(VarArg, int); + size_of_block ++; + } + } + else + msh->IntBuf[i] = va_arg(VarArg, int); + + RecBlk(msh, msh->buf, size_of_block); + } + } + else + { + if(msh->typ & Asc) + { + for(i=0;iSolSiz;i++) + if(kwd->fmt[i] == 'r') + fprintf(msh->hdl, "%.15lg ", va_arg(VarArg, double)); + else if(kwd->fmt[i] == 'n') { + nb_repeat = va_arg(VarArg, int); + fprintf(msh->hdl, "%d ", nb_repeat); + for(k=0;khdl, "%d ", va_arg(VarArg, int)); + } + else + fprintf(msh->hdl, "%d ", va_arg(VarArg, int)); + } + else + { + pos = 0; + + for(i=0;iSolSiz;i++) + if(kwd->fmt[i] == 'r') + { + DblBuf = (double *)&msh->buf[ pos ]; + *DblBuf = va_arg(VarArg, double); + pos += 8; + } + else if(kwd->fmt[i] == 'n') + { + IntBuf = (int *)&msh->buf[ pos ]; + nb_repeat = va_arg(VarArg, int); + *IntBuf = nb_repeat; + pos += 4; + for(k=0;kbuf[ pos ]; + *IntBuf = va_arg(VarArg, int); + pos += 4; + } + } + else + { + IntBuf = (int *)&msh->buf[ pos ]; + *IntBuf = va_arg(VarArg, int); + pos += 4; + } + RecBlk(msh, msh->buf, pos/4); + } + } + } + else + { + if(msh->ver == 1) + { + FltSolTab = va_arg(VarArg, float *); + + if(msh->typ & Asc) + for(j=0;jSolSiz;j++) + fprintf(msh->hdl, "%g ", FltSolTab[j]); + else + RecBlk(msh, (unsigned char *)FltSolTab, kwd->NmbWrd); + } + else + { + DblSolTab = va_arg(VarArg, double *); + + if(msh->typ & Asc) + for(j=0;jSolSiz;j++) + fprintf(msh->hdl, "%.15lg ", DblSolTab[j]); + else + RecBlk(msh, (unsigned char *)DblSolTab, kwd->NmbWrd); + } + } + + va_end(VarArg); + + if(msh->typ & Asc) + fprintf(msh->hdl, "\n"); } /*----------------------------------------------------------*/ -/* Private procedure for transmesh : copy a whole line */ +/* Private procedure for transmesh : copy a whole line */ /*----------------------------------------------------------*/ void GmfCpyLin(int InpIdx, int OutIdx, int KwdCod) { - double d; - float f; - int i, a; - GmfMshSct *InpMsh = GmfMshTab[ InpIdx ], *OutMsh = GmfMshTab[ OutIdx ]; - KwdSct *kwd = &InpMsh->KwdTab[ KwdCod ]; - - for(i=0;iSolSiz;i++) - { - if(kwd->fmt[i] == 'r') - { - if(InpMsh->ver == 1) - { - if(InpMsh->typ & Asc) - fscanf(InpMsh->hdl, "%f", &f); - else - ScaWrd(InpMsh, (unsigned char *)&f); - - d = f; - } - else - { - if(InpMsh->typ & Asc) - fscanf(InpMsh->hdl, "%lf", &d); - else - ScaDblWrd(InpMsh, (unsigned char *)&d); - - f = (float)d; - } - - if(OutMsh->ver == 1) - if(OutMsh->typ & Asc) - fprintf(OutMsh->hdl, "%g ", f); - else - RecWrd(OutMsh, (unsigned char *)&f); - else - if(OutMsh->typ & Asc) - fprintf(OutMsh->hdl, "%.15g ", d); - else - RecDblWrd(OutMsh, (unsigned char *)&d); - } - else if(kwd->fmt[i] == 'n') - { - int k, nb_repeat = 0; - - if(InpMsh->typ & Asc) - fscanf(InpMsh->hdl, "%d", &a); - else - ScaWrd(InpMsh, (unsigned char *)&a); - - nb_repeat = a; - - if(OutMsh->typ & Asc) - fprintf(OutMsh->hdl, "%d ", a); - else - RecWrd(OutMsh, (unsigned char *)&a); - - for(k=0;ktyp & Asc) - fscanf(InpMsh->hdl, "%d", &a); - else - ScaWrd(InpMsh, (unsigned char *)&a); - - if(OutMsh->typ & Asc) - fprintf(OutMsh->hdl, "%d ", a); - else - RecWrd(OutMsh, (unsigned char *)&a); - } - } - else - { - if(InpMsh->typ & Asc) - fscanf(InpMsh->hdl, "%d", &a); - else - ScaWrd(InpMsh, (unsigned char *)&a); - - if(OutMsh->typ & Asc) - fprintf(OutMsh->hdl, "%d ", a); - else - RecWrd(OutMsh, (unsigned char *)&a); - } - } - - if(OutMsh->typ & Asc) - fprintf(OutMsh->hdl, "\n"); + double d; + float f; + int i, a; + GmfMshSct *InpMsh = GmfMshTab[ InpIdx ], *OutMsh = GmfMshTab[ OutIdx ]; + KwdSct *kwd = &InpMsh->KwdTab[ KwdCod ]; + + for(i=0;iSolSiz;i++) + { + if(kwd->fmt[i] == 'r') + { + if(InpMsh->ver == 1) + { + if(InpMsh->typ & Asc) + fscanf(InpMsh->hdl, "%f", &f); + else + ScaWrd(InpMsh, (unsigned char *)&f); + + d = f; + } + else + { + if(InpMsh->typ & Asc) + fscanf(InpMsh->hdl, "%lf", &d); + else + ScaDblWrd(InpMsh, (unsigned char *)&d); + + f = (float)d; + } + + if(OutMsh->ver == 1) + if(OutMsh->typ & Asc) + fprintf(OutMsh->hdl, "%g ", f); + else + RecWrd(OutMsh, (unsigned char *)&f); + else + if(OutMsh->typ & Asc) + fprintf(OutMsh->hdl, "%.15g ", d); + else + RecDblWrd(OutMsh, (unsigned char *)&d); + } + else if(kwd->fmt[i] == 'n') + { + int k, nb_repeat = 0; + + if(InpMsh->typ & Asc) + fscanf(InpMsh->hdl, "%d", &a); + else + ScaWrd(InpMsh, (unsigned char *)&a); + + nb_repeat = a; + + if(OutMsh->typ & Asc) + fprintf(OutMsh->hdl, "%d ", a); + else + RecWrd(OutMsh, (unsigned char *)&a); + + for(k=0;ktyp & Asc) + fscanf(InpMsh->hdl, "%d", &a); + else + ScaWrd(InpMsh, (unsigned char *)&a); + + if(OutMsh->typ & Asc) + fprintf(OutMsh->hdl, "%d ", a); + else + RecWrd(OutMsh, (unsigned char *)&a); + } + } + else + { + if(InpMsh->typ & Asc) + fscanf(InpMsh->hdl, "%d", &a); + else + ScaWrd(InpMsh, (unsigned char *)&a); + + if(OutMsh->typ & Asc) + fprintf(OutMsh->hdl, "%d ", a); + else + RecWrd(OutMsh, (unsigned char *)&a); + } + } + + if(OutMsh->typ & Asc) + fprintf(OutMsh->hdl, "\n"); } /*----------------------------------------------------------*/ -/* Find every kw present in a meshfile */ +/* Find every kw present in a meshfile */ /*----------------------------------------------------------*/ static int ScaKwdTab(GmfMshSct *msh) { - int KwdCod; - long NexPos, CurPos, EndPos; - char str[ GmfStrSiz ]; - - if(msh->typ & Asc) - { - /* Scan each string in the file until the end */ - - while(fscanf(msh->hdl, "%s", str) != EOF) - { - /* Fast test in order to reject quickly the numeric values */ - - if(isalpha(str[0])) - { - /* Search which kwd code this string is associated with, - then get its header and save the curent position in file (just before the data) */ - - for(KwdCod=1; KwdCod<= GmfMaxKwd; KwdCod++) - if(!strcmp(str, GmfKwdFmt[ KwdCod ][0])) - { - ScaKwdHdr(msh, KwdCod); - break; - } - } - else if(str[0] == '#') - while(fgetc(msh->hdl) != '\n'); - } - } - else - { - /* Get file size */ - - CurPos = ftell(msh->hdl); - fseek(msh->hdl, 0, SEEK_END); - EndPos = ftell(msh->hdl); - fseek(msh->hdl, CurPos, SEEK_SET); - - /* Jump through kwd positions in the file */ - - do - { - /* Get the kwd code and the next kwd position */ - - ScaWrd(msh, (unsigned char *)&KwdCod); - NexPos = GetPos(msh); - - if(NexPos > EndPos) - return(0); - - /* Check if this kwd belongs to this mesh version */ - - if( (KwdCod >= 1) && (KwdCod <= GmfMaxKwd) ) - ScaKwdHdr(msh, KwdCod); - - /* Go to the next kwd */ - - if(NexPos) - fseek(msh->hdl, NexPos, SEEK_SET); - }while(NexPos && (KwdCod != GmfEnd)); - } - - return(1); + int KwdCod; + long NexPos, CurPos, EndPos; + char str[ GmfStrSiz ]; + + if(msh->typ & Asc) + { + /* Scan each string in the file until the end */ + + while(fscanf(msh->hdl, "%s", str) != EOF) + { + /* Fast test in order to reject quickly the numeric values */ + + if(isalpha(str[0])) + { + /* Search which kwd code this string is associated with, + then get its header and save the curent position in file (just before the data) */ + + for(KwdCod=1; KwdCod<= GmfMaxKwd; KwdCod++) + if(!strcmp(str, GmfKwdFmt[ KwdCod ][0])) + { + ScaKwdHdr(msh, KwdCod); + break; + } + } + else if(str[0] == '#') + while(fgetc(msh->hdl) != '\n'); + } + } + else + { + /* Get file size */ + + CurPos = ftell(msh->hdl); + fseek(msh->hdl, 0, SEEK_END); + EndPos = ftell(msh->hdl); + fseek(msh->hdl, CurPos, SEEK_SET); + + /* Jump through kwd positions in the file */ + + do + { + /* Get the kwd code and the next kwd position */ + + ScaWrd(msh, (unsigned char *)&KwdCod); + NexPos = GetPos(msh); + + if(NexPos > EndPos) + return(0); + + /* Check if this kwd belongs to this mesh version */ + + if( (KwdCod >= 1) && (KwdCod <= GmfMaxKwd) ) + ScaKwdHdr(msh, KwdCod); + + /* Go to the next kwd */ + + if(NexPos) + fseek(msh->hdl, NexPos, SEEK_SET); + }while(NexPos && (KwdCod != GmfEnd)); + } + + return(1); } /*----------------------------------------------------------*/ -/* Read and setup the keyword's header */ +/* Read and setup the keyword's header */ /*----------------------------------------------------------*/ static void ScaKwdHdr(GmfMshSct *msh, int KwdCod) { - int i; - KwdSct *kwd = &msh->KwdTab[ KwdCod ]; - - if(!strcmp("i", GmfKwdFmt[ KwdCod ][2])) - { - if(msh->typ & Asc) - fscanf(msh->hdl, "%d", &kwd->NmbLin); - else - ScaWrd(msh, (unsigned char *)&kwd->NmbLin); - } - else - kwd->NmbLin = 1; - - if(!strcmp("sr", GmfKwdFmt[ KwdCod ][3])) - { - if(msh->typ & Asc) - { - fscanf(msh->hdl, "%d", &kwd->NmbTyp); - - for(i=0;iNmbTyp;i++) - fscanf(msh->hdl, "%d", &kwd->TypTab[i]); - } - else - { - ScaWrd(msh, (unsigned char *)&kwd->NmbTyp); - - for(i=0;iNmbTyp;i++) - ScaWrd(msh, (unsigned char *)&kwd->TypTab[i]); - } - } - - ExpFmt(msh, KwdCod); - kwd->pos = ftell(msh->hdl); + int i; + KwdSct *kwd = &msh->KwdTab[ KwdCod ]; + + if(!strcmp("i", GmfKwdFmt[ KwdCod ][2])) + { + if(msh->typ & Asc) + fscanf(msh->hdl, "%d", &kwd->NmbLin); + else + ScaWrd(msh, (unsigned char *)&kwd->NmbLin); + } + else + kwd->NmbLin = 1; + + if(!strcmp("sr", GmfKwdFmt[ KwdCod ][3])) + { + if(msh->typ & Asc) + { + fscanf(msh->hdl, "%d", &kwd->NmbTyp); + + for(i=0;iNmbTyp;i++) + fscanf(msh->hdl, "%d", &kwd->TypTab[i]); + } + else + { + ScaWrd(msh, (unsigned char *)&kwd->NmbTyp); + + for(i=0;iNmbTyp;i++) + ScaWrd(msh, (unsigned char *)&kwd->TypTab[i]); + } + } + + ExpFmt(msh, KwdCod); + kwd->pos = ftell(msh->hdl); } /*----------------------------------------------------------*/ -/* Expand the compacted format and compute the line size */ +/* Expand the compacted format and compute the line size */ /*----------------------------------------------------------*/ static void ExpFmt(GmfMshSct *msh, int KwdCod) { - int i, j, TmpSiz=0; - char chr; - const char *InpFmt = GmfKwdFmt[ KwdCod ][3]; - KwdSct *kwd = &msh->KwdTab[ KwdCod ]; - - /* Set the kwd's type */ - - if(!strlen(GmfKwdFmt[ KwdCod ][2])) - kwd->typ = InfKwd; - else if(!strcmp(InpFmt, "sr")) - kwd->typ = SolKwd; - else - kwd->typ = RegKwd; - - /* Get the solution-field's size */ - - if(kwd->typ == SolKwd) - for(i=0;iNmbTyp;i++) - switch(kwd->TypTab[i]) - { - case GmfSca : TmpSiz += 1; break; - case GmfVec : TmpSiz += msh->dim; break; - case GmfSymMat : TmpSiz += (msh->dim * (msh->dim+1)) / 2; break; - case GmfMat : TmpSiz += msh->dim * msh->dim; break; - } - - /* Scan each character from the format string */ - - i = kwd->SolSiz = kwd->NmbWrd = 0; - - while(i < strlen(InpFmt)) - { - chr = InpFmt[ i++ ]; - - if(chr == 'd') - { - chr = InpFmt[i++]; - - for(j=0;jdim;j++) - kwd->fmt[ kwd->SolSiz++ ] = chr; - } - else if(chr == 's') - { - chr = InpFmt[i++]; - - for(j=0;jfmt[ kwd->SolSiz++ ] = chr; - } - else - kwd->fmt[ kwd->SolSiz++ ] = chr; - } - - for(i=0;iSolSiz;i++) - if(kwd->fmt[i] == 'i') - kwd->NmbWrd++; - else if(msh->ver >= 2) - kwd->NmbWrd += 2; - else - kwd->NmbWrd++; + int i, j, TmpSiz=0; + char chr; + const char *InpFmt = GmfKwdFmt[ KwdCod ][3]; + KwdSct *kwd = &msh->KwdTab[ KwdCod ]; + + /* Set the kwd's type */ + + if(!strlen(GmfKwdFmt[ KwdCod ][2])) + kwd->typ = InfKwd; + else if(!strcmp(InpFmt, "sr")) + kwd->typ = SolKwd; + else + kwd->typ = RegKwd; + + /* Get the solution-field's size */ + + if(kwd->typ == SolKwd) + for(i=0;iNmbTyp;i++) + switch(kwd->TypTab[i]) + { + case GmfSca : TmpSiz += 1; break; + case GmfVec : TmpSiz += msh->dim; break; + case GmfSymMat : TmpSiz += (msh->dim * (msh->dim+1)) / 2; break; + case GmfMat : TmpSiz += msh->dim * msh->dim; break; + } + + /* Scan each character from the format string */ + + i = kwd->SolSiz = kwd->NmbWrd = 0; + + while(i < strlen(InpFmt)) + { + chr = InpFmt[ i++ ]; + + if(chr == 'd') + { + chr = InpFmt[i++]; + + for(j=0;jdim;j++) + kwd->fmt[ kwd->SolSiz++ ] = chr; + } + else if(chr == 's') + { + chr = InpFmt[i++]; + + for(j=0;jfmt[ kwd->SolSiz++ ] = chr; + } + else + kwd->fmt[ kwd->SolSiz++ ] = chr; + } + + for(i=0;iSolSiz;i++) + if(kwd->fmt[i] == 'i') + kwd->NmbWrd++; + else if(msh->ver >= 2) + kwd->NmbWrd += 2; + else + kwd->NmbWrd++; } /*----------------------------------------------------------*/ -/* Read a four bytes word from a mesh file */ +/* Read a four bytes word from a mesh file */ /*----------------------------------------------------------*/ static void ScaWrd(GmfMshSct *msh, unsigned char *wrd) { - unsigned char swp; + unsigned char swp; - fread(wrd, WrdSiz, 1, msh->hdl); + fread(wrd, WrdSiz, 1, msh->hdl); - if(msh->cod == 1) - return; + if(msh->cod == 1) + return; - swp = wrd[3]; - wrd[3] = wrd[0]; - wrd[0] = swp; + swp = wrd[3]; + wrd[3] = wrd[0]; + wrd[0] = swp; - swp = wrd[2]; - wrd[2] = wrd[1]; - wrd[1] = swp; + swp = wrd[2]; + wrd[2] = wrd[1]; + wrd[1] = swp; } /*----------------------------------------------------------*/ -/* Read an eight bytes word from a mesh file */ +/* Read an eight bytes word from a mesh file */ /*----------------------------------------------------------*/ static void ScaDblWrd(GmfMshSct *msh, unsigned char *wrd) { - int i; - unsigned char swp; + int i; + unsigned char swp; - fread(wrd, WrdSiz, 2, msh->hdl); + fread(wrd, WrdSiz, 2, msh->hdl); - if(msh->cod == 1) - return; + if(msh->cod == 1) + return; - for(i=0;i<4;i++) - { - swp = wrd[7-i]; - wrd[7-i] = wrd[i]; - wrd[i] = swp; - } + for(i=0;i<4;i++) + { + swp = wrd[7-i]; + wrd[7-i] = wrd[i]; + wrd[i] = swp; + } } /*----------------------------------------------------------*/ -/* Read ablock of four bytes word from a mesh file */ +/* Read ablock of four bytes word from a mesh file */ /*----------------------------------------------------------*/ static void ScaBlk(GmfMshSct *msh, unsigned char *blk, int siz) { - int i, j; - unsigned char swp, *wrd; + int i, j; + unsigned char swp, *wrd; - fread(blk, WrdSiz, siz, msh->hdl); + fread(blk, WrdSiz, siz, msh->hdl); - if(msh->cod == 1) - return; + if(msh->cod == 1) + return; - for(i=0;iver >= 3) - ScaDblWrd(msh, (unsigned char*)&pos); - else - { - ScaWrd(msh, (unsigned char*)&IntVal); - pos = IntVal; - } - - return(pos); + int IntVal; + long pos; + + if(msh->ver >= 3) + ScaDblWrd(msh, (unsigned char*)&pos); + else + { + ScaWrd(msh, (unsigned char*)&IntVal); + pos = IntVal; + } + + return(pos); } /*----------------------------------------------------------*/ -/* Write a four bytes word to a mesh file */ +/* Write a four bytes word to a mesh file */ /*----------------------------------------------------------*/ static void RecWrd(GmfMshSct *msh, unsigned char *wrd) { - fwrite(wrd, WrdSiz, 1, msh->hdl); + fwrite(wrd, WrdSiz, 1, msh->hdl); } /*----------------------------------------------------------*/ -/* Write an eight bytes word to a mesh file */ +/* Write an eight bytes word to a mesh file */ /*----------------------------------------------------------*/ static void RecDblWrd(GmfMshSct *msh, unsigned char *wrd) { - fwrite(wrd, WrdSiz, 2, msh->hdl); + fwrite(wrd, WrdSiz, 2, msh->hdl); } /*----------------------------------------------------------*/ -/* Write a block of four bytes word to a mesh file */ +/* Write a block of four bytes word to a mesh file */ /*----------------------------------------------------------*/ static void RecBlk(GmfMshSct *msh, unsigned char *blk, int siz) { - /* Copy this line-block into the main mesh buffer */ + /* Copy this line-block into the main mesh buffer */ - if(siz) - { - memcpy(&msh->blk[ msh->pos ], blk, siz * WrdSiz); - msh->pos += siz * WrdSiz; - } + if(siz) + { + memcpy(&msh->blk[ msh->pos ], blk, siz * WrdSiz); + msh->pos += siz * WrdSiz; + } - /* When the buffer is full or this procedure is called with a 0 size, flush the cache on disk */ + /* When the buffer is full or this procedure is called with a 0 size, flush the cache on disk */ - if( (msh->pos > BufSiz) || (!siz && msh->pos) ) - { - fwrite(msh->blk, 1, msh->pos, msh->hdl); - msh->pos = 0; - } + if( (msh->pos > BufSiz) || (!siz && msh->pos) ) + { + fwrite(msh->blk, 1, msh->pos, msh->hdl); + msh->pos = 0; + } } /*----------------------------------------------------------*/ -/* Write a 4 or 8 bytes position in a mesh file */ +/* Write a 4 or 8 bytes position in a mesh file */ /*----------------------------------------------------------*/ static void SetPos(GmfMshSct *msh, long pos) { - int IntVal; - - if(msh->ver >= 3) - RecDblWrd(msh, (unsigned char*)&pos); - else - { - IntVal = pos; - RecWrd(msh, (unsigned char*)&IntVal); - } + int IntVal; + + if(msh->ver >= 3) + RecDblWrd(msh, (unsigned char*)&pos); + else + { + IntVal = pos; + RecWrd(msh, (unsigned char*)&IntVal); + } } diff --git a/src/DriverGMF/libmesh5.h b/src/DriverGMF/libmesh5.h index 66579574d..066853f52 100644 --- a/src/DriverGMF/libmesh5.h +++ b/src/DriverGMF/libmesh5.h @@ -1,21 +1,21 @@ /*----------------------------------------------------------*/ -/* */ -/* LIBMESH V 5.46 */ -/* */ +/* */ +/* LIBMESH V 5.46 */ +/* */ /*----------------------------------------------------------*/ -/* */ -/* Description: handle .meshb file format I/O */ -/* Author: Loic MARECHAL */ -/* Creation date: feb 16 2007 */ -/* Last modification: dec 09 2011 */ -/* */ +/* */ +/* Description: handle .meshb file format I/O */ +/* Author: Loic MARECHAL */ +/* Creation date: feb 16 2007 */ +/* Last modification: dec 09 2011 */ +/* */ /*----------------------------------------------------------*/ /*----------------------------------------------------------*/ -/* Defines */ +/* Defines */ /*----------------------------------------------------------*/ #include "SMESH_DriverGMF.hxx" @@ -35,92 +35,92 @@ enum GmfKwdCod { - GmfReserved1, \ - GmfVersionFormatted, \ - GmfReserved2, \ - GmfDimension, \ - GmfVertices, \ - GmfEdges, \ - GmfTriangles, \ - GmfQuadrilaterals, \ - GmfTetrahedra, \ - GmfPrisms, \ - GmfHexahedra, \ - GmfIterationsAll, \ - GmfTimesAll, \ - GmfCorners, \ - GmfRidges, \ - GmfRequiredVertices, \ - GmfRequiredEdges, \ - GmfRequiredTriangles, \ - GmfRequiredQuadrilaterals, \ - GmfTangentAtEdgeVertices, \ - GmfNormalAtVertices, \ - GmfNormalAtTriangleVertices, \ - GmfNormalAtQuadrilateralVertices, \ - GmfAngleOfCornerBound, \ - GmfTrianglesP2, \ - GmfEdgesP2, \ - GmfSolAtPyramids, \ - GmfQuadrilateralsQ2, \ - GmfISolAtPyramids, \ - GmfSubDomainFromGeom, \ - GmfTetrahedraP2, \ - GmfFault_NearTri, \ - GmfFault_Inter, \ - GmfHexahedraQ2, \ - GmfExtraVerticesAtEdges, \ - GmfExtraVerticesAtTriangles, \ - GmfExtraVerticesAtQuadrilaterals, \ - GmfExtraVerticesAtTetrahedra, \ - GmfExtraVerticesAtPrisms, \ - GmfExtraVerticesAtHexahedra, \ - GmfVerticesOnGeometricVertices, \ - GmfVerticesOnGeometricEdges, \ - GmfVerticesOnGeometricTriangles, \ - GmfVerticesOnGeometricQuadrilaterals, \ - GmfEdgesOnGeometricEdges, \ - GmfFault_FreeEdge, \ - GmfPolyhedra, \ - GmfPolygons, \ - GmfFault_Overlap, \ - GmfPyramids, \ - GmfBoundingBox, \ - GmfBody, \ - GmfPrivateTable, \ - GmfFault_BadShape, \ - GmfEnd, \ - GmfTrianglesOnGeometricTriangles, \ - GmfTrianglesOnGeometricQuadrilaterals, \ - GmfQuadrilateralsOnGeometricTriangles, \ - GmfQuadrilateralsOnGeometricQuadrilaterals, \ - GmfTangents, \ - GmfNormals, \ - GmfTangentAtVertices, \ - GmfSolAtVertices, \ - GmfSolAtEdges, \ - GmfSolAtTriangles, \ - GmfSolAtQuadrilaterals, \ - GmfSolAtTetrahedra, \ - GmfSolAtPrisms, \ - GmfSolAtHexahedra, \ - GmfDSolAtVertices, \ - GmfISolAtVertices, \ - GmfISolAtEdges, \ - GmfISolAtTriangles, \ - GmfISolAtQuadrilaterals, \ - GmfISolAtTetrahedra, \ - GmfISolAtPrisms, \ - GmfISolAtHexahedra, \ - GmfIterations, \ - GmfTime, \ - GmfFault_SmallTri, \ - GmfCoarseHexahedra + GmfReserved1, \ + GmfVersionFormatted, \ + GmfReserved2, \ + GmfDimension, \ + GmfVertices, \ + GmfEdges, \ + GmfTriangles, \ + GmfQuadrilaterals, \ + GmfTetrahedra, \ + GmfPrisms, \ + GmfHexahedra, \ + GmfIterationsAll, \ + GmfTimesAll, \ + GmfCorners, \ + GmfRidges, \ + GmfRequiredVertices, \ + GmfRequiredEdges, \ + GmfRequiredTriangles, \ + GmfRequiredQuadrilaterals, \ + GmfTangentAtEdgeVertices, \ + GmfNormalAtVertices, \ + GmfNormalAtTriangleVertices, \ + GmfNormalAtQuadrilateralVertices, \ + GmfAngleOfCornerBound, \ + GmfTrianglesP2, \ + GmfEdgesP2, \ + GmfSolAtPyramids, \ + GmfQuadrilateralsQ2, \ + GmfISolAtPyramids, \ + GmfSubDomainFromGeom, \ + GmfTetrahedraP2, \ + GmfFault_NearTri, \ + GmfFault_Inter, \ + GmfHexahedraQ2, \ + GmfExtraVerticesAtEdges, \ + GmfExtraVerticesAtTriangles, \ + GmfExtraVerticesAtQuadrilaterals, \ + GmfExtraVerticesAtTetrahedra, \ + GmfExtraVerticesAtPrisms, \ + GmfExtraVerticesAtHexahedra, \ + GmfVerticesOnGeometricVertices, \ + GmfVerticesOnGeometricEdges, \ + GmfVerticesOnGeometricTriangles, \ + GmfVerticesOnGeometricQuadrilaterals, \ + GmfEdgesOnGeometricEdges, \ + GmfFault_FreeEdge, \ + GmfPolyhedra, \ + GmfPolygons, \ + GmfFault_Overlap, \ + GmfPyramids, \ + GmfBoundingBox, \ + GmfBody, \ + GmfPrivateTable, \ + GmfFault_BadShape, \ + GmfEnd, \ + GmfTrianglesOnGeometricTriangles, \ + GmfTrianglesOnGeometricQuadrilaterals, \ + GmfQuadrilateralsOnGeometricTriangles, \ + GmfQuadrilateralsOnGeometricQuadrilaterals, \ + GmfTangents, \ + GmfNormals, \ + GmfTangentAtVertices, \ + GmfSolAtVertices, \ + GmfSolAtEdges, \ + GmfSolAtTriangles, \ + GmfSolAtQuadrilaterals, \ + GmfSolAtTetrahedra, \ + GmfSolAtPrisms, \ + GmfSolAtHexahedra, \ + GmfDSolAtVertices, \ + GmfISolAtVertices, \ + GmfISolAtEdges, \ + GmfISolAtTriangles, \ + GmfISolAtQuadrilaterals, \ + GmfISolAtTetrahedra, \ + GmfISolAtPrisms, \ + GmfISolAtHexahedra, \ + GmfIterations, \ + GmfTime, \ + GmfFault_SmallTri, \ + GmfCoarseHexahedra }; /*----------------------------------------------------------*/ -/* External procedures */ +/* External procedures */ /*----------------------------------------------------------*/ MESHDriverGMF_EXPORT extern int GmfOpenMesh(const char *, int, ...); @@ -133,7 +133,7 @@ MESHDriverGMF_EXPORT extern void GmfSetLin(int, int, ...); /*----------------------------------------------------------*/ -/* Fortran 77 API */ +/* Fortran 77 API */ /*----------------------------------------------------------*/ #if defined(F77_NO_UNDER_SCORE) @@ -144,7 +144,7 @@ MESHDriverGMF_EXPORT extern void GmfSetLin(int, int, ...); /*----------------------------------------------------------*/ -/* Transmesh private API */ +/* Transmesh private API */ /*----------------------------------------------------------*/ #ifdef TRANSMESH diff --git a/src/DriverMED/DriverMED_R_SMESHDS_Mesh.cxx b/src/DriverMED/DriverMED_R_SMESHDS_Mesh.cxx index 35caa0286..d6bb729e4 100644 --- a/src/DriverMED/DriverMED_R_SMESHDS_Mesh.cxx +++ b/src/DriverMED/DriverMED_R_SMESHDS_Mesh.cxx @@ -71,6 +71,7 @@ DriverMED_R_SMESHDS_Mesh ::Perform() { Status aResult = DRS_FAIL; + bool isDescConn = false; #ifndef _DEXCEPT_ try{ #endif @@ -173,15 +174,26 @@ DriverMED_R_SMESHDS_Mesh } } + // Are there any MED cells in descending connectivity + //--------------------------------------------------- + if (!isDescConn) { + MED::TEntityInfo aEntityInfoDesc = aMed->GetEntityInfo(aMeshInfo, eDESC); + MED::TEntityInfo::iterator anEntityIterDesc = aEntityInfoDesc.begin(); + for (; anEntityIterDesc != aEntityInfoDesc.end() && !isDescConn; anEntityIterDesc++) { + const EEntiteMaillage& anEntity = anEntityIterDesc->first; + if (anEntity != eNOEUD) isDescConn = true; + } + } + // Reading pre information about all MED cells //-------------------------------------------- typedef MED::TVector TNodeIds; bool takeNumbers = true; // initially we trust the numbers from file - MED::TEntityInfo aEntityInfo = aMed->GetEntityInfo(aMeshInfo); + MED::TEntityInfo aEntityInfo = aMed->GetEntityInfo(aMeshInfo, eNOD); MED::TEntityInfo::iterator anEntityIter = aEntityInfo.begin(); - for(; anEntityIter != aEntityInfo.end(); anEntityIter++){ + for (; anEntityIter != aEntityInfo.end(); anEntityIter++) { const EEntiteMaillage& anEntity = anEntityIter->first; - if(anEntity == eNOEUD) continue; + if (anEntity == eNOEUD) continue; // Reading MED cells to the corresponding SMDS structure //------------------------------------------------------ const MED::TGeom2Size& aGeom2Size = anEntityIter->second; @@ -905,6 +917,12 @@ DriverMED_R_SMESHDS_Mesh #endif if (myMesh) myMesh->compactMesh(); + + if (aResult == DRS_OK && isDescConn) { + INFOS("There are some elements in descending connectivity in med file. They were not read !!!"); + aResult = DRS_WARN_DESCENDING; + } + if(MYDEBUG) MESSAGE("Perform - aResult status = "<Delete(); // vtkSmartPointer! myHighlightActor->Initialize(); myPreHighlightActor = SMESH_SVTKActor::New(); + myPreHighlightActor->Delete(); myPreHighlightActor->Initialize(); myIsShrinkable = false; @@ -150,6 +151,42 @@ SMESH_ActorDef::SMESH_ActorDef() vtkFloatingPointType aLineWidth = SMESH::GetFloat("SMESH:element_width",1); vtkFloatingPointType aOutlineWidth = SMESH::GetFloat("SMESH:outline_width",1); + SMESH::LabelFont aFamilyNd = SMESH::FntTimes; + bool aBoldNd = true; + bool anItalicNd = false; + bool aShadowNd = false; + int aSizeNd = 10; + if ( mgr->hasValue( "SMESH", "numbering_node_font" ) ) { + QFont f = mgr->fontValue( "SMESH", "numbering_node_font" ); + if ( f.family() == "Arial" ) aFamilyNd = SMESH::FntArial; + else if ( f.family() == "Courier" ) aFamilyNd = SMESH::FntCourier; + else if ( f.family() == "Times" ) aFamilyNd = SMESH::FntTimes; + aBoldNd = f.bold(); + anItalicNd = f.italic(); + aShadowNd = f.overline(); + aSizeNd = f.pointSize(); + } + vtkFloatingPointType anRGBNd[3] = {1,1,1}; + SMESH::GetColor( "SMESH", "numbering_node_color", anRGBNd[0], anRGBNd[1], anRGBNd[2], QColor( 255, 255, 255 ) ); + + SMESH::LabelFont aFamilyEl = SMESH::FntTimes; + bool aBoldEl = true; + bool anItalicEl = false; + bool aShadowEl = false; + int aSizeEl = 12; + if ( mgr->hasValue( "SMESH", "numbering_elem_font" ) ) { + QFont f = mgr->fontValue( "SMESH", "numbering_elem_font" ); + if ( f.family() == "Arial" ) aFamilyEl = SMESH::FntArial; + else if ( f.family() == "Courier" ) aFamilyEl = SMESH::FntCourier; + else if ( f.family() == "Times" ) aFamilyEl = SMESH::FntTimes; + aBoldEl = f.bold(); + anItalicEl = f.italic(); + aShadowEl = f.overline(); + aSizeEl = f.pointSize(); + } + vtkFloatingPointType anRGBEl[3] = {0,1,0}; + SMESH::GetColor( "SMESH", "numbering_elem_color", anRGBEl[0], anRGBEl[1], anRGBEl[2], QColor( 0, 255, 0 ) ); + vtkMatrix4x4 *aMatrix = vtkMatrix4x4::New(); VTKViewer_ExtractUnstructuredGrid* aFilter = NULL; @@ -180,6 +217,7 @@ SMESH_ActorDef::SMESH_ActorDef() my2DActor->SetStoreGemetryMapping(true); my2DActor->SetUserMatrix(aMatrix); my2DActor->PickableOff(); + my2DActor->SetFontProperties( aFamilyEl, aSizeEl, aBoldEl, anItalicEl, aShadowEl, anRGBEl[0], anRGBEl[1], anRGBEl[2] ); my2DActor->SetProperty(mySurfaceProp); my2DActor->SetBackfaceProperty(myBackSurfaceProp); my2DActor->SetRepresentation(SMESH_DeviceActor::eSurface); @@ -218,6 +256,7 @@ SMESH_ActorDef::SMESH_ActorDef() my3DActor->SetStoreGemetryMapping(true); my3DActor->SetUserMatrix(aMatrix); my3DActor->PickableOff(); + my3DActor->SetFontProperties( aFamilyEl, aSizeEl, aBoldEl, anItalicEl, aShadowEl, anRGBEl[0], anRGBEl[1], anRGBEl[2] ); my3DActor->SetProperty(myNormalVProp); my3DActor->SetBackfaceProperty(myReversedVProp); my3DActor->SetRepresentation(SMESH_DeviceActor::eSurface); @@ -287,6 +326,7 @@ SMESH_ActorDef::SMESH_ActorDef() my1DActor->SetUserMatrix(aMatrix); my1DActor->PickableOff(); my1DActor->SetHighlited(true); + my1DActor->SetFontProperties( aFamilyEl, aSizeEl, aBoldEl, anItalicEl, aShadowEl, anRGBEl[0], anRGBEl[1], anRGBEl[2] ); my1DActor->SetProperty(myEdgeProp); my1DActor->SetRepresentation(SMESH_DeviceActor::eSurface); aFilter = my1DActor->GetExtractUnstructuredGrid(); @@ -298,7 +338,7 @@ SMESH_ActorDef::SMESH_ActorDef() my1DProp->DeepCopy(myEdgeProp); my1DProp->SetLineWidth(aLineWidth + aLineWidthInc); my1DProp->SetPointSize(aElem0DSize); - + my1DExtProp = vtkProperty::New(); my1DExtProp->DeepCopy(myEdgeProp); anRGB[0] = 1 - anRGB[0]; @@ -332,6 +372,7 @@ SMESH_ActorDef::SMESH_ActorDef() my0DActor->SetUserMatrix(aMatrix); my0DActor->SetStoreGemetryMapping(true); my0DActor->PickableOff(); + my0DActor->SetFontProperties( aFamilyEl, aSizeEl, aBoldEl, anItalicEl, aShadowEl, anRGBEl[0], anRGBEl[1], anRGBEl[2] ); my0DActor->SetVisibility(false); my0DActor->SetProperty(my0DProp); my0DActor->SetRepresentation(SMESH_DeviceActor::eSurface); @@ -339,7 +380,7 @@ SMESH_ActorDef::SMESH_ActorDef() //aFilter->SetModeOfExtraction(VTKViewer_ExtractUnstructuredGrid::ePoints); aFilter->SetModeOfChanging(VTKViewer_ExtractUnstructuredGrid::eAdding); aFilter->RegisterCellsWithType(VTK_VERTEX); - + //Definition 0D device of the actor (ball elements) //----------------------------------------------- myBallProp = vtkProperty::New(); @@ -351,13 +392,14 @@ SMESH_ActorDef::SMESH_ActorDef() myBallActor->SetUserMatrix(aMatrix); myBallActor->SetStoreGemetryMapping(true); myBallActor->PickableOff(); + myBallActor->SetFontProperties( aFamilyEl, aSizeEl, aBoldEl, anItalicEl, aShadowEl, anRGBEl[0], anRGBEl[1], anRGBEl[2] ); myBallActor->SetVisibility(false); myBallActor->SetProperty(myBallProp); myBallActor->SetRepresentation(SMESH_DeviceActor::eSurface); aFilter = myBallActor->GetExtractUnstructuredGrid(); aFilter->SetModeOfChanging(VTKViewer_ExtractUnstructuredGrid::eAdding); aFilter->RegisterCellsWithType(VTK_POLY_VERTEX); - + //my0DExtProp = vtkProperty::New(); //my0DExtProp->DeepCopy(my0DProp); //anRGB[0] = 1 - anRGB[0]; @@ -391,11 +433,12 @@ SMESH_ActorDef::SMESH_ActorDef() myNodeActor->SetStoreClippingMapping(true); myNodeActor->PickableOff(); myNodeActor->SetVisibility(false); + myNodeActor->SetFontProperties( aFamilyNd, aSizeNd, aBoldNd, anItalicNd, aShadowNd, anRGBNd[0], anRGBNd[1], anRGBNd[2] ); myNodeActor->SetProperty(myNodeProp); myNodeActor->SetRepresentation(SMESH_DeviceActor::ePoint); aFilter = myNodeActor->GetExtractUnstructuredGrid(); aFilter->SetModeOfExtraction(VTKViewer_ExtractUnstructuredGrid::ePoints); - + myNodeExtProp = vtkProperty::New(); myNodeExtProp->DeepCopy(myNodeProp); anRGB[0] = 1 - anRGB[0]; @@ -422,7 +465,7 @@ SMESH_ActorDef::SMESH_ActorDef() myBaseActor->SetStoreGemetryMapping(true); myBaseActor->GetProperty()->SetOpacity(0.0); myPickableActor = myBaseActor; - + myHighlightProp = vtkProperty::New(); myHighlightProp->SetAmbient(1.0); myHighlightProp->SetDiffuse(0.0); @@ -436,7 +479,7 @@ SMESH_ActorDef::SMESH_ActorDef() myBallHighlightProp = vtkProperty::New(); myBallHighlightProp->DeepCopy(myHighlightProp); myBallHighlightProp->SetPointSize(aBallElemSize); - + myOutLineProp = vtkProperty::New(); myOutLineProp->SetAmbient(1.0); @@ -478,7 +521,7 @@ SMESH_ActorDef::SMESH_ActorDef() //Definition of myScalarBarActor //------------------------------ myLookupTable = vtkLookupTable::New(); - //Fix for Bug PAL5195 - SMESH764: + //Fix for Bug PAL5195 - SMESH764: //Controls - Aspect Ratio: incorrect colors of the best and worst values myLookupTable->SetHueRange(0.667,0.0); @@ -497,11 +540,11 @@ SMESH_ActorDef::SMESH_ActorDef() myEntityMode = eAllEntity; myEntityModeCache = eAllEntity; - + // Clipping planes myImplicitBoolean = vtkImplicitBoolean::New(); myImplicitBoolean->SetOperationTypeToIntersection(); - + //Quadratic 2D elements representation //----------------------------------------------------------------------------- int aQuadratic2DMode = mgr->integerValue( "SMESH", "quadratic_mode", 0); @@ -515,11 +558,11 @@ SMESH_ActorDef::SMESH_ActorDef() my2DActor->SetQuadraticArcMode(true); my1DActor->SetQuadraticArcMode(true); } - + int aQuadraticAngle = mgr->integerValue( "SMESH", "max_angle", 2); myHighlitableActor->SetQuadraticArcAngle(aQuadraticAngle); my2DActor->SetQuadraticArcAngle(aQuadraticAngle); - + // Set colors of the name actor SMESH::GetColor( "SMESH", "default_grp_color", anRGB[0], anRGB[1], anRGB[2], QColor( 0, 170, 255 ) ); myNameActor->SetBackgroundColor(anRGB[0], anRGB[1], anRGB[2]); @@ -539,12 +582,9 @@ SMESH_ActorDef::~SMESH_ActorDef() { if(MYDEBUG) MESSAGE("~SMESH_ActorDef - "<Delete(); myScalarBarActor->Delete(); myLookupTable->Delete(); @@ -553,47 +593,53 @@ SMESH_ActorDef::~SMESH_ActorDef() myBackSurfaceProp->Delete(); myNormalVProp->Delete(); myReversedVProp->Delete(); - myOutLineProp->Delete(); - myEdgeProp->Delete(); + myNodeProp->Delete(); + + myNodeActor->Delete(); + myBaseActor->Delete(); + //myPickableActor->Delete(); myPickableActor == myBaseActor + myHighlightProp->Delete(); + myOutLineProp->Delete(); myPreselectProp->Delete(); - myNodeProp->Delete(); - myNodeExtProp->Delete(); - - my0DProp->Delete(); - my0DActor->Delete(); - myBallActor->Delete(); - - //my0DExtProp->Delete(); - //my0DExtActor->Delete(); - - my1DProp->Delete(); - my1DActor->Delete(); + myBallHighlightProp->Delete(); + myBallPreselectProp->Delete(); - my1DExtProp->Delete(); - my1DExtActor->Delete(); + myHighlitableActor->Delete(); - my2DActor->Delete(); my2DExtProp->Delete(); + my3DExtProp->Delete(); + my2DActor->Delete(); my2DExtActor->Delete(); my3DActor->Delete(); - my3DExtProp->Delete(); my3DExtActor->Delete(); + // myControlActor->Delete(); myControlActor == my2DActor - myNodeActor->Delete(); - myBaseActor->Delete(); + myNodeExtProp->Delete(); + myNodeExtActor->Delete(); - myNodeExtActor->Delete(); - myHighlitableActor->Delete(); + my1DProp->Delete(); + my1DActor->Delete(); + my1DExtProp->Delete(); + my1DExtActor->Delete(); + + my0DProp->Delete(); + my0DActor->Delete(); + myBallProp->Delete(); + myBallActor->Delete(); + //my0DExtProp->Delete(); + //my0DExtActor->Delete(); myImplicitBoolean->Delete(); - myTimeStamp->Delete(); - myBallHighlightProp->Delete(); - myBallPreselectProp->Delete(); - +#ifndef DISABLE_PLOT2DVIEWER + if(my2dHistogram) { + SMESH::ProcessIn2DViewers(this,SMESH::RemoveFrom2dViewer); + delete my2dHistogram; + } +#endif } void SMESH_ActorDef::Delete() @@ -609,7 +655,7 @@ void SMESH_ActorDef::Delete() } void SMESH_ActorDef::SetPointsLabeled( bool theIsPointsLabeled ) -{ +{ if(myNodeActor) { myNodeActor->SetPointsLabeled(theIsPointsLabeled); SetRepresentation(GetRepresentation()); @@ -617,6 +663,48 @@ void SMESH_ActorDef::SetPointsLabeled( bool theIsPointsLabeled ) } } +void SMESH_ActorDef::SetPointsFontProperties( SMESH::LabelFont theFamily, int theSize, + bool theBold, bool theItalic, bool theShadow, + vtkFloatingPointType r, vtkFloatingPointType g, vtkFloatingPointType b ) +{ + if(myNodeActor) { + myNodeActor->SetFontProperties( theFamily, theSize, theBold, theItalic, theShadow, r, g, b ); + SetRepresentation( GetRepresentation() ); + myTimeStamp->Modified(); + } +} + +void SMESH_ActorDef::SetCellsFontProperties( SMESH::LabelFont theFamily, int theSize, + bool theBold, bool theItalic, bool theShadow, + vtkFloatingPointType r, vtkFloatingPointType g, vtkFloatingPointType b ) +{ + if(my3DActor) { + my3DActor->SetFontProperties( theFamily, theSize, theBold, theItalic, theShadow, r, g, b ); + SetRepresentation( GetRepresentation() ); + myTimeStamp->Modified(); + } + if(my2DActor) { + my2DActor->SetFontProperties( theFamily, theSize, theBold, theItalic, theShadow, r, g, b ); + SetRepresentation( GetRepresentation() ); + myTimeStamp->Modified(); + } + if(my1DActor) { + my1DActor->SetFontProperties( theFamily, theSize, theBold, theItalic, theShadow, r, g, b ); + SetRepresentation( GetRepresentation() ); + myTimeStamp->Modified(); + } + if(my0DActor) { + my0DActor->SetFontProperties( theFamily, theSize, theBold, theItalic, theShadow, r, g, b ); + SetRepresentation( GetRepresentation() ); + myTimeStamp->Modified(); + } + if(myBallActor) { + myBallActor->SetFontProperties( theFamily, theSize, theBold, theItalic, theShadow, r, g, b ); + SetRepresentation( GetRepresentation() ); + myTimeStamp->Modified(); + } +} + bool SMESH_ActorDef::GetPointsLabeled() { return myNodeActor && myNodeActor->GetPointsLabeled(); } @@ -634,10 +722,10 @@ void SMESH_ActorDef::SetCellsLabeled(bool theIsCellsLabeled) if(my0DActor) my0DActor->SetCellsLabeled(theIsCellsLabeled); - + if(myBallActor) myBallActor->SetCellsLabeled(theIsCellsLabeled); - + myTimeStamp->Modified(); } @@ -712,7 +800,7 @@ bool SMESH_ActorDef::GetFacesOrientation3DVectors() } -void +void SMESH_ActorDef:: SetControlMode(eControl theMode) { @@ -720,12 +808,16 @@ SetControlMode(eControl theMode) } -void +void SMESH_ActorDef:: SetControlMode(eControl theMode, bool theCheckEntityMode) { - SUIT_ResourceMgr* mgr = SUIT_Session::session()->resourceMgr(); + vtkLookupTable* lookupTable = static_cast(myScalarBarActor->GetLookupTable()); + bool isLogarithmic = lookupTable->GetScale() == VTK_SCALE_LOG10; + lookupTable->SetScale(VTK_SCALE_LINEAR); + + SUIT_ResourceMgr* mgr = SUIT_Session::session()->resourceMgr(); if( !mgr ) return; @@ -947,7 +1039,7 @@ SetControlMode(eControl theMode, if (!myIsEntityModeCache){ myEntityModeCache = GetEntityMode(); myIsEntityModeCache=true; - } + } SetEntityMode(eEdges); } else if(myControlActor == my2DActor) { @@ -959,7 +1051,7 @@ SetControlMode(eControl theMode, if (!myIsEntityModeCache){ myEntityModeCache = GetEntityMode(); myIsEntityModeCache=true; - } + } SetEntityMode(eFaces); break; default: @@ -973,7 +1065,7 @@ SetControlMode(eControl theMode, if (!myIsEntityModeCache){ myEntityModeCache = GetEntityMode(); myIsEntityModeCache=true; - } + } SetEntityMode(eVolumes); } } @@ -991,15 +1083,22 @@ SetControlMode(eControl theMode, myTimeStamp->Modified(); Modified(); + + lookupTable = static_cast(myScalarBarActor->GetLookupTable()); + double * range = lookupTable->GetRange(); + + if (isLogarithmic && range[0] > 1e-07 && range[1] > 1e-07) + lookupTable->SetScale(VTK_SCALE_LOG10); + Update(); } void SMESH_ActorDef::AddToRender(vtkRenderer* theRenderer){ - + //myHighlightActor->AddToRender(theRenderer); - theRenderer->AddActor(myBaseActor); + theRenderer->AddActor(myBaseActor); theRenderer->AddActor(myNodeExtActor); theRenderer->AddActor(my1DExtActor); @@ -1014,7 +1113,7 @@ void SMESH_ActorDef::AddToRender(vtkRenderer* theRenderer){ //theRenderer->AddActor(my0DExtActor); theRenderer->AddActor(myHighlitableActor); - + theRenderer->AddActor2D(myScalarBarActor); // the superclass' method should be called at the end @@ -1048,8 +1147,8 @@ void SMESH_ActorDef::RemoveFromRender(vtkRenderer* theRenderer){ } -bool SMESH_ActorDef::Init(TVisualObjPtr theVisualObj, - const char* theEntry, +bool SMESH_ActorDef::Init(TVisualObjPtr theVisualObj, + const char* theEntry, const char* theName, int theIsClear) { @@ -1066,23 +1165,23 @@ bool SMESH_ActorDef::Init(TVisualObjPtr theVisualObj, myHighlitableActor->Init(myVisualObj,myImplicitBoolean); myNodeExtActor->Init(myVisualObj,myImplicitBoolean); - + my0DActor->Init(myVisualObj,myImplicitBoolean); myBallActor->Init(myVisualObj,myImplicitBoolean); //my0DExtActor->Init(myVisualObj,myImplicitBoolean); - + my1DActor->Init(myVisualObj,myImplicitBoolean); my1DExtActor->Init(myVisualObj,myImplicitBoolean); - + my2DActor->Init(myVisualObj,myImplicitBoolean); my2DExtActor->Init(myVisualObj,myImplicitBoolean); my3DActor->Init(myVisualObj,myImplicitBoolean); my3DExtActor->Init(myVisualObj,myImplicitBoolean); - + my0DActor->GetMapper()->SetLookupTable(myLookupTable); myBallActor->GetMapper()->SetLookupTable(myLookupTable); //my0DExtActor->GetMapper()->SetLookupTable(myLookupTable); - + my1DActor->GetMapper()->SetLookupTable(myLookupTable); my1DExtActor->GetMapper()->SetLookupTable(myLookupTable); @@ -1090,7 +1189,7 @@ bool SMESH_ActorDef::Init(TVisualObjPtr theVisualObj, my2DExtActor->GetMapper()->SetLookupTable(myLookupTable); my3DActor->GetMapper()->SetLookupTable(myLookupTable); my3DExtActor->GetMapper()->SetLookupTable(myLookupTable); - + vtkFloatingPointType aFactor, aUnits; my2DActor->GetPolygonOffsetParameters(aFactor,aUnits); my2DActor->SetPolygonOffsetParameters(aFactor,aUnits*0.75); @@ -1108,7 +1207,7 @@ bool SMESH_ActorDef::Init(TVisualObjPtr theVisualObj, int aMode = mgr->integerValue( "SMESH", "display_mode" ); SetRepresentation(-1); - + if(aMode == 0){ SetRepresentation(eEdge); }else if(aMode == 1){ @@ -1116,7 +1215,7 @@ bool SMESH_ActorDef::Init(TVisualObjPtr theVisualObj, }else if(aMode == 2){ SetRepresentation(ePoint); } - + if(aMode == 3){ SetShrink(); } @@ -1149,7 +1248,7 @@ void SMESH_ActorDef::SetTransform(VTKViewer_Transform* theTransform){ myNodeActor->SetTransform(theTransform); myBaseActor->SetTransform(theTransform); - + myHighlitableActor->SetTransform(theTransform); myNodeExtActor->SetTransform(theTransform); @@ -1185,7 +1284,7 @@ vtkMapper* SMESH_ActorDef::GetMapper(){ } -vtkUnstructuredGrid* SMESH_ActorDef::GetUnstructuredGrid(){ +vtkUnstructuredGrid* SMESH_ActorDef::GetUnstructuredGrid(){ return myVisualObj->GetUnstructuredGrid(); } @@ -1194,7 +1293,7 @@ bool SMESH_ActorDef::IsInfinitive(){ vtkDataSet *aDataSet = myPickableActor->GetUnstructuredGrid(); aDataSet->Update(); myIsInfinite = aDataSet->GetNumberOfCells() == 0 || - ( aDataSet->GetNumberOfCells() == 1 && + ( aDataSet->GetNumberOfCells() == 1 && aDataSet->GetCell(0)->GetCellType() == VTK_VERTEX ); return SALOME_Actor::IsInfinitive(); } @@ -1292,7 +1391,7 @@ void SMESH_ActorDef::SetVisibility(int theMode, bool theIsUpdateRepersentation){ myNodeActor->VisibilityOff(); myBaseActor->VisibilityOff(); - + myNodeExtActor->VisibilityOff(); my0DActor->VisibilityOff(); @@ -1301,18 +1400,18 @@ void SMESH_ActorDef::SetVisibility(int theMode, bool theIsUpdateRepersentation){ my1DActor->VisibilityOff(); my1DExtActor->VisibilityOff(); - + my2DActor->VisibilityOff(); my2DExtActor->VisibilityOff(); my3DActor->VisibilityOff(); my3DExtActor->VisibilityOff(); - + myScalarBarActor->VisibilityOff(); - + if(GetVisibility()){ if(theIsUpdateRepersentation) SetRepresentation(GetRepresentation()); - + if(myControlMode != eNone){ switch(myControlMode){ case eFreeNodes: @@ -1360,34 +1459,34 @@ void SMESH_ActorDef::SetVisibility(int theMode, bool theIsUpdateRepersentation){ if(myEntityMode & eEdges && GetRepresentation() != ePoint){ my1DActor->VisibilityOn(); } - + if(myEntityMode & eFaces && GetRepresentation() != ePoint){ my2DActor->VisibilityOn(); } - + if(myEntityMode & eVolumes && GetRepresentation() != ePoint){ my3DActor->VisibilityOn(); } - - if(myNodeActor->GetPointsLabeled()){ + + if(myNodeActor->GetPointsLabeled()){ myNodeActor->VisibilityOn(); } if(my0DActor) my0DActor->UpdateLabels(); - + if(myBallActor) myBallActor->UpdateLabels(); - + if(my1DActor) my1DActor->UpdateLabels(); - + if(my2DActor) my2DActor->UpdateLabels(); - + if(my3DActor) - my3DActor->UpdateLabels(); - } + my3DActor->UpdateLabels(); + } #ifndef DISABLE_PLOT2DVIEWER else SMESH::ProcessIn2DViewers(this,SMESH::RemoveFrom2dViewer); @@ -1508,7 +1607,7 @@ void SMESH_ActorDef::SetEntityMode(unsigned int theMode) //#ifdef VTK_HAVE_POLYHEDRON aFilter->RegisterCellsWithType(VTK_POLYHEDRON); //#endif - + aHightFilter->RegisterCellsWithType(VTK_TETRA); aHightFilter->RegisterCellsWithType(VTK_VOXEL); aHightFilter->RegisterCellsWithType(VTK_HEXAHEDRON); @@ -1531,7 +1630,7 @@ void SMESH_ActorDef::SetEntityMode(unsigned int theMode) } void SMESH_ActorDef::SetRepresentation (int theMode) -{ +{ int aNbEdges = myVisualObj->GetNbEntities(SMDSAbs_Edge); int aNbFaces = myVisualObj->GetNbEntities(SMDSAbs_Face); int aNbVolumes = myVisualObj->GetNbEntities(SMDSAbs_Volume); @@ -1553,7 +1652,7 @@ void SMESH_ActorDef::SetRepresentation (int theMode) case eSurface: if (!aNbFaces && !aNbVolumes && !aNb0Ds && !aNbBalls) return; break; - } + } myRepresentation = theMode; } @@ -1566,7 +1665,7 @@ void SMESH_ActorDef::SetRepresentation (int theMode) myIsShrunk = true; } else { SetShrink(); - } + } } myPickableActor = myBaseActor; @@ -1607,7 +1706,7 @@ void SMESH_ActorDef::SetRepresentation (int theMode) my2DActor->SetQuadraticArcMode(true); my2DExtActor->SetRepresentation(aReperesent); - + my3DActor->SetProperty(aPropVN); my3DActor->SetBackfaceProperty(aPropVR); my3DActor->SetRepresentation(aReperesent); @@ -1632,7 +1731,7 @@ void SMESH_ActorDef::SetRepresentation (int theMode) aReperesent = SMESH_DeviceActor::eInsideframe; break; } - + if(aQuadraticMode == SMESH_Actor::eLines) my1DActor->SetQuadraticArcMode(false); else if(aQuadraticMode == SMESH_Actor::eArcs) @@ -1664,7 +1763,7 @@ void SMESH_ActorDef::SetPointRepresentation(bool theIsPointsVisible){ SetRepresentation(GetRepresentation()); } -bool SMESH_ActorDef::GetPointRepresentation(){ +bool SMESH_ActorDef::GetPointRepresentation(){ return myIsPointsVisible || myNodeActor->GetPointsLabeled(); } @@ -1681,13 +1780,13 @@ void SMESH_ActorDef::UpdateHighlight(){ { if(myIsHighlighted) { myHighlitableActor->SetProperty(myHighlightProp); - myBallActor->SetProperty(myBallHighlightProp); + myBallActor->SetProperty(myBallHighlightProp); }else if(myIsPreselected){ myHighlitableActor->SetProperty(myPreselectProp); - myBallActor->SetProperty(myBallPreselectProp); + myBallActor->SetProperty(myBallPreselectProp); } else if(anIsVisible){ - myBallActor->SetProperty(myBallProp); - (myRepresentation == eSurface) ? + myBallActor->SetProperty(myBallProp); + (myRepresentation == eSurface) ? myHighlitableActor->SetProperty(myOutLineProp) : myHighlitableActor->SetProperty(myEdgeProp); } if(GetUnstructuredGrid()->GetNumberOfCells()) { @@ -1724,10 +1823,10 @@ void SMESH_ActorDef::highlight(bool theHighlight){ } -void SMESH_ActorDef::SetPreSelected(bool thePreselect){ +void SMESH_ActorDef::SetPreSelected(bool thePreselect){ if ( myIsPreselected == thePreselect ) return; - myIsPreselected = thePreselect; + myIsPreselected = thePreselect; UpdateHighlight(); } @@ -1781,30 +1880,30 @@ void SMESH_ActorDef::Update(){ if(my0DActor) my0DActor->UpdateLabels(); - + if(myBallActor) myBallActor->UpdateLabels(); - + if(my1DActor) my1DActor->UpdateLabels(); - + if(my2DActor) my2DActor->UpdateLabels(); if(my3DActor) my3DActor->UpdateLabels(); - + if(myIsFacesOriented){ SetFacesOriented(myIsFacesOriented); } - + if(myVisualObj->GetEntitiesFlag()) { myEntityMode |= myVisualObj->GetEntitiesState(); } - + SetEntityMode(GetEntityMode()); SetVisibility(GetVisibility()); - + myTimeStamp->Modified(); Modified(); } @@ -1851,7 +1950,7 @@ void SMESH_ActorDef::SetSufaceColor(vtkFloatingPointType r,vtkFloatingPointType if( SMESH_GroupObj* aGroupObj = dynamic_cast( myVisualObj.get() ) ) if( aGroupObj->GetElementType() == SMDSAbs_Face ) myNameActor->SetBackgroundColor(r,g,b); - + myDeltaBrightness = delta; QColor bfc = Qtx::mainColorToSecondary(QColor(int(r*255),int(g*255),int(b*255)), delta); myBackSurfaceProp->SetColor( bfc.red() / 255. , bfc.green() / 255. , bfc.blue() / 255. ); @@ -1869,7 +1968,7 @@ void SMESH_ActorDef::SetVolumeColor(vtkFloatingPointType r,vtkFloatingPointType if( SMESH_GroupObj* aGroupObj = dynamic_cast( myVisualObj.get() ) ) if( aGroupObj->GetElementType() == SMDSAbs_Volume ) myNameActor->SetBackgroundColor(r,g,b); - + myDeltaVBrightness = delta; QColor bfc = Qtx::mainColorToSecondary(QColor(int(r*255),int(g*255),int(b*255)), delta); myReversedVProp->SetColor( bfc.red() / 255. , bfc.green() / 255. , bfc.blue() / 255. ); @@ -1905,7 +2004,7 @@ void SMESH_ActorDef::GetOutlineColor(vtkFloatingPointType& r,vtkFloatingPointTyp } -void SMESH_ActorDef::SetNodeColor(vtkFloatingPointType r,vtkFloatingPointType g,vtkFloatingPointType b){ +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); if( SMESH_GroupObj* aGroupObj = dynamic_cast( myVisualObj.get() ) ) @@ -1914,11 +2013,11 @@ void SMESH_ActorDef::SetNodeColor(vtkFloatingPointType r,vtkFloatingPointType g, Modified(); } -void SMESH_ActorDef::GetNodeColor(vtkFloatingPointType& r,vtkFloatingPointType& g,vtkFloatingPointType& b){ +void SMESH_ActorDef::GetNodeColor(vtkFloatingPointType& r,vtkFloatingPointType& g,vtkFloatingPointType& b){ ::GetColor(myNodeProp,r,g,b); } -void SMESH_ActorDef::Set0DColor(vtkFloatingPointType r,vtkFloatingPointType g,vtkFloatingPointType b){ +void SMESH_ActorDef::Set0DColor(vtkFloatingPointType r,vtkFloatingPointType g,vtkFloatingPointType b){ my0DProp->SetColor(r,g,b); if( SMESH_GroupObj* aGroupObj = dynamic_cast( myVisualObj.get() ) ) if( aGroupObj->GetElementType() == SMDSAbs_0DElement ) @@ -1926,11 +2025,11 @@ void SMESH_ActorDef::Set0DColor(vtkFloatingPointType r,vtkFloatingPointType g,vt Modified(); } -void SMESH_ActorDef::Get0DColor(vtkFloatingPointType& r,vtkFloatingPointType& g,vtkFloatingPointType& b){ +void SMESH_ActorDef::Get0DColor(vtkFloatingPointType& r,vtkFloatingPointType& g,vtkFloatingPointType& b){ ::GetColor(my0DProp,r,g,b); } -void SMESH_ActorDef::SetBallColor(vtkFloatingPointType r,vtkFloatingPointType g,vtkFloatingPointType b){ +void SMESH_ActorDef::SetBallColor(vtkFloatingPointType r,vtkFloatingPointType g,vtkFloatingPointType b){ myBallProp->SetColor(r,g,b); if( SMESH_GroupObj* aGroupObj = dynamic_cast( myVisualObj.get() ) ) if( aGroupObj->GetElementType() == SMDSAbs_Ball ) @@ -1938,27 +2037,27 @@ void SMESH_ActorDef::SetBallColor(vtkFloatingPointType r,vtkFloatingPointType g, Modified(); } -void SMESH_ActorDef::GetBallColor(vtkFloatingPointType& r,vtkFloatingPointType& g,vtkFloatingPointType& b){ +void SMESH_ActorDef::GetBallColor(vtkFloatingPointType& r,vtkFloatingPointType& g,vtkFloatingPointType& b){ ::GetColor(myBallProp,r,g,b); } -void SMESH_ActorDef::SetHighlightColor(vtkFloatingPointType r,vtkFloatingPointType g,vtkFloatingPointType b){ +void SMESH_ActorDef::SetHighlightColor(vtkFloatingPointType r,vtkFloatingPointType g,vtkFloatingPointType b){ myHighlightProp->SetColor(r,g,b); myBallHighlightProp->SetColor(r,g,b); Modified(); } -void SMESH_ActorDef::GetHighlightColor(vtkFloatingPointType& r,vtkFloatingPointType& g,vtkFloatingPointType& b){ +void SMESH_ActorDef::GetHighlightColor(vtkFloatingPointType& r,vtkFloatingPointType& g,vtkFloatingPointType& b){ ::GetColor(myHighlightProp,r,g,b); } -void SMESH_ActorDef::SetPreHighlightColor(vtkFloatingPointType r,vtkFloatingPointType g,vtkFloatingPointType b){ +void SMESH_ActorDef::SetPreHighlightColor(vtkFloatingPointType r,vtkFloatingPointType g,vtkFloatingPointType b){ myPreselectProp->SetColor(r,g,b); myBallPreselectProp->SetColor(r,g,b); Modified(); } -void SMESH_ActorDef::GetPreHighlightColor(vtkFloatingPointType& r,vtkFloatingPointType& g,vtkFloatingPointType& b){ +void SMESH_ActorDef::GetPreHighlightColor(vtkFloatingPointType& r,vtkFloatingPointType& g,vtkFloatingPointType& b){ ::GetColor(myPreselectProp,r,g,b); } @@ -1972,7 +2071,7 @@ void SMESH_ActorDef::SetLineWidth(vtkFloatingPointType theVal){ myEdgeProp->SetLineWidth(theVal); my1DProp->SetLineWidth(theVal + aLineWidthInc); - my1DExtProp->SetLineWidth(theVal + aLineWidthInc); + my1DExtProp->SetLineWidth(theVal + aLineWidthInc); my2DExtProp->SetLineWidth(theVal + aLineWidthInc); my3DExtProp->SetLineWidth(theVal + aLineWidthInc); myOutLineProp->SetLineWidth(theVal); @@ -2064,7 +2163,7 @@ SMESH_ActorDef::SetImplicitFunctionUsed(bool theIsImplicitFunctionUsed) my3DExtActor->SetImplicitFunctionUsed(theIsImplicitFunctionUsed); } -vtkIdType +vtkIdType SMESH_ActorDef::AddClippingPlane(vtkPlane* thePlane) { if(thePlane){ @@ -2095,7 +2194,7 @@ GetNumberOfClippingPlanes() return myCippingPlaneCont.size(); } -vtkPlane* +vtkPlane* SMESH_ActorDef:: GetClippingPlane(vtkIdType theID) { @@ -2223,7 +2322,7 @@ void SMESH_ActorDef::UpdateScalarBar() int coloringType = mgr->integerValue("SMESH", "distribution_coloring_type", 0); myScalarBarActor->SetDistributionColoringType(coloringType); - + QColor distributionColor = mgr->colorValue("SMESH", "distribution_color", QColor(255, 255, 255)); double rgb[3]; @@ -2232,7 +2331,7 @@ void SMESH_ActorDef::UpdateScalarBar() rgb[2]= distributionColor.blue()/255.; myScalarBarActor->SetDistributionColor(rgb); - + } void SMESH_ActorDef::UpdateDistribution() @@ -2251,7 +2350,8 @@ void SMESH_ActorDef::UpdateDistribution() elemIds.push_back( (*e)->GetID()); vtkLookupTable* lookupTable = static_cast(myScalarBarActor->GetLookupTable()); double * range = lookupTable->GetRange(); - fun->GetHistogram(nbIntervals, nbEvents, funValues, elemIds, range); + bool isLogarithmic = lookupTable->GetScale() == VTK_SCALE_LOG10; + fun->GetHistogram(nbIntervals, nbEvents, funValues, elemIds, range, isLogarithmic); myScalarBarActor->SetDistribution(nbEvents); } } @@ -2305,17 +2405,17 @@ SPlot2d_Histogram* SMESH_ActorDef::UpdatePlot2Histogram() { if(my2dHistogram) my2dHistogram->clearAllPoints(); - + if(SMESH::Controls::NumericalFunctor* fun = dynamic_cast(myFunctor.get())) { - + if(!my2dHistogram) { my2dHistogram = new SPlot2d_Histogram(); Handle(SALOME_InteractiveObject) anIO = new SALOME_InteractiveObject(getIO()->getEntry(),"SMESH",getName()); my2dHistogram->setIO(anIO); } - + int nbIntervals = myScalarBarActor->GetMaximumNumberOfColors(); std::vector nbEvents; std::vector funValues; @@ -2323,22 +2423,23 @@ SPlot2d_Histogram* SMESH_ActorDef::UpdatePlot2Histogram() { if ( ! dynamic_cast(myVisualObj.get())) dynamic_cast(myVisualObj.get())->GetEntities( fun->GetType(), elems ); std::vector elemIds; - + for ( SMESH_VisualObjDef::TEntityList::iterator e = elems.begin(); e != elems.end(); ++e) elemIds.push_back( (*e)->GetID()); vtkLookupTable* lookupTable = static_cast(myScalarBarActor->GetLookupTable()); double * range = lookupTable->GetRange(); - fun->GetHistogram(nbIntervals, nbEvents, funValues, elemIds, range); + bool isLogarithmic = lookupTable->GetScale() == VTK_SCALE_LOG10; + fun->GetHistogram(nbIntervals, nbEvents, funValues, elemIds, range, isLogarithmic); - for ( int i = 0; i < std::min( nbEvents.size(), funValues.size() -1 ); i++ ) + for ( int i = 0; i < std::min( nbEvents.size(), funValues.size() -1 ); i++ ) my2dHistogram->addPoint(funValues[i] + (funValues[i+1] - funValues[i])/2.0, static_cast(nbEvents[i])); if(funValues.size() >= 2) my2dHistogram->setWidth((funValues[1] - funValues[0]) * 0.8) ; } - + //Color of the histogram if(myScalarBarActor->GetDistributionColoringType() == SMESH_MULTICOLOR_TYPE) my2dHistogram->setAutoAssign(true); @@ -2349,7 +2450,7 @@ SPlot2d_Histogram* SMESH_ActorDef::UpdatePlot2Histogram() { my2dHistogram->setColor(aColor); } - + return my2dHistogram; } #endif diff --git a/src/OBJECT/SMESH_Actor.h b/src/OBJECT/SMESH_Actor.h index fc954253d..bbd7ac965 100644 --- a/src/OBJECT/SMESH_Actor.h +++ b/src/OBJECT/SMESH_Actor.h @@ -31,6 +31,7 @@ #include // To fix some redefinition #include #include "SMESH_Object.h" +#include "SMESH_ActorUtils.h" #include @@ -162,6 +163,13 @@ class SMESHOBJECT_EXPORT SMESH_Actor: public SALOME_Actor virtual void UpdateScalarBar() = 0; virtual void UpdateDistribution() = 0; + virtual void SetPointsFontProperties( SMESH::LabelFont family, int size, + bool bold, bool italic, bool shadow, + vtkFloatingPointType r, vtkFloatingPointType g, vtkFloatingPointType b ) = 0; + virtual void SetCellsFontProperties( SMESH::LabelFont family, int size, + bool bold, bool italic, bool shadow, + vtkFloatingPointType r, vtkFloatingPointType g, vtkFloatingPointType b ) = 0; + #ifndef DISABLE_PLOT2DVIEWER virtual SPlot2d_Histogram* GetPlot2Histogram() = 0; virtual SPlot2d_Histogram* UpdatePlot2Histogram() = 0; diff --git a/src/OBJECT/SMESH_ActorDef.h b/src/OBJECT/SMESH_ActorDef.h index 11d7fe41a..47dc703a0 100644 --- a/src/OBJECT/SMESH_ActorDef.h +++ b/src/OBJECT/SMESH_ActorDef.h @@ -180,6 +180,13 @@ class SMESH_ActorDef : public SMESH_Actor virtual void SetPointsLabeled(bool theIsPointsLabeled); virtual bool GetPointsLabeled(); + virtual void SetPointsFontProperties( SMESH::LabelFont family, int size, + bool bold, bool italic, bool shadow, + vtkFloatingPointType r, vtkFloatingPointType g, vtkFloatingPointType b ); + virtual void SetCellsFontProperties( SMESH::LabelFont family, int size, + bool bold, bool italic, bool shadow, + vtkFloatingPointType r, vtkFloatingPointType g, vtkFloatingPointType b ); + virtual void SetCellsLabeled(bool theIsCellsLabeled); virtual bool GetCellsLabeled(); diff --git a/src/OBJECT/SMESH_ActorUtils.cxx b/src/OBJECT/SMESH_ActorUtils.cxx index bb9fd64b1..c756156e0 100644 --- a/src/OBJECT/SMESH_ActorUtils.cxx +++ b/src/OBJECT/SMESH_ActorUtils.cxx @@ -144,10 +144,10 @@ namespace SMESH void GetColor( const QString& theSect, - const QString& theName, - QColor& color, - int& delta, - QString def) + const QString& theName, + QColor& color, + int& delta, + QString def) { SUIT_ResourceMgr* mgr = SUIT_Session::session()->resourceMgr(); @@ -160,15 +160,15 @@ namespace SMESH std::map GetEntitiesFromObject(SMESH_VisualObj *theObject) { std::map entities; entities.insert(std::pair(SMDSAbs_0DElement, - theObject ? theObject->GetNbEntities(SMDSAbs_0DElement) : 0)); + theObject ? theObject->GetNbEntities(SMDSAbs_0DElement) : 0)); entities.insert(std::pair(SMDSAbs_Ball, - theObject ? theObject->GetNbEntities(SMDSAbs_Ball) : 0)); + theObject ? theObject->GetNbEntities(SMDSAbs_Ball) : 0)); entities.insert(std::pair(SMDSAbs_Edge, - theObject ? theObject->GetNbEntities(SMDSAbs_Edge) : 0)); + theObject ? theObject->GetNbEntities(SMDSAbs_Edge) : 0)); entities.insert(std::pair(SMDSAbs_Face, - theObject ? theObject->GetNbEntities(SMDSAbs_Face) : 0)); + theObject ? theObject->GetNbEntities(SMDSAbs_Face) : 0)); entities.insert(std::pair(SMDSAbs_Volume, - theObject ? theObject->GetNbEntities(SMDSAbs_Volume) : 0)); + theObject ? theObject->GetNbEntities(SMDSAbs_Volume) : 0)); return entities; } diff --git a/src/OBJECT/SMESH_ActorUtils.h b/src/OBJECT/SMESH_ActorUtils.h index 3a15c40ad..ce189fbe8 100644 --- a/src/OBJECT/SMESH_ActorUtils.h +++ b/src/OBJECT/SMESH_ActorUtils.h @@ -33,6 +33,13 @@ class SMESH_Actor; namespace SMESH { + //! Label font family + enum LabelFont { + FntArial, //!< arial font family + FntCourier, //!< courier font family + FntTimes, //!< times font family + }; + SMESHOBJECT_EXPORT vtkFloatingPointType GetFloat( const QString& theValue, @@ -71,10 +78,10 @@ SMESHOBJECT_EXPORT SMESHOBJECT_EXPORT void GetColor( const QString& theSect, - const QString& theName, - QColor& color, - int& delta, - QString def); + const QString& theName, + QColor& color, + int& delta, + QString def); SMESHOBJECT_EXPORT std::map diff --git a/src/OBJECT/SMESH_CellLabelActor.cxx b/src/OBJECT/SMESH_CellLabelActor.cxx index 3e117de16..297c37da9 100644 --- a/src/OBJECT/SMESH_CellLabelActor.cxx +++ b/src/OBJECT/SMESH_CellLabelActor.cxx @@ -69,21 +69,19 @@ SMESH_CellLabelActor::SMESH_CellLabelActor() { myClsLabeledDataMapper->SetLabelFormat("%d"); myClsLabeledDataMapper->SetLabelModeToLabelScalars(); - vtkTextProperty* aClsTextProp = vtkTextProperty::New(); - aClsTextProp->SetFontFamilyToTimes(); - static int aCellsFontSize = 12; - aClsTextProp->SetFontSize(aCellsFontSize); - aClsTextProp->SetBold(1); - aClsTextProp->SetItalic(0); - aClsTextProp->SetShadow(0); - myClsLabeledDataMapper->SetLabelTextProperty(aClsTextProp); - aClsTextProp->Delete(); + myClsTextProp = vtkTextProperty::New(); + myClsTextProp->SetFontFamilyToTimes(); + myClsTextProp->SetFontSize(12); + myClsTextProp->SetBold(1); + myClsTextProp->SetItalic(0); + myClsTextProp->SetShadow(0); + myClsTextProp->SetColor( 0, 1, 0 ); + myClsLabeledDataMapper->SetLabelTextProperty(myClsTextProp); myIsCellsLabeled = false; myCellsLabels = vtkActor2D::New(); myCellsLabels->SetMapper(myClsLabeledDataMapper); - myCellsLabels->GetProperty()->SetColor(0,1,0); myCellsLabels->SetVisibility(myIsCellsLabeled); vtkCallbackCommand* callBackCommand = vtkCallbackCommand::New(); @@ -91,7 +89,7 @@ SMESH_CellLabelActor::SMESH_CellLabelActor() { callBackCommand->SetCallback(SMESH_CellLabelActor::ProcessEvents); myTransformFilter->AddObserver("VTKViewer_TransformFilter::TransformationFinished", - callBackCommand); + callBackCommand); callBackCommand->Delete(); } @@ -103,26 +101,43 @@ SMESH_CellLabelActor::~SMESH_CellLabelActor() { //Deleting of cells numbering pipeline //--------------------------------------- myCellsNumDataSet->Delete(); - - myClsLabeledDataMapper->RemoveAllInputs(); - myClsLabeledDataMapper->Delete(); - - // commented: porting to vtk 5.0 - // myClsSelectVisiblePoints->UnRegisterAllOutputs(); - myClsSelectVisiblePoints->Delete(); - + myCellsLabels->Delete(); // commented: porting to vtk 5.0 // myClsMaskPoints->UnRegisterAllOutputs(); myClsMaskPoints->Delete(); - // commented: porting to vtk 5.0 // myCellCenters->UnRegisterAllOutputs(); myCellCenters->Delete(); - - myCellsLabels->Delete(); + + myClsLabeledDataMapper->RemoveAllInputs(); + myClsLabeledDataMapper->Delete(); + // commented: porting to vtk 5.0 + // myClsSelectVisiblePoints->UnRegisterAllOutputs(); + myClsSelectVisiblePoints->Delete(); + myClsTextProp->Delete(); } +void SMESH_CellLabelActor::SetFontProperties( SMESH::LabelFont family, int size, + bool bold, bool italic, bool shadow, + vtkFloatingPointType r, vtkFloatingPointType g, vtkFloatingPointType b ) +{ + switch ( family ) { + case SMESH::FntArial: + myClsTextProp->SetFontFamilyToArial(); break; + case SMESH::FntCourier: + myClsTextProp->SetFontFamilyToCourier(); break; + case SMESH::FntTimes: + default: + myClsTextProp->SetFontFamilyToTimes(); break; + } + myClsTextProp->SetFontSize( size ); + myClsTextProp->SetBold( bold ); + myClsTextProp->SetItalic( italic ); + myClsTextProp->SetShadow( shadow ); + myClsTextProp->SetColor( r, g, b ); +} + void SMESH_CellLabelActor::SetCellsLabeled(bool theIsCellsLabeled) { myTransformFilter->Update(); vtkUnstructuredGrid* aGrid = vtkUnstructuredGrid::SafeDownCast(myTransformFilter->GetOutput()); @@ -176,9 +191,9 @@ void SMESH_CellLabelActor::UpdateLabels() { void SMESH_CellLabelActor::ProcessEvents(vtkObject* vtkNotUsed(theObject), - unsigned long theEvent, - void* theClientData, - void* vtkNotUsed(theCallData)) { + unsigned long theEvent, + void* theClientData, + void* vtkNotUsed(theCallData)) { SMESH_CellLabelActor* self = reinterpret_cast(theClientData); if(self) self->UpdateLabels(); diff --git a/src/OBJECT/SMESH_CellLabelActor.h b/src/OBJECT/SMESH_CellLabelActor.h index 988a0dcaf..f9a6a239d 100644 --- a/src/OBJECT/SMESH_CellLabelActor.h +++ b/src/OBJECT/SMESH_CellLabelActor.h @@ -27,12 +27,14 @@ #define SMESH_CELL_LABEL_ACTOR_H #include "SMESH_DeviceActor.h" +#include "SMESH_ActorUtils.h" class vtkSelectVisiblePoints; class vtkLabeledDataMapper; class vtkActor2D; class vtkMaskPoints; class vtkUnstructuredGrid; +class vtkTextProperty; class VTKViewer_CellCenters; @@ -42,9 +44,9 @@ public: static SMESH_CellLabelActor* New(); static void ProcessEvents(vtkObject* theObject, - unsigned long theEvent, - void* theClientData, - void* theCallData); + unsigned long theEvent, + void* theClientData, + void* theCallData); vtkTypeMacro(SMESH_CellLabelActor, SMESH_DeviceActor); @@ -57,6 +59,10 @@ public: virtual void AddToRender(vtkRenderer* theRenderer); virtual void RemoveFromRender(vtkRenderer* theRenderer); + + virtual void SetFontProperties( SMESH::LabelFont family, int size, + bool bold, bool italic, bool shadow, + vtkFloatingPointType r, vtkFloatingPointType g, vtkFloatingPointType b ); void UpdateLabels(); @@ -72,6 +78,7 @@ protected: vtkLabeledDataMapper* myClsLabeledDataMapper; vtkSelectVisiblePoints* myClsSelectVisiblePoints; SMESH_DeviceActor* myBaseActor; //Pointer to the base actor + vtkTextProperty* myClsTextProp; protected: // Not implemented. diff --git a/src/OBJECT/SMESH_DeviceActor.cxx b/src/OBJECT/SMESH_DeviceActor.cxx index d53765d79..c82bbf305 100644 --- a/src/OBJECT/SMESH_DeviceActor.cxx +++ b/src/OBJECT/SMESH_DeviceActor.cxx @@ -138,33 +138,29 @@ SMESH_DeviceActor { if(MYDEBUG) MESSAGE("~SMESH_DeviceActor - "<Delete(); - myMapper->Delete(); - myShrinkFilter->Delete(); + myProperty->Delete(); - myExtractUnstructuredGrid->Delete(); + myExtractGeometry->Delete(); myMergeFilter->Delete(); + myExtractUnstructuredGrid->Delete(); - myGeomFilter->Delete(); + // Orientation of faces + myFaceOrientationFilter->Delete(); + myFaceOrientationDataMapper->RemoveAllInputs(); + myFaceOrientationDataMapper->Delete(); + myFaceOrientation->Delete(); - myExtractGeometry->Delete(); + myGeomFilter->Delete(); myTransformFilter->Delete(); - for(int i = 0, iEnd = myPassFilter.size(); i < iEnd; i++){ + for(int i = 0, iEnd = myPassFilter.size(); i < iEnd; i++) myPassFilter[i]->Delete(); - } - - // Orientation of faces - myFaceOrientationFilter->Delete(); - - myFaceOrientationDataMapper->RemoveAllInputs(); - myFaceOrientationDataMapper->Delete(); - myFaceOrientation->Delete(); + myShrinkFilter->Delete(); } diff --git a/src/OBJECT/SMESH_NodeLabelActor.cxx b/src/OBJECT/SMESH_NodeLabelActor.cxx index 5d7b33507..b3a8d3d0f 100644 --- a/src/OBJECT/SMESH_NodeLabelActor.cxx +++ b/src/OBJECT/SMESH_NodeLabelActor.cxx @@ -63,21 +63,19 @@ SMESH_NodeLabelActor::SMESH_NodeLabelActor() { myPtsLabeledDataMapper->SetLabelFormat("%d"); myPtsLabeledDataMapper->SetLabelModeToLabelScalars(); - vtkTextProperty* aPtsTextProp = vtkTextProperty::New(); - aPtsTextProp->SetFontFamilyToTimes(); - static int aPointsFontSize = 10; - aPtsTextProp->SetFontSize(aPointsFontSize); - aPtsTextProp->SetBold(1); - aPtsTextProp->SetItalic(0); - aPtsTextProp->SetShadow(0); - myPtsLabeledDataMapper->SetLabelTextProperty(aPtsTextProp); - aPtsTextProp->Delete(); + myPtsTextProp = vtkTextProperty::New(); + myPtsTextProp->SetFontFamilyToTimes(); + myPtsTextProp->SetFontSize(10); + myPtsTextProp->SetBold(1); + myPtsTextProp->SetItalic(0); + myPtsTextProp->SetShadow(0); + myPtsTextProp->SetColor( 1, 1, 1 ); + myPtsLabeledDataMapper->SetLabelTextProperty(myPtsTextProp); myIsPointsLabeled = false; myPointLabels = vtkActor2D::New(); myPointLabels->SetMapper(myPtsLabeledDataMapper); - myPointLabels->GetProperty()->SetColor(1,1,1); myPointLabels->SetVisibility(myIsPointsLabeled); vtkCallbackCommand* callBackCommand = vtkCallbackCommand::New(); @@ -85,7 +83,7 @@ SMESH_NodeLabelActor::SMESH_NodeLabelActor() { callBackCommand->SetCallback(SMESH_NodeLabelActor::ProcessEvents); myTransformFilter->AddObserver("VTKViewer_TransformFilter::TransformationFinished", - callBackCommand); + callBackCommand); callBackCommand->Delete(); } @@ -109,7 +107,27 @@ SMESH_NodeLabelActor::~SMESH_NodeLabelActor() { // myPtsMaskPoints->UnRegisterAllOutputs(); myPtsMaskPoints->Delete(); myPointLabels->Delete(); + myPtsTextProp->Delete(); +} +void SMESH_NodeLabelActor::SetFontProperties( SMESH::LabelFont family, int size, + bool bold, bool italic, bool shadow, + vtkFloatingPointType r, vtkFloatingPointType g, vtkFloatingPointType b ) +{ + switch ( family ) { + case SMESH::FntArial: + myPtsTextProp->SetFontFamilyToArial(); break; + case SMESH::FntCourier: + myPtsTextProp->SetFontFamilyToCourier(); break; + case SMESH::FntTimes: + default: + myPtsTextProp->SetFontFamilyToTimes(); break; + } + myPtsTextProp->SetFontSize( size ); + myPtsTextProp->SetBold( bold ); + myPtsTextProp->SetItalic( italic ); + myPtsTextProp->SetShadow( shadow ); + myPtsTextProp->SetColor( r, g, b ); } void SMESH_NodeLabelActor::SetPointsLabeled(bool theIsPointsLabeled) { @@ -178,9 +196,9 @@ void SMESH_NodeLabelActor::UpdateLabels() { void SMESH_NodeLabelActor::ProcessEvents(vtkObject* vtkNotUsed(theObject), - unsigned long theEvent, - void* theClientData, - void* vtkNotUsed(theCallData)) { + unsigned long theEvent, + void* theClientData, + void* vtkNotUsed(theCallData)) { SMESH_NodeLabelActor* self = reinterpret_cast(theClientData); if(self) self->UpdateLabels(); diff --git a/src/OBJECT/SMESH_NodeLabelActor.h b/src/OBJECT/SMESH_NodeLabelActor.h index a15a2330b..03de78f3a 100644 --- a/src/OBJECT/SMESH_NodeLabelActor.h +++ b/src/OBJECT/SMESH_NodeLabelActor.h @@ -27,22 +27,23 @@ #define SMESH_NODE_LABEL_ACTOR_H #include "SMESH_DeviceActor.h" +#include "SMESH_ActorUtils.h" class vtkSelectVisiblePoints; class vtkLabeledDataMapper; class vtkActor2D; class vtkMaskPoints; class vtkUnstructuredGrid; - +class vtkTextProperty; class SMESHOBJECT_EXPORT SMESH_NodeLabelActor : public SMESH_DeviceActor { public: static SMESH_NodeLabelActor* New(); static void ProcessEvents(vtkObject* theObject, - unsigned long theEvent, - void* theClientData, - void* theCallData); + unsigned long theEvent, + void* theClientData, + void* theCallData); vtkTypeMacro(SMESH_NodeLabelActor, SMESH_DeviceActor); @@ -55,6 +56,10 @@ public: virtual void AddToRender(vtkRenderer* theRenderer); virtual void RemoveFromRender(vtkRenderer* theRenderer); + + virtual void SetFontProperties( SMESH::LabelFont family, int size, + bool bold, bool italic, bool shadow, + vtkFloatingPointType r, vtkFloatingPointType g, vtkFloatingPointType b ); void UpdateLabels(); @@ -68,6 +73,7 @@ protected: vtkMaskPoints* myPtsMaskPoints; vtkLabeledDataMapper* myPtsLabeledDataMapper; vtkSelectVisiblePoints* myPtsSelectVisiblePoints; + vtkTextProperty* myPtsTextProp; protected: // Not implemented. diff --git a/src/OBJECT/SMESH_Object.cxx b/src/OBJECT/SMESH_Object.cxx index 30bef0579..96b25c9b9 100644 --- a/src/OBJECT/SMESH_Object.cxx +++ b/src/OBJECT/SMESH_Object.cxx @@ -567,12 +567,12 @@ vtkUnstructuredGrid* SMESH_VisualObjDef::GetUnstructuredGrid() bool SMESH_VisualObjDef::IsValid() const { //MESSAGE("SMESH_VisualObjDef::IsValid"); - return GetNbEntities(SMDSAbs_Node) > 0 || - GetNbEntities(SMDSAbs_0DElement) > 0 || - GetNbEntities(SMDSAbs_Ball) > 0 || - GetNbEntities(SMDSAbs_Edge) > 0 || - GetNbEntities(SMDSAbs_Face) > 0 || - GetNbEntities(SMDSAbs_Volume) > 0 ; + return ( GetNbEntities(SMDSAbs_0DElement) > 0 || + GetNbEntities(SMDSAbs_Ball ) > 0 || + GetNbEntities(SMDSAbs_Edge ) > 0 || + GetNbEntities(SMDSAbs_Face ) > 0 || + GetNbEntities(SMDSAbs_Volume ) > 0 || + GetNbEntities(SMDSAbs_Node ) > 0 ); } //================================================================================= @@ -659,6 +659,8 @@ SMESH_MeshObj::~SMESH_MeshObj() { if ( MYDEBUG ) MESSAGE("SMESH_MeshObj - this = "<Delete(); } //================================================================================= @@ -995,11 +997,16 @@ int SMESH_GroupObj::GetEntities( const SMDSAbs_ElementType theType, TEntityList& theResList.clear(); SMDS_Mesh* aMesh = myMeshObj->GetMesh(); - if ( myGroupServer->Size() == 0 || aMesh == 0 ) + if ( aMesh == 0 ) return 0; SMDSAbs_ElementType aGrpType = SMDSAbs_ElementType(myGroupServer->GetType()); + if ( aGrpType != theType && theType != SMDSAbs_Node ) + return 0; + SMESH::long_array_var anIds = myGroupServer->GetListOfID(); + if ( anIds->length() == 0 ) + return 0; if ( aGrpType == theType ) return getPointers( theType, anIds, aMesh, theResList ); @@ -1007,7 +1014,7 @@ int SMESH_GroupObj::GetEntities( const SMDSAbs_ElementType theType, TEntityList& return getNodesFromElems( anIds, aMesh, theResList ); else return 0; -} +} diff --git a/src/OBJECT/SMESH_Object.h b/src/OBJECT/SMESH_Object.h index 5ce10b850..ade792093 100644 --- a/src/OBJECT/SMESH_Object.h +++ b/src/OBJECT/SMESH_Object.h @@ -45,6 +45,9 @@ #include "SMESH_Controls.hxx" #include "SMDSAbs_ElementType.hxx" +#include +#include CORBA_SERVER_HEADER(SMESH_Mesh) + class SMDS_Mesh; class vtkUnstructuredGrid; @@ -62,6 +65,7 @@ public: virtual int GetNbEntities( const SMDSAbs_ElementType theType) const = 0; virtual SMDS_Mesh* GetMesh() const = 0; + virtual SMESH::SMESH_Mesh_ptr GetMeshServer() = 0; virtual bool GetEdgeNodes( const int theElemId, const int theEdgeNum, diff --git a/src/OBJECT/SMESH_ObjectDef.h b/src/OBJECT/SMESH_ObjectDef.h index 4532a0197..56f754375 100644 --- a/src/OBJECT/SMESH_ObjectDef.h +++ b/src/OBJECT/SMESH_ObjectDef.h @@ -70,6 +70,7 @@ public: virtual int GetEntities( const SMDSAbs_ElementType, TEntityList& ) const = 0; virtual bool IsNodePrs() const = 0; virtual SMDS_Mesh* GetMesh() const = 0; + virtual SMESH::SMESH_Mesh_ptr GetMeshServer() = 0; virtual bool IsValid() const; @@ -135,10 +136,11 @@ public: virtual void UpdateFunctor( const SMESH::Controls::FunctorPtr& theFunctor ); - SMESH::SMESH_Mesh_ptr GetMeshServer() { return myClient.GetMeshServer(); } - SMDS_Mesh* GetMesh() const { return myClient.GetMesh(); } + virtual SMESH::SMESH_Mesh_ptr GetMeshServer() { return myClient.GetMeshServer(); } + virtual SMDS_Mesh* GetMesh() const { return myClient.GetMesh(); } protected: + SMESH_Client myClient; vtkUnstructuredGrid* myEmptyGrid; }; @@ -161,6 +163,7 @@ public: virtual void UpdateFunctor( const SMESH::Controls::FunctorPtr& theFunctor ); virtual int GetElemDimension( const int theObjId ); virtual SMDS_Mesh* GetMesh() const { return myMeshObj->GetMesh(); } + virtual SMESH::SMESH_Mesh_ptr GetMeshServer() { return myMeshObj->GetMeshServer(); } protected: diff --git a/src/OBJECT/SMESH_PreviewActorsCollection.cxx b/src/OBJECT/SMESH_PreviewActorsCollection.cxx index 9fecefb18..9d6d1c80f 100644 --- a/src/OBJECT/SMESH_PreviewActorsCollection.cxx +++ b/src/OBJECT/SMESH_PreviewActorsCollection.cxx @@ -65,8 +65,8 @@ SMESH_PreviewActorsCollection::~SMESH_PreviewActorsCollection() } bool SMESH_PreviewActorsCollection::Init( const TopoDS_Shape& theShape, - TopAbs_ShapeEnum theType, - const QString& theEntry ) + TopAbs_ShapeEnum theType, + const QString& theEntry ) { SUIT_ResourceMgr* mgr = SUIT_Session::session()->resourceMgr(); diff --git a/src/OBJECT/SMESH_SVTKActor.cxx b/src/OBJECT/SMESH_SVTKActor.cxx index b86c81d54..48ad86910 100644 --- a/src/OBJECT/SMESH_SVTKActor.cxx +++ b/src/OBJECT/SMESH_SVTKActor.cxx @@ -124,29 +124,32 @@ SMESH_SVTKActor for(int ind = 1; ind <= aNbOfParts; ind++){ int aPartId = theMapIndex( ind ); if(vtkCell* aCell = theMapActor->GetElemCell(aPartId)) - { + { #if VTK_XVERSION > 50700 if (aCell->GetCellType() != VTK_POLYHEDRON) #endif - if(aCell->GetCellType() == VTK_VERTEX ) { - my0DGrid->InsertNextCell(aCell->GetCellType(),aCell->GetPointIds()); - } else if(aCell->GetCellType() == VTK_POLY_VERTEX ) { - myBallGrid->InsertNextCell(aCell->GetCellType(),aCell->GetPointIds()); - } else { - myUnstructuredGrid->InsertNextCell(aCell->GetCellType(),aCell->GetPointIds()); + { + if(aCell->GetCellType() == VTK_VERTEX ) { + my0DGrid->InsertNextCell(aCell->GetCellType(),aCell->GetPointIds()); + } else if(aCell->GetCellType() == VTK_POLY_VERTEX ) { + myBallGrid->InsertNextCell(aCell->GetCellType(),aCell->GetPointIds()); + } else { + myUnstructuredGrid->InsertNextCell(aCell->GetCellType(),aCell->GetPointIds()); + } } #if VTK_XVERSION > 50700 else - { - vtkPolyhedron *polyhedron = dynamic_cast(aCell); - if (!polyhedron) - throw SALOME_Exception(LOCALIZED ("not a polyhedron")); - vtkIdType *pts = polyhedron->GetFaces(); - myUnstructuredGrid->InsertNextCell(aCell->GetCellType(),pts[0], pts+1); - } -#endif + { + vtkPolyhedron *polyhedron = dynamic_cast(aCell); + if (!polyhedron) + throw SALOME_Exception(LOCALIZED ("not a polyhedron")); + vtkIdType *pts = polyhedron->GetFaces(); + myUnstructuredGrid->InsertNextCell(aCell->GetCellType(),pts[0], pts+1); } - +#endif + } + } + UnShrink(); if(theMapActor->IsShrunk()){ SetShrinkFactor(theMapActor->GetShrinkFactor()); @@ -154,9 +157,8 @@ SMESH_SVTKActor } myMapIndex = theMapIndex; - } } - + void SMESH_SVTKActor ::Initialize() diff --git a/src/PluginUtils/GeomSelectionTools.cxx b/src/PluginUtils/GeomSelectionTools.cxx index 07c7f0830..cfb841f5c 100644 --- a/src/PluginUtils/GeomSelectionTools.cxx +++ b/src/PluginUtils/GeomSelectionTools.cxx @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -225,7 +226,8 @@ TopAbs_ShapeEnum GeomSelectionTools::entryToShapeType(std::string entry){ // if the Geom Object is a group if (aShape->GetType() == GEOM_GROUP){ // MESSAGE("It's a group"); - GEOM::GEOM_IGroupOperations_var aGroupOp = _geomEngine->GetIGroupOperations(myStudy->StudyId()); + GEOM::GEOM_IGroupOperations_wrap aGroupOp = + _geomEngine->GetIGroupOperations(myStudy->StudyId()); ShapeType= (TopAbs_ShapeEnum)aGroupOp->GetType(aShape); } // if not diff --git a/src/SMDS/ObjectPool.hxx b/src/SMDS/ObjectPool.hxx index 1ee371055..261ed6459 100644 --- a/src/SMDS/ObjectPool.hxx +++ b/src/SMDS/ObjectPool.hxx @@ -21,9 +21,18 @@ #define _OBJECTPOOL_HXX_ #include -#include +//#include #include +namespace +{ + // assure deallocation of memory of a vector + template void clearVector(std::vector& v ) + { + std::vector emptyVec; v.swap( emptyVec ); + } +} + template class ObjectPool { @@ -70,7 +79,7 @@ public: virtual ~ObjectPool() { - for (int i = 0; i < _chunkList.size(); i++) + for (size_t i = 0; i < _chunkList.size(); i++) delete[] _chunkList[i]; } @@ -101,7 +110,7 @@ public: void destroy(X* obj) { long adrobj = (long) (obj); - for (int i = 0; i < _chunkList.size(); i++) + for (size_t i = 0; i < _chunkList.size(); i++) { X* chunk = _chunkList[i]; long adrmin = (long) (chunk); @@ -121,6 +130,16 @@ public: } } + void clear() + { + _nextFree = 0; + _maxAvail = 0; + for (size_t i = 0; i < _chunkList.size(); i++) + delete[] _chunkList[i]; + clearVector( _chunkList ); + clearVector( _freeList ); + } + // void destroy(int toFree) // { // // no control 0<= toFree < _freeList.size() diff --git a/src/SMDS/SMDS_Mesh.cxx b/src/SMDS/SMDS_Mesh.cxx index fe6f186e4..999df6d25 100644 --- a/src/SMDS/SMDS_Mesh.cxx +++ b/src/SMDS/SMDS_Mesh.cxx @@ -2656,6 +2656,13 @@ SMDS_Mesh::~SMDS_Mesh() myNodeIDFactory->ReleaseID(node->GetID(), node->getVtkId()); } } + myGrid->Delete(); + + delete myNodePool; + delete myVolumePool; + delete myFacePool; + delete myEdgePool; + delete myBallPool; } //================================================================================ @@ -2688,50 +2695,56 @@ void SMDS_Mesh::Clear() myElementIDFactory->Clear(); } - SMDS_ElemIteratorPtr itv = elementsIterator(); - while (itv->more()) - { - SMDS_MeshElement* elem = (SMDS_MeshElement*)(itv->next()); - SMDSAbs_ElementType aType = elem->GetType(); - switch (aType) - { - case SMDSAbs_0DElement: - delete elem; - break; - case SMDSAbs_Edge: - myEdgePool->destroy(static_cast(elem)); - break; - case SMDSAbs_Face: - myFacePool->destroy(static_cast(elem)); - break; - case SMDSAbs_Volume: - myVolumePool->destroy(static_cast(elem)); - break; - case SMDSAbs_Ball: - myBallPool->destroy(static_cast(elem)); - break; - default: - break; - } - } - myCells.clear(); - myCellIdVtkToSmds.clear(); - //myCellIdSmdsToVtk.clear(); + // SMDS_ElemIteratorPtr itv = elementsIterator(); + // while (itv->more()) + // { + // SMDS_MeshElement* elem = (SMDS_MeshElement*)(itv->next()); + // SMDSAbs_ElementType aType = elem->GetType(); + // switch (aType) + // { + // case SMDSAbs_0DElement: + // delete elem; + // break; + // case SMDSAbs_Edge: + // myEdgePool->destroy(static_cast(elem)); + // break; + // case SMDSAbs_Face: + // myFacePool->destroy(static_cast(elem)); + // break; + // case SMDSAbs_Volume: + // myVolumePool->destroy(static_cast(elem)); + // break; + // case SMDSAbs_Ball: + // myBallPool->destroy(static_cast(elem)); + // break; + // default: + // break; + // } + // } + myVolumePool->clear(); + myFacePool->clear(); + myEdgePool->clear(); + myBallPool->clear(); + + clearVector( myCells ); + clearVector( myCellIdVtkToSmds ); SMDS_NodeIteratorPtr itn = nodesIterator(); while (itn->more()) { SMDS_MeshNode *node = (SMDS_MeshNode*)(itn->next()); node->SetPosition(SMDS_SpacePosition::originSpacePosition()); - myNodePool->destroy(node); + //myNodePool->destroy(node); } - myNodes.clear(); + myNodePool->clear(); + clearVector( myNodes ); list::iterator itc=myChildren.begin(); while(itc!=myChildren.end()) (*itc)->Clear(); myModified = false; + myModifTime++; xmin = 0; xmax = 0; ymin = 0; ymax = 0; zmin = 0; zmax = 0; diff --git a/src/SMDS/SMDS_MeshGroup.cxx b/src/SMDS/SMDS_MeshGroup.cxx index b81ffe55a..e945c285e 100644 --- a/src/SMDS/SMDS_MeshGroup.cxx +++ b/src/SMDS/SMDS_MeshGroup.cxx @@ -122,17 +122,21 @@ void SMDS_MeshGroup::Clear() //purpose : //======================================================================= -void SMDS_MeshGroup::Add(const SMDS_MeshElement * theElem) +bool SMDS_MeshGroup::Add(const SMDS_MeshElement * theElem) { // the type of the group is determined by the first element added - if (myElements.empty()) myType = theElem->GetType(); + if (myElements.empty()) { + myType = theElem->GetType(); + } else if (theElem->GetType() != myType) { MESSAGE("SMDS_MeshGroup::Add : Type Mismatch "<GetType()<<"!="<InsertPoint(myVtkID, x, y, z); SMDS_CellLinks *cellLinks = dynamic_cast(grid->GetCellLinks()); assert(cellLinks); - if (myVtkID >= cellLinks->GetLinksSize()) - cellLinks->ResizeL(myVtkID+SMDS_Mesh::chunkSize); + cellLinks->ResizeForPoint( myVtkID ); } SMDS_MeshNode::~SMDS_MeshNode() diff --git a/src/SMDS/SMDS_UnstructuredGrid.cxx b/src/SMDS/SMDS_UnstructuredGrid.cxx index 1eb5c445d..5a0578996 100644 --- a/src/SMDS/SMDS_UnstructuredGrid.cxx +++ b/src/SMDS/SMDS_UnstructuredGrid.cxx @@ -17,7 +17,6 @@ // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // -#define CHRONODEF #include "SMDS_UnstructuredGrid.hxx" #include "SMDS_Mesh.hxx" #include "SMDS_MeshInfo.hxx" @@ -44,14 +43,14 @@ SMDS_CellLinks* SMDS_CellLinks::New() return new SMDS_CellLinks(); } -vtkCellLinks::Link* SMDS_CellLinks::ResizeL(vtkIdType sz) +void SMDS_CellLinks::ResizeForPoint(vtkIdType vtkID) { - return vtkCellLinks::Resize(sz); -} - -vtkIdType SMDS_CellLinks::GetLinksSize() -{ - return this->Size; + if ( vtkID > this->MaxId ) + { + this->MaxId = vtkID; + if ( vtkID >= this->Size ) + vtkCellLinks::Resize( vtkID+SMDS_Mesh::chunkSize ); + } } SMDS_CellLinks::SMDS_CellLinks() : @@ -154,7 +153,7 @@ void SMDS_UnstructuredGrid::setSMDS_mesh(SMDS_Mesh *mesh) void SMDS_UnstructuredGrid::compactGrid(std::vector& idNodesOldToNew, int newNodeSize, std::vector& idCellsOldToNew, int newCellSize) { - MESSAGE("------------------------- SMDS_UnstructuredGrid::compactGrid " << newNodeSize << " " << newCellSize);CHRONO(1); + MESSAGE("------------------------- SMDS_UnstructuredGrid::compactGrid " << newNodeSize << " " << newCellSize);//CHRONO(1); int alreadyCopied = 0; // --- if newNodeSize, create a new compacted vtkPoints diff --git a/src/SMDS/SMDS_UnstructuredGrid.hxx b/src/SMDS/SMDS_UnstructuredGrid.hxx index 774c54e27..4cd1dae37 100644 --- a/src/SMDS/SMDS_UnstructuredGrid.hxx +++ b/src/SMDS/SMDS_UnstructuredGrid.hxx @@ -54,8 +54,7 @@ class SMDS_MeshVolume; class SMDS_EXPORT SMDS_CellLinks: public vtkCellLinks { public: - vtkCellLinks::Link* ResizeL(vtkIdType sz); - vtkIdType GetLinksSize(); + void ResizeForPoint(vtkIdType vtkID); static SMDS_CellLinks* New(); protected: SMDS_CellLinks(); @@ -108,6 +107,7 @@ public: static SMDS_UnstructuredGrid* New(); SMDS_Mesh *_mesh; + protected: SMDS_UnstructuredGrid(); ~SMDS_UnstructuredGrid(); diff --git a/src/SMDS/SMDS_VtkEdge.cxx b/src/SMDS/SMDS_VtkEdge.cxx index cb324014e..d3cf38655 100644 --- a/src/SMDS/SMDS_VtkEdge.cxx +++ b/src/SMDS/SMDS_VtkEdge.cxx @@ -33,7 +33,7 @@ SMDS_VtkEdge::SMDS_VtkEdge() { } -SMDS_VtkEdge::SMDS_VtkEdge(std::vector nodeIds, SMDS_Mesh* mesh) +SMDS_VtkEdge::SMDS_VtkEdge(std::vector& nodeIds, SMDS_Mesh* mesh) { init(nodeIds, mesh); } @@ -42,7 +42,7 @@ SMDS_VtkEdge::~SMDS_VtkEdge() { } -void SMDS_VtkEdge::init(std::vector nodeIds, SMDS_Mesh* mesh) +void SMDS_VtkEdge::init(std::vector& nodeIds, SMDS_Mesh* mesh) { SMDS_MeshEdge::init(); vtkUnstructuredGrid* grid = mesh->getGrid(); diff --git a/src/SMDS/SMDS_VtkEdge.hxx b/src/SMDS/SMDS_VtkEdge.hxx index c5f04300b..ff28a3af6 100644 --- a/src/SMDS/SMDS_VtkEdge.hxx +++ b/src/SMDS/SMDS_VtkEdge.hxx @@ -35,9 +35,9 @@ class SMDS_EXPORT SMDS_VtkEdge: public SMDS_MeshEdge public: SMDS_VtkEdge(); - SMDS_VtkEdge(std::vector nodeIds, SMDS_Mesh* mesh); + SMDS_VtkEdge(std::vector& nodeIds, SMDS_Mesh* mesh); ~SMDS_VtkEdge(); - void init(std::vector nodeIds, SMDS_Mesh* mesh); + void init(std::vector& nodeIds, SMDS_Mesh* mesh); bool ChangeNodes(const SMDS_MeshNode * node1, const SMDS_MeshNode * node2); virtual bool ChangeNodes(const SMDS_MeshNode* nodes[], const int nbNodes); virtual bool IsMediumNode(const SMDS_MeshNode* node) const; diff --git a/src/SMESH/Makefile.am b/src/SMESH/Makefile.am index 72cc31ce1..340862396 100644 --- a/src/SMESH/Makefile.am +++ b/src/SMESH/Makefile.am @@ -95,5 +95,6 @@ libSMESHimpl_la_LDFLAGS = \ $(DriverCGNS_LIB) \ ../SMESHUtils/libSMESHUtils.la \ $(BOOST_LIB_THREAD) \ + $(BOOST_LIB_SYSTEM) \ $(GEOM_LDFLAGS) -lNMTTools \ $(CAS_LDPATH) -lTKShHealing -lTKPrim -lTKG2d -lTKCDF diff --git a/src/SMESH/SMESH_Algo.cxx b/src/SMESH/SMESH_Algo.cxx index f7bd7f9bf..ac294864b 100644 --- a/src/SMESH/SMESH_Algo.cxx +++ b/src/SMESH/SMESH_Algo.cxx @@ -87,6 +87,8 @@ SMESH_Algo::SMESH_Algo (int hypId, int studyId, SMESH_Gen * gen) _onlyUnaryInput = _requireDiscreteBoundary = _requireShape = true; _quadraticMesh = _supportSubmeshes = false; _error = COMPERR_OK; + for ( int i = 0; i < 4; ++i ) + _neededLowerHyps[ i ] = false; } //============================================================================= @@ -823,19 +825,42 @@ void SMESH_Algo::addBadInputElement(const SMDS_MeshElement* elem) _badInputElements.push_back( elem ); } +//======================================================================= +//function : addBadInputElements +//purpose : store a bad input elements or nodes preventing computation +//======================================================================= + +void SMESH_Algo::addBadInputElements(const SMESHDS_SubMesh* sm, + const bool addNodes) +{ + if ( sm ) + { + if ( addNodes ) + { + SMDS_NodeIteratorPtr nIt = sm->GetNodes(); + while ( nIt->more() ) addBadInputElement( nIt->next() ); + } + else + { + SMDS_ElemIteratorPtr eIt = sm->GetElements(); + while ( eIt->more() ) addBadInputElement( eIt->next() ); + } + } +} + //============================================================================= /*! * */ //============================================================================= -int SMESH_Algo::NumberOfWires(const TopoDS_Shape& S) -{ - int i = 0; - for (TopExp_Explorer exp(S,TopAbs_WIRE); exp.More(); exp.Next()) - i++; - return i; -} +// int SMESH_Algo::NumberOfWires(const TopoDS_Shape& S) +// { +// int i = 0; +// for (TopExp_Explorer exp(S,TopAbs_WIRE); exp.More(); exp.Next()) +// i++; +// return i; +// } //============================================================================= /*! diff --git a/src/SMESH/SMESH_Algo.hxx b/src/SMESH/SMESH_Algo.hxx index 1a3be0876..76f6de979 100644 --- a/src/SMESH/SMESH_Algo.hxx +++ b/src/SMESH/SMESH_Algo.hxx @@ -43,17 +43,18 @@ #include #include +class SMDS_MeshNode; +class SMESHDS_Mesh; +class SMESHDS_SubMesh; class SMESH_Gen; -class SMESH_Mesh; class SMESH_HypoFilter; -class TopoDS_Vertex; -class TopoDS_Wire; +class SMESH_Mesh; +class SMESH_MesherHelper; +class SMESH_subMesh; class TopoDS_Face; class TopoDS_Shape; -class SMESHDS_Mesh; -class SMDS_MeshNode; -class SMESH_subMesh; -class SMESH_MesherHelper; +class TopoDS_Vertex; +class TopoDS_Wire; class gp_XYZ; typedef std::map< SMESH_subMesh*, std::vector > MapShapeNbElems; @@ -231,6 +232,10 @@ public: bool SupportSubmeshes() const { return _supportSubmeshes; } // 5 - whether supports submeshes if !NeedDiscreteBoundary() + bool NeedLowerHyps(int dim) const { return _neededLowerHyps[ dim ]; } + // 6 - if algo !NeedDiscreteBoundary() but requires presence of + // hypotheses of dimension to generate all-dimensional mesh. + // This info is used not to issue warnings on hiding of lower global algos. public: // ================================================================== @@ -302,7 +307,7 @@ public: */ static bool FaceNormal(const SMDS_MeshElement* F, gp_XYZ& normal, bool normalized=true); - static int NumberOfWires(const TopoDS_Shape& S); + //static int NumberOfWires(const TopoDS_Shape& S); int NumberOfPoints(SMESH_Mesh& aMesh,const TopoDS_Wire& W); /*! @@ -363,6 +368,9 @@ public: */ void addBadInputElement(const SMDS_MeshElement* elem); + void addBadInputElements(const SMESHDS_SubMesh* sm, + const bool addNodes=false); + protected: std::vector _compatibleHypothesis; @@ -373,9 +381,10 @@ protected: // in what turn and with what input shape. // These fields must be redefined if necessary by each descendant at constructor. bool _onlyUnaryInput; // mesh one shape of GetDim() at once. Default TRUE - bool _requireDiscreteBoundary; // GetDim()-1 mesh must be present. Default TRUE + bool _requireDiscreteBoundary;// GetDim()-1 mesh must be present. Default TRUE bool _requireShape; // work with GetDim()-1 mesh bound to geom only. Default TRUE bool _supportSubmeshes; // if !_requireDiscreteBoundary. Default FALSE + bool _neededLowerHyps[4]; // hyp dims needed by algo that !NeedDiscreteBoundary(). Df. FALSE // indicates if quadratic mesh creation is required, // is usually set like this: _quadraticMesh = SMESH_MesherHelper::IsQuadraticSubMesh(shape) diff --git a/src/SMESH/SMESH_Gen.cxx b/src/SMESH/SMESH_Gen.cxx index 95013c9d4..a9ef17d1e 100644 --- a/src/SMESH/SMESH_Gen.cxx +++ b/src/SMESH/SMESH_Gen.cxx @@ -53,6 +53,9 @@ using namespace std; +//#include + + //============================================================================= /*! * Constructor @@ -67,11 +70,12 @@ SMESH_Gen::SMESH_Gen() _segmentation = _nbSegments = 10; SMDS_Mesh::_meshList.clear(); MESSAGE(SMDS_Mesh::_meshList.size()); - _counters = new counters(100); + //_counters = new counters(100); #ifdef WITH_SMESH_CANCEL_COMPUTE _compute_canceled = false; _sm_current = NULL; #endif + //vtkDebugLeaks::SetExitError(0); } //============================================================================= @@ -83,6 +87,12 @@ SMESH_Gen::SMESH_Gen() SMESH_Gen::~SMESH_Gen() { MESSAGE("SMESH_Gen::~SMESH_Gen"); + std::map < int, StudyContextStruct * >::iterator i_sc = _mapStudyContext.begin(); + for ( ; i_sc != _mapStudyContext.end(); ++i_sc ) + { + delete i_sc->second->myDocument; + delete i_sc->second; + } } //============================================================================= @@ -312,6 +322,7 @@ bool SMESH_Gen::Compute(SMESH_Mesh & aMesh, .And( SMESH_HypoFilter::IsMoreLocalThan( algoShape, aMesh )); if ( SMESH_Algo* subAlgo = (SMESH_Algo*) aMesh.GetHypothesis( aSubShape, filter, true )) { + if ( ! subAlgo->NeedDiscreteBoundary() ) continue; SMESH_Hypothesis::Hypothesis_Status status; if ( subAlgo->CheckHypothesis( aMesh, aSubShape, status )) // mesh a lower smToCompute starting from vertices @@ -360,7 +371,8 @@ bool SMESH_Gen::Compute(SMESH_Mesh & aMesh, // fix quadratic mesh by bending iternal links near concave boundary if ( aShape.IsSame( aMesh.GetShapeToMesh() ) && - !aShapesId ) // not preview + !aShapesId && // not preview + ret ) // everything is OK { SMESH_MesherHelper aHelper( aMesh ); if ( aHelper.IsQuadraticMesh() != SMESH_MesherHelper::LINEAR ) @@ -581,12 +593,13 @@ static bool checkConformIgnoredAlgos(SMESH_Mesh& aMesh, } else { - bool isGlobal = (aMesh.IsMainShape( aSubMesh->GetSubShape() )); - int dim = algo->GetDim(); + bool isGlobal = (aMesh.IsMainShape( aSubMesh->GetSubShape() )); + int dim = algo->GetDim(); int aMaxGlobIgnoDim = ( aGlobIgnoAlgo ? aGlobIgnoAlgo->GetDim() : -1 ); + bool isNeededDim = ( aGlobIgnoAlgo ? aGlobIgnoAlgo->NeedLowerHyps( dim ) : false ); - if ( dim < aMaxGlobIgnoDim && - ( isGlobal || !aGlobIgnoAlgo->SupportSubmeshes() )) + if (( dim < aMaxGlobIgnoDim && !isNeededDim ) && + ( isGlobal || !aGlobIgnoAlgo->SupportSubmeshes() )) { // algo is hidden by a global algo theErrors.push_back( SMESH_Gen::TAlgoStateError() ); @@ -642,8 +655,15 @@ static bool checkMissing(SMESH_Gen* aGen, set& aCheckedMap, list< SMESH_Gen::TAlgoStateError > & theErrors) { - if ( aSubMesh->GetSubShape().ShapeType() == TopAbs_VERTEX || - aCheckedMap.count( aSubMesh )) + switch ( aSubMesh->GetSubShape().ShapeType() ) + { + case TopAbs_EDGE: + case TopAbs_FACE: + case TopAbs_SOLID: break; // check this submesh, it can be meshed + default: + return true; // not meshable submesh + } + if ( aCheckedMap.count( aSubMesh )) return true; //MESSAGE("=====checkMissing"); diff --git a/src/SMESH/SMESH_Hypothesis.cxx b/src/SMESH/SMESH_Hypothesis.cxx index fafd29b4b..964032af5 100644 --- a/src/SMESH/SMESH_Hypothesis.cxx +++ b/src/SMESH/SMESH_Hypothesis.cxx @@ -42,13 +42,13 @@ SMESH_Hypothesis::SMESH_Hypothesis(int hypId, int studyId, SMESH_Gen* gen) : SMESHDS_Hypothesis(hypId) { - _gen = gen; - _studyId = studyId; - StudyContextStruct* myStudyContext = _gen->GetStudyContext(_studyId); - myStudyContext->mapHypothesis[_hypId] = this; - _type = PARAM_ALGO; - _shapeType = 0; // to be set by algo with TopAbs_Enum + _gen = gen; + _studyId = studyId; + _type = PARAM_ALGO; + _shapeType = 0; // to be set by algo with TopAbs_Enum _param_algo_dim = -1; // to be set by algo parameter + StudyContextStruct* myStudyContext = gen->GetStudyContext(_studyId); + myStudyContext->mapHypothesis[hypId] = this; } //============================================================================= diff --git a/src/SMESH/SMESH_Hypothesis.hxx b/src/SMESH/SMESH_Hypothesis.hxx index 4c29ff333..ec21fff14 100644 --- a/src/SMESH/SMESH_Hypothesis.hxx +++ b/src/SMESH/SMESH_Hypothesis.hxx @@ -71,10 +71,11 @@ public: SMESH_Hypothesis(int hypId, int studyId, SMESH_Gen* gen); virtual ~SMESH_Hypothesis(); virtual int GetDim() const; - int GetStudyId() const; - virtual void NotifySubMeshesHypothesisModification(); + int GetStudyId() const; + SMESH_Gen* GetGen() const { return (SMESH_Gen*) _gen; } virtual int GetShapeType() const; virtual const char* GetLibName() const; + virtual void NotifySubMeshesHypothesisModification(); void SetLibName(const char* theLibName); //void SetParameters(const char *theParameters); diff --git a/src/SMESH/SMESH_Mesh.cxx b/src/SMESH/SMESH_Mesh.cxx index 2616e0b5f..ecc9e6061 100644 --- a/src/SMESH/SMESH_Mesh.cxx +++ b/src/SMESH/SMESH_Mesh.cxx @@ -103,13 +103,12 @@ SMESH_Mesh::SMESH_Mesh(int theLocalId, _studyId = theStudyId; _gen = theGen; _myDocument = theDocument; - _idDoc = theDocument->NewMesh(theIsEmbeddedMode); - _myMeshDS = theDocument->GetMesh(_idDoc); + _myMeshDS = theDocument->NewMesh(theIsEmbeddedMode,theLocalId); _isShapeToMesh = false; _isAutoColor = false; _isModified = false; _shapeDiagonal = 0.0; - _callUp = 0; + _callUp = NULL; _myMeshDS->ShapeToMesh( PseudoShape() ); } @@ -122,7 +121,6 @@ SMESH_Mesh::SMESH_Mesh(int theLocalId, SMESH_Mesh::SMESH_Mesh(): _id(-1), _studyId(-1), - _idDoc(-1), _groupId( 0 ), _nbSubShapes( 0 ), _isShapeToMesh( false ), @@ -660,8 +658,6 @@ SMESH_Hypothesis::Hypothesis_Status } HasModificationsToDiscard(); // to reset _isModified flag if a mesh becomes empty - GetMeshDS()->Modified(); - if(MYDEBUG) subMesh->DumpAlgoState(true); if(MYDEBUG) SCRUTE(ret); return ret; @@ -735,8 +731,6 @@ SMESH_Hypothesis::Hypothesis_Status HasModificationsToDiscard(); // to reset _isModified flag if mesh become empty - GetMeshDS()->Modified(); - if(MYDEBUG) subMesh->DumpAlgoState(true); if(MYDEBUG) SCRUTE(ret); return ret; @@ -1262,7 +1256,7 @@ void SMESH_Mesh::ExportMED(const char * file, myWriter.SetFile ( file, MED::EVersion(theVersion) ); myWriter.SetMesh ( meshPart ? (SMESHDS_Mesh*) meshPart : _myMeshDS ); if ( !theMeshName ) - myWriter.SetMeshId ( _idDoc ); + myWriter.SetMeshId ( _id ); else { myWriter.SetMeshId ( -1 ); myWriter.SetMeshName( theMeshName ); @@ -1355,7 +1349,7 @@ void SMESH_Mesh::ExportDAT(const char * file, DriverDAT_W_SMDS_Mesh myWriter; myWriter.SetFile( file ); myWriter.SetMesh( meshPart ? (SMESHDS_Mesh*) meshPart : _myMeshDS ); - myWriter.SetMeshId(_idDoc); + myWriter.SetMeshId(_id); myWriter.Perform(); } @@ -1372,7 +1366,7 @@ void SMESH_Mesh::ExportUNV(const char * file, DriverUNV_W_SMDS_Mesh myWriter; myWriter.SetFile( file ); myWriter.SetMesh( meshPart ? (SMESHDS_Mesh*) meshPart : _myMeshDS ); - myWriter.SetMeshId(_idDoc); + myWriter.SetMeshId(_id); // myWriter.SetGroups(_mapGroup); if ( !meshPart ) @@ -1405,7 +1399,7 @@ void SMESH_Mesh::ExportSTL(const char * file, myWriter.SetFile( file ); myWriter.SetIsAscii( isascii ); myWriter.SetMesh( meshPart ? (SMESHDS_Mesh*) meshPart : _myMeshDS); - myWriter.SetMeshId(_idDoc); + myWriter.SetMeshId(_id); myWriter.Perform(); } diff --git a/src/SMESH/SMESH_Mesh.hxx b/src/SMESH/SMESH_Mesh.hxx index 2b926f5dd..8e01301b6 100644 --- a/src/SMESH/SMESH_Mesh.hxx +++ b/src/SMESH/SMESH_Mesh.hxx @@ -344,7 +344,6 @@ private: protected: int _id; // id given by creator (unique within the creator instance) int _studyId; - int _idDoc; // id given by SMESHDS_Document int _groupId; // id generator for group objects int _nbSubShapes; // initial nb of subshapes in the shape to mesh bool _isShapeToMesh;// set to true when a shape is given (only once) diff --git a/src/SMESH/SMESH_MeshEditor.cxx b/src/SMESH/SMESH_MeshEditor.cxx index ce9b88f8a..e87561024 100644 --- a/src/SMESH/SMESH_MeshEditor.cxx +++ b/src/SMESH/SMESH_MeshEditor.cxx @@ -97,6 +97,8 @@ #include #include +#include + #include #include @@ -4169,7 +4171,7 @@ void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap & mapNewNodes, vecNewNodes[ 1 ]->second.back())) { myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(), vecNewNodes[ 1 ]->second.back())); - srcElements.Append( myLastCreatedElems.Last() ); + srcElements.Append( elem ); } } else { @@ -4179,7 +4181,7 @@ void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap & mapNewNodes, myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(), vecNewNodes[ 1 ]->second.back(), vecNewNodes[ 2 ]->second.back())); - srcElements.Append( myLastCreatedElems.Last() ); + srcElements.Append( elem ); } } } @@ -4201,19 +4203,20 @@ void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap & mapNewNodes, int iNext = ( iNode + 1 == nbNodes ) ? 0 : iNode + 1; const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first; const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first; - // check if a link is free + // check if a link n1-n2 is free if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) { hasFreeLinks = true; - // make an edge and a ceiling for a new edge - if ( !aMesh->FindEdge( n1, n2 )) { - myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // free link edge + // make a new edge and a ceiling for a new edge + const SMDS_MeshElement* edge; + if ( ! ( edge = aMesh->FindEdge( n1, n2 ))) { + myLastCreatedElems.Append( edge = aMesh->AddEdge( n1, n2 )); // free link edge srcElements.Append( myLastCreatedElems.Last() ); } n1 = vecNewNodes[ iNode ]->second.back(); n2 = vecNewNodes[ iNext ]->second.back(); if ( !aMesh->FindEdge( n1, n2 )) { - myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // ceiling edge - srcElements.Append( myLastCreatedElems.Last() ); + myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // new edge ceiling + srcElements.Append( edge ); } } } @@ -4235,14 +4238,14 @@ void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap & mapNewNodes, // find medium node if ( !aMesh->FindEdge( n1, n2, n3 )) { myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // free link edge - srcElements.Append( myLastCreatedElems.Last() ); + srcElements.Append( elem ); } n1 = vecNewNodes[ iNode ]->second.back(); n2 = vecNewNodes[ iNext ]->second.back(); n3 = vecNewNodes[ iNode+nbn ]->second.back(); if ( !aMesh->FindEdge( n1, n2, n3 )) { myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // ceiling edge - srcElements.Append( myLastCreatedElems.Last() ); + srcElements.Append( elem ); } } } @@ -4498,7 +4501,7 @@ void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap & mapNewNodes, } while ( srcElements.Length() < myLastCreatedElems.Length() ) - srcElements.Append( myLastCreatedElems.Last() ); + srcElements.Append( elem ); } } // loop on swept elements } @@ -6001,8 +6004,10 @@ SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens, // Sort existing groups by types and collect their names - // to store an old group and a generated new one - typedef pair< SMESHDS_GroupBase*, SMESHDS_Group* > TOldNewGroup; + // to store an old group and a generated new ones + using boost::tuple; + using boost::make_tuple; + typedef tuple< SMESHDS_GroupBase*, SMESHDS_Group*, SMESHDS_Group* > TOldNewGroup; vector< list< TOldNewGroup > > groupsByType( SMDSAbs_NbElementTypes ); vector< TOldNewGroup* > orderedOldNewGroups; // in order of old groups // group names @@ -6018,11 +6023,12 @@ SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens, if ( !group ) continue; SMESHDS_GroupBase* groupDS = group->GetGroupDS(); if ( !groupDS || groupDS->IsEmpty() ) continue; - groupNames.insert( group->GetName() ); + groupNames.insert ( group->GetName() ); groupDS->SetStoreName( group->GetName() ); - SMESHDS_Group* newGroup = new SMESHDS_Group( newGroupID++, mesh->GetMeshDS(), - groupDS->GetType() ); - groupsByType[ groupDS->GetType() ].push_back( make_pair( groupDS, newGroup )); + const SMDSAbs_ElementType type = groupDS->GetType(); + SMESHDS_Group* newGroup = new SMESHDS_Group( newGroupID++, mesh->GetMeshDS(), type ); + SMESHDS_Group* newTopGroup = new SMESHDS_Group( newGroupID++, mesh->GetMeshDS(), type ); + groupsByType[ groupDS->GetType() ].push_back( make_tuple( groupDS, newGroup, newTopGroup )); orderedOldNewGroups.push_back( & groupsByType[ groupDS->GetType() ].back() ); } @@ -6033,7 +6039,7 @@ SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens, const SMESH_SequenceOfElemPtr& gens = isNodes ? nodeGens : elemGens; const SMESH_SequenceOfElemPtr& elems = isNodes ? myLastCreatedNodes : myLastCreatedElems; if ( gens.Length() != elems.Length() ) - throw SALOME_Exception(LOCALIZED("invalid args")); + throw SALOME_Exception("SMESH_MeshEditor::generateGroups(): invalid args"); // loop on created elements for (int iElem = 1; iElem <= elems.Length(); ++iElem ) @@ -6049,7 +6055,7 @@ SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens, ++iElem; // skip all elements made by sourceElem continue; } - // collect all elements made by sourceElem + // collect all elements made by the iElem-th sourceElem list< const SMDS_MeshElement* > resultElems; if ( const SMDS_MeshElement* resElem = elems( iElem )) if ( resElem != sourceElem ) @@ -6063,14 +6069,25 @@ SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens, list< TOldNewGroup >::iterator gOldNew, gLast = groupsOldNew.end(); for ( gOldNew = groupsOldNew.begin(); gOldNew != gLast; ++gOldNew ) { - SMESHDS_GroupBase* oldGroup = gOldNew->first; + SMESHDS_GroupBase* oldGroup = gOldNew->get<0>(); if ( oldGroup->Contains( sourceElem )) // sourceElem is in oldGroup { // fill in a new group - SMDS_MeshGroup & newGroup = gOldNew->second->SMDSGroup(); + SMDS_MeshGroup & newGroup = gOldNew->get<1>()->SMDSGroup(); + list< const SMDS_MeshElement* > rejectedElems; // elements of other type list< const SMDS_MeshElement* >::iterator resLast = resultElems.end(), resElemIt; for ( resElemIt = resultElems.begin(); resElemIt != resLast; ++resElemIt ) - newGroup.Add( *resElemIt ); + if ( !newGroup.Add( *resElemIt )) + rejectedElems.push_back( *resElemIt ); + + // fill "top" group + if ( !rejectedElems.empty() ) + { + SMDS_MeshGroup & newTopGroup = gOldNew->get<2>()->SMDSGroup(); + resLast = rejectedElems.end(); + for ( resElemIt = rejectedElems.begin(); resElemIt != resLast; ++resElemIt ) + !newTopGroup.Add( *resElemIt ); + } } } } // loop on created elements @@ -6078,35 +6095,52 @@ SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens, // Create new SMESH_Groups from SMESHDS_Groups and remove empty SMESHDS_Groups + list topGrouIds; for ( size_t i = 0; i < orderedOldNewGroups.size(); ++i ) { - SMESHDS_GroupBase* oldGroupDS = orderedOldNewGroups[i]->first; - SMESHDS_Group* newGroupDS = orderedOldNewGroups[i]->second; - if ( newGroupDS->IsEmpty() ) - { - mesh->GetMeshDS()->RemoveGroup( newGroupDS ); - } - else - { - // make a name - string name = oldGroupDS->GetStoreName(); - if ( !targetMesh ) { - name += "_"; - name += postfix; - int nb = 1; - while ( !groupNames.insert( name ).second ) // name exists - name = SMESH_Comment( oldGroupDS->GetStoreName() ) << "_" << postfix << "_" << nb++; + SMESHDS_GroupBase* oldGroupDS = orderedOldNewGroups[i]->get<0>(); + SMESHDS_Group* newGroups[2] = { orderedOldNewGroups[i]->get<1>(), + orderedOldNewGroups[i]->get<2>() }; + const int nbNewGroups = !newGroups[0]->IsEmpty() + !newGroups[1]->IsEmpty(); + for ( int is2nd = 0; is2nd < 2; ++is2nd ) + { + SMESHDS_Group* newGroupDS = newGroups[ is2nd ]; + if ( newGroupDS->IsEmpty() ) + { + mesh->GetMeshDS()->RemoveGroup( newGroupDS ); + } + else + { + // set group type + newGroupDS->SetType( newGroupDS->GetElements()->next()->GetType() ); + + // make a name + const bool isTop = ( nbNewGroups == 2 && + newGroupDS->GetType() == oldGroupDS->GetType() ); + string name = oldGroupDS->GetStoreName(); + if ( !targetMesh ) { + string suffix = ( isTop ? "top": postfix.c_str() ); + name += "_"; + name += suffix; + int nb = 1; + while ( !groupNames.insert( name ).second ) // name exists + name = SMESH_Comment( oldGroupDS->GetStoreName() ) << "_" << suffix << "_" << nb++; + } + else if ( isTop ) { + name += "_top"; + } + newGroupDS->SetStoreName( name.c_str() ); + + // make a SMESH_Groups + mesh->AddGroup( newGroupDS ); + if ( isTop ) + topGrouIds.push_back( newGroupDS->GetID() ); + else + newGroupIDs->push_back( newGroupDS->GetID() ); } - newGroupDS->SetStoreName( name.c_str() ); - - // make a SMESH_Groups - mesh->AddGroup( newGroupDS ); - newGroupIDs->push_back( newGroupDS->GetID() ); - - // set group type - newGroupDS->SetType( newGroupDS->GetElements()->next()->GetType() ); } } + newGroupIDs->splice( newGroupIDs->end(), topGrouIds ); return newGroupIDs; } diff --git a/src/SMESH/SMESH_MesherHelper.cxx b/src/SMESH/SMESH_MesherHelper.cxx index ab1cc9cab..668b33232 100644 --- a/src/SMESH/SMESH_MesherHelper.cxx +++ b/src/SMESH/SMESH_MesherHelper.cxx @@ -31,14 +31,13 @@ #include "SMDS_FacePosition.hxx" #include "SMDS_IteratorOnIterators.hxx" #include "SMDS_VolumeTool.hxx" +#include "SMESH_Block.hxx" #include "SMESH_ProxyMesh.hxx" #include "SMESH_subMesh.hxx" #include #include -#include #include -#include #include #include #include @@ -199,7 +198,7 @@ bool SMESH_MesherHelper::IsQuadraticSubMesh(const TopoDS_Shape& aSh) //======================================================================= //function : SetSubShape -//purpose : Set geomerty to make elements on +//purpose : Set geometry to make elements on //======================================================================= void SMESH_MesherHelper::SetSubShape(const int aShID) @@ -214,7 +213,7 @@ void SMESH_MesherHelper::SetSubShape(const int aShID) //======================================================================= //function : SetSubShape -//purpose : Set geomerty to create elements on +//purpose : Set geometry to create elements on //======================================================================= void SMESH_MesherHelper::SetSubShape(const TopoDS_Shape& aSh) @@ -1709,6 +1708,25 @@ namespace } } +//======================================================================= +//function : IsSameElemGeometry +//purpose : Returns true if all elements of a sub-mesh are of same shape +//======================================================================= + +bool SMESH_MesherHelper::IsSameElemGeometry(const SMESHDS_SubMesh* smDS, + SMDSAbs_GeometryType shape, + const bool nullSubMeshRes) +{ + if ( !smDS ) return nullSubMeshRes; + + SMDS_ElemIteratorPtr elemIt = smDS->GetElements(); + while ( elemIt->more() ) + if ( elemIt->next()->GetGeomType() != shape ) + return false; + + return true; +} + //======================================================================= //function : LoadNodeColumns //purpose : Load nodes bound to face into a map of node columns @@ -1738,7 +1756,7 @@ bool SMESH_MesherHelper::LoadNodeColumns(TParam2ColumnMap & theParam2 SMESHDS_Mesh* theMesh, SMESH_ProxyMesh* theProxyMesh) { - // get a right submesh of theFace + // get a right sub-mesh of theFace const SMESHDS_SubMesh* faceSubMesh = 0; if ( theProxyMesh ) @@ -1758,70 +1776,74 @@ bool SMESH_MesherHelper::LoadNodeColumns(TParam2ColumnMap & theParam2 if ( !faceSubMesh || faceSubMesh->NbElements() == 0 ) return false; - // get data of edges for normalization of params - - vector< double > length; - double fullLen = 0; - list::const_iterator edge; + if ( theParam2ColumnMap.empty() ) { - for ( edge = theBaseSide.begin(); edge != theBaseSide.end(); ++edge ) + // get data of edges for normalization of params + + vector< double > length; + double fullLen = 0; + list::const_iterator edge; { - double len = std::max( 1e-10, SMESH_Algo::EdgeLength( *edge )); - fullLen += len; - length.push_back( len ); + for ( edge = theBaseSide.begin(); edge != theBaseSide.end(); ++edge ) + { + double len = std::max( 1e-10, SMESH_Algo::EdgeLength( *edge )); + fullLen += len; + length.push_back( len ); + } } - } - // get nodes on theBaseEdge sorted by param on edge and initialize theParam2ColumnMap with them - edge = theBaseSide.begin(); - for ( int iE = 0; edge != theBaseSide.end(); ++edge, ++iE ) - { - map< double, const SMDS_MeshNode*> sortedBaseNodes; - SMESH_Algo::GetSortedNodesOnEdge( theMesh, *edge,/*noMedium=*/true, sortedBaseNodes); - if ( sortedBaseNodes.empty() ) continue; - - map< double, const SMDS_MeshNode*>::iterator u_n = sortedBaseNodes.begin(); - if ( theProxyMesh ) // from sortedBaseNodes remove nodes not shared by faces of faceSubMesh + // get nodes on theBaseEdge sorted by param on edge and initialize theParam2ColumnMap with them + edge = theBaseSide.begin(); + for ( int iE = 0; edge != theBaseSide.end(); ++edge, ++iE ) { - const SMDS_MeshNode* n1 = sortedBaseNodes.begin()->second; - const SMDS_MeshNode* n2 = sortedBaseNodes.rbegin()->second; - bool allNodesAreProxy = ( n1 != theProxyMesh->GetProxyNode( n1 ) && - n2 != theProxyMesh->GetProxyNode( n2 )); - if ( allNodesAreProxy ) - for ( u_n = sortedBaseNodes.begin(); u_n != sortedBaseNodes.end(); u_n++ ) - u_n->second = theProxyMesh->GetProxyNode( u_n->second ); - - if ( u_n = sortedBaseNodes.begin(), !isNodeInSubMesh( u_n->second, faceSubMesh )) + map< double, const SMDS_MeshNode*> sortedBaseNN; + SMESH_Algo::GetSortedNodesOnEdge( theMesh, *edge,/*noMedium=*/true, sortedBaseNN); + if ( sortedBaseNN.empty() ) continue; + + map< double, const SMDS_MeshNode*>::iterator u_n = sortedBaseNN.begin(); + if ( theProxyMesh ) // from sortedBaseNN remove nodes not shared by faces of faceSubMesh { - while ( ++u_n != sortedBaseNodes.end() && !isNodeInSubMesh( u_n->second, faceSubMesh )); - sortedBaseNodes.erase( sortedBaseNodes.begin(), u_n ); + const SMDS_MeshNode* n1 = sortedBaseNN.begin()->second; + const SMDS_MeshNode* n2 = sortedBaseNN.rbegin()->second; + bool allNodesAreProxy = ( n1 != theProxyMesh->GetProxyNode( n1 ) && + n2 != theProxyMesh->GetProxyNode( n2 )); + if ( allNodesAreProxy ) + for ( u_n = sortedBaseNN.begin(); u_n != sortedBaseNN.end(); u_n++ ) + u_n->second = theProxyMesh->GetProxyNode( u_n->second ); + + if ( u_n = sortedBaseNN.begin(), !isNodeInSubMesh( u_n->second, faceSubMesh )) + { + while ( ++u_n != sortedBaseNN.end() && !isNodeInSubMesh( u_n->second, faceSubMesh )); + sortedBaseNN.erase( sortedBaseNN.begin(), u_n ); + } + else if ( u_n = --sortedBaseNN.end(), !isNodeInSubMesh( u_n->second, faceSubMesh )) + { + while ( u_n != sortedBaseNN.begin() && !isNodeInSubMesh( (--u_n)->second, faceSubMesh )); + sortedBaseNN.erase( ++u_n, sortedBaseNN.end() ); + } + if ( sortedBaseNN.empty() ) continue; } - else if ( u_n = --sortedBaseNodes.end(), !isNodeInSubMesh( u_n->second, faceSubMesh )) + + double f, l; + BRep_Tool::Range( *edge, f, l ); + if ( edge->Orientation() == TopAbs_REVERSED ) std::swap( f, l ); + const double coeff = 1. / ( l - f ) * length[iE] / fullLen; + const double prevPar = theParam2ColumnMap.empty() ? 0 : theParam2ColumnMap.rbegin()->first; + for ( u_n = sortedBaseNN.begin(); u_n != sortedBaseNN.end(); u_n++ ) { - while ( u_n != sortedBaseNodes.begin() && !isNodeInSubMesh( (--u_n)->second, faceSubMesh )); - sortedBaseNodes.erase( ++u_n, sortedBaseNodes.end() ); + double par = prevPar + coeff * ( u_n->first - f ); + TParam2ColumnMap::iterator u2nn = + theParam2ColumnMap.insert( theParam2ColumnMap.end(), make_pair( par, TNodeColumn())); + u2nn->second.push_back( u_n->second ); } - if ( sortedBaseNodes.empty() ) continue; - } - - double f, l; - BRep_Tool::Range( *edge, f, l ); - if ( edge->Orientation() == TopAbs_REVERSED ) std::swap( f, l ); - const double coeff = 1. / ( l - f ) * length[iE] / fullLen; - const double prevPar = theParam2ColumnMap.empty() ? 0 : theParam2ColumnMap.rbegin()->first; - for ( u_n = sortedBaseNodes.begin(); u_n != sortedBaseNodes.end(); u_n++ ) - { - double par = prevPar + coeff * ( u_n->first - f ); - TParam2ColumnMap::iterator u2nn = - theParam2ColumnMap.insert( theParam2ColumnMap.end(), make_pair( par, TNodeColumn())); - u2nn->second.push_back( u_n->second ); } + if ( theParam2ColumnMap.empty() ) + return false; } - if ( theParam2ColumnMap.empty() ) - return false; - - int nbRows = 1 + faceSubMesh->NbElements() / ( theParam2ColumnMap.size()-1 ); + // nb rows of nodes + int prevNbRows = theParam2ColumnMap.begin()->second.size(); // current, at least 1 here + int expectedNbRows = faceSubMesh->NbElements() / ( theParam2ColumnMap.size()-1 ); // to be added // fill theParam2ColumnMap column by column by passing from nodes on // theBaseEdge up via mesh faces on theFace @@ -1834,35 +1856,172 @@ bool SMESH_MesherHelper::LoadNodeColumns(TParam2ColumnMap & theParam2 { vector& nCol1 = par_nVec_1->second; vector& nCol2 = par_nVec_2->second; - nCol1.resize( nbRows ); - nCol2.resize( nbRows ); + nCol1.resize( prevNbRows + expectedNbRows ); + nCol2.resize( prevNbRows + expectedNbRows ); - int i1, i2, iRow = 0; - const SMDS_MeshNode *n1 = nCol1[0], *n2 = nCol2[0]; + int i1, i2, foundNbRows = 0; + const SMDS_MeshNode *n1 = nCol1[ prevNbRows-1 ]; + const SMDS_MeshNode *n2 = nCol2[ prevNbRows-1 ]; // find face sharing node n1 and n2 and belonging to faceSubMesh while ( const SMDS_MeshElement* face = SMESH_MeshEditor::FindFaceInSet( n1, n2, emptySet, avoidSet, &i1, &i2)) { if ( faceSubMesh->Contains( face )) { - int nbNodes = face->IsQuadratic() ? face->NbNodes()/2 : face->NbNodes(); + int nbNodes = face->NbCornerNodes(); if ( nbNodes != 4 ) return false; + if ( foundNbRows + 1 > expectedNbRows ) + return false; n1 = face->GetNode( (i2+2) % 4 ); // opposite corner of quadrangle face n2 = face->GetNode( (i1+2) % 4 ); - if ( ++iRow >= nbRows ) - return false; - nCol1[ iRow ] = n1; - nCol2[ iRow ] = n2; - avoidSet.clear(); + nCol1[ prevNbRows + foundNbRows] = n1; + nCol2[ prevNbRows + foundNbRows] = n2; + ++foundNbRows; } avoidSet.insert( face ); } - // set a real height - nCol1.resize( iRow + 1 ); - nCol2.resize( iRow + 1 ); + if ( foundNbRows != expectedNbRows ) + return false; + avoidSet.clear(); + } + return ( theParam2ColumnMap.size() > 1 && + theParam2ColumnMap.begin()->second.size() == prevNbRows + expectedNbRows ); +} + +namespace +{ + //================================================================================ + /*! + * \brief Return true if a node is at a corner of a 2D structured mesh of FACE + */ + //================================================================================ + + bool isCornerOfStructure( const SMDS_MeshNode* n, + const SMESHDS_SubMesh* faceSM ) + { + int nbFacesInSM = 0; + if ( n ) { + SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator( SMDSAbs_Face ); + while ( fIt->more() ) + nbFacesInSM += faceSM->Contains( fIt->next() ); + } + return ( nbFacesInSM == 1 ); + } +} + +//======================================================================= +//function : IsStructured +//purpose : Return true if 2D mesh on FACE is structured +//======================================================================= + +bool SMESH_MesherHelper::IsStructured( SMESH_subMesh* faceSM ) +{ + SMESHDS_SubMesh* fSM = faceSM->GetSubMeshDS(); + if ( !fSM || fSM->NbElements() == 0 ) + return false; + + list< TopoDS_Edge > edges; + list< int > nbEdgesInWires; + int nbWires = SMESH_Block::GetOrderedEdges( TopoDS::Face( faceSM->GetSubShape() ), + edges, nbEdgesInWires ); + if ( nbWires != 1 ) + return false; + + // algo: find corners of a structure and then analyze nb of faces and + // length of structure sides + + SMESHDS_Mesh* meshDS = faceSM->GetFather()->GetMeshDS(); + + // rotate edges to get the first node being at corner + // (in principle it's not necessary but so far none SALOME algo can make + // such a structured mesh that all corner nodes are not on VERTEXes) + bool isCorner = false; + int nbRemainEdges = nbEdgesInWires.front(); + do { + TopoDS_Vertex V = IthVertex( 0, edges.front() ); + isCorner = isCornerOfStructure( SMESH_Algo::VertexNode( V, meshDS ), fSM); + if ( !isCorner ) { + edges.splice( edges.end(), edges, edges.begin() ); + --nbRemainEdges; + } + } + while ( !isCorner && nbRemainEdges > 0 ); + + if ( !isCorner ) + return false; + + // get all nodes from EDGEs + list< const SMDS_MeshNode* > nodes; + list< TopoDS_Edge >::iterator edge = edges.begin(); + for ( ; edge != edges.end(); ++edge ) + { + map< double, const SMDS_MeshNode* > u2Nodes; + if ( !SMESH_Algo::GetSortedNodesOnEdge( meshDS, *edge, + /*skipMedium=*/true, u2Nodes )) + return false; + + list< const SMDS_MeshNode* > edgeNodes; + map< double, const SMDS_MeshNode* >::iterator u2n = u2Nodes.begin(); + if ( !nodes.empty() && nodes.back() == u2n->second ) + ++u2n; + map< double, const SMDS_MeshNode* >::iterator u2nEnd = --u2Nodes.end(); + if ( nodes.empty() || nodes.back() != u2nEnd->second ) + ++u2nEnd; + for ( ; u2n != u2nEnd; ++u2n ) + edgeNodes.push_back( u2n->second ); + + if ( edge->Orientation() == TopAbs_REVERSED ) + edgeNodes.reverse(); + nodes.splice( nodes.end(), edgeNodes, edgeNodes.begin(), edgeNodes.end() ); + } + + // get length of structured sides + vector nbEdgesInSide; + int nbEdges = 0; + list< const SMDS_MeshNode* >::iterator n = ++nodes.begin(); + for ( ; n != nodes.end(); ++n ) + { + ++nbEdges; + if ( isCornerOfStructure( *n, fSM )) { + nbEdgesInSide.push_back( nbEdges ); + nbEdges = 0; + } + } + + // checks + if ( nbEdgesInSide.size() != 4 ) + return false; + if ( nbEdgesInSide[0] != nbEdgesInSide[2] ) + return false; + if ( nbEdgesInSide[1] != nbEdgesInSide[3] ) + return false; + if ( nbEdgesInSide[0] * nbEdgesInSide[1] != fSM->NbElements() ) + return false; + + return true; +} + +//======================================================================= +//function : Count +//purpose : Count nb of sub-shapes +//======================================================================= + +int SMESH_MesherHelper::Count(const TopoDS_Shape& shape, + const TopAbs_ShapeEnum type, + const bool ignoreSame) +{ + if ( ignoreSame ) { + TopTools_IndexedMapOfShape map; + TopExp::MapShapes( shape, type, map ); + return map.Extent(); + } + else { + int nb = 0; + for ( TopExp_Explorer exp( shape, type ); exp.More(); exp.Next() ) + ++nb; + return nb; } - return theParam2ColumnMap.size() > 1 && theParam2ColumnMap.begin()->second.size() > 1; } //======================================================================= diff --git a/src/SMESH/SMESH_MesherHelper.hxx b/src/SMESH/SMESH_MesherHelper.hxx index da6cfcbfb..af5e10673 100644 --- a/src/SMESH/SMESH_MesherHelper.hxx +++ b/src/SMESH/SMESH_MesherHelper.hxx @@ -58,12 +58,15 @@ typedef gp_XY (*xyFunPtr)(const gp_XY& uv1, const gp_XY& uv2); //======================================================================= /*! - * \brief It helps meshers to add elements + * \brief It helps meshers to add elements and provides other utilities * - * It allow meshers not to care about creation of medium nodes + * - It allows meshers not to care about creation of medium nodes * when filling a quadratic mesh. Helper does it itself. - * It defines degree of elements to create when IsQuadraticSubMesh() + * It defines order of elements to create when IsQuadraticSubMesh() * is called. + * - It provides information on a shape it is initialized with: + * periodicity, presence of singularities etc. + * - ... */ //======================================================================= @@ -73,13 +76,15 @@ public: // ---------- PUBLIC UTILITIES ---------- /*! - * \brief Returns true if given node is medium - * \param n - node to check - * \param typeToCheck - type of elements containing the node to ask about node status + * \brief Returns true if all elements of a sub-mesh are of same shape + * \param smDS - sub-mesh to check elements of + * \param shape - expected shape of elements + * \param nullSubMeshRes - result value for the case of smDS == NULL * \retval bool - check result */ - static bool IsMedium(const SMDS_MeshNode* node, - const SMDSAbs_ElementType typeToCheck = SMDSAbs_All); + static bool IsSameElemGeometry(const SMESHDS_SubMesh* smDS, + SMDSAbs_GeometryType shape, + const bool nullSubMeshRes = true); /*! * \brief Load nodes bound to face into a map of node columns @@ -107,6 +112,19 @@ public: const TopoDS_Edge& theBaseEdge, SMESHDS_Mesh* theMesh, SMESH_ProxyMesh* theProxyMesh=0); + /*! + * \brief Return true if 2D mesh on FACE is structured + */ + static bool IsStructured( SMESH_subMesh* faceSM ); + + /*! + * \brief Returns true if given node is medium + * \param n - node to check + * \param typeToCheck - type of elements containing the node to ask about node status + * \retval bool - check result + */ + static bool IsMedium(const SMDS_MeshNode* node, + const SMDSAbs_ElementType typeToCheck = SMDSAbs_All); /*! * \brief Return support shape of a node * \param node - the node @@ -128,6 +146,17 @@ public: return ind; } + /*! + * \brief Count nb of sub-shapes + * \param shape - the shape + * \param type - the type of sub-shapes to count + * \param ignoreSame - if true, use map not to count same shapes, esle use explorer + * \retval int - the calculated number + */ + static int Count(const TopoDS_Shape& shape, + const TopAbs_ShapeEnum type, + const bool ignoreSame); + /*! * \brief Return number of unique ancestors of the shape */ @@ -141,13 +170,12 @@ public: const SMESH_Mesh& mesh, TopAbs_ShapeEnum ancestorType); /*! - * \brief Find a common ancestors of two shapes of the given type + * \brief Find a common ancestor, of the given type, of two shapes */ static TopoDS_Shape GetCommonAncestor(const TopoDS_Shape& shape1, const TopoDS_Shape& shape2, const SMESH_Mesh& mesh, TopAbs_ShapeEnum ancestorType); - /*! * \brief Return orientation of sub-shape in the main shape */ @@ -205,7 +233,8 @@ public: * or the next methods. By defaul elements are set on the shape if * a mesh has no shape to be meshed */ - void SetElementsOnShape(bool toSet) { mySetElemOnShape = toSet; } + bool SetElementsOnShape(bool toSet) + { bool res = mySetElemOnShape; mySetElemOnShape = toSet; return res; } /*! * \brief Set shape to make elements on without calling IsQuadraticSubMesh() diff --git a/src/SMESH/SMESH_Pattern.cxx b/src/SMESH/SMESH_Pattern.cxx index cc493ca34..757a83354 100644 --- a/src/SMESH/SMESH_Pattern.cxx +++ b/src/SMESH/SMESH_Pattern.cxx @@ -514,7 +514,8 @@ static bool isMeshBoundToShape(SMESHDS_Mesh * aMeshDS, bool SMESH_Pattern::Load (SMESH_Mesh* theMesh, const TopoDS_Face& theFace, - bool theProject) + bool theProject, + TopoDS_Vertex the1stVertex) { MESSAGE(" ::Load(face) " ); Clear(); @@ -538,10 +539,9 @@ bool SMESH_Pattern::Load (SMESH_Mesh* theMesh, // check if face is closed bool isClosed = helper.HasSeam(); - TopoDS_Vertex bidon; list eList; list::iterator elIt; - SMESH_Block::GetOrderedEdges( face, bidon, eList, myNbKeyPntInBoundary ); + SMESH_Block::GetOrderedEdges( face, eList, myNbKeyPntInBoundary, the1stVertex ); // check that requested or needed projection is possible bool isMainShape = theMesh->IsMainShape( face ); @@ -2370,7 +2370,7 @@ bool SMESH_Pattern::Apply (const TopoDS_Face& theFace, list< TopoDS_Edge > eList; list< int > nbVertexInWires; - int nbWires = SMESH_Block::GetOrderedEdges( face, theVertexOnKeyPoint1, eList, nbVertexInWires); + int nbWires = SMESH_Block::GetOrderedEdges( face, eList, nbVertexInWires, theVertexOnKeyPoint1); if ( !theVertexOnKeyPoint1.IsSame( TopExp::FirstVertex( eList.front(), true ))) { MESSAGE( " theVertexOnKeyPoint1 not found in the outer wire "); diff --git a/src/SMESH/SMESH_Pattern.hxx b/src/SMESH/SMESH_Pattern.hxx index 2ba7666aa..272e7bef5 100644 --- a/src/SMESH/SMESH_Pattern.hxx +++ b/src/SMESH/SMESH_Pattern.hxx @@ -35,7 +35,7 @@ #include #include -#include +#include #include #include #include @@ -48,7 +48,6 @@ class SMDS_MeshNode; class SMESH_Mesh; class SMESHDS_SubMesh; class TopoDS_Shell; -class TopoDS_Vertex; class TopoDS_Face; class TopoDS_Edge; @@ -71,7 +70,8 @@ class SMESH_EXPORT SMESH_Pattern { bool Load (SMESH_Mesh* theMesh, const TopoDS_Face& theFace, - bool theProject = false); + bool theProject = false, + TopoDS_Vertex the1stVertex=TopoDS_Vertex()); // Create a pattern from the mesh built on . // ==true makes override nodes positions // on computed by mesher diff --git a/src/SMESH/SMESH_subMesh.cxx b/src/SMESH/SMESH_subMesh.cxx index 5fae7685a..1c03f3fc3 100644 --- a/src/SMESH/SMESH_subMesh.cxx +++ b/src/SMESH/SMESH_subMesh.cxx @@ -264,11 +264,11 @@ bool SMESH_subMesh::IsMeshComputed() const //============================================================================= /*! - * + * Return true if all sub-meshes have been meshed */ //============================================================================= -bool SMESH_subMesh::subMeshesComputed() +bool SMESH_subMesh::SubMeshesComputed() const { int myDim = SMESH_Gen::GetShapeDim( _subShape ); int dimToCheck = myDim - 1; @@ -1398,7 +1398,7 @@ bool SMESH_subMesh::ComputeStateEngine(int event) if (!algo->OnlyUnaryInput()) shape = getCollection( gen, algo, subComputed ); else - subComputed = subMeshesComputed(); + subComputed = SubMeshesComputed(); ret = ( algo->NeedDiscreteBoundary() ? subComputed : algo->SupportSubmeshes() ? true : ( !subComputed || _father->IsNotConformAllowed() )); @@ -1474,9 +1474,12 @@ bool SMESH_subMesh::ComputeStateEngine(int event) } } catch ( SALOME_Exception& S_ex ) { + const int skipSalomeShift = 7; /* to skip "Salome " of + "Salome Exception" prefix returned + by SALOME_Exception::what() */ if ( !_computeError ) _computeError = SMESH_ComputeError::New(); _computeError->myName = COMPERR_SLM_EXCEPTION; - _computeError->myComment = S_ex.what(); + _computeError->myComment = S_ex.what() + skipSalomeShift; } catch ( std::exception& exc ) { if ( !_computeError ) _computeError = SMESH_ComputeError::New(); @@ -1519,7 +1522,26 @@ bool SMESH_subMesh::ComputeStateEngine(int event) { _computeError.reset(); } - updateDependantsState( SUBMESH_COMPUTED ); // send event SUBMESH_COMPUTED + + // send event SUBMESH_COMPUTED + if ( ret ) { + if ( !algo->NeedDiscreteBoundary() ) + // send SUBMESH_COMPUTED to dependants of all sub-meshes of shape + for (subS.ReInit(); subS.More(); subS.Next()) + { + SMESH_subMesh* sm = _father->GetSubMesh( subS.Current() ); + SMESH_subMeshIteratorPtr smIt = sm->getDependsOnIterator(false,false); + while ( smIt->more() ) { + sm = smIt->next(); + if ( sm->GetSubShape().ShapeType() == TopAbs_VERTEX ) + sm->updateDependantsState( SUBMESH_COMPUTED ); + else + break; + } + } + else + updateDependantsState( SUBMESH_COMPUTED ); + } } break; #ifdef WITH_SMESH_CANCEL_COMPUTE @@ -1862,9 +1884,7 @@ void SMESH_subMesh::updateDependantsState(const compute_event theEvent) for (; it.More(); it.Next()) { const TopoDS_Shape& ancestor = it.Value(); - SMESH_subMesh *aSubMesh = - _father->GetSubMeshContaining(ancestor); - if (aSubMesh) + if ( SMESH_subMesh *aSubMesh = _father->GetSubMeshContaining(ancestor)) aSubMesh->ComputeStateEngine( theEvent ); } } @@ -1933,7 +1953,7 @@ TopoDS_Shape SMESH_subMesh::getCollection(SMESH_Gen * theGen, SMESH_Algo* theAlgo, bool & theSubComputed) { - theSubComputed = subMeshesComputed(); + theSubComputed = SubMeshesComputed(); TopoDS_Shape mainShape = _father->GetMeshDS()->ShapeToMesh(); @@ -1966,7 +1986,7 @@ TopoDS_Shape SMESH_subMesh::getCollection(SMESH_Gen * theGen, if (strcmp( anAlgo->GetName(), theAlgo->GetName()) == 0 && // same algo anAlgo->GetUsedHypothesis( *_father, S, ignoreAuxiliaryHyps ) == aUsedHyp) // same hyps aBuilder.Add( aCompound, S ); - if ( !subMesh->subMeshesComputed() ) + if ( !subMesh->SubMeshesComputed() ) theSubComputed = false; } } @@ -2192,20 +2212,19 @@ void SMESH_subMesh::DeleteEventListener(EventListener* listener) { map< EventListener*, EventListenerData* >::iterator l_d = _eventListeners.find( listener ); - if ( l_d != _eventListeners.end() ) { - if ( l_d->first && l_d->first->IsDeletable() ) - { - l_d->first->BeforeDelete( this, l_d->second ); - delete l_d->first; - } + if ( l_d != _eventListeners.end() && l_d->first ) + { if ( l_d->second && l_d->second->IsDeletable() ) { delete l_d->second; } + l_d->first->myBusySM.erase( this ); + if ( l_d->first->IsDeletable() ) + { + l_d->first->BeforeDelete( this, l_d->second ); + delete l_d->first; + } _eventListeners.erase( l_d ); - - if ( l_d->first && !l_d->first->IsDeletable() ) - l_d->first->myBusySM.erase( this ); } } @@ -2343,22 +2362,23 @@ namespace { //================================================================================ SMESH_subMeshIteratorPtr SMESH_subMesh::getDependsOnIterator(const bool includeSelf, - const bool reverse) + const bool reverse) const { + SMESH_subMesh *me = (SMESH_subMesh*) this; SMESH_subMesh *prepend=0, *append=0; if ( includeSelf ) { - if ( reverse ) prepend = this; - else append = this; + if ( reverse ) prepend = me; + else append = me; } typedef map < int, SMESH_subMesh * > TMap; if ( reverse ) { return SMESH_subMeshIteratorPtr - ( new _Iterator( new SMDS_mapReverseIterator( DependsOn() ), prepend, append )); + ( new _Iterator( new SMDS_mapReverseIterator( me->DependsOn() ), prepend, append )); } { return SMESH_subMeshIteratorPtr - ( new _Iterator( new SMDS_mapIterator( DependsOn() ), prepend, append )); + ( new _Iterator( new SMDS_mapIterator( me->DependsOn() ), prepend, append )); } } diff --git a/src/SMESH/SMESH_subMesh.hxx b/src/SMESH/SMESH_subMesh.hxx index 43b8349f1..0c956cea6 100644 --- a/src/SMESH/SMESH_subMesh.hxx +++ b/src/SMESH/SMESH_subMesh.hxx @@ -84,7 +84,7 @@ class SMESH_EXPORT SMESH_subMesh * \brief Return iterator on the submeshes this one depends on */ SMESH_subMeshIteratorPtr getDependsOnIterator(const bool includeSelf, - const bool complexShapeFirst); + const bool complexShapeFirst) const; const TopoDS_Shape & GetSubShape() const; @@ -253,6 +253,8 @@ public: void SetIsAlwaysComputed(bool isAlCo); bool IsAlwaysComputed() { return _alwaysComputed; } + bool SubMeshesComputed() const; + /*! * \brief Find common submeshes (based on shared subshapes with other @@ -267,9 +269,6 @@ protected: // ================================================================== void insertDependence(const TopoDS_Shape aSubShape); - bool subMeshesComputed(); - //bool SubMeshesReady(); - void removeSubMeshElementsAndNodes(); void updateDependantsState(const compute_event theEvent); void updateSubMeshState(const compute_state theState); diff --git a/src/SMESH/memoire.h b/src/SMESH/memoire.h index 258eda28b..531752fbe 100644 --- a/src/SMESH/memoire.h +++ b/src/SMESH/memoire.h @@ -28,7 +28,7 @@ void memostat(const char* f, int l); void memostat(const char* f, int l) { #ifdef WIN32 - //rnv: TODO: find alternative of the malloc_stats() on windows platform + //rnv: TODO: find alternative of the malloc_stats() on windows platform #else /* struct mallinfo mem = mallinfo(); */ /* std::cerr << f << ":"<< l << " " << mem.arena << " " << mem.ordblks << " " << mem.hblks << " " << mem.hblkhd << " " << mem.uordblks << " " << mem.fordblks << " " << mem.keepcost << std::endl; */ diff --git a/src/SMESHDS/SMESHDS_Document.cxx b/src/SMESHDS/SMESHDS_Document.cxx index 315275e33..ff16aa2b0 100644 --- a/src/SMESHDS/SMESHDS_Document.cxx +++ b/src/SMESHDS/SMESHDS_Document.cxx @@ -55,13 +55,15 @@ SMESHDS_Document::~SMESHDS_Document() //function : NewMesh //purpose : //======================================================================= -int SMESHDS_Document::NewMesh(bool theIsEmbeddedMode) -{ - static int aNewMeshID = 0; - aNewMeshID++; - SMESHDS_Mesh *aNewMesh = new SMESHDS_Mesh(aNewMeshID,theIsEmbeddedMode); - myMeshes[aNewMeshID] = aNewMesh; - return aNewMeshID; +SMESHDS_Mesh * SMESHDS_Document::NewMesh(bool theIsEmbeddedMode, int MeshID) +{ + std::map::iterator i_m = + myMeshes.insert( make_pair( MeshID, (SMESHDS_Mesh*)0 )).first; + if ( i_m->second ) + throw SALOME_Exception("SMESHDS_Document::NewMesh(): ID of existing mesh given"); + SMESHDS_Mesh *aNewMesh = new SMESHDS_Mesh(MeshID,theIsEmbeddedMode); + i_m->second = aNewMesh; + return aNewMesh; } //======================================================================= diff --git a/src/SMESHDS/SMESHDS_Document.hxx b/src/SMESHDS/SMESHDS_Document.hxx index 4b7f1fcd1..172b723e2 100644 --- a/src/SMESHDS/SMESHDS_Document.hxx +++ b/src/SMESHDS/SMESHDS_Document.hxx @@ -38,8 +38,8 @@ class SMESHDS_EXPORT SMESHDS_Document { public: SMESHDS_Document(int UserID); - ~SMESHDS_Document(); - int NewMesh(bool theIsEmbeddedMode); + ~SMESHDS_Document(); + SMESHDS_Mesh * NewMesh(bool theIsEmbeddedMode, int MeshID); void RemoveMesh(int MeshID); SMESHDS_Mesh * GetMesh(int MeshID); void AddHypothesis(SMESHDS_Hypothesis * H); diff --git a/src/SMESHDS/SMESHDS_GroupOnFilter.cxx b/src/SMESHDS/SMESHDS_GroupOnFilter.cxx index 32bd8c7f3..80082af0d 100644 --- a/src/SMESHDS/SMESHDS_GroupOnFilter.cxx +++ b/src/SMESHDS/SMESHDS_GroupOnFilter.cxx @@ -28,6 +28,9 @@ #include "SMESHDS_Mesh.hxx" #include "SMDS_SetIterator.hxx" +#include +#include + using namespace std; //============================================================================= @@ -40,9 +43,12 @@ SMESHDS_GroupOnFilter::SMESHDS_GroupOnFilter (const int theID, const SMESHDS_Mesh* theMesh, const SMDSAbs_ElementType theType, const SMESH_PredicatePtr& thePredicate) - : SMESHDS_GroupBase(theID,theMesh,theType), myMeshModifTime(0), myPredicateTic(0) + : SMESHDS_GroupBase(theID,theMesh,theType), + myMeshInfo( SMDSEntity_Last, 0 ), + myMeshModifTime(0), + myPredicateTic(0), + myNbElemToSkip(0) { - setChanged(); SetPredicate( thePredicate ); } @@ -52,7 +58,7 @@ SMESHDS_GroupOnFilter::SMESHDS_GroupOnFilter (const int theID, */ //================================================================================ -void SMESHDS_GroupOnFilter::SetPredicate( const SMESH_PredicatePtr& thePredicate) +void SMESHDS_GroupOnFilter::SetPredicate( const SMESH_PredicatePtr& thePredicate ) { myPredicate = thePredicate; ++myPredicateTic; @@ -70,7 +76,36 @@ void SMESHDS_GroupOnFilter::SetPredicate( const SMESH_PredicatePtr& thePredicate int SMESHDS_GroupOnFilter::Extent() const { update(); - return myElements.size(); + return std::accumulate( myMeshInfo.begin(), myMeshInfo.end(), 0 ); +} + +//================================================================================ +/*! + * \brief Checks emptyness + */ +//================================================================================ + +bool SMESHDS_GroupOnFilter::IsEmpty() +{ + if ( IsUpToDate() ) + { + return ( Extent() == 0 ); + } + else // not up-to-date + { + setChanged(); + SMDS_ElemIteratorPtr okElemIt = GetElements(); + if ( !okElemIt->more() ) + { + // no satisfying elements + setChanged( false ); + } + else + { + return false; + } + } + return true; } //================================================================================ @@ -95,6 +130,53 @@ bool SMESHDS_GroupOnFilter::Contains (const SMDS_MeshElement* elem) return myPredicate ? myPredicate->IsSatisfy( elem->GetID() ) : false; } +//================================================================================ +namespace // Iterator +{ + struct TIterator : public SMDS_ElemIterator + { + SMESH_PredicatePtr myPredicate; + SMDS_ElemIteratorPtr myElemIt; + const SMDS_MeshElement* myNextElem; + size_t myNbToFind, myNbFound; + TIterator( const SMESH_PredicatePtr& filter, + SMDS_ElemIteratorPtr& elems, + size_t nbToFind): + myPredicate( filter ), + myElemIt( elems ), + myNextElem( 0 ), + myNbToFind( nbToFind ), + myNbFound( 0 ) + { + next(); + } + virtual bool more() + { + return myNextElem; + } + virtual const SMDS_MeshElement* next() + { + const SMDS_MeshElement* res = myNextElem; + myNbFound += bool( res ); + myNextElem = 0; + if ( myNbFound < myNbToFind ) + while ( myElemIt->more() && !myNextElem ) + { + myNextElem = myElemIt->next(); + if ( !myPredicate->IsSatisfy( myNextElem->GetID() )) + myNextElem = 0; + } + return res; + } + }; + + struct TEmptyIterator : public SMDS_ElemIterator + { + virtual bool more() { return false; } + virtual const SMDS_MeshElement* next() { return 0; } + }; +} + //================================================================================ /*! * \brief Return iterator on all elements @@ -103,25 +185,84 @@ bool SMESHDS_GroupOnFilter::Contains (const SMDS_MeshElement* elem) SMDS_ElemIteratorPtr SMESHDS_GroupOnFilter::GetElements() const { - update(); - return SMDS_ElemIteratorPtr - ( new SMDS_ElementVectorIterator( myElements.begin(), myElements.end() )); + size_t nbToFind = std::numeric_limits::max(); + + SMDS_ElemIteratorPtr elemIt; + if ( myPredicate ) + { + myPredicate->SetMesh( GetMesh() ); // hope myPredicate updates self here if necessary + + elemIt = GetMesh()->elementsIterator( GetType() ); + if ( IsUpToDate() ) + { + nbToFind = Extent(); + if ( nbToFind == GetMesh()->GetMeshInfo().NbElements( GetType() )) + return elemIt; // all elements are OK + for ( size_t i = 0; i < myNbElemToSkip; ++i ) + elemIt->next(); // skip w/o check + } + } + else + { + elemIt = SMDS_ElemIteratorPtr( new TEmptyIterator ); + } + return SMDS_ElemIteratorPtr ( new TIterator( myPredicate, elemIt, nbToFind )); } //================================================================================ /*! - * \brief return ID of theIndex-th element - * \param theIndex - index countered from 1 - * \retval int - element ID + * \brief Return info on sub-types of elements */ //================================================================================ -int SMESHDS_GroupOnFilter::GetID (const int theIndex) +std::vector< int > SMESHDS_GroupOnFilter::GetMeshInfo() const { update(); - if ( theIndex < 1 || theIndex > myElements.size() ) - return -1; - return myElements[ theIndex-1 ]->GetID(); + return myMeshInfo; +} + +//================================================================================ +/*! + * \brief Fill ids of elements. And return their number. + * \a ids must be pre-allocated using nb of elements of type == GetType() + */ +//================================================================================ + +int SMESHDS_GroupOnFilter::getElementIds( void* ids, size_t idSize ) const +{ + SMESHDS_GroupOnFilter* me = const_cast( this ); + + char* curID = (char*) ids; + SMDS_ElemIteratorPtr elIt = GetElements(); + if ( elIt->more() ) + { + if ( IsUpToDate() ) + { + for ( ; elIt->more(); curID += idSize ) + (*(int*) curID) = elIt->next()->GetID(); + } + else + { + me->setChanged(); + + // find out nb of elements to skip w/o check before the 1st OK element + const SMDS_MeshElement* firstOkElem = me->setNbElemToSkip( elIt ); + + me->myMeshInfo.assign( SMDSEntity_Last, 0 ); + me->myMeshInfo[ firstOkElem->GetEntityType() ]++; + + (*(int*) curID) = firstOkElem->GetID(); + for ( curID += idSize; elIt->more(); curID += idSize ) + { + const SMDS_MeshElement* e = elIt->next(); + (*(int*) curID) = e->GetID(); + me->myMeshInfo[ e->GetEntityType() ]++; + } + } + } + me->setChanged( false ); + + return ( curID - (char*)ids ) / idSize; } //================================================================================ @@ -154,23 +295,17 @@ bool SMESHDS_GroupOnFilter::IsUpToDate() const void SMESHDS_GroupOnFilter::update() const { + SMESHDS_GroupOnFilter* me = const_cast( this ); if ( !IsUpToDate() ) { - SMESHDS_GroupOnFilter* me = const_cast( this ); - me->myElements.clear(); - if ( myPredicate ) - { - myPredicate->SetMesh( GetMesh() ); // hope myPredicate updates self here if necessary - me->myElements.reserve( GetMesh()->GetMeshInfo().NbElements(GetType())); - SMDS_ElemIteratorPtr elIt = GetMesh()->elementsIterator(GetType()); + me->setChanged(); + SMDS_ElemIteratorPtr elIt = GetElements(); + if ( elIt->more() ) { + // find out nb of elements to skip w/o check before the 1st OK element + const SMDS_MeshElement* e = me->setNbElemToSkip( elIt ); + ++me->myMeshInfo[ e->GetEntityType() ]; while ( elIt->more() ) - { - const SMDS_MeshElement* e = elIt->next(); - if ( myPredicate->IsSatisfy( e->GetID() )) - me->myElements.push_back( e ); - } - vector< const SMDS_MeshElement*> elems( me->myElements.begin(), me->myElements.end() ); - me->myElements.swap( elems ); + ++me->myMeshInfo[ elIt->next()->GetEntityType() ]; } me->setChanged( false ); } @@ -178,7 +313,7 @@ void SMESHDS_GroupOnFilter::update() const //================================================================================ /*! - * \brief Sets myMeshModifTime according to modification state + * \brief Sets myMeshModifTime and clear fields according to modification state */ //================================================================================ @@ -187,4 +322,31 @@ void SMESHDS_GroupOnFilter::setChanged(bool changed) myMeshModifTime = GetMesh()->GetMTime(); if ( changed && myMeshModifTime != 0 ) --myMeshModifTime; + if ( changed ) { + myNbElemToSkip = 0; + myMeshInfo.assign( SMDSEntity_Last, 0 ); + } +} + +//================================================================================ +/*! + * \brief Sets myNbElemToSkip + * \param okElemIt - iterator on OK elements + * \retval const SMDS_MeshElement* - the first OK element + */ +//================================================================================ + +const SMDS_MeshElement* +SMESHDS_GroupOnFilter::setNbElemToSkip( SMDS_ElemIteratorPtr& okElemIt ) +{ + // find out nb of elements to skip w/o check before the 1st OK element + const SMDS_MeshElement* firstOkElem = okElemIt->next(); + if ( myNbElemToSkip == 0 ) + { + SMDS_ElemIteratorPtr elemIt = GetMesh()->elementsIterator( GetType() ); + myNbElemToSkip = 0; + while ( elemIt->next() != firstOkElem ) + ++myNbElemToSkip; + } + return firstOkElem; } diff --git a/src/SMESHDS/SMESHDS_GroupOnFilter.hxx b/src/SMESHDS/SMESHDS_GroupOnFilter.hxx index b1e33e5fc..9200744d2 100644 --- a/src/SMESHDS/SMESHDS_GroupOnFilter.hxx +++ b/src/SMESHDS/SMESHDS_GroupOnFilter.hxx @@ -46,7 +46,18 @@ class SMESHDS_EXPORT SMESHDS_GroupOnFilter: public SMESHDS_GroupBase SMESH_PredicatePtr GetPredicate() const { return myPredicate; } - virtual int Extent() const; + std::vector< int > GetMeshInfo() const; + + template< typename IDTYPE > + int GetElementIds( IDTYPE* ids ) const + { + return getElementIds( (void*)ids, sizeof(IDTYPE)); + } + + + virtual int Extent() const; + + virtual bool IsEmpty(); virtual bool Contains (const int theID); @@ -54,21 +65,22 @@ class SMESHDS_EXPORT SMESHDS_GroupOnFilter: public SMESHDS_GroupBase virtual SMDS_ElemIteratorPtr GetElements() const; - virtual int GetID (const int theIndex); - - virtual int GetTic() const; + virtual int GetTic() const; - bool IsUpToDate() const; + bool IsUpToDate() const; private: void update() const; void setChanged(bool changed=true); + const SMDS_MeshElement* setNbElemToSkip( SMDS_ElemIteratorPtr& elIt ); + int getElementIds( void* ids, size_t idSize ) const; SMESH_PredicatePtr myPredicate; - std::vector< const SMDS_MeshElement*> myElements; - unsigned long myMeshModifTime; // when myElements was filled + std::vector< int > myMeshInfo; + size_t myMeshModifTime; // when myMeshInfo was updated int myPredicateTic; + size_t myNbElemToSkip; }; #endif diff --git a/src/SMESHDS/SMESHDS_SubMesh.cxx b/src/SMESHDS/SMESHDS_SubMesh.cxx index 32073bb50..9eb49ff07 100644 --- a/src/SMESHDS/SMESHDS_SubMesh.cxx +++ b/src/SMESHDS/SMESHDS_SubMesh.cxx @@ -469,8 +469,8 @@ SMESHDS_SubMeshIteratorPtr SMESHDS_SubMesh::GetSubMeshIterator() const void SMESHDS_SubMesh::Clear() { - myElements.clear(); - myNodes.clear(); + clearVector( myElements ); + clearVector( myNodes ); myUnusedIdNodes = 0; myUnusedIdElements = 0; SMESHDS_SubMeshIteratorPtr sub = GetSubMeshIterator(); diff --git a/src/SMESHDS/SMESH_Controls.hxx b/src/SMESHDS/SMESH_Controls.hxx index 49d6ab1d2..e23cc43e3 100644 --- a/src/SMESHDS/SMESH_Controls.hxx +++ b/src/SMESHDS/SMESH_Controls.hxx @@ -23,6 +23,9 @@ #ifndef _SMESH_CONTROLS_HXX_ #define _SMESH_CONTROLS_HXX_ +// This file is named incosistently with others, i.e. not SMESHDS_Controls.hxx, +// because it was moved from ../Controls/SMESH_Controls.hxx + #include "SMDSAbs_ElementType.hxx" #include diff --git a/src/SMESHGUI/SMESHGUI.cxx b/src/SMESHGUI/SMESHGUI.cxx index 86de4f316..5c87d1c2c 100644 --- a/src/SMESHGUI/SMESHGUI.cxx +++ b/src/SMESHGUI/SMESHGUI.cxx @@ -357,12 +357,10 @@ anEntryList.append( aMeshSO->GetID().c_str() ); -#ifdef WITHGENERICOBJ // obj has been published in study. Its refcount has been incremented. // It is safe to decrement its refcount // so that it will be destroyed when the entry in study will be removed aMeshes[i]->UnRegister(); -#endif } else { isEmpty = true; @@ -1110,9 +1108,10 @@ vtkLookupTable* lookupTable = static_cast(aScalarBarActor->GetLookupTable()); double * minmax = lookupTable->GetRange(); + bool isLogarithmic = lookupTable->GetScale() == VTK_SCALE_LOG10; std::vector nbEvents; std::vector funValues; - aNumFun->GetHistogram( nbIntervals, nbEvents, funValues, elements, minmax ); + aNumFun->GetHistogram( nbIntervals, nbEvents, funValues, elements, minmax, isLogarithmic ); QString anInitialPath = ""; if ( SUIT_FileDlg::getLastVisitedPath().isEmpty() ) anInitialPath = QDir::currentPath(); @@ -1605,7 +1604,7 @@ aControl = SMESH_Actor::eCoincidentElems3D; break; } - + anActor->SetControlMode(aControl); anActor->GetScalarBarActor()->SetTitle( functorToString( anActor->GetFunctor() ).toLatin1().constData() ); SMESH::RepaintCurrentView(); @@ -1812,22 +1811,23 @@ std::string anEntry = SO->GetID(); /** Erase graphical object **/ - if(SO->FindAttribute(anAttr, "AttributeIOR")){ - ViewManagerList aViewMenegers = anApp->viewManagers(); - ViewManagerList::const_iterator it = aViewMenegers.begin(); - for( ; it != aViewMenegers.end(); it++) { - SUIT_ViewManager* vm = *it; - int nbSf = vm ? vm->getViewsCount() : 0; - if(vm) { - QVector aViews = vm->getViews(); - for(int i = 0; i < nbSf; i++){ - SUIT_ViewWindow *sf = aViews[i]; - if(SMESH_Actor* anActor = SMESH::FindActorByEntry(sf,anEntry.c_str())){ - SMESH::RemoveActor(sf,anActor); - } - } - } - } + if(SO->FindAttribute(anAttr, "AttributeIOR")) { + SMESH::RemoveVisualObjectWithActors( anEntry.c_str(), true); + // ViewManagerList aViewMenegers = anApp->viewManagers(); + // ViewManagerList::const_iterator it = aViewMenegers.begin(); + // for( ; it != aViewMenegers.end(); it++) { + // SUIT_ViewManager* vm = *it; + // int nbSf = vm ? vm->getViewsCount() : 0; + // if(vm) { + // QVector aViews = vm->getViews(); + // for(int i = 0; i < nbSf; i++){ + // SUIT_ViewWindow *sf = aViews[i]; + // if(SMESH_Actor* anActor = SMESH::FindActorByEntry(sf,anEntry.c_str())){ + // SMESH::RemoveActor(sf,anActor); + // } + // } + // } + // } } /** Remove an object from data structures **/ SMESH::SMESH_GroupBase_var aGroup = SMESH::SMESH_GroupBase::_narrow( SMESH::SObjectToObject( SO )); @@ -1891,8 +1891,7 @@ SMESH::SMESH_Gen_var SMESHGUI::myComponentSMESH = SMESH::SMESH_Gen::_nil(); */ //============================================================================= SMESHGUI::SMESHGUI() : -SalomeApp_Module( "SMESH" ), -LightApp_Module( "SMESH" ) +SalomeApp_Module( "SMESH" ) { if ( CORBA::is_nil( myComponentSMESH ) ) { @@ -1927,10 +1926,6 @@ LightApp_Module( "SMESH" ) myEventCallbackCommand->SetCallback( SMESHGUI::ProcessEvents ); myPriority = 0.0; - SMESH::GetFilterManager(); - SMESH::GetPattern(); - SMESH::GetMeasurements(); - /* load resources for all available meshers */ SMESH::InitAvailableHypotheses(); } @@ -1942,12 +1937,6 @@ LightApp_Module( "SMESH" ) //============================================================================= SMESHGUI::~SMESHGUI() { -#ifdef WITHGENERICOBJ - SMESH::GetFilterManager()->UnRegister(); - SMESH::GetMeasurements()->UnRegister(); -#endif - SMESH::GetFilterManager() = SMESH::FilterManager::_nil(); - SMESH::GetMeasurements() = SMESH::Measurements::_nil(); } //============================================================================= @@ -4747,7 +4736,7 @@ void SMESHGUI::createPreferences() setPreferenceProperty( notifyMode, "indexes", indices ); int infoGroup = addPreference( tr( "PREF_GROUP_INFO" ), genTab ); - setPreferenceProperty( infoGroup, "columns", 4 ); + setPreferenceProperty( infoGroup, "columns", 2 ); int elemInfo = addPreference( tr( "PREF_ELEM_INFO" ), infoGroup, LightApp_Preferences::Selector, "SMESH", "mesh_elem_info" ); modes.clear(); modes.append( tr( "PREF_ELEM_INFO_SIMPLE" ) ); @@ -4762,6 +4751,10 @@ void SMESHGUI::createPreferences() setPreferenceProperty( nodesLim, "max", 10000000 ); setPreferenceProperty( nodesLim, "step", 10000 ); setPreferenceProperty( nodesLim, "special", tr( "PREF_UPDATE_LIMIT_NOLIMIT" ) ); + addPreference( tr( "PREF_ELEM_INFO_GRP_DETAILS" ), infoGroup, LightApp_Preferences::Bool, "SMESH", "elem_info_grp_details" ); + addPreference( tr( "PREF_DUMP_BASE_INFO" ), infoGroup, LightApp_Preferences::Bool, "SMESH", "info_dump_base" ); + addPreference( tr( "PREF_DUMP_ELEM_INFO" ), infoGroup, LightApp_Preferences::Bool, "SMESH", "info_dump_elem" ); + addPreference( tr( "PREF_DUMP_ADD_INFO" ), infoGroup, LightApp_Preferences::Bool, "SMESH", "info_dump_add" ); int segGroup = addPreference( tr( "PREF_GROUP_SEGMENT_LENGTH" ), genTab ); setPreferenceProperty( segGroup, "columns", 2 ); @@ -4892,6 +4885,15 @@ void SMESHGUI::createPreferences() setPreferenceProperty( shrink, "min", 0 ); setPreferenceProperty( shrink, "max", 100 ); + int numGroup = addPreference( tr( "PREF_GROUP_NUMBERING" ), meshTab ); + setPreferenceProperty( numGroup, "columns", 2 ); + + addPreference( tr( "PREF_NUMBERING_NODE" ), numGroup, LightApp_Preferences::Color, "SMESH", "numbering_node_color" ); + addVtkFontPref( tr( "PREF_NUMBERING_FONT" ), numGroup, "numbering_node_font", true ); + + addPreference( tr( "PREF_NUMBERING_ELEM" ), numGroup, LightApp_Preferences::Color, "SMESH", "numbering_elem_color" ); + addVtkFontPref( tr( "PREF_NUMBERING_FONT" ), numGroup, "numbering_elem_font", true ); + int orientGroup = addPreference( tr( "PREF_GROUP_FACES_ORIENTATION" ), meshTab ); setPreferenceProperty( orientGroup, "columns", 1 ); @@ -5078,6 +5080,12 @@ void SMESHGUI::preferencesChanged( const QString& sect, const QString& name ) QString val = aResourceMgr->stringValue( "SMESH", name ); myComponentSMESH->SetOption( name.toLatin1().constData(), val.toLatin1().constData() ); } + else if ( name == QString( "numbering_node_color" ) || name == QString( "numbering_node_font" ) ) { + SMESH::UpdateFontProp( this ); + } + else if ( name == QString( "numbering_elem_color" ) || name == QString( "numbering_elem_font" ) ) { + SMESH::UpdateFontProp( this ); + } if(aWarning.size() != 0){ aWarning += "The default values are applied instead."; @@ -6345,7 +6353,7 @@ void SMESHGUI::restoreVisualParameters (int savePoint) \param param parameter \return identifier of preferences */ -int SMESHGUI::addVtkFontPref( const QString& label, const int pId, const QString& param ) +int SMESHGUI::addVtkFontPref( const QString& label, const int pId, const QString& param, const bool needSize ) { int tfont = addPreference( label, pId, LightApp_Preferences::Font, "SMESH", param ); @@ -6359,6 +6367,7 @@ int SMESHGUI::addVtkFontPref( const QString& label, const int pId, const QString setPreferenceProperty( tfont, "fonts", fam ); int f = QtxFontEdit::Family | QtxFontEdit::Bold | QtxFontEdit::Italic | QtxFontEdit::Shadow; + if ( needSize ) f = f | QtxFontEdit::Size; setPreferenceProperty( tfont, "features", f ); return tfont; diff --git a/src/SMESHGUI/SMESHGUI.h b/src/SMESHGUI/SMESHGUI.h index 6f5237ce3..f45cfbfb5 100644 --- a/src/SMESHGUI/SMESHGUI.h +++ b/src/SMESHGUI/SMESHGUI.h @@ -200,9 +200,10 @@ protected: private: void OnEditDelete(); - int addVtkFontPref( const QString& label, - const int pId, - const QString& param ); + int addVtkFontPref( const QString&, + const int, + const QString&, + const bool = false); void connectView( const SUIT_ViewWindow* ); diff --git a/src/SMESHGUI/SMESHGUI_BuildCompoundDlg.cxx b/src/SMESHGUI/SMESHGUI_BuildCompoundDlg.cxx index 51e194370..cadd4593f 100644 --- a/src/SMESHGUI/SMESHGUI_BuildCompoundDlg.cxx +++ b/src/SMESHGUI/SMESHGUI_BuildCompoundDlg.cxx @@ -347,13 +347,11 @@ bool SMESHGUI_BuildCompoundDlg::ClickOnApply() SMESHGUI::Modified(); -#ifdef WITHGENERICOBJ // obj has been published in study. Its refcount has been incremented. // It is safe to decrement its refcount // so that it will be destroyed when the entry in study will be removed if (!CORBA::is_nil(aCompoundMesh)) aCompoundMesh->UnRegister(); -#endif return true; } diff --git a/src/SMESHGUI/SMESHGUI_ComputeDlg.cxx b/src/SMESHGUI/SMESHGUI_ComputeDlg.cxx index 7bf81c56c..1d5555e7e 100644 --- a/src/SMESHGUI/SMESHGUI_ComputeDlg.cxx +++ b/src/SMESHGUI/SMESHGUI_ComputeDlg.cxx @@ -41,6 +41,7 @@ // SALOME GEOM includes #include #include +#include // SALOME GUI includes #include @@ -58,6 +59,7 @@ // SALOME KERNEL includes #include #include +#include // OCCT includes #include @@ -386,17 +388,23 @@ namespace SMESH } // ----------------------------------------------------------------------- /*! - * \brief Return sub-shape by ID + * \brief Return sub-shape by ID. WARNING: UnRegister() must be called on a result */ GEOM::GEOM_Object_ptr getSubShape( int subShapeID, GEOM::GEOM_Object_var aMainShape) { GEOM::GEOM_Object_var aSubShape; - if ( subShapeID == 1 ) + if ( subShapeID == 1 ) { aSubShape = aMainShape; - else if ( _PTR(SObject) so = getSubShapeSO( subShapeID, aMainShape )) + aSubShape->Register(); + } + else if ( _PTR(SObject) so = getSubShapeSO( subShapeID, aMainShape )) { aSubShape = SMESH::SObjectToInterface( so ); - else + aSubShape->Register(); + } + else { aSubShape = SMESH::GetSubShape( aMainShape, subShapeID ); + // future call of UnRegister() will delete a servant of this new object + } return aSubShape._retn(); } // ----------------------------------------------------------------------- @@ -433,7 +441,8 @@ namespace SMESH text = aSO->GetName().c_str(); else { text = QString("#%1").arg( subShapeID ); - QString typeName = shapeTypeName( getSubShape( subShapeID, aMainShape )); + GEOM::GEOM_Object_wrap shape = getSubShape( subShapeID, aMainShape ); + QString typeName = shapeTypeName( shape ); if ( typeName.length() ) text += QString(" (%1)").arg(typeName); } @@ -712,24 +721,43 @@ void SMESHGUI_ComputeDlg_QThread::cancel() //================================================================================ //================================================================================ -SMESHGUI_ComputeDlg_QThreadQDialog::SMESHGUI_ComputeDlg_QThreadQDialog(QWidget *parent, - SMESH::SMESH_Gen_var gen, +SMESHGUI_ComputeDlg_QThreadQDialog::SMESHGUI_ComputeDlg_QThreadQDialog(QWidget * parent, + SMESH::SMESH_Gen_var gen, SMESH::SMESH_Mesh_var mesh, GEOM::GEOM_Object_var mainShape) - : QDialog(parent), + : QDialog(parent, + Qt::WindowSystemMenuHint | + Qt::WindowCloseButtonHint | + Qt::Dialog | + Qt::WindowMaximizeButtonHint), qthread(gen, mesh, mainShape) { // -- setWindowTitle(tr("Compute")); + setMinimumWidth( 200 ); + cancelButton = new QPushButton(tr("Cancel")); cancelButton->setDefault(true); + + QLabel * nbNodesName = new QLabel(tr("SMESH_MESHINFO_NODES"), this ); + QLabel * nbElemsName = new QLabel(tr("SMESH_MESHINFO_ELEMENTS"), this ); + nbNodesLabel = new QLabel("0", this ); + nbElemsLabel = new QLabel("0", this ); + + QGridLayout* layout = new QGridLayout(this); + layout->setMargin( MARGIN ); + layout->setSpacing( SPACING ); + layout->addWidget(nbNodesName, 0, 0); + layout->addWidget(nbNodesLabel, 0, 1); + layout->addWidget(nbElemsName, 1, 0); + layout->addWidget(nbElemsLabel, 1, 1); + layout->addWidget(cancelButton, 2, 0, 1, 2); + adjustSize(); + update(); + connect(cancelButton, SIGNAL(clicked()), this, SLOT(onCancel())); - QHBoxLayout *layout = new QHBoxLayout; - layout->addWidget(cancelButton); - setLayout(layout); - resize(200, 50); // -- - startTimer(30); // 30 millisecs + startTimer(300); // millisecs qthread.start(); } @@ -749,6 +777,8 @@ void SMESHGUI_ComputeDlg_QThreadQDialog::timerEvent(QTimerEvent *event) { close(); } + nbNodesLabel->setText( QString("%1").arg( qthread.getMesh()->NbNodes() )); + nbElemsLabel->setText( QString("%1").arg( qthread.getMesh()->NbElements() )); event->accept(); } @@ -1094,20 +1124,22 @@ void SMESHGUI_BaseComputeOp::onPublishShape() foreach ( row, rows ) { int curSub = table()->item(row, COL_SHAPEID)->text().toInt(); - GEOM::GEOM_Object_var shape = SMESH::getSubShape( curSub, myMainShape ); + GEOM::GEOM_Object_wrap shape = SMESH::getSubShape( curSub, myMainShape ); if ( !shape->_is_nil() && ! SMESH::getSubShapeSO( curSub, myMainShape )) { if ( !SMESH::getSubShapeSO( 1, myMainShape )) // the main shape not published { QString name = GEOMBase::GetDefaultName( SMESH::shapeTypeName( myMainShape, "MAIN_SHAPE" )); - SALOMEDS::SObject_var so = + SALOMEDS::SObject_wrap so = geomGen->AddInStudy( study, myMainShape, name.toLatin1().data(), GEOM::GEOM_Object::_nil()); // look for myMainShape in the table for ( int r = 0, nr = table()->rowCount(); r < nr; ++r ) { if ( table()->item( r, COL_SHAPEID )->text() == "1" ) { if ( so->_is_nil() ) { - table()->item( r, COL_SHAPE )->setText( so->GetName() ); - table()->item( r, COL_PUBLISHED )->setText( so->GetID() ); + CORBA::String_var name = so->GetName(); + CORBA::String_var entry = so->GetID(); + table()->item( r, COL_SHAPE )->setText( name.in() ); + table()->item( r, COL_PUBLISHED )->setText( entry.in() ); } break; } @@ -1115,10 +1147,12 @@ void SMESHGUI_BaseComputeOp::onPublishShape() if ( curSub == 1 ) continue; } QString name = GEOMBase::GetDefaultName( SMESH::shapeTypeName( shape, "ERROR_SHAPE" )); - SALOMEDS::SObject_var so = geomGen->AddInStudy( study, shape, name.toLatin1().data(), myMainShape); + SALOMEDS::SObject_wrap so = geomGen->AddInStudy( study, shape, name.toLatin1().data(), myMainShape); if ( !so->_is_nil() ) { - table()->item( row, COL_SHAPE )->setText( so->GetName() ); - table()->item( row, COL_PUBLISHED )->setText( so->GetID() ); + CORBA::String_var name = so->GetName(); + CORBA::String_var entry = so->GetID(); + table()->item( row, COL_SHAPE )->setText( name.in() ); + table()->item( row, COL_PUBLISHED )->setText( entry.in() ); } } } diff --git a/src/SMESHGUI/SMESHGUI_ComputeDlg.h b/src/SMESHGUI/SMESHGUI_ComputeDlg.h index 49aa2477c..c01dad073 100644 --- a/src/SMESHGUI/SMESHGUI_ComputeDlg.h +++ b/src/SMESHGUI/SMESHGUI_ComputeDlg.h @@ -271,20 +271,21 @@ class SMESHGUI_EXPORT SMESHGUI_ComputeDlg_QThread : public QThread Q_OBJECT public: - SMESHGUI_ComputeDlg_QThread(SMESH::SMESH_Gen_var gen, + SMESHGUI_ComputeDlg_QThread(SMESH::SMESH_Gen_var gen, SMESH::SMESH_Mesh_var mesh, GEOM::GEOM_Object_var mainShape); - bool result(); - void cancel(); - + bool result(); + void cancel(); + SMESH::SMESH_Mesh_var& getMesh() { return myMesh; } + protected: void run(); private: - SMESH::SMESH_Gen_var myGen; + SMESH::SMESH_Gen_var myGen; SMESH::SMESH_Mesh_var myMesh; GEOM::GEOM_Object_var myMainShape; - bool myResult; + bool myResult; }; /*! @@ -296,8 +297,8 @@ class SMESHGUI_EXPORT SMESHGUI_ComputeDlg_QThreadQDialog : public QDialog Q_OBJECT public: - SMESHGUI_ComputeDlg_QThreadQDialog(QWidget *parent, - SMESH::SMESH_Gen_var gen, + SMESHGUI_ComputeDlg_QThreadQDialog(QWidget * parent, + SMESH::SMESH_Gen_var gen, SMESH::SMESH_Mesh_var mesh, GEOM::GEOM_Object_var mainShape); bool result(); @@ -311,8 +312,9 @@ private slots: private: SMESHGUI_ComputeDlg_QThread qthread; - QPushButton *cancelButton; - + QPushButton * cancelButton; + QLabel * nbNodesLabel; + QLabel * nbElemsLabel; }; #endif // SMESHGUI_COMPUTEDLG_H diff --git a/src/SMESHGUI/SMESHGUI_GEOMGenUtils.cxx b/src/SMESHGUI/SMESHGUI_GEOMGenUtils.cxx index ead9da3c0..c0daa7005 100644 --- a/src/SMESHGUI/SMESHGUI_GEOMGenUtils.cxx +++ b/src/SMESHGUI/SMESHGUI_GEOMGenUtils.cxx @@ -30,6 +30,7 @@ // SALOME GEOM includes #include +#include // SALOME KERNEL includes #include @@ -114,10 +115,11 @@ namespace SMESH _PTR(Study) aStudy = SMESH::GetActiveStudyDocument(); if (!aStudy || geomGen->_is_nil()) return GEOM::GEOM_Object::_nil(); - GEOM::GEOM_IShapesOperations_var aShapesOp = geomGen->GetIShapesOperations(aStudy->StudyId()); + GEOM::GEOM_IShapesOperations_wrap aShapesOp = + geomGen->GetIShapesOperations(aStudy->StudyId()); if (aShapesOp->_is_nil()) return GEOM::GEOM_Object::_nil(); - GEOM::GEOM_Object_var subShape = aShapesOp->GetSubShape (theMainShape,theID); + GEOM::GEOM_Object_wrap subShape = aShapesOp->GetSubShape (theMainShape,theID); return subShape._retn(); } } // end of namespace SMESH diff --git a/src/SMESHGUI/SMESHGUI_GroupDlg.cxx b/src/SMESHGUI/SMESHGUI_GroupDlg.cxx index f6d02c232..03ebc2731 100644 --- a/src/SMESHGUI/SMESHGUI_GroupDlg.cxx +++ b/src/SMESHGUI/SMESHGUI_GroupDlg.cxx @@ -44,6 +44,7 @@ // SALOME GEOM includes #include #include +#include // SALOME GUI includes #include @@ -1033,8 +1034,6 @@ bool SMESHGUI_GroupDlg::onApply() return false; _PTR(Study) aStudy = SMESH::GetActiveStudyDocument(); - GEOM::GEOM_IGroupOperations_var aGroupOp = - SMESH::GetGEOMGen()->GetIGroupOperations(aStudy->StudyId()); if (myGeomObjects->length() == 1) { myGroupOnGeom = myMesh->CreateGroupFromGEOM(aType, @@ -1053,8 +1052,7 @@ bool SMESHGUI_GroupDlg::onApply() if (geomGen->_is_nil() || !aStudy) return false; - GEOM::GEOM_IGroupOperations_var op = - geomGen->GetIGroupOperations(aStudy->StudyId()); + GEOM::GEOM_IGroupOperations_wrap op = geomGen->GetIGroupOperations(aStudy->StudyId()); if (op->_is_nil()) return false; @@ -1071,8 +1069,8 @@ bool SMESHGUI_GroupDlg::onApply() } } - GEOM::GEOM_Object_var aMeshShape = myMesh->GetShapeToMesh(); - GEOM::GEOM_Object_var aGroupVar = op->CreateGroup(aMeshShape, aGroupType); + GEOM::GEOM_Object_var aMeshShape = myMesh->GetShapeToMesh(); + GEOM::GEOM_Object_wrap aGroupVar = op->CreateGroup(aMeshShape, aGroupType); op->UnionList(aGroupVar, myGeomObjects); if (op->IsDone()) { @@ -1373,15 +1371,19 @@ void SMESHGUI_GroupDlg::onObjectSelectionChanged() // Check if group constructed on the same shape as a mesh or on its child _PTR(Study) aStudy = SMESH::GetActiveStudyDocument(); - GEOM::GEOM_IGroupOperations_var anOp = - SMESH::GetGEOMGen()->GetIGroupOperations(aStudy->StudyId()); // The main shape of the group GEOM::GEOM_Object_var aGroupMainShape; - if (aGeomGroup->GetType() == 37) + if (aGeomGroup->GetType() == 37) { + GEOM::GEOM_IGroupOperations_wrap anOp = + SMESH::GetGEOMGen()->GetIGroupOperations(aStudy->StudyId()); aGroupMainShape = anOp->GetMainShape(aGeomGroup); - else - aGroupMainShape = GEOM::GEOM_Object::_duplicate(aGeomGroup); + // aGroupMainShape is an existing servant => GEOM_Object_var not GEOM_Object_wrap + } + else { + aGroupMainShape = aGeomGroup; + aGroupMainShape->Register(); + } _PTR(SObject) aGroupMainShapeSO = aStudy->FindObjectID(aGroupMainShape->GetStudyEntry()); @@ -1951,7 +1953,7 @@ void SMESHGUI_GroupDlg::onAdd() } else if (myCurrentLineEdit == myGeomGroupLine && myGeomObjects->length() == 1) { _PTR(Study) aStudy = SMESH::GetActiveStudyDocument(); - GEOM::GEOM_IGroupOperations_var aGroupOp = + GEOM::GEOM_IGroupOperations_wrap aGroupOp = SMESH::GetGEOMGen()->GetIGroupOperations(aStudy->StudyId()); SMESH::ElementType aGroupType = SMESH::ALL; diff --git a/src/SMESHGUI/SMESHGUI_GroupOnShapeDlg.cxx b/src/SMESHGUI/SMESHGUI_GroupOnShapeDlg.cxx index f4cde4f1b..c31a07c44 100644 --- a/src/SMESHGUI/SMESHGUI_GroupOnShapeDlg.cxx +++ b/src/SMESHGUI/SMESHGUI_GroupOnShapeDlg.cxx @@ -33,6 +33,7 @@ #include #include +#include #include #include @@ -204,7 +205,7 @@ LightApp_Dialog* SMESHGUI_GroupOnShapeOp::dlg() const */ //================================================================================ -static SMESH::ElementType elementType(GEOM::GEOM_Object_var& geom) +static SMESH::ElementType elementType(GEOM::GEOM_Object_var geom) { if ( !geom->_is_nil() ) { switch ( geom->GetShapeType() ) { @@ -219,17 +220,18 @@ static SMESH::ElementType elementType(GEOM::GEOM_Object_var& geom) default: return SMESH::ALL; } _PTR(Study) aStudy = SMESH::GetActiveStudyDocument(); - GEOM::GEOM_IShapesOperations_var aShapeOp = + GEOM::GEOM_IShapesOperations_wrap aShapeOp = SMESH::GetGEOMGen()->GetIShapesOperations(aStudy->StudyId()); if ( geom->GetType() == 37 ) { // geom group - GEOM::GEOM_IGroupOperations_var aGroupOp = + GEOM::GEOM_IGroupOperations_wrap aGroupOp = SMESH::GetGEOMGen()->GetIGroupOperations(aStudy->StudyId()); if ( !aGroupOp->_is_nil() ) { + // mainShape is an existing servant => GEOM_Object_var not GEOM_Object_wrap GEOM::GEOM_Object_var mainShape = aGroupOp->GetMainShape( geom ); GEOM::ListOfLong_var ids = aGroupOp->GetObjects( geom ); if ( ids->length() && !mainShape->_is_nil() && !aShapeOp->_is_nil() ) { - GEOM::GEOM_Object_var member = aShapeOp->GetSubShape( mainShape, ids[0] ); + GEOM::GEOM_Object_wrap member = aShapeOp->GetSubShape( mainShape, ids[0] ); return elementType( member ); } } @@ -237,7 +239,7 @@ static SMESH::ElementType elementType(GEOM::GEOM_Object_var& geom) else if ( !aShapeOp->_is_nil() ) { // just a compoud shape GEOM::ListOfLong_var ids = aShapeOp->SubShapeAllIDs( geom, GEOM::SHAPE, false ); if ( ids->length() ) { - GEOM::GEOM_Object_var member = aShapeOp->GetSubShape( geom, ids[0] ); + GEOM::GEOM_Object_wrap member = aShapeOp->GetSubShape( geom, ids[0] ); return elementType( member ); } } @@ -489,13 +491,13 @@ void SMESHGUI_GroupOnShapeOp::selectionDone() } } - if ( myDlg->myElemGeomBtn->isChecked() ) // elem geomerty selection + if ( myDlg->myElemGeomBtn->isChecked() ) // elem geometry selection { myDlg->myElemGeomList->clear(); myDlg->myElemGeomList->addItems( goodNames ); myElemGeoIDs = goodIds; } - else if ( myDlg->myNodeGeomBtn->isChecked() ) // Node geomerty selection + else if ( myDlg->myNodeGeomBtn->isChecked() ) // Node geometry selection { myDlg->myNodeGeomList->clear(); myDlg->myNodeGeomList->addItems( goodNames ); diff --git a/src/SMESHGUI/SMESHGUI_Hypotheses.cxx b/src/SMESHGUI/SMESHGUI_Hypotheses.cxx index 7b10c0ff5..e2852230c 100644 --- a/src/SMESHGUI/SMESHGUI_Hypotheses.cxx +++ b/src/SMESHGUI/SMESHGUI_Hypotheses.cxx @@ -51,23 +51,32 @@ #define SPACING 6 #define MARGIN 11 -//To disable automatic genericobj management, the following line should be commented. -//Otherwise, it should be uncommented. Refer to KERNEL_SRC/src/SALOMEDSImpl/SALOMEDSImpl_AttributeIOR.cxx -#define WITHGENERICOBJ - SMESHGUI_GenericHypothesisCreator::SMESHGUI_GenericHypothesisCreator( const QString& theHypType ) - : myHypType( theHypType ), myIsCreate( false ), myDlg( 0 ) + : myToDeleteInitParamsHypo( false ), + myHypType( theHypType ), + myIsCreate( false ), + myDlg( 0 ) { } SMESHGUI_GenericHypothesisCreator::~SMESHGUI_GenericHypothesisCreator() { + if ( myToDeleteInitParamsHypo && !myInitParamsHypo->_is_nil() ) + myInitParamsHypo->UnRegister(); } void SMESHGUI_GenericHypothesisCreator::setInitParamsHypothesis(SMESH::SMESH_Hypothesis_ptr hyp) { - if ( !CORBA::is_nil( hyp ) && hypType() == hyp->GetName() ) - myInitParamsHypo = SMESH::SMESH_Hypothesis::_duplicate( hyp ); + if ( !CORBA::is_nil( hyp ) ) { + if ( myToDeleteInitParamsHypo && !myInitParamsHypo->_is_nil() ) + myInitParamsHypo->UnRegister(); + CORBA::String_var hypName = hyp->GetName(); + if ( hypType() == hypName.in() ) + { + myInitParamsHypo = SMESH::SMESH_Hypothesis::_duplicate( hyp ); + myToDeleteInitParamsHypo = !SMESH::FindSObject( myInitParamsHypo ); + } + } } void SMESHGUI_GenericHypothesisCreator::create( SMESH::SMESH_Hypothesis_ptr initParamsHyp, @@ -91,19 +100,15 @@ void SMESHGUI_GenericHypothesisCreator::create( bool isAlgo, if (isAlgo) { SMESH::SMESH_Hypothesis_var anAlgo = SMESH::CreateHypothesis( hypType(), theHypName, isAlgo ); -#ifdef WITHGENERICOBJ if (!CORBA::is_nil(anAlgo)) anAlgo->UnRegister(); -#endif } else { SMESH::SMESH_Hypothesis_var aHypothesis = SMESH::CreateHypothesis( hypType(), theHypName, false ); editHypothesis( aHypothesis.in(), theHypName, theParent, obj, slot ); -#ifdef WITHGENERICOBJ if (!CORBA::is_nil(aHypothesis)) aHypothesis->UnRegister(); -#endif } } @@ -128,9 +133,7 @@ void SMESHGUI_GenericHypothesisCreator::editHypothesis( SMESH::SMESH_Hypothesis_ { myHypName = theHypName; myHypo = SMESH::SMESH_Hypothesis::_duplicate( h ); -#ifdef WITHGENERICOBJ myHypo->Register(); -#endif SMESHGUI_HypothesisDlg* Dlg = new SMESHGUI_HypothesisDlg( this, theParent ); connect( Dlg, SIGNAL( finished( int ) ), this, SLOT( onDialogFinished( int ) ) ); @@ -302,9 +305,7 @@ void SMESHGUI_GenericHypothesisCreator::onDialogFinished( int result ) } } SMESHGUI::GetSMESHGUI()->updateObjBrowser( true, 0 ); -#ifdef WITHGENERICOBJ myHypo->UnRegister(); -#endif myHypo = SMESH::SMESH_Hypothesis::_nil(); myInitParamsHypo = SMESH::SMESH_Hypothesis::_nil(); diff --git a/src/SMESHGUI/SMESHGUI_Hypotheses.h b/src/SMESHGUI/SMESHGUI_Hypotheses.h index bb5d9f8ac..22fc991f2 100644 --- a/src/SMESHGUI/SMESHGUI_Hypotheses.h +++ b/src/SMESHGUI/SMESHGUI_Hypotheses.h @@ -130,6 +130,7 @@ private: private: SMESH::SMESH_Hypothesis_var myHypo, myInitParamsHypo; + bool myToDeleteInitParamsHypo; QString myHypName; QString myHypType; ListOfWidgets myParamWidgets; diff --git a/src/SMESHGUI/SMESHGUI_HypothesesUtils.cxx b/src/SMESHGUI/SMESHGUI_HypothesesUtils.cxx index 2c5d1828c..b52f7308e 100644 --- a/src/SMESHGUI/SMESHGUI_HypothesesUtils.cxx +++ b/src/SMESHGUI/SMESHGUI_HypothesesUtils.cxx @@ -612,23 +612,21 @@ namespace SMESH return res < SMESH::HYP_UNKNOWN_FATAL; } - bool RemoveHypothesisOrAlgorithmOnMesh (_PTR(SObject) MorSM, + bool RemoveHypothesisOrAlgorithmOnMesh (_PTR(SObject) MorSM, SMESH::SMESH_Hypothesis_ptr anHyp) { - SALOMEDS::GenericAttribute_var anAttr; - SALOMEDS::AttributeIOR_var anIOR; int res = SMESH::HYP_UNKNOWN_FATAL; SUIT_OverrideCursor wc; if (MorSM) { try { GEOM::GEOM_Object_var aShapeObject = SMESH::GetShapeOnMeshOrSubMesh(MorSM); - SMESH::SMESH_Mesh_var aMesh = SMESH::SObjectToInterface(MorSM); - SMESH::SMESH_subMesh_var aSubMesh = SMESH::SObjectToInterface(MorSM); - + SMESH::SMESH_Mesh_var aMesh = SMESH::SObjectToInterface(MorSM); + SMESH::SMESH_subMesh_var aSubMesh = SMESH::SObjectToInterface(MorSM); + if (!aSubMesh->_is_nil()) aMesh = aSubMesh->GetFather(); - + if (!aMesh->_is_nil()) { if (aMesh->HasShapeToMesh() && !aShapeObject->_is_nil()) { res = aMesh->RemoveHypothesis(aShapeObject, anHyp); diff --git a/src/SMESHGUI/SMESHGUI_MergeDlg.cxx b/src/SMESHGUI/SMESHGUI_MergeDlg.cxx index 877d6b6d4..b1345a00a 100644 --- a/src/SMESHGUI/SMESHGUI_MergeDlg.cxx +++ b/src/SMESHGUI/SMESHGUI_MergeDlg.cxx @@ -670,7 +670,7 @@ bool SMESHGUI_MergeDlg::ClickOnApply() aMeshEditor->MergeElements (aGroupsOfElements.inout()); if ( myTypeId == 0 ) { - if (myAction ==0) + if (myAction == 0 ) SUIT_MessageBox::information(SMESHGUI::desktop(), tr("SMESH_INFORMATION"), tr("SMESH_MERGED_NODES").arg(QString::number(ListCoincident->count()).toLatin1().data())); else diff --git a/src/SMESHGUI/SMESHGUI_MeshInfo.cxx b/src/SMESHGUI/SMESHGUI_MeshInfo.cxx index 3b90ce6d6..98761c133 100644 --- a/src/SMESHGUI/SMESHGUI_MeshInfo.cxx +++ b/src/SMESHGUI/SMESHGUI_MeshInfo.cxx @@ -34,17 +34,23 @@ #include "SMDS_BallElement.hxx" #include "SMDS_EdgePosition.hxx" #include "SMDS_FacePosition.hxx" +#include "SMESHDS_Mesh.hxx" #include "SMESH_ControlsDef.hxx" #include +#include #include #include +#include #include #include +#include #include #include +#include +#include #include #include #include @@ -52,8 +58,10 @@ #include #include #include +#include #include #include +#include #include #include #include @@ -68,6 +76,17 @@ const int MARGIN = 9; const int MAXITEMS = 10; const int GROUPS_ID = 100; const int SUBMESHES_ID = 200; +const int SPACING_INFO = 2; + +enum InfoRole { + TypeRole = Qt::UserRole + 10, + IdRole, +}; + +enum InfoType { + NodeConnectivity = 100, + ElemConnectivity, +}; /*! \class ExtraWidget @@ -117,6 +136,68 @@ void ExtraWidget::updateControls( int total, int index, int blockSize ) next->setEnabled( (index+1)*blockSize < total ); } +/*! + \class DumpFileDlg + \brief Customization of standard "Save file" dialog box for dump info operation + \internal +*/ + +class DumpFileDlg : public SUIT_FileDlg +{ +public: + DumpFileDlg( QWidget* parent ); + + QCheckBox* myBaseChk; + QCheckBox* myElemChk; + QCheckBox* myAddChk; +}; + +/*! + \brief Constructor + \internal +*/ +DumpFileDlg::DumpFileDlg( QWidget* parent ) : SUIT_FileDlg( parent, false, true, true ) +{ + QGridLayout* grid = ::qobject_cast( layout() ); + if ( grid ) { + QWidget* hB = new QWidget( this ); + myBaseChk = new QCheckBox( SMESHGUI::tr( "PREF_DUMP_BASE_INFO" ), hB ); + myElemChk = new QCheckBox( SMESHGUI::tr( "PREF_DUMP_ELEM_INFO" ), hB ); + myAddChk = new QCheckBox( SMESHGUI::tr( "PREF_DUMP_ADD_INFO" ), hB ); + + QHBoxLayout* layout = new QHBoxLayout( hB ); + layout->addWidget( myBaseChk ); + layout->addWidget( myElemChk ); + layout->addWidget( myAddChk ); + + QPushButton* pb = new QPushButton( this ); + + int row = grid->rowCount(); + grid->addWidget( new QLabel( "", this ), row, 0 ); + grid->addWidget( hB, row, 1, 1, 3 ); + grid->addWidget( pb, row, 5 ); + + pb->hide(); + } +} + +/*! + \brief Get depth of the tree item + \internal + \param theItem tree widget item + \return item's depth in tree widget (where top-level items have zero depth) +*/ +static int itemDepth( QTreeWidgetItem* item ) +{ + int d = 0; + QTreeWidgetItem* p = item->parent(); + while ( p ) { + d++; + p = p->parent(); + } + return d; +} + /*! \class SMESHGUI_MeshInfo \brief Base mesh information widget @@ -165,6 +246,14 @@ SMESHGUI_MeshInfo::SMESHGUI_MeshInfo( QWidget* parent ) myWidgets[ index++ ] << aElemLine; myWidgets[ index++ ] << aElemLab << aElemTotal << aElemLin << aElemQuad; + // ... Number elements + QWidget* aNbLine = createLine(); + QLabel* aNbTotal = createField(); + QLabel* aNbLin = createField(); + QLabel* aNbQuad = createField(); + myWidgets[ index++ ] << aNbLine; + myWidgets[ index++ ] << new QLabel( "", this ) << aNbTotal << aNbLin << aNbQuad; + // ... 0D elements QWidget* a0DLine = createLine(); QLabel* a0DLab = new QLabel( tr( "0D_LAB" ), this ); @@ -274,58 +363,63 @@ SMESHGUI_MeshInfo::SMESHGUI_MeshInfo( QWidget* parent ) l->addWidget( aElemTotal, 5, 1 ); l->addWidget( aElemLin, 5, 2 ); l->addWidget( aElemQuad, 5, 3 ); - l->addWidget( a0DLine, 6, 1, 1, 3 ); - l->addWidget( a0DLab, 7, 0 ); - l->addWidget( a0DTotal, 7, 1 ); - l->addWidget( aBallLine, 8, 1, 1, 3 ); - l->addWidget( aBallLab, 9, 0 ); - l->addWidget( aBallTotal, 9, 1 ); - l->addWidget( a1DLine, 10, 1, 1, 3 ); - l->addWidget( a1DLab, 11, 0 ); - l->addWidget( a1DTotal, 11, 1 ); - l->addWidget( a1DLin, 11, 2 ); - l->addWidget( a1DQuad, 11, 3 ); - l->addWidget( a2DLine, 12, 1, 1, 3 ); - l->addWidget( a2DLab, 13, 0 ); - l->addWidget( a2DTotal, 13, 1 ); - l->addWidget( a2DLin, 13, 2 ); - l->addWidget( a2DQuad, 13, 3 ); - l->addWidget( a2DTriLab, 14, 0 ); - l->addWidget( a2DTriTotal, 14, 1 ); - l->addWidget( a2DTriLin, 14, 2 ); - l->addWidget( a2DTriQuad, 14, 3 ); - l->addWidget( a2DQuaLab, 15, 0 ); - l->addWidget( a2DQuaTotal, 15, 1 ); - l->addWidget( a2DQuaLin, 15, 2 ); - l->addWidget( a2DQuaQuad, 15, 3 ); - l->addWidget( a2DPolLab, 16, 0 ); - l->addWidget( a2DPolTotal, 16, 1 ); - l->addWidget( a3DLine, 17, 1, 1, 3 ); - l->addWidget( a3DLab, 18, 0 ); - l->addWidget( a3DTotal, 18, 1 ); - l->addWidget( a3DLin, 18, 2 ); - l->addWidget( a3DQuad, 18, 3 ); - l->addWidget( a3DTetLab, 19, 0 ); - l->addWidget( a3DTetTotal, 19, 1 ); - l->addWidget( a3DTetLin, 19, 2 ); - l->addWidget( a3DTetQuad, 19, 3 ); - l->addWidget( a3DHexLab, 20, 0 ); - l->addWidget( a3DHexTotal, 20, 1 ); - l->addWidget( a3DHexLin, 20, 2 ); - l->addWidget( a3DHexQuad, 20, 3 ); - l->addWidget( a3DPyrLab, 21, 0 ); - l->addWidget( a3DPyrTotal, 21, 1 ); - l->addWidget( a3DPyrLin, 21, 2 ); - l->addWidget( a3DPyrQuad, 21, 3 ); - l->addWidget( a3DPriLab, 22, 0 ); - l->addWidget( a3DPriTotal, 22, 1 ); - l->addWidget( a3DPriLin, 22, 2 ); - l->addWidget( a3DPriQuad, 22, 3 ); - l->addWidget( a3DHexPriLab, 23, 0 ); - l->addWidget( a3DHexPriTotal, 23, 1 ); - l->addWidget( a3DPolLab, 24, 0 ); - l->addWidget( a3DPolTotal, 24, 1 ); - l->addWidget( myLoadBtn, 25, 1, 1, 3 ); + l->addWidget( aNbLine, 6, 1, 1, 3 ); + l->addWidget( aNbTotal, 7, 1 ); + l->addWidget( aNbLin, 7, 2 ); + l->addWidget( aNbQuad, 7, 3 ); + l->addWidget( a0DLine, 8, 1, 1, 3 ); + l->addWidget( a0DLab, 9, 0 ); + l->addWidget( a0DTotal, 9, 1 ); + l->addWidget( aBallLine, 10, 1, 1, 3 ); + l->addWidget( aBallLab, 11, 0 ); + l->addWidget( aBallTotal, 11, 1 ); + l->addWidget( a1DLine, 12, 1, 1, 3 ); + l->addWidget( a1DLab, 13, 0 ); + l->addWidget( a1DTotal, 13, 1 ); + l->addWidget( a1DLin, 13, 2 ); + l->addWidget( a1DQuad, 13, 3 ); + l->addWidget( a2DLine, 14, 1, 1, 3 ); + l->addWidget( a2DLab, 15, 0 ); + l->addWidget( a2DTotal, 15, 1 ); + l->addWidget( a2DLin, 15, 2 ); + l->addWidget( a2DQuad, 15, 3 ); + l->addWidget( a2DTriLab, 16, 0 ); + l->addWidget( a2DTriTotal, 16, 1 ); + l->addWidget( a2DTriLin, 16, 2 ); + l->addWidget( a2DTriQuad, 16, 3 ); + l->addWidget( a2DQuaLab, 17, 0 ); + l->addWidget( a2DQuaTotal, 17, 1 ); + l->addWidget( a2DQuaLin, 17, 2 ); + l->addWidget( a2DQuaQuad, 17, 3 ); + l->addWidget( a2DPolLab, 18, 0 ); + l->addWidget( a2DPolTotal, 18, 1 ); + l->addWidget( a3DLine, 19, 1, 1, 3 ); + l->addWidget( a3DLab, 20, 0 ); + l->addWidget( a3DTotal, 20, 1 ); + l->addWidget( a3DLin, 20, 2 ); + l->addWidget( a3DQuad, 20, 3 ); + l->addWidget( a3DTetLab, 21, 0 ); + l->addWidget( a3DTetTotal, 21, 1 ); + l->addWidget( a3DTetLin, 21, 2 ); + l->addWidget( a3DTetQuad, 21, 3 ); + l->addWidget( a3DHexLab, 22, 0 ); + l->addWidget( a3DHexTotal, 22, 1 ); + l->addWidget( a3DHexLin, 22, 2 ); + l->addWidget( a3DHexQuad, 22, 3 ); + l->addWidget( a3DPyrLab, 23, 0 ); + l->addWidget( a3DPyrTotal, 23, 1 ); + l->addWidget( a3DPyrLin, 23, 2 ); + l->addWidget( a3DPyrQuad, 23, 3 ); + l->addWidget( a3DPriLab, 24, 0 ); + l->addWidget( a3DPriTotal, 24, 1 ); + l->addWidget( a3DPriLin, 24, 2 ); + l->addWidget( a3DPriQuad, 24, 3 ); + l->addWidget( a3DHexPriLab, 25, 0 ); + l->addWidget( a3DHexPriTotal, 25, 1 ); + l->addWidget( a3DPolLab, 26, 0 ); + l->addWidget( a3DPolTotal, 26, 1 ); + l->addWidget( myLoadBtn, 27, 1, 1, 3 ); + l->setColumnStretch( 0, 0 ); l->setColumnStretch( 1, 5 ); l->setColumnStretch( 2, 5 ); @@ -434,7 +528,12 @@ void SMESHGUI_MeshInfo::showInfo( SMESH::SMESH_IDSource_ptr obj ) myWidgets[i3DPrisms][iQuadratic] ->setProperty( "text", QString::number( info[SMDSEntity_Quad_Penta] ) ); myWidgets[i3DHexaPrisms][iTotal] ->setProperty( "text", QString::number( info[SMDSEntity_Hexagonal_Prism] ) ); myWidgets[i3DPolyhedrons][iTotal] ->setProperty( "text", QString::number( info[SMDSEntity_Polyhedra] ) ); - + long nbElemTotal = info[SMDSEntity_0D] + info[SMDSEntity_Ball] + nbEdges + nb2DLinear + nb2DQuadratic + nb3DLinear + nb3DQuadratic; + long nbElemLinerial = info[SMDSEntity_Edge] + nb2DLinear + nb3DLinear; + long nbElemQuadratic = info[SMDSEntity_Quad_Edge] + nb2DQuadratic + nb3DQuadratic; + myWidgets[iNb][iTotal] ->setProperty( "text", QString::number( nbElemTotal ) ); + myWidgets[iNb][iLinear] ->setProperty( "text", QString::number( nbElemLinerial ) ); + myWidgets[iNb][iQuadratic]->setProperty( "text", QString::number( nbElemQuadratic ) ); // before full loading from study file, type of elements in a sub-mesh can't be defined // in some cases bool infoOK = obj->IsMeshInfoCorrect(); @@ -460,6 +559,9 @@ void SMESHGUI_MeshInfo::showInfo( SMESH::SMESH_IDSource_ptr obj ) myWidgets[i2DQuadrangles][iLinear] ->setProperty( "text", "?" ); myWidgets[i2DQuadrangles][iQuadratic]->setProperty( "text", "?" ); myWidgets[i2DPolygons][iTotal] ->setProperty( "text", "?" ); + myWidgets[iNb][iTotal] ->setProperty( "text", "?" ); + myWidgets[iNb][iLinear] ->setProperty( "text", "?" ); + myWidgets[iNb][iQuadratic] ->setProperty( "text", "?" ); } else if ( nb3DLinear + nb3DQuadratic > 0 ) { @@ -479,6 +581,9 @@ void SMESHGUI_MeshInfo::showInfo( SMESH::SMESH_IDSource_ptr obj ) myWidgets[i3DPrisms][iQuadratic] ->setProperty( "text", "?" ); myWidgets[i3DHexaPrisms][iTotal] ->setProperty( "text", "?" ); myWidgets[i3DPolyhedrons][iTotal] ->setProperty( "text", "?" ); + myWidgets[iNb][iTotal] ->setProperty( "text", "?" ); + myWidgets[iNb][iLinear] ->setProperty( "text", "?" ); + myWidgets[iNb][iQuadratic] ->setProperty( "text", "?" ); } } else @@ -516,6 +621,9 @@ void SMESHGUI_MeshInfo::showInfo( SMESH::SMESH_IDSource_ptr obj ) myWidgets[i3DPrisms][iQuadratic] ->setProperty( "text", "?" ); myWidgets[i3DHexaPrisms][iTotal] ->setProperty( "text", "?" ); myWidgets[i3DPolyhedrons][iTotal] ->setProperty( "text", "?" ); + myWidgets[iNb][iTotal] ->setProperty( "text", "?" ); + myWidgets[iNb][iLinear] ->setProperty( "text", "?" ); + myWidgets[iNb][iQuadratic] ->setProperty( "text", "?" ); } } } @@ -585,6 +693,9 @@ void SMESHGUI_MeshInfo::clear() myWidgets[i3DPrisms][iQuadratic] ->setProperty( "text", QString::number( 0 ) ); myWidgets[i3DHexaPrisms][iTotal] ->setProperty( "text", QString::number( 0 ) ); myWidgets[i3DPolyhedrons][iTotal] ->setProperty( "text", QString::number( 0 ) ); + myWidgets[iNb][iTotal] ->setProperty( "text", QString::number( 0 ) ); + myWidgets[iNb][iLinear] ->setProperty( "text", QString::number( 0 ) ); + myWidgets[iNb][iQuadratic] ->setProperty( "text", QString::number( 0 ) ); } /*! @@ -647,6 +758,66 @@ void SMESHGUI_MeshInfo::setFieldsVisible( int start, int end, bool on ) } } +void SMESHGUI_MeshInfo::saveInfo( QTextStream &out ) +{ + out << QString( 9, '-' ) << "\n"; + out << tr( "BASE_INFO" ) << "\n"; + out << QString( 9, '-' ) << "\n"; + out << tr( "NAME_LAB" ) << " " << ( myWidgets[iName][iSingle]->property( "text" ) ).toString() << "\n"; + out << tr( "OBJECT_LAB" ) << " " << ( myWidgets[iObject][iSingle]->property( "text" ) ).toString() << "\n"; + out << tr( "NODES_LAB" ) << " " << ( myWidgets[iNodes][iTotal]->property( "text" ) ).toString() << "\n"; + out << tr( "ELEMENTS_LAB" ) << "\n"; + out << QString( SPACING_INFO, ' ' ) << tr( "TOTAL_LAB" ) << ": " << ( myWidgets[iNb][iTotal]->property( "text" ) ).toString() << "\n"; + out << QString( SPACING_INFO, ' ' ) << tr( "LINEAR_LAB" ) << ": " << ( myWidgets[iNb][iLinear]->property( "text" ) ).toString() << "\n"; + out << QString( SPACING_INFO, ' ' ) << tr( "QUADRATIC_LAB" ) << ": " << ( myWidgets[iNb][iQuadratic]->property( "text" ) ).toString() << "\n"; + out << QString( SPACING_INFO, ' ' ) << tr( "0D_LAB" ) << "\n"; + out << QString( SPACING_INFO*2, ' ' ) << tr( "TOTAL_LAB" ) << ": " << ( myWidgets[i0D][iTotal]->property( "text" ) ).toString() << "\n"; + out << QString( SPACING_INFO, ' ' ) << tr( "BALL_LAB" ) << "\n"; + out << QString( SPACING_INFO*2, ' ' ) << tr( "TOTAL_LAB" ) << ": " << ( myWidgets[iBalls][iTotal]->property( "text" ) ).toString() << "\n"; + out << QString( SPACING_INFO, ' ' ) << tr( "1D_LAB" ) << "\n"; + out << QString( SPACING_INFO*2, ' ' ) << tr( "TOTAL_LAB" ) << ": " << ( myWidgets[i1D][iTotal]->property( "text" ) ).toString() << "\n"; + out << QString( SPACING_INFO*2, ' ' ) << tr( "LINEAR_LAB" ) << ": " << ( myWidgets[i1D][iLinear]->property( "text" ) ).toString() << "\n"; + out << QString( SPACING_INFO*2, ' ' ) << tr( "QUADRATIC_LAB" ) << ": " << ( myWidgets[i1D][iQuadratic]->property( "text" ) ).toString() << "\n"; + out << QString( SPACING_INFO, ' ' ) << tr( "2D_LAB" ) << "\n"; + out << QString( SPACING_INFO*2, ' ' ) << tr( "TOTAL_LAB" ) << ": " << ( myWidgets[i2D][iTotal]->property( "text" ) ).toString() << "\n"; + out << QString( SPACING_INFO*2, ' ' ) << tr( "LINEAR_LAB" ) << ": " << ( myWidgets[i2D][iLinear]->property( "text" ) ).toString() << "\n"; + out << QString( SPACING_INFO*2, ' ' ) << tr( "QUADRATIC_LAB" ) << ": " << ( myWidgets[i2D][iQuadratic]->property( "text" ) ).toString() << "\n"; + out << QString( SPACING_INFO*2, ' ' ) << tr( "TRIANGLES_LAB" ) << "\n"; + out << QString( SPACING_INFO*3, ' ' ) << tr( "TOTAL_LAB" ) << ": " << ( myWidgets[i2DTriangles][iTotal]->property( "text" ) ).toString() << "\n"; + out << QString( SPACING_INFO*3, ' ' ) << tr( "LINEAR_LAB" ) << ": " << ( myWidgets[i2DTriangles][iLinear]->property( "text" ) ).toString() << "\n"; + out << QString( SPACING_INFO*3, ' ' ) << tr( "QUADRATIC_LAB" ) << ": " << ( myWidgets[i2DTriangles][iQuadratic]->property( "text" ) ).toString() << "\n"; + out << QString( SPACING_INFO*2, ' ' ) << tr( "QUADRANGLES_LAB" ) << "\n"; + out << QString( SPACING_INFO*3, ' ' ) << tr( "TOTAL_LAB" ) << ": " << ( myWidgets[i2DQuadrangles][iTotal]->property( "text" ) ).toString() << "\n"; + out << QString( SPACING_INFO*3, ' ' ) << tr( "LINEAR_LAB" ) << ": " << ( myWidgets[i2DQuadrangles][iLinear]->property( "text" ) ).toString() << "\n"; + out << QString( SPACING_INFO*3, ' ' ) << tr( "QUADRATIC_LAB" ) << ": " << ( myWidgets[i2DQuadrangles][iQuadratic]->property( "text" ) ).toString() << "\n"; + out << QString( SPACING_INFO*2, ' ' ) << tr( "POLYGONS_LAB" ) << "\n"; + out << QString( SPACING_INFO*3, ' ' ) << tr( "TOTAL_LAB" ) << ": " << ( myWidgets[i2DPolygons][iTotal]->property( "text" ) ).toString() << "\n"; + out << QString( SPACING_INFO, ' ' ) << tr( "3D_LAB" ) << "\n"; + out << QString( SPACING_INFO*2, ' ' ) << tr( "TOTAL_LAB" ) << ": " << ( myWidgets[i3D][iTotal]->property( "text" ) ).toString() << "\n"; + out << QString( SPACING_INFO*2, ' ' ) << tr( "LINEAR_LAB" ) << ": " << ( myWidgets[i3D][iLinear]->property( "text" ) ).toString() << "\n"; + out << QString( SPACING_INFO*2, ' ' ) << tr( "QUADRATIC_LAB" ) << ": " << ( myWidgets[i3D][iQuadratic]->property( "text" ) ).toString() << "\n"; + out << QString( SPACING_INFO*2, ' ' ) << tr( "TETRAHEDRONS_LAB" ) << "\n"; + out << QString( SPACING_INFO*3, ' ' ) << tr( "TOTAL_LAB" ) << ": " << ( myWidgets[i3DTetrahedrons][iTotal]->property( "text" ) ).toString() << "\n"; + out << QString( SPACING_INFO*3, ' ' ) << tr( "LINEAR_LAB" ) << ": " << ( myWidgets[i3DTetrahedrons][iLinear]->property( "text" ) ).toString() << "\n"; + out << QString( SPACING_INFO*3, ' ' ) << tr( "QUADRATIC_LAB" ) << ": " << ( myWidgets[i3DTetrahedrons][iQuadratic]->property( "text" ) ).toString() << "\n"; + out << QString( SPACING_INFO*2, ' ' ) << tr( "HEXAHEDONRS_LAB" ) << "\n"; + out << QString( SPACING_INFO*3, ' ' ) << tr( "TOTAL_LAB" ) << ": " << ( myWidgets[i3DHexahedrons][iTotal]->property( "text" ) ).toString() << "\n"; + out << QString( SPACING_INFO*3, ' ' ) << tr( "LINEAR_LAB" ) << ": " << ( myWidgets[i3DHexahedrons][iLinear]->property( "text" ) ).toString() << "\n"; + out << QString( SPACING_INFO*3, ' ' ) << tr( "QUADRATIC_LAB" ) << ": " << ( myWidgets[i3DHexahedrons][iQuadratic]->property( "text" ) ).toString() << "\n"; + out << QString( SPACING_INFO*2, ' ' ) << tr( "PYRAMIDS_LAB" ) << "\n"; + out << QString( SPACING_INFO*3, ' ' ) << tr( "TOTAL_LAB" ) << ": " << ( myWidgets[i3DPyramids][iTotal]->property( "text" ) ).toString() << "\n"; + out << QString( SPACING_INFO*3, ' ' ) << tr( "LINEAR_LAB" ) << ": " << ( myWidgets[i3DPyramids][iLinear]->property( "text" ) ).toString() << "\n"; + out << QString( SPACING_INFO*3, ' ' ) << tr( "QUADRATIC_LAB" ) << ": " << ( myWidgets[i3DPyramids][iQuadratic]->property( "text" ) ).toString() << "\n"; + out << QString( SPACING_INFO*2, ' ' ) << tr( "PRISMS_LAB" ) << "\n"; + out << QString( SPACING_INFO*3, ' ' ) << tr( "TOTAL_LAB" ) << ": " << ( myWidgets[i3DPrisms][iTotal]->property( "text" ) ).toString() << "\n"; + out << QString( SPACING_INFO*3, ' ' ) << tr( "LINEAR_LAB" ) << ": " << ( myWidgets[i3DPrisms][iLinear]->property( "text" ) ).toString() << "\n"; + out << QString( SPACING_INFO*3, ' ' ) << tr( "QUADRATIC_LAB" ) << ": " << ( myWidgets[i3DPrisms][iQuadratic]->property( "text" ) ).toString() << "\n"; + out << QString( SPACING_INFO*2, ' ' ) << tr( "HEX_PRISMS_LAB" ) << "\n"; + out << QString( SPACING_INFO*3, ' ' ) << tr( "TOTAL_LAB" ) << ": " << ( myWidgets[i3DHexaPrisms][iTotal]->property( "text" ) ).toString() << "\n"; + out << QString( SPACING_INFO*2, ' ' ) << tr( "POLYHEDRONS_LAB" ) << "\n"; + out << QString( SPACING_INFO*3, ' ' ) << tr( "TOTAL_LAB" ) << ": " << ( myWidgets[i3DPolyhedrons][iTotal]->property( "text" ) ).toString() << "\n" << "\n"; +} + /*! \class SMESHGUI_ElemInfo \brief Base class for the mesh element information widget. @@ -886,7 +1057,8 @@ void SMESHGUI_SimpleElemInfo::information( const QList& ids ) clearInternal(); if ( actor() ) { - int precision = SMESHGUI::resourceMgr()->integerValue( "SMESH", "length_precision", 6 ); + int grp_details = SMESHGUI::resourceMgr()->booleanValue( "SMESH", "elem_info_grp_details", false ); + int precision = SMESHGUI::resourceMgr()->integerValue( "SMESH", "length_precision", 6 ); int cprecision = -1; if ( SMESHGUI::resourceMgr()->booleanValue( "SMESH", "use_precision", false ) ) cprecision = SMESHGUI::resourceMgr()->integerValue( "SMESH", "controls_precision", -1 ); @@ -899,11 +1071,11 @@ void SMESHGUI_SimpleElemInfo::information( const QList& ids ) if ( !node ) return; // node ID - myInfo->append( QString( "%1 #%2" ).arg( tr( "NODE" ) ).arg( id ) ); + myInfo->append( QString( "%1 #%2" ).arg( SMESHGUI_ElemInfo::tr( "NODE" ) ).arg( id ) ); // separator myInfo->append( "" ); // coordinates - myInfo->append( QString( "%1: (%2, %3, %4)" ).arg( tr( "COORDINATES" ) ). + myInfo->append( QString( "%1: (%2, %3, %4)" ).arg( SMESHGUI_ElemInfo::tr( "COORDINATES" ) ). arg( node->X(), 0, precision > 0 ? 'f' : 'g', qAbs( precision ) ). arg( node->Y(), 0, precision > 0 ? 'f' : 'g', qAbs( precision ) ). arg( node->Z(), 0, precision > 0 ? 'f' : 'g', qAbs( precision ) ) ); @@ -912,25 +1084,120 @@ void SMESHGUI_SimpleElemInfo::information( const QList& ids ) // connectivity Connectivity connectivity = nodeConnectivity( node ); if ( !connectivity.isEmpty() ) { - myInfo->append( QString( "%1:" ).arg( tr( "CONNECTIVITY" ) ) ); + myInfo->append( QString( "%1:" ).arg( SMESHGUI_ElemInfo::tr( "CONNECTIVITY" ) ) ); QString con = formatConnectivity( connectivity, SMDSAbs_0DElement ); if ( !con.isEmpty() ) - myInfo->append( QString( "- %1: %2" ).arg( tr( "0D_ELEMENTS" ) ).arg( con ) ); + myInfo->append( QString( "- %1: %2" ).arg( SMESHGUI_ElemInfo::tr( "0D_ELEMENTS" ) ).arg( con ) ); con = formatConnectivity( connectivity, SMDSAbs_Edge ); if ( !con.isEmpty() ) - myInfo->append( QString( "- %1: %2" ).arg( tr( "EDGES" ) ).arg( con ) ); + myInfo->append( QString( "- %1: %2" ).arg( SMESHGUI_ElemInfo::tr( "EDGES" ) ).arg( con ) ); con = formatConnectivity( connectivity, SMDSAbs_Ball ); if ( !con.isEmpty() ) - myInfo->append( QString( "- %1: %2" ).arg( tr( "BALL_ELEMENTS" ) ).arg( con ) ); + myInfo->append( QString( "- %1: %2" ).arg( SMESHGUI_ElemInfo::tr( "BALL_ELEMENTS" ) ).arg( con ) ); con = formatConnectivity( connectivity, SMDSAbs_Face ); if ( !con.isEmpty() ) - myInfo->append( QString( "- %1: %2" ).arg( tr( "FACES" ) ).arg( con ) ); + myInfo->append( QString( "- %1: %2" ).arg( SMESHGUI_ElemInfo::tr( "FACES" ) ).arg( con ) ); con = formatConnectivity( connectivity, SMDSAbs_Volume ); if ( !con.isEmpty() ) - myInfo->append( QString( "- %1: %2" ).arg( tr( "VOLUMES" ) ).arg( con ) ); + myInfo->append( QString( "- %1: %2" ).arg( SMESHGUI_ElemInfo::tr( "VOLUMES" ) ).arg( con ) ); } else { - myInfo->append( QString( "%1" ).arg( tr( "FREE_NODE" ) ).arg( id ) ); + myInfo->append( QString( "%1" ).arg( SMESHGUI_ElemInfo::tr( "FREE_NODE" ) ).arg( id ) ); + } + // node position + SMESH::SMESH_Mesh_ptr aMeshPtr = actor()->GetObject()->GetMeshServer(); + if ( !CORBA::is_nil( aMeshPtr ) ) { + SMESH::NodePosition_var pos = aMeshPtr->GetNodePosition( id ); + int shapeID = pos->shapeID; + if ( shapeID > 0 ) { + QString shapeType; + double u, v; + switch ( pos->shapeType ) { + case GEOM::EDGE: + shapeType = SMESHGUI_ElemInfo::tr( "GEOM_EDGE" ); + if ( pos->params.length() == 1 ) + u = pos->params[0]; + break; + case GEOM::FACE: + shapeType = SMESHGUI_ElemInfo::tr( "GEOM_FACE" ); + if ( pos->params.length() == 2 ) { + u = pos->params[0]; + v = pos->params[1]; + } + break; + case GEOM::VERTEX: + shapeType = SMESHGUI_ElemInfo::tr( "GEOM_VERTEX" ); + break; + default: + shapeType = SMESHGUI_ElemInfo::tr( "GEOM_SOLID" ); + break; + } + // separator + myInfo->append( "" ); + myInfo->append( QString( "%1:" ).arg( SMESHGUI_ElemInfo::tr( "POSITION" ) ) ); + myInfo->append( QString( "- %1: #%2" ).arg( shapeType ).arg( shapeID ) ); + if ( pos->shapeType == GEOM::EDGE || pos->shapeType == GEOM::FACE ) { + myInfo->append( QString( "- %1: #%2" ).arg( SMESHGUI_ElemInfo::tr( "U_POSITION" ) ). + arg( QString::number( u, precision > 0 ? 'f' : 'g', qAbs( precision )) ) ); + if ( pos->shapeType == GEOM::FACE ) { + myInfo->append( QString( "- %1: #%2" ).arg( SMESHGUI_ElemInfo::tr( "V_POSITION" ) ). + arg( QString::number( v, precision > 0 ? 'f' : 'g', qAbs( precision )) ) ); + } + } + } + } + // groups node belongs to + SMESH::SMESH_Mesh_ptr aMesh = actor()->GetObject()->GetMeshServer(); + if ( !CORBA::is_nil( aMesh ) ) { + SMESH::ListOfGroups_var groups = aMesh->GetGroups(); + myInfo->append( "" ); // separator + bool top_created = false; + for ( int i = 0; i < groups->length(); i++ ) { + SMESH::SMESH_GroupBase_var aGrp = groups[i]; + if ( CORBA::is_nil( aGrp ) ) continue; + QString aName = aGrp->GetName(); + if ( aGrp->GetType() == SMESH::NODE && !aName.isEmpty() && aGrp->Contains( id ) ) { + if ( !top_created ) { + myInfo->append( QString( "%1:" ).arg( SMESHGUI_AddInfo::tr( "GROUPS" ) ) ); + top_created = true; + } + myInfo->append( QString( "+ %1:" ).arg( aName.trimmed() ) ); + if ( grp_details ) { + SMESH::SMESH_Group_var aStdGroup = SMESH::SMESH_Group::_narrow( aGrp ); + SMESH::SMESH_GroupOnGeom_var aGeomGroup = SMESH::SMESH_GroupOnGeom::_narrow( aGrp ); + SMESH::SMESH_GroupOnFilter_var aFltGroup = SMESH::SMESH_GroupOnFilter::_narrow( aGrp ); + + // type : group on geometry, standalone group, group on filter + if ( !CORBA::is_nil( aStdGroup ) ) { + myInfo->append( QString( " - %1: %2" ).arg( SMESHGUI_AddInfo::tr( "TYPE" ) ). + arg( SMESHGUI_AddInfo::tr( "STANDALONE_GROUP" ) ) ); + } + else if ( !CORBA::is_nil( aGeomGroup ) ) { + myInfo->append( QString( " - %1: %2" ).arg( SMESHGUI_AddInfo::tr( "TYPE" ) ). + arg( SMESHGUI_AddInfo::tr( "GROUP_ON_GEOMETRY" ) ) ); + GEOM::GEOM_Object_var gobj = aGeomGroup->GetShape(); + _PTR(SObject) sobj = SMESH::ObjectToSObject( gobj ); + if ( sobj ) { + myInfo->append( QString( " - %1: %2: %3" ).arg( SMESHGUI_AddInfo::tr( "TYPE" ) ). + arg( SMESHGUI_AddInfo::tr( "GEOM_OBJECT" ) ).arg( sobj->GetName().c_str() ) ); + } + } + else if ( !CORBA::is_nil( aFltGroup ) ) { + myInfo->append( QString( " - %1: %2" ).arg( SMESHGUI_AddInfo::tr( "TYPE" ) ). + arg( SMESHGUI_AddInfo::tr( "GROUP_ON_FILTER" ) ) ); + } + + // size + myInfo->append( QString( " - %1: %2" ).arg( SMESHGUI_AddInfo::tr( "SIZE" ) ). + arg( QString::number( aGrp->Size() ) ) ); + + // color + SALOMEDS::Color color = aGrp->GetColor(); + myInfo->append( QString( " - %1: %2" ).arg( SMESHGUI_AddInfo::tr( "COLOR" ) ). + arg( QColor( color.R*255., color.G*255., color.B*255. ).name() ) ); + } + } + } } } else { @@ -945,15 +1212,15 @@ void SMESHGUI_SimpleElemInfo::information( const QList& ids ) QString stype; switch( e->GetType() ) { case SMDSAbs_0DElement: - stype = tr( "0D ELEMENT" ); break; + stype = SMESHGUI_ElemInfo::tr( "0D_ELEMENT" ); break; case SMDSAbs_Ball: - stype = tr( "BALL" ); break; + stype = SMESHGUI_ElemInfo::tr( "BALL" ); break; case SMDSAbs_Edge: - stype = tr( "EDGE" ); break; + stype = SMESHGUI_ElemInfo::tr( "EDGE" ); break; case SMDSAbs_Face: - stype = tr( "FACE" ); break; + stype = SMESHGUI_ElemInfo::tr( "FACE" ); break; case SMDSAbs_Volume: - stype = tr( "VOLUME" ); break; + stype = SMESHGUI_ElemInfo::tr( "VOLUME" ); break; default: break; } @@ -966,50 +1233,50 @@ void SMESHGUI_SimpleElemInfo::information( const QList& ids ) switch( e->GetEntityType() ) { case SMDSEntity_Triangle: case SMDSEntity_Quad_Triangle: - gtype = tr( "TRIANGLE" ); break; + gtype = SMESHGUI_ElemInfo::tr( "TRIANGLE" ); break; case SMDSEntity_Quadrangle: case SMDSEntity_Quad_Quadrangle: case SMDSEntity_BiQuad_Quadrangle: - gtype = tr( "QUADRANGLE" ); break; + gtype = SMESHGUI_ElemInfo::tr( "QUADRANGLE" ); break; case SMDSEntity_Polygon: case SMDSEntity_Quad_Polygon: - gtype = tr( "POLYGON" ); break; + gtype = SMESHGUI_ElemInfo::tr( "POLYGON" ); break; case SMDSEntity_Tetra: case SMDSEntity_Quad_Tetra: - gtype = tr( "TETRAHEDRON" ); break; + gtype = SMESHGUI_ElemInfo::tr( "TETRAHEDRON" ); break; case SMDSEntity_Pyramid: case SMDSEntity_Quad_Pyramid: - gtype = tr( "PYRAMID" ); break; + gtype = SMESHGUI_ElemInfo::tr( "PYRAMID" ); break; case SMDSEntity_Hexa: case SMDSEntity_Quad_Hexa: case SMDSEntity_TriQuad_Hexa: - gtype = tr( "HEXAHEDRON" ); break; + gtype = SMESHGUI_ElemInfo::tr( "HEXAHEDRON" ); break; case SMDSEntity_Penta: case SMDSEntity_Quad_Penta: - gtype = tr( "PRISM" ); break; + gtype = SMESHGUI_ElemInfo::tr( "PRISM" ); break; case SMDSEntity_Hexagonal_Prism: - gtype = tr( "HEX_PRISM" ); break; + gtype = SMESHGUI_ElemInfo::tr( "HEX_PRISM" ); break; case SMDSEntity_Polyhedra: case SMDSEntity_Quad_Polyhedra: - gtype = tr( "POLYHEDRON" ); break; + gtype = SMESHGUI_ElemInfo::tr( "POLYHEDRON" ); break; default: break; } if ( !gtype.isEmpty() ) - myInfo->append( QString( "%1: %2" ).arg( tr( "TYPE" ) ).arg( gtype ) ); + myInfo->append( QString( "%1: %2" ).arg( SMESHGUI_ElemInfo::tr( "TYPE" ) ).arg( gtype ) ); // quadratic flag and gravity center (any element except 0D) if ( e->GetEntityType() > SMDSEntity_0D && e->GetEntityType() < SMDSEntity_Ball ) { // quadratic flag - myInfo->append( QString( "%1? %2" ).arg( tr( "QUADRATIC" ) ).arg( e->IsQuadratic() ? tr( "YES" ) : tr( "NO" ) ) ); + myInfo->append( QString( "%1? %2" ).arg( SMESHGUI_ElemInfo::tr( "QUADRATIC" ) ).arg( e->IsQuadratic() ? SMESHGUI_ElemInfo::tr( "YES" ) : SMESHGUI_ElemInfo::tr( "NO" ) ) ); // separator myInfo->append( "" ); // gravity center XYZ gc = gravityCenter( e ); - myInfo->append( QString( "%1: (%2, %3, %4)" ).arg( tr( "GRAVITY_CENTER" ) ).arg( gc.x() ).arg( gc.y() ).arg( gc.z() ) ); + myInfo->append( QString( "%1: (%2, %3, %4)" ).arg( SMESHGUI_ElemInfo::tr( "GRAVITY_CENTER" ) ).arg( gc.x() ).arg( gc.y() ).arg( gc.z() ) ); } if ( const SMDS_BallElement* ball = dynamic_cast( e )) { // ball diameter - myInfo->append( QString( "%1: %2" ).arg( tr( "BALL_DIAMETER" ) ).arg( ball->GetDiameter() )); + myInfo->append( QString( "%1: %2" ).arg( SMESHGUI_ElemInfo::tr( "BALL_DIAMETER" ) ).arg( ball->GetDiameter() )); } // separator myInfo->append( "" ); @@ -1018,37 +1285,37 @@ void SMESHGUI_SimpleElemInfo::information( const QList& ids ) for ( int idx = 1; nodeIt->more(); idx++ ) { const SMDS_MeshNode* node = static_cast( nodeIt->next() ); // node number and ID - myInfo->append( QString( "%1 %2/%3 - #%4" ).arg( tr( "NODE" ) ).arg( idx ).arg( e->NbNodes() ).arg( node->GetID() ) ); + myInfo->append( QString( "%1 %2/%3 - #%4" ).arg( SMESHGUI_ElemInfo::tr( "NODE" ) ).arg( idx ).arg( e->NbNodes() ).arg( node->GetID() ) ); // node coordinates - myInfo->append( QString( "%1: (%2, %3, %4)" ).arg( tr( "COORDINATES" ) ). + myInfo->append( QString( "%1: (%2, %3, %4)" ).arg( SMESHGUI_ElemInfo::tr( "COORDINATES" ) ). arg( node->X(), 0, precision > 0 ? 'f' : 'g', qAbs( precision ) ). arg( node->Y(), 0, precision > 0 ? 'f' : 'g', qAbs( precision ) ). arg( node->Z(), 0, precision > 0 ? 'f' : 'g', qAbs( precision ) ) ); // node connectivity Connectivity connectivity = nodeConnectivity( node ); if ( !connectivity.isEmpty() ) { - myInfo->append( QString( "%1:" ).arg( tr( "CONNECTIVITY" ) ) ); + myInfo->append( QString( "%1:" ).arg( SMESHGUI_ElemInfo::tr( "CONNECTIVITY" ) ) ); QString con = formatConnectivity( connectivity, SMDSAbs_0DElement ); if ( !con.isEmpty() ) - myInfo->append( QString( "- %1: %2" ).arg( tr( "0D_ELEMENTS" ) ).arg( con ) ); + myInfo->append( QString( "- %1: %2" ).arg( SMESHGUI_ElemInfo::tr( "0D_ELEMENTS" ) ).arg( con ) ); con = formatConnectivity( connectivity, SMDSAbs_Edge ); if ( !con.isEmpty() ) - myInfo->append( QString( "- %1: %2" ).arg( tr( "EDGES" ) ).arg( con ) ); + myInfo->append( QString( "- %1: %2" ).arg( SMESHGUI_ElemInfo::tr( "EDGES" ) ).arg( con ) ); con = formatConnectivity( connectivity, SMDSAbs_Face ); if ( !con.isEmpty() ) - myInfo->append( QString( "- %1: %2" ).arg( tr( "FACES" ) ).arg( con ) ); + myInfo->append( QString( "- %1: %2" ).arg( SMESHGUI_ElemInfo::tr( "FACES" ) ).arg( con ) ); con = formatConnectivity( connectivity, SMDSAbs_Volume ); if ( !con.isEmpty() ) - myInfo->append( QString( "- %1: %2" ).arg( tr( "VOLUMES" ) ).arg( con ) ); + myInfo->append( QString( "- %1: %2" ).arg( SMESHGUI_ElemInfo::tr( "VOLUMES" ) ).arg( con ) ); } else { - myInfo->append( QString( "%1" ).arg( tr( "FREE_NODE" ) ).arg( id ) ); + myInfo->append( QString( "%1" ).arg( SMESHGUI_ElemInfo::tr( "FREE_NODE" ) ).arg( id ) ); } } // separator myInfo->append( "" ); //controls - myInfo->append( QString( "%1:" ).arg( tr( "MEN_CTRL" ) ) ); + myInfo->append( QString( "%1:" ).arg( SMESHGUI_ElemInfo::tr( "CONTROLS" ) ) ); //Length if ( e->GetType() == SMDSAbs_Edge ) { afunctor.reset( new SMESH::Controls::Length() ); @@ -1066,7 +1333,7 @@ void SMESHGUI_SimpleElemInfo::information( const QList& ids ) afunctor.reset( new SMESH::Controls::Taper() ); afunctor->SetMesh( actor()->GetObject()->GetMesh() ); afunctor->SetPrecision( cprecision ); - myInfo->append( QString( "- %1: %2" ).arg( tr( "MEN_TAPER" ) ).arg( afunctor->GetValue( id ) ) ); + myInfo->append( QString( "- %1: %2" ).arg( tr( "TAPER_ELEMENTS" ) ).arg( afunctor->GetValue( id ) ) ); //AspectRatio2D afunctor.reset( new SMESH::Controls::AspectRatio() ); afunctor->SetMesh( actor()->GetObject()->GetMesh() ); @@ -1080,12 +1347,12 @@ void SMESHGUI_SimpleElemInfo::information( const QList& ids ) afunctor.reset( new SMESH::Controls::Warping() ); afunctor->SetMesh( actor()->GetObject()->GetMesh() ); afunctor->SetPrecision( cprecision ); - myInfo->append( QString( "- %1: %2" ).arg( tr( "STB_WARP" ) ).arg( afunctor->GetValue( id ) ) ); + myInfo->append( QString( "- %1: %2" ).arg( tr( "WARP_ELEMENTS" ) ).arg( afunctor->GetValue( id ) ) ); //Skew afunctor.reset( new SMESH::Controls::Skew() ); afunctor->SetMesh( actor()->GetObject()->GetMesh() ); afunctor->SetPrecision( cprecision ); - myInfo->append( QString( "- %1: %2" ).arg( tr( "TOP_SKEW" ) ).arg( afunctor->GetValue( id ) ) ); + myInfo->append( QString( "- %1: %2" ).arg( tr( "SKEW_ELEMENTS" ) ).arg( afunctor->GetValue( id ) ) ); //ElemDiam2D afunctor.reset( new SMESH::Controls::MaxElementLength2D() ); afunctor->SetMesh( actor()->GetObject()->GetMesh() ); @@ -1099,30 +1366,85 @@ void SMESHGUI_SimpleElemInfo::information( const QList& ids ) //Volume afunctor.reset( new SMESH::Controls::Volume() ); afunctor->SetMesh( actor()->GetObject()->GetMesh() ); - myInfo->append( QString( "- %1: %2" ).arg( tr( "MEN_VOLUME_3D" ) ).arg( afunctor->GetValue( id ) ) ); + myInfo->append( QString( "- %1: %2" ).arg( tr( "VOLUME_3D_ELEMENTS" ) ).arg( afunctor->GetValue( id ) ) ); //ElementDiameter3D afunctor.reset( new SMESH::Controls::Volume() ); afunctor->SetMesh( actor()->GetObject()->GetMesh() ); myInfo->append( QString( "- %1: %2" ).arg( tr( "MAX_ELEMENT_LENGTH_3D" ) ).arg( afunctor->GetValue( id ) ) ); } - /* - if( e->GetType() >= SMDSAbs_Edge && e->GetType() <= SMDSAbs_Volume ) { - // separator - myInfo->append( "" ); - //shapeID - int shapeID = e->getshapeId(); - if ( shapeID > 0 ) { - QString shapeType; - switch ( actor()->GetObject()->GetMesh()->FindElement( shapeID )->GetType() ) { - case SMDS_TOP_EDGE: shapeType = tr( "EDGE" ); break; - case SMDS_TOP_FACE: shapeType = tr( "FACE" ); break; - case SMDS_TOP_VERTEX: shapeType = tr( "VERTEX" ); break; - default: shapeType = tr( "SOLID" ); - } - myInfo->append( QString( "%1: %2 #%3" ).arg( tr( "Position" ) ).arg( shapeType ).arg( shapeID ) ); + // element position + if ( e->GetType() >= SMDSAbs_Edge && e->GetType() <= SMDSAbs_Volume ) { + SMESH::SMESH_Mesh_ptr aMesh = actor()->GetObject()->GetMeshServer(); + if ( !CORBA::is_nil( aMesh ) ) { + SMESH::ElementPosition pos = aMesh->GetElementPosition( id ); + int shapeID = pos.shapeID; + if ( shapeID > 0 ) { + myInfo->append( "" ); // separator + QString shapeType; + switch ( pos.shapeType ) { + case GEOM::EDGE: shapeType = SMESHGUI_ElemInfo::tr( "GEOM_EDGE" ); break; + case GEOM::FACE: shapeType = SMESHGUI_ElemInfo::tr( "GEOM_FACE" ); break; + case GEOM::VERTEX: shapeType = SMESHGUI_ElemInfo::tr( "GEOM_VERTEX" ); break; + case GEOM::SOLID: shapeType = SMESHGUI_ElemInfo::tr( "GEOM_SOLID" ); break; + case GEOM::SHELL: shapeType = SMESHGUI_ElemInfo::tr( "GEOM_SHELL" ); break; + default: shapeType = SMESHGUI_ElemInfo::tr( "GEOM_SHAPE" ); break; + } + myInfo->append( QString( "%1: %2 #%3" ).arg( SMESHGUI_ElemInfo::tr( "POSITION" ) ).arg( shapeType ).arg( shapeID ) ); + } + } + } + // groups element belongs to + SMESH::SMESH_Mesh_ptr aMesh = actor()->GetObject()->GetMeshServer(); + if ( !CORBA::is_nil( aMesh ) ) { + SMESH::ListOfGroups_var groups = aMesh->GetGroups(); + myInfo->append( "" ); // separator + bool top_created = false; + for ( int i = 0; i < groups->length(); i++ ) { + SMESH::SMESH_GroupBase_var aGrp = groups[i]; + if ( CORBA::is_nil( aGrp ) ) continue; + QString aName = aGrp->GetName(); + if ( aGrp->GetType() != SMESH::NODE && !aName.isEmpty() && aGrp->Contains( id ) ) { + if ( !top_created ) { + myInfo->append( QString( "%1:" ).arg( SMESHGUI_AddInfo::tr( "GROUPS" ) ) ); + top_created = true; + } + myInfo->append( QString( "+ %1:" ).arg( aName.trimmed() ) ); + if ( grp_details ) { + SMESH::SMESH_Group_var aStdGroup = SMESH::SMESH_Group::_narrow( aGrp ); + SMESH::SMESH_GroupOnGeom_var aGeomGroup = SMESH::SMESH_GroupOnGeom::_narrow( aGrp ); + SMESH::SMESH_GroupOnFilter_var aFltGroup = SMESH::SMESH_GroupOnFilter::_narrow( aGrp ); + + // type : group on geometry, standalone group, group on filter + if ( !CORBA::is_nil( aStdGroup ) ) { + myInfo->append( QString( " - %1: %2" ).arg( SMESHGUI_AddInfo::tr( "TYPE" ) ). + arg( SMESHGUI_AddInfo::tr( "STANDALONE_GROUP" ) ) ); + } + else if ( !CORBA::is_nil( aGeomGroup ) ) { + myInfo->append( QString( " - %1: %2" ).arg( SMESHGUI_AddInfo::tr( "TYPE" ) ). + arg( SMESHGUI_AddInfo::tr( "GROUP_ON_GEOMETRY" ) ) ); + GEOM::GEOM_Object_var gobj = aGeomGroup->GetShape(); + _PTR(SObject) sobj = SMESH::ObjectToSObject( gobj ); + if ( sobj ) { + myInfo->append( QString( " - %1: %2: %3" ).arg( SMESHGUI_AddInfo::tr( "TYPE" ) ). + arg( SMESHGUI_AddInfo::tr( "GEOM_OBJECT" ) ).arg( sobj->GetName().c_str() ) ); + } + } + else if ( !CORBA::is_nil( aFltGroup ) ) { + myInfo->append( QString( " - %1: %2" ).arg( SMESHGUI_AddInfo::tr( "TYPE" ) ). + arg( SMESHGUI_AddInfo::tr( "GROUP_ON_FILTER" ) ) ); + } + + myInfo->append( QString( " - %1: %2" ).arg( SMESHGUI_AddInfo::tr( "SIZE" ) ). + arg( QString::number( aGrp->Size() ) ) ); + + // color + SALOMEDS::Color color = aGrp->GetColor(); + myInfo->append( QString( " - %1: %2" ).arg( SMESHGUI_AddInfo::tr( "COLOR" ) ). + arg( QColor( color.R*255., color.G*255., color.B*255. ).name() ) ); + } + } } } - */ } // separator if ( ids.count() > 1 ) { @@ -1142,6 +1464,16 @@ void SMESHGUI_SimpleElemInfo::clearInternal() myInfo->clear(); } +void SMESHGUI_SimpleElemInfo::saveInfo( QTextStream &out ) +{ + out << QString( 12, '-' ) << "\n"; + out << SMESHGUI_ElemInfo::tr( "ELEM_INFO" ) << "\n"; + out << QString( 12, '-' ) << "\n"; + out << myInfo->toPlainText(); + out << "\n"; +} + + /*! \class SMESHGUI_TreeElemInfo::ItemDelegate \brief Item delegate for tree mesh info widget @@ -1194,6 +1526,7 @@ SMESHGUI_TreeElemInfo::SMESHGUI_TreeElemInfo( QWidget* parent ) QVBoxLayout* l = new QVBoxLayout( frame() ); l->setMargin( 0 ); l->addWidget( myInfo ); + connect( myInfo, SIGNAL( itemDoubleClicked( QTreeWidgetItem*, int ) ), this, SLOT( itemDoubleClicked( QTreeWidgetItem*, int ) ) ); } /*! @@ -1205,7 +1538,8 @@ void SMESHGUI_TreeElemInfo::information( const QList& ids ) clearInternal(); if ( actor() ) { - int precision = SMESHGUI::resourceMgr()->integerValue( "SMESH", "length_precision", 6 ); + int grp_details = SMESHGUI::resourceMgr()->booleanValue( "SMESH", "elem_info_grp_details", false ); + int precision = SMESHGUI::resourceMgr()->integerValue( "SMESH", "length_precision", 6 ); int cprecision = -1; if ( SMESHGUI::resourceMgr()->booleanValue( "SMESH", "use_precision", false ) ) cprecision = SMESHGUI::resourceMgr()->integerValue( "SMESH", "controls_precision", -1 ); @@ -1220,11 +1554,11 @@ void SMESHGUI_TreeElemInfo::information( const QList& ids ) // node ID QTreeWidgetItem* nodeItem = createItem( 0, Bold | All ); - nodeItem->setText( 0, tr( "NODE" ) ); + nodeItem->setText( 0, SMESHGUI_ElemInfo::tr( "NODE" ) ); nodeItem->setText( 1, QString( "#%1" ).arg( id ) ); // coordinates QTreeWidgetItem* coordItem = createItem( nodeItem, Bold ); - coordItem->setText( 0, tr( "COORDINATES" ) ); + coordItem->setText( 0, SMESHGUI_ElemInfo::tr( "COORDINATES" ) ); QTreeWidgetItem* xItem = createItem( coordItem ); xItem->setText( 0, "X" ); xItem->setText( 1, QString::number( node->X(), precision > 0 ? 'f' : 'g', qAbs( precision ) ) ); @@ -1236,73 +1570,142 @@ void SMESHGUI_TreeElemInfo::information( const QList& ids ) zItem->setText( 1, QString::number( node->Z(), precision > 0 ? 'f' : 'g', qAbs( precision ) ) ); // connectivity QTreeWidgetItem* conItem = createItem( nodeItem, Bold ); - conItem->setText( 0, tr( "CONNECTIVITY" ) ); + conItem->setText( 0, SMESHGUI_ElemInfo::tr( "CONNECTIVITY" ) ); Connectivity connectivity = nodeConnectivity( node ); if ( !connectivity.isEmpty() ) { QString con = formatConnectivity( connectivity, SMDSAbs_0DElement ); if ( !con.isEmpty() ) { QTreeWidgetItem* i = createItem( conItem ); - i->setText( 0, tr( "0D_ELEMENTS" ) ); + i->setText( 0, SMESHGUI_ElemInfo::tr( "0D_ELEMENTS" ) ); i->setText( 1, con ); } con = formatConnectivity( connectivity, SMDSAbs_Ball ); if ( !con.isEmpty() ) { QTreeWidgetItem* i = createItem( conItem ); - i->setText( 0, tr( "BALL_ELEMENTS" ) ); + i->setText( 0, SMESHGUI_ElemInfo::tr( "BALL_ELEMENTS" ) ); i->setText( 1, con ); + i->setData( 1, TypeRole, NodeConnectivity ); } con = formatConnectivity( connectivity, SMDSAbs_Edge ); if ( !con.isEmpty() ) { QTreeWidgetItem* i = createItem( conItem ); - i->setText( 0, tr( "EDGES" ) ); + i->setText( 0, SMESHGUI_ElemInfo::tr( "EDGES" ) ); i->setText( 1, con ); + i->setData( 1, TypeRole, NodeConnectivity ); } con = formatConnectivity( connectivity, SMDSAbs_Face ); if ( !con.isEmpty() ) { QTreeWidgetItem* i = createItem( conItem ); - i->setText( 0, tr( "FACES" ) ); + i->setText( 0, SMESHGUI_ElemInfo::tr( "FACES" ) ); i->setText( 1, con ); + i->setData( 1, TypeRole, NodeConnectivity ); } con = formatConnectivity( connectivity, SMDSAbs_Volume ); if ( !con.isEmpty() ) { QTreeWidgetItem* i = createItem( conItem ); - i->setText( 0, tr( "VOLUMES" ) ); + i->setText( 0, SMESHGUI_ElemInfo::tr( "VOLUMES" ) ); i->setText( 1, con ); + i->setData( 1, TypeRole, NodeConnectivity ); } } else { - conItem->setText( 1, tr( "FREE_NODE" ) ); + conItem->setText( 1, SMESHGUI_ElemInfo::tr( "FREE_NODE" ) ); } // node position - int shapeID = node->getshapeId(); - if ( shapeID > 0 ) - { - SMDS_PositionPtr pos = node->GetPosition(); - SMDS_TypeOfPosition posType = pos->GetTypeOfPosition(); - QString shapeType; - double u,v; - switch ( posType ) { - case SMDS_TOP_EDGE: shapeType = tr( "EDGE" ); - u = static_cast( pos )->GetUParameter(); - break; - case SMDS_TOP_FACE: shapeType = tr( "FACE" ); - u = static_cast( pos )->GetUParameter(); - v = static_cast( pos )->GetVParameter(); - break; - case SMDS_TOP_VERTEX: shapeType = tr( "VERTEX" ); break; - default: shapeType = tr( "SOLID" ); + SMESH::SMESH_Mesh_ptr aMeshPtr = actor()->GetObject()->GetMeshServer(); + if ( !CORBA::is_nil( aMeshPtr ) ) { + SMESH::NodePosition_var pos = aMeshPtr->GetNodePosition( id ); + int shapeID = pos->shapeID; + if ( shapeID > 0 ) { + QString shapeType; + double u, v; + switch ( pos->shapeType ) { + case GEOM::EDGE: + shapeType = SMESHGUI_ElemInfo::tr( "GEOM_EDGE" ); + if ( pos->params.length() == 1 ) + u = pos->params[0]; + break; + case GEOM::FACE: + shapeType = SMESHGUI_ElemInfo::tr( "GEOM_FACE" ); + if ( pos->params.length() == 2 ) { + u = pos->params[0]; + v = pos->params[1]; + } + break; + case GEOM::VERTEX: + shapeType = SMESHGUI_ElemInfo::tr( "GEOM_VERTEX" ); + break; + default: + shapeType = SMESHGUI_ElemInfo::tr( "GEOM_SOLID" ); + break; + } + QTreeWidgetItem* posItem = createItem( nodeItem, Bold ); + posItem->setText( 0, SMESHGUI_ElemInfo::tr("POSITION") ); + posItem->setText( 1, (shapeType + " #%1").arg( shapeID )); + if ( pos->shapeType == GEOM::EDGE || pos->shapeType == GEOM::FACE ) { + QTreeWidgetItem* uItem = createItem( posItem ); + uItem->setText( 0, SMESHGUI_ElemInfo::tr("U_POSITION") ); + uItem->setText( 1, QString::number( u, precision > 0 ? 'f' : 'g', qAbs( precision ))); + if ( pos->shapeType == GEOM::FACE ) { + QTreeWidgetItem* vItem = createItem( posItem ); + vItem->setText( 0, SMESHGUI_ElemInfo::tr("V_POSITION") ); + vItem->setText( 1, QString::number( v, precision > 0 ? 'f' : 'g', qAbs( precision ))); + } + } } - QTreeWidgetItem* posItem = createItem( nodeItem, Bold ); - posItem->setText( 0, tr("NODE_POSITION") ); - posItem->setText( 1, (shapeType + " #%1").arg( shapeID )); - if ( posType == SMDS_TOP_EDGE || posType == SMDS_TOP_FACE ) { - QTreeWidgetItem* uItem = createItem( posItem ); - uItem->setText( 0, tr("U_POSITION") ); - uItem->setText( 1, QString::number( u, precision > 0 ? 'f' : 'g', qAbs( precision ))); - if ( posType == SMDS_TOP_FACE ) { - QTreeWidgetItem* vItem = createItem( posItem ); - vItem->setText( 0, tr("V_POSITION") ); - vItem->setText( 1, QString::number( v, precision > 0 ? 'f' : 'g', qAbs( precision ))); + } + // groups node belongs to + SMESH::SMESH_Mesh_ptr aMesh = actor()->GetObject()->GetMeshServer(); + if ( !CORBA::is_nil( aMesh ) ) { + SMESH::ListOfGroups_var groups = aMesh->GetGroups(); + QTreeWidgetItem* groupsItem = 0; + for ( int i = 0; i < groups->length(); i++ ) { + SMESH::SMESH_GroupBase_var aGrp = groups[i]; + if ( CORBA::is_nil( aGrp ) ) continue; + QString aName = aGrp->GetName(); + if ( aGrp->GetType() == SMESH::NODE && !aName.isEmpty() && aGrp->Contains( id ) ) { + if ( !groupsItem ) { + groupsItem = createItem( nodeItem, Bold ); + groupsItem->setText( 0, SMESHGUI_AddInfo::tr( "GROUPS" ) ); + } + QTreeWidgetItem* it = createItem( groupsItem, Bold ); + it->setText( 0, aName.trimmed() ); + if ( grp_details ) { + SMESH::SMESH_Group_var aStdGroup = SMESH::SMESH_Group::_narrow( aGrp ); + SMESH::SMESH_GroupOnGeom_var aGeomGroup = SMESH::SMESH_GroupOnGeom::_narrow( aGrp ); + SMESH::SMESH_GroupOnFilter_var aFltGroup = SMESH::SMESH_GroupOnFilter::_narrow( aGrp ); + + // type : group on geometry, standalone group, group on filter + QTreeWidgetItem* typeItem = createItem( it ); + typeItem->setText( 0, SMESHGUI_AddInfo::tr( "TYPE" ) ); + if ( !CORBA::is_nil( aStdGroup ) ) { + typeItem->setText( 1, SMESHGUI_AddInfo::tr( "STANDALONE_GROUP" ) ); + } + else if ( !CORBA::is_nil( aGeomGroup ) ) { + typeItem->setText( 1, SMESHGUI_AddInfo::tr( "GROUP_ON_GEOMETRY" ) ); + GEOM::GEOM_Object_var gobj = aGeomGroup->GetShape(); + _PTR(SObject) sobj = SMESH::ObjectToSObject( gobj ); + if ( sobj ) { + QTreeWidgetItem* gobjItem = createItem( typeItem ); + gobjItem->setText( 0, SMESHGUI_AddInfo::tr( "GEOM_OBJECT" ) ); + gobjItem->setText( 1, sobj->GetName().c_str() ); + } + } + else if ( !CORBA::is_nil( aFltGroup ) ) { + typeItem->setText( 1, SMESHGUI_AddInfo::tr( "GROUP_ON_FILTER" ) ); + } + + // size + QTreeWidgetItem* sizeItem = createItem( it ); + sizeItem->setText( 0, SMESHGUI_AddInfo::tr( "SIZE" ) ); + sizeItem->setText( 1, QString::number( aGrp->Size() ) ); + + // color + SALOMEDS::Color color = aGrp->GetColor(); + QTreeWidgetItem* colorItem = createItem( it ); + colorItem->setText( 0, SMESHGUI_AddInfo::tr( "COLOR" ) ); + colorItem->setBackground( 1, QBrush( QColor( color.R*255., color.G*255., color.B*255.) ) ); + } } } } @@ -1319,15 +1722,15 @@ void SMESHGUI_TreeElemInfo::information( const QList& ids ) QString stype; switch( e->GetType() ) { case SMDSAbs_0DElement: - stype = tr( "0D ELEMENT" ); break; + stype = SMESHGUI_ElemInfo::tr( "0D_ELEMENT" ); break; case SMDSAbs_Ball: - stype = tr( "BALL" ); break; + stype = SMESHGUI_ElemInfo::tr( "BALL" ); break; case SMDSAbs_Edge: - stype = tr( "EDGE" ); break; + stype = SMESHGUI_ElemInfo::tr( "EDGE" ); break; case SMDSAbs_Face: - stype = tr( "FACE" ); break; + stype = SMESHGUI_ElemInfo::tr( "FACE" ); break; case SMDSAbs_Volume: - stype = tr( "VOLUME" ); break; + stype = SMESHGUI_ElemInfo::tr( "VOLUME" ); break; default: break; } @@ -1340,50 +1743,50 @@ void SMESHGUI_TreeElemInfo::information( const QList& ids ) switch( e->GetEntityType() ) { case SMDSEntity_Triangle: case SMDSEntity_Quad_Triangle: - gtype = tr( "TRIANGLE" ); break; + gtype = SMESHGUI_ElemInfo::tr( "TRIANGLE" ); break; case SMDSEntity_Quadrangle: case SMDSEntity_Quad_Quadrangle: case SMDSEntity_BiQuad_Quadrangle: - gtype = tr( "QUADRANGLE" ); break; + gtype = SMESHGUI_ElemInfo::tr( "QUADRANGLE" ); break; case SMDSEntity_Polygon: case SMDSEntity_Quad_Polygon: - gtype = tr( "POLYGON" ); break; + gtype = SMESHGUI_ElemInfo::tr( "POLYGON" ); break; case SMDSEntity_Tetra: case SMDSEntity_Quad_Tetra: - gtype = tr( "TETRAHEDRON" ); break; + gtype = SMESHGUI_ElemInfo::tr( "TETRAHEDRON" ); break; case SMDSEntity_Pyramid: case SMDSEntity_Quad_Pyramid: - gtype = tr( "PYRAMID" ); break; + gtype = SMESHGUI_ElemInfo::tr( "PYRAMID" ); break; case SMDSEntity_Hexa: case SMDSEntity_Quad_Hexa: case SMDSEntity_TriQuad_Hexa: - gtype = tr( "HEXAHEDRON" ); break; + gtype = SMESHGUI_ElemInfo::tr( "HEXAHEDRON" ); break; case SMDSEntity_Penta: case SMDSEntity_Quad_Penta: - gtype = tr( "PRISM" ); break; + gtype = SMESHGUI_ElemInfo::tr( "PRISM" ); break; case SMDSEntity_Hexagonal_Prism: - gtype = tr( "HEX_PRISM" ); break; + gtype = SMESHGUI_ElemInfo::tr( "HEX_PRISM" ); break; case SMDSEntity_Polyhedra: case SMDSEntity_Quad_Polyhedra: - gtype = tr( "POLYHEDRON" ); break; + gtype = SMESHGUI_ElemInfo::tr( "POLYHEDRON" ); break; default: break; } if ( !gtype.isEmpty() ) { QTreeWidgetItem* typeItem = createItem( elemItem, Bold ); - typeItem->setText( 0, tr( "TYPE" ) ); + typeItem->setText( 0, SMESHGUI_ElemInfo::tr( "TYPE" ) ); typeItem->setText( 1, gtype ); } // quadratic flag and gravity center (any element except 0D) if ( e->GetEntityType() > SMDSEntity_0D && e->GetEntityType() < SMDSEntity_Ball ) { // quadratic flag QTreeWidgetItem* quadItem = createItem( elemItem, Bold ); - quadItem->setText( 0, tr( "QUADRATIC" ) ); - quadItem->setText( 1, e->IsQuadratic() ? tr( "YES" ) : tr( "NO" ) ); + quadItem->setText( 0, SMESHGUI_ElemInfo::tr( "QUADRATIC" ) ); + quadItem->setText( 1, e->IsQuadratic() ? SMESHGUI_ElemInfo::tr( "YES" ) : SMESHGUI_ElemInfo::tr( "NO" ) ); // gravity center XYZ gc = gravityCenter( e ); QTreeWidgetItem* gcItem = createItem( elemItem, Bold ); - gcItem->setText( 0, tr( "GRAVITY_CENTER" ) ); + gcItem->setText( 0, SMESHGUI_ElemInfo::tr( "GRAVITY_CENTER" ) ); QTreeWidgetItem* xItem = createItem( gcItem ); xItem->setText( 0, "X" ); xItem->setText( 1, QString::number( gc.x(), precision > 0 ? 'f' : 'g', qAbs( precision ) ) ); @@ -1397,23 +1800,25 @@ void SMESHGUI_TreeElemInfo::information( const QList& ids ) if ( const SMDS_BallElement* ball = dynamic_cast( e )) { // ball diameter QTreeWidgetItem* diamItem = createItem( elemItem, Bold ); - diamItem->setText( 0, tr( "BALL_DIAMETER" ) ); + diamItem->setText( 0, SMESHGUI_ElemInfo::tr( "BALL_DIAMETER" ) ); diamItem->setText( 1, QString( "%1" ).arg( ball->GetDiameter() )); } // connectivity QTreeWidgetItem* conItem = createItem( elemItem, Bold ); - conItem->setText( 0, tr( "CONNECTIVITY" ) ); + conItem->setText( 0, SMESHGUI_ElemInfo::tr( "CONNECTIVITY" ) ); SMDS_ElemIteratorPtr nodeIt = e->nodesIterator(); for ( int idx = 1; nodeIt->more(); idx++ ) { const SMDS_MeshNode* node = static_cast( nodeIt->next() ); // node number and ID QTreeWidgetItem* nodeItem = createItem( conItem, Bold ); - nodeItem->setText( 0, QString( "%1 %2 / %3" ).arg( tr( "NODE" ) ).arg( idx ).arg( e->NbNodes() ) ); + nodeItem->setText( 0, QString( "%1 %2 / %3" ).arg( SMESHGUI_ElemInfo::tr( "NODE" ) ).arg( idx ).arg( e->NbNodes() ) ); nodeItem->setText( 1, QString( "#%1" ).arg( node->GetID() ) ); + nodeItem->setData( 1, TypeRole, ElemConnectivity ); + nodeItem->setData( 1, IdRole, node->GetID() ); nodeItem->setExpanded( false ); // node coordinates QTreeWidgetItem* coordItem = createItem( nodeItem ); - coordItem->setText( 0, tr( "COORDINATES" ) ); + coordItem->setText( 0, SMESHGUI_ElemInfo::tr( "COORDINATES" ) ); QTreeWidgetItem* xItem = createItem( coordItem ); xItem->setText( 0, "X" ); xItem->setText( 1, QString::number( node->X(), precision > 0 ? 'f' : 'g', qAbs( precision ) ) ); @@ -1425,44 +1830,48 @@ void SMESHGUI_TreeElemInfo::information( const QList& ids ) zItem->setText( 1, QString::number( node->Z(), precision > 0 ? 'f' : 'g', qAbs( precision ) ) ); // node connectivity QTreeWidgetItem* nconItem = createItem( nodeItem ); - nconItem->setText( 0, tr( "CONNECTIVITY" ) ); + nconItem->setText( 0, SMESHGUI_ElemInfo::tr( "CONNECTIVITY" ) ); Connectivity connectivity = nodeConnectivity( node ); if ( !connectivity.isEmpty() ) { QString con = formatConnectivity( connectivity, SMDSAbs_0DElement ); if ( !con.isEmpty() ) { QTreeWidgetItem* i = createItem( nconItem ); - i->setText( 0, tr( "0D_ELEMENTS" ) ); + i->setText( 0, SMESHGUI_ElemInfo::tr( "0D_ELEMENTS" ) ); i->setText( 1, con ); } con = formatConnectivity( connectivity, SMDSAbs_Edge ); if ( !con.isEmpty() ) { QTreeWidgetItem* i = createItem( nconItem ); - i->setText( 0, tr( "EDGES" ) ); + i->setText( 0, SMESHGUI_ElemInfo::tr( "EDGES" ) ); i->setText( 1, con ); + i->setData( 1, TypeRole, NodeConnectivity ); } con = formatConnectivity( connectivity, SMDSAbs_Ball ); if ( !con.isEmpty() ) { QTreeWidgetItem* i = createItem( nconItem ); - i->setText( 0, tr( "BALL_ELEMENTS" ) ); + i->setText( 0, SMESHGUI_ElemInfo::tr( "BALL_ELEMENTS" ) ); i->setText( 1, con ); + i->setData( 1, TypeRole, NodeConnectivity ); } con = formatConnectivity( connectivity, SMDSAbs_Face ); if ( !con.isEmpty() ) { QTreeWidgetItem* i = createItem( nconItem ); - i->setText( 0, tr( "FACES" ) ); + i->setText( 0, SMESHGUI_ElemInfo::tr( "FACES" ) ); i->setText( 1, con ); + i->setData( 1, TypeRole, NodeConnectivity ); } con = formatConnectivity( connectivity, SMDSAbs_Volume ); if ( !con.isEmpty() ) { QTreeWidgetItem* i = createItem( nconItem ); - i->setText( 0, tr( "VOLUMES" ) ); + i->setText( 0, SMESHGUI_ElemInfo::tr( "VOLUMES" ) ); i->setText( 1, con ); + i->setData( 1, TypeRole, NodeConnectivity ); } } } //Controls QTreeWidgetItem* cntrItem = createItem( elemItem, Bold ); - cntrItem->setText( 0, tr( "MEN_CTRL" ) ); + cntrItem->setText( 0, SMESHGUI_ElemInfo::tr( "CONTROLS" ) ); //Length if( e->GetType()==SMDSAbs_Edge){ afunctor.reset( new SMESH::Controls::Length() ); @@ -1485,7 +1894,7 @@ void SMESHGUI_TreeElemInfo::information( const QList& ids ) afunctor->SetMesh( actor()->GetObject()->GetMesh() ); afunctor->SetPrecision( cprecision ); QTreeWidgetItem* taperlItem = createItem( cntrItem, Bold ); - taperlItem->setText( 0, tr( "MEN_TAPER" ) ); + taperlItem->setText( 0, tr( "TAPER_ELEMENTS" ) ); taperlItem->setText( 1, QString( "%1" ).arg( afunctor->GetValue( id ) ) ); //AspectRatio2D afunctor.reset( new SMESH::Controls::AspectRatio() ); @@ -1505,14 +1914,14 @@ void SMESHGUI_TreeElemInfo::information( const QList& ids ) afunctor->SetMesh( actor()->GetObject()->GetMesh() ); afunctor->SetPrecision( cprecision ); QTreeWidgetItem* warpItem = createItem( cntrItem, Bold ); - warpItem->setText( 0, tr( "STB_WARP" )); + warpItem->setText( 0, tr( "WARP_ELEMENTS" )); warpItem->setText( 1, QString( "%1" ).arg( afunctor->GetValue( id ) ) ); //Skew afunctor.reset( new SMESH::Controls::Skew() ); afunctor->SetMesh( actor()->GetObject()->GetMesh() ); afunctor->SetPrecision( cprecision ); QTreeWidgetItem* skewItem = createItem( cntrItem, Bold ); - skewItem->setText( 0, tr( "TOP_SKEW" ) ); + skewItem->setText( 0, tr( "SKEW_ELEMENTS" ) ); skewItem->setText( 1, QString( "%1" ).arg( afunctor->GetValue( id ) ) ); //ElemDiam2D afunctor.reset( new SMESH::Controls::MaxElementLength2D() ); @@ -1532,7 +1941,7 @@ void SMESHGUI_TreeElemInfo::information( const QList& ids ) afunctor.reset( new SMESH::Controls::Volume() ); afunctor->SetMesh( actor()->GetObject()->GetMesh() ); QTreeWidgetItem* volItem = createItem( cntrItem, Bold ); - volItem->setText( 0, tr( "MEN_VOLUME_3D" ) ); + volItem->setText( 0, tr( "VOLUME_3D_ELEMENTS" ) ); volItem->setText( 1, QString( "%1" ).arg( afunctor->GetValue( id ) ) ); //ElementDiameter3D afunctor.reset( new SMESH::Controls::MaxElementLength3D() ); @@ -1541,24 +1950,83 @@ void SMESHGUI_TreeElemInfo::information( const QList& ids ) diam3Item->setText( 0, tr( "MAX_ELEMENT_LENGTH_3D" ) ); diam3Item->setText( 1, QString( "%1" ).arg( afunctor->GetValue( id ) ) ); } - /* - if( e->GetType() >= SMDSAbs_Edge && e->GetType() <= SMDSAbs_Volume ) { - //shapeID - int shapeID = e->getshapeId(); - if ( shapeID > 0 ) { - QTreeWidgetItem* shItem = createItem( elemItem, Bold ); - QString shapeType; - switch ( actor()->GetObject()->GetMesh()->FindElement( shapeID )->GetType() ) { - case SMDS_TOP_EDGE: shapeType = tr( "EDGE" ); break; - case SMDS_TOP_FACE: shapeType = tr( "FACE" ); break; - case SMDS_TOP_VERTEX: shapeType = tr( "VERTEX" ); break; - default: shapeType = tr( "SOLID" ); + // element position + if ( e->GetType() >= SMDSAbs_Edge && e->GetType() <= SMDSAbs_Volume ) { + SMESH::SMESH_Mesh_ptr aMesh = actor()->GetObject()->GetMeshServer(); + if ( !CORBA::is_nil( aMesh ) ) { + SMESH::ElementPosition pos = aMesh->GetElementPosition( id ); + int shapeID = pos.shapeID; + if ( shapeID > 0 ) { + QTreeWidgetItem* shItem = createItem( elemItem, Bold ); + QString shapeType; + switch ( pos.shapeType ) { + case GEOM::EDGE: shapeType = SMESHGUI_ElemInfo::tr( "GEOM_EDGE" ); break; + case GEOM::FACE: shapeType = SMESHGUI_ElemInfo::tr( "GEOM_FACE" ); break; + case GEOM::VERTEX: shapeType = SMESHGUI_ElemInfo::tr( "GEOM_VERTEX" ); break; + case GEOM::SOLID: shapeType = SMESHGUI_ElemInfo::tr( "GEOM_SOLID" ); break; + case GEOM::SHELL: shapeType = SMESHGUI_ElemInfo::tr( "GEOM_SHELL" ); break; + default: shapeType = SMESHGUI_ElemInfo::tr( "GEOM_SHAPE" ); break; + } + shItem->setText( 0, SMESHGUI_ElemInfo::tr( "POSITION" ) ); + shItem->setText( 1, QString( "%1 #%2" ).arg( shapeType ).arg( shapeID ) ); + } + } + } + // groups element belongs to + SMESH::SMESH_Mesh_ptr aMesh = actor()->GetObject()->GetMeshServer(); + if ( !CORBA::is_nil( aMesh ) ) { + SMESH::ListOfGroups_var groups = aMesh->GetGroups(); + QTreeWidgetItem* groupsItem = 0; + for ( int i = 0; i < groups->length(); i++ ) { + SMESH::SMESH_GroupBase_var aGrp = groups[i]; + if ( CORBA::is_nil( aGrp ) ) continue; + QString aName = aGrp->GetName(); + if ( aGrp->GetType() != SMESH::NODE && !aName.isEmpty() && aGrp->Contains( id ) ) { + if ( !groupsItem ) { + groupsItem = createItem( elemItem, Bold ); + groupsItem->setText( 0, SMESHGUI_AddInfo::tr( "GROUPS" ) ); + } + QTreeWidgetItem* it = createItem( groupsItem, Bold ); + it->setText( 0, aName.trimmed() ); + if ( grp_details ) { + SMESH::SMESH_Group_var aStdGroup = SMESH::SMESH_Group::_narrow( aGrp ); + SMESH::SMESH_GroupOnGeom_var aGeomGroup = SMESH::SMESH_GroupOnGeom::_narrow( aGrp ); + SMESH::SMESH_GroupOnFilter_var aFltGroup = SMESH::SMESH_GroupOnFilter::_narrow( aGrp ); + + // type : group on geometry, standalone group, group on filter + QTreeWidgetItem* typeItem = createItem( it ); + typeItem->setText( 0, SMESHGUI_AddInfo::tr( "TYPE" ) ); + if ( !CORBA::is_nil( aStdGroup ) ) { + typeItem->setText( 1, SMESHGUI_AddInfo::tr( "STANDALONE_GROUP" ) ); + } + else if ( !CORBA::is_nil( aGeomGroup ) ) { + typeItem->setText( 1, SMESHGUI_AddInfo::tr( "GROUP_ON_GEOMETRY" ) ); + GEOM::GEOM_Object_var gobj = aGeomGroup->GetShape(); + _PTR(SObject) sobj = SMESH::ObjectToSObject( gobj ); + if ( sobj ) { + QTreeWidgetItem* gobjItem = createItem( typeItem ); + gobjItem->setText( 0, SMESHGUI_AddInfo::tr( "GEOM_OBJECT" ) ); + gobjItem->setText( 1, sobj->GetName().c_str() ); + } + } + else if ( !CORBA::is_nil( aFltGroup ) ) { + typeItem->setText( 1, SMESHGUI_AddInfo::tr( "GROUP_ON_FILTER" ) ); + } + + // size + QTreeWidgetItem* sizeItem = createItem( it ); + sizeItem->setText( 0, SMESHGUI_AddInfo::tr( "SIZE" ) ); + sizeItem->setText( 1, QString::number( aGrp->Size() ) ); + + // color + SALOMEDS::Color color = aGrp->GetColor(); + QTreeWidgetItem* colorItem = createItem( it ); + colorItem->setText( 0, SMESHGUI_AddInfo::tr( "COLOR" ) ); + colorItem->setBackground( 1, QBrush( QColor( color.R*255., color.G*255., color.B*255.) ) ); + } } - shItem->setText( 0, tr( "Position" ) ); - shItem->setText( 1, QString( "%1 #%2" ).arg(shapeType).arg( shapeID ) ); } } - */ } } } @@ -1600,6 +2068,51 @@ QTreeWidgetItem* SMESHGUI_TreeElemInfo::createItem( QTreeWidgetItem* parent, int return item; } +void SMESHGUI_TreeElemInfo::contextMenuEvent( QContextMenuEvent* e ) +{ + QList< QTreeWidgetItem* > widgets = myInfo->selectedItems(); + if ( widgets.isEmpty() ) return; + QTreeWidgetItem* aTreeItem = widgets.first(); + int type = aTreeItem->data( 1, TypeRole ).toInt(); + int id = aTreeItem->data( 1, IdRole ).toInt(); + QMenu menu; + QAction* a = menu.addAction( tr( "SHOW_ITEM_INFO" ) ); + if ( type == ElemConnectivity && id > 0 && menu.exec( e->globalPos() ) == a ) + emit( itemInfo( id ) ); + else if ( type == NodeConnectivity && menu.exec( e->globalPos() ) == a ) + emit( itemInfo( aTreeItem->text( 1 ) ) ); +} + +void SMESHGUI_TreeElemInfo::itemDoubleClicked( QTreeWidgetItem* theItem, int theColumn ) +{ + if ( theItem ) { + int type = theItem->data( 1, TypeRole ).toInt(); + int id = theItem->data( 1, IdRole ).toInt(); + if ( type == ElemConnectivity && id > 0 ) + emit( itemInfo( id ) ); + else if ( type == NodeConnectivity ) + emit( itemInfo( theItem->text( 1 ) ) ); + } +} + +void SMESHGUI_TreeElemInfo::saveInfo( QTextStream &out ) +{ + out << QString( 12, '-' ) << "\n"; + out << SMESHGUI_ElemInfo::tr( "ELEM_INFO" ) << "\n"; + out << QString( 12, '-' ) << "\n"; + + QTreeWidgetItemIterator it( myInfo ); + while ( *it ) { + if ( !( *it )->text(0).isEmpty() ) { + out << QString( SPACING_INFO * itemDepth( *it ), ' ' ) << ( *it )->text(0); + if ( !( *it )->text(1).isEmpty() ) out << ": " << ( *it )->text(1); + out << "\n"; + } + ++it; + } + out << "\n"; +} + /*! \class GrpComputor \brief Mesh information computer @@ -2059,6 +2572,26 @@ void SMESHGUI_AddInfo::showNextSubMeshes() showSubMeshes(); } +void SMESHGUI_AddInfo::saveInfo( QTextStream &out ) +{ + out << QString( 15, '-') << "\n"; + out << tr( "ADDITIONAL_INFO" ) << "\n"; + out << QString( 15, '-' ) << "\n"; + QTreeWidgetItemIterator it( this ); + while ( *it ) { + if ( !( ( *it )->text(0) ).isEmpty() ) { + out << QString( SPACING_INFO * itemDepth( *it ), ' ' ) << ( *it )->text(0); + if ( ( *it )->text(0) == tr( "COLOR" ) ) { + out << ": " << ( ( ( *it )->background(1) ).color() ).name(); + } + else if ( !( ( *it )->text(1) ).isEmpty() ) out << ": " << ( *it )->text(1); + out << "\n"; + } + ++it; + } + out << "\n"; +} + /*! \class SMESHGUI_MeshInfoDlg \brief Mesh information dialog box @@ -2124,6 +2657,8 @@ SMESHGUI_MeshInfoDlg::SMESHGUI_MeshInfoDlg( QWidget* parent, int page ) okBtn->setAutoDefault( true ); okBtn->setDefault( true ); okBtn->setFocus(); + QPushButton* dumpBtn = new QPushButton( tr( "BUT_DUMP_MESH" ), this ); + dumpBtn->setAutoDefault( true ); QPushButton* helpBtn = new QPushButton( tr( "SMESH_BUT_HELP" ), this ); helpBtn->setAutoDefault( true ); @@ -2132,6 +2667,7 @@ SMESHGUI_MeshInfoDlg::SMESHGUI_MeshInfoDlg( QWidget* parent, int page ) btnLayout->setMargin( 0 ); btnLayout->addWidget( okBtn ); + btnLayout->addWidget( dumpBtn ); btnLayout->addStretch( 10 ); btnLayout->addWidget( helpBtn ); @@ -2144,12 +2680,15 @@ SMESHGUI_MeshInfoDlg::SMESHGUI_MeshInfoDlg( QWidget* parent, int page ) myTabWidget->setCurrentIndex( qMax( (int)BaseInfo, qMin( (int)ElemInfo, page ) ) ); connect( okBtn, SIGNAL( clicked() ), this, SLOT( reject() ) ); + connect( dumpBtn, SIGNAL( clicked() ), this, SLOT( dump() ) ); connect( helpBtn, SIGNAL( clicked() ), this, SLOT( help() ) ); connect( myTabWidget, SIGNAL( currentChanged( int ) ), this, SLOT( updateSelection() ) ); connect( myMode, SIGNAL( buttonClicked( int ) ), this, SLOT( modeChanged() ) ); - connect( myID, SIGNAL( textEdited( QString ) ), this, SLOT( idChanged() ) ); + connect( myID, SIGNAL( textChanged( QString ) ), this, SLOT( idChanged() ) ); connect( SMESHGUI::GetSMESHGUI(), SIGNAL( SignalDeactivateActiveDialog() ), this, SLOT( deactivate() ) ); connect( SMESHGUI::GetSMESHGUI(), SIGNAL( SignalCloseAllDialogs() ), this, SLOT( reject() ) ); + connect( myElemInfo, SIGNAL( itemInfo( int ) ), this, SLOT( showItemInfo( int ) ) ); + connect( myElemInfo, SIGNAL( itemInfo( QString ) ), this, SLOT( showItemInfo( QString ) ) ); updateSelection(); } @@ -2354,8 +2893,79 @@ void SMESHGUI_MeshInfoDlg::idChanged() } } selector->AddOrRemoveIndex( IO, ID, false ); - if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() ) + if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() ) { aViewWindow->highlight( IO, true, true ); + aViewWindow->Repaint(); + } myElemInfo->showInfo( ids, myMode->checkedId() == ElemMode ); } } + +void SMESHGUI_MeshInfoDlg::showItemInfo( int id ) +{ + if ( id > 0 && myActor->GetObject()->GetMesh()->FindNode( id ) ) { + myMode->button( NodeMode )->click(); + myID->setText( QString::number( id ) ); + } +} + +void SMESHGUI_MeshInfoDlg::showItemInfo( const QString& theStr ) +{ + if ( !theStr.isEmpty() ) { + myMode->button( ElemMode )->click(); + myID->setText( theStr ); + } +} + +void SMESHGUI_MeshInfoDlg::dump() +{ + SUIT_Application* app = SUIT_Session::session()->activeApplication(); + if ( !app ) return; + SalomeApp_Study* appStudy = dynamic_cast( app->activeStudy() ); + if ( !appStudy ) return; + _PTR( Study ) aStudy = appStudy->studyDS(); + + QStringList aFilters; + aFilters.append( tr( "TEXT_FILES" ) ); + + bool anIsBase = true; + bool anIsElem = true; + bool anIsAdd = true; + + if ( SUIT_ResourceMgr* aResourceMgr = SMESHGUI::resourceMgr() ) { + anIsBase = aResourceMgr->booleanValue( "SMESH", "info_dump_base", anIsBase ); + anIsElem = aResourceMgr->booleanValue( "SMESH", "info_dump_elem", anIsElem ); + anIsAdd = aResourceMgr->booleanValue( "SMESH", "info_dump_add", anIsAdd ); + } + + DumpFileDlg fd( this ); + fd.setWindowTitle( tr( "SAVE_INFO" ) ); + fd.setFilters( aFilters ); + fd.myBaseChk->setChecked( anIsBase ); + fd.myElemChk->setChecked( anIsElem ); + fd.myAddChk ->setChecked( anIsAdd ); + if ( fd.exec() == QDialog::Accepted ) + { + QString aFileName = fd.selectedFile(); + + bool toBase = fd.myBaseChk->isChecked(); + bool toElem = fd.myElemChk->isChecked(); + bool toAdd = fd.myAddChk->isChecked(); + + if ( !aFileName.isEmpty() ) { + QFileInfo aFileInfo( aFileName ); + if ( aFileInfo.isDir() ) + return; + + QFile aFile( aFileName ); + if ( !aFile.open( QIODevice::WriteOnly | QIODevice::Text ) ) + return; + + QTextStream out( &aFile ); + + if ( toBase ) myBaseInfo->saveInfo( out ); + if ( toElem ) myElemInfo->saveInfo( out ); + if ( toAdd ) myAddInfo ->saveInfo( out ); + } + } +} diff --git a/src/SMESHGUI/SMESHGUI_MeshInfo.h b/src/SMESHGUI/SMESHGUI_MeshInfo.h index a2fa39930..8e3756674 100644 --- a/src/SMESHGUI/SMESHGUI_MeshInfo.h +++ b/src/SMESHGUI/SMESHGUI_MeshInfo.h @@ -41,6 +41,7 @@ #include CORBA_SERVER_HEADER(SMESH_Group) class QButtonGroup; +class QContextMenuEvent; class QLabel; class QLineEdit; class QPushButton; @@ -64,7 +65,10 @@ class SMESHGUI_EXPORT SMESHGUI_MeshInfo : public QFrame iNodesEnd, iElementsStart = iNodesEnd, iElements, - i0DStart, + iNbStart, + iNb, + iNbEnd, + i0DStart = iNbEnd, i0D, i0DEnd, iBallsStart = i0DEnd, @@ -107,6 +111,7 @@ public: void showInfo( SMESH::SMESH_IDSource_ptr ); void clear(); + void saveInfo( QTextStream &out ); private: enum { Bold = 0x01, Italic = 0x02 }; @@ -136,6 +141,7 @@ public: void showInfo( long, bool ); void showInfo( QSet, bool ); void clear(); + virtual void saveInfo( QTextStream &out ) = 0; protected: struct XYZ @@ -161,6 +167,10 @@ protected: QString formatConnectivity( Connectivity, int ); XYZ gravityCenter( const SMDS_MeshElement* ); +signals: + void itemInfo( int ); + void itemInfo( const QString& ); + private slots: void showPrevious(); void showNext(); @@ -177,8 +187,11 @@ private: class SMESHGUI_EXPORT SMESHGUI_SimpleElemInfo : public SMESHGUI_ElemInfo { + Q_OBJECT + public: SMESHGUI_SimpleElemInfo( QWidget* = 0 ); + void saveInfo( QTextStream &out ); protected: void information( const QList& ); @@ -190,17 +203,24 @@ private: class SMESHGUI_EXPORT SMESHGUI_TreeElemInfo : public SMESHGUI_ElemInfo { + Q_OBJECT; + class ItemDelegate; enum { Bold = 0x01, All = 0x80 }; public: SMESHGUI_TreeElemInfo( QWidget* = 0 ); + void saveInfo( QTextStream &out ); protected: + void contextMenuEvent( QContextMenuEvent* e ); void information( const QList& ); void clearInternal(); +private slots: + void itemDoubleClicked( QTreeWidgetItem*, int ); + private: QTreeWidgetItem* createItem( QTreeWidgetItem* = 0, int = 0 ); @@ -236,6 +256,7 @@ public: void showInfo( SMESH::SMESH_IDSource_ptr ); // void clear(); + void saveInfo( QTextStream &out ); private slots: void changeLoadToCompute(); @@ -291,6 +312,9 @@ private slots: void deactivate(); void modeChanged(); void idChanged(); + void showItemInfo( int ); + void showItemInfo( const QString& ); + void dump(); private: QTabWidget* myTabWidget; diff --git a/src/SMESHGUI/SMESHGUI_MeshOp.cxx b/src/SMESHGUI/SMESHGUI_MeshOp.cxx index df085305b..9d9aa1c0c 100644 --- a/src/SMESHGUI/SMESHGUI_MeshOp.cxx +++ b/src/SMESHGUI/SMESHGUI_MeshOp.cxx @@ -40,6 +40,7 @@ #include #include #include +#include // SALOME GUI includes #include @@ -56,6 +57,8 @@ // SALOME KERNEL includes #include #include +#include +#include // Qt includes #include @@ -336,8 +339,7 @@ bool SMESHGUI_MeshOp::isSubshapeOk() const _PTR(Study) aStudy = SMESH::GetActiveStudyDocument(); if (geomGen->_is_nil() || !aStudy) return false; - GEOM::GEOM_IGroupOperations_var op = - geomGen->GetIGroupOperations(aStudy->StudyId()); + GEOM::GEOM_IGroupOperations_wrap op = geomGen->GetIGroupOperations(aStudy->StudyId()); if (op->_is_nil()) return false; // check all selected shapes @@ -352,18 +354,18 @@ bool SMESHGUI_MeshOp::isSubshapeOk() const if (aSubGeomVar->_is_nil()) return false; // skl for NPAL14695 - implementation of searching of mainObj - GEOM::GEOM_Object_var mainObj = op->GetMainShape(aSubGeomVar); - //if (mainObj->_is_nil() || - // string(mainObj->GetEntry()) != string(mainGeom->GetEntry())) return false; + GEOM::GEOM_Object_var mainObj = op->GetMainShape(aSubGeomVar); /* _var not _wrap as + mainObj already exists! */ while(1) { if (mainObj->_is_nil()) return false; - if (std::string(mainObj->GetEntry()) == std::string(mainGeom->GetEntry())) + CORBA::String_var entry1 = mainObj->GetEntry(); + CORBA::String_var entry2 = mainGeom->GetEntry(); + if (std::string( entry1.in() ) == entry2.in() ) return true; mainObj = op->GetMainShape(mainObj); } } - //return true; } return false; @@ -896,7 +898,8 @@ void SMESHGUI_MeshOp::existingHyps( const int theDim, SMESH::SMESH_Hypothesis_var aHypVar = SMESH::SMESH_Hypothesis::_narrow( aVar ); if ( !aHypVar->_is_nil() ) { - HypothesisData* aData = SMESH::GetHypothesisData( aHypVar->GetName() ); + CORBA::String_var hypType = aHypVar->GetName(); + HypothesisData* aData = SMESH::GetHypothesisData( hypType.in() ); if ( !aData) continue; if ( ( theDim == -1 || aData->Dim.contains( theDim ) ) && ( isCompatible ( theAlgoData, aData, theHypType )) && @@ -1710,7 +1713,7 @@ bool SMESHGUI_MeshOp::createSubMesh( QString& theMess, QStringList& theEntryList GEOM::GEOM_Gen_var geomGen = SMESH::GetGEOMGen(); _PTR(Study) aStudy = SMESH::GetActiveStudyDocument(); if (!geomGen->_is_nil() && aStudy) { - GEOM::GEOM_IGroupOperations_var op = + GEOM::GEOM_IGroupOperations_wrap op = geomGen->GetIGroupOperations(aStudy->StudyId()); if (!op->_is_nil()) { // check and add all selected GEOM objects: they must be @@ -1735,18 +1738,19 @@ bool SMESHGUI_MeshOp::createSubMesh( QString& theMess, QStringList& theEntryList aSeq[iSubSh] = aSubGeomVar; } // create a group - GEOM::GEOM_Object_var aGroupVar = op->CreateGroup(mainGeom, aGroupType); + GEOM::GEOM_Object_wrap aGroupVar = op->CreateGroup(mainGeom, aGroupType); op->UnionList(aGroupVar, aSeq); if (op->IsDone()) { - aGeomVar = aGroupVar; + aGeomVar = aGroupVar.in(); // publish the GEOM group in study QString aNewGeomGroupName ("Auto_group_for_"); aNewGeomGroupName += aName; - SALOMEDS::SObject_var aNewGroupSO = - geomGen->AddInStudy(aSMESHGen->GetCurrentStudy(), aGeomVar, - aNewGeomGroupName.toLatin1().data(), mainGeom); + SALOMEDS::Study_var aStudyVar = _CAST(Study, aStudy)->GetStudy(); + SALOMEDS::SObject_wrap aNewGroupSO = + geomGen->AddInStudy( aStudyVar, aGeomVar, + aNewGeomGroupName.toLatin1().data(), mainGeom); } } } diff --git a/src/SMESHGUI/SMESHGUI_Preferences_ScalarBarDlg.cxx b/src/SMESHGUI/SMESHGUI_Preferences_ScalarBarDlg.cxx index 7f0a861ae..4e3f3d5b5 100644 --- a/src/SMESHGUI/SMESHGUI_Preferences_ScalarBarDlg.cxx +++ b/src/SMESHGUI/SMESHGUI_Preferences_ScalarBarDlg.cxx @@ -18,13 +18,12 @@ // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com -// // SMESH SMESHGUI : GUI for SMESH component // File : SMESHGUI_Preferences_ScalarBarDlg.cxx // Author : Nicolas REJNERI, Open CASCADE S.A.S. // SMESH includes -// + #include "SMESHGUI_Preferences_ScalarBarDlg.h" #include "SMESHGUI.h" @@ -130,22 +129,28 @@ SMESHGUI_Preferences_ScalarBarDlg::SMESHGUI_Preferences_ScalarBarDlg( SMESHGUI* /******************************************************************************/ // Scalar range myRangeGrp = new QGroupBox ( tr( "SMESH_RANGE_SCALARBAR" ), this ); - QHBoxLayout* myRangeGrpLayout = new QHBoxLayout( myRangeGrp ); + //QHBoxLayout* myRangeGrpLayout = new QHBoxLayout( myRangeGrp ); + QGridLayout* myRangeGrpLayout = new QGridLayout( myRangeGrp ); myRangeGrpLayout->setSpacing( SPACING_SIZE ); myRangeGrpLayout->setMargin( MARGIN_SIZE ); - + myMinEdit = new QLineEdit( myRangeGrp ); myMinEdit->setMinimumWidth( MINIMUM_WIDTH ); myMinEdit->setValidator( new QDoubleValidator( this ) ); - + myMaxEdit = new QLineEdit( myRangeGrp ); myMaxEdit->setMinimumWidth( MINIMUM_WIDTH ); myMaxEdit->setValidator( new QDoubleValidator( this ) ); - - myRangeGrpLayout->addWidget( new QLabel( tr( "SMESH_RANGE_MIN" ), myRangeGrp ) ); - myRangeGrpLayout->addWidget( myMinEdit ); - myRangeGrpLayout->addWidget( new QLabel( tr( "SMESH_RANGE_MAX" ), myRangeGrp ) ); - myRangeGrpLayout->addWidget( myMaxEdit ); - + + myLogarithmicCheck = new QCheckBox (myRangeGrp); + myLogarithmicCheck->setText(tr("SMESH_LOGARITHMIC_SCALARBAR")); + myLogarithmicCheck->setChecked(false); + + myRangeGrpLayout->addWidget( new QLabel( tr( "SMESH_RANGE_MIN" ), myRangeGrp ), 0, 0, 1, 1 ); + myRangeGrpLayout->addWidget( myMinEdit, 0, 1, 1, 1 ); + myRangeGrpLayout->addWidget( new QLabel( tr( "SMESH_RANGE_MAX" ), myRangeGrp ), 0, 2, 1, 1 ); + myRangeGrpLayout->addWidget( myMaxEdit, 0, 3, 1, 1 ); + myRangeGrpLayout->addWidget( myLogarithmicCheck, 1, 0, 1, 4 ); + aTopLayout->addWidget( myRangeGrp ); /******************************************************************************/ @@ -255,19 +260,19 @@ SMESHGUI_Preferences_ScalarBarDlg::SMESHGUI_Preferences_ScalarBarDlg( SMESHGUI* myYSpin = new SMESHGUI_SpinBox(myOriginDimGrp); myYSpin->setAcceptNames( false ); - myYSpin->RangeStepAndValidator( 0.0, 1.0, 0.1, "parametric_precision" ); + myYSpin->RangeStepAndValidator( 0.0, 1.0, 0.1, "parametric_precision" ); myYSpin->setMinimumWidth( MINIMUM_WIDTH ); myYSpin->setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed ) ); myWidthSpin = new SMESHGUI_SpinBox(myOriginDimGrp); myWidthSpin->setAcceptNames( false ); - myWidthSpin->RangeStepAndValidator( 0.0, 1.0, 0.1, "parametric_precision" ); + myWidthSpin->RangeStepAndValidator( 0.0, 1.0, 0.1, "parametric_precision" ); myWidthSpin->setMinimumWidth( MINIMUM_WIDTH ); myWidthSpin->setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed ) ); myHeightSpin = new SMESHGUI_SpinBox(myOriginDimGrp); myHeightSpin->setAcceptNames( false ); - myHeightSpin->RangeStepAndValidator( 0.0, 1.0, 0.1, "parametric_precision" ); + myHeightSpin->RangeStepAndValidator( 0.0, 1.0, 0.1, "parametric_precision" ); myHeightSpin->setMinimumWidth( MINIMUM_WIDTH ); myHeightSpin->setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed ) ); @@ -297,18 +302,18 @@ SMESHGUI_Preferences_ScalarBarDlg::SMESHGUI_Preferences_ScalarBarDlg( SMESHGUI* myDistribColorGrp->addButton(myDMonoColor);myDistribColorGrp->setId(myDMonoColor,1); myDistribColorGrp->addButton(myDMultiColor);myDistribColorGrp->setId(myDMultiColor,2); - + aDistributionGrpLayout->addWidget( myDMultiColor ); aDistributionGrpLayout->addWidget( myDMonoColor ); - + //Color of the Distribution in monocolor case: myDistributionColorLbl = new QLabel( tr( "SMESH_DISTRIBUTION_COLOR" ), myDistributionGrp ); aDistributionGrpLayout->addWidget( myDistributionColorLbl ); myMonoColorBtn = new QtxColorButton( myDistributionGrp ); aDistributionGrpLayout->addWidget(myMonoColorBtn); - + aTopLayout->addWidget(myDistributionGrp); - + /******************************************************************************/ // Common buttons myButtonGrp = new QGroupBox( this ); @@ -351,13 +356,13 @@ SMESHGUI_Preferences_ScalarBarDlg::SMESHGUI_Preferences_ScalarBarDlg( SMESHGUI* myTitleFontCombo->setCurrentIndex(1); if( f.family()=="Times") myTitleFontCombo->setCurrentIndex(2); - + myTitleBoldCheck->setChecked ( f.bold() ); myTitleItalicCheck->setChecked( f.italic() ); myTitleShadowCheck->setChecked( f.overline() ); } - - QColor labelColor = mgr->colorValue("SMESH", "scalar_bar_label_color", + + QColor labelColor = mgr->colorValue("SMESH", "scalar_bar_label_color", QColor(255, 255, 255)); myLabelsColorBtn->setColor(labelColor); myLabelsFontCombo->setCurrentIndex(0); @@ -369,7 +374,7 @@ SMESHGUI_Preferences_ScalarBarDlg::SMESHGUI_Preferences_ScalarBarDlg( SMESHGUI* myLabelsFontCombo->setCurrentIndex(1); if (f.family() == "Times") myLabelsFontCombo->setCurrentIndex(2); - + myLabelsBoldCheck ->setChecked( f.bold() ); myLabelsItalicCheck->setChecked( f.italic() ); myLabelsShadowCheck->setChecked( f.overline() ); @@ -391,7 +396,7 @@ SMESHGUI_Preferences_ScalarBarDlg::SMESHGUI_Preferences_ScalarBarDlg( SMESHGUI* QString name = isHoriz ? "scalar_bar_horizontal_%1" : "scalar_bar_vertical_%1"; - myIniX = mgr->doubleValue("SMESH", name.arg( "x" ), + myIniX = mgr->doubleValue("SMESH", name.arg( "x" ), myHorizRadioBtn->isChecked() ? DEF_HOR_X : DEF_VER_X); myIniY = mgr->doubleValue("SMESH", name.arg( "y" ), @@ -412,18 +417,16 @@ SMESHGUI_Preferences_ScalarBarDlg::SMESHGUI_Preferences_ScalarBarDlg( SMESHGUI* int coloringType = mgr->integerValue("SMESH", "distribution_coloring_type", 0); if( coloringType == SMESH_MONOCOLOR_TYPE ) { myDMonoColor->setChecked(true); - onDistributionChanged(myDistribColorGrp->id(myDMonoColor)); + onDistributionChanged(myDistribColorGrp->id(myDMonoColor)); } else { myDMultiColor->setChecked(true); onDistributionChanged(myDistribColorGrp->id(myDMultiColor)); } - + QColor distributionColor = mgr->colorValue("SMESH", "distribution_color", QColor(255, 255, 255)); myMonoColorBtn->setColor(distributionColor); - - // --> then init from selection if necessary onSelectionChanged(); @@ -434,6 +437,8 @@ SMESHGUI_Preferences_ScalarBarDlg::SMESHGUI_Preferences_ScalarBarDlg( SMESHGUI* connect( myApplyBtn, SIGNAL( clicked() ), this, SLOT( onApply() ) ); connect( myCancelBtn, SIGNAL( clicked() ), this, SLOT( onCancel() ) ); connect( myHelpBtn, SIGNAL(clicked()), this, SLOT( onHelp() ) ); + connect( myMinEdit, SIGNAL( textChanged(const QString &) ), this, SLOT( onMinMaxChanged() ) ); + connect( myMaxEdit, SIGNAL( textChanged(const QString &) ), this, SLOT( onMinMaxChanged() ) ); connect( myXSpin, SIGNAL( valueChanged( double ) ), this, SLOT( onXYChanged() ) ); connect( myYSpin, SIGNAL( valueChanged( double ) ), this, SLOT( onXYChanged() ) ); connect( aOrientationGrp, SIGNAL( buttonClicked( int ) ), this, SLOT( onOrientationChanged() ) ); @@ -528,9 +533,9 @@ bool SMESHGUI_Preferences_ScalarBarDlg::onApply() if( myDistributionGrp->isChecked() ) { int ColoringType = myDMultiColor->isChecked() ? SMESH_MULTICOLOR_TYPE : SMESH_MONOCOLOR_TYPE; distributionTypeChanged = (ColoringType != myScalarBarActor->GetDistributionColoringType()); - if(distributionTypeChanged) + if (distributionTypeChanged) myScalarBarActor->SetDistributionColoringType(ColoringType); - + if( !myDMultiColor->isChecked() ) { QColor aTColor = myMonoColorBtn->color(); double rgb[3], oldRgb[3];; @@ -551,29 +556,31 @@ bool SMESHGUI_Preferences_ScalarBarDlg::onApply() double oldMinMax[2] = { myLookupTable->GetRange()[0], myLookupTable->GetRange()[1] }; bool rangeChanges = ( fabs( oldMinMax[0] - aMin ) + fabs( oldMinMax[1] - aMax ) > 0.001 * ( aMax-aMin + oldMinMax[1]-oldMinMax[0] )); - + bool nbColorsChanged = (myColorsSpin->value() != myScalarBarActor->GetMaximumNumberOfColors()); if(nbColorsChanged) myScalarBarActor->SetMaximumNumberOfColors(myColorsSpin->value()); - myLookupTable->SetRange( aMin, aMax ); myLookupTable->SetNumberOfTableValues(myColorsSpin->value()); + + bool scaleChanged = (myLogarithmicCheck->isChecked() != (myLookupTable->GetScale() == VTK_SCALE_LOG10)); + if (scaleChanged) + myLookupTable->SetScale(myLogarithmicCheck->isChecked() ? VTK_SCALE_LOG10 : VTK_SCALE_LINEAR); + myLookupTable->Build(); - if( nbColorsChanged || rangeChanges) + if (nbColorsChanged || rangeChanges || scaleChanged) myActor->UpdateDistribution(); - + #ifndef DISABLE_PLOT2DVIEWER - if( myActor->GetPlot2Histogram() && - (nbColorsChanged || + if( myActor->GetPlot2Histogram() && + (nbColorsChanged || rangeChanges || - distributionTypeChanged || + distributionTypeChanged || colorChanged )) SMESH::ProcessIn2DViewers(myActor); #endif - - SMESH::RepaintCurrentView(); return true; @@ -601,7 +608,7 @@ void SMESHGUI_Preferences_ScalarBarDlg::onCancel() void SMESHGUI_Preferences_ScalarBarDlg::onHelp() { LightApp_Application* app = (LightApp_Application*)(SUIT_Session::session()->activeApplication()); - if (app) + if (app) app->onHelpContextModule(mySMESHGUI ? app->moduleName(mySMESHGUI->moduleName()) : QString(""), myHelpFileName); else { QString platform; @@ -612,7 +619,7 @@ void SMESHGUI_Preferences_ScalarBarDlg::onHelp() #endif SUIT_MessageBox::warning(this, tr("WRN_WARNING"), tr("EXTERNAL_BROWSER_CANNOT_SHOW_PAGE"). - arg(app->resourceMgr()->stringValue("ExternalBrowser", + arg(app->resourceMgr()->stringValue("ExternalBrowser", platform)). arg(myHelpFileName)); } @@ -639,9 +646,13 @@ void SMESHGUI_Preferences_ScalarBarDlg::onSelectionChanged() SMESH_ScalarBarActor* myScalarBarActor = myActor->GetScalarBarActor(); if ( myScalarBarActor->GetLookupTable() ) { - vtkFloatingPointType *range = myScalarBarActor->GetLookupTable()->GetRange(); + vtkLookupTable* aLookupTable = static_cast(myScalarBarActor->GetLookupTable()); + + vtkFloatingPointType *range = aLookupTable->GetRange(); myMinEdit->setText( QString::number( range[0],'g',12 ) ); myMaxEdit->setText( QString::number( range[1],'g',12 ) ); + myLogarithmicCheck->setChecked(aLookupTable->GetScale() == VTK_SCALE_LOG10); + myLogarithmicCheck->setEnabled(range[0] > 1e-07 && range[1] > 1e-07); } vtkTextProperty* aTitleTextPrp = myScalarBarActor->GetTitleTextProperty(); @@ -682,15 +693,14 @@ void SMESHGUI_Preferences_ScalarBarDlg::onSelectionChanged() myMonoColorBtn->setColor( QColor( (int)( aTColor[0]*255 ), (int)( aTColor[1]*255 ), (int)( aTColor[2]*255 ) ) ); if ( coloringType == SMESH_MONOCOLOR_TYPE ) { myDMonoColor->setChecked(true); - onDistributionChanged(myDistribColorGrp->id(myDMonoColor)); + onDistributionChanged(myDistribColorGrp->id(myDMonoColor)); } else { myDMultiColor->setChecked(true); onDistributionChanged(myDistribColorGrp->id(myDMultiColor)); } myDistributionGrp->setChecked((bool)myScalarBarActor->GetDistributionVisibility()); onDistributionActivated(myScalarBarActor->GetDistributionVisibility()); - - + myRangeGrp->setEnabled( true ); myFontGrp->setEnabled( true ); myLabColorGrp->setEnabled( true ); @@ -727,6 +737,22 @@ void SMESHGUI_Preferences_ScalarBarDlg::closeEvent( QCloseEvent* e ) QDialog::closeEvent( e ); } +//================================================================================================= +/*! + * SMESHGUI_Preferences_ScalarBarDlg::onMinMaxChanged + * + * Called when Scalar Range values are changed + */ +//================================================================================================= +void SMESHGUI_Preferences_ScalarBarDlg::onMinMaxChanged() +{ + double aMin = myMinEdit->text().toDouble(); + double aMax = myMaxEdit->text().toDouble(); + bool isLogarithmicEnabled = (aMin > 1e-07 && aMax > 1e-07); + myLogarithmicCheck->setChecked(isLogarithmicEnabled); + myLogarithmicCheck->setEnabled(isLogarithmicEnabled); +} + //================================================================================================= /*! * SMESHGUI_Preferences_ScalarBarDlg::onXYChanged @@ -833,7 +859,7 @@ void SMESHGUI_Preferences_ScalarBarDlg::initScalarBarFromResources() QString name; if (mgr){ // initialize from resoources - + // horizontal name = QString("scalar_bar_horizontal_%1"); if (mgr->hasValue("SMESH", name.arg( "x" ))) diff --git a/src/SMESHGUI/SMESHGUI_Preferences_ScalarBarDlg.h b/src/SMESHGUI/SMESHGUI_Preferences_ScalarBarDlg.h index 804b4aa6a..05dea0f59 100644 --- a/src/SMESHGUI/SMESHGUI_Preferences_ScalarBarDlg.h +++ b/src/SMESHGUI/SMESHGUI_Preferences_ScalarBarDlg.h @@ -23,7 +23,7 @@ // SMESH SMESHGUI : GUI for SMESH component // File : SMESHGUI_Preferences_ScalarBarDlg.h // Author : Nicolas REJNERI, Open CASCADE S.A.S. -// + #ifndef SMESHGUI_PREFERENCES_SCALARBARDLG_H #define SMESHGUI_PREFERENCES_SCALARBARDLG_H @@ -78,6 +78,7 @@ protected slots: void onHelp(); void onSelectionChanged(); void onXYChanged(); + void onMinMaxChanged(); void onOrientationChanged(); void onDistributionChanged( int ); void onDistributionActivated( bool ); @@ -94,6 +95,7 @@ private: QGroupBox* myRangeGrp; QLineEdit* myMinEdit; QLineEdit* myMaxEdit; + QCheckBox* myLogarithmicCheck; QGroupBox* myFontGrp; QtxColorButton* myTitleColorBtn; diff --git a/src/SMESHGUI/SMESHGUI_Selection.cxx b/src/SMESHGUI/SMESHGUI_Selection.cxx index efa3c2361..758993e4d 100644 --- a/src/SMESHGUI/SMESHGUI_Selection.cxx +++ b/src/SMESHGUI/SMESHGUI_Selection.cxx @@ -653,7 +653,7 @@ bool SMESHGUI_Selection::isImported( const int ind ) const SMESH::SMESH_Mesh_var aMesh = SMESH::SMESH_Mesh::_narrow( SMESH::SObjectToObject( SO ) ); if( !aMesh->_is_nil() ) { - SALOME_MED::MedFileInfo* inf = aMesh->GetMEDFileInfo(); + SALOME_MED::MedFileInfo_var inf = aMesh->GetMEDFileInfo(); res = strlen( (char*)inf->fileName ) > 0; } } diff --git a/src/SMESHGUI/SMESHGUI_ShapeByMeshDlg.cxx b/src/SMESHGUI/SMESHGUI_ShapeByMeshDlg.cxx index 940dd4f3e..511d0d5fa 100644 --- a/src/SMESHGUI/SMESHGUI_ShapeByMeshDlg.cxx +++ b/src/SMESHGUI/SMESHGUI_ShapeByMeshDlg.cxx @@ -40,6 +40,7 @@ // SALOME GEOM includes #include #include +#include // SALOME GUI includes #include @@ -53,6 +54,8 @@ // SALOME KERNEL includes #include +#include +#include // OCCT includes #include @@ -80,8 +83,9 @@ enum { EDGE = 0, FACE, VOLUME }; * \brief Dialog to publish a sub-shape of the mesh main shape * by selecting mesh elements */ -SMESHGUI_ShapeByMeshDlg::SMESHGUI_ShapeByMeshDlg() - : SMESHGUI_Dialog( 0, false, true, OK | Close ) +SMESHGUI_ShapeByMeshDlg::SMESHGUI_ShapeByMeshDlg(bool isMultipleAllowed) + : SMESHGUI_Dialog( 0, false, true, OK | Close ), + myIsMultipleAllowed( isMultipleAllowed ) { setWindowTitle(tr("CAPTION")); @@ -169,8 +173,7 @@ SMESHGUI_ShapeByMeshOp::SMESHGUI_ShapeByMeshOp(bool isMultipleAllowed): if ( GeometryGUI::GetGeomGen()->_is_nil() )// check that GEOM_Gen exists GeometryGUI::InitGeomGen(); - myDlg = new SMESHGUI_ShapeByMeshDlg; - myDlg->setMultipleAllowed(myIsMultipleAllowed); + myDlg = new SMESHGUI_ShapeByMeshDlg(myIsMultipleAllowed); connect(myDlg->myElemTypeGroup, SIGNAL(buttonClicked(int)), SLOT(onTypeChanged(int))); connect(myDlg->myElementId, SIGNAL(textChanged(const QString&)), SLOT(onElemIdChanged(const QString&))); @@ -223,7 +226,7 @@ SMESH::SMESH_Mesh_ptr SMESHGUI_ShapeByMeshOp::GetMesh() //======================================================================= // function : GetShape() -// purpose : Get published sub-shape +// purpose : Return published sub-shape, it must be UnRegister()ed! //======================================================================= GEOM::GEOM_Object_ptr SMESHGUI_ShapeByMeshOp::GetShape() { @@ -306,85 +309,92 @@ void SMESHGUI_ShapeByMeshOp::commitOperation() try { QStringList aListId = myDlg->myElementId->text().split( " ", QString::SkipEmptyParts); if (aListId.count() == 1) + { + int elemID = (aListId.first()).toInt(); + // GEOM_Object is published -> no need to UnRegister() + myGeomObj = GEOM::GEOM_Object::_duplicate + (SMESHGUI::GetSMESHGen()->GetGeometryByMeshElement + ( myMesh.in(), elemID, myDlg->myGeomName->text().toLatin1().constData()) ); + } + else + { + GEOM::GEOM_Gen_var geomGen = SMESH::GetGEOMGen(); + _PTR(Study) aStudy = SMESH::GetActiveStudyDocument(); + + if (geomGen->_is_nil() || !aStudy) + return; + + GEOM::GEOM_IShapesOperations_wrap aShapesOp = + geomGen->GetIShapesOperations(aStudy->StudyId()); + if (aShapesOp->_is_nil() ) + return; + + TopAbs_ShapeEnum aGroupType = TopAbs_SHAPE; + + std::map aGeomObjectsMap; + GEOM::GEOM_Object_wrap aGeomObject; + + GEOM::GEOM_Object_var aMeshShape = myMesh->GetShapeToMesh(); + + for ( int i = 0; i < aListId.count(); i++ ) { - int elemID = (aListId.first()).toInt(); - myGeomObj = GEOM::GEOM_Object::_duplicate( - SMESHGUI::GetSMESHGen()->GetGeometryByMeshElement - ( myMesh.in(), elemID, myDlg->myGeomName->text().toLatin1().constData()) ); + aGeomObject = // received object need UnRegister()! + SMESHGUI::GetSMESHGen()->FindGeometryByMeshElement(myMesh.in(), aListId[i].toInt()); + + if (aGeomObject->_is_nil()) continue; + + double anId = aShapesOp->GetSubShapeIndex(aMeshShape, aGeomObject); + if (aShapesOp->IsDone() && !aGeomObjectsMap.count(anId) ) + { + aGeomObjectsMap[anId] = aGeomObject; + + TopAbs_ShapeEnum aSubShapeType = (TopAbs_ShapeEnum)aGeomObject->GetShapeType(); + if (i == 0) + aGroupType = aSubShapeType; + else if (aSubShapeType != aGroupType) + aGroupType = TopAbs_SHAPE; + } } - else + + int aNumberOfGO = aGeomObjectsMap.size(); + if (aNumberOfGO == 1) { - GEOM::GEOM_Gen_var geomGen = SMESH::GetGEOMGen(); - _PTR(Study) aStudy = SMESH::GetActiveStudyDocument(); - - if (geomGen->_is_nil() || !aStudy) - return; - - GEOM::GEOM_IShapesOperations_var aShapesOp = - geomGen->GetIShapesOperations(aStudy->StudyId()); - if (aShapesOp->_is_nil() ) + aGeomObject = (*aGeomObjectsMap.begin()).second; + } + else if (aNumberOfGO > 1) + { + GEOM::GEOM_IGroupOperations_wrap aGroupOp = + geomGen->GetIGroupOperations(aStudy->StudyId()); + if(aGroupOp->_is_nil()) return; - - TopAbs_ShapeEnum aGroupType = TopAbs_SHAPE; - - std::map aGeomObjectsMap; - GEOM::GEOM_Object_var aGeomObject; - GEOM::GEOM_Object_var aMeshShape = myMesh->GetShapeToMesh(); - - for ( int i = 0; i < aListId.count(); i++ ) - { - aGeomObject = - SMESHGUI::GetSMESHGen()->FindGeometryByMeshElement(myMesh.in(), aListId[i].toInt()); + GEOM::ListOfGO_var aGeomObjects = new GEOM::ListOfGO(); + aGeomObjects->length( aNumberOfGO ); - if (aGeomObject->_is_nil()) continue; - - double anId = aShapesOp->GetSubShapeIndex(aMeshShape, aGeomObject); - if (aShapesOp->IsDone() && aGeomObjectsMap.find(anId) == aGeomObjectsMap.end()) - { - aGeomObjectsMap[anId] = aGeomObject; + int i = 0; + std::map::iterator anIter; + for (anIter = aGeomObjectsMap.begin(); anIter!=aGeomObjectsMap.end(); anIter++) + aGeomObjects[i++] = (*anIter).second.in(); - TopAbs_ShapeEnum aSubShapeType = (TopAbs_ShapeEnum)aGeomObject->GetShapeType(); - if (i == 0) - aGroupType = aSubShapeType; - else if (aSubShapeType != aGroupType) - aGroupType = TopAbs_SHAPE; - } - } - - int aNumberOfGO = aGeomObjectsMap.size(); - if (aNumberOfGO == 1) - myGeomObj = (*aGeomObjectsMap.begin()).second; - else if (aNumberOfGO > 1) - { - GEOM::GEOM_IGroupOperations_var aGroupOp = - geomGen->GetIGroupOperations(aStudy->StudyId()); - if(aGroupOp->_is_nil()) - return; - - GEOM::ListOfGO_var aGeomObjects = new GEOM::ListOfGO(); - aGeomObjects->length( aNumberOfGO ); - - int i = 0; - std::map::iterator anIter; - for (anIter = aGeomObjectsMap.begin(); anIter!=aGeomObjectsMap.end(); anIter++) - aGeomObjects[i++] = (*anIter).second; - - //create geometry group - myGeomObj = aGroupOp->CreateGroup(aMeshShape, aGroupType); - aGroupOp->UnionList(myGeomObj, aGeomObjects); - - if (!aGroupOp->IsDone()) - return; - } - - // publish the GEOM object in study - QString aNewGeomGroupName ( myDlg->myGeomName->text() ); - - SALOMEDS::SObject_var aNewGroupSO = - geomGen->AddInStudy(SMESHGUI::GetSMESHGen()->GetCurrentStudy(), myGeomObj, - aNewGeomGroupName.toLatin1().data(), aMeshShape); + //create geometry group + aGeomObject = aGroupOp->CreateGroup(aMeshShape, aGroupType); + aGroupOp->UnionList(myGeomObj, aGeomObjects); + + if (!aGroupOp->IsDone()) + return; } + + // publish the GEOM object in study + QString aNewGeomGroupName ( myDlg->myGeomName->text() ); + SALOMEDS::Study_var aStudyVar = _CAST(Study,aStudy)->GetStudy(); + SALOMEDS::SObject_wrap aNewGroupSO = + geomGen->AddInStudy( aStudyVar, aGeomObject, + aNewGeomGroupName.toLatin1().data(), aMeshShape); + + // get a GEOM_Object already published, which doesn't need UnRegister() + CORBA::Object_var obj = aNewGroupSO->GetObject(); + myGeomObj = GEOM::GEOM_Object::_narrow( obj ); + } } catch (const SALOME::SALOME_Exception& S_ex) { SalomeApp_Tools::QtCatchCorbaException(S_ex); diff --git a/src/SMESHGUI/SMESHGUI_ShapeByMeshDlg.h b/src/SMESHGUI/SMESHGUI_ShapeByMeshDlg.h index 63477e34c..9d9d95070 100644 --- a/src/SMESHGUI/SMESHGUI_ShapeByMeshDlg.h +++ b/src/SMESHGUI/SMESHGUI_ShapeByMeshDlg.h @@ -51,7 +51,7 @@ class SMESHGUI_EXPORT SMESHGUI_ShapeByMeshDlg : public SMESHGUI_Dialog Q_OBJECT public: - SMESHGUI_ShapeByMeshDlg(); + SMESHGUI_ShapeByMeshDlg(bool isMultipleAllowed); virtual ~SMESHGUI_ShapeByMeshDlg(); private: diff --git a/src/SMESHGUI/SMESHGUI_VTKUtils.cxx b/src/SMESHGUI/SMESHGUI_VTKUtils.cxx index 6562da87a..229d7f809 100644 --- a/src/SMESHGUI/SMESHGUI_VTKUtils.cxx +++ b/src/SMESHGUI/SMESHGUI_VTKUtils.cxx @@ -34,6 +34,8 @@ #include #include +#include "SMESH_NodeLabelActor.h" +#include "SMESH_CellLabelActor.h" #include #include @@ -614,7 +616,7 @@ namespace SMESH int deltaF, deltaV; SMESH::GetColor( "SMESH", "fill_color", c, deltaF, "0,170,255|-100" ); SMESH::GetColor( "SMESH", "volume_color", c, deltaV, "255,0,170|-100" ); - SMESH::GetColor( "SMESH", "default_grp_color", c ); + c = SMESH::GetColor( "SMESH", "default_grp_color", c ); SALOMEDS::Color aColor = aGroup->GetColor(); if( !( aColor.R > 0 || aColor.G > 0 || aColor.B > 0 )) { @@ -949,6 +951,81 @@ namespace SMESH } + void UpdateFontProp( SMESHGUI* theModule ) + { + if ( !theModule ) return; + + SalomeApp_Application* app = dynamic_cast< SalomeApp_Application* >( theModule->application() ); + if ( !app ) return; + + SUIT_ResourceMgr* mgr = SMESH::GetResourceMgr( theModule ); + if ( !mgr ) return; + // + vtkFloatingPointType anRGBNd[3] = {1,1,1}; + SMESH::GetColor( "SMESH", "numbering_node_color", anRGBNd[0], anRGBNd[1], anRGBNd[2], QColor( 255, 255, 255 ) ); + int aSizeNd = 10; + SMESH::LabelFont aFamilyNd = SMESH::FntTimes; + bool aBoldNd = true; + bool anItalicNd = false; + bool aShadowNd = false; + + if ( mgr->hasValue( "SMESH", "numbering_node_font" ) ) { + QFont f = mgr->fontValue( "SMESH", "numbering_node_font" ); + if ( f.family() == "Arial" ) aFamilyNd = SMESH::FntArial; + else if ( f.family() == "Courier" ) aFamilyNd = SMESH::FntCourier; + else if ( f.family() == "Times" ) aFamilyNd = SMESH::FntTimes; + aBoldNd = f.bold(); + anItalicNd = f.italic(); + aShadowNd = f.overline(); + aSizeNd = f.pointSize(); + } + // + vtkFloatingPointType anRGBEl[3] = {0,1,0}; + SMESH::GetColor( "SMESH", "numbering_elem_color", anRGBEl[0], anRGBEl[1], anRGBEl[2], QColor( 0, 255, 0 ) ); + int aSizeEl = 12; + SMESH::LabelFont aFamilyEl = SMESH::FntTimes; + bool aBoldEl = true; + bool anItalicEl = false; + bool aShadowEl = false; + + if ( mgr->hasValue( "SMESH", "numbering_elem_font" ) ) { + QFont f = mgr->fontValue( "SMESH", "numbering_elem_font" ); + + if ( f.family() == "Arial" ) aFamilyEl = SMESH::FntArial; + else if ( f.family() == "Courier" ) aFamilyEl = SMESH::FntCourier; + else if ( f.family() == "Times" ) aFamilyEl = SMESH::FntTimes; + aBoldEl = f.bold(); + anItalicEl = f.italic(); + aShadowEl = f.overline(); + aSizeEl = f.pointSize(); + } + // + ViewManagerList vmList; + app->viewManagers( SVTK_Viewer::Type(), vmList ); + foreach ( SUIT_ViewManager* vm, vmList ) { + QVector views = vm->getViews(); + foreach ( SUIT_ViewWindow* vw, views ) { + // update VTK viewer properties + if ( SVTK_ViewWindow* aVtkView = GetVtkViewWindow( vw ) ) { + // update actors + vtkRenderer* aRenderer = aVtkView->getRenderer(); + VTK::ActorCollectionCopy aCopy( aRenderer->GetActors() ); + vtkActorCollection* aCollection = aCopy.GetActors(); + aCollection->InitTraversal(); + while ( vtkActor* anAct = aCollection->GetNextActor() ) { + if ( SMESH_NodeLabelActor* anActor = dynamic_cast< SMESH_NodeLabelActor* >( anAct ) ) { + anActor->SetFontProperties( aFamilyNd, aSizeNd, aBoldNd, anItalicNd, aShadowNd, anRGBNd[0], anRGBNd[1], anRGBNd[2] ); + } + else if ( SMESH_CellLabelActor* anActor = dynamic_cast< SMESH_CellLabelActor* >( anAct ) ) { + anActor->SetFontProperties( aFamilyEl, aSizeEl, aBoldEl, anItalicEl, aShadowEl, anRGBEl[0], anRGBEl[1], anRGBEl[2] ); + } + } + aVtkView->Repaint( false ); + } + } + } + } + //---------------------------------------------------------------------------- SVTK_Selector* GetSelector(SUIT_ViewWindow *theWindow) diff --git a/src/SMESHGUI/SMESHGUI_VTKUtils.h b/src/SMESHGUI/SMESHGUI_VTKUtils.h index 94d69a9cd..b226f7767 100644 --- a/src/SMESHGUI/SMESHGUI_VTKUtils.h +++ b/src/SMESHGUI/SMESHGUI_VTKUtils.h @@ -137,6 +137,9 @@ SMESHGUI_EXPORT SMESHGUI_EXPORT void UpdateSelectionProp( SMESHGUI* ); +SMESHGUI_EXPORT + void UpdateFontProp( SMESHGUI* ); + //---------------------------------------------------------------------------- SMESHGUI_EXPORT SVTK_Selector* GetSelector( SUIT_ViewWindow* = GetActiveWindow() ); diff --git a/src/SMESHGUI/SMESH_msg_en.ts b/src/SMESHGUI/SMESH_msg_en.ts index 5d43fc78a..5e82b9bb1 100644 --- a/src/SMESHGUI/SMESH_msg_en.ts +++ b/src/SMESHGUI/SMESH_msg_en.ts @@ -75,18 +75,6 @@ ASPECTRATIO_ELEMENTS Aspect Ratio - - NODE_POSITION - Position - - - U_POSITION - U - - - V_POSITION - V - COL_ALGO_HEADER Algorithm @@ -1490,6 +1478,10 @@ so that the application may crash. Do you wish to continue visualization? SMESH_DRS_4 + MED file contains some elements in descending connectivity. They were not read. + + + SMESH_DRS_5 The file is incorrect, some data is missed @@ -1836,6 +1828,10 @@ Check algorithm documentation for supported geometry SMESH_LENGTH Length + + SMESH_LOGARITHMIC_SCALARBAR + Logarithmic + SMESH_MAKE_GROUPS Generate groups @@ -1910,7 +1906,7 @@ Check algorithm documentation for supported geometry SMESH_MERGED_NODES - %1 nodes successfully merged. + %1 groups of nodes successfully merged. SMESH_NO_ELEMENTS_DETECTED @@ -2232,6 +2228,22 @@ Check algorithm documentation for supported geometry SMESH_PRECISION Precision + + PREF_GROUP_NUMBERING + Numbering + + + PREF_NUMBERING_NODE + Nodes: Color + + + PREF_NUMBERING_ELEM + Edges: Color + + + PREF_NUMBERING_FONT + Font + SMESH_PREFERENCES_SCALARBAR Scalar Bar Preferences @@ -2591,6 +2603,10 @@ Check algorithm documentation for supported geometry SMESH_VISU_PROBLEM + Mesh visualization failed + + + SMESH_VISU_PROBLEM_MEMORY Mesh visualization failed, probably due to lack of memory @@ -4199,6 +4215,22 @@ Please, create VTK viewer and try again PREF_ELEM_INFO_TREE Tree + + PREF_ELEM_INFO_GRP_DETAILS + Show details on groups in element information tab + + + PREF_DUMP_BASE_INFO + Dump base information + + + PREF_DUMP_ELEM_INFO + Dump element information + + + PREF_DUMP_ADD_INFO + Dump additional information + PREF_GPP_NODES_LIMIT Automatic nodes compute limit @@ -6396,6 +6428,10 @@ as they are of improper type: SMESHGUI_MeshInfo + + BASE_INFO + Base information + NAME_LAB Name: @@ -6547,6 +6583,18 @@ as they are of improper type: ELEM_MODE Element + + BUT_DUMP_MESH + &Dump + + + TEXT_FILES + Text files (*.txt) + + + SAVE_INFO + Save info + X_FROM_Y_ITEMS_SHOWN %1-%2 from %3 items shown @@ -6554,61 +6602,65 @@ as they are of improper type: SMESHGUI_ElemInfo + + ELEM_INFO + Element information + COORDINATES - COORDINATES + Coordinates CONNECTIVITY - CONNECTIVITY + Connectivity GRAVITY_CENTER - GRAVITY CENTER + Gravity Center NODE - NODE + Node 0D_ELEMENT - 0D ELEMENT + 0D Element 0D_ELEMENTS - 0D ELEMENTS + 0D Elements BALL_ELEMENT - BALL ELEMENT + Ball Element BALL_ELEMENTS - BALL ELEMENTS + Ball Elements EDGE - EDGE + Edge EDGES - EDGES + Edges FACE - FACE + Face FACES - FACES + Faces VOLUME - VOLUME + Volume VOLUMES - VOLUMES + Volumes FREE_NODE @@ -6616,7 +6668,7 @@ as they are of improper type: TYPE - TYPE + Type TRIANGLE @@ -6656,7 +6708,7 @@ as they are of improper type: QUADRATIC - QUADRATIC + Quadratic YES @@ -6666,6 +6718,57 @@ as they are of improper type: NO No + + BALL_DIAMETER + Diameter + + + GEOM_VERTEX + Vertex + + + GEOM_EDGE + Edge + + + GEOM_FACE + Face + + + GEOM_SOLID + Solid + + + GEOM_SHELL + Shell + + + GEOM_SHAPE + Shape + + + POSITION + Position + + + U_POSITION + U + + + V_POSITION + V + + + CONTROLS + Quality Controls + + + + SMESHGUI_TreeElemInfo + + SHOW_ITEM_INFO + Show info + PROPERTY Property @@ -6677,6 +6780,10 @@ as they are of improper type: SMESHGUI_AddInfo + + ADDITIONAL_INFO + Additional information + NAME Name diff --git a/src/SMESHGUI/SMESH_msg_fr.ts b/src/SMESHGUI/SMESH_msg_fr.ts index fad91d480..b322da2b2 100755 --- a/src/SMESHGUI/SMESH_msg_fr.ts +++ b/src/SMESHGUI/SMESH_msg_fr.ts @@ -63,18 +63,6 @@ ASPECTRATIO_ELEMENTS Rapport de forme - - NODE_POSITION - Position - - - U_POSITION - U - - - V_POSITION - V - COL_ALGO_HEADER Algorithme @@ -1462,6 +1450,10 @@ ce qui peut faire planter l'application. Voulez-vous continuer la visualisa SMESH_DRS_4 + MED file contains some elements in descending connectivity. They were not read. + + + SMESH_DRS_5 Le fichier n'est pas correct, des données sont manquantes @@ -1808,6 +1800,10 @@ Référez-vous à la documentation sur l'algorithme et la géométrie suppo SMESH_LENGTH Longueur + + SMESH_LOGARITHMIC_SCALARBAR + Logarithmic + SMESH_MAKE_GROUPS Générer les groupes @@ -2204,6 +2200,22 @@ Référez-vous à la documentation sur l'algorithme et la géométrie suppo SMESH_PRECISION Précision + + PREF_GROUP_NUMBERING + Numbering + + + PREF_NUMBERING_NODE + Nodes: Color + + + PREF_NUMBERING_ELEM + Edges: Color + + + PREF_NUMBERING_FONT + Police + SMESH_PREFERENCES_SCALARBAR Préférences de la barre d'échelle @@ -4154,6 +4166,22 @@ Ouvrez une fenêtre VTK et essayez de nouveau PREF_ELEM_INFO_TREE Arbre + + PREF_ELEM_INFO_GRP_DETAILS + Show details on groups in element information tab + + + PREF_DUMP_BASE_INFO + Dump base information + + + PREF_DUMP_ELEM_INFO + Dump element information + + + PREF_DUMP_ADD_INFO + Dump additional information + PREF_GPP_NODES_LIMIT Calcul automatique du nombre de nœuds: limite @@ -6315,6 +6343,10 @@ en raison de leurs types incompatibles: SMESHGUI_MeshInfo + + BASE_INFO + Informations de base + NAME_LAB Nom: @@ -6466,6 +6498,18 @@ en raison de leurs types incompatibles: ELEM_MODE Elément + + BUT_DUMP_MESH + &Dump + + + TEXT_FILES + Text files (*.txt) + + + SAVE_INFO + Save info + X_FROM_Y_ITEMS_SHOWN %1-%2 sur %3 éléments affichés @@ -6473,6 +6517,10 @@ en raison de leurs types incompatibles: SMESHGUI_ElemInfo + + ELEM_INFO + Infos sur les éléments + COORDINATES COORDONNÉES @@ -6585,6 +6633,57 @@ en raison de leurs types incompatibles: NO Non + + BALL_DIAMETER + Diamètre + + + GEOM_VERTEX + Sommet + + + GEOM_EDGE + Arête + + + GEOM_FACE + Face + + + GEOM_SOLID + Solide + + + GEOM_SHELL + Coque + + + GEOM_SHAPE + Forme + + + POSITION + Position + + + U_POSITION + U + + + V_POSITION + V + + + CONTROLS + Quality Controls + + + + SMESHGUI_TreeElemInfo + + SHOW_ITEM_INFO + Show info + PROPERTY Propriété @@ -6596,6 +6695,10 @@ en raison de leurs types incompatibles: SMESHGUI_AddInfo + + ADDITIONAL_INFO + Infos détaillées + NAME Nom diff --git a/src/SMESHUtils/Makefile.am b/src/SMESHUtils/Makefile.am index a90736ca5..7f5cac140 100644 --- a/src/SMESHUtils/Makefile.am +++ b/src/SMESHUtils/Makefile.am @@ -33,7 +33,8 @@ salomeinclude_HEADERS = \ SMESH_Comment.hxx \ SMESH_ComputeError.hxx \ SMESH_File.hxx \ - SMESH_Utils.hxx + SMESH_Utils.hxx \ + SMESH_TryCatch.hxx # Libraries targets @@ -44,6 +45,7 @@ dist_libSMESHUtils_la_SOURCES = \ SMESH_Quadtree.cxx \ SMESH_Octree.cxx \ SMESH_OctreeNode.cxx \ + SMESH_TryCatch.cxx \ SMESH_File.cxx # additionnal information to compile and link file diff --git a/src/SMESHUtils/SMESH_Block.cxx b/src/SMESHUtils/SMESH_Block.cxx index b28dc7d67..205e6aba2 100644 --- a/src/SMESHUtils/SMESH_Block.cxx +++ b/src/SMESHUtils/SMESH_Block.cxx @@ -957,10 +957,10 @@ int SMESH_Block::GetShapeIDByParams ( const gp_XYZ& theCoord ) /*! * \brief Return number of wires and a list of oredered edges. * \param theFace - the face to process - * \param theFirstVertex - the vertex of the outer wire to set first in the returned - * list ( theFirstVertex may be NULL ) * \param theEdges - all ordered edges of theFace (outer edges goes first). * \param theNbEdgesInWires - nb of edges (== nb of vertices in closed wire) in each wire + * \param theFirstVertex - the vertex of the outer wire to set first in the returned + * list ( theFirstVertex may be NULL ) * \param theShapeAnalysisAlgo - if true, ShapeAnalysis::OuterWire() is used to find * the outer wire else BRepTools::OuterWire() is used. * \retval int - nb of wires @@ -972,9 +972,9 @@ int SMESH_Block::GetShapeIDByParams ( const gp_XYZ& theCoord ) //================================================================================ int SMESH_Block::GetOrderedEdges (const TopoDS_Face& theFace, - TopoDS_Vertex theFirstVertex, list< TopoDS_Edge >& theEdges, list< int > & theNbEdgesInWires, + TopoDS_Vertex theFirstVertex, const bool theShapeAnalysisAlgo) { // put wires in a list, so that an outer wire comes first @@ -1352,7 +1352,7 @@ bool SMESH_Block::FindBlockShapes(const TopoDS_Shell& theShell, // find bottom edges and veritices list< TopoDS_Edge > eList; list< int > nbVertexInWires; - GetOrderedEdges( TopoDS::Face( Fxy0 ), TopoDS::Vertex( V000 ), eList, nbVertexInWires ); + GetOrderedEdges( TopoDS::Face( Fxy0 ), eList, nbVertexInWires, TopoDS::Vertex( V000 ) ); if ( nbVertexInWires.size() != 1 || nbVertexInWires.front() != 4 ) { MESSAGE(" LoadBlockShapes() error "); return false; @@ -1374,7 +1374,7 @@ bool SMESH_Block::FindBlockShapes(const TopoDS_Shell& theShell, // find top edges and veritices eList.clear(); - GetOrderedEdges( TopoDS::Face( Fxy1 ), TopoDS::Vertex( V001 ), eList, nbVertexInWires ); + GetOrderedEdges( TopoDS::Face( Fxy1 ), eList, nbVertexInWires, TopoDS::Vertex( V001 ) ); if ( nbVertexInWires.size() != 1 || nbVertexInWires.front() != 4 ) { MESSAGE(" LoadBlockShapes() error "); return false; diff --git a/src/SMESHUtils/SMESH_Block.hxx b/src/SMESHUtils/SMESH_Block.hxx index 4971db99a..65c41bbec 100644 --- a/src/SMESHUtils/SMESH_Block.hxx +++ b/src/SMESHUtils/SMESH_Block.hxx @@ -256,7 +256,7 @@ public: public: // --------------- - // Block geomerty + // Block geometry // --------------- @@ -275,9 +275,9 @@ public: // Return true if an in-block parameter increases along theEdge curve static int GetOrderedEdges (const TopoDS_Face& theFace, - TopoDS_Vertex theFirstVertex, std::list< TopoDS_Edge >& theEdges, std::list< int > & theNbEdgesInWires, + TopoDS_Vertex theFirstVertex=TopoDS_Vertex(), const bool theShapeAnalysisAlgo=false); // Return nb wires and a list of oredered edges. // It is used to assign indices to subshapes. diff --git a/src/SMESHUtils/SMESH_TryCatch.cxx b/src/SMESHUtils/SMESH_TryCatch.cxx new file mode 100644 index 000000000..78808cf1c --- /dev/null +++ b/src/SMESHUtils/SMESH_TryCatch.cxx @@ -0,0 +1,33 @@ +// Copyright (C) 2007-2012 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, +// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com + +#include "SMESH_TryCatch.hxx" + +void SMESH::throwSalomeEx(const char* txt) +{ + throw SALOME_Exception( txt ); +} + +void SMESH::doNothing(const char* txt) +{ + MESSAGE( txt << " " << __FILE__ << ": " << __LINE__ ); +} + diff --git a/src/SMESHUtils/SMESH_TryCatch.hxx b/src/SMESHUtils/SMESH_TryCatch.hxx new file mode 100644 index 000000000..18b9eecaa --- /dev/null +++ b/src/SMESHUtils/SMESH_TryCatch.hxx @@ -0,0 +1,109 @@ +// Copyright (C) 2007-2012 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, +// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// File : SMESH_TryCatch.hxx +// Created : Mon Dec 17 15:43:38 2012 +// Author : Edward AGAPOV (eap) + +#ifndef __SMESH_TryCatch_HXX__ +#define __SMESH_TryCatch_HXX__ + +#include "SMESH_Comment.hxx" +#include "SMESH_ComputeError.hxx" +#include "SMESH_Utils.hxx" + +#include +#include +#include +#include +#include + +// IMPORTANT: include this file _after_ OCC ones, else OCC_CATCH_SIGNALS can be undefined! + +#ifndef OCC_CATCH_SIGNALS +#define OCC_CATCH_SIGNALS +#endif + +// Define macros to catch and convert some of possible exceptions into text or SALOME_Exception + +//------------------------------------------------------------------------------------- +#define SMESH_TRY \ + try { \ + OCC_CATCH_SIGNALS \ + +//------------------------------------------------------------------------------------- +// A macro to add a custom catch clause to SMESH_CATCH +// To add your own catch close, define SMY_OWN_CATCH macro before including this file. +#ifndef SMY_OWN_CATCH +#define SMY_OWN_CATCH +#endif + +//------------------------------------------------------------------------------------- +// A macro allowing to retrieve a result returned by onExceptionFun +#define SMESH_CAUGHT + +//------------------------------------------------------------------------------------- +// A macro makes description of a caught exception and calls onExceptionFun(const char*). +// Two onExceptionFun() are defined here: SMESH::throwSalomeEx() and SMESH::doNothing(). +// To add your own catch close, define SMY_OWN_CATCH macro before including this file. + +#define SMESH_CATCH( onExceptionFun ) \ + } \ + catch (Standard_Failure& ex) \ + { \ + SMESH_Comment text("OCCT Exception: "); \ + text << ": " << ex.DynamicType()->Name(); \ + if ( ex.GetMessageString() && strlen( ex.GetMessageString() )) \ + text << ": " << ex.GetMessageString(); \ + SMESH_CAUGHT onExceptionFun( text ); \ + } \ + catch ( ::SMESH_ComputeError& ce ) \ + { \ + if ( !ce.myComment.empty() ) \ + SMESH_CAUGHT onExceptionFun( ce.myComment.c_str() ); \ + else if ( ce.IsCommon() ) \ + SMESH_CAUGHT onExceptionFun( ce.CommonName().c_str() ); \ + else \ + SMESH_CAUGHT onExceptionFun \ + (SMESH_Comment("SMESH_ComputeError: ") << ce.myName ); \ + } \ + catch ( const std::exception& ex) \ + { \ + SMESH_CAUGHT onExceptionFun( ex.what() ); \ + } \ + \ + SMY_OWN_CATCH \ + \ + catch (...) \ + { \ + SMESH_CAUGHT onExceptionFun("Unknown Exception caught"); \ + } + +//------------------------------------------------------------------------------------- +// Functions that can be used as an argument of SMESH_CATCH + +namespace SMESH +{ + SMESHUtils_EXPORT void throwSalomeEx(const char* txt); + SMESHUtils_EXPORT void doNothing(const char* txt); +} + +#endif diff --git a/src/SMESHUtils/SMESH_TypeDefs.hxx b/src/SMESHUtils/SMESH_TypeDefs.hxx index 0dbdd7422..daadb673c 100644 --- a/src/SMESHUtils/SMESH_TypeDefs.hxx +++ b/src/SMESHUtils/SMESH_TypeDefs.hxx @@ -48,6 +48,9 @@ typedef std::set< const SMDS_MeshNode*, TIDCompare > TIDSortedNodeSet; typedef std::pair< const SMDS_MeshNode*, const SMDS_MeshNode* > NLink; +struct faceQuadStruct; // defined in StdMeshers_Quadrangle_2D.hxx +typedef boost::shared_ptr TFaceQuadStructPtr; + namespace SMESHUtils { diff --git a/src/SMESH_I/Makefile.am b/src/SMESH_I/Makefile.am index 08ba9b702..9ea8491dd 100644 --- a/src/SMESH_I/Makefile.am +++ b/src/SMESH_I/Makefile.am @@ -51,10 +51,6 @@ salomeinclude_HEADERS = \ SMESH_MeshPartDS.hxx \ SMESH.hxx -# Scripts to be installed. -dist_salomescript_DATA= \ - smeshpy.py - # Libraries targets lib_LTLIBRARIES = libSMESHEngine.la diff --git a/src/SMESH_I/SMESH_2smeshpy.cxx b/src/SMESH_I/SMESH_2smeshpy.cxx index 4dc84a2a1..57a076883 100644 --- a/src/SMESH_I/SMESH_2smeshpy.cxx +++ b/src/SMESH_I/SMESH_2smeshpy.cxx @@ -26,11 +26,13 @@ // #include "SMESH_2smeshpy.hxx" -#include "utilities.h" #include "SMESH_PythonDump.hxx" #include "SMESH_NoteBook.hxx" #include "SMESH_Filter_i.hxx" +#include +#include + #include #include @@ -431,7 +433,7 @@ _pyGen::_pyGen(Resource_DataMapOfAsciiStringAsciiString& theEntry2AccessorMethod { // find a GEOM entry _pyID geomID; - SALOMEDS::SComponent_var geomComp = theStudy->FindComponent("GEOM"); + SALOMEDS::SComponent_wrap geomComp = theStudy->FindComponent("GEOM"); if ( geomComp->_is_nil() ) return; CORBA::String_var entry = geomComp->GetID(); geomID = entry.in(); @@ -1329,7 +1331,7 @@ bool _pyGen::IsNotPublished(const _pyID& theObjID) const // either the SMESH object is not in study or it is a GEOM object if ( IsGeomObject( theObjID )) { - SALOMEDS::SObject_var so = myStudy->FindObjectID( theObjID.ToCString() ); + SALOMEDS::SObject_wrap so = myStudy->FindObjectID( theObjID.ToCString() ); if ( so->_is_nil() ) return true; CORBA::Object_var obj = so->GetObject(); return CORBA::is_nil( obj ); diff --git a/src/SMESH_I/SMESH_DumpPython.cxx b/src/SMESH_I/SMESH_DumpPython.cxx index e76a8a736..b609c5750 100644 --- a/src/SMESH_I/SMESH_DumpPython.cxx +++ b/src/SMESH_I/SMESH_DumpPython.cxx @@ -25,15 +25,17 @@ // Module : SMESH #include "SMESH_PythonDump.hxx" -#include "SMESH_Gen_i.hxx" + +#include "SMESH_2smeshpy.hxx" +#include "SMESH_Comment.hxx" #include "SMESH_Filter_i.hxx" +#include "SMESH_Gen_i.hxx" #include "SMESH_MeshEditor_i.hxx" -#include "SMESH_2smeshpy.hxx" + +#include #include #include -#include - #ifdef _DEBUG_ static int MYDEBUG = 0; @@ -72,7 +74,7 @@ namespace SMESH 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(); + SALOMEDS::Study_var aStudy = aSMESHGen->GetCurrentStudy(); if(!aStudy->_is_nil() && !aCollection.IsEmpty()){ aSMESHGen->AddToPythonScript(aStudy->StudyId(),aCollection); if(MYDEBUG) MESSAGE(aString); @@ -238,10 +240,13 @@ namespace SMESH TPythonDump:: operator<<(SALOMEDS::SObject_ptr aSObject) { - if ( !aSObject->_is_nil() ) - myStream << aSObject->GetID(); - else + if ( !aSObject->_is_nil() ) { + CORBA::String_var entry = aSObject->GetID(); + myStream << entry.in(); + } + else { myStream << NotPublishedObjectName(); + } return *this; } @@ -249,9 +254,9 @@ namespace SMESH TPythonDump:: operator<<(CORBA::Object_ptr theArg) { - SMESH_Gen_i* aSMESHGen = SMESH_Gen_i::GetSMESHGen(); - SALOMEDS::Study_var aStudy = aSMESHGen->GetCurrentStudy(); - SALOMEDS::SObject_var aSObject = SMESH_Gen_i::ObjectToSObject(aStudy,theArg); + SMESH_Gen_i* aSMESHGen = SMESH_Gen_i::GetSMESHGen(); + SALOMEDS::Study_var aStudy = aSMESHGen->GetCurrentStudy(); + SALOMEDS::SObject_wrap aSObject = SMESH_Gen_i::ObjectToSObject(aStudy,theArg); if(!aSObject->_is_nil()) { CORBA::String_var id = aSObject->GetID(); myStream << id; @@ -270,8 +275,8 @@ namespace SMESH TPythonDump:: operator<<(SMESH::SMESH_Hypothesis_ptr theArg) { - SALOMEDS::Study_var aStudy = SMESH_Gen_i::GetSMESHGen()->GetCurrentStudy(); - SALOMEDS::SObject_var aSObject = SMESH_Gen_i::ObjectToSObject(aStudy,theArg); + SALOMEDS::Study_var aStudy = SMESH_Gen_i::GetSMESHGen()->GetCurrentStudy(); + SALOMEDS::SObject_wrap aSObject = SMESH_Gen_i::ObjectToSObject(aStudy,theArg); if(aSObject->_is_nil() && !CORBA::is_nil(theArg)) myStream << "hyp_" << theArg->GetId(); else @@ -285,18 +290,22 @@ namespace SMESH { if ( CORBA::is_nil( theArg ) ) return *this << "None"; - SMESH_Gen_i* aSMESHGen = SMESH_Gen_i::GetSMESHGen(); - SALOMEDS::Study_var aStudy = aSMESHGen->GetCurrentStudy(); - SALOMEDS::SObject_var aSObject = SMESH_Gen_i::ObjectToSObject(aStudy,theArg); + SMESH_Gen_i* aSMESHGen = SMESH_Gen_i::GetSMESHGen(); + SALOMEDS::Study_var aStudy = aSMESHGen->GetCurrentStudy(); + SALOMEDS::SObject_wrap aSObject = SMESH_Gen_i::ObjectToSObject(aStudy,theArg); if(!aSObject->_is_nil()) + { return *this << aSObject; + } if ( SMESH::Filter_i* filter = SMESH::DownCast( theArg )) + { return *this << filter; - SMESH::SMESH_Mesh_var mesh = theArg->GetMesh(); - if ( !theArg->_is_equivalent( mesh )) + } + if ( SMESH_MeshEditor_i::IsTemporaryIDSource( theArg )) { - SMESH::long_array_var anElementsId = theArg->GetIDs(); - SMESH::array_of_ElementType_var types = theArg->GetTypes(); + SMESH::SMESH_Mesh_var mesh = theArg->GetMesh(); + SMESH::long_array_var anElementsId = theArg->GetIDs(); + SMESH::array_of_ElementType_var types = theArg->GetTypes(); SMESH::ElementType type = types->length() ? types[0] : SMESH::ALL; return *this << mesh << ".GetIDSource(" << anElementsId << ", " << type << ")"; } @@ -590,7 +599,8 @@ Engines::TMPFile* SMESH_Gen_i::DumpPython (CORBA::Object_ptr theStudy, if (CORBA::is_nil(aStudy)) return new Engines::TMPFile(0); - SALOMEDS::SObject_var aSO = aStudy->FindComponent(ComponentDataType()); + CORBA::String_var compDataType = ComponentDataType(); + SALOMEDS::SObject_wrap aSO = aStudy->FindComponent( compDataType.in() ); if (CORBA::is_nil(aSO)) return new Engines::TMPFile(0); @@ -599,9 +609,9 @@ Engines::TMPFile* SMESH_Gen_i::DumpPython (CORBA::Object_ptr theStudy, Resource_DataMapOfAsciiStringAsciiString aMapNames; //TCollection_AsciiString s ("qwertyuioplkjhgfdsazxcvbnmQWERTYUIOPLKJHGFDSAZXCVBNM0987654321_"); - SALOMEDS::ChildIterator_var Itr = aStudy->NewChildIterator(aSO); + SALOMEDS::ChildIterator_wrap Itr = aStudy->NewChildIterator(aSO); for (Itr->InitEx(true); Itr->More(); Itr->Next()) { - SALOMEDS::SObject_var aValue = Itr->Value(); + SALOMEDS::SObject_wrap aValue = Itr->Value(); CORBA::String_var anID = aValue->GetID(); CORBA::String_var aName = aValue->GetName(); TCollection_AsciiString aGUIName ( (char*) aName.in() ); @@ -613,13 +623,15 @@ Engines::TMPFile* SMESH_Gen_i::DumpPython (CORBA::Object_ptr theStudy, } // Get trace of restored study - //SALOMEDS::SObject_var aSO = SMESH_Gen_i::ObjectToSObject(theStudy, _this()); + //SALOMEDS::SObject_wrap aSO = SMESH_Gen_i::ObjectToSObject(theStudy, _this()); SALOMEDS::StudyBuilder_var aStudyBuilder = aStudy->NewBuilder(); - SALOMEDS::GenericAttribute_var anAttr = + SALOMEDS::GenericAttribute_wrap anAttr = aStudyBuilder->FindOrCreateAttribute(aSO, "AttributePythonObject"); - char* oldValue = SALOMEDS::AttributePythonObject::_narrow(anAttr)->GetObject(); - TCollection_AsciiString aSavedTrace (oldValue); + SALOMEDS::AttributePythonObject_var pyAttr = + SALOMEDS::AttributePythonObject::_narrow(anAttr); + CORBA::String_var oldValue = pyAttr->GetObject(); + TCollection_AsciiString aSavedTrace (oldValue.in()); // Add trace of API methods calls and replace study entries by names TCollection_AsciiString aScript; @@ -675,14 +687,16 @@ void SMESH_Gen_i::SavePython (SALOMEDS::Study_ptr theStudy) TCollection_AsciiString aScript = GetNewPythonLines(theStudy->StudyId()); // Check contents of PythonObject attribute - SALOMEDS::SObject_var aSO = theStudy->FindComponent(ComponentDataType()); - //SALOMEDS::SObject_var aSO = SMESH_Gen_i::ObjectToSObject(theStudy, _this()); + CORBA::String_var compDataType = ComponentDataType(); + SALOMEDS::SObject_wrap aSO = theStudy->FindComponent( compDataType.in() ); SALOMEDS::StudyBuilder_var aStudyBuilder = theStudy->NewBuilder(); - SALOMEDS::GenericAttribute_var anAttr = + SALOMEDS::GenericAttribute_wrap anAttr = aStudyBuilder->FindOrCreateAttribute(aSO, "AttributePythonObject"); - char* oldValue = SALOMEDS::AttributePythonObject::_narrow(anAttr)->GetObject(); - TCollection_AsciiString oldScript (oldValue); + SALOMEDS::AttributePythonObject_var pyAttr = + SALOMEDS::AttributePythonObject::_narrow(anAttr); + CORBA::String_var oldValue = pyAttr->GetObject(); + TCollection_AsciiString oldScript (oldValue.in()); if (oldScript.Length() > 0) { oldScript += "\n"; @@ -692,7 +706,7 @@ void SMESH_Gen_i::SavePython (SALOMEDS::Study_ptr theStudy) } // Store in PythonObject attribute - SALOMEDS::AttributePythonObject::_narrow(anAttr)->SetObject(oldScript.ToCString(), 1); + pyAttr->SetObject(oldScript.ToCString(), 1); // Clean trace of API methods calls CleanPythonTrace(theStudy->StudyId()); @@ -776,7 +790,9 @@ namespace { isValidName = false; } // shorten names like CartesianParameters3D_400_400_400_1000000_1 - if ( aName.Length() > 20 && nbUnderscore > 2 ) + const int nbAllowedUnderscore = 3; /* changed from 2 to 3 by an user request + posted to SALOME Forum */ + if ( aName.Length() > 20 && nbUnderscore > nbAllowedUnderscore ) { p = aName.Location( "_", 20, aName.Length()); if ( p > 1 ) @@ -792,14 +808,14 @@ namespace { */ //============================================================================= TCollection_AsciiString SMESH_Gen_i::DumpPython_impl - (SALOMEDS::Study_ptr theStudy, + (SALOMEDS::Study_ptr theStudy, Resource_DataMapOfAsciiStringAsciiString& theObjectNames, Resource_DataMapOfAsciiStringAsciiString& theNames, - bool isPublished, - bool isMultiFile, - bool isHistoricalDump, - bool& aValidScript, - const TCollection_AsciiString& theSavedTrace) + bool isPublished, + bool isMultiFile, + bool isHistoricalDump, + bool& aValidScript, + const TCollection_AsciiString& theSavedTrace) { int aStudyID = theStudy->StudyId(); @@ -1014,7 +1030,8 @@ TCollection_AsciiString SMESH_Gen_i::DumpPython_impl if (isPublished) { //Output the script that sets up the visual parameters. - char* script = theStudy->GetDefaultScript(ComponentDataType(), "\t"); + CORBA::String_var compDataType = ComponentDataType(); + char* script = theStudy->GetDefaultScript( compDataType.in(), "\t"); if (script && strlen(script) > 0) { anUpdatedScript += "\n\n\t### Store presentation parameters of displayed objects\n"; anUpdatedScript += script; diff --git a/src/SMESH_I/SMESH_Filter_i.cxx b/src/SMESH_I/SMESH_Filter_i.cxx index fc5314b8c..f7040c5ab 100644 --- a/src/SMESH_I/SMESH_Filter_i.cxx +++ b/src/SMESH_I/SMESH_Filter_i.cxx @@ -18,24 +18,23 @@ // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com -// // SMESH SMESH_I : idl implementation based on 'SMESH' unit's calsses // File : SMESH_Filter_i.cxx // Author : Alexey Petrov, OCC // Module : SMESH -// -#include "SMESH_Filter_i.hxx" -#include "SMESH_Gen_i.hxx" -#include "SMESH_PythonDump.hxx" +#include "SMESH_Filter_i.hxx" +#include "SMDS_ElemIterator.hxx" #include "SMDS_Mesh.hxx" -#include "SMDS_MeshNode.hxx" #include "SMDS_MeshElement.hxx" -#include "SMDS_ElemIterator.hxx" - +#include "SMDS_MeshNode.hxx" #include "SMESHDS_Mesh.hxx" +#include "SMESH_Gen_i.hxx" +#include "SMESH_PythonDump.hxx" + +#include #include #include @@ -496,7 +495,9 @@ static TopoDS_Shape getShapeByName( const char* theName ) { CORBA::Object_var anObj = aList[ 0 ]->GetObject(); GEOM::GEOM_Object_var aGeomObj = GEOM::GEOM_Object::_narrow( anObj ); - return aSMESHGen->GeomObjectToShape( aGeomObj ); + TopoDS_Shape shape = aSMESHGen->GeomObjectToShape( aGeomObj ); + SALOME::UnRegister( aList ); // UnRegister() objects in aList + return shape; } } } @@ -509,7 +510,7 @@ static TopoDS_Shape getShapeByID (const char* theID) SMESH_Gen_i* aSMESHGen = SMESH_Gen_i::GetSMESHGen(); SALOMEDS::Study_var aStudy = aSMESHGen->GetCurrentStudy(); if ( !aStudy->_is_nil() ) { - SALOMEDS::SObject_var aSObj = aStudy->FindObjectID(theID); + SALOMEDS::SObject_wrap aSObj = aStudy->FindObjectID(theID); if ( !aSObj->_is_nil() ) { CORBA::Object_var obj = aSObj->GetObject(); GEOM::GEOM_Object_var aGeomObj = GEOM::GEOM_Object::_narrow(obj); @@ -526,7 +527,7 @@ static std::string getShapeNameByID (const char* theID) SMESH_Gen_i* aSMESHGen = SMESH_Gen_i::GetSMESHGen(); SALOMEDS::Study_var aStudy = aSMESHGen->GetCurrentStudy(); if ( !aStudy->_is_nil() ) { - SALOMEDS::SObject_var aSObj = aStudy->FindObjectID(theID); + SALOMEDS::SObject_wrap aSObj = aStudy->FindObjectID(theID); if ( !aSObj->_is_nil() ) { CORBA::String_var name = aSObj->GetName(); return name.in(); @@ -578,12 +579,12 @@ CORBA::Double NumericalFunctor_i::GetValue( CORBA::Long theId ) return myNumericalFunctorPtr->GetValue( theId ); } -SMESH::Histogram* NumericalFunctor_i::GetHistogram(CORBA::Short nbIntervals) +SMESH::Histogram* NumericalFunctor_i::GetHistogram(CORBA::Short nbIntervals, CORBA::Boolean isLogarithmic) { std::vector nbEvents; std::vector funValues; std::vector elements; - myNumericalFunctorPtr->GetHistogram(nbIntervals,nbEvents,funValues,elements); + myNumericalFunctorPtr->GetHistogram(nbIntervals,nbEvents,funValues,elements,0,isLogarithmic); #ifdef WIN32 nbIntervals = CORBA::Short( min( nbEvents.size(), funValues.size() - 1)); diff --git a/src/SMESH_I/SMESH_Filter_i.hxx b/src/SMESH_I/SMESH_Filter_i.hxx index cb82aa6d5..d874819a8 100644 --- a/src/SMESH_I/SMESH_Filter_i.hxx +++ b/src/SMESH_I/SMESH_Filter_i.hxx @@ -18,13 +18,12 @@ // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com -// // SMESH SMESH_I : idl implementation based on 'SMESH' unit's calsses // File : SMESH_Filter_i.hxx // Author : Alexey Petrov, OCC // Module : SMESH -// + #ifndef _SMESH_FILTER_I_HXX_ #define _SMESH_FILTER_I_HXX_ @@ -162,7 +161,7 @@ namespace SMESH { public: CORBA::Double GetValue( CORBA::Long theElementId ); - SMESH::Histogram* GetHistogram(CORBA::Short nbIntervals); + SMESH::Histogram* GetHistogram(CORBA::Short nbIntervals, CORBA::Boolean isLogarithmic); void SetPrecision( CORBA::Long thePrecision ); CORBA::Long GetPrecision(); Controls::NumericalFunctorPtr GetNumericalFunctor(); diff --git a/src/SMESH_I/SMESH_Gen_i.cxx b/src/SMESH_I/SMESH_Gen_i.cxx index ca74c6a0b..8fb303ad3 100644 --- a/src/SMESH_I/SMESH_Gen_i.cxx +++ b/src/SMESH_I/SMESH_Gen_i.cxx @@ -116,6 +116,11 @@ #include CORBA_CLIENT_HEADER(SALOME_ModuleCatalog) #include CORBA_CLIENT_HEADER(SALOME_Session) +// helpers about SALOME::GenericObj +#include +#include +#include + #include #include #include @@ -176,16 +181,16 @@ PortableServer::ServantBase_var SMESH_Gen_i::GetServant( CORBA::Object_ptr theOb CORBA::Object_var SMESH_Gen_i::SObjectToObject( SALOMEDS::SObject_ptr theSObject ) { - SALOMEDS::GenericAttribute_var anAttr; + SALOMEDS::GenericAttribute_wrap anAttr; CORBA::Object_var anObj; if ( !theSObject->_is_nil() ) { try { - if( theSObject->FindAttribute( anAttr, "AttributeIOR" ) ) { - SALOMEDS::AttributeIOR_var anIOR = SALOMEDS::AttributeIOR::_narrow( anAttr ); + if( theSObject->FindAttribute( anAttr.inout(), "AttributeIOR" ) ) { + SALOMEDS::AttributeIOR_wrap anIOR = anAttr; CORBA::String_var aValue = anIOR->Value(); if( strcmp( aValue, "" ) != 0 ) anObj = GetORB()->string_to_object( aValue ); - } + } } catch( ... ) { INFOS( "SObjectToObject - Unknown exception was caught!!!" ); @@ -234,7 +239,7 @@ SALOME_LifeCycleCORBA* SMESH_Gen_i::GetLCC() { * Get GEOM::GEOM_Gen reference */ //============================================================================= -GEOM::GEOM_Gen_ptr SMESH_Gen_i::GetGeomEngine() { +GEOM::GEOM_Gen_var SMESH_Gen_i::GetGeomEngine() { //CCRT GEOM::GEOM_Gen_var aGeomEngine = //CCRT GEOM::GEOM_Gen::_narrow( GetLCC()->FindOrLoad_Component("FactoryServer","GEOM") ); //CCRT return aGeomEngine._retn(); @@ -341,7 +346,7 @@ SMESH_Gen_i::~SMESH_Gen_i() } myStudyContextMap.clear(); // delete shape reader - if ( !myShapeReader ) + if ( myShapeReader ) delete myShapeReader; } @@ -604,29 +609,27 @@ void SMESH_Gen_i::setCurrentStudy( SALOMEDS::Study_ptr theStudy, myCurrentStudy = SALOMEDS::Study::_duplicate( theStudy ); // create study context, if it doesn't exist and set current study int studyId = GetCurrentStudyID(); - if ( myStudyContextMap.find( studyId ) == myStudyContextMap.end() ) { + if ( myStudyContextMap.find( studyId ) == myStudyContextMap.end() ) myStudyContextMap[ studyId ] = new StudyContext; - } // myCurrentStudy may be nil if ( !theStudyIsBeingClosed && !CORBA::is_nil( myCurrentStudy ) ) { SALOMEDS::StudyBuilder_var aStudyBuilder = myCurrentStudy->NewBuilder(); - if( !myCurrentStudy->FindComponent( "GEOM" )->_is_nil() ) - aStudyBuilder->LoadWith( myCurrentStudy->FindComponent( "GEOM" ), GetGeomEngine() ); - + SALOMEDS::SComponent_wrap GEOM_var = myCurrentStudy->FindComponent( "GEOM" ); + if( !GEOM_var->_is_nil() ) + aStudyBuilder->LoadWith( GEOM_var, GetGeomEngine() ); // NPAL16168, issue 0020210 // Let meshes update their data depending on GEOM groups that could change if ( curStudyId != studyId ) { - //SALOMEDS::SComponent_var me = PublishComponent( myCurrentStudy ); - SALOMEDS::SComponent_var me = SALOMEDS::SComponent::_narrow - ( myCurrentStudy->FindComponent( ComponentDataType() ) ); + CORBA::String_var compDataType = ComponentDataType(); + SALOMEDS::SComponent_wrap me = myCurrentStudy->FindComponent( compDataType.in() ); if ( !me->_is_nil() ) { - SALOMEDS::ChildIterator_var anIter = myCurrentStudy->NewChildIterator( me ); + SALOMEDS::ChildIterator_wrap anIter = myCurrentStudy->NewChildIterator( me ); for ( ; anIter->More(); anIter->Next() ) { - SALOMEDS::SObject_var so = anIter->Value(); - CORBA::Object_var ior = SObjectToObject( so ); - if ( SMESH_Mesh_i* mesh = SMESH::DownCast( ior )) + SALOMEDS::SObject_wrap so = anIter->Value(); + CORBA::Object_var ior = SObjectToObject( so ); + if ( SMESH_Mesh_i* mesh = SMESH::DownCast( ior )) mesh->CheckGeomGroupModif(); } } @@ -682,7 +685,7 @@ SMESH::SMESH_Hypothesis_ptr SMESH_Gen_i::CreateHypothesis( const char* theHypNam // Publish hypothesis/algorithm in the study if ( CanPublishInStudy( hyp ) ) { - SALOMEDS::SObject_var aSO = PublishHypothesis( myCurrentStudy, hyp ); + SALOMEDS::SObject_wrap aSO = PublishHypothesis( myCurrentStudy, hyp ); if ( !aSO->_is_nil() ) { // Update Python script TPythonDump() << aSO << " = " << this << ".CreateHypothesis('" @@ -746,9 +749,11 @@ SMESH_Gen_i::GetHypothesisParameterValues (const char* theHypType, // 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! + for ( int i = 0; i < nbLocalHyps; i++ ) { + CORBA::String_var hypName = aHypList[i]->GetName(); + if ( strcmp( theHypType, hypName.in() ) == 0 ) // FOUND local! return SMESH::SMESH_Hypothesis::_duplicate( aHypList[i] ); + } // check super shapes TopTools_ListIteratorOfListOfShape itShape( mesh->GetAncestors( shape )); while ( nbLocalHyps == 0 && itShape.More() ) { @@ -896,7 +901,7 @@ SMESH::SMESH_Mesh_ptr SMESH_Gen_i::CreateMesh( GEOM::GEOM_Object_ptr theShapeObj if ( CanPublishInStudy( mesh ) ) { SALOMEDS::StudyBuilder_var aStudyBuilder = myCurrentStudy->NewBuilder(); aStudyBuilder->NewCommand(); // There is a transaction - SALOMEDS::SObject_var aSO = PublishMesh( myCurrentStudy, mesh.in() ); + SALOMEDS::SObject_wrap aSO = PublishMesh( myCurrentStudy, mesh.in() ); aStudyBuilder->CommitCommand(); if ( !aSO->_is_nil() ) { // Update Python script @@ -927,7 +932,7 @@ SMESH::SMESH_Mesh_ptr SMESH_Gen_i::CreateEmptyMesh() if ( CanPublishInStudy( mesh ) ) { SALOMEDS::StudyBuilder_var aStudyBuilder = myCurrentStudy->NewBuilder(); aStudyBuilder->NewCommand(); // There is a transaction - SALOMEDS::SObject_var aSO = PublishMesh( myCurrentStudy, mesh.in() ); + SALOMEDS::SObject_wrap aSO = PublishMesh( myCurrentStudy, mesh.in() ); aStudyBuilder->CommitCommand(); if ( !aSO->_is_nil() ) { // Update Python script @@ -958,7 +963,7 @@ SMESH::SMESH_Mesh_ptr SMESH_Gen_i::CreateMeshesFromUNV( const char* theFileName if ( CanPublishInStudy( aMesh ) ) { SALOMEDS::StudyBuilder_var aStudyBuilder = myCurrentStudy->NewBuilder(); aStudyBuilder->NewCommand(); // There is a transaction - SALOMEDS::SObject_var aSO = PublishMesh( myCurrentStudy, aMesh.in(), aFileName.c_str() ); + SALOMEDS::SObject_wrap aSO = PublishMesh( myCurrentStudy, aMesh.in(), aFileName.c_str() ); aStudyBuilder->CommitCommand(); if ( !aSO->_is_nil() ) { // Update Python script @@ -990,6 +995,13 @@ SMESH::mesh_array* SMESH_Gen_i::CreateMeshesFromMEDorSAUV( const char* theFileNa const char* theCommandNameForPython, const char* theFileNameForPython) { +#ifdef WIN32 + char bname[ _MAX_FNAME ]; + _splitpath( theFileNameForPython, NULL, NULL, bname, NULL ); + string aFileName = bname; +#else + string aFileName = basename( theFileNameForPython ); +#endif // Retrieve mesh names from the file DriverMED_R_SMESHDS_Mesh myReader; myReader.SetFile( theFileName ); @@ -1020,9 +1032,12 @@ SMESH::mesh_array* SMESH_Gen_i::CreateMeshesFromMEDorSAUV( const char* theFileNa SMESH::SMESH_Mesh_var mesh = createMesh(); // publish mesh in the study - SALOMEDS::SObject_var aSO; + SALOMEDS::SObject_wrap aSO; if ( CanPublishInStudy( mesh ) ) - aSO = PublishMesh( myCurrentStudy, mesh.in(), (*it).c_str() ); + // little trick: for MED file theFileName and theFileNameForPython are the same, but they are different for SAUV + // - as names of meshes are stored in MED file, we use them for data publishing + // - as mesh name is not stored in UNV file, we use file name as name of mesh when publishing data + aSO = PublishMesh( myCurrentStudy, mesh.in(), ( theFileName == theFileNameForPython ) ? (*it).c_str() : aFileName.c_str() ); if ( !aSO->_is_nil() ) { // Python Dump aPythonDump << aSO; @@ -1120,12 +1135,19 @@ SMESH::SMESH_Mesh_ptr SMESH_Gen_i::CreateMeshesFromSTL( const char* theFileName if(MYDEBUG) MESSAGE( "SMESH_Gen_i::CreateMeshesFromSTL" ); SMESH::SMESH_Mesh_var aMesh = createMesh(); - string aFileName; + //string aFileName; +#ifdef WIN32 + char bname[ _MAX_FNAME ]; + _splitpath( theFileName, NULL, NULL, bname, NULL ); + string aFileName = bname; +#else + string aFileName = basename( theFileName ); +#endif // publish mesh in the study if ( CanPublishInStudy( aMesh ) ) { SALOMEDS::StudyBuilder_var aStudyBuilder = myCurrentStudy->NewBuilder(); aStudyBuilder->NewCommand(); // There is a transaction - SALOMEDS::SObject_var aSO = PublishInStudy + SALOMEDS::SObject_wrap aSO = PublishInStudy ( myCurrentStudy, SALOMEDS::SObject::_nil(), aMesh.in(), aFileName.c_str() ); aStudyBuilder->CommitCommand(); if ( !aSO->_is_nil() ) { @@ -1199,15 +1221,17 @@ SMESH::mesh_array* SMESH_Gen_i::CreateMeshesFromCGNS( const char* theFileName, meshServant->GetImpl().GetMeshDS()->Modified(); // publish mesh in the study - SALOMEDS::SObject_var aSO; + SALOMEDS::SObject_wrap aSO; if ( CanPublishInStudy( mesh ) ) aSO = PublishMesh( myCurrentStudy, mesh.in(), meshName.c_str() ); // Python Dump - if ( !aSO->_is_nil() ) + if ( !aSO->_is_nil() ) { aPythonDump << aSO; - else + } + else { aPythonDump << "mesh_" << i; + } } aStudyBuilder->CommitCommand(); } @@ -1250,7 +1274,7 @@ SMESH_Gen_i::CreateMeshesFromGMF( const char* theFileName, if ( CanPublishInStudy( aMesh ) ) { SALOMEDS::StudyBuilder_var aStudyBuilder = myCurrentStudy->NewBuilder(); aStudyBuilder->NewCommand(); // There is a transaction - SALOMEDS::SObject_var aSO = PublishInStudy + SALOMEDS::SObject_wrap aSO = PublishInStudy ( myCurrentStudy, SALOMEDS::SObject::_nil(), aMesh.in(), aFileName.c_str() ); aStudyBuilder->CommitCommand(); if ( !aSO->_is_nil() ) { @@ -1320,16 +1344,16 @@ SALOMEDS::SObject_ptr SMESH_Gen_i::GetAlgoSO(const ::SMESH_Algo* algo) if ( algo ) { if ( !myCurrentStudy->_is_nil() ) { // find algo in the study - SALOMEDS::SComponent_var father = SALOMEDS::SComponent::_narrow - ( myCurrentStudy->FindComponent( ComponentDataType() ) ); + CORBA::String_var compDataType = ComponentDataType(); + SALOMEDS::SComponent_wrap father = myCurrentStudy->FindComponent( compDataType.in() ); if ( !father->_is_nil() ) { - SALOMEDS::ChildIterator_var itBig = myCurrentStudy->NewChildIterator( father ); + SALOMEDS::ChildIterator_wrap itBig = myCurrentStudy->NewChildIterator( father ); for ( ; itBig->More(); itBig->Next() ) { - SALOMEDS::SObject_var gotBranch = itBig->Value(); + SALOMEDS::SObject_wrap gotBranch = itBig->Value(); if ( gotBranch->Tag() == GetAlgorithmsRootTag() ) { - SALOMEDS::ChildIterator_var algoIt = myCurrentStudy->NewChildIterator( gotBranch ); + SALOMEDS::ChildIterator_wrap algoIt = myCurrentStudy->NewChildIterator( gotBranch ); for ( ; algoIt->More(); algoIt->Next() ) { - SALOMEDS::SObject_var algoSO = algoIt->Value(); + SALOMEDS::SObject_wrap algoSO = algoIt->Value(); CORBA::Object_var algoIOR = SObjectToObject( algoSO ); if ( !CORBA::is_nil( algoIOR )) { SMESH_Hypothesis_i* impl = SMESH::DownCast( algoIOR ); @@ -1396,11 +1420,14 @@ SMESH::compute_error_array* SMESH_Gen_i::GetComputeErrors( SMESH::SMESH_Mesh_ptr errStruct.code = -( error->myName < 0 ? error->myName + 1: error->myName ); // -1 -> 0 errStruct.comment = error->myComment.c_str(); errStruct.subShapeID = sm->GetId(); - SALOMEDS::SObject_var algoSO = GetAlgoSO( error->myAlgo ); - if ( !algoSO->_is_nil() ) - errStruct.algoName = algoSO->GetName(); - else + SALOMEDS::SObject_wrap algoSO = GetAlgoSO( error->myAlgo ); + if ( !algoSO->_is_nil() ) { + CORBA::String_var algoName = algoSO->GetName(); + errStruct.algoName = algoName; + } + else { errStruct.algoName = error->myAlgo->GetName(); + } errStruct.hasBadMesh = !error->myBadElements.empty(); } } @@ -1548,9 +1575,11 @@ SMESH::algo_error_array* SMESH_Gen_i::GetAlgoState( SMESH::SMESH_Mesh_ptr theMes errStruct.algoDim = error->_algoDim; errStruct.isGlobalAlgo = error->_isGlobalAlgo; errStruct.algoName = ""; - SALOMEDS::SObject_var algoSO = GetAlgoSO( error->_algo ); - if ( !algoSO->_is_nil() ) - errStruct.algoName = algoSO->GetName(); + SALOMEDS::SObject_wrap algoSO = GetAlgoSO( error->_algo ); + if ( !algoSO->_is_nil() ) { + CORBA::String_var algoName = algoSO->GetName(); + errStruct.algoName = algoName.in(); + } } } } @@ -2004,7 +2033,7 @@ SMESH::long_array* SMESH_Gen_i::Evaluate(SMESH::SMESH_Mesh_ptr theMesh, * \param theMesh - the mesh the element is in * \param theElementID - the element ID * \param theGeomName - the name of the result geom object if it is not yet published - * \retval GEOM::GEOM_Object_ptr - the found or just published geom object + * \retval GEOM::GEOM_Object_ptr - the found or just published geom object (no need to UnRegister()) */ //================================================================================ @@ -2016,31 +2045,34 @@ SMESH_Gen_i::GetGeometryByMeshElement( SMESH::SMESH_Mesh_ptr theMesh, { Unexpect aCatch(SALOME_SalomeException); - GEOM::GEOM_Object_var geom = FindGeometryByMeshElement(theMesh, theElementID); + GEOM::GEOM_Object_wrap geom = FindGeometryByMeshElement(theMesh, theElementID); if ( !geom->_is_nil() ) { GEOM::GEOM_Object_var mainShape = theMesh->GetShapeToMesh(); GEOM::GEOM_Gen_ptr geomGen = GetGeomEngine(); // try to find the corresponding SObject - SALOMEDS::SObject_var SObj = ObjectToSObject( myCurrentStudy, geom.in() ); + SALOMEDS::SObject_wrap SObj = ObjectToSObject( myCurrentStudy, geom.in() ); if ( SObj->_is_nil() ) // submesh can be not found even if published { // try to find published submesh GEOM::ListOfLong_var list = geom->GetSubShapeIndices(); if ( !geom->IsMainShape() && list->length() == 1 ) { - SALOMEDS::SObject_var mainSO = ObjectToSObject( myCurrentStudy, mainShape ); - SALOMEDS::ChildIterator_var it; - if ( !mainSO->_is_nil() ) + SALOMEDS::SObject_wrap mainSO = ObjectToSObject( myCurrentStudy, mainShape ); + SALOMEDS::ChildIterator_wrap it; + if ( !mainSO->_is_nil() ) { it = myCurrentStudy->NewChildIterator( mainSO ); + } if ( !it->_is_nil() ) { - for ( it->InitEx(true); SObj->_is_nil() && it->More(); it->Next() ) { - GEOM::GEOM_Object_var subGeom = - GEOM::GEOM_Object::_narrow( SObjectToObject( it->Value() )); + for ( it->InitEx(true); it->More(); it->Next() ) { + SALOMEDS::SObject_wrap so = it->Value(); + CORBA::Object_var obj = SObjectToObject( so ); + GEOM::GEOM_Object_var subGeom = GEOM::GEOM_Object::_narrow( obj ); if ( !subGeom->_is_nil() ) { GEOM::ListOfLong_var subList = subGeom->GetSubShapeIndices(); if ( subList->length() == 1 && list[0] == subList[0] ) { - SObj = it->Value(); + SObj = so; geom = subGeom; + break; } } } @@ -2051,8 +2083,12 @@ SMESH_Gen_i::GetGeometryByMeshElement( SMESH::SMESH_Mesh_ptr theMesh, SObj = geomGen->AddInStudy( myCurrentStudy, geom, theGeomName, mainShape ); // return only published geometry - if ( !SObj->_is_nil() ) - return geom._retn(); + if ( !SObj->_is_nil() ) { + //return geom._retn(); -- servant of geom must be UnRegister()ed; + CORBA::Object_var obj = SObjectToObject( SObj ); + GEOM::GEOM_Object_var go = GEOM::GEOM_Object::_narrow( obj ); + return go._retn(); + } } return GEOM::GEOM_Object::_nil(); } @@ -2062,7 +2098,7 @@ SMESH_Gen_i::GetGeometryByMeshElement( SMESH::SMESH_Mesh_ptr theMesh, * \brief Return geometrical object the given element is built on. * \param theMesh - the mesh the element is in * \param theElementID - the element ID - * \retval GEOM::GEOM_Object_ptr - the found geom object + * \retval GEOM::GEOM_Object_ptr - the found or created (UnRegister()!) geom object */ //================================================================================ @@ -2092,14 +2128,16 @@ SMESH_Gen_i::FindGeometryByMeshElement( SMESH::SMESH_Mesh_ptr theMesh, GEOM::GEOM_Object_var geom = ShapeToGeomObject( meshDS->IndexToShape( shapeID )); if ( geom->_is_nil() ) { // try to find a published sub-shape - SALOMEDS::SObject_var mainSO = ObjectToSObject( myCurrentStudy, mainShape ); - SALOMEDS::ChildIterator_var it; - if ( !mainSO->_is_nil() ) + SALOMEDS::SObject_wrap mainSO = ObjectToSObject( myCurrentStudy, mainShape ); + SALOMEDS::ChildIterator_wrap it; + if ( !mainSO->_is_nil() ) { it = myCurrentStudy->NewChildIterator( mainSO ); + } if ( !it->_is_nil() ) { for ( it->InitEx(true); it->More(); it->Next() ) { - GEOM::GEOM_Object_var subGeom = - GEOM::GEOM_Object::_narrow( SObjectToObject( it->Value() )); + SALOMEDS::SObject_wrap so = it->Value(); + CORBA::Object_var obj = SObjectToObject( so ); + GEOM::GEOM_Object_var subGeom = GEOM::GEOM_Object::_narrow( obj ); if ( !subGeom->_is_nil() ) { GEOM::ListOfLong_var subList = subGeom->GetSubShapeIndices(); if ( subList->length() == 1 && shapeID == subList[0] ) { @@ -2112,11 +2150,14 @@ SMESH_Gen_i::FindGeometryByMeshElement( SMESH::SMESH_Mesh_ptr theMesh, } if ( geom->_is_nil() ) { // explode - GEOM::GEOM_IShapesOperations_var op = + GEOM::GEOM_IShapesOperations_wrap op = geomGen->GetIShapesOperations( GetCurrentStudyID() ); if ( !op->_is_nil() ) geom = op->GetSubShape( mainShape, shapeID ); } + else { + geom->Register(); + } if ( !geom->_is_nil() ) { GeomObjectToShape( geom ); // let geom client remember the found shape return geom._retn(); @@ -2345,7 +2386,7 @@ SMESH_Gen_i::ConcatenateCommon(const SMESH::mesh_array& theMeshesArray, if ( theCommonGroups ) { for(aGroupType=SMESH::NODE;aGroupType<=SMESH::BALL;aGroupType=(SMESH::ElementType)(aGroupType+1)) { string str = "Gr"; - SALOMEDS::SObject_var aMeshSObj = ObjectToSObject( myCurrentStudy, anInitMesh ); + SALOMEDS::SObject_wrap aMeshSObj = ObjectToSObject( myCurrentStudy, anInitMesh ); if(aMeshSObj) str += aMeshSObj->GetName(); str += "_"; @@ -2512,7 +2553,7 @@ SMESH_Gen_i::ConcatenateCommon(const SMESH::mesh_array& theMeshesArray, } // IPAL21468 Change icon of compound because it need not be computed. - SALOMEDS::SObject_var aMeshSObj = ObjectToSObject( myCurrentStudy, aNewMesh ); + SALOMEDS::SObject_wrap aMeshSObj = ObjectToSObject( myCurrentStudy, aNewMesh ); SetPixMap( aMeshSObj, "ICON_SMESH_TREE_MESH" ); if (aNewMeshDS) @@ -2558,7 +2599,7 @@ SMESH::SMESH_Mesh_ptr SMESH_Gen_i::CopyMesh(SMESH::SMESH_IDSource_ptr meshPart, SMESH_Mesh_i* newMesh_i = SMESH::DownCast( newMesh ); if ( !newMesh_i ) THROW_SALOME_CORBA_EXCEPTION( "can't create a mesh", SALOME::INTERNAL_ERROR ); - SALOMEDS::SObject_var meshSO = ObjectToSObject(myCurrentStudy, newMesh ); + SALOMEDS::SObject_wrap meshSO = ObjectToSObject(myCurrentStudy, newMesh ); if ( !meshSO->_is_nil() ) { SetName( meshSO, meshName, "Mesh" ); @@ -2883,9 +2924,9 @@ SALOMEDS::TMPFile* SMESH_Gen_i::Save( SALOMEDS::SComponent_ptr theComponent, // SetStoreName() to groups before storing hypotheses to let them refer to // groups using "store name", which is "Group " { - SALOMEDS::ChildIterator_var itBig = myCurrentStudy->NewChildIterator( theComponent ); + SALOMEDS::ChildIterator_wrap itBig = myCurrentStudy->NewChildIterator( theComponent ); for ( ; itBig->More(); itBig->Next() ) { - SALOMEDS::SObject_var gotBranch = itBig->Value(); + SALOMEDS::SObject_wrap gotBranch = itBig->Value(); if ( gotBranch->Tag() > GetAlgorithmsRootTag() ) { CORBA::Object_var anObject = SObjectToObject( gotBranch ); if ( !CORBA::is_nil( anObject ) ) { @@ -2920,9 +2961,9 @@ SALOMEDS::TMPFile* SMESH_Gen_i::Save( SALOMEDS::SComponent_ptr theComponent, aFile->CreateOnDisk(); // --> iterator for top-level objects - SALOMEDS::ChildIterator_var itBig = myCurrentStudy->NewChildIterator( theComponent ); + SALOMEDS::ChildIterator_wrap itBig = myCurrentStudy->NewChildIterator( theComponent ); for ( ; itBig->More(); itBig->Next() ) { - SALOMEDS::SObject_var gotBranch = itBig->Value(); + SALOMEDS::SObject_wrap gotBranch = itBig->Value(); // --> hypotheses root branch (only one for the study) if ( gotBranch->Tag() == GetHypothesisRootTag() ) { @@ -2931,9 +2972,9 @@ SALOMEDS::TMPFile* SMESH_Gen_i::Save( SALOMEDS::SComponent_ptr theComponent, aTopGroup->CreateOnDisk(); // iterator for all hypotheses - SALOMEDS::ChildIterator_var it = myCurrentStudy->NewChildIterator( gotBranch ); + SALOMEDS::ChildIterator_wrap it = myCurrentStudy->NewChildIterator( gotBranch ); for ( ; it->More(); it->Next() ) { - SALOMEDS::SObject_var mySObject = it->Value(); + SALOMEDS::SObject_wrap mySObject = it->Value(); CORBA::Object_var anObject = SObjectToObject( mySObject ); if ( !CORBA::is_nil( anObject ) ) { SMESH::SMESH_Hypothesis_var myHyp = SMESH::SMESH_Hypothesis::_narrow( anObject ); @@ -3000,9 +3041,9 @@ SALOMEDS::TMPFile* SMESH_Gen_i::Save( SALOMEDS::SComponent_ptr theComponent, aTopGroup->CreateOnDisk(); // iterator for all algorithms - SALOMEDS::ChildIterator_var it = myCurrentStudy->NewChildIterator( gotBranch ); + SALOMEDS::ChildIterator_wrap it = myCurrentStudy->NewChildIterator( gotBranch ); for ( ; it->More(); it->Next() ) { - SALOMEDS::SObject_var mySObject = it->Value(); + SALOMEDS::SObject_wrap mySObject = it->Value(); CORBA::Object_var anObject = SObjectToObject( mySObject ); if ( !CORBA::is_nil( anObject ) ) { SMESH::SMESH_Hypothesis_var myHyp = SMESH::SMESH_Hypothesis::_narrow( anObject ); @@ -3126,12 +3167,12 @@ SALOMEDS::TMPFile* SMESH_Gen_i::Save( SALOMEDS::SComponent_ptr theComponent, aDataset->CloseOnDisk(); // write reference on a shape if exists - SALOMEDS::SObject_var myRef; + SALOMEDS::SObject_wrap myRef; bool shapeRefFound = false; - bool found = gotBranch->FindSubObject( GetRefOnShapeTag(), myRef ); + bool found = gotBranch->FindSubObject( GetRefOnShapeTag(), myRef.inout() ); if ( found ) { - SALOMEDS::SObject_var myShape; - bool ok = myRef->ReferencedObject( myShape ); + SALOMEDS::SObject_wrap myShape; + bool ok = myRef->ReferencedObject( myShape.inout() ); if ( ok ) { shapeRefFound = (! CORBA::is_nil( myShape->GetObject() )); string myRefOnObject = myShape->GetID(); @@ -3146,8 +3187,8 @@ SALOMEDS::TMPFile* SMESH_Gen_i::Save( SALOMEDS::SComponent_ptr theComponent, } // write applied hypotheses if exist - SALOMEDS::SObject_var myHypBranch; - found = gotBranch->FindSubObject( GetRefOnAppliedHypothesisTag(), myHypBranch ); + SALOMEDS::SObject_wrap myHypBranch; + found = gotBranch->FindSubObject( GetRefOnAppliedHypothesisTag(), myHypBranch.inout() ); if ( found && !shapeRefFound && hasShape) { // remove applied hyps myCurrentStudy->NewBuilder()->RemoveObjectWithChildren( myHypBranch ); } @@ -3155,12 +3196,12 @@ SALOMEDS::TMPFile* SMESH_Gen_i::Save( SALOMEDS::SComponent_ptr theComponent, aGroup = new HDFgroup( "Applied Hypotheses", aTopGroup ); aGroup->CreateOnDisk(); - SALOMEDS::ChildIterator_var it = myCurrentStudy->NewChildIterator( myHypBranch ); + SALOMEDS::ChildIterator_wrap it = myCurrentStudy->NewChildIterator( myHypBranch ); int hypNb = 0; for ( ; it->More(); it->Next() ) { - SALOMEDS::SObject_var mySObject = it->Value(); - SALOMEDS::SObject_var myRefOnHyp; - bool ok = mySObject->ReferencedObject( myRefOnHyp ); + SALOMEDS::SObject_wrap mySObject = it->Value(); + SALOMEDS::SObject_wrap myRefOnHyp; + bool ok = mySObject->ReferencedObject( myRefOnHyp.inout() ); if ( ok ) { // san - it is impossible to recover applied hypotheses // using their entries within Load() method, @@ -3189,8 +3230,9 @@ SALOMEDS::TMPFile* SMESH_Gen_i::Save( SALOMEDS::SComponent_ptr theComponent, } // write applied algorithms if exist - SALOMEDS::SObject_var myAlgoBranch; - found = gotBranch->FindSubObject( GetRefOnAppliedAlgorithmsTag(), myAlgoBranch ); + SALOMEDS::SObject_wrap myAlgoBranch; + found = gotBranch->FindSubObject( GetRefOnAppliedAlgorithmsTag(), + myAlgoBranch.inout() ); if ( found && !shapeRefFound && hasShape) { // remove applied algos myCurrentStudy->NewBuilder()->RemoveObjectWithChildren( myAlgoBranch ); } @@ -3198,12 +3240,12 @@ SALOMEDS::TMPFile* SMESH_Gen_i::Save( SALOMEDS::SComponent_ptr theComponent, aGroup = new HDFgroup( "Applied Algorithms", aTopGroup ); aGroup->CreateOnDisk(); - SALOMEDS::ChildIterator_var it = myCurrentStudy->NewChildIterator( myAlgoBranch ); + SALOMEDS::ChildIterator_wrap it = myCurrentStudy->NewChildIterator( myAlgoBranch ); int algoNb = 0; for ( ; it->More(); it->Next() ) { - SALOMEDS::SObject_var mySObject = it->Value(); - SALOMEDS::SObject_var myRefOnAlgo; - bool ok = mySObject->ReferencedObject( myRefOnAlgo ); + SALOMEDS::SObject_wrap mySObject = it->Value(); + SALOMEDS::SObject_wrap myRefOnAlgo; + bool ok = mySObject->ReferencedObject( myRefOnAlgo.inout() ); if ( ok ) { // san - it is impossible to recover applied algorithms // using their entries within Load() method, @@ -3234,18 +3276,18 @@ SALOMEDS::TMPFile* SMESH_Gen_i::Save( SALOMEDS::SComponent_ptr theComponent, // --> submesh objects sub-branches for ( int i = GetSubMeshOnVertexTag(); i <= GetSubMeshOnCompoundTag(); i++ ) { - SALOMEDS::SObject_var mySubmeshBranch; - found = gotBranch->FindSubObject( i, mySubmeshBranch ); + SALOMEDS::SObject_wrap mySubmeshBranch; + found = gotBranch->FindSubObject( i, mySubmeshBranch.inout() ); if ( found ) // check if there is shape reference in submeshes { bool hasShapeRef = false; - SALOMEDS::ChildIterator_var itSM = + SALOMEDS::ChildIterator_wrap itSM = myCurrentStudy->NewChildIterator( mySubmeshBranch ); for ( ; itSM->More(); itSM->Next() ) { - SALOMEDS::SObject_var mySubRef, myShape, mySObject = itSM->Value(); - if ( mySObject->FindSubObject( GetRefOnShapeTag(), mySubRef )) - mySubRef->ReferencedObject( myShape ); + SALOMEDS::SObject_wrap mySubRef, myShape, mySObject = itSM->Value(); + if ( mySObject->FindSubObject( GetRefOnShapeTag(), mySubRef.inout() )) + mySubRef->ReferencedObject( myShape.inout() ); if ( !CORBA::is_nil( myShape ) && !CORBA::is_nil( myShape->GetObject() )) hasShapeRef = true; else @@ -3296,9 +3338,9 @@ SALOMEDS::TMPFile* SMESH_Gen_i::Save( SALOMEDS::SComponent_ptr theComponent, aGroup->CreateOnDisk(); // iterator for all submeshes of given type - SALOMEDS::ChildIterator_var itSM = myCurrentStudy->NewChildIterator( mySubmeshBranch ); + SALOMEDS::ChildIterator_wrap itSM = myCurrentStudy->NewChildIterator( mySubmeshBranch ); for ( ; itSM->More(); itSM->Next() ) { - SALOMEDS::SObject_var mySObject = itSM->Value(); + SALOMEDS::SObject_wrap mySObject = itSM->Value(); CORBA::Object_var anSubObject = SObjectToObject( mySObject ); if ( !CORBA::is_nil( anSubObject )) { @@ -3313,9 +3355,9 @@ SALOMEDS::TMPFile* SMESH_Gen_i::Save( SALOMEDS::SComponent_ptr theComponent, aSubGroup->CreateOnDisk(); // write reference on a shape, already checked if it exists - SALOMEDS::SObject_var mySubRef, myShape; - if ( mySObject->FindSubObject( GetRefOnShapeTag(), mySubRef )) - mySubRef->ReferencedObject( myShape ); + SALOMEDS::SObject_wrap mySubRef, myShape; + if ( mySObject->FindSubObject( GetRefOnShapeTag(), mySubRef.inout() )) + mySubRef->ReferencedObject( myShape.inout() ); string myRefOnObject = myShape->GetID(); if ( myRefOnObject.length() > 0 ) { aSize[ 0 ] = myRefOnObject.length() + 1; @@ -3326,18 +3368,19 @@ SALOMEDS::TMPFile* SMESH_Gen_i::Save( SALOMEDS::SComponent_ptr theComponent, } // write applied hypotheses if exist - SALOMEDS::SObject_var mySubHypBranch; - found = mySObject->FindSubObject( GetRefOnAppliedHypothesisTag(), mySubHypBranch ); + SALOMEDS::SObject_wrap mySubHypBranch; + found = mySObject->FindSubObject( GetRefOnAppliedHypothesisTag(), + mySubHypBranch.inout() ); if ( found ) { aSubSubGroup = new HDFgroup( "Applied Hypotheses", aSubGroup ); aSubSubGroup->CreateOnDisk(); - SALOMEDS::ChildIterator_var it = myCurrentStudy->NewChildIterator( mySubHypBranch ); + SALOMEDS::ChildIterator_wrap it = myCurrentStudy->NewChildIterator( mySubHypBranch ); int hypNb = 0; for ( ; it->More(); it->Next() ) { - SALOMEDS::SObject_var mySubSObject = it->Value(); - SALOMEDS::SObject_var myRefOnHyp; - bool ok = mySubSObject->ReferencedObject( myRefOnHyp ); + SALOMEDS::SObject_wrap mySubSObject = it->Value(); + SALOMEDS::SObject_wrap myRefOnHyp; + bool ok = mySubSObject->ReferencedObject( myRefOnHyp.inout() ); if ( ok ) { //string myRefOnObject = myRefOnHyp->GetID(); CORBA::Object_var anObject = SObjectToObject( myRefOnHyp ); @@ -3361,18 +3404,20 @@ SALOMEDS::TMPFile* SMESH_Gen_i::Save( SALOMEDS::SComponent_ptr theComponent, } // write applied algorithms if exist - SALOMEDS::SObject_var mySubAlgoBranch; - found = mySObject->FindSubObject( GetRefOnAppliedAlgorithmsTag(), mySubAlgoBranch ); + SALOMEDS::SObject_wrap mySubAlgoBranch; + found = mySObject->FindSubObject( GetRefOnAppliedAlgorithmsTag(), + mySubAlgoBranch.inout() ); if ( found ) { aSubSubGroup = new HDFgroup( "Applied Algorithms", aSubGroup ); aSubSubGroup->CreateOnDisk(); - SALOMEDS::ChildIterator_var it = myCurrentStudy->NewChildIterator( mySubAlgoBranch ); + SALOMEDS::ChildIterator_wrap it = + myCurrentStudy->NewChildIterator( mySubAlgoBranch ); int algoNb = 0; for ( ; it->More(); it->Next() ) { - SALOMEDS::SObject_var mySubSObject = it->Value(); - SALOMEDS::SObject_var myRefOnAlgo; - bool ok = mySubSObject->ReferencedObject( myRefOnAlgo ); + SALOMEDS::SObject_wrap mySubSObject = it->Value(); + SALOMEDS::SObject_wrap myRefOnAlgo; + bool ok = mySubSObject->ReferencedObject( myRefOnAlgo.inout() ); if ( ok ) { //string myRefOnObject = myRefOnAlgo->GetID(); CORBA::Object_var anObject = SObjectToObject( myRefOnAlgo ); @@ -3442,9 +3487,9 @@ SALOMEDS::TMPFile* SMESH_Gen_i::Save( SALOMEDS::SComponent_ptr theComponent, } // groups root sub-branch - SALOMEDS::SObject_var myGroupsBranch; + SALOMEDS::SObject_wrap myGroupsBranch; for ( int i = GetNodeGroupsTag(); i <= GetBallElementsGroupsTag(); i++ ) { - found = gotBranch->FindSubObject( i, myGroupsBranch ); + found = gotBranch->FindSubObject( i, myGroupsBranch.inout() ); if ( found ) { char name_group[ 30 ]; if ( i == GetNodeGroupsTag() ) @@ -3463,9 +3508,9 @@ SALOMEDS::TMPFile* SMESH_Gen_i::Save( SALOMEDS::SComponent_ptr theComponent, aGroup = new HDFgroup( name_group, aTopGroup ); aGroup->CreateOnDisk(); - SALOMEDS::ChildIterator_var it = myCurrentStudy->NewChildIterator( myGroupsBranch ); + SALOMEDS::ChildIterator_wrap it = myCurrentStudy->NewChildIterator( myGroupsBranch ); for ( ; it->More(); it->Next() ) { - SALOMEDS::SObject_var mySObject = it->Value(); + SALOMEDS::SObject_wrap mySObject = it->Value(); CORBA::Object_var aSubObject = SObjectToObject( mySObject ); if ( !CORBA::is_nil( aSubObject ) ) { SMESH_GroupBase_i* myGroupImpl = @@ -3515,9 +3560,9 @@ SALOMEDS::TMPFile* SMESH_Gen_i::Save( SALOMEDS::SComponent_ptr theComponent, SMESHDS_GroupOnGeom* aGeomGrp = dynamic_cast( aGrpBaseDS ); if ( aGeomGrp ) { - SALOMEDS::SObject_var mySubRef, myShape; - if (mySObject->FindSubObject( GetRefOnShapeTag(), mySubRef ) && - mySubRef->ReferencedObject( myShape ) && + SALOMEDS::SObject_wrap mySubRef, myShape; + if (mySObject->FindSubObject( GetRefOnShapeTag(), mySubRef.inout() ) && + mySubRef->ReferencedObject( myShape.inout() ) && !CORBA::is_nil( myShape->GetObject() )) { string myRefOnObject = myShape->GetID(); @@ -3878,10 +3923,10 @@ bool SMESH_Gen_i::Load( SALOMEDS::SComponent_ptr theComponent, TCollection_AsciiString tmpDir = isMultiFile ? TCollection_AsciiString( ( char* )theURL ) : ( char* )SALOMEDS_Tool::GetTmpDir().c_str(); - INFOS( "THE URL++++++++++++++" ) - INFOS( theURL ); - INFOS( "THE TMP PATH+++++++++" ); - INFOS( tmpDir ); + INFOS( "THE URL++++++++++++++" ); + INFOS( theURL ); + INFOS( "THE TMP PATH+++++++++" ); + INFOS( tmpDir ); // Convert the stream into sequence of files to process SALOMEDS::ListOfFileNames_var aFileSeq = SALOMEDS_Tool::PutStreamToFiles( theStream, @@ -4020,8 +4065,8 @@ bool SMESH_Gen_i::Load( SALOMEDS::SComponent_ptr theComponent, if ( myImpl ) { // myImpl->LoadFrom( hypdata.c_str() ); hypDataList.push_back( make_pair( myImpl, hypdata )); - string iorString = GetORB()->object_to_string( myHyp ); - int newId = myStudyContext->findId( iorString ); + CORBA::String_var iorString = GetORB()->object_to_string( myHyp ); + int newId = myStudyContext->findId( iorString.in() ); myStudyContext->mapOldToNew( id, newId ); } else @@ -4120,8 +4165,8 @@ bool SMESH_Gen_i::Load( SALOMEDS::SComponent_ptr theComponent, if ( myImpl ) { //myImpl->LoadFrom( hypdata.c_str() ); hypDataList.push_back( make_pair( myImpl, hypdata )); - string iorString = GetORB()->object_to_string( myHyp ); - int newId = myStudyContext->findId( iorString ); + CORBA::String_var iorString = GetORB()->object_to_string( myHyp ); + int newId = myStudyContext->findId( iorString.in() ); myStudyContext->mapOldToNew( id, newId ); } else @@ -4161,8 +4206,8 @@ bool SMESH_Gen_i::Load( SALOMEDS::SComponent_ptr theComponent, continue; meshGroupList.push_back( make_pair( myNewMeshImpl, aTopGroup )); - string iorString = GetORB()->object_to_string( myNewMesh ); - int newId = myStudyContext->findId( iorString ); + CORBA::String_var iorString = GetORB()->object_to_string( myNewMesh ); + int newId = myStudyContext->findId( iorString.in() ); myStudyContext->mapOldToNew( id, newId ); // ouv : NPAL12872 @@ -4178,6 +4223,7 @@ bool SMESH_Gen_i::Load( SALOMEDS::SComponent_ptr theComponent, aDataset->ReadFromDisk( anAutoColor ); aDataset->CloseOnDisk(); myNewMeshImpl->GetImpl().SetAutoColor( (bool)anAutoColor[0] ); + delete [] anAutoColor; } // try to read and set reference to shape @@ -4191,7 +4237,7 @@ bool SMESH_Gen_i::Load( SALOMEDS::SComponent_ptr theComponent, aDataset->ReadFromDisk( refFromFile ); aDataset->CloseOnDisk(); if ( strlen( refFromFile ) > 0 ) { - SALOMEDS::SObject_var shapeSO = myCurrentStudy->FindObjectID( refFromFile ); + SALOMEDS::SObject_wrap shapeSO = myCurrentStudy->FindObjectID( refFromFile ); // Make sure GEOM data are loaded first //loadGeomData( shapeSO->GetFatherComponent() ); @@ -4203,6 +4249,7 @@ bool SMESH_Gen_i::Load( SALOMEDS::SComponent_ptr theComponent, myNewMeshImpl->SetShape( aShapeObject ); } } + delete [] refFromFile; } // issue 20918. Restore Persistent Id of SMESHDS_Mesh @@ -4215,6 +4262,7 @@ bool SMESH_Gen_i::Load( SALOMEDS::SComponent_ptr theComponent, aDataset->ReadFromDisk( meshPersistentId ); aDataset->CloseOnDisk(); myNewMeshImpl->GetImpl().GetMeshDS()->SetPersistentId( *meshPersistentId ); + delete [] meshPersistentId; } } } @@ -4245,8 +4293,8 @@ bool SMESH_Gen_i::Load( SALOMEDS::SComponent_ptr theComponent, bool hasData = false; // get mesh old id - string iorString = GetORB()->object_to_string( myNewMeshImpl->_this() ); - int newId = myStudyContext->findId( iorString ); + CORBA::String_var iorString = GetORB()->object_to_string( myNewMeshImpl->_this() ); + int newId = myStudyContext->findId( iorString.in() ); int id = myStudyContext->getOldId( newId ); // try to find mesh data dataset @@ -4265,6 +4313,7 @@ bool SMESH_Gen_i::Load( SALOMEDS::SComponent_ptr theComponent, // myReader.Perform(); hasData = true; } + delete [] strHasData; } // Try to get applied ALGORITHMS (mesh is not cleared by algo addition because @@ -4287,9 +4336,10 @@ bool SMESH_Gen_i::Load( SALOMEDS::SComponent_ptr theComponent, aDataset->ReadFromDisk( refFromFile ); aDataset->CloseOnDisk(); // san - it is impossible to recover applied algorithms using their entries within Load() method - //SALOMEDS::SObject_var hypSO = myCurrentStudy->FindObjectID( refFromFile ); + //SALOMEDS::SObject_wrap hypSO = myCurrentStudy->FindObjectID( refFromFile ); //CORBA::Object_var hypObject = SObjectToObject( hypSO ); int id = atoi( refFromFile ); + delete [] refFromFile; string anIOR = myStudyContext->getIORbyOldId( id ); if ( !anIOR.empty() ) { CORBA::Object_var hypObject = GetORB()->string_to_object( anIOR.c_str() ); @@ -4323,9 +4373,10 @@ bool SMESH_Gen_i::Load( SALOMEDS::SComponent_ptr theComponent, aDataset->ReadFromDisk( refFromFile ); aDataset->CloseOnDisk(); // san - it is impossible to recover applied hypotheses using their entries within Load() method - //SALOMEDS::SObject_var hypSO = myCurrentStudy->FindObjectID( refFromFile ); + //SALOMEDS::SObject_wrap hypSO = myCurrentStudy->FindObjectID( refFromFile ); //CORBA::Object_var hypObject = SObjectToObject( hypSO ); int id = atoi( refFromFile ); + delete [] refFromFile; string anIOR = myStudyContext->getIORbyOldId( id ); if ( !anIOR.empty() ) { CORBA::Object_var hypObject = GetORB()->string_to_object( anIOR.c_str() ); @@ -4393,7 +4444,7 @@ bool SMESH_Gen_i::Load( SALOMEDS::SComponent_ptr theComponent, aDataset->ReadFromDisk( refFromFile ); aDataset->CloseOnDisk(); if ( strlen( refFromFile ) > 0 ) { - SALOMEDS::SObject_var subShapeSO = myCurrentStudy->FindObjectID( refFromFile ); + SALOMEDS::SObject_wrap subShapeSO = myCurrentStudy->FindObjectID( refFromFile ); CORBA::Object_var subShapeObject = SObjectToObject( subShapeSO ); if ( !CORBA::is_nil( subShapeObject ) ) { aSubShapeObject = GEOM::GEOM_Object::_narrow( subShapeObject ); @@ -4543,7 +4594,7 @@ bool SMESH_Gen_i::Load( SALOMEDS::SComponent_ptr theComponent, aDataset->ReadFromDisk( refFromFile ); aDataset->CloseOnDisk(); if ( strlen( refFromFile ) > 0 ) { - SALOMEDS::SObject_var shapeSO = myCurrentStudy->FindObjectID( refFromFile ); + SALOMEDS::SObject_wrap shapeSO = myCurrentStudy->FindObjectID( refFromFile ); CORBA::Object_var shapeObject = SObjectToObject( shapeSO ); if ( !CORBA::is_nil( shapeObject ) ) { aShapeObject = GEOM::GEOM_Object::_narrow( shapeObject ); @@ -4579,7 +4630,7 @@ bool SMESH_Gen_i::Load( SALOMEDS::SComponent_ptr theComponent, continue; string iorSubString = GetORB()->object_to_string( aNewGroup ); - int newSubId = myStudyContext->findId( iorSubString ); + int newSubId = myStudyContext->findId( iorSubString ); myStudyContext->mapOldToNew( subid, newSubId ); SMESH_GroupBase_i* aGroupImpl = SMESH::DownCast< SMESH_GroupBase_i*>( aNewGroup ); @@ -4770,24 +4821,6 @@ void SMESH_Gen_i::Close( SALOMEDS::SComponent_ptr theComponent ) myStudyContextMap.erase( studyId ); } - // delete SMESH_Mesh's -// See bug IPAL19437. -// -// StudyContextStruct* context = myGen.GetStudyContext( studyId ); -// map< int, SMESH_Mesh* >::iterator i_mesh = context->mapMesh.begin(); -// for ( ; i_mesh != context->mapMesh.end(); ++i_mesh ) { -// printf( "--------------------------- SMESH_Gen_i::Close, delete aGroup = %p \n", i_mesh->second ); -// delete i_mesh->second; -// } - - - // delete SMESHDS_Mesh's - // it's too long on big meshes -// if ( context->myDocument ) { -// delete context->myDocument; -// context->myDocument = 0; -// } - // remove the tmp files meshes are loaded from SMESH_PreMeshInfo::RemoveStudyFiles_TMP_METHOD( theComponent ); @@ -4906,7 +4939,7 @@ void SMESH_Gen_i::SetName(const char* theIOR, { if ( theIOR && strcmp( theIOR, "" ) ) { CORBA::Object_var anObject = GetORB()->string_to_object( theIOR ); - SALOMEDS::SObject_var aSO = ObjectToSObject( myCurrentStudy, anObject ); + SALOMEDS::SObject_wrap aSO = ObjectToSObject( myCurrentStudy, anObject ); if ( !aSO->_is_nil() ) { SetName( aSO, theName ); } diff --git a/src/SMESH_I/SMESH_Gen_i.hxx b/src/SMESH_I/SMESH_Gen_i.hxx index 746f73765..c78122345 100644 --- a/src/SMESH_I/SMESH_Gen_i.hxx +++ b/src/SMESH_I/SMESH_Gen_i.hxx @@ -36,13 +36,15 @@ #include CORBA_CLIENT_HEADER(SALOMEDS) #include CORBA_CLIENT_HEADER(SALOMEDS_Attributes) +#include "SMESH_Gen.hxx" #include "SMESH_Mesh_i.hxx" #include "SMESH_Hypothesis_i.hxx" -#include "SALOME_Component_i.hxx" -#include "SALOME_NamingService.hxx" -#include "SMESH_Gen.hxx" -#include "GEOM_Client.hxx" +#include +#include +#include + +#include #include #include @@ -146,7 +148,7 @@ public: // Get SALOME_LifeCycleCORBA object static SALOME_LifeCycleCORBA* GetLCC(); // Retrieve and get GEOM engine reference - static GEOM::GEOM_Gen_ptr GetGeomEngine(); + static GEOM::GEOM_Gen_var GetGeomEngine(); // Get object of the CORBA reference static PortableServer::ServantBase_var GetServant( CORBA::Object_ptr theObject ); // Get CORBA object corresponding to the SALOMEDS::SObject @@ -630,6 +632,15 @@ namespace SMESH { return dynamic_cast(SMESH_Gen_i::GetServant(theArg).in()); } + + /*! + * \brief Function used in SMESH_CATCH to convert a caught exception to + * SALOME::SALOME_Exception + */ + inline void throwCorbaException(const char* excText) + { + THROW_SALOME_CORBA_EXCEPTION( excText, SALOME::INTERNAL_ERROR ); + } } diff --git a/src/SMESH_I/SMESH_Gen_i_1.cxx b/src/SMESH_I/SMESH_Gen_i_1.cxx index 1638083b5..b78d04a85 100644 --- a/src/SMESH_I/SMESH_Gen_i_1.cxx +++ b/src/SMESH_I/SMESH_Gen_i_1.cxx @@ -26,16 +26,19 @@ #include "SMESH_Gen_i.hxx" -#include "SMESH_Mesh_i.hxx" -#include "SMESH_Hypothesis_i.hxx" #include "SMESH_Algo_i.hxx" +#include "SMESH_Comment.hxx" #include "SMESH_Group_i.hxx" +#include "SMESH_Hypothesis_i.hxx" +#include "SMESH_Mesh_i.hxx" #include "SMESH_subMesh_i.hxx" #include CORBA_CLIENT_HEADER(SALOME_ModuleCatalog) -#include "utilities.h" -#include "Utils_ExceptHandlers.hxx" +#include +#include +#include +#include #include #include @@ -182,13 +185,13 @@ bool SMESH_Gen_i::CanPublishInStudy(CORBA::Object_ptr theIOR) //======================================================================= //function : ObjectToSObject -//purpose : +//purpose : Put a result into a SALOMEDS::SObject_wrap or call UnRegister()! //======================================================================= SALOMEDS::SObject_ptr SMESH_Gen_i::ObjectToSObject(SALOMEDS::Study_ptr theStudy, CORBA::Object_ptr theObject) { - SALOMEDS::SObject_var aSO; + SALOMEDS::SObject_wrap aSO; if ( !CORBA::is_nil( theStudy ) && !CORBA::is_nil( theObject )) { CORBA::String_var objStr = SMESH_Gen_i::GetORB()->object_to_string( theObject ); @@ -256,30 +259,33 @@ static SALOMEDS::SObject_ptr publish(SALOMEDS::Study_ptr theStudy, const char* thePixMap = 0, const bool theSelectable = true) { - SALOMEDS::SObject_var SO = SMESH_Gen_i::ObjectToSObject( theStudy, theIOR ); + SALOMEDS::SObject_wrap SO = SMESH_Gen_i::ObjectToSObject( theStudy, theIOR ); SALOMEDS::StudyBuilder_var aStudyBuilder = theStudy->NewBuilder(); if ( SO->_is_nil() ) { if ( theTag == 0 ) SO = aStudyBuilder->NewObject( theFatherObject ); - else if ( !theFatherObject->FindSubObject( theTag, SO )) + else if ( !theFatherObject->FindSubObject( theTag, SO.inout() )) SO = aStudyBuilder->NewObjectToTag( theFatherObject, theTag ); } - SALOMEDS::GenericAttribute_var anAttr; + SALOMEDS::GenericAttribute_wrap anAttr; if ( !CORBA::is_nil( theIOR )) { anAttr = aStudyBuilder->FindOrCreateAttribute( SO, "AttributeIOR" ); CORBA::String_var objStr = SMESH_Gen_i::GetORB()->object_to_string( theIOR ); - SALOMEDS::AttributeIOR::_narrow(anAttr)->SetValue( objStr.in() ); + SALOMEDS::AttributeIOR_wrap iorAttr = anAttr; + iorAttr->SetValue( objStr.in() ); } if ( thePixMap ) { anAttr = aStudyBuilder->FindOrCreateAttribute( SO, "AttributePixMap" ); - SALOMEDS::AttributePixMap_var pm = SALOMEDS::AttributePixMap::_narrow( anAttr ); + SALOMEDS::AttributePixMap_wrap pm = anAttr; pm->SetPixMap( thePixMap ); } if ( !theSelectable ) { - anAttr = aStudyBuilder->FindOrCreateAttribute( SO, "AttributeSelectable" ); - SALOMEDS::AttributeSelectable::_narrow( anAttr )->SetSelectable( false ); + anAttr = aStudyBuilder->FindOrCreateAttribute( SO, "AttributeSelectable" ); + SALOMEDS::AttributeSelectable_wrap selAttr = anAttr; + selAttr->SetSelectable( false ); } + return SO._retn(); } @@ -293,18 +299,18 @@ void SMESH_Gen_i::SetName(SALOMEDS::SObject_ptr theSObject, const char* theDefaultName) { if ( !theSObject->_is_nil() ) { - SALOMEDS::StudyBuilder_var aStudyBuilder = theSObject->GetStudy()->NewBuilder(); - SALOMEDS::GenericAttribute_var anAttr = + SALOMEDS::Study_var aStudy = theSObject->GetStudy(); + SALOMEDS::StudyBuilder_var aStudyBuilder = aStudy->NewBuilder(); + SALOMEDS::GenericAttribute_wrap anAttr = aStudyBuilder->FindOrCreateAttribute( theSObject, "AttributeName" ); - SALOMEDS::AttributeName_var aNameAttr = SALOMEDS::AttributeName::_narrow( anAttr ); + SALOMEDS::AttributeName_wrap aNameAttr = anAttr; if ( theName && strlen( theName ) != 0 ) aNameAttr->SetValue( theName ); else { - CORBA::String_var curName = CORBA::string_dup( aNameAttr->Value() ); - if ( strlen( curName ) == 0 ) { - TCollection_AsciiString aName( (char*) theDefaultName ); - aName += TCollection_AsciiString("_") + TCollection_AsciiString( theSObject->Tag() ); - aNameAttr->SetValue( aName.ToCString() ); + CORBA::String_var curName = aNameAttr->Value(); + if ( strlen( curName.in() ) == 0 ) { + SMESH_Comment aName(theDefaultName); + aNameAttr->SetValue( ( aName<< "_" << theSObject->Tag()).c_str() ); } } } @@ -320,11 +326,11 @@ void SMESH_Gen_i::SetPixMap(SALOMEDS::SObject_ptr theSObject, { if ( !theSObject->_is_nil() && thePixMap && strlen( thePixMap )) { - SALOMEDS::Study_var aStudy = theSObject->GetStudy(); + SALOMEDS::Study_var aStudy = theSObject->GetStudy(); SALOMEDS::StudyBuilder_var aStudyBuilder = aStudy->NewBuilder(); - SALOMEDS::GenericAttribute_var anAttr = + SALOMEDS::GenericAttribute_wrap anAttr = aStudyBuilder->FindOrCreateAttribute( theSObject, "AttributePixMap" ); - SALOMEDS::AttributePixMap_var aPMAttr = SALOMEDS::AttributePixMap::_narrow( anAttr ); + SALOMEDS::AttributePixMap_wrap aPMAttr = anAttr; aPMAttr->SetPixMap( thePixMap ); } } @@ -339,24 +345,27 @@ static void addReference (SALOMEDS::Study_ptr theStudy, CORBA::Object_ptr theToObject, int theTag = 0) { - SALOMEDS::SObject_var aToObjSO = SMESH_Gen_i::ObjectToSObject( theStudy, theToObject ); + SALOMEDS::SObject_wrap aToObjSO = SMESH_Gen_i::ObjectToSObject( theStudy, theToObject ); if ( !aToObjSO->_is_nil() && !theSObject->_is_nil() ) { SALOMEDS::StudyBuilder_var aStudyBuilder = theStudy->NewBuilder(); - SALOMEDS::SObject_var aReferenceSO; + SALOMEDS::SObject_wrap aReferenceSO; if ( !theTag ) { // check if the reference to theToObject already exists // and find a free label for the reference object bool isReferred = false; int tag = 1; - SALOMEDS::ChildIterator_var anIter = theStudy->NewChildIterator( theSObject ); + SALOMEDS::ChildIterator_wrap anIter = theStudy->NewChildIterator( theSObject ); for ( ; !isReferred && anIter->More(); anIter->Next(), ++tag ) { - if ( anIter->Value()->ReferencedObject( aReferenceSO )) { - if ( strcmp( aReferenceSO->GetID(), aToObjSO->GetID() ) == 0 ) + SALOMEDS::SObject_wrap curSO = anIter->Value(); + if ( curSO->ReferencedObject( aReferenceSO.inout() )) { + CORBA::String_var refEntry = aReferenceSO->GetID(); + CORBA::String_var toEntry = aToObjSO->GetID(); + if ( strcmp( refEntry, toEntry ) == 0 ) isReferred = true; } else if ( !theTag ) { - SALOMEDS::GenericAttribute_var anAttr; - if ( !anIter->Value()->FindAttribute( anAttr, "AttributeIOR" )) + SALOMEDS::GenericAttribute_wrap anAttr; + if ( !curSO->FindAttribute( anAttr.inout(), "AttributeIOR" )) theTag = tag; } } @@ -365,7 +374,7 @@ static void addReference (SALOMEDS::Study_ptr theStudy, if ( !theTag ) theTag = tag; } - if ( !theSObject->FindSubObject( theTag, aReferenceSO )) + if ( !theSObject->FindSubObject( theTag, aReferenceSO.inout() )) aReferenceSO = aStudyBuilder->NewObjectToTag( theSObject, theTag ); aStudyBuilder->Addreference( aReferenceSO, aToObjSO ); } @@ -386,7 +395,7 @@ SALOMEDS::SObject_ptr SMESH_Gen_i::PublishInStudy(SALOMEDS::Study_ptr theStudy throw (SALOME::SALOME_Exception) { Unexpect aCatch(SALOME_SalomeException); - SALOMEDS::SObject_var aSO; + SALOMEDS::SObject_wrap aSO; if ( CORBA::is_nil( theStudy ) || CORBA::is_nil( theIOR )) return aSO._retn(); if(MYDEBUG) MESSAGE("PublishInStudy"); @@ -432,8 +441,8 @@ SALOMEDS::SComponent_ptr SMESH_Gen_i::PublishComponent(SALOMEDS::Study_ptr theSt return SALOMEDS::SComponent::_nil(); if(MYDEBUG) MESSAGE("PublishComponent"); - SALOMEDS::SComponent_var father = - SALOMEDS::SComponent::_narrow( theStudy->FindComponent( ComponentDataType() ) ); + CORBA::String_var compDataType = ComponentDataType(); + SALOMEDS::SComponent_wrap father = theStudy->FindComponent( compDataType.in() ); if ( !CORBA::is_nil( father ) ) return father._retn(); @@ -442,20 +451,21 @@ SALOMEDS::SComponent_ptr SMESH_Gen_i::PublishComponent(SALOMEDS::Study_ptr theSt if ( CORBA::is_nil( aCat ) ) return father._retn(); - SALOME_ModuleCatalog::Acomponent_var aComp = aCat->GetComponent( ComponentDataType() ); + SALOME_ModuleCatalog::Acomponent_var aComp = aCat->GetComponent( compDataType.in() ); if ( CORBA::is_nil( aComp ) ) return father._retn(); - SALOMEDS::StudyBuilder_var aStudyBuilder = theStudy->NewBuilder(); - SALOMEDS::GenericAttribute_var anAttr; - SALOMEDS::AttributePixMap_var aPixmap; + SALOMEDS::StudyBuilder_var aStudyBuilder = theStudy->NewBuilder(); + SALOMEDS::GenericAttribute_wrap anAttr; + SALOMEDS::AttributePixMap_wrap aPixmap; - father = aStudyBuilder->NewComponent( ComponentDataType() ); + father = aStudyBuilder->NewComponent( compDataType.in() ); aStudyBuilder->DefineComponentInstance( father, SMESH_Gen::_this() ); anAttr = aStudyBuilder->FindOrCreateAttribute( father, "AttributePixMap" ); - aPixmap = SALOMEDS::AttributePixMap::_narrow( anAttr ); - aPixmap ->SetPixMap( "ICON_OBJBROWSER_SMESH" ); - SetName( father, aComp->componentusername(), "MESH" ); + aPixmap = anAttr; + aPixmap->SetPixMap( "ICON_OBJBROWSER_SMESH" ); + CORBA::String_var userName = aComp->componentusername(); + SetName( father, userName.in(), "MESH" ); if(MYDEBUG) MESSAGE("PublishComponent--END"); return father._retn(); @@ -475,9 +485,10 @@ static long findMaxChildTag( SALOMEDS::SObject_ptr theSObject ) if ( !theSObject->_is_nil() ) { SALOMEDS::Study_var aStudy = theSObject->GetStudy(); if ( !aStudy->_is_nil() ) { - SALOMEDS::ChildIterator_var anIter = aStudy->NewChildIterator( theSObject ); + SALOMEDS::ChildIterator_wrap anIter = aStudy->NewChildIterator( theSObject ); for ( ; anIter->More(); anIter->Next() ) { - long nTag = anIter->Value()->Tag(); + SALOMEDS::SObject_wrap anSO = anIter->Value(); + long nTag = anSO->Tag(); if ( nTag > aTag ) aTag = nTag; } @@ -502,10 +513,10 @@ SALOMEDS::SObject_ptr SMESH_Gen_i::PublishMesh (SALOMEDS::Study_ptr theStudy, // find or publish a mesh - SALOMEDS::SObject_var aMeshSO = ObjectToSObject( theStudy, theMesh ); + SALOMEDS::SObject_wrap aMeshSO = ObjectToSObject( theStudy, theMesh ); if ( aMeshSO->_is_nil() ) { - SALOMEDS::SComponent_var father = PublishComponent( theStudy ); + SALOMEDS::SComponent_wrap father = PublishComponent( theStudy ); if ( father->_is_nil() ) return aMeshSO._retn(); @@ -531,9 +542,10 @@ SALOMEDS::SObject_ptr SMESH_Gen_i::PublishMesh (SALOMEDS::Study_ptr theStudy, // Publish global hypotheses SMESH::ListOfHypothesis_var hypList = theMesh->GetHypothesisList( aShapeObject ); - for ( int i = 0; i < hypList->length(); i++ ) { + for ( int i = 0; i < hypList->length(); i++ ) + { SMESH::SMESH_Hypothesis_var aHyp = SMESH::SMESH_Hypothesis::_narrow( hypList[ i ]); - PublishHypothesis( theStudy, aHyp ); + SALOMEDS::SObject_wrap so = PublishHypothesis( theStudy, aHyp ); AddHypothesisToShape( theStudy, theMesh, aShapeObject, aHyp ); } } @@ -549,7 +561,7 @@ SALOMEDS::SObject_ptr SMESH_Gen_i::PublishMesh (SALOMEDS::Study_ptr theStudy, SMESH::SMESH_subMesh_ptr aSubMesh = (*subIt).second->_this(); if ( !CORBA::is_nil( aSubMesh )) { aShapeObject = aSubMesh->GetSubShape(); - PublishSubMesh( theStudy, theMesh, aSubMesh, aShapeObject ); + SALOMEDS::SObject_wrap( PublishSubMesh( theStudy, theMesh, aSubMesh, aShapeObject )); } } @@ -560,12 +572,11 @@ SALOMEDS::SObject_ptr SMESH_Gen_i::PublishMesh (SALOMEDS::Study_ptr theStudy, { SMESH::SMESH_GroupBase_ptr aGroup = (*it).second; if ( !aGroup->_is_nil() ) { - GEOM::GEOM_Object_var aShapeObj; - SMESH::SMESH_GroupOnGeom_var aGeomGroup = - SMESH::SMESH_GroupOnGeom::_narrow( aGroup ); + GEOM::GEOM_Object_var aShapeObj; + SMESH::SMESH_GroupOnGeom_var aGeomGroup = SMESH::SMESH_GroupOnGeom::_narrow( aGroup ); if ( !aGeomGroup->_is_nil() ) aShapeObj = aGeomGroup->GetShape(); - PublishGroup( theStudy, theMesh, aGroup, aShapeObj ); + SALOMEDS::SObject_wrap( PublishGroup( theStudy, theMesh, aGroup, aShapeObj )); } } @@ -588,10 +599,10 @@ SALOMEDS::SObject_ptr SMESH_Gen_i::PublishSubMesh (SALOMEDS::Study_ptr theS theSubMesh->_is_nil() || theShapeObject->_is_nil() ) return SALOMEDS::SObject::_nil(); - SALOMEDS::SObject_var aSubMeshSO = ObjectToSObject( theStudy, theSubMesh ); + SALOMEDS::SObject_wrap aSubMeshSO = ObjectToSObject( theStudy, theSubMesh ); if ( aSubMeshSO->_is_nil() ) { - SALOMEDS::SObject_var aMeshSO = ObjectToSObject( theStudy, theMesh ); + SALOMEDS::SObject_wrap aMeshSO = ObjectToSObject( theStudy, theMesh ); if ( aMeshSO->_is_nil() ) { aMeshSO = PublishMesh( theStudy, theMesh ); if ( aMeshSO->_is_nil()) @@ -632,8 +643,11 @@ SALOMEDS::SObject_ptr SMESH_Gen_i::PublishSubMesh (SALOMEDS::Study_ptr theS } // Find or create submesh root - SALOMEDS::SObject_var aRootSO = publish (theStudy, CORBA::Object::_nil(), + SALOMEDS::SObject_wrap aRootSO = publish (theStudy, CORBA::Object::_nil(), aMeshSO, aRootTag, 0, false ); + if ( aRootSO->_is_nil() ) + return aSubMeshSO._retn(); + SetName( aRootSO, aRootName ); // Add new submesh to corresponding sub-tree @@ -652,13 +666,12 @@ SALOMEDS::SObject_ptr SMESH_Gen_i::PublishSubMesh (SALOMEDS::Study_ptr theS // Publish hypothesis - SMESH::ListOfHypothesis * hypList = theMesh->GetHypothesisList( theShapeObject ); - if ( hypList ) - for ( int i = 0; i < hypList->length(); i++ ) { - SMESH::SMESH_Hypothesis_var aHyp = SMESH::SMESH_Hypothesis::_narrow( (*hypList)[ i ]); - PublishHypothesis( theStudy, aHyp ); - AddHypothesisToShape( theStudy, theMesh, theShapeObject, aHyp ); - } + SMESH::ListOfHypothesis_var hypList = theMesh->GetHypothesisList( theShapeObject ); + for ( int i = 0; i < hypList->length(); i++ ) { + SMESH::SMESH_Hypothesis_var aHyp = SMESH::SMESH_Hypothesis::_narrow( hypList[ i ]); + SALOMEDS::SObject_wrap so = PublishHypothesis( theStudy, aHyp ); + AddHypothesisToShape( theStudy, theMesh, theShapeObject, aHyp ); + } return aSubMeshSO._retn(); } @@ -677,10 +690,10 @@ SALOMEDS::SObject_ptr SMESH_Gen_i::PublishGroup (SALOMEDS::Study_ptr theStudy if (theStudy->_is_nil() || theMesh->_is_nil() || theGroup->_is_nil() ) return SALOMEDS::SObject::_nil(); - SALOMEDS::SObject_var aGroupSO = ObjectToSObject( theStudy, theGroup ); + SALOMEDS::SObject_wrap aGroupSO = ObjectToSObject( theStudy, theGroup ); if ( aGroupSO->_is_nil() ) { - SALOMEDS::SObject_var aMeshSO = ObjectToSObject( theStudy, theMesh ); + SALOMEDS::SObject_wrap aMeshSO = ObjectToSObject( theStudy, theMesh ); if ( aMeshSO->_is_nil() ) { aMeshSO = PublishInStudy( theStudy, SALOMEDS::SObject::_nil(), theMesh, ""); if ( aMeshSO->_is_nil()) @@ -698,8 +711,10 @@ SALOMEDS::SObject_ptr SMESH_Gen_i::PublishGroup (SALOMEDS::Study_ptr theStudy long aRootTag = GetNodeGroupsTag() + aType - 1; // Find or create groups root - SALOMEDS::SObject_var aRootSO = publish (theStudy, CORBA::Object::_nil(), + SALOMEDS::SObject_wrap aRootSO = publish (theStudy, CORBA::Object::_nil(), aMeshSO, aRootTag, 0, false ); + if ( aRootSO->_is_nil() ) return SALOMEDS::SObject::_nil(); + if ( aType < sizeof(aRootNames)/sizeof(char*) ) SetName( aRootSO, aRootNames[aType] ); @@ -746,35 +761,34 @@ SALOMEDS::SObject_ptr if (theStudy->_is_nil() || theHyp->_is_nil()) return SALOMEDS::SObject::_nil(); - SALOMEDS::SObject_var aHypSO = ObjectToSObject( theStudy, theHyp ); + CORBA::String_var hypType = theHyp->GetName(); + + SALOMEDS::SObject_wrap aHypSO = ObjectToSObject( theStudy, theHyp ); if ( aHypSO->_is_nil() ) { - SALOMEDS::SComponent_var father = PublishComponent( theStudy ); + SALOMEDS::SComponent_wrap father = PublishComponent( theStudy ); if ( father->_is_nil() ) return aHypSO._retn(); //Find or Create Hypothesis root bool isAlgo = ( !SMESH::SMESH_Algo::_narrow( theHyp )->_is_nil() ); int aRootTag = isAlgo ? GetAlgorithmsRootTag() : GetHypothesisRootTag(); - SALOMEDS::SObject_var aRootSO = + SALOMEDS::SObject_wrap aRootSO = publish (theStudy, CORBA::Object::_nil(),father, aRootTag, isAlgo ? "ICON_SMESH_TREE_ALGO" : "ICON_SMESH_TREE_HYPO", false); SetName( aRootSO, isAlgo ? "Algorithms" : "Hypotheses" ); // Add New Hypothesis string aPmName = isAlgo ? "ICON_SMESH_TREE_ALGO_" : "ICON_SMESH_TREE_HYPO_"; - aPmName += theHyp->GetName(); + aPmName += hypType.in(); // prepend plugin name to pixmap name - string pluginName = myHypCreatorMap[string(theHyp->GetName())]->GetModuleName(); + string pluginName = myHypCreatorMap[ hypType.in() ]->GetModuleName(); if ( pluginName != "StdMeshers" ) aPmName = pluginName + "::" + aPmName; aHypSO = publish( theStudy, theHyp, aRootSO, 0, aPmName.c_str() ); } - if ( !aHypSO->_is_nil() ) { - CORBA::String_var aHypName = CORBA::string_dup( theHyp->GetName() ); - SetName( aHypSO, theName, aHypName ); - } + SetName( aHypSO, theName, hypType.in() ); if(MYDEBUG) MESSAGE("PublishHypothesis--END") return aHypSO._retn(); @@ -791,7 +805,7 @@ SALOMEDS::SObject_ptr GEOM::GEOM_Object_ptr theShape) { if(MYDEBUG) MESSAGE("GetMeshOrSubmeshByShape") - SALOMEDS::SObject_var aMeshOrSubMesh; + SALOMEDS::SObject_wrap aMeshOrSubMesh; if (theMesh->_is_nil() || ( theShape->_is_nil() && theMesh->HasShapeToMesh())) return aMeshOrSubMesh._retn(); @@ -834,15 +848,15 @@ bool SMESH_Gen_i::AddHypothesisToShape(SALOMEDS::Study_ptr theStudy, && theMesh->HasShapeToMesh()) ) return false; - SALOMEDS::SObject_var aMeshSO = ObjectToSObject( theStudy, theMesh ); + SALOMEDS::SObject_wrap aMeshSO = ObjectToSObject( theStudy, theMesh ); if ( aMeshSO->_is_nil() ) aMeshSO = PublishMesh( theStudy, theMesh ); - SALOMEDS::SObject_var aHypSO = PublishHypothesis( theStudy, theHyp ); + SALOMEDS::SObject_wrap aHypSO = PublishHypothesis( theStudy, theHyp ); if ( aMeshSO->_is_nil() || aHypSO->_is_nil()) return false; // Find a mesh or submesh refering to theShape - SALOMEDS::SObject_var aMeshOrSubMesh = + SALOMEDS::SObject_wrap aMeshOrSubMesh = GetMeshOrSubmeshByShape( theStudy, theMesh, theShape ); if ( aMeshOrSubMesh->_is_nil() ) { @@ -861,15 +875,14 @@ bool SMESH_Gen_i::AddHypothesisToShape(SALOMEDS::Study_ptr theStudy, //Find or Create Applied Hypothesis root bool aIsAlgo = !SMESH::SMESH_Algo::_narrow( theHyp )->_is_nil(); - SALOMEDS::SObject_var AHR = + SALOMEDS::SObject_wrap AHR = publish (theStudy, CORBA::Object::_nil(), aMeshOrSubMesh, aIsAlgo ? GetRefOnAppliedAlgorithmsTag() : GetRefOnAppliedHypothesisTag(), aIsAlgo ? "ICON_SMESH_TREE_ALGO" : "ICON_SMESH_TREE_HYPO", false); SetName( AHR, aIsAlgo ? "Applied algorithms" : "Applied hypotheses" ); - if ( AHR->_is_nil() ) - return false; addReference( theStudy, AHR, theHyp ); + if(MYDEBUG) MESSAGE("AddHypothesisToShape--END") return true; } @@ -889,27 +902,36 @@ bool SMESH_Gen_i::RemoveHypothesisFromShape(SALOMEDS::Study_ptr theStudy && theMesh->HasShapeToMesh())) return false; - SALOMEDS::SObject_var aHypSO = ObjectToSObject( theStudy, theHyp ); + SALOMEDS::SObject_wrap aHypSO = ObjectToSObject( theStudy, theHyp ); if ( aHypSO->_is_nil() ) return false; + CORBA::String_var hypEntry = aHypSO->GetID(); + // Find a mesh or submesh refering to theShape - SALOMEDS::SObject_var aMeshOrSubMesh = + SALOMEDS::SObject_wrap aMeshOrSubMesh = GetMeshOrSubmeshByShape( theStudy, theMesh, theShape ); if ( aMeshOrSubMesh->_is_nil() ) return false; // Find and remove a reference to aHypSO - SALOMEDS::SObject_var aRef, anObj; - CORBA::String_var anID = CORBA::string_dup( aHypSO->GetID() ); - SALOMEDS::ChildIterator_var it = theStudy->NewChildIterator( aMeshOrSubMesh ); - for ( it->InitEx( true ); it->More(); it->Next() ) { + SALOMEDS::SObject_wrap aRef, anObj; + SALOMEDS::ChildIterator_wrap it = theStudy->NewChildIterator( aMeshOrSubMesh ); + bool found = false; + for ( it->InitEx( true ); ( it->More() && !found ); it->Next() ) { anObj = it->Value(); - if (anObj->ReferencedObject( aRef ) && strcmp( aRef->GetID(), anID ) == 0 ) { - theStudy->NewBuilder()->RemoveObject( anObj ); - break; + if (anObj->ReferencedObject( aRef.inout() )) + { + CORBA::String_var refEntry = aRef->GetID(); + found = ( strcmp( refEntry, hypEntry ) == 0 ); + } + if ( found ) + { + SALOMEDS::StudyBuilder_var builder = theStudy->NewBuilder(); + builder->RemoveObject( anObj ); } } + return true; } @@ -919,7 +941,7 @@ bool SMESH_Gen_i::RemoveHypothesisFromShape(SALOMEDS::Study_ptr theStudy //======================================================================= void SMESH_Gen_i::UpdateParameters(/*CORBA::Object_ptr theObject,*/ const char* theParameters) { - SALOMEDS::Study_ptr aStudy = GetCurrentStudy(); + SALOMEDS::Study_var aStudy = GetCurrentStudy(); if ( aStudy->_is_nil() ) return; myLastParameters.clear(); @@ -950,11 +972,11 @@ void SMESH_Gen_i::UpdateParameters(/*CORBA::Object_ptr theObject,*/ const char* // if(VARIABLE_DEBUG) // cout<<"UpdateParameters : "<_is_nil() || CORBA::is_nil(theObject)) // return; - // SALOMEDS::SObject_var aSObj = ObjectToSObject(aStudy,theObject); + // SALOMEDS::SObject_wrap aSObj = ObjectToSObject(aStudy,theObject); // if(aSObj->_is_nil()) // return; @@ -1066,22 +1088,21 @@ char* SMESH_Gen_i::ParseParameters(const char* theParameters) //function : GetParameters //purpose : //======================================================================= + char* SMESH_Gen_i::GetParameters(CORBA::Object_ptr theObject) { - TCollection_AsciiString aResult; - - SALOMEDS::Study_ptr aStudy = GetCurrentStudy(); - SALOMEDS::SObject_var aSObj = ObjectToSObject(aStudy,theObject); - - if(!aStudy->_is_nil() && - !CORBA::is_nil(theObject) && - !aSObj->_is_nil()){ - - SALOMEDS::GenericAttribute_var anAttr; - if ( aSObj->FindAttribute(anAttr, "AttributeString")) { - aResult = TCollection_AsciiString(SALOMEDS::AttributeString::_narrow(anAttr)->Value()); + CORBA::String_var aResult(""); + + SALOMEDS::SObject_wrap aSObj = ObjectToSObject( myCurrentStudy,theObject); + if ( !aSObj->_is_nil() ) + { + SALOMEDS::GenericAttribute_wrap attr; + if ( aSObj->FindAttribute( attr.inout(), "AttributeString")) + { + SALOMEDS::AttributeString_wrap strAttr = attr; + aResult = strAttr->Value(); } } - - return CORBA::string_dup( aResult.ToCString() ); + + return CORBA::string_dup( aResult.in() ); } diff --git a/src/SMESH_I/SMESH_Group_i.cxx b/src/SMESH_I/SMESH_Group_i.cxx index 1b99653c6..535ebc176 100644 --- a/src/SMESH_I/SMESH_Group_i.cxx +++ b/src/SMESH_I/SMESH_Group_i.cxx @@ -156,11 +156,16 @@ void SMESH_GroupBase_i::SetName( const char* theName ) 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 << "' )"; + SMESH_Gen_i* aGen = myMeshServant->GetGen(); + SALOMEDS::Study_var aStudy = aGen->GetCurrentStudy(); + SALOMEDS::SObject_var anSO = aGen->ObjectToSObject( aStudy, _this() ); + if ( !anSO->_is_nil() ) + { + aGen->SetName( anSO, theName ); + + // Update Python script + TPythonDump() << _this() << ".SetName( '" << theName << "' )"; + } } //============================================================================= @@ -678,6 +683,7 @@ void SMESH_GroupBase_i::SetColorNumber(CORBA::Long color) * Inherited from SMESH_IDSource */ //============================================================================= + SMESH::long_array* SMESH_GroupBase_i::GetMeshInfo() { if ( myPreMeshInfo ) @@ -777,6 +783,7 @@ void SMESH_GroupOnFilter_i::SetFilter(SMESH::Filter_ptr theFilter) if ( myFilter ) { + myFilter->SetMesh( SMESH::SMESH_Mesh::_nil() ); // to UnRegister() the mesh myFilter->Register(); SMESH::DownCast< SMESH::Filter_i* >( myFilter )->AddWaiter( this ); } @@ -795,6 +802,67 @@ SMESH::Filter_ptr SMESH_GroupOnFilter_i::GetFilter() return f._retn(); } +//======================================================================= +//function : GetIDs +//purpose : Returns ids of members +//======================================================================= + +SMESH::long_array* SMESH_GroupOnFilter_i::GetListOfID() +{ + if ( myPreMeshInfo ) + myPreMeshInfo->FullLoadFromFile(); + + SMESH::long_array_var aRes = new SMESH::long_array(); + SMESHDS_GroupBase* aGroupDS = GetGroupDS(); + if ( SMESHDS_GroupOnFilter* grDS = dynamic_cast< SMESHDS_GroupOnFilter*>( GetGroupDS() )) + { + const SMDS_MeshInfo& meshInfo = aGroupDS->GetMesh()->GetMeshInfo(); + aRes->length( meshInfo.NbElements( aGroupDS->GetType() )); + if ( aRes->length() ) // else aRes[0] -> SIGSEGV + aRes->length( grDS->GetElementIds( &aRes[0] )); + + if ( 0 < aRes->length() && aRes->length() < 100 ) // for comfortable testing ;) + std::sort( &aRes[0], &aRes[0] + aRes->length() ); + } + MESSAGE("get list of IDs of a vague group"); + return aRes._retn(); +} + +//============================================================================= +/*! + * Returns statistic of mesh elements + * Result array of number enityties + * Inherited from SMESH_IDSource + */ +//============================================================================= + +SMESH::long_array* SMESH_GroupOnFilter_i::GetMeshInfo() +{ + if ( myPreMeshInfo ) + return myPreMeshInfo->GetMeshInfo(); + + SMESH::long_array_var aRes = new SMESH::long_array(); + aRes->length(SMESH::Entity_Last); + for (int i = SMESH::Entity_Node; i < SMESH::Entity_Last; i++) + aRes[i] = 0; + + if ( SMESHDS_GroupBase* g = GetGroupDS()) + { + if ( g->GetType() == SMDSAbs_Node || ( myNbNodes > -1 && g->GetTic() == myGroupDSTic)) + aRes[ SMDSEntity_Node ] = GetNumberOfNodes(); + + if ( g->GetType() != SMDSAbs_Node ) + { + vector< int > nbElems = static_cast< SMESHDS_GroupOnFilter* >( g )->GetMeshInfo(); + for ( size_t i = SMESH::Entity_Node; i < SMESH::Entity_Last; i++) + if ( i < nbElems.size() ) + aRes[i] = nbElems[ i ]; + } + } + + return aRes._retn(); +} + #define SEPAR '^' //================================================================================ diff --git a/src/SMESH_I/SMESH_Group_i.hxx b/src/SMESH_I/SMESH_Group_i.hxx index dcb441057..226319b62 100644 --- a/src/SMESH_I/SMESH_Group_i.hxx +++ b/src/SMESH_I/SMESH_Group_i.hxx @@ -110,14 +110,14 @@ protected: SMESH_PreMeshInfo* myPreMeshInfo; // mesh info before full loading from study file friend class SMESH_PreMeshInfo; + int myNbNodes, myGroupDSTic; + private: SMESH_Mesh_i* myMeshServant; int myLocalID; void changeLocalId(int localId) { myLocalID = localId; } friend class SMESH_Mesh_i; - - int myNbNodes, myGroupDSTic; }; // ====== @@ -183,6 +183,8 @@ class SMESH_I_EXPORT SMESH_GroupOnFilter_i: // CORBA interface implementation void SetFilter(SMESH::Filter_ptr theFilter); SMESH::Filter_ptr GetFilter(); + virtual SMESH::long_array* GetListOfID(); + virtual SMESH::long_array* GetMeshInfo(); // method of SMESH::Filter_i::TPredicateChangeWaiter virtual void PredicateChanged(); diff --git a/src/SMESH_I/SMESH_Hypothesis_i.cxx b/src/SMESH_I/SMESH_Hypothesis_i.cxx index f0fed2964..c6d837f49 100644 --- a/src/SMESH_I/SMESH_Hypothesis_i.cxx +++ b/src/SMESH_I/SMESH_Hypothesis_i.cxx @@ -25,11 +25,14 @@ // Author : Paul RASCLE, EDF // Module : SMESH // -#include -#include #include "SMESH_Hypothesis_i.hxx" #include "SMESH_Gen_i.hxx" -#include "utilities.h" + +#include +#include + +#include +#include using namespace std; @@ -42,7 +45,7 @@ using namespace std; //============================================================================= SMESH_Hypothesis_i::SMESH_Hypothesis_i( PortableServer::POA_ptr thePOA ) - : SALOME::GenericObj_i( thePOA ) + : SALOME::GenericObj_i( thePOA ) { MESSAGE( "SMESH_Hypothesis_i::SMESH_Hypothesis_i / Début" ); myBaseImpl = 0; @@ -127,12 +130,13 @@ CORBA::Long SMESH_Hypothesis_i::GetId() * */ //============================================================================= -bool SMESH_Hypothesis_i::IsPublished(){ +bool SMESH_Hypothesis_i::IsPublished() +{ bool res = false; - SMESH_Gen_i *gen = SMESH_Gen_i::GetSMESHGen(); - if(gen){ - SALOMEDS::SObject_var SO = - SMESH_Gen_i::ObjectToSObject(gen->GetCurrentStudy() , SMESH::SMESH_Hypothesis::_narrow(_this())); + if ( SMESH_Gen_i *gen = SMESH_Gen_i::GetSMESHGen()) + { + SALOMEDS::Study_var study = gen->GetCurrentStudy(); + SALOMEDS::SObject_wrap SO = SMESH_Gen_i::ObjectToSObject( study, _this()); res = !SO->_is_nil(); } return res; @@ -210,105 +214,6 @@ void SMESH_Hypothesis_i::setOldParameters (const char* theParameters) } } -//============================================================================= -/*! - * SMESH_Hypothesis_i::SetParameters() - * - */ -//============================================================================= -// void SMESH_Hypothesis_i::SetParameters(const char* theParameters) -// { -// SMESH_Gen_i *gen = SMESH_Gen_i::GetSMESHGen(); -// //char * aParameters = CORBA::string_dup(theParameters); -// if(gen){ -// gen->UpdateParameters(theParameters); -// // if(IsPublished()) { -// // SMESH_Gen_i::GetSMESHGen()->UpdateParameters(SMESH::SMESH_Hypothesis::_narrow(_this()),aParameters); -// // } -// // else { -// // myBaseImpl->SetParameters(gen->ParseParameters(aParameters)); -// // } -// } -// } - -// //============================================================================= -// /*! -// * SMESH_Hypothesis_i::GetParameters() -// * -// */ -// //============================================================================= -// char* SMESH_Hypothesis_i::GetParameters() -// { -// SMESH_Gen_i *gen = SMESH_Gen_i::GetSMESHGen(); -// char* aResult; -// if(IsPublished()) { -// MESSAGE("SMESH_Hypothesis_i::GetParameters() : Get Parameters from SObject"); -// aResult = gen->GetParameters(SMESH::SMESH_Hypothesis::_narrow(_this())); -// } -// else { -// MESSAGE("SMESH_Hypothesis_i::GetParameters() : Get local parameters"); -// aResult = myBaseImpl->GetParameters(); -// } -// return CORBA::string_dup(aResult); -// } - -// //============================================================================= -// /*! -// * SMESH_Hypothesis_i::GetLastParameters() -// * -// */ -// //============================================================================= -// SMESH::ListOfParameters* SMESH_Hypothesis_i::GetLastParameters() -// { -// SMESH::ListOfParameters_var aResult = new SMESH::ListOfParameters(); -// SMESH_Gen_i *gen = SMESH_Gen_i::GetSMESHGen(); -// if(gen) { -// char *aParameters; -// if(IsPublished()) -// aParameters = GetParameters(); -// else -// aParameters = myBaseImpl->GetLastParameters(); - -// SALOMEDS::Study_ptr aStudy = gen->GetCurrentStudy(); -// if(!aStudy->_is_nil()) { -// SALOMEDS::ListOfListOfStrings_var aSections = aStudy->ParseVariables(aParameters); -// if(aSections->length() > 0) { -// SALOMEDS::ListOfStrings aVars = aSections[aSections->length()-1]; -// aResult->length(aVars.length()); -// for(int i = 0;i < aVars.length();i++) -// aResult[i] = CORBA::string_dup( aVars[i]); -// } -// } -// } -// return aResult._retn(); -// } - -// //============================================================================= -// /*! -// * SMESH_Hypothesis_i::SetLastParameters() -// * -// */ -// //============================================================================= -// void SMESH_Hypothesis_i::SetLastParameters(const char* theParameters) -// { -// if(!IsPublished()) { -// myBaseImpl->SetLastParameters(theParameters); -// } -// } -// //============================================================================= -// /*! -// * SMESH_Hypothesis_i::ClearParameters() -// * -// */ -// //============================================================================= -// void SMESH_Hypothesis_i::ClearParameters() -// { -// myMethod2VarParams.clear(); -// // if(!IsPublished()) { -// // myBaseImpl->ClearParameters(); -// // } -// } - //============================================================================= /*! * SMESH_Hypothesis_i::GetImpl diff --git a/src/SMESH_I/SMESH_MEDMesh_i.cxx b/src/SMESH_I/SMESH_MEDMesh_i.cxx index 823c8a037..ffde0e00f 100644 --- a/src/SMESH_I/SMESH_MEDMesh_i.cxx +++ b/src/SMESH_I/SMESH_MEDMesh_i.cxx @@ -31,6 +31,9 @@ #include "SMESHDS_Mesh.hxx" #include "SMESHDS_SubMesh.hxx" +#include "SMESH_MEDSupport_i.hxx" +#include "SMESH_MEDFamily_i.hxx" + #include #include #include @@ -46,15 +49,13 @@ #include #include -#include "utilities.h" -#include "Utils_CorbaException.hxx" - -#include "SMESH_MEDSupport_i.hxx" -#include "SMESH_MEDFamily_i.hxx" +#include +#include -# include "Utils_ORB_INIT.hxx" -# include "Utils_SINGLETON.hxx" -# include "Utils_ExceptHandlers.hxx" +#include +#include +#include +#include extern "C" { @@ -119,11 +120,12 @@ char *SMESH_MEDMesh_i::getName() throw(SALOME::SALOME_Exception) { SMESH_Gen_i* gen = SMESH_Gen_i::GetSMESHGen(); SALOMEDS::Study_var study = gen->GetCurrentStudy(); - SALOMEDS::SObject_var meshSO = gen->ObjectToSObject( study, _mesh_i->_this()); + SALOMEDS::SObject_wrap meshSO = gen->ObjectToSObject( study, _mesh_i->_this()); if ( meshSO->_is_nil() ) return CORBA::string_dup("toto"); CORBA::String_var name = meshSO->GetName(); + return CORBA::string_dup( name.in() ); } catch(...) @@ -856,50 +858,8 @@ void SMESH_MEDMesh_i::addInStudy(SALOMEDS::Study_ptr myStudy, if (_meshId != "") { MESSAGE("Mesh already in Study"); - THROW_SALOME_CORBA_EXCEPTION("Mesh already in Study", - SALOME::BAD_PARAM); - }; - - /* - * SALOMEDS::StudyBuilder_var myBuilder = myStudy->NewBuilder(); - * - * // Create SComponent labelled 'MED' if it doesn't already exit - * SALOMEDS::SComponent_var medfather = myStudy->FindComponent("MED"); - * if ( CORBA::is_nil(medfather) ) - * { - * MESSAGE("Add Component MED"); - * medfather = myBuilder->NewComponent("MED"); - * //myBuilder->AddAttribute (medfather,SALOMEDS::Name,"MED"); - * SALOMEDS::AttributeName_var aName = SALOMEDS::AttributeName::_narrow( - * myBuilder->FindOrCreateAttribute(medfather, "AttributeName")); - * aName->SetValue("MED"); - * - * myBuilder->DefineComponentInstance(medfather,myIor); - * - * } ; - * - * MESSAGE("Add a mesh Object under MED"); - * myBuilder->NewCommand(); - * SALOMEDS::SObject_var newObj = myBuilder->NewObject(medfather); - * - * ORB_INIT &init = *SINGLETON_::Instance() ; - * ASSERT(SINGLETON_::IsAlreadyExisting()) ; - * CORBA::ORB_var &orb = init(0,0); - * CORBA::String_var iorStr = orb->object_to_string(myIor); - * //myBuilder->AddAttribute(newObj,SALOMEDS::IOR,iorStr.in()); - * SALOMEDS::AttributeIOR_var aIOR = SALOMEDS::AttributeIOR::_narrow( - * myBuilder->FindOrCreateAttribute(newObj, "AttributeIOR")); - * aIOR->SetValue(iorStr.c_str()); - * - * //myBuilder->AddAttribute(newObj,SALOMEDS::Name,_mesh_i->getName().c_str()); - * SALOMEDS::AttributeName_var aName = SALOMEDS::AttributeName::_narrow( - * myBuilder->FindOrCreateAttribute(newObj, "AttributeName")); - * aName->SetValue(_mesh_i->getName().c_str()); - * - * _meshId = newObj->GetID(); - * myBuilder->CommitCommand(); - * - */ + THROW_SALOME_CORBA_EXCEPTION("Mesh already in Study", SALOME::BAD_PARAM); + } END_OF("Mesh_i::addInStudy(SALOMEDS::Study_ptr myStudy)"); } diff --git a/src/SMESH_I/SMESH_MeshEditor_i.cxx b/src/SMESH_I/SMESH_MeshEditor_i.cxx index 0709265bf..87e886112 100644 --- a/src/SMESH_I/SMESH_MeshEditor_i.cxx +++ b/src/SMESH_I/SMESH_MeshEditor_i.cxx @@ -29,8 +29,6 @@ #include "SMESH_MeshEditor_i.hxx" -#include "DriverMED_R_SMESHDS_Mesh.h" -#include "DriverMED_W_SMESHDS_Mesh.h" #include "SMDS_EdgePosition.hxx" #include "SMDS_ElemIterator.hxx" #include "SMDS_FacePosition.hxx" @@ -41,34 +39,24 @@ #include "SMDS_MeshVolume.hxx" #include "SMDS_PolyhedralVolumeOfNodes.hxx" #include "SMDS_SetIterator.hxx" -#include "SMDS_SetIterator.hxx" #include "SMDS_VolumeTool.hxx" -#include "SMESHDS_Command.hxx" -#include "SMESHDS_CommandType.hxx" #include "SMESHDS_Group.hxx" #include "SMESHDS_GroupOnGeom.hxx" #include "SMESH_ControlsDef.hxx" #include "SMESH_Filter_i.hxx" -#include "SMESH_Filter_i.hxx" -#include "SMESH_Gen_i.hxx" #include "SMESH_Gen_i.hxx" #include "SMESH_Group.hxx" #include "SMESH_Group_i.hxx" -#include "SMESH_Group_i.hxx" -#include "SMESH_MEDMesh_i.hxx" -#include "SMESH_MeshEditor.hxx" #include "SMESH_MeshPartDS.hxx" #include "SMESH_MesherHelper.hxx" -#include "SMESH_PreMeshInfo.hxx" -#include "SMESH_PythonDump.hxx" #include "SMESH_PythonDump.hxx" #include "SMESH_subMeshEventListener.hxx" #include "SMESH_subMesh_i.hxx" -#include "SMESH_subMesh_i.hxx" -#include "utilities.h" -#include "Utils_ExceptHandlers.hxx" -#include "Utils_CorbaException.hxx" +#include +#include +#include +#include #include #include @@ -93,6 +81,8 @@ #include #include +#include "SMESH_TryCatch.hxx" // include after OCCT headers! + #define cast2Node(elem) static_cast( elem ) using namespace std; @@ -112,7 +102,7 @@ namespace MeshEditor_I { SMDSAbs_ElementType myPreviewType; // type to show //!< Constructor TPreviewMesh(SMDSAbs_ElementType previewElements = SMDSAbs_All) { - _isShapeToMesh = (_id =_studyId =_idDoc = 0); + _isShapeToMesh = (_id =_studyId = 0); _myMeshDS = new SMESHDS_Mesh( _id, true ); myPreviewType = previewElements; } @@ -543,9 +533,6 @@ SMESH::MeshPreviewStruct* SMESH_MeshEditor_i::GetPreviewData() else { aMeshDS = getEditor().GetMeshDS(); } - int nbEdges = aMeshDS->NbEdges(); - int nbFaces = aMeshDS->NbFaces(); - int nbVolum = aMeshDS->NbVolumes(); myPreviewData = new SMESH::MeshPreviewStruct(); myPreviewData->nodesXYZ.length(aMeshDS->NbNodes()); @@ -555,14 +542,15 @@ SMESH::MeshPreviewStruct* SMESH_MeshEditor_i::GetPreviewData() if (TPreviewMesh * aPreviewMesh = dynamic_cast< TPreviewMesh* >( getEditor().GetMesh() )) { previewType = aPreviewMesh->myPreviewType; switch ( previewType ) { - case SMDSAbs_Edge : nbFaces = nbVolum = 0; break; - case SMDSAbs_Face : nbEdges = nbVolum = 0; break; - case SMDSAbs_Volume: nbEdges = nbFaces = 0; break; + case SMDSAbs_Edge : break; + case SMDSAbs_Face : break; + case SMDSAbs_Volume: break; default:; + if ( aMeshDS->GetMeshInfo().NbElements() == 0 ) previewType = SMDSAbs_Node; } } - myPreviewData->elementTypes.length(nbEdges + nbFaces + nbVolum); + myPreviewData->elementTypes.length( aMeshDS->GetMeshInfo().NbElements( previewType )); int i = 0, j = 0; SMDS_ElemIteratorPtr itMeshElems = aMeshDS->elementsIterator(previewType); @@ -709,6 +697,11 @@ SMESH::SMESH_IDSource_ptr SMESH_MeshEditor_i::MakeIDSource(const SMESH::long_arr return anIDSourceVar._retn(); } +bool SMESH_MeshEditor_i::IsTemporaryIDSource( SMESH::SMESH_IDSource_ptr& idSource ) +{ + return SMESH::DownCast( idSource ); +} + void SMESH_MeshEditor_i::deleteAuxIDSources() { std::list< _IDSource* >::iterator idSrcIt = myAuxIDSources.begin(); @@ -863,6 +856,8 @@ CORBA::Long SMESH_MeshEditor_i::AddBall(CORBA::Long IDOfNode, CORBA::Double diam if ( diameter < std::numeric_limits::min() ) THROW_SALOME_CORBA_EXCEPTION("Invalid diameter", SALOME::BAD_PARAM); + SMESH_TRY; + const SMDS_MeshNode* aNode = getMeshDS()->FindNode(IDOfNode); SMDS_MeshElement* elem = getMeshDS()->AddBall(aNode, diameter); @@ -876,6 +871,8 @@ CORBA::Long SMESH_MeshEditor_i::AddBall(CORBA::Long IDOfNode, CORBA::Double diam if (elem) return elem->GetID(); + SMESH_CATCH( SMESH::throwCorbaException ); + return 0; } @@ -1144,6 +1141,8 @@ SMESH_MeshEditor_i::Create0DElementsOnAllNodes(SMESH::SMESH_IDSource_ptr theObje SMESH::SMESH_IDSource_var result; TPythonDump pyDump; + SMESH_TRY; + TIDSortedElemSet elements, elems0D; if ( idSourceToSet( theObject, getMeshDS(), elements, SMDSAbs_All, /*emptyIfIsMesh=*/1)) getEditor().Create0DElementsOnAllNodes( elements, elems0D ); @@ -1190,6 +1189,8 @@ SMESH_MeshEditor_i::Create0DElementsOnAllNodes(SMESH::SMESH_IDSource_ptr theObje pyDump << " = " << this << ".Create0DElementsOnAllNodes( " << theObject << ", '" << theGroupName << "' )"; + SMESH_CATCH( SMESH::throwCorbaException ); + return result._retn(); } @@ -5281,10 +5282,10 @@ void SMESH_MeshEditor_i::ConvertFromQuadraticObject(SMESH::SMESH_IDSource_ptr th SMESH::SMESH_Mesh_ptr SMESH_MeshEditor_i::makeMesh(const char* theMeshName) { - SMESH_Gen_i* gen = SMESH_Gen_i::GetSMESHGen(); - SMESH::SMESH_Mesh_var mesh = gen->CreateEmptyMesh(); - SALOMEDS::Study_var study = gen->GetCurrentStudy(); - SALOMEDS::SObject_var meshSO = gen->ObjectToSObject( study, mesh ); + SMESH_Gen_i* gen = SMESH_Gen_i::GetSMESHGen(); + SMESH::SMESH_Mesh_var mesh = gen->CreateEmptyMesh(); + SALOMEDS::Study_var study = gen->GetCurrentStudy(); + SALOMEDS::SObject_wrap meshSO = gen->ObjectToSObject( study, mesh ); gen->SetName( meshSO, theMeshName, "Mesh" ); gen->SetPixMap( meshSO, "ICON_SMESH_TREE_MESH_IMPORTED"); @@ -6199,8 +6200,10 @@ CORBA::Boolean SMESH_MeshEditor_i::DoubleNodesOnGroupBoundaries( const SMESH::Li CORBA::Boolean createJointElems ) throw (SALOME::SALOME_Exception) { - initData(); + bool aResult = false; + SMESH_TRY; + initData(); SMESHDS_Mesh* aMeshDS = getMeshDS(); @@ -6222,7 +6225,7 @@ CORBA::Boolean SMESH_MeshEditor_i::DoubleNodesOnGroupBoundaries( const SMESH::Li } } - bool aResult = getEditor().DoubleNodesOnGroupBoundaries( domains, createJointElems ); + aResult = getEditor().DoubleNodesOnGroupBoundaries( domains, createJointElems ); // TODO publish the groups of flat elements in study myMesh->GetMeshDS()->Modified(); @@ -6230,6 +6233,9 @@ CORBA::Boolean SMESH_MeshEditor_i::DoubleNodesOnGroupBoundaries( const SMESH::Li // Update Python script TPythonDump() << "isDone = " << this << ".DoubleNodesOnGroupBoundaries( " << &theDomains << ", " << createJointElems << " )"; + + SMESH_CATCH( SMESH::throwCorbaException ); + return aResult; } @@ -6289,8 +6295,10 @@ void SMESH_MeshEditor_i::CreateHoleSkin(CORBA::Double radius, const char* groupName, const SMESH::double_array& theNodesCoords, SMESH::array_of_long_array_out GroupsOfNodes) -throw (SALOME::SALOME_Exception) + throw (SALOME::SALOME_Exception) { + SMESH_TRY; + initData(); std::vector > aListOfListOfNodes; ::SMESH_MeshEditor aMeshEditor( myMesh ); @@ -6301,27 +6309,33 @@ throw (SALOME::SALOME_Exception) vector nodesCoords; for (int i = 0; i < theNodesCoords.length(); i++) - { - nodesCoords.push_back( theNodesCoords[i] ); + { + nodesCoords.push_back( theNodesCoords[i] ); } TopoDS_Shape aShape = SMESH_Gen_i::GetSMESHGen()->GeomObjectToShape( theShape ); - aMeshEditor.CreateHoleSkin(radius, aShape, theNodeSearcher, groupName, nodesCoords, aListOfListOfNodes); + aMeshEditor.CreateHoleSkin(radius, aShape, theNodeSearcher, groupName, + nodesCoords, aListOfListOfNodes); GroupsOfNodes = new SMESH::array_of_long_array; GroupsOfNodes->length( aListOfListOfNodes.size() ); std::vector >::iterator llIt = aListOfListOfNodes.begin(); for ( CORBA::Long i = 0; llIt != aListOfListOfNodes.end(); llIt++, i++ ) - { - vector& aListOfNodes = *llIt; - vector::iterator lIt = aListOfNodes.begin();; - SMESH::long_array& aGroup = (*GroupsOfNodes)[ i ]; - aGroup.length( aListOfNodes.size() ); - for ( int j = 0; lIt != aListOfNodes.end(); lIt++, j++ ) - aGroup[ j ] = (*lIt); - } + { + vector& aListOfNodes = *llIt; + vector::iterator lIt = aListOfNodes.begin();; + SMESH::long_array& aGroup = (*GroupsOfNodes)[ i ]; + aGroup.length( aListOfNodes.size() ); + for ( int j = 0; lIt != aListOfNodes.end(); lIt++, j++ ) + aGroup[ j ] = (*lIt); + } TPythonDump() << "lists_nodes = " << this << ".CreateHoleSkin( " - << radius << ", " << theShape << ", " << ", " << groupName << ", " << theNodesCoords << " )"; + << radius << ", " + << theShape + << ", '" << groupName << "', " + << theNodesCoords << " )"; + + SMESH_CATCH( SMESH::throwCorbaException ); } diff --git a/src/SMESH_I/SMESH_MeshEditor_i.hxx b/src/SMESH_I/SMESH_MeshEditor_i.hxx index a6a0e3c44..d3295821d 100644 --- a/src/SMESH_I/SMESH_MeshEditor_i.hxx +++ b/src/SMESH_I/SMESH_MeshEditor_i.hxx @@ -84,6 +84,7 @@ public: */ SMESH::SMESH_IDSource_ptr MakeIDSource(const SMESH::long_array& IDsOfElements, SMESH::ElementType type); + static bool IsTemporaryIDSource( SMESH::SMESH_IDSource_ptr& idSource ); CORBA::Boolean RemoveElements(const SMESH::long_array & IDsOfElements); CORBA::Boolean RemoveNodes(const SMESH::long_array & IDsOfNodes); CORBA::Long RemoveOrphanNodes(); diff --git a/src/SMESH_I/SMESH_Mesh_i.cxx b/src/SMESH_I/SMESH_Mesh_i.cxx index afe765649..cf8441623 100644 --- a/src/SMESH_I/SMESH_Mesh_i.cxx +++ b/src/SMESH_I/SMESH_Mesh_i.cxx @@ -31,10 +31,12 @@ #include "SMDS_ElemIterator.hxx" #include "SMDS_FacePosition.hxx" #include "SMDS_IteratorOnIterators.hxx" +#include "SMDS_MeshGroup.hxx" #include "SMDS_SetIterator.hxx" #include "SMDS_VolumeTool.hxx" #include "SMESHDS_Command.hxx" #include "SMESHDS_CommandType.hxx" +#include "SMESHDS_Group.hxx" #include "SMESHDS_GroupOnGeom.hxx" #include "SMESH_Filter_i.hxx" #include "SMESH_Gen_i.hxx" @@ -50,12 +52,15 @@ #include "SMESH_subMesh_i.hxx" #include +#include +#include #include -#include #include #include #include + #include +#include // OCCT Includes #include @@ -74,11 +79,14 @@ #include #include +#include "SMESH_TryCatch.hxx" // include after OCCT headers! + // STL Includes #include #include #include #include + #include #ifdef _DEBUG_ @@ -92,10 +100,6 @@ using SMESH::TPythonDump; int SMESH_Mesh_i::_idGenerator = 0; -//To disable automatic genericobj management, the following line should be commented. -//Otherwise, it should be uncommented. Refer to KERNEL_SRC/src/SALOMEDSImpl/SALOMEDSImpl_AttributeIOR.cxx -#define WITHGENERICOBJ - //============================================================================= /*! * Constructor @@ -108,10 +112,10 @@ SMESH_Mesh_i::SMESH_Mesh_i( PortableServer::POA_ptr thePOA, : SALOME::GenericObj_i( thePOA ) { MESSAGE("SMESH_Mesh_i"); - _impl = NULL; - _gen_i = gen_i; - _id = _idGenerator++; - _studyId = studyId; + _impl = NULL; + _gen_i = gen_i; + _id = _idGenerator++; + _studyId = studyId; _preMeshInfo = NULL; } @@ -125,50 +129,38 @@ SMESH_Mesh_i::~SMESH_Mesh_i() { MESSAGE("~SMESH_Mesh_i"); -#ifdef WITHGENERICOBJ // destroy groups map::iterator itGr; - for (itGr = _mapGroups.begin(); itGr != _mapGroups.end(); itGr++) { - if ( CORBA::is_nil( itGr->second )) - continue; - SMESH_GroupBase_i* aGroup = dynamic_cast(SMESH_Gen_i::GetServant(itGr->second).in()); - if (aGroup) { - // this method is called from destructor of group (PAL6331) + for (itGr = _mapGroups.begin(); itGr != _mapGroups.end(); itGr++) + if (SMESH_GroupBase_i* aGroup = SMESH::DownCast(itGr->second)) + { + // _impl->RemoveGroup() is called by ~SMESH_GroupBase_i() (PAL6331) //_impl->RemoveGroup( aGroup->GetLocalID() ); aGroup->myMeshServant = 0; aGroup->UnRegister(); } - } _mapGroups.clear(); // destroy submeshes map::iterator itSM; - for ( itSM = _mapSubMeshIor.begin(); itSM != _mapSubMeshIor.end(); itSM++ ) { - if ( CORBA::is_nil( itSM->second )) - continue; - SMESH_subMesh_i* aSubMesh = dynamic_cast(SMESH_Gen_i::GetServant(itSM->second).in()); - if (aSubMesh) { + for ( itSM = _mapSubMeshIor.begin(); itSM != _mapSubMeshIor.end(); itSM++ ) + if ( SMESH_subMesh_i* aSubMesh = SMESH::DownCast( itSM->second )) + { aSubMesh->UnRegister(); } - } _mapSubMeshIor.clear(); // destroy hypotheses map::iterator itH; - for ( itH = _mapHypo.begin(); itH != _mapHypo.end(); itH++ ) { - if ( CORBA::is_nil( itH->second )) - continue; - SMESH_Hypothesis_i* aHypo = dynamic_cast(SMESH_Gen_i::GetServant(itH->second).in()); - if (aHypo) { + for ( itH = _mapHypo.begin(); itH != _mapHypo.end(); itH++ ) + if ( SMESH_Hypothesis_i* aHypo = SMESH::DownCast( itH->second )) + { aHypo->UnRegister(); } - } _mapHypo.clear(); -#endif delete _impl; _impl = NULL; - - if ( _preMeshInfo ) delete _preMeshInfo; _preMeshInfo = NULL; + delete _preMeshInfo; _preMeshInfo = NULL; } //============================================================================= @@ -280,6 +272,8 @@ void SMESH_Mesh_i::Clear() throw (SALOME::SALOME_Exception) catch(SALOME_Exception & S_ex) { THROW_SALOME_CORBA_EXCEPTION(S_ex.what(), SALOME::BAD_PARAM); } + _impl->GetMeshDS()->Modified(); + TPythonDump() << _this() << ".Clear()"; } @@ -302,6 +296,9 @@ void SMESH_Mesh_i::ClearSubMesh(CORBA::Long ShapeID) catch(SALOME_Exception & S_ex) { THROW_SALOME_CORBA_EXCEPTION(S_ex.what(), SALOME::BAD_PARAM); } + _impl->GetMeshDS()->Modified(); + + TPythonDump() << _this() << ".ClearSubMesh( " << ShapeID << " )"; } //============================================================================= @@ -323,6 +320,8 @@ static SMESH::DriverMED_ReadStatus ConvertDriverMEDReadStatus (int theStatus) res = SMESH::DRS_WARN_RENUMBER; break; case DriverMED_R_SMESHDS_Mesh::DRS_WARN_SKIP_ELEM: res = SMESH::DRS_WARN_SKIP_ELEM; break; + case DriverMED_R_SMESHDS_Mesh::DRS_WARN_DESCENDING: + res = SMESH::DRS_WARN_DESCENDING; break; case DriverMED_R_SMESHDS_Mesh::DRS_FAIL: default: res = SMESH::DRS_FAIL; break; @@ -453,11 +452,15 @@ char* SMESH_Mesh_i::GetVersionString(SMESH::MED_VERSION version, CORBA::Short nb int SMESH_Mesh_i::ImportUNVFile( const char* theFileName ) throw ( SALOME::SALOME_Exception ) { + SMESH_TRY; + // Read mesh with name = into SMESH_Mesh _impl->UNVToMesh( theFileName ); CreateGroupServants(); + SMESH_CATCH( SMESH::throwCorbaException ); + return 1; } @@ -471,12 +474,30 @@ int SMESH_Mesh_i::ImportUNVFile( const char* theFileName ) int SMESH_Mesh_i::ImportSTLFile( const char* theFileName ) throw ( SALOME::SALOME_Exception ) { + SMESH_TRY; + // Read mesh with name = into SMESH_Mesh _impl->STLToMesh( theFileName ); + SMESH_CATCH( SMESH::throwCorbaException ); + return 1; } +//================================================================================ +/*! + * \brief Function used in SMESH_CATCH by ImportGMFFile() + */ +//================================================================================ + +namespace +{ + SMESH_ComputeErrorPtr exceptionToComputeError(const char* excText) + { + return SMESH_ComputeError::New( Driver_Mesh::DRS_FAIL, excText ); + } +} + //================================================================================ /*! * \brief Imports data from a GMF file and returns an error description @@ -488,29 +509,16 @@ SMESH::ComputeError* SMESH_Mesh_i::ImportGMFFile( const char* theFileName, throw (SALOME::SALOME_Exception) { SMESH_ComputeErrorPtr error; - try { - error = _impl->GMFToMesh( theFileName, theMakeRequiredGroups ); - } - catch ( std::bad_alloc& exc ) { - error = SMESH_ComputeError::New( Driver_Mesh::DRS_FAIL, "std::bad_alloc raised" ); - } - catch ( Standard_OutOfMemory& exc ) { - error = SMESH_ComputeError::New( Driver_Mesh::DRS_FAIL, "Standard_OutOfMemory raised" ); - } - catch (Standard_Failure& ex) { - error = SMESH_ComputeError::New( Driver_Mesh::DRS_FAIL, ex.DynamicType()->Name() ); - if ( ex.GetMessageString() && strlen( ex.GetMessageString() )) - error->myComment += string(": ") + ex.GetMessageString(); - } - catch ( SALOME_Exception& S_ex ) { - error = SMESH_ComputeError::New( Driver_Mesh::DRS_FAIL, S_ex.what() ); - } - catch ( std::exception& exc ) { - error = SMESH_ComputeError::New( Driver_Mesh::DRS_FAIL, exc.what() ); - } - catch (...) { - error = SMESH_ComputeError::New( Driver_Mesh::DRS_FAIL, "Unknown exception" ); - } + +#undef SMESH_CAUGHT +#define SMESH_CAUGHT error = + SMESH_TRY; + + error = _impl->GMFToMesh( theFileName, theMakeRequiredGroups ); + + SMESH_CATCH( exceptionToComputeError ); +#undef SMESH_CAUGHT +#define SMESH_CAUGHT CreateGroupServants(); @@ -621,9 +629,7 @@ SMESH_Hypothesis::Hypothesis_Status status = _impl->AddHypothesis(myLocSubShape, hypId); if ( !SMESH_Hypothesis::IsStatusFatal(status) ) { _mapHypo[hypId] = SMESH::SMESH_Hypothesis::_duplicate( myHyp ); -#ifdef WITHGENERICOBJ _mapHypo[hypId]->Register(); -#endif // assure there is a corresponding submesh if ( !_impl->IsMainShape( myLocSubShape )) { int shapeId = _impl->GetMeshDS()->ShapeToIndex( myLocSubShape ); @@ -827,7 +833,7 @@ SMESH::SMESH_subMesh_ptr SMESH_Mesh_i::GetSubMesh(GEOM::GEOM_Object_ptr aSubShap if ( subMesh->_is_nil() ) subMesh = createSubMesh( aSubShapeObject ); if ( _gen_i->CanPublishInStudy( subMesh )) { - SALOMEDS::SObject_var aSO = + SALOMEDS::SObject_wrap aSO = _gen_i->PublishSubMesh(_gen_i->GetCurrentStudy(), aMesh, subMesh, aSubShapeObject, theName ); if ( !aSO->_is_nil()) { @@ -850,27 +856,32 @@ SMESH::SMESH_subMesh_ptr SMESH_Mesh_i::GetSubMesh(GEOM::GEOM_Object_ptr aSubShap //============================================================================= void SMESH_Mesh_i::RemoveSubMesh( SMESH::SMESH_subMesh_ptr theSubMesh ) - throw (SALOME::SALOME_Exception) + throw (SALOME::SALOME_Exception) { - if(MYDEBUG) MESSAGE("SMESH_Mesh_i::RemoveSubMesh"); + SMESH_TRY; + if ( theSubMesh->_is_nil() ) return; GEOM::GEOM_Object_var aSubShapeObject; - SALOMEDS::Study_ptr aStudy = _gen_i->GetCurrentStudy(); + SALOMEDS::Study_var aStudy = _gen_i->GetCurrentStudy(); if ( !aStudy->_is_nil() ) { // Remove submesh's SObject - SALOMEDS::SObject_var anSO = _gen_i->ObjectToSObject( aStudy, theSubMesh ); + SALOMEDS::SObject_wrap anSO = _gen_i->ObjectToSObject( aStudy, theSubMesh ); if ( !anSO->_is_nil() ) { long aTag = SMESH_Gen_i::GetRefOnShapeTag(); - SALOMEDS::SObject_var anObj, aRef; - if ( anSO->FindSubObject( aTag, anObj ) && anObj->ReferencedObject( aRef ) ) - aSubShapeObject = GEOM::GEOM_Object::_narrow( aRef->GetObject() ); - -// if ( aSubShapeObject->_is_nil() ) // not published shape (IPAL13617) -// aSubShapeObject = theSubMesh->GetSubShape(); + SALOMEDS::SObject_wrap anObj, aRef; + if ( anSO->FindSubObject( aTag, anObj.inout() ) && + anObj->ReferencedObject( aRef.inout() )) + { + CORBA::Object_var obj = aRef->GetObject(); + aSubShapeObject = GEOM::GEOM_Object::_narrow( obj ); + } + // if ( aSubShapeObject->_is_nil() ) // not published shape (IPAL13617) + // aSubShapeObject = theSubMesh->GetSubShape(); - aStudy->NewBuilder()->RemoveObjectWithChildren( anSO ); + SALOMEDS::StudyBuilder_var builder = aStudy->NewBuilder(); + builder->RemoveObjectWithChildren( anSO ); // Update Python script TPythonDump() << _this() << ".RemoveSubMesh( " << anSO << " )"; @@ -880,6 +891,8 @@ void SMESH_Mesh_i::RemoveSubMesh( SMESH::SMESH_subMesh_ptr theSubMesh ) if ( removeSubMesh( theSubMesh, aSubShapeObject.in() )) if ( _preMeshInfo ) _preMeshInfo->ForgetOrLoad(); + + SMESH_CATCH( SMESH::throwCorbaException ); } //============================================================================= @@ -900,7 +913,7 @@ SMESH::SMESH_Group_ptr SMESH_Mesh_i::CreateGroup( SMESH::ElementType theElemType SMESH::SMESH_Group::_narrow( createGroup( theElemType, theName )); if ( _gen_i->CanPublishInStudy( aNewGroup ) ) { - SALOMEDS::SObject_var aSO = + SALOMEDS::SObject_wrap aSO = _gen_i->PublishGroup(_gen_i->GetCurrentStudy(), _this(), aNewGroup, GEOM::GEOM_Object::_nil(), theName); if ( !aSO->_is_nil()) { @@ -937,7 +950,7 @@ SMESH_Mesh_i::CreateGroupFromGEOM (SMESH::ElementType theElemType, ( createGroup( theElemType, theName, aShape )); if ( _gen_i->CanPublishInStudy( aNewGroup ) ) { - SALOMEDS::SObject_var aSO = + SALOMEDS::SObject_wrap aSO = _gen_i->PublishGroup(_gen_i->GetCurrentStudy(), _this(), aNewGroup, theGeomObj, theName); if ( !aSO->_is_nil()) { @@ -987,7 +1000,7 @@ SMESH_Mesh_i::CreateGroupFromFilter(SMESH::ElementType theElemType, if ( _gen_i->CanPublishInStudy( aNewGroup ) ) { - SALOMEDS::SObject_var aSO = + SALOMEDS::SObject_wrap aSO = _gen_i->PublishGroup(_gen_i->GetCurrentStudy(), _this(), aNewGroup, GEOM::GEOM_Object::_nil(), theName); if ( !aSO->_is_nil()) { @@ -1012,26 +1025,31 @@ void SMESH_Mesh_i::RemoveGroup( SMESH::SMESH_GroupBase_ptr theGroup ) if ( theGroup->_is_nil() ) return; + SMESH_TRY; + SMESH_GroupBase_i* aGroup = dynamic_cast( SMESH_Gen_i::GetServant( theGroup ).in() ); if ( !aGroup ) return; - SALOMEDS::Study_ptr aStudy = _gen_i->GetCurrentStudy(); + SALOMEDS::Study_var aStudy = _gen_i->GetCurrentStudy(); if ( !aStudy->_is_nil() ) { - SALOMEDS::SObject_var aGroupSO = _gen_i->ObjectToSObject( aStudy, theGroup ); + SALOMEDS::SObject_wrap aGroupSO = _gen_i->ObjectToSObject( aStudy, theGroup ); if ( !aGroupSO->_is_nil() ) { // Update Python script TPythonDump() << _this() << ".RemoveGroup( " << aGroupSO << " )"; // Remove group's SObject - aStudy->NewBuilder()->RemoveObjectWithChildren( aGroupSO ); + SALOMEDS::StudyBuilder_var builder = aStudy->NewBuilder(); + builder->RemoveObjectWithChildren( aGroupSO ); } } // Remove the group from SMESH data structures removeGroup( aGroup->GetLocalID() ); + + SMESH_CATCH( SMESH::throwCorbaException ); } //============================================================================= @@ -1043,6 +1061,7 @@ void SMESH_Mesh_i::RemoveGroup( SMESH::SMESH_GroupBase_ptr theGroup ) void SMESH_Mesh_i::RemoveGroupWithContents( SMESH::SMESH_GroupBase_ptr theGroup ) throw (SALOME::SALOME_Exception) { + SMESH_TRY; if ( _preMeshInfo ) _preMeshInfo->FullLoadFromFile(); @@ -1070,6 +1089,8 @@ void SMESH_Mesh_i::RemoveGroupWithContents( SMESH::SMESH_GroupBase_ptr theGroup // Remove group RemoveGroup( theGroup ); + + SMESH_CATCH( SMESH::throwCorbaException ); } //================================================================================ @@ -1138,63 +1159,58 @@ SMESH::SMESH_Group_ptr SMESH_Mesh_i::UnionGroups( SMESH::SMESH_GroupBase_ptr the const char* theName ) throw (SALOME::SALOME_Exception) { + SMESH::SMESH_Group_var aResGrp; + + SMESH_TRY; if ( _preMeshInfo ) _preMeshInfo->FullLoadFromFile(); - try - { - if ( theGroup1->_is_nil() || theGroup2->_is_nil() || - theGroup1->GetType() != theGroup2->GetType() ) - return SMESH::SMESH_Group::_nil(); + if ( theGroup1->_is_nil() || theGroup2->_is_nil() || + theGroup1->GetType() != theGroup2->GetType() ) + return SMESH::SMESH_Group::_nil(); + + TPythonDump pyDump; - // Create Union - SMESH::SMESH_Group_var aResGrp = CreateGroup( theGroup1->GetType(), theName ); - if ( aResGrp->_is_nil() ) - return SMESH::SMESH_Group::_nil(); + // Create Union + aResGrp = CreateGroup( theGroup1->GetType(), theName ); + if ( aResGrp->_is_nil() ) + return SMESH::SMESH_Group::_nil(); - SMESH::long_array_var anIds1 = theGroup1->GetListOfID(); - SMESH::long_array_var anIds2 = theGroup2->GetListOfID(); + SMESH::long_array_var anIds1 = theGroup1->GetListOfID(); + SMESH::long_array_var anIds2 = theGroup2->GetListOfID(); - TColStd_MapOfInteger aResMap; + TColStd_MapOfInteger aResMap; - for ( int i1 = 0, n1 = anIds1->length(); i1 < n1; i1++ ) - aResMap.Add( anIds1[ i1 ] ); + for ( int i1 = 0, n1 = anIds1->length(); i1 < n1; i1++ ) + aResMap.Add( anIds1[ i1 ] ); - for ( int i2 = 0, n2 = anIds2->length(); i2 < n2; i2++ ) - aResMap.Add( anIds2[ i2 ] ); + for ( int i2 = 0, n2 = anIds2->length(); i2 < n2; i2++ ) + aResMap.Add( anIds2[ i2 ] ); - SMESH::long_array_var aResIds = new SMESH::long_array; - aResIds->length( aResMap.Extent() ); + SMESH::long_array_var aResIds = new SMESH::long_array; + aResIds->length( aResMap.Extent() ); - int resI = 0; - TColStd_MapIteratorOfMapOfInteger anIter( aResMap ); - for( ; anIter.More(); anIter.Next() ) - aResIds[ resI++ ] = anIter.Key(); + int resI = 0; + TColStd_MapIteratorOfMapOfInteger anIter( aResMap ); + for( ; anIter.More(); anIter.Next() ) + aResIds[ resI++ ] = anIter.Key(); - aResGrp->Add( aResIds ); + 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 + pyDump << aResGrp << " = " << _this() << ".UnionGroups( " + << theGroup1 << ", " << theGroup2 << ", '" + << theName << "' )"; - // Update Python script - TPythonDump() << aResGrp << " = " << _this() << ".UnionGroups( " - << theGroup1 << ", " << theGroup2 << ", '" - << theName << "' )"; + SMESH_CATCH( SMESH::throwCorbaException ); - return aResGrp._retn(); - } - catch( ... ) - { - return SMESH::SMESH_Group::_nil(); - } + return aResGrp._retn(); } //============================================================================= /*! \brief Union list of groups. New group is created. All mesh elements that are - present in initial groups are added to the new one. + 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 @@ -1202,7 +1218,7 @@ SMESH::SMESH_Group_ptr SMESH_Mesh_i::UnionGroups( SMESH::SMESH_GroupBase_ptr the //============================================================================= SMESH::SMESH_Group_ptr SMESH_Mesh_i::UnionListOfGroups(const SMESH::ListOfGroups& theGroups, const char* theName ) -throw (SALOME::SALOME_Exception) + throw (SALOME::SALOME_Exception) { if ( _preMeshInfo ) _preMeshInfo->FullLoadFromFile(); @@ -1210,67 +1226,59 @@ throw (SALOME::SALOME_Exception) if ( !theName ) return SMESH::SMESH_Group::_nil(); - try - { - vector< 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; + SMESH::SMESH_Group_var aResGrp; - // check type - SMESH::ElementType aCurrType = aGrp->GetType(); - if ( aType == SMESH::ALL ) - aType = aCurrType; - else - { - if ( aType != aCurrType ) - return SMESH::SMESH_Group::_nil(); - } + SMESH_TRY; - // unite ids - SMESH::long_array_var aCurrIds = aGrp->GetListOfID(); - for ( int i = 0, n = aCurrIds->length(); i < n; i++ ) - { - int aCurrId = aCurrIds[ i ]; - anIds.push_back( aCurrId ); - } + vector< 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(); } - // 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.size() ); - - //NCollection_Map< int >::Iterator anIter( anIds ); - for ( int i = 0; iGetListOfID(); + for ( int i = 0, n = aCurrIds->length(); i < n; i++ ) { - aResIds[ i ] = anIds[i]; + int aCurrId = aCurrIds[ i ]; + anIds.push_back( aCurrId ); } - 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() ); + TPythonDump pyDump; - // Update Python script - - TPythonDump() << aResGrp << " = " << _this() << ".UnionListOfGroups( " - << &theGroups << ", '" << theName << "' )"; - - return aResGrp._retn(); - } - catch( ... ) - { + // Create group + 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.size() ); + + for ( size_t i = 0; iAdd( aResIds ); + + // Update Python script + pyDump << aResGrp << " = " << _this() << ".UnionListOfGroups( " + << &theGroups << ", '" << theName << "' )"; + + SMESH_CATCH( SMESH::throwCorbaException ); + + return aResGrp._retn(); } //============================================================================= @@ -1281,9 +1289,12 @@ throw (SALOME::SALOME_Exception) //============================================================================= SMESH::SMESH_Group_ptr SMESH_Mesh_i::IntersectGroups( SMESH::SMESH_GroupBase_ptr theGroup1, SMESH::SMESH_GroupBase_ptr theGroup2, - const char* theName ) + const char* theName ) throw (SALOME::SALOME_Exception) { + SMESH::SMESH_Group_var aResGrp; + + SMESH_TRY; if ( _preMeshInfo ) _preMeshInfo->FullLoadFromFile(); @@ -1291,8 +1302,10 @@ SMESH::SMESH_Group_ptr SMESH_Mesh_i::IntersectGroups( SMESH::SMESH_GroupBase_ptr theGroup1->GetType() != theGroup2->GetType() ) return SMESH::SMESH_Group::_nil(); + TPythonDump pyDump; + // Create Intersection - SMESH::SMESH_Group_var aResGrp = CreateGroup( theGroup1->GetType(), theName ); + aResGrp = CreateGroup( theGroup1->GetType(), theName ); if ( aResGrp->_is_nil() ) return aResGrp; @@ -1305,27 +1318,21 @@ SMESH::SMESH_Group_ptr SMESH_Mesh_i::IntersectGroups( SMESH::SMESH_GroupBase_ptr aMap1.Add( anIds1[ i1 ] ); TColStd_SequenceOfInteger aSeq; - for ( int i2 = 0, n2 = anIds2->length(); i2 < n2; i2++ ) if ( aMap1.Contains( anIds2[ i2 ] ) ) aSeq.Append( anIds2[ i2 ] ); SMESH::long_array_var aResIds = new SMESH::long_array; aResIds->length( aSeq.Length() ); - - for ( int resI = 0, resN = aSeq.Length(); resI < resN; resI++ ) + for ( size_t resI = 0, resN = aSeq.Length(); resI < resN; resI++ ) aResIds[ resI ] = aSeq( resI + 1 ); - 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() << ".IntersectGroups( " - << theGroup1 << ", " << theGroup2 << ", '" << theName << "')"; + pyDump << aResGrp << " = " << _this() << ".IntersectGroups( " + << theGroup1 << ", " << theGroup2 << ", '" << theName << "')"; + + SMESH_CATCH( SMESH::throwCorbaException ); return aResGrp._retn(); } @@ -1344,88 +1351,79 @@ SMESH_Mesh_i::IntersectListOfGroups(const SMESH::ListOfGroups& theGroups, const char* theName ) throw (SALOME::SALOME_Exception) { + SMESH::SMESH_Group_var aResGrp; + + SMESH_TRY; if ( _preMeshInfo ) _preMeshInfo->FullLoadFromFile(); 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++ ) { - 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(); - } + SMESH::SMESH_GroupBase_var aGrp = theGroups[ g ]; + if ( CORBA::is_nil( aGrp ) ) + continue; - // 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(); - vector< int > anIds; - NCollection_DataMap< int, int >::Iterator anIter( anIdToCount ); - for ( ; anIter.More(); anIter.Next() ) + // check type + SMESH::ElementType aCurrType = aGrp->GetType(); + if ( aType == SMESH::ALL ) + aType = aCurrType; + else { - int aCurrId = anIter.Key(); - int aCurrNb = anIter.Value(); - if ( aCurrNb == nbGrp ) - anIds.push_back( aCurrId ); + if ( aType != aCurrType ) + return SMESH::SMESH_Group::_nil(); } - // 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.size() ); - - //NCollection_Map< int >::Iterator aListIter( anIds ); - for ( int i = 0; iGetListOfID(); + for ( int i = 0, n = aCurrIds->length(); i < n; i++ ) { - aResIds[ i ] = anIds[i]; + int aCurrId = aCurrIds[ i ]; + if ( !anIdToCount.IsBound( aCurrId ) ) + anIdToCount.Bind( aCurrId, 1 ); + else + anIdToCount( aCurrId ) = anIdToCount( aCurrId ) + 1; } - 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() ); + // create map of ids + int nbGrp = theGroups.length(); + vector< 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.push_back( aCurrId ); + } - // Update Python script - - TPythonDump() << aResGrp << " = " << _this() << ".IntersectListOfGroups( " - << &theGroups << ", '" << theName << "' )"; + TPythonDump pyDump; - return aResGrp._retn(); - } - catch( ... ) - { + // Create group + 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.size() ); + + for ( size_t i = 0; iAdd( aResIds ); + + // Update Python script + pyDump << aResGrp << " = " << _this() << ".IntersectListOfGroups( " + << &theGroups << ", '" << theName << "' )"; + + SMESH_CATCH( SMESH::throwCorbaException ); + + return aResGrp._retn(); } //============================================================================= @@ -1439,6 +1437,9 @@ SMESH::SMESH_Group_ptr SMESH_Mesh_i::CutGroups( SMESH::SMESH_GroupBase_ptr theGr const char* theName ) throw (SALOME::SALOME_Exception) { + SMESH::SMESH_Group_var aResGrp; + + SMESH_TRY; if ( _preMeshInfo ) _preMeshInfo->FullLoadFromFile(); @@ -1446,8 +1447,10 @@ SMESH::SMESH_Group_ptr SMESH_Mesh_i::CutGroups( SMESH::SMESH_GroupBase_ptr theGr theGroup1->GetType() != theGroup2->GetType() ) return SMESH::SMESH_Group::_nil(); + TPythonDump pyDump; + // Perform Cutting - SMESH::SMESH_Group_var aResGrp = CreateGroup( theGroup1->GetType(), theName ); + aResGrp = CreateGroup( theGroup1->GetType(), theName ); if ( aResGrp->_is_nil() ) return aResGrp; @@ -1469,18 +1472,14 @@ SMESH::SMESH_Group_ptr SMESH_Mesh_i::CutGroups( SMESH::SMESH_GroupBase_ptr theGr for ( int resI = 0, resN = aSeq.Length(); resI < resN; resI++ ) aResIds[ resI ] = aSeq( resI + 1 ); - 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() << ".CutGroups( " - << theGroup1 << ", " << theGroup2 << ", '" - << theName << "' )"; + pyDump << aResGrp << " = " << _this() << ".CutGroups( " + << theGroup1 << ", " << theGroup2 << ", '" + << theName << "' )"; + + SMESH_CATCH( SMESH::throwCorbaException ); return aResGrp._retn(); } @@ -1501,124 +1500,122 @@ SMESH_Mesh_i::CutListOfGroups(const SMESH::ListOfGroups& theMainGroups, const char* theName ) throw (SALOME::SALOME_Exception) { + SMESH::SMESH_Group_var aResGrp; + + SMESH_TRY; if ( _preMeshInfo ) _preMeshInfo->FullLoadFromFile(); if ( !theName ) return SMESH::SMESH_Group::_nil(); - try + set< int > aToolIds; + SMESH::ElementType aType = SMESH::ALL; + int g, n; + // iterate through tool groups + for ( g = 0, n = theToolGroups.length(); g < n; g++ ) { - set< 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(); - } + SMESH::SMESH_GroupBase_var aGrp = theToolGroups[ g ]; + if ( CORBA::is_nil( aGrp ) ) + continue; - // 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.insert( aCurrId ); - } + // check type + SMESH::ElementType aCurrType = aGrp->GetType(); + if ( aType == SMESH::ALL ) + aType = aCurrType; + else + { + if ( aType != aCurrType ) + return SMESH::SMESH_Group::_nil(); } - vector< int > anIds; // result - - // Iterate through main group - for ( g = 0, n = theMainGroups.length(); g < n; g++ ) + // unite tool ids + SMESH::long_array_var aCurrIds = aGrp->GetListOfID(); + for ( int i = 0, n = aCurrIds->length(); i < n; i++ ) { - SMESH::SMESH_GroupBase_var aGrp = theMainGroups[ g ]; - if ( CORBA::is_nil( aGrp ) ) - continue; + int aCurrId = aCurrIds[ i ]; + aToolIds.insert( aCurrId ); + } + } - // check type - SMESH::ElementType aCurrType = aGrp->GetType(); - if ( aType == SMESH::ALL ) - aType = aCurrType; - else - { - if ( aType != aCurrType ) - return SMESH::SMESH_Group::_nil(); - } + vector< int > anIds; // result - // 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.count( aCurrId ) ) - anIds.push_back( aCurrId ); - } - } + // 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; - // 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.size() ); - - for (int i=0; iGetType(); + if ( aType == SMESH::ALL ) + aType = aCurrType; + else { - aResIds[ i ] = anIds[i]; + if ( aType != aCurrType ) + return SMESH::SMESH_Group::_nil(); } - 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() ); + // 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.count( aCurrId ) ) + anIds.push_back( aCurrId ); + } + } - // Update Python script + TPythonDump pyDump; - TPythonDump() << aResGrp << " = " << _this() << ".CutListOfGroups( " - << &theMainGroups << ", " << &theToolGroups << ", '" - << theName << "' )"; - - return aResGrp._retn(); - } - catch( ... ) - { + // Create group + 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.size() ); + + for (int i=0; iAdd( aResIds ); + + // Update Python script + pyDump << aResGrp << " = " << _this() << ".CutListOfGroups( " + << &theMainGroups << ", " << &theToolGroups << ", '" + << theName << "' )"; + + SMESH_CATCH( SMESH::throwCorbaException ); + + return aResGrp._retn(); } //============================================================================= /*! \brief Create groups of entities from existing groups of superior dimensions - System + 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 + * + IMP 19939 */ //============================================================================= + SMESH::SMESH_Group_ptr SMESH_Mesh_i::CreateDimGroup(const SMESH::ListOfGroups& theGroups, SMESH::ElementType theElemType, const char* theName ) throw (SALOME::SALOME_Exception) { + SMESH::SMESH_Group_var aResGrp; + + SMESH_TRY; if ( _preMeshInfo ) _preMeshInfo->FullLoadFromFile(); @@ -1629,141 +1626,73 @@ SMESH_Mesh_i::CreateDimGroup(const SMESH::ListOfGroups& theGroups, SMDSAbs_ElementType anElemType = (SMDSAbs_ElementType)theElemType; - try - { - // Create map of nodes from all groups + // Create a group - set< 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; + TPythonDump pyDump; - 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.insert( 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.insert( aNode->GetID() ); - } - } - } - } + aResGrp = CreateGroup( theElemType, theName ); + if ( aResGrp->_is_nil() ) + return SMESH::SMESH_Group::_nil(); + + SMESHDS_GroupBase* groupBaseDS = + SMESH::DownCast( aResGrp )->GetGroupDS(); + SMDS_MeshGroup& resGroupCore = static_cast< SMESHDS_Group* >( groupBaseDS )->SMDSGroup(); + + for ( int g = 0, n = theGroups.length(); g < n; g++ ) // loop on theGroups + { + SMESH::SMESH_GroupBase_var aGrp = theGroups[ g ]; + if ( CORBA::is_nil( aGrp ) ) + continue; - // Get result identifiers + groupBaseDS = SMESH::DownCast( aGrp )->GetGroupDS(); + SMDS_ElemIteratorPtr elIt = groupBaseDS->GetElements(); - vector< int > aResultIds; - if ( theElemType == SMESH::NODE ) + if ( theElemType == SMESH::NODE ) // get all nodes of elements { - //NCollection_Map< int >::Iterator aNodeIter( aNodeMap ); - set::iterator iter = aNodeMap.begin(); - for ( ; iter != aNodeMap.end(); iter++ ) - aResultIds.push_back( *iter); + while ( elIt->more() ) { + const SMDS_MeshElement* el = elIt->next(); + SMDS_ElemIteratorPtr nIt = el->nodesIterator(); + while ( nIt->more() ) + resGroupCore.Add( nIt->next() ); + } } - else + else // get elements of theElemType based on nodes of every element of group { - // Create list of elements of given dimension constructed on the nodes - vector< int > anElemList; - //NCollection_Map< int >::Iterator aNodeIter( aNodeMap ); - //for ( ; aNodeIter.More(); aNodeIter.Next() ) - set::iterator iter = aNodeMap.begin(); - for ( ; iter != aNodeMap.end(); iter++ ) + while ( elIt->more() ) { - const SMDS_MeshElement* aNode = - dynamic_cast( aMeshDS->FindNode( *iter ) ); - 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.push_back( anElem->GetID() ); - } - } - - // check whether all nodes of elements are present in nodes map - for (int i=0; i< anElemList.size(); i++) - { - const SMDS_MeshElement* anElem = aMeshDS->FindElement( anElemList[i] ); - if ( !anElem ) - continue; - - bool isOk = true; - SMDS_ElemIteratorPtr aNodeIter = anElem->nodesIterator(); - while( aNodeIter->more() ) + const SMDS_MeshElement* el = elIt->next(); // an element of group + TIDSortedElemSet elNodes( el->begin_nodes(), el->end_nodes() ); + TIDSortedElemSet checkedElems; + SMDS_ElemIteratorPtr nIt = el->nodesIterator(); + while ( nIt->more() ) { - const SMDS_MeshNode* aNode = - dynamic_cast( aNodeIter->next() ); - if ( !aNode || !aNodeMap.count( aNode->GetID() ) ) + const SMDS_MeshNode* n = static_cast( nIt->next() ); + SMDS_ElemIteratorPtr elOfTypeIt = n->GetInverseElementIterator( anElemType ); + // check nodes of elements of theElemType around el + while ( elOfTypeIt->more() ) { - isOk = false; - break; + const SMDS_MeshElement* elOfType = elOfTypeIt->next(); + if ( !checkedElems.insert( elOfType ).second ) continue; + + SMDS_ElemIteratorPtr nIt2 = elOfType->nodesIterator(); + bool allNodesOK = true; + while ( nIt2->more() && allNodesOK ) + allNodesOK = elNodes.count( nIt2->next() ); + if ( allNodesOK ) + resGroupCore.Add( elOfType ); } - } - if ( isOk ) - aResultIds.push_back( 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.size() ); - - for (int i=0; i< aResultIds.size(); i++) - aResIds[ i ] = aResultIds[i]; - 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 + pyDump << aResGrp << " = " << _this() << ".CreateDimGroup( " + << &theGroups << ", " << theElemType << ", '" << theName << "' )"; - // Update Python script - - TPythonDump() << aResGrp << " = " << _this() << ".CreateDimGroup( " - << &theGroups << ", " << theElemType << ", '" << theName << "' )"; + SMESH_CATCH( SMESH::throwCorbaException ); - return aResGrp._retn(); - } - catch( ... ) - { - return SMESH::SMESH_Group::_nil(); - } + return aResGrp._retn(); } //================================================================================ @@ -1778,13 +1707,13 @@ void SMESH_Mesh_i::addGeomGroupData(GEOM::GEOM_Object_ptr theGeomObj, if ( CORBA::is_nil( theGeomObj ) || theGeomObj->GetType() != GEOM_GROUP ) return; // group SO - SALOMEDS::Study_var study = _gen_i->GetCurrentStudy(); - SALOMEDS::SObject_var groupSO = _gen_i->ObjectToSObject( study, theGeomObj ); + SALOMEDS::Study_var study = _gen_i->GetCurrentStudy(); + SALOMEDS::SObject_wrap groupSO = _gen_i->ObjectToSObject( study, theGeomObj ); if ( groupSO->_is_nil() ) return; // group indices GEOM::GEOM_Gen_var geomGen = _gen_i->GetGeomEngine(); - GEOM::GEOM_IGroupOperations_var groupOp = + GEOM::GEOM_IGroupOperations_wrap groupOp = geomGen->GetIGroupOperations( _gen_i->GetCurrentStudyID() ); GEOM::ListOfLong_var ids = groupOp->GetObjects( theGeomObj ); @@ -1832,7 +1761,7 @@ TopoDS_Shape SMESH_Mesh_i::newGroupShape( TGeomGroupData & groupData) // get geom group SALOMEDS::Study_var study = _gen_i->GetCurrentStudy(); if ( study->_is_nil() ) return newShape; // means "not changed" - SALOMEDS::SObject_var groupSO = study->FindObjectID( groupData._groupEntry.c_str() ); + SALOMEDS::SObject_wrap groupSO = study->FindObjectID( groupData._groupEntry.c_str() ); if ( !groupSO->_is_nil() ) { CORBA::Object_var groupObj = _gen_i->SObjectToObject( groupSO ); @@ -1842,9 +1771,9 @@ TopoDS_Shape SMESH_Mesh_i::newGroupShape( TGeomGroupData & groupData) // get indices of group items set curIndices; GEOM::GEOM_Gen_var geomGen = _gen_i->GetGeomEngine(); - GEOM::GEOM_IGroupOperations_var groupOp = + GEOM::GEOM_IGroupOperations_wrap groupOp = geomGen->GetIGroupOperations( _gen_i->GetCurrentStudyID() ); - GEOM::ListOfLong_var ids = groupOp->GetObjects( geomGroup ); + GEOM::ListOfLong_var ids = groupOp->GetObjects( geomGroup ); for ( int i = 0; i < ids->length(); ++i ) curIndices.insert( ids[i] ); @@ -1859,7 +1788,7 @@ TopoDS_Shape SMESH_Mesh_i::newGroupShape( TGeomGroupData & groupData) TCollection_AsciiString groupIOR = geomGen->GetStringFromIOR( geomGroup ); geomClient->RemoveShapeFromBuffer( groupIOR ); newShape = _gen_i->GeomObjectToShape( geomGroup ); - } + } if ( newShape.IsNull() ) { // geom group becomes empty - return empty compound @@ -2084,10 +2013,10 @@ void SMESH_Mesh_i::CheckGeomGroupModif() if ( _mapGroups.find( oldID ) == _mapGroups.end() ) continue; // get group name - SALOMEDS::SObject_var groupSO = _gen_i->ObjectToSObject( study,_mapGroups[oldID] ); - CORBA::String_var name = groupSO->GetName(); + SALOMEDS::SObject_wrap groupSO = _gen_i->ObjectToSObject( study,_mapGroups[oldID] ); + CORBA::String_var name = groupSO->GetName(); // update - SMESH_GroupBase_i* group_i = SMESH::DownCast(_mapGroups[oldID] ); + SMESH_GroupBase_i* group_i = SMESH::DownCast(_mapGroups[oldID] ); int newID; if ( group_i && _impl->AddGroup( geomType->second, name.in(), newID, geom._shape )) group_i->changeLocalId( newID ); @@ -2101,7 +2030,7 @@ void SMESH_Mesh_i::CheckGeomGroupModif() // Update icons CORBA::Long newNbEntities = NbNodes() + NbElements(); - list< SALOMEDS::SObject_var > soToUpdateIcons; + list< SALOMEDS::SObject_wrap > soToUpdateIcons; if ( newNbEntities != nbEntities ) { // Add all SObjects with icons to soToUpdateIcons @@ -2116,7 +2045,7 @@ void SMESH_Mesh_i::CheckGeomGroupModif() soToUpdateIcons.push_back( _gen_i->ObjectToSObject( study, i_gr->second )); } - list< SALOMEDS::SObject_var >::iterator so = soToUpdateIcons.begin(); + list< SALOMEDS::SObject_wrap >::iterator so = soToUpdateIcons.begin(); for ( ; so != soToUpdateIcons.end(); ++so ) _gen_i->SetPixMap( *so, "ICON_SMESH_TREE_MESH_WARN" ); } @@ -2128,16 +2057,18 @@ void SMESH_Mesh_i::CheckGeomGroupModif() //============================================================================= SMESH::SMESH_Group_ptr SMESH_Mesh_i::ConvertToStandalone( SMESH::SMESH_GroupBase_ptr theGroup ) + throw (SALOME::SALOME_Exception) { + SMESH::SMESH_Group_var aGroup; + + SMESH_TRY; + if ( _preMeshInfo ) _preMeshInfo->FullLoadFromFile(); - 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 ) @@ -2156,15 +2087,15 @@ SMESH::SMESH_Group_ptr SMESH_Mesh_i::ConvertToStandalone( SMESH::SMESH_GroupBase _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(); + SALOMEDS::SObject_wrap aGroupSO; + SALOMEDS::Study_var aStudy = _gen_i->GetCurrentStudy(); + if ( !aStudy->_is_nil() ) { + builder = aStudy->NewBuilder(); aGroupSO = _gen_i->ObjectToSObject( aStudy, theGroup ); - if ( !aGroupSO->_is_nil() ) { - + if ( !aGroupSO->_is_nil() ) + { // remove reference to geometry - SALOMEDS::ChildIterator_var chItr = aStudy->NewChildIterator(aGroupSO); + SALOMEDS::ChildIterator_wrap chItr = aStudy->NewChildIterator(aGroupSO); for ( ; chItr->More(); chItr->Next() ) // Remove group's child SObject builder->RemoveObject( chItr->Value() ); @@ -2180,28 +2111,26 @@ SMESH::SMESH_Group_ptr SMESH_Mesh_i::ConvertToStandalone( SMESH::SMESH_GroupBase const int isEmpty = ( elemTypes->length() == 0 ); if ( !isEmpty ) { - SALOMEDS::GenericAttribute_var anAttr = + SALOMEDS::GenericAttribute_wrap anAttr = builder->FindOrCreateAttribute( aGroupSO, "AttributePixMap" ); - SALOMEDS::AttributePixMap_var pm = SALOMEDS::AttributePixMap::_narrow( anAttr ); + SALOMEDS::AttributePixMap_wrap pm = anAttr; pm->SetPixMap( "ICON_SMESH_TREE_GROUP" ); } } } } - // 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 ); + _gen_i->RegisterObject( aGroup ); + + CORBA::String_var ior = _gen_i->GetORB()->object_to_string( aGroup ); + builder->SetIOR( aGroupSO, ior.in() ); - builder->SetIOR( aGroupSO, _gen_i->GetORB()->object_to_string( aGroup ) ); + SMESH_CATCH( SMESH::throwCorbaException ); return aGroup._retn(); } @@ -2339,11 +2268,6 @@ SMESH::SMESH_GroupBase_ptr SMESH_Mesh_i::createGroup (SMESH::ElementType else aGroupImpl = new SMESH_Group_i( SMESH_Gen_i::GetPOA(), this, anId ); - // 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 - aGroup = SMESH::SMESH_GroupBase::_narrow( aGroupImpl->_this() ); _mapGroups[anId] = SMESH::SMESH_GroupBase::_duplicate( aGroup ); @@ -2390,57 +2314,57 @@ void SMESH_Mesh_i::removeGroup( const int theId ) //============================================================================= SMESH::log_array * SMESH_Mesh_i::GetLog(CORBA::Boolean clearAfterGet) -throw(SALOME::SALOME_Exception) + throw(SALOME::SALOME_Exception) { + SMESH::log_array_var aLog; + + SMESH_TRY; if ( _preMeshInfo ) _preMeshInfo->FullLoadFromFile(); - SMESH::log_array_var aLog; - try{ - list < SMESHDS_Command * >logDS = _impl->GetLog(); - aLog = new SMESH::log_array; - int indexLog = 0; - int lg = logDS.size(); - SCRUTE(lg); - aLog->length(lg); - list < SMESHDS_Command * >::iterator its = logDS.begin(); - while(its != logDS.end()){ - SMESHDS_Command *com = *its; - int comType = com->GetType(); - //SCRUTE(comType); - int lgcom = com->GetNumber(); - //SCRUTE(lgcom); - const list < int >&intList = com->GetIndexes(); - int inum = intList.size(); - //SCRUTE(inum); - list < int >::const_iterator ii = intList.begin(); - const list < double >&coordList = com->GetCoords(); - int rnum = coordList.size(); - //SCRUTE(rnum); - list < double >::const_iterator ir = coordList.begin(); - aLog[indexLog].commandType = comType; - aLog[indexLog].number = lgcom; - aLog[indexLog].coords.length(rnum); - aLog[indexLog].indexes.length(inum); - for(int i = 0; i < rnum; i++){ - aLog[indexLog].coords[i] = *ir; - //MESSAGE(" "<logDS = _impl->GetLog(); + aLog = new SMESH::log_array; + int indexLog = 0; + int lg = logDS.size(); + SCRUTE(lg); + aLog->length(lg); + list < SMESHDS_Command * >::iterator its = logDS.begin(); + while(its != logDS.end()){ + SMESHDS_Command *com = *its; + int comType = com->GetType(); + //SCRUTE(comType); + int lgcom = com->GetNumber(); + //SCRUTE(lgcom); + const list < int >&intList = com->GetIndexes(); + int inum = intList.size(); + //SCRUTE(inum); + list < int >::const_iterator ii = intList.begin(); + const list < double >&coordList = com->GetCoords(); + int rnum = coordList.size(); + //SCRUTE(rnum); + list < double >::const_iterator ir = coordList.begin(); + aLog[indexLog].commandType = comType; + aLog[indexLog].number = lgcom; + aLog[indexLog].coords.length(rnum); + aLog[indexLog].indexes.length(inum); + for(int i = 0; i < rnum; i++){ + aLog[indexLog].coords[i] = *ir; + //MESSAGE(" "<ClearLog(); - } - catch(SALOME_Exception & S_ex){ - THROW_SALOME_CORBA_EXCEPTION(S_ex.what(), SALOME::BAD_PARAM); + for(int i = 0; i < inum; i++){ + aLog[indexLog].indexes[i] = *ii; + //MESSAGE(" "<ClearLog(); + + SMESH_CATCH( SMESH::throwCorbaException ); + return aLog._retn(); } @@ -2453,8 +2377,9 @@ throw(SALOME::SALOME_Exception) void SMESH_Mesh_i::ClearLog() throw(SALOME::SALOME_Exception) { - if(MYDEBUG) MESSAGE("SMESH_Mesh_i::ClearLog"); + SMESH_TRY; _impl->ClearLog(); + SMESH_CATCH( SMESH::throwCorbaException ); } //============================================================================= @@ -2465,7 +2390,6 @@ void SMESH_Mesh_i::ClearLog() throw(SALOME::SALOME_Exception) CORBA::Long SMESH_Mesh_i::GetId()throw(SALOME::SALOME_Exception) { - if(MYDEBUG) MESSAGE("SMESH_Mesh_i::GetId"); return _id; } @@ -2541,18 +2465,24 @@ void SMESH_Mesh_i::SetImpl(::SMESH_Mesh * impl) //============================================================================= SMESH::SMESH_MeshEditor_ptr SMESH_Mesh_i::GetMeshEditor() + throw (SALOME::SALOME_Exception) { + SMESH::SMESH_MeshEditor_var aMeshEdVar; + + SMESH_TRY; if ( _preMeshInfo ) _preMeshInfo->FullLoadFromFile(); // Create MeshEditor SMESH_MeshEditor_i *aMeshEditor = new SMESH_MeshEditor_i( this, false ); - SMESH::SMESH_MeshEditor_var aMesh = aMeshEditor->_this(); + aMeshEdVar = aMeshEditor->_this(); // Update Python script TPythonDump() << aMeshEditor << " = " << _this() << ".GetMeshEditor()"; - return aMesh._retn(); + SMESH_CATCH( SMESH::throwCorbaException ); + + return aMeshEdVar._retn(); } //============================================================================= @@ -2562,13 +2492,20 @@ SMESH::SMESH_MeshEditor_ptr SMESH_Mesh_i::GetMeshEditor() //============================================================================= SMESH::SMESH_MeshEditor_ptr SMESH_Mesh_i::GetMeshEditPreviewer() + throw (SALOME::SALOME_Exception) { + SMESH::SMESH_MeshEditor_var aMeshEdVar; + + SMESH_TRY; if ( _preMeshInfo ) _preMeshInfo->FullLoadFromFile(); SMESH_MeshEditor_i *aMeshEditor = new SMESH_MeshEditor_i( this, true ); - SMESH::SMESH_MeshEditor_var aMesh = aMeshEditor->_this(); - return aMesh._retn(); + aMeshEdVar = aMeshEditor->_this(); + + SMESH_CATCH( SMESH::throwCorbaException ); + + return aMeshEdVar._retn(); } //================================================================================ @@ -2731,25 +2668,23 @@ string SMESH_Mesh_i::prepareMeshNameAndGroups(const char* file, // Perform Export PrepareForWriting(file, overwrite); string aMeshName = "Mesh"; - SALOMEDS::Study_ptr aStudy = _gen_i->GetCurrentStudy(); + SALOMEDS::Study_var aStudy = _gen_i->GetCurrentStudy(); if ( !aStudy->_is_nil() ) { - SALOMEDS::SObject_var aMeshSO = _gen_i->ObjectToSObject( aStudy, _this() ); + SALOMEDS::SObject_wrap aMeshSO = _gen_i->ObjectToSObject( aStudy, _this() ); if ( !aMeshSO->_is_nil() ) { CORBA::String_var name = aMeshSO->GetName(); aMeshName = name; // asv : 27.10.04 : fix of 6903: check for StudyLocked before adding attributes if ( !aStudy->GetProperties()->IsLocked() ) { - SALOMEDS::GenericAttribute_var anAttr; + SALOMEDS::GenericAttribute_wrap anAttr; SALOMEDS::StudyBuilder_var aStudyBuilder = aStudy->NewBuilder(); - SALOMEDS::AttributeExternalFileDef_var aFileName; anAttr=aStudyBuilder->FindOrCreateAttribute(aMeshSO, "AttributeExternalFileDef"); - aFileName = SALOMEDS::AttributeExternalFileDef::_narrow(anAttr); + SALOMEDS::AttributeExternalFileDef_wrap aFileName = anAttr; ASSERT(!aFileName->_is_nil()); aFileName->SetValue(file); - SALOMEDS::AttributeFileType_var aFileType; anAttr=aStudyBuilder->FindOrCreateAttribute(aMeshSO, "AttributeFileType"); - aFileType = SALOMEDS::AttributeFileType::_narrow(anAttr); + SALOMEDS::AttributeFileType_wrap aFileType = anAttr; ASSERT(!aFileType->_is_nil()); aFileType->SetValue("FICHIERMED"); } @@ -2924,9 +2859,9 @@ void SMESH_Mesh_i::ExportPartToMED(::SMESH::SMESH_IDSource_ptr meshPart, PrepareForWriting(file, overwrite); string aMeshName = "Mesh"; - SALOMEDS::Study_ptr aStudy = _gen_i->GetCurrentStudy(); + SALOMEDS::Study_var aStudy = _gen_i->GetCurrentStudy(); if ( !aStudy->_is_nil() ) { - SALOMEDS::SObject_var SO = _gen_i->ObjectToSObject( aStudy, meshPart ); + SALOMEDS::SObject_wrap SO = _gen_i->ObjectToSObject( aStudy, meshPart ); if ( !SO->_is_nil() ) { CORBA::String_var name = SO->GetName(); aMeshName = name; @@ -3479,10 +3414,17 @@ SMESH::long_array* SMESH_Mesh_i::GetNodesId() SMESH::ElementType SMESH_Mesh_i::GetElementType( const CORBA::Long id, const bool iselem ) throw (SALOME::SALOME_Exception) { + SMESH::ElementType type; + SMESH_TRY; + if ( _preMeshInfo ) _preMeshInfo->FullLoadFromFile(); - return ( SMESH::ElementType )_impl->GetElementType( id, iselem ); + type = ( SMESH::ElementType ) _impl->GetElementType( id, iselem ); + + SMESH_CATCH( SMESH::throwCorbaException ); + + return type; } //============================================================================= @@ -3512,11 +3454,12 @@ SMESH::EntityType SMESH_Mesh_i::GetElementGeomType( const CORBA::Long id ) SMESH::long_array* SMESH_Mesh_i::GetSubMeshElementsId(const CORBA::Long ShapeID) throw (SALOME::SALOME_Exception) { + SMESH::long_array_var aResult = new SMESH::long_array(); + + SMESH_TRY; if ( _preMeshInfo ) _preMeshInfo->FullLoadFromFile(); - SMESH::long_array_var aResult = new SMESH::long_array(); - SMESH_subMesh* SM = _impl->GetSubMeshContaining(ShapeID); if(!SM) return aResult._retn(); @@ -3531,6 +3474,8 @@ SMESH::long_array* SMESH_Mesh_i::GetSubMeshElementsId(const CORBA::Long ShapeID) aResult[i++] = eIt->next()->GetID(); } + SMESH_CATCH( SMESH::throwCorbaException ); + return aResult._retn(); } @@ -3546,11 +3491,12 @@ SMESH::long_array* SMESH_Mesh_i::GetSubMeshNodesId(const CORBA::Long ShapeID, CORBA::Boolean all) throw (SALOME::SALOME_Exception) { + SMESH::long_array_var aResult = new SMESH::long_array(); + + SMESH_TRY; if ( _preMeshInfo ) _preMeshInfo->FullLoadFromFile(); - SMESH::long_array_var aResult = new SMESH::long_array(); - SMESH_subMesh* SM = _impl->GetSubMeshContaining(ShapeID); if(!SM) return aResult._retn(); @@ -3583,6 +3529,8 @@ SMESH::long_array* SMESH_Mesh_i::GetSubMeshNodesId(const CORBA::Long ShapeID, for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) aResult[i++] = *itElem; + SMESH_CATCH( SMESH::throwCorbaException ); + return aResult._retn(); } @@ -3595,6 +3543,9 @@ SMESH::long_array* SMESH_Mesh_i::GetSubMeshNodesId(const CORBA::Long ShapeID, SMESH::ElementType SMESH_Mesh_i::GetSubMeshElementType(const CORBA::Long ShapeID) throw (SALOME::SALOME_Exception) { + SMESH::ElementType type; + + SMESH_TRY; if ( _preMeshInfo ) _preMeshInfo->FullLoadFromFile(); @@ -3609,7 +3560,12 @@ SMESH::ElementType SMESH_Mesh_i::GetSubMeshElementType(const CORBA::Long ShapeID SMDS_ElemIteratorPtr eIt = SDSM->GetElements(); const SMDS_MeshElement* anElem = eIt->next(); - return ( SMESH::ElementType ) anElem->GetType(); + + type = ( SMESH::ElementType ) anElem->GetType(); + + SMESH_CATCH( SMESH::throwCorbaException ); + + return type; } @@ -3755,6 +3711,52 @@ SMESH::NodePosition* SMESH_Mesh_i::GetNodePosition(CORBA::Long NodeID) return aNodePosition; } +//============================================================================= +/*! + * \brief Return position of an element on shape + */ +//============================================================================= + +SMESH::ElementPosition SMESH_Mesh_i::GetElementPosition(CORBA::Long ElemID) +{ + if ( _preMeshInfo ) + _preMeshInfo->FullLoadFromFile(); + + SMESH::ElementPosition anElementPosition; + anElementPosition.shapeID = 0; + anElementPosition.shapeType = GEOM::SHAPE; + + SMESHDS_Mesh* mesh = _impl->GetMeshDS(); + if ( !mesh ) return anElementPosition; + + if ( const SMDS_MeshElement* anElem = mesh->FindElement( ElemID ) ) + { + anElementPosition.shapeID = anElem->getshapeId(); + const TopoDS_Shape& aSp = mesh->IndexToShape( anElem->getshapeId() ); + if ( !aSp.IsNull() ) { + switch ( aSp.ShapeType() ) { + case TopAbs_EDGE: + anElementPosition.shapeType = GEOM::EDGE; + break; + case TopAbs_FACE: + anElementPosition.shapeType = GEOM::FACE; + break; + case TopAbs_VERTEX: + anElementPosition.shapeType = GEOM::VERTEX; + break; + case TopAbs_SOLID: + anElementPosition.shapeType = GEOM::SOLID; + break; + case TopAbs_SHELL: + anElementPosition.shapeType = GEOM::SHELL; + break; + default:; + } + } + } + return anElementPosition; +} + //============================================================================= /*! * If given element is node returns IDs of shape from position @@ -3803,7 +3805,6 @@ CORBA::Long SMESH_Mesh_i::GetShapeIDForElem(const CORBA::Long id) if(!elem) return -1; - //SMESH::SMESH_MeshEditor_var aMeshEditor = SMESH_Mesh_i::GetMeshEditor(); ::SMESH_MeshEditor aMeshEditor(_impl); int index = aMeshEditor.FindShape( elem ); if(index>0) @@ -4146,7 +4147,7 @@ SMESH::double_array* SMESH_Mesh_i::BaryCenter(const CORBA::Long id) void SMESH_Mesh_i::CreateGroupServants() { - SALOMEDS::Study_ptr aStudy = _gen_i->GetCurrentStudy(); + SALOMEDS::Study_var aStudy = _gen_i->GetCurrentStudy(); set addedIDs; ::SMESH_Mesh::GroupIteratorPtr groupIt = _impl->GetGroups(); @@ -4172,10 +4173,6 @@ void SMESH_Mesh_i::CreateGroupServants() aGroupImpl = new SMESH_Group_i( SMESH_Gen_i::GetPOA(), this, anId ); } - // To ensure correct mapping of servant and correct reference counting in GenericObj_i - SMESH_Gen_i::GetPOA()->activate_object( aGroupImpl ); - aGroupImpl->Register(); - SMESH::SMESH_GroupBase_var groupVar = SMESH::SMESH_GroupBase::_narrow( aGroupImpl->_this() ); _mapGroups[anId] = SMESH::SMESH_GroupBase::_duplicate( groupVar ); @@ -4255,7 +4252,7 @@ void SMESH_Mesh_i::checkGroupNames() if ( !nbGrp ) return; - SALOMEDS::Study_ptr aStudy = _gen_i->GetCurrentStudy(); + SALOMEDS::Study_var aStudy = _gen_i->GetCurrentStudy(); if ( aStudy->_is_nil() ) return; // nothing to do @@ -4271,7 +4268,7 @@ void SMESH_Mesh_i::checkGroupNames() SMESH::SMESH_GroupBase_ptr aGrp = (*grpList)[ gIndx ]; if ( !aGrp ) continue; - SALOMEDS::SObject_var aGrpSO = _gen_i->ObjectToSObject( aStudy, aGrp ); + SALOMEDS::SObject_wrap aGrpSO = _gen_i->ObjectToSObject( aStudy, aGrp ); if ( aGrpSO->_is_nil() ) continue; // correct name of the mesh group if necessary @@ -4315,7 +4312,7 @@ SMESH::string_array* SMESH_Mesh_i::GetLastParameters() SMESH_Gen_i *gen = SMESH_Gen_i::GetSMESHGen(); if(gen) { char *aParameters = GetParameters(); - SALOMEDS::Study_ptr aStudy = gen->GetCurrentStudy(); + SALOMEDS::Study_var aStudy = gen->GetCurrentStudy(); if(!aStudy->_is_nil()) { SALOMEDS::ListOfListOfStrings_var aSections = aStudy->ParseVariables(aParameters); if(aSections->length() > 0) { diff --git a/src/SMESH_I/SMESH_Mesh_i.hxx b/src/SMESH_I/SMESH_Mesh_i.hxx index ca7e1af64..a98be336e 100644 --- a/src/SMESH_I/SMESH_Mesh_i.hxx +++ b/src/SMESH_I/SMESH_Mesh_i.hxx @@ -155,36 +155,31 @@ public: SMESH::SMESH_Group_ptr CutListOfGroups( const SMESH::ListOfGroups& theMainGroups, const SMESH::ListOfGroups& theToolGroups, const char* theName ) - throw (SALOME::SALOME_Exception); + throw (SALOME::SALOME_Exception); SMESH::SMESH_Group_ptr CreateDimGroup( const SMESH::ListOfGroups& theGroups, SMESH::ElementType theElemType, const char* theName ) - throw (SALOME::SALOME_Exception); - + throw (SALOME::SALOME_Exception); - SMESH::SMESH_Group_ptr ConvertToStandalone( SMESH::SMESH_GroupBase_ptr theGroupOn ); -// SMESH::string_array* GetLog(CORBA::Boolean clearAfterGet) -// throw (SALOME::SALOME_Exception); + SMESH::SMESH_Group_ptr ConvertToStandalone( SMESH::SMESH_GroupBase_ptr theGroupOn ) + throw (SALOME::SALOME_Exception); SMESH::log_array* GetLog(CORBA::Boolean clearAfterGet) throw (SALOME::SALOME_Exception); - SMESH::SMESH_MeshEditor_ptr GetMeshEditor(); + SMESH::SMESH_MeshEditor_ptr GetMeshEditor() throw (SALOME::SALOME_Exception); - SMESH::SMESH_MeshEditor_ptr GetMeshEditPreviewer(); + SMESH::SMESH_MeshEditor_ptr GetMeshEditPreviewer() throw (SALOME::SALOME_Exception); CORBA::Boolean HasModificationsToDiscard() throw (SALOME::SALOME_Exception); - void ClearLog() - throw (SALOME::SALOME_Exception); + void ClearLog() throw (SALOME::SALOME_Exception); - CORBA::Long GetId() - throw (SALOME::SALOME_Exception); + CORBA::Long GetId() throw (SALOME::SALOME_Exception); - CORBA::Long GetStudyId() - throw (SALOME::SALOME_Exception); + CORBA::Long GetStudyId() throw (SALOME::SALOME_Exception); // --- C++ interface void SetImpl(::SMESH_Mesh* impl); @@ -464,6 +459,11 @@ public: */ SMESH::NodePosition* GetNodePosition(CORBA::Long NodeID); + /*! + * \brief Return position of an element on shape + */ + SMESH::ElementPosition GetElementPosition(CORBA::Long ElemID); + /*! * If given element is node returns IDs of shape from position * If there is not node for given ID - returns -1 diff --git a/src/SMESH_I/SMESH_NoteBook.cxx b/src/SMESH_I/SMESH_NoteBook.cxx index 7ecbe0823..816a29a97 100644 --- a/src/SMESH_I/SMESH_NoteBook.cxx +++ b/src/SMESH_I/SMESH_NoteBook.cxx @@ -30,6 +30,9 @@ #include #include +#include +#include + #include #include @@ -642,14 +645,14 @@ void SMESH_NoteBook::ReplaceVariables() // this (and above) code can work wrong since nb of states can differ from nb of // dumped calls due to the fix of // issue 0021364:: Dump of netgen parameters has duplicate lines - SMESH_Gen_i *aGen = SMESH_Gen_i::GetSMESHGen(); - SALOMEDS::Study_ptr aStudy = aGen->GetCurrentStudy(); - SALOMEDS::SObject_var sobj = aStudy->FindObjectID( (*it).first.ToCString() ); - CORBA::Object_var obj = aGen->SObjectToObject( sobj ); + SMESH_Gen_i * aGen = SMESH_Gen_i::GetSMESHGen(); + SALOMEDS::Study_var aStudy = aGen->GetCurrentStudy(); + SALOMEDS::SObject_wrap sobj = aStudy->FindObjectID( (*it).first.ToCString() ); + CORBA::Object_var obj = aGen->SObjectToObject( sobj ); if ( SMESH_Hypothesis_i* h = SMESH::DownCast< SMESH_Hypothesis_i*>( obj )) { TState aCurrentState = aStates->GetCurrectState(); - int argIndex = h->getParamIndex( aMethod, aCurrentState.size() ); + int argIndex = h->getParamIndex( aMethod, aCurrentState.size() ); if ( 0 <= argIndex && argIndex < aCurrentState.size() && !aCurrentState[argIndex].IsEmpty() ) aCmd->SetArg( 1, aCurrentState[argIndex] ); @@ -681,22 +684,26 @@ void SMESH_NoteBook::InitObjectMap() if(!aGen) return; - SALOMEDS::Study_ptr aStudy = aGen->GetCurrentStudy(); + SALOMEDS::Study_var aStudy = aGen->GetCurrentStudy(); if(aStudy->_is_nil()) return; - SALOMEDS::SObject_var aSO = aStudy->FindComponent(aGen->ComponentDataType()); + CORBA::String_var compDataType = aGen->ComponentDataType(); + SALOMEDS::SObject_wrap aSO = aStudy->FindComponent( compDataType.in() ); if(CORBA::is_nil(aSO)) return; - SALOMEDS::ChildIterator_var Itr = aStudy->NewChildIterator(aSO); - char* aParameters; - for(Itr->InitEx(true); Itr->More(); Itr->Next()) { - SALOMEDS::SObject_var aSObject = Itr->Value(); - SALOMEDS::GenericAttribute_var anAttr; - if ( aSObject->FindAttribute(anAttr, "AttributeString")) { - aParameters = SALOMEDS::AttributeString::_narrow(anAttr)->Value(); - SALOMEDS::ListOfListOfStrings_var aSections = aStudy->ParseVariables(aParameters); + SALOMEDS::ChildIterator_wrap Itr = aStudy->NewChildIterator(aSO); + CORBA::String_var aParameters; + for( Itr->InitEx(true); Itr->More(); Itr->Next()) + { + SALOMEDS::SObject_wrap aSObject = Itr->Value(); + SALOMEDS::GenericAttribute_wrap anAttr; + if ( aSObject->FindAttribute( anAttr.inout(), "AttributeString")) + { + SALOMEDS::AttributeString_wrap strAttr = anAttr; + aParameters = strAttr->Value(); + SALOMEDS::ListOfListOfStrings_var aSections = aStudy->ParseVariables(aParameters.in()); if(MYDEBUG) { cout<<"Entry : "<< aSObject->GetID()<length(); i++) { TState aVars; SALOMEDS::ListOfStrings aListOfVars = aSections[i]; - for(int j = 0;jIsVariable(aVar.ToCString())) { aVar.InsertBefore(1, SMESH::TVar::Quote() ); @@ -888,7 +896,7 @@ bool SMESH_NoteBook::GetReal(const TCollection_AsciiString& theVarName, double& const char* aName = aVarName.ToCString(); if(aStudy->IsVariable(aName) && (aStudy->IsReal(aName) || aStudy->IsInteger(aName))) { - theValue = aStudy->GetReal(aVarName.ToCString()); + theValue = aStudy->GetReal(aName); ok = true; } diff --git a/src/SMESH_I/SMESH_PreMeshInfo.cxx b/src/SMESH_I/SMESH_PreMeshInfo.cxx index 0a3d58614..caee49db7 100644 --- a/src/SMESH_I/SMESH_PreMeshInfo.cxx +++ b/src/SMESH_I/SMESH_PreMeshInfo.cxx @@ -38,37 +38,24 @@ #include "SMESH_Mesh_i.hxx" #include "SMESH_subMesh_i.hxx" +#include + #include #include #include #include -#include #include +#include -#include -#include #include #include +#include "SMESH_TryCatch.hxx" + #include CORBA_SERVER_HEADER(SALOME_Session) -#define MYDEBUGOUT(msg) //std::cout << msg << std::endl; -//================================================================================ -#define PreMeshInfo_TRY \ - try { OCC_CATCH_SIGNALS -//================================================================================ -#define PreMeshInfo_CATCH } \ - catch (Standard_Failure& ex) { \ - onExceptionCaught(SMESH_Comment("OCC Exception caught: \t")<GetCurrentStudy(); if ( !study->_is_nil() && study->StudyId() == mesh->GetStudyId() ) { - SALOMEDS::SObject_var meshSO = gen->ObjectToSObject(study, mesh->_this() ); - CORBA::Object_var obj = gen->GetNS()->Resolve( "/Kernel/Session" ); + SALOMEDS::SObject_wrap meshSO = gen->ObjectToSObject(study, mesh->_this() ); + CORBA::Object_var obj = gen->GetNS()->Resolve( "/Kernel/Session" ); _session = SALOME::Session::_narrow( obj ); if ( !meshSO->_is_nil() && !_session->_is_nil() ) { @@ -430,7 +405,7 @@ void SMESH_PreMeshInfo::LoadFromFile( SMESH_Mesh_i* mesh, const std::string& hdfFile, const bool toRemoveFiles) { - PreMeshInfo_TRY; + SMESH_TRY; SMESH_PreMeshInfo* meshPreInfo = new SMESH_PreMeshInfo( mesh,meshID,medFile,hdfFile ); mesh->changePreMeshInfo() = meshPreInfo; @@ -454,7 +429,7 @@ void SMESH_PreMeshInfo::LoadFromFile( SMESH_Mesh_i* mesh, { meshPreInfo->FullLoadFromFile(); } - PreMeshInfo_CATCH; + SMESH_CATCH( SMESH::doNothing ); } //================================================================================ @@ -797,7 +772,7 @@ void SMESH_PreMeshInfo::SaveToFile( SMESH_Mesh_i* mesh, HDFgroup* infoHdfGroup = new HDFgroup( hdfGroupName, hdfFile ); infoHdfGroup->CreateOnDisk(); - PreMeshInfo_TRY; + SMESH_TRY; // info of mesh meshInfo2hdf( mesh->GetMeshInfo(), "Mesh", infoHdfGroup ); @@ -840,7 +815,7 @@ void SMESH_PreMeshInfo::SaveToFile( SMESH_Mesh_i* mesh, } } - PreMeshInfo_CATCH; + SMESH_CATCH( SMESH::doNothing ); infoHdfGroup->CloseOnDisk(); } @@ -861,7 +836,7 @@ void SMESH_PreMeshInfo::FullLoadFromFile() const ::SMESH_Mesh& mesh = _mesh->GetImpl(); SMESHDS_Mesh* meshDS = mesh.GetMeshDS(); - PreMeshInfo_TRY; + SMESH_TRY; MYDEBUGOUT( "BEG FullLoadFromFile() " << _meshID ); @@ -882,7 +857,7 @@ void SMESH_PreMeshInfo::FullLoadFromFile() const // load sub-meshes readSubMeshes( &myReader ); - PreMeshInfo_CATCH; + SMESH_CATCH( SMESH::doNothing ); _mesh->changePreMeshInfo() = meshInfo; @@ -929,6 +904,7 @@ void SMESH_PreMeshInfo::readSubMeshes(DriverMED_R_SMESHDS_Mesh* reader) const aDataset->ReadFromDisk( isModified ); aDataset->CloseOnDisk(); _mesh->GetImpl().SetIsModified( bool(*isModified)); + delete [] isModified; } bool submeshesInFamilies = ( ! aTopGroup->ExistInternalObject( "Submeshes" )); @@ -1144,7 +1120,7 @@ void SMESH_PreMeshInfo::readSubMeshes(DriverMED_R_SMESHDS_Mesh* reader) const void SMESH_PreMeshInfo::ForgetAllData() const { - PreMeshInfo_TRY; + SMESH_TRY; if ( _mesh->changePreMeshInfo() != this ) return _mesh->changePreMeshInfo()->ForgetAllData(); @@ -1165,9 +1141,9 @@ void SMESH_PreMeshInfo::ForgetAllData() const map::iterator id2sm = _mesh->_mapSubMeshIor.begin(); for ( ; id2sm != _mesh->_mapSubMeshIor.end(); ++id2sm ) { - if ( SMESH_subMesh_i* sm = SMESH::DownCast( id2sm->second )) + if ( SMESH_subMesh_i* sm_i = SMESH::DownCast( id2sm->second )) { - SMESH_PreMeshInfo* & info = sm->changePreMeshInfo(); + SMESH_PreMeshInfo* & info = sm_i->changePreMeshInfo(); delete info; info = NULL; } @@ -1176,12 +1152,12 @@ void SMESH_PreMeshInfo::ForgetAllData() const _mesh->changePreMeshInfo() = NULL; delete this; - PreMeshInfo_CATCH; + SMESH_CATCH( SMESH::doNothing ); // Finalize loading - // PreMeshInfo_TRY; + // SMESH_TRY; // ::SMESH_Mesh& mesh = _mesh->GetImpl(); @@ -1192,7 +1168,19 @@ void SMESH_PreMeshInfo::ForgetAllData() const // // hyp->UpdateAsMeshesRestored(); - // PreMeshInfo_CATCH; + // SMESH_CATCH( SMESH::doNothing ); +} + +//================================================================================ +/*! + * \brief remove all SMESH_PreMeshInfo fields from mesh and its child objects w/o data loading + */ +//================================================================================ + +void SMESH_PreMeshInfo::ForgetAllData( SMESH_Mesh_i* mesh ) +{ + if ( mesh && mesh->changePreMeshInfo() ) + mesh->changePreMeshInfo()->ForgetAllData(); } //================================================================================ @@ -1274,10 +1262,10 @@ void SMESH_PreMeshInfo::RemoveStudyFiles_TMP_METHOD(SALOMEDS::SComponent_ptr sme SALOMEDS::Study_var study = smeshComp->GetStudy(); if ( theStudyIDToMeshCounter[ (int) study->StudyId() ] > 0 ) { - SALOMEDS::ChildIterator_var itBig = study->NewChildIterator( smeshComp ); + SALOMEDS::ChildIterator_wrap itBig = study->NewChildIterator( smeshComp ); for ( ; itBig->More(); itBig->Next() ) { - SALOMEDS::SObject_var gotBranch = itBig->Value(); - CORBA::Object_var anObject = SMESH_Gen_i::SObjectToObject( gotBranch ); + SALOMEDS::SObject_wrap gotBranch = itBig->Value(); + CORBA::Object_var anObject = SMESH_Gen_i::SObjectToObject( gotBranch ); if ( SMESH_Mesh_i* mesh = SMESH::DownCast( anObject )) { if ( mesh->changePreMeshInfo() ) diff --git a/src/SMESH_I/SMESH_PreMeshInfo.hxx b/src/SMESH_I/SMESH_PreMeshInfo.hxx index 38b15a242..f92ce96c3 100644 --- a/src/SMESH_I/SMESH_PreMeshInfo.hxx +++ b/src/SMESH_I/SMESH_PreMeshInfo.hxx @@ -52,7 +52,7 @@ class SMESH_Mesh_i; class SMESH_PreMeshInfo : public SMDS_MeshInfo { public: - // fills SMESH_PreMeshInfo field of all objects of mesh + // fills SMESH_PreMeshInfo* field of all objects of mesh static void LoadFromFile( SMESH_Mesh_i* mesh, const int meshID, const std::string& medFile, @@ -64,6 +64,9 @@ public: const int meshID, HDFfile* hdfFile); + // remove all SMESH_PreMeshInfo fields from mesh and its child objects w/o data loading + static void ForgetAllData( SMESH_Mesh_i* mesh ); + // reads all data and remove all SMESH_PreMeshInfo fields from objects void FullLoadFromFile() const; diff --git a/src/SMESH_I/smeshpy.py b/src/SMESH_I/smeshpy.py deleted file mode 100644 index fa01ce28f..000000000 --- a/src/SMESH_I/smeshpy.py +++ /dev/null @@ -1,97 +0,0 @@ -# -*- coding: iso-8859-1 -*- -# Copyright (C) 2007-2012 CEA/DEN, EDF R&D, OPEN CASCADE -# -# Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -# CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -# -# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com -# - -# SMESH SMESH_I : idl implementation based on 'SMESH' unit's calsses -# File : smeshpy.py -# Module : SMESH -# -import salome -import SMESH - -from SALOME_utilities import * - -#============================================================================= - -class smeshpy: - _geom = None - _smesh = None - _studyId = None - - #-------------------------------------------------------------------------- - - def __init__(self): - try: - self._geom = salome.lcc.FindOrLoadComponent("FactoryServer","GEOM") - self._smesh = salome.lcc.FindOrLoadComponent("FactoryServer","SMESH") - except: - MESSAGE( "exception in smeshpy:__init__" ) - self._study = salome.myStudy - self._smesh.SetCurrentStudy(self._study) - - #-------------------------------------------------------------------------- - - def CreateMesh(self, shapeId): - try: - shape = salome.IDToObject(shapeId) - aMesh = self._smesh.CreateMesh(shape) - return aMesh - except: - MESSAGE( "exception in smeshpy:Init" ) - return None - - #-------------------------------------------------------------------------- - - def CreateHypothesis(self, name, libname): - try: - hyp = self._smesh.CreateHypothesis(name, libname) - return hyp - except: - MESSAGE( "exception in smeshpy:CreateHypothesis" ) - return None - - #-------------------------------------------------------------------------- - - def Compute(self, mesh, shapeId): - try: - shape = salome.IDToObject(shapeId) - ret=self._smesh.Compute(mesh, shape) - return ret - except: - MESSAGE( "exception in smeshpy:Compute" ) - return 0 - -#============================================================================= -## #-------------------------------------------------------------------------- - -##def SmeshInit(shapeId): -## import salome -## import SMESH -## geom = salome.lcc.FindOrLoadComponent("FactoryServer", "GEOM") -## smesh = salome.lcc.FindOrLoadComponent("FactoryServer", "SMESH") -## shape = salome.IDToObject(shapeId) -## studyId = salome.myStudyId -## MESSAGE( str(studyId) ) -## aMesh = smesh.Init(geom, studyId, shape) -## return aMesh - -## #-------------------------------------------------------------------------- diff --git a/src/SMESH_SWIG/smeshDC.py b/src/SMESH_SWIG/smeshDC.py index c07bfef20..ab1c52ecc 100644 --- a/src/SMESH_SWIG/smeshDC.py +++ b/src/SMESH_SWIG/smeshDC.py @@ -186,7 +186,10 @@ def GetName(obj): if isinstance(obj, SALOMEDS._objref_SObject): # study object return obj.GetName() - ior = salome.orb.object_to_string(obj) + try: + ior = salome.orb.object_to_string(obj) + except: + ior = None if ior: # CORBA object studies = salome.myStudyManager.GetOpenStudies() @@ -520,8 +523,10 @@ class smeshDC(SMESH._objref_SMESH_Gen): # @param mergeNodesAndElements if true, equal nodes and elements aremerged # @param mergeTolerance tolerance for merging nodes # @param allGroups forces creation of groups of all elements + # @param name name of a new mesh def Concatenate( self, meshes, uniteIdenticalGroups, - mergeNodesAndElements = False, mergeTolerance = 1e-5, allGroups = False): + mergeNodesAndElements = False, mergeTolerance = 1e-5, allGroups = False, + name = ""): if not meshes: return None for i,m in enumerate(meshes): if isinstance(m, Mesh): @@ -534,7 +539,7 @@ class smeshDC(SMESH._objref_SMESH_Gen): else: aSmeshMesh = SMESH._objref_SMESH_Gen.Concatenate( self,meshes,uniteIdenticalGroups,mergeNodesAndElements,mergeTolerance) - aMesh = Mesh(self, self.geompyD, aSmeshMesh) + aMesh = Mesh(self, self.geompyD, aSmeshMesh, name=name) return aMesh ## Create a mesh by copying a part of another mesh. @@ -775,36 +780,39 @@ class smeshDC(SMESH._objref_SMESH_Gen): if isinstance( theCriterion, SMESH._objref_NumericalFunctor ): return theCriterion aFilterMgr = self.CreateFilterManager() + functor = None if theCriterion == FT_AspectRatio: - return aFilterMgr.CreateAspectRatio() + functor = aFilterMgr.CreateAspectRatio() elif theCriterion == FT_AspectRatio3D: - return aFilterMgr.CreateAspectRatio3D() + functor = aFilterMgr.CreateAspectRatio3D() elif theCriterion == FT_Warping: - return aFilterMgr.CreateWarping() + functor = aFilterMgr.CreateWarping() elif theCriterion == FT_MinimumAngle: - return aFilterMgr.CreateMinimumAngle() + functor = aFilterMgr.CreateMinimumAngle() elif theCriterion == FT_Taper: - return aFilterMgr.CreateTaper() + functor = aFilterMgr.CreateTaper() elif theCriterion == FT_Skew: - return aFilterMgr.CreateSkew() + functor = aFilterMgr.CreateSkew() elif theCriterion == FT_Area: - return aFilterMgr.CreateArea() + functor = aFilterMgr.CreateArea() elif theCriterion == FT_Volume3D: - return aFilterMgr.CreateVolume3D() + functor = aFilterMgr.CreateVolume3D() elif theCriterion == FT_MaxElementLength2D: - return aFilterMgr.CreateMaxElementLength2D() + functor = aFilterMgr.CreateMaxElementLength2D() elif theCriterion == FT_MaxElementLength3D: - return aFilterMgr.CreateMaxElementLength3D() + functor = aFilterMgr.CreateMaxElementLength3D() elif theCriterion == FT_MultiConnection: - return aFilterMgr.CreateMultiConnection() + functor = aFilterMgr.CreateMultiConnection() elif theCriterion == FT_MultiConnection2D: - return aFilterMgr.CreateMultiConnection2D() + functor = aFilterMgr.CreateMultiConnection2D() elif theCriterion == FT_Length: - return aFilterMgr.CreateLength() + functor = aFilterMgr.CreateLength() elif theCriterion == FT_Length2D: - return aFilterMgr.CreateLength2D() + functor = aFilterMgr.CreateLength2D() else: print "Error: given parameter is not numerical functor type." + aFilterMgr.UnRegister() + return functor ## Creates hypothesis # @param theHType mesh hypothesis type (string) @@ -978,10 +986,11 @@ class Mesh: self.geompyD=geompyD if obj is None: obj = 0 + objHasName = False if obj != 0: - objHasName = True if isinstance(obj, geompyDC.GEOM._objref_GEOM_Object): self.geom = obj + objHasName = True # publish geom of mesh (issue 0021122) if not self.geom.GetStudyEntry() and smeshpyD.GetCurrentStudy(): objHasName = False @@ -990,9 +999,9 @@ class Mesh: geompyD.init_geom( smeshpyD.GetCurrentStudy()) pass if name: - geo_name = name + geo_name = name + " shape" else: - geo_name = "%s_%s_for_meshing"%(self.geom.GetShapeType(), id(self.geom)%100) + geo_name = "%s_%s to mesh"%(self.geom.GetShapeType(), id(self.geom)%100) geompyD.addToStudy( self.geom, geo_name ) self.mesh = self.smeshpyD.CreateMesh(self.geom) @@ -1000,10 +1009,10 @@ class Mesh: self.SetMesh(obj) else: self.mesh = self.smeshpyD.CreateEmptyMesh() - if name != 0: + if name: self.smeshpyD.SetName(self.mesh, name) - elif obj != 0 and objHasName: - self.smeshpyD.SetName(self.mesh, GetName(obj)) + elif objHasName: + self.smeshpyD.SetName(self.mesh, GetName(obj)) # + " mesh" if not self.geom: self.geom = self.mesh.GetShapeToMesh() @@ -1021,8 +1030,11 @@ class Mesh: # @param theMesh a SMESH_Mesh object # @ingroup l2_construct def SetMesh(self, theMesh): + if self.mesh: self.mesh.UnRegister() self.mesh = theMesh - self.geom = self.mesh.GetShapeToMesh() + if self.mesh: + self.mesh.Register() + self.geom = self.mesh.GetShapeToMesh() ## Returns the mesh, that is an instance of SMESH_Mesh interface # @return a SMESH_Mesh object @@ -1096,19 +1108,25 @@ class Mesh: return self.smeshpyD.GetGeometryByMeshElement( self.mesh, theElementID, theGeomName ) ## Returns the mesh dimension depending on the dimension of the underlying shape + # or, if the mesh is not based on any shape, basing on deimension of elements # @return mesh dimension as an integer value [0,3] # @ingroup l1_auxiliary def MeshDimension(self): - shells = self.geompyD.SubShapeAllIDs( self.geom, geompyDC.ShapeType["SHELL"] ) - if len( shells ) > 0 : - return 3 - elif self.geompyD.NumberOfFaces( self.geom ) > 0 : - return 2 - elif self.geompyD.NumberOfEdges( self.geom ) > 0 : - return 1 + if self.mesh.HasShapeToMesh(): + shells = self.geompyD.SubShapeAllIDs( self.geom, geompyDC.ShapeType["SOLID"] ) + if len( shells ) > 0 : + return 3 + elif self.geompyD.NumberOfFaces( self.geom ) > 0 : + return 2 + elif self.geompyD.NumberOfEdges( self.geom ) > 0 : + return 1 + else: + return 0; else: - return 0; - pass + if self.NbVolumes() > 0: return 3 + if self.NbFaces() > 0: return 2 + if self.NbEdges() > 0: return 1 + return 0 ## Evaluates size of prospective mesh on a shape # @return a list where i-th element is a number of elements of i-th SMESH.EntityType @@ -1190,7 +1208,7 @@ class Mesh: "Invalid input mesh", #COMPERR_BAD_INPUT_MESH "std::exception", #COMPERR_STD_EXCEPTION "OCC exception", #COMPERR_OCC_EXCEPTION - "SALOME exception", #COMPERR_SLM_EXCEPTION + "..", #COMPERR_SLM_EXCEPTION "Unknown exception", #COMPERR_EXCEPTION "Memory allocation problem", #COMPERR_MEMORY_PB "Algorithm failed", #COMPERR_ALGO_FAILED @@ -1275,7 +1293,8 @@ class Mesh: # @ingroup l2_construct def Clear(self): self.mesh.Clear() - if salome.sg.hasDesktop(): + if ( salome.sg.hasDesktop() and + salome.myStudyManager.GetStudyByID( self.mesh.GetStudyId() )): smeshgui = salome.ImportComponentGUI("SMESH") smeshgui.Init(self.mesh.GetStudyId()) smeshgui.SetMeshIcon( salome.ObjectToID( self.mesh ), False, True ) @@ -1356,7 +1375,7 @@ class Mesh: # @return True of False # @ingroup l2_hypotheses def IsUsedHypothesis(self, hyp, geom): - if not hyp or not geom: + if not hyp: # or not geom return False if isinstance( hyp, Mesh_Algorithm ): hyp = hyp.GetAlgorithm() @@ -1376,11 +1395,16 @@ class Mesh: if isinstance( hyp, Mesh_Algorithm ): hyp = hyp.GetAlgorithm() pass - if not geom: - geom = self.geom + shape = geom + if not shape: + shape = self.geom pass - status = self.mesh.RemoveHypothesis(geom, hyp) - return status + if self.IsUsedHypothesis( hyp, shape ): + return self.mesh.RemoveHypothesis( shape, hyp ) + hypName = GetName( hyp ) + geoName = GetName( shape ) + print "WARNING: RemoveHypothesis() failed as '%s' is not assigned to '%s' shape" % ( hypName, geoName ) + return None ## Gets the list of hypotheses added on a geometry # @param geom a sub-shape of mesh geometry @@ -2109,6 +2133,12 @@ class Mesh: def GetNodePosition(self,NodeID): return self.mesh.GetNodePosition(NodeID) + ## @brief Returns the position of an element on the shape + # @return SMESH::ElementPosition + # @ingroup l1_meshinfo + def GetElementPosition(self,ElemID): + return self.mesh.GetElementPosition(ElemID) + ## If the given element is a node, returns the ID of shape # \n If there is no node for the given ID - returns -1 # @return an integer value @@ -3186,7 +3216,9 @@ class Mesh: ## Generates new elements by extrusion of the elements with given ids # @param IDsOfElements the list of elements ids for extrusion - # @param StepVector vector or DirStruct, defining the direction and value of extrusion for one step (the total extrusion length will be NbOfSteps * ||StepVector||) + # @param StepVector vector or DirStruct or 3 vector components, defining + # the direction and value of extrusion for one step (the total extrusion + # length will be NbOfSteps * ||StepVector||) # @param NbOfSteps the number of steps # @param MakeGroups forces the generation of new groups from existing ones # @param IsNodes is True if elements with given ids are nodes @@ -3195,8 +3227,10 @@ class Mesh: def ExtrusionSweep(self, IDsOfElements, StepVector, NbOfSteps, MakeGroups=False, IsNodes = False): if IDsOfElements == []: IDsOfElements = self.GetElementsId() - if ( isinstance( StepVector, geompyDC.GEOM._objref_GEOM_Object)): + if isinstance( StepVector, geompyDC.GEOM._objref_GEOM_Object): StepVector = self.smeshpyD.GetDirStruct(StepVector) + if isinstance( StepVector, list ): + StepVector = self.smeshpyD.MakeDirStruct(*StepVector) NbOfSteps,Parameters,hasVars = ParseParameters(NbOfSteps) Parameters = StepVector.PS.parameters + var_separator + Parameters self.mesh.SetParameters(Parameters) @@ -3213,7 +3247,9 @@ class Mesh: ## Generates new elements by extrusion of the elements with given ids # @param IDsOfElements is ids of elements - # @param StepVector vector, defining the direction and value of extrusion + # @param StepVector vector or DirStruct or 3 vector components, defining + # the direction and value of extrusion for one step (the total extrusion + # length will be NbOfSteps * ||StepVector||) # @param NbOfSteps the number of steps # @param ExtrFlags sets flags for extrusion # @param SewTolerance uses for comparing locations of nodes if flag @@ -3225,6 +3261,8 @@ class Mesh: ExtrFlags, SewTolerance, MakeGroups=False): if ( isinstance( StepVector, geompyDC.GEOM._objref_GEOM_Object)): StepVector = self.smeshpyD.GetDirStruct(StepVector) + if isinstance( StepVector, list ): + StepVector = self.smeshpyD.MakeDirStruct(*StepVector) if MakeGroups: return self.editor.AdvancedExtrusionMakeGroups(IDsOfElements, StepVector, NbOfSteps, ExtrFlags, SewTolerance) @@ -3235,7 +3273,9 @@ class Mesh: ## Generates new elements by extrusion of the elements which belong to the object # @param theObject the object which elements should be processed. # It can be a mesh, a sub mesh or a group. - # @param StepVector vector, defining the direction and value of extrusion for one step (the total extrusion length will be NbOfSteps * ||StepVector||) + # @param StepVector vector or DirStruct or 3 vector components, defining + # the direction and value of extrusion for one step (the total extrusion + # length will be NbOfSteps * ||StepVector||) # @param NbOfSteps the number of steps # @param MakeGroups forces the generation of new groups from existing ones # @param IsNodes is True if elements which belong to the object are nodes @@ -3246,6 +3286,8 @@ class Mesh: theObject = theObject.GetMesh() if ( isinstance( StepVector, geompyDC.GEOM._objref_GEOM_Object)): StepVector = self.smeshpyD.GetDirStruct(StepVector) + if isinstance( StepVector, list ): + StepVector = self.smeshpyD.MakeDirStruct(*StepVector) NbOfSteps,Parameters,hasVars = ParseParameters(NbOfSteps) Parameters = StepVector.PS.parameters + var_separator + Parameters self.mesh.SetParameters(Parameters) @@ -3263,7 +3305,9 @@ class Mesh: ## Generates new elements by extrusion of the elements which belong to the object # @param theObject object which elements should be processed. # It can be a mesh, a sub mesh or a group. - # @param StepVector vector, defining the direction and value of extrusion for one step (the total extrusion length will be NbOfSteps * ||StepVector||) + # @param StepVector vector or DirStruct or 3 vector components, defining + # the direction and value of extrusion for one step (the total extrusion + # length will be NbOfSteps * ||StepVector||) # @param NbOfSteps the number of steps # @param MakeGroups to generate new groups from existing ones # @return list of created groups (SMESH_GroupBase) if MakeGroups=True, empty list otherwise @@ -3273,6 +3317,8 @@ class Mesh: theObject = theObject.GetMesh() if ( isinstance( StepVector, geompyDC.GEOM._objref_GEOM_Object)): StepVector = self.smeshpyD.GetDirStruct(StepVector) + if isinstance( StepVector, list ): + StepVector = self.smeshpyD.MakeDirStruct(*StepVector) NbOfSteps,Parameters,hasVars = ParseParameters(NbOfSteps) Parameters = StepVector.PS.parameters + var_separator + Parameters self.mesh.SetParameters(Parameters) @@ -3284,7 +3330,9 @@ class Mesh: ## Generates new elements by extrusion of the elements which belong to the object # @param theObject object which elements should be processed. # It can be a mesh, a sub mesh or a group. - # @param StepVector vector, defining the direction and value of extrusion for one step (the total extrusion length will be NbOfSteps * ||StepVector||) + # @param StepVector vector or DirStruct or 3 vector components, defining + # the direction and value of extrusion for one step (the total extrusion + # length will be NbOfSteps * ||StepVector||) # @param NbOfSteps the number of steps # @param MakeGroups forces the generation of new groups from existing ones # @return list of created groups (SMESH_GroupBase) if MakeGroups=True, empty list otherwise @@ -3294,6 +3342,8 @@ class Mesh: theObject = theObject.GetMesh() if ( isinstance( StepVector, geompyDC.GEOM._objref_GEOM_Object)): StepVector = self.smeshpyD.GetDirStruct(StepVector) + if isinstance( StepVector, list ): + StepVector = self.smeshpyD.MakeDirStruct(*StepVector) NbOfSteps,Parameters,hasVars = ParseParameters(NbOfSteps) Parameters = StepVector.PS.parameters + var_separator + Parameters self.mesh.SetParameters(Parameters) diff --git a/src/SMESH_SWIG_WITHIHM/libSMESH_Swig.cxx b/src/SMESH_SWIG_WITHIHM/libSMESH_Swig.cxx index 679a8d853..905ca5f51 100644 --- a/src/SMESH_SWIG_WITHIHM/libSMESH_Swig.cxx +++ b/src/SMESH_SWIG_WITHIHM/libSMESH_Swig.cxx @@ -83,12 +83,15 @@ namespace SALOMEDS::GenericAttribute_var anAttr = theStudyBuilder->FindOrCreateAttribute(aDomainRoot,"AttributeName"); SALOMEDS::AttributeName_var aName = SALOMEDS::AttributeName::_narrow(anAttr); aName->SetValue(theName.toLatin1().data()); + aName->UnRegister(); anAttr = theStudyBuilder->FindOrCreateAttribute(aDomainRoot,"AttributePixMap"); SALOMEDS::AttributePixMap_var aPixmap = SALOMEDS::AttributePixMap::_narrow(anAttr); aPixmap->SetPixMap(thePixmap.toLatin1().data()); + aPixmap->UnRegister(); anAttr = theStudyBuilder->FindOrCreateAttribute(aDomainRoot,"AttributeSelectable"); SALOMEDS::AttributeSelectable_var aSelAttr = SALOMEDS::AttributeSelectable::_narrow(anAttr); aSelAttr->SetSelectable(false); + aSelAttr->UnRegister(); } return aDomainRoot; @@ -126,12 +129,12 @@ namespace //--------------------------------------------------------------- inline SALOMEDS::SObject_var - AddToDomain(const std::string& theIOR, - const SALOMEDS::SComponent_var& theSComponentMesh, + AddToDomain(const std::string& theIOR, + const SALOMEDS::SComponent_var& theSComponentMesh, const SALOMEDS::StudyBuilder_var& theStudyBuilder, - CORBA::Long theDomainRootTag, - const QString& theDomainName, - const QString& theDomainPixmap) + CORBA::Long theDomainRootTag, + const QString& theDomainName, + const QString& theDomainPixmap) { SALOMEDS::SObject_var aDomain = GetDomainRoot(theSComponentMesh, theStudyBuilder, @@ -140,6 +143,7 @@ namespace theDomainPixmap); // Add New Hypothesis SALOMEDS::SObject_var aSObject = theStudyBuilder->NewObject(aDomain); + aDomain->UnRegister(); SALOMEDS::GenericAttribute_var anAttr = theStudyBuilder->FindOrCreateAttribute(aSObject,"AttributePixMap"); SALOMEDS::AttributePixMap_var aPixmap = SALOMEDS::AttributePixMap::_narrow(anAttr); CORBA::Object_var anObject = StringToObject(theIOR); @@ -147,9 +151,11 @@ namespace CORBA::String_var aType = aDomainItem->GetName(); QString aPixmapName = theDomainPixmap + "_" + aType.in(); aPixmap->SetPixMap(aPixmapName.toLatin1().data()); + aPixmap->UnRegister(); anAttr = theStudyBuilder->FindOrCreateAttribute(aSObject,"AttributeIOR"); SALOMEDS::AttributeIOR_var anIOR = SALOMEDS::AttributeIOR::_narrow(anAttr); anIOR->SetValue(theIOR.c_str()); + anIOR->UnRegister(); return aSObject; } @@ -187,44 +193,52 @@ namespace //--------------------------------------------------------------- void - SetDomain(const char* theMeshOrSubMeshEntry, - const char* theDomainEntry, - const SALOMEDS::Study_var& theStudy, + SetDomain(const char* theMeshOrSubMeshEntry, + const char* theDomainEntry, + const SALOMEDS::Study_var& theStudy, const SALOMEDS::StudyBuilder_var& theStudyBuilder, - long theRefOnAppliedDomainTag, - const QString& theAppliedDomainMEN, - const QString& theAppliedDomainICON) + long theRefOnAppliedDomainTag, + const QString& theAppliedDomainMEN, + const QString& theAppliedDomainICON) { SALOMEDS::SObject_var aMeshOrSubMeshSO = theStudy->FindObjectID(theMeshOrSubMeshEntry); - SALOMEDS::SObject_var aHypothesisSO = theStudy->FindObjectID(theDomainEntry); + SALOMEDS::SObject_var aHypothesisSO = theStudy->FindObjectID(theDomainEntry); if(!aMeshOrSubMeshSO->_is_nil() && !aHypothesisSO->_is_nil()){ //Find or Create Applied Hypothesis root SALOMEDS::SObject_var anAppliedDomainSO; - if(!aMeshOrSubMeshSO->FindSubObject(theRefOnAppliedDomainTag,anAppliedDomainSO)){ + if( !aMeshOrSubMeshSO->FindSubObject( theRefOnAppliedDomainTag, anAppliedDomainSO )) + { anAppliedDomainSO = theStudyBuilder->NewObjectToTag(aMeshOrSubMeshSO,theRefOnAppliedDomainTag); SALOMEDS::GenericAttribute_var anAttr = theStudyBuilder->FindOrCreateAttribute(anAppliedDomainSO,"AttributeName"); SALOMEDS::AttributeName_var aName = SALOMEDS::AttributeName::_narrow(anAttr); aName->SetValue(theAppliedDomainMEN.toLatin1().data()); + aName->UnRegister(); anAttr = theStudyBuilder->FindOrCreateAttribute(anAppliedDomainSO,"AttributeSelectable"); SALOMEDS::AttributeSelectable_var aSelAttr = SALOMEDS::AttributeSelectable::_narrow(anAttr); aSelAttr->SetSelectable(false); + aSelAttr->UnRegister(); anAttr = theStudyBuilder->FindOrCreateAttribute(anAppliedDomainSO,"AttributePixMap"); SALOMEDS::AttributePixMap_var aPixmap = SALOMEDS::AttributePixMap::_narrow(anAttr); aPixmap->SetPixMap(theAppliedDomainICON.toLatin1().data()); + aPixmap->UnRegister(); } SALOMEDS::SObject_var aSObject = theStudyBuilder->NewObject(anAppliedDomainSO); theStudyBuilder->Addreference(aSObject,aHypothesisSO); + aSObject->UnRegister(); + anAppliedDomainSO->UnRegister(); } + if ( !aMeshOrSubMeshSO->_is_nil() ) aMeshOrSubMeshSO->UnRegister(); + if ( !aHypothesisSO->_is_nil()) aHypothesisSO->UnRegister(); } //--------------------------------------------------------------- void - SetHypothesis(const char* theMeshOrSubMeshEntry, - const char* theDomainEntry, - const SALOMEDS::Study_var& theStudy, + SetHypothesis(const char* theMeshOrSubMeshEntry, + const char* theDomainEntry, + const SALOMEDS::Study_var& theStudy, const SALOMEDS::StudyBuilder_var& theStudyBuilder) { SetDomain(theMeshOrSubMeshEntry, @@ -239,9 +253,9 @@ namespace //--------------------------------------------------------------- void - SetAlgorithms(const char* theMeshOrSubMeshEntry, - const char* theDomainEntry, - const SALOMEDS::Study_var& theStudy, + SetAlgorithms(const char* theMeshOrSubMeshEntry, + const char* theDomainEntry, + const SALOMEDS::Study_var& theStudy, const SALOMEDS::StudyBuilder_var& theStudyBuilder) { SetDomain(theMeshOrSubMeshEntry, @@ -296,31 +310,36 @@ SMESH_Swig::Init(int theStudyID) { class TEvent: public SALOME_Event { - int myStudyID; - SALOMEDS::Study_var& myStudy; + int myStudyID; + SALOMEDS::Study_var& myStudy; SALOMEDS::StudyBuilder_var& myStudyBuilder; - SALOMEDS::SComponent_var& mySComponentMesh; + SALOMEDS::SComponent_var& mySComponentMesh; public: - TEvent(int theStudyID, - SALOMEDS::Study_var& theStudy, + TEvent(int theStudyID, + SALOMEDS::Study_var& theStudy, SALOMEDS::StudyBuilder_var& theStudyBuilder, - SALOMEDS::SComponent_var& theSComponentMesh): - myStudyID(theStudyID), - myStudy(theStudy), - myStudyBuilder(theStudyBuilder), + SALOMEDS::SComponent_var& theSComponentMesh): + myStudyID (theStudyID), + myStudy (theStudy), + myStudyBuilder (theStudyBuilder), mySComponentMesh(theSComponentMesh) {} + ~TEvent() + { + if ( !mySComponentMesh->_is_nil() ) mySComponentMesh->UnRegister(); + } + virtual void Execute() { - SUIT_Session* aSession = SUIT_Session::session(); + SUIT_Session* aSession = SUIT_Session::session(); SUIT_Application* anApplication = aSession->activeApplication(); - SalomeApp_Application* anApp = dynamic_cast(anApplication); + SalomeApp_Application* anApp = dynamic_cast(anApplication); SALOME_NamingService* aNamingService = anApp->namingService(); - CORBA::Object_var anObject = aNamingService->Resolve("/myStudyManager"); + CORBA::Object_var anObject = aNamingService->Resolve("/myStudyManager"); SALOMEDS::StudyManager_var aStudyMgr = SALOMEDS::StudyManager::_narrow(anObject); myStudy = aStudyMgr->GetStudyByID(myStudyID); @@ -334,26 +353,33 @@ SMESH_Swig::Init(int theStudyID) SALOMEDS::AttributePixMap_var aPixmap; SALOMEDS::SComponent_var aSComponent = myStudy->FindComponent("SMESH"); - if(aSComponent->_is_nil()){ + if ( aSComponent->_is_nil() ) + { bool aLocked = myStudy->GetProperties()->IsLocked(); if (aLocked) myStudy->GetProperties()->SetLocked(false); - - aSComponent = myStudyBuilder->NewComponent("SMESH"); - anAttr = myStudyBuilder->FindOrCreateAttribute(aSComponent,"AttributeName"); - aName = SALOMEDS::AttributeName::_narrow(anAttr); - SMESHGUI* aSMESHGUI = SMESHGUI::GetSMESHGUI(); //SRN: BugID IPAL9186, load a SMESH gui if it hasn't been loaded - if (!aSMESHGUI){ + SMESHGUI* aSMESHGUI = SMESHGUI::GetSMESHGUI(); + //SRN: BugID IPAL9186, load a SMESH gui if it hasn't been loaded + if (!aSMESHGUI) { CAM_Module* aModule = anApp->module("Mesh"); if(!aModule) - aModule = anApp->loadModule("Mesh"); + aModule = anApp->loadModule("Mesh"); aSMESHGUI = dynamic_cast(aModule); } //SRN: BugID IPAL9186: end of a fix + + aSComponent = myStudyBuilder->NewComponent("SMESH"); + + anAttr = myStudyBuilder->FindOrCreateAttribute(aSComponent,"AttributeName"); + aName = SALOMEDS::AttributeName::_narrow(anAttr); aName->SetValue(aSMESHGUI->moduleName().toLatin1().data()); + aName->UnRegister(); + anAttr = myStudyBuilder->FindOrCreateAttribute(aSComponent,"AttributePixMap"); aPixmap = SALOMEDS::AttributePixMap::_narrow(anAttr); aPixmap->SetPixMap( "ICON_OBJBROWSER_SMESH" ); + aPixmap->UnRegister(); + myStudyBuilder->DefineComponentInstance(aSComponent,aSMESHGen); if (aLocked) myStudy->GetProperties()->SetLocked(true); @@ -388,22 +414,29 @@ const char* SMESH_Swig::AddNewMesh(const char* theIOR) // VSR: added temporarily - to be removed - objects are published automatically by engine SALOMEDS::SObject_var aSObject = myStudy->FindObjectIOR(theIOR); - if (aSObject->_is_nil()){ + if (aSObject->_is_nil()) + { //Find or Create Hypothesis root - GetHypothesisRoot(mySComponentMesh,myStudyBuilder); - GetAlgorithmsRoot(mySComponentMesh,myStudyBuilder); + SALOMEDS::SObject_var hroot = GetHypothesisRoot(mySComponentMesh,myStudyBuilder); + SALOMEDS::SObject_var aroot = GetAlgorithmsRoot(mySComponentMesh,myStudyBuilder); + hroot->UnRegister(); + aroot->UnRegister(); // Add New Mesh aSObject = myStudyBuilder->NewObject(mySComponentMesh); SALOMEDS::GenericAttribute_var anAttr = myStudyBuilder->FindOrCreateAttribute(aSObject,"AttributePixMap"); SALOMEDS::AttributePixMap_var aPixmap = SALOMEDS::AttributePixMap::_narrow(anAttr); aPixmap->SetPixMap( "ICON_SMESH_TREE_MESH" ); + aPixmap->UnRegister(); + anAttr = myStudyBuilder->FindOrCreateAttribute(aSObject, "AttributeIOR"); SALOMEDS::AttributeIOR_var anIOR = SALOMEDS::AttributeIOR::_narrow(anAttr); anIOR->SetValue(theIOR); + anIOR->UnRegister(); } CORBA::String_var anEntry = aSObject->GetID(); + aSObject->UnRegister(); return anEntry._retn(); } @@ -418,6 +451,8 @@ const char* SMESH_Swig::AddNewHypothesis(const char* theIOR) mySComponentMesh, myStudyBuilder); CORBA::String_var anEntry = aSObject->GetID(); + aSObject->UnRegister(); + return anEntry._retn(); } @@ -431,6 +466,8 @@ const char* SMESH_Swig::AddNewAlgorithms(const char* theIOR) mySComponentMesh, myStudyBuilder); CORBA::String_var anEntry = aSObject->GetID(); + aSObject->UnRegister(); + return anEntry._retn(); } @@ -439,13 +476,16 @@ const char* SMESH_Swig::AddNewAlgorithms(const char* theIOR) void SMESH_Swig::SetShape(const char* theShapeEntry, const char* theMeshEntry) { - SALOMEDS::SObject_var aMeshSO = myStudy->FindObjectID( theMeshEntry ); SALOMEDS::SObject_var aGeomShapeSO = myStudy->FindObjectID( theShapeEntry ); + SALOMEDS::SObject_var aMeshSO = myStudy->FindObjectID( theMeshEntry ); if(!aMeshSO->_is_nil() && !aGeomShapeSO->_is_nil()){ SALOMEDS::SObject_var aSObject = myStudyBuilder->NewObjectToTag(aMeshSO, SMESH::Tag_RefOnShape); myStudyBuilder->Addreference(aSObject,aGeomShapeSO); + aSObject->UnRegister(); } + if ( !aMeshSO->_is_nil() ) aMeshSO->UnRegister(); + if ( !aGeomShapeSO->_is_nil() ) aGeomShapeSO->UnRegister(); } @@ -485,49 +525,57 @@ const char* SMESH_Swig::AddSubMesh(const char* theMeshEntry, int theShapeType) { SALOMEDS::SObject_var aMeshSO = myStudy->FindObjectID(theMeshEntry); - if(!aMeshSO->_is_nil()){ + if(!aMeshSO->_is_nil()) { long aShapeTag; QString aSubMeshName; - switch(theShapeType){ + switch(theShapeType) { case TopAbs_SOLID: - aShapeTag = SMESH::Tag_SubMeshOnSolid; + aShapeTag = SMESH::Tag_SubMeshOnSolid; aSubMeshName = QObject::tr("SMESH_MEN_SubMeshesOnSolid"); break; case TopAbs_FACE: - aShapeTag = SMESH::Tag_SubMeshOnFace; + aShapeTag = SMESH::Tag_SubMeshOnFace; aSubMeshName = QObject::tr("SMESH_MEN_SubMeshesOnFace"); break; case TopAbs_EDGE: - aShapeTag = SMESH::Tag_SubMeshOnEdge; + aShapeTag = SMESH::Tag_SubMeshOnEdge; aSubMeshName = QObject::tr("SMESH_MEN_SubMeshesOnEdge"); break; case TopAbs_VERTEX: - aShapeTag = SMESH::Tag_SubMeshOnVertex; + aShapeTag = SMESH::Tag_SubMeshOnVertex; aSubMeshName = QObject::tr("SMESH_MEN_SubMeshesOnVertex"); break; default: - aShapeTag = SMESH::Tag_SubMeshOnCompound; + aShapeTag = SMESH::Tag_SubMeshOnCompound; aSubMeshName = QObject::tr("SMESH_MEN_SubMeshesOnCompound"); } - SALOMEDS::SObject_var aSubMeshesRoot; SALOMEDS::GenericAttribute_var anAttr; - if(!aMeshSO->FindSubObject(aShapeTag,aSubMeshesRoot)){ + SALOMEDS::SObject_var aSubMeshesRoot; + if ( !aMeshSO->FindSubObject( aShapeTag, aSubMeshesRoot ) ) + { aSubMeshesRoot = myStudyBuilder->NewObjectToTag(aMeshSO,aShapeTag); anAttr = myStudyBuilder->FindOrCreateAttribute(aSubMeshesRoot,"AttributeName"); SALOMEDS::AttributeName_var aName = SALOMEDS::AttributeName::_narrow(anAttr); aName->SetValue(aSubMeshName.toLatin1().data()); + aName->UnRegister(); anAttr = myStudyBuilder->FindOrCreateAttribute(aSubMeshesRoot,"AttributeSelectable"); SALOMEDS::AttributeSelectable_var aSelAttr = SALOMEDS::AttributeSelectable::_narrow(anAttr); aSelAttr->SetSelectable(false); + aSelAttr->UnRegister(); } + aSubMeshesRoot->UnRegister(); + aMeshSO->UnRegister(); SALOMEDS::SObject_var aSObject = myStudyBuilder->NewObject(aSubMeshesRoot); anAttr = myStudyBuilder->FindOrCreateAttribute(aSObject,"AttributeIOR"); SALOMEDS::AttributeIOR_var anIOR = SALOMEDS::AttributeIOR::_narrow(anAttr); anIOR->SetValue(theSubMeshIOR); + anIOR->UnRegister(); CORBA::String_var aString = aSObject->GetID(); + aSObject->UnRegister(); + return aString._retn(); } @@ -537,17 +585,20 @@ const char* SMESH_Swig::AddSubMesh(const char* theMeshEntry, const char* SMESH_Swig::AddSubMeshOnShape(const char* theMeshEntry, const char* theGeomShapeEntry, const char* theSubMeshIOR, - int ShapeType) + int ShapeType) { SALOMEDS::SObject_var aGeomShapeSO = myStudy->FindObjectID(theGeomShapeEntry); - if(!aGeomShapeSO->_is_nil()){ - const char * aSubMeshEntry = AddSubMesh(theMeshEntry,theSubMeshIOR,ShapeType); + if(!aGeomShapeSO->_is_nil()) + { + const char * aSubMeshEntry = AddSubMesh(theMeshEntry,theSubMeshIOR,ShapeType); SALOMEDS::SObject_var aSubMeshSO = myStudy->FindObjectID(aSubMeshEntry); - if(!aSubMeshSO->_is_nil()){ - SetShape(theGeomShapeEntry,aSubMeshEntry); + if ( !aSubMeshSO->_is_nil()) { + SetShape( theGeomShapeEntry, aSubMeshEntry ); CORBA::String_var aString = aSubMeshSO->GetID(); + aSubMeshSO->UnRegister(); return aString._retn(); } + aGeomShapeSO->UnRegister(); } return ""; @@ -566,11 +617,11 @@ void SMESH_Swig::CreateAndDisplayActor( const char* Mesh_Entry ) } virtual void Execute() { //SMESH::UpdateView(SMESH::eDisplay, _entry); - SUIT_Session* aSession = SUIT_Session::session(); + SUIT_Session* aSession = SUIT_Session::session(); SUIT_Application* anApplication = aSession->activeApplication(); - SalomeApp_Application* anApp = dynamic_cast(anApplication); - /*SUIT_ViewManager* vman = */anApp->getViewManager(VTKViewer_Viewer::Type(),true); - SMESHGUI_Displayer* aDisp = new SMESHGUI_Displayer(anApp); + SalomeApp_Application* anApp = dynamic_cast(anApplication); + /*SUIT_ViewManager* vman = */anApp->getViewManager(VTKViewer_Viewer::Type(),true); + SMESHGUI_Displayer* aDisp = new SMESHGUI_Displayer(anApp); aDisp->Display(_entry,1); } }; @@ -584,31 +635,31 @@ void SMESH_Swig::EraseActor( const char* Mesh_Entry, const bool allViewers ) { private: const char* _entry; - bool _allViewers; + bool _allViewers; public: TEvent(const char* Mesh_Entry, const bool allViewers ) { _entry = Mesh_Entry; _allViewers = allViewers; } virtual void Execute() { - SUIT_Session* aSession = SUIT_Session::session(); + SUIT_Session* aSession = SUIT_Session::session(); SUIT_Application* anApplication = aSession->activeApplication(); - SalomeApp_Application* anApp = dynamic_cast(anApplication); - SMESHGUI_Displayer* aDisp = new SMESHGUI_Displayer(anApp); + SalomeApp_Application* anApp = dynamic_cast(anApplication); + SMESHGUI_Displayer* aDisp = new SMESHGUI_Displayer(anApp); ViewManagerList aManagers; if ( !_allViewers ) { - aManagers << anApp->activeViewManager(); + aManagers << anApp->activeViewManager(); } else { - aManagers = anApp->viewManagers(); + aManagers = anApp->viewManagers(); } foreach( SUIT_ViewManager* aMgr, aManagers ) { - if ( aMgr && aMgr->getType() == VTKViewer_Viewer::Type() ) { - SALOME_View* aSalomeView = dynamic_cast(aMgr->getViewModel()); - if (aSalomeView) { - aDisp->Erase(_entry,true, true, aSalomeView); - } - } + if ( aMgr && aMgr->getType() == VTKViewer_Viewer::Type() ) { + SALOME_View* aSalomeView = dynamic_cast(aMgr->getViewModel()); + if (aSalomeView) { + aDisp->Erase(_entry,true, true, aSalomeView); + } + } } } }; @@ -626,6 +677,8 @@ void SMESH_Swig::SetName(const char* theEntry, anAttr = myStudyBuilder->FindOrCreateAttribute(aSObject,"AttributeName"); aName = SALOMEDS::AttributeName::_narrow(anAttr); aName->SetValue(theName); + aName->UnRegister(); + aSObject->UnRegister(); } } @@ -638,33 +691,33 @@ void SMESH_Swig::SetName(const char* theEntry, //================================================================================ void SMESH_Swig::SetMeshIcon(const char* theMeshEntry, - const bool theIsComputed, - const bool isEmpty) + const bool theIsComputed, + const bool isEmpty) { class TEvent: public SALOME_Event { SALOMEDS::Study_var myStudy; - std::string myMeshEntry; - bool myIsComputed, myIsEmpty; + std::string myMeshEntry; + bool myIsComputed, myIsEmpty; public: TEvent(const SALOMEDS::Study_var& theStudy, - const std::string& theMeshEntry, - const bool theIsComputed, - const bool isEmpty): - myStudy(theStudy), - myMeshEntry(theMeshEntry), + const std::string& theMeshEntry, + const bool theIsComputed, + const bool isEmpty): + myStudy (theStudy), + myMeshEntry (theMeshEntry), myIsComputed(theIsComputed), - myIsEmpty(isEmpty) + myIsEmpty (isEmpty) {} virtual void Execute() { - SALOMEDS::SObject_var aMeshSO = myStudy->FindObjectID(myMeshEntry.c_str()); - if(!aMeshSO->_is_nil()) - if(_PTR(SObject) aMesh = ClientFactory::SObject(aMeshSO)) - SMESH::ModifiedMesh(aMesh,myIsComputed,myIsEmpty); + SALOMEDS::SObject_ptr aMeshSO = myStudy->FindObjectID(myMeshEntry.c_str()); + if(_PTR(SObject) aMesh = ClientFactory::SObject(aMeshSO)) + SMESH::ModifiedMesh(aMesh,myIsComputed,myIsEmpty); + // aMeshSO->UnRegister(); ~aMesh() already called UnRegister()! } }; diff --git a/src/StdMeshers/StdMeshers_Cartesian_3D.cxx b/src/StdMeshers/StdMeshers_Cartesian_3D.cxx index 20283d9ca..937c86806 100644 --- a/src/StdMeshers/StdMeshers_Cartesian_3D.cxx +++ b/src/StdMeshers/StdMeshers_Cartesian_3D.cxx @@ -645,7 +645,7 @@ namespace */ void Grid::ComputeNodes(SMESH_MesherHelper& helper) { - // state of each node of the grid relative to the geomerty + // state of each node of the grid relative to the geometry const size_t nbGridNodes = _coords[0].size() * _coords[1].size() * _coords[2].size(); vector< bool > isNodeOut( nbGridNodes, false ); _nodes.resize( nbGridNodes, 0 ); diff --git a/src/StdMeshers/StdMeshers_CompositeHexa_3D.cxx b/src/StdMeshers/StdMeshers_CompositeHexa_3D.cxx index a4235d863..38d36f450 100644 --- a/src/StdMeshers/StdMeshers_CompositeHexa_3D.cxx +++ b/src/StdMeshers/StdMeshers_CompositeHexa_3D.cxx @@ -655,10 +655,9 @@ bool _QuadFaceGrid::Init(const TopoDS_Face& f) //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); + int nbWire = SMESH_Block::GetOrderedEdges (myFace, edges, nbEdgesInWire); if ( nbWire != 1 ) return false; diff --git a/src/StdMeshers/StdMeshers_FaceSide.cxx b/src/StdMeshers/StdMeshers_FaceSide.cxx index 36f0680cc..37bc6c346 100644 --- a/src/StdMeshers/StdMeshers_FaceSide.cxx +++ b/src/StdMeshers/StdMeshers_FaceSide.cxx @@ -160,11 +160,10 @@ StdMeshers_FaceSide::StdMeshers_FaceSide(const TopoDS_Face& theFace, double d4 = GCPnts_AbscissaPoint::Length( A2dC, myFirst[i], p4 ); //cout<<"len = "< 0 ) + { + StdMeshers_FaceSide* me = (StdMeshers_FaceSide*) this; + me->myNbPonits = 0; + me->myNbSegments = 0; + me->myMissingVertexNodes = false; + + for ( int i = 0; i < NbEdges(); ++i ) + { + TopoDS_Vertex v1 = SMESH_MesherHelper::IthVertex( 0, myEdge[i] ); + if ( SMESH_Algo::VertexNode( v1, myProxyMesh->GetMeshDS() )) + me->myNbPonits += 1; // for the first end + else + me->myMissingVertexNodes = true; + + if ( const SMESHDS_SubMesh* sm = myProxyMesh->GetSubMesh( Edge(i) )) { + int nbN = sm->NbNodes(); + if ( myIgnoreMediumNodes ) { + SMDS_ElemIteratorPtr elemIt = sm->GetElements(); + if ( elemIt->more() && elemIt->next()->IsQuadratic() ) + nbN -= sm->NbElements(); + } + me->myNbPonits += nbN; + me->myNbSegments += sm->NbElements(); + } + } + TopoDS_Vertex v1 = SMESH_MesherHelper::IthVertex( 1, Edge( NbEdges()-1 )); + if ( SMESH_Algo::VertexNode( v1, myProxyMesh->GetMeshDS() )) + me->myNbPonits++; // for the last end + else + me->myMissingVertexNodes = true; + } + return myNbPonits; +} + +//======================================================================= +//function : NbSegments +//purpose : Return nb edges +// Call it with update == true if mesh of this side can be recomputed +// since creation of this side +//======================================================================= + +int StdMeshers_FaceSide::NbSegments(const bool update) const +{ + return NbPoints( update ), myNbSegments; } //================================================================================ @@ -709,7 +806,6 @@ BRepAdaptor_CompCurve* StdMeshers_FaceSide::GetCurve3d() const return new BRepAdaptor_CompCurve( aWire ); } - //================================================================================ /*! * \brief Return 2D point by normalized parameter @@ -743,6 +839,35 @@ gp_Pnt2d StdMeshers_FaceSide::Value2d(double U) const return myDefaultPnt2d; } +//================================================================================ +/*! + * \brief Return XYZ by normalized parameter + * \param U - normalized parameter value + * \retval gp_Pnt - point + */ +//================================================================================ + +gp_Pnt StdMeshers_FaceSide::Value3d(double U) const +{ + int i = EdgeIndex( U ); + double prevU = i ? myNormPar[ i-1 ] : 0; + double r = ( U - prevU )/ ( myNormPar[ i ] - prevU ); + + double par = myFirst[i] * ( 1 - r ) + myLast[i] * r; + + // check parametrization of curve + if( !myIsUniform[i] ) + { + double aLen3dU = r * myEdgeLength[i] * ( myFirst[i]>myLast[i] ? -1. : 1.); + GCPnts_AbscissaPoint AbPnt + ( const_cast( myC3dAdaptor[i]), aLen3dU, myFirst[i] ); + if( AbPnt.IsDone() ) { + par = AbPnt.Parameter(); + } + } + return myC3dAdaptor[ i ].Value(par); +} + //================================================================================ /*! * \brief Return wires of a face as StdMeshers_FaceSide's @@ -755,10 +880,9 @@ TSideVector StdMeshers_FaceSide::GetFaceWires(const TopoDS_Face& theFace, TError & theError, SMESH_ProxyMesh::Ptr theProxyMesh) { - TopoDS_Vertex V1; list< TopoDS_Edge > edges, internalEdges; list< int > nbEdgesInWires; - int nbWires = SMESH_Block::GetOrderedEdges (theFace, V1, edges, nbEdgesInWires); + int nbWires = SMESH_Block::GetOrderedEdges (theFace, edges, nbEdgesInWires); // split list of all edges into separate wires TSideVector wires( nbWires ); diff --git a/src/StdMeshers/StdMeshers_FaceSide.hxx b/src/StdMeshers/StdMeshers_FaceSide.hxx index 1d4521dfe..b4ab06966 100644 --- a/src/StdMeshers/StdMeshers_FaceSide.hxx +++ b/src/StdMeshers/StdMeshers_FaceSide.hxx @@ -102,13 +102,22 @@ public: */ void Reverse(); /*! - * \brief Return nb nodes on edges and vertices (+1 to be == GetUVPtStruct().size() ) + * \brief Make ignore medium nodes */ - int NbPoints() const { return myNbPonits; } + void SetIgnoreMediumNodes(bool toIgnore); + + /*! + * \brief Return nb nodes on edges and vertices (+1 to be == GetUVPtStruct().size() ). + * Call it with update == true if mesh of this side can be recomputed + * since creation of this side + */ + int NbPoints(const bool update = false) const; /*! * \brief Return nb edges + * Call it with update == true if mesh of this side can be recomputed + * since creation of this side */ - int NbSegments() const { return myNbSegments; } + int NbSegments(const bool update = false) const; /*! * \brief Return mesh */ @@ -117,6 +126,7 @@ public: * \brief Return true if there are vertices without nodes */ bool MissVertexNode() const { return myMissingVertexNodes; } + /*! * \brief Return detailed data on nodes * \param isXConst - true if normalized parameter X is constant @@ -139,6 +149,7 @@ public: * For a closed side, the 1st point repeats at end */ std::vector GetOrderedNodes() const; + /*! * \brief Return edge and parameter on edge by normalized parameter */ @@ -147,6 +158,10 @@ public: * \brief Return UV by normalized parameter */ gp_Pnt2d Value2d(double U) const; + /*! + * \brief Return XYZ by normalized parameter + */ + gp_Pnt Value3d(double U) const; /*! * \brief Creates a Adaptor2d_Curve2d to be used in SMESH_Block */ diff --git a/src/StdMeshers/StdMeshers_Hexa_3D.cxx b/src/StdMeshers/StdMeshers_Hexa_3D.cxx index 92f00af3a..cc33934e1 100644 --- a/src/StdMeshers/StdMeshers_Hexa_3D.cxx +++ b/src/StdMeshers/StdMeshers_Hexa_3D.cxx @@ -295,7 +295,7 @@ namespace //============================================================================= bool StdMeshers_Hexa_3D::Compute(SMESH_Mesh & aMesh, - const TopoDS_Shape & aShape)// throw(SALOME_Exception) + const TopoDS_Shape & aShape) { // PAL14921. Enable catching std::bad_alloc and Standard_OutOfMemory outside //Unexpect aCatch(SalomeException); @@ -371,20 +371,12 @@ bool StdMeshers_Hexa_3D::Compute(SMESH_Mesh & aMesh, for ( int i = 0; i < 6; ++i ) { const TopoDS_Face& sideF = aCubeSide[i]._quad->face; - if ( SMESHDS_SubMesh* smDS = meshDS->MeshElements( sideF )) + if ( !SMESH_MesherHelper::IsSameElemGeometry( meshDS->MeshElements( sideF ), + SMDSGeom_QUADRANGLE, + /*nullSubMeshRes=*/false )) { - bool isAllQuad = true; - SMDS_ElemIteratorPtr fIt = smDS->GetElements(); - while ( fIt->more() && isAllQuad ) - { - const SMDS_MeshElement* f = fIt->next(); - isAllQuad = ( f->NbCornerNodes() == 4 ); - } - if ( !isAllQuad ) - { - SMESH_ComputeErrorPtr err = ComputePentahedralMesh(aMesh, aShape, proxymesh.get()); - return error( err ); - } + SMESH_ComputeErrorPtr err = ComputePentahedralMesh(aMesh, aShape, proxymesh.get()); + return error( err ); } } } diff --git a/src/StdMeshers/StdMeshers_Prism_3D.cxx b/src/StdMeshers/StdMeshers_Prism_3D.cxx index 85eaef566..00a536105 100644 --- a/src/StdMeshers/StdMeshers_Prism_3D.cxx +++ b/src/StdMeshers/StdMeshers_Prism_3D.cxx @@ -27,15 +27,24 @@ // #include "StdMeshers_Prism_3D.hxx" -#include "StdMeshers_ProjectionUtils.hxx" -#include "SMESH_MesherHelper.hxx" -#include "SMDS_VolumeTool.hxx" -#include "SMDS_VolumeOfNodes.hxx" #include "SMDS_EdgePosition.hxx" +#include "SMDS_VolumeOfNodes.hxx" +#include "SMDS_VolumeTool.hxx" #include "SMESH_Comment.hxx" +#include "SMESH_Gen.hxx" +#include "SMESH_HypoFilter.hxx" +#include "SMESH_MesherHelper.hxx" +#include "StdMeshers_FaceSide.hxx" +#include "StdMeshers_ProjectionSource1D.hxx" +#include "StdMeshers_ProjectionSource2D.hxx" +#include "StdMeshers_ProjectionUtils.hxx" +#include "StdMeshers_Projection_1D.hxx" +#include "StdMeshers_Projection_1D2D.hxx" +#include "StdMeshers_Quadrangle_2D.hxx" #include "utilities.h" +#include #include #include #include @@ -44,6 +53,7 @@ #include #include #include +#include #include #include #include @@ -69,6 +79,112 @@ enum { ID_BOT_FACE = SMESH_Block::ID_Fxy0, namespace { + //======================================================================= + /*! + * \brief Quadrangle algorithm + */ + struct TQuadrangleAlgo : public StdMeshers_Quadrangle_2D + { + TQuadrangleAlgo(int studyId, SMESH_Gen* gen) + : StdMeshers_Quadrangle_2D( gen->GetANewId(), studyId, gen) + { + } + static StdMeshers_Quadrangle_2D* instance( SMESH_Algo* fatherAlgo, + SMESH_MesherHelper* helper=0) + { + static TQuadrangleAlgo* algo = new TQuadrangleAlgo( fatherAlgo->GetStudyId(), + fatherAlgo->GetGen() ); + if ( helper && + algo->myProxyMesh && + algo->myProxyMesh->GetMesh() != helper->GetMesh() ) + algo->myProxyMesh.reset( new SMESH_ProxyMesh( *helper->GetMesh() )); + + algo->myQuadStruct.reset(); + + if ( helper ) + algo->_quadraticMesh = helper->GetIsQuadratic(); + + return algo; + } + }; + //======================================================================= + /*! + * \brief Algorithm projecting 1D mesh + */ + struct TProjction1dAlgo : public StdMeshers_Projection_1D + { + StdMeshers_ProjectionSource1D myHyp; + + TProjction1dAlgo(int studyId, SMESH_Gen* gen) + : StdMeshers_Projection_1D( gen->GetANewId(), studyId, gen), + myHyp( gen->GetANewId(), studyId, gen) + { + StdMeshers_Projection_1D::_sourceHypo = & myHyp; + } + static TProjction1dAlgo* instance( SMESH_Algo* fatherAlgo ) + { + static TProjction1dAlgo* algo = new TProjction1dAlgo( fatherAlgo->GetStudyId(), + fatherAlgo->GetGen() ); + return algo; + } + }; + //======================================================================= + /*! + * \brief Algorithm projecting 2D mesh + */ + struct TProjction2dAlgo : public StdMeshers_Projection_1D2D + { + StdMeshers_ProjectionSource2D myHyp; + + TProjction2dAlgo(int studyId, SMESH_Gen* gen) + : StdMeshers_Projection_1D2D( gen->GetANewId(), studyId, gen), + myHyp( gen->GetANewId(), studyId, gen) + { + StdMeshers_Projection_2D::_sourceHypo = & myHyp; + } + static TProjction2dAlgo* instance( SMESH_Algo* fatherAlgo ) + { + static TProjction2dAlgo* algo = new TProjction2dAlgo( fatherAlgo->GetStudyId(), + fatherAlgo->GetGen() ); + return algo; + } + }; + + //================================================================================ + /*! + * \brief Make \a botE be the BOTTOM_SIDE of \a quad. + * Return false if the BOTTOM_SIDE is composite + */ + //================================================================================ + + bool setBottomEdge( const TopoDS_Edge& botE, + faceQuadStruct::Ptr& quad, + const TopoDS_Shape& face) + { + quad->side[ QUAD_TOP_SIDE ]->Reverse(); + quad->side[ QUAD_LEFT_SIDE ]->Reverse(); + int edgeIndex = 0; + for ( size_t i = 0; i < quad->side.size(); ++i ) + { + StdMeshers_FaceSide* quadSide = quad->side[i]; + for ( int iE = 0; iE < quadSide->NbEdges(); ++iE ) + if ( botE.IsSame( quadSide->Edge( iE ))) + { + if ( quadSide->NbEdges() > 1 ) + return false; + edgeIndex = i; + i = quad->side.size(); // to quit from the outer loop + break; + } + } + if ( edgeIndex != QUAD_BOTTOM_SIDE ) + quad->shift( quad->side.size() - edgeIndex, /*keepUnitOri=*/false ); + + quad->face = TopoDS::Face( face ); + + return true; + } + //================================================================================ /*! * \brief Return iterator pointing to node column for the given parameter @@ -216,92 +332,40 @@ namespace { //================================================================================ /*! - * \brief Removes submeshes meshed with regular grid from given list + * \brief Removes submeshes that are or can be meshed with regular grid from given list * \retval int - nb of removed submeshes */ //================================================================================ - int removeQuasiQuads(list< SMESH_subMesh* >& notQuadSubMesh) + int removeQuasiQuads(list< SMESH_subMesh* >& notQuadSubMesh, + SMESH_MesherHelper* helper, + StdMeshers_Quadrangle_2D* quadAlgo) { - int oldNbSM = notQuadSubMesh.size(); - SMESHDS_Mesh* mesh = notQuadSubMesh.front()->GetFather()->GetMeshDS(); + int nbRemoved = 0; + //SMESHDS_Mesh* mesh = notQuadSubMesh.front()->GetFather()->GetMeshDS(); list< SMESH_subMesh* >::iterator smIt = notQuadSubMesh.begin(); -#define __NEXT_SM { ++smIt; continue; } while ( smIt != notQuadSubMesh.end() ) { SMESH_subMesh* faceSm = *smIt; SMESHDS_SubMesh* faceSmDS = faceSm->GetSubMeshDS(); - int nbQuads = faceSmDS->NbElements(); - if ( nbQuads == 0 ) __NEXT_SM; - - // get oredered edges - list< TopoDS_Edge > orderedEdges; - list< int > nbEdgesInWires; - TopoDS_Vertex V000; - int nbWires = SMESH_Block::GetOrderedEdges( TopoDS::Face( faceSm->GetSubShape() ), - V000, orderedEdges, nbEdgesInWires ); - if ( nbWires != 1 || nbEdgesInWires.front() <= 4 ) - __NEXT_SM; - - // get nb of segements on edges - list nbSegOnEdge; - list< TopoDS_Edge >::iterator edge = orderedEdges.begin(); - for ( ; edge != orderedEdges.end(); ++edge ) - { - if ( SMESHDS_SubMesh* edgeSmDS = mesh->MeshElements( *edge )) - nbSegOnEdge.push_back( edgeSmDS->NbElements() ); - else - nbSegOnEdge.push_back(0); - } - - // unite nbSegOnEdge of continues edges - int nbEdges = nbEdgesInWires.front(); - list::iterator nbSegIt = nbSegOnEdge.begin(); - for ( edge = orderedEdges.begin(); edge != orderedEdges.end(); ) - { - const TopoDS_Edge& e1 = *edge++; - const TopoDS_Edge& e2 = ( edge == orderedEdges.end() ? orderedEdges.front() : *edge ); - if ( SMESH_Algo::IsContinuous( e1, e2 )) - { - // common vertex of continues edges must be shared by two 2D mesh elems of geom face - TopoDS_Vertex vCommon = TopExp::LastVertex( e1, true ); - const SMDS_MeshNode* vNode = SMESH_Algo::VertexNode( vCommon, mesh ); - int nbF = 0; - if ( vNode ) - { - SMDS_ElemIteratorPtr fIt = vNode->GetInverseElementIterator(SMDSAbs_Face); - while ( fIt->more() ) - nbF += faceSmDS->Contains( fIt->next() ); - } - list::iterator nbSegIt1 = nbSegIt++; - if ( !vNode || nbF == 2 ) // !vNode - two edges can be meshed as one - { - // unite - if ( nbSegIt == nbSegOnEdge.end() ) nbSegIt = nbSegOnEdge.begin(); - *nbSegIt += *nbSegIt1; - nbSegOnEdge.erase( nbSegIt1 ); - --nbEdges; - } - } - else - { - ++nbSegIt; - } - } - vector nbSegVec( nbSegOnEdge.begin(), nbSegOnEdge.end()); - if ( nbSegVec.size() == 4 && - nbSegVec[0] == nbSegVec[2] && - nbSegVec[1] == nbSegVec[3] && - nbSegVec[0] * nbSegVec[1] == nbQuads - ) + int nbQuads = faceSmDS ? faceSmDS->NbElements() : 0; + bool toRemove; + if ( nbQuads > 0 ) + toRemove = helper->IsStructured( faceSm ); + else + toRemove = quadAlgo->CheckNbEdges( *helper->GetMesh(), + faceSm->GetSubShape() ); + nbRemoved += toRemove; + if ( toRemove ) smIt = notQuadSubMesh.erase( smIt ); else - __NEXT_SM; + ++smIt; } - return oldNbSM - notQuadSubMesh.size(); + return nbRemoved; } -} + +} // namespace //======================================================================= //function : StdMeshers_Prism_3D @@ -311,9 +375,16 @@ namespace { StdMeshers_Prism_3D::StdMeshers_Prism_3D(int hypId, int studyId, SMESH_Gen* gen) :SMESH_3D_Algo(hypId, studyId, gen) { - _name = "Prism_3D"; - _shapeType = (1 << TopAbs_SHELL) | (1 << TopAbs_SOLID); // 1 bit per shape type - myProjectTriangles = false; + _name = "Prism_3D"; + _shapeType = (1 << TopAbs_SOLID); // 1 bit per shape type + _onlyUnaryInput = false; // accept all SOLIDs at once + _requireDiscreteBoundary = false; // mesh FACEs and EDGEs by myself + _supportSubmeshes = true; // "source" FACE must be meshed by other algo + _neededLowerHyps[ 1 ] = true; // suppress warning on hiding a global 1D algo + _neededLowerHyps[ 2 ] = true; // suppress warning on hiding a global 2D algo + + //myProjectTriangles = false; + mySetErrorToSM = true; // to pass an error to a sub-mesh of a current solid or not } //================================================================================ @@ -374,7 +445,7 @@ bool StdMeshers_Prism_3D::CheckHypothesis(SMESH_Mesh& a //======================================================================= //function : Compute -//purpose : +//purpose : Compute mesh on a COMPOUND of SOLIDs //======================================================================= bool StdMeshers_Prism_3D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& theShape) @@ -382,15 +453,388 @@ bool StdMeshers_Prism_3D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& theSh SMESH_MesherHelper helper( theMesh ); myHelper = &helper; - myHelper->IsQuadraticSubMesh( theShape ); + int nbSolids = helper.Count( theShape, TopAbs_SOLID, /*skipSame=*/false ); + if ( nbSolids < 1 ) + return true; + + Prism_3D::TPrismTopo prism; + + if ( nbSolids == 1 ) + { + return ( initPrism( prism, TopExp_Explorer( theShape, TopAbs_SOLID ).Current() ) && + compute( prism )); + } + + TopTools_IndexedDataMapOfShapeListOfShape faceToSolids; + TopExp::MapShapesAndAncestors( theShape, TopAbs_FACE, TopAbs_SOLID, faceToSolids ); + + // look for meshed FACEs ("source" FACEs) that must be prism bottoms + list< TopoDS_Face > meshedFaces;//, notQuadMeshedFaces, notQuadFaces; + const bool meshHasQuads = ( theMesh.NbQuadrangles() > 0 ); + for ( int iF = 1; iF < faceToSolids.Extent(); ++iF ) + { + const TopoDS_Face& face = TopoDS::Face( faceToSolids.FindKey( iF )); + SMESH_subMesh* faceSM = theMesh.GetSubMesh( face ); + if ( !faceSM->IsEmpty() ) + { + if ( !meshHasQuads || + !helper.IsSameElemGeometry( faceSM->GetSubMeshDS(), SMDSGeom_QUADRANGLE ) || + !helper.IsStructured( faceSM )) + // notQuadMeshedFaces are of higher priority + meshedFaces.push_front( face ); + else + meshedFaces.push_back( face ); + } + } + //meshedFaces.splice( meshedFaces.begin(), notQuadMeshedFaces ); + + // if ( meshedFaces.empty() ) + // return error( COMPERR_BAD_INPUT_MESH, "No meshed source faces found" ); + + TopTools_MapOfShape meshedSolids; + list< Prism_3D::TPrismTopo > meshedPrism; + TopTools_ListIteratorOfListOfShape solidIt; - // Analyse mesh and geomerty to find block sub-shapes and submeshes - if ( !myBlock.Init( myHelper, theShape )) - return error( myBlock.GetError()); + while ( meshedSolids.Extent() < nbSolids ) + { + if ( _computeCanceled ) + return toSM( error( SMESH_ComputeError::New(COMPERR_CANCELED))); - SMESHDS_Mesh* meshDS = theMesh.GetMeshDS(); + // compute prisms having avident computed source FACE + while ( !meshedFaces.empty() ) + { + TopoDS_Face face = meshedFaces.front(); + meshedFaces.pop_front(); + TopTools_ListOfShape& solidList = faceToSolids.ChangeFromKey( face ); + while ( !solidList.IsEmpty() ) + { + TopoDS_Shape solid = solidList.First(); + solidList.RemoveFirst(); + if ( meshedSolids.Add( solid )) + { + prism.Clear(); + prism.myBottom = face; + if ( !initPrism( prism, solid ) || + !compute( prism )) + return false; - int volumeID = meshDS->ShapeToIndex( theShape ); + meshedFaces.push_front( prism.myTop ); + meshedPrism.push_back( prism ); + } + } + } + if ( meshedSolids.Extent() == nbSolids ) + break; + + // below in the loop we try to find source FACEs somehow + + // project mesh from source FACEs of computed prisms to + // prisms sharing wall FACEs + list< Prism_3D::TPrismTopo >::iterator prismIt = meshedPrism.begin(); + for ( ; prismIt != meshedPrism.end(); ++prismIt ) + { + for ( size_t iW = 0; iW < prismIt->myWallQuads.size(); ++iW ) + { + Prism_3D::TQuadList::iterator wQuad = prismIt->myWallQuads[iW].begin(); + for ( ; wQuad != prismIt->myWallQuads[iW].end(); ++ wQuad ) + { + const TopoDS_Face& wFace = (*wQuad)->face; + TopTools_ListOfShape& solidList = faceToSolids.ChangeFromKey( wFace ); + solidIt.Initialize( solidList ); + while ( solidIt.More() ) + { + const TopoDS_Shape& solid = solidIt.Value(); + if ( meshedSolids.Contains( solid )) { + solidList.Remove( solidIt ); + continue; // already computed prism + } + // find a source FACE of the SOLID: it's a FACE sharing a bottom EDGE with wFace + const TopoDS_Edge& wEdge = (*wQuad)->side[ QUAD_TOP_SIDE ]->Edge(0); + PShapeIteratorPtr faceIt = myHelper->GetAncestors( wEdge, *myHelper->GetMesh(), + TopAbs_FACE); + while ( const TopoDS_Shape* f = faceIt->next() ) + { + const TopoDS_Face& candidateF = TopoDS::Face( *f ); + prism.Clear(); + prism.myBottom = candidateF; + mySetErrorToSM = false; + if ( !myHelper->IsSubShape( candidateF, prismIt->myShape3D ) && + !myHelper->GetMesh()->GetSubMesh( candidateF )->IsMeshComputed() && + initPrism( prism, solid ) && + project2dMesh( prismIt->myBottom, candidateF)) + { + mySetErrorToSM = true; + if ( !compute( prism )) + return false; + meshedFaces.push_front( prism.myTop ); + meshedFaces.push_front( prism.myBottom ); + meshedPrism.push_back( prism ); + meshedSolids.Add( solid ); + } + InitComputeError(); + } + mySetErrorToSM = true; + InitComputeError(); + if ( meshedSolids.Contains( solid )) + solidList.Remove( solidIt ); + else + solidIt.Next(); + } + } + } + if ( !meshedFaces.empty() ) + break; // to compute prisms with avident sources + } + + // find FACEs with local 1D hyps, which has to be computed by now, + // or at least any computed FACEs + for ( int iF = 1; ( meshedFaces.empty() && iF < faceToSolids.Extent() ); ++iF ) + { + const TopoDS_Face& face = TopoDS::Face( faceToSolids.FindKey( iF )); + const TopTools_ListOfShape& solidList = faceToSolids.FindFromKey( face ); + if ( solidList.IsEmpty() ) continue; + SMESH_subMesh* faceSM = theMesh.GetSubMesh( face ); + if ( !faceSM->IsEmpty() ) + { + meshedFaces.push_back( face ); // lower priority + } + else + { + bool allSubMeComputed = true; + SMESH_subMeshIteratorPtr smIt = faceSM->getDependsOnIterator(false,true); + while ( smIt->more() && allSubMeComputed ) + allSubMeComputed = smIt->next()->IsMeshComputed(); + if ( allSubMeComputed ) + { + faceSM->ComputeStateEngine( SMESH_subMesh::COMPUTE ); + if ( !faceSM->IsEmpty() ) + meshedFaces.push_front( face ); // higher priority + else + faceSM->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE ); + } + } + } + + + // TODO. there are other ways to find out the source FACE: + // propagation, topological similarity, ect. + + + if ( meshedFaces.empty() ) // set same error to 10 not-computed solids + { + SMESH_ComputeErrorPtr err = SMESH_ComputeError::New + ( COMPERR_BAD_INPUT_MESH, "No meshed source face found", this ); + + const int maxNbErrors = 10; // limit nb errors not to overload the Compute dialog + TopExp_Explorer solid( theShape, TopAbs_SOLID ); + for ( int i = 0; ( i < maxNbErrors && solid.More() ); ++i, solid.Next() ) + if ( !meshedSolids.Contains( solid.Current() )) + { + SMESH_subMesh* sm = theMesh.GetSubMesh( solid.Current() ); + sm->GetComputeError() = err; + } + return false; + } + } + return true; +} + +//================================================================================ +/*! + * \brief Find wall faces by bottom edges + */ +//================================================================================ + +bool StdMeshers_Prism_3D::getWallFaces( Prism_3D::TPrismTopo & thePrism, + const int totalNbFaces) +{ + thePrism.myWallQuads.clear(); + + SMESH_Mesh* mesh = myHelper->GetMesh(); + + StdMeshers_Quadrangle_2D* quadAlgo = TQuadrangleAlgo::instance( this, myHelper ); + + TopTools_MapOfShape faceMap; + TopTools_IndexedDataMapOfShapeListOfShape edgeToFaces; + TopExp::MapShapesAndAncestors( thePrism.myShape3D, + TopAbs_EDGE, TopAbs_FACE, edgeToFaces ); + + // ------------------------------ + // Get the 1st row of wall FACEs + // ------------------------------ + + list< TopoDS_Edge >::iterator edge = thePrism.myBottomEdges.begin(); + std::list< int >::iterator nbE = thePrism.myNbEdgesInWires.begin(); + int iE = 0; + while ( edge != thePrism.myBottomEdges.end() ) + { + ++iE; + if ( BRep_Tool::Degenerated( *edge )) + { + edge = thePrism.myBottomEdges.erase( edge ); + --iE; + --(*nbE); + } + else + { + TopTools_ListIteratorOfListOfShape faceIt( edgeToFaces.FindFromKey( *edge )); + for ( ; faceIt.More(); faceIt.Next() ) + { + const TopoDS_Face& face = TopoDS::Face( faceIt.Value() ); + if ( !thePrism.myBottom.IsSame( face )) + { + Prism_3D::TQuadList quadList( 1, quadAlgo->CheckNbEdges( *mesh, face )); + if ( !quadList.back() ) + return toSM( error(TCom("Side face #") << shapeID( face ) + << " not meshable with quadrangles")); + if ( ! setBottomEdge( *edge, quadList.back(), face )) + return toSM( error(TCom("Composite 'horizontal' edges are not supported"))); + thePrism.myWallQuads.push_back( quadList ); + faceMap.Add( face ); + break; + } + } + ++edge; + } + if ( iE == *nbE ) + { + iE = 0; + ++nbE; + } + } + + // ------------------------- + // Find the rest wall FACEs + // ------------------------- + + // Compose a vector of indixes of right neighbour FACE for each wall FACE + // that is not so evident in case of several WIREs + thePrism.myRightQuadIndex.clear(); + for ( size_t i = 0; i < thePrism.myWallQuads.size(); ++i ) + thePrism.myRightQuadIndex.push_back( i+1 ); + list< int >::iterator nbEinW = thePrism.myNbEdgesInWires.begin(); + for ( int iLeft = 0; nbEinW != thePrism.myNbEdgesInWires.end(); ++nbEinW ) + { + thePrism.myRightQuadIndex[ iLeft + *nbEinW - 1 ] = iLeft; // 1st EDGE index of a current WIRE + iLeft += *nbEinW; + } + + while ( totalNbFaces - faceMap.Extent() > 2 ) + { + // find wall FACEs adjacent to each of wallQuads by the right side EDGE + int nbKnownFaces; + do { + nbKnownFaces = faceMap.Extent(); + StdMeshers_FaceSide *rightSide, *topSide; // sides of the quad + for ( size_t i = 0; i < thePrism.myWallQuads.size(); ++i ) + { + rightSide = thePrism.myWallQuads[i].back()->side[ QUAD_RIGHT_SIDE ]; + for ( int iE = 0; iE < rightSide->NbEdges(); ++iE ) // rightSide can be composite + { + const TopoDS_Edge & rightE = rightSide->Edge( iE ); + TopTools_ListIteratorOfListOfShape face( edgeToFaces.FindFromKey( rightE )); + for ( ; face.More(); face.Next() ) + if ( faceMap.Add( face.Value() )) + { + // a new wall FACE encountered, store it in thePrism.myWallQuads + const int iRight = thePrism.myRightQuadIndex[i]; + topSide = thePrism.myWallQuads[ iRight ].back()->side[ QUAD_TOP_SIDE ]; + const TopoDS_Edge& newBotE = topSide->Edge(0); + const TopoDS_Shape& newWallF = face.Value(); + thePrism.myWallQuads[ iRight ].push_back( quadAlgo->CheckNbEdges( *mesh, newWallF )); + if ( !thePrism.myWallQuads[ iRight ].back() ) + return toSM( error(TCom("Side face #") << shapeID( newWallF ) << + " not meshable with quadrangles")); + if ( ! setBottomEdge( newBotE, thePrism.myWallQuads[ iRight ].back(), newWallF )) + return toSM( error(TCom("Composite 'horizontal' edges are not supported"))); + } + } + } + } while ( nbKnownFaces != faceMap.Extent() ); + + // find wall FACEs adjacent to each of thePrism.myWallQuads by the top side EDGE + if ( totalNbFaces - faceMap.Extent() > 2 ) + { + for ( size_t i = 0; i < thePrism.myWallQuads.size(); ++i ) + { + StdMeshers_FaceSide* topSide = thePrism.myWallQuads[i].back()->side[ QUAD_TOP_SIDE ]; + const TopoDS_Edge & topE = topSide->Edge( 0 ); + if ( topSide->NbEdges() > 1 ) + return toSM( error(COMPERR_BAD_SHAPE, TCom("Side face #") << + shapeID( thePrism.myWallQuads[i].back()->face ) + << " has a composite top edge")); + TopTools_ListIteratorOfListOfShape faceIt( edgeToFaces.FindFromKey( topE )); + for ( ; faceIt.More(); faceIt.Next() ) + if ( faceMap.Add( faceIt.Value() )) + { + // a new wall FACE encountered, store it in wallQuads + thePrism.myWallQuads[ i ].push_back( quadAlgo->CheckNbEdges( *mesh, faceIt.Value() )); + if ( !thePrism.myWallQuads[ i ].back() ) + return toSM( error(TCom("Side face #") << shapeID( faceIt.Value() ) << + " not meshable with quadrangles")); + if ( ! setBottomEdge( topE, thePrism.myWallQuads[ i ].back(), faceIt.Value() )) + return toSM( error(TCom("Composite 'horizontal' edges are not supported"))); + if ( totalNbFaces - faceMap.Extent() == 2 ) + { + i = thePrism.myWallQuads.size(); // to quit from the outer loop + break; + } + } + } + } + } // while ( totalNbFaces - faceMap.Extent() > 2 ) + + // ------------------ + // Find the top FACE + // ------------------ + + if ( thePrism.myTop.IsNull() ) + { + // now only top and bottom FACEs are not in the faceMap + faceMap.Add( thePrism.myBottom ); + for ( TopExp_Explorer f( thePrism.myShape3D, TopAbs_FACE );f.More(); f.Next() ) + if ( !faceMap.Contains( f.Current() )) { + thePrism.myTop = TopoDS::Face( f.Current() ); + break; + } + if ( thePrism.myTop.IsNull() ) + return toSM( error("Top face not found")); + } + + // Check that the top FACE shares all the top EDGEs + for ( size_t i = 0; i < thePrism.myWallQuads.size(); ++i ) + { + StdMeshers_FaceSide* topSide = thePrism.myWallQuads[i].back()->side[ QUAD_TOP_SIDE ]; + const TopoDS_Edge & topE = topSide->Edge( 0 ); + if ( !myHelper->IsSubShape( topE, thePrism.myTop )) + return toSM( error( TCom("Wrong source face (#") << shapeID( thePrism.myBottom ))); + } + + return true; +} + +//======================================================================= +//function : compute +//purpose : Compute mesh on a SOLID +//======================================================================= + +bool StdMeshers_Prism_3D::compute(const Prism_3D::TPrismTopo& thePrism) +{ + myHelper->IsQuadraticSubMesh( thePrism.myShape3D ); + if ( _computeCanceled ) + return toSM( error( SMESH_ComputeError::New(COMPERR_CANCELED))); + + // Make all side FACEs of thePrism meshed with quads + if ( !computeWalls( thePrism )) + return false; + + // Analyse mesh and geometry to find block sub-shapes and submeshes + if ( !myBlock.Init( myHelper, thePrism )) + return toSM( error( myBlock.GetError())); + + SMESHDS_Mesh* meshDS = myHelper->GetMeshDS(); + + int volumeID = meshDS->ShapeToIndex( thePrism.myShape3D ); // To compute coordinates of a node inside a block, it is necessary to know @@ -415,13 +859,13 @@ bool StdMeshers_Prism_3D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& theSh // try to use transformation (issue 0020680) vector trsf; - if ( myBlock.GetLayersTransformation(trsf)) + if ( myBlock.GetLayersTransformation( trsf, thePrism )) { // loop on nodes inside the bottom face TNode2ColumnMap::iterator bot_column = myBotToColumnMap.begin(); for ( ; bot_column != myBotToColumnMap.end(); ++bot_column ) { - const TNode& tBotNode = bot_column->first; // bottom TNode + const Prism_3D::TNode& tBotNode = bot_column->first; // bottom TNode if ( tBotNode.GetPositionType() != SMDS_TOP_FACE ) continue; // node is not inside face @@ -443,11 +887,11 @@ bool StdMeshers_Prism_3D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& theSh else // use block approach { // loop on nodes inside the bottom face - TNode prevBNode; + Prism_3D::TNode prevBNode; TNode2ColumnMap::iterator bot_column = myBotToColumnMap.begin(); for ( ; bot_column != myBotToColumnMap.end(); ++bot_column ) { - const TNode& tBotNode = bot_column->first; // bottom TNode + const Prism_3D::TNode& tBotNode = bot_column->first; // bottom TNode if ( tBotNode.GetPositionType() != SMDS_TOP_FACE ) continue; // node is not inside face @@ -460,9 +904,9 @@ bool StdMeshers_Prism_3D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& theSh paramHint = prevBNode.GetParams(); if ( !myBlock.ComputeParameters( tBotNode.GetCoords(), tBotNode.ChangeParams(), ID_BOT_FACE, paramHint )) - return error(TCom("Can't compute normalized parameters for node ") - << tBotNode.myNode->GetID() << " on the face #" - << myBlock.SubMesh( ID_BOT_FACE )->GetId() ); + return toSM( error(TCom("Can't compute normalized parameters for node ") + << tBotNode.myNode->GetID() << " on the face #" + << myBlock.SubMesh( ID_BOT_FACE )->GetId() )); prevBNode = tBotNode; myShapeXYZ[ ID_BOT_FACE ] = tBotNode.GetCoords(); @@ -475,9 +919,9 @@ bool StdMeshers_Prism_3D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& theSh if ( column.size() > 2 ) { gp_Pnt topCoords = myShapeXYZ[ ID_TOP_FACE ]; if ( !myBlock.ComputeParameters( topCoords, topParams, ID_TOP_FACE, topParams )) - return error(TCom("Can't compute normalized parameters ") - << "for node " << column.back()->GetID() - << " on the face #"<< column.back()->getshapeId() ); + return toSM( error(TCom("Can't compute normalized parameters ") + << "for node " << column.back()->GetID() + << " on the face #"<< column.back()->getshapeId() )); } // vertical loop @@ -504,7 +948,7 @@ bool StdMeshers_Prism_3D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& theSh // compute coords for a new node gp_XYZ coords; if ( !SMESH_Block::ShellPoint( params, myShapeXYZ, coords )) - return error("Can't compute coordinates by normalized parameters"); + return toSM( error("Can't compute coordinates by normalized parameters")); SHOWYXZ("TOPFacePoint ",myShapeXYZ[ ID_TOP_FACE]); SHOWYXZ("BOT Node "<< tBotNode.myNode->GetID(),gpXYZ(tBotNode.myNode)); @@ -520,7 +964,7 @@ bool StdMeshers_Prism_3D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& theSh // Create volumes SMESHDS_SubMesh* smDS = myBlock.SubMeshDS( ID_BOT_FACE ); - if ( !smDS ) return error(COMPERR_BAD_INPUT_MESH, "Null submesh"); + if ( !smDS ) return toSM( error(COMPERR_BAD_INPUT_MESH, "Null submesh")); // loop on bottom mesh faces SMDS_ElemIteratorPtr faceIt = smDS->GetElements(); @@ -529,11 +973,9 @@ bool StdMeshers_Prism_3D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& theSh const SMDS_MeshElement* face = faceIt->next(); if ( !face || face->GetType() != SMDSAbs_Face ) continue; - int nbNodes = face->NbNodes(); - if ( face->IsQuadratic() ) - nbNodes /= 2; // find node columns for each node + int nbNodes = face->NbCornerNodes(); vector< const TNodeColumn* > columns( nbNodes ); for ( int i = 0; i < nbNodes; ++i ) { @@ -541,13 +983,13 @@ bool StdMeshers_Prism_3D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& theSh if ( n->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE ) { TNode2ColumnMap::iterator bot_column = myBotToColumnMap.find( n ); if ( bot_column == myBotToColumnMap.end() ) - return error(TCom("No nodes found above node ") << n->GetID() ); + return toSM( error(TCom("No nodes found above node ") << n->GetID() )); columns[ i ] = & bot_column->second; } else { columns[ i ] = myBlock.GetNodeColumn( n ); if ( !columns[ i ] ) - return error(TCom("No side nodes found above node ") << n->GetID() ); + return toSM( error(TCom("No side nodes found above node ") << n->GetID() )); } } // create prisms @@ -562,16 +1004,275 @@ bool StdMeshers_Prism_3D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& theSh return true; } +//======================================================================= +//function : computeWalls +//purpose : Compute 2D mesh on walls FACEs of a prism +//======================================================================= + +bool StdMeshers_Prism_3D::computeWalls(const Prism_3D::TPrismTopo& thePrism) +{ + SMESH_Mesh* mesh = myHelper->GetMesh(); + SMESHDS_Mesh* meshDS = myHelper->GetMeshDS(); + + TProjction1dAlgo* projector1D = TProjction1dAlgo::instance( this ); + StdMeshers_Quadrangle_2D* quadAlgo = TQuadrangleAlgo::instance( this, myHelper ); + + SMESH_HypoFilter hyp1dFilter( SMESH_HypoFilter::IsAlgo(),/*not=*/true); + hyp1dFilter.And( SMESH_HypoFilter::HasDim( 1 )); + hyp1dFilter.And( SMESH_HypoFilter::IsMoreLocalThan( thePrism.myShape3D, *mesh )); + + // Discretize equally 'vertical' EDGEs + // ----------------------------------- + // find source FACE sides for projection: either already computed ones or + // the 'most composite' ones + multimap< int, int > wgt2quad; + for ( size_t iW = 0; iW != thePrism.myWallQuads.size(); ++iW ) + { + Prism_3D::TQuadList::const_iterator quad = thePrism.myWallQuads[iW].begin(); + int wgt = 0; // "weight" + for ( ; quad != thePrism.myWallQuads[iW].end(); ++quad ) + { + StdMeshers_FaceSide* lftSide = (*quad)->side[ QUAD_LEFT_SIDE ]; + for ( int i = 0; i < lftSide->NbEdges(); ++i ) + { + ++wgt; + const TopoDS_Edge& E = lftSide->Edge(i); + if ( mesh->GetSubMesh( E )->IsMeshComputed() ) + wgt += 10; + else if ( mesh->GetHypothesis( E, hyp1dFilter, true )) // local hypothesis! + wgt += 100; + } + } + wgt2quad.insert( make_pair( wgt, iW )); + + // in quadratic mesh, pass ignoreMediumNodes to quad sides + if ( myHelper->GetIsQuadratic() ) + { + quad = thePrism.myWallQuads[iW].begin(); + for ( ; quad != thePrism.myWallQuads[iW].end(); ++quad ) + for ( int i = 0; i < NB_QUAD_SIDES; ++i ) + (*quad)->side[ i ]->SetIgnoreMediumNodes( true ); + } + } + + // Project 'vertical' EDGEs, from left to right + multimap< int, int >::reverse_iterator w2q = wgt2quad.rbegin(); + for ( ; w2q != wgt2quad.rend(); ++w2q ) + { + const int iW = w2q->second; + const Prism_3D::TQuadList& quads = thePrism.myWallQuads[ iW ]; + Prism_3D::TQuadList::const_iterator quad = quads.begin(); + for ( ; quad != quads.end(); ++quad ) + { + StdMeshers_FaceSide* rgtSide = (*quad)->side[ QUAD_RIGHT_SIDE ]; // tgt + StdMeshers_FaceSide* lftSide = (*quad)->side[ QUAD_LEFT_SIDE ]; // src + bool swapLeftRight = ( lftSide->NbSegments( /*update=*/true ) == 0 && + rgtSide->NbSegments( /*update=*/true ) > 0 ); + if ( swapLeftRight ) + std::swap( lftSide, rgtSide ); + + // assure that all the source (left) EDGEs are meshed + int nbSrcSegments = 0; + for ( int i = 0; i < lftSide->NbEdges(); ++i ) + { + const TopoDS_Edge& srcE = lftSide->Edge(i); + SMESH_subMesh* srcSM = mesh->GetSubMesh( srcE ); + if ( !srcSM->IsMeshComputed() ) { + srcSM->ComputeSubMeshStateEngine( SMESH_subMesh::COMPUTE ); + srcSM->ComputeStateEngine ( SMESH_subMesh::COMPUTE ); + if ( !srcSM->IsMeshComputed() ) + return false; + } + nbSrcSegments += srcSM->GetSubMeshDS()->NbElements(); + } + // check target EDGEs + int nbTgtMeshed = 0, nbTgtSegments = 0; + vector< bool > isTgtEdgeComputed( rgtSide->NbEdges() ); + for ( int i = 0; i < rgtSide->NbEdges(); ++i ) + { + const TopoDS_Edge& tgtE = rgtSide->Edge(i); + SMESH_subMesh* tgtSM = mesh->GetSubMesh( tgtE ); + if (( isTgtEdgeComputed[ i ] = tgtSM->IsMeshComputed() )) { + ++nbTgtMeshed; + nbTgtSegments += tgtSM->GetSubMeshDS()->NbElements(); + } + } + if ( rgtSide->NbEdges() == nbTgtMeshed ) // all tgt EDGEs meshed + { + if ( nbTgtSegments != nbSrcSegments ) + { + for ( int i = 0; i < lftSide->NbEdges(); ++i ) + addBadInputElements( meshDS->MeshElements( lftSide->Edge( i ))); + for ( int i = 0; i < rgtSide->NbEdges(); ++i ) + addBadInputElements( meshDS->MeshElements( rgtSide->Edge( i ))); + return toSM( error( TCom("Different nb of segment on logically vertical edges #") + << shapeID( lftSide->Edge(0) ) << " and #" + << shapeID( rgtSide->Edge(0) ) << ": " + << nbSrcSegments << " != " << nbTgtSegments )); + } + continue; + } + // Compute + if ( nbTgtMeshed == 0 ) + { + // compute nodes on target VERTEXes + const UVPtStructVec& srcNodeStr = lftSide->GetUVPtStruct(); + if ( srcNodeStr.size() == 0 ) + return toSM( error( TCom("Invalid node positions on edge #") << + shapeID( lftSide->Edge(0) ))); + vector< SMDS_MeshNode* > newNodes( srcNodeStr.size() ); + for ( int is2ndV = 0; is2ndV < 2; ++is2ndV ) + { + const TopoDS_Edge& E = rgtSide->Edge( is2ndV ? rgtSide->NbEdges()-1 : 0 ); + TopoDS_Vertex v = myHelper->IthVertex( is2ndV, E ); + mesh->GetSubMesh( v )->ComputeStateEngine( SMESH_subMesh::COMPUTE ); + const SMDS_MeshNode* n = SMESH_Algo::VertexNode( v, meshDS ); + newNodes[ is2ndV ? 0 : newNodes.size()-1 ] = (SMDS_MeshNode*) n; + } + + // compute nodes on target EDGEs + rgtSide->Reverse(); // direct it same as the lftSide + myHelper->SetElementsOnShape( false ); + TopoDS_Edge tgtEdge; + for ( size_t iN = 1; iN < srcNodeStr.size()-1; ++iN ) // add nodes + { + gp_Pnt p = rgtSide->Value3d ( srcNodeStr[ iN ].normParam ); + double u = rgtSide->Parameter( srcNodeStr[ iN ].normParam, tgtEdge ); + newNodes[ iN ] = meshDS->AddNode( p.X(), p.Y(), p.Z() ); + meshDS->SetNodeOnEdge( newNodes[ iN ], tgtEdge, u ); + } + for ( size_t iN = 1; iN < srcNodeStr.size(); ++iN ) // add segments + { + SMDS_MeshElement* newEdge = myHelper->AddEdge( newNodes[ iN-1 ], newNodes[ iN ] ); + std::pair id2type = + myHelper->GetMediumPos( newNodes[ iN-1 ], newNodes[ iN ] ); + if ( id2type.second == TopAbs_EDGE ) + { + meshDS->SetMeshElementOnShape( newEdge, id2type.first ); + } + else // new nodes are on different EDGEs; put one of them on VERTEX + { + const int edgeIndex = rgtSide->EdgeIndex( srcNodeStr[ iN-1 ].normParam ); + const double vertexParam = rgtSide->LastParameter( edgeIndex ); + const gp_Pnt p = BRep_Tool::Pnt( rgtSide->LastVertex( edgeIndex )); + const int isPrev = ( Abs( srcNodeStr[ iN-1 ].normParam - vertexParam ) < + Abs( srcNodeStr[ iN ].normParam - vertexParam )); + meshDS->SetMeshElementOnShape( newEdge, newNodes[ iN-(1-isPrev) ]->getshapeId() ); + meshDS->UnSetNodeOnShape( newNodes[ iN-isPrev ] ); + meshDS->SetNodeOnVertex ( newNodes[ iN-isPrev ], rgtSide->LastVertex( edgeIndex )); + meshDS->MoveNode( newNodes[ iN-isPrev ], p.X(), p.Y(), p.Z() ); + } + } + myHelper->SetElementsOnShape( true ); + for ( int i = 0; i < rgtSide->NbEdges(); ++i ) // update state of sub-meshes + { + const TopoDS_Edge& E = rgtSide->Edge( i ); + SMESH_subMesh* tgtSM = mesh->GetSubMesh( E ); + tgtSM->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE ); + } + + // to continue projection from the just computed side as a source + if ( !swapLeftRight && rgtSide->NbEdges() > 1 && w2q->second == iW ) + { + std::pair wgt2quadKeyVal( w2q->first + 1, thePrism.myRightQuadIndex[ iW ]); + wgt2quad.insert( wgt2quadKeyVal ); // it will be skipped by ++w2q + wgt2quad.insert( wgt2quadKeyVal ); + w2q = wgt2quad.rbegin(); + } + } + else + { + // HOPE assigned hypotheses are OK, so that equal nb of segments will be generated + //return toSM( error("Partial projection not implemented")); + } + } // loop on quads of a composite wall side + } // loop on the ordered wall sides + + + + for ( size_t iW = 0; iW != thePrism.myWallQuads.size(); ++iW ) + { + Prism_3D::TQuadList::const_iterator quad = thePrism.myWallQuads[iW].begin(); + for ( ; quad != thePrism.myWallQuads[iW].end(); ++quad ) + { + // Top EDGEs must be projections from the bottom ones + // to compute stuctured quad mesh on wall FACEs + // --------------------------------------------------- + const TopoDS_Edge& botE = (*quad)->side[ QUAD_BOTTOM_SIDE ]->Edge(0); + const TopoDS_Edge& topE = (*quad)->side[ QUAD_TOP_SIDE ]->Edge(0); + + projector1D->myHyp.SetSourceEdge( botE ); + + SMESH_subMesh* tgtEdgeSm = mesh->GetSubMesh( topE ); + if ( !tgtEdgeSm->IsMeshComputed() ) + { + // compute nodes on VERTEXes + tgtEdgeSm->ComputeSubMeshStateEngine( SMESH_subMesh::COMPUTE ); + // project segments + projector1D->InitComputeError(); + bool ok = projector1D->Compute( *mesh, topE ); + if ( !ok ) + { + SMESH_ComputeErrorPtr err = projector1D->GetComputeError(); + if ( err->IsOK() ) err->myName = COMPERR_ALGO_FAILED; + tgtEdgeSm->GetComputeError() = err; + return false; + } + } + tgtEdgeSm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE ); + + // Compute quad mesh on wall FACEs + // ------------------------------- + const TopoDS_Face& face = (*quad)->face; + SMESH_subMesh* fSM = mesh->GetSubMesh( face ); + if ( ! fSM->IsMeshComputed() ) + { + // make all EDGES meshed + fSM->ComputeSubMeshStateEngine( SMESH_subMesh::COMPUTE ); + if ( !fSM->SubMeshesComputed() ) + return toSM( error( COMPERR_BAD_INPUT_MESH, + "Not all edges have valid algorithm and hypothesis")); + // mesh the + quadAlgo->InitComputeError(); + bool ok = quadAlgo->Compute( *mesh, face ); + fSM->GetComputeError() = quadAlgo->GetComputeError(); + if ( !ok ) + return false; + fSM->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE ); + } + if ( myHelper->GetIsQuadratic() ) + { + // fill myHelper with medium nodes built by quadAlgo + SMDS_ElemIteratorPtr fIt = fSM->GetSubMeshDS()->GetElements(); + while ( fIt->more() ) + myHelper->AddTLinks( dynamic_cast( fIt->next() )); + } + } + } + + return true; +} //======================================================================= //function : Evaluate //purpose : //======================================================================= -bool StdMeshers_Prism_3D::Evaluate(SMESH_Mesh& theMesh, +bool StdMeshers_Prism_3D::Evaluate(SMESH_Mesh& theMesh, const TopoDS_Shape& theShape, - MapShapeNbElems& aResMap) + MapShapeNbElems& aResMap) { + if ( theShape.ShapeType() == TopAbs_COMPOUND ) + { + bool ok = true; + for ( TopoDS_Iterator it( theShape ); it.More(); it.Next() ) + ok &= Evaluate( theMesh, it.Value(), aResMap ); + return ok; + } + SMESH_MesherHelper helper( theMesh ); + myHelper = &helper; + myHelper->SetSubShape( theShape ); + // find face contains only triangles vector < SMESH_subMesh * >meshFaces; TopTools_SequenceOfShape aFaces; @@ -582,11 +1283,9 @@ bool StdMeshers_Prism_3D::Evaluate(SMESH_Mesh& theMesh, SMESH_subMesh *aSubMesh = theMesh.GetSubMesh(exp.Current()); meshFaces.push_back(aSubMesh); MapShapeNbElemsItr anIt = aResMap.find(meshFaces[i-1]); - if( anIt==aResMap.end() ) { - SMESH_ComputeErrorPtr& smError = aSubMesh->GetComputeError(); - smError.reset( new SMESH_ComputeError(COMPERR_ALGO_FAILED,"Submesh can not be evaluated",this)); - return false; - } + if( anIt==aResMap.end() ) + return toSM( error( "Submesh can not be evaluated")); + std::vector aVec = (*anIt).second; int nbtri = Max(aVec[SMDSEntity_Triangle],aVec[SMDSEntity_Quad_Triangle]); int nbqua = Max(aVec[SMDSEntity_Quadrangle],aVec[SMDSEntity_Quad_Quadrangle]); @@ -603,9 +1302,7 @@ bool StdMeshers_Prism_3D::Evaluate(SMESH_Mesh& theMesh, for(int i=SMDSEntity_Node; iGetComputeError(); - smError.reset( new SMESH_ComputeError(COMPERR_ALGO_FAILED,"Submesh can not be evaluated",this)); - return false; + return toSM( error( "Submesh can not be evaluated" )); } if(NumBase==0) NumBase = 1; // only quads => set 1 faces as base @@ -676,7 +1373,6 @@ bool StdMeshers_Prism_3D::Evaluate(SMESH_Mesh& theMesh, return true; } - //================================================================================ /*! * \brief Create prisms @@ -815,24 +1511,24 @@ bool StdMeshers_Prism_3D::assocOrProjBottom2Top() SMESHDS_SubMesh * topSMDS = topSM->GetSubMeshDS(); if ( !botSMDS || botSMDS->NbElements() == 0 ) - return error(TCom("No elememts on face #") << botSM->GetId()); + return toSM( error(TCom("No elememts on face #") << botSM->GetId() )); - bool needProject = false; - if ( !topSMDS || - botSMDS->NbElements() != topSMDS->NbElements() || - botSMDS->NbNodes() != topSMDS->NbNodes()) + bool needProject = !topSM->IsMeshComputed(); + if ( !needProject && + (botSMDS->NbElements() != topSMDS->NbElements() || + botSMDS->NbNodes() != topSMDS->NbNodes())) { - MESSAGE("nb elem bot " << botSMDS->NbElements() << " top " << topSMDS->NbElements()); - MESSAGE("nb node bot " << botSMDS->NbNodes() << " top " << topSMDS->NbNodes()); - if ( myBlock.HasNotQuadElemOnTop() ) - return error(TCom("Mesh on faces #") << botSM->GetId() - <<" and #"<< topSM->GetId() << " seems different" ); - needProject = true; + MESSAGE("nb elem bot " << botSMDS->NbElements() << + " top " << ( topSMDS ? topSMDS->NbElements() : 0 )); + MESSAGE("nb node bot " << botSMDS->NbNodes() << + " top " << ( topSMDS ? topSMDS->NbNodes() : 0 )); + return toSM( error(TCom("Mesh on faces #") << botSM->GetId() + <<" and #"<< topSM->GetId() << " seems different" )); } if ( 0/*needProject && !myProjectTriangles*/ ) - return error(TCom("Mesh on faces #") << botSM->GetId() - <<" and #"<< topSM->GetId() << " seems different" ); + return toSM( error(TCom("Mesh on faces #") << botSM->GetId() + <<" and #"<< topSM->GetId() << " seems different" )); ///RETURN_BAD_RESULT("Need to project but not allowed"); if ( needProject ) @@ -847,16 +1543,16 @@ bool StdMeshers_Prism_3D::assocOrProjBottom2Top() if ( !TAssocTool::FindSubShapeAssociation( botFace, myBlock.Mesh(), topFace, myBlock.Mesh(), shape2ShapeMap) ) - return error(TCom("Topology of faces #") << botSM->GetId() - <<" and #"<< topSM->GetId() << " seems different" ); + return toSM( error(TCom("Topology of faces #") << botSM->GetId() + <<" and #"<< topSM->GetId() << " seems different" )); // Find matching nodes of top and bottom faces TNodeNodeMap n2nMap; if ( ! TAssocTool::FindMatchingNodesOnFaces( botFace, myBlock.Mesh(), topFace, myBlock.Mesh(), shape2ShapeMap, n2nMap )) - return error(TCom("Mesh on faces #") << botSM->GetId() - <<" and #"<< topSM->GetId() << " seems different" ); + return toSM( error(TCom("Mesh on faces #") << botSM->GetId() + <<" and #"<< topSM->GetId() << " seems different" )); // Fill myBotToColumnMap @@ -870,7 +1566,7 @@ bool StdMeshers_Prism_3D::assocOrProjBottom2Top() if ( botNode->GetPosition()->GetTypeOfPosition() != SMDS_TOP_FACE ) continue; // wall columns are contained in myBlock // create node column - TNode bN( botNode ); + Prism_3D::TNode bN( botNode ); TNode2ColumnMap::iterator bN_col = myBotToColumnMap.insert( make_pair ( bN, TNodeColumn() )).first; TNodeColumn & column = bN_col->second; @@ -891,23 +1587,24 @@ bool StdMeshers_Prism_3D::assocOrProjBottom2Top() bool StdMeshers_Prism_3D::projectBottomToTop() { + SMESHDS_Mesh* meshDS = myBlock.MeshDS(); SMESH_subMesh * botSM = myBlock.SubMesh( ID_BOT_FACE ); SMESH_subMesh * topSM = myBlock.SubMesh( ID_TOP_FACE ); SMESHDS_SubMesh * botSMDS = botSM->GetSubMeshDS(); SMESHDS_SubMesh * topSMDS = topSM->GetSubMeshDS(); - if ( topSMDS ) + if ( topSMDS && topSMDS->NbElements() > 0 ) topSM->ComputeStateEngine( SMESH_subMesh::CLEAN ); - SMESHDS_Mesh* meshDS = myBlock.MeshDS(); - int shapeID = myHelper->GetSubShapeID(); - int topFaceID = meshDS->ShapeToIndex( topSM->GetSubShape() ); + const TopoDS_Shape& botFace = myBlock.Shape( ID_BOT_FACE ); // oriented within the 3D SHAPE + const TopoDS_Shape& topFace = myBlock.Shape( ID_TOP_FACE); + int topFaceID = meshDS->ShapeToIndex( topFace ); // Fill myBotToColumnMap int zSize = myBlock.VerticalSize(); - TNode prevTNode; + Prism_3D::TNode prevTNode; SMDS_NodeIteratorPtr nIt = botSMDS->GetNodes(); while ( nIt->more() ) { @@ -915,21 +1612,21 @@ bool StdMeshers_Prism_3D::projectBottomToTop() if ( botNode->GetPosition()->GetTypeOfPosition() != SMDS_TOP_FACE ) continue; // strange // compute bottom node params - TNode bN( botNode ); + Prism_3D::TNode bN( botNode ); gp_XYZ paramHint(-1,-1,-1); if ( prevTNode.IsNeighbor( bN )) paramHint = prevTNode.GetParams(); if ( !myBlock.ComputeParameters( bN.GetCoords(), bN.ChangeParams(), ID_BOT_FACE, paramHint )) - return error(TCom("Can't compute normalized parameters for node ") - << botNode->GetID() << " on the face #"<< botSM->GetId() ); + return toSM( error(TCom("Can't compute normalized parameters for node ") + << botNode->GetID() << " on the face #"<< botSM->GetId() )); prevTNode = bN; // compute top node coords gp_XYZ topXYZ; gp_XY topUV; if ( !myBlock.FacePoint( ID_TOP_FACE, bN.GetParams(), topXYZ ) || !myBlock.FaceUV ( ID_TOP_FACE, bN.GetParams(), topUV )) - return error(TCom("Can't compute coordinates " - "by normalized parameters on the face #")<< topSM->GetId() ); + return toSM( error(TCom("Can't compute coordinates " + "by normalized parameters on the face #")<< topSM->GetId() )); SMDS_MeshNode * topNode = meshDS->AddNode( topXYZ.X(),topXYZ.Y(),topXYZ.Z() ); meshDS->SetNodeOnFace( topNode, topFaceID, topUV.X(), topUV.Y() ); // create node column @@ -943,36 +1640,43 @@ bool StdMeshers_Prism_3D::projectBottomToTop() // Create top faces + const bool oldSetElemsOnShape = myHelper->SetElementsOnShape( false ); + + // care of orientation; + // if the bottom faces is orienetd OK then top faces must be reversed + bool reverseTop = true; + if ( myHelper->NbAncestors( botFace, *myBlock.Mesh(), TopAbs_SOLID ) > 1 ) + reverseTop = ! SMESH_Algo::IsReversedSubMesh( TopoDS::Face( botFace ), meshDS ); + int iFrw, iRev, *iPtr = &( reverseTop ? iRev : iFrw ); + // loop on bottom mesh faces SMDS_ElemIteratorPtr faceIt = botSMDS->GetElements(); + vector< const SMDS_MeshNode* > nodes; while ( faceIt->more() ) { const SMDS_MeshElement* face = faceIt->next(); if ( !face || face->GetType() != SMDSAbs_Face ) continue; - int nbNodes = face->NbNodes(); - if ( face->IsQuadratic() ) - nbNodes /= 2; // find top node in columns for each bottom node - vector< const SMDS_MeshNode* > nodes( nbNodes ); - for ( int i = 0; i < nbNodes; ++i ) + int nbNodes = face->NbCornerNodes(); + nodes.resize( nbNodes ); + for ( iFrw = 0, iRev = nbNodes-1; iFrw < nbNodes; ++iFrw, --iRev ) { - const SMDS_MeshNode* n = face->GetNode( nbNodes - i - 1 ); + const SMDS_MeshNode* n = face->GetNode( *iPtr ); if ( n->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE ) { TNode2ColumnMap::iterator bot_column = myBotToColumnMap.find( n ); if ( bot_column == myBotToColumnMap.end() ) - return error(TCom("No nodes found above node ") << n->GetID() ); - nodes[ i ] = bot_column->second.back(); + return toSM( error(TCom("No nodes found above node ") << n->GetID() )); + nodes[ iFrw ] = bot_column->second.back(); } else { const TNodeColumn* column = myBlock.GetNodeColumn( n ); if ( !column ) - return error(TCom("No side nodes found above node ") << n->GetID() ); - nodes[ i ] = column->back(); + return toSM( error(TCom("No side nodes found above node ") << n->GetID() )); + nodes[ iFrw ] = column->back(); } } - // create a face, with reversed orientation SMDS_MeshElement* newFace = 0; switch ( nbNodes ) { @@ -987,13 +1691,35 @@ bool StdMeshers_Prism_3D::projectBottomToTop() default: newFace = meshDS->AddPolygonalFace( nodes ); } - if ( newFace && shapeID > 0 ) - meshDS->SetMeshElementOnShape( newFace, shapeID ); + if ( newFace ) + meshDS->SetMeshElementOnShape( newFace, topFaceID ); } + myHelper->SetElementsOnShape( oldSetElemsOnShape ); + return true; } +//======================================================================= +//function : project2dMesh +//purpose : Project mesh faces from a source FACE of one prism (theSrcFace) +// to a source FACE of another prism (theTgtFace) +//======================================================================= + +bool StdMeshers_Prism_3D::project2dMesh(const TopoDS_Face& theSrcFace, + const TopoDS_Face& theTgtFace) +{ + TProjction2dAlgo* projector2D = TProjction2dAlgo::instance( this ); + projector2D->myHyp.SetSourceFace( theSrcFace ); + bool ok = projector2D->Compute( *myHelper->GetMesh(), theTgtFace ); + + SMESH_subMesh* tgtSM = myHelper->GetMesh()->GetSubMesh( theTgtFace ); + tgtSM->ComputeStateEngine ( SMESH_subMesh::CHECK_COMPUTE_STATE ); + tgtSM->ComputeSubMeshStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE ); + + return ok; +} + //================================================================================ /*! * \brief Set projection coordinates of a node to a face and it's sub-shapes @@ -1031,23 +1757,78 @@ bool StdMeshers_Prism_3D::setFaceAndEdgesXYZ( const int faceID, const gp_XYZ& pa return true; } -//================================================================================ -/*! - * \brief Return true if this node and other one belong to one face - */ -//================================================================================ +//======================================================================= +//function : toSM +//purpose : If (!isOK), sets the error to a sub-mesh of a current SOLID +//======================================================================= -bool TNode::IsNeighbor( const TNode& other ) const +bool StdMeshers_Prism_3D::toSM( bool isOK ) { - if ( !other.myNode || !myNode ) return false; + if ( mySetErrorToSM && + !isOK && + myHelper && + !myHelper->GetSubShape().IsNull() && + myHelper->GetSubShape().ShapeType() == TopAbs_SOLID) + { + SMESH_subMesh* sm = myHelper->GetMesh()->GetSubMesh( myHelper->GetSubShape() ); + sm->GetComputeError() = this->GetComputeError(); + // clear error in order not to return it twice + _error = COMPERR_OK; + _comment.clear(); + } + return isOK; +} + +//======================================================================= +//function : shapeID +//purpose : Return index of a shape +//======================================================================= - SMDS_ElemIteratorPtr fIt = other.myNode->GetInverseElementIterator(SMDSAbs_Face); - while ( fIt->more() ) - if ( fIt->next()->GetNodeIndex( myNode ) >= 0 ) - return true; - return false; +int StdMeshers_Prism_3D::shapeID( const TopoDS_Shape& S ) +{ + if ( S.IsNull() ) return 0; + if ( !myHelper ) return -3; + return myHelper->GetMeshDS()->ShapeToIndex( S ); } +namespace Prism_3D +{ + //================================================================================ + /*! + * \brief Return true if this node and other one belong to one face + */ + //================================================================================ + + bool Prism_3D::TNode::IsNeighbor( const Prism_3D::TNode& other ) const + { + if ( !other.myNode || !myNode ) return false; + + SMDS_ElemIteratorPtr fIt = other.myNode->GetInverseElementIterator(SMDSAbs_Face); + while ( fIt->more() ) + if ( fIt->next()->GetNodeIndex( myNode ) >= 0 ) + return true; + return false; + } + + //================================================================================ + /*! + * \brief Prism initialization + */ + //================================================================================ + + void TPrismTopo::Clear() + { + myShape3D.Nullify(); + myTop.Nullify(); + myBottom.Nullify(); + myWallQuads.clear(); + myBottomEdges.clear(); + myNbEdgesInWires.clear(); + myWallQuads.clear(); + } + +} // namespace Prism_3D + //================================================================================ /*! * \brief Constructor. Initialization is needed @@ -1076,242 +1857,142 @@ void StdMeshers_PrismAsBlock::Clear() myShapeIndex2ColumnMap.clear(); } -//================================================================================ -/*! - * \brief Initialization. - * \param helper - helper loaded with mesh and 3D shape - * \param shape3D - a closed shell or solid - * \retval bool - false if a mesh or a shape are KO - */ -//================================================================================ +//======================================================================= +//function : initPrism +//purpose : Analyse shape geometry and mesh. +// If there are triangles on one of faces, it becomes 'bottom'. +// thePrism.myBottom can be already set up. +//======================================================================= -bool StdMeshers_PrismAsBlock::Init(SMESH_MesherHelper* helper, - const TopoDS_Shape& shape3D) +bool StdMeshers_Prism_3D::initPrism(Prism_3D::TPrismTopo& thePrism, + const TopoDS_Shape& shape3D) { - if ( mySide ) { - delete mySide; mySide = 0; - } - vector< TSideFace* > sideFaces( NB_WALL_FACES, 0 ); - vector< pair< double, double> > params ( NB_WALL_FACES ); - mySide = new TSideFace( sideFaces, params ); - - myHelper = helper; - SMESHDS_Mesh* meshDS = myHelper->GetMeshDS(); + myHelper->SetSubShape( shape3D ); - SMESH_Block::init(); - myShapeIDMap.Clear(); - myShapeIndex2ColumnMap.clear(); - - int wallFaceIds[ NB_WALL_FACES ] = { // to walk around a block - SMESH_Block::ID_Fx0z, SMESH_Block::ID_F1yz, - SMESH_Block::ID_Fx1z, SMESH_Block::ID_F0yz - }; - - myError = SMESH_ComputeError::New(); - - // ------------------------------------------------------------- - // Look for top and bottom faces: not quadrangle ones or meshed - // with not quadrangle elements - // ------------------------------------------------------------- + SMESH_subMesh* mainSubMesh = myHelper->GetMesh()->GetSubMeshContaining( shape3D ); + if ( !mainSubMesh ) return toSM( error(COMPERR_BAD_INPUT_MESH,"Null submesh of shape3D")); + // detect not-quad FACE sub-meshes of the 3D SHAPE list< SMESH_subMesh* > notQuadGeomSubMesh; list< SMESH_subMesh* > notQuadElemSubMesh; int nbFaces = 0; // - SMESH_subMesh* mainSubMesh = myHelper->GetMesh()->GetSubMeshContaining( shape3D ); - if ( !mainSubMesh ) return error(COMPERR_BAD_INPUT_MESH,"Null submesh of shape3D"); - - // analyse face submeshes - SMESH_subMeshIteratorPtr smIt = mainSubMesh->getDependsOnIterator(false,false); + SMESH_subMesh* anyFaceSM = 0; + SMESH_subMeshIteratorPtr smIt = mainSubMesh->getDependsOnIterator(false,true); while ( smIt->more() ) { SMESH_subMesh* sm = smIt->next(); const TopoDS_Shape& face = sm->GetSubShape(); - if ( face.ShapeType() != TopAbs_FACE ) - continue; + if ( face.ShapeType() > TopAbs_FACE ) break; + else if ( face.ShapeType() < TopAbs_FACE ) continue; nbFaces++; + anyFaceSM = sm; - // is quadrangle face? + // is quadrangle FACE? list< TopoDS_Edge > orderedEdges; list< int > nbEdgesInWires; - TopoDS_Vertex V000; - int nbWires = GetOrderedEdges( TopoDS::Face( face ), - V000, orderedEdges, nbEdgesInWires ); + int nbWires = SMESH_Block::GetOrderedEdges( TopoDS::Face( face ), orderedEdges, + nbEdgesInWires ); if ( nbWires != 1 || nbEdgesInWires.front() != 4 ) notQuadGeomSubMesh.push_back( sm ); // look for not quadrangle mesh elements - if ( SMESHDS_SubMesh* smDS = sm->GetSubMeshDS() ) { - bool hasNotQuad = false; - SMDS_ElemIteratorPtr eIt = smDS->GetElements(); - while ( eIt->more() && !hasNotQuad ) { - const SMDS_MeshElement* elem = eIt->next(); - if ( elem->GetType() == SMDSAbs_Face ) { - int nbNodes = elem->NbNodes(); - if ( elem->IsQuadratic() ) - nbNodes /= 2; - hasNotQuad = ( nbNodes != 4 ); - } - } - if ( hasNotQuad ) + if ( SMESHDS_SubMesh* smDS = sm->GetSubMeshDS() ) + if ( !myHelper->IsSameElemGeometry( smDS, SMDSGeom_QUADRANGLE )) notQuadElemSubMesh.push_back( sm ); - } - else { - return error(COMPERR_BAD_INPUT_MESH,TCom("Not meshed face #")<GetId()); - } - // check if a quadrangle face is meshed with a quadranglar grid - if ( notQuadGeomSubMesh.back() != sm && - notQuadElemSubMesh.back() != sm ) - { - // count nb edges on face sides - vector< int > nbEdges; - nbEdges.reserve( nbEdgesInWires.front() ); - for ( list< TopoDS_Edge >::iterator edge = orderedEdges.begin(); - edge != orderedEdges.end(); ++edge ) - { - if ( SMESHDS_SubMesh* smDS = meshDS->MeshElements( *edge )) - nbEdges.push_back ( smDS->NbElements() ); - else - nbEdges.push_back ( 0 ); - } - int nbQuads = sm->GetSubMeshDS()->NbElements(); - if ( nbEdges[0] * nbEdges[1] != nbQuads || - nbEdges[0] != nbEdges[2] || - nbEdges[1] != nbEdges[3] ) - notQuadElemSubMesh.push_back( sm ); - } } - // ---------------------------------------------------------------------- - // Analyse mesh and topology of faces: choose the bottom submesh. - // If there are not quadrangle geom faces, they are top and bottom ones. - // Not quadrangle geom faces must be only on top and bottom. - // ---------------------------------------------------------------------- - - SMESH_subMesh * botSM = 0; - SMESH_subMesh * topSM = 0; - - int nbNotQuad = notQuadGeomSubMesh.size(); int nbNotQuadMeshed = notQuadElemSubMesh.size(); - bool hasNotQuad = ( nbNotQuad || nbNotQuadMeshed ); + int nbNotQuad = notQuadGeomSubMesh.size(); + bool hasNotQuad = ( nbNotQuad || nbNotQuadMeshed ); // detect bad cases if ( nbNotQuadMeshed > 2 ) { - return error(COMPERR_BAD_INPUT_MESH, - TCom("More than 2 faces with not quadrangle elements: ") - < 0 && nbNotQuad != 2 ) + if ( nbNotQuad > 2 || !thePrism.myBottom.IsNull() ) { - // Issue 0020843 - one of side faces is quasi-quadrilateral. + // Issue 0020843 - one of side FACEs is quasi-quadrilateral (not 4 EDGEs). // Remove from notQuadGeomSubMesh faces meshed with regular grid - nbQuasiQuads = removeQuasiQuads( notQuadGeomSubMesh ); + int nbQuasiQuads = removeQuasiQuads( notQuadGeomSubMesh, myHelper, + TQuadrangleAlgo::instance(this,myHelper) ); nbNotQuad -= nbQuasiQuads; - if ( nbNotQuad > 0 && nbNotQuad != 2 ) - return error(COMPERR_BAD_SHAPE, - TCom("More than 2 not quadrilateral faces: ") - < 2 ) + return toSM( error(COMPERR_BAD_SHAPE, + TCom("More than 2 not quadrilateral faces: ") < 0 ) botSM = notQuadElemSubMesh.front(); else botSM = notQuadGeomSubMesh.front(); if ( nbNotQuadMeshed > 1 ) topSM = notQuadElemSubMesh.back(); else if ( nbNotQuad > 1 ) topSM = notQuadGeomSubMesh.back(); - } - // detect other bad cases - if ( nbNotQuad == 2 && nbNotQuadMeshed > 0 ) { - bool ok = false; - if ( nbNotQuadMeshed == 1 ) - ok = ( find( notQuadGeomSubMesh.begin(), - notQuadGeomSubMesh.end(), botSM ) != notQuadGeomSubMesh.end() ); - else - ok = ( notQuadGeomSubMesh == notQuadElemSubMesh ); - if ( !ok ) - return error(COMPERR_BAD_INPUT_MESH, "Side face meshed with not quadrangle elements"); + + if ( topSM == botSM ) { + if ( nbNotQuadMeshed > 1 ) topSM = notQuadElemSubMesh.front(); + else topSM = notQuadGeomSubMesh.front(); + } + + // detect mesh triangles on wall FACEs + if ( nbNotQuad == 2 && nbNotQuadMeshed > 0 ) { + bool ok = false; + if ( nbNotQuadMeshed == 1 ) + ok = ( find( notQuadGeomSubMesh.begin(), + notQuadGeomSubMesh.end(), botSM ) != notQuadGeomSubMesh.end() ); + else + ok = ( notQuadGeomSubMesh == notQuadElemSubMesh ); + if ( !ok ) + return toSM( error(COMPERR_BAD_INPUT_MESH, + "Side face meshed with not quadrangle elements")); + } } - myNotQuadOnTop = ( nbNotQuadMeshed > 1 ); - MESSAGE("myNotQuadOnTop " << myNotQuadOnTop << " nbNotQuadMeshed " << nbNotQuadMeshed); - - // ---------------------------------------------------------- + thePrism.myNotQuadOnTop = ( nbNotQuadMeshed > 1 ); - if ( nbNotQuad == 0 ) // Standard block of 6 quadrangle faces ? + // use thePrism.myBottom + if ( !thePrism.myBottom.IsNull() ) { - // SMESH_Block will perform geometry analysis, we need just to find 2 - // connected vertices on top and bottom - - TopoDS_Vertex Vbot, Vtop; - if ( nbNotQuadMeshed > 0 ) // Look for vertices - { - TopTools_IndexedMapOfShape edgeMap; - TopExp::MapShapes( botSM->GetSubShape(), TopAbs_EDGE, edgeMap ); - // vertex 1 is any vertex of the bottom face - Vbot = TopExp::FirstVertex( TopoDS::Edge( edgeMap( 1 ))); - // vertex 2 is end vertex of edge sharing Vbot and not belonging to the bottom face - TopTools_ListIteratorOfListOfShape ancestIt = Mesh()->GetAncestors( Vbot ); - for ( ; Vtop.IsNull() && ancestIt.More(); ancestIt.Next() ) - { - const TopoDS_Shape & ancestor = ancestIt.Value(); - if ( ancestor.ShapeType() == TopAbs_EDGE && !edgeMap.FindIndex( ancestor )) - { - TopoDS_Vertex V1, V2; - TopExp::Vertices( TopoDS::Edge( ancestor ), V1, V2); - if ( Vbot.IsSame ( V1 )) Vtop = V2; - else if ( Vbot.IsSame ( V2 )) Vtop = V1; - // check that Vtop belongs to shape3D - TopExp_Explorer exp( shape3D, TopAbs_VERTEX ); - for ( ; exp.More(); exp.Next() ) - if ( Vtop.IsSame( exp.Current() )) - break; - if ( !exp.More() ) - Vtop.Nullify(); - } + if ( botSM ) { + if ( ! botSM->GetSubShape().IsSame( thePrism.myBottom )) { + std::swap( botSM, topSM ); + if ( ! botSM->GetSubShape().IsSame( thePrism.myBottom )) + return toSM( error( COMPERR_BAD_INPUT_MESH, + "Incompatible non-structured sub-meshes")); } } - // get shell from shape3D - TopoDS_Shell shell; - TopExp_Explorer exp( shape3D, TopAbs_SHELL ); - int nbShell = 0; - for ( ; exp.More(); exp.Next(), ++nbShell ) - shell = TopoDS::Shell( exp.Current() ); -// if ( nbShell != 1 ) -// RETURN_BAD_RESULT("There must be 1 shell in the block"); - - // Load geometry in SMESH_Block - if ( !SMESH_Block::FindBlockShapes( shell, Vbot, Vtop, myShapeIDMap )) { - if ( !hasNotQuad ) - return error(COMPERR_BAD_SHAPE, "Can't detect top and bottom of a prism"); - } else { - if ( !botSM ) botSM = Mesh()->GetSubMeshContaining( myShapeIDMap( ID_BOT_FACE )); - if ( !topSM ) topSM = Mesh()->GetSubMeshContaining( myShapeIDMap( ID_TOP_FACE )); + botSM = myHelper->GetMesh()->GetSubMesh( thePrism.myBottom ); } - - } // end Standard block of 6 quadrangle faces - // -------------------------------------------------------- - - // Here the top and bottom faces are found - if ( nbNotQuadMeshed == 2 ) // roughly check correspondence of horiz meshes + } + else if ( !botSM ) // find a proper bottom { -// SMESHDS_SubMesh* topSMDS = topSM->GetSubMeshDS(); -// SMESHDS_SubMesh* botSMDS = botSM->GetSubMeshDS(); -// if ( topSMDS->NbNodes() != botSMDS->NbNodes() || -// topSMDS->NbElements() != botSMDS->NbElements() ) -// RETURN_BAD_RESULT("Top mesh doesn't correspond to bottom one"); + // composite walls or not prism shape + for ( TopExp_Explorer f( shape3D, TopAbs_FACE ); f.More(); f.Next() ) + { + int minNbFaces = 2 + myHelper->Count( f.Current(), TopAbs_EDGE, false); + if ( nbFaces >= minNbFaces) + { + thePrism.Clear(); + thePrism.myBottom = TopoDS::Face( f.Current() ); + if ( initPrism( thePrism, shape3D )) + return true; + } + return toSM( error( COMPERR_BAD_SHAPE )); + } } - // --------------------------------------------------------- - // If there are not quadrangle geom faces, we emulate - // a block of 6 quadrangle faces. - // Load SMESH_Block with faces and edges geometry - // --------------------------------------------------------- - - // find vertex 000 - the one with smallest coordinates (for easy DEBUG :-) TopoDS_Vertex V000; double minVal = DBL_MAX, minX, val; @@ -1328,63 +2009,101 @@ bool StdMeshers_PrismAsBlock::Init(SMESH_MesherHelper* helper, } } + thePrism.myShape3D = shape3D; + if ( thePrism.myBottom.IsNull() ) + thePrism.myBottom = TopoDS::Face( botSM->GetSubShape() ); + thePrism.myBottom.Orientation( myHelper->GetSubShapeOri( shape3D, + thePrism.myBottom )); // Get ordered bottom edges - list< TopoDS_Edge > orderedEdges; - list< int > nbEInW; - SMESH_Block::GetOrderedEdges( TopoDS::Face( botSM->GetSubShape().Reversed() ), - V000, orderedEdges, nbEInW ); -// if ( nbEInW.size() != 1 ) -// RETURN_BAD_RESULT("Wrong prism geometry"); - - // Get Wall faces corresponding to the ordered bottom edges - list< TopoDS_Face > wallFaces; - if ( !GetWallFaces( Mesh(), shape3D, botSM->GetSubShape(), orderedEdges, nbEInW, wallFaces)) - return error(COMPERR_BAD_SHAPE, "Can't find side faces"); - - // check that the found top and bottom faces are opposite + TopoDS_Face reverseBottom = // to have order of top EDGEs as in the top FACE + TopoDS::Face( thePrism.myBottom.Reversed() ); + SMESH_Block::GetOrderedEdges( reverseBottom, + thePrism.myBottomEdges, + thePrism.myNbEdgesInWires, V000 ); + + // Get Wall faces corresponding to the ordered bottom edges and the top FACE + if ( !getWallFaces( thePrism, nbFaces )) + return false; //toSM( error(COMPERR_BAD_SHAPE, "Can't find side faces")); + + if ( topSM ) { - for (TopExp_Explorer edge(botSM->GetSubShape(), TopAbs_EDGE); edge.More(); edge.Next()) - if ( helper->IsSubShape( edge.Current(), topSM->GetSubShape() )) - return error(notQuadGeomSubMesh.empty() ? COMPERR_BAD_INPUT_MESH : COMPERR_BAD_SHAPE, - "Non-quadrilateral faces are not opposite"); + if ( !thePrism.myTop.IsSame( topSM->GetSubShape() )) + return toSM( error + (notQuadGeomSubMesh.empty() ? COMPERR_BAD_INPUT_MESH : COMPERR_BAD_SHAPE, + "Non-quadrilateral faces are not opposite")); + + // check that the found top and bottom FACEs are opposite + list< TopoDS_Edge >::iterator edge = thePrism.myBottomEdges.begin(); + for ( ; edge != thePrism.myBottomEdges.end(); ++edge ) + if ( myHelper->IsSubShape( *edge, thePrism.myTop )) + return toSM( error + (notQuadGeomSubMesh.empty() ? COMPERR_BAD_INPUT_MESH : COMPERR_BAD_SHAPE, + "Non-quadrilateral faces are not opposite")); } - // Protect from a distorted block (test 3D_mesh_HEXA3D/B7 on 32bit platform) - // check that all wall faces have an edge common with the top face - { - list< TopoDS_Face >::iterator faceIt = wallFaces.begin(); - for ( ; faceIt != wallFaces.end(); ++faceIt ) - { - bool hasCommon = false; - for (TopExp_Explorer edge(*faceIt, TopAbs_EDGE); !hasCommon && edge.More(); edge.Next()) - if ( helper->IsSubShape( edge.Current(), topSM->GetSubShape() )) - hasCommon = true; - if ( !hasCommon ) - return error(COMPERR_BAD_SHAPE); - } + return true; +} + +//================================================================================ +/*! + * \brief Initialization. + * \param helper - helper loaded with mesh and 3D shape + * \param thePrism - a prosm data + * \retval bool - false if a mesh or a shape are KO + */ +//================================================================================ + +bool StdMeshers_PrismAsBlock::Init(SMESH_MesherHelper* helper, + const Prism_3D::TPrismTopo& thePrism) +{ + if ( mySide ) { + delete mySide; mySide = 0; } + vector< TSideFace* > sideFaces( NB_WALL_FACES, 0 ); + vector< pair< double, double> > params( NB_WALL_FACES ); + mySide = new TSideFace( sideFaces, params ); + + myHelper = helper; + SMESHDS_Mesh* meshDS = myHelper->GetMeshDS(); + + SMESH_Block::init(); + myShapeIDMap.Clear(); + myShapeIndex2ColumnMap.clear(); + + int wallFaceIds[ NB_WALL_FACES ] = { // to walk around a block + SMESH_Block::ID_Fx0z, SMESH_Block::ID_F1yz, + SMESH_Block::ID_Fx1z, SMESH_Block::ID_F0yz + }; + + myError = SMESH_ComputeError::New(); + + myNotQuadOnTop = thePrism.myNotQuadOnTop; // Find columns of wall nodes and calculate edges' lengths // -------------------------------------------------------- myParam2ColumnMaps.clear(); - myParam2ColumnMaps.resize( orderedEdges.size() ); // total nb edges + myParam2ColumnMaps.resize( thePrism.myBottomEdges.size() ); // total nb edges - int iE, nbEdges = nbEInW.front(); // nb outer edges - vector< double > edgeLength( nbEdges ); - map< double, int > len2edgeMap; + size_t iE, nbEdges = thePrism.myNbEdgesInWires.front(); // nb outer edges + vector< double > edgeLength( nbEdges ); + multimap< double, int > len2edgeMap; - list< TopoDS_Edge >::iterator edgeIt = orderedEdges.begin(); - list< TopoDS_Face >::iterator faceIt = wallFaces.begin(); - for ( iE = 0; iE < nbEdges; ++edgeIt, ++faceIt ) + list< TopoDS_Edge >::const_iterator edgeIt = thePrism.myBottomEdges.begin(); + for ( iE = 0; iE < nbEdges; ++iE, ++edgeIt ) { TParam2ColumnMap & faceColumns = myParam2ColumnMaps[ iE ]; - if ( !myHelper->LoadNodeColumns( faceColumns, *faceIt, *edgeIt, meshDS )) - return error(COMPERR_BAD_INPUT_MESH, TCom("Can't find regular quadrangle mesh ") - << "on a side face #" << MeshDS()->ShapeToIndex( *faceIt )); - SHOWYXZ("\np1 F "<second.front() )); - SHOWYXZ("p2 F "<second.front() )); + Prism_3D::TQuadList::const_iterator quad = thePrism.myWallQuads[ iE ].begin(); + for ( ; quad != thePrism.myWallQuads[ iE ].end(); ++quad ) + { + const TopoDS_Edge& quadBot = (*quad)->side[ QUAD_BOTTOM_SIDE ]->Edge( 0 ); + if ( !myHelper->LoadNodeColumns( faceColumns, (*quad)->face, quadBot, meshDS )) + return error(COMPERR_BAD_INPUT_MESH, TCom("Can't find regular quadrangle mesh ") + << "on a side face #" << MeshDS()->ShapeToIndex( (*quad)->face )); + } + SHOWYXZ("\np1 F " <second.front() )); + SHOWYXZ("p2 F " <second.front() )); SHOWYXZ("V First "<ShapeToIndex( *edgeIt )); - // assure length uniqueness - edgeLength[ iE ] *= smDS->NbNodes() + edgeLength[ iE ] / ( 1000 + iE ); - len2edgeMap[ edgeLength[ iE ]] = iE; + len2edgeMap.insert( make_pair( edgeLength[ iE ], iE )); } - ++iE; } // Load columns of internal edges (forming holes) // and fill map ShapeIndex to TParam2ColumnMap for them - for ( ; edgeIt != orderedEdges.end() ; ++edgeIt, ++faceIt ) + for ( ; edgeIt != thePrism.myBottomEdges.end() ; ++edgeIt, ++iE ) { TParam2ColumnMap & faceColumns = myParam2ColumnMaps[ iE ]; - if ( !myHelper->LoadNodeColumns( faceColumns, *faceIt, *edgeIt, meshDS )) - return error(COMPERR_BAD_INPUT_MESH, TCom("Can't find regular quadrangle mesh ") - << "on a side face #" << MeshDS()->ShapeToIndex( *faceIt )); + + Prism_3D::TQuadList::const_iterator quad = thePrism.myWallQuads[ iE ].begin(); + for ( ; quad != thePrism.myWallQuads[ iE ].end(); ++quad ) + { + const TopoDS_Edge& quadBot = (*quad)->side[ QUAD_BOTTOM_SIDE ]->Edge( 0 ); + if ( !myHelper->LoadNodeColumns( faceColumns, (*quad)->face, quadBot, meshDS )) + return error(COMPERR_BAD_INPUT_MESH, TCom("Can't find regular quadrangle mesh ") + << "on a side face #" << MeshDS()->ShapeToIndex( (*quad)->face )); + } // edge columns int id = MeshDS()->ShapeToIndex( *edgeIt ); bool isForward = true; // meaningless for intenal wires @@ -1422,10 +2144,10 @@ bool StdMeshers_PrismAsBlock::Init(SMESH_MesherHelper* helper, const SMDS_MeshNode* n1 = faceColumns.rbegin()->second.front(); id = n1->getshapeId(); myShapeIndex2ColumnMap[ id ] = make_pair( & faceColumns, isForward ); -// SHOWYXZ("\np1 F "<second.front() )); -// SHOWYXZ("p2 F "<second.front() )); -// SHOWYXZ("V First "<second.front() )); + // SHOWYXZ("p2 F " <second.front() )); + // SHOWYXZ("V First "<::const_iterator botE = thePrism.myBottomEdges.begin(); + for ( iE = 0; iE < nbEdges; ++iE, ++botE ) { - // split? + TFaceQuadStructPtr quad = thePrism.myWallQuads[ iE ].front(); + // split? map< int, int >::iterator i_nb = iE2nbSplit.find( iE ); if ( i_nb != iE2nbSplit.end() ) { // split! @@ -1475,23 +2197,22 @@ bool StdMeshers_PrismAsBlock::Init(SMESH_MesherHelper* helper, const bool isForward = StdMeshers_PrismAsBlock::IsForwardEdge( myHelper->GetMeshDS(), myParam2ColumnMaps[iE], - *edgeIt, SMESH_Block::ID_Fx0z ); + *botE, SMESH_Block::ID_Fx0z ); for ( int i = 0; i < nbSplit; ++i ) { double f = ( isForward ? params[ i ] : params[ nbSplit - i-1 ]); double l = ( isForward ? params[ i+1 ] : params[ nbSplit - i ]); TSideFace* comp = new TSideFace( myHelper, wallFaceIds[ iSide ], - *faceIt, *edgeIt, + thePrism.myWallQuads[ iE ], *botE, &myParam2ColumnMaps[ iE ], f, l ); mySide->SetComponent( iSide++, comp ); } } else { TSideFace* comp = new TSideFace( myHelper, wallFaceIds[ iSide ], - *faceIt, *edgeIt, + thePrism.myWallQuads[ iE ], *botE, &myParam2ColumnMaps[ iE ]); mySide->SetComponent( iSide++, comp ); } - ++iE; } } else { // **************************** Unite faces @@ -1503,30 +2224,27 @@ bool StdMeshers_PrismAsBlock::Init(SMESH_MesherHelper* helper, for ( iE = 0; iE < nbExraFaces; ++iE ) sumLen += edgeLength[ iE ]; - vector< TSideFace* > components( nbExraFaces ); + vector< TSideFace* > components( nbExraFaces ); vector< pair< double, double> > params( nbExraFaces ); - faceIt = wallFaces.begin(); - edgeIt = orderedEdges.begin(); - for ( iE = 0; iE < nbExraFaces; ++edgeIt, ++faceIt ) + list< TopoDS_Edge >::const_iterator botE = thePrism.myBottomEdges.begin(); + for ( iE = 0; iE < nbExraFaces; ++iE, ++botE ) { components[ iE ] = new TSideFace( myHelper, wallFaceIds[ iSide ], - *faceIt, *edgeIt, + thePrism.myWallQuads[ iE ], *botE, &myParam2ColumnMaps[ iE ]); double u1 = u0 + edgeLength[ iE ] / sumLen; params[ iE ] = make_pair( u0 , u1 ); u0 = u1; - ++iE; } mySide->SetComponent( iSide++, new TSideFace( components, params )); // fill the rest faces - for ( ; iE < nbEdges; ++faceIt, ++edgeIt ) + for ( ; iE < nbEdges; ++iE, ++botE ) { TSideFace* comp = new TSideFace( myHelper, wallFaceIds[ iSide ], - *faceIt, *edgeIt, + thePrism.myWallQuads[ iE ], *botE, &myParam2ColumnMaps[ iE ]); mySide->SetComponent( iSide++, comp ); - ++iE; } } @@ -1534,9 +2252,6 @@ bool StdMeshers_PrismAsBlock::Init(SMESH_MesherHelper* helper, // Fill geometry fields of SMESH_Block // ------------------------------------ - TopoDS_Face botF = TopoDS::Face( botSM->GetSubShape() ); - TopoDS_Face topF = TopoDS::Face( topSM->GetSubShape() ); - vector< int > botEdgeIdVec; SMESH_Block::GetFaceEdgesIDs( ID_BOT_FACE, botEdgeIdVec ); @@ -1549,7 +2264,7 @@ bool StdMeshers_PrismAsBlock::Init(SMESH_MesherHelper* helper, TSideFace * sideFace = mySide->GetComponent( iF ); if ( !sideFace ) RETURN_BAD_RESULT("NULL TSideFace"); - int fID = sideFace->FaceID(); + int fID = sideFace->FaceID(); // in-block ID // fill myShapeIDMap if ( sideFace->InsertSubShapes( myShapeIDMap ) != 8 && @@ -1593,8 +2308,8 @@ bool StdMeshers_PrismAsBlock::Init(SMESH_MesherHelper* helper, // pcurves on horizontal faces for ( iE = 0; iE < NB_WALL_FACES; ++iE ) { if ( edgeIdVec[ BOTTOM_EDGE ] == botEdgeIdVec[ iE ] ) { - botPcurves[ iE ] = sideFace->HorizPCurve( false, botF ); - topPcurves[ iE ] = sideFace->HorizPCurve( true, topF ); + botPcurves[ iE ] = sideFace->HorizPCurve( false, thePrism.myBottom ); + topPcurves[ iE ] = sideFace->HorizPCurve( true, thePrism.myTop ); break; } } @@ -1603,13 +2318,13 @@ bool StdMeshers_PrismAsBlock::Init(SMESH_MesherHelper* helper, // horizontal faces geometry { SMESH_Block::TFace& tFace = myFace[ ID_BOT_FACE - ID_FirstF ]; - tFace.Set( ID_BOT_FACE, new BRepAdaptor_Surface( botF ), botPcurves, isForward ); - SMESH_Block::Insert( botF, ID_BOT_FACE, myShapeIDMap ); + tFace.Set( ID_BOT_FACE, new BRepAdaptor_Surface( thePrism.myBottom ), botPcurves, isForward ); + SMESH_Block::Insert( thePrism.myBottom, ID_BOT_FACE, myShapeIDMap ); } { SMESH_Block::TFace& tFace = myFace[ ID_TOP_FACE - ID_FirstF ]; - tFace.Set( ID_TOP_FACE, new BRepAdaptor_Surface( topF ), topPcurves, isForward ); - SMESH_Block::Insert( topF, ID_TOP_FACE, myShapeIDMap ); + tFace.Set( ID_TOP_FACE, new BRepAdaptor_Surface( thePrism.myTop ), topPcurves, isForward ); + SMESH_Block::Insert( thePrism.myTop, ID_TOP_FACE, myShapeIDMap ); } // Fill map ShapeIndex to TParam2ColumnMap @@ -1685,7 +2400,8 @@ const TNodeColumn* StdMeshers_PrismAsBlock::GetNodeColumn(const SMDS_MeshNode* n // from bottom to top. //======================================================================= -bool StdMeshers_PrismAsBlock::GetLayersTransformation(vector & trsf) const +bool StdMeshers_PrismAsBlock::GetLayersTransformation(vector & trsf, + const Prism_3D::TPrismTopo& prism) const { const int zSize = VerticalSize(); if ( zSize < 3 ) return true; @@ -1695,21 +2411,17 @@ bool StdMeshers_PrismAsBlock::GetLayersTransformation(vector & trsf) co vector< const TNodeColumn* > columns; { - const TopoDS_Shape& baseFace = Shape(ID_BOT_FACE); - list< TopoDS_Edge > orderedEdges; - list< int > nbEdgesInWires; - GetOrderedEdges( TopoDS::Face( baseFace ), TopoDS_Vertex(), orderedEdges, nbEdgesInWires ); bool isReverse; - list< TopoDS_Edge >::iterator edgeIt = orderedEdges.begin(); - for ( int iE = 0; iE < nbEdgesInWires.front(); ++iE, ++edgeIt ) + list< TopoDS_Edge >::const_iterator edgeIt = prism.myBottomEdges.begin(); + for ( int iE = 0; iE < prism.myNbEdgesInWires.front(); ++iE, ++edgeIt ) { if ( BRep_Tool::Degenerated( *edgeIt )) continue; const TParam2ColumnMap* u2colMap = - GetParam2ColumnMap( myHelper->GetMeshDS()->ShapeToIndex( *edgeIt ), isReverse ); + GetParam2ColumnMap( MeshDS()->ShapeToIndex( *edgeIt ), isReverse ); if ( !u2colMap ) return false; - isReverse = ( edgeIt->Orientation() == TopAbs_REVERSED ); double f = u2colMap->begin()->first, l = u2colMap->rbegin()->first; - if ( isReverse ) swap ( f, l ); + //isReverse = ( edgeIt->Orientation() == TopAbs_REVERSED ); + //if ( isReverse ) swap ( f, l ); -- u2colMap takes orientation into account const int nbCol = 5; for ( int i = 0; i < nbCol; ++i ) { @@ -1784,7 +2496,7 @@ bool StdMeshers_PrismAsBlock::IsForwardEdge(SMESHDS_Mesh* meshDS, } else { - const TNodeColumn& firstCol = columnsMap.begin()->second; + const TNodeColumn& firstCol = columnsMap.begin()->second; const SMDS_MeshNode* bottomNode = firstCol[0]; TopoDS_Shape firstVertex = SMESH_MesherHelper::GetSubShapeByNode( bottomNode, meshDS ); isForward = ( firstVertex.IsSame( TopExp::FirstVertex( bottomEdge, true ))); @@ -1795,94 +2507,61 @@ bool StdMeshers_PrismAsBlock::IsForwardEdge(SMESHDS_Mesh* meshDS, return isForward; } -//================================================================================ -/*! - * \brief Find wall faces by bottom edges - * \param mesh - the mesh - * \param mainShape - the prism - * \param bottomFace - the bottom face - * \param bottomEdges - edges bounding the bottom face - * \param wallFaces - faces list to fill in - */ -//================================================================================ - -bool StdMeshers_PrismAsBlock::GetWallFaces( SMESH_Mesh* mesh, - const TopoDS_Shape & mainShape, - const TopoDS_Shape & bottomFace, - std::list< TopoDS_Edge >& bottomEdges, - std::list< int > & nbEInW, - std::list< TopoDS_Face >& wallFaces) -{ - wallFaces.clear(); - - TopTools_IndexedMapOfShape faceMap; - TopExp::MapShapes( mainShape, TopAbs_FACE, faceMap ); - - list< TopoDS_Edge >::iterator edge = bottomEdges.begin(); - std::list< int >::iterator nbE = nbEInW.begin(); - int iE = 0; - while ( edge != bottomEdges.end() ) - { - ++iE; - if ( BRep_Tool::Degenerated( *edge )) - { - edge = bottomEdges.erase( edge ); - --iE; - --(*nbE); - } - else - { - PShapeIteratorPtr fIt = myHelper->GetAncestors( *edge, *mesh, TopAbs_FACE ); - while ( fIt->more() ) - { - const TopoDS_Shape* face = fIt->next(); - if ( !bottomFace.IsSame( *face ) && // not bottom - faceMap.FindIndex( *face )) // belongs to the prism - { - wallFaces.push_back( TopoDS::Face( *face )); - break; - } - } - ++edge; - } - if ( iE == *nbE ) - { - iE = 0; - ++nbE; - } - } - return ( wallFaces.size() == bottomEdges.size() ); -} - //================================================================================ /*! * \brief Constructor * \param faceID - in-block ID - * \param face - geom face + * \param face - geom FACE + * \param baseEdge - EDGE proreply oriented in the bottom EDGE !!! * \param columnsMap - map of node columns * \param first - first normalized param * \param last - last normalized param */ //================================================================================ -StdMeshers_PrismAsBlock::TSideFace::TSideFace(SMESH_MesherHelper* helper, - const int faceID, - const TopoDS_Face& face, - const TopoDS_Edge& baseEdge, - TParam2ColumnMap* columnsMap, - const double first, - const double last): +StdMeshers_PrismAsBlock::TSideFace::TSideFace(SMESH_MesherHelper* helper, + const int faceID, + const Prism_3D::TQuadList& quadList, + const TopoDS_Edge& baseEdge, + TParam2ColumnMap* columnsMap, + const double first, + const double last): myID( faceID ), myParamToColumnMap( columnsMap ), - myBaseEdge( baseEdge ), myHelper( helper ) { - mySurface.Initialize( face ); myParams.resize( 1 ); myParams[ 0 ] = make_pair( first, last ); - myIsForward = StdMeshers_PrismAsBlock::IsForwardEdge( myHelper->GetMeshDS(), - *myParamToColumnMap, - myBaseEdge, myID ); + mySurface = PSurface( new BRepAdaptor_Surface( quadList.front()->face )); + myBaseEdge = baseEdge; + myIsForward = StdMeshers_PrismAsBlock::IsForwardEdge( myHelper->GetMeshDS(), + *myParamToColumnMap, + myBaseEdge, myID ); + if ( quadList.size() > 1 ) // side is vertically composite + { + // fill myShapeID2Surf map to enable finding a right surface by any sub-shape ID + + SMESHDS_Mesh* meshDS = myHelper->GetMeshDS(); + + TopTools_IndexedDataMapOfShapeListOfShape subToFaces; + Prism_3D::TQuadList::const_iterator quad = quadList.begin(); + for ( ; quad != quadList.end(); ++quad ) + { + const TopoDS_Face& face = (*quad)->face; + TopExp::MapShapesAndAncestors( face, TopAbs_VERTEX, TopAbs_FACE, subToFaces ); + TopExp::MapShapesAndAncestors( face, TopAbs_EDGE, TopAbs_FACE, subToFaces ); + myShapeID2Surf.insert( make_pair( meshDS->ShapeToIndex( face ), + PSurface( new BRepAdaptor_Surface( face )))); + } + for ( int i = 1; i <= subToFaces.Extent(); ++i ) + { + const TopoDS_Shape& sub = subToFaces.FindKey( i ); + TopTools_ListOfShape& faces = subToFaces( i ); + int subID = meshDS->ShapeToIndex( sub ); + int faceID = meshDS->ShapeToIndex( faces.First() ); + myShapeID2Surf.insert ( make_pair( subID, myShapeID2Surf[ faceID ])); + } + } } //================================================================================ @@ -2102,21 +2781,18 @@ gp_Pnt StdMeshers_PrismAsBlock::TSideFace::Value(const Standard_Real U, TParam2ColumnIt u_col1, u_col2; double vR, hR = GetColumns( U, u_col1, u_col2 ); - const SMDS_MeshNode* n1 = 0; - const SMDS_MeshNode* n2 = 0; - const SMDS_MeshNode* n3 = 0; - const SMDS_MeshNode* n4 = 0; + const SMDS_MeshNode* nn[4]; - // BEGIN issue 0020680: EDF 1252 SMESH: Bad cell created by Radial prism in center of torus + // BEGIN issue 0020680: Bad cell created by Radial prism in center of torus // Workaround for a wrongly located point returned by mySurface.Value() for // UV located near boundary of BSpline surface. - // To bypass the problem, we take point from 3D curve of edge. + // To bypass the problem, we take point from 3D curve of EDGE. // It solves pb of the bloc_fiss_new.py const double tol = 1e-3; if ( V < tol || V+tol >= 1. ) { - n1 = V < tol ? u_col1->second.front() : u_col1->second.back(); - n3 = V < tol ? u_col2->second.front() : u_col2->second.back(); + nn[0] = V < tol ? u_col1->second.front() : u_col1->second.back(); + nn[2] = V < tol ? u_col2->second.front() : u_col2->second.back(); TopoDS_Edge edge; if ( V < tol ) { @@ -2124,38 +2800,76 @@ gp_Pnt StdMeshers_PrismAsBlock::TSideFace::Value(const Standard_Real U, } else { - TopoDS_Shape s = myHelper->GetSubShapeByNode( n1, myHelper->GetMeshDS() ); + TopoDS_Shape s = myHelper->GetSubShapeByNode( nn[0], myHelper->GetMeshDS() ); if ( s.ShapeType() != TopAbs_EDGE ) - s = myHelper->GetSubShapeByNode( n3, myHelper->GetMeshDS() ); + s = myHelper->GetSubShapeByNode( nn[2], myHelper->GetMeshDS() ); if ( s.ShapeType() == TopAbs_EDGE ) edge = TopoDS::Edge( s ); } if ( !edge.IsNull() ) { - double u1 = myHelper->GetNodeU( edge, n1 ); - double u3 = myHelper->GetNodeU( edge, n3 ); + double u1 = myHelper->GetNodeU( edge, nn[0] ); + double u3 = myHelper->GetNodeU( edge, nn[2] ); double u = u1 * ( 1 - hR ) + u3 * hR; TopLoc_Location loc; double f,l; Handle(Geom_Curve) curve = BRep_Tool::Curve( edge,loc,f,l ); return curve->Value( u ).Transformed( loc ); } } - // END issue 0020680: EDF 1252 SMESH: Bad cell created by Radial prism in center of torus + // END issue 0020680: Bad cell created by Radial prism in center of torus + + vR = getRAndNodes( & u_col1->second, V, nn[0], nn[1] ); + vR = getRAndNodes( & u_col2->second, V, nn[2], nn[3] ); - vR = getRAndNodes( & u_col1->second, V, n1, n2 ); - vR = getRAndNodes( & u_col2->second, V, n3, n4 ); + if ( !myShapeID2Surf.empty() ) // side is vertically composite + { + // find a FACE on which the 4 nodes lie + TSideFace* me = (TSideFace*) this; + int notFaceID1 = 0, notFaceID2 = 0; + for ( int i = 0; i < 4; ++i ) + if ( nn[i]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE ) // node on FACE + { + me->mySurface = me->myShapeID2Surf[ nn[i]->getshapeId() ]; + notFaceID2 = 0; + break; + } + else if ( notFaceID1 == 0 ) // node on EDGE or VERTEX + { + me->mySurface = me->myShapeID2Surf[ nn[i]->getshapeId() ]; + notFaceID1 = nn[i]->getshapeId(); + } + else if ( notFaceID1 != nn[i]->getshapeId() ) // node on other EDGE or VERTEX + { + if ( mySurface != me->myShapeID2Surf[ nn[i]->getshapeId() ]) + notFaceID2 = nn[i]->getshapeId(); + } + if ( notFaceID2 ) // no nodes of FACE and nodes are on different FACEs + { + SMESHDS_Mesh* meshDS = myHelper->GetMeshDS(); + TopoDS_Shape face = myHelper->GetCommonAncestor( meshDS->IndexToShape( notFaceID1 ), + meshDS->IndexToShape( notFaceID2 ), + *myHelper->GetMesh(), + TopAbs_FACE ); + if ( face.IsNull() ) + throw SALOME_Exception("StdMeshers_PrismAsBlock::TSideFace::Value() face.IsNull()"); + int faceID = meshDS->ShapeToIndex( face ); + me->mySurface = me->myShapeID2Surf[ faceID ]; + if ( !mySurface ) + throw SALOME_Exception("StdMeshers_PrismAsBlock::TSideFace::Value() !mySurface"); + } + } - gp_XY uv1 = myHelper->GetNodeUV( mySurface.Face(), n1, n4); - gp_XY uv2 = myHelper->GetNodeUV( mySurface.Face(), n2, n3); + gp_XY uv1 = myHelper->GetNodeUV( mySurface->Face(), nn[0], nn[2]); + gp_XY uv2 = myHelper->GetNodeUV( mySurface->Face(), nn[1], nn[3]); gp_XY uv12 = uv1 * ( 1 - vR ) + uv2 * vR; - gp_XY uv3 = myHelper->GetNodeUV( mySurface.Face(), n3, n2); - gp_XY uv4 = myHelper->GetNodeUV( mySurface.Face(), n4, n1); + gp_XY uv3 = myHelper->GetNodeUV( mySurface->Face(), nn[2], nn[0]); + gp_XY uv4 = myHelper->GetNodeUV( mySurface->Face(), nn[3], nn[1]); gp_XY uv34 = uv3 * ( 1 - vR ) + uv4 * vR; gp_XY uv = uv12 * ( 1 - hR ) + uv34 * hR; - gp_Pnt p = mySurface.Value( uv.X(), uv.Y() ); + gp_Pnt p = mySurface->Value( uv.X(), uv.Y() ); return p; } diff --git a/src/StdMeshers/StdMeshers_Prism_3D.hxx b/src/StdMeshers/StdMeshers_Prism_3D.hxx index 42d56fe16..5a3ea2145 100644 --- a/src/StdMeshers/StdMeshers_Prism_3D.hxx +++ b/src/StdMeshers/StdMeshers_Prism_3D.hxx @@ -37,56 +37,80 @@ #include "SMESH_Comment.hxx" #include "SMESH_Mesh.hxx" #include "SMESH_MesherHelper.hxx" +#include "SMESH_TypeDefs.hxx" #include "SMESH_subMesh.hxx" -#include - #include #include #include #include #include +#include #include #include +#include +namespace Prism_3D +{ + struct TNode; + struct TPrismTopo; +} class SMESHDS_SubMesh; class TopoDS_Edge; -class TopoDS_Faces; -struct TNode; - -typedef std::vector TNodeColumn; +typedef TopTools_IndexedMapOfOrientedShape TBlockShapes; +typedef std::vector TNodeColumn; +typedef std::map< double, TNodeColumn > TParam2ColumnMap; +typedef std::map< double, TNodeColumn >::const_iterator TParam2ColumnIt; // map of bottom nodes to the column of nodes above them // (the column includes the bottom nodes) -typedef std::map< TNode, TNodeColumn > TNode2ColumnMap; -typedef std::map< double, TNodeColumn > TParam2ColumnMap; -typedef std::map< double, TNodeColumn >::const_iterator TParam2ColumnIt; +typedef std::map< Prism_3D::TNode, TNodeColumn > TNode2ColumnMap; -typedef TopTools_IndexedMapOfOrientedShape TBlockShapes; -// =============================================== -/*! - * \brief Structure containing node relative data - */ -// =============================================== - -struct TNode +namespace Prism_3D { - const SMDS_MeshNode* myNode; - mutable gp_XYZ myParams; + // =============================================== + /*! + * \brief Structure containing node relative data + */ + struct TNode + { + const SMDS_MeshNode* myNode; + mutable gp_XYZ myParams; + + gp_XYZ GetCoords() const { return gp_XYZ( myNode->X(), myNode->Y(), myNode->Z() ); } + gp_XYZ GetParams() const { return myParams; } + gp_XYZ& ChangeParams() const { return myParams; } + bool HasParams() const { return myParams.X() >= 0.0; } + SMDS_TypeOfPosition GetPositionType() const + { return myNode ? myNode->GetPosition()->GetTypeOfPosition() : SMDS_TOP_UNSPEC; } + bool IsNeighbor( const TNode& other ) const; + + TNode(const SMDS_MeshNode* node = 0): myNode(node), myParams(-1,-1,-1) {} + bool operator < (const TNode& other) const { return myNode->GetID() < other.myNode->GetID(); } + }; + // =============================================== + /*! + * \brief Topological data of the prism + */ + typedef std::list< TFaceQuadStructPtr > TQuadList; + + struct TPrismTopo + { + TopoDS_Shape myShape3D; + TopoDS_Face myBottom; + TopoDS_Face myTop; + std::list< TopoDS_Edge > myBottomEdges; + std::vector< TQuadList> myWallQuads; // wall sides can be vertically composite + std::vector< int > myRightQuadIndex; // index of right neighbour wall quad + std::list< int > myNbEdgesInWires; - gp_XYZ GetCoords() const { return gp_XYZ( myNode->X(), myNode->Y(), myNode->Z() ); } - gp_XYZ GetParams() const { return myParams; } - gp_XYZ& ChangeParams() const { return myParams; } - bool HasParams() const { return myParams.X() >= 0.0; } - SMDS_TypeOfPosition GetPositionType() const - { return myNode ? myNode->GetPosition()->GetTypeOfPosition() : SMDS_TOP_UNSPEC; } - bool IsNeighbor( const TNode& other ) const; + bool myNotQuadOnTop; - TNode(const SMDS_MeshNode* node = 0): myNode(node), myParams(-1,-1,-1) {} - bool operator < (const TNode& other) const { return myNode->GetID() < other.myNode->GetID(); } -}; + void Clear(); + }; +} // =============================================================== /*! @@ -95,11 +119,9 @@ struct TNode * emulated by division/uniting of missing/excess faces. * It also manage associations between block sub-shapes and a mesh. */ -// =============================================================== - class STDMESHERS_EXPORT StdMeshers_PrismAsBlock: public SMESH_Block { -public: + public: /*! * \brief Constructor. Initialization is needed */ @@ -109,14 +131,11 @@ public: /*! * \brief Initialization. - * \param helper - helper loaded with mesh and 3D shape - * \param shape3D - a closed shell or solid - * \retval bool - false if a mesh or a shape are KO - * - * Analyse shape geometry and mesh. - * If there are triangles on one of faces, it becomes 'bottom' + * \param helper - helper loaded with mesh and 3D shape + * \param prism - prism topology + * \retval bool - false if a mesh or a shape are KO */ - bool Init(SMESH_MesherHelper* helper, const TopoDS_Shape& shape3D); + bool Init(SMESH_MesherHelper* helper, const Prism_3D::TPrismTopo& prism); /*! * \brief Return problem description @@ -166,7 +185,8 @@ public: * by nodes of the bottom. Layer is a set of nodes at a certain step * from bottom to top. */ - bool GetLayersTransformation(std::vector & trsf) const; + bool GetLayersTransformation(std::vector & trsf, + const Prism_3D::TPrismTopo& prism) const; /*! * \brief Return pointer to mesh @@ -224,20 +244,6 @@ public: const TParam2ColumnMap& columnsMap, const TopoDS_Edge & bottomEdge, const int sideFaceID); - /*! - * \brief Find wall faces by bottom edges - * \param mesh - the mesh - * \param mainShape - the prism - * \param bottomFace - the bottom face - * \param bottomEdges - edges bounding the bottom face - * \param wallFaces - faces list to fill in - */ - bool GetWallFaces( SMESH_Mesh* mesh, - const TopoDS_Shape & mainShape, - const TopoDS_Shape & bottomFace, - std::list< TopoDS_Edge >& bottomEdges, - std::list< int > & nbEInW, - std::list< TopoDS_Face >& wallFaces); private: @@ -252,25 +258,28 @@ private: // -------------------------------------------------------------------- class TSideFace: public Adaptor3d_Surface { + typedef boost::shared_ptr PSurface; + int myID; //!< in-block ID // map used to find out real UV by it's normalized UV TParam2ColumnMap* myParamToColumnMap; - BRepAdaptor_Surface mySurface; + PSurface mySurface; TopoDS_Edge myBaseEdge; + map< int, PSurface > myShapeID2Surf; // first and last normalized params and orientaion for each component or it-self std::vector< std::pair< double, double> > myParams; bool myIsForward; std::vector< TSideFace* > myComponents; SMESH_MesherHelper * myHelper; public: - TSideFace( SMESH_MesherHelper* helper, - const int faceID, - const TopoDS_Face& face, - const TopoDS_Edge& baseEdge, - TParam2ColumnMap* columnsMap, - const double first = 0.0, - const double last = 1.0); - TSideFace( const std::vector< TSideFace* >& components, + TSideFace( SMESH_MesherHelper* helper, + const int faceID, + const Prism_3D::TQuadList& quadList, + const TopoDS_Edge& baseEdge, + TParam2ColumnMap* columnsMap, + const double first = 0.0, + const double last = 1.0); + TSideFace( const std::vector< TSideFace* >& components, const std::vector< std::pair< double, double> > & params); TSideFace( const TSideFace& other ); ~TSideFace(); @@ -380,14 +389,12 @@ private: myError = SMESH_ComputeError::New(error,comment); return myError->IsOK(); } -}; +}; // class StdMeshers_PrismAsBlock // ============================================= /*! * \brief Algo building prisms on a prism shape */ -// ============================================= - class STDMESHERS_EXPORT StdMeshers_Prism_3D: public SMESH_3D_Algo { public: @@ -423,6 +430,28 @@ public: private: + /*! + * \brief Analyse shape geometry and mesh. + * If there are triangles on one of faces, it becomes 'bottom' + */ + bool initPrism(Prism_3D::TPrismTopo& thePrism, const TopoDS_Shape& theSolid); + + /*! + * \brief Fill thePrism.myWallQuads and thePrism.myTopEdges + */ + bool getWallFaces( Prism_3D::TPrismTopo& thePrism, + const int totalNbFaces); + + /*! + * \brief Compute mesh on a SOLID + */ + bool compute(const Prism_3D::TPrismTopo& thePrism); + + /*! + * \brief Compute 2D mesh on walls FACEs of a prism + */ + bool computeWalls(const Prism_3D::TPrismTopo& thePrism); + /*! * \brief Find correspondence between bottom and top nodes. * If elements on the bottom and top faces are topologically different, @@ -433,11 +462,18 @@ private: /*! * \brief Remove quadrangles from the top face and - * create triangles there by projection from the bottom + * create triangles there by projection from the bottom * \retval bool - a success or not */ bool projectBottomToTop(); + /*! + * \brief Project mesh faces from a source FACE of one prism to + * a source FACE of another prism + * \retval bool - a success or not + */ + bool project2dMesh(const TopoDS_Face& source, const TopoDS_Face& target); + /*! * \brief Set projection coordinates of a node to a face and it's sub-shapes * \param faceID - the face given by in-block ID @@ -446,9 +482,20 @@ private: */ bool setFaceAndEdgesXYZ( const int faceID, const gp_XYZ& params, int z ); + /*! + * \brief If (!isOK), sets the error to a sub-mesh of a current SOLID + */ + bool toSM( bool isOK ); + + /*! + * \brief Return index of a shape + */ + int shapeID( const TopoDS_Shape& S ); + private: bool myProjectTriangles; + bool mySetErrorToSM; StdMeshers_PrismAsBlock myBlock; SMESH_MesherHelper* myHelper; @@ -458,6 +505,7 @@ private: // map of bottom nodes to the column of nodes above them // (the column includes the bottom node) TNode2ColumnMap myBotToColumnMap; -}; + +}; // class StdMeshers_Prism_3D #endif diff --git a/src/StdMeshers/StdMeshers_ProjectionSource2D.cxx b/src/StdMeshers/StdMeshers_ProjectionSource2D.cxx index 479bdd6ec..38017bf69 100644 --- a/src/StdMeshers/StdMeshers_ProjectionSource2D.cxx +++ b/src/StdMeshers/StdMeshers_ProjectionSource2D.cxx @@ -28,6 +28,7 @@ #include "StdMeshers_ProjectionSource2D.hxx" #include "SMESH_Mesh.hxx" +#include "SMESH_MesherHelper.hxx" #include "StdMeshers_ProjectionUtils.hxx" #include "utilities.h" @@ -111,7 +112,7 @@ void StdMeshers_ProjectionSource2D::SetVertexAssociation(const TopoDS_Shape& sou { // possibly there is only 1 vertex in the face if ( !_sourceFace.IsNull() && - StdMeshers_ProjectionUtils::Count( _sourceFace, TopAbs_VERTEX, /*ignoreSame=*/true) != 1 ) + SMESH_MesherHelper::Count( _sourceFace, TopAbs_VERTEX, /*ignoreSame=*/true) != 1 ) throw SALOME_Exception(LOCALIZED("Two or none pairs of vertices must be provided")); } diff --git a/src/StdMeshers/StdMeshers_ProjectionUtils.cxx b/src/StdMeshers/StdMeshers_ProjectionUtils.cxx index 76785fad0..805915b56 100644 --- a/src/StdMeshers/StdMeshers_ProjectionUtils.cxx +++ b/src/StdMeshers/StdMeshers_ProjectionUtils.cxx @@ -215,13 +215,12 @@ namespace { list subMeshes = tgtMesh1->GetGroupSubMeshesContaining(tgtShape); list::iterator sm = subMeshes.begin(); int type, last = TopAbs_SHAPE; - StdMeshers_ProjectionUtils util; for ( ; sm != subMeshes.end(); ++sm ) { const TopoDS_Shape & group = (*sm)->GetSubShape(); // check if group is similar to srcGroup for ( type = srcGroup.ShapeType(); type < last; ++type) - if ( util.Count( srcGroup, (TopAbs_ShapeEnum)type, 0) != - util.Count( group, (TopAbs_ShapeEnum)type, 0)) + if ( SMESH_MesherHelper::Count( srcGroup, (TopAbs_ShapeEnum)type, 0) != + SMESH_MesherHelper::Count( group, (TopAbs_ShapeEnum)type, 0)) break; if ( type == last ) return group; @@ -285,7 +284,7 @@ namespace { // get edges of the face TopoDS_Edge edgeGr1, edgeGr2, verticEdge2; list< TopoDS_Edge > edges; list< int > nbEdgesInWire; - SMESH_Block::GetOrderedEdges( face, v1, edges, nbEdgesInWire); + SMESH_Block::GetOrderedEdges( face, edges, nbEdgesInWire, v1); if ( nbEdgesInWire.front() != 4 ) return _StoreBadShape( face ); list< TopoDS_Edge >::iterator edge = edges.begin(); @@ -713,7 +712,7 @@ bool StdMeshers_ProjectionUtils::FindSubShapeAssociation(const TopoDS_Shape& the // Maybe groups contain only one member TopoDS_Iterator it1( theShape1 ), it2( theShape2 ); TopAbs_ShapeEnum memberType = it1.Value().ShapeType(); - int nbMembers = Count( theShape1, memberType, true ); + int nbMembers = SMESH_MesherHelper::Count( theShape1, memberType, true ); if ( nbMembers == 0 ) return true; if ( nbMembers == 1 ) { return FindSubShapeAssociation( it1.Value(), theMesh1, it2.Value(), theMesh2, theMap ); @@ -762,7 +761,8 @@ bool StdMeshers_ProjectionUtils::FindSubShapeAssociation(const TopoDS_Shape& the if ( groupEdges[ is2ndGroup ].Contains( f.Current() )) if ( ++nbGroupEdges > 1 ) break; - bool add = (nbGroupEdges > 1 || Count( face, TopAbs_EDGE, true ) == 1 ); + bool add = (nbGroupEdges > 1 || + SMESH_MesherHelper::Count( face, TopAbs_EDGE, true ) == 1 ); if ( !add ) { add = true; for ( TopExp_Explorer v( face, TopAbs_VERTEX ); add && v.More(); v.Next()) @@ -779,8 +779,8 @@ bool StdMeshers_ProjectionUtils::FindSubShapeAssociation(const TopoDS_Shape& the } // Associate shells // - int nbFaces1 = Count( shell1, TopAbs_FACE, 0 ); - int nbFaces2 = Count( shell2, TopAbs_FACE, 0 ); + int nbFaces1 = SMESH_MesherHelper:: Count( shell1, TopAbs_FACE, 0 ); + int nbFaces2 = SMESH_MesherHelper:: Count( shell2, TopAbs_FACE, 0 ); if ( nbFaces1 != nbFaces2 ) RETURN_BAD_RESULT("Different nb of faces found for shells"); if ( nbFaces1 > 0 ) { @@ -997,16 +997,22 @@ bool StdMeshers_ProjectionUtils::FindSubShapeAssociation(const TopoDS_Shape& the if ( face2.Orientation() >= TopAbs_INTERNAL ) face2.Orientation( TopAbs_FORWARD ); TopoDS_Edge edge1, edge2; // get outer edge of theShape1 - edge1 = TopoDS::Edge( OuterShape( face1, TopAbs_EDGE )); - // find out if any edge of face2 is a propagation edge of outer edge1 + TopoDS_Shape wire = OuterShape( face1, TopAbs_WIRE ); + //edge1 = TopoDS::Edge( OuterShape( face1, TopAbs_EDGE )); map propag_edges; // use map to find the closest propagation edge - for ( TopExp_Explorer exp( face2, TopAbs_EDGE ); exp.More(); exp.Next() ) { - edge2 = TopoDS::Edge( exp.Current() ); - pair step_edge = GetPropagationEdge( theMesh1, edge2, edge1 ); - if ( !step_edge.second.IsNull() ) { // propagation found - propag_edges.insert( step_edge ); - if ( step_edge.first == 1 ) break; // most close found + for ( TopoDS_Iterator edgeIt( wire ); edgeIt.More(); edgeIt.Next() ) + { + edge1 = TopoDS::Edge( edgeIt.Value() ); + // find out if any edge of face2 is a propagation edge of outer edge1 + for ( TopExp_Explorer exp( face2, TopAbs_EDGE ); exp.More(); exp.Next() ) { + edge2 = TopoDS::Edge( exp.Current() ); + pair step_edge = GetPropagationEdge( theMesh1, edge2, edge1 ); + if ( !step_edge.second.IsNull() ) { // propagation found + propag_edges.insert( step_edge ); + if ( step_edge.first == 1 ) break; // most close found + } } + if ( !propag_edges.empty() && propag_edges.begin()->first == 1 ) break; } if ( !propag_edges.empty() ) // propagation found { @@ -1118,7 +1124,11 @@ bool StdMeshers_ProjectionUtils::FindSubShapeAssociation(const TopoDS_Shape& the TopoDS_Vertex VV1[2], VV2[2]; if ( vMap1.Extent() != vMap2.Extent() ) - RETURN_BAD_RESULT("Different nb of vertices"); + { + if ( SMESH_MesherHelper:: Count( theShape1, TopAbs_EDGE, /*ignoreSame=*/false ) != + SMESH_MesherHelper:: Count( theShape2, TopAbs_EDGE, /*ignoreSame=*/false )) + RETURN_BAD_RESULT("Different nb of vertices"); + } if ( vMap1.Extent() == 1 ) { InsertAssociation( vMap1(1), vMap2(1), theMap ); @@ -1158,10 +1168,10 @@ bool StdMeshers_ProjectionUtils::FindSubShapeAssociation(const TopoDS_Shape& the // Find transformation to make the shapes be of similar size at same location Bnd_Box box[2]; - for ( int i = 1; i <= vMap1.Extent(); ++i ) { + for ( int i = 1; i <= vMap1.Extent(); ++i ) box[ 0 ].Add( BRep_Tool::Pnt ( TopoDS::Vertex( vMap1( i )))); + for ( int i = 1; i <= vMap2.Extent(); ++i ) box[ 1 ].Add( BRep_Tool::Pnt ( TopoDS::Vertex( vMap2( i )))); - } gp_Pnt gc[2]; // box center double x0,y0,z0, x1,y1,z1; @@ -1281,8 +1291,8 @@ int StdMeshers_ProjectionUtils::FindFaceAssociation(const TopoDS_Face& face1, edges1.clear(); edges2.clear(); - if ( SMESH_Block::GetOrderedEdges( face1, VV1[0], edges1, nbEInW1, outer_wire_algo) != - SMESH_Block::GetOrderedEdges( face2, VV2[0], edges2, nbEInW2, outer_wire_algo) ) + if ( SMESH_Block::GetOrderedEdges( face1, edges1, nbEInW1, VV1[0], outer_wire_algo) != + SMESH_Block::GetOrderedEdges( face2, edges2, nbEInW2, VV2[0], outer_wire_algo) ) CONT_BAD_RESULT("Different number of wires in faces "); if ( nbEInW1 != nbEInW2 && outer_wire_algo == 0 && @@ -1364,8 +1374,8 @@ int StdMeshers_ProjectionUtils::FindFaceAssociation(const TopoDS_Face& face1, { edges1.clear(); edges2.clear(); - SMESH_Block::GetOrderedEdges( face1, VV1[0], edges1, nbEInW1, i_ok_wire_algo); - SMESH_Block::GetOrderedEdges( face2, VV2[0], edges2, nbEInW2, i_ok_wire_algo); + SMESH_Block::GetOrderedEdges( face1, edges1, nbEInW1, VV1[0], i_ok_wire_algo); + SMESH_Block::GetOrderedEdges( face2, edges2, nbEInW2, VV2[0], i_ok_wire_algo); } gp_XY dUV = v0f2UV.XY() - v0f1UV.XY(); // UV shift between 2 faces // @@ -2099,33 +2109,7 @@ bool StdMeshers_ProjectionUtils::MakeComputed(SMESH_subMesh * sm, const int iter //================================================================================ /*! - * \brief Count nb of sub-shapes - * \param shape - the shape - * \param type - the type of sub-shapes to count - * \retval int - the calculated number - */ -//================================================================================ - -int StdMeshers_ProjectionUtils::Count(const TopoDS_Shape& shape, - const TopAbs_ShapeEnum type, - const bool ignoreSame) -{ - if ( ignoreSame ) { - TopTools_IndexedMapOfShape map; - TopExp::MapShapes( shape, type, map ); - return map.Extent(); - } - else { - int nb = 0; - for ( TopExp_Explorer exp( shape, type ); exp.More(); exp.Next() ) - ++nb; - return nb; - } -} - -//================================================================================ -/*! - * \brief Return a boundary EDGE of edgeContainer + * \brief Return a boundary EDGE (or all boundary EDGEs) of edgeContainer */ //================================================================================ @@ -2223,7 +2207,7 @@ void StdMeshers_ProjectionUtils::SetEventListener(SMESH_subMesh* subMesh, TopoDS_Shape srcShape, SMESH_Mesh* srcMesh) { - // Set listener that resets an event listener on source submesh when + // Set the listener that resets an event listener on source submesh when // "ProjectionSource*D" hypothesis is modified since source shape can be changed subMesh->SetEventListener( GetHypModifWaiter(),0,subMesh); diff --git a/src/StdMeshers/StdMeshers_ProjectionUtils.hxx b/src/StdMeshers/StdMeshers_ProjectionUtils.hxx index 1d22b54b7..97d55ba22 100644 --- a/src/StdMeshers/StdMeshers_ProjectionUtils.hxx +++ b/src/StdMeshers/StdMeshers_ProjectionUtils.hxx @@ -53,13 +53,13 @@ struct StdMeshers_ShapeShapeBiDirectionMap { TopTools_DataMapOfShapeShape _map1to2, _map2to1; - // convension: s1 - target, s2 - source + // convention: s1 - target, s2 - source bool Bind( const TopoDS_Shape& s1, const TopoDS_Shape& s2 ) { _map1to2.Bind( s1, s2 ); return _map2to1.Bind( s2, s1 ); } bool IsBound( const TopoDS_Shape& s, const bool isShape2=false ) const { return (isShape2 ? _map2to1 : _map1to2).IsBound( s ); } bool IsEmpty() const { return _map1to2.IsEmpty(); } - int Extent() const { return _map1to2.Extent(); } + int Extent() const { return _map1to2.Extent(); } void Clear() { _map1to2.Clear(); _map2to1.Clear(); } const TopoDS_Shape& operator()( const TopoDS_Shape& s, const bool isShape2=false ) const { // if we get a Standard_NoSuchObject here, it means that the calling code @@ -196,17 +196,6 @@ class StdMeshers_ProjectionUtils */ static bool MakeComputed(SMESH_subMesh * sm, const int iterationNb = 0); - /*! - * \brief Count nb of sub-shapes - * \param shape - the shape - * \param type - the type of sub-shapes to count - * \param ignoreSame - if true, use map not to count same shapes, esle use explorer - * \retval int - the calculated number - */ - static int Count(const TopoDS_Shape& shape, - const TopAbs_ShapeEnum type, - const bool ignoreSame); - /*! * \brief Set event listeners to submesh with projection algo * \param subMesh - submesh with projection algo @@ -218,7 +207,7 @@ class StdMeshers_ProjectionUtils SMESH_Mesh* srcMesh); /*! - * \brief Return a boundary EDGE of edgeContainer + * \brief Return a boundary EDGE (or all boundary EDGEs) of edgeContainer */ static TopoDS_Edge GetBoundaryEdge(const TopoDS_Shape& edgeContainer, const SMESH_Mesh& mesh, diff --git a/src/StdMeshers/StdMeshers_Projection_1D2D.cxx b/src/StdMeshers/StdMeshers_Projection_1D2D.cxx index 7e5cfe821..f9fe63dc3 100644 --- a/src/StdMeshers/StdMeshers_Projection_1D2D.cxx +++ b/src/StdMeshers/StdMeshers_Projection_1D2D.cxx @@ -70,7 +70,7 @@ namespace * \brief Structure used to temporary remove EventProparatorToEdges from faceSubMesh * in order to prevent propagation of CLEAN event from FACE to EDGEs during * StdMeshers_Projection_1D2D::Compute(). The CLEAN event is emmited by Pattern mapper - * and causes removal of faces generated on adjacent FACEs. + * and causes removal of faces generated on adjacent FACEs. */ struct UnsetterOfEventProparatorToEdges { @@ -108,9 +108,13 @@ bool StdMeshers_Projection_1D2D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape { UnsetterOfEventProparatorToEdges eventBarrier( theMesh.GetSubMesh( theShape )); + // 1) Project faces + if ( !StdMeshers_Projection_2D::Compute(theMesh, theShape)) return false; + // 2) Create segments + SMESHDS_Mesh * meshDS = theMesh.GetMeshDS(); SMESHDS_SubMesh * faceSubMesh = meshDS->MeshElements( theShape ); @@ -173,7 +177,7 @@ bool StdMeshers_Projection_1D2D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape meshDS->SetMeshElementOnShape( e, edgeID ); } } - } + } return true; } diff --git a/src/StdMeshers/StdMeshers_Projection_2D.cxx b/src/StdMeshers/StdMeshers_Projection_2D.cxx index ad6f45e57..7467a19f9 100644 --- a/src/StdMeshers/StdMeshers_Projection_2D.cxx +++ b/src/StdMeshers/StdMeshers_Projection_2D.cxx @@ -51,6 +51,7 @@ #include #include #include +#include #include #include #include @@ -248,7 +249,7 @@ namespace { /*! * \brief find new nodes belonging to one free border of mesh on face * \param sm - submesh on edge or vertex containg nodes to choose from - * \param face - the face bound the submesh + * \param face - the face bound by the submesh * \param u2nodes - map to fill with nodes * \param seamNodes - set of found nodes * \retval bool - is a success @@ -290,43 +291,45 @@ namespace { if ( !smV1->IsMeshComputed() || !smV2->IsMeshComputed() ) RETURN_BAD_RESULT("Empty vertex submeshes"); - // Look for a new node on V1 - nIt = smV1->GetSubMeshDS()->GetNodes(); const SMDS_MeshNode* nV1 = 0; - while ( nIt->more() && !nV1 ) { - const SMDS_MeshNode* node = nIt->next(); - if ( !isOldNode( node ) ) nV1 = node; - } - if ( !nV1 ) - RETURN_BAD_RESULT("No new node found on V1"); - - // Find a new node connected to nV1 and belonging to edge submesh; const SMDS_MeshNode* nE = 0; - SMESHDS_SubMesh* smDS = sm->GetSubMeshDS(); - SMDS_ElemIteratorPtr vElems = nV1->GetInverseElementIterator(SMDSAbs_Face); - while ( vElems->more() && !nE ) { - const SMDS_MeshElement* elem = vElems->next(); - int nbNodes = elem->NbNodes(); - if ( elem->IsQuadratic() ) - nbNodes /= 2; - int iV1 = elem->GetNodeIndex( nV1 ); - // try next after nV1 - int iE = SMESH_MesherHelper::WrapIndex( iV1 + 1, nbNodes ); - if ( smDS->Contains( elem->GetNode( iE ) )) - nE = elem->GetNode( iE ); - if ( !nE ) { - // try node before nV1 - iE = SMESH_MesherHelper::WrapIndex( iV1 - 1, nbNodes ); - if ( smDS->Contains( elem->GetNode( iE ))) + + // Look for nV1 - a new node on V1 + nIt = smV1->GetSubMeshDS()->GetNodes(); + while ( nIt->more() && !nE ) { + const SMDS_MeshNode* node = nIt->next(); + if ( isOldNode( node ) ) continue; + nV1 = node; + + // Find nE - a new node connected to nV1 and belonging to edge submesh; + SMESHDS_SubMesh* smDS = sm->GetSubMeshDS(); + SMDS_ElemIteratorPtr vElems = nV1->GetInverseElementIterator(SMDSAbs_Face); + while ( vElems->more() && !nE ) { + const SMDS_MeshElement* elem = vElems->next(); + int nbNodes = elem->NbNodes(); + if ( elem->IsQuadratic() ) + nbNodes /= 2; + int iV1 = elem->GetNodeIndex( nV1 ); + // try next after nV1 + int iE = SMESH_MesherHelper::WrapIndex( iV1 + 1, nbNodes ); + if ( smDS->Contains( elem->GetNode( iE ) )) nE = elem->GetNode( iE ); - } - if ( nE && elem->IsQuadratic() ) { // find medium node between nV1 and nE - if ( Abs( iV1 - iE ) == 1 ) - nE = elem->GetNode( Min ( iV1, iE ) + nbNodes ); - else - nE = elem->GetNode( elem->NbNodes() - 1 ); + if ( !nE ) { + // try node before nV1 + iE = SMESH_MesherHelper::WrapIndex( iV1 - 1, nbNodes ); + if ( smDS->Contains( elem->GetNode( iE ))) + nE = elem->GetNode( iE ); + } + if ( nE && elem->IsQuadratic() ) { // find medium node between nV1 and nE + if ( Abs( iV1 - iE ) == 1 ) + nE = elem->GetNode( Min ( iV1, iE ) + nbNodes ); + else + nE = elem->GetNode( elem->NbNodes() - 1 ); + } } } + if ( !nV1 ) + RETURN_BAD_RESULT("No new node found on V1"); if ( !nE ) RETURN_BAD_RESULT("new node on edge not found"); @@ -393,7 +396,9 @@ namespace { // make any local coord systems of src and tgt faces vector srcPP, tgtPP; // 3 points on face boundaries to make axes of CS - SMESH_subMesh * srcSM = srcMesh->GetSubMesh( srcFace ); + int tgtNbVert = SMESH_MesherHelper::Count( tgtFace, TopAbs_VERTEX, /*ignoreSame=*/true ); + int srcNbVert = SMESH_MesherHelper::Count( srcFace, TopAbs_VERTEX, /*ignoreSame=*/true ); + SMESH_subMesh * srcSM = srcMesh->GetSubMesh( srcFace ); SMESH_subMeshIteratorPtr smIt = srcSM->getDependsOnIterator(/*includeSelf=*/false,false); srcSM = smIt->next(); // sm of a vertex while ( smIt->more() && srcPP.size() < 3 ) @@ -430,7 +435,11 @@ namespace { if ( tgtShape.ShapeType() == TopAbs_VERTEX ) { tgtP = BRep_Tool::Pnt( TopoDS::Vertex( tgtShape )); - pOK = true; + if ( srcNbVert == tgtNbVert || tgtPP.empty() ) + pOK = true; + else + pOK = (( tgtP.Distance( tgtPP[0] ) > tol*tol ) && + ( tgtPP.size() == 1 || tgtP.Distance( tgtPP[1] ) > tol*tol )); //cout << "V - nS " << p._node->GetID() << " - nT " << SMESH_Algo::VertexNode(TopoDS::Vertex( tgtShape),tgtMesh->GetMeshDS())->GetID() << endl; } else if ( tgtPP.size() > 0 ) @@ -786,7 +795,7 @@ bool StdMeshers_Projection_2D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& // Make sub-shapes association // --------------------------- - TopoDS_Face tgtFace = TopoDS::Face( theShape.Oriented(TopAbs_FORWARD)); + TopoDS_Face tgtFace = TopoDS::Face( theShape.Oriented(TopAbs_FORWARD)); TopoDS_Shape srcShape = _sourceHypo->GetSourceFace().Oriented(TopAbs_FORWARD); TAssocTool::TShapeShapeMap shape2ShapeMap; @@ -797,8 +806,8 @@ bool StdMeshers_Projection_2D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& { if ( srcShape.ShapeType() == TopAbs_FACE ) { - int nbE1 = TAssocTool::Count( tgtFace, TopAbs_EDGE, /*ignoreSame=*/true ); - int nbE2 = TAssocTool::Count( srcShape, TopAbs_EDGE, /*ignoreSame=*/true ); + int nbE1 = SMESH_MesherHelper::Count( tgtFace, TopAbs_EDGE, /*ignoreSame=*/true ); + int nbE2 = SMESH_MesherHelper::Count( srcShape, TopAbs_EDGE, /*ignoreSame=*/true ); if ( nbE1 != nbE2 ) return error(COMPERR_BAD_SHAPE, SMESH_Comment("Different number of edges in source and target faces: ") @@ -879,38 +888,47 @@ bool StdMeshers_Projection_2D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& const bool toProjectNodes = ( nbFaceNodes > 0 && ( uvBox.IsVoid() || uvBox.SquareExtent() < DBL_MIN )); - // Load pattern from the source face - SMESH_Pattern mapper; - mapper.Load( srcMesh, srcFace, toProjectNodes ); - if ( mapper.GetErrorCode() != SMESH_Pattern::ERR_OK ) - return error(COMPERR_BAD_INPUT_MESH,"Can't load mesh pattern from the source face"); - - // Find the first target vertex corresponding to first vertex of the + // Find the corresponding source and target vertex // and flag needed to call mapper.Apply() - TopoDS_Vertex srcV1 = TopoDS::Vertex( mapper.GetSubShape( 1 )); - if ( srcV1.IsNull() ) - RETURN_BAD_RESULT("Mesh is not bound to the face"); - if ( !shape2ShapeMap.IsBound( srcV1, /*isSrc=*/true )) - RETURN_BAD_RESULT("Not associated vertices, srcV1 " << srcV1.TShape().operator->() ); - TopoDS_Vertex tgtV1 = TopoDS::Vertex( shape2ShapeMap( srcV1, /*isSrc=*/true )); - - if ( !SMESH_MesherHelper::IsSubShape( srcV1, srcFace )) - RETURN_BAD_RESULT("Wrong srcV1 " << srcV1.TShape().operator->()); - if ( !SMESH_MesherHelper::IsSubShape( tgtV1, tgtFace )) - RETURN_BAD_RESULT("Wrong tgtV1 " << tgtV1.TShape().operator->()); - - // try to find out orientation by order of edges + TopoDS_Vertex srcV1, tgtV1; bool reverse = false; + + if ( _sourceHypo->HasVertexAssociation() ) { + srcV1 = _sourceHypo->GetSourceVertex(1); + tgtV1 = _sourceHypo->GetTargetVertex(1); + } else { + srcV1 = TopoDS::Vertex( TopExp_Explorer( srcFace, TopAbs_VERTEX ).Current() ); + tgtV1 = TopoDS::Vertex( shape2ShapeMap( srcV1, /*isSrc=*/true )); + } list< TopoDS_Edge > tgtEdges, srcEdges; list< int > nbEdgesInWires; - SMESH_Block::GetOrderedEdges( tgtFace, tgtV1, tgtEdges, nbEdgesInWires); - SMESH_Block::GetOrderedEdges( srcFace, srcV1, srcEdges, nbEdgesInWires); - if ( nbEdgesInWires.front() > 1 ) // possible to find out + SMESH_Block::GetOrderedEdges( tgtFace, tgtEdges, nbEdgesInWires, tgtV1 ); + SMESH_Block::GetOrderedEdges( srcFace, srcEdges, nbEdgesInWires, srcV1 ); + + if ( nbEdgesInWires.front() > 1 ) // possible to find out orientation { TopoDS_Edge srcE1 = srcEdges.front(), tgtE1 = tgtEdges.front(); TopoDS_Shape srcE1bis = shape2ShapeMap( tgtE1 ); reverse = ( ! srcE1.IsSame( srcE1bis )); + if ( reverse && + _sourceHypo->HasVertexAssociation() && + nbEdgesInWires.front() > 2 && + helper.IsRealSeam( tgtEdges.front() )) + { + // projection to a face with seam EDGE; pb is that GetOrderedEdges() + // always puts a seam EDGE first (if possible) and as a result + // we can't use only theReverse flag to correctly associate source + // and target faces in the mapper. Thus we select srcV1 so that + // GetOrderedEdges() to return EDGEs in a needed order + list< TopoDS_Edge >::iterator edge = srcEdges.begin(); + for ( ; edge != srcEdges.end(); ++edge ) { + if ( srcE1bis.IsSame( *edge )) { + srcV1 = helper.IthVertex( 0, *edge ); + break; + } + } + } } else if ( nbEdgesInWires.front() == 1 ) { @@ -922,6 +940,12 @@ bool StdMeshers_Projection_2D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& RETURN_BAD_RESULT("Bad result from SMESH_Block::GetOrderedEdges()"); } + // Load pattern from the source face + SMESH_Pattern mapper; + mapper.Load( srcMesh, srcFace, toProjectNodes, srcV1 ); + if ( mapper.GetErrorCode() != SMESH_Pattern::ERR_OK ) + return error(COMPERR_BAD_INPUT_MESH,"Can't load mesh pattern from the source face"); + // -------------------- // Perform 2D mapping // -------------------- @@ -952,7 +976,7 @@ bool StdMeshers_Projection_2D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& // Make groups of nodes to merge - // loop on edge and vertex submeshes of a target face + // loop on EDGE and VERTEX sub-meshes of a target FACE smIt = tgtSubMesh->getDependsOnIterator(/*includeSelf=*/false,/*complexShapeFirst=*/false); while ( smIt->more() ) { @@ -963,6 +987,24 @@ bool StdMeshers_Projection_2D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& //if ( !is1DComputed && sm->GetSubShape().ShapeType() == TopAbs_EDGE ) //break; + if ( helper.IsDegenShape( sm->GetId() ) ) // to merge all nodes on degenerated + { + if ( sm->GetSubShape().ShapeType() == TopAbs_EDGE ) + { + groupsOfNodes.push_back( list< const SMDS_MeshNode* >() ); + SMESH_subMeshIteratorPtr smDegenIt + = sm->getDependsOnIterator(/*includeSelf=*/true,/*complexShapeFirst=*/false); + while ( smDegenIt->more() ) + if (( smDS = smDegenIt->next()->GetSubMeshDS() )) + { + SMDS_NodeIteratorPtr nIt = smDS->GetNodes(); + while ( nIt->more() ) + groupsOfNodes.back().push_back( nIt->next() ); + } + } + continue; // do not treat sm of degen VERTEX + } + // Sort new and old nodes of a submesh separately bool isSeam = helper.IsRealSeam( sm->GetId() ); @@ -1021,18 +1063,36 @@ bool StdMeshers_Projection_2D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& u_oldNode = u2nodesMaps[ OLD_NODES ].begin(); newEnd = u2nodesMaps[ OLD_NODES ].end(); for ( ; u_oldNode != newEnd; ++u_oldNode ) - _badInputElements.push_back( u_oldNode->second ); + SMESH_Algo::addBadInputElement( u_oldNode->second ); return error( COMPERR_BAD_INPUT_MESH, SMESH_Comment( "Existing mesh mismatches the projected 2D mesh on " ) << ( sm->GetSubShape().ShapeType() == TopAbs_EDGE ? "edge" : "vertex" ) << " #" << sm->GetId() ); } if ( isSeam && !mergeSeamToNew ) { - //RETURN_BAD_RESULT - MESSAGE("Different nb of old and seam nodes " << - u2nodesMaps[ OLD_NODES ].size() << " != " << u2nodesOnSeam.size()); + const TopoDS_Shape& seam = sm->GetSubShape(); + if ( u2nodesMaps[ NEW_NODES ].size() > 0 && + u2nodesOnSeam.size() > 0 && + seam.ShapeType() == TopAbs_EDGE ) + { + int nbE1 = SMESH_MesherHelper::Count( tgtFace, TopAbs_EDGE, /*ignoreSame=*/true ); + int nbE2 = SMESH_MesherHelper::Count( srcFace, TopAbs_EDGE, /*ignoreSame=*/true ); + if ( nbE1 != nbE2 ) // 2 EDGEs are mapped to a seam EDGE + { + // find the 2 EDGEs of srcFace + TopTools_DataMapIteratorOfDataMapOfShapeShape src2tgtIt( shape2ShapeMap._map2to1 ); + for ( ; src2tgtIt.More(); src2tgtIt.Next() ) + if ( seam.IsSame( src2tgtIt.Value() )) + SMESH_Algo::addBadInputElements + ( srcMesh->GetMeshDS()->MeshElements( src2tgtIt.Key() )); + return error( COMPERR_BAD_INPUT_MESH, + "Different number of nodes on two edges projected to a seam edge" ); + } + } } + // Make groups of nodes to merge + u_oldNode = u2nodesMaps[ OLD_NODES ].begin(); u_newNode = u2nodesMaps[ NEW_NODES ].begin(); newEnd = u2nodesMaps[ NEW_NODES ].end(); @@ -1053,7 +1113,8 @@ bool StdMeshers_Projection_2D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& groupsOfNodes.back().push_back( u_newNode->second ); groupsOfNodes.back().push_back( u_newOnSeam->second ); } - } + + } // loop on EDGE and VERTEX submeshes of a target FACE // Merge @@ -1061,7 +1122,7 @@ bool StdMeshers_Projection_2D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& int nbFaceBeforeMerge = tgtSubMesh->GetSubMeshDS()->NbElements(); editor.MergeNodes( groupsOfNodes ); int nbFaceAtferMerge = tgtSubMesh->GetSubMeshDS()->NbElements(); - if ( nbFaceBeforeMerge != nbFaceAtferMerge ) + if ( nbFaceBeforeMerge != nbFaceAtferMerge && !helper.HasDegeneratedEdges() ) return error(COMPERR_BAD_INPUT_MESH, "Probably invalid node parameters on geom faces"); // ---------------------------------------------------------------- diff --git a/src/StdMeshers/StdMeshers_Projection_3D.cxx b/src/StdMeshers/StdMeshers_Projection_3D.cxx index ed22742f7..7c07b40f3 100644 --- a/src/StdMeshers/StdMeshers_Projection_3D.cxx +++ b/src/StdMeshers/StdMeshers_Projection_3D.cxx @@ -219,13 +219,13 @@ bool StdMeshers_Projection_3D::Compute(SMESH_Mesh& aMesh, const TopoDS_Shape& aS SMESH_Comment("Target shape must have 1 shell but not ") << nbShell); // Check that shapes are blocks - if ( TAssocTool::Count( tgtShell, TopAbs_FACE , 1 ) != 6 || - TAssocTool::Count( tgtShell, TopAbs_EDGE , 1 ) != 12 || - TAssocTool::Count( tgtShell, TopAbs_WIRE , 1 ) != 6 ) + if ( SMESH_MesherHelper::Count( tgtShell, TopAbs_FACE , 1 ) != 6 || + SMESH_MesherHelper::Count( tgtShell, TopAbs_EDGE , 1 ) != 12 || + SMESH_MesherHelper::Count( tgtShell, TopAbs_WIRE , 1 ) != 6 ) return error(COMPERR_BAD_SHAPE, "Target shape is not a block"); - if ( TAssocTool::Count( srcShell, TopAbs_FACE , 1 ) != 6 || - TAssocTool::Count( srcShell, TopAbs_EDGE , 1 ) != 12 || - TAssocTool::Count( srcShell, TopAbs_WIRE , 1 ) != 6 ) + if ( SMESH_MesherHelper::Count( srcShell, TopAbs_FACE , 1 ) != 6 || + SMESH_MesherHelper::Count( srcShell, TopAbs_EDGE , 1 ) != 12 || + SMESH_MesherHelper::Count( srcShell, TopAbs_WIRE , 1 ) != 6 ) return error(COMPERR_BAD_SHAPE, "Source shape is not a block"); // Assure that mesh on a source shape is computed @@ -459,13 +459,13 @@ bool StdMeshers_Projection_3D::Evaluate(SMESH_Mesh& aMesh, SMESH_Comment("Target shape must have 1 shell but not ") << nbShell); // Check that shapes are blocks - if ( TAssocTool::Count( tgtShell, TopAbs_FACE , 1 ) != 6 || - TAssocTool::Count( tgtShell, TopAbs_EDGE , 1 ) != 12 || - TAssocTool::Count( tgtShell, TopAbs_WIRE , 1 ) != 6 ) + if ( SMESH_MesherHelper::Count( tgtShell, TopAbs_FACE , 1 ) != 6 || + SMESH_MesherHelper::Count( tgtShell, TopAbs_EDGE , 1 ) != 12 || + SMESH_MesherHelper::Count( tgtShell, TopAbs_WIRE , 1 ) != 6 ) return error(COMPERR_BAD_SHAPE, "Target shape is not a block"); - if ( TAssocTool::Count( srcShell, TopAbs_FACE , 1 ) != 6 || - TAssocTool::Count( srcShell, TopAbs_EDGE , 1 ) != 12 || - TAssocTool::Count( srcShell, TopAbs_WIRE , 1 ) != 6 ) + if ( SMESH_MesherHelper::Count( srcShell, TopAbs_FACE , 1 ) != 6 || + SMESH_MesherHelper::Count( srcShell, TopAbs_EDGE , 1 ) != 12 || + SMESH_MesherHelper::Count( srcShell, TopAbs_WIRE , 1 ) != 6 ) return error(COMPERR_BAD_SHAPE, "Source shape is not a block"); // Assure that mesh on a source shape is computed diff --git a/src/StdMeshers/StdMeshers_Quadrangle_2D.cxx b/src/StdMeshers/StdMeshers_Quadrangle_2D.cxx index d75a5aac2..5146d08d2 100644 --- a/src/StdMeshers/StdMeshers_Quadrangle_2D.cxx +++ b/src/StdMeshers/StdMeshers_Quadrangle_2D.cxx @@ -78,6 +78,11 @@ typedef SMESH_Comment TComm; StdMeshers_Quadrangle_2D::StdMeshers_Quadrangle_2D (int hypId, int studyId, SMESH_Gen* gen) : SMESH_2D_Algo(hypId, studyId, gen), + myQuadranglePreference(false), + myTrianglePreference(false), + myTriaVertexID(-1), + myNeedSmooth(false), + myQuadType(QUAD_STANDARD), myHelper( 0 ) { MESSAGE("StdMeshers_Quadrangle_2D::StdMeshers_Quadrangle_2D"); @@ -122,6 +127,7 @@ bool StdMeshers_Quadrangle_2D::CheckHypothesis myQuadType = QUAD_STANDARD; myQuadranglePreference = false; myTrianglePreference = false; + myQuadStruct.reset(); bool isFirstParams = true; @@ -211,10 +217,10 @@ bool StdMeshers_Quadrangle_2D::Compute (SMESH_Mesh& aMesh, _quadraticMesh = myHelper->IsQuadraticSubMesh(aShape); myNeedSmooth = false; - FaceQuadStruct *quad = CheckNbEdges(aMesh, aShape); - std::auto_ptr quadDeleter (quad); // to delete quad at exit from Compute() + FaceQuadStruct::Ptr quad = CheckNbEdges(aMesh, aShape); if (!quad) return false; + myQuadStruct = quad; if (myQuadranglePreference) { int n1 = quad->side[0]->NbPoints(); @@ -781,24 +787,25 @@ static bool twoEdgesMeatAtVertex(const TopoDS_Edge& e1, */ //============================================================================= -FaceQuadStruct* StdMeshers_Quadrangle_2D::CheckNbEdges(SMESH_Mesh & aMesh, - const TopoDS_Shape & aShape) - //throw(SALOME_Exception) +FaceQuadStruct::Ptr StdMeshers_Quadrangle_2D::CheckNbEdges(SMESH_Mesh & aMesh, + const TopoDS_Shape & aShape) { + if ( myQuadStruct && myQuadStruct->face.IsSame( aShape )) + return myQuadStruct; + TopoDS_Face F = TopoDS::Face(aShape); if ( F.Orientation() >= TopAbs_INTERNAL ) F.Orientation( TopAbs_FORWARD ); const bool ignoreMediumNodes = _quadraticMesh; // verify 1 wire only, with 4 edges - TopoDS_Vertex V; list< TopoDS_Edge > edges; list< int > nbEdgesInWire; - int nbWire = SMESH_Block::GetOrderedEdges (F, V, edges, nbEdgesInWire); + int nbWire = SMESH_Block::GetOrderedEdges (F, edges, nbEdgesInWire); if (nbWire != 1) { error(COMPERR_BAD_SHAPE, TComm("Wrong number of wires: ") << nbWire); - return 0; + return FaceQuadStruct::Ptr(); } - FaceQuadStruct* quad = new FaceQuadStruct; + FaceQuadStruct::Ptr quad( new FaceQuadStruct ); quad->uv_grid = 0; quad->side.reserve(nbEdgesInWire.front()); quad->face = F; @@ -809,7 +816,7 @@ FaceQuadStruct* StdMeshers_Quadrangle_2D::CheckNbEdges(SMESH_Mesh & aMes { SMESH_Comment comment; SMESHDS_Mesh* meshDS = aMesh.GetMeshDS(); - if (myTriaVertexID == -1) + if (myTriaVertexID < 1) { comment << "No Base vertex parameter provided for a trilateral geometrical face"; } @@ -853,13 +860,13 @@ FaceQuadStruct* StdMeshers_Quadrangle_2D::CheckNbEdges(SMESH_Mesh & aMes comment << meshDS->ShapeToIndex(v.Current()) << (vMap.Extent()==3 ? "]" : ", "); } error(comment); - delete quad; - return quad = 0; + quad.reset(); + return quad; } else if (nbEdgesInWire.front() == 4) // exactly 4 edges { for (; edgeIt != edges.end(); ++edgeIt, nbSides++) - quad->side.push_back(new StdMeshers_FaceSide(F, *edgeIt, &aMesh, nbSides < TOP_SIDE, + quad->side.push_back(new StdMeshers_FaceSide(F, *edgeIt, &aMesh, nbSides < QUAD_TOP_SIDE, ignoreMediumNodes, myProxyMesh)); } else if (nbEdgesInWire.front() > 4) // more than 4 edges - try to unite some @@ -886,14 +893,14 @@ FaceQuadStruct* StdMeshers_Quadrangle_2D::CheckNbEdges(SMESH_Mesh & aMes if ( sideEdges.size() == 1 && BRep_Tool::Degenerated( sideEdges.front() )) degenSides.push_back( nbSides ); - quad->side.push_back(new StdMeshers_FaceSide(F, sideEdges, &aMesh, nbSides < TOP_SIDE, + quad->side.push_back(new StdMeshers_FaceSide(F, sideEdges, &aMesh, nbSides < QUAD_TOP_SIDE, ignoreMediumNodes, myProxyMesh)); ++nbSides; } if ( !degenSides.empty() && nbSides - degenSides.size() == 4 ) { myNeedSmooth = true; - for ( unsigned i = TOP_SIDE; i < quad->side.size(); ++i ) + for ( unsigned i = QUAD_TOP_SIDE; i < quad->side.size(); ++i ) quad->side[i]->Reverse(); for ( int i = degenSides.size()-1; i > -1; --i ) @@ -902,20 +909,19 @@ FaceQuadStruct* StdMeshers_Quadrangle_2D::CheckNbEdges(SMESH_Mesh & aMes delete degenSide; quad->side.erase( quad->side.begin() + degenSides[ i ] ); } - for ( unsigned i = TOP_SIDE; i < quad->side.size(); ++i ) + for ( unsigned i = QUAD_TOP_SIDE; i < quad->side.size(); ++i ) quad->side[i]->Reverse(); nbSides -= degenSides.size(); } // issue 20222. Try to unite only edges shared by two same faces - if (nbSides < 4) { - // delete found sides - { FaceQuadStruct cleaner(*quad); } - quad->side.clear(); + if (nbSides < 4) + { + quad.reset( new FaceQuadStruct ); quad->side.reserve(nbEdgesInWire.front()); nbSides = 0; - SMESH_Block::GetOrderedEdges (F, V, edges, nbEdgesInWire); + SMESH_Block::GetOrderedEdges (F, edges, nbEdgesInWire); while (!edges.empty()) { sideEdges.clear(); sideEdges.splice(sideEdges.end(), edges, edges.begin()); @@ -938,7 +944,7 @@ FaceQuadStruct* StdMeshers_Quadrangle_2D::CheckNbEdges(SMESH_Mesh & aMes } } quad->side.push_back(new StdMeshers_FaceSide(F, sideEdges, &aMesh, - nbSides < TOP_SIDE, + nbSides < QUAD_TOP_SIDE, ignoreMediumNodes, myProxyMesh)); ++nbSides; } @@ -953,13 +959,11 @@ FaceQuadStruct* StdMeshers_Quadrangle_2D::CheckNbEdges(SMESH_Mesh & aMes MESSAGE (myHelper->GetMeshDS()->ShapeToIndex(quad->side[i]->Edge(e)) << " "); MESSAGE (")\n"); } - //cout << endl; #endif if (!nbSides) nbSides = nbEdgesInWire.front(); error(COMPERR_BAD_SHAPE, TComm("Face must have 4 sides but not ") << nbSides); - delete quad; - quad = 0; + quad.reset(); } return quad; @@ -982,10 +986,9 @@ bool StdMeshers_Quadrangle_2D::CheckNbEdgesForEvaluate(SMESH_Mesh& aMesh, const TopoDS_Face & F = TopoDS::Face(aShape); // verify 1 wire only, with 4 edges - TopoDS_Vertex V; list< TopoDS_Edge > edges; list< int > nbEdgesInWire; - int nbWire = SMESH_Block::GetOrderedEdges (F, V, edges, nbEdgesInWire); + int nbWire = SMESH_Block::GetOrderedEdges (F, edges, nbEdgesInWire); if (nbWire != 1) { return false; } @@ -1101,7 +1104,7 @@ bool StdMeshers_Quadrangle_2D::CheckNbEdgesForEvaluate(SMESH_Mesh& aMesh, // issue 20222. Try to unite only edges shared by two same faces if (nbSides < 4) { nbSides = 0; - SMESH_Block::GetOrderedEdges (F, V, edges, nbEdgesInWire); + SMESH_Block::GetOrderedEdges (F, edges, nbEdgesInWire); while (!edges.empty()) { sideEdges.clear(); sideEdges.splice(sideEdges.end(), edges, edges.begin()); @@ -1158,52 +1161,59 @@ bool StdMeshers_Quadrangle_2D::CheckNbEdgesForEvaluate(SMESH_Mesh& aMesh, */ //============================================================================= -FaceQuadStruct *StdMeshers_Quadrangle_2D::CheckAnd2Dcompute - (SMESH_Mesh & aMesh, - const TopoDS_Shape & aShape, - const bool CreateQuadratic) //throw(SALOME_Exception) +FaceQuadStruct::Ptr +StdMeshers_Quadrangle_2D::CheckAnd2Dcompute (SMESH_Mesh & aMesh, + const TopoDS_Shape & aShape, + const bool CreateQuadratic) { _quadraticMesh = CreateQuadratic; - FaceQuadStruct *quad = CheckNbEdges(aMesh, aShape); - - if (!quad) return 0; - - // set normalized grid on unit square in parametric domain - bool stat = SetNormalizedGrid(aMesh, aShape, quad); - if (!stat) { - if (quad) delete quad; - quad = 0; + FaceQuadStruct::Ptr quad = CheckNbEdges(aMesh, aShape); + if ( quad ) + { + // set normalized grid on unit square in parametric domain + if (!SetNormalizedGrid(aMesh, aShape, quad)) + quad.reset(); } - return quad; } //============================================================================= /*! - * + * */ //============================================================================= faceQuadStruct::~faceQuadStruct() { - for (int i = 0; i < side.size(); i++) { - if (side[i]) delete side[i]; + for (size_t i = 0; i < side.size(); i++) { + if (side[i]) { + delete side[i]; + for (size_t j = i+1; j < side.size(); j++) + if ( side[i] == side[j] ) + side[j] = 0; + } + } + side.clear(); + + if (uv_grid) { + delete [] uv_grid; + uv_grid = 0; } - if (uv_grid) delete [] uv_grid; } -namespace { - inline const vector& GetUVPtStructIn(FaceQuadStruct* quad, int i, int nbSeg) +namespace +{ + inline const vector& getUVPtStructIn(FaceQuadStruct::Ptr& quad, int i, int nbSeg) { - bool isXConst = (i == BOTTOM_SIDE || i == TOP_SIDE); - double constValue = (i == BOTTOM_SIDE || i == LEFT_SIDE) ? 0 : 1; + bool isXConst = (i == QUAD_BOTTOM_SIDE || i == QUAD_TOP_SIDE); + double constValue = (i == QUAD_BOTTOM_SIDE || i == QUAD_LEFT_SIDE) ? 0 : 1; return quad->isEdgeOut[i] ? quad->side[i]->SimulateUVPtStruct(nbSeg,isXConst,constValue) : quad->side[i]->GetUVPtStruct(isXConst,constValue); } - inline gp_UV CalcUV(double x, double y, + inline gp_UV calcUV(double x, double y, const gp_UV& a0,const gp_UV& a1,const gp_UV& a2,const gp_UV& a3, const gp_UV& p0,const gp_UV& p1,const gp_UV& p2,const gp_UV& p3) { @@ -1219,9 +1229,9 @@ namespace { */ //============================================================================= -bool StdMeshers_Quadrangle_2D::SetNormalizedGrid (SMESH_Mesh & aMesh, - const TopoDS_Shape& aShape, - FaceQuadStruct* & quad) //throw (SALOME_Exception) +bool StdMeshers_Quadrangle_2D::SetNormalizedGrid (SMESH_Mesh & aMesh, + const TopoDS_Shape& aShape, + FaceQuadStruct::Ptr & quad) { // Algorithme décrit dans "Génération automatique de maillages" // P.L. GEORGE, MASSON, § 6.4.1 p. 84-85 @@ -1257,10 +1267,10 @@ bool StdMeshers_Quadrangle_2D::SetNormalizedGrid (SMESH_Mesh & aMesh, UVPtStruct *uv_grid = quad->uv_grid = new UVPtStruct[nbvertic * nbhoriz]; - const vector& uv_e0 = GetUVPtStructIn(quad, 0, nbhoriz - 1); - const vector& uv_e1 = GetUVPtStructIn(quad, 1, nbvertic - 1); - const vector& uv_e2 = GetUVPtStructIn(quad, 2, nbhoriz - 1); - const vector& uv_e3 = GetUVPtStructIn(quad, 3, nbvertic - 1); + const vector& uv_e0 = getUVPtStructIn(quad, 0, nbhoriz - 1); + const vector& uv_e1 = getUVPtStructIn(quad, 1, nbvertic - 1); + const vector& uv_e2 = getUVPtStructIn(quad, 2, nbhoriz - 1); + const vector& uv_e3 = getUVPtStructIn(quad, 3, nbvertic - 1); if (uv_e0.empty() || uv_e1.empty() || uv_e2.empty() || uv_e3.empty()) //return error("Can't find nodes on sides"); @@ -1330,7 +1340,7 @@ bool StdMeshers_Quadrangle_2D::SetNormalizedGrid (SMESH_Mesh & aMesh, double x = uv_grid[ij].x; double y = uv_grid[ij].y; - gp_UV uv = CalcUV(x,y, a0,a1,a2,a3, p0,p1,p2,p3); + gp_UV uv = calcUV(x,y, a0,a1,a2,a3, p0,p1,p2,p3); uv_grid[ij].u = uv.X(); uv_grid[ij].v = uv.Y(); @@ -1344,64 +1354,72 @@ bool StdMeshers_Quadrangle_2D::SetNormalizedGrid (SMESH_Mesh & aMesh, //purpose : auxilary function for ComputeQuadPref //======================================================================= -static void ShiftQuad(FaceQuadStruct* quad, const int num, bool) +static void shiftQuad(FaceQuadStruct::Ptr& quad, const int num, bool) +{ + quad->shift( num, /*ori=*/true ); +} + +//================================================================================ +/*! + * \brief Rotate sides of a quad by nb + * \param nb - number of rotation quartes + * \param ori - to keep orientation of sides as in an unit quad or not + */ +//================================================================================ + +void FaceQuadStruct::shift( size_t nb, bool ori ) { - StdMeshers_FaceSide* side[4] = { quad->side[0], quad->side[1], - quad->side[2], quad->side[3] }; - for (int i = BOTTOM_SIDE; i < NB_SIDES; ++i) { - int id = (i + num) % NB_SIDES; - bool wasForward = (i < TOP_SIDE); - bool newForward = (id < TOP_SIDE); - if (wasForward != newForward) - side[ i ]->Reverse(); - quad->side[ id ] = side[ i ]; + if ( nb == 0 ) return; + StdMeshers_FaceSide* sideArr[4] = { side[0], side[1], side[2], side[3] }; + for (int i = QUAD_BOTTOM_SIDE; i < NB_QUAD_SIDES; ++i) { + int id = (i + nb) % NB_QUAD_SIDES; + bool wasForward = (i < QUAD_TOP_SIDE); + bool newForward = (id < QUAD_TOP_SIDE); + if (ori && wasForward != newForward) + sideArr[ i ]->Reverse(); + side[ id ] = sideArr[ i ]; } } //======================================================================= -//function : CalcUV +//function : calcUV //purpose : auxilary function for ComputeQuadPref //======================================================================= -static gp_UV CalcUV(double x0, double x1, double y0, double y1, - FaceQuadStruct* quad, +static gp_UV calcUV(double x0, double x1, double y0, double y1, + FaceQuadStruct::Ptr& quad, const gp_UV& a0, const gp_UV& a1, const gp_UV& a2, const gp_UV& a3) { - // const vector& uv_eb = quad->side[0]->GetUVPtStruct(true,0); - // const vector& uv_er = quad->side[1]->GetUVPtStruct(false,1); - // const vector& uv_et = quad->side[2]->GetUVPtStruct(true,1); - // const vector& uv_el = quad->side[3]->GetUVPtStruct(false,0); - double x = (x0 + y0 * (x1 - x0)) / (1 - (y1 - y0) * (x1 - x0)); double y = y0 + x * (y1 - y0); - gp_UV p0 = quad->side[BOTTOM_SIDE]->Value2d(x).XY(); - gp_UV p1 = quad->side[RIGHT_SIDE ]->Value2d(y).XY(); - gp_UV p2 = quad->side[TOP_SIDE ]->Value2d(x).XY(); - gp_UV p3 = quad->side[LEFT_SIDE ]->Value2d(y).XY(); + gp_UV p0 = quad->side[QUAD_BOTTOM_SIDE]->Value2d(x).XY(); + gp_UV p1 = quad->side[QUAD_RIGHT_SIDE ]->Value2d(y).XY(); + gp_UV p2 = quad->side[QUAD_TOP_SIDE ]->Value2d(x).XY(); + gp_UV p3 = quad->side[QUAD_LEFT_SIDE ]->Value2d(y).XY(); - gp_UV uv = CalcUV(x,y, a0,a1,a2,a3, p0,p1,p2,p3); + gp_UV uv = calcUV(x,y, a0,a1,a2,a3, p0,p1,p2,p3); return uv; } //======================================================================= -//function : CalcUV2 +//function : calcUV2 //purpose : auxilary function for ComputeQuadPref //======================================================================= -static gp_UV CalcUV2(double x, double y, - FaceQuadStruct* quad, +static gp_UV calcUV2(double x, double y, + FaceQuadStruct::Ptr& quad, const gp_UV& a0, const gp_UV& a1, const gp_UV& a2, const gp_UV& a3) { - gp_UV p0 = quad->side[BOTTOM_SIDE]->Value2d(x).XY(); - gp_UV p1 = quad->side[RIGHT_SIDE ]->Value2d(y).XY(); - gp_UV p2 = quad->side[TOP_SIDE ]->Value2d(x).XY(); - gp_UV p3 = quad->side[LEFT_SIDE ]->Value2d(y).XY(); + gp_UV p0 = quad->side[QUAD_BOTTOM_SIDE]->Value2d(x).XY(); + gp_UV p1 = quad->side[QUAD_RIGHT_SIDE ]->Value2d(y).XY(); + gp_UV p2 = quad->side[QUAD_TOP_SIDE ]->Value2d(x).XY(); + gp_UV p3 = quad->side[QUAD_LEFT_SIDE ]->Value2d(y).XY(); - gp_UV uv = CalcUV(x,y, a0,a1,a2,a3, p0,p1,p2,p3); + gp_UV uv = calcUV(x,y, a0,a1,a2,a3, p0,p1,p2,p3); return uv; } @@ -1415,7 +1433,7 @@ static gp_UV CalcUV2(double x, double y, bool StdMeshers_Quadrangle_2D::ComputeQuadPref (SMESH_Mesh & aMesh, const TopoDS_Shape& aShape, - FaceQuadStruct* quad) + FaceQuadStruct::Ptr quad) { // Auxilary key in order to keep old variant // of meshing after implementation new variant @@ -1440,21 +1458,21 @@ bool StdMeshers_Quadrangle_2D::ComputeQuadPref (SMESH_Mesh & aMesh, if (dh>=dv) { if (nt>nb) { // it is a base case => not shift quad but me be replacement is need - ShiftQuad(quad,0,WisF); + shiftQuad(quad,0,WisF); } else { // we have to shift quad on 2 - ShiftQuad(quad,2,WisF); + shiftQuad(quad,2,WisF); } } else { if (nr>nl) { // we have to shift quad on 1 - ShiftQuad(quad,1,WisF); + shiftQuad(quad,1,WisF); } else { // we have to shift quad on 3 - ShiftQuad(quad,3,WisF); + shiftQuad(quad,3,WisF); } } @@ -1518,13 +1536,9 @@ bool StdMeshers_Quadrangle_2D::ComputeQuadPref (SMESH_Mesh & aMesh, UpdateDegenUV( quad ); // arrays for normalized params - //cout<<"Dump B:"<X()<<","<Y()<<","<Z()<<")"<Value(UV.X(),UV.Y()); SMDS_MeshNode * N = meshDS->AddNode(P.X(), P.Y(), P.Z()); meshDS->SetNodeOnFace(N, geomFaceID, UV.X(), UV.Y()); @@ -1599,7 +1606,7 @@ bool StdMeshers_Quadrangle_2D::ComputeQuadPref (SMESH_Mesh & aMesh, for (j=2; jValue(UV.X(),UV.Y()); SMDS_MeshNode* N = meshDS->AddNode(P.X(), P.Y(), P.Z()); meshDS->SetNodeOnFace(N, geomFaceID, UV.X(), UV.Y()); @@ -1610,14 +1617,6 @@ bool StdMeshers_Quadrangle_2D::ComputeQuadPref (SMESH_Mesh & aMesh, for (i=1; i<=UVtmp.Length() && UVL.Length()X()<<","<Y()<<","<Z()<<")"; - // } - // cout<Value(UV.X(),UV.Y()); SMDS_MeshNode * N = meshDS->AddNode(P.X(), P.Y(), P.Z()); meshDS->SetNodeOnFace(N, geomFaceID, UV.X(), UV.Y()); @@ -1670,7 +1669,7 @@ bool StdMeshers_Quadrangle_2D::ComputeQuadPref (SMESH_Mesh & aMesh, for (j=2; jValue(UV.X(),UV.Y()); SMDS_MeshNode* N = meshDS->AddNode(P.X(), P.Y(), P.Z()); meshDS->SetNodeOnFace(N, geomFaceID, UV.X(), UV.Y()); @@ -1733,7 +1732,7 @@ bool StdMeshers_Quadrangle_2D::ComputeQuadPref (SMESH_Mesh & aMesh, for (j=1; jValue(UV.X(),UV.Y()); SMDS_MeshNode* N = meshDS->AddNode(P.X(), P.Y(), P.Z()); meshDS->SetNodeOnFace(N, geomFaceID, UV.X(), UV.Y()); @@ -1743,12 +1742,6 @@ bool StdMeshers_Quadrangle_2D::ComputeQuadPref (SMESH_Mesh & aMesh, } } // add diagonal layers - //cout<<"UVL.Length()="<Value(UV.X(),UV.Y()); SMDS_MeshNode* N = meshDS->AddNode(P.X(), P.Y(), P.Z()); meshDS->SetNodeOnFace(N, geomFaceID, UV.X(),UV.Y()); @@ -1798,7 +1791,7 @@ bool StdMeshers_Quadrangle_2D::ComputeQuadPref (SMESH_Mesh & aMesh, for (j=2; jValue(UV.X(),UV.Y()); SMDS_MeshNode* N = meshDS->AddNode(P.X(), P.Y(), P.Z()); meshDS->SetNodeOnFace(N, geomFaceID, UV.X(),UV.Y()); @@ -1848,7 +1841,7 @@ bool StdMeshers_Quadrangle_2D::ComputeQuadPref (SMESH_Mesh & aMesh, for (j=1; jValue(UV.X(),UV.Y()); SMDS_MeshNode* N = meshDS->AddNode(P.X(), P.Y(), P.Z()); meshDS->SetNodeOnFace(N, geomFaceID, UV.X(), UV.Y()); @@ -1865,7 +1858,7 @@ bool StdMeshers_Quadrangle_2D::ComputeQuadPref (SMESH_Mesh & aMesh, double x = npt.Value(i+1+drl) + npb.Value(j) * (npt.Value(nt-i) - npt.Value(i+1+drl)); double y = yy0 + dyy*x; - gp_UV UV = CalcUV2(x, y, quad, a0, a1, a2, a3); + gp_UV UV = calcUV2(x, y, quad, a0, a1, a2, a3); gp_Pnt P = S->Value(UV.X(),UV.Y()); SMDS_MeshNode* N = meshDS->AddNode(P.X(), P.Y(), P.Z()); meshDS->SetNodeOnFace(N, geomFaceID, UV.X(), UV.Y()); @@ -1891,7 +1884,7 @@ bool StdMeshers_Quadrangle_2D::ComputeQuadPref (SMESH_Mesh & aMesh, for (j=2; j<=nb; j++) { double x = npb.Value(j)*npt.Value(nt-i); double y = y0 + dy*x; - gp_UV UV = CalcUV2(x, y, quad, a0, a1, a2, a3); + gp_UV UV = calcUV2(x, y, quad, a0, a1, a2, a3); gp_Pnt P = S->Value(UV.X(),UV.Y()); SMDS_MeshNode* N = meshDS->AddNode(P.X(), P.Y(), P.Z()); meshDS->SetNodeOnFace(N, geomFaceID, UV.X(), UV.Y()); @@ -1908,7 +1901,7 @@ bool StdMeshers_Quadrangle_2D::ComputeQuadPref (SMESH_Mesh & aMesh, double x = npt.Value(i+1) + npb.Value(j) * (npt.Value(nt-i-drl) - npt.Value(i+1)); double y = yy0 + dyy*x; - gp_UV UV = CalcUV2(x, y, quad, a0, a1, a2, a3); + gp_UV UV = calcUV2(x, y, quad, a0, a1, a2, a3); gp_Pnt P = S->Value(UV.X(),UV.Y()); SMDS_MeshNode* N = meshDS->AddNode(P.X(), P.Y(), P.Z()); meshDS->SetNodeOnFace(N, geomFaceID, UV.X(), UV.Y()); @@ -2147,13 +2140,13 @@ namespace inline SMDS_MeshNode* makeNode( UVPtStruct & uvPt, const double y, - FaceQuadStruct* quad, + FaceQuadStruct::Ptr& quad, const gp_UV* UVs, SMESH_MesherHelper* helper, Handle(Geom_Surface) S) { - const vector& uv_eb = quad->side[BOTTOM_SIDE]->GetUVPtStruct(); - const vector& uv_et = quad->side[TOP_SIDE ]->GetUVPtStruct(); + const vector& uv_eb = quad->side[QUAD_BOTTOM_SIDE]->GetUVPtStruct(); + const vector& uv_et = quad->side[QUAD_TOP_SIDE ]->GetUVPtStruct(); double rBot = ( uv_eb.size() - 1 ) * uvPt.normParam; double rTop = ( uv_et.size() - 1 ) * uvPt.normParam; int iBot = int( rBot ); @@ -2162,11 +2155,11 @@ namespace double xTop = uv_et[ iTop ].normParam + ( rTop - iTop ) * ( uv_et[ iTop+1 ].normParam - uv_et[ iTop ].normParam ); double x = xBot + y * ( xTop - xBot ); - gp_UV uv = CalcUV(/*x,y=*/x, y, + gp_UV uv = calcUV(/*x,y=*/x, y, /*a0,...=*/UVs[UV_A0], UVs[UV_A1], UVs[UV_A2], UVs[UV_A3], - /*p0=*/quad->side[BOTTOM_SIDE]->Value2d( x ).XY(), + /*p0=*/quad->side[QUAD_BOTTOM_SIDE]->Value2d( x ).XY(), /*p1=*/UVs[ UV_R ], - /*p2=*/quad->side[TOP_SIDE ]->Value2d( x ).XY(), + /*p2=*/quad->side[QUAD_TOP_SIDE ]->Value2d( x ).XY(), /*p3=*/UVs[ UV_L ]); gp_Pnt P = S->Value( uv.X(), uv.Y() ); uvPt.u = uv.X(); @@ -2178,7 +2171,7 @@ namespace vector& next_base, const int j, int & next_base_len, - FaceQuadStruct* quad, + FaceQuadStruct::Ptr& quad, gp_UV* UVs, const double y, SMESH_MesherHelper* helper, @@ -2247,7 +2240,7 @@ namespace vector& next_base, const int j, int & next_base_len, - FaceQuadStruct* quad, + FaceQuadStruct::Ptr& quad, gp_UV* UVs, const double y, SMESH_MesherHelper* helper, @@ -2310,7 +2303,7 @@ namespace vector& next_base, const int j, int & next_base_len, - FaceQuadStruct* quad, + FaceQuadStruct::Ptr & quad, gp_UV* UVs, const double y, SMESH_MesherHelper* helper, @@ -2325,7 +2318,7 @@ namespace //======================================================================= bool StdMeshers_Quadrangle_2D::ComputeReduced (SMESH_Mesh & aMesh, const TopoDS_Shape& aShape, - FaceQuadStruct* quad) + FaceQuadStruct::Ptr quad) { SMESHDS_Mesh * meshDS = aMesh.GetMeshDS(); const TopoDS_Face& F = TopoDS::Face(aShape); @@ -2398,21 +2391,21 @@ bool StdMeshers_Quadrangle_2D::ComputeReduced (SMESH_Mesh & aMesh, if (dh >= dv) { if (nt > nb) { // it is a base case => not shift quad but may be replacement is need - ShiftQuad(quad,0,true); + shiftQuad(quad,0,true); } else { // we have to shift quad on 2 - ShiftQuad(quad,2,true); + shiftQuad(quad,2,true); } } else { if (nr > nl) { // we have to shift quad on 1 - ShiftQuad(quad,1,true); + shiftQuad(quad,1,true); } else { // we have to shift quad on 3 - ShiftQuad(quad,3,true); + shiftQuad(quad,3,true); } } @@ -2520,7 +2513,7 @@ bool StdMeshers_Quadrangle_2D::ComputeReduced (SMESH_Mesh & aMesh, // diagonal node double y0 = npl.Value(i+1); double y1 = npr.Value(i+1); - gp_UV UV = CalcUV(x0, x1, y0, y1, quad, a0, a1, a2, a3); + gp_UV UV = calcUV(x0, x1, y0, y1, quad, a0, a1, a2, a3); gp_Pnt P = S->Value(UV.X(),UV.Y()); SMDS_MeshNode * N = meshDS->AddNode(P.X(), P.Y(), P.Z()); meshDS->SetNodeOnFace(N, geomFaceID, UV.X(), UV.Y()); @@ -2530,7 +2523,7 @@ bool StdMeshers_Quadrangle_2D::ComputeReduced (SMESH_Mesh & aMesh, for (j=2; jValue(UV.X(),UV.Y()); SMDS_MeshNode* N = meshDS->AddNode(P.X(), P.Y(), P.Z()); meshDS->SetNodeOnFace(N, geomFaceID, UV.X(), UV.Y()); @@ -2575,7 +2568,7 @@ bool StdMeshers_Quadrangle_2D::ComputeReduced (SMESH_Mesh & aMesh, // diagonal node double y0 = npl.Value(i+1); double y1 = npr.Value(i+1); - gp_UV UV = CalcUV(x0, x1, y0, y1, quad, a0, a1, a2, a3); + gp_UV UV = calcUV(x0, x1, y0, y1, quad, a0, a1, a2, a3); gp_Pnt P = S->Value(UV.X(),UV.Y()); SMDS_MeshNode * N = meshDS->AddNode(P.X(), P.Y(), P.Z()); meshDS->SetNodeOnFace(N, geomFaceID, UV.X(), UV.Y()); @@ -2585,7 +2578,7 @@ bool StdMeshers_Quadrangle_2D::ComputeReduced (SMESH_Mesh & aMesh, for (j=2; jValue(UV.X(),UV.Y()); SMDS_MeshNode* N = meshDS->AddNode(P.X(), P.Y(), P.Z()); meshDS->SetNodeOnFace(N, geomFaceID, UV.X(), UV.Y()); @@ -2640,7 +2633,7 @@ bool StdMeshers_Quadrangle_2D::ComputeReduced (SMESH_Mesh & aMesh, for (j=1; jValue(UV.X(),UV.Y()); SMDS_MeshNode* N = meshDS->AddNode(P.X(), P.Y(), P.Z()); meshDS->SetNodeOnFace(N, geomFaceID, UV.X(), UV.Y()); @@ -2676,21 +2669,21 @@ bool StdMeshers_Quadrangle_2D::ComputeReduced (SMESH_Mesh & aMesh, if (nr == nl) { if (nt < nb) { // it is a base case => not shift quad - //ShiftQuad(quad,0,true); + //shiftQuad(quad,0,true); } else { // we have to shift quad on 2 - ShiftQuad(quad,2,true); + shiftQuad(quad,2,true); } } else { if (nl > nr) { // we have to shift quad on 1 - ShiftQuad(quad,1,true); + shiftQuad(quad,1,true); } else { // we have to shift quad on 3 - ShiftQuad(quad,3,true); + shiftQuad(quad,3,true); } } @@ -3273,7 +3266,7 @@ namespace // data for smoothing */ //================================================================================ -void StdMeshers_Quadrangle_2D::UpdateDegenUV(FaceQuadStruct* quad) +void StdMeshers_Quadrangle_2D::UpdateDegenUV(FaceQuadStruct::Ptr quad) { for ( unsigned i = 0; i < quad->side.size(); ++i ) { @@ -3291,7 +3284,7 @@ void StdMeshers_Quadrangle_2D::UpdateDegenUV(FaceQuadStruct* quad) // find another side sharing the degenerated shape bool isPrev = ( degenInd == 0 ); - if ( i >= TOP_SIDE ) + if ( i >= QUAD_TOP_SIDE ) isPrev = !isPrev; int i2 = ( isPrev ? ( i + 3 ) : ( i + 1 )) % 4; StdMeshers_FaceSide* side2 = quad->side[ i2 ]; @@ -3318,7 +3311,7 @@ void StdMeshers_Quadrangle_2D::UpdateDegenUV(FaceQuadStruct* quad) */ //================================================================================ -void StdMeshers_Quadrangle_2D::Smooth (FaceQuadStruct* quad) +void StdMeshers_Quadrangle_2D::Smooth (FaceQuadStruct::Ptr quad) { if ( !myNeedSmooth ) return; diff --git a/src/StdMeshers/StdMeshers_Quadrangle_2D.hxx b/src/StdMeshers/StdMeshers_Quadrangle_2D.hxx index 000c01f66..6ffe0e68f 100644 --- a/src/StdMeshers/StdMeshers_Quadrangle_2D.hxx +++ b/src/StdMeshers/StdMeshers_Quadrangle_2D.hxx @@ -42,16 +42,18 @@ class StdMeshers_FaceSide; struct uvPtStruct; -enum TSideID { BOTTOM_SIDE=0, RIGHT_SIDE, TOP_SIDE, LEFT_SIDE, NB_SIDES }; +enum TSideID { QUAD_BOTTOM_SIDE=0, QUAD_RIGHT_SIDE, QUAD_TOP_SIDE, QUAD_LEFT_SIDE, NB_QUAD_SIDES }; typedef uvPtStruct UVPtStruct; typedef struct faceQuadStruct { std::vector< StdMeshers_FaceSide*> side; - bool isEdgeOut[4]; // true, if an edge has more nodes, than the opposite + bool isEdgeOut[4]; // true, if an EDGE has more nodes, than an opposite one UVPtStruct* uv_grid; TopoDS_Face face; ~faceQuadStruct(); + void shift( size_t nb, bool keepUnitOri ); + typedef boost::shared_ptr Ptr; } FaceQuadStruct; class STDMESHERS_EXPORT StdMeshers_Quadrangle_2D: public SMESH_2D_Algo @@ -70,12 +72,12 @@ public: virtual bool Evaluate(SMESH_Mesh & aMesh, const TopoDS_Shape & aShape, MapShapeNbElems& aResMap); - FaceQuadStruct* CheckAnd2Dcompute(SMESH_Mesh& aMesh, - const TopoDS_Shape& aShape, - const bool CreateQuadratic); + FaceQuadStruct::Ptr CheckAnd2Dcompute(SMESH_Mesh& aMesh, + const TopoDS_Shape& aShape, + const bool CreateQuadratic); - FaceQuadStruct* CheckNbEdges(SMESH_Mesh& aMesh, - const TopoDS_Shape& aShape); + FaceQuadStruct::Ptr CheckNbEdges(SMESH_Mesh& aMesh, + const TopoDS_Shape& aShape); protected: @@ -85,9 +87,9 @@ protected: std::vector& aNbNodes, bool& IsQuadratic); - bool SetNormalizedGrid(SMESH_Mesh& aMesh, - const TopoDS_Shape& aShape, - FaceQuadStruct*& quad); + bool SetNormalizedGrid(SMESH_Mesh& aMesh, + const TopoDS_Shape& aShape, + FaceQuadStruct::Ptr& quad); void SplitQuad(SMESHDS_Mesh *theMeshDS, const int theFaceID, @@ -96,23 +98,23 @@ protected: const SMDS_MeshNode* theNode3, const SMDS_MeshNode* theNode4); - bool ComputeQuadPref(SMESH_Mesh& aMesh, + bool ComputeQuadPref(SMESH_Mesh& aMesh, const TopoDS_Shape& aShape, - FaceQuadStruct* quad); + FaceQuadStruct::Ptr quad); - bool EvaluateQuadPref(SMESH_Mesh& aMesh, + bool EvaluateQuadPref(SMESH_Mesh& aMesh, const TopoDS_Shape& aShape, - std::vector& aNbNodes, - MapShapeNbElems& aResMap, - bool IsQuadratic); + std::vector& aNbNodes, + MapShapeNbElems& aResMap, + bool isQuadratic); - bool ComputeReduced (SMESH_Mesh& aMesh, + bool ComputeReduced (SMESH_Mesh& aMesh, const TopoDS_Shape& aShape, - FaceQuadStruct* quad); + FaceQuadStruct::Ptr quad); - void UpdateDegenUV(FaceQuadStruct* quad); + void UpdateDegenUV(FaceQuadStruct::Ptr quad); - void Smooth (FaceQuadStruct* quad); + void Smooth (FaceQuadStruct::Ptr quad); // true if QuadranglePreference hypothesis is assigned that forces @@ -132,6 +134,8 @@ protected: SMESH_MesherHelper* myHelper; // tool for working with quadratic elements SMESH_ProxyMesh::Ptr myProxyMesh; + + FaceQuadStruct::Ptr myQuadStruct; }; #endif diff --git a/src/StdMeshers/StdMeshers_RadialPrism_3D.cxx b/src/StdMeshers/StdMeshers_RadialPrism_3D.cxx index 6ae4ac787..ec34a041c 100644 --- a/src/StdMeshers/StdMeshers_RadialPrism_3D.cxx +++ b/src/StdMeshers/StdMeshers_RadialPrism_3D.cxx @@ -26,8 +26,11 @@ // Created : Fri Oct 20 11:37:07 2006 // Author : Edward AGAPOV (eap) // + #include "StdMeshers_RadialPrism_3D.hxx" +#include + #include "StdMeshers_ProjectionUtils.hxx" #include "StdMeshers_NumberOfLayers.hxx" #include "StdMeshers_LayerDistribution.hxx" @@ -45,7 +48,11 @@ #include #include +#if OCC_VERSION_LARGE > 0x06050400 +#include +#else #include +#endif #include #include #include @@ -55,7 +62,6 @@ #include #include - using namespace std; #define RETURN_BAD_RESULT(msg) { MESSAGE(")-: Error: " << msg); return false; } @@ -162,7 +168,11 @@ bool StdMeshers_RadialPrism_3D::Compute(SMESH_Mesh& aMesh, const TopoDS_Shape& a // get 2 shells TopoDS_Solid solid = TopoDS::Solid( aShape ); +#if OCC_VERSION_LARGE > 0x06050400 + TopoDS_Shell outerShell = BRepClass3d::OuterShell( solid ); +#else TopoDS_Shell outerShell = BRepTools::OuterShell( solid ); +#endif TopoDS_Shape innerShell; int nbShells = 0; for ( TopoDS_Iterator It (solid); It.More(); It.Next(), ++nbShells ) @@ -402,7 +412,11 @@ bool StdMeshers_RadialPrism_3D::Evaluate(SMESH_Mesh& aMesh, { // get 2 shells TopoDS_Solid solid = TopoDS::Solid( aShape ); +#if OCC_VERSION_LARGE > 0x06050400 + TopoDS_Shell outerShell = BRepClass3d::OuterShell( solid ); +#else TopoDS_Shell outerShell = BRepTools::OuterShell( solid ); +#endif TopoDS_Shape innerShell; int nbShells = 0; for ( TopoDS_Iterator It (solid); It.More(); It.Next(), ++nbShells ) diff --git a/src/StdMeshersGUI/StdMeshersGUI_StdHypothesisCreator.cxx b/src/StdMeshersGUI/StdMeshersGUI_StdHypothesisCreator.cxx index 0a033c033..1e5234d6b 100644 --- a/src/StdMeshersGUI/StdMeshersGUI_StdHypothesisCreator.cxx +++ b/src/StdMeshersGUI/StdMeshersGUI_StdHypothesisCreator.cxx @@ -42,6 +42,8 @@ #include +#include + // SALOME GUI includes #include @@ -418,7 +420,7 @@ bool StdMeshersGUI_StdHypothesisCreator::checkParams( QString& msg ) const GEOM::GEOM_Gen_var geomGen = SMESH::GetGEOMGen(); _PTR(Study) aStudy = SMESH::GetActiveStudyDocument(); - GEOM::GEOM_IShapesOperations_var shapeOp; + GEOM::GEOM_IShapesOperations_wrap shapeOp; if ( !geomGen->_is_nil() && aStudy ) shapeOp = geomGen->GetIShapesOperations( aStudy->StudyId() ); if ( !shapeOp->_is_nil() ) diff --git a/src/StdMeshersGUI/StdMeshersGUI_SubShapeSelectorWdg.cxx b/src/StdMeshersGUI/StdMeshersGUI_SubShapeSelectorWdg.cxx index 637163f66..03b6750b6 100644 --- a/src/StdMeshersGUI/StdMeshersGUI_SubShapeSelectorWdg.cxx +++ b/src/StdMeshersGUI/StdMeshersGUI_SubShapeSelectorWdg.cxx @@ -68,9 +68,6 @@ #include #include -// SALOME KERNEL includes -#include - #define SPACING 6 #define MARGIN 0 @@ -251,7 +248,7 @@ void StdMeshersGUI_SubShapeSelectorWdg::SelectionIntoArgument() GEOM::GEOM_Object_var aGeomObj = GetGeomObjectByEntry( IO->getEntry() ); if ( !CORBA::is_nil( aGeomObj ) ) { // Selected Object From Study - GEOM::GEOM_Object_ptr aGeomFatherObj = aGeomObj->GetMainShape(); + GEOM::GEOM_Object_var aGeomFatherObj = aGeomObj->GetMainShape(); QString aFatherEntry = ""; QString aMainFatherEntry = ""; TopoDS_Shape shape; @@ -259,13 +256,13 @@ void StdMeshersGUI_SubShapeSelectorWdg::SelectionIntoArgument() // Get Main Shape GEOM::GEOM_Object_var aGeomMain = GetGeomObjectByEntry( myEntry ); if ( !CORBA::is_nil( aGeomMain ) && aGeomMain->GetType() == 37 ) { // Main Shape is a Group - GEOM::GEOM_Object_ptr aMainFatherObj = aGeomMain->GetMainShape(); + GEOM::GEOM_Object_var aMainFatherObj = aGeomMain->GetMainShape(); if ( !CORBA::is_nil( aMainFatherObj ) ) aMainFatherEntry = aMainFatherObj->GetStudyEntry(); } aFatherEntry = aGeomFatherObj->GetStudyEntry(); } - + if ( aFatherEntry != "" && ( aFatherEntry == myEntry || aFatherEntry == aMainFatherEntry ) ) { if ( aGeomObj->GetType() == 37 /*GEOM_GROUP*/ ) { // Selected Group that belongs the main object @@ -470,18 +467,17 @@ GEOM::GEOM_Object_var StdMeshersGUI_SubShapeSelectorWdg::GetGeomObjectByEntry( c { GEOM::GEOM_Object_var aGeomObj; SALOMEDS::Study_var aStudy = SMESHGUI::GetSMESHGen()->GetCurrentStudy(); - if (aStudy != 0) { + if ( !aStudy->_is_nil() ) + { SALOMEDS::SObject_var aSObj = aStudy->FindObjectID( theEntry.toLatin1().data() ); - SALOMEDS::GenericAttribute_var anAttr; - - if (!aSObj->_is_nil() && aSObj->FindAttribute(anAttr, "AttributeIOR")) { - SALOMEDS::AttributeIOR_var anIOR = SALOMEDS::AttributeIOR::_narrow(anAttr); - CORBA::String_var aVal = anIOR->Value(); - CORBA::Object_var obj = aStudy->ConvertIORToObject(aVal); + if (!aSObj->_is_nil() ) + { + CORBA::Object_var obj = aSObj->GetObject(); aGeomObj = GEOM::GEOM_Object::_narrow(obj); + aSObj->UnRegister(); } } - return aGeomObj; + return aGeomObj._retn(); } //================================================================================= diff --git a/src/StdMeshers_I/StdMeshers_ImportSource1D_i.cxx b/src/StdMeshers_I/StdMeshers_ImportSource1D_i.cxx index e2ad32141..cf6eb6986 100644 --- a/src/StdMeshers_I/StdMeshers_ImportSource1D_i.cxx +++ b/src/StdMeshers_I/StdMeshers_ImportSource1D_i.cxx @@ -32,8 +32,9 @@ #include "SMESH_PythonDump.hxx" #include "StdMeshers_ObjRefUlils.hxx" -#include "Utils_CorbaException.hxx" -#include "utilities.h" +#include +#include +#include #include @@ -97,7 +98,7 @@ void StdMeshers_ImportSource1D_i::SetSourceEdges(const SMESH::ListOfGroups& grou THROW_SALOME_CORBA_EXCEPTION("Wrong group type", SALOME::BAD_PARAM); smesh_groups.push_back( gp_i->GetSmeshGroup() ); - SALOMEDS::SObject_var so = SMESH_Gen_i::GetSMESHGen()->ObjectToSObject(study, groups[i]); + SALOMEDS::SObject_wrap so = SMESH_Gen_i::ObjectToSObject(study, groups[i]); if ( !so->_is_nil()) { CORBA::String_var entry = so->GetID(); @@ -178,8 +179,8 @@ char* StdMeshers_ImportSource1D_i::SaveTo() os << " " << _groupEntries[i]; // id - SALOMEDS::SObject_var groupSO = study->FindObjectID( _groupEntries[i] ); - CORBA::Object_var groupObj; + SALOMEDS::SObject_wrap groupSO = study->FindObjectID( _groupEntries[i] ); + CORBA::Object_var groupObj; if ( !groupSO->_is_nil() ) groupObj = groupSO->GetObject(); StdMeshers_ObjRefUlils::SaveToStream( groupObj, os ); diff --git a/src/StdMeshers_I/StdMeshers_ImportSource2D_i.cxx b/src/StdMeshers_I/StdMeshers_ImportSource2D_i.cxx index 35f9d3fb0..29d14804d 100644 --- a/src/StdMeshers_I/StdMeshers_ImportSource2D_i.cxx +++ b/src/StdMeshers_I/StdMeshers_ImportSource2D_i.cxx @@ -97,11 +97,12 @@ void StdMeshers_ImportSource2D_i::SetSourceFaces(const SMESH::ListOfGroups& grou THROW_SALOME_CORBA_EXCEPTION("Wrong group type", SALOME::BAD_PARAM); smesh_groups.push_back( gp_i->GetSmeshGroup() ); - SALOMEDS::SObject_var so = SMESH_Gen_i::GetSMESHGen()->ObjectToSObject(study, groups[i]); + SALOMEDS::SObject_var so = SMESH_Gen_i::ObjectToSObject(study, groups[i]); if ( !so->_is_nil()) { CORBA::String_var entry = so->GetID(); entries.push_back( entry.in() ); + so->UnRegister(); } } this->GetImpl()->SetGroups( smesh_groups ); @@ -179,9 +180,11 @@ char* StdMeshers_ImportSource2D_i::SaveTo() // id SALOMEDS::SObject_var groupSO = study->FindObjectID( _groupEntries[i] ); - CORBA::Object_var groupObj; - if ( !groupSO->_is_nil() ) + CORBA::Object_var groupObj; + if ( !groupSO->_is_nil() ) { groupObj = groupSO->GetObject(); + groupSO->UnRegister(); + } StdMeshers_ObjRefUlils::SaveToStream( groupObj, os ); } diff --git a/src/StdMeshers_I/StdMeshers_LayerDistribution_i.cxx b/src/StdMeshers_I/StdMeshers_LayerDistribution_i.cxx index e162f22aa..0d4381be1 100644 --- a/src/StdMeshers_I/StdMeshers_LayerDistribution_i.cxx +++ b/src/StdMeshers_I/StdMeshers_LayerDistribution_i.cxx @@ -88,11 +88,16 @@ void StdMeshers_LayerDistribution_i::SetLayerDistribution(SMESH::SMESH_Hypothesi this->GetImpl()->SetLayerDistribution( hyp_i->GetImpl() ); myHyp = SMESH::SMESH_Hypothesis::_duplicate( hyp1D ); // Remove SO of 1D hypothesis if it was published - if (SMESH_Gen_i* gen = SMESH_Gen_i::GetSMESHGen()) { + if (SMESH_Gen_i* gen = SMESH_Gen_i::GetSMESHGen()) + { SALOMEDS::Study_var study = gen->GetCurrentStudy(); - SALOMEDS::SObject_var SO = gen->ObjectToSObject( study, hyp1D ); + SALOMEDS::SObject_var SO = gen->ObjectToSObject( study, hyp1D ); if ( ! SO->_is_nil() ) - study->NewBuilder()->RemoveObjectWithChildren( SO ); + { + SALOMEDS::StudyBuilder_var builder = study->NewBuilder(); + builder->RemoveObjectWithChildren( SO ); + SO->UnRegister(); + } } // Update Python script: write creation of 1D hyp as it is not published and // for this, SMESH_Gen does not write it's creation diff --git a/src/StdMeshers_I/StdMeshers_ObjRefUlils.cxx b/src/StdMeshers_I/StdMeshers_ObjRefUlils.cxx index 910d0aaa8..390bd34c5 100644 --- a/src/StdMeshers_I/StdMeshers_ObjRefUlils.cxx +++ b/src/StdMeshers_I/StdMeshers_ObjRefUlils.cxx @@ -27,6 +27,7 @@ // #include "StdMeshers_ObjRefUlils.hxx" +#include #include using namespace std; @@ -60,8 +61,8 @@ StdMeshers_ObjRefUlils::EntryOrShapeToGeomObject (const std::string& theEntry, if (SMESH_Gen_i* gen = SMESH_Gen_i::GetSMESHGen()) { SALOMEDS::Study_var study = gen->GetCurrentStudy(); if ( ! theEntry.empty() && ! study->_is_nil() ) { - SALOMEDS::SObject_var sobj= study->FindObjectID( theEntry.c_str() ); - CORBA::Object_var obj = gen->SObjectToObject( sobj ); + SALOMEDS::SObject_wrap sobj = study->FindObjectID( theEntry.c_str() ); + CORBA::Object_var obj = gen->SObjectToObject( sobj ); geom = GEOM::GEOM_Object::_narrow( obj ); } } @@ -87,9 +88,10 @@ void StdMeshers_ObjRefUlils::SaveToStream( const TopoDS_Shape& theShape, ostream if (SMESH_Gen_i* gen = SMESH_Gen_i::GetSMESHGen()) { GEOM::GEOM_Object_var geom = gen->ShapeToGeomObject( theShape ); if ( ! geom->_is_nil() ) { - SALOMEDS::SObject_var sobj = gen->ObjectToSObject( gen->GetCurrentStudy(), geom ); + SALOMEDS::SObject_wrap sobj = gen->ObjectToSObject( gen->GetCurrentStudy(), geom ); if ( !sobj->_is_nil() ) { - stream << " " << sobj->GetID(); + CORBA::String_var entry = sobj->GetID(); + stream << " " << entry.in(); ok = true; } } @@ -114,9 +116,9 @@ TopoDS_Shape StdMeshers_ObjRefUlils::LoadFromStream( istream & stream) if ( ! study->_is_nil() ) { string str; if (stream >> str) { - SALOMEDS::SObject_var sobj= study->FindObjectID( str.c_str() ); - CORBA::Object_var obj = gen->SObjectToObject( sobj ); - GEOM::GEOM_Object_var geom = GEOM::GEOM_Object::_narrow( obj ); + SALOMEDS::SObject_wrap sobj = study->FindObjectID( str.c_str() ); + CORBA::Object_var obj = gen->SObjectToObject( sobj ); + GEOM::GEOM_Object_var geom = GEOM::GEOM_Object::_narrow( obj ); return gen->GeomObjectToShape( geom.in() ); } } diff --git a/src/Tools/MeshCut/MeshCut_Maillage.cxx b/src/Tools/MeshCut/MeshCut_Maillage.cxx index 0ae4437e0..08284c21a 100644 --- a/src/Tools/MeshCut/MeshCut_Maillage.cxx +++ b/src/Tools/MeshCut/MeshCut_Maillage.cxx @@ -1121,8 +1121,8 @@ void Maillage::outputMED(std::string fichierMED) // Création de la famille if (MEDfamilyCr(fid, maa, nomfam, numfam, 0, MED_NO_GROUP) < 0) ERREUR("Error MEDfamilyCr"); - delete gro; - } + delete gro; + } } @@ -1437,7 +1437,7 @@ void Maillage::outputMED(std::string fichierMED) if (MEDfamilyCr(fid, maa, nomfam, numfam, 1, gro) < 0) ERREUR("Error MEDfamilyCr"); - delete gro; + delete gro; } } diff --git a/src/Tools/YamsPlug/monYamsPlugDialog.py b/src/Tools/YamsPlug/monYamsPlugDialog.py index c92765d78..43158e05d 100644 --- a/src/Tools/YamsPlug/monYamsPlugDialog.py +++ b/src/Tools/YamsPlug/monYamsPlugDialog.py @@ -20,7 +20,7 @@ # Modules Python # Modules Eficas -import os +import os, subprocess from YamsPlugDialog import Ui_YamsPlugDialog from monViewText import MonViewText from PyQt4.QtGui import * @@ -64,11 +64,8 @@ class MonYamsPlugDialog(Ui_YamsPlugDialog,QWidget): maDoc=os.environ['DISTENE_YAMS_DOC_PDF'] except Exception: QMessageBox.warning( self, "Help unavailable", str(maDoc) + " not found") - old_ld=os.getenv("LD_LIBRARY_PATH") - command="unset LD_LIBRARY_PATH;" - command+="xdg-open "+maDoc+";" - command+="export LD_LIBRARY_PATH=%s"%old_ld - os.system(command) + command="xdg-open "+maDoc+";" + subprocess.call(command, shell=True) def PBOKPressed(self): diff --git a/src/Tools/padder/meshjob/impl/MeshJobManager_i.cxx b/src/Tools/padder/meshjob/impl/MeshJobManager_i.cxx index 612906070..76c71870e 100644 --- a/src/Tools/padder/meshjob/impl/MeshJobManager_i.cxx +++ b/src/Tools/padder/meshjob/impl/MeshJobManager_i.cxx @@ -294,9 +294,9 @@ CORBA::Long MeshJobManager_i::initialize(const MESHJOB::MeshJobParameterList & m break; default: _lastErrorMessage = - std::string("The type of the file ")+ - std::string(currentMesh.file_name)+ - std::string(" is not recognized"); + std::string("The type of the file ")+ + std::string(currentMesh.file_name)+ + std::string(" is not recognized"); LOG(_lastErrorMessage); return JOBID_UNDEFINED; } diff --git a/src/Tools/padder/meshjob/impl/MeshJobManager_i.hxx b/src/Tools/padder/meshjob/impl/MeshJobManager_i.hxx index f53d7aa34..40e2a96ce 100644 --- a/src/Tools/padder/meshjob/impl/MeshJobManager_i.hxx +++ b/src/Tools/padder/meshjob/impl/MeshJobManager_i.hxx @@ -42,9 +42,9 @@ public: ~MeshJobManager_i(); bool configure (const char *configId, - const MESHJOB::ConfigParameter & configParameter); + const MESHJOB::ConfigParameter & configParameter); CORBA::Long initialize (const MESHJOB::MeshJobParameterList & meshJobParameterList, - const char *configId); + const char *configId); bool start (CORBA::Long jobId); char* getState (CORBA::Long jobId); MESHJOB::MeshJobResults * finalize(CORBA::Long jobId); diff --git a/src/Tools/padder/meshjob/impl/SPADDERPluginTester_i.hxx b/src/Tools/padder/meshjob/impl/SPADDERPluginTester_i.hxx index 26a7416cd..6aa4c71ce 100644 --- a/src/Tools/padder/meshjob/impl/SPADDERPluginTester_i.hxx +++ b/src/Tools/padder/meshjob/impl/SPADDERPluginTester_i.hxx @@ -33,8 +33,8 @@ class SPADDERPluginTester_i: { public: SPADDERPluginTester_i(CORBA::ORB_ptr orb, PortableServer::POA_ptr poa, - PortableServer::ObjectId * contId, - const char *instanceName, const char *interfaceName); + PortableServer::ObjectId * contId, + const char *instanceName, const char *interfaceName); virtual ~SPADDERPluginTester_i(); void demo(CORBA::Double a,CORBA::Double b,CORBA::Double& c); -- 2.39.2

9A`ar$~=WYgc1 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�f;_ZeDYK@HN#l_3C!5cOA}u25L6Kb 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¯Oz!12o_==$2-$+ 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 diff --git a/doc/salome/gui/SMESH/images/prism_needs_hyps.png b/doc/salome/gui/SMESH/images/prism_needs_hyps.png new file mode 100644 index 0000000000000000000000000000000000000000..8c567809df180b98afe8c1ebf95f78bfffd5b275 GIT binary patch literal 19373 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